1 // SPDX-License-Identifier: GPL-2.0+
5 * Handling for dynamically adding/removing IPMI devices through
6 * a module parameter (and thus sysfs).
8 #include <linux/moduleparam.h>
9 #include <linux/ipmi.h>
12 #define PFX "ipmi_hotmod: "
14 static int hotmod_handler(const char *val
, const struct kernel_param
*kp
);
16 module_param_call(hotmod
, hotmod_handler
, NULL
, NULL
, 0200);
17 MODULE_PARM_DESC(hotmod
, "Add and remove interfaces. See"
18 " Documentation/IPMI.txt in the kernel sources for the"
22 * Parms come in as <op1>[:op2[:op3...]]. ops are:
23 * add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]]
31 enum hotmod_op
{ HM_ADD
, HM_REMOVE
};
37 static const struct hotmod_vals hotmod_ops
[] = {
39 { "remove", HM_REMOVE
},
43 static const struct hotmod_vals hotmod_si
[] = {
50 static const struct hotmod_vals hotmod_as
[] = {
51 { "mem", IPMI_MEM_ADDR_SPACE
},
52 { "i/o", IPMI_IO_ADDR_SPACE
},
56 static int parse_str(const struct hotmod_vals
*v
, int *val
, char *name
,
62 s
= strchr(*curr
, ',');
64 pr_warn(PFX
"No hotmod %s given.\n", name
);
69 for (i
= 0; v
[i
].name
; i
++) {
70 if (strcmp(*curr
, v
[i
].name
) == 0) {
77 pr_warn(PFX
"Invalid hotmod %s '%s'\n", name
, *curr
);
81 static int check_hotmod_int_op(const char *curr
, const char *option
,
82 const char *name
, int *val
)
86 if (strcmp(curr
, name
) == 0) {
88 pr_warn(PFX
"No option given for '%s'\n", curr
);
91 *val
= simple_strtoul(option
, &n
, 0);
92 if ((*n
!= '\0') || (*option
== '\0')) {
93 pr_warn(PFX
"Bad option given for '%s'\n", curr
);
101 static int hotmod_handler(const char *val
, const struct kernel_param
*kp
)
103 char *str
= kstrdup(val
, GFP_KERNEL
);
105 char *next
, *curr
, *s
, *n
, *o
;
107 enum si_type si_type
;
121 /* Kill any trailing spaces, as we can get a "\n" from echo. */
124 while ((ival
>= 0) && isspace(str
[ival
])) {
129 for (curr
= str
; curr
; curr
= next
) {
134 ipmb
= 0; /* Choose the default if not specified */
136 next
= strchr(curr
, ':');
142 rv
= parse_str(hotmod_ops
, &ival
, "operation", &curr
);
147 rv
= parse_str(hotmod_si
, &ival
, "interface type", &curr
);
152 rv
= parse_str(hotmod_as
, &addr_space
, "address space", &curr
);
156 s
= strchr(curr
, ',');
161 addr
= simple_strtoul(curr
, &n
, 0);
162 if ((*n
!= '\0') || (*curr
== '\0')) {
163 pr_warn(PFX
"Invalid hotmod address '%s'\n", curr
);
169 s
= strchr(curr
, ',');
174 o
= strchr(curr
, '=');
179 rv
= check_hotmod_int_op(curr
, o
, "rsp", ®spacing
);
184 rv
= check_hotmod_int_op(curr
, o
, "rsi", ®size
);
189 rv
= check_hotmod_int_op(curr
, o
, "rsh", ®shift
);
194 rv
= check_hotmod_int_op(curr
, o
, "irq", &irq
);
199 rv
= check_hotmod_int_op(curr
, o
, "ipmb", &ipmb
);
206 pr_warn(PFX
"Invalid hotmod option '%s'\n", curr
);
213 memset(&io
, 0, sizeof(io
));
214 io
.addr_source
= SI_HOTMOD
;
215 io
.si_type
= si_type
;
217 io
.addr_type
= addr_space
;
220 io
.regspacing
= regspacing
;
222 io
.regspacing
= DEFAULT_REGSPACING
;
223 io
.regsize
= regsize
;
225 io
.regsize
= DEFAULT_REGSIZE
;
226 io
.regshift
= regshift
;
229 io
.irq_setup
= ipmi_std_irq_setup
;
230 io
.slave_addr
= ipmb
;
232 rv
= ipmi_si_add_smi(&io
);
236 ipmi_si_remove_by_data(addr_space
, si_type
, addr
);