mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
A CPU wedged with interrupts masked ignores the stop IPI, and without pseudo-NMI there is no NMI IPI to escalate to: a reboot proceeds with the CPU still running, and a kdump misses its registers. Add a third rung to smp_send_stop(): once the IPI (and pseudo-NMI IPI, if enabled) rungs have run, signal SDEI event 0 at whatever stayed online. Firmware delivers it regardless of the target's DAIF, so it reaches a CPU a plain IPI cannot; the target acks by going offline, which the caller already polls for. Fold the stop bookkeeping into one arm64_nmi_cpu_stop(regs, die_on_crash), shared by the stop IPI handlers, panic_smp_self_stop() and the SDEI handler, replacing the near-duplicate local_cpu_stop() and ipi_cpu_crash_stop(). @die_on_crash is the only difference: the IPI handlers pass true and PSCI CPU_OFF the CPU on a crash stop so a capture kernel can reclaim it; the SDEI handler and self-stop pass false and park. The SDEI park is required, not conservative -- its handler runs inside an SDEI event that is never completed (completing it resumes the wedged context), and a CPU_OFF from that unfinished-event context wedges EL3 on some firmware (left as a follow-up). The dump is unaffected; only re-onlining the CPU in an SMP capture kernel is lost. Suggested-by: Douglas Anderson <dianders@chromium.org> Signed-off-by: Kiryl Shutsemau (Meta) <kas@kernel.org> Reviewed-by: Douglas Anderson <dianders@chromium.org> Tested-by: Yin Fengwei <fengwei_yin@linux.alibaba.com> Signed-off-by: Will Deacon <will@kernel.org>
49 lines
1.5 KiB
C
49 lines
1.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef __ASM_NMI_H
|
|
#define __ASM_NMI_H
|
|
|
|
#include <linux/cpumask.h>
|
|
|
|
struct pt_regs;
|
|
|
|
/*
|
|
* Cross-CPU NMI provider hooks, consulted by the arm64 arch code before
|
|
* its regular-IRQ / pseudo-NMI IPI paths. The SDEI provider in
|
|
* drivers/firmware/arm_sdei_nmi.c implements them when active; a future
|
|
* FEAT_NMI provider could slot in here too. The stubs let callers stay
|
|
* unconditional when ARM_SDEI_NMI is off.
|
|
*
|
|
* sdei_nmi_active() lets a caller test for the service before committing
|
|
* to (and waiting on) the SDEI stop rung; sdei_nmi_stop_cpus() then signals
|
|
* the targets, which ack by going offline.
|
|
*/
|
|
#ifdef CONFIG_ARM_SDEI_NMI
|
|
bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu);
|
|
bool sdei_nmi_active(void);
|
|
void sdei_nmi_stop_cpus(const cpumask_t *mask);
|
|
#else
|
|
static inline bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask,
|
|
int exclude_cpu)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline bool sdei_nmi_active(void)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline void sdei_nmi_stop_cpus(const cpumask_t *mask) { }
|
|
#endif
|
|
|
|
/*
|
|
* The common "stop this CPU" entry every arm64 stop path funnels through:
|
|
* the regular/pseudo-NMI stop IPI handlers, panic_smp_self_stop(), and the
|
|
* SDEI cross-CPU NMI handler. @die_on_crash powers the CPU off on the kdump
|
|
* crash path (IPI handlers) instead of parking it (SDEI / self-stop).
|
|
* Defined in arch/arm64/kernel/smp.c.
|
|
*/
|
|
void __noreturn arm64_nmi_cpu_stop(struct pt_regs *regs, bool die_on_crash);
|
|
|
|
#endif /* __ASM_NMI_H */
|