aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/ipmi/ipmi_si_hotmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/ipmi/ipmi_si_hotmod.c')
-rw-r--r--drivers/char/ipmi/ipmi_si_hotmod.c222
1 files changed, 112 insertions, 110 deletions
diff --git a/drivers/char/ipmi/ipmi_si_hotmod.c b/drivers/char/ipmi/ipmi_si_hotmod.c
index c0067fd0480d..03140f6cdf6f 100644
--- a/drivers/char/ipmi/ipmi_si_hotmod.c
+++ b/drivers/char/ipmi/ipmi_si_hotmod.c
@@ -10,7 +10,9 @@
#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);
@@ -54,8 +56,8 @@ static const struct hotmod_vals hotmod_as[] = {
{ NULL }
};
-static int parse_str(const struct hotmod_vals *v, int *val, char *name,
- char **curr)
+static int parse_str(const struct hotmod_vals *v, unsigned int *val, char *name,
+ const char **curr)
{
char *s;
int i;
@@ -80,7 +82,7 @@ static int parse_str(const struct hotmod_vals *v, int *val, char *name,
}
static int check_hotmod_int_op(const char *curr, const char *option,
- const char *name, int *val)
+ const char *name, unsigned int *val)
{
char *n;
@@ -99,22 +101,94 @@ static int check_hotmod_int_op(const char *curr, const char *option,
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;
+
+ 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)
{
- char *str = kstrdup(val, GFP_KERNEL);
+ char *str = kstrdup(val, GFP_KERNEL), *curr, *next;
int rv;
- char *next, *curr, *s, *n, *o;
- enum hotmod_op op;
- enum si_type si_type;
- int addr_space;
- unsigned long addr;
- int regspacing;
- int regsize;
- int regshift;
- int irq;
- int ipmb;
+ struct ipmi_plat_data h;
+ unsigned int len;
int ival;
- int len;
if (!str)
return -ENOMEM;
@@ -128,11 +202,7 @@ static int hotmod_handler(const char *val, const struct kernel_param *kp)
}
for (curr = str; curr; curr = next) {
- regspacing = 1;
- regsize = 1;
- regshift = 0;
- irq = 0;
- ipmb = 0; /* Choose the default if not specified */
+ enum hotmod_op op;
next = strchr(curr, ':');
if (next) {
@@ -140,101 +210,28 @@ static int hotmod_handler(const char *val, const struct kernel_param *kp)
next++;
}
- rv = parse_str(hotmod_ops, &ival, "operation", &curr);
- if (rv)
- break;
- op = ival;
-
- rv = parse_str(hotmod_si, &ival, "interface type", &curr);
+ memset(&h, 0, sizeof(h));
+ rv = parse_hotmod_str(curr, &op, &h);
if (rv)
- break;
- si_type = ival;
-
- rv = parse_str(hotmod_as, &addr_space, "address space", &curr);
- if (rv)
- break;
-
- s = strchr(curr, ',');
- if (s) {
- *s = '\0';
- s++;
- }
- addr = simple_strtoul(curr, &n, 0);
- if ((*n != '\0') || (*curr == '\0')) {
- pr_warn("Invalid hotmod address '%s'\n", curr);
- break;
- }
-
- 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", &regspacing);
- if (rv < 0)
- goto out;
- else if (rv)
- continue;
- rv = check_hotmod_int_op(curr, o, "rsi", &regsize);
- if (rv < 0)
- goto out;
- else if (rv)
- continue;
- rv = check_hotmod_int_op(curr, o, "rsh", &regshift);
- if (rv < 0)
- goto out;
- else if (rv)
- continue;
- rv = check_hotmod_int_op(curr, o, "irq", &irq);
- if (rv < 0)
- goto out;
- else if (rv)
- continue;
- rv = check_hotmod_int_op(curr, o, "ipmb", &ipmb);
- if (rv < 0)
- goto out;
- else if (rv)
- continue;
-
- rv = -EINVAL;
- pr_warn("Invalid hotmod option '%s'\n", curr);
goto out;
- }
if (op == HM_ADD) {
- struct si_sm_io io;
-
- memset(&io, 0, sizeof(io));
- io.addr_source = SI_HOTMOD;
- io.si_type = si_type;
- io.addr_data = addr;
- io.addr_type = addr_space;
-
- io.addr = NULL;
- io.regspacing = regspacing;
- if (!io.regspacing)
- io.regspacing = DEFAULT_REGSPACING;
- io.regsize = regsize;
- if (!io.regsize)
- io.regsize = DEFAULT_REGSIZE;
- io.regshift = regshift;
- io.irq = irq;
- if (io.irq)
- io.irq_setup = ipmi_std_irq_setup;
- io.slave_addr = ipmb;
-
- rv = ipmi_si_add_smi(&io);
- if (rv)
- goto out;
+ ipmi_platform_add("hotmod-ipmi-si",
+ atomic_inc_return(&hotmod_nr),
+ &h);
} else {
- ipmi_si_remove_by_data(addr_space, si_type, addr);
+ 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);
+ }
+ if (dev)
+ put_device(dev);
}
}
rv = len;
@@ -242,3 +239,8 @@ out:
kfree(str);
return rv;
}
+
+void ipmi_si_hotmod_exit(void)
+{
+ ipmi_remove_platform_device_by_name("hotmod-ipmi-si");
+}