]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - queue-4.19/ipmi_si-fix-crash-when-using-hard-coded-device.patch
5.0-stable patches
[thirdparty/kernel/stable-queue.git] / queue-4.19 / ipmi_si-fix-crash-when-using-hard-coded-device.patch
CommitLineData
1e9c9310
SL
1From e60de9df336c3e715143b3d1c04885b0ec69e9c1 Mon Sep 17 00:00:00 2001
2From: Corey Minyard <cminyard@mvista.com>
3Date: Tue, 26 Mar 2019 11:10:04 -0500
4Subject: ipmi_si: Fix crash when using hard-coded device
5
6Backport from 41b766d661bf94a364960862cfc248a78313dbd3
7
8When excuting a command like:
9 modprobe ipmi_si ports=0xffc0e3 type=bt
10The system would get an oops.
11
12The trouble here is that ipmi_si_hardcode_find_bmc() is called before
13ipmi_si_platform_init(), but initialization of the hard-coded device
14creates an IPMI platform device, which won't be initialized yet.
15
16The real trouble is that hard-coded devices aren't created with
17any device, and the fixup is done later. So do it right, create the
18hard-coded devices as normal platform devices.
19
20This required adding some new resource types to the IPMI platform
21code for passing information required by the hard-coded device
22and adding some code to remove the hard-coded platform devices
23on module removal.
24
25To enforce the "hard-coded devices passed by the user take priority
26over firmware devices" rule, some special code was added to check
27and see if a hard-coded device already exists.
28
29The backport required some minor fixups and adding the device
30id table that had been added in another change and was used
31in this one.
32
33Reported-by: Yang Yingliang <yangyingliang@huawei.com>
34Cc: stable@vger.kernel.org # v4.15+
35Signed-off-by: Corey Minyard <cminyard@mvista.com>
36Tested-by: Yang Yingliang <yangyingliang@huawei.com>
37Signed-off-by: Sasha Levin <sashal@kernel.org>
af18a487 38Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1e9c9310 39---
af18a487
GKH
40 drivers/char/ipmi/ipmi_si.h | 4
41 drivers/char/ipmi/ipmi_si_hardcode.c | 232 +++++++++++++++++++++++++----------
42 drivers/char/ipmi/ipmi_si_intf.c | 22 ++-
43 drivers/char/ipmi/ipmi_si_platform.c | 30 +++-
44 4 files changed, 216 insertions(+), 72 deletions(-)
1e9c9310 45
1e9c9310
SL
46--- a/drivers/char/ipmi/ipmi_si.h
47+++ b/drivers/char/ipmi/ipmi_si.h
af18a487 48@@ -25,7 +25,9 @@ void ipmi_irq_finish_setup(struct si_sm_
1e9c9310
SL
49 int ipmi_si_remove_by_dev(struct device *dev);
50 void ipmi_si_remove_by_data(int addr_space, enum si_type si_type,
51 unsigned long addr);
52-int ipmi_si_hardcode_find_bmc(void);
53+void ipmi_hardcode_init(void);
54+void ipmi_si_hardcode_exit(void);
55+int ipmi_si_hardcode_match(int addr_type, unsigned long addr);
56 void ipmi_si_platform_init(void);
57 void ipmi_si_platform_shutdown(void);
58
1e9c9310
SL
59--- a/drivers/char/ipmi/ipmi_si_hardcode.c
60+++ b/drivers/char/ipmi/ipmi_si_hardcode.c
61@@ -1,6 +1,7 @@
62 // SPDX-License-Identifier: GPL-2.0+
63
64 #include <linux/moduleparam.h>
65+#include <linux/platform_device.h>
66 #include "ipmi_si.h"
67
68 #define PFX "ipmi_hardcode: "
69@@ -11,23 +12,22 @@
70
71 #define SI_MAX_PARMS 4
72
73-static char *si_type[SI_MAX_PARMS];
74 #define MAX_SI_TYPE_STR 30
75-static char si_type_str[MAX_SI_TYPE_STR];
76+static char si_type_str[MAX_SI_TYPE_STR] __initdata;
77 static unsigned long addrs[SI_MAX_PARMS];
78 static unsigned int num_addrs;
79 static unsigned int ports[SI_MAX_PARMS];
80 static unsigned int num_ports;
81-static int irqs[SI_MAX_PARMS];
82-static unsigned int num_irqs;
83-static int regspacings[SI_MAX_PARMS];
84-static unsigned int num_regspacings;
85-static int regsizes[SI_MAX_PARMS];
86-static unsigned int num_regsizes;
87-static int regshifts[SI_MAX_PARMS];
88-static unsigned int num_regshifts;
89-static int slave_addrs[SI_MAX_PARMS]; /* Leaving 0 chooses the default value */
90-static unsigned int num_slave_addrs;
91+static int irqs[SI_MAX_PARMS] __initdata;
92+static unsigned int num_irqs __initdata;
93+static int regspacings[SI_MAX_PARMS] __initdata;
94+static unsigned int num_regspacings __initdata;
95+static int regsizes[SI_MAX_PARMS] __initdata;
96+static unsigned int num_regsizes __initdata;
97+static int regshifts[SI_MAX_PARMS] __initdata;
98+static unsigned int num_regshifts __initdata;
99+static int slave_addrs[SI_MAX_PARMS] __initdata;
100+static unsigned int num_slave_addrs __initdata;
101
102 module_param_string(type, si_type_str, MAX_SI_TYPE_STR, 0);
103 MODULE_PARM_DESC(type, "Defines the type of each interface, each"
af18a487 104@@ -72,12 +72,133 @@ MODULE_PARM_DESC(slave_addrs, "Set the d
1e9c9310
SL
105 " overridden by this parm. This is an array indexed"
106 " by interface number.");
107
108-int ipmi_si_hardcode_find_bmc(void)
109+static struct platform_device *ipmi_hc_pdevs[SI_MAX_PARMS];
110+
111+static void __init ipmi_hardcode_init_one(const char *si_type_str,
112+ unsigned int i,
113+ unsigned long addr,
114+ unsigned int flags)
af18a487 115+{
1e9c9310
SL
116+ struct platform_device *pdev;
117+ unsigned int num_r = 1, size;
118+ struct resource r[4];
119+ struct property_entry p[6];
120+ enum si_type si_type;
121+ unsigned int regspacing, regsize;
122+ int rv;
123+
124+ memset(p, 0, sizeof(p));
125+ memset(r, 0, sizeof(r));
126+
127+ if (!si_type_str || !*si_type_str || strcmp(si_type_str, "kcs") == 0) {
128+ size = 2;
129+ si_type = SI_KCS;
130+ } else if (strcmp(si_type_str, "smic") == 0) {
131+ size = 2;
132+ si_type = SI_SMIC;
133+ } else if (strcmp(si_type_str, "bt") == 0) {
134+ size = 3;
135+ si_type = SI_BT;
136+ } else if (strcmp(si_type_str, "invalid") == 0) {
137+ /*
138+ * Allow a firmware-specified interface to be
139+ * disabled.
140+ */
141+ size = 1;
142+ si_type = SI_TYPE_INVALID;
143+ } else {
144+ pr_warn("Interface type specified for interface %d, was invalid: %s\n",
145+ i, si_type_str);
146+ return;
147+ }
148+
149+ regsize = regsizes[i];
150+ if (regsize == 0)
151+ regsize = DEFAULT_REGSIZE;
152+
153+ p[0] = PROPERTY_ENTRY_U8("ipmi-type", si_type);
154+ p[1] = PROPERTY_ENTRY_U8("slave-addr", slave_addrs[i]);
155+ p[2] = PROPERTY_ENTRY_U8("addr-source", SI_HARDCODED);
156+ p[3] = PROPERTY_ENTRY_U8("reg-shift", regshifts[i]);
157+ p[4] = PROPERTY_ENTRY_U8("reg-size", regsize);
158+ /* Last entry must be left NULL to terminate it. */
159+
160+ /*
161+ * Register spacing is derived from the resources in
162+ * the IPMI platform code.
163+ */
164+ regspacing = regspacings[i];
165+ if (regspacing == 0)
166+ regspacing = regsize;
167+
168+ r[0].start = addr;
169+ r[0].end = r[0].start + regsize - 1;
170+ r[0].name = "IPMI Address 1";
171+ r[0].flags = flags;
172+
173+ if (size > 1) {
174+ r[1].start = r[0].start + regspacing;
175+ r[1].end = r[1].start + regsize - 1;
176+ r[1].name = "IPMI Address 2";
177+ r[1].flags = flags;
178+ num_r++;
179+ }
180+
181+ if (size > 2) {
182+ r[2].start = r[1].start + regspacing;
183+ r[2].end = r[2].start + regsize - 1;
184+ r[2].name = "IPMI Address 3";
185+ r[2].flags = flags;
186+ num_r++;
187+ }
188+
189+ if (irqs[i]) {
190+ r[num_r].start = irqs[i];
191+ r[num_r].end = irqs[i];
192+ r[num_r].name = "IPMI IRQ";
193+ r[num_r].flags = IORESOURCE_IRQ;
194+ num_r++;
195+ }
196+
197+ pdev = platform_device_alloc("hardcode-ipmi-si", i);
198+ if (!pdev) {
199+ pr_err("Error allocating IPMI platform device %d\n", i);
200+ return;
201+ }
202+
203+ rv = platform_device_add_resources(pdev, r, num_r);
204+ if (rv) {
205+ dev_err(&pdev->dev,
206+ "Unable to add hard-code resources: %d\n", rv);
207+ goto err;
208+ }
209+
210+ rv = platform_device_add_properties(pdev, p);
211+ if (rv) {
212+ dev_err(&pdev->dev,
213+ "Unable to add hard-code properties: %d\n", rv);
214+ goto err;
215+ }
216+
217+ rv = platform_device_add(pdev);
218+ if (rv) {
219+ dev_err(&pdev->dev,
220+ "Unable to add hard-code device: %d\n", rv);
221+ goto err;
222+ }
223+
224+ ipmi_hc_pdevs[i] = pdev;
225+ return;
226+
227+err:
228+ platform_device_put(pdev);
229+}
230+
231+void __init ipmi_hardcode_init(void)
af18a487
GKH
232 {
233- int ret = -ENODEV;
234- int i;
235- struct si_sm_io io;
1e9c9310
SL
236+ unsigned int i;
237 char *str;
238+ char *si_type[SI_MAX_PARMS];
239
240 /* Parse out the si_type string into its components. */
241 str = si_type_str;
242@@ -94,54 +215,45 @@ int ipmi_si_hardcode_find_bmc(void)
243 }
244 }
245
246- memset(&io, 0, sizeof(io));
247 for (i = 0; i < SI_MAX_PARMS; i++) {
248- if (!ports[i] && !addrs[i])
249- continue;
250-
251- io.addr_source = SI_HARDCODED;
252- pr_info(PFX "probing via hardcoded address\n");
af18a487
GKH
253+ if (i < num_ports && ports[i])
254+ ipmi_hardcode_init_one(si_type[i], i, ports[i],
255+ IORESOURCE_IO);
256+ if (i < num_addrs && addrs[i])
257+ ipmi_hardcode_init_one(si_type[i], i, addrs[i],
258+ IORESOURCE_MEM);
259+ }
260+}
261
1e9c9310
SL
262- if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) {
263- io.si_type = SI_KCS;
264- } else if (strcmp(si_type[i], "smic") == 0) {
265- io.si_type = SI_SMIC;
266- } else if (strcmp(si_type[i], "bt") == 0) {
267- io.si_type = SI_BT;
268- } else {
269- pr_warn(PFX "Interface type specified for interface %d, was invalid: %s\n",
270- i, si_type[i]);
271- continue;
272- }
af18a487
GKH
273+void ipmi_si_hardcode_exit(void)
274+{
275+ unsigned int i;
1e9c9310
SL
276
277- if (ports[i]) {
278- /* An I/O port */
279- io.addr_data = ports[i];
280- io.addr_type = IPMI_IO_ADDR_SPACE;
281- } else if (addrs[i]) {
282- /* A memory port */
283- io.addr_data = addrs[i];
284- io.addr_type = IPMI_MEM_ADDR_SPACE;
285- } else {
286- pr_warn(PFX "Interface type specified for interface %d, but port and address were not set or set to zero.\n",
287- i);
288- continue;
289- }
af18a487
GKH
290+ for (i = 0; i < SI_MAX_PARMS; i++) {
291+ if (ipmi_hc_pdevs[i])
292+ platform_device_unregister(ipmi_hc_pdevs[i]);
293+ }
294+}
1e9c9310
SL
295
296- io.addr = NULL;
297- io.regspacing = regspacings[i];
298- if (!io.regspacing)
299- io.regspacing = DEFAULT_REGSPACING;
300- io.regsize = regsizes[i];
301- if (!io.regsize)
302- io.regsize = DEFAULT_REGSIZE;
303- io.regshift = regshifts[i];
304- io.irq = irqs[i];
305- if (io.irq)
306- io.irq_setup = ipmi_std_irq_setup;
307- io.slave_addr = slave_addrs[i];
1e9c9310
SL
308+/*
309+ * Returns true of the given address exists as a hardcoded address,
310+ * false if not.
311+ */
312+int ipmi_si_hardcode_match(int addr_type, unsigned long addr)
313+{
314+ unsigned int i;
af18a487
GKH
315
316- ret = ipmi_si_add_smi(&io);
1e9c9310
SL
317+ if (addr_type == IPMI_IO_ADDR_SPACE) {
318+ for (i = 0; i < num_ports; i++) {
319+ if (ports[i] == addr)
320+ return 1;
321+ }
322+ } else {
323+ for (i = 0; i < num_addrs; i++) {
324+ if (addrs[i] == addr)
325+ return 1;
326+ }
af18a487
GKH
327 }
328- return ret;
1e9c9310
SL
329+
330+ return 0;
331 }
1e9c9310
SL
332--- a/drivers/char/ipmi/ipmi_si_intf.c
333+++ b/drivers/char/ipmi/ipmi_si_intf.c
334@@ -1862,6 +1862,18 @@ int ipmi_si_add_smi(struct si_sm_io *io)
335 int rv = 0;
336 struct smi_info *new_smi, *dup;
337
338+ /*
339+ * If the user gave us a hard-coded device at the same
340+ * address, they presumably want us to use it and not what is
341+ * in the firmware.
342+ */
343+ if (io->addr_source != SI_HARDCODED &&
344+ ipmi_si_hardcode_match(io->addr_type, io->addr_data)) {
345+ dev_info(io->dev,
346+ "Hard-coded device at this address already exists");
347+ return -ENODEV;
348+ }
349+
350 if (!io->io_setup) {
351 if (io->addr_type == IPMI_IO_ADDR_SPACE) {
352 io->io_setup = ipmi_si_port_setup;
af18a487 353@@ -2094,7 +2106,7 @@ static int try_smi_init(struct smi_info
1e9c9310
SL
354 return rv;
355 }
356
357-static int init_ipmi_si(void)
358+static int __init init_ipmi_si(void)
359 {
360 struct smi_info *e;
361 enum ipmi_addr_src type = SI_INVALID;
362@@ -2102,12 +2114,9 @@ static int init_ipmi_si(void)
363 if (initialized)
364 return 0;
365
366+ ipmi_hardcode_init();
367 pr_info("IPMI System Interface driver.\n");
368
369- /* If the user gave us a device, they presumably want us to use it */
370- if (!ipmi_si_hardcode_find_bmc())
371- goto do_scan;
372-
373 ipmi_si_platform_init();
374
375 ipmi_si_pci_init();
376@@ -2118,7 +2127,6 @@ static int init_ipmi_si(void)
377 with multiple BMCs we assume that there will be several instances
378 of a given type so if we succeed in registering a type then also
379 try to register everything else of the same type */
380-do_scan:
381 mutex_lock(&smi_infos_lock);
382 list_for_each_entry(e, &smi_infos, link) {
383 /* Try to register a device if it has an IRQ and we either
384@@ -2304,6 +2312,8 @@ static void cleanup_ipmi_si(void)
385 list_for_each_entry_safe(e, tmp_e, &smi_infos, link)
386 cleanup_one_si(e);
387 mutex_unlock(&smi_infos_lock);
388+
389+ ipmi_si_hardcode_exit();
390 }
391 module_exit(cleanup_ipmi_si);
392
1e9c9310
SL
393--- a/drivers/char/ipmi/ipmi_si_platform.c
394+++ b/drivers/char/ipmi/ipmi_si_platform.c
af18a487 395@@ -126,8 +126,6 @@ ipmi_get_info_from_resources(struct plat
1e9c9310
SL
396 if (res_second->start > io->addr_data)
397 io->regspacing = res_second->start - io->addr_data;
398 }
399- io->regsize = DEFAULT_REGSIZE;
400- io->regshift = 0;
401
402 return res;
403 }
af18a487 404@@ -135,7 +133,7 @@ ipmi_get_info_from_resources(struct plat
1e9c9310
SL
405 static int platform_ipmi_probe(struct platform_device *pdev)
406 {
407 struct si_sm_io io;
408- u8 type, slave_addr, addr_source;
409+ u8 type, slave_addr, addr_source, regsize, regshift;
410 int rv;
411
412 rv = device_property_read_u8(&pdev->dev, "addr-source", &addr_source);
af18a487 413@@ -147,7 +145,7 @@ static int platform_ipmi_probe(struct pl
1e9c9310
SL
414 if (addr_source == SI_SMBIOS) {
415 if (!si_trydmi)
416 return -ENODEV;
417- } else {
418+ } else if (addr_source != SI_HARDCODED) {
419 if (!si_tryplatform)
420 return -ENODEV;
421 }
af18a487 422@@ -167,11 +165,23 @@ static int platform_ipmi_probe(struct pl
1e9c9310
SL
423 case SI_BT:
424 io.si_type = type;
425 break;
426+ case SI_TYPE_INVALID: /* User disabled this in hardcode. */
427+ return -ENODEV;
428 default:
429 dev_err(&pdev->dev, "ipmi-type property is invalid\n");
430 return -EINVAL;
431 }
432
433+ io.regsize = DEFAULT_REGSIZE;
434+ rv = device_property_read_u8(&pdev->dev, "reg-size", &regsize);
435+ if (!rv)
436+ io.regsize = regsize;
437+
438+ io.regshift = 0;
439+ rv = device_property_read_u8(&pdev->dev, "reg-shift", &regshift);
440+ if (!rv)
441+ io.regshift = regshift;
442+
443 if (!ipmi_get_info_from_resources(pdev, &io))
444 return -EINVAL;
445
af18a487 446@@ -191,7 +201,8 @@ static int platform_ipmi_probe(struct pl
1e9c9310
SL
447
448 io.dev = &pdev->dev;
449
450- pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n",
451+ pr_info("ipmi_si: %s: %s %#lx regsize %d spacing %d irq %d\n",
452+ ipmi_addr_src_to_str(addr_source),
453 (io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem",
454 io.addr_data, io.regsize, io.regspacing, io.irq);
455
af18a487 456@@ -356,6 +367,9 @@ static int acpi_ipmi_probe(struct platfo
1e9c9310
SL
457 goto err_free;
458 }
459
460+ io.regsize = DEFAULT_REGSIZE;
461+ io.regshift = 0;
462+
463 res = ipmi_get_info_from_resources(pdev, &io);
464 if (!res) {
465 rv = -EINVAL;
af18a487 466@@ -417,6 +431,11 @@ static int ipmi_remove(struct platform_d
1e9c9310
SL
467 return ipmi_si_remove_by_dev(&pdev->dev);
468 }
469
470+static const struct platform_device_id si_plat_ids[] = {
471+ { "hardcode-ipmi-si", 0 },
472+ { }
473+};
474+
475 struct platform_driver ipmi_platform_driver = {
476 .driver = {
477 .name = DEVICE_NAME,
af18a487 478@@ -425,6 +444,7 @@ struct platform_driver ipmi_platform_dri
1e9c9310
SL
479 },
480 .probe = ipmi_probe,
481 .remove = ipmi_remove,
482+ .id_table = si_plat_ids
483 };
484
485 void ipmi_si_platform_init(void)