hc
2023-12-09 b22da3d8526a935aa31e086e63f60ff3246cb61c
kernel/drivers/char/ipmi/ipmi_si_hotmod.c
....@@ -5,17 +5,20 @@
55 * Handling for dynamically adding/removing IPMI devices through
66 * a module parameter (and thus sysfs).
77 */
8
+
9
+#define pr_fmt(fmt) "ipmi_hotmod: " fmt
10
+
811 #include <linux/moduleparam.h>
912 #include <linux/ipmi.h>
13
+#include <linux/atomic.h>
1014 #include "ipmi_si.h"
11
-
12
-#define PFX "ipmi_hotmod: "
15
+#include "ipmi_plat_data.h"
1316
1417 static int hotmod_handler(const char *val, const struct kernel_param *kp);
1518
1619 module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200);
1720 MODULE_PARM_DESC(hotmod, "Add and remove interfaces. See"
18
- " Documentation/IPMI.txt in the kernel sources for the"
21
+ " Documentation/driver-api/ipmi.rst in the kernel sources for the"
1922 " gory details.");
2023
2124 /*
....@@ -53,15 +56,15 @@
5356 { NULL }
5457 };
5558
56
-static int parse_str(const struct hotmod_vals *v, int *val, char *name,
57
- char **curr)
59
+static int parse_str(const struct hotmod_vals *v, unsigned int *val, char *name,
60
+ const char **curr)
5861 {
5962 char *s;
6063 int i;
6164
6265 s = strchr(*curr, ',');
6366 if (!s) {
64
- pr_warn(PFX "No hotmod %s given.\n", name);
67
+ pr_warn("No hotmod %s given\n", name);
6568 return -EINVAL;
6669 }
6770 *s = '\0';
....@@ -74,23 +77,23 @@
7477 }
7578 }
7679
77
- pr_warn(PFX "Invalid hotmod %s '%s'\n", name, *curr);
80
+ pr_warn("Invalid hotmod %s '%s'\n", name, *curr);
7881 return -EINVAL;
7982 }
8083
8184 static int check_hotmod_int_op(const char *curr, const char *option,
82
- const char *name, int *val)
85
+ const char *name, unsigned int *val)
8386 {
8487 char *n;
8588
8689 if (strcmp(curr, name) == 0) {
8790 if (!option) {
88
- pr_warn(PFX "No option given for '%s'\n", curr);
91
+ pr_warn("No option given for '%s'\n", curr);
8992 return -EINVAL;
9093 }
9194 *val = simple_strtoul(option, &n, 0);
9295 if ((*n != '\0') || (*option == '\0')) {
93
- pr_warn(PFX "Bad option given for '%s'\n", curr);
96
+ pr_warn("Bad option given for '%s'\n", curr);
9497 return -EINVAL;
9598 }
9699 return 1;
....@@ -98,22 +101,95 @@
98101 return 0;
99102 }
100103
104
+static int parse_hotmod_str(const char *curr, enum hotmod_op *op,
105
+ struct ipmi_plat_data *h)
106
+{
107
+ char *s, *o;
108
+ int rv;
109
+ unsigned int ival;
110
+
111
+ h->iftype = IPMI_PLAT_IF_SI;
112
+ rv = parse_str(hotmod_ops, &ival, "operation", &curr);
113
+ if (rv)
114
+ return rv;
115
+ *op = ival;
116
+
117
+ rv = parse_str(hotmod_si, &ival, "interface type", &curr);
118
+ if (rv)
119
+ return rv;
120
+ h->type = ival;
121
+
122
+ rv = parse_str(hotmod_as, &ival, "address space", &curr);
123
+ if (rv)
124
+ return rv;
125
+ h->space = ival;
126
+
127
+ s = strchr(curr, ',');
128
+ if (s) {
129
+ *s = '\0';
130
+ s++;
131
+ }
132
+ rv = kstrtoul(curr, 0, &h->addr);
133
+ if (rv) {
134
+ pr_warn("Invalid hotmod address '%s': %d\n", curr, rv);
135
+ return rv;
136
+ }
137
+
138
+ while (s) {
139
+ curr = s;
140
+ s = strchr(curr, ',');
141
+ if (s) {
142
+ *s = '\0';
143
+ s++;
144
+ }
145
+ o = strchr(curr, '=');
146
+ if (o) {
147
+ *o = '\0';
148
+ o++;
149
+ }
150
+ rv = check_hotmod_int_op(curr, o, "rsp", &h->regspacing);
151
+ if (rv < 0)
152
+ return rv;
153
+ else if (rv)
154
+ continue;
155
+ rv = check_hotmod_int_op(curr, o, "rsi", &h->regsize);
156
+ if (rv < 0)
157
+ return rv;
158
+ else if (rv)
159
+ continue;
160
+ rv = check_hotmod_int_op(curr, o, "rsh", &h->regshift);
161
+ if (rv < 0)
162
+ return rv;
163
+ else if (rv)
164
+ continue;
165
+ rv = check_hotmod_int_op(curr, o, "irq", &h->irq);
166
+ if (rv < 0)
167
+ return rv;
168
+ else if (rv)
169
+ continue;
170
+ rv = check_hotmod_int_op(curr, o, "ipmb", &h->slave_addr);
171
+ if (rv < 0)
172
+ return rv;
173
+ else if (rv)
174
+ continue;
175
+
176
+ pr_warn("Invalid hotmod option '%s'\n", curr);
177
+ return -EINVAL;
178
+ }
179
+
180
+ h->addr_source = SI_HOTMOD;
181
+ return 0;
182
+}
183
+
184
+static atomic_t hotmod_nr;
185
+
101186 static int hotmod_handler(const char *val, const struct kernel_param *kp)
102187 {
103
- char *str = kstrdup(val, GFP_KERNEL);
188
+ char *str = kstrdup(val, GFP_KERNEL), *curr, *next;
104189 int rv;
105
- char *next, *curr, *s, *n, *o;
106
- enum hotmod_op op;
107
- enum si_type si_type;
108
- int addr_space;
109
- unsigned long addr;
110
- int regspacing;
111
- int regsize;
112
- int regshift;
113
- int irq;
114
- int ipmb;
190
+ struct ipmi_plat_data h;
191
+ unsigned int len;
115192 int ival;
116
- int len;
117193
118194 if (!str)
119195 return -ENOMEM;
....@@ -127,11 +203,7 @@
127203 }
128204
129205 for (curr = str; curr; curr = next) {
130
- regspacing = 1;
131
- regsize = 1;
132
- regshift = 0;
133
- irq = 0;
134
- ipmb = 0; /* Choose the default if not specified */
206
+ enum hotmod_op op;
135207
136208 next = strchr(curr, ':');
137209 if (next) {
....@@ -139,101 +211,28 @@
139211 next++;
140212 }
141213
142
- rv = parse_str(hotmod_ops, &ival, "operation", &curr);
214
+ memset(&h, 0, sizeof(h));
215
+ rv = parse_hotmod_str(curr, &op, &h);
143216 if (rv)
144
- break;
145
- op = ival;
146
-
147
- rv = parse_str(hotmod_si, &ival, "interface type", &curr);
148
- if (rv)
149
- break;
150
- si_type = ival;
151
-
152
- rv = parse_str(hotmod_as, &addr_space, "address space", &curr);
153
- if (rv)
154
- break;
155
-
156
- s = strchr(curr, ',');
157
- if (s) {
158
- *s = '\0';
159
- s++;
160
- }
161
- addr = simple_strtoul(curr, &n, 0);
162
- if ((*n != '\0') || (*curr == '\0')) {
163
- pr_warn(PFX "Invalid hotmod address '%s'\n", curr);
164
- break;
165
- }
166
-
167
- while (s) {
168
- curr = s;
169
- s = strchr(curr, ',');
170
- if (s) {
171
- *s = '\0';
172
- s++;
173
- }
174
- o = strchr(curr, '=');
175
- if (o) {
176
- *o = '\0';
177
- o++;
178
- }
179
- rv = check_hotmod_int_op(curr, o, "rsp", &regspacing);
180
- if (rv < 0)
181
- goto out;
182
- else if (rv)
183
- continue;
184
- rv = check_hotmod_int_op(curr, o, "rsi", &regsize);
185
- if (rv < 0)
186
- goto out;
187
- else if (rv)
188
- continue;
189
- rv = check_hotmod_int_op(curr, o, "rsh", &regshift);
190
- if (rv < 0)
191
- goto out;
192
- else if (rv)
193
- continue;
194
- rv = check_hotmod_int_op(curr, o, "irq", &irq);
195
- if (rv < 0)
196
- goto out;
197
- else if (rv)
198
- continue;
199
- rv = check_hotmod_int_op(curr, o, "ipmb", &ipmb);
200
- if (rv < 0)
201
- goto out;
202
- else if (rv)
203
- continue;
204
-
205
- rv = -EINVAL;
206
- pr_warn(PFX "Invalid hotmod option '%s'\n", curr);
207217 goto out;
208
- }
209218
210219 if (op == HM_ADD) {
211
- struct si_sm_io io;
212
-
213
- memset(&io, 0, sizeof(io));
214
- io.addr_source = SI_HOTMOD;
215
- io.si_type = si_type;
216
- io.addr_data = addr;
217
- io.addr_type = addr_space;
218
-
219
- io.addr = NULL;
220
- io.regspacing = regspacing;
221
- if (!io.regspacing)
222
- io.regspacing = DEFAULT_REGSPACING;
223
- io.regsize = regsize;
224
- if (!io.regsize)
225
- io.regsize = DEFAULT_REGSIZE;
226
- io.regshift = regshift;
227
- io.irq = irq;
228
- if (io.irq)
229
- io.irq_setup = ipmi_std_irq_setup;
230
- io.slave_addr = ipmb;
231
-
232
- rv = ipmi_si_add_smi(&io);
233
- if (rv)
234
- goto out;
220
+ ipmi_platform_add("hotmod-ipmi-si",
221
+ atomic_inc_return(&hotmod_nr),
222
+ &h);
235223 } else {
236
- ipmi_si_remove_by_data(addr_space, si_type, addr);
224
+ struct device *dev;
225
+
226
+ dev = ipmi_si_remove_by_data(h.space, h.type, h.addr);
227
+ if (dev && dev_is_platform(dev)) {
228
+ struct platform_device *pdev;
229
+
230
+ pdev = to_platform_device(dev);
231
+ if (strcmp(pdev->name, "hotmod-ipmi-si") == 0)
232
+ platform_device_unregister(pdev);
233
+ }
234
+ if (dev)
235
+ put_device(dev);
237236 }
238237 }
239238 rv = len;
....@@ -241,3 +240,8 @@
241240 kfree(str);
242241 return rv;
243242 }
243
+
244
+void ipmi_si_hotmod_exit(void)
245
+{
246
+ ipmi_remove_platform_device_by_name("hotmod-ipmi-si");
247
+}