1 // SPDX-License-Identifier: GPL-2.0+
5 * Handling for dynamically adding/removing IPMI devices through
6 * a module parameter (and thus sysfs).
9 #define pr_fmt(fmt) "ipmi_hotmod: " fmt
11 #include <linux/moduleparam.h>
12 #include <linux/ipmi.h>
15 static int hotmod_handler(const char *val
, const struct kernel_param
*kp
);
17 module_param_call(hotmod
, hotmod_handler
, NULL
, NULL
, 0200);
18 MODULE_PARM_DESC(hotmod
, "Add and remove interfaces. See"
19 " Documentation/IPMI.txt in the kernel sources for the"
23 * Parms come in as <op1>[:op2[:op3...]]. ops are:
24 * add|remove,kcs|bt|smic,mem|i/o,<address>[,<opt1>[,<opt2>[,...]]]
32 enum hotmod_op
{ HM_ADD
, HM_REMOVE
};
38 static const struct hotmod_vals hotmod_ops
[] = {
40 { "remove", HM_REMOVE
},
44 static const struct hotmod_vals hotmod_si
[] = {
51 static const struct hotmod_vals hotmod_as
[] = {
52 { "mem", IPMI_MEM_ADDR_SPACE
},
53 { "i/o", IPMI_IO_ADDR_SPACE
},
57 static int parse_str(const struct hotmod_vals
*v
, int *val
, char *name
,
63 s
= strchr(*curr
, ',');
65 pr_warn("No hotmod %s given\n", name
);
70 for (i
= 0; v
[i
].name
; i
++) {
71 if (strcmp(*curr
, v
[i
].name
) == 0) {
78 pr_warn("Invalid hotmod %s '%s'\n", name
, *curr
);
82 static int check_hotmod_int_op(const char *curr
, const char *option
,
83 const char *name
, int *val
)
87 if (strcmp(curr
, name
) == 0) {
89 pr_warn("No option given for '%s'\n", curr
);
92 *val
= simple_strtoul(option
, &n
, 0);
93 if ((*n
!= '\0') || (*option
== '\0')) {
94 pr_warn("Bad option given for '%s'\n", curr
);
102 static int hotmod_handler(const char *val
, const struct kernel_param
*kp
)
104 char *str
= kstrdup(val
, GFP_KERNEL
);
106 char *next
, *curr
, *s
, *n
, *o
;
108 enum si_type si_type
;
122 /* Kill any trailing spaces, as we can get a "\n" from echo. */
125 while ((ival
>= 0) && isspace(str
[ival
])) {
130 for (curr
= str
; curr
; curr
= next
) {
135 ipmb
= 0; /* Choose the default if not specified */
137 next
= strchr(curr
, ':');
143 rv
= parse_str(hotmod_ops
, &ival
, "operation", &curr
);
148 rv
= parse_str(hotmod_si
, &ival
, "interface type", &curr
);
153 rv
= parse_str(hotmod_as
, &addr_space
, "address space", &curr
);
157 s
= strchr(curr
, ',');
162 addr
= simple_strtoul(curr
, &n
, 0);
163 if ((*n
!= '\0') || (*curr
== '\0')) {
164 pr_warn("Invalid hotmod address '%s'\n", curr
);
170 s
= strchr(curr
, ',');
175 o
= strchr(curr
, '=');
180 rv
= check_hotmod_int_op(curr
, o
, "rsp", ®spacing
);
185 rv
= check_hotmod_int_op(curr
, o
, "rsi", ®size
);
190 rv
= check_hotmod_int_op(curr
, o
, "rsh", ®shift
);
195 rv
= check_hotmod_int_op(curr
, o
, "irq", &irq
);
200 rv
= check_hotmod_int_op(curr
, o
, "ipmb", &ipmb
);
207 pr_warn("Invalid hotmod option '%s'\n", curr
);
214 memset(&io
, 0, sizeof(io
));
215 io
.addr_source
= SI_HOTMOD
;
216 io
.si_type
= si_type
;
218 io
.addr_type
= addr_space
;
221 io
.regspacing
= regspacing
;
223 io
.regspacing
= DEFAULT_REGSPACING
;
224 io
.regsize
= regsize
;
226 io
.regsize
= DEFAULT_REGSIZE
;
227 io
.regshift
= regshift
;
230 io
.irq_setup
= ipmi_std_irq_setup
;
231 io
.slave_addr
= ipmb
;
233 rv
= ipmi_si_add_smi(&io
);
237 ipmi_si_remove_by_data(addr_space
, si_type
, addr
);