From 0435bcc4e5858c632c1b6d5afa637580d9779890 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:01 +0200 Subject: [PATCH 01/32] irqchip/bcm2712-mip: Fix OF node reference imbalance The init callback must not decrement the reference count of the provided irqchip OF node. This should not cause any trouble currently, but if the driver ever starts probe deferring it could lead to warnings about reference underflow and saturation. Fixes: 32c6c054661a ("irqchip: Add Broadcom BCM2712 MSI-X interrupt controller") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli --- drivers/irqchip/irq-bcm2712-mip.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/irqchip/irq-bcm2712-mip.c b/drivers/irqchip/irq-bcm2712-mip.c index 9bd7bc0bf6d5..256c2d59f717 100644 --- a/drivers/irqchip/irq-bcm2712-mip.c +++ b/drivers/irqchip/irq-bcm2712-mip.c @@ -239,7 +239,6 @@ static int __init mip_of_msi_init(struct device_node *node, struct device_node * int ret; pdev = of_find_device_by_node(node); - of_node_put(node); if (!pdev) return -EPROBE_DEFER; From a8452d1d59d46066051e676d5daa472cd08cb304 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:02 +0200 Subject: [PATCH 02/32] irqchip/bcm2712-mip: Fix section mismatch Platform drivers can be probed after their init sections have been discarded so the irqchip init callback must not live in init. Fixes: 32c6c054661a ("irqchip: Add Broadcom BCM2712 MSI-X interrupt controller") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli --- drivers/irqchip/irq-bcm2712-mip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-bcm2712-mip.c b/drivers/irqchip/irq-bcm2712-mip.c index 256c2d59f717..8466646e5a2d 100644 --- a/drivers/irqchip/irq-bcm2712-mip.c +++ b/drivers/irqchip/irq-bcm2712-mip.c @@ -232,7 +232,7 @@ static int mip_parse_dt(struct mip_priv *mip, struct device_node *np) return ret; } -static int __init mip_of_msi_init(struct device_node *node, struct device_node *parent) +static int mip_of_msi_init(struct device_node *node, struct device_node *parent) { struct platform_device *pdev; struct mip_priv *mip; From e9db5332caaf4789ae3bafe72f61ad8e6e0c2d81 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:03 +0200 Subject: [PATCH 03/32] irqchip/irq-bcm7038-l1: Fix section mismatch Platform drivers can be probed after their init sections have been discarded so the irqchip init callback must not live in init. Fixes: c057c799e379 ("irqchip/irq-bcm7038-l1: Switch to IRQCHIP_PLATFORM_DRIVER") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli --- drivers/irqchip/irq-bcm7038-l1.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index 04fac0cc857f..eda33bd5d080 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -219,9 +219,8 @@ static int bcm7038_l1_set_affinity(struct irq_data *d, } #endif -static int __init bcm7038_l1_init_one(struct device_node *dn, - unsigned int idx, - struct bcm7038_l1_chip *intc) +static int bcm7038_l1_init_one(struct device_node *dn, unsigned int idx, + struct bcm7038_l1_chip *intc) { struct resource res; resource_size_t sz; @@ -395,8 +394,7 @@ static const struct irq_domain_ops bcm7038_l1_domain_ops = { .map = bcm7038_l1_map, }; -static int __init bcm7038_l1_of_init(struct device_node *dn, - struct device_node *parent) +static int bcm7038_l1_of_init(struct device_node *dn, struct device_node *parent) { struct bcm7038_l1_chip *intc; int idx, ret; From bfc0c5beab1fde843677923cf008f41d583c980a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:04 +0200 Subject: [PATCH 04/32] irqchip/irq-bcm7120-l2: Fix section mismatch Platform drivers can be probed after their init sections have been discarded so the irqchip init callbacks must not live in init. Fixes: 3ac268d5ed22 ("irqchip/irq-bcm7120-l2: Switch to IRQCHIP_PLATFORM_DRIVER") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli --- drivers/irqchip/irq-bcm7120-l2.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index ff22c3104401..b6c85560c42e 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -143,8 +143,7 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, return 0; } -static int __init bcm7120_l2_intc_iomap_7120(struct device_node *dn, - struct bcm7120_l2_intc_data *data) +static int bcm7120_l2_intc_iomap_7120(struct device_node *dn, struct bcm7120_l2_intc_data *data) { int ret; @@ -177,8 +176,7 @@ static int __init bcm7120_l2_intc_iomap_7120(struct device_node *dn, return 0; } -static int __init bcm7120_l2_intc_iomap_3380(struct device_node *dn, - struct bcm7120_l2_intc_data *data) +static int bcm7120_l2_intc_iomap_3380(struct device_node *dn, struct bcm7120_l2_intc_data *data) { unsigned int gc_idx; @@ -208,10 +206,9 @@ static int __init bcm7120_l2_intc_iomap_3380(struct device_node *dn, return 0; } -static int __init bcm7120_l2_intc_probe(struct device_node *dn, - struct device_node *parent, +static int bcm7120_l2_intc_probe(struct device_node *dn, struct device_node *parent, int (*iomap_regs_fn)(struct device_node *, - struct bcm7120_l2_intc_data *), + struct bcm7120_l2_intc_data *), const char *intc_name) { unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; @@ -339,15 +336,13 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn, return ret; } -static int __init bcm7120_l2_intc_probe_7120(struct device_node *dn, - struct device_node *parent) +static int bcm7120_l2_intc_probe_7120(struct device_node *dn, struct device_node *parent) { return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_7120, "BCM7120 L2"); } -static int __init bcm7120_l2_intc_probe_3380(struct device_node *dn, - struct device_node *parent) +static int bcm7120_l2_intc_probe_3380(struct device_node *dn, struct device_node *parent) { return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_3380, "BCM3380 L2"); From bbe1775924478e95372c2f896064ab6446000713 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:05 +0200 Subject: [PATCH 05/32] irqchip/irq-brcmstb-l2: Fix section mismatch Platform drivers can be probed after their init sections have been discarded so the irqchip init callbacks must not live in init. Fixes: 51d9db5c8fbb ("irqchip/irq-brcmstb-l2: Switch to IRQCHIP_PLATFORM_DRIVER") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli --- drivers/irqchip/irq-brcmstb-l2.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index 1bec5b2cd3f0..53e67c6c01f7 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -138,10 +138,8 @@ static void brcmstb_l2_intc_resume(struct irq_data *d) irq_reg_writel(gc, ~b->saved_mask, ct->regs.enable); } -static int __init brcmstb_l2_intc_of_init(struct device_node *np, - struct device_node *parent, - const struct brcmstb_intc_init_params - *init_params) +static int brcmstb_l2_intc_of_init(struct device_node *np, struct device_node *parent, + const struct brcmstb_intc_init_params *init_params) { unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; unsigned int set = 0; @@ -257,14 +255,12 @@ static int __init brcmstb_l2_intc_of_init(struct device_node *np, return ret; } -static int __init brcmstb_l2_edge_intc_of_init(struct device_node *np, - struct device_node *parent) +static int brcmstb_l2_edge_intc_of_init(struct device_node *np, struct device_node *parent) { return brcmstb_l2_intc_of_init(np, parent, &l2_edge_intc_init); } -static int __init brcmstb_l2_lvl_intc_of_init(struct device_node *np, - struct device_node *parent) +static int brcmstb_l2_lvl_intc_of_init(struct device_node *np, struct device_node *parent) { return brcmstb_l2_intc_of_init(np, parent, &l2_lvl_intc_init); } From 64acfd8e680ff8992c101fe19aadb112ce551072 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:06 +0200 Subject: [PATCH 06/32] irqchip/imx-mu-msi: Fix section mismatch Platform drivers can be probed after their init sections have been discarded so the irqchip init callbacks must not live in init. Fixes: 70afdab904d2 ("irqchip: Add IMX MU MSI controller driver") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-imx-mu-msi.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/irqchip/irq-imx-mu-msi.c b/drivers/irqchip/irq-imx-mu-msi.c index d2a4e8a61a42..41df168aa7da 100644 --- a/drivers/irqchip/irq-imx-mu-msi.c +++ b/drivers/irqchip/irq-imx-mu-msi.c @@ -296,9 +296,8 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = { }, }; -static int __init imx_mu_of_init(struct device_node *dn, - struct device_node *parent, - const struct imx_mu_dcfg *cfg) +static int imx_mu_of_init(struct device_node *dn, struct device_node *parent, + const struct imx_mu_dcfg *cfg) { struct platform_device *pdev = of_find_device_by_node(dn); struct device_link *pd_link_a; @@ -416,20 +415,17 @@ static const struct dev_pm_ops imx_mu_pm_ops = { imx_mu_runtime_resume, NULL) }; -static int __init imx_mu_imx7ulp_of_init(struct device_node *dn, - struct device_node *parent) +static int imx_mu_imx7ulp_of_init(struct device_node *dn, struct device_node *parent) { return imx_mu_of_init(dn, parent, &imx_mu_cfg_imx7ulp); } -static int __init imx_mu_imx6sx_of_init(struct device_node *dn, - struct device_node *parent) +static int imx_mu_imx6sx_of_init(struct device_node *dn, struct device_node *parent) { return imx_mu_of_init(dn, parent, &imx_mu_cfg_imx6sx); } -static int __init imx_mu_imx8ulp_of_init(struct device_node *dn, - struct device_node *parent) +static int imx_mu_imx8ulp_of_init(struct device_node *dn, struct device_node *parent) { return imx_mu_of_init(dn, parent, &imx_mu_cfg_imx8ulp); } From 5b338fbb2b5b21d61a9eaba14dcf43108de30258 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:07 +0200 Subject: [PATCH 07/32] irqchip/renesas-rzg2l: Fix section mismatch Platform drivers can be probed after their init sections have been discarded so the irqchip init callbacks must not live in init. Fixes: d011c022efe27579 ("irqchip/renesas-rzg2l: Add support for RZ/Five SoC") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Geert Uytterhoeven --- drivers/irqchip/irq-renesas-rzg2l.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c index 2a54adeb4cc7..12b6eb150301 100644 --- a/drivers/irqchip/irq-renesas-rzg2l.c +++ b/drivers/irqchip/irq-renesas-rzg2l.c @@ -597,14 +597,12 @@ static int rzg2l_irqc_common_init(struct device_node *node, struct device_node * return 0; } -static int __init rzg2l_irqc_init(struct device_node *node, - struct device_node *parent) +static int rzg2l_irqc_init(struct device_node *node, struct device_node *parent) { return rzg2l_irqc_common_init(node, parent, &rzg2l_irqc_chip); } -static int __init rzfive_irqc_init(struct device_node *node, - struct device_node *parent) +static int rzfive_irqc_init(struct device_node *node, struct device_node *parent) { return rzg2l_irqc_common_init(node, parent, &rzfive_irqc_chip); } From f798bdb9aa81c425184f92e3d0b44d3b53d10da7 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:08 +0200 Subject: [PATCH 08/32] irqchip/starfive-jh8100: Fix section mismatch Platform drivers can be probed after their init sections have been discarded so the irqchip init callback must not live in init. Fixes: e4e535036173 ("irqchip: Add StarFive external interrupt controller") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Changhuang Liang --- drivers/irqchip/irq-starfive-jh8100-intc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-starfive-jh8100-intc.c b/drivers/irqchip/irq-starfive-jh8100-intc.c index 2460798ec158..117f2c651ebd 100644 --- a/drivers/irqchip/irq-starfive-jh8100-intc.c +++ b/drivers/irqchip/irq-starfive-jh8100-intc.c @@ -114,8 +114,7 @@ static void starfive_intc_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int __init starfive_intc_init(struct device_node *intc, - struct device_node *parent) +static int starfive_intc_init(struct device_node *intc, struct device_node *parent) { struct starfive_irq_chip *irqc; struct reset_control *rst; From 9b685058ca936752285c5520d351b828312ac965 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:09 +0200 Subject: [PATCH 09/32] irqchip/qcom-irq-combiner: Fix section mismatch Platform drivers can be probed after their init sections have been discarded so the probe callback must not live in init. Fixes: f20cc9b00c7b ("irqchip/qcom: Add IRQ combiner driver") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner --- drivers/irqchip/qcom-irq-combiner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/qcom-irq-combiner.c b/drivers/irqchip/qcom-irq-combiner.c index 18e696dc7f4d..9308088773be 100644 --- a/drivers/irqchip/qcom-irq-combiner.c +++ b/drivers/irqchip/qcom-irq-combiner.c @@ -222,7 +222,7 @@ static int get_registers(struct platform_device *pdev, struct combiner *comb) return 0; } -static int __init combiner_probe(struct platform_device *pdev) +static int combiner_probe(struct platform_device *pdev) { struct combiner *combiner; int nregs; From 3540d99c03a88d4ebf65026f1f1926d3af658fb1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:10 +0200 Subject: [PATCH 10/32] irqchip: Drop leftover brackets Drop some unnecessary brackets in platform_irqchip_probe() mistakenly left by commit 9322d1915f9d ("irqchip: Plug a OF node reference leak in platform_irqchip_probe()"). Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Geert Uytterhoeven --- drivers/irqchip/irqchip.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c index 0ee7b6b71f5f..652d20d2b07f 100644 --- a/drivers/irqchip/irqchip.c +++ b/drivers/irqchip/irqchip.c @@ -38,9 +38,8 @@ int platform_irqchip_probe(struct platform_device *pdev) struct device_node *par_np __free(device_node) = of_irq_find_parent(np); of_irq_init_cb_t irq_init_cb = of_device_get_match_data(&pdev->dev); - if (!irq_init_cb) { + if (!irq_init_cb) return -EINVAL; - } if (par_np == np) par_np = NULL; @@ -53,9 +52,8 @@ int platform_irqchip_probe(struct platform_device *pdev) * interrupt controller. The actual initialization callback of this * interrupt controller can check for specific domains as necessary. */ - if (par_np && !irq_find_matching_host(par_np, DOMAIN_BUS_ANY)) { + if (par_np && !irq_find_matching_host(par_np, DOMAIN_BUS_ANY)) return -EPROBE_DEFER; - } return irq_init_cb(np, par_np); } From 1e3e330c07076a0582385bbea029c9cc918fa30d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:46:11 +0200 Subject: [PATCH 11/32] irqchip: Pass platform device to platform drivers The IRQCHIP_PLATFORM_DRIVER macros can be used to convert OF irqchip drivers to platform drivers but currently reuse the OF init callback prototype that only takes OF nodes as arguments. This forces drivers to do reverse lookups of their struct devices during probe if they need them for things like dev_printk() and device managed resources. Half of the drivers doing reverse lookups also currently fail to release the additional reference taken during the lookup, while other drivers have had the reference leak plugged in various ways (e.g. using non-intuitive cleanup constructs which still confuse static checkers). Switch to using a probe callback that takes a platform device as its first argument to simplify drivers and plug the remaining (mostly benign) reference leaks. Fixes: 32c6c054661a ("irqchip: Add Broadcom BCM2712 MSI-X interrupt controller") Fixes: 70afdab904d2 ("irqchip: Add IMX MU MSI controller driver") Fixes: a6199bb514d8 ("irqchip: Add Qualcomm MPM controller driver") Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli Reviewed-by: Changhuang Liang --- drivers/irqchip/irq-bcm2712-mip.c | 10 ++----- drivers/irqchip/irq-bcm7038-l1.c | 5 ++-- drivers/irqchip/irq-bcm7120-l2.c | 20 ++++--------- drivers/irqchip/irq-brcmstb-l2.c | 21 ++++++------- drivers/irqchip/irq-imx-mu-msi.c | 24 +++++++-------- drivers/irqchip/irq-mchp-eic.c | 5 ++-- drivers/irqchip/irq-meson-gpio.c | 5 ++-- drivers/irqchip/irq-qcom-mpm.c | 6 ++-- drivers/irqchip/irq-renesas-rzg2l.c | 35 +++++++--------------- drivers/irqchip/irq-renesas-rzv2h.c | 32 ++++++-------------- drivers/irqchip/irq-starfive-jh8100-intc.c | 5 ++-- drivers/irqchip/irqchip.c | 6 ++-- drivers/irqchip/qcom-pdc.c | 5 ++-- include/linux/irqchip.h | 8 ++++- 14 files changed, 78 insertions(+), 109 deletions(-) diff --git a/drivers/irqchip/irq-bcm2712-mip.c b/drivers/irqchip/irq-bcm2712-mip.c index 8466646e5a2d..4761974ad650 100644 --- a/drivers/irqchip/irq-bcm2712-mip.c +++ b/drivers/irqchip/irq-bcm2712-mip.c @@ -232,16 +232,12 @@ static int mip_parse_dt(struct mip_priv *mip, struct device_node *np) return ret; } -static int mip_of_msi_init(struct device_node *node, struct device_node *parent) +static int mip_msi_probe(struct platform_device *pdev, struct device_node *parent) { - struct platform_device *pdev; + struct device_node *node = pdev->dev.of_node; struct mip_priv *mip; int ret; - pdev = of_find_device_by_node(node); - if (!pdev) - return -EPROBE_DEFER; - mip = kzalloc(sizeof(*mip), GFP_KERNEL); if (!mip) return -ENOMEM; @@ -284,7 +280,7 @@ static int mip_of_msi_init(struct device_node *node, struct device_node *parent) } IRQCHIP_PLATFORM_DRIVER_BEGIN(mip_msi) -IRQCHIP_MATCH("brcm,bcm2712-mip", mip_of_msi_init) +IRQCHIP_MATCH("brcm,bcm2712-mip", mip_msi_probe) IRQCHIP_PLATFORM_DRIVER_END(mip_msi) MODULE_DESCRIPTION("Broadcom BCM2712 MSI-X interrupt controller"); MODULE_AUTHOR("Phil Elwell "); diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index eda33bd5d080..821b288587ca 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -394,8 +394,9 @@ static const struct irq_domain_ops bcm7038_l1_domain_ops = { .map = bcm7038_l1_map, }; -static int bcm7038_l1_of_init(struct device_node *dn, struct device_node *parent) +static int bcm7038_l1_probe(struct platform_device *pdev, struct device_node *parent) { + struct device_node *dn = pdev->dev.of_node; struct bcm7038_l1_chip *intc; int idx, ret; @@ -453,7 +454,7 @@ static int bcm7038_l1_of_init(struct device_node *dn, struct device_node *parent } IRQCHIP_PLATFORM_DRIVER_BEGIN(bcm7038_l1) -IRQCHIP_MATCH("brcm,bcm7038-l1-intc", bcm7038_l1_of_init) +IRQCHIP_MATCH("brcm,bcm7038-l1-intc", bcm7038_l1_probe) IRQCHIP_PLATFORM_DRIVER_END(bcm7038_l1) MODULE_DESCRIPTION("Broadcom STB 7038-style L1/L2 interrupt controller"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index b6c85560c42e..518c9d4366a5 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -206,14 +206,14 @@ static int bcm7120_l2_intc_iomap_3380(struct device_node *dn, struct bcm7120_l2_ return 0; } -static int bcm7120_l2_intc_probe(struct device_node *dn, struct device_node *parent, +static int bcm7120_l2_intc_probe(struct platform_device *pdev, struct device_node *parent, int (*iomap_regs_fn)(struct device_node *, struct bcm7120_l2_intc_data *), const char *intc_name) { unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; + struct device_node *dn = pdev->dev.of_node; struct bcm7120_l2_intc_data *data; - struct platform_device *pdev; struct irq_chip_generic *gc; struct irq_chip_type *ct; int ret = 0; @@ -224,14 +224,7 @@ static int bcm7120_l2_intc_probe(struct device_node *dn, struct device_node *par if (!data) return -ENOMEM; - pdev = of_find_device_by_node(dn); - if (!pdev) { - ret = -ENODEV; - goto out_free_data; - } - data->num_parent_irqs = platform_irq_count(pdev); - put_device(&pdev->dev); if (data->num_parent_irqs <= 0) { pr_err("invalid number of parent interrupts\n"); ret = -ENOMEM; @@ -331,20 +324,19 @@ static int bcm7120_l2_intc_probe(struct device_node *dn, struct device_node *par if (data->map_base[idx]) iounmap(data->map_base[idx]); } -out_free_data: kfree(data); return ret; } -static int bcm7120_l2_intc_probe_7120(struct device_node *dn, struct device_node *parent) +static int bcm7120_l2_intc_probe_7120(struct platform_device *pdev, struct device_node *parent) { - return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_7120, + return bcm7120_l2_intc_probe(pdev, parent, bcm7120_l2_intc_iomap_7120, "BCM7120 L2"); } -static int bcm7120_l2_intc_probe_3380(struct device_node *dn, struct device_node *parent) +static int bcm7120_l2_intc_probe_3380(struct platform_device *pdev, struct device_node *parent) { - return bcm7120_l2_intc_probe(dn, parent, bcm7120_l2_intc_iomap_3380, + return bcm7120_l2_intc_probe(pdev, parent, bcm7120_l2_intc_iomap_3380, "BCM3380 L2"); } diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index 53e67c6c01f7..bb7078d6524f 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -138,11 +138,12 @@ static void brcmstb_l2_intc_resume(struct irq_data *d) irq_reg_writel(gc, ~b->saved_mask, ct->regs.enable); } -static int brcmstb_l2_intc_of_init(struct device_node *np, struct device_node *parent, - const struct brcmstb_intc_init_params *init_params) +static int brcmstb_l2_intc_probe(struct platform_device *pdev, struct device_node *parent, + const struct brcmstb_intc_init_params *init_params) { unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; unsigned int set = 0; + struct device_node *np = pdev->dev.of_node; struct brcmstb_l2_intc_data *data; struct irq_chip_type *ct; int ret; @@ -255,21 +256,21 @@ static int brcmstb_l2_intc_of_init(struct device_node *np, struct device_node *p return ret; } -static int brcmstb_l2_edge_intc_of_init(struct device_node *np, struct device_node *parent) +static int brcmstb_l2_edge_intc_probe(struct platform_device *pdev, struct device_node *parent) { - return brcmstb_l2_intc_of_init(np, parent, &l2_edge_intc_init); + return brcmstb_l2_intc_probe(pdev, parent, &l2_edge_intc_init); } -static int brcmstb_l2_lvl_intc_of_init(struct device_node *np, struct device_node *parent) +static int brcmstb_l2_lvl_intc_probe(struct platform_device *pdev, struct device_node *parent) { - return brcmstb_l2_intc_of_init(np, parent, &l2_lvl_intc_init); + return brcmstb_l2_intc_probe(pdev, parent, &l2_lvl_intc_init); } IRQCHIP_PLATFORM_DRIVER_BEGIN(brcmstb_l2) -IRQCHIP_MATCH("brcm,l2-intc", brcmstb_l2_edge_intc_of_init) -IRQCHIP_MATCH("brcm,hif-spi-l2-intc", brcmstb_l2_edge_intc_of_init) -IRQCHIP_MATCH("brcm,upg-aux-aon-l2-intc", brcmstb_l2_edge_intc_of_init) -IRQCHIP_MATCH("brcm,bcm7271-l2-intc", brcmstb_l2_lvl_intc_of_init) +IRQCHIP_MATCH("brcm,l2-intc", brcmstb_l2_edge_intc_probe) +IRQCHIP_MATCH("brcm,hif-spi-l2-intc", brcmstb_l2_edge_intc_probe) +IRQCHIP_MATCH("brcm,upg-aux-aon-l2-intc", brcmstb_l2_edge_intc_probe) +IRQCHIP_MATCH("brcm,bcm7271-l2-intc", brcmstb_l2_lvl_intc_probe) IRQCHIP_PLATFORM_DRIVER_END(brcmstb_l2) MODULE_DESCRIPTION("Broadcom STB generic L2 interrupt controller"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/irq-imx-mu-msi.c b/drivers/irqchip/irq-imx-mu-msi.c index 41df168aa7da..c598f2f52fc6 100644 --- a/drivers/irqchip/irq-imx-mu-msi.c +++ b/drivers/irqchip/irq-imx-mu-msi.c @@ -296,10 +296,9 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = { }, }; -static int imx_mu_of_init(struct device_node *dn, struct device_node *parent, - const struct imx_mu_dcfg *cfg) +static int imx_mu_probe(struct platform_device *pdev, struct device_node *parent, + const struct imx_mu_dcfg *cfg) { - struct platform_device *pdev = of_find_device_by_node(dn); struct device_link *pd_link_a; struct device_link *pd_link_b; struct imx_mu_msi *msi_data; @@ -415,28 +414,27 @@ static const struct dev_pm_ops imx_mu_pm_ops = { imx_mu_runtime_resume, NULL) }; -static int imx_mu_imx7ulp_of_init(struct device_node *dn, struct device_node *parent) +static int imx_mu_imx7ulp_probe(struct platform_device *pdev, struct device_node *parent) { - return imx_mu_of_init(dn, parent, &imx_mu_cfg_imx7ulp); + return imx_mu_probe(pdev, parent, &imx_mu_cfg_imx7ulp); } -static int imx_mu_imx6sx_of_init(struct device_node *dn, struct device_node *parent) +static int imx_mu_imx6sx_probe(struct platform_device *pdev, struct device_node *parent) { - return imx_mu_of_init(dn, parent, &imx_mu_cfg_imx6sx); + return imx_mu_probe(pdev, parent, &imx_mu_cfg_imx6sx); } -static int imx_mu_imx8ulp_of_init(struct device_node *dn, struct device_node *parent) +static int imx_mu_imx8ulp_probe(struct platform_device *pdev, struct device_node *parent) { - return imx_mu_of_init(dn, parent, &imx_mu_cfg_imx8ulp); + return imx_mu_probe(pdev, parent, &imx_mu_cfg_imx8ulp); } IRQCHIP_PLATFORM_DRIVER_BEGIN(imx_mu_msi) -IRQCHIP_MATCH("fsl,imx7ulp-mu-msi", imx_mu_imx7ulp_of_init) -IRQCHIP_MATCH("fsl,imx6sx-mu-msi", imx_mu_imx6sx_of_init) -IRQCHIP_MATCH("fsl,imx8ulp-mu-msi", imx_mu_imx8ulp_of_init) +IRQCHIP_MATCH("fsl,imx7ulp-mu-msi", imx_mu_imx7ulp_probe) +IRQCHIP_MATCH("fsl,imx6sx-mu-msi", imx_mu_imx6sx_probe) +IRQCHIP_MATCH("fsl,imx8ulp-mu-msi", imx_mu_imx8ulp_probe) IRQCHIP_PLATFORM_DRIVER_END(imx_mu_msi, .pm = &imx_mu_pm_ops) - MODULE_AUTHOR("Frank Li "); MODULE_DESCRIPTION("Freescale MU MSI controller driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/irqchip/irq-mchp-eic.c b/drivers/irqchip/irq-mchp-eic.c index 516a3a0e359c..b513a899c085 100644 --- a/drivers/irqchip/irq-mchp-eic.c +++ b/drivers/irqchip/irq-mchp-eic.c @@ -199,8 +199,9 @@ static const struct irq_domain_ops mchp_eic_domain_ops = { .free = irq_domain_free_irqs_common, }; -static int mchp_eic_init(struct device_node *node, struct device_node *parent) +static int mchp_eic_probe(struct platform_device *pdev, struct device_node *parent) { + struct device_node *node = pdev->dev.of_node; struct irq_domain *parent_domain = NULL; int ret, i; @@ -273,7 +274,7 @@ static int mchp_eic_init(struct device_node *node, struct device_node *parent) } IRQCHIP_PLATFORM_DRIVER_BEGIN(mchp_eic) -IRQCHIP_MATCH("microchip,sama7g5-eic", mchp_eic_init) +IRQCHIP_MATCH("microchip,sama7g5-eic", mchp_eic_probe) IRQCHIP_PLATFORM_DRIVER_END(mchp_eic) MODULE_DESCRIPTION("Microchip External Interrupt Controller"); diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c index 7d177626d64b..09ebf1d9c21b 100644 --- a/drivers/irqchip/irq-meson-gpio.c +++ b/drivers/irqchip/irq-meson-gpio.c @@ -572,8 +572,9 @@ static int meson_gpio_irq_parse_dt(struct device_node *node, struct meson_gpio_i return 0; } -static int meson_gpio_irq_of_init(struct device_node *node, struct device_node *parent) +static int meson_gpio_irq_probe(struct platform_device *pdev, struct device_node *parent) { + struct device_node *node = pdev->dev.of_node; struct irq_domain *domain, *parent_domain; struct meson_gpio_irq_controller *ctl; int ret; @@ -630,7 +631,7 @@ static int meson_gpio_irq_of_init(struct device_node *node, struct device_node * } IRQCHIP_PLATFORM_DRIVER_BEGIN(meson_gpio_intc) -IRQCHIP_MATCH("amlogic,meson-gpio-intc", meson_gpio_irq_of_init) +IRQCHIP_MATCH("amlogic,meson-gpio-intc", meson_gpio_irq_probe) IRQCHIP_PLATFORM_DRIVER_END(meson_gpio_intc) MODULE_AUTHOR("Jerome Brunet "); diff --git a/drivers/irqchip/irq-qcom-mpm.c b/drivers/irqchip/irq-qcom-mpm.c index 8d569f7c5a7a..83f31ea657b7 100644 --- a/drivers/irqchip/irq-qcom-mpm.c +++ b/drivers/irqchip/irq-qcom-mpm.c @@ -320,9 +320,9 @@ static bool gic_hwirq_is_mapped(struct mpm_gic_map *maps, int cnt, u32 hwirq) return false; } -static int qcom_mpm_init(struct device_node *np, struct device_node *parent) +static int qcom_mpm_probe(struct platform_device *pdev, struct device_node *parent) { - struct platform_device *pdev = of_find_device_by_node(np); + struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; struct irq_domain *parent_domain; struct generic_pm_domain *genpd; @@ -478,7 +478,7 @@ static int qcom_mpm_init(struct device_node *np, struct device_node *parent) } IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_mpm) -IRQCHIP_MATCH("qcom,mpm", qcom_mpm_init) +IRQCHIP_MATCH("qcom,mpm", qcom_mpm_probe) IRQCHIP_PLATFORM_DRIVER_END(qcom_mpm) MODULE_DESCRIPTION("Qualcomm Technologies, Inc. MSM Power Manager"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/irqchip/irq-renesas-rzg2l.c b/drivers/irqchip/irq-renesas-rzg2l.c index 12b6eb150301..1bf19deb02c4 100644 --- a/drivers/irqchip/irq-renesas-rzg2l.c +++ b/drivers/irqchip/irq-renesas-rzg2l.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include @@ -528,18 +527,15 @@ static int rzg2l_irqc_parse_interrupts(struct rzg2l_irqc_priv *priv, return 0; } -static int rzg2l_irqc_common_init(struct device_node *node, struct device_node *parent, - const struct irq_chip *irq_chip) +static int rzg2l_irqc_common_probe(struct platform_device *pdev, struct device_node *parent, + const struct irq_chip *irq_chip) { - struct platform_device *pdev = of_find_device_by_node(node); - struct device *dev __free(put_device) = pdev ? &pdev->dev : NULL; struct irq_domain *irq_domain, *parent_domain; + struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; struct reset_control *resetn; int ret; - if (!pdev) - return -ENODEV; - parent_domain = irq_find_host(parent); if (!parent_domain) return dev_err_probe(dev, -ENODEV, "cannot find parent domain\n"); @@ -583,33 +579,22 @@ static int rzg2l_irqc_common_init(struct device_node *node, struct device_node * register_syscore_ops(&rzg2l_irqc_syscore_ops); - /* - * Prevent the cleanup function from invoking put_device by assigning - * NULL to dev. - * - * make coccicheck will complain about missing put_device calls, but - * those are false positives, as dev will be automatically "put" via - * __free_put_device on the failing path. - * On the successful path we don't actually want to "put" dev. - */ - dev = NULL; - return 0; } -static int rzg2l_irqc_init(struct device_node *node, struct device_node *parent) +static int rzg2l_irqc_probe(struct platform_device *pdev, struct device_node *parent) { - return rzg2l_irqc_common_init(node, parent, &rzg2l_irqc_chip); + return rzg2l_irqc_common_probe(pdev, parent, &rzg2l_irqc_chip); } -static int rzfive_irqc_init(struct device_node *node, struct device_node *parent) +static int rzfive_irqc_probe(struct platform_device *pdev, struct device_node *parent) { - return rzg2l_irqc_common_init(node, parent, &rzfive_irqc_chip); + return rzg2l_irqc_common_probe(pdev, parent, &rzfive_irqc_chip); } IRQCHIP_PLATFORM_DRIVER_BEGIN(rzg2l_irqc) -IRQCHIP_MATCH("renesas,rzg2l-irqc", rzg2l_irqc_init) -IRQCHIP_MATCH("renesas,r9a07g043f-irqc", rzfive_irqc_init) +IRQCHIP_MATCH("renesas,rzg2l-irqc", rzg2l_irqc_probe) +IRQCHIP_MATCH("renesas,r9a07g043f-irqc", rzfive_irqc_probe) IRQCHIP_PLATFORM_DRIVER_END(rzg2l_irqc) MODULE_AUTHOR("Lad Prabhakar "); MODULE_DESCRIPTION("Renesas RZ/G2L IRQC Driver"); diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c index 9018d9c3911e..899a423b5da8 100644 --- a/drivers/irqchip/irq-renesas-rzv2h.c +++ b/drivers/irqchip/irq-renesas-rzv2h.c @@ -490,29 +490,15 @@ static int rzv2h_icu_parse_interrupts(struct rzv2h_icu_priv *priv, struct device return 0; } -static void rzv2h_icu_put_device(void *data) -{ - put_device(data); -} - -static int rzv2h_icu_init_common(struct device_node *node, struct device_node *parent, - const struct rzv2h_hw_info *hw_info) +static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_node *parent, + const struct rzv2h_hw_info *hw_info) { struct irq_domain *irq_domain, *parent_domain; + struct device_node *node = pdev->dev.of_node; struct rzv2h_icu_priv *rzv2h_icu_data; - struct platform_device *pdev; struct reset_control *resetn; int ret; - pdev = of_find_device_by_node(node); - if (!pdev) - return -ENODEV; - - ret = devm_add_action_or_reset(&pdev->dev, rzv2h_icu_put_device, - &pdev->dev); - if (ret < 0) - return ret; - parent_domain = irq_find_host(parent); if (!parent_domain) { dev_err(&pdev->dev, "cannot find parent domain\n"); @@ -618,19 +604,19 @@ static const struct rzv2h_hw_info rzv2h_hw_params = { .field_width = 8, }; -static int rzg3e_icu_init(struct device_node *node, struct device_node *parent) +static int rzg3e_icu_probe(struct platform_device *pdev, struct device_node *parent) { - return rzv2h_icu_init_common(node, parent, &rzg3e_hw_params); + return rzv2h_icu_probe_common(pdev, parent, &rzg3e_hw_params); } -static int rzv2h_icu_init(struct device_node *node, struct device_node *parent) +static int rzv2h_icu_probe(struct platform_device *pdev, struct device_node *parent) { - return rzv2h_icu_init_common(node, parent, &rzv2h_hw_params); + return rzv2h_icu_probe_common(pdev, parent, &rzv2h_hw_params); } IRQCHIP_PLATFORM_DRIVER_BEGIN(rzv2h_icu) -IRQCHIP_MATCH("renesas,r9a09g047-icu", rzg3e_icu_init) -IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_init) +IRQCHIP_MATCH("renesas,r9a09g047-icu", rzg3e_icu_probe) +IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_probe) IRQCHIP_PLATFORM_DRIVER_END(rzv2h_icu) MODULE_AUTHOR("Fabrizio Castro "); MODULE_DESCRIPTION("Renesas RZ/V2H(P) ICU Driver"); diff --git a/drivers/irqchip/irq-starfive-jh8100-intc.c b/drivers/irqchip/irq-starfive-jh8100-intc.c index 117f2c651ebd..705361b4ebe0 100644 --- a/drivers/irqchip/irq-starfive-jh8100-intc.c +++ b/drivers/irqchip/irq-starfive-jh8100-intc.c @@ -114,8 +114,9 @@ static void starfive_intc_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int starfive_intc_init(struct device_node *intc, struct device_node *parent) +static int starfive_intc_probe(struct platform_device *pdev, struct device_node *parent) { + struct device_node *intc = pdev->dev.of_node; struct starfive_irq_chip *irqc; struct reset_control *rst; struct clk *clk; @@ -198,7 +199,7 @@ static int starfive_intc_init(struct device_node *intc, struct device_node *pare } IRQCHIP_PLATFORM_DRIVER_BEGIN(starfive_intc) -IRQCHIP_MATCH("starfive,jh8100-intc", starfive_intc_init) +IRQCHIP_MATCH("starfive,jh8100-intc", starfive_intc_probe) IRQCHIP_PLATFORM_DRIVER_END(starfive_intc) MODULE_DESCRIPTION("StarFive JH8100 External Interrupt Controller"); diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c index 652d20d2b07f..689c8e448901 100644 --- a/drivers/irqchip/irqchip.c +++ b/drivers/irqchip/irqchip.c @@ -36,9 +36,9 @@ int platform_irqchip_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device_node *par_np __free(device_node) = of_irq_find_parent(np); - of_irq_init_cb_t irq_init_cb = of_device_get_match_data(&pdev->dev); + platform_irq_probe_t irq_probe = of_device_get_match_data(&pdev->dev); - if (!irq_init_cb) + if (!irq_probe) return -EINVAL; if (par_np == np) @@ -55,6 +55,6 @@ int platform_irqchip_probe(struct platform_device *pdev) if (par_np && !irq_find_matching_host(par_np, DOMAIN_BUS_ANY)) return -EPROBE_DEFER; - return irq_init_cb(np, par_np); + return irq_probe(pdev, par_np); } EXPORT_SYMBOL_GPL(platform_irqchip_probe); diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c index 52d77546aacb..518f7f0f3dab 100644 --- a/drivers/irqchip/qcom-pdc.c +++ b/drivers/irqchip/qcom-pdc.c @@ -350,9 +350,10 @@ static int pdc_setup_pin_mapping(struct device_node *np) #define QCOM_PDC_SIZE 0x30000 -static int qcom_pdc_init(struct device_node *node, struct device_node *parent) +static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *parent) { struct irq_domain *parent_domain, *pdc_domain; + struct device_node *node = pdev->dev.of_node; resource_size_t res_size; struct resource res; int ret; @@ -428,7 +429,7 @@ static int qcom_pdc_init(struct device_node *node, struct device_node *parent) } IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_pdc) -IRQCHIP_MATCH("qcom,pdc", qcom_pdc_init) +IRQCHIP_MATCH("qcom,pdc", qcom_pdc_probe) IRQCHIP_PLATFORM_DRIVER_END(qcom_pdc) MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Power Domain Controller"); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/irqchip.h b/include/linux/irqchip.h index d5e6024cb2a8..bc4ddacd6ddc 100644 --- a/include/linux/irqchip.h +++ b/include/linux/irqchip.h @@ -17,12 +17,18 @@ #include #include +typedef int (*platform_irq_probe_t)(struct platform_device *, struct device_node *); + /* Undefined on purpose */ extern of_irq_init_cb_t typecheck_irq_init_cb; +extern platform_irq_probe_t typecheck_irq_probe; #define typecheck_irq_init_cb(fn) \ (__typecheck(typecheck_irq_init_cb, &fn) ? fn : fn) +#define typecheck_irq_probe(fn) \ + (__typecheck(typecheck_irq_probe, &fn) ? fn : fn) + /* * This macro must be used by the different irqchip drivers to declare * the association between their DT compatible string and their @@ -42,7 +48,7 @@ extern int platform_irqchip_probe(struct platform_device *pdev); static const struct of_device_id drv_name##_irqchip_match_table[] = { #define IRQCHIP_MATCH(compat, fn) { .compatible = compat, \ - .data = typecheck_irq_init_cb(fn), }, + .data = typecheck_irq_probe(fn), }, #define IRQCHIP_PLATFORM_DRIVER_END(drv_name, ...) \ From 1230fbb225abf3f04c64697c6b0f8dfb473b3790 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:50:27 +0200 Subject: [PATCH 12/32] irqchip: Enable compile testing of Broadcom drivers There seems to be nothing preventing the Broadcom drivers from being compile tested so enable that for wider build coverage. Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli --- drivers/irqchip/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index a61c6dc63c29..9b7153777688 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -151,7 +151,7 @@ config BCM6345_L1_IRQ config BCM7038_L1_IRQ tristate "Broadcom STB 7038-style L1/L2 interrupt controller driver" - depends on ARCH_BRCMSTB || BMIPS_GENERIC + depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST default ARCH_BRCMSTB || BMIPS_GENERIC select GENERIC_IRQ_CHIP select IRQ_DOMAIN @@ -159,14 +159,14 @@ config BCM7038_L1_IRQ config BCM7120_L2_IRQ tristate "Broadcom STB 7120-style L2 interrupt controller driver" - depends on ARCH_BRCMSTB || BMIPS_GENERIC + depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST default ARCH_BRCMSTB || BMIPS_GENERIC select GENERIC_IRQ_CHIP select IRQ_DOMAIN config BRCMSTB_L2_IRQ tristate "Broadcom STB generic L2 interrupt controller driver" - depends on ARCH_BCM2835 || ARCH_BRCMSTB || BMIPS_GENERIC + depends on ARCH_BCM2835 || ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST default ARCH_BCM2835 || ARCH_BRCMSTB || BMIPS_GENERIC select GENERIC_IRQ_CHIP select IRQ_DOMAIN From 867c6aa283fbc1e9eded7d4f2cd7b3f9f4cb5e9e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:54:26 +0200 Subject: [PATCH 13/32] irqchip/meson-gpio: Drop unused module alias The driver has never supported anything but OF probing so drop the unused platform alias that was erroneously added by commit a947aa00edd4 ("irqchip/meson-gpio: Make it possible to build as a module"). Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-meson-gpio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c index 09ebf1d9c21b..6c5e2ff0d1cf 100644 --- a/drivers/irqchip/irq-meson-gpio.c +++ b/drivers/irqchip/irq-meson-gpio.c @@ -637,4 +637,3 @@ IRQCHIP_PLATFORM_DRIVER_END(meson_gpio_intc) MODULE_AUTHOR("Jerome Brunet "); MODULE_DESCRIPTION("Meson GPIO Interrupt Multiplexer driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:meson-gpio-intc"); From b03127a4e778435bd90794e654834f94860c80e9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:54:27 +0200 Subject: [PATCH 14/32] irqchip/mvebu-pic: Drop unused module alias The driver has never supported anything but OF probing so drop the unused platform alias. Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner Reviewed-by: Andrew Lunn --- drivers/irqchip/irq-mvebu-pic.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/irqchip/irq-mvebu-pic.c b/drivers/irqchip/irq-mvebu-pic.c index cd8b73482b9f..10b85128183a 100644 --- a/drivers/irqchip/irq-mvebu-pic.c +++ b/drivers/irqchip/irq-mvebu-pic.c @@ -195,5 +195,3 @@ MODULE_AUTHOR("Yehuda Yitschak "); MODULE_AUTHOR("Thomas Petazzoni "); MODULE_DESCRIPTION("Marvell Armada 7K/8K PIC driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:mvebu_pic"); - From dcc31768ffc1571407cf9b52f96f0505b0573450 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Oct 2025 11:54:28 +0200 Subject: [PATCH 15/32] irqchip/ts4800: Drop unused module alias The driver has never supported anything but OF probing so drop the unused platform alias. Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-ts4800.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/irqchip/irq-ts4800.c b/drivers/irqchip/irq-ts4800.c index 1e236d5b7516..2e4013c6834d 100644 --- a/drivers/irqchip/irq-ts4800.c +++ b/drivers/irqchip/irq-ts4800.c @@ -165,4 +165,3 @@ module_platform_driver(ts4800_ic_driver); MODULE_AUTHOR("Damien Riegel "); MODULE_DESCRIPTION("Multiplexed-IRQs driver for TS-4800's FPGA"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:ts4800_irqc"); From c475c0b71314b222af576f93e2d32df077f14ad2 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 15 Oct 2025 12:55:12 -0700 Subject: [PATCH 16/32] irqchip/riscv-imsic: Remove redundant irq_data lookups imsic_irq_set_affinity() already takes the irq_data pointer as a parameter, so it is pointless to look it up again from the IRQ number. Signed-off-by: Samuel Holland Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-riscv-imsic-platform.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-riscv-imsic-platform.c b/drivers/irqchip/irq-riscv-imsic-platform.c index 643c8e459611..7228a33f6c37 100644 --- a/drivers/irqchip/irq-riscv-imsic-platform.c +++ b/drivers/irqchip/irq-riscv-imsic-platform.c @@ -158,11 +158,11 @@ static int imsic_irq_set_affinity(struct irq_data *d, const struct cpumask *mask tmp_vec.local_id = new_vec->local_id; /* Point device to the temporary vector */ - imsic_msi_update_msg(irq_get_irq_data(d->irq), &tmp_vec); + imsic_msi_update_msg(d, &tmp_vec); } /* Point device to the new vector */ - imsic_msi_update_msg(irq_get_irq_data(d->irq), new_vec); + imsic_msi_update_msg(d, new_vec); /* Update irq descriptors with the new vector */ d->chip_data = new_vec; From 79eaabc61dfbf5a4b680f42d3a113d05333c3960 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 15 Oct 2025 12:55:13 -0700 Subject: [PATCH 17/32] irqchip/riscv-imsic: Embed the vector array in lpriv Reduce pointer chasing and the number of allocations by using a flexible array member for the vector array instead of a separate allocation. Signed-off-by: Samuel Holland Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-riscv-imsic-state.c | 10 ++-------- drivers/irqchip/irq-riscv-imsic-state.h | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c index dc95ad856d80..9a499efdebe3 100644 --- a/drivers/irqchip/irq-riscv-imsic-state.c +++ b/drivers/irqchip/irq-riscv-imsic-state.c @@ -487,7 +487,6 @@ static void __init imsic_local_cleanup(void) lpriv = per_cpu_ptr(imsic->lpriv, cpu); bitmap_free(lpriv->dirty_bitmap); - kfree(lpriv->vectors); } free_percpu(imsic->lpriv); @@ -501,7 +500,8 @@ static int __init imsic_local_init(void) int cpu, i; /* Allocate per-CPU private state */ - imsic->lpriv = alloc_percpu(typeof(*imsic->lpriv)); + imsic->lpriv = __alloc_percpu(struct_size(imsic->lpriv, vectors, global->nr_ids + 1), + __alignof__(*imsic->lpriv)); if (!imsic->lpriv) return -ENOMEM; @@ -521,12 +521,6 @@ static int __init imsic_local_init(void) timer_setup(&lpriv->timer, imsic_local_timer_callback, TIMER_PINNED); #endif - /* Allocate vector array */ - lpriv->vectors = kcalloc(global->nr_ids + 1, sizeof(*lpriv->vectors), - GFP_KERNEL); - if (!lpriv->vectors) - goto fail_local_cleanup; - /* Setup vector array */ for (i = 0; i <= global->nr_ids; i++) { vec = &lpriv->vectors[i]; diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h index 57f951952b0c..196457f1bbca 100644 --- a/drivers/irqchip/irq-riscv-imsic-state.h +++ b/drivers/irqchip/irq-riscv-imsic-state.h @@ -40,7 +40,7 @@ struct imsic_local_priv { #endif /* Local vector table */ - struct imsic_vector *vectors; + struct imsic_vector vectors[]; }; struct imsic_priv { From 3a16b053840e04c45325dc313a23986ec7f37a50 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Wed, 15 Oct 2025 12:55:14 -0700 Subject: [PATCH 18/32] irqchip/riscv-imsic: Inline imsic_vector_from_local_id() This function is only called from one place, which is in the interrupt handling hot path. Inline it to improve code generation and to take advantage of this_cpu operations. lpriv and imsic->base_domain can never be NULL because irq_set_chained_handler() is called after they are allocated. Signed-off-by: Samuel Holland Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-riscv-imsic-early.c | 11 +++-------- drivers/irqchip/irq-riscv-imsic-state.c | 10 ---------- drivers/irqchip/irq-riscv-imsic-state.h | 2 -- 3 files changed, 3 insertions(+), 20 deletions(-) diff --git a/drivers/irqchip/irq-riscv-imsic-early.c b/drivers/irqchip/irq-riscv-imsic-early.c index 2c4c682627b8..6bac67cc0b6d 100644 --- a/drivers/irqchip/irq-riscv-imsic-early.c +++ b/drivers/irqchip/irq-riscv-imsic-early.c @@ -91,9 +91,8 @@ static int __init imsic_ipi_domain_init(void) { return 0; } */ static void imsic_handle_irq(struct irq_desc *desc) { + struct imsic_local_priv *lpriv = this_cpu_ptr(imsic->lpriv); struct irq_chip *chip = irq_desc_get_chip(desc); - int cpu = smp_processor_id(); - struct imsic_vector *vec; unsigned long local_id; /* @@ -113,16 +112,12 @@ static void imsic_handle_irq(struct irq_desc *desc) continue; } - if (unlikely(!imsic->base_domain)) - continue; - - vec = imsic_vector_from_local_id(cpu, local_id); - if (!vec) { + if (unlikely(local_id > imsic->global.nr_ids)) { pr_warn_ratelimited("vector not found for local ID 0x%lx\n", local_id); continue; } - generic_handle_irq(vec->irq); + generic_handle_irq(lpriv->vectors[local_id].irq); } chained_irq_exit(chip, desc); diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c index 9a499efdebe3..385368052d5c 100644 --- a/drivers/irqchip/irq-riscv-imsic-state.c +++ b/drivers/irqchip/irq-riscv-imsic-state.c @@ -434,16 +434,6 @@ void imsic_vector_debug_show_summary(struct seq_file *m, int ind) } #endif -struct imsic_vector *imsic_vector_from_local_id(unsigned int cpu, unsigned int local_id) -{ - struct imsic_local_priv *lpriv = per_cpu_ptr(imsic->lpriv, cpu); - - if (!lpriv || imsic->global.nr_ids < local_id) - return NULL; - - return &lpriv->vectors[local_id]; -} - struct imsic_vector *imsic_vector_alloc(unsigned int irq, const struct cpumask *mask) { struct imsic_vector *vec = NULL; diff --git a/drivers/irqchip/irq-riscv-imsic-state.h b/drivers/irqchip/irq-riscv-imsic-state.h index 196457f1bbca..6332501dcbd8 100644 --- a/drivers/irqchip/irq-riscv-imsic-state.h +++ b/drivers/irqchip/irq-riscv-imsic-state.h @@ -95,8 +95,6 @@ static inline struct imsic_vector *imsic_vector_get_move(struct imsic_vector *ve void imsic_vector_force_move_cleanup(struct imsic_vector *vec); void imsic_vector_move(struct imsic_vector *old_vec, struct imsic_vector *new_vec); -struct imsic_vector *imsic_vector_from_local_id(unsigned int cpu, unsigned int local_id); - struct imsic_vector *imsic_vector_alloc(unsigned int irq, const struct cpumask *mask); void imsic_vector_free(struct imsic_vector *vector); From a7f25e00c4c97d4842117fba06b4c6064ba1e354 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 17 Oct 2025 07:52:26 +0200 Subject: [PATCH 19/32] irqchip/qcom-irq-combiner: Rename driver structure The "_probe" suffix of the driver structure name prevents modpost from warning about section mismatches so replace it to catch any future issues like the recently fixed probe function being incorrectly marked as __init. Signed-off-by: Johan Hovold Signed-off-by: Thomas Gleixner --- drivers/irqchip/qcom-irq-combiner.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/qcom-irq-combiner.c b/drivers/irqchip/qcom-irq-combiner.c index 9308088773be..09819007d08e 100644 --- a/drivers/irqchip/qcom-irq-combiner.c +++ b/drivers/irqchip/qcom-irq-combiner.c @@ -266,11 +266,11 @@ static const struct acpi_device_id qcom_irq_combiner_ids[] = { { } }; -static struct platform_driver qcom_irq_combiner_probe = { +static struct platform_driver qcom_irq_combiner_driver = { .driver = { .name = "qcom-irq-combiner", .acpi_match_table = ACPI_PTR(qcom_irq_combiner_ids), }, .probe = combiner_probe, }; -builtin_platform_driver(qcom_irq_combiner_probe); +builtin_platform_driver(qcom_irq_combiner_driver); From e95f66dd0e74d654e5ff344c72cfd6bd9f6c60a3 Mon Sep 17 00:00:00 2001 From: Lucas Zampieri Date: Fri, 24 Oct 2025 09:36:40 +0100 Subject: [PATCH 20/32] dt-bindings: vendor-prefixes: Add UltraRISC Add vendor prefix for UltraRISC Technology Co., Ltd. Signed-off-by: Lucas Zampieri Signed-off-by: Thomas Gleixner Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20251024083647.475239-2-lzampier@redhat.com --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index f1d1882009ba..647746e6f75f 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1705,6 +1705,8 @@ patternProperties: description: Universal Scientific Industrial Co., Ltd. "^usr,.*": description: U.S. Robotics Corporation + "^ultrarisc,.*": + description: UltraRISC Technology Co., Ltd. "^ultratronik,.*": description: Ultratronik GmbH "^utoo,.*": From 9dfb295a93eb109be989aac48f675db5b1c68bd8 Mon Sep 17 00:00:00 2001 From: Charles Mirabile Date: Fri, 24 Oct 2025 09:36:41 +0100 Subject: [PATCH 21/32] dt-bindings: interrupt-controller: Add UltraRISC DP1000 PLIC Add compatible strings for the PLIC found in UltraRISC DP1000 SoC. The PLIC is part of the UR-CP100 core and has a hardware bug requiring a workaround. Signed-off-by: Charles Mirabile Signed-off-by: Lucas Zampieri Signed-off-by: Thomas Gleixner Acked-by: Conor Dooley Link: https://patch.msgid.link/20251024083647.475239-3-lzampier@redhat.com --- .../bindings/interrupt-controller/sifive,plic-1.0.0.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml index f683d696909b..234cdc2a1a26 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml @@ -75,6 +75,9 @@ properties: - sophgo,sg2044-plic - thead,th1520-plic - const: thead,c900-plic + - items: + - const: ultrarisc,dp1000-plic + - const: ultrarisc,cp100-plic - items: - const: sifive,plic-1.0.0 - const: riscv,plic0 From 14ff9e54dd14339776afff78e2d29e0edb3a4402 Mon Sep 17 00:00:00 2001 From: Charles Mirabile Date: Fri, 24 Oct 2025 09:36:42 +0100 Subject: [PATCH 22/32] irqchip/sifive-plic: Cache the interrupt enable state Optimize the PLIC driver by maintaining the interrupt enable state in the handler's enable_save array during normal operation rather than only during suspend/resume. This eliminates the need to read enable registers during suspend and makes the enable state immediately available for other purposes. Let __plic_toggle() update both the hardware registers and the cached enable_save state atomically within the existing enable_lock protection. That allows to remove the suspend-time enable register reading since handler::enable_save now always reflects the current state. [ tglx: Massaged change log ] Signed-off-by: Charles Mirabile Signed-off-by: Lucas Zampieri Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251024083647.475239-4-lzampier@redhat.com --- drivers/irqchip/irq-sifive-plic.c | 36 +++++++++++-------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index cbd7697bc148..d518a8b46874 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -94,15 +94,22 @@ static DEFINE_PER_CPU(struct plic_handler, plic_handlers); static int plic_irq_set_type(struct irq_data *d, unsigned int type); -static void __plic_toggle(void __iomem *enable_base, int hwirq, int enable) +static void __plic_toggle(struct plic_handler *handler, int hwirq, int enable) { - u32 __iomem *reg = enable_base + (hwirq / 32) * sizeof(u32); + u32 __iomem *base = handler->enable_base; u32 hwirq_mask = 1 << (hwirq % 32); + int group = hwirq / 32; + u32 value; + + value = readl(base + group); if (enable) - writel(readl(reg) | hwirq_mask, reg); + value |= hwirq_mask; else - writel(readl(reg) & ~hwirq_mask, reg); + value &= ~hwirq_mask; + + handler->enable_save[group] = value; + writel(value, base + group); } static void plic_toggle(struct plic_handler *handler, int hwirq, int enable) @@ -110,7 +117,7 @@ static void plic_toggle(struct plic_handler *handler, int hwirq, int enable) unsigned long flags; raw_spin_lock_irqsave(&handler->enable_lock, flags); - __plic_toggle(handler->enable_base, hwirq, enable); + __plic_toggle(handler, hwirq, enable); raw_spin_unlock_irqrestore(&handler->enable_lock, flags); } @@ -247,33 +254,16 @@ static int plic_irq_set_type(struct irq_data *d, unsigned int type) static int plic_irq_suspend(void) { - unsigned int i, cpu; - unsigned long flags; - u32 __iomem *reg; struct plic_priv *priv; priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv; /* irq ID 0 is reserved */ - for (i = 1; i < priv->nr_irqs; i++) { + for (unsigned int i = 1; i < priv->nr_irqs; i++) { __assign_bit(i, priv->prio_save, readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID)); } - for_each_present_cpu(cpu) { - struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); - - if (!handler->present) - continue; - - raw_spin_lock_irqsave(&handler->enable_lock, flags); - for (i = 0; i < DIV_ROUND_UP(priv->nr_irqs, 32); i++) { - reg = handler->enable_base + i * sizeof(u32); - handler->enable_save[i] = readl(reg); - } - raw_spin_unlock_irqrestore(&handler->enable_lock, flags); - } - return 0; } From 539d147ef69c3e2f9817de0fcf1dc8ba12938909 Mon Sep 17 00:00:00 2001 From: Charles Mirabile Date: Fri, 24 Oct 2025 09:36:43 +0100 Subject: [PATCH 23/32] irqchip/sifive-plic: Add support for UltraRISC DP1000 PLIC Add a new compatible for the plic found in UltraRISC DP1000 with a quirk to work around a known hardware bug with IRQ claiming in the UR-CP100 cores. When claiming an interrupt on UR-CP100 cores, all other interrupts must be disabled before the claim register is accessed to prevent incorrect handling of the interrupt. This is a hardware bug in the CP100 core implementation, not specific to the DP1000 SoC. When the PLIC_QUIRK_CP100_CLAIM_REGISTER_ERRATUM flag is present, a specialized handler (plic_handle_irq_cp100) disables all interrupts except for the first pending one before reading the claim register, and then restores the interrupts before further processing of the claimed interrupt continues. This implementation leverages the enable_save optimization, which maintains the current interrupt enable state in memory, avoiding additional register reads during the workaround. The driver matches on "ultrarisc,cp100-plic" to apply the quirk to all SoCs using UR-CP100 cores, regardless of the specific SoC implementation. This has no impact on other platforms. [ tglx: Condensed the code a bit, massaged change log and comments ] Co-developed-by: Zhang Xincheng Signed-off-by: Zhang Xincheng Signed-off-by: Charles Mirabile Signed-off-by: Lucas Zampieri Signed-off-by: Thomas Gleixner Acked-by: Samuel Holland Link: https://patch.msgid.link/20251024083647.475239-5-lzampier@redhat.com --- drivers/irqchip/irq-sifive-plic.c | 104 +++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index d518a8b46874..c03340e7117c 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -49,6 +49,8 @@ #define CONTEXT_ENABLE_BASE 0x2000 #define CONTEXT_ENABLE_SIZE 0x80 +#define PENDING_BASE 0x1000 + /* * Each hart context has a set of control registers associated with it. Right * now there's only two: a source priority threshold over which the hart will @@ -63,6 +65,7 @@ #define PLIC_ENABLE_THRESHOLD 0 #define PLIC_QUIRK_EDGE_INTERRUPT 0 +#define PLIC_QUIRK_CP100_CLAIM_REGISTER_ERRATUM 1 struct plic_priv { struct fwnode_handle *fwnode; @@ -388,6 +391,98 @@ static void plic_handle_irq(struct irq_desc *desc) chained_irq_exit(chip, desc); } +static u32 cp100_isolate_pending_irq(int nr_irq_groups, struct plic_handler *handler) +{ + u32 __iomem *pending = handler->priv->regs + PENDING_BASE; + u32 __iomem *enable = handler->enable_base; + u32 pending_irqs = 0; + int i, j; + + /* Look for first pending interrupt */ + for (i = 0; i < nr_irq_groups; i++) { + /* Any pending interrupts would be annihilated, so skip checking them */ + if (!handler->enable_save[i]) + continue; + + pending_irqs = handler->enable_save[i] & readl_relaxed(pending + i); + if (pending_irqs) + break; + } + + if (!pending_irqs) + return 0; + + /* Isolate lowest set bit */ + pending_irqs &= -pending_irqs; + + /* Disable all interrupts but the first pending one */ + for (j = 0; j < nr_irq_groups; j++) { + u32 new_mask = j == i ? pending_irqs : 0; + + if (new_mask != handler->enable_save[j]) + writel_relaxed(new_mask, enable + j); + } + return pending_irqs; +} + +static irq_hw_number_t cp100_get_hwirq(struct plic_handler *handler, void __iomem *claim) +{ + int nr_irq_groups = DIV_ROUND_UP(handler->priv->nr_irqs, 32); + u32 __iomem *enable = handler->enable_base; + irq_hw_number_t hwirq = 0; + u32 iso_mask; + int i; + + guard(raw_spinlock)(&handler->enable_lock); + + /* Existing enable state is already cached in enable_save */ + iso_mask = cp100_isolate_pending_irq(nr_irq_groups, handler); + if (!iso_mask) + return 0; + + /* + * Interrupts delievered to hardware still become pending, but only + * interrupts that are both pending and enabled can be claimed. + * Clearing the enable bit for all interrupts but the first pending + * one avoids a hardware bug that occurs during read from the claim + * register with more than one eligible interrupt. + */ + hwirq = readl(claim); + + /* Restore previous state */ + for (i = 0; i < nr_irq_groups; i++) { + u32 written = i == hwirq / 32 ? iso_mask : 0; + u32 stored = handler->enable_save[i]; + + if (stored != written) + writel_relaxed(stored, enable + i); + } + return hwirq; +} + +static void plic_handle_irq_cp100(struct irq_desc *desc) +{ + struct plic_handler *handler = this_cpu_ptr(&plic_handlers); + struct irq_chip *chip = irq_desc_get_chip(desc); + void __iomem *claim = handler->hart_base + CONTEXT_CLAIM; + irq_hw_number_t hwirq; + + WARN_ON_ONCE(!handler->present); + + chained_irq_enter(chip, desc); + + while ((hwirq = cp100_get_hwirq(handler, claim))) { + int err = generic_handle_domain_irq(handler->priv->irqdomain, hwirq); + + if (unlikely(err)) { + pr_warn_ratelimited("%pfwP: can't find mapping for hwirq %lu\n", + handler->priv->fwnode, hwirq); + } + } + + chained_irq_exit(chip, desc); +} + static void plic_set_threshold(struct plic_handler *handler, u32 threshold) { /* priority must be > threshold to trigger an interrupt */ @@ -424,6 +519,8 @@ static const struct of_device_id plic_match[] = { .data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) }, { .compatible = "thead,c900-plic", .data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) }, + { .compatible = "ultrarisc,cp100-plic", + .data = (const void *)BIT(PLIC_QUIRK_CP100_CLAIM_REGISTER_ERRATUM) }, {} }; @@ -658,12 +755,17 @@ static int plic_probe(struct fwnode_handle *fwnode) } if (global_setup) { + void (*handler_fn)(struct irq_desc *) = plic_handle_irq; + + if (test_bit(PLIC_QUIRK_CP100_CLAIM_REGISTER_ERRATUM, &handler->priv->plic_quirks)) + handler_fn = plic_handle_irq_cp100; + /* Find parent domain and register chained handler */ domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), DOMAIN_BUS_ANY); if (domain) plic_parent_irq = irq_create_mapping(domain, RV_IRQ_EXT); if (plic_parent_irq) - irq_set_chained_handler(plic_parent_irq, plic_handle_irq); + irq_set_chained_handler(plic_parent_irq, handler_fn); cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING, "irqchip/sifive/plic:starting", From a045359e72455c4fd178fbedbf398f8df7da97e7 Mon Sep 17 00:00:00 2001 From: Charles Mirabile Date: Mon, 3 Nov 2025 11:18:13 -0500 Subject: [PATCH 24/32] irqchip/sifive-plic: Fix call to __plic_toggle() in M-Mode code path The code path for M-Mode linux that disables interrupts for other contexts was missed when refactoring __plic_toggle(). Since the new version caches updates to the state for the primary context, its use in this codepath is no longer desireable even if it could be made correct. Replace the calls to __plic_toggle() with a loop that simply disables all of the interrupts in groups of 32 with a direct mmio write. Fixes: 14ff9e54dd14 ("irqchip/sifive-plic: Cache the interrupt enable state") Reported-by: kernel test robot Signed-off-by: Charles Mirabile Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251103161813.2437427-1-cmirabil@redhat.com Closes: https://lore.kernel.org/oe-kbuild-all/202510271316.AQM7gCCy-lkp@intel.com/ --- drivers/irqchip/irq-sifive-plic.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-sifive-plic.c b/drivers/irqchip/irq-sifive-plic.c index c03340e7117c..c5db7d6e3f7c 100644 --- a/drivers/irqchip/irq-sifive-plic.c +++ b/drivers/irqchip/irq-sifive-plic.c @@ -679,12 +679,11 @@ static int plic_probe(struct fwnode_handle *fwnode) if (parent_hwirq != RV_IRQ_EXT) { /* Disable S-mode enable bits if running in M-mode. */ if (IS_ENABLED(CONFIG_RISCV_M_MODE)) { - void __iomem *enable_base = priv->regs + - CONTEXT_ENABLE_BASE + - i * CONTEXT_ENABLE_SIZE; + u32 __iomem *enable_base = priv->regs + CONTEXT_ENABLE_BASE + + i * CONTEXT_ENABLE_SIZE; - for (hwirq = 1; hwirq <= nr_irqs; hwirq++) - __plic_toggle(enable_base, hwirq, 0); + for (int j = 0; j <= nr_irqs / 32; j++) + writel(0, enable_base + j); } continue; } From 45cc441de72e61b92d5eed5a9851a0301a7469de Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 6 Nov 2025 16:52:01 +0100 Subject: [PATCH 25/32] irqchip/irq-bcm7038-l1: Remove unused reg_mask_status() reg_mask_status() is not referenced anywhere leading to W=1 warning: irq-bcm7038-l1.c:85:28: error: unused function 'reg_mask_status' [-Werror,-Wunused-function] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Thomas Gleixner Reviewed-by: Florian Fainelli Link: https://patch.msgid.link/20251106155200.337399-2-krzysztof.kozlowski@linaro.org --- drivers/irqchip/irq-bcm7038-l1.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index 821b288587ca..ea1446c0a09c 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -82,12 +82,6 @@ static inline unsigned int reg_status(struct bcm7038_l1_chip *intc, return (0 * intc->n_words + word) * sizeof(u32); } -static inline unsigned int reg_mask_status(struct bcm7038_l1_chip *intc, - unsigned int word) -{ - return (1 * intc->n_words + word) * sizeof(u32); -} - static inline unsigned int reg_mask_set(struct bcm7038_l1_chip *intc, unsigned int word) { From b90ac5fe3285aa8bed625375d1df959c4c9a2cdb Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Tue, 21 Oct 2025 17:41:39 +0800 Subject: [PATCH 26/32] dt-bindings: interrupt-controller: Add Anlogic DR1V90 PLIC Add PLIC support for Anlogic DR1V90. Signed-off-by: Junhui Liu Signed-off-by: Thomas Gleixner Acked-by: Conor Dooley Link: https://patch.msgid.link/20251021-dr1v90-basic-dt-v3-4-5478db4f664a@pigmoral.tech --- .../bindings/interrupt-controller/sifive,plic-1.0.0.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml index 234cdc2a1a26..6fdb7ae9e85a 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml @@ -58,6 +58,7 @@ properties: - const: andestech,nceplic100 - items: - enum: + - anlogic,dr1v90-plic - canaan,k210-plic - eswin,eic7700-plic - sifive,fu540-c000-plic From 579951da64253e9592d21e54b1535e0119df78ab Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Tue, 21 Oct 2025 17:41:40 +0800 Subject: [PATCH 27/32] dt-bindings: interrupt-controller: Add Anlogic DR1V90 ACLINT MSWI Add MSWI support for Anlogic DR1V90 SoC, which uses Nuclei UX900 with a TIMER unit compliant with the ACLINT specification. Signed-off-by: Junhui Liu Signed-off-by: Thomas Gleixner Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20251021-dr1v90-basic-dt-v3-5-5478db4f664a@pigmoral.tech --- .../thead,c900-aclint-mswi.yaml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-mswi.yaml b/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-mswi.yaml index d6fb08a54167..62fd220e126e 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-mswi.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-mswi.yaml @@ -4,18 +4,23 @@ $id: http://devicetree.org/schemas/interrupt-controller/thead,c900-aclint-mswi.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Sophgo sg2042 CLINT Machine-level Software Interrupt Device +title: ACLINT Machine-level Software Interrupt Device maintainers: - Inochi Amaoto properties: compatible: - items: - - enum: - - sophgo,sg2042-aclint-mswi - - sophgo,sg2044-aclint-mswi - - const: thead,c900-aclint-mswi + oneOf: + - items: + - enum: + - sophgo,sg2042-aclint-mswi + - sophgo,sg2044-aclint-mswi + - const: thead,c900-aclint-mswi + - items: + - enum: + - anlogic,dr1v90-aclint-mswi + - const: nuclei,ux900-aclint-mswi reg: maxItems: 1 From a1c3a7d7ee0291e6bbc89192cb942cbebadb31fe Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Tue, 21 Oct 2025 17:41:41 +0800 Subject: [PATCH 28/32] dt-bindings: interrupt-controller: Add Anlogic DR1V90 ACLINT SSWI Add SSWI support for Anlogic DR1V90 SoC, which uses Nuclei UX900 with a TIMER unit compliant with the ACLINT specification. Signed-off-by: Junhui Liu Signed-off-by: Thomas Gleixner Acked-by: Rob Herring (Arm) Link: https://patch.msgid.link/20251021-dr1v90-basic-dt-v3-6-5478db4f664a@pigmoral.tech --- .../bindings/interrupt-controller/thead,c900-aclint-sswi.yaml | 4 ++++ 1 file changed, 4 insertions(+) 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 c1ab865fcd64..d02c6886283a 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-sswi.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/thead,c900-aclint-sswi.yaml @@ -30,6 +30,10 @@ properties: - const: thead,c900-aclint-sswi - items: - const: mips,p8700-aclint-sswi + - items: + - enum: + - anlogic,dr1v90-aclint-sswi + - const: nuclei,ux900-aclint-sswi reg: maxItems: 1 From 47a4ebbf91d31782113e7def707b53953bae3050 Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Tue, 21 Oct 2025 17:41:44 +0800 Subject: [PATCH 29/32] irqchip/aclint-sswi: Add Nuclei UX900 support Reuse the generic ACLINT SSWI probe for Nuclei UX900 since it is compliant with the ACLINT specification. Signed-off-by: Junhui Liu Signed-off-by: Thomas Gleixner Link: https://patch.msgid.link/20251021-dr1v90-basic-dt-v3-9-5478db4f664a@pigmoral.tech --- drivers/irqchip/irq-aclint-sswi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-aclint-sswi.c b/drivers/irqchip/irq-aclint-sswi.c index 93e28e9f281f..fee30f3bc5ac 100644 --- a/drivers/irqchip/irq-aclint-sswi.c +++ b/drivers/irqchip/irq-aclint-sswi.c @@ -175,7 +175,8 @@ static int __init generic_aclint_sswi_early_probe(struct device_node *node, { return generic_aclint_sswi_probe(&node->fwnode); } -IRQCHIP_DECLARE(generic_aclint_sswi, "mips,p8700-aclint-sswi", generic_aclint_sswi_early_probe); +IRQCHIP_DECLARE(mips_p8700_sswi, "mips,p8700-aclint-sswi", generic_aclint_sswi_early_probe); +IRQCHIP_DECLARE(nuclei_ux900_sswi, "nuclei,ux900-aclint-sswi", generic_aclint_sswi_early_probe); /* THEAD variant */ #define THEAD_C9XX_CSR_SXSTATUS 0x5c0 From 7083e142256f92d079d2749e002f2f2499e5f63c Mon Sep 17 00:00:00 2001 From: Ryan Chen Date: Thu, 30 Oct 2025 14:01:55 +0800 Subject: [PATCH 30/32] dt-bindings: interrupt-controller: aspeed,ast2700: Correct #interrupt-cells and interrupts count Update the AST2700 interrupt controller binding to match the actual hardware and the irq-aspeed-intc driver behavior. - Interrupts: First-level INTC banks request multiple interrupt lines to the root GIC, with a maximum of 10 per bank. Second-level INTC banks request only one interrupt line to their parent INTC-IC. Therefore, set the interrupts property to allow a minimum of 1 and a maximum of 10 entries. - #interrupt-cells: Set '#interrupt-cells' to <1> since the aspeed intc driver does not support specifying a trigger type; only the interrupt index is used. Signed-off-by: Ryan Chen Signed-off-by: Thomas Gleixner Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251030060155.2342604-2-ryan_chen@aspeedtech.com --- .../interrupt-controller/aspeed,ast2700-intc.yaml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-intc.yaml index 55636d06a674..999df5b905c5 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-intc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-intc.yaml @@ -25,13 +25,14 @@ properties: interrupt-controller: true '#interrupt-cells': - const: 2 + const: 1 description: The first cell is the IRQ number, the second cell is the trigger type as defined in interrupt.txt in this directory. interrupts: - maxItems: 6 + minItems: 1 + maxItems: 10 description: | Depend to which INTC0 or INTC1 used. INTC0 and INTC1 are two kinds of interrupt controller with enable and raw @@ -74,13 +75,17 @@ examples: interrupt-controller@12101b00 { compatible = "aspeed,ast2700-intc-ic"; reg = <0 0x12101b00 0 0x10>; - #interrupt-cells = <2>; + #interrupt-cells = <1>; interrupt-controller; interrupts = , , , , , - ; + , + , + , + , + ; }; }; From e4ca1520081bc67b2a1a01a5ad4013a82300e06e Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Wed, 5 Nov 2025 17:45:32 +0800 Subject: [PATCH 31/32] dt-bindings: interrupt-controller: Add support for Amlogic S6 S7 and S7D SoCs Update the device tree binding document for GPIO interrupt controller of Amlogic S6 S7 and S7D SoCs. Signed-off-by: Xianwei Zhao Signed-off-by: Thomas Gleixner Acked-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20251105-irqchip-gpio-s6-s7-s7d-v1-1-b4d1fe4781c1@amlogic.com --- .../bindings/interrupt-controller/amlogic,meson-gpio-intc.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.yaml index 3d60d9e9e208..d0fad930de9d 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/amlogic,meson-gpio-intc.yaml @@ -39,6 +39,9 @@ properties: - amlogic,a4-gpio-ao-intc - amlogic,a5-gpio-intc - amlogic,c3-gpio-intc + - amlogic,s6-gpio-intc + - amlogic,s7-gpio-intc + - amlogic,s7d-gpio-intc - amlogic,t7-gpio-intc - const: amlogic,meson-gpio-intc From fc584d871c1641949594ccf12a48bb226636b189 Mon Sep 17 00:00:00 2001 From: Xianwei Zhao Date: Wed, 5 Nov 2025 17:45:33 +0800 Subject: [PATCH 32/32] irqchip/meson-gpio: Add support for Amlogic S6 S7 and S7D SoCs The Amlogic S6/S7/S7D SoCs support GPIO interrupt lines: S6 IRQ Number: - 99:98 2 pins on bank CC - 97 1 pin on bank TESTN - 96:81 16 pins on bank A - 80:65 16 pins on bank Z - 64:45 20 pins on bank X - 44:37 8 pins on bank H offs H1 - 36:32 5 pins on bank F - 31:25 7 pins on bank D - 24:22 3 pins on bank E - 21:14 8 pins on bank C - 13:0 14 pins on bank B S7 IRQ Number: - 83:82 2 pins on bank CC - 81 1 pin on bank TESTN - 80:68 13 pins on bank Z - 67:48 20 pins on bank X - 47:36 12 pins on bank H - 35:24 12 pins on bank D - 23:22 2 pins on bank E - 21:14 8 pins on bank C - 13:0 14 pins on bank B S7D IRQ Number: - 83:82 2 pins on bank CC - 81:75 7 pins on bank DV - 74 1 pin on bank TESTN - 73:61 13 pins on bank Z - 60:41 20 pins on bank X - 40:29 12 pins on bank H - 28:24 5 pins on bank D - 23:22 2 pins on bank E - 21:14 8 pins on bank C - 13:0 14 pins on bank B Add the required compatibles and interrupt count initializers. Signed-off-by: Xianwei Zhao Signed-off-by: Thomas Gleixner Reviewed-by: Neil Armstrong Link: https://patch.msgid.link/20251105-irqchip-gpio-s6-s7-s7d-v1-2-b4d1fe4781c1@amlogic.com --- drivers/irqchip/irq-meson-gpio.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c index 6c5e2ff0d1cf..3fcbb044ae60 100644 --- a/drivers/irqchip/irq-meson-gpio.c +++ b/drivers/irqchip/irq-meson-gpio.c @@ -174,6 +174,14 @@ static const struct meson_gpio_irq_params s4_params = { INIT_MESON_S4_COMMON_DATA(82) }; +static const struct meson_gpio_irq_params s6_params = { + INIT_MESON_S4_COMMON_DATA(100) +}; + +static const struct meson_gpio_irq_params s7_params = { + INIT_MESON_S4_COMMON_DATA(84) +}; + static const struct meson_gpio_irq_params c3_params = { INIT_MESON_S4_COMMON_DATA(55) }; @@ -195,6 +203,9 @@ static const struct of_device_id meson_irq_gpio_matches[] __maybe_unused = { { .compatible = "amlogic,a4-gpio-ao-intc", .data = &a4_ao_params }, { .compatible = "amlogic,a4-gpio-intc", .data = &a4_params }, { .compatible = "amlogic,a5-gpio-intc", .data = &a5_params }, + { .compatible = "amlogic,s6-gpio-intc", .data = &s6_params }, + { .compatible = "amlogic,s7-gpio-intc", .data = &s7_params }, + { .compatible = "amlogic,s7d-gpio-intc", .data = &s7_params }, { .compatible = "amlogic,c3-gpio-intc", .data = &c3_params }, { .compatible = "amlogic,t7-gpio-intc", .data = &t7_params }, { }