Boring updates for interrupt drivers:

- Support for a couple of new ARM64 and RISCV SoC variants and their
     magic interrupt controllers which either can reuse existing code or
     require quirks due to a botched hardware implementation.
 
   - More section mismatch fixes.
 
   - The usual cleanups and fixes all over the place.
 -----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAmkswMYTHHRnbHhAbGlu
 dXRyb25peC5kZQAKCRCmGPVMDXSYoZvSEACZdCx7vO2XX7oef7DxQ6EKFA/NQvd0
 xJGFTBlrxIucp26yUxWKkuDVdhu8WYe13zJG6+LVl9IxH3IIBa2duQ4HhIyqxuz6
 z74IDjBlOcKAHu2xLFJmBIS4vGTd6UPOg1KvSrIFd9oiuMXikphbnFgyrFGAFiSQ
 J1gP7mKZATUH08mTXK5k1pmBIbMjEHpyyTdBEJKoVgiN/MB/qsq95dy0Oxal+C13
 1cOKBaFreTMdX+77U5RucBcGaLHW4SdoaAVaqc/UXw2c2TAezbt/gPYexRpkdVaG
 2tuYTWIfCUuHbjUoOOYwI+ILnuiBMzjxlIUx3uSvcvtUVO4YuMDR4JOWVsevtfgI
 uUV+4OPq9kBI6PNqAyo16NhDdZ9rmjg3q14F9oyidQfR5gRbsZPPDmtCB/M2jbE1
 n3LlsHUJt0UYo8ZqCPrGhiw9hkGXv4wsEl10FKkyoNrQ0Y4SCUrdzGdr6vwhAAub
 yxMe1+BrFQT23R9l+qVrUZmDmpV9tlFNr6rPwtucrQX3PMWEfAeCc6a/vjY3eqJl
 sZ4pGyFEx0cwfKzHu1/SmNpnjSNdyc7niiN8HAQ7AnxzRW13fDdGQuuVGsKxHyJc
 Tke9wJsyUO4MxpSQDI+cmpsF8OeJDHuRDKMBdLFxlLPhABECdLUO0qKq9l0Ry/Ji
 uDkc3WvM14zKpw==
 =kdyt
 -----END PGP SIGNATURE-----

Merge tag 'irq-drivers-2025-11-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq driver updates from Thomas Gleixner:
 "Boring updates for interrupt drivers:

   - Support for a couple of new ARM64 and RISCV SoC variants and their
     magic interrupt controllers which either can reuse existing code or
     require quirks due to a botched hardware implementation

   - More section mismatch fixes

   - The usual cleanups and fixes all over the place"

* tag 'irq-drivers-2025-11-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (32 commits)
  irqchip/meson-gpio: Add support for Amlogic S6 S7 and S7D SoCs
  dt-bindings: interrupt-controller: Add support for Amlogic S6 S7 and S7D SoCs
  dt-bindings: interrupt-controller: aspeed,ast2700: Correct #interrupt-cells and interrupts count
  irqchip/aclint-sswi: Add Nuclei UX900 support
  dt-bindings: interrupt-controller: Add Anlogic DR1V90 ACLINT SSWI
  dt-bindings: interrupt-controller: Add Anlogic DR1V90 ACLINT MSWI
  dt-bindings: interrupt-controller: Add Anlogic DR1V90 PLIC
  irqchip/irq-bcm7038-l1: Remove unused reg_mask_status()
  irqchip/sifive-plic: Fix call to __plic_toggle() in M-Mode code path
  irqchip/sifive-plic: Add support for UltraRISC DP1000 PLIC
  irqchip/sifive-plic: Cache the interrupt enable state
  dt-bindings: interrupt-controller: Add UltraRISC DP1000 PLIC
  dt-bindings: vendor-prefixes: Add UltraRISC
  irqchip/qcom-irq-combiner: Rename driver structure
  irqchip/riscv-imsic: Inline imsic_vector_from_local_id()
  irqchip/riscv-imsic: Embed the vector array in lpriv
  irqchip/riscv-imsic: Remove redundant irq_data lookups
  irqchip/ts4800: Drop unused module alias
  irqchip/mvebu-pic: Drop unused module alias
  irqchip/meson-gpio: Drop unused module alias
  ...
This commit is contained in:
Linus Torvalds 2025-12-02 09:32:53 -08:00
commit 15b87bec89
30 changed files with 264 additions and 223 deletions

View File

@ -39,6 +39,9 @@ properties:
- amlogic,a4-gpio-ao-intc - amlogic,a4-gpio-ao-intc
- amlogic,a5-gpio-intc - amlogic,a5-gpio-intc
- amlogic,c3-gpio-intc - amlogic,c3-gpio-intc
- amlogic,s6-gpio-intc
- amlogic,s7-gpio-intc
- amlogic,s7d-gpio-intc
- amlogic,t7-gpio-intc - amlogic,t7-gpio-intc
- const: amlogic,meson-gpio-intc - const: amlogic,meson-gpio-intc

View File

