diff options
author | Paul Mackerras <paulus@samba.org> | 2014-05-29 20:26:18 +1000 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2014-06-17 14:33:08 +1000 |
commit | 824c5e65678f330ae7c33eb05b6bc08fd4a70f6a (patch) | |
tree | f9d3287d350ab104517d085e1b500abecc9eef01 | |
parent | c34dd7c3d3469c949232a1c5a10ef36d1b1ddfcb (diff) | |
download | powerpc-824c5e65678f330ae7c33eb05b6bc08fd4a70f6a.tar.gz |
powerpc/powernv: Fix race in checking reason for off-line CPU waking up
Currently, when an off-line CPU wakes up from nap, we check for the
possible reasons for the wakeup (split-core mode change, or the CPU
needs to come online) before clearing the IPI that woke us. This
leaves a possible race in the situation where we wake up for some
unrelated reason, typically a leftover IPI from a KVM guest exit.
If some other CPU sets a flag and then sends an IPI at just the right
time, it is possible that we don't see the flag but then clear the
IPI that the other CPU sent, and therefore miss a wakeup.
To fix this, we clear the IPI first, and only check for any flags
after a barrier. That way if we miss the flag setting we are sure not
to have cleared the IPI that the other CPU sent.
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/platforms/powernv/smp.c | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index d2592d8914f5ee..96ffaa1c77203c 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c @@ -177,15 +177,21 @@ static void pnv_smp_cpu_kill_self(void) power7_nap(); ppc64_runlatch_on(); + /* + * Clear the IPI that woke us up before checking for the + * reason, so as to avoid a race where we wake up for + * some other reason, find nothing and clear the interrupt + * just as some other cpu is sending us an interrupt. + */ + icp_native_flush_interrupt(); + local_paca->irq_happened &= PACA_IRQ_HARD_DIS; + smp_mb(); + if (!cpu_core_split_required()) { if (generic_check_cpu_restart(cpu)) break; DBG("CPU%d Unexpected exit while offline !\n", cpu); } - - /* Clear the IPI that woke us up and go back to nap */ - icp_native_flush_interrupt(); - local_paca->irq_happened &= PACA_IRQ_HARD_DIS; } mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_PECE1); DBG("CPU%d coming online...\n", cpu); |