diff options
Diffstat (limited to 'arch/powerpc/platforms/powernv/smp.c')
-rw-r--r-- | arch/powerpc/platforms/powernv/smp.c | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index 4753958cd509..b716f666e48a 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c | |||
@@ -149,6 +149,7 @@ static int pnv_smp_cpu_disable(void) | |||
149 | static void pnv_smp_cpu_kill_self(void) | 149 | static void pnv_smp_cpu_kill_self(void) |
150 | { | 150 | { |
151 | unsigned int cpu; | 151 | unsigned int cpu; |
152 | unsigned long srr1; | ||
152 | 153 | ||
153 | /* Standard hot unplug procedure */ | 154 | /* Standard hot unplug procedure */ |
154 | local_irq_disable(); | 155 | local_irq_disable(); |
@@ -165,13 +166,25 @@ static void pnv_smp_cpu_kill_self(void) | |||
165 | mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1); | 166 | mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1); |
166 | while (!generic_check_cpu_restart(cpu)) { | 167 | while (!generic_check_cpu_restart(cpu)) { |
167 | ppc64_runlatch_off(); | 168 | ppc64_runlatch_off(); |
168 | power7_nap(1); | 169 | srr1 = power7_nap(1); |
169 | ppc64_runlatch_on(); | 170 | ppc64_runlatch_on(); |
170 | 171 | ||
171 | /* Clear the IPI that woke us up */ | 172 | /* |
172 | icp_native_flush_interrupt(); | 173 | * If the SRR1 value indicates that we woke up due to |
173 | local_paca->irq_happened &= PACA_IRQ_HARD_DIS; | 174 | * an external interrupt, then clear the interrupt. |
174 | mb(); | 175 | * We clear the interrupt before checking for the |
176 | * reason, so as to avoid a race where we wake up for | ||
177 | * some other reason, find nothing and clear the interrupt | ||
178 | * just as some other cpu is sending us an interrupt. | ||
179 | * If we returned from power7_nap as a result of | ||
180 | * having finished executing in a KVM guest, then srr1 | ||
181 | * contains 0. | ||
182 | */ | ||
183 | if ((srr1 & SRR1_WAKEMASK) == SRR1_WAKEEE) { | ||
184 | icp_native_flush_interrupt(); | ||
185 | local_paca->irq_happened &= PACA_IRQ_HARD_DIS; | ||
186 | smp_mb(); | ||
187 | } | ||
175 | 188 | ||
176 | if (cpu_core_split_required()) | 189 | if (cpu_core_split_required()) |
177 | continue; | 190 | continue; |