diff options
author | Michael Ellerman <mpe@ellerman.id.au> | 2018-01-07 22:54:32 -0500 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2018-01-07 22:54:32 -0500 |
commit | e2d5915293ffdff977ddcfc12b817b08c53ffa7a (patch) | |
tree | 0fef452ae038633aace938a23f7bc40d815475a3 | |
parent | ecb101aed86156ec7cd71e5dca668e09146e6994 (diff) |
powerpc/pseries: Make RAS IRQ explicitly dependent on DLPAR WQ
The hotplug code uses its own workqueue to handle IRQ requests
(pseries_hp_wq), however that workqueue is initialized after
init_ras_IRQ(). That can lead to a kernel panic if any hotplug
interrupts fire after init_ras_IRQ() but before pseries_hp_wq is
initialised. eg:
UDP-Lite hash table entries: 2048 (order: 0, 65536 bytes)
NET: Registered protocol family 1
Unpacking initramfs...
(qemu) object_add memory-backend-ram,id=mem1,size=10G
(qemu) device_add pc-dimm,id=dimm1,memdev=mem1
Unable to handle kernel paging request for data at address 0xf94d03007c421378
Faulting instruction address: 0xc00000000012d744
Oops: Kernel access of bad area, sig: 11 [#1]
LE SMP NR_CPUS=2048 NUMA pSeries
Modules linked in:
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.15.0-rc2-ziviani+ #26
task: (ptrval) task.stack: (ptrval)
NIP: c00000000012d744 LR: c00000000012d744 CTR: 0000000000000000
REGS: (ptrval) TRAP: 0380 Not tainted (4.15.0-rc2-ziviani+)
MSR: 8000000000009033 <SF,EE,ME,IR,DR,RI,LE> CR: 28088042 XER: 20040000
CFAR: c00000000012d3c4 SOFTE: 0
...
NIP [c00000000012d744] __queue_work+0xd4/0x5c0
LR [c00000000012d744] __queue_work+0xd4/0x5c0
Call Trace:
[c0000000fffefb90] [c00000000012d744] __queue_work+0xd4/0x5c0 (unreliable)
[c0000000fffefc70] [c00000000012dce4] queue_work_on+0xb4/0xf0
This commit makes the RAS IRQ registration explicitly dependent on the
creation of the pseries_hp_wq.
Reported-by: Min Deng <mdeng@redhat.com>
Reported-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>
Tested-by: Jose Ricardo Ziviani <joserz@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
-rw-r--r-- | arch/powerpc/platforms/pseries/dlpar.c | 21 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pseries.h | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/ras.c | 3 |
3 files changed, 22 insertions, 4 deletions
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 6e35780c5962..a0b20c03f078 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c | |||
@@ -574,11 +574,26 @@ static ssize_t dlpar_show(struct class *class, struct class_attribute *attr, | |||
574 | 574 | ||
575 | static CLASS_ATTR_RW(dlpar); | 575 | static CLASS_ATTR_RW(dlpar); |
576 | 576 | ||
577 | static int __init pseries_dlpar_init(void) | 577 | int __init dlpar_workqueue_init(void) |
578 | { | 578 | { |
579 | if (pseries_hp_wq) | ||
580 | return 0; | ||
581 | |||
579 | pseries_hp_wq = alloc_workqueue("pseries hotplug workqueue", | 582 | pseries_hp_wq = alloc_workqueue("pseries hotplug workqueue", |
580 | WQ_UNBOUND, 1); | 583 | WQ_UNBOUND, 1); |
584 | |||
585 | return pseries_hp_wq ? 0 : -ENOMEM; | ||
586 | } | ||
587 | |||
588 | static int __init dlpar_sysfs_init(void) | ||
589 | { | ||
590 | int rc; | ||
591 | |||
592 | rc = dlpar_workqueue_init(); | ||
593 | if (rc) | ||
594 | return rc; | ||
595 | |||
581 | return sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr); | 596 | return sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr); |
582 | } | 597 | } |
583 | machine_device_initcall(pseries, pseries_dlpar_init); | 598 | machine_device_initcall(pseries, dlpar_sysfs_init); |
584 | 599 | ||
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 4470a3194311..1ae1d9f4dbe9 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h | |||
@@ -98,4 +98,6 @@ static inline unsigned long cmo_get_page_size(void) | |||
98 | return CMO_PageSize; | 98 | return CMO_PageSize; |
99 | } | 99 | } |
100 | 100 | ||
101 | int dlpar_workqueue_init(void); | ||
102 | |||
101 | #endif /* _PSERIES_PSERIES_H */ | 103 | #endif /* _PSERIES_PSERIES_H */ |
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 4923ffe230cf..81d8614e7379 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c | |||
@@ -69,7 +69,8 @@ static int __init init_ras_IRQ(void) | |||
69 | /* Hotplug Events */ | 69 | /* Hotplug Events */ |
70 | np = of_find_node_by_path("/event-sources/hot-plug-events"); | 70 | np = of_find_node_by_path("/event-sources/hot-plug-events"); |
71 | if (np != NULL) { | 71 | if (np != NULL) { |
72 | request_event_sources_irqs(np, ras_hotplug_interrupt, | 72 | if (dlpar_workqueue_init() == 0) |
73 | request_event_sources_irqs(np, ras_hotplug_interrupt, | ||
73 | "RAS_HOTPLUG"); | 74 | "RAS_HOTPLUG"); |
74 | of_node_put(np); | 75 | of_node_put(np); |
75 | } | 76 | } |