aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/paca.c
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2010-05-13 15:40:11 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-05-21 03:31:11 -0400
commit1fc711f7ffb01089efc58042cfdbac8573d1b59a (patch)
tree7c057a32c140e8d617a9cff34ca5d2227e9acdb8 /arch/powerpc/kernel/paca.c
parentd504bed676caad29a3dba3d3727298c560628f5c (diff)
powerpc/kexec: Fix race in kexec shutdown
In kexec_prepare_cpus, the primary CPU IPIs the secondary CPUs to kexec_smp_down(). kexec_smp_down() calls kexec_smp_wait() which sets the hw_cpu_id() to -1. The primary does this while leaving IRQs on which means the primary can take a timer interrupt which can lead to the IPIing one of the secondary CPUs (say, for a scheduler re-balance) but since the secondary CPU now has a hw_cpu_id = -1, we IPI CPU -1... Kaboom! We are hitting this case regularly on POWER7 machines. There is also a second race, where the primary will tear down the MMU mappings before knowing the secondaries have entered real mode. Also, the secondaries are clearing out any pending IPIs before guaranteeing that no more will be received. This changes kexec_prepare_cpus() so that we turn off IRQs in the primary CPU much earlier. It adds a paca flag to say that the secondaries have entered the kexec_smp_down() IPI and turned off IRQs, rather than overloading hw_cpu_id with -1. This new paca flag is again used to in indicate when the secondaries has entered real mode. It also ensures that all CPUs have their IRQs off before we clear out any pending IPI requests (in kexec_cpu_down()) to ensure there are no trailing IPIs left unacknowledged. Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/paca.c')
-rw-r--r--arch/powerpc/kernel/paca.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index 0c40c6f476fe..f88acf0218db 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -18,6 +18,7 @@
18#include <asm/pgtable.h> 18#include <asm/pgtable.h>
19#include <asm/iseries/lpar_map.h> 19#include <asm/iseries/lpar_map.h>
20#include <asm/iseries/hv_types.h> 20#include <asm/iseries/hv_types.h>
21#include <asm/kexec.h>
21 22
22/* This symbol is provided by the linker - let it fill in the paca 23/* This symbol is provided by the linker - let it fill in the paca
23 * field correctly */ 24 * field correctly */
@@ -97,6 +98,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
97 new_paca->kernelbase = (unsigned long) _stext; 98 new_paca->kernelbase = (unsigned long) _stext;
98 new_paca->kernel_msr = MSR_KERNEL; 99 new_paca->kernel_msr = MSR_KERNEL;
99 new_paca->hw_cpu_id = 0xffff; 100 new_paca->hw_cpu_id = 0xffff;
101 new_paca->kexec_state = KEXEC_STATE_NONE;
100 new_paca->__current = &init_task; 102 new_paca->__current = &init_task;
101#ifdef CONFIG_PPC_STD_MMU_64 103#ifdef CONFIG_PPC_STD_MMU_64
102 new_paca->slb_shadow_ptr = &slb_shadow[cpu]; 104 new_paca->slb_shadow_ptr = &slb_shadow[cpu];