Commit 1cd6ed7c authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman

powerpc/xmon: Wait for secondaries before IPI'ing on system reset

An externally triggered system reset (e.g., via QEMU nmi command, or pseries
reset button) can cause system reset interrupts on all CPUs. In case this causes
xmon to be entered, it is undesirable for the primary (first) CPU into xmon to
trigger an NMI IPI to others, because this may cause a nested system reset
interrupt.

So spin for a time waiting for secondaries to join xmon before performing the
NMI IPI, similarly to what the crash dump code does.
Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
[mpe: Only do it when we come in from system reset, not via sysrq etc.]
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 102c05e8
...@@ -418,7 +418,22 @@ int cpus_are_in_xmon(void) ...@@ -418,7 +418,22 @@ int cpus_are_in_xmon(void)
{ {
return !cpumask_empty(&cpus_in_xmon); return !cpumask_empty(&cpus_in_xmon);
} }
#endif
static bool wait_for_other_cpus(int ncpus)
{
unsigned long timeout;
/* We wait for 2s, which is a metric "little while" */
for (timeout = 20000; timeout != 0; --timeout) {
if (cpumask_weight(&cpus_in_xmon) >= ncpus)
return true;
udelay(100);
barrier();
}
return false;
}
#endif /* CONFIG_SMP */
static inline int unrecoverable_excp(struct pt_regs *regs) static inline int unrecoverable_excp(struct pt_regs *regs)
{ {
...@@ -440,7 +455,6 @@ static int xmon_core(struct pt_regs *regs, int fromipi) ...@@ -440,7 +455,6 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
int cpu; int cpu;
int secondary; int secondary;
unsigned long timeout;
#endif #endif
local_irq_save(flags); local_irq_save(flags);
...@@ -527,13 +541,17 @@ static int xmon_core(struct pt_regs *regs, int fromipi) ...@@ -527,13 +541,17 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
xmon_owner = cpu; xmon_owner = cpu;
mb(); mb();
if (ncpus > 1) { if (ncpus > 1) {
smp_send_debugger_break(); /*
/* wait for other cpus to come in */ * A system reset (trap == 0x100) can be triggered on
for (timeout = 100000000; timeout != 0; --timeout) { * all CPUs, so when we come in via 0x100 try waiting
if (cpumask_weight(&cpus_in_xmon) >= ncpus) * for the other CPUs to come in before we send the
break; * debugger break (IPI). This is similar to
barrier(); * crash_kexec_secondary().
} */
if (TRAP(regs) != 0x100 || !wait_for_other_cpus(ncpus))
smp_send_debugger_break();
wait_for_other_cpus(ncpus);
} }
remove_bpts(); remove_bpts();
disable_surveillance(); disable_surveillance();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment