aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2014-05-29 20:26:18 +1000
committerPaul Mackerras <paulus@samba.org>2014-06-17 14:33:08 +1000
commit824c5e65678f330ae7c33eb05b6bc08fd4a70f6a (patch)
treef9d3287d350ab104517d085e1b500abecc9eef01
parentc34dd7c3d3469c949232a1c5a10ef36d1b1ddfcb (diff)
downloadpowerpc-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.c14
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);