@ -25,13 +25,14 @@ properties:
interrupt-controller: true interrupt-controller: true
'#interrupt-cells': '#interrupt-cells':
const: 2 const: 1
description: description:
The first cell is the IRQ number, the second cell is the trigger The first cell is the IRQ number, the second cell is the trigger
type as defined in interrupt.txt in this directory. type as defined in interrupt.txt in this directory.
interrupts: interrupts:
maxItems: 6 minItems: 1
maxItems: 10
description: | description: |
Depend to which INTC0 or INTC1 used. Depend to which INTC0 or INTC1 used.
INTC0 and INTC1 are two kinds of interrupt controller with enable and raw INTC0 and INTC1 are two kinds of interrupt controller with enable and raw
@ -74,13 +75,17 @@ examples:
interrupt-controller@12101b00 { interrupt-controller@12101b00 {
compatible = "aspeed,ast2700-intc-ic"; compatible = "aspeed,ast2700-intc-ic";
reg = <0 0x12101b00 0 0x10>; reg = <0 0x12101b00 0 0x10>;
#interrupt-cells = <2>; #interrupt-cells = <1>;
interrupt-controller; interrupt-controller;
interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>, interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 193 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 194 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 195 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>; <GIC_SPI 197 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 198 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 199 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH>;
}; };
}; };

View File

@ -58,6 +58,7 @@ properties:
- const: andestech,nceplic100 - const: andestech,nceplic100
- items: - items:
- enum: - enum:
- anlogic,dr1v90-plic
- canaan,k210-plic - canaan,k210-plic
- eswin,eic7700-plic - eswin,eic7700-plic
- sifive,fu540-c000-plic - sifive,fu540-c000-plic
@ -75,6 +76,9 @@ properties:
- sophgo,sg2044-plic - sophgo,sg2044-plic
- thead,th1520-plic - thead,th1520-plic
- const: thead,c900-plic - const: thead,c900-plic
- items:
- const: ultrarisc,dp1000-plic
- const: ultrarisc,cp100-plic
- items: - items:
- const: sifive,plic-1.0.0 - const: sifive,plic-1.0.0
- const: riscv,plic0 - const: riscv,plic0

View File

@ -4,18 +4,23 @@
$id: http://devicetree.org/schemas/interrupt-controller/thead,c900-aclint-mswi.yaml# $id: http://devicetree.org/schemas/interrupt-controller/thead,c900-aclint-mswi.yaml#
$schema: http://devicetree.org/meta-schemas/core.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: maintainers:
- Inochi Amaoto <inochiama@outlook.com> - Inochi Amaoto <inochiama@outlook.com>
properties: properties:
compatible: compatible:
items: oneOf:
- enum: - items:
- sophgo,sg2042-aclint-mswi - enum:
- sophgo,sg2044-aclint-mswi - sophgo,sg2042-aclint-mswi
- const: thead,c900-aclint-mswi - sophgo,sg2044-aclint-mswi
- const: thead,c900-aclint-mswi
- items:
- enum:
- anlogic,dr1v90-aclint-mswi
- const: nuclei,ux900-aclint-mswi
reg: reg:
maxItems: 1 maxItems: 1

View File

@ -30,6 +30,10 @@ properties:
- const: thead,c900-aclint-sswi - const: thead,c900-aclint-sswi
- items: - items:
- const: mips,p8700-aclint-sswi - const: mips,p8700-aclint-sswi
- items:
- enum:
- anlogic,dr1v90-aclint-sswi
- const: nuclei,ux900-aclint-sswi
reg: reg:
maxItems: 1 maxItems: 1

View File

@ -1705,6 +1705,8 @@ patternProperties:
description: Universal Scientific Industrial Co., Ltd. description: Universal Scientific Industrial Co., Ltd.
"^usr,.*": "^usr,.*":
description: U.S. Robotics Corporation description: U.S. Robotics Corporation
"^ultrarisc,.*":
description: UltraRISC Technology Co., Ltd.
"^ultratronik,.*": "^ultratronik,.*":
description: Ultratronik GmbH description: Ultratronik GmbH
"^utoo,.*": "^utoo,.*":

View File

@ -150,7 +150,7 @@ config BCM6345_L1_IRQ
config BCM7038_L1_IRQ config BCM7038_L1_IRQ
tristate "Broadcom STB 7038-style L1/L2 interrupt controller driver" 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 default ARCH_BRCMSTB || BMIPS_GENERIC
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
select IRQ_DOMAIN select IRQ_DOMAIN
@ -158,14 +158,14 @@ config BCM7038_L1_IRQ
config BCM7120_L2_IRQ config BCM7120_L2_IRQ
tristate "Broadcom STB 7120-style L2 interrupt controller driver" 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 default ARCH_BRCMSTB || BMIPS_GENERIC
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
select IRQ_DOMAIN select IRQ_DOMAIN
config BRCMSTB_L2_IRQ config BRCMSTB_L2_IRQ
tristate "Broadcom STB generic L2 interrupt controller driver" 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 default ARCH_BCM2835 || ARCH_BRCMSTB || BMIPS_GENERIC
select GENERIC_IRQ_CHIP select GENERIC_IRQ_CHIP
select IRQ_DOMAIN select IRQ_DOMAIN

View File

@ -175,7 +175,8 @@ static int __init generic_aclint_sswi_early_probe(struct device_node *node,
{ {
return generic_aclint_sswi_probe(&node->fwnode); 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 */ /* THEAD variant */
#define THEAD_C9XX_CSR_SXSTATUS 0x5c0 #define THEAD_C9XX_CSR_SXSTATUS 0x5c0

View File

@ -232,17 +232,12 @@ static int mip_parse_dt(struct mip_priv *mip, struct device_node *np)
return ret; return ret;
} }
static int __init 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; struct mip_priv *mip;
int ret; int ret;
pdev = of_find_device_by_node(node);
of_node_put(node);
if (!pdev)
return -EPROBE_DEFER;
mip = kzalloc(sizeof(*mip), GFP_KERNEL); mip = kzalloc(sizeof(*mip), GFP_KERNEL);
if (!mip) if (!mip)
return -ENOMEM; return -ENOMEM;
@ -285,7 +280,7 @@ static int __init mip_of_msi_init(struct device_node *node, struct device_node *
} }
IRQCHIP_PLATFORM_DRIVER_BEGIN(mip_msi) 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) IRQCHIP_PLATFORM_DRIVER_END(mip_msi)
MODULE_DESCRIPTION("Broadcom BCM2712 MSI-X interrupt controller"); MODULE_DESCRIPTION("Broadcom BCM2712 MSI-X interrupt controller");
MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>"); MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.com>");

View File

@ -82,12 +82,6 @@ static inline unsigned int reg_status(struct bcm7038_l1_chip *intc,
return (0 * intc->n_words + word) * sizeof(u32); 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, static inline unsigned int reg_mask_set(struct bcm7038_l1_chip *intc,
unsigned int word) unsigned int word)
{ {
@ -219,9 +213,8 @@ static int bcm7038_l1_set_affinity(struct irq_data *d,
} }
#endif #endif
static int __init bcm7038_l1_init_one(struct device_node *dn, static int bcm7038_l1_init_one(struct device_node *dn, unsigned int idx,
unsigned int idx, struct bcm7038_l1_chip *intc)
struct bcm7038_l1_chip *intc)
{ {
struct resource res; struct resource res;
resource_size_t sz; resource_size_t sz;
@ -395,9 +388,9 @@ static const struct irq_domain_ops bcm7038_l1_domain_ops = {
.map = bcm7038_l1_map, .map = bcm7038_l1_map,
}; };
static int __init bcm7038_l1_of_init(struct device_node *dn, static int bcm7038_l1_probe(struct platform_device *pdev, struct device_node *parent)
struct device_node *parent)
{ {
struct device_node *dn = pdev->dev.of_node;
struct bcm7038_l1_chip *intc; struct bcm7038_l1_chip *intc;
int idx, ret; int idx, ret;
@ -455,7 +448,7 @@ static int __init bcm7038_l1_of_init(struct device_node *dn,
} }
IRQCHIP_PLATFORM_DRIVER_BEGIN(bcm7038_l1) 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) IRQCHIP_PLATFORM_DRIVER_END(bcm7038_l1)
MODULE_DESCRIPTION("Broadcom STB 7038-style L1/L2 interrupt controller"); MODULE_DESCRIPTION("Broadcom STB 7038-style L1/L2 interrupt controller");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");

View File

@ -143,8 +143,7 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn,
return 0; return 0;
} }
static int __init bcm7120_l2_intc_iomap_7120(struct device_node *dn, static int bcm7120_l2_intc_iomap_7120(struct device_node *dn, struct bcm7120_l2_intc_data *data)
struct bcm7120_l2_intc_data *data)
{ {
int ret; int ret;
@ -177,8 +176,7 @@ static int __init bcm7120_l2_intc_iomap_7120(struct device_node *dn,
return 0; return 0;
} }
static int __init bcm7120_l2_intc_iomap_3380(struct device_node *dn, static int bcm7120_l2_intc_iomap_3380(struct device_node *dn, struct bcm7120_l2_intc_data *data)
struct bcm7120_l2_intc_data *data)
{ {
unsigned int gc_idx; unsigned int gc_idx;
@ -208,15 +206,14 @@ static int __init bcm7120_l2_intc_iomap_3380(struct device_node *dn,
return 0; return 0;
} }
static int __init bcm7120_l2_intc_probe(struct device_node *dn, static int bcm7120_l2_intc_probe(struct platform_device *pdev, struct device_node *parent,
struct device_node *parent,
int (*iomap_regs_fn)(struct device_node *, int (*iomap_regs_fn)(struct device_node *,
struct bcm7120_l2_intc_data *), struct bcm7120_l2_intc_data *),
const char *intc_name) const char *intc_name)
{ {
unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
struct device_node *dn = pdev->dev.of_node;
struct bcm7120_l2_intc_data *data; struct bcm7120_l2_intc_data *data;
struct platform_device *pdev;
struct irq_chip_generic *gc; struct irq_chip_generic *gc;
struct irq_chip_type *ct; struct irq_chip_type *ct;
int ret = 0; int ret = 0;
@ -227,14 +224,7 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn,
if (!data) if (!data)
return -ENOMEM; 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); data->num_parent_irqs = platform_irq_count(pdev);
put_device(&pdev->dev);
if (data->num_parent_irqs <= 0) { if (data->num_parent_irqs <= 0) {
pr_err("invalid number of parent interrupts\n"); pr_err("invalid number of parent interrupts\n");
ret = -ENOMEM; ret = -ENOMEM;
@ -334,22 +324,19 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn,
if (data->map_base[idx]) if (data->map_base[idx])
iounmap(data->map_base[idx]); iounmap(data->map_base[idx]);
} }
out_free_data:
kfree(data); kfree(data);
return ret; return ret;
} }
static int __init bcm7120_l2_intc_probe_7120(struct device_node *dn, static int bcm7120_l2_intc_probe_7120(struct platform_device *pdev, struct device_node *parent)
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"); "BCM7120 L2");
} }
static int __init bcm7120_l2_intc_probe_3380(struct device_node *dn, static int bcm7120_l2_intc_probe_3380(struct platform_device *pdev, struct device_node *parent)
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"); "BCM3380 L2");
} }

