ipmi_si: Move the hotmod handling to another file.
authorCorey Minyard <cminyard@mvista.com>
Wed, 13 Sep 2017 03:28:49 +0000 (22:28 -0500)
committerCorey Minyard <cminyard@mvista.com>
Wed, 27 Sep 2017 21:03:45 +0000 (16:03 -0500)
Signed-off-by: Corey Minyard <cminyard@mvista.com>
drivers/char/ipmi/Makefile
drivers/char/ipmi/ipmi_si.h
drivers/char/ipmi/ipmi_si_hotmod.c [new file with mode: 0644]
drivers/char/ipmi/ipmi_si_intf.c

index eefb0b301e836bf77f481e39db0f1181729e8485..61c7d5d32f4a3f3f20ec4eb7e7cd31835582fef1 100644 (file)
@@ -2,7 +2,8 @@
 # Makefile for the ipmi drivers.
 #
 
-ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o
+ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o \
+       ipmi_si_hotmod.o
 
 obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
 obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
index 9573b35d73af0431f57fe57d21a41533efc67d04..4ceb5ac3ad98a88f1c86001c1d83cffb2682a249 100644 (file)
@@ -20,3 +20,5 @@ void ipmi_irq_start_cleanup(struct si_sm_io *io);
 int ipmi_std_irq_setup(struct si_sm_io *io);
 void ipmi_irq_finish_setup(struct si_sm_io *io);
 int ipmi_si_remove_by_dev(struct device *dev);
+void ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
+                           unsigned long addr);
diff --git a/drivers/char/ipmi/ipmi_si_hotmod.c b/drivers/char/ipmi/ipmi_si_hotmod.c
new file mode 100644 (file)
index 0000000..da57161
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * ipmi_si_hotmod.c
+ *
+ * Handling for dynamically adding/removing IPMI devices through
+ * a module parameter (and thus sysfs).
+ */
+#include <linux/moduleparam.h>
+#include <linux/ipmi.h>
+#include "ipmi_si.h"
+
+#define PFX "ipmi_hotmod: "
+
+static int hotmod_handler(const char *val, struct kernel_param *kp);
+
+module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200);
+MODULE_PARM_DESC(hotmod, "Add and remove interfaces.  See"
+                " Documentation/IPMI.txt 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, int *val, char *name,
+                    char **curr)
+{
+       char *s;
+       int  i;
+
+       s = strchr(*curr, ',');
+       if (!s) {
+               pr_warn(PFX "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(PFX "Invalid hotmod %s '%s'\n", name, *curr);
+       return -EINVAL;
+}
+
+static int check_hotmod_int_op(const char *curr, const char *option,
+                              const char *name, int *val)
+{
+       char *n;
+
+       if (strcmp(curr, name) == 0) {
+               if (!option) {
+                       pr_warn(PFX "No option given for '%s'\n", curr);
+                       return -EINVAL;
+               }
+               *val = simple_strtoul(option, &n, 0);
+               if ((*n != '\0') || (*option == '\0')) {
+                       pr_warn(PFX "Bad option given for '%s'\n", curr);
+                       return -EINVAL;
+               }
+               return 1;
+       }
+       return 0;
+}
+
+static int hotmod_handler(const char *val, struct kernel_param *kp)
+{
+       char *str = kstrdup(val, GFP_KERNEL);
+       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;
+       int ival;
+       int len;
+
+       if (!str)
+               return -ENOMEM;
+
+       /* Kill any trailing spaces, as we can get a "\n" from echo. */
+       len = strlen(str);
+       ival = len - 1;
+       while ((ival >= 0) && isspace(str[ival])) {
+               str[ival] = '\0';
+               ival--;
+       }
+
+       for (curr = str; curr; curr = next) {
+               regspacing = 1;
+               regsize = 1;
+               regshift = 0;
+               irq = 0;
+               ipmb = 0; /* Choose the default if not specified */
+
+               next = strchr(curr, ':');
+               if (next) {
+                       *next = '\0';
+                       next++;
+               }
+
+               rv = parse_str(hotmod_ops, &ival, "operation", &curr);
+               if (rv)
+                       break;
+               op = ival;
+
+               rv = parse_str(hotmod_si, &ival, "interface type", &curr);
+               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(PFX "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(PFX "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;
+               } else {
+                       ipmi_si_remove_by_data(addr_space, si_type, addr);
+               }
+       }
+       rv = len;
+out:
+       kfree(str);
+       return rv;
+}
index 6c2e14af832160ae97cd40a91a80fe475be703d5..02e263b2152a50a89b762bc567aa1a7e4263e2ef 100644 (file)
@@ -1310,13 +1310,6 @@ static unsigned int num_slave_addrs;
 
 static const char * const addr_space_to_str[] = { "i/o", "mem" };
 
-static int hotmod_handler(const char *val, struct kernel_param *kp);
-
-module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200);
-MODULE_PARM_DESC(hotmod, "Add and remove interfaces.  See"
-                " Documentation/IPMI.txt in the kernel sources for the"
-                " gory details.");
-
 #ifdef CONFIG_ACPI
 module_param_named(tryacpi, si_tryacpi, bool, 0);
 MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the"
@@ -1689,86 +1682,6 @@ static int mem_setup(struct si_sm_io *io)
        return 0;
 }
 
