[RFC PATCH v2 39/45] arm64: smp: Fall back to IRQ when IPI NMI request fails
Vladimir Murzin
vladimir.murzin at arm.com
Mon Jul 27 09:34:47 PDT 2026
Existing IPI setup logic relies on ipi_should_be_nmi() to decide
whether to request an NMI (if supported) or an ordinary IRQ. If NMI is
not supported, using an ordinary IRQ is acceptable.
FEAT_NMI requires complementary support in the interrupt
controller. If FEAT_NMI is present but interrupt controller support is
absent, request_percpu_nmi() can fail.
One way to prevent this would be to extend ipi_should_be_nmi() to also
check for interrupt controller support. However, since falling back to
an ordinary IRQ is acceptable, treat ipi_should_be_nmi() as a hint
instead. Whether an IPI is actually registered as an NMI is determined
by the success or failure of request_percpu_nmi(). If the request
fails, fall back to request_irq().
Track which IPIs were actually registered as NMIs and use that state
in the per-CPU enable and disable paths. This avoids calling the
percpu NMI helpers for an IPI that fell back to regular IRQ handling.
Signed-off-by: Vladimir Murzin <vladimir.murzin at arm.com>
---
arch/arm64/kernel/smp.c | 31 +++++++++++++++++++++++--------
1 file changed, 23 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 3dd4bc02caed..9bacdbb2aa44 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -69,11 +69,13 @@ static int nr_ipi __ro_after_init = NR_IPI;
struct ipi_descs {
struct irq_desc *descs[MAX_IPI];
+ DECLARE_BITMAP(nmi_bitmap, MAX_IPI);
};
static DEFINE_PER_CPU_READ_MOSTLY(struct ipi_descs, pcpu_ipi_desc);
#define get_ipi_desc(__cpu, __ipi) (per_cpu_ptr(&pcpu_ipi_desc, __cpu)->descs[__ipi])
+#define get_ipi_nmi_bitmap(__cpu) (per_cpu_ptr(&pcpu_ipi_desc, __cpu)->nmi_bitmap)
struct ipi_irq_ops {
void (*setup)(int ipi, int ncpus);
@@ -1051,31 +1053,44 @@ static bool ipi_should_be_nmi(enum ipi_msg_type ipi)
static void ipi_sgi_setup(int ipi, int ncpus)
{
+ bool is_nmi = ipi_should_be_nmi(ipi);
int err, irq, cpu;
if (WARN_ON_ONCE(ncpus))
return;
-
irq = ipi_irq_base + ipi;
- if (ipi_should_be_nmi(ipi)) {
- err = request_percpu_nmi(irq, ipi_handler, "IPI", NULL, &irq_stat);
- WARN(err, "Could not request IRQ %d as NMI, err=%d\n", irq, err);
- } else {
+ /*
+ * Try to request NMI if it should be
+ */
+ if (is_nmi && request_percpu_nmi(irq, ipi_handler, "IPI", NULL, &irq_stat)) {
+ /*
+ * Fallback to regular IRQ
+ */
+ is_nmi = false;
+ }
+
+ /*
+ * Otherwise regular IRQ
+ */
+ if (!is_nmi) {
err = request_percpu_irq(irq, ipi_handler, "IPI", &irq_stat);
WARN(err, "Could not request IRQ %d as IRQ, err=%d\n", irq, err);
}
- for_each_possible_cpu(cpu)
+ for_each_possible_cpu(cpu) {
get_ipi_desc(cpu, ipi) = irq_to_desc(irq);
+ if (is_nmi)
+ set_bit(ipi, get_ipi_nmi_bitmap(cpu));
+ }
irq_set_status_flags(irq, IRQ_HIDDEN);
}
static void ipi_sgi_enable(int cpu, int ipi)
{
- if (ipi_should_be_nmi(ipi)) {
+ if (test_bit(ipi, get_ipi_nmi_bitmap(cpu))) {
prepare_percpu_nmi(ipi_irq_base + ipi);
enable_percpu_nmi(ipi_irq_base + ipi, 0);
} else {
@@ -1085,7 +1100,7 @@ static void ipi_sgi_enable(int cpu, int ipi)
static void ipi_sgi_disable(int cpu, int ipi)
{
- if (ipi_should_be_nmi(ipi)) {
+ if (test_bit(ipi, get_ipi_nmi_bitmap(cpu))) {
disable_percpu_nmi(ipi_irq_base + ipi);
teardown_percpu_nmi(ipi_irq_base + ipi);
} else {
--
2.34.1
More information about the linux-arm-kernel
mailing list