Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/Roqc/test-suite/output/   (Beweissystem des Inria Version 9.1.0©)  Datei vom 15.8.2025 mit Größe 1 kB image not shown  

Quelle  ipmi_si_hotmod.c   Sprache: unbekannt

 
// SPDX-License-Identifier: GPL-2.0+
/*
 * ipmi_si_hotmod.c
 *
 * Handling for dynamically adding/removing IPMI devices through
 * a module parameter (and thus sysfs).
 */


#define pr_fmt(fmt) "ipmi_hotmod: " fmt

#include <linux/moduleparam.h>
#include <linux/ipmi.h>
#include <linux/atomic.h>
#include "ipmi_si.h"
#include "ipmi_plat_data.h"

static int hotmod_handler(const char *val, const struct kernel_param *kp);

module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200);
MODULE_PARM_DESC(hotmod,
   "Add and remove interfaces. See Documentation/driver-api/ipmi.rst in the kernel sources for the gory details.");

/*
 * Parms come in as <op1>[:op2[:op3...]].  ops are:
 *   add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]]
 * Options are:
 *   rsp=<regspacing>
 *   rsi=<regsize>
 *   rsh=<regshift>
 *   irq=<irq>
 *   ipmb=<ipmb addr>
 */

enum hotmod_op { HM_ADD, HM_REMOVE };
struct hotmod_vals {
 const char *name;
 const int  val;
};

static const struct hotmod_vals hotmod_ops[] = {
 { "add", HM_ADD },
 { "remove", HM_REMOVE },
 { NULL }
};

static const struct hotmod_vals hotmod_si[] = {
 { "kcs", SI_KCS },
 { "smic", SI_SMIC },
 { "bt",  SI_BT },
 { NULL }
};

static const struct hotmod_vals hotmod_as[] = {
 { "mem", IPMI_MEM_ADDR_SPACE },
 { "i/o", IPMI_IO_ADDR_SPACE },
 { NULL }
};

static int parse_str(const struct hotmod_vals *v, unsigned int *val, char *name,
       const char **curr)
{
 char *s;
 int  i;

 s = strchr(*curr, ',');
 if (!s) {
  pr_warn("No hotmod %s given\n", name);
  return -EINVAL;
 }
 *s = '\0';
 s++;
 for (i = 0; v[i].name; i++) {
  if (strcmp(*curr, v[i].name) == 0) {
   *val = v[i].val;
   *curr = s;
   return 0;
  }
 }

 pr_warn("Invalid hotmod %s '%s'\n", name, *curr);
 return -EINVAL;
}

static int check_hotmod_int_op(const char *curr, const char *option,
          const char *name, unsigned int *val)
{
 char *n;

 if (strcmp(curr, name) == 0) {
  if (!option) {
   pr_warn("No option given for '%s'\n", curr);
   return -EINVAL;
  }
  *val = simple_strtoul(option, &n, 0);
  if ((*n != '\0') || (*option == '\0')) {
   pr_warn("Bad option given for '%s'\n", curr);
   return -EINVAL;
  }
  return 1;
 }
 return 0;
}

static int parse_hotmod_str(const char *curr, enum hotmod_op *op,
       struct ipmi_plat_data *h)
{
 char *s, *o;
 int rv;
 unsigned int ival;

 h->iftype = IPMI_PLAT_IF_SI;
 rv = parse_str(hotmod_ops, &ival, "operation", &curr);
 if (rv)
  return rv;
 *op = ival;

 rv = parse_str(hotmod_si, &ival, "interface type", &curr);
 if (rv)
  return rv;
 h->type = ival;

 rv = parse_str(hotmod_as, &ival, "address space", &curr);
 if (rv)
  return rv;
 h->space = ival;

 s = strchr(curr, ',');
 if (s) {
  *s = '\0';
  s++;
 }
 rv = kstrtoul(curr, 0, &h->addr);
 if (rv) {
  pr_warn("Invalid hotmod address '%s': %d\n", curr, rv);
  return rv;
 }

 while (s) {
  curr = s;
  s = strchr(curr, ',');
  if (s) {
   *s = '\0';
   s++;
  }
  o = strchr(curr, '=');
  if (o) {
   *o = '\0';
   o++;
  }
  rv = check_hotmod_int_op(curr, o, "rsp", &h->regspacing);
  if (rv < 0)
   return rv;
  else if (rv)
   continue;
  rv = check_hotmod_int_op(curr, o, "rsi", &h->regsize);
  if (rv < 0)
   return rv;
  else if (rv)
   continue;
  rv = check_hotmod_int_op(curr, o, "rsh", &h->regshift);
  if (rv < 0)
   return rv;
  else if (rv)
   continue;
  rv = check_hotmod_int_op(curr, o, "irq", &h->irq);
  if (rv < 0)
   return rv;
  else if (rv)
   continue;
  rv = check_hotmod_int_op(curr, o, "ipmb", &h->slave_addr);
  if (rv < 0)
   return rv;
  else if (rv)
   continue;

  pr_warn("Invalid hotmod option '%s'\n", curr);
  return -EINVAL;
 }

 h->addr_source = SI_HOTMOD;
 return 0;
}

static atomic_t hotmod_nr;

static int hotmod_handler(const char *val, const struct kernel_param *kp)
{
 int  rv;
 struct ipmi_plat_data h;
 char *str, *curr, *next;

 str = kstrdup(val, GFP_KERNEL);
 if (!str)
  return -ENOMEM;

 /* Kill any trailing spaces, as we can get a "\n" from echo. */
 for (curr = strstrip(str); curr; curr = next) {
  enum hotmod_op op;

  next = strchr(curr, ':');
  if (next) {
   *next = '\0';
   next++;
  }

  memset(&h, 0, sizeof(h));
  rv = parse_hotmod_str(curr, &op, &h);
  if (rv)
   goto out;

  if (op == HM_ADD) {
   ipmi_platform_add("hotmod-ipmi-si",
       atomic_inc_return(&hotmod_nr),
       &h);
  } else {
   struct device *dev;

   dev = ipmi_si_remove_by_data(h.space, h.type, h.addr);
   if (dev && dev_is_platform(dev)) {
    struct platform_device *pdev;

    pdev = to_platform_device(dev);
    if (strcmp(pdev->name, "hotmod-ipmi-si") == 0)
     platform_device_unregister(pdev);
   }
   put_device(dev);
  }
 }
 rv = strlen(val);
out:
 kfree(str);
 return rv;
}

void ipmi_si_hotmod_exit(void)
{
 ipmi_remove_platform_device_by_name("hotmod-ipmi-si");
}

Messung V0.5
C=97 H=92 G=94

[ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ]