From 93174c05dd2e9b02eb6b5c93dd9109087ae4ffcf Mon Sep 17 00:00:00 2001 From: "Jiri Slaby (SUSE)" Date: Wed, 11 Jun 2025 12:43:38 +0200 Subject: [PATCH 01/28] irqchip: Use dev_fwnode() irq_domain_create_simple() takes a fwnode as the first argument. It can be extracted from struct device using the dev_fwnode() helper instead of using of_node with of_fwnode_handle(). So use the dev_fwnode() helper. Signed-off-by: Jiri Slaby (SUSE) Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/20250611104348.192092-10-jirislaby@kernel.org --- drivers/irqchip/irq-imgpdc.c | 4 ++-- drivers/irqchip/irq-imx-irqsteer.c | 4 ++-- drivers/irqchip/irq-keystone.c | 4 ++-- drivers/irqchip/irq-mvebu-pic.c | 2 +- drivers/irqchip/irq-pruss-intc.c | 2 +- drivers/irqchip/irq-renesas-intc-irqpin.c | 6 ++---- drivers/irqchip/irq-renesas-irqc.c | 2 +- drivers/irqchip/irq-renesas-rza1.c | 5 ++--- drivers/irqchip/irq-renesas-rzg2l.c | 5 ++--- drivers/irqchip/irq-renesas-rzv2h.c | 2 +- drivers/irqchip/irq-stm32mp-exti.c | 4 +--- drivers/irqchip/irq-ti-sci-inta.c | 3 +-- drivers/irqchip/irq-ti-sci-intr.c | 3 +-- drivers/irqchip/irq-ts4800.c | 2 +- 14 files changed, 20 insertions(+), 28 deletions(-) diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c index f0410d5d7315..e9ef2f5a7207 100644 --- a/drivers/irqchip/irq-imgpdc.c +++ b/drivers/irqchip/irq-imgpdc.c @@ -372,8 +372,8 @@ static int pdc_intc_probe(struct platform_device *pdev) priv->syswake_irq = irq; /* Set up an IRQ domain */ - priv->domain = irq_domain_create_linear(of_fwnode_handle(node), 16, &irq_generic_chip_ops, - priv); + priv->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), 16, &irq_generic_chip_ops, + priv); if (unlikely(!priv->domain)) { dev_err(&pdev->dev, "cannot add IRQ domain\n"); return -ENOMEM; diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c index 6dc9ac48fee5..4682ce5bf8d3 100644 --- a/drivers/irqchip/irq-imx-irqsteer.c +++ b/drivers/irqchip/irq-imx-irqsteer.c @@ -212,8 +212,8 @@ static int imx_irqsteer_probe(struct platform_device *pdev) /* steer all IRQs into configured channel */ writel_relaxed(BIT(data->channel), data->regs + CHANCTRL); - data->domain = irq_domain_create_linear(of_fwnode_handle(np), data->reg_num * 32, - &imx_irqsteer_domain_ops, data); + data->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), data->reg_num * 32, + &imx_irqsteer_domain_ops, data); if (!data->domain) { dev_err(&pdev->dev, "failed to create IRQ domain\n"); ret = -ENOMEM; diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index c9e902b7bf48..922fff09354f 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -157,8 +157,8 @@ static int keystone_irq_probe(struct platform_device *pdev) kirq->chip.irq_mask = keystone_irq_setmask; kirq->chip.irq_unmask = keystone_irq_unmask; - kirq->irqd = irq_domain_create_linear(of_fwnode_handle(np), KEYSTONE_N_IRQ, - &keystone_irq_ops, kirq); + kirq->irqd = irq_domain_create_linear(dev_fwnode(dev), KEYSTONE_N_IRQ, &keystone_irq_ops, + kirq); if (!kirq->irqd) { dev_err(dev, "IRQ domain registration failed\n"); return -ENODEV; diff --git a/drivers/irqchip/irq-mvebu-pic.c b/drivers/irqchip/irq-mvebu-pic.c index 8db638aa21d2..cd8b73482b9f 100644 --- a/drivers/irqchip/irq-mvebu-pic.c +++ b/drivers/irqchip/irq-mvebu-pic.c @@ -150,7 +150,7 @@ static int mvebu_pic_probe(struct platform_device *pdev) return -EINVAL; } - pic->domain = irq_domain_create_linear(of_fwnode_handle(node), PIC_MAX_IRQS, + pic->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), PIC_MAX_IRQS, &mvebu_pic_domain_ops, pic); if (!pic->domain) { dev_err(&pdev->dev, "Failed to allocate irq domain\n"); diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c index 87a5813fd835..81078d56f38d 100644 --- a/drivers/irqchip/irq-pruss-intc.c +++ b/drivers/irqchip/irq-pruss-intc.c @@ -555,7 +555,7 @@ static int pruss_intc_probe(struct platform_device *pdev) mutex_init(&intc->lock); - intc->domain = irq_domain_create_linear(of_fwnode_handle(dev->of_node), max_system_events, + intc->domain = irq_domain_create_linear(dev_fwnode(dev), max_system_events, &pruss_intc_irq_domain_ops, intc); if (!intc->domain) return -ENOMEM; diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c index 0959ed43b1a9..117b74b635ea 100644 --- a/drivers/irqchip/irq-renesas-intc-irqpin.c +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c @@ -513,10 +513,8 @@ static int intc_irqpin_probe(struct platform_device *pdev) irq_chip->irq_set_wake = intc_irqpin_irq_set_wake; irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND; - p->irq_domain = irq_domain_create_simple(of_fwnode_handle(dev->of_node), - nirqs, 0, - &intc_irqpin_irq_domain_ops, - p); + p->irq_domain = irq_domain_create_simple(dev_fwnode(dev), nirqs, 0, + &intc_irqpin_irq_domain_ops, p); if (!p->irq_domain) { ret = -ENXIO; dev_err(dev, "cannot initialize irq domain\n"); diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 5c3196e5a437..b46bbb66c264 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -168,7 +168,7 @@ static int irqc_probe(struct platform_device *pdev) p->cpu_int_base = p->iomem + IRQC_INT_CPU_BASE(0); /* SYS-SPI */ - p->irq_domain = irq_domain_create_linear(of_fwnode_handle(dev->of_node), p->number_of_irqs, + p->irq_domain = irq_domain_create_linear(dev_fwnode(dev), p->number_of_irqs, &irq_generic_chip_ops, p); if (!p->irq_domain) { ret = -ENXIO; diff --git a/drivers/irqchip/irq-renesas-rza1.c b/drivers/irqchip/irq-renesas-rza1.c index 0a9640ba0adb..a697eb55ac90 100644 --- a/drivers/irqchip/irq-renesas-rza1.c +++ b/drivers/irqchip/irq-renesas-rza1.c @@ -231,9 +231,8 @@ static int rza1_irqc_probe(struct platform_device *pdev) priv->chip.irq_set_type = rza1_irqc_set_type; priv->chip.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE; - priv->irq_domain = irq_domain_create_hierarchy(parent, 0, IRQC_NUM_IRQ, - of_fwnode_handle(np), &rza1_irqc_domain_ops, - priv); + priv->irq_domain = irq_domain_create_hierarchy(parent, 0, IRQC_NUM_IRQ, dev_fwnode(dev), + &rza1_irqc_domain_ops, priv); if (!priv->irq_domain) { dev_err(dev, "cannot initialize irq domain\n"); ret = -ENOMEM; diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c index 1e861bd64f97..360d88687e4f 100644 --- a/drivers/irqchip/irq-renesas-rzg2l.c +++ b/drivers/irqchip/irq-renesas-rzg2l.c @@ -574,9 +574,8 @@ static int rzg2l_irqc_common_init(struct device_node *node, struct device_node * raw_spin_lock_init(&rzg2l_irqc_data->lock); - irq_domain = irq_domain_create_hierarchy(parent_domain, 0, IRQC_NUM_IRQ, - of_fwnode_handle(node), &rzg2l_irqc_domain_ops, - rzg2l_irqc_data); + irq_domain = irq_domain_create_hierarchy(parent_domain, 0, IRQC_NUM_IRQ, dev_fwnode(dev), + &rzg2l_irqc_domain_ops, rzg2l_irqc_data); if (!irq_domain) { pm_runtime_put(dev); return dev_err_probe(dev, -ENOMEM, "failed to add irq domain\n"); diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c index 69b32c19e8ff..57c5a3c008c9 100644 --- a/drivers/irqchip/irq-renesas-rzv2h.c +++ b/drivers/irqchip/irq-renesas-rzv2h.c @@ -558,7 +558,7 @@ static int rzv2h_icu_init_common(struct device_node *node, struct device_node *p raw_spin_lock_init(&rzv2h_icu_data->lock); irq_domain = irq_domain_create_hierarchy(parent_domain, 0, ICU_NUM_IRQ, - of_fwnode_handle(node), &rzv2h_icu_domain_ops, + dev_fwnode(&pdev->dev), &rzv2h_icu_domain_ops, rzv2h_icu_data); if (!irq_domain) { dev_err(&pdev->dev, "failed to add irq domain\n"); diff --git a/drivers/irqchip/irq-stm32mp-exti.c b/drivers/irqchip/irq-stm32mp-exti.c index c6b4407d05f9..a24f4f1a4f8f 100644 --- a/drivers/irqchip/irq-stm32mp-exti.c +++ b/drivers/irqchip/irq-stm32mp-exti.c @@ -683,9 +683,7 @@ static int stm32mp_exti_probe(struct platform_device *pdev) } domain = irq_domain_create_hierarchy(parent_domain, 0, drv_data->bank_nr * IRQS_PER_BANK, - of_fwnode_handle(np), &stm32mp_exti_domain_ops, - host_data); - + dev_fwnode(dev), &stm32mp_exti_domain_ops, host_data); if (!domain) { dev_err(dev, "Could not register exti domain\n"); return -ENOMEM; diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c index 7de59238e6b0..01963d36cfaf 100644 --- a/drivers/irqchip/irq-ti-sci-inta.c +++ b/drivers/irqchip/irq-ti-sci-inta.c @@ -701,8 +701,7 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev) if (ret) return ret; - domain = irq_domain_create_linear(of_fwnode_handle(dev_of_node(dev)), - ti_sci_get_num_resources(inta->vint), + domain = irq_domain_create_linear(dev_fwnode(dev), ti_sci_get_num_resources(inta->vint), &ti_sci_inta_irq_domain_ops, inta); if (!domain) { dev_err(dev, "Failed to allocate IRQ domain\n"); diff --git a/drivers/irqchip/irq-ti-sci-intr.c b/drivers/irqchip/irq-ti-sci-intr.c index 07fff5ae5ce0..354613e74ad0 100644 --- a/drivers/irqchip/irq-ti-sci-intr.c +++ b/drivers/irqchip/irq-ti-sci-intr.c @@ -274,8 +274,7 @@ static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev) return PTR_ERR(intr->out_irqs); } - domain = irq_domain_create_hierarchy(parent_domain, 0, 0, - of_fwnode_handle(dev_of_node(dev)), + domain = irq_domain_create_hierarchy(parent_domain, 0, 0, dev_fwnode(dev), &ti_sci_intr_irq_domain_ops, intr); if (!domain) { dev_err(dev, "Failed to allocate IRQ domain\n"); diff --git a/drivers/irqchip/irq-ts4800.c b/drivers/irqchip/irq-ts4800.c index e625f4fb2bb8..1e236d5b7516 100644 --- a/drivers/irqchip/irq-ts4800.c +++ b/drivers/irqchip/irq-ts4800.c @@ -125,7 +125,7 @@ static int ts4800_ic_probe(struct platform_device *pdev) return -EINVAL; } - data->domain = irq_domain_create_linear(of_fwnode_handle(node), 8, &ts4800_ic_ops, data); + data->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev), 8, &ts4800_ic_ops, data); if (!data->domain) { dev_err(&pdev->dev, "cannot add IRQ domain\n"); return -ENOMEM; From 2250db8628a0d8293ad2e0671138b848a185fba1 Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Sat, 21 Jun 2025 01:49:51 -0400 Subject: [PATCH 02/28] irqchip/mips-gic: Allow forced affinity Devices of the Realtek MIPS Otto platform use the official rtl-otto-timer as clock event generator and CPU clocksource. It is registered for each CPU startup via cpuhp_setup_state() and forces the affinity of the clockevent interrupts to the appropriate CPU via irq_force_affinity(). On the "smaller" devices with a vendor specific interrupt controller (supported by irq-realtek-rtl) the registration works fine. The "larger" RTL931x series is based on a MIPS interAptiv dual core with a MIPS GIC controller. Interrupt routing setup is cancelled because gic_set_affinity() does not accept the current (not yet online) CPU as a target. Relax the checks by evaluating the force parameter that is provided for exactly this purpose like in other drivers. With this the affinity can be set as follows: - force = false: allow to set affinity to any online cpu - force = true: allow to set affinity to any cpu Co-developed-by: Sebastian Gottschall Signed-off-by: Sebastian Gottschall Signed-off-by: Markus Stockhausen Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/20250621054952.380374-1-markus.stockhausen@gmx.de --- drivers/irqchip/irq-mips-gic.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 34e8d09c12a0..19a57c5e2b2e 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -375,9 +375,13 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, /* * The GIC specifies that we can only route an interrupt to one VP(E), * ie. CPU in Linux parlance, at a time. Therefore we always route to - * the first online CPU in the mask. + * the first forced or online CPU in the mask. */ - cpu = cpumask_first_and(cpumask, cpu_online_mask); + if (force) + cpu = cpumask_first(cpumask); + else + cpu = cpumask_first_and(cpumask, cpu_online_mask); + if (cpu >= NR_CPUS) return -EINVAL; From 5fe331cdcfba5b2c2dd8211127dadefcaaa97dec Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 12 Jun 2025 17:39:05 +0300 Subject: [PATCH 03/28] riscv: Helper to parse hart index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RISC-V APLIC specification defines "hart index" in [1]. Similar definitions can be found for ACLINT in [2] Quote from the APLIC specification: Within a given interrupt domain, each of the domain’s harts has a unique index number in the range 0 to 2^14 − 1 (= 16,383). The index number a domain associates with a hart may or may not have any relationship to the unique hart identifier (“hart ID”) that the RISC-V Privileged Architecture assigns to the hart. Two different interrupt domains may employ entirely different index numbers for the same set of harts. Further, it says in "4.5 Memory-mapped control region for an interrupt domain": The array of IDC structures may include some for potential hart index numbers that are not actual hart index numbers in the domain. For example, the first IDC structure is always for hart index 0, but 0 is not necessarily a valid index number for any hart in the domain. Support arbitrary hart indices specified in an optional property "riscv,hart-indexes" which is specified as an array of u32 elements, one per interrupt target, listing hart indexes in the same order as in "interrupts-extended". If this property is not specified, fall back to use logical hart indices within the domain. Signed-off-by: Vladimir Kondratiev Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/20250612143911.3224046-2-vladimir.kondratiev@mobileye.com Link: https://github.com/riscv/riscv-aia [1] Link: https://github.com/riscvarchive/riscv-aclint [2] --- arch/riscv/include/asm/irq.h | 2 ++ arch/riscv/kernel/irq.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/arch/riscv/include/asm/irq.h b/arch/riscv/include/asm/irq.h index 7b038f3b7cb0..59c975f750c9 100644 --- a/arch/riscv/include/asm/irq.h +++ b/arch/riscv/include/asm/irq.h @@ -22,6 +22,8 @@ void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu); void riscv_set_intc_hwnode_fn(struct fwnode_handle *(*fn)(void)); struct fwnode_handle *riscv_get_intc_hwnode(void); +int riscv_get_hart_index(struct fwnode_handle *fwnode, u32 logical_index, + u32 *hart_index); #ifdef CONFIG_ACPI diff --git a/arch/riscv/kernel/irq.c b/arch/riscv/kernel/irq.c index 9ceda02507ca..b6af20bc300f 100644 --- a/arch/riscv/kernel/irq.c +++ b/arch/riscv/kernel/irq.c @@ -32,6 +32,40 @@ struct fwnode_handle *riscv_get_intc_hwnode(void) } EXPORT_SYMBOL_GPL(riscv_get_intc_hwnode); +/** + * riscv_get_hart_index() - get hart index for interrupt delivery + * @fwnode: interrupt controller node + * @logical_index: index within the "interrupts-extended" property + * @hart_index: filled with the hart index to use + * + * RISC-V uses term "hart index" for its interrupt controllers, for the + * purpose of the interrupt routing to destination harts. + * It may be arbitrary numbers assigned to each destination hart in context + * of the particular interrupt domain. + * + * These numbers encoded in the optional property "riscv,hart-indexes" + * that should contain hart index for each interrupt destination in the same + * order as in the "interrupts-extended" property. If this property + * not exist, it assumed equal to the logical index, i.e. index within the + * "interrupts-extended" property. + * + * Return: error code + */ +int riscv_get_hart_index(struct fwnode_handle *fwnode, u32 logical_index, + u32 *hart_index) +{ + static const char *prop_hart_index = "riscv,hart-indexes"; + struct device_node *np = to_of_node(fwnode); + + if (!np || !of_property_present(np, prop_hart_index)) { + *hart_index = logical_index; + return 0; + } + + return of_property_read_u32_index(np, prop_hart_index, + logical_index, hart_index); +} + #ifdef CONFIG_IRQ_STACKS #include From 81f335e10605beda222d51d348a1ac058d4bac61 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 12 Jun 2025 17:39:06 +0300 Subject: [PATCH 04/28] irqchip/riscv-aplic: Use riscv_get_hart_index() Use the global helper function instead of the local implementation. Signed-off-by: Vladimir Kondratiev Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/20250612143911.3224046-3-vladimir.kondratiev@mobileye.com --- drivers/irqchip/irq-riscv-aplic-direct.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/irqchip/irq-riscv-aplic-direct.c b/drivers/irqchip/irq-riscv-aplic-direct.c index 205ad61d15e4..c2a75bf3d20c 100644 --- a/drivers/irqchip/irq-riscv-aplic-direct.c +++ b/drivers/irqchip/irq-riscv-aplic-direct.c @@ -219,20 +219,6 @@ static int aplic_direct_parse_parent_hwirq(struct device *dev, u32 index, return 0; } -static int aplic_direct_get_hart_index(struct device *dev, u32 logical_index, - u32 *hart_index) -{ - const char *prop_hart_index = "riscv,hart-indexes"; - struct device_node *np = to_of_node(dev->fwnode); - - if (!np || !of_property_present(np, prop_hart_index)) { - *hart_index = logical_index; - return 0; - } - - return of_property_read_u32_index(np, prop_hart_index, logical_index, hart_index); -} - int aplic_direct_setup(struct device *dev, void __iomem *regs) { int i, j, rc, cpu, current_cpu, setup_count = 0; @@ -279,7 +265,7 @@ int aplic_direct_setup(struct device *dev, void __iomem *regs) cpumask_set_cpu(cpu, &direct->lmask); idc = per_cpu_ptr(&aplic_idcs, cpu); - rc = aplic_direct_get_hart_index(dev, i, &idc->hart_index); + rc = riscv_get_hart_index(dev->fwnode, i, &idc->hart_index); if (rc) { dev_warn(dev, "hart index not found for IDC%d\n", i); continue; From ed651979bb780270ae14b35ca6bae68f658eddad Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 12 Jun 2025 17:39:07 +0300 Subject: [PATCH 05/28] dt-bindings: interrupt-controller: Add MIPS P8700 aclint-sswi Add ACLINT-SSWI variant for the MIPS P8700 SoC. This CPU has a SSWI device compliant with the RISC-V draft spec (see [1]). CPU indexes on this platform are not continuous, instead it uses bit-fields to encode hart,core,cluster numbers, thus the DT property "riscv,hart-indexes" is mandatory for it. Signed-off-by: Vladimir Kondratiev Signed-off-by: Thomas Gleixner Acked-by: Conor Dooley Link: https://lore.kernel.org/all/20250612143911.3224046-4-vladimir.kondratiev@mobileye.com Link: https://github.com/riscvarchive/riscv-aclint [1] --- .../thead,c900-aclint-sswi.yaml | 64 ++++++++++++++++--- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-sswi.yaml b/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-sswi.yaml index 8d330906bbbd..c1ab865fcd64 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-sswi.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-sswi.yaml @@ -4,23 +4,32 @@ $id: http://devicetree.org/schemas/interrupt-controller/thead,c900-aclint-sswi.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: T-HEAD C900 ACLINT Supervisor-level Software Interrupt Device +title: ACLINT Supervisor-level Software Interrupt Device maintainers: - Inochi Amaoto description: - The SSWI device is a part of the THEAD ACLINT device. It provides - supervisor-level IPI functionality for a set of HARTs on a THEAD - platform. It provides a register to set an IPI (SETSSIP) for each - HART connected to the SSWI device. + The SSWI device is a part of the ACLINT device. It provides + supervisor-level IPI functionality for a set of HARTs on a supported + platforms. It provides a register to set an IPI (SETSSIP) for each + HART connected to the SSWI device. See draft specification + https://github.com/riscvarchive/riscv-aclint + + Following variants of the SSWI ACLINT supported, using dedicated + compatible string + - THEAD C900 + - MIPS P8700 properties: compatible: - items: - - enum: - - sophgo,sg2044-aclint-sswi - - const: thead,c900-aclint-sswi + oneOf: + - items: + - enum: + - sophgo,sg2044-aclint-sswi + - const: thead,c900-aclint-sswi + - items: + - const: mips,p8700-aclint-sswi reg: maxItems: 1 @@ -34,6 +43,14 @@ properties: minItems: 1 maxItems: 4095 + riscv,hart-indexes: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 4095 + description: + A list of hart indexes that APLIC should use to address each hart + that is mentioned in the "interrupts-extended" + additionalProperties: false required: @@ -43,8 +60,22 @@ required: - interrupt-controller - interrupts-extended +allOf: + - if: + properties: + compatible: + contains: + const: mips,p8700-aclint-sswi + then: + required: + - riscv,hart-indexes + else: + properties: + riscv,hart-indexes: false + examples: - | + //Example 1 interrupt-controller@94000000 { compatible = "sophgo,sg2044-aclint-sswi", "thead,c900-aclint-sswi"; reg = <0x94000000 0x00004000>; @@ -55,4 +86,19 @@ examples: <&cpu3intc 1>, <&cpu4intc 1>; }; + + - | + //Example 2 + interrupt-controller@94000000 { + compatible = "mips,p8700-aclint-sswi"; + reg = <0x94000000 0x00004000>; + #interrupt-cells = <0>; + interrupt-controller; + interrupts-extended = <&cpu1intc 1>, + <&cpu2intc 1>, + <&cpu3intc 1>, + <&cpu4intc 1>; + riscv,hart-indexes = <0x0 0x1 0x10 0x11>; + }; + ... From df0f030ee7e444c55341f4210124115878284125 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 12 Jun 2025 17:39:08 +0300 Subject: [PATCH 06/28] irqchip/thead-c900-aclint-sswi: Generalize aclint-sswi driver and add MIPS P800 support Refactor the Thead specific implementation of the ACLINT-SSWI irqchip: - Rename the source file and related details to reflect the generic nature of the driver - Factor out the generic code that serves both Thead and MIPS variants. This generic part is compliant with the RISC-V draft spec [1] - Provide generic and Thead specific initialization functions Signed-off-by: Vladimir Kondratiev Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/20250612143911.3224046-5-vladimir.kondratiev@mobileye.com Link: https://github.com/riscvarchive/riscv-aclint [1] --- drivers/irqchip/Kconfig | 15 +++- drivers/irqchip/Makefile | 2 +- ...d-c900-aclint-sswi.c => irq-aclint-sswi.c} | 90 +++++++++++++------ include/linux/cpuhotplug.h | 2 +- 4 files changed, 74 insertions(+), 35 deletions(-) rename drivers/irqchip/{irq-thead-c900-aclint-sswi.c => irq-aclint-sswi.c} (68%) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 0d196e447142..39f6f421fc75 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -634,18 +634,25 @@ config STARFIVE_JH8100_INTC If you don't know what to do here, say Y. -config THEAD_C900_ACLINT_SSWI - bool "THEAD C9XX ACLINT S-mode IPI Interrupt Controller" +config ACLINT_SSWI + bool "RISC-V ACLINT S-mode IPI Interrupt Controller" depends on RISCV depends on SMP select IRQ_DOMAIN_HIERARCHY select GENERIC_IRQ_IPI_MUX help - This enables support for T-HEAD specific ACLINT SSWI device - support. + This enables support for variants of the RISC-V ACLINT-SSWI device. + Supported variants are: + - T-HEAD, with compatible "thead,c900-aclint-sswi" + - MIPS P8700, with compatible "mips,p8700-aclint-sswi" If you don't know what to do here, say Y. +# Backwards compatibility so oldconfig does not drop it. +config THEAD_C900_ACLINT_SSWI + bool + select ACLINT_SSWI + config EXYNOS_IRQ_COMBINER bool "Samsung Exynos IRQ combiner support" if COMPILE_TEST depends on (ARCH_EXYNOS && ARM) || COMPILE_TEST diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 23ca4959e6ce..0458d6c5d161 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -105,7 +105,7 @@ obj-$(CONFIG_RISCV_APLIC_MSI) += irq-riscv-aplic-msi.o obj-$(CONFIG_RISCV_IMSIC) += irq-riscv-imsic-state.o irq-riscv-imsic-early.o irq-riscv-imsic-platform.o obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o obj-$(CONFIG_STARFIVE_JH8100_INTC) += irq-starfive-jh8100-intc.o -obj-$(CONFIG_THEAD_C900_ACLINT_SSWI) += irq-thead-c900-aclint-sswi.o +obj-$(CONFIG_ACLINT_SSWI) += irq-aclint-sswi.o obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o obj-$(CONFIG_IMX_INTMUX) += irq-imx-intmux.o obj-$(CONFIG_IMX_MU_MSI) += irq-imx-mu-msi.o diff --git a/drivers/irqchip/irq-thead-c900-aclint-sswi.c b/drivers/irqchip/irq-aclint-sswi.c similarity index 68% rename from drivers/irqchip/irq-thead-c900-aclint-sswi.c rename to drivers/irqchip/irq-aclint-sswi.c index 8ff6e7a1363b..0131194d4847 100644 --- a/drivers/irqchip/irq-thead-c900-aclint-sswi.c +++ b/drivers/irqchip/irq-aclint-sswi.c @@ -3,7 +3,8 @@ * Copyright (C) 2024 Inochi Amaoto */ -#define pr_fmt(fmt) "thead-c900-aclint-sswi: " fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -21,56 +22,50 @@ #include #include -#define THEAD_ACLINT_xSWI_REGISTER_SIZE 4 - -#define THEAD_C9XX_CSR_SXSTATUS 0x5c0 -#define THEAD_C9XX_SXSTATUS_CLINTEE BIT(17) - static int sswi_ipi_virq __ro_after_init; static DEFINE_PER_CPU(void __iomem *, sswi_cpu_regs); -static void thead_aclint_sswi_ipi_send(unsigned int cpu) +static void aclint_sswi_ipi_send(unsigned int cpu) { writel(0x1, per_cpu(sswi_cpu_regs, cpu)); } -static void thead_aclint_sswi_ipi_clear(void) +static void aclint_sswi_ipi_clear(void) { writel_relaxed(0x0, this_cpu_read(sswi_cpu_regs)); } -static void thead_aclint_sswi_ipi_handle(struct irq_desc *desc) +static void aclint_sswi_ipi_handle(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); csr_clear(CSR_IP, IE_SIE); - thead_aclint_sswi_ipi_clear(); + aclint_sswi_ipi_clear(); ipi_mux_process(); chained_irq_exit(chip, desc); } -static int thead_aclint_sswi_starting_cpu(unsigned int cpu) +static int aclint_sswi_starting_cpu(unsigned int cpu) { enable_percpu_irq(sswi_ipi_virq, irq_get_trigger_type(sswi_ipi_virq)); return 0; } -static int thead_aclint_sswi_dying_cpu(unsigned int cpu) +static int aclint_sswi_dying_cpu(unsigned int cpu) { - thead_aclint_sswi_ipi_clear(); + aclint_sswi_ipi_clear(); disable_percpu_irq(sswi_ipi_virq); return 0; } -static int __init thead_aclint_sswi_parse_irq(struct fwnode_handle *fwnode, - void __iomem *reg) +static int __init aclint_sswi_parse_irq(struct fwnode_handle *fwnode, void __iomem *reg) { struct of_phandle_args parent; unsigned long hartid; @@ -97,7 +92,7 @@ static int __init thead_aclint_sswi_parse_irq(struct fwnode_handle *fwnode, cpu = riscv_hartid_to_cpuid(hartid); - per_cpu(sswi_cpu_regs, cpu) = reg + i * THEAD_ACLINT_xSWI_REGISTER_SIZE; + per_cpu(sswi_cpu_regs, cpu) = reg + hart_index * 4; } pr_info("%pfwP: register %u CPU%s\n", fwnode, contexts, str_plural(contexts)); @@ -105,17 +100,12 @@ static int __init thead_aclint_sswi_parse_irq(struct fwnode_handle *fwnode, return 0; } -static int __init thead_aclint_sswi_probe(struct fwnode_handle *fwnode) +static int __init aclint_sswi_probe(struct fwnode_handle *fwnode) { struct irq_domain *domain; void __iomem *reg; int virq, rc; - /* If it is T-HEAD CPU, check whether SSWI is enabled */ - if (riscv_cached_mvendorid(0) == THEAD_VENDOR_ID && - !(csr_read(THEAD_C9XX_CSR_SXSTATUS) & THEAD_C9XX_SXSTATUS_CLINTEE)) - return -ENOTSUPP; - if (!is_of_node(fwnode)) return -EINVAL; @@ -124,7 +114,7 @@ static int __init thead_aclint_sswi_probe(struct fwnode_handle *fwnode) return -ENOMEM; /* Parse SSWI setting */ - rc = thead_aclint_sswi_parse_irq(fwnode, reg); + rc = aclint_sswi_parse_irq(fwnode, reg); if (rc < 0) return rc; @@ -146,22 +136,64 @@ static int __init thead_aclint_sswi_probe(struct fwnode_handle *fwnode) } /* Register SSWI irq and handler */ - virq = ipi_mux_create(BITS_PER_BYTE, thead_aclint_sswi_ipi_send); + virq = ipi_mux_create(BITS_PER_BYTE, aclint_sswi_ipi_send); if (virq <= 0) { pr_err("unable to create muxed IPIs\n"); irq_dispose_mapping(sswi_ipi_virq); return virq < 0 ? virq : -ENOMEM; } - irq_set_chained_handler(sswi_ipi_virq, thead_aclint_sswi_ipi_handle); + irq_set_chained_handler(sswi_ipi_virq, aclint_sswi_ipi_handle); - cpuhp_setup_state(CPUHP_AP_IRQ_THEAD_ACLINT_SSWI_STARTING, - "irqchip/thead-aclint-sswi:starting", - thead_aclint_sswi_starting_cpu, - thead_aclint_sswi_dying_cpu); + cpuhp_setup_state(CPUHP_AP_IRQ_ACLINT_SSWI_STARTING, + "irqchip/aclint-sswi:starting", + aclint_sswi_starting_cpu, + aclint_sswi_dying_cpu); riscv_ipi_set_virq_range(virq, BITS_PER_BYTE); + return 0; +} + +/* generic/MIPS variant */ +static int __init generic_aclint_sswi_probe(struct fwnode_handle *fwnode) +{ + int rc; + + rc = aclint_sswi_probe(fwnode); + if (rc) + return rc; + + /* Announce that SSWI is providing IPIs */ + pr_info("providing IPIs using ACLINT SSWI\n"); + + return 0; +} + +static int __init generic_aclint_sswi_early_probe(struct device_node *node, + struct device_node *parent) +{ + return generic_aclint_sswi_probe(&node->fwnode); +} +IRQCHIP_DECLARE(generic_aclint_sswi, "mips,p8700-aclint-sswi", generic_aclint_sswi_early_probe); + +/* THEAD variant */ +#define THEAD_C9XX_CSR_SXSTATUS 0x5c0 +#define THEAD_C9XX_SXSTATUS_CLINTEE BIT(17) + +static int __init thead_aclint_sswi_probe(struct fwnode_handle *fwnode) +{ + int rc; + + /* If it is T-HEAD CPU, check whether SSWI is enabled */ + if (riscv_cached_mvendorid(0) == THEAD_VENDOR_ID && + !(csr_read(THEAD_C9XX_CSR_SXSTATUS) & THEAD_C9XX_SXSTATUS_CLINTEE)) + return -ENOTSUPP; + + rc = aclint_sswi_probe(fwnode); + if (rc) + return rc; + /* Announce that SSWI is providing IPIs */ pr_info("providing IPIs using THEAD ACLINT SSWI\n"); diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index df366ee15456..d381420bbd5f 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -145,7 +145,7 @@ enum cpuhp_state { CPUHP_AP_IRQ_EIOINTC_STARTING, CPUHP_AP_IRQ_AVECINTC_STARTING, CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING, - CPUHP_AP_IRQ_THEAD_ACLINT_SSWI_STARTING, + CPUHP_AP_IRQ_ACLINT_SSWI_STARTING, CPUHP_AP_IRQ_RISCV_IMSIC_STARTING, CPUHP_AP_IRQ_RISCV_SBI_IPI_STARTING, CPUHP_AP_ARM_MVEBU_COHERENCY, From 93406e374295ad25ab06104f734459cd25ce7134 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 12 Jun 2025 17:39:11 +0300 Subject: [PATCH 07/28] irqchip/aclint-sswi: Remove unneeded includes None of them are required for building the driver. Signed-off-by: Vladimir Kondratiev Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/20250612143911.3224046-8-vladimir.kondratiev@mobileye.com --- drivers/irqchip/irq-aclint-sswi.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/irqchip/irq-aclint-sswi.c b/drivers/irqchip/irq-aclint-sswi.c index 0131194d4847..d9f28c02c6d4 100644 --- a/drivers/irqchip/irq-aclint-sswi.c +++ b/drivers/irqchip/irq-aclint-sswi.c @@ -7,15 +7,9 @@ #include #include -#include -#include #include #include -#include -#include #include -#include -#include #include #include #include From c8c8443a64a186df0508c709d51fe9c7db0b5d55 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 12 Jun 2025 17:39:10 +0300 Subject: [PATCH 08/28] irqchip/aclint-sswi: Reduce data scope Move variables to the innermost scope where they are used Signed-off-by: Vladimir Kondratiev Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/20250612143911.3224046-7-vladimir.kondratiev@mobileye.com --- drivers/irqchip/irq-aclint-sswi.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/irqchip/irq-aclint-sswi.c b/drivers/irqchip/irq-aclint-sswi.c index d9f28c02c6d4..9d8b19be66b6 100644 --- a/drivers/irqchip/irq-aclint-sswi.c +++ b/drivers/irqchip/irq-aclint-sswi.c @@ -61,18 +61,18 @@ static int aclint_sswi_dying_cpu(unsigned int cpu) static int __init aclint_sswi_parse_irq(struct fwnode_handle *fwnode, void __iomem *reg) { - struct of_phandle_args parent; - unsigned long hartid; - u32 contexts, i; - int rc, cpu; + u32 contexts = of_irq_count(to_of_node(fwnode)); - contexts = of_irq_count(to_of_node(fwnode)); if (!(contexts)) { pr_err("%pfwP: no ACLINT SSWI context available\n", fwnode); return -EINVAL; } - for (i = 0; i < contexts; i++) { + for (u32 i = 0; i < contexts; i++) { + struct of_phandle_args parent; + unsigned long hartid; + int rc, cpu; + rc = of_irq_parse_one(to_of_node(fwnode), i, &parent); if (rc) return rc; From 128ab2cfd0205fe395196a9f3221bcddd6adf54e Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Thu, 12 Jun 2025 17:39:09 +0300 Subject: [PATCH 09/28] irqchip/aslint-sswi: Resolve hart index Resolve hart index according to assignment in the "riscv,hart-indexes" property as defined in the specification [1] Signed-off-by: Vladimir Kondratiev Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/20250612143911.3224046-6-vladimir.kondratiev@mobileye.com Link: https://github.com/riscvarchive/riscv-aclint [1] --- drivers/irqchip/irq-aclint-sswi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/irqchip/irq-aclint-sswi.c b/drivers/irqchip/irq-aclint-sswi.c index 9d8b19be66b6..93e28e9f281f 100644 --- a/drivers/irqchip/irq-aclint-sswi.c +++ b/drivers/irqchip/irq-aclint-sswi.c @@ -71,6 +71,7 @@ static int __init aclint_sswi_parse_irq(struct fwnode_handle *fwnode, void __iom for (u32 i = 0; i < contexts; i++) { struct of_phandle_args parent; unsigned long hartid; + u32 hart_index; int rc, cpu; rc = of_irq_parse_one(to_of_node(fwnode), i, &parent); @@ -86,6 +87,11 @@ static int __init aclint_sswi_parse_irq(struct fwnode_handle *fwnode, void __iom cpu = riscv_hartid_to_cpuid(hartid); + rc = riscv_get_hart_index(fwnode, i, &hart_index); + if (rc) { + pr_warn("%pfwP: hart index [%d] not found\n", fwnode, i); + return -EINVAL; + } per_cpu(sswi_cpu_regs, cpu) = reg + hart_index * 4; } From de2942828e7670526289f098df7e50b112e8ff1e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 1 Jul 2025 11:59:21 +0100 Subject: [PATCH 10/28] irqchip/renesas-rzv2h: Enable SKIP_SET_WAKE and MASK_ON_SUSPEND The interrupt controller found on RZ/G3E doesn't provide any facility to configure the wakeup sources. That's the reason why the driver lacks the irq_set_wake() callback for the interrupt chip. But this prevent to properly enter power management states like "suspend to idle". Enable the flags IRQCHIP_SKIP_SET_WAKE and IRQCHIP_MASK_ON_SUSPEND so the interrupt suspend logic can handle the chip correctly. Signed-off-by: Biju Das Signed-off-by: Thomas Gleixner Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/all/20250701105923.52151-1-biju.das.jz@bp.renesas.com --- drivers/irqchip/irq-renesas-rzv2h.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c index 57c5a3c008c9..3daa5de0f05c 100644 --- a/drivers/irqchip/irq-renesas-rzv2h.c +++ b/drivers/irqchip/irq-renesas-rzv2h.c @@ -427,7 +427,9 @@ static const struct irq_chip rzv2h_icu_chip = { .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_set_type = rzv2h_icu_set_type, .irq_set_affinity = irq_chip_set_affinity_parent, - .flags = IRQCHIP_SET_TYPE_MASKED, + .flags = IRQCHIP_MASK_ON_SUSPEND | + IRQCHIP_SET_TYPE_MASKED | + IRQCHIP_SKIP_SET_WAKE, }; static int rzv2h_icu_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, From 41a5f82885e152c364e587ab30df4e582e96b73a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 2 Jul 2025 10:53:54 +0200 Subject: [PATCH 11/28] irqchip/renesas-rzv2h: Remove unneeded includes The RZ/V2H ICU driver does not use clocks, of_address, or syscore. Signed-off-by: Geert Uytterhoeven Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/d4fbffc39af2eaa7bc50a0a97ffb3a22e3c4cb6a.1751446168.git.geert+renesas@glider.be --- drivers/irqchip/irq-renesas-rzv2h.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c index 3daa5de0f05c..9018d9c3911e 100644 --- a/drivers/irqchip/irq-renesas-rzv2h.c +++ b/drivers/irqchip/irq-renesas-rzv2h.c @@ -11,18 +11,15 @@ #include #include -#include #include #include #include #include #include -#include #include #include #include #include -#include /* DT "interrupts" indexes */ #define ICU_IRQ_START 1 From 858e65af91351f8842bbe2c5ae6f100778783f42 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 26 Jun 2025 16:48:58 +0200 Subject: [PATCH 12/28] irqdomain: Add device pointer to irq_domain_info and msi_domain_info Add device pointer to irq_domain_info and msi_domain_info, so that the device can be specified at domain creation time. Signed-off-by: Thomas Gleixner Signed-off-by: Nam Cao Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/943e52403b20cf13c320d55bd4446b4562466aab.1750860131.git.namcao@linutronix.de --- include/linux/irqdomain.h | 2 ++ include/linux/msi.h | 2 ++ kernel/irq/irqdomain.c | 1 + kernel/irq/msi.c | 3 ++- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 7387d183029b..266b5e5bb8ce 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -279,6 +279,7 @@ struct irq_domain_chip_generic_info; * domains are added using same fwnode * @ops: Domain operation callbacks * @host_data: Controller private data pointer + * @dev: Device which creates the domain * @dgc_info: Geneneric chip information structure pointer used to * create generic chips for the domain if not NULL. * @init: Function called when the domain is created. @@ -298,6 +299,7 @@ struct irq_domain_info { const char *name_suffix; const struct irq_domain_ops *ops; void *host_data; + struct device *dev; #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY /** * @parent: Pointer to the parent irq domain used in a hierarchy domain diff --git a/include/linux/msi.h b/include/linux/msi.h index 6863540f4b71..77227d23ea84 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -488,6 +488,7 @@ struct msi_domain_ops { * gets initialized to the maximum software index limit * by the domain creation code. * @ops: The callback data structure + * @dev: Device which creates the domain * @chip: Optional: associated interrupt chip * @chip_data: Optional: associated interrupt chip data * @handler: Optional: associated interrupt flow handler @@ -501,6 +502,7 @@ struct msi_domain_info { enum irq_domain_bus_token bus_token; unsigned int hwsize; struct msi_domain_ops *ops; + struct device *dev; struct irq_chip *chip; void *chip_data; irq_flow_handler_t handler; diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index c8b6de09047b..4afbd3ac532f 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -317,6 +317,7 @@ static struct irq_domain *__irq_domain_instantiate(const struct irq_domain_info domain->flags |= info->domain_flags; domain->exit = info->exit; + domain->dev = info->dev; #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY if (info->parent) { diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 9febe797a5f6..9b09ad3f9914 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -889,6 +889,7 @@ static struct irq_domain *__msi_create_irq_domain(struct fwnode_handle *fwnode, if (domain) { irq_domain_update_bus_token(domain, info->bus_token); + domain->dev = info->dev; if (info->flags & MSI_FLAG_PARENT_PM_DEV) domain->pm_dev = parent->pm_dev; } @@ -1051,6 +1052,7 @@ bool msi_create_device_irq_domain(struct device *dev, unsigned int domid, bundle->info.data = domain_data; bundle->info.chip_data = chip_data; bundle->info.alloc_data = &bundle->alloc_info; + bundle->info.dev = dev; pops = parent->msi_parent_ops; snprintf(bundle->name, sizeof(bundle->name), "%s%s-%s", @@ -1089,7 +1091,6 @@ bool msi_create_device_irq_domain(struct device *dev, unsigned int domid, if (!domain) return false; - domain->dev = dev; dev->msi.data->__domains[domid].domain = domain; if (msi_domain_prepare_irqs(domain, dev, hwsize, &bundle->alloc_info)) { From 91650ca5efcf4be00eae5620ad571ce4cdf66ab5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 26 Jun 2025 16:48:59 +0200 Subject: [PATCH 13/28] irqchip/bcm2712-mip: Switch to msi_create_parent_irq_domain() Switch to use the concise helper to create an MSI parent domain. Signed-off-by: Thomas Gleixner Signed-off-by: Nam Cao Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/92a6d68db014e945337c10649a41605da05783da.1750860131.git.namcao@linutronix.de --- drivers/irqchip/irq-bcm2712-mip.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/irqchip/irq-bcm2712-mip.c b/drivers/irqchip/irq-bcm2712-mip.c index 63de5ef6cf2d..9bd7bc0bf6d5 100644 --- a/drivers/irqchip/irq-bcm2712-mip.c +++ b/drivers/irqchip/irq-bcm2712-mip.c @@ -172,18 +172,18 @@ static const struct msi_parent_ops mip_msi_parent_ops = { static int mip_init_domains(struct mip_priv *mip, struct device_node *np) { - struct irq_domain *middle; + struct irq_domain_info info = { + .fwnode = of_fwnode_handle(np), + .ops = &mip_middle_domain_ops, + .host_data = mip, + .size = mip->num_msis, + .parent = mip->parent, + .dev = mip->dev, + }; - middle = irq_domain_create_hierarchy(mip->parent, 0, mip->num_msis, of_fwnode_handle(np), - &mip_middle_domain_ops, mip); - if (!middle) + if (!msi_create_parent_irq_domain(&info, &mip_msi_parent_ops)) return -ENOMEM; - irq_domain_update_bus_token(middle, DOMAIN_BUS_GENERIC_MSI); - middle->dev = mip->dev; - middle->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; - middle->msi_parent_ops = &mip_msi_parent_ops; - /* * All MSI-X unmasked for the host, masked for the VPU, and edge-triggered. */ From 59422904dd9855f94d00dc66598bef1bd2663894 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 26 Jun 2025 16:49:00 +0200 Subject: [PATCH 14/28] irqchip/riscv-imsic: Convert to msi_create_parent_irq_domain() helper Now that we have a concise helper to create an MSI parent domain, switch the RISC-V letter soup over to that. Signed-off-by: Marc Zyngier Signed-off-by: Thomas Gleixner Signed-off-by: Nam Cao Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/b906a38d443577de45923b335d80fc54c5638da0.1750860131.git.namcao@linutronix.de Link: https://lore.kernel.org/all/20241204124549.607054-6-maz@kernel.org --- drivers/irqchip/irq-riscv-imsic-platform.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c index 1b9fbfce9581..74a2a28f9403 100644 --- a/drivers/irqchip/irq-riscv-imsic-platform.c +++ b/drivers/irqchip/irq-riscv-imsic-platform.c @@ -307,6 +307,11 @@ static const struct msi_parent_ops imsic_msi_parent_ops = { int imsic_irqdomain_init(void) { + struct irq_domain_info info = { + .fwnode = imsic->fwnode, + .ops = &imsic_base_domain_ops, + .host_data = imsic, + }; struct imsic_global_config *global; if (!imsic || !imsic->fwnode) { @@ -320,16 +325,11 @@ int imsic_irqdomain_init(void) } /* Create Base IRQ domain */ - imsic->base_domain = irq_domain_create_tree(imsic->fwnode, - &imsic_base_domain_ops, imsic); + imsic->base_domain = msi_create_parent_irq_domain(&info, &imsic_msi_parent_ops); if (!imsic->base_domain) { pr_err("%pfwP: failed to create IMSIC base domain\n", imsic->fwnode); return -ENOMEM; } - imsic->base_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; - imsic->base_domain->msi_parent_ops = &imsic_msi_parent_ops; - - irq_domain_update_bus_token(imsic->base_domain, DOMAIN_BUS_NEXUS); global = &imsic->global; pr_info("%pfwP: hart-index-bits: %d, guest-index-bits: %d\n", From c7cc7b122a4cf1235b53e5bb5f441ce95d8b0cd2 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 26 Jun 2025 16:49:01 +0200 Subject: [PATCH 15/28] irqchip/imx-mu-msi: Convert to msi_create_parent_irq_domain() helper Now that we have a concise helper to create an MSI parent domain, switch the IMX letter soup over to that. Signed-off-by: Marc Zyngier Signed-off-by: Thomas Gleixner Signed-off-by: Nam Cao Signed-off-by: Thomas Gleixner Reviewed-by: Frank Li Link: https://lore.kernel.org/all/4f05fff99b6cc5875d2f4dadd31707e2dedaafc8.1750860131.git.namcao@linutronix.de Link: https://lore.kernel.org/all/20241204124549.607054-7-maz@kernel.org --- drivers/irqchip/irq-imx-mu-msi.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/irqchip/irq-imx-mu-msi.c b/drivers/irqchip/irq-imx-mu-msi.c index 137da1927d14..d2a4e8a61a42 100644 --- a/drivers/irqchip/irq-imx-mu-msi.c +++ b/drivers/irqchip/irq-imx-mu-msi.c @@ -223,21 +223,21 @@ static const struct msi_parent_ops imx_mu_msi_parent_ops = { static int imx_mu_msi_domains_init(struct imx_mu_msi *msi_data, struct device *dev) { - struct fwnode_handle *fwnodes = dev_fwnode(dev); + struct irq_domain_info info = { + .ops = &imx_mu_msi_domain_ops, + .fwnode = dev_fwnode(dev), + .size = IMX_MU_CHANS, + .host_data = msi_data, + }; struct irq_domain *parent; /* Initialize MSI domain parent */ - parent = irq_domain_create_linear(fwnodes, IMX_MU_CHANS, - &imx_mu_msi_domain_ops, msi_data); + parent = msi_create_parent_irq_domain(&info, &imx_mu_msi_parent_ops); if (!parent) { dev_err(dev, "failed to create IRQ domain\n"); return -ENOMEM; } - - irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS); parent->dev = parent->pm_dev = dev; - parent->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; - parent->msi_parent_ops = &imx_mu_msi_parent_ops; return 0; } From 7f91d608cc43ea7f417caf097a87d2619a0e2747 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 26 Jun 2025 16:49:02 +0200 Subject: [PATCH 16/28] irqchip/loongson-pch-msi.c: Switch to msi_create_parent_irq_domain() Switch to use the concise helper to create an MSI parent domain. Signed-off-by: Thomas Gleixner Signed-off-by: Nam Cao Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/7ae78d7b7e33ad8ca1ec2ba28957546c81ba86f7.1750860131.git.namcao@linutronix.de --- drivers/irqchip/irq-loongson-pch-msi.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/irqchip/irq-loongson-pch-msi.c b/drivers/irqchip/irq-loongson-pch-msi.c index a0257c7bef10..4aedc9b90ff7 100644 --- a/drivers/irqchip/irq-loongson-pch-msi.c +++ b/drivers/irqchip/irq-loongson-pch-msi.c @@ -153,26 +153,21 @@ static struct msi_parent_ops pch_msi_parent_ops = { .init_dev_msi_info = msi_lib_init_dev_msi_info, }; -static int pch_msi_init_domains(struct pch_msi_data *priv, - struct irq_domain *parent, +static int pch_msi_init_domains(struct pch_msi_data *priv, struct irq_domain *parent, struct fwnode_handle *domain_handle) { - struct irq_domain *middle_domain; + struct irq_domain_info info = { + .ops = &pch_msi_middle_domain_ops, + .size = priv->num_irqs, + .parent = parent, + .host_data = priv, + .fwnode = domain_handle, + }; - middle_domain = irq_domain_create_hierarchy(parent, 0, priv->num_irqs, - domain_handle, - &pch_msi_middle_domain_ops, - priv); - if (!middle_domain) { + if (!msi_create_parent_irq_domain(&info, &pch_msi_parent_ops)) { pr_err("Failed to create the MSI middle domain\n"); return -ENOMEM; } - - irq_domain_update_bus_token(middle_domain, DOMAIN_BUS_NEXUS); - - middle_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; - middle_domain->msi_parent_ops = &pch_msi_parent_ops; - return 0; } From 7c0dbd80de036d400525b8df862be665d321d0fc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 26 Jun 2025 16:49:03 +0200 Subject: [PATCH 17/28] irqchip/sg2042-msi: Switch to msi_create_parent_irq_domain() Switch to use the concise helper to create an MSI parent domain. Signed-off-by: Thomas Gleixner Signed-off-by: Nam Cao Signed-off-by: Thomas Gleixner Reviewed-by: Chen Wang Link: https://lore.kernel.org/all/3e901db1a4c87678af053019774d95b73bfb9ef9.1750860131.git.namcao@linutronix.de --- drivers/irqchip/irq-sg2042-msi.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/irqchip/irq-sg2042-msi.c b/drivers/irqchip/irq-sg2042-msi.c index af16bc5a3c8b..bcfddc51bc6a 100644 --- a/drivers/irqchip/irq-sg2042-msi.c +++ b/drivers/irqchip/irq-sg2042-msi.c @@ -219,20 +219,18 @@ static const struct msi_parent_ops sg2044_msi_parent_ops = { static int sg204x_msi_init_domains(struct sg204x_msi_chipdata *data, struct irq_domain *plic_domain, struct device *dev) { - struct fwnode_handle *fwnode = dev_fwnode(dev); - struct irq_domain *middle_domain; + struct irq_domain_info info = { + .ops = &sg204x_msi_middle_domain_ops, + .parent = plic_domain, + .size = data->num_irqs, + .fwnode = dev_fwnode(dev), + .host_data = data, + }; - middle_domain = irq_domain_create_hierarchy(plic_domain, 0, data->num_irqs, fwnode, - &sg204x_msi_middle_domain_ops, data); - if (!middle_domain) { + if (!msi_create_parent_irq_domain(&info, data->chip_info->parent_ops)) { pr_err("Failed to create the MSI middle domain\n"); return -ENOMEM; } - - irq_domain_update_bus_token(middle_domain, DOMAIN_BUS_NEXUS); - - middle_domain->flags |= IRQ_DOMAIN_FLAG_MSI_PARENT; - middle_domain->msi_parent_ops = data->chip_info->parent_ops; return 0; } From 6e44ac411255e0a48674862b53f2b1b47148c209 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 26 Jun 2025 16:49:04 +0200 Subject: [PATCH 18/28] irqchip/alpine-msi: Clean up whitespace style Tidy up the coding style. Only formatting changes. Signed-off-by: Thomas Gleixner Signed-off-by: Nam Cao Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/3bbf719fcd974b0f52a832552b986116bdc70203.1750860131.git.namcao@linutronix.de --- drivers/irqchip/irq-alpine-msi.c | 37 +++++++++++--------------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/drivers/irqchip/irq-alpine-msi.c b/drivers/irqchip/irq-alpine-msi.c index a5289dc26dca..7e379a6985a6 100644 --- a/drivers/irqchip/irq-alpine-msi.c +++ b/drivers/irqchip/irq-alpine-msi.c @@ -29,11 +29,11 @@ #define ALPINE_MSIX_SPI_TARGET_CLUSTER0 BIT(16) struct alpine_msix_data { - spinlock_t msi_map_lock; - phys_addr_t addr; - u32 spi_first; /* The SGI number that MSIs start */ - u32 num_spis; /* The number of SGIs for MSIs */ - unsigned long *msi_map; + spinlock_t msi_map_lock; + phys_addr_t addr; + u32 spi_first; /* The SGI number that MSIs start */ + u32 num_spis; /* The number of SGIs for MSIs */ + unsigned long *msi_map; }; static void alpine_msix_mask_msi_irq(struct irq_data *d) @@ -76,8 +76,7 @@ static int alpine_msix_allocate_sgi(struct alpine_msix_data *priv, int num_req) return priv->spi_first + first; } -static void alpine_msix_free_sgi(struct alpine_msix_data *priv, unsigned sgi, - int num_req) +static void alpine_msix_free_sgi(struct alpine_msix_data *priv, unsigned int sgi, int num_req) { int first = sgi - priv->spi_first; @@ -88,14 +87,12 @@ static void alpine_msix_free_sgi(struct alpine_msix_data *priv, unsigned sgi, spin_unlock(&priv->msi_map_lock); } -static void alpine_msix_compose_msi_msg(struct irq_data *data, - struct msi_msg *msg) +static void alpine_msix_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) { struct alpine_msix_data *priv = irq_data_get_irq_chip_data(data); phys_addr_t msg_addr = priv->addr; msg_addr |= (data->hwirq << 3); - msg->address_hi = upper_32_bits(msg_addr); msg->address_lo = lower_32_bits(msg_addr); msg->data = 0; @@ -116,8 +113,7 @@ static struct irq_chip middle_irq_chip = { .irq_compose_msi_msg = alpine_msix_compose_msi_msg, }; -static int alpine_msix_gic_domain_alloc(struct irq_domain *domain, - unsigned int virq, int sgi) +static int alpine_msix_gic_domain_alloc(struct irq_domain *domain, unsigned int virq, int sgi) { struct irq_fwspec fwspec; struct irq_data *d; @@ -138,12 +134,10 @@ static int alpine_msix_gic_domain_alloc(struct irq_domain *domain, d = irq_domain_get_irq_data(domain->parent, virq); d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING); - return 0; } -static int alpine_msix_middle_domain_alloc(struct irq_domain *domain, - unsigned int virq, +static int alpine_msix_middle_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *args) { struct alpine_msix_data *priv = domain->host_data; @@ -161,7 +155,6 @@ static int alpine_msix_middle_domain_alloc(struct irq_domain *domain, irq_domain_set_hwirq_and_chip(domain, virq + i, sgi + i, &middle_irq_chip, priv); } - return 0; err_sgi: @@ -170,8 +163,7 @@ err_sgi: return err; } -static void alpine_msix_middle_domain_free(struct irq_domain *domain, - unsigned int virq, +static void alpine_msix_middle_domain_free(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs) { struct irq_data *d = irq_domain_get_irq_data(domain, virq); @@ -186,8 +178,7 @@ static const struct irq_domain_ops alpine_msix_middle_domain_ops = { .free = alpine_msix_middle_domain_free, }; -static int alpine_msix_init_domains(struct alpine_msix_data *priv, - struct device_node *node) +static int alpine_msix_init_domains(struct alpine_msix_data *priv, struct device_node *node) { struct irq_domain *middle_domain, *msi_domain, *gic_domain; struct device_node *gic_node; @@ -224,8 +215,7 @@ static int alpine_msix_init_domains(struct alpine_msix_data *priv, return 0; } -static int alpine_msix_init(struct device_node *node, - struct device_node *parent) +static int alpine_msix_init(struct device_node *node, struct device_node *parent) { struct alpine_msix_data *priv; struct resource res; @@ -271,8 +261,7 @@ static int alpine_msix_init(struct device_node *node, goto err_priv; } - pr_debug("Registering %d msixs, starting at %d\n", - priv->num_spis, priv->spi_first); + pr_debug("Registering %d msixs, starting at %d\n", priv->num_spis, priv->spi_first); ret = alpine_msix_init_domains(priv, node); if (ret) From 71476f915f92cd9fb209f8729d700703ec3c36bc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 26 Jun 2025 16:49:05 +0200 Subject: [PATCH 19/28] irqchip/alpine-msi: Convert to lock guards Convert lock/unlock pairs to guards and tidy up the code. No functional change. Signed-off-by: Thomas Gleixner Signed-off-by: Nam Cao Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/7886b9595aaf8e102f79364784f68dec9c49b023.1750860131.git.namcao@linutronix.de --- drivers/irqchip/irq-alpine-msi.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/irqchip/irq-alpine-msi.c b/drivers/irqchip/irq-alpine-msi.c index 7e379a6985a6..cf188e5feefc 100644 --- a/drivers/irqchip/irq-alpine-msi.c +++ b/drivers/irqchip/irq-alpine-msi.c @@ -60,19 +60,12 @@ static int alpine_msix_allocate_sgi(struct alpine_msix_data *priv, int num_req) { int first; - spin_lock(&priv->msi_map_lock); - - first = bitmap_find_next_zero_area(priv->msi_map, priv->num_spis, 0, - num_req, 0); - if (first >= priv->num_spis) { - spin_unlock(&priv->msi_map_lock); + guard(spinlock)(&priv->msi_map_lock); + first = bitmap_find_next_zero_area(priv->msi_map, priv->num_spis, 0, num_req, 0); + if (first >= priv->num_spis) return -ENOSPC; - } bitmap_set(priv->msi_map, first, num_req); - - spin_unlock(&priv->msi_map_lock); - return priv->spi_first + first; } @@ -80,11 +73,8 @@ static void alpine_msix_free_sgi(struct alpine_msix_data *priv, unsigned int sgi { int first = sgi - priv->spi_first; - spin_lock(&priv->msi_map_lock); - + guard(spinlock)(&priv->msi_map_lock); bitmap_clear(priv->msi_map, first, num_req); - - spin_unlock(&priv->msi_map_lock); } static void alpine_msix_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) From f7c2dd9f4c2d93b8dfb30dcc91b7e241fc1f5811 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 26 Jun 2025 16:49:06 +0200 Subject: [PATCH 20/28] irqchip/alpine-msi: Convert to __free Tidy up the code with __free. No functional change. Signed-off-by: Thomas Gleixner Signed-off-by: Nam Cao Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/ff2c9460d03e44cb2946521dbae5ce800d34523e.1750860131.git.namcao@linutronix.de --- drivers/irqchip/irq-alpine-msi.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/irqchip/irq-alpine-msi.c b/drivers/irqchip/irq-alpine-msi.c index cf188e5feefc..43d6db290138 100644 --- a/drivers/irqchip/irq-alpine-msi.c +++ b/drivers/irqchip/irq-alpine-msi.c @@ -207,11 +207,10 @@ static int alpine_msix_init_domains(struct alpine_msix_data *priv, struct device static int alpine_msix_init(struct device_node *node, struct device_node *parent) { - struct alpine_msix_data *priv; + struct alpine_msix_data *priv __free(kfree) = kzalloc(sizeof(*priv), GFP_KERNEL); struct resource res; int ret; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -220,7 +219,7 @@ static int alpine_msix_init(struct device_node *node, struct device_node *parent ret = of_address_to_resource(node, 0, &res); if (ret) { pr_err("Failed to allocate resource\n"); - goto err_priv; + return ret; } /* @@ -235,34 +234,28 @@ static int alpine_msix_init(struct device_node *node, struct device_node *parent if (of_property_read_u32(node, "al,msi-base-spi", &priv->spi_first)) { pr_err("Unable to parse MSI base\n"); - ret = -EINVAL; - goto err_priv; + return -EINVAL; } if (of_property_read_u32(node, "al,msi-num-spis", &priv->num_spis)) { pr_err("Unable to parse MSI numbers\n"); - ret = -EINVAL; - goto err_priv; + return -EINVAL; } - priv->msi_map = bitmap_zalloc(priv->num_spis, GFP_KERNEL); - if (!priv->msi_map) { - ret = -ENOMEM; - goto err_priv; - } + unsigned long *msi_map __free(kfree) = bitmap_zalloc(priv->num_spis, GFP_KERNEL); + + if (!msi_map) + return -ENOMEM; + priv->msi_map = msi_map; pr_debug("Registering %d msixs, starting at %d\n", priv->num_spis, priv->spi_first); ret = alpine_msix_init_domains(priv, node); if (ret) - goto err_map; + return ret; + retain_and_null_ptr(priv); + retain_and_null_ptr(msi_map); return 0; - -err_map: - bitmap_free(priv->msi_map); -err_priv: - kfree(priv); - return ret; } IRQCHIP_DECLARE(alpine_msix, "al,alpine-msix", alpine_msix_init); From 7a91ad7ebd618d89c0966f19fe453701b1e17494 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 26 Jun 2025 16:49:07 +0200 Subject: [PATCH 21/28] irqchip/alpine-msi: Switch to msi_create_parent_irq_domain() Move away from the legacy MSI domain setup, switch to use msi_create_parent_irq_domain(). Signed-off-by: Thomas Gleixner Signed-off-by: Nam Cao Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/ec08fea004e7c3aa18c3f5657a8cafeb1adfcc1d.1750860131.git.namcao@linutronix.de --- drivers/irqchip/Kconfig | 1 + drivers/irqchip/irq-alpine-msi.c | 69 +++++++++++++------------------- 2 files changed, 28 insertions(+), 42 deletions(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 39f6f421fc75..d596155b314c 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -85,6 +85,7 @@ config ALPINE_MSI bool depends on PCI select PCI_MSI + select IRQ_MSI_LIB select GENERIC_IRQ_CHIP config AL_FIC diff --git a/drivers/irqchip/irq-alpine-msi.c b/drivers/irqchip/irq-alpine-msi.c index 43d6db290138..159d9ec7c0dd 100644 --- a/drivers/irqchip/irq-alpine-msi.c +++ b/drivers/irqchip/irq-alpine-msi.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -36,26 +37,6 @@ struct alpine_msix_data { unsigned long *msi_map; }; -static void alpine_msix_mask_msi_irq(struct irq_data *d) -{ - pci_msi_mask_irq(d); - irq_chip_mask_parent(d); -} - -static void alpine_msix_unmask_msi_irq(struct irq_data *d) -{ - pci_msi_unmask_irq(d); - irq_chip_unmask_parent(d); -} - -static struct irq_chip alpine_msix_irq_chip = { - .name = "MSIx", - .irq_mask = alpine_msix_mask_msi_irq, - .irq_unmask = alpine_msix_unmask_msi_irq, - .irq_eoi = irq_chip_eoi_parent, - .irq_set_affinity = irq_chip_set_affinity_parent, -}; - static int alpine_msix_allocate_sgi(struct alpine_msix_data *priv, int num_req) { int first; @@ -88,12 +69,6 @@ static void alpine_msix_compose_msi_msg(struct irq_data *data, struct msi_msg *m msg->data = 0; } -static struct msi_domain_info alpine_msix_domain_info = { - .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_PCI_MSIX, - .chip = &alpine_msix_irq_chip, -}; - static struct irq_chip middle_irq_chip = { .name = "alpine_msix_middle", .irq_mask = irq_chip_mask_parent, @@ -164,13 +139,35 @@ static void alpine_msix_middle_domain_free(struct irq_domain *domain, unsigned i } static const struct irq_domain_ops alpine_msix_middle_domain_ops = { + .select = msi_lib_irq_domain_select, .alloc = alpine_msix_middle_domain_alloc, .free = alpine_msix_middle_domain_free, }; +#define ALPINE_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ + MSI_FLAG_USE_DEF_CHIP_OPS | \ + MSI_FLAG_PCI_MSI_MASK_PARENT) + +#define ALPINE_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \ + MSI_FLAG_PCI_MSIX) + +static struct msi_parent_ops alpine_msi_parent_ops = { + .supported_flags = ALPINE_MSI_FLAGS_SUPPORTED, + .required_flags = ALPINE_MSI_FLAGS_REQUIRED, + .chip_flags = MSI_CHIP_FLAG_SET_EOI, + .bus_select_token = DOMAIN_BUS_NEXUS, + .bus_select_mask = MATCH_PCI_MSI, + .prefix = "ALPINE-", + .init_dev_msi_info = msi_lib_init_dev_msi_info, +}; + static int alpine_msix_init_domains(struct alpine_msix_data *priv, struct device_node *node) { - struct irq_domain *middle_domain, *msi_domain, *gic_domain; + struct irq_domain_info info = { + .fwnode = of_fwnode_handle(node), + .ops = &alpine_msix_middle_domain_ops, + .host_data = priv, + }; struct device_node *gic_node; gic_node = of_irq_find_parent(node); @@ -179,29 +176,17 @@ static int alpine_msix_init_domains(struct alpine_msix_data *priv, struct device return -ENODEV; } - gic_domain = irq_find_host(gic_node); + info.parent = irq_find_host(gic_node); of_node_put(gic_node); - if (!gic_domain) { + if (!info.parent) { pr_err("Failed to find the GIC domain\n"); return -ENXIO; } - middle_domain = irq_domain_create_hierarchy(gic_domain, 0, 0, NULL, - &alpine_msix_middle_domain_ops, priv); - if (!middle_domain) { - pr_err("Failed to create the MSIX middle domain\n"); - return -ENOMEM; - } - - msi_domain = pci_msi_create_irq_domain(of_fwnode_handle(node), - &alpine_msix_domain_info, - middle_domain); - if (!msi_domain) { + if (!msi_create_parent_irq_domain(&info, &alpine_msi_parent_ops)) { pr_err("Failed to create MSI domain\n"); - irq_domain_remove(middle_domain); return -ENOMEM; } - return 0; } From bafb2901317ff53c0add8b40e96267ad2d2e8ffb Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Thu, 26 Jun 2025 16:49:08 +0200 Subject: [PATCH 22/28] irqchip/armada-370-xp: Switch to msi_create_parent_irq_domain() Move away from the legacy MSI domain setup, switch to use msi_create_parent_irq_domain(). Signed-off-by: Nam Cao Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/976892e3ce64fcf52387833abee08ddfa47d2a82.1750860131.git.namcao@linutronix.de --- drivers/irqchip/Kconfig | 1 + drivers/irqchip/irq-armada-370-xp.c | 48 +++++++++++++++-------------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index d596155b314c..0f195ad49941 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -79,6 +79,7 @@ config ARMADA_370_XP_IRQ bool select GENERIC_IRQ_CHIP select PCI_MSI if PCI + select IRQ_MSI_LIB if PCI select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP config ALPINE_MSI diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 67b672a78862..a44c49e985b7 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -156,7 +157,6 @@ * @parent_irq: parent IRQ if MPIC is not top-level interrupt controller * @domain: MPIC main interrupt domain * @ipi_domain: IPI domain - * @msi_domain: MSI domain * @msi_inner_domain: MSI inner domain * @msi_used: bitmap of used MSI numbers * @msi_lock: mutex serializing access to @msi_used @@ -176,7 +176,6 @@ struct mpic { struct irq_domain *ipi_domain; #endif #ifdef CONFIG_PCI_MSI - struct irq_domain *msi_domain; struct irq_domain *msi_inner_domain; DECLARE_BITMAP(msi_used, PCI_MSI_FULL_DOORBELL_NR); struct mutex msi_lock; @@ -234,18 +233,6 @@ static void mpic_irq_unmask(struct irq_data *d) #ifdef CONFIG_PCI_MSI -static struct irq_chip mpic_msi_irq_chip = { - .name = "MPIC MSI", - .irq_mask = pci_msi_mask_irq, - .irq_unmask = pci_msi_unmask_irq, -}; - -static struct msi_domain_info mpic_msi_domain_info = { - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), - .chip = &mpic_msi_irq_chip, -}; - static void mpic_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) { unsigned int cpu = cpumask_first(irq_data_get_effective_affinity_mask(d)); @@ -314,6 +301,7 @@ static void mpic_msi_free(struct irq_domain *domain, unsigned int virq, unsigned } static const struct irq_domain_ops mpic_msi_domain_ops = { + .select = msi_lib_irq_domain_select, .alloc = mpic_msi_alloc, .free = mpic_msi_free, }; @@ -331,6 +319,21 @@ static void mpic_msi_reenable_percpu(struct mpic *mpic) writel(1, mpic->per_cpu + MPIC_INT_CLEAR_MASK); } +#define MPIC_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ + MSI_FLAG_USE_DEF_CHIP_OPS) +#define MPIC_MSI_FLAGS_SUPPORTED (MSI_FLAG_MULTI_PCI_MSI | \ + MSI_FLAG_PCI_MSIX | \ + MSI_GENERIC_FLAGS_MASK) + +static const struct msi_parent_ops mpic_msi_parent_ops = { + .required_flags = MPIC_MSI_FLAGS_REQUIRED, + .supported_flags = MPIC_MSI_FLAGS_SUPPORTED, + .bus_select_token = DOMAIN_BUS_NEXUS, + .bus_select_mask = MATCH_PCI_MSI, + .prefix = "MPIC-", + .init_dev_msi_info = msi_lib_init_dev_msi_info, +}; + static int __init mpic_msi_init(struct mpic *mpic, struct device_node *node, phys_addr_t main_int_phys_base) { @@ -348,18 +351,17 @@ static int __init mpic_msi_init(struct mpic *mpic, struct device_node *node, mpic->msi_doorbell_mask = PCI_MSI_FULL_DOORBELL_MASK; } - mpic->msi_inner_domain = irq_domain_create_linear(NULL, mpic->msi_doorbell_size, - &mpic_msi_domain_ops, mpic); + struct irq_domain_info info = { + .fwnode = of_fwnode_handle(node), + .ops = &mpic_msi_domain_ops, + .host_data = mpic, + .size = mpic->msi_doorbell_size, + }; + + mpic->msi_inner_domain = msi_create_parent_irq_domain(&info, &mpic_msi_parent_ops); if (!mpic->msi_inner_domain) return -ENOMEM; - mpic->msi_domain = pci_msi_create_irq_domain(of_fwnode_handle(node), &mpic_msi_domain_info, - mpic->msi_inner_domain); - if (!mpic->msi_domain) { - irq_domain_remove(mpic->msi_inner_domain); - return -ENOMEM; - } - mpic_msi_reenable_percpu(mpic); /* Unmask low 16 MSI irqs on non-IPI platforms */ From 94b59d5f567a148a3eb25265a4e60f8605ff8423 Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Thu, 26 Jun 2025 16:49:09 +0200 Subject: [PATCH 23/28] irqchip/ls-scfg-msi: Switch to use msi_create_parent_irq_domain() Move away from the legacy MSI domain setup, switch to use msi_create_parent_irq_domain(). Signed-off-by: Nam Cao Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/6d23d93fa1f1e65526698f97c9888fa5d12abc7b.1750860131.git.namcao@linutronix.de --- drivers/irqchip/Kconfig | 1 + drivers/irqchip/irq-ls-scfg-msi.c | 47 ++++++++++++++----------------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 0f195ad49941..ce7f7314b47d 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -436,6 +436,7 @@ config LS_SCFG_MSI def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE select IRQ_MSI_IOMMU depends on PCI_MSI + select IRQ_MSI_LIB config PARTITION_PERCPU bool diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 84bc5e4b47cf..7eca751d6548 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,6 @@ struct ls_scfg_msi { spinlock_t lock; struct platform_device *pdev; struct irq_domain *parent; - struct irq_domain *msi_domain; void __iomem *regs; phys_addr_t msiir_addr; struct ls_scfg_msi_cfg *cfg; @@ -57,17 +57,18 @@ struct ls_scfg_msi { unsigned long *used; }; -static struct irq_chip ls_scfg_msi_irq_chip = { - .name = "MSI", - .irq_mask = pci_msi_mask_irq, - .irq_unmask = pci_msi_unmask_irq, -}; +#define MPIC_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \ + MSI_FLAG_USE_DEF_CHIP_OPS) +#define MPIC_MSI_FLAGS_SUPPORTED (MSI_FLAG_PCI_MSIX | \ + MSI_GENERIC_FLAGS_MASK) -static struct msi_domain_info ls_scfg_msi_domain_info = { - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | - MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_PCI_MSIX), - .chip = &ls_scfg_msi_irq_chip, +static const struct msi_parent_ops ls_scfg_msi_parent_ops = { + .required_flags = MPIC_MSI_FLAGS_REQUIRED, + .supported_flags = MPIC_MSI_FLAGS_SUPPORTED, + .bus_select_token = DOMAIN_BUS_NEXUS, + .bus_select_mask = MATCH_PCI_MSI, + .prefix = "MSI-", + .init_dev_msi_info = msi_lib_init_dev_msi_info, }; static int msi_affinity_flag = 1; @@ -185,6 +186,7 @@ static void ls_scfg_msi_domain_irq_free(struct irq_domain *domain, } static const struct irq_domain_ops ls_scfg_msi_domain_ops = { + .select = msi_lib_irq_domain_select, .alloc = ls_scfg_msi_domain_irq_alloc, .free = ls_scfg_msi_domain_irq_free, }; @@ -214,21 +216,15 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc) static int ls_scfg_msi_domains_init(struct ls_scfg_msi *msi_data) { - /* Initialize MSI domain parent */ - msi_data->parent = irq_domain_create_linear(NULL, - msi_data->irqs_num, - &ls_scfg_msi_domain_ops, - msi_data); - if (!msi_data->parent) { - dev_err(&msi_data->pdev->dev, "failed to create IRQ domain\n"); - return -ENOMEM; - } + struct irq_domain_info info = { + .fwnode = of_fwnode_handle(msi_data->pdev->dev.of_node), + .ops = &ls_scfg_msi_domain_ops, + .host_data = msi_data, + .size = msi_data->irqs_num, + }; - msi_data->msi_domain = pci_msi_create_irq_domain( - of_fwnode_handle(msi_data->pdev->dev.of_node), - &ls_scfg_msi_domain_info, - msi_data->parent); - if (!msi_data->msi_domain) { + msi_data->parent = msi_create_parent_irq_domain(&info, &ls_scfg_msi_parent_ops); + if (!msi_data->parent) { dev_err(&msi_data->pdev->dev, "failed to create MSI domain\n"); irq_domain_remove(msi_data->parent); return -ENOMEM; @@ -405,7 +401,6 @@ static void ls_scfg_msi_remove(struct platform_device *pdev) for (i = 0; i < msi_data->msir_num; i++) ls_scfg_msi_teardown_hwirq(&msi_data->msir[i]); - irq_domain_remove(msi_data->msi_domain); irq_domain_remove(msi_data->parent); platform_set_drvdata(pdev, NULL); From aabf4ff06b9789f3cd167bf9e2eb25f1fdb5541a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 16 Jul 2025 14:43:45 -0500 Subject: [PATCH 24/28] irqchip/ls-scfg-msi: Fix NULL dereference in error handling The call to irq_domain_remove(msi_data->parent); was accidentally left behind during a code refactor. It's not necessary to free "msi_data->parent" because it is NULL and, in fact, trying to free it will lead to a NULL pointer dereference. Delete the unnecessary code. Fixes: 94b59d5f567a ("irqchip/ls-scfg-msi: Switch to use msi_create_parent_irq_domain()") Signed-off-by: Dan Carpenter Signed-off-by: Thomas Gleixner Reviewed-by: Nam Cao Link: https://lore.kernel.org/all/15059507-6422-4333-94ca-e8e8840bd289@sabinyo.mountain --- drivers/irqchip/irq-ls-scfg-msi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 7eca751d6548..4910f364e568 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -226,7 +226,6 @@ static int ls_scfg_msi_domains_init(struct ls_scfg_msi *msi_data) msi_data->parent = msi_create_parent_irq_domain(&info, &ls_scfg_msi_parent_ops); if (!msi_data->parent) { dev_err(&msi_data->pdev->dev, "failed to create MSI domain\n"); - irq_domain_remove(msi_data->parent); return -ENOMEM; } From 97c03ec2c0e0621bbd7a56f5be19bd2de552e6f4 Mon Sep 17 00:00:00 2001 From: Zenghui Yu Date: Wed, 9 Jul 2025 21:00:46 +0800 Subject: [PATCH 25/28] irqchip/gic-v3: Fix GICD_CTLR register naming It was incorrectly named as GICD_CTRL in a pr_info() and comments. Fix them. Signed-off-by: Zenghui Yu Signed-off-by: Thomas Gleixner Acked-by: Marc Zyngier Link: https://lore.kernel.org/all/20250709130046.1354-1-yuzenghui@huawei.com --- drivers/irqchip/irq-gic-v3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index efc791c43d44..dbeb85677b08 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -190,12 +190,12 @@ static void __init gic_prio_init(void) /* * How priority values are used by the GIC depends on two things: - * the security state of the GIC (controlled by the GICD_CTRL.DS bit) + * the security state of the GIC (controlled by the GICD_CTLR.DS bit) * and if Group 0 interrupts can be delivered to Linux in the non-secure * world as FIQs (controlled by the SCR_EL3.FIQ bit). These affect the * way priorities are presented in ICC_PMR_EL1 and in the distributor: * - * GICD_CTRL.DS | SCR_EL3.FIQ | ICC_PMR_EL1 | Distributor + * GICD_CTLR.DS | SCR_EL3.FIQ | ICC_PMR_EL1 | Distributor * ------------------------------------------------------- * 1 | - | unchanged | unchanged * ------------------------------------------------------- @@ -223,7 +223,7 @@ static void __init gic_prio_init(void) dist_prio_nmi = __gicv3_prio_to_ns(dist_prio_nmi); } - pr_info("GICD_CTRL.DS=%d, SCR_EL3.FIQ=%d\n", + pr_info("GICD_CTLR.DS=%d, SCR_EL3.FIQ=%d\n", cpus_have_security_disabled, !cpus_have_group0); } From ea92b6046d352740c15f35e703c1b13a47dd99b0 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Wed, 16 Jul 2025 18:07:45 +0530 Subject: [PATCH 26/28] irqchip/riscv-imsic: Add kernel parameter to disable IPIs When injecting IPIs to a set of harts, the IMSIC IPI support will do a separate MMIO write to the SETIPNUM_LE register of each target hart. This means on a platform where IMSIC is trap-n-emulated, there will be N MMIO traps when injecting IPI to N target harts hence IMSIC IPIs will be slow on such platforms compared to the SBI IPI extension. Unfortunately, there is no DT, ACPI, or any other way of discovering whether the underlying IMSIC is trap-n-emulated. Using MMIO write to the SETIPNUM_LE register for injecting IPI is purely a software choice in the IMSIC driver hence add a kernel parameter to allow users to disable IMSIC IPIs on platforms with trap-n-emulated IMSIC. Signed-off-by: Anup Patel Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/20250716123745.557585-1-apatel@ventanamicro.com --- .../admin-guide/kernel-parameters.txt | 7 +++++++ drivers/irqchip/irq-riscv-imsic-early.c | 20 ++++++++++++++++++- drivers/irqchip/irq-riscv-imsic-state.c | 7 ++++--- drivers/irqchip/irq-riscv-imsic-state.h | 1 + 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index f1f2c0874da9..7f0e12d0d260 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2538,6 +2538,13 @@ requires the kernel to be built with CONFIG_ARM64_PSEUDO_NMI. + irqchip.riscv_imsic_noipi + [RISC-V,EARLY] + Force the kernel to not use IMSIC software injected MSIs + as IPIs. Intended for system where IMSIC is trap-n-emulated, + and thus want to reduce MMIO traps when triggering IPIs + to multiple harts. + irqfixup [HW] When an interrupt is not handled search all handlers for it. Intended to get systems with badly broken diff --git a/drivers/irqchip/irq-riscv-imsic-early.c b/drivers/irqchip/irq-riscv-imsic-early.c index d9ae87808651..2709cacf4855 100644 --- a/drivers/irqchip/irq-riscv-imsic-early.c +++ b/drivers/irqchip/irq-riscv-imsic-early.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,14 @@ #include "irq-riscv-imsic-state.h" static int imsic_parent_irq; +bool imsic_noipi __ro_after_init; + +static int __init imsic_noipi_cfg(char *buf) +{ + imsic_noipi = true; + return 0; +} +early_param("irqchip.riscv_imsic_noipi", imsic_noipi_cfg); #ifdef CONFIG_SMP static void imsic_ipi_send(unsigned int cpu) @@ -32,12 +41,18 @@ static void imsic_ipi_send(unsigned int cpu) static void imsic_ipi_starting_cpu(void) { + if (imsic_noipi) + return; + /* Enable IPIs for current CPU. */ __imsic_id_set_enable(IMSIC_IPI_ID); } static void imsic_ipi_dying_cpu(void) { + if (imsic_noipi) + return; + /* Disable IPIs for current CPU. */ __imsic_id_clear_enable(IMSIC_IPI_ID); } @@ -46,6 +61,9 @@ static int __init imsic_ipi_domain_init(void) { int virq; + if (imsic_noipi) + return 0; + /* Create IMSIC IPI multiplexing */ virq = ipi_mux_create(IMSIC_NR_IPI, imsic_ipi_send); if (virq <= 0) @@ -88,7 +106,7 @@ static void imsic_handle_irq(struct irq_desc *desc) while ((local_id = csr_swap(CSR_TOPEI, 0))) { local_id >>= TOPEI_ID_SHIFT; - if (local_id == IMSIC_IPI_ID) { + if (!imsic_noipi && local_id == IMSIC_IPI_ID) { if (IS_ENABLED(CONFIG_SMP)) ipi_mux_process(); continue; diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c index 77670dd645ac..dc95ad856d80 100644 --- a/drivers/irqchip/irq-riscv-imsic-state.c +++ b/drivers/irqchip/irq-riscv-imsic-state.c @@ -134,7 +134,7 @@ static bool __imsic_local_sync(struct imsic_local_priv *lpriv) lockdep_assert_held(&lpriv->lock); for_each_set_bit(i, lpriv->dirty_bitmap, imsic->global.nr_ids + 1) { - if (!i || i == IMSIC_IPI_ID) + if (!i || (!imsic_noipi && i == IMSIC_IPI_ID)) goto skip; vec = &lpriv->vectors[i]; @@ -419,7 +419,7 @@ void imsic_vector_debug_show(struct seq_file *m, struct imsic_vector *vec, int i seq_printf(m, "%*starget_cpu : %5u\n", ind, "", vec->cpu); seq_printf(m, "%*starget_local_id : %5u\n", ind, "", vec->local_id); seq_printf(m, "%*sis_reserved : %5u\n", ind, "", - (vec->local_id <= IMSIC_IPI_ID) ? 1 : 0); + (!imsic_noipi && vec->local_id <= IMSIC_IPI_ID) ? 1 : 0); seq_printf(m, "%*sis_enabled : %5u\n", ind, "", is_enabled ? 1 : 0); seq_printf(m, "%*sis_move_pending : %5u\n", ind, "", mvec ? 1 : 0); if (mvec) { @@ -583,7 +583,8 @@ static int __init imsic_matrix_init(void) irq_matrix_assign_system(imsic->matrix, 0, false); /* Reserve IPI ID because it is special and used internally */ - irq_matrix_assign_system(imsic->matrix, IMSIC_IPI_ID, false); + if (!imsic_noipi) + irq_matrix_assign_system(imsic->matrix, IMSIC_IPI_ID, false); return 0; } diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h index 3202ffa4e849..57f951952b0c 100644 --- a/drivers/irqchip/irq-riscv-imsic-state.h +++ b/drivers/irqchip/irq-riscv-imsic-state.h @@ -61,6 +61,7 @@ struct imsic_priv { struct irq_domain *base_domain; }; +extern bool imsic_noipi; extern struct imsic_priv *imsic; void __imsic_eix_update(unsigned long base_id, unsigned long num_id, bool pend, bool val); From bc398dc4f3677ca381d5b64f8e55005131e68650 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 9 Jul 2025 20:45:01 +0200 Subject: [PATCH 27/28] irqchip/renesas-intc-irqpin: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Convert the Renesas INTC External IRQ Pin driver from SIMPLE_DEV_PM_OPS() to DEFINE_SIMPLE_DEV_PM_OPS() and pm_sleep_ptr(). This allows to drop the __maybe_unused annotations from its suspend callbacks, and reduces kernel size in case CONFIG_PM or CONFIG_PM_SLEEP is disabled. Signed-off-by: Geert Uytterhoeven Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/865e5274cc516d8c345048330a46e753e2bda677.1752086656.git.geert+renesas@glider.be --- drivers/irqchip/irq-renesas-intc-irqpin.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c index 117b74b635ea..7951292d2d9b 100644 --- a/drivers/irqchip/irq-renesas-intc-irqpin.c +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c @@ -570,7 +570,7 @@ static void intc_irqpin_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused intc_irqpin_suspend(struct device *dev) +static int intc_irqpin_suspend(struct device *dev) { struct intc_irqpin_priv *p = dev_get_drvdata(dev); @@ -580,7 +580,7 @@ static int __maybe_unused intc_irqpin_suspend(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(intc_irqpin_pm_ops, intc_irqpin_suspend, NULL); +static DEFINE_SIMPLE_DEV_PM_OPS(intc_irqpin_pm_ops, intc_irqpin_suspend, NULL); static struct platform_driver intc_irqpin_device_driver = { .probe = intc_irqpin_probe, @@ -588,7 +588,7 @@ static struct platform_driver intc_irqpin_device_driver = { .driver = { .name = "renesas_intc_irqpin", .of_match_table = intc_irqpin_dt_ids, - .pm = &intc_irqpin_pm_ops, + .pm = pm_sleep_ptr(&intc_irqpin_pm_ops), } }; From 2aad477b5b734f52825f7c31780222a5a17c06d3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 9 Jul 2025 20:45:42 +0200 Subject: [PATCH 28/28] irqchip/renesas-irqc: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Convert the Renesas IRQC driver from SIMPLE_DEV_PM_OPS() to DEFINE_SIMPLE_DEV_PM_OPS() and pm_sleep_ptr(). This allows to drop the __maybe_unused annotations from its suspend callback, and reduces kernel size in case CONFIG_PM or CONFIG_PM_SLEEP is disabled. Signed-off-by: Geert Uytterhoeven Signed-off-by: Thomas Gleixner Link: https://lore.kernel.org/all/5a14f9932da20ec46cde27f314414474072755ed.1752086718.git.geert+renesas@glider.be --- drivers/irqchip/irq-renesas-irqc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index b46bbb66c264..a20a6471b0e4 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -227,7 +227,7 @@ static void irqc_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused irqc_suspend(struct device *dev) +static int irqc_suspend(struct device *dev) { struct irqc_priv *p = dev_get_drvdata(dev); @@ -237,7 +237,7 @@ static int __maybe_unused irqc_suspend(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(irqc_pm_ops, irqc_suspend, NULL); +static DEFINE_SIMPLE_DEV_PM_OPS(irqc_pm_ops, irqc_suspend, NULL); static const struct of_device_id irqc_dt_ids[] = { { .compatible = "renesas,irqc", }, @@ -251,7 +251,7 @@ static struct platform_driver irqc_device_driver = { .driver = { .name = "renesas_irqc", .of_match_table = irqc_dt_ids, - .pm = &irqc_pm_ops, + .pm = pm_sleep_ptr(&irqc_pm_ops), } };