xref: /linux/drivers/firmware/arm_sdei_nmi.c (revision 85cdaca6970028bf6f544c355c90035586836ddf)
10c2c5659SKiryl Shutsemau (Meta) // SPDX-License-Identifier: GPL-2.0
20c2c5659SKiryl Shutsemau (Meta) /*
30c2c5659SKiryl Shutsemau (Meta)  * arm64 SDEI-based cross-CPU NMI service.
40c2c5659SKiryl Shutsemau (Meta)  *
50c2c5659SKiryl Shutsemau (Meta)  * Delivering an "NMI-shaped" event to an EL1 context that has locally
60c2c5659SKiryl Shutsemau (Meta)  * masked interrupts, on silicon without FEAT_NMI, can be done two ways:
70c2c5659SKiryl Shutsemau (Meta)  *
80c2c5659SKiryl Shutsemau (Meta)  *   - pseudo-NMI: mask "interrupts" via the GIC priority register
90c2c5659SKiryl Shutsemau (Meta)  *     (ICC_PMR_EL1) instead of PSTATE.DAIF, leaving a high-priority band
100c2c5659SKiryl Shutsemau (Meta)  *     deliverable. Functionally this works -- but it reimplements every
110c2c5659SKiryl Shutsemau (Meta)  *     local_irq_disable()/enable() and exception entry/exit as a PMR
120c2c5659SKiryl Shutsemau (Meta)  *     write plus synchronisation, a cost paid on that hot path forever,
130c2c5659SKiryl Shutsemau (Meta)  *     whether or not an NMI is ever delivered.
140c2c5659SKiryl Shutsemau (Meta)  *
150c2c5659SKiryl Shutsemau (Meta)  *   - SDEI: leave interrupt masking as the cheap PSTATE.DAIF operation
160c2c5659SKiryl Shutsemau (Meta)  *     and have the firmware bounce an EL3-routed Group-0 SGI back to
170c2c5659SKiryl Shutsemau (Meta)  *     NS-EL1 as an event callback. The cost is a firmware round-trip,
180c2c5659SKiryl Shutsemau (Meta)  *     but only at the rare moment delivery is actually needed.
190c2c5659SKiryl Shutsemau (Meta)  *
200c2c5659SKiryl Shutsemau (Meta)  * This driver takes the second path: it keeps the IRQ-mask hot path
210c2c5659SKiryl Shutsemau (Meta)  * free and pays only when it fires, which is what makes cross-CPU NMI
220c2c5659SKiryl Shutsemau (Meta)  * affordable on hardware where the pseudo-NMI tax isn't, until FEAT_NMI
230c2c5659SKiryl Shutsemau (Meta)  * makes NMI masking cheap in the architecture itself.
240c2c5659SKiryl Shutsemau (Meta)  *
250c2c5659SKiryl Shutsemau (Meta)  * Capabilities provided:
260c2c5659SKiryl Shutsemau (Meta)  *
270c2c5659SKiryl Shutsemau (Meta)  *   - sdei_nmi_trigger_cpumask_backtrace() — override for arm64's
280c2c5659SKiryl Shutsemau (Meta)  *     arch_trigger_cpumask_backtrace(), so sysrq-l, RCU stall dumps,
290c2c5659SKiryl Shutsemau (Meta)  *     hardlockup_all_cpu_backtrace, soft-lockup/hung-task secondary
300c2c5659SKiryl Shutsemau (Meta)  *     dumps all reach interrupt-masked CPUs.
310c2c5659SKiryl Shutsemau (Meta)  *
32*d639f762SKiryl Shutsemau (Meta)  *   - sdei_nmi_stop_cpus() — the last rung of smp_send_stop()'s
33*d639f762SKiryl Shutsemau (Meta)  *     escalation (reboot/halt and the panic/kdump crash stop alike),
34*d639f762SKiryl Shutsemau (Meta)  *     reaching CPUs that ignored the stop IPIs; on the kdump path the
35*d639f762SKiryl Shutsemau (Meta)  *     wedged context is captured into the vmcore before the CPU parks.
36*d639f762SKiryl Shutsemau (Meta)  *
370c2c5659SKiryl Shutsemau (Meta)  * Delivery uses the standard SDEI software-signalled event (event 0) and
380c2c5659SKiryl Shutsemau (Meta)  * SDEI_EVENT_SIGNAL. We register a handler for event 0, enable it, and
390c2c5659SKiryl Shutsemau (Meta)  * poke a target CPU with sdei_event_signal(0, mpidr): firmware makes
400c2c5659SKiryl Shutsemau (Meta)  * event 0 pending on that PE and dispatches the handler NMI-like,
410c2c5659SKiryl Shutsemau (Meta)  * regardless of the target's DAIF.
420c2c5659SKiryl Shutsemau (Meta)  * Availability is simply whether event 0 registers and enables -- if SDEI
430c2c5659SKiryl Shutsemau (Meta)  * and its software-signalled event are present we use it, otherwise the
440c2c5659SKiryl Shutsemau (Meta)  * driver stays inert.
450c2c5659SKiryl Shutsemau (Meta)  */
460c2c5659SKiryl Shutsemau (Meta) 
470c2c5659SKiryl Shutsemau (Meta) #define pr_fmt(fmt) "sdei_nmi: " fmt
480c2c5659SKiryl Shutsemau (Meta) 
490c2c5659SKiryl Shutsemau (Meta) #include <linux/arm_sdei.h>
500c2c5659SKiryl Shutsemau (Meta) #include <linux/cpumask.h>
510c2c5659SKiryl Shutsemau (Meta) #include <linux/init.h>
520c2c5659SKiryl Shutsemau (Meta) #include <linux/kernel.h>
530c2c5659SKiryl Shutsemau (Meta) #include <linux/kprobes.h>
540c2c5659SKiryl Shutsemau (Meta) #include <linux/nmi.h>
550c2c5659SKiryl Shutsemau (Meta) #include <linux/printk.h>
560c2c5659SKiryl Shutsemau (Meta) #include <linux/ptrace.h>
570c2c5659SKiryl Shutsemau (Meta) #include <linux/smp.h>
580c2c5659SKiryl Shutsemau (Meta) #include <linux/types.h>
590c2c5659SKiryl Shutsemau (Meta) 
600c2c5659SKiryl Shutsemau (Meta) #include <asm/nmi.h>
610c2c5659SKiryl Shutsemau (Meta) #include <asm/smp_plat.h>
620c2c5659SKiryl Shutsemau (Meta) 
630c2c5659SKiryl Shutsemau (Meta) static bool sdei_nmi_available;
640c2c5659SKiryl Shutsemau (Meta) 
650c2c5659SKiryl Shutsemau (Meta) #define SDEI_NMI_EVENT			0
660c2c5659SKiryl Shutsemau (Meta) 
67*d639f762SKiryl Shutsemau (Meta) /*
68*d639f762SKiryl Shutsemau (Meta)  * Backtrace and stop both ride SDEI event 0. That is not a chosen economy:
69*d639f762SKiryl Shutsemau (Meta)  * event 0 is the only architecturally software-signalled event -- the sole
70*d639f762SKiryl Shutsemau (Meta)  * event SDEI_EVENT_SIGNAL can target at an arbitrary PE. Every other event
71*d639f762SKiryl Shutsemau (Meta)  * number is a firmware/platform interrupt-bound event, not something the
72*d639f762SKiryl Shutsemau (Meta)  * kernel can raise cross-CPU, so a dedicated "stop" event would need
73*d639f762SKiryl Shutsemau (Meta)  * firmware to define and bind it -- exactly the firmware dependency this
74*d639f762SKiryl Shutsemau (Meta)  * driver sets out to avoid.
75*d639f762SKiryl Shutsemau (Meta)  *
76*d639f762SKiryl Shutsemau (Meta)  * Sharing one event means the handler must tell a stop apart from a
77*d639f762SKiryl Shutsemau (Meta)  * backtrace. A stop is terminal and system-wide -- sdei_nmi_stop_cpus() is
78*d639f762SKiryl Shutsemau (Meta)  * only reached from smp_send_stop() (reboot/halt/panic/kdump), which never
79*d639f762SKiryl Shutsemau (Meta)  * returns -- so once a stop is requested, every later event-0 fire is a
80*d639f762SKiryl Shutsemau (Meta)  * stop too. A single write-once flag therefore carries as much as a
81*d639f762SKiryl Shutsemau (Meta)  * per-CPU mask would: sdei_nmi_stop_cpus() sets it before signalling, and
82*d639f762SKiryl Shutsemau (Meta)  * the handler reads a set flag as "stop this CPU" and a clear flag as
83*d639f762SKiryl Shutsemau (Meta)  * "backtrace" (handled by nmi_cpu_backtrace(), which self-gates on the
84*d639f762SKiryl Shutsemau (Meta)  * framework's backtrace mask). A backtrace fire that races in after a stop
85*d639f762SKiryl Shutsemau (Meta)  * has begun just stops that CPU instead -- harmless, it is going down.
86*d639f762SKiryl Shutsemau (Meta)  */
87*d639f762SKiryl Shutsemau (Meta) static bool sdei_nmi_stopping;
88*d639f762SKiryl Shutsemau (Meta) 
890c2c5659SKiryl Shutsemau (Meta) static int sdei_nmi_handler(u32 event, struct pt_regs *regs, void *arg)
900c2c5659SKiryl Shutsemau (Meta) {
910c2c5659SKiryl Shutsemau (Meta) 	/*
92*d639f762SKiryl Shutsemau (Meta) 	 * No smp_rmb() pairing sdei_nmi_stop_cpus()'s dsb(ishst): the flag is
93*d639f762SKiryl Shutsemau (Meta) 	 * the only shared value, and this handler runs only because firmware
94*d639f762SKiryl Shutsemau (Meta) 	 * delivered the event -- a round-trip past that store -- so the read
95*d639f762SKiryl Shutsemau (Meta) 	 * cannot be stale and there is no second load for a barrier to order.
96*d639f762SKiryl Shutsemau (Meta) 	 */
97*d639f762SKiryl Shutsemau (Meta) 	if (READ_ONCE(sdei_nmi_stopping)) {
98*d639f762SKiryl Shutsemau (Meta) 		/*
99*d639f762SKiryl Shutsemau (Meta) 		 * Never returns, and deliberately never completes the SDEI
100*d639f762SKiryl Shutsemau (Meta) 		 * event: SDEI_EVENT_COMPLETE has firmware restore the
101*d639f762SKiryl Shutsemau (Meta) 		 * interrupted context, which would land the CPU back in
102*d639f762SKiryl Shutsemau (Meta) 		 * the wedged loop (or in do_idle, which BUGs at
103*d639f762SKiryl Shutsemau (Meta) 		 * cpuhp_report_idle_dead once it sees itself offline).
104*d639f762SKiryl Shutsemau (Meta) 		 * Returning a modified pt_regs doesn't help --
105*d639f762SKiryl Shutsemau (Meta) 		 * arch/arm64/kernel/sdei.c::do_sdei_event only honours a PC
106*d639f762SKiryl Shutsemau (Meta) 		 * override via its IRQ-state heuristic and otherwise hands
107*d639f762SKiryl Shutsemau (Meta) 		 * EL3 its own saved-context slot back.
108*d639f762SKiryl Shutsemau (Meta) 		 *
109*d639f762SKiryl Shutsemau (Meta) 		 * Trade-off: EL3 retains ~one saved-context slot per parked
110*d639f762SKiryl Shutsemau (Meta) 		 * CPU until the next hardware reset (~hundreds of bytes per
111*d639f762SKiryl Shutsemau (Meta) 		 * CPU). Recoverability is unchanged versus an IPI-stopped
112*d639f762SKiryl Shutsemau (Meta) 		 * CPU: neither comes back without a reset.
113*d639f762SKiryl Shutsemau (Meta) 		 */
114*d639f762SKiryl Shutsemau (Meta) 		arm64_nmi_cpu_stop(regs, false);
115*d639f762SKiryl Shutsemau (Meta) 		/* unreachable */
116*d639f762SKiryl Shutsemau (Meta) 	}
117*d639f762SKiryl Shutsemau (Meta) 
118*d639f762SKiryl Shutsemau (Meta) 	/*
1190c2c5659SKiryl Shutsemau (Meta) 	 * nmi_cpu_backtrace() no-ops unless this CPU's bit is set in the
1200c2c5659SKiryl Shutsemau (Meta) 	 * global backtrace mask (driven by nmi_trigger_cpumask_backtrace()),
1210c2c5659SKiryl Shutsemau (Meta) 	 * so a fire that reaches a CPU not being backtraced is harmless.
1220c2c5659SKiryl Shutsemau (Meta) 	 */
1230c2c5659SKiryl Shutsemau (Meta) 	nmi_cpu_backtrace(regs);
1240c2c5659SKiryl Shutsemau (Meta) 	return SDEI_EV_HANDLED;
1250c2c5659SKiryl Shutsemau (Meta) }
1260c2c5659SKiryl Shutsemau (Meta) NOKPROBE_SYMBOL(sdei_nmi_handler);
1270c2c5659SKiryl Shutsemau (Meta) 
1280c2c5659SKiryl Shutsemau (Meta) static void sdei_nmi_fire(unsigned int target_cpu)
1290c2c5659SKiryl Shutsemau (Meta) {
1300c2c5659SKiryl Shutsemau (Meta) 	int err = sdei_event_signal(SDEI_NMI_EVENT, cpu_logical_map(target_cpu));
1310c2c5659SKiryl Shutsemau (Meta) 
1320c2c5659SKiryl Shutsemau (Meta) 	if (err)
1330c2c5659SKiryl Shutsemau (Meta) 		pr_warn("SDEI_EVENT_SIGNAL to CPU %u failed: %d\n",
1340c2c5659SKiryl Shutsemau (Meta) 			target_cpu, err);
1350c2c5659SKiryl Shutsemau (Meta) }
1360c2c5659SKiryl Shutsemau (Meta) 
1370c2c5659SKiryl Shutsemau (Meta) /*
1380c2c5659SKiryl Shutsemau (Meta)  * Raise callback for nmi_trigger_cpumask_backtrace(): signal event 0
1390c2c5659SKiryl Shutsemau (Meta)  * at every CPU still pending in @mask. The framework excludes the local
1400c2c5659SKiryl Shutsemau (Meta)  * CPU from @mask before calling us.
1410c2c5659SKiryl Shutsemau (Meta)  */
1420c2c5659SKiryl Shutsemau (Meta) static void sdei_nmi_raise_backtrace(cpumask_t *mask)
1430c2c5659SKiryl Shutsemau (Meta) {
1440c2c5659SKiryl Shutsemau (Meta) 	unsigned int cpu;
1450c2c5659SKiryl Shutsemau (Meta) 
1460c2c5659SKiryl Shutsemau (Meta) 	/*
1470c2c5659SKiryl Shutsemau (Meta) 	 * Publish backtrace_mask (set by nmi_trigger_cpumask_backtrace())
1480c2c5659SKiryl Shutsemau (Meta) 	 * before signalling. As in the stop path, the SMC is not a memory
1490c2c5659SKiryl Shutsemau (Meta) 	 * store, so dsb(ishst) is needed for the target to observe the mask.
1500c2c5659SKiryl Shutsemau (Meta) 	 */
1510c2c5659SKiryl Shutsemau (Meta) 	dsb(ishst);
1520c2c5659SKiryl Shutsemau (Meta) 
1530c2c5659SKiryl Shutsemau (Meta) 	for_each_cpu(cpu, mask)
1540c2c5659SKiryl Shutsemau (Meta) 		sdei_nmi_fire(cpu);
1550c2c5659SKiryl Shutsemau (Meta) }
1560c2c5659SKiryl Shutsemau (Meta) 
1570c2c5659SKiryl Shutsemau (Meta) /*
1580c2c5659SKiryl Shutsemau (Meta)  * Override hook for arch_trigger_cpumask_backtrace() (see
1590c2c5659SKiryl Shutsemau (Meta)  * arch/arm64/kernel/smp.c). Returns true when SDEI handled the request,
1600c2c5659SKiryl Shutsemau (Meta)  * which is the case whenever SDEI is active; on a false return the arch
1610c2c5659SKiryl Shutsemau (Meta)  * falls back to its regular-IRQ (or pseudo-NMI, if enabled) IPI.
1620c2c5659SKiryl Shutsemau (Meta)  *
1630c2c5659SKiryl Shutsemau (Meta)  * On a kernel built without paying the pseudo-NMI hot-path cost (the
1640c2c5659SKiryl Shutsemau (Meta)  * usual case for this driver's target), the IPI can't reach a CPU that
1650c2c5659SKiryl Shutsemau (Meta)  * has interrupts masked -- so the backtrace of the one CPU you care
1660c2c5659SKiryl Shutsemau (Meta)  * about comes back empty. SDEI is dispatched out of EL3 and lands
1670c2c5659SKiryl Shutsemau (Meta)  * regardless of the target's DAIF, without taxing the IRQ-mask path.
1680c2c5659SKiryl Shutsemau (Meta)  */
1690c2c5659SKiryl Shutsemau (Meta) bool sdei_nmi_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
1700c2c5659SKiryl Shutsemau (Meta) {
1710c2c5659SKiryl Shutsemau (Meta) 	if (!sdei_nmi_available)
1720c2c5659SKiryl Shutsemau (Meta) 		return false;
1730c2c5659SKiryl Shutsemau (Meta) 
1740c2c5659SKiryl Shutsemau (Meta) 	nmi_trigger_cpumask_backtrace(mask, exclude_cpu,
1750c2c5659SKiryl Shutsemau (Meta) 				      sdei_nmi_raise_backtrace);
1760c2c5659SKiryl Shutsemau (Meta) 	return true;
1770c2c5659SKiryl Shutsemau (Meta) }
1780c2c5659SKiryl Shutsemau (Meta) 
179*d639f762SKiryl Shutsemau (Meta) bool sdei_nmi_active(void)
180*d639f762SKiryl Shutsemau (Meta) {
181*d639f762SKiryl Shutsemau (Meta) 	return sdei_nmi_available;
182*d639f762SKiryl Shutsemau (Meta) }
183*d639f762SKiryl Shutsemau (Meta) 
184*d639f762SKiryl Shutsemau (Meta) /*
185*d639f762SKiryl Shutsemau (Meta)  * Last rung of the stop escalation in smp_send_stop() (see
186*d639f762SKiryl Shutsemau (Meta)  * arch/arm64/kernel/smp.c). The caller runs the regular stop IPI (and
187*d639f762SKiryl Shutsemau (Meta)  * the pseudo-NMI stop IPI, where available) first; @mask holds whatever
188*d639f762SKiryl Shutsemau (Meta)  * stayed online through those -- typically CPUs wedged with interrupts
189*d639f762SKiryl Shutsemau (Meta)  * masked, unreachable by an IPI. Mark the stop in progress and signal
190*d639f762SKiryl Shutsemau (Meta)  * event 0 at each target; a target acks by marking itself offline, which
191*d639f762SKiryl Shutsemau (Meta)  * the caller polls for. The caller has already confirmed sdei_nmi_active().
192*d639f762SKiryl Shutsemau (Meta)  */
193*d639f762SKiryl Shutsemau (Meta) void sdei_nmi_stop_cpus(const cpumask_t *mask)
194*d639f762SKiryl Shutsemau (Meta) {
195*d639f762SKiryl Shutsemau (Meta) 	unsigned int cpu;
196*d639f762SKiryl Shutsemau (Meta) 
197*d639f762SKiryl Shutsemau (Meta) 	WRITE_ONCE(sdei_nmi_stopping, true);
198*d639f762SKiryl Shutsemau (Meta) 
199*d639f762SKiryl Shutsemau (Meta) 	/*
200*d639f762SKiryl Shutsemau (Meta) 	 * Publish the flag before signalling. The signal goes out via an SMC
201*d639f762SKiryl Shutsemau (Meta) 	 * to firmware, not a memory store, so smp_wmb() ordering is not
202*d639f762SKiryl Shutsemau (Meta) 	 * enough: use dsb(ishst) to make the store globally visible before the
203*d639f762SKiryl Shutsemau (Meta) 	 * SMC executes, as gic_ipi_send_mask() does for its SGI. The SDEI spec
204*d639f762SKiryl Shutsemau (Meta) 	 * does not require the dispatch to order the caller's prior stores.
205*d639f762SKiryl Shutsemau (Meta) 	 */
206*d639f762SKiryl Shutsemau (Meta) 	dsb(ishst);
207*d639f762SKiryl Shutsemau (Meta) 
208*d639f762SKiryl Shutsemau (Meta) 	for_each_cpu(cpu, mask)
209*d639f762SKiryl Shutsemau (Meta) 		sdei_nmi_fire(cpu);
210*d639f762SKiryl Shutsemau (Meta) }
211*d639f762SKiryl Shutsemau (Meta) 
2120c2c5659SKiryl Shutsemau (Meta) /*
2130c2c5659SKiryl Shutsemau (Meta)  * device_initcall (after arch_initcall(sdei_init), so the SDEI subsystem
2140c2c5659SKiryl Shutsemau (Meta)  * is up): probe the firmware, register the event, and turn on the
2150c2c5659SKiryl Shutsemau (Meta)  * cross-CPU service. If the probe fails the driver stays inert and the
2160c2c5659SKiryl Shutsemau (Meta)  * override hooks decline, leaving the arch's own paths in place.
2170c2c5659SKiryl Shutsemau (Meta)  */
2180c2c5659SKiryl Shutsemau (Meta) static int __init sdei_nmi_init(void)
2190c2c5659SKiryl Shutsemau (Meta) {
2200c2c5659SKiryl Shutsemau (Meta) 	int err;
2210c2c5659SKiryl Shutsemau (Meta) 
2220c2c5659SKiryl Shutsemau (Meta) 	if (!sdei_is_present())
2230c2c5659SKiryl Shutsemau (Meta) 		return 0;
2240c2c5659SKiryl Shutsemau (Meta) 
2250c2c5659SKiryl Shutsemau (Meta) 	err = sdei_event_register(SDEI_NMI_EVENT, sdei_nmi_handler, NULL);
2260c2c5659SKiryl Shutsemau (Meta) 	if (err) {
2270c2c5659SKiryl Shutsemau (Meta) 		pr_err("sdei_event_register(%u) failed: %d\n",
2280c2c5659SKiryl Shutsemau (Meta) 		       SDEI_NMI_EVENT, err);
2290c2c5659SKiryl Shutsemau (Meta) 		return 0;
2300c2c5659SKiryl Shutsemau (Meta) 	}
2310c2c5659SKiryl Shutsemau (Meta) 
2320c2c5659SKiryl Shutsemau (Meta) 	err = sdei_event_enable(SDEI_NMI_EVENT);
2330c2c5659SKiryl Shutsemau (Meta) 	if (err) {
2340c2c5659SKiryl Shutsemau (Meta) 		pr_err("sdei_event_enable(%u) failed: %d\n",
2350c2c5659SKiryl Shutsemau (Meta) 		       SDEI_NMI_EVENT, err);
2360c2c5659SKiryl Shutsemau (Meta) 		sdei_event_unregister(SDEI_NMI_EVENT);
2370c2c5659SKiryl Shutsemau (Meta) 		return 0;
2380c2c5659SKiryl Shutsemau (Meta) 	}
2390c2c5659SKiryl Shutsemau (Meta) 
2400c2c5659SKiryl Shutsemau (Meta) 	sdei_nmi_available = true;
2410c2c5659SKiryl Shutsemau (Meta) 	pr_info("using SDEI cross-CPU NMI (SDEI_EVENT_SIGNAL, event %u)\n",
2420c2c5659SKiryl Shutsemau (Meta) 		SDEI_NMI_EVENT);
2430c2c5659SKiryl Shutsemau (Meta) 
2440c2c5659SKiryl Shutsemau (Meta) 	return 0;
2450c2c5659SKiryl Shutsemau (Meta) }
2460c2c5659SKiryl Shutsemau (Meta) device_initcall(sdei_nmi_init);
247