Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/hwmon/occ/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 4 kB image not shown  

Quelle  p9_sbe.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0+
// Copyright IBM Corp 2019

#include <linux/device.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/fsi-occ.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/string.h>
#include <linux/sysfs.h>

#include "common.h"

#define OCC_CHECKSUM_RETRIES 3

struct p9_sbe_occ {
 struct occ occ;
 bool sbe_error;
 void *ffdc;
 size_t ffdc_len;
 size_t ffdc_size;
 struct mutex sbe_error_lock; /* lock access to ffdc data */
 struct device *sbe;
};

#define to_p9_sbe_occ(x) container_of((x), struct p9_sbe_occ, occ)

static ssize_t ffdc_read(struct file *filp, struct kobject *kobj,
    const struct bin_attribute *battr, char *buf, loff_t pos,
    size_t count)
{
 ssize_t rc = 0;
 struct occ *occ = dev_get_drvdata(kobj_to_dev(kobj));
 struct p9_sbe_occ *ctx = to_p9_sbe_occ(occ);

 mutex_lock(&ctx->sbe_error_lock);
 if (ctx->sbe_error) {
  rc = memory_read_from_buffer(buf, count, &pos, ctx->ffdc,
          ctx->ffdc_len);
  if (pos >= ctx->ffdc_len)
   ctx->sbe_error = false;
 }
 mutex_unlock(&ctx->sbe_error_lock);

 return rc;
}
static const BIN_ATTR_RO(ffdc, OCC_MAX_RESP_WORDS * 4);

static bool p9_sbe_occ_save_ffdc(struct p9_sbe_occ *ctx, const void *resp,
     size_t resp_len)
{
 bool notify = false;

 mutex_lock(&ctx->sbe_error_lock);
 if (!ctx->sbe_error) {
  if (resp_len > ctx->ffdc_size) {
   kvfree(ctx->ffdc);
   ctx->ffdc = kvmalloc(resp_len, GFP_KERNEL);
   if (!ctx->ffdc) {
    ctx->ffdc_len = 0;
    ctx->ffdc_size = 0;
    goto done;
   }

   ctx->ffdc_size = resp_len;
  }

  notify = true;
  ctx->sbe_error = true;
  ctx->ffdc_len = resp_len;
  memcpy(ctx->ffdc, resp, resp_len);
 }

done:
 mutex_unlock(&ctx->sbe_error_lock);
 return notify;
}

static int p9_sbe_occ_send_cmd(struct occ *occ, u8 *cmd, size_t len,
          void *resp, size_t resp_len)
{
 size_t original_resp_len = resp_len;
 struct p9_sbe_occ *ctx = to_p9_sbe_occ(occ);
 int rc, i;

 for (i = 0; i < OCC_CHECKSUM_RETRIES; ++i) {
  rc = fsi_occ_submit(ctx->sbe, cmd, len, resp, &resp_len);
  if (rc >= 0)
   break;
  if (resp_len) {
   if (p9_sbe_occ_save_ffdc(ctx, resp, resp_len))
    sysfs_notify(&occ->bus_dev->kobj, NULL,
          bin_attr_ffdc.attr.name);
   return rc;
  }
  if (rc != -EBADE)
   return rc;
  resp_len = original_resp_len;
 }

 switch (((struct occ_response *)resp)->return_status) {
 case OCC_RESP_CMD_IN_PRG:
  rc = -ETIMEDOUT;
  break;
 case OCC_RESP_SUCCESS:
  rc = 0;
  break;
 case OCC_RESP_CMD_INVAL:
 case OCC_RESP_CMD_LEN_INVAL:
 case OCC_RESP_DATA_INVAL:
 case OCC_RESP_CHKSUM_ERR:
  rc = -EINVAL;
  break;
 case OCC_RESP_INT_ERR:
 case OCC_RESP_BAD_STATE:
 case OCC_RESP_CRIT_EXCEPT:
 case OCC_RESP_CRIT_INIT:
 case OCC_RESP_CRIT_WATCHDOG:
 case OCC_RESP_CRIT_OCB:
 case OCC_RESP_CRIT_HW:
  rc = -EREMOTEIO;
  break;
 default:
  rc = -EPROTO;
 }

 return rc;
}

static int p9_sbe_occ_probe(struct platform_device *pdev)
{
 int rc;
 struct occ *occ;
 struct p9_sbe_occ *ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx),
           GFP_KERNEL);
 if (!ctx)
  return -ENOMEM;

 mutex_init(&ctx->sbe_error_lock);

 ctx->sbe = pdev->dev.parent;
 occ = &ctx->occ;
 occ->bus_dev = &pdev->dev;
 platform_set_drvdata(pdev, occ);

 occ->powr_sample_time_us = 500;
 occ->poll_cmd_data = 0x20;  /* P9 OCC poll data */
 occ->send_cmd = p9_sbe_occ_send_cmd;

 rc = occ_setup(occ);
 if (rc == -ESHUTDOWN)
  rc = -ENODEV; /* Host is shutdown, don't spew errors */

 if (!rc) {
  rc = device_create_bin_file(occ->bus_dev, &bin_attr_ffdc);
  if (rc) {
   dev_warn(occ->bus_dev,
     "failed to create SBE error ffdc file\n");
   rc = 0;
  }
 }

 return rc;
}

static void p9_sbe_occ_remove(struct platform_device *pdev)
{
 struct occ *occ = platform_get_drvdata(pdev);
 struct p9_sbe_occ *ctx = to_p9_sbe_occ(occ);

 device_remove_bin_file(occ->bus_dev, &bin_attr_ffdc);

 ctx->sbe = NULL;
 occ_shutdown(occ);

 kvfree(ctx->ffdc);
}

static const struct of_device_id p9_sbe_occ_of_match[] = {
 { .compatible = "ibm,p9-occ-hwmon" },
 { .compatible = "ibm,p10-occ-hwmon" },
 {}
};
MODULE_DEVICE_TABLE(of, p9_sbe_occ_of_match);

static struct platform_driver p9_sbe_occ_driver = {
 .driver = {
  .name = "occ-hwmon",
  .of_match_table = p9_sbe_occ_of_match,
 },
 .probe = p9_sbe_occ_probe,
 .remove = p9_sbe_occ_remove,
};

module_platform_driver(p9_sbe_occ_driver);

MODULE_AUTHOR("Eddie James ");
MODULE_DESCRIPTION("BMC P9 OCC hwmon driver");
MODULE_LICENSE("GPL");

Messung V0.5
C=96 H=94 G=94

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.