View File

@ -138,13 +138,12 @@ static void brcmstb_l2_intc_resume(struct irq_data *d)
irq_reg_writel(gc, ~b->saved_mask, ct->regs.enable); irq_reg_writel(gc, ~b->saved_mask, ct->regs.enable);
} }
static int __init brcmstb_l2_intc_of_init(struct device_node *np, static int brcmstb_l2_intc_probe(struct platform_device *pdev, struct device_node *parent,
struct device_node *parent, const struct brcmstb_intc_init_params *init_params)
const struct brcmstb_intc_init_params
*init_params)
{ {
unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
unsigned int set = 0; unsigned int set = 0;
struct device_node *np = pdev->dev.of_node;
struct brcmstb_l2_intc_data *data; struct brcmstb_l2_intc_data *data;
struct irq_chip_type *ct; struct irq_chip_type *ct;
int ret; int ret;
@ -257,23 +256,21 @@ static int __init brcmstb_l2_intc_of_init(struct device_node *np,
return ret; return ret;
} }
static int __init brcmstb_l2_edge_intc_of_init(struct device_node *np, static int brcmstb_l2_edge_intc_probe(struct platform_device *pdev, struct device_node *parent)
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 __init brcmstb_l2_lvl_intc_of_init(struct device_node *np, static int brcmstb_l2_lvl_intc_probe(struct platform_device *pdev, struct device_node *parent)
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_PLATFORM_DRIVER_BEGIN(brcmstb_l2)
IRQCHIP_MATCH("brcm,l2-intc", brcmstb_l2_edge_intc_of_init) IRQCHIP_MATCH("brcm,l2-intc", brcmstb_l2_edge_intc_probe)
IRQCHIP_MATCH("brcm,hif-spi-l2-intc", brcmstb_l2_edge_intc_of_init) IRQCHIP_MATCH("brcm,hif-spi-l2-intc", brcmstb_l2_edge_intc_probe)
IRQCHIP_MATCH("brcm,upg-aux-aon-l2-intc", brcmstb_l2_edge_intc_of_init) IRQCHIP_MATCH("brcm,upg-aux-aon-l2-intc", brcmstb_l2_edge_intc_probe)
IRQCHIP_MATCH("brcm,bcm7271-l2-intc", brcmstb_l2_lvl_intc_of_init) IRQCHIP_MATCH("brcm,bcm7271-l2-intc", brcmstb_l2_lvl_intc_probe)
IRQCHIP_PLATFORM_DRIVER_END(brcmstb_l2) IRQCHIP_PLATFORM_DRIVER_END(brcmstb_l2)
MODULE_DESCRIPTION("Broadcom STB generic L2 interrupt controller"); MODULE_DESCRIPTION("Broadcom STB generic L2 interrupt controller");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");

View File

@ -296,11 +296,9 @@ static const struct imx_mu_dcfg imx_mu_cfg_imx8ulp = {
}, },
}; };
static int __init imx_mu_of_init(struct device_node *dn, static int imx_mu_probe(struct platform_device *pdev, struct device_node *parent,
struct device_node *parent, const struct imx_mu_dcfg *cfg)
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_a;
struct device_link *pd_link_b; struct device_link *pd_link_b;
struct imx_mu_msi *msi_data; struct imx_mu_msi *msi_data;
@ -416,31 +414,27 @@ static const struct dev_pm_ops imx_mu_pm_ops = {
imx_mu_runtime_resume, NULL) imx_mu_runtime_resume, NULL)
}; };
static int __init imx_mu_imx7ulp_of_init(struct device_node *dn, static int imx_mu_imx7ulp_probe(struct platform_device *pdev, struct device_node *parent)
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 __init imx_mu_imx6sx_of_init(struct device_node *dn, static int imx_mu_imx6sx_probe(struct platform_device *pdev, struct device_node *parent)
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 __init imx_mu_imx8ulp_of_init(struct device_node *dn, static int imx_mu_imx8ulp_probe(struct platform_device *pdev, struct device_node *parent)
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_PLATFORM_DRIVER_BEGIN(imx_mu_msi)
IRQCHIP_MATCH("fsl,imx7ulp-mu-msi", imx_mu_imx7ulp_of_init) IRQCHIP_MATCH("fsl,imx7ulp-mu-msi", imx_mu_imx7ulp_probe)
IRQCHIP_MATCH("fsl,imx6sx-mu-msi", imx_mu_imx6sx_of_init) IRQCHIP_MATCH("fsl,imx6sx-mu-msi", imx_mu_imx6sx_probe)
IRQCHIP_MATCH("fsl,imx8ulp-mu-msi", imx_mu_imx8ulp_of_init) IRQCHIP_MATCH("fsl,imx8ulp-mu-msi", imx_mu_imx8ulp_probe)
IRQCHIP_PLATFORM_DRIVER_END(imx_mu_msi, .pm = &imx_mu_pm_ops) IRQCHIP_PLATFORM_DRIVER_END(imx_mu_msi, .pm = &imx_mu_pm_ops)
MODULE_AUTHOR("Frank Li <Frank.Li@nxp.com>"); MODULE_AUTHOR("Frank Li <Frank.Li@nxp.com>");
MODULE_DESCRIPTION("Freescale MU MSI controller driver"); MODULE_DESCRIPTION("Freescale MU MSI controller driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@ -199,8 +199,9 @@ static const struct irq_domain_ops mchp_eic_domain_ops = {
.free = irq_domain_free_irqs_common, .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; struct irq_domain *parent_domain = NULL;
int ret, i; 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_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) IRQCHIP_PLATFORM_DRIVER_END(mchp_eic)
MODULE_DESCRIPTION("Microchip External Interrupt Controller"); MODULE_DESCRIPTION("Microchip External Interrupt Controller");

View File

@ -174,6 +174,14 @@ static const struct meson_gpio_irq_params s4_params = {
INIT_MESON_S4_COMMON_DATA(82) 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 = { static const struct meson_gpio_irq_params c3_params = {
INIT_MESON_S4_COMMON_DATA(55) 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-ao-intc", .data = &a4_ao_params },
{ .compatible = "amlogic,a4-gpio-intc", .data = &a4_params }, { .compatible = "amlogic,a4-gpio-intc", .data = &a4_params },
{ .compatible = "amlogic,a5-gpio-intc", .data = &a5_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,c3-gpio-intc", .data = &c3_params },
{ .compatible = "amlogic,t7-gpio-intc", .data = &t7_params }, { .compatible = "amlogic,t7-gpio-intc", .data = &t7_params },
{ } { }
@ -572,8 +583,9 @@ static int meson_gpio_irq_parse_dt(struct device_node *node, struct meson_gpio_i
return 0; 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 irq_domain *domain, *parent_domain;
struct meson_gpio_irq_controller *ctl; struct meson_gpio_irq_controller *ctl;
int ret; int ret;
@ -630,10 +642,9 @@ static int meson_gpio_irq_of_init(struct device_node *node, struct device_node *
} }
IRQCHIP_PLATFORM_DRIVER_BEGIN(meson_gpio_intc) 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) IRQCHIP_PLATFORM_DRIVER_END(meson_gpio_intc)
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
MODULE_DESCRIPTION("Meson GPIO Interrupt Multiplexer driver"); MODULE_DESCRIPTION("Meson GPIO Interrupt Multiplexer driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:meson-gpio-intc");

View File

@ -195,5 +195,3 @@ MODULE_AUTHOR("Yehuda Yitschak <yehuday@marvell.com>");
MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>"); MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
MODULE_DESCRIPTION("Marvell Armada 7K/8K PIC driver"); MODULE_DESCRIPTION("Marvell Armada 7K/8K PIC driver");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:mvebu_pic");

View File

@ -320,9 +320,9 @@ static bool gic_hwirq_is_mapped(struct mpm_gic_map *maps, int cnt, u32 hwirq)
return false; 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 device *dev = &pdev->dev;
struct irq_domain *parent_domain; struct irq_domain *parent_domain;
struct generic_pm_domain *genpd; 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_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) IRQCHIP_PLATFORM_DRIVER_END(qcom_mpm)
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. MSM Power Manager"); MODULE_DESCRIPTION("Qualcomm Technologies, Inc. MSM Power Manager");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");

View File

@ -8,7 +8,6 @@
*/ */
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/cleanup.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
@ -528,18 +527,15 @@ static int rzg2l_irqc_parse_interrupts(struct rzg2l_irqc_priv *priv,
return 0; return 0;
} }
static int rzg2l_irqc_common_init(struct device_node *node, struct device_node *parent, static int rzg2l_irqc_common_probe(struct platform_device *pdev, struct device_node *parent,
const struct irq_chip *irq_chip) 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 irq_domain *irq_domain, *parent_domain;
struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct reset_control *resetn; struct reset_control *resetn;
int ret; int ret;
if (!pdev)
return -ENODEV;
parent_domain = irq_find_host(parent); parent_domain = irq_find_host(parent);
if (!parent_domain) if (!parent_domain)
return dev_err_probe(dev, -ENODEV, "cannot find parent domain\n"); return dev_err_probe(dev, -ENODEV, "cannot find parent domain\n");
@ -583,35 +579,22 @@ static int rzg2l_irqc_common_init(struct device_node *node, struct device_node *
register_syscore_ops(&rzg2l_irqc_syscore_ops); 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; return 0;
} }
static int __init rzg2l_irqc_init(struct device_node *node, static int rzg2l_irqc_probe(struct platform_device *pdev, struct device_node *parent)
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 __init rzfive_irqc_init(struct device_node *node, static int rzfive_irqc_probe(struct platform_device *pdev, struct device_node *parent)
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_PLATFORM_DRIVER_BEGIN(rzg2l_irqc)
IRQCHIP_MATCH("renesas,rzg2l-irqc", rzg2l_irqc_init) IRQCHIP_MATCH("renesas,rzg2l-irqc", rzg2l_irqc_probe)
IRQCHIP_MATCH("renesas,r9a07g043f-irqc", rzfive_irqc_init) IRQCHIP_MATCH("renesas,r9a07g043f-irqc", rzfive_irqc_probe)
IRQCHIP_PLATFORM_DRIVER_END(rzg2l_irqc) IRQCHIP_PLATFORM_DRIVER_END(rzg2l_irqc)
MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>"); MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>");
MODULE_DESCRIPTION("Renesas RZ/G2L IRQC Driver"); MODULE_DESCRIPTION("Renesas RZ/G2L IRQC Driver");

View File

@ -490,29 +490,15 @@ static int rzv2h_icu_parse_interrupts(struct rzv2h_icu_priv *priv, struct device
return 0; return 0;
} }
static void rzv2h_icu_put_device(void *data) static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_node *parent,
{ const struct rzv2h_hw_info *hw_info)
put_device(data);
}
static int rzv2h_icu_init_common(struct device_node *node, struct device_node *parent,
const struct rzv2h_hw_info *hw_info)
{ {
struct irq_domain *irq_domain, *parent_domain; struct irq_domain *irq_domain, *parent_domain;
struct device_node *node = pdev->dev.of_node;
struct rzv2h_icu_priv *rzv2h_icu_data; struct rzv2h_icu_priv *rzv2h_icu_data;
struct platform_device *pdev;
struct reset_control *resetn; struct reset_control *resetn;
int ret; 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); parent_domain = irq_find_host(parent);
if (!parent_domain) { if (!parent_domain) {
dev_err(&pdev->dev, "cannot find parent domain\n"); 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, .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_PLATFORM_DRIVER_BEGIN(rzv2h_icu)
IRQCHIP_MATCH("renesas,r9a09g047-icu", rzg3e_icu_init) IRQCHIP_MATCH("renesas,r9a09g047-icu", rzg3e_icu_probe)
IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_init) IRQCHIP_MATCH("renesas,r9a09g057-icu", rzv2h_icu_probe)
IRQCHIP_PLATFORM_DRIVER_END(rzv2h_icu) IRQCHIP_PLATFORM_DRIVER_END(rzv2h_icu)
MODULE_AUTHOR("Fabrizio Castro <fabrizio.castro.jz@renesas.com>"); MODULE_AUTHOR("Fabrizio Castro <fabrizio.castro.jz@renesas.com>");
MODULE_DESCRIPTION("Renesas RZ/V2H(P) ICU Driver"); MODULE_DESCRIPTION("Renesas RZ/V2H(P) ICU Driver");

View File

@ -91,9 +91,8 @@ static int __init imsic_ipi_domain_init(void) { return 0; }
*/ */
static void imsic_handle_irq(struct irq_desc *desc) 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); struct irq_chip *chip = irq_desc_get_chip(desc);
int cpu = smp_processor_id();
struct imsic_vector *vec;
unsigned long local_id; unsigned long local_id;
/* /*
@ -113,16 +112,12 @@ static void imsic_handle_irq(struct irq_desc *desc)
continue; continue;
} }
if (unlikely(!imsic->base_domain)) if (unlikely(local_id > imsic->global.nr_ids)) {
continue;
vec = imsic_vector_from_local_id(cpu, local_id);
if (!vec) {
pr_warn_ratelimited("vector not found for local ID 0x%lx\n", local_id); pr_warn_ratelimited("vector not found for local ID 0x%lx\n", local_id);
continue; continue;
} }
generic_handle_irq(vec->irq); generic_handle_irq(lpriv->vectors[local_id].irq);
} }
chained_irq_exit(chip, desc); chained_irq_exit(chip, desc);

View File

@ -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; tmp_vec.local_id = new_vec->local_id;
/* Point device to the temporary vector */ /* 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 */ /* 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 */ /* Update irq descriptors with the new vector */
d->chip_data = new_vec; d->chip_data = new_vec;

View File

@ -434,16 +434,6 @@ void imsic_vector_debug_show_summary(struct seq_file *m, int ind)
} }
#endif #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 *imsic_vector_alloc(unsigned int irq, const struct cpumask *mask)
{ {
struct imsic_vector *vec = NULL; struct imsic_vector *vec = NULL;
@ -487,7 +477,6 @@ static void __init imsic_local_cleanup(void)
lpriv = per_cpu_ptr(imsic->lpriv, cpu); lpriv = per_cpu_ptr(imsic->lpriv, cpu);
bitmap_free(lpriv->dirty_bitmap); bitmap_free(lpriv->dirty_bitmap);
kfree(lpriv->vectors);
} }
free_percpu(imsic->lpriv); free_percpu(imsic->lpriv);
@ -501,7 +490,8 @@ static int __init imsic_local_init(void)
int cpu, i; int cpu, i;
/* Allocate per-CPU private state */ /* 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) if (!imsic->lpriv)
return -ENOMEM; return -ENOMEM;
@ -521,12 +511,6 @@ static int __init imsic_local_init(void)
timer_setup(&lpriv->timer, imsic_local_timer_callback, TIMER_PINNED); timer_setup(&lpriv->timer, imsic_local_timer_callback, TIMER_PINNED);
#endif #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 */ /* Setup vector array */
for (i = 0; i <= global->nr_ids; i++) { for (i = 0; i <= global->nr_ids; i++) {
vec = &lpriv->vectors[i]; vec = &lpriv->vectors[i];

View File

@ -40,7 +40,7 @@ struct imsic_local_priv {
#endif #endif
/* Local vector table */ /* Local vector table */
struct imsic_vector *vectors; struct imsic_vector vectors[];
}; };
struct imsic_priv { struct imsic_priv {
@ -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_force_move_cleanup(struct imsic_vector *vec);
void imsic_vector_move(struct imsic_vector *old_vec, struct imsic_vector *new_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); struct imsic_vector *imsic_vector_alloc(unsigned int irq, const struct cpumask *mask);
void imsic_vector_free(struct imsic_vector *vector); void imsic_vector_free(struct imsic_vector *vector);

View File

@ -49,6 +49,8 @@
#define CONTEXT_ENABLE_BASE 0x2000 #define CONTEXT_ENABLE_BASE 0x2000
#define CONTEXT_ENABLE_SIZE 0x80 #define CONTEXT_ENABLE_SIZE 0x80
#define PENDING_BASE 0x1000
/* /*
* Each hart context has a set of control registers associated with it. Right * 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 * 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_ENABLE_THRESHOLD 0
#define PLIC_QUIRK_EDGE_INTERRUPT 0 #define PLIC_QUIRK_EDGE_INTERRUPT 0
#define PLIC_QUIRK_CP100_CLAIM_REGISTER_ERRATUM 1
struct plic_priv { struct plic_priv {
struct fwnode_handle *fwnode; struct fwnode_handle *fwnode;
@ -94,15 +97,22 @@ static DEFINE_PER_CPU(struct plic_handler, plic_handlers);
static int plic_irq_set_type(struct irq_data *d, unsigned int type); 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); u32 hwirq_mask = 1 << (hwirq % 32);
int group = hwirq / 32;
u32 value;
value = readl(base + group);
if (enable) if (enable)
writel(readl(reg) | hwirq_mask, reg); value |= hwirq_mask;
else 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) static void plic_toggle(struct plic_handler *handler, int hwirq, int enable)
@ -110,7 +120,7 @@ static void plic_toggle(struct plic_handler *handler, int hwirq, int enable)
unsigned long flags; unsigned long flags;
raw_spin_lock_irqsave(&handler->enable_lock, 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); raw_spin_unlock_irqrestore(&handler->enable_lock, flags);
} }
@ -247,33 +257,16 @@ static int plic_irq_set_type(struct irq_data *d, unsigned int type)
static int plic_irq_suspend(void) static int plic_irq_suspend(void)
{ {
unsigned int i, cpu;
unsigned long flags;
u32 __iomem *reg;
struct plic_priv *priv; struct plic_priv *priv;
priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv; priv = per_cpu_ptr(&plic_handlers, smp_processor_id())->priv;
/* irq ID 0 is reserved */ /* 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, __assign_bit(i, priv->prio_save,
readl(priv->regs + PRIORITY_BASE + i * PRIORITY_PER_ID)); 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; return 0;
} }
@ -398,6 +391,98 @@ static void plic_handle_irq(struct irq_desc *desc)
chained_irq_exit(chip, 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) static void plic_set_threshold(struct plic_handler *handler, u32 threshold)
{ {
/* priority must be > threshold to trigger an interrupt */ /* priority must be > threshold to trigger an interrupt */
@ -434,6 +519,8 @@ static const struct of_device_id plic_match[] = {
.data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) }, .data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) },
{ .compatible = "thead,c900-plic", { .compatible = "thead,c900-plic",
.data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) }, .data = (const void *)BIT(PLIC_QUIRK_EDGE_INTERRUPT) },
{ .compatible = "ultrarisc,cp100-plic",
.data = (const void *)BIT(PLIC_QUIRK_CP100_CLAIM_REGISTER_ERRATUM) },
{} {}
}; };
@ -592,12 +679,11 @@ static int plic_probe(struct fwnode_handle *fwnode)
if (parent_hwirq != RV_IRQ_EXT) { if (parent_hwirq != RV_IRQ_EXT) {
/* Disable S-mode enable bits if running in M-mode. */ /* Disable S-mode enable bits if running in M-mode. */
if (IS_ENABLED(CONFIG_RISCV_M_MODE)) { if (IS_ENABLED(CONFIG_RISCV_M_MODE)) {
void __iomem *enable_base = priv->regs + u32 __iomem *enable_base = priv->regs + CONTEXT_ENABLE_BASE +
CONTEXT_ENABLE_BASE + i * CONTEXT_ENABLE_SIZE;
i * CONTEXT_ENABLE_SIZE;
for (hwirq = 1; hwirq <= nr_irqs; hwirq++) for (int j = 0; j <= nr_irqs / 32; j++)
__plic_toggle(enable_base, hwirq, 0); writel(0, enable_base + j);
} }
continue; continue;
} }
@ -668,12 +754,17 @@ static int plic_probe(struct fwnode_handle *fwnode)
} }
if (global_setup) { 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 */ /* Find parent domain and register chained handler */
domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), DOMAIN_BUS_ANY); domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), DOMAIN_BUS_ANY);
if (domain) if (domain)
plic_parent_irq = irq_create_mapping(domain, RV_IRQ_EXT); plic_parent_irq = irq_create_mapping(domain, RV_IRQ_EXT);
if (plic_parent_irq) 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, cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
"irqchip/sifive/plic:starting", "irqchip/sifive/plic:starting",

