[RFC PATCH v2 39/45] arm64: smp: Fall back to IRQ when IPI NMI request fails
Jinjie Ruan
ruanjinjie at huawei.com
Thu Aug 13 02:20:01 PDT 2026
在 2026/7/28 0:34, Vladimir Murzin 写道:
> 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.
Hi Vladimir,
Should we update the following comment and mention that "regular IPI
will also be used when the nmi_bitmap is not set"?
936 void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int
exclude_cpu)
937 {
938 >-------/*
939 >------- * NOTE: though nmi_trigger_cpumask_backtrace() has "nmi_"
in the name,
940 >------- * nothing about it truly needs to be implemented using an
NMI, it's
941 >------- * just that it's _allowed_ to work with NMIs. If
ipi_should_be_nmi()
942 >------- * returned false our backtrace attempt will just use a
regular IPI.
943 >------- */
944 >-------nmi_trigger_cpumask_backtrace(mask, exclude_cpu,
arm64_backtrace_ipi);
945 }
otherwise, LGTM
Reviewed-by: Jinjie Ruan <ruanjinjie at huawei.com>
>
> 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 {
More information about the linux-arm-kernel
mailing list