powerpc/pseries: Fix kexec regression caused by CPPR tracking
Mark Nelson
markn at au1.ibm.com
Mon Feb 8 13:45:12 EST 2010
The code to track the CPPR values added by commit
49bd3647134ea47420067aea8d1401e722bf2aac ("powerpc/pseries: Track previous
CPPR values to correctly EOI interrupts") broke kexec on pseries because
the kexec code in xics.c calls xics_set_cpu_priority() before the IPI has
been EOI'ed. This wasn't a problem previously but it now triggers a BUG_ON
in xics_set_cpu_priority() because os_cppr->index isn't 0:
Oops: Exception in kernel mode, sig: 5 [#1]
SMP NR_CPUS=128 NUMA
kernel BUG at arch/powerpc/platforms/pseries/xics.c:791!
pSeries
Modules linked in: ehea dm_mirror dm_region_hash dm_log dm_zero dm_snapshot parport_pc parport dm_multipath autofs4
NIP: c0000000000461bc LR: c000000000046260 CTR: c00000000004bc08
REGS: c00000000fffb770 TRAP: 0700 Not tainted (2.6.33-rc6-autokern1)
MSR: 8000000000021032 <ME,CE,IR,DR> CR: 48000022 XER: 00000001
TASK = c000000000aef700[0] 'swapper' THREAD: c000000000bcc000 CPU: 0
GPR00: 0000000000000001 c00000000fffb9f0 c000000000bcc9e8 0000000000000000
GPR04: 0000000000000000 0000000000000000 00000000000000dc 0000000000000002
GPR08: c0000000040036e8 c000000004002e40 0000000000000898 0000000000000000
GPR12: 0000000000000002 c000000000bf8480 0000000003500000 c000000000792f28
GPR16: c0000000007915e0 0000000000000000 0000000000419000 0000000003da8990
GPR20: c0000000008a8990 0000000000000010 c000000000ae92c0 0000000000000010
GPR24: 0000000000000000 c000000000be2380 0000000000000000 0000000000200200
GPR28: 0000000000000001 0000000000000001 c000000000b249e8 0000000000000000
NIP [c0000000000461bc] .xics_set_cpu_priority+0x38/0xb8
LR [c000000000046260] .xics_teardown_cpu+0x24/0xa4
Call Trace:
[c00000000fffb9f0] [00000000ffffebf3] 0xffffebf3 (unreliable)
[c00000000fffba60] [c000000000046260] .xics_teardown_cpu+0x24/0xa4
[c00000000fffbae0] [c000000000046330] .xics_kexec_teardown_cpu+0x18/0xb4
[c00000000fffbb60] [c00000000004a150] .pseries_kexec_cpu_down_xics+0x20/0x38
[c00000000fffbbf0] [c00000000002e5b8] .kexec_smp_down+0x48/0x7c
[c00000000fffbc70] [c0000000000b2dd0] .generic_smp_call_function_interrupt+0xf4/0x1b4
[c00000000fffbd20] [c00000000002aed0] .smp_message_recv+0x48/0x100
[c00000000fffbda0] [c000000000046ae0] .xics_ipi_dispatch+0x84/0x148
[c00000000fffbe30] [c0000000000d62dc] .handle_IRQ_event+0xc8/0x248
[c00000000fffbf00] [c0000000000d8eb4] .handle_percpu_irq+0x80/0xf4
[c00000000fffbf90] [c000000000029048] .call_handle_irq+0x1c/0x2c
[c000000000bcfa30] [c00000000000ec84] .do_IRQ+0x1b8/0x2a4
[c000000000bcfae0] [c000000000004804] hardware_interrupt_entry+0x1c/0x98
Fix this problem by setting the index on the CPPR stack to 0 before calling
xics_set_cpu_priority() in xics_teardown_cpu().
Also make it clear that we only want to set the priority when there's just
one CPPR value in the stack, and enforce it by updating the value of
os_cppr->stack[0] rather than os_cppr->stack[os_cppr->index].
While we're at it change the BUG_ON to a WARN_ON.
Reported-by: Anton Blanchard <anton at samba.org>
Signed-off-by: Mark Nelson <markn at au1.ibm.com>
---
Ben, if it's not too late for 2.6.33 this would be really nice to have
as without it we can't kexec on pseries.
arch/powerpc/platforms/pseries/xics.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
Index: upstream/arch/powerpc/platforms/pseries/xics.c
===================================================================
--- upstream.orig/arch/powerpc/platforms/pseries/xics.c
+++ upstream/arch/powerpc/platforms/pseries/xics.c
@@ -784,9 +784,13 @@ static void xics_set_cpu_priority(unsign
{
struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
- BUG_ON(os_cppr->index != 0);
+ /*
+ * we only really want to set the priority when there's
+ * just one cppr value on the stack
+ */
+ WARN_ON(os_cppr->index != 0);
- os_cppr->stack[os_cppr->index] = cppr;
+ os_cppr->stack[0] = cppr;
if (firmware_has_feature(FW_FEATURE_LPAR))
lpar_cppr_info(cppr);
@@ -821,8 +825,14 @@ void xics_setup_cpu(void)
void xics_teardown_cpu(void)
{
+ struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
int cpu = smp_processor_id();
+ /*
+ * we have to reset the cppr index to 0 because we're
+ * not going to return from the IPI
+ */
+ os_cppr->index = 0;
xics_set_cpu_priority(0);
/* Clear any pending IPI request */
More information about the Linuxppc-dev
mailing list