View File

@ -114,9 +114,9 @@ static void starfive_intc_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc); chained_irq_exit(chip, desc);
} }
static int __init starfive_intc_init(struct device_node *intc, static int starfive_intc_probe(struct platform_device *pdev, struct device_node *parent)
struct device_node *parent)
{ {
struct device_node *intc = pdev->dev.of_node;
struct starfive_irq_chip *irqc; struct starfive_irq_chip *irqc;
struct reset_control *rst; struct reset_control *rst;
struct clk *clk; struct clk *clk;
@ -199,7 +199,7 @@ static int __init starfive_intc_init(struct device_node *intc,
} }
IRQCHIP_PLATFORM_DRIVER_BEGIN(starfive_intc) 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) IRQCHIP_PLATFORM_DRIVER_END(starfive_intc)
MODULE_DESCRIPTION("StarFive JH8100 External Interrupt Controller"); MODULE_DESCRIPTION("StarFive JH8100 External Interrupt Controller");

View File

@ -165,4 +165,3 @@ module_platform_driver(ts4800_ic_driver);
MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>"); MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>");
MODULE_DESCRIPTION("Multiplexed-IRQs driver for TS-4800's FPGA"); MODULE_DESCRIPTION("Multiplexed-IRQs driver for TS-4800's FPGA");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:ts4800_irqc");

