4 * Handling for dynamically adding/removing IPMI devices through
5 * a module parameter (and thus sysfs).
7 #include <linux/moduleparam.h>
8 #include <linux/ipmi.h>
11 #define PFX "ipmi_hotmod: "
13 static int hotmod_handler(const char *val
, const struct kernel_param
*kp
);
15 module_param_call(hotmod
, hotmod_handler
, NULL
, NULL
, 0200);
16 MODULE_PARM_DESC(hotmod
, "Add and remove interfaces. See"
17 " Documentation/IPMI.txt in the kernel sources for the"
21 * Parms come in as <op1>[:op2[:op3...]]. ops are:
22 * add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]]
30 enum hotmod_op
{ HM_ADD
, HM_REMOVE
};
36 static const struct hotmod_vals hotmod_ops
[] = {
38 { "remove", HM_REMOVE
},
42 static const struct hotmod_vals hotmod_si
[] = {
49 static const struct hotmod_vals hotmod_as
[] = {
50 { "mem", IPMI_MEM_ADDR_SPACE
},
51 { "i/o", IPMI_IO_ADDR_SPACE
},
55 static int parse_str(const struct hotmod_vals
*v
, int *val
, char *name
,
61 s
= strchr(*curr
, ',');
63 pr_warn(PFX
"No hotmod %s given.\n", name
);
68 for (i
= 0; v
[i
].name
; i
++) {
69 if (strcmp(*curr
, v
[i
].name
) == 0) {
76 pr_warn(PFX
"Invalid hotmod %s '%s'\n", name
, *curr
);
80 static int check_hotmod_int_op(const char *curr
, const char *option
,
81 const char *name
, int *val
)
85 if (strcmp(curr
, name
) == 0) {
87 pr_warn(PFX
"No option given for '%s'\n", curr
);
90 *val
= simple_strtoul(option
, &n
, 0);
91 if ((*n
!= '\0') || (*option
== '\0')) {
92 pr_warn(PFX
"Bad option given for '%s'\n", curr
);
100 static int hotmod_handler(const char *val
, const struct kernel_param
*kp
)
102 char *str
= kstrdup(val
, GFP_KERNEL
);
104 char *next
, *curr
, *s
, *n
, *o
;
106 enum si_type si_type
;
120 /* Kill any trailing spaces, as we can get a "\n" from echo. */
123 while ((ival
>= 0) && isspace(str
[ival
])) {
128 for (curr
= str
; curr
; curr
= next
) {
133 ipmb
= 0; /* Choose the default if not specified */
135 next
= strchr(curr
, ':');
141 rv
= parse_str(hotmod_ops
, &ival
, "operation", &curr
);
146 rv
= parse_str(hotmod_si
, &ival
, "interface type", &curr
);
151 rv
= parse_str(hotmod_as
, &addr_space
, "address space", &curr
);
155 s
= strchr(curr
, ',');
160 addr
= simple_strtoul(curr
, &n
, 0);
161 if ((*n
!= '\0') || (*curr
== '\0')) {
162 pr_warn(PFX
"Invalid hotmod address '%s'\n", curr
);
168 s
= strchr(curr
, ',');
173 o
= strchr(curr
, '=');
178 rv
= check_hotmod_int_op(curr
, o
, "rsp", ®spacing
);
183 rv
= check_hotmod_int_op(curr
, o
, "rsi", ®size
);
188 rv
= check_hotmod_int_op(curr
, o
, "rsh", ®shift
);
193 rv
= check_hotmod_int_op(curr
, o
, "irq", &irq
);
198 rv
= check_hotmod_int_op(curr
, o
, "ipmb", &ipmb
);
205 pr_warn(PFX
"Invalid hotmod option '%s'\n", curr
);
212 memset(&io
, 0, sizeof(io
));
213 io
.addr_source
= SI_HOTMOD
;
214 io
.si_type
= si_type
;
216 io
.addr_type
= addr_space
;
219 io
.regspacing
= regspacing
;
221 io
.regspacing
= DEFAULT_REGSPACING
;
222 io
.regsize
= regsize
;
224 io
.regsize
= DEFAULT_REGSIZE
;
225 io
.regshift
= regshift
;
228 io
.irq_setup
= ipmi_std_irq_setup
;
229 io
.slave_addr
= ipmb
;
231 rv
= ipmi_si_add_smi(&io
);
235 ipmi_si_remove_by_data(addr_space
, si_type
, addr
);