diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-03-11 13:50:30 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-03-11 13:50:30 -0700 |
commit | 02d4df78c5ae70d283ebb4f78b9dcfdd4dfb71c2 (patch) | |
tree | cb8d854f7987a864e3699a616e028953844181db /drivers | |
parent | 045395d86acd02062b067bd325d4880391f2ce02 (diff) | |
parent | f7f56d59a3923e95bad2c49615a4d7313ed78314 (diff) |
Merge tag 'irq-core-2024-03-10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq updates from Thomas Gleixner:
"Core:
- Make affinity changes take effect immediately for interrupt
threads. This reduces the impact on isolated CPUs as it pulls over
the thread right away instead of doing it after the next hardware
interrupt arrived.
- Cleanup and improvements for the interrupt chip simulator
- Deduplication of the interrupt descriptor initialization code so
the sparse and non-sparse mode share more code.
Drivers:
- A set of conversions to platform_drivers::remove_new() which gets
rid of the pointless return value.
- A new driver for the Starfive JH8100 SoC
- Support for Amlogic-T7 SoCs
- Improvement for the interrupt handling and EOI management for the
loongson interrupt controller.
- The usual fixes and improvements all over the place"
* tag 'irq-core-2024-03-10' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (33 commits)
irqchip/ts4800: Convert to platform_driver::remove_new() callback
irqchip/stm32-exti: Convert to platform_driver::remove_new() callback
irqchip/renesas-rza1: Convert to platform_driver::remove_new() callback
irqchip/renesas-irqc: Convert to platform_driver::remove_new() callback
irqchip/renesas-intc-irqpin: Convert to platform_driver::remove_new() callback
irqchip/pruss-intc: Convert to platform_driver::remove_new() callback
irqchip/mvebu-pic: Convert to platform_driver::remove_new() callback
irqchip/madera: Convert to platform_driver::remove_new() callback
irqchip/ls-scfg-msi: Convert to platform_driver::remove_new() callback
irqchip/keystone: Convert to platform_driver::remove_new() callback
irqchip/imx-irqsteer: Convert to platform_driver::remove_new() callback
irqchip/imx-intmux: Convert to platform_driver::remove_new() callback
irqchip/imgpdc: Convert to platform_driver::remove_new() callback
irqchip: Add StarFive external interrupt controller
dt-bindings: interrupt-controller: Add starfive,jh8100-intc
arm64: dts: Add gpio_intc node for Amlogic-T7 SoCs
irqchip/meson-gpio: Add support for Amlogic-T7 SoCs
dt-bindings: interrupt-controller: Add support for Amlogic-T7 SoCs
irqchip/vic: Fix a kernel-doc warning
genirq: Wake interrupt threads immediately when changing affinity
...
Diffstat (limited to 'drivers')
24 files changed, 324 insertions, 145 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index f7149d0f3d45..72c07a12f5e1 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -546,6 +546,17 @@ config SIFIVE_PLIC select IRQ_DOMAIN_HIERARCHY select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP +config STARFIVE_JH8100_INTC + bool "StarFive JH8100 External Interrupt Controller" + depends on ARCH_STARFIVE || COMPILE_TEST + default ARCH_STARFIVE + select IRQ_DOMAIN_HIERARCHY + help + This enables support for the INTC chip found in StarFive JH8100 + SoC. + + If you don't know what to do here, say Y. + 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 ffd945fe71aa..ec4a18380998 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -96,6 +96,7 @@ obj-$(CONFIG_CSKY_MPINTC) += irq-csky-mpintc.o obj-$(CONFIG_CSKY_APB_INTC) += irq-csky-apb-intc.o obj-$(CONFIG_RISCV_INTC) += irq-riscv-intc.o obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o +obj-$(CONFIG_STARFIVE_JH8100_INTC) += irq-starfive-jh8100-intc.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-bcm6345-l1.c b/drivers/irqchip/irq-bcm6345-l1.c index 9745a119d0e6..eb02d203c963 100644 --- a/drivers/irqchip/irq-bcm6345-l1.c +++ b/drivers/irqchip/irq-bcm6345-l1.c @@ -242,7 +242,7 @@ static int __init bcm6345_l1_init_one(struct device_node *dn, else if (intc->n_words != n_words) return -EINVAL; - cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32), + cpu = intc->cpus[idx] = kzalloc(struct_size(cpu, enable_cache, n_words), GFP_KERNEL); if (!cpu) return -ENOMEM; diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index 24ca1d656adc..36e71af054e9 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -249,7 +249,7 @@ static int __init bcm7038_l1_init_one(struct device_node *dn, return -EINVAL; } - cpu = intc->cpus[idx] = kzalloc(sizeof(*cpu) + n_words * sizeof(u32), + cpu = intc->cpus[idx] = kzalloc(struct_size(cpu, mask_cache, n_words), GFP_KERNEL); if (!cpu) return -ENOMEM; diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index b822752c4261..fca888b36680 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -4436,12 +4436,12 @@ static const struct irq_domain_ops its_sgi_domain_ops = { static int its_vpe_id_alloc(void) { - return ida_simple_get(&its_vpeid_ida, 0, ITS_MAX_VPEID, GFP_KERNEL); + return ida_alloc_max(&its_vpeid_ida, ITS_MAX_VPEID - 1, GFP_KERNEL); } static void its_vpe_id_free(u16 id) { - ida_simple_remove(&its_vpeid_ida, id); + ida_free(&its_vpeid_ida, id); } static int its_vpe_init(struct its_vpe *vpe) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 98b0329b7154..20a75f0353cd 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -19,6 +19,7 @@ #include <linux/percpu.h> #include <linux/refcount.h> #include <linux/slab.h> +#include <linux/iopoll.h> #include <linux/irqchip.h> #include <linux/irqchip/arm-gic-common.h> @@ -180,11 +181,6 @@ static enum gic_intid_range get_intid_range(struct irq_data *d) return __get_intid_range(d->hwirq); } -static inline unsigned int gic_irq(struct irq_data *d) -{ - return d->hwirq; -} - static inline bool gic_irq_in_rdist(struct irq_data *d) { switch (get_intid_range(d)) { @@ -251,17 +247,13 @@ static inline void __iomem *gic_dist_base(struct irq_data *d) static void gic_do_wait_for_rwp(void __iomem *base, u32 bit) { - u32 count = 1000000; /* 1s! */ + u32 val; + int ret; - while (readl_relaxed(base + GICD_CTLR) & bit) { - count--; - if (!count) { - pr_err_ratelimited("RWP timeout, gone fishing\n"); - return; - } - cpu_relax(); - udelay(1); - } + ret = readl_relaxed_poll_timeout_atomic(base + GICD_CTLR, val, !(val & bit), + 1, USEC_PER_SEC); + if (ret == -ETIMEDOUT) + pr_err_ratelimited("RWP timeout, gone fishing\n"); } /* Wait for completion of a distributor change */ @@ -279,8 +271,8 @@ static void gic_redist_wait_for_rwp(void) static void gic_enable_redist(bool enable) { void __iomem *rbase; - u32 count = 1000000; /* 1s! */ u32 val; + int ret; if (gic_data.flags & FLAGS_WORKAROUND_GICR_WAKER_MSM8996) return; @@ -301,16 +293,13 @@ static void gic_enable_redist(bool enable) return; /* No PM support in this redistributor */ } - while (--count) { - val = readl_relaxed(rbase + GICR_WAKER); - if (enable ^ (bool)(val & GICR_WAKER_ChildrenAsleep)) - break; - cpu_relax(); - udelay(1); - } - if (!count) + ret = readl_relaxed_poll_timeout_atomic(rbase + GICR_WAKER, val, + enable ^ (bool)(val & GICR_WAKER_ChildrenAsleep), + 1, USEC_PER_SEC); + if (ret == -ETIMEDOUT) { pr_err_ratelimited("redistributor failed to %s...\n", enable ? "wakeup" : "sleep"); + } } /* @@ -548,7 +537,7 @@ static int gic_irq_nmi_setup(struct irq_data *d) * A secondary irq_chip should be in charge of LPI request, * it should not be possible to get there */ - if (WARN_ON(gic_irq(d) >= 8192)) + if (WARN_ON(irqd_to_hwirq(d) >= 8192)) return -EINVAL; /* desc lock should already be held */ @@ -588,7 +577,7 @@ static void gic_irq_nmi_teardown(struct irq_data *d) * A secondary irq_chip should be in charge of LPI request, * it should not be possible to get there */ - if (WARN_ON(gic_irq(d) >= 8192)) + if (WARN_ON(irqd_to_hwirq(d) >= 8192)) return; /* desc lock should already be held */ @@ -626,7 +615,7 @@ static bool gic_arm64_erratum_2941627_needed(struct irq_data *d) static void gic_eoi_irq(struct irq_data *d) { - write_gicreg(gic_irq(d), ICC_EOIR1_EL1); + write_gicreg(irqd_to_hwirq(d), ICC_EOIR1_EL1); isb(); if (gic_arm64_erratum_2941627_needed(d)) { @@ -646,19 +635,19 @@ static void gic_eoimode1_eoi_irq(struct irq_data *d) * No need to deactivate an LPI, or an interrupt that * is is getting forwarded to a vcpu. */ - if (gic_irq(d) >= 8192 || irqd_is_forwarded_to_vcpu(d)) + if (irqd_to_hwirq(d) >= 8192 || irqd_is_forwarded_to_vcpu(d)) return; if (!gic_arm64_erratum_2941627_needed(d)) - gic_write_dir(gic_irq(d)); + gic_write_dir(irqd_to_hwirq(d)); else gic_poke_irq(d, GICD_ICACTIVER); } static int gic_set_type(struct irq_data *d, unsigned int type) { + irq_hw_number_t irq = irqd_to_hwirq(d); enum gic_intid_range range; - unsigned int irq = gic_irq(d); void __iomem *base; u32 offset, index; int ret; @@ -684,7 +673,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) ret = gic_configure_irq(index, type, base + offset, NULL); if (ret && (range == PPI_RANGE || range == EPPI_RANGE)) { /* Misconfigured PPIs are usually not fatal */ - pr_warn("GIC: PPI INTID%d is secure or misconfigured\n", irq); + pr_warn("GIC: PPI INTID%ld is secure or misconfigured\n", irq); ret = 0; } diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 412196a7dad5..98aa383e39db 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -162,11 +162,6 @@ static inline void __iomem *gic_cpu_base(struct irq_data *d) return gic_data_cpu_base(gic_data); } -static inline unsigned int gic_irq(struct irq_data *d) -{ - return d->hwirq; -} - static inline bool cascading_gic_irq(struct irq_data *d) { void *data = irq_data_get_irq_handler_data(d); @@ -183,14 +178,16 @@ static inline bool cascading_gic_irq(struct irq_data *d) */ static void gic_poke_irq(struct irq_data *d, u32 offset) { - u32 mask = 1 << (gic_irq(d) % 32); - writel_relaxed(mask, gic_dist_base(d) + offset + (gic_irq(d) / 32) * 4); + u32 mask = 1 << (irqd_to_hwirq(d) % 32); + + writel_relaxed(mask, gic_dist_base(d) + offset + (irqd_to_hwirq(d) / 32) * 4); } static int gic_peek_irq(struct irq_data *d, u32 offset) { - u32 mask = 1 << (gic_irq(d) % 32); - return !!(readl_relaxed(gic_dist_base(d) + offset + (gic_irq(d) / 32) * 4) & mask); + u32 mask = 1 << (irqd_to_hwirq(d) % 32); + + return !!(readl_relaxed(gic_dist_base(d) + offset + (irqd_to_hwirq(d) / 32) * 4) & mask); } static void gic_mask_irq(struct irq_data *d) @@ -220,7 +217,7 @@ static void gic_unmask_irq(struct irq_data *d) static void gic_eoi_irq(struct irq_data *d) { - u32 hwirq = gic_irq(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); if (hwirq < 16) hwirq = this_cpu_read(sgi_intid); @@ -230,7 +227,7 @@ static void gic_eoi_irq(struct irq_data *d) static void gic_eoimode1_eoi_irq(struct irq_data *d) { - u32 hwirq = gic_irq(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); /* Do not deactivate an IRQ forwarded to a vcpu. */ if (irqd_is_forwarded_to_vcpu(d)) @@ -293,8 +290,8 @@ static int gic_irq_get_irqchip_state(struct irq_data *d, static int gic_set_type(struct irq_data *d, unsigned int type) { + irq_hw_number_t gicirq = irqd_to_hwirq(d); void __iomem *base = gic_dist_base(d); - unsigned int gicirq = gic_irq(d); int ret; /* Interrupt configuration for SGIs can't be changed */ @@ -309,7 +306,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) ret = gic_configure_irq(gicirq, type, base + GIC_DIST_CONFIG, NULL); if (ret && gicirq < 32) { /* Misconfigured PPIs are usually not fatal */ - pr_warn("GIC: PPI%d is secure or misconfigured\n", gicirq - 16); + pr_warn("GIC: PPI%ld is secure or misconfigured\n", gicirq - 16); ret = 0; } @@ -319,7 +316,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) { /* Only interrupts on the primary GIC can be forwarded to a vcpu. */ - if (cascading_gic_irq(d) || gic_irq(d) < 16) + if (cascading_gic_irq(d) || irqd_to_hwirq(d) < 16) return -EINVAL; if (vcpu) @@ -796,7 +793,7 @@ static void rmw_writeb(u8 bval, void __iomem *addr) static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) { - void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + gic_irq(d); + void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + irqd_to_hwirq(d); struct gic_chip_data *gic = irq_data_get_irq_chip_data(d); unsigned int cpu; diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c index 5831be454673..b42ed68acfa6 100644 --- a/drivers/irqchip/irq-imgpdc.c +++ b/drivers/irqchip/irq-imgpdc.c @@ -461,12 +461,11 @@ err_generic: return ret; } -static int pdc_intc_remove(struct platform_device *pdev) +static void pdc_intc_remove(struct platform_device *pdev) { struct pdc_intc_priv *priv = platform_get_drvdata(pdev); irq_domain_remove(priv->domain); - return 0; } static const struct of_device_id pdc_intc_match[] = { @@ -479,8 +478,8 @@ static struct platform_driver pdc_intc_driver = { .name = "pdc-intc", .of_match_table = pdc_intc_match, }, - .probe = pdc_intc_probe, - .remove = pdc_intc_remove, + .probe = pdc_intc_probe, + .remove_new = pdc_intc_remove, }; static int __init pdc_intc_init(void) diff --git a/drivers/irqchip/irq-imx-intmux.c b/drivers/irqchip/irq-imx-intmux.c index aa041e4dfee0..656eab21285c 100644 --- a/drivers/irqchip/irq-imx-intmux.c +++ b/drivers/irqchip/irq-imx-intmux.c @@ -282,7 +282,7 @@ out: return ret; } -static int imx_intmux_remove(struct platform_device *pdev) +static void imx_intmux_remove(struct platform_device *pdev) { struct intmux_data *data = platform_get_drvdata(pdev); int i; @@ -298,8 +298,6 @@ static int imx_intmux_remove(struct platform_device *pdev) } pm_runtime_disable(&pdev->dev); - - return 0; } #ifdef CONFIG_PM @@ -354,11 +352,11 @@ static const struct of_device_id imx_intmux_id[] = { static struct platform_driver imx_intmux_driver = { .driver = { - .name = "imx-intmux", - .of_match_table = imx_intmux_id, - .pm = &imx_intmux_pm_ops, + .name = "imx-intmux", + .of_match_table = imx_intmux_id, + .pm = &imx_intmux_pm_ops, }, - .probe = imx_intmux_probe, - .remove = imx_intmux_remove, + .probe = imx_intmux_probe, + .remove_new = imx_intmux_remove, }; builtin_platform_driver(imx_intmux_driver); diff --git a/drivers/irqchip/irq-imx-irqsteer.c b/drivers/irqchip/irq-imx-irqsteer.c index bd9543314539..20cf7a9e9ece 100644 --- a/drivers/irqchip/irq-imx-irqsteer.c +++ b/drivers/irqchip/irq-imx-irqsteer.c @@ -231,7 +231,7 @@ out: return ret; } -static int imx_irqsteer_remove(struct platform_device *pdev) +static void imx_irqsteer_remove(struct platform_device *pdev) { struct irqsteer_data *irqsteer_data = platform_get_drvdata(pdev); int i; @@ -243,8 +243,6 @@ static int imx_irqsteer_remove(struct platform_device *pdev) irq_domain_remove(irqsteer_data->domain); clk_disable_unprepare(irqsteer_data->ipg_clk); - - return 0; } #ifdef CONFIG_PM @@ -307,11 +305,11 @@ static const struct of_device_id imx_irqsteer_dt_ids[] = { static struct platform_driver imx_irqsteer_driver = { .driver = { - .name = "imx-irqsteer", - .of_match_table = imx_irqsteer_dt_ids, - .pm = &imx_irqsteer_pm_ops, + .name = "imx-irqsteer", + .of_match_table = imx_irqsteer_dt_ids, + .pm = &imx_irqsteer_pm_ops, }, - .probe = imx_irqsteer_probe, - .remove = imx_irqsteer_remove, + .probe = imx_irqsteer_probe, + .remove_new = imx_irqsteer_remove, }; builtin_platform_driver(imx_irqsteer_driver); diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index a36396db4b08..30f1979fa124 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -190,7 +190,7 @@ static int keystone_irq_probe(struct platform_device *pdev) return 0; } -static int keystone_irq_remove(struct platform_device *pdev) +static void keystone_irq_remove(struct platform_device *pdev) { struct keystone_irq_device *kirq = platform_get_drvdata(pdev); int hwirq; @@ -201,7 +201,6 @@ static int keystone_irq_remove(struct platform_device *pdev) irq_dispose_mapping(irq_find_mapping(kirq->irqd, hwirq)); irq_domain_remove(kirq->irqd); - return 0; } static const struct of_device_id keystone_irq_dt_ids[] = { @@ -212,7 +211,7 @@ MODULE_DEVICE_TABLE(of, keystone_irq_dt_ids); static struct platform_driver keystone_irq_device_driver = { .probe = keystone_irq_probe, - .remove = keystone_irq_remove, + .remove_new = keystone_irq_remove, .driver = { .name = "keystone_irq", .of_match_table = of_match_ptr(keystone_irq_dt_ids), diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c index b3736bdd4b9f..b64cbe3052e8 100644 --- a/drivers/irqchip/irq-loongson-eiointc.c +++ b/drivers/irqchip/irq-loongson-eiointc.c @@ -198,6 +198,12 @@ static void eiointc_irq_dispatch(struct irq_desc *desc) for (i = 0; i < eiointc_priv[0]->vec_count / VEC_COUNT_PER_REG; i++) { pending = iocsr_read64(EIOINTC_REG_ISR + (i << 3)); + + /* Skip handling if pending bitmap is zero */ + if (!pending) + continue; + + /* Clear the IRQs */ iocsr_write64(pending, EIOINTC_REG_ISR + (i << 3)); while (pending) { int bit = __ffs(pending); @@ -304,23 +310,7 @@ static int eiointc_suspend(void) static void eiointc_resume(void) { - int i, j; - struct irq_desc *desc; - struct irq_data *irq_data; - eiointc_router_init(0); - - for (i = 0; i < nr_pics; i++) { - for (j = 0; j < eiointc_priv[0]->vec_count; j++) { - desc = irq_resolve_mapping(eiointc_priv[i]->eiointc_domain, j); - if (desc && desc->handle_irq && desc->handle_irq != handle_bad_irq) { - raw_spin_lock(&desc->lock); - irq_data = irq_domain_get_irq_data(eiointc_priv[i]->eiointc_domain, irq_desc_get_irq(desc)); - eiointc_set_irq_affinity(irq_data, irq_data->common->affinity, 0); - raw_spin_unlock(&desc->lock); - } - } - } } static struct syscore_ops eiointc_syscore_ops = { diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c index 15cf80b46322..1aef5c4d27c6 100644 --- a/drivers/irqchip/irq-ls-scfg-msi.c +++ b/drivers/irqchip/irq-ls-scfg-msi.c @@ -398,7 +398,7 @@ static int ls_scfg_msi_probe(struct platform_device *pdev) return 0; } -static int ls_scfg_msi_remove(struct platform_device *pdev) +static void ls_scfg_msi_remove(struct platform_device *pdev) { struct ls_scfg_msi *msi_data = platform_get_drvdata(pdev); int i; @@ -410,17 +410,15 @@ static int ls_scfg_msi_remove(struct platform_device *pdev) irq_domain_remove(msi_data->parent); platform_set_drvdata(pdev, NULL); - - return 0; } static struct platform_driver ls_scfg_msi_driver = { .driver = { - .name = "ls-scfg-msi", - .of_match_table = ls_scfg_msi_id, + .name = "ls-scfg-msi", + .of_match_table = ls_scfg_msi_id, }, - .probe = ls_scfg_msi_probe, - .remove = ls_scfg_msi_remove, + .probe = ls_scfg_msi_probe, + .remove_new = ls_scfg_msi_remove, }; module_platform_driver(ls_scfg_msi_driver); diff --git a/drivers/irqchip/irq-madera.c b/drivers/irqchip/irq-madera.c index 3eb1f8cdf674..acceb6e7fa95 100644 --- a/drivers/irqchip/irq-madera.c +++ b/drivers/irqchip/irq-madera.c @@ -222,7 +222,7 @@ static int madera_irq_probe(struct platform_device *pdev) return 0; } -static int madera_irq_remove(struct platform_device *pdev) +static void madera_irq_remove(struct platform_device *pdev) { struct madera *madera = dev_get_drvdata(pdev->dev.parent); @@ -232,13 +232,11 @@ static int madera_irq_remove(struct platform_device *pdev) */ madera->irq_dev = NULL; regmap_del_irq_chip(madera->irq, madera->irq_data); - - return 0; } static struct platform_driver madera_irq_driver = { - .probe = &madera_irq_probe, - .remove = &madera_irq_remove, + .probe = madera_irq_probe, + .remove_new = madera_irq_remove, .driver = { .name = "madera-irq", .pm = &madera_irq_pm_ops, diff --git a/drivers/irqchip/irq-meson-gpio.c b/drivers/irqchip/irq-meson-gpio.c index f88df39f4129..9a1791908598 100644 --- a/drivers/irqchip/irq-meson-gpio.c +++ b/drivers/irqchip/irq-meson-gpio.c @@ -154,6 +154,10 @@ static const struct meson_gpio_irq_params c3_params = { INIT_MESON_S4_COMMON_DATA(55) }; +static const struct meson_gpio_irq_params t7_params = { + INIT_MESON_S4_COMMON_DATA(157) +}; + static const struct of_device_id meson_irq_gpio_matches[] __maybe_unused = { { .compatible = "amlogic,meson8-gpio-intc", .data = &meson8_params }, { .compatible = "amlogic,meson8b-gpio-intc", .data = &meson8b_params }, @@ -165,6 +169,7 @@ static const struct of_device_id meson_irq_gpio_matches[] __maybe_unused = { { .compatible = "amlogic,meson-a1-gpio-intc", .data = &a1_params }, { .compatible = "amlogic,meson-s4-gpio-intc", .data = &s4_params }, { .compatible = "amlogic,c3-gpio-intc", .data = &c3_params }, + { .compatible = "amlogic,t7-gpio-intc", .data = &t7_params }, { } }; diff --git a/drivers/irqchip/irq-mvebu-pic.c b/drivers/irqchip/irq-mvebu-pic.c index ef3d3646ccc2..d17d9c0e2880 100644 --- a/drivers/irqchip/irq-mvebu-pic.c +++ b/drivers/irqchip/irq-mvebu-pic.c @@ -167,14 +167,12 @@ static int mvebu_pic_probe(struct platform_device *pdev) return 0; } -static int mvebu_pic_remove(struct platform_device *pdev) +static void mvebu_pic_remove(struct platform_device *pdev) { struct mvebu_pic *pic = platform_get_drvdata(pdev); on_each_cpu(mvebu_pic_disable_percpu_irq, pic, 1); irq_domain_remove(pic->domain); - - return 0; } static const struct of_device_id mvebu_pic_of_match[] = { @@ -184,11 +182,11 @@ static const struct of_device_id mvebu_pic_of_match[] = { MODULE_DEVICE_TABLE(of, mvebu_pic_of_match); static struct platform_driver mvebu_pic_driver = { - .probe = mvebu_pic_probe, - .remove = mvebu_pic_remove, + .probe = mvebu_pic_probe, + .remove_new = mvebu_pic_remove, .driver = { - .name = "mvebu-pic", - .of_match_table = mvebu_pic_of_match, + .name = "mvebu-pic", + .of_match_table = mvebu_pic_of_match, }, }; module_platform_driver(mvebu_pic_driver); diff --git a/drivers/irqchip/irq-pruss-intc.c b/drivers/irqchip/irq-pruss-intc.c index 0f64ecb9b1f4..060eb000e9d3 100644 --- a/drivers/irqchip/irq-pruss-intc.c +++ b/drivers/irqchip/irq-pruss-intc.c @@ -599,7 +599,7 @@ fail_irq: return ret; } -static int pruss_intc_remove(struct platform_device *pdev) +static void pruss_intc_remove(struct platform_device *pdev) { struct pruss_intc *intc = platform_get_drvdata(pdev); u8 max_system_events = intc->soc_config->num_system_events; @@ -616,8 +616,6 @@ static int pruss_intc_remove(struct platform_device *pdev) irq_dispose_mapping(irq_find_mapping(intc->domain, hwirq)); irq_domain_remove(intc->domain); - - return 0; } static const struct pruss_intc_match_data pruss_intc_data = { @@ -645,12 +643,12 @@ MODULE_DEVICE_TABLE(of, pruss_intc_of_match); static struct platform_driver pruss_intc_driver = { .driver = { - .name = "pruss-intc", - .of_match_table = pruss_intc_of_match, - .suppress_bind_attrs = true, + .name = "pruss-intc", + .of_match_table = pruss_intc_of_match, + .suppress_bind_attrs = true, }, - .probe = pruss_intc_probe, - .remove = pruss_intc_remove, + .probe = pruss_intc_probe, + .remove_new = pruss_intc_remove, }; module_platform_driver(pruss_intc_driver); diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c index fa19585f3dee..9ad37237ba95 100644 --- a/drivers/irqchip/irq-renesas-intc-irqpin.c +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c @@ -561,14 +561,13 @@ err0: return ret; } -static int intc_irqpin_remove(struct platform_device *pdev) +static void intc_irqpin_remove(struct platform_device *pdev) { struct intc_irqpin_priv *p = platform_get_drvdata(pdev); irq_domain_remove(p->irq_domain); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - return 0; } static int __maybe_unused intc_irqpin_suspend(struct device *dev) @@ -585,11 +584,11 @@ static SIMPLE_DEV_PM_OPS(intc_irqpin_pm_ops, intc_irqpin_suspend, NULL); static struct platform_driver intc_irqpin_device_driver = { .probe = intc_irqpin_probe, - .remove = intc_irqpin_remove, + .remove_new = intc_irqpin_remove, .driver = { - .name = "renesas_intc_irqpin", - .of_match_table = intc_irqpin_dt_ids, - .pm = &intc_irqpin_pm_ops, + .name = "renesas_intc_irqpin", + .of_match_table = intc_irqpin_dt_ids, + .pm = &intc_irqpin_pm_ops, } }; diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 49b446b396f9..76026e0b8e20 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -218,14 +218,13 @@ err_runtime_pm_disable: return ret; } -static int irqc_remove(struct platform_device *pdev) +static void irqc_remove(struct platform_device *pdev) { struct irqc_priv *p = platform_get_drvdata(pdev); irq_domain_remove(p->irq_domain); pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - return 0; } static int __maybe_unused irqc_suspend(struct device *dev) @@ -248,11 +247,11 @@ MODULE_DEVICE_TABLE(of, irqc_dt_ids); static struct platform_driver irqc_device_driver = { .probe = irqc_probe, - .remove = irqc_remove, + .remove_new = irqc_remove, .driver = { - .name = "renesas_irqc", + .name = "renesas_irqc", .of_match_table = irqc_dt_ids, - .pm = &irqc_pm_ops, + .pm = &irqc_pm_ops, } }; diff --git a/drivers/irqchip/irq-renesas-rza1.c b/drivers/irqchip/irq-renesas-rza1.c index e4c99c2e0373..f05afe82db4d 100644 --- a/drivers/irqchip/irq-renesas-rza1.c +++ b/drivers/irqchip/irq-renesas-rza1.c @@ -244,12 +244,11 @@ out_put_node: return ret; } -static int rza1_irqc_remove(struct platform_device *pdev) +static void rza1_irqc_remove(struct platform_device *pdev) { struct rza1_irqc_priv *priv = platform_get_drvdata(pdev); irq_domain_remove(priv->irq_domain); - return 0; } static const struct of_device_id rza1_irqc_dt_ids[] = { @@ -260,9 +259,9 @@ MODULE_DEVICE_TABLE(of, rza1_irqc_dt_ids); static struct platform_driver rza1_irqc_device_driver = { .probe = rza1_irqc_probe, - .remove = rza1_irqc_remove, + .remove_new = rza1_irqc_remove, .driver = { - .name = "renesas_rza1_irqc", + .name = "renesas_rza1_irqc", .of_match_table = rza1_irqc_dt_ids, } }; diff --git a/drivers/irqchip/irq-starfive-jh8100-intc.c b/drivers/irqchip/irq-starfive-jh8100-intc.c new file mode 100644 index 000000000000..0f5837176e53 --- /dev/null +++ b/drivers/irqchip/irq-starfive-jh8100-intc.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * StarFive JH8100 External Interrupt Controller driver + * + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * + * Author: Changhuang Liang <changhuang.liang@starfivetech.com> + */ + +#define pr_fmt(fmt) "irq-starfive-jh8100: " fmt + +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/irq.h> +#include <linux/irqchip.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/irqdomain.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/reset.h> +#include <linux/spinlock.h> + +#define STARFIVE_INTC_SRC0_CLEAR 0x10 +#define STARFIVE_INTC_SRC0_MASK 0x14 +#define STARFIVE_INTC_SRC0_INT 0x1c + +#define STARFIVE_INTC_SRC_IRQ_NUM 32 + +struct starfive_irq_chip { + void __iomem *base; + struct irq_domain *domain; + raw_spinlock_t lock; +}; + +static void starfive_intc_bit_set(struct starfive_irq_chip *irqc, + u32 reg, u32 bit_mask) +{ + u32 value; + + value = ioread32(irqc->base + reg); + value |= bit_mask; + iowrite32(value, irqc->base + reg); +} + +static void starfive_intc_bit_clear(struct starfive_irq_chip *irqc, + u32 reg, u32 bit_mask) +{ + u32 value; + + value = ioread32(irqc->base + reg); + value &= ~bit_mask; + iowrite32(value, irqc->base + reg); +} + +static void starfive_intc_unmask(struct irq_data *d) +{ + struct starfive_irq_chip *irqc = irq_data_get_irq_chip_data(d); + + raw_spin_lock(&irqc->lock); + starfive_intc_bit_clear(irqc, STARFIVE_INTC_SRC0_MASK, BIT(d->hwirq)); + raw_spin_unlock(&irqc->lock); +} + +static void starfive_intc_mask(struct irq_data *d) +{ + struct starfive_irq_chip *irqc = irq_data_get_irq_chip_data(d); + + raw_spin_lock(&irqc->lock); + starfive_intc_bit_set(irqc, STARFIVE_INTC_SRC0_MASK, BIT(d->hwirq)); + raw_spin_unlock(&irqc->lock); +} + +static struct irq_chip intc_dev = { + .name = "StarFive JH8100 INTC", + .irq_unmask = starfive_intc_unmask, + .irq_mask = starfive_intc_mask, +}; + +static int starfive_intc_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_domain_set_info(d, irq, hwirq, &intc_dev, d->host_data, + handle_level_irq, NULL, NULL); + + return 0; +} + +static const struct irq_domain_ops starfive_intc_domain_ops = { + .xlate = irq_domain_xlate_onecell, + .map = starfive_intc_map, +}; + +static void starfive_intc_irq_handler(struct irq_desc *desc) +{ + struct starfive_irq_chip *irqc = irq_data_get_irq_handler_data(&desc->irq_data); + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned long value; + int hwirq; + + chained_irq_enter(chip, desc); + + value = ioread32(irqc->base + STARFIVE_INTC_SRC0_INT); + while (value) { + hwirq = ffs(value) - 1; + + generic_handle_domain_irq(irqc->domain, hwirq); + + starfive_intc_bit_set(irqc, STARFIVE_INTC_SRC0_CLEAR, BIT(hwirq)); + starfive_intc_bit_clear(irqc, STARFIVE_INTC_SRC0_CLEAR, BIT(hwirq)); + + __clear_bit(hwirq, &value); + } + + chained_irq_exit(chip, desc); +} + +static int __init starfive_intc_init(struct device_node *intc, + struct device_node *parent) +{ + struct starfive_irq_chip *irqc; + struct reset_control *rst; + struct clk *clk; + int parent_irq; + int ret; + + irqc = kzalloc(sizeof(*irqc), GFP_KERNEL); + if (!irqc) + return -ENOMEM; + + irqc->base = of_iomap(intc, 0); + if (!irqc->base) { + pr_err("Unable to map registers\n"); + ret = -ENXIO; + goto err_free; + } + + rst = of_reset_control_get_exclusive(intc, NULL); + if (IS_ERR(rst)) { + pr_err("Unable to get reset control %pe\n", rst); + ret = PTR_ERR(rst); + goto err_unmap; + } + + clk = of_clk_get(intc, 0); + if (IS_ERR(clk)) { + pr_err("Unable to get clock %pe\n", clk); + ret = PTR_ERR(clk); + goto err_reset_put; + } + + ret = reset_control_deassert(rst); + if (ret) + goto err_clk_put; + + ret = clk_prepare_enable(clk); + if (ret) + goto err_reset_assert; + + raw_spin_lock_init(&irqc->lock); + + irqc->domain = irq_domain_add_linear(intc, STARFIVE_INTC_SRC_IRQ_NUM, + &starfive_intc_domain_ops, irqc); + if (!irqc->domain) { + pr_err("Unable to create IRQ domain\n"); + ret = -EINVAL; + goto err_clk_disable; + } + + parent_irq = of_irq_get(intc, 0); + if (parent_irq < 0) { + pr_err("Failed to get main IRQ: %d\n", parent_irq); + ret = parent_irq; + goto err_remove_domain; + } + + irq_set_chained_handler_and_data(parent_irq, starfive_intc_irq_handler, + irqc); + + pr_info("Interrupt controller register, nr_irqs %d\n", + STARFIVE_INTC_SRC_IRQ_NUM); + + return 0; + +err_remove_domain: + irq_domain_remove(irqc->domain); +err_clk_disable: + clk_disable_unprepare(clk); +err_reset_assert: + reset_control_assert(rst); +err_clk_put: + clk_put(clk); +err_reset_put: + reset_control_put(rst); +err_unmap: + iounmap(irqc->base); +err_free: + kfree(irqc); + return ret; +} + +IRQCHIP_PLATFORM_DRIVER_BEGIN(starfive_intc) +IRQCHIP_MATCH("starfive,jh8100-intc", starfive_intc_init) +IRQCHIP_PLATFORM_DRIVER_END(starfive_intc) + +MODULE_DESCRIPTION("StarFive JH8100 External Interrupt Controller"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Changhuang Liang <changhuang.liang@starfivetech.com>"); diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 971240e2e31b..26a5193d0ae4 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -898,10 +898,9 @@ static void stm32_exti_remove_irq(void *data) irq_domain_remove(domain); } -static int stm32_exti_remove(struct platform_device *pdev) +static void stm32_exti_remove(struct platform_device *pdev) { stm32_exti_h_syscore_deinit(); - return 0; } static int stm32_exti_probe(struct platform_device *pdev) @@ -991,10 +990,10 @@ MODULE_DEVICE_TABLE(of, stm32_exti_ids); static struct platform_driver stm32_exti_driver = { .probe = stm32_exti_probe, - .remove = stm32_exti_remove, + .remove_new = stm32_exti_remove, .driver = { - .name = "stm32_exti", - .of_match_table = stm32_exti_ids, + .name = "stm32_exti", + .of_match_table = stm32_exti_ids, }, }; diff --git a/drivers/irqchip/irq-ts4800.c b/drivers/irqchip/irq-ts4800.c index b2d61d4f6fe6..57f610dab6b8 100644 --- a/drivers/irqchip/irq-ts4800.c +++ b/drivers/irqchip/irq-ts4800.c @@ -139,13 +139,11 @@ static int ts4800_ic_probe(struct platform_device *pdev) return 0; } -static int ts4800_ic_remove(struct platform_device *pdev) +static void ts4800_ic_remove(struct platform_device *pdev) { struct ts4800_irq_data *data = platform_get_drvdata(pdev); irq_domain_remove(data->domain); - - return 0; } static const struct of_device_id ts4800_ic_of_match[] = { @@ -155,11 +153,11 @@ static const struct of_device_id ts4800_ic_of_match[] = { MODULE_DEVICE_TABLE(of, ts4800_ic_of_match); static struct platform_driver ts4800_ic_driver = { - .probe = ts4800_ic_probe, - .remove = ts4800_ic_remove, + .probe = ts4800_ic_probe, + .remove_new = ts4800_ic_remove, .driver = { - .name = "ts4800-irqc", - .of_match_table = ts4800_ic_of_match, + .name = "ts4800-irqc", + .of_match_table = ts4800_ic_of_match, }, }; module_platform_driver(ts4800_ic_driver); diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index 9e3d5561e04e..ea93e7236c4a 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -47,9 +47,8 @@ /** * struct vic_device - VIC PM device - * @parent_irq: The parent IRQ number of the VIC if cascaded, or 0. - * @irq: The IRQ number for the base of the VIC. * @base: The register base for the VIC. + * @irq: The IRQ number for the base of the VIC. * @valid_sources: A bitmask of valid interrupts * @resume_sources: A bitmask of interrupts for resume. * @resume_irqs: The IRQs enabled for resume. |