From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 92772C531D0 for ; Mon, 27 Jul 2026 16:38:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=sQvTYn0As91dNcGdOPmJrYTNw2DRrc2arGvhh9MNg/A=; b=lCHNhnE5AgwTocAUocHjA5vlte 1fKOCyNPGo7lxrP+70JG9SVUfoDHjsAffvySI75iHfS2Yu3NPYFa8P/23DOYJo98avgJv7jXdap7a 5LTwz2BXzSMCefNxwOnGQ0Gc+5NPcxwQAhg4g1vvWS9z75x0pBxtWea0FsK2uijacd4AUKOAkM3r2 Q5gZqiEDXf0EtGRXfhOihz1CnC7T1yz+Inr0kfGZbE4+BBEuc26HkX6uQTPxYAic96/Xgj5us07L4 284s8cwRSzFfptmla8nApsyFzwTS+6yIbBVzlNMVqZluKt/9aIwkVByKnUoWv/j4qPvMSWcQuG1V1 9E/jCzLQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.99.1 #2 (Red Hat Linux)) id 1woOKs-00000003OTW-2DWE; Mon, 27 Jul 2026 16:37:50 +0000 Received: from foss.arm.com ([217.140.110.172]) by bombadil.infradead.org with esmtp (Exim 4.99.1 #2 (Red Hat Linux)) id 1woOJJ-00000003NP5-3Nbj for linux-arm-kernel@lists.infradead.org; Mon, 27 Jul 2026 16:36:20 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 573591756; Mon, 27 Jul 2026 09:36:08 -0700 (PDT) Received: from login2.euhpc2.arm.com (login2.euhpc2.arm.com [10.58.100.22]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 7FAC73F86F; Mon, 27 Jul 2026 09:36:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1785170172; bh=d1uAZ4Gj8cyzMDCWGqWYnReTMXcZCzEUfQVjJprp1aA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=g92QyfuoH+JyoJY2dhO4xYfLTbNC9SFNDb8EY/CgpHO7k5CEs12p/RRuiWUL8b+/C CCFAk842Xrpsr8WnVHBO9eJ0+ayldyF75F203GgD9dBv3KB2staOq369oDXt5dTjdP r356lUZAlm1G4yXoWmY30IQitNTBR+0hSk7xTOro= From: Vladimir Murzin To: linux-arm-kernel@lists.infradead.org Cc: mark.rutland@arm.com, maz@kernel.org, will@kernel.org, catalin.marinas@arm.com, ruanjinjie@huawei.com, liaochang1@huawei.com Subject: [RFC PATCH v2 42/45] irqchip/gic-v3: Implement FEAT_GICv3_NMI support Date: Mon, 27 Jul 2026 17:34:50 +0100 Message-Id: <20260727163453.7969-43-vladimir.murzin@arm.com> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20260727163453.7969-1-vladimir.murzin@arm.com> References: <20260727163453.7969-1-vladimir.murzin@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.9.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20260727_093613_958054_6793283A X-CRM114-Status: GOOD ( 20.07 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Lorenzo Pieralisi The FEAT_GICv3_NMI GIC feature coupled with the CPU FEAT_NMI enables handling NMI interrupts in HW on aarch64, by adding a superpriority interrupt to the existing GIC priority scheme. Implement GIC driver support for the FEAT_GICv3_NMI feature. Check, through the ARM64 capabilitity infrastructure, if support for FEAT_NMI was detected on the core and the system has not overridden the detection and forced pseudo-NMIs enablement. If FEAT_NMI is detected, it was not overridden (check embedded in the system_uses_nmi() call) and the GIC supports the FEAT_GICv3_NMI feature, initialize NMIs related HW GIC registers and route irq to NMI handling logic. Signed-off-by: Lorenzo Pieralisi Signed-off-by: Mark Brown Signed-off-by: Ada Couprie Diaz Signed-off-by: Vladimir Murzin --- drivers/irqchip/irq-gic-v3.c | 114 +++++++++++++++++++++++++++-- include/linux/irqchip/arm-gic-v3.h | 4 + 2 files changed, 111 insertions(+), 7 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index c75acd5f9e7f..a21ed3dcf46f 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -64,6 +64,7 @@ struct gic_chip_data { u32 nr_redist_regions; u64 flags; bool has_rss; + bool has_nmi; unsigned int ppi_nr; struct partition_affinity *parts; unsigned int nr_parts; @@ -89,6 +90,9 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); static bool pseudo_nmi_support_forbidden; +static DEFINE_RAW_SPINLOCK(gic_nmi_lock); + + /* * There are 16 SGIs, though we only actually use 8 in Linux. The other 8 SGIs * are potentially stolen by the secure side. Some code, especially code dealing @@ -252,6 +256,37 @@ enum gic_intid_range { __INVALID_RANGE__ }; +#ifdef CONFIG_ARM64 +#include + +static inline bool gic_supports_v3_3_nmi(void) +{ + return gic_data.has_nmi && system_uses_nmi(); +} + +static inline u64 gic_read_nmiar(void) +{ + u64 irqstat; + + irqstat = read_sysreg_s(SYS_ICC_NMIAR1_EL1); + + dsb(sy); + + return irqstat; +} + +#else +static inline bool gic_supports_v3_3_nmi(void) +{ + return false; +} + +static inline u64 gic_read_nmiar(void) +{ + BUG(); +} +#endif + static enum gic_intid_range __get_intid_range(irq_hw_number_t hwirq) { switch (hwirq) { @@ -438,6 +473,8 @@ static u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index) return GICD_ICFGRnE; case GICD_IROUTER: return GICD_IROUTERnE; + case GICD_INMIR: + return GICD_INMIRnE; default: break; } @@ -467,6 +504,42 @@ static int gic_peek_irq(struct irq_data *d, u32 offset) return !!(readl_relaxed(base + offset + (index / 32) * 4) & mask); } +static void gic_irq_configure_nmi(struct irq_data *d, bool enable) +{ + void __iomem *base, *addr; + unsigned long val; + u32 offset, index; + + offset = convert_offset_index(d, GICD_INMIR, &index); + + if (gic_irq_in_rdist(d)) + base = gic_data_rdist_sgi_base(); + else + base = gic_dist_base_alias(d); + + addr = base + offset + (index / 32) * 4; + + raw_spin_lock(&gic_nmi_lock); + + val = readl_relaxed(addr); + + __assign_bit(index % 32, &val, enable); + + writel_relaxed(val, addr); + + raw_spin_unlock(&gic_nmi_lock); +} + +static void gic_irq_enable_nmi(struct irq_data *d) +{ + gic_irq_configure_nmi(d, true); +} + +static void gic_irq_disable_nmi(struct irq_data *d) +{ + gic_irq_configure_nmi(d, false); +} + static void gic_poke_irq(struct irq_data *d, u32 offset) { void __iomem *base; @@ -598,7 +671,7 @@ static int gic_irq_nmi_setup(struct irq_data *d) { struct irq_desc *desc = irq_to_desc(d->irq); - if (!gic_supports_pseudo_nmi()) + if (!gic_supports_pseudo_nmi() && !gic_supports_v3_3_nmi()) return -EINVAL; if (gic_peek_irq(d, GICD_ISENABLER)) { @@ -617,7 +690,10 @@ static int gic_irq_nmi_setup(struct irq_data *d) if (!gic_irq_in_rdist(d)) desc->handle_irq = handle_fasteoi_nmi; - gic_irq_set_prio(d, dist_prio_nmi); + if (gic_supports_v3_3_nmi()) + gic_irq_enable_nmi(d); + else + gic_irq_set_prio(d, dist_prio_nmi); return 0; } @@ -626,7 +702,7 @@ static void gic_irq_nmi_teardown(struct irq_data *d) { struct irq_desc *desc = irq_to_desc(d->irq); - if (WARN_ON(!gic_supports_pseudo_nmi())) + if (WARN_ON(!gic_supports_pseudo_nmi() && !gic_supports_v3_3_nmi())) return; if (gic_peek_irq(d, GICD_ISENABLER)) { @@ -645,7 +721,10 @@ static void gic_irq_nmi_teardown(struct irq_data *d) if (!gic_irq_in_rdist(d)) desc->handle_irq = handle_fasteoi_irq; - gic_irq_set_prio(d, dist_prio_irq); + if (gic_supports_v3_3_nmi()) + gic_irq_disable_nmi(d); + else + gic_irq_set_prio(d, dist_prio_irq); } static bool gic_arm64_erratum_2941627_needed(struct irq_data *d) @@ -836,7 +915,8 @@ static void __gic_handle_nmi(u32 irqnr, struct pt_regs *regs) gic_complete_ack(irqnr); if (generic_handle_domain_nmi(gic_data.domain, irqnr)) { - WARN_ONCE(true, "Unexpected pseudo-NMI (irqnr %u)\n", irqnr); + WARN_ONCE(true, "Unexpected %sNMI (irqnr %u)\n", + gic_supports_pseudo_nmi() ? "pseudo-" : "", irqnr); gic_deactivate_unhandled(irqnr); } } @@ -911,7 +991,11 @@ static void __gic_handle_irq_from_irqsoff(struct pt_regs *regs) static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) { - if (unlikely(gic_supports_pseudo_nmi() && !interrupts_enabled(regs))) + if (gic_supports_v3_3_nmi() && in_nmi()) { + u32 irqnr = gic_read_nmiar(); + + __gic_handle_nmi(irqnr, regs); + } else if (unlikely(gic_supports_pseudo_nmi() && !interrupts_enabled(regs))) __gic_handle_irq_from_irqsoff(regs); else __gic_handle_irq_from_irqson(regs); @@ -1964,6 +2048,19 @@ static void gic_enable_pseudo_nmi(void) gic_has_relaxed_pmr_sync() ? "relaxed" : "forced"); static_branch_enable(&supports_pseudo_nmi); +} + +static void gic_enable_nmi_support(void) +{ + if ((!gic_prio_masking_enabled() || pseudo_nmi_support_forbidden) && !gic_supports_v3_3_nmi()) + return; + + /* + * Initialize pseudo-NMIs only if GIC driver cannot take advantage + * of core (FEAT_NMI) and GIC (FEAT_GICv3_NMI) in HW + */ + if (!gic_supports_v3_3_nmi()) + gic_enable_pseudo_nmi(); if (static_branch_likely(&supports_deactivate_key)) gic_eoimode1_chip.flags |= IRQCHIP_SUPPORTS_NMI; @@ -2032,6 +2129,9 @@ static int __init gic_init_bases(phys_addr_t dist_phys_base, irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED); gic_data.has_rss = !!(typer & GICD_TYPER_RSS); + gic_data.has_nmi = !!(typer & GICD_TYPER_NMI); + + pr_info("Non-maskable interrupt property %s supported\n", gic_data.has_nmi ? "is" : "not"); if (typer & GICD_TYPER_MBIS) { err = mbi_init(handle, gic_data.domain); @@ -2047,7 +2147,7 @@ static int __init gic_init_bases(phys_addr_t dist_phys_base, gic_prio_init(); gic_dist_init(); gic_cpu_init(); - gic_enable_pseudo_nmi(); + gic_enable_nmi_support(); gic_smp_init(); gic_cpu_pm_init(); diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index ea5fd2374ebe..ebccd76cadda 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -30,6 +30,7 @@ #define GICD_ICFGR 0x0C00 #define GICD_IGRPMODR 0x0D00 #define GICD_NSACR 0x0E00 +#define GICD_INMIR 0x0F80 #define GICD_IGROUPRnE 0x1000 #define GICD_ISENABLERnE 0x1200 #define GICD_ICENABLERnE 0x1400 @@ -39,6 +40,7 @@ #define GICD_ICACTIVERnE 0x1C00 #define GICD_IPRIORITYRnE 0x2000 #define GICD_ICFGRnE 0x3000 +#define GICD_INMIRnE 0x3B00 #define GICD_IROUTER 0x6000 #define GICD_IROUTERnE 0x8000 #define GICD_IDREGS 0xFFD0 @@ -83,6 +85,7 @@ #define GICD_TYPER_LPIS (1U << 17) #define GICD_TYPER_MBIS (1U << 16) #define GICD_TYPER_ESPI (1U << 8) +#define GICD_TYPER_NMI (1U << 9) #define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1) #define GICD_TYPER_NUM_LPIS(typer) ((((typer) >> 11) & 0x1f) + 1) @@ -238,6 +241,7 @@ #define GICR_ICFGR0 GICD_ICFGR #define GICR_IGRPMODR0 GICD_IGRPMODR #define GICR_NSACR GICD_NSACR +#define GICR_INMIR0 GICD_INMIR #define GICR_TYPER_PLPIS (1U << 0) #define GICR_TYPER_VLPIS (1U << 1) -- 2.34.1