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