View File

@ -36,11 +36,10 @@ int platform_irqchip_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct device_node *par_np __free(device_node) = of_irq_find_parent(np); 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; return -EINVAL;
}
if (par_np == np) if (par_np == np)
par_np = NULL; par_np = NULL;
@ -53,10 +52,9 @@ int platform_irqchip_probe(struct platform_device *pdev)
* interrupt controller. The actual initialization callback of this * interrupt controller. The actual initialization callback of this
* interrupt controller can check for specific domains as necessary. * 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 -EPROBE_DEFER;
}
return irq_init_cb(np, par_np); return irq_probe(pdev, par_np);
} }
EXPORT_SYMBOL_GPL(platform_irqchip_probe); EXPORT_SYMBOL_GPL(platform_irqchip_probe);

View File

@ -222,7 +222,7 @@ static int get_registers(struct platform_device *pdev, struct combiner *comb)
return 0; return 0;
} }
static int __init combiner_probe(struct platform_device *pdev) static int combiner_probe(struct platform_device *pdev)
{ {
struct combiner *combiner; struct combiner *combiner;
int nregs; int nregs;
@ -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 = { .driver = {
.name = "qcom-irq-combiner", .name = "qcom-irq-combiner",
.acpi_match_table = ACPI_PTR(qcom_irq_combiner_ids), .acpi_match_table = ACPI_PTR(qcom_irq_combiner_ids),
}, },
.probe = combiner_probe, .probe = combiner_probe,
}; };
builtin_platform_driver(qcom_irq_combiner_probe); builtin_platform_driver(qcom_irq_combiner_driver);