-/*
- * 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, int *val, char *name,
-                    char **curr)
-{
-       char *s;
-       int  i;
-
-       s = strchr(*curr, ',');
-       if (!s) {
-               pr_warn(PFX "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(PFX "Invalid hotmod %s '%s'\n", name, *curr);
-       return -EINVAL;
-}
-
-static int check_hotmod_int_op(const char *curr, const char *option,
-                              const char *name, int *val)
-{
-       char *n;
-
-       if (strcmp(curr, name) == 0) {
-               if (!option) {
-                       pr_warn(PFX "No option given for '%s'\n", curr);
-                       return -EINVAL;
-               }
-               *val = simple_strtoul(option, &n, 0);
-               if ((*n != '\0') || (*option == '\0')) {
-                       pr_warn(PFX "Bad option given for '%s'\n", curr);
-                       return -EINVAL;
-               }
-               return 1;
-       }
-       return 0;
-}
-
 static struct smi_info *smi_info_alloc(void)
 {
        struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -1778,162 +1691,6 @@ static struct smi_info *smi_info_alloc(void)
        return info;
 }
 
-static int hotmod_handler(const char *val, struct kernel_param *kp)
-{
-       char *str = kstrdup(val, GFP_KERNEL);
-       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;
-       int ival;
-       int len;
-
-       if (!str)
-               return -ENOMEM;
-
-       /* Kill any trailing spaces, as we can get a "\n" from echo. */
-       len = strlen(str);
-       ival = len - 1;
-       while ((ival >= 0) && isspace(str[ival])) {
-               str[ival] = '\0';
-               ival--;
-       }
-
-       for (curr = str; curr; curr = next) {
-               regspacing = 1;
-               regsize = 1;
-               regshift = 0;
-               irq = 0;
-               ipmb = 0; /* Choose the default if not specified */
-
-               next = strchr(curr, ':');
-               if (next) {
-                       *next = '\0';
-                       next++;
-               }
-
-               rv = parse_str(hotmod_ops, &ival, "operation", &curr);
-               if (rv)
-                       break;
-               op = ival;
-
-               rv = parse_str(hotmod_si, &ival, "interface type", &curr);
-               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(PFX "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(PFX "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;
-               } else {
-                       /* remove */
-                       struct smi_info *e, *tmp_e;
-
-                       mutex_lock(&smi_infos_lock);
-                       list_for_each_entry_safe(e, tmp_e, &smi_infos, link) {
-                               if (e->io.addr_type != addr_space)
-                                       continue;
-                               if (e->io.si_type != si_type)
-                                       continue;
-                               if (e->io.addr_data == addr)
-                                       cleanup_one_si(e);
-                       }
-                       mutex_unlock(&smi_infos_lock);
-               }
-       }
-       rv = len;
-out:
-       kfree(str);
-       return rv;
-}
-
 static int hardcode_find_bmc(void)
 {
        int ret = -ENODEV;
@@ -3779,6 +3536,24 @@ int ipmi_si_remove_by_dev(struct device *dev)
        return rv;
 }
 
+void ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
+                           unsigned long addr)
+{
+       /* remove */
+       struct smi_info *e, *tmp_e;
+
+       mutex_lock(&smi_infos_lock);
+       list_for_each_entry_safe(e, tmp_e, &smi_infos, link) {
+               if (e->io.addr_type != addr_space)
+                       continue;
+               if (e->io.si_type != si_type)
+                       continue;
+               if (e->io.addr_data == addr)
+                       cleanup_one_si(e);
+       }
+       mutex_unlock(&smi_infos_lock);
+}
+
 static void cleanup_ipmi_si(void)
 {
        struct smi_info *e, *tmp_e;