From 50b10bd0c2d721ad38abd1abe3acdefb6caa0944 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 18 Aug 2026 12:09:33 +0100 Subject: irqchip/renesas-rzg2l: Fix loss of interrupt rzg2l_clear_irq_int() and rzg2l_clear_tint_int() perform a read-modify-write on the ISCR/TSCR status registers to clear the bit for the interrupt just handled. Since these registers are write-0-to-clear per bit, this is racy: If another interrupt's status bit gets set between the read and the write, that bit is written back as 0 by the software-constructed value, clearing an interrupt that hasn't been serviced yet and losing it. This can be reproduced by triggering multiple interrupts at once, e.g.: gpioset -c gpiochip0 355=0 353=0 328=0 352=0 Fix this by writing back only the bit being cleared, with all other bits set to 1, instead of read-modify-writing the whole register. Since 1-bits are left unchanged by hardware, concurrently-set status bits for other interrupts are preserved. Fixes: 3fed09559cd8 ("irqchip: Add RZ/G2L IA55 Interrupt Controller driver") Signed-off-by: Biju Das Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260818110937.5816-1-biju.das.jz@bp.renesas.com --- drivers/irqchip/irq-renesas-rzg2l.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c index f6b2e69a2f4e..b3774f82855a 100644 --- a/drivers/irqchip/irq-renesas-rzg2l.c +++ b/drivers/irqchip/irq-renesas-rzg2l.c @@ -161,7 +161,7 @@ static void rzg2l_clear_irq_int(struct rzg2l_irqc_priv *priv, unsigned int hwirq * falling/rising-edge. */ if ((iscr & bit) && (iitsr & IITSR_IITSEL_MASK(hw_irq))) { - writel_relaxed(iscr & ~bit, priv->base + ISCR); + writel_relaxed(~bit, priv->base + ISCR); /* * Enforce that the posted write is flushed to prevent that the * just handled interrupt is raised again. @@ -177,7 +177,7 @@ static void rzg2l_clear_tint_int(struct rzg2l_irqc_priv *priv, unsigned int hwir reg = readl_relaxed(priv->base + TSCR); if (reg & bit) { - writel_relaxed(reg & ~bit, priv->base + TSCR); + writel_relaxed(~bit, priv->base + TSCR); /* * Enforce that the posted write is flushed to prevent that the * just handled interrupt is raised again. -- cgit v1.2.3 From b76eee9c2157223aa4aac42ceebb563288e078aa Mon Sep 17 00:00:00 2001 From: Ryan Chen Date: Wed, 19 Aug 2026 09:09:19 +0800 Subject: irqchip/ast2700-intc: Avoid allocating in the irq_domain activate() callback The interrupt core calls the irq_domain_activate() callback from __setup_irq() with desc->lock held and interrupts disabled. Both aspeed_intc1_irq_domain_activate() and aspeed_intc0_resolve_route() test a compatible string with fwnode_device_is_compatible(). fwnode_device_is_compatible() invokes fwnode_property_match_string(), which allocates with GFP_KERNEL. That's obviously not possible with interrupts disabled and a raw spinlock held. Both call sites are only ever handed OF nodes, so use of_device_is_compatible() instead: it walks the property in place and does not allocate. Fixes: 07825e41519a ("irqchip/ast2700-intc: Add AST2700-A2 support") Reported-by: Andrew Jeffery Signed-off-by: Ryan Chen Signed-off-by: Thomas Gleixner Tested-by: Andrew Jeffery Link: https://patch.msgid.link/20260819-fix-ast2700-intc-atomic-alloc-v1-1-d92a02e2a239@aspeedtech.com --- drivers/irqchip/irq-ast2700-intc0.c | 2 +- drivers/irqchip/irq-ast2700-intc1.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-ast2700-intc0.c b/drivers/irqchip/irq-ast2700-intc0.c index 14b8b88f1179..c85b98a19bd4 100644 --- a/drivers/irqchip/irq-ast2700-intc0.c +++ b/drivers/irqchip/irq-ast2700-intc0.c @@ -312,7 +312,7 @@ int aspeed_intc0_resolve_route(const struct irq_domain *c0domain, size_t nc1outs return -ENOENT; if (!IS_ENABLED(CONFIG_ASPEED_AST2700_INTC_TEST) && - !fwnode_device_is_compatible(c0domain->fwnode, "aspeed,ast2700-intc0")) + !of_device_is_compatible(to_of_node(c0domain->fwnode), "aspeed,ast2700-intc0")) return -ENODEV; intc0 = c0domain->host_data; diff --git a/drivers/irqchip/irq-ast2700-intc1.c b/drivers/irqchip/irq-ast2700-intc1.c index 59e8f0d5ddcd..df6acbafce2d 100644 --- a/drivers/irqchip/irq-ast2700-intc1.c +++ b/drivers/irqchip/irq-ast2700-intc1.c @@ -157,7 +157,8 @@ static int aspeed_intc1_irq_domain_activate(struct irq_domain *domain, intc1->ranges.nranges, intc1->ranges.ranges, &resolved); if (rc < 0) { - if (!fwnode_device_is_compatible(intc1->upstream->fwnode, "riscv,aplic")) { + if (!of_device_is_compatible(to_of_node(intc1->upstream->fwnode), + "riscv,aplic")) { dev_warn(intc1->dev, "Failed to resolve interrupt route for hwirq %lu in domain %s\n", data->hwirq, domain->name); -- cgit v1.2.3 From 34b7e953d19a39515f8fc6c0820ebf243ea6b026 Mon Sep 17 00:00:00 2001 From: Michael Pesa Date: Tue, 21 Jul 2026 22:02:43 -0700 Subject: irqchip/ast2700-intc: Disable all interrupt merge banks on probe The INTC0 interrupt-merge (INTM) space has 50 sources at 10 per bank, i.e. INTC0_INTM_NUM / INTM_IRQS_PER_BANK = 5 banks. This is reflected everywhere the banks are indexed: the aspeed_intc0_intm_routes[] table has 5 valid entries, and the mask/unmask/eoi paths compute the bank as (hwirq - INTM_BASE) / INTM_IRQS_PER_BANK, spanning banks 0-4. However, INTC0_INTM_BANK_NUM is hardcoded to 3, so aspeed_intc0_disable_intm() only clears IER for banks 0-2 at probe. Banks 3 and 4 are left in whatever state the firmware configured them , which can leave interrupts enabled before a handler is installed. Derive the bank count from the source count so the probe-time disable covers every bank. Fixes: 07825e41519a ("irqchip/ast2700-intc: Add AST2700-A2 support") Signed-off-by: Michael Pesa Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260722050243.298355-1-michael.pesa@icloud.com --- drivers/irqchip/irq-ast2700-intc0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-ast2700-intc0.c b/drivers/irqchip/irq-ast2700-intc0.c index c85b98a19bd4..1e375e9dffae 100644 --- a/drivers/irqchip/irq-ast2700-intc0.c +++ b/drivers/irqchip/irq-ast2700-intc0.c @@ -48,9 +48,9 @@ #define INTC0_INTMX_IER 0x1b00 #define INTC0_INTMX_ISR 0x1b04 #define INTC0_INTMX_BANK_SIZE 0x10 -#define INTC0_INTM_BANK_NUM 3 #define INTC0_IRQS_PER_BANK 32 #define INTM_IRQS_PER_BANK 10 +#define INTC0_INTM_BANK_NUM (INTC0_INTM_NUM / INTM_IRQS_PER_BANK) #define INTC0_SEL_BASE 0x200 #define INTC0_SEL_BANK_SIZE 0x4 #define INTC0_SEL_ROUTE_SIZE 0x100 -- cgit v1.2.3 From 3dfc0ab5fefd052c6028c4632b1fad8bdaf7967e Mon Sep 17 00:00:00 2001 From: Sascha Bischoff Date: Tue, 11 Aug 2026 15:27:00 +0000 Subject: irqchip/gic-v5: Clear per-CPU IRS data on teardown IRS affinity setup publishes an IRS pointer and IAFFID state in the per-CPU data before the remaining IRS initialization can fail. The error path then frees the IRS data without clearing that published state, leaving CPUs associated with freed memory. On initialization failure and normal IRS teardown, clear the per-CPU IRS association by removing the stale pointer to irs_data. Also invalidate the per-CPU IAFFID state for any CPUs that were tied to the IRS before it was freed. Fixes: 5cb1b6dab2de ("irqchip/gic-v5: Add GICv5 IRS/SPI support") Fixes: 35866efa52fe ("irqchip/gic-v5: Add ACPI IRS probing") Signed-off-by: Sascha Bischoff Signed-off-by: Thomas Gleixner Reviewed-by: Lorenzo Pieralisi Link: https://sashiko.dev/#/patchset/20260724104819.1296803-1-sascha.bischoff@arm.com?part=2 Link: https://patch.msgid.link/20260811152630.942023-2-sascha.bischoff@arm.com --- drivers/irqchip/irq-gic-v5-irs.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-irs.c index f3fce0b1e25d..3028a8bbbf68 100644 --- a/drivers/irqchip/irq-gic-v5-irs.c +++ b/drivers/irqchip/irq-gic-v5-irs.c @@ -651,6 +651,18 @@ static int __init gicv5_irs_of_init_affinity(struct device_node *node, return ret; } +static void __init gicv5_irs_clear_affinity(struct gicv5_irs_chip_data *irs_data) +{ + int cpu; + + for_each_possible_cpu(cpu) { + if (per_cpu(per_cpu_irs_data, cpu) == irs_data) { + per_cpu(cpu_iaffid, cpu).valid = false; + per_cpu(per_cpu_irs_data, cpu) = NULL; + } + } +} + static void irs_setup_pri_bits(u32 idr1) { switch (FIELD_GET(GICV5_IRS_IDR1_PRIORITY_BITS, idr1)) { @@ -773,6 +785,7 @@ static int __init gicv5_irs_of_init(struct device_node *node) return ret; out_iomem: + gicv5_irs_clear_affinity(irs_data); iounmap(irs_base); out_err: kfree(irs_data); @@ -787,6 +800,7 @@ void __init gicv5_irs_remove(void) gicv5_deinit_lpis(); list_for_each_entry_safe(irs_data, tmp_data, &irs_nodes, entry) { + gicv5_irs_clear_affinity(irs_data); iounmap(irs_data->irs_base); list_del(&irs_data->entry); kfree(irs_data); @@ -951,6 +965,7 @@ static int __init gic_acpi_parse_madt_irs(union acpi_subtable_headers *header, return 0; out_map: + gicv5_irs_clear_affinity(irs_data); iounmap(irs_base); out_release: release_mem_region(r->start, resource_size(r)); -- cgit v1.2.3 From ac6db0e0bee18cd4385418c752a007e1aba4ec14 Mon Sep 17 00:00:00 2001 From: Sascha Bischoff Date: Tue, 11 Aug 2026 15:27:31 +0000 Subject: irqchip/gic-v5: Synchronize CPU interface disable The write disabling the GICv5 CPU interface is only guaranteed to take effect after a context synchronization event. Without one, execution can return from gicv5_cpu_disable_interrupts() while an interrupt is still able to be taken. Add an ISB after the ICC_CR0_EL1 write to ensure interrupts are disabled before the function returns. No corresponding ISB is added when enabling the interface, as interrupt delivery is asynchronous and there is no obvious benefit to waiting for it. Fixes: 7ec80fb3f025 ("irqchip/gic-v5: Add GICv5 PPI support") Signed-off-by: Sascha Bischoff Signed-off-by: Thomas Gleixner Reviewed-by: Lorenzo Pieralisi Link: https://sashiko.dev/#/patchset/20260724104819.1296803-1-sascha.bischoff@arm.com?part=6 Link: https://patch.msgid.link/20260811152630.942023-3-sascha.bischoff@arm.com --- drivers/irqchip/irq-gic-v5.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c index 5dcf404ab4c8..ca48c8b305a8 100644 --- a/drivers/irqchip/irq-gic-v5.c +++ b/drivers/irqchip/irq-gic-v5.c @@ -983,6 +983,7 @@ static void gicv5_cpu_disable_interrupts(void) cr0 = FIELD_PREP(ICC_CR0_EL1_EN, 0); write_sysreg_s(cr0, SYS_ICC_CR0_EL1); + isb(); } static void gicv5_cpu_enable_interrupts(void) -- cgit v1.2.3 From 328affc639ce9873a7a0a3fd6b8339f19767529b Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 12 Aug 2026 11:10:29 +0200 Subject: irqchip/gic-v5: Check get_logical_index() return value in MADT IAFFID parsing In gic_acpi_parse_iaffid() a given MADT GICC entry might not correspond to a logical cpu recognized by the kernel, resulting in the cpu variable initialization to an error value. Currently, the get_logical_index() return value is not checked for failure, which might result in out-of-bounds memory corruption while trying to index a per_cpu variable array. Add a check to evaluate get_logical_index() return value. Fixes: 35866efa52fe ("irqchip/gic-v5: Add ACPI IRS probing") Signed-off-by: Lorenzo Pieralisi Signed-off-by: Thomas Gleixner Link: https://sashiko.dev/#/message/20260810104747.E5CE71F000E9%40smtp.kernel.org Link: https://patch.msgid.link/20260812-gicv5-7-2-fixes-v1-1-3743e82c69a4@kernel.org --- drivers/irqchip/irq-gic-v5-irs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-irs.c index 3028a8bbbf68..0bd9ae9ae12e 100644 --- a/drivers/irqchip/irq-gic-v5-irs.c +++ b/drivers/irqchip/irq-gic-v5-irs.c @@ -874,6 +874,8 @@ static int __init gic_acpi_parse_iaffid(union acpi_subtable_headers *header, return 0; cpu = get_logical_index(gicc->arm_mpidr); + if (cpu < 0) + return 0; if (gicc->iaffid & ~GENMASK(current_iaffid_bits - 1, 0)) { pr_warn("CPU %d iaffid 0x%x exceeds IRS iaffid bits\n", cpu, gicc->iaffid); -- cgit v1.2.3 From aa079dbf4c2598c2613a0e464efcb2c232753c51 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 12 Aug 2026 11:10:30 +0200 Subject: irqchip/gic-v5: Check for NULL LPI domain on domain teardown In gicv5_free_lpi_domain() the LPI domain being freed can be NULL. Check it and return before trying to free it if it is. Fixes: 0f0101325876 ("irqchip/gic-v5: Add GICv5 LPI/IPI support") Signed-off-by: Lorenzo Pieralisi Signed-off-by: Thomas Gleixner Link: https://sashiko.dev/#/message/20260810104747.E5CE71F000E9%40smtp.kernel.org Link: https://patch.msgid.link/20260812-gicv5-7-2-fixes-v1-2-3743e82c69a4@kernel.org --- drivers/irqchip/irq-gic-v5.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c index ca48c8b305a8..21514646a768 100644 --- a/drivers/irqchip/irq-gic-v5.c +++ b/drivers/irqchip/irq-gic-v5.c @@ -862,6 +862,9 @@ void __init gicv5_init_lpi_domain(void) void __init gicv5_free_lpi_domain(void) { + if (!gicv5_global_data.lpi_domain) + return; + irq_domain_remove(gicv5_global_data.lpi_domain); gicv5_global_data.lpi_domain = NULL; } -- cgit v1.2.3 From 79b115c2a29204cb7e836b0df0b8c466be4b2250 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 12 Aug 2026 11:10:31 +0200 Subject: irqchip/gic-v5: Disable IRSes on probe failures GICv5 driver probe failures cause IRSes initialized by the kernel to be unmapped and their data structures to be destroyed but the current driver leaves the probed IRSes enabled, whereas they should be disabled. Disable IRSes on driver probe failures so that the IRSes are brought back to their quiescent HW state. Fixes: 5cb1b6dab2de ("irqchip/gic-v5: Add GICv5 IRS/SPI support") Fixes: 35866efa52fe ("irqchip/gic-v5: Add ACPI IRS probing") Signed-off-by: Lorenzo Pieralisi Signed-off-by: Thomas Gleixner Link: https://sashiko.dev/#/message/20260810104747.E5CE71F000E9%40smtp.kernel.org Link: https://patch.msgid.link/20260812-gicv5-7-2-fixes-v1-3-3743e82c69a4@kernel.org --- drivers/irqchip/irq-gic-v5-irs.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-irs.c index 0bd9ae9ae12e..9d25ce8bfd8c 100644 --- a/drivers/irqchip/irq-gic-v5-irs.c +++ b/drivers/irqchip/irq-gic-v5-irs.c @@ -488,6 +488,12 @@ static int gicv5_irs_wait_for_idle(struct gicv5_irs_chip_data *irs_data) GICV5_IRS_CR0_IDLE, NULL); } +static void __init gicv5_irs_disable(struct gicv5_irs_chip_data *irs_data) +{ + irs_writel_relaxed(irs_data, 0, GICV5_IRS_CR0); + gicv5_irs_wait_for_idle(irs_data); +} + void gicv5_irs_syncr(void) { struct gicv5_irs_chip_data *irs_data; @@ -786,6 +792,7 @@ static int __init gicv5_irs_of_init(struct device_node *node) out_iomem: gicv5_irs_clear_affinity(irs_data); + gicv5_irs_disable(irs_data); iounmap(irs_base); out_err: kfree(irs_data); @@ -801,6 +808,7 @@ void __init gicv5_irs_remove(void) list_for_each_entry_safe(irs_data, tmp_data, &irs_nodes, entry) { gicv5_irs_clear_affinity(irs_data); + gicv5_irs_disable(irs_data); iounmap(irs_data->irs_base); list_del(&irs_data->entry); kfree(irs_data); @@ -968,6 +976,7 @@ static int __init gic_acpi_parse_madt_irs(union acpi_subtable_headers *header, out_map: gicv5_irs_clear_affinity(irs_data); + gicv5_irs_disable(irs_data); iounmap(irs_base); out_release: release_mem_region(r->start, resource_size(r)); -- cgit v1.2.3 From 183750b276c229c5253b3b11581f6cd8877b753e Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 12 Aug 2026 11:10:32 +0200 Subject: irqchip/gic-v5: Fix gicv5_init_common() error paths Current code fails to disable interrupts on gicv5_starting_cpu() failure and to set the handle_arch_irq pointer to NULL if gicv5_irs_enable() fails. Update the respective error paths to fix them. Fixes: 7ec80fb3f025 ("irqchip/gic-v5: Add GICv5 PPI support") Signed-off-by: Lorenzo Pieralisi Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260812-gicv5-7-2-fixes-v1-4-3743e82c69a4@kernel.org --- drivers/irqchip/irq-gic-v5.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c index 21514646a768..24dbbf5c5c31 100644 --- a/drivers/irqchip/irq-gic-v5.c +++ b/drivers/irqchip/irq-gic-v5.c @@ -1174,7 +1174,7 @@ static int __init gicv5_init_common(struct fwnode_handle *parent_domain) ret = gicv5_starting_cpu(smp_processor_id()); if (ret) - goto out_dom; + goto out_int; ret = set_handle_irq(gicv5_handle_irq); if (ret) @@ -1182,16 +1182,17 @@ static int __init gicv5_init_common(struct fwnode_handle *parent_domain) ret = gicv5_irs_enable(); if (ret) - goto out_int; + goto out_handle; gicv5_smp_init(); gicv5_irs_its_probe(); return 0; +out_handle: + set_handle_irq(NULL); out_int: gicv5_cpu_disable_interrupts(); -out_dom: gicv5_free_domains(); return ret; } -- cgit v1.2.3 From dc2eae1620bdb4562aa43f1c34c8427308ab4436 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 12 Aug 2026 11:10:33 +0200 Subject: irqchip/gic-v5: Release IRS iomem region on driver init failure In gicv5_irs_of_init(), an IRS is set-up using of_io_request_and_map() to request its memory region (corresponding to the configuration frame) and map the IRS configuration frame. On gicv5_irs_of_init() failure, the driver unmaps the IRS iomem region but does not release the requested memory region leaving it allocated in the iomem resource tree. Fix it by releasing the iomem region on gicv5_irs_of_init() probe failure. Likewise, on both OF and ACPI driver init failure, IRS iomem regions are requested but never released in gicv5_irs_remove(). Stash a copy of the IRS iomem region in a struct resource in struct gicv5_irs_chip_data and use it to release the requested region in gicv5_irs_remove() if the driver probe fails. Fixes: 5cb1b6dab2de ("irqchip/gic-v5: Add GICv5 IRS/SPI support") Fixes: 35866efa52fe ("irqchip/gic-v5: Add ACPI IRS probing") Signed-off-by: Lorenzo Pieralisi Signed-off-by: Thomas Gleixner Link: https://sashiko.dev/#/message/20260810104747.E5CE71F000E9%40smtp.kernel.org Link: https://patch.msgid.link/20260812-gicv5-7-2-fixes-v1-5-3743e82c69a4@kernel.org --- drivers/irqchip/irq-gic-v5-irs.c | 10 ++++++++++ include/linux/irqchip/arm-gic-v5.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-irs.c index 9d25ce8bfd8c..86da9f82a7b0 100644 --- a/drivers/irqchip/irq-gic-v5-irs.c +++ b/drivers/irqchip/irq-gic-v5-irs.c @@ -740,6 +740,7 @@ static int __init gicv5_irs_init(struct gicv5_irs_chip_data *irs_data) static int __init gicv5_irs_of_init(struct device_node *node) { struct gicv5_irs_chip_data *irs_data; + struct resource res; void __iomem *irs_base; u8 iaffid_bits; u32 idr; @@ -757,6 +758,11 @@ static int __init gicv5_irs_of_init(struct device_node *node) goto out_err; } + if (of_address_to_resource(node, ret, &res)) { + ret = -EINVAL; + goto out_err; + } + irs_base = of_io_request_and_map(node, ret, of_node_full_name(node)); if (IS_ERR(irs_base)) { pr_err("%pOF: unable to map GICv5 IRS registers\n", node); @@ -765,6 +771,7 @@ static int __init gicv5_irs_of_init(struct device_node *node) } irs_data->fwnode = of_fwnode_handle(node); + irs_data->res = res; gicv5_irs_init_bases(irs_data, irs_base, of_property_read_bool(node, "dma-noncoherent")); idr = irs_readl_relaxed(irs_data, GICV5_IRS_IDR1); @@ -794,6 +801,7 @@ out_iomem: gicv5_irs_clear_affinity(irs_data); gicv5_irs_disable(irs_data); iounmap(irs_base); + release_mem_region(res.start, resource_size(&res)); out_err: kfree(irs_data); return ret; @@ -810,6 +818,7 @@ void __init gicv5_irs_remove(void) gicv5_irs_clear_affinity(irs_data); gicv5_irs_disable(irs_data); iounmap(irs_data->irs_base); + release_mem_region(irs_data->res.start, resource_size(&irs_data->res)); list_del(&irs_data->entry); kfree(irs_data); } @@ -958,6 +967,7 @@ static int __init gic_acpi_parse_madt_irs(union acpi_subtable_headers *header, } gicv5_irs_init_bases(irs_data, irs_base, irs->flags & ACPI_MADT_IRS_NON_COHERENT); + irs_data->res = *r; gicv5_irs_acpi_init_affinity(irs->irs_id, irs_data); diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h index f78787e654f4..2c2fb39f049c 100644 --- a/include/linux/irqchip/arm-gic-v5.h +++ b/include/linux/irqchip/arm-gic-v5.h @@ -6,6 +6,7 @@ #define __LINUX_IRQCHIP_ARM_GIC_V5_H #include +#include #include #include @@ -324,6 +325,7 @@ struct gicv5_irs_chip_data { struct list_head entry; struct fwnode_handle *fwnode; void __iomem *irs_base; + struct resource res; u32 flags; u32 spi_min; u32 spi_range; -- cgit v1.2.3 From 9dfcc2187282816d42b9f8aa2b689c732ebbcc01 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 12 Aug 2026 11:10:34 +0200 Subject: irqchip/gic-v5: Use logical cpu 0 irs_data for dynamic IST allocation In set-ups with a 2-level IST, L1 table entries are created dynamically when LPIs are allocated. The L1 allocation and mapping, implemented in gicv5_irs_iste_alloc() is carried out in preemtible context and can be carried out on any IRS in the system. Current code indexes the per_cpu_irs_data per cpu array using smp_processor_id() to retrieve the IRS that is local to the core executing gicv5_irs_iste_alloc(). Since that's preemptible context, the core executing that function can change on preemption. Given that every IRS in the system is equivalent to each core, this is not really an issue in that even if the thread is preempted and resumed on a different cpu, the table allocation and mapping to an IRS would work seamlessly regardless. On the other hand, smp_processor_id() spits a legitimate splat on DEBUG_PREEMPT kernels when used in preemtible context and this should be fixed. Given that all IRSes are equivalent from a core perspective in terms of IST initialization, always choose as a policy the IRS local to logical cpu 0, preventing the smp_processor_id() splat. Fixes: 0f0101325876 ("irqchip/gic-v5: Add GICv5 LPI/IPI support") Signed-off-by: Lorenzo Pieralisi Signed-off-by: Thomas Gleixner Link: https://sashiko.dev/#/message/20260810104747.E5CE71F000E9%40smtp.kernel.org Link: https://patch.msgid.link/20260812-gicv5-7-2-fixes-v1-6-3743e82c69a4@kernel.org --- drivers/irqchip/irq-gic-v5-irs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-v5-irs.c b/drivers/irqchip/irq-gic-v5-irs.c index 86da9f82a7b0..b3feb6340b59 100644 --- a/drivers/irqchip/irq-gic-v5-irs.c +++ b/drivers/irqchip/irq-gic-v5-irs.c @@ -199,7 +199,7 @@ int gicv5_irs_iste_alloc(const u32 lpi) if (!gicv5_global_data.ist.l2) return 0; - irs_data = per_cpu(per_cpu_irs_data, smp_processor_id()); + irs_data = per_cpu(per_cpu_irs_data, 0); if (!irs_data) return -ENOENT; -- cgit v1.2.3 From a1ee1a1ca75b674f503c74eb8b3ca77612ba3c0c Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Wed, 12 Aug 2026 11:10:35 +0200 Subject: irqchip/gic-v5: Defer default SPI and LPI IAFFID programming SPI and LPI interrupts do not have an architected default value for their IAFFID (interrupt affinity ID) - the property that determines an IRQ affinity. Current code awkwardly tries to set a default IAFFID value corresponding to the logical cpu executing the gicv5_hwirq_init() function at SPI/LPI allocation time. There are two issues with this approach: - gicv5_hwirq_init() is called in preemptible context and current code uses smp_processor_id() to check the logical cpu executing the function. Whilst that's harmless, it can spit a splat on DEBUG_PREEMPT kernels - Setting the default SPI/LPI IAFFID to the one belonging to the cpu executing the IRQ allocation is a completely arbitrary choice It is saner to remove the SPI/LPI IAFFID set-up in the SPI/LPI domain IRQ allocation code and flag SPI/LPI irqchips as IRQCHIP_AFFINITY_PRE_STARTUP so that the SPI/LPI affinity is initialized by IRQ core to a sane value before an IRQ is started up using the respective irq_chip irq_set_affinity() callback. Fixes: 5cb1b6dab2de ("irqchip/gic-v5: Add GICv5 IRS/SPI support") Fixes: 0f0101325876 ("irqchip/gic-v5: Add GICv5 LPI/IPI support") Signed-off-by: Lorenzo Pieralisi Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20260812-gicv5-7-2-fixes-v1-7-3743e82c69a4@kernel.org --- drivers/irqchip/irq-gic-v5.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c index 24dbbf5c5c31..ac2d423b1723 100644 --- a/drivers/irqchip/irq-gic-v5.c +++ b/drivers/irqchip/irq-gic-v5.c @@ -87,25 +87,13 @@ static void gicv5_ppi_priority_init(void) static void gicv5_hwirq_init(irq_hw_number_t hwirq, u8 priority, u8 hwirq_type) { - u64 cdpri, cdaff; - u16 iaffid; - int ret; + u64 cdpri; if (hwirq_type == GICV5_HWIRQ_TYPE_LPI || hwirq_type == GICV5_HWIRQ_TYPE_SPI) { cdpri = FIELD_PREP(GICV5_GIC_CDPRI_PRIORITY_MASK, priority) | FIELD_PREP(GICV5_GIC_CDPRI_TYPE_MASK, hwirq_type) | FIELD_PREP(GICV5_GIC_CDPRI_ID_MASK, hwirq); gic_insn(cdpri, CDPRI); - - ret = gicv5_irs_cpu_to_iaffid(smp_processor_id(), &iaffid); - - if (WARN_ON_ONCE(ret)) - return; - - cdaff = FIELD_PREP(GICV5_GIC_CDAFF_IAFFID_MASK, iaffid) | - FIELD_PREP(GICV5_GIC_CDAFF_TYPE_MASK, hwirq_type) | - FIELD_PREP(GICV5_GIC_CDAFF_ID_MASK, hwirq); - gic_insn(cdaff, CDAFF); } } @@ -548,6 +536,7 @@ static const struct irq_chip gicv5_spi_irq_chip = { .irq_get_irqchip_state = gicv5_spi_irq_get_irqchip_state, .irq_set_irqchip_state = gicv5_spi_irq_set_irqchip_state, .flags = IRQCHIP_SET_TYPE_MASKED | + IRQCHIP_AFFINITY_PRE_STARTUP | IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, }; @@ -561,7 +550,8 @@ static const struct irq_chip gicv5_lpi_irq_chip = { .irq_retrigger = gicv5_lpi_irq_retrigger, .irq_get_irqchip_state = gicv5_lpi_irq_get_irqchip_state, .irq_set_irqchip_state = gicv5_lpi_irq_set_irqchip_state, - .flags = IRQCHIP_SKIP_SET_WAKE | + .flags = IRQCHIP_AFFINITY_PRE_STARTUP | + IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, }; -- cgit v1.2.3 From 58b34b72b64bfbfc5f8ad4d8f229942aff76597e Mon Sep 17 00:00:00 2001 From: Rustam Adilov Date: Thu, 20 Aug 2026 21:20:17 +0500 Subject: irqchip/irq-realtek-rtl: Use readl_be()/writel_be() instead of readl()/writel() When CONFIG_SWAP_IO_SPACE is enabled, readl() performs a swap from little endian device to big endian CPU and vice versa for writel(). This is incorrect for Realtek Interrupt controller as that is a big endian device and so the LE to BE conversions are unwanted. Fix this by converting the MMIO accesses to readl_be() and writel_be(). Fixes: 9f3a0f34b84a ("irqchip: Add support for Realtek RTL838x/RTL839x interrupt controller") Signed-off-by: Rustam Adilov Signed-off-by: Thomas Gleixner Tested-by: Carlo Szelinsky Link: https://patch.msgid.link/20260820162017.28507-1-adilov@disroot.org --- drivers/irqchip/irq-realtek-rtl.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/irqchip/irq-realtek-rtl.c b/drivers/irqchip/irq-realtek-rtl.c index c8becb458da2..26e52c3f8c68 100644 --- a/drivers/irqchip/irq-realtek-rtl.c +++ b/drivers/irqchip/irq-realtek-rtl.c @@ -1,5 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Realtek Interrupt controller. + * + * The Realtek Interrupt controller is a big endian device found in the + * Realtek MIPS SoCs. + * * Copyright (C) 2020 Birger Koblitz * Copyright (C) 2020 Bert Vermeulen * Copyright (C) 2020 John Crispin @@ -50,18 +55,18 @@ static inline void enable_gimr(unsigned int cpu, unsigned int hw_irq) { u32 gimr; - gimr = readl(REG(cpu, RTL_ICTL_GIMR)); + gimr = readl_be(REG(cpu, RTL_ICTL_GIMR)); gimr |= BIT(hw_irq); - writel(gimr, REG(cpu, RTL_ICTL_GIMR)); + writel_be(gimr, REG(cpu, RTL_ICTL_GIMR)); } static inline void disable_gimr(unsigned int cpu, unsigned int hw_irq) { u32 gimr; - gimr = readl(REG(cpu, RTL_ICTL_GIMR)); + gimr = readl_be(REG(cpu, RTL_ICTL_GIMR)); gimr &= ~BIT(hw_irq); - writel(gimr, REG(cpu, RTL_ICTL_GIMR)); + writel_be(gimr, REG(cpu, RTL_ICTL_GIMR)); } static void write_irr(unsigned int cpu, int hw_irq, u32 value) @@ -71,9 +76,9 @@ static void write_irr(unsigned int cpu, int hw_irq, u32 value) unsigned int shift = IRR_SHIFT(hw_irq); u32 irr; - irr = readl(irr0 + offset) & ~(0xf << shift); + irr = readl_be(irr0 + offset) & ~(0xf << shift); irr |= (value & 0xf) << shift; - writel(irr, irr0 + offset); + writel_be(irr, irr0 + offset); } static void realtek_ictl_unmask_irq(struct irq_data *i) @@ -159,7 +164,8 @@ static void realtek_irq_dispatch(struct irq_desc *desc) unsigned int hw_irq; chained_irq_enter(chip, desc); - pending = readl(REG(cpu, RTL_ICTL_GIMR)) & readl(REG(cpu, RTL_ICTL_GISR)) & output->mask; + pending = readl_be(REG(cpu, RTL_ICTL_GIMR)) & + readl_be(REG(cpu, RTL_ICTL_GISR)) & output->mask; if (unlikely(!pending)) { spurious_interrupt(); -- cgit v1.2.3