View File

@ -350,9 +350,10 @@ static int pdc_setup_pin_mapping(struct device_node *np)
#define QCOM_PDC_SIZE 0x30000 #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 irq_domain *parent_domain, *pdc_domain;
struct device_node *node = pdev->dev.of_node;
resource_size_t res_size; resource_size_t res_size;
struct resource res; struct resource res;
int ret; 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_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) IRQCHIP_PLATFORM_DRIVER_END(qcom_pdc)
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Power Domain Controller"); MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Power Domain Controller");
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");

View File

@ -17,12 +17,18 @@
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
typedef int (*platform_irq_probe_t)(struct platform_device *, struct device_node *);
/* Undefined on purpose */ /* Undefined on purpose */
extern of_irq_init_cb_t typecheck_irq_init_cb; extern of_irq_init_cb_t typecheck_irq_init_cb;
extern platform_irq_probe_t typecheck_irq_probe;
#define typecheck_irq_init_cb(fn) \ #define typecheck_irq_init_cb(fn) \
(__typecheck(typecheck_irq_init_cb, &fn) ? fn : 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 * This macro must be used by the different irqchip drivers to declare
* the association between their DT compatible string and their * 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[] = { static const struct of_device_id drv_name##_irqchip_match_table[] = {
#define IRQCHIP_MATCH(compat, fn) { .compatible = compat, \ #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, ...) \ #define IRQCHIP_PLATFORM_DRIVER_END(drv_name, ...) \