From d315c627a18249930750fe4eb2b21f3fe9b32ea4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 30 Oct 2020 18:59:19 +0200 Subject: regmap: irq: Convert to use irq_domain_create_legacy() irq_domain_create_legacy() takes a fwnode as parameter contrary to irq_domain_add_legacy() which requires a OF node. Switch the regmap irq domain creation to use that new function so it is not longer limited to OF based usage. Signed-off-by: Andy Shevchenko Signed-off-by: Thomas Gleixner Reviewed-by: Rafael J. Wysocki Acked-by: Mark Brown Link: https://lore.kernel.org/r/20201030165919.86234-6-andriy.shevchenko@linux.intel.com --- drivers/base/regmap/regmap-irq.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index ad5c2de395d1..19db764ffa4a 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -803,13 +803,12 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode, } if (irq_base) - d->domain = irq_domain_add_legacy(to_of_node(fwnode), - chip->num_irqs, irq_base, - 0, ®map_domain_ops, d); + d->domain = irq_domain_create_legacy(fwnode, chip->num_irqs, + irq_base, 0, + ®map_domain_ops, d); else - d->domain = irq_domain_add_linear(to_of_node(fwnode), - chip->num_irqs, - ®map_domain_ops, d); + d->domain = irq_domain_create_linear(fwnode, chip->num_irqs, + ®map_domain_ops, d); if (!d->domain) { dev_err(map->dev, "Failed to create IRQ domain\n"); ret = -ENOMEM; -- cgit v1.2.3 From 42a590b0fdf72498ebf47b01ddf006ee92cbfc70 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 9 Dec 2020 11:15:04 +0100 Subject: irqchip/gic: Spelling s/REturn/Return/ Fix a capitalization typo. Signed-off-by: Geert Uytterhoeven Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201209101504.2206941-1-geert+renesas@glider.be --- drivers/irqchip/irq-gic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 6053245a4754..a3c2f18131b2 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -973,7 +973,7 @@ void gic_migrate_target(unsigned int new_cpu_id) /* * gic_get_sgir_physaddr - get the physical address for the SGI register * - * REturn the physical address of the SGI register to be used + * Return the physical address of the SGI register to be used * by some early assembly code when the kernel is not yet available. */ static unsigned long gic_dist_physaddr; -- cgit v1.2.3 From 3ee36352e26935c7e8145eb4e7ed38b536ca01fc Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Sat, 5 Dec 2020 17:15:44 +0800 Subject: irqchip/loongson-htpic: Fix build warnings Fix build warnings as below: drivers/irqchip/irq-loongson-htpic.c: In function 'htpic_reg_init': >> drivers/irqchip/irq-loongson-htpic.c:62:12: warning: variable 'val' set but not used [-Wunused-but-set-variable] 62 | uint32_t val; | ^~~ drivers/irqchip/irq-loongson-htpic.c: At top level: >> drivers/irqchip/irq-loongson-htpic.c:84:12: warning: no previous prototype for 'htpic_of_init' [-Wmissing-prototypes] 84 | int __init htpic_of_init(struct device_node *node, struct device_node *parent) | ^~~~~~~~~~~~~ Fixes: a93f1d903fa34fc2c5d9fa450bd ("irqchip: Add driver for Loongson-3 HyperTransport PIC controller") Reported-by: kernel test robot Signed-off-by: Huacai Chen Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/1607159744-995-1-git-send-email-chenhuacai@kernel.org --- drivers/irqchip/irq-loongson-htpic.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-loongson-htpic.c b/drivers/irqchip/irq-loongson-htpic.c index 63f72803c8c4..1b801c4fb026 100644 --- a/drivers/irqchip/irq-loongson-htpic.c +++ b/drivers/irqchip/irq-loongson-htpic.c @@ -59,11 +59,10 @@ static void htpic_reg_init(void) int i; for (i = 0; i < HTINT_NUM_VECTORS; i++) { - uint32_t val; - /* Disable all HT Vectors */ writel(0x0, htpic->base + HTINT_EN_OFF + i * 0x4); - val = readl(htpic->base + i * 0x4); + /* Read back to force write */ + (void) readl(htpic->base + i * 0x4); /* Ack all possible pending IRQs */ writel(GENMASK(31, 0), htpic->base + i * 0x4); } @@ -81,7 +80,7 @@ struct syscore_ops htpic_syscore_ops = { .resume = htpic_resume, }; -int __init htpic_of_init(struct device_node *node, struct device_node *parent) +static int __init htpic_of_init(struct device_node *node, struct device_node *parent) { unsigned int parent_irq[4]; int i, err; -- cgit v1.2.3 From b16a1caf4686895427c810219d4b2f796e676160 Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Mon, 30 Nov 2020 18:15:05 +0800 Subject: irqchip/ls-extirq: Add LS1043A, LS1088A external interrupt support Add an new IRQ chip declaration for LS1043A and LS1088A, and cleanup the use of the "bit_reverse" property, now gated on the Soc type. Signed-off-by: Hou Zhiqiang Signed-off-by: Biwen Li Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201130101515.27431-1-biwen.li@oss.nxp.com --- drivers/irqchip/irq-ls-extirq.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-ls-extirq.c b/drivers/irqchip/irq-ls-extirq.c index 4d1179fed77c..f94f974a8764 100644 --- a/drivers/irqchip/irq-ls-extirq.c +++ b/drivers/irqchip/irq-ls-extirq.c @@ -18,7 +18,7 @@ struct ls_extirq_data { struct regmap *syscon; u32 intpcr; - bool bit_reverse; + bool is_ls1021a_or_ls1043a; u32 nirq; struct irq_fwspec map[MAXIRQ]; }; @@ -30,7 +30,7 @@ ls_extirq_set_type(struct irq_data *data, unsigned int type) irq_hw_number_t hwirq = data->hwirq; u32 value, mask; - if (priv->bit_reverse) + if (priv->is_ls1021a_or_ls1043a) mask = 1U << (31 - hwirq); else mask = 1U << hwirq; @@ -174,14 +174,8 @@ ls_extirq_of_init(struct device_node *node, struct device_node *parent) if (ret) goto out; - if (of_device_is_compatible(node, "fsl,ls1021a-extirq")) { - u32 revcr; - - ret = regmap_read(priv->syscon, LS1021A_SCFGREVCR, &revcr); - if (ret) - goto out; - priv->bit_reverse = (revcr != 0); - } + priv->is_ls1021a_or_ls1043a = of_device_is_compatible(node, "fsl,ls1021a-extirq") || + of_device_is_compatible(node, "fsl,ls1043a-extirq"); domain = irq_domain_add_hierarchy(parent_domain, 0, priv->nirq, node, &extirq_domain_ops, priv); @@ -195,3 +189,5 @@ out: } IRQCHIP_DECLARE(ls1021a_extirq, "fsl,ls1021a-extirq", ls_extirq_of_init); +IRQCHIP_DECLARE(ls1043a_extirq, "fsl,ls1043a-extirq", ls_extirq_of_init); +IRQCHIP_DECLARE(ls1088a_extirq, "fsl,ls1088a-extirq", ls_extirq_of_init); -- cgit v1.2.3 From 3841245e8498a789c65dedd7ffa8fb2fee2c0684 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 29 Nov 2020 13:55:25 +0000 Subject: irqchip/alpine-msi: Fix freeing of interrupts on allocation error path The alpine-msi driver has an interesting allocation error handling, where it frees the same interrupts repeatedly. Hilarity follows. This code is probably never executed, but let's fix it nonetheless. Fixes: e6b78f2c3e14 ("irqchip: Add the Alpine MSIX interrupt controller") Signed-off-by: Marc Zyngier Reviewed-by: Antoine Tenart Cc: Tsahee Zidenberg Cc: Antoine Tenart Link: https://lore.kernel.org/r/20201129135525.396671-1-maz@kernel.org --- drivers/irqchip/irq-alpine-msi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-alpine-msi.c b/drivers/irqchip/irq-alpine-msi.c index 23a3b877f7f1..ede02dc2bcd0 100644 --- a/drivers/irqchip/irq-alpine-msi.c +++ b/drivers/irqchip/irq-alpine-msi.c @@ -165,8 +165,7 @@ static int alpine_msix_middle_domain_alloc(struct irq_domain *domain, return 0; err_sgi: - while (--i >= 0) - irq_domain_free_irqs_parent(domain, virq, i); + irq_domain_free_irqs_parent(domain, virq, i - 1); alpine_msix_free_sgi(priv, sgi, nr_irqs); return err; } -- cgit v1.2.3 From 0b39498230ae53e6af981141be99f4c7d5144de6 Mon Sep 17 00:00:00 2001 From: Shenming Lu Date: Sat, 28 Nov 2020 22:18:56 +0800 Subject: irqchip/gic-v4.1: Reduce the delay when polling GICR_VPENDBASER.Dirty The 10us delay of the poll on the GICR_VPENDBASER.Dirty bit is too high, which might greatly affect the total scheduling latency of a vCPU in our measurement. So we reduce it to 1 to lessen the impact. Signed-off-by: Shenming Lu Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201128141857.983-2-lushenming@huawei.com --- drivers/irqchip/irq-gic-v3-its.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 4069c215328b..d74ef418e386 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -3808,7 +3808,7 @@ static void its_wait_vpt_parse_complete(void) WARN_ON_ONCE(readq_relaxed_poll_timeout_atomic(vlpi_base + GICR_VPENDBASER, val, !(val & GICR_VPENDBASER_Dirty), - 10, 500)); + 1, 500)); } static void its_vpe_schedule(struct its_vpe *vpe) -- cgit v1.2.3 From 5f0c75e7a1333f5ebb5303af55d8c863ea292c23 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 25 Nov 2020 11:32:03 +0100 Subject: irqchip/ocelot: prepare to support more SoC This patch extends irqchip driver for oceleot to be used with other vcoreiii base platforms. Signed-off-by: Gregory CLEMENT Signed-off-by: Marc Zyngier Acked-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201125103206.136498-4-gregory.clement@bootlin.com --- drivers/irqchip/irq-mscc-ocelot.c | 76 +++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-mscc-ocelot.c b/drivers/irqchip/irq-mscc-ocelot.c index 88143c0b700c..6d4029a2ded0 100644 --- a/drivers/irqchip/irq-mscc-ocelot.c +++ b/drivers/irqchip/irq-mscc-ocelot.c @@ -12,30 +12,51 @@ #include #include -#define ICPU_CFG_INTR_INTR_STICKY 0x10 -#define ICPU_CFG_INTR_INTR_ENA 0x18 -#define ICPU_CFG_INTR_INTR_ENA_CLR 0x1c -#define ICPU_CFG_INTR_INTR_ENA_SET 0x20 -#define ICPU_CFG_INTR_DST_INTR_IDENT(x) (0x38 + 0x4 * (x)) -#define ICPU_CFG_INTR_INTR_TRIGGER(x) (0x5c + 0x4 * (x)) - -#define OCELOT_NR_IRQ 24 +#define ICPU_CFG_INTR_DST_INTR_IDENT(_p, x) ((_p)->reg_off_ident + 0x4 * (x)) +#define ICPU_CFG_INTR_INTR_TRIGGER(_p, x) ((_p)->reg_off_trigger + 0x4 * (x)) + +#define FLAGS_HAS_TRIGGER BIT(0) + +struct chip_props { + u8 flags; + u8 reg_off_sticky; + u8 reg_off_ena; + u8 reg_off_ena_clr; + u8 reg_off_ena_set; + u8 reg_off_ident; + u8 reg_off_trigger; + u8 reg_off_ena_irq0; + u8 n_irq; +}; + +static struct chip_props ocelot_props = { + .flags = FLAGS_HAS_TRIGGER, + .reg_off_sticky = 0x10, + .reg_off_ena = 0x18, + .reg_off_ena_clr = 0x1c, + .reg_off_ena_set = 0x20, + .reg_off_ident = 0x38, + .reg_off_trigger = 0x5c, + .n_irq = 24, +}; static void ocelot_irq_unmask(struct irq_data *data) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); + struct irq_domain *d = data->domain; + struct chip_props *p = d->host_data; struct irq_chip_type *ct = irq_data_get_chip_type(data); unsigned int mask = data->mask; u32 val; irq_gc_lock(gc); - val = irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(0)) | - irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(1)); + val = irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(p, 0)) | + irq_reg_readl(gc, ICPU_CFG_INTR_INTR_TRIGGER(p, 1)); if (!(val & mask)) - irq_reg_writel(gc, mask, ICPU_CFG_INTR_INTR_STICKY); + irq_reg_writel(gc, mask, p->reg_off_sticky); *ct->mask_cache &= ~mask; - irq_reg_writel(gc, mask, ICPU_CFG_INTR_INTR_ENA_SET); + irq_reg_writel(gc, mask, p->reg_off_ena_set); irq_gc_unlock(gc); } @@ -43,8 +64,9 @@ static void ocelot_irq_handler(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct irq_domain *d = irq_desc_get_handler_data(desc); + struct chip_props *p = d->host_data; struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0); - u32 reg = irq_reg_readl(gc, ICPU_CFG_INTR_DST_INTR_IDENT(0)); + u32 reg = irq_reg_readl(gc, ICPU_CFG_INTR_DST_INTR_IDENT(p, 0)); chained_irq_enter(chip, desc); @@ -58,8 +80,9 @@ static void ocelot_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int __init ocelot_irq_init(struct device_node *node, - struct device_node *parent) +static int __init vcoreiii_irq_init(struct device_node *node, + struct device_node *parent, + struct chip_props *p) { struct irq_domain *domain; struct irq_chip_generic *gc; @@ -69,14 +92,14 @@ static int __init ocelot_irq_init(struct device_node *node, if (!parent_irq) return -EINVAL; - domain = irq_domain_add_linear(node, OCELOT_NR_IRQ, + domain = irq_domain_add_linear(node, p->n_irq, &irq_generic_chip_ops, NULL); if (!domain) { pr_err("%pOFn: unable to add irq domain\n", node); return -ENOMEM; } - ret = irq_alloc_domain_generic_chips(domain, OCELOT_NR_IRQ, 1, + ret = irq_alloc_domain_generic_chips(domain, p->n_irq, 1, "icpu", handle_level_irq, 0, 0, 0); if (ret) { @@ -92,16 +115,18 @@ static int __init ocelot_irq_init(struct device_node *node, goto err_gc_free; } - gc->chip_types[0].regs.ack = ICPU_CFG_INTR_INTR_STICKY; - gc->chip_types[0].regs.mask = ICPU_CFG_INTR_INTR_ENA_CLR; + gc->chip_types[0].regs.ack = p->reg_off_sticky; + gc->chip_types[0].regs.mask = p->reg_off_ena_clr; gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; - gc->chip_types[0].chip.irq_unmask = ocelot_irq_unmask; + if (p->flags & FLAGS_HAS_TRIGGER) + gc->chip_types[0].chip.irq_unmask = ocelot_irq_unmask; /* Mask and ack all interrupts */ - irq_reg_writel(gc, 0, ICPU_CFG_INTR_INTR_ENA); - irq_reg_writel(gc, 0xffffffff, ICPU_CFG_INTR_INTR_STICKY); + irq_reg_writel(gc, 0, p->reg_off_ena); + irq_reg_writel(gc, 0xffffffff, p->reg_off_sticky); + domain->host_data = p; irq_set_chained_handler_and_data(parent_irq, ocelot_irq_handler, domain); @@ -115,4 +140,11 @@ err_domain_remove: return ret; } + +static int __init ocelot_irq_init(struct device_node *node, + struct device_node *parent) +{ + return vcoreiii_irq_init(node, parent, &ocelot_props); +} + IRQCHIP_DECLARE(ocelot_icpu, "mscc,ocelot-icpu-intr", ocelot_irq_init); -- cgit v1.2.3 From ffce73d4415391b2d6da4878bf04d6610edf56db Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 25 Nov 2020 11:32:04 +0100 Subject: irqchip/ocelot: Add support for Luton platforms This patch extends irqchip driver for oceleot to be used with an other vcoreiii base platform: Luton. For this platform there is a few differences: - the interrupt must be enabled for the parent controller - there is no trigger register needed to be managed Signed-off-by: Gregory CLEMENT Signed-off-by: Marc Zyngier Acked-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201125103206.136498-5-gregory.clement@bootlin.com --- drivers/irqchip/irq-mscc-ocelot.c | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-mscc-ocelot.c b/drivers/irqchip/irq-mscc-ocelot.c index 6d4029a2ded0..496f955b8fc4 100644 --- a/drivers/irqchip/irq-mscc-ocelot.c +++ b/drivers/irqchip/irq-mscc-ocelot.c @@ -16,6 +16,7 @@ #define ICPU_CFG_INTR_INTR_TRIGGER(_p, x) ((_p)->reg_off_trigger + 0x4 * (x)) #define FLAGS_HAS_TRIGGER BIT(0) +#define FLAGS_NEED_INIT_ENABLE BIT(1) struct chip_props { u8 flags; @@ -40,6 +41,17 @@ static struct chip_props ocelot_props = { .n_irq = 24, }; +static struct chip_props luton_props = { + .flags = FLAGS_NEED_INIT_ENABLE, + .reg_off_sticky = 0, + .reg_off_ena = 0x4, + .reg_off_ena_clr = 0x8, + .reg_off_ena_set = 0xc, + .reg_off_ident = 0x18, + .reg_off_ena_irq0 = 0x14, + .n_irq = 28, +}; + static void ocelot_irq_unmask(struct irq_data *data) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); @@ -115,17 +127,27 @@ static int __init vcoreiii_irq_init(struct device_node *node, goto err_gc_free; } - gc->chip_types[0].regs.ack = p->reg_off_sticky; - gc->chip_types[0].regs.mask = p->reg_off_ena_clr; gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; - gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; - if (p->flags & FLAGS_HAS_TRIGGER) + gc->chip_types[0].regs.ack = p->reg_off_sticky; + if (p->flags & FLAGS_HAS_TRIGGER) { + gc->chip_types[0].regs.mask = p->reg_off_ena_clr; gc->chip_types[0].chip.irq_unmask = ocelot_irq_unmask; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; + } else { + gc->chip_types[0].regs.enable = p->reg_off_ena_set; + gc->chip_types[0].regs.disable = p->reg_off_ena_clr; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; + gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; + } /* Mask and ack all interrupts */ irq_reg_writel(gc, 0, p->reg_off_ena); irq_reg_writel(gc, 0xffffffff, p->reg_off_sticky); + /* Overall init */ + if (p->flags & FLAGS_NEED_INIT_ENABLE) + irq_reg_writel(gc, BIT(0), p->reg_off_ena_irq0); + domain->host_data = p; irq_set_chained_handler_and_data(parent_irq, ocelot_irq_handler, domain); @@ -148,3 +170,11 @@ static int __init ocelot_irq_init(struct device_node *node, } IRQCHIP_DECLARE(ocelot_icpu, "mscc,ocelot-icpu-intr", ocelot_irq_init); + +static int __init luton_irq_init(struct device_node *node, + struct device_node *parent) +{ + return vcoreiii_irq_init(node, parent, &luton_props); +} + +IRQCHIP_DECLARE(luton_icpu, "mscc,luton-icpu-intr", luton_irq_init); -- cgit v1.2.3 From 7efdfbd15a21788de8c0743590e777f151a3031b Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 25 Nov 2020 11:32:05 +0100 Subject: irqchip/ocelot: Add support for Serval platforms This patch extends irqchip driver for ocelot to be used with an other vcoreiii base platform: Serval. Based on a larger patch from Lars Povlsen Signed-off-by: Gregory CLEMENT Signed-off-by: Marc Zyngier Acked-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201125103206.136498-6-gregory.clement@bootlin.com --- drivers/irqchip/irq-mscc-ocelot.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/irqchip/irq-mscc-ocelot.c b/drivers/irqchip/irq-mscc-ocelot.c index 496f955b8fc4..da5a0ad991a1 100644 --- a/drivers/irqchip/irq-mscc-ocelot.c +++ b/drivers/irqchip/irq-mscc-ocelot.c @@ -41,6 +41,17 @@ static struct chip_props ocelot_props = { .n_irq = 24, }; +static struct chip_props serval_props = { + .flags = FLAGS_HAS_TRIGGER, + .reg_off_sticky = 0xc, + .reg_off_ena = 0x14, + .reg_off_ena_clr = 0x18, + .reg_off_ena_set = 0x1c, + .reg_off_ident = 0x20, + .reg_off_trigger = 0x4, + .n_irq = 24, +}; + static struct chip_props luton_props = { .flags = FLAGS_NEED_INIT_ENABLE, .reg_off_sticky = 0, @@ -171,6 +182,14 @@ static int __init ocelot_irq_init(struct device_node *node, IRQCHIP_DECLARE(ocelot_icpu, "mscc,ocelot-icpu-intr", ocelot_irq_init); +static int __init serval_irq_init(struct device_node *node, + struct device_node *parent) +{ + return vcoreiii_irq_init(node, parent, &serval_props); +} + +IRQCHIP_DECLARE(serval_icpu, "mscc,serval-icpu-intr", serval_irq_init); + static int __init luton_irq_init(struct device_node *node, struct device_node *parent) { -- cgit v1.2.3 From 550c1424acf0123ba0c17e22dfcac92d152b2f0e Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 25 Nov 2020 11:32:06 +0100 Subject: irqchip/ocelot: Add support for Jaguar2 platforms This patch extends irqchip driver for ocelot to be used with an other vcoreiii base platform: Jaguar2. Based on a larger patch from Lars Povlsen Signed-off-by: Gregory CLEMENT Signed-off-by: Marc Zyngier Acked-by: Alexandre Belloni Link: https://lore.kernel.org/r/20201125103206.136498-7-gregory.clement@bootlin.com --- drivers/irqchip/irq-mscc-ocelot.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/irqchip/irq-mscc-ocelot.c b/drivers/irqchip/irq-mscc-ocelot.c index da5a0ad991a1..8235d98650c1 100644 --- a/drivers/irqchip/irq-mscc-ocelot.c +++ b/drivers/irqchip/irq-mscc-ocelot.c @@ -63,6 +63,17 @@ static struct chip_props luton_props = { .n_irq = 28, }; +static struct chip_props jaguar2_props = { + .flags = FLAGS_HAS_TRIGGER, + .reg_off_sticky = 0x10, + .reg_off_ena = 0x18, + .reg_off_ena_clr = 0x1c, + .reg_off_ena_set = 0x20, + .reg_off_ident = 0x38, + .reg_off_trigger = 0x5c, + .n_irq = 29, +}; + static void ocelot_irq_unmask(struct irq_data *data) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); @@ -197,3 +208,11 @@ static int __init luton_irq_init(struct device_node *node, } IRQCHIP_DECLARE(luton_icpu, "mscc,luton-icpu-intr", luton_irq_init); + +static int __init jaguar2_irq_init(struct device_node *node, + struct device_node *parent) +{ + return vcoreiii_irq_init(node, parent, &jaguar2_props); +} + +IRQCHIP_DECLARE(jaguar2_icpu, "mscc,jaguar2-icpu-intr", jaguar2_irq_init); -- cgit v1.2.3 From 6abbd6988971aaa607b026eaa0ffd2301352f2ea Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Mon, 9 Nov 2020 09:41:17 +0000 Subject: irqchip/gic, gic-v3: Make SGIs use handle_percpu_devid_irq() handle_percpu_devid_fasteoi_ipi() states: * The biggest difference with the IRQ version is that the interrupt is * EOIed early, as the IPI could result in a context switch, and we need to * make sure the IPI can fire again All that can actually happen scheduler-wise within the handling of an IPI is the raising of TIF_NEED_RESCHED (and / or folding thereof into preempt_count); see scheduler_ipi() or sched_ttwu_pending() for instance. Said flag / preempt_count is evaluated some time later before returning to whatever context was interrupted, and this gates a call to preempt_schedule_irq() (arm64_preempt_schedule_irq() in arm64). Per the above, SGI's do not need a different handler than PPI's, so make them use the same (handle_percpu_devid_irq). Signed-off-by: Valentin Schneider Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201109094121.29975-2-valentin.schneider@arm.com --- drivers/irqchip/irq-gic-v3.c | 6 ------ drivers/irqchip/irq-gic.c | 8 +------- 2 files changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 16fecc0febe8..3fc65375cbe0 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1302,12 +1302,6 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, switch (__get_intid_range(hw)) { case SGI_RANGE: - irq_set_percpu_devid(irq); - irq_domain_set_info(d, irq, hw, chip, d->host_data, - handle_percpu_devid_fasteoi_ipi, - NULL, NULL); - break; - case PPI_RANGE: case EPPI_RANGE: irq_set_percpu_devid(irq); diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index a3c2f18131b2..b1d9c22caf2e 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1005,13 +1005,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, struct irq_data *irqd = irq_desc_get_irq_data(irq_to_desc(irq)); switch (hw) { - case 0 ... 15: - irq_set_percpu_devid(irq); - irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data, - handle_percpu_devid_fasteoi_ipi, - NULL, NULL); - break; - case 16 ... 31: + case 0 ... 31: irq_set_percpu_devid(irq); irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data, handle_percpu_devid_irq, NULL, NULL); -- cgit v1.2.3 From e52e73b7e9f7d08b8c2ef6fb1657105093e22a03 Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Mon, 9 Nov 2020 09:41:18 +0000 Subject: irqchip/armada-370-xp: Make IPIs use handle_percpu_devid_irq() As done for the Arm GIC irqchips, move IPIs to handle_percpu_devid_irq() as handle_percpu_devid_fasteoi_ipi() isn't actually required. Signed-off-by: Valentin Schneider Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201109094121.29975-3-valentin.schneider@arm.com --- drivers/irqchip/irq-armada-370-xp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index d7eb2e93db8f..32938dfc0e46 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -382,7 +382,7 @@ static int armada_370_xp_ipi_alloc(struct irq_domain *d, irq_set_percpu_devid(virq + i); irq_domain_set_info(d, virq + i, i, &ipi_irqchip, d->host_data, - handle_percpu_devid_fasteoi_ipi, + handle_percpu_devid_irq, NULL, NULL); } -- cgit v1.2.3 From ffdad793d579c9286c7b67a86d1a3c890fb32082 Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Mon, 9 Nov 2020 09:41:19 +0000 Subject: irqchip/bcm2836: Make IPIs use handle_percpu_devid_irq() As done for the Arm GIC irqchips, move IPIs to handle_percpu_devid_irq() as handle_percpu_devid_fasteoi_ipi() isn't actually required. Signed-off-by: Valentin Schneider Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201109094121.29975-4-valentin.schneider@arm.com --- drivers/irqchip/irq-bcm2836.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c index cbc7c740e4dc..5f5eb8877c41 100644 --- a/drivers/irqchip/irq-bcm2836.c +++ b/drivers/irqchip/irq-bcm2836.c @@ -209,7 +209,7 @@ static int bcm2836_arm_irqchip_ipi_alloc(struct irq_domain *d, irq_set_percpu_devid(virq + i); irq_domain_set_info(d, virq + i, i, &bcm2836_arm_irqchip_ipi, d->host_data, - handle_percpu_devid_fasteoi_ipi, + handle_percpu_devid_irq, NULL, NULL); } -- cgit v1.2.3 From a2e042e13ff322ad523a2f131dd6e03e8bc05053 Mon Sep 17 00:00:00 2001 From: Valentin Schneider Date: Mon, 9 Nov 2020 09:41:20 +0000 Subject: irqchip/hip04: Make IPIs use handle_percpu_devid_irq() As done for the Arm GIC irqchips, move IPIs to handle_percpu_devid_irq() as handle_percpu_devid_fasteoi_ipi() isn't actually required. Signed-off-by: Valentin Schneider Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201109094121.29975-5-valentin.schneider@arm.com --- drivers/irqchip/irq-hip04.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index 9b73dcfaf48d..a6ed877d9dd3 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -296,11 +296,7 @@ static void hip04_irq_cpu_init(struct hip04_irq_data *intc) static int hip04_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { - if (hw < 16) { - irq_set_percpu_devid(irq); - irq_set_chip_and_handler(irq, &hip04_irq_chip, - handle_percpu_devid_fasteoi_ipi); - } else if (hw < 32) { + if (hw < 32) { irq_set_percpu_devid(irq); irq_set_chip_and_handler(irq, &hip04_irq_chip, handle_percpu_devid_irq); -- cgit v1.2.3 From 04e7f423f4a96ad492fd51bf2234b8982400ab5f Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Thu, 5 Nov 2020 13:22:09 -0800 Subject: drivers/irqchip: Remove EZChip NPS interrupt controller NPS platform has been removed from ARC port and there are no in-tree users of it now. So RIP ! Signed-off-by: Vineet Gupta Signed-off-by: Marc Zyngier Cc: Thomas Gleixner Cc: Jason Cooper Cc: Marc Zyngier Cc: linux-kernel@vger.kernel.org Link: https://lore.kernel.org/r/20201105212210.1891598-3-vgupta@synopsys.com --- drivers/irqchip/Kconfig | 7 -- drivers/irqchip/Makefile | 1 - drivers/irqchip/irq-eznps.c | 165 -------------------------------------------- 3 files changed, 173 deletions(-) delete mode 100644 drivers/irqchip/irq-eznps.c (limited to 'drivers') diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 2aa79c32ee22..94920a51c628 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -387,13 +387,6 @@ config LS_SCFG_MSI config PARTITION_PERCPU bool -config EZNPS_GIC - bool "NPS400 Global Interrupt Manager (GIM)" - depends on ARC || (COMPILE_TEST && !64BIT) - select IRQ_DOMAIN - help - Support the EZchip NPS400 global interrupt controller - config STM32_EXTI bool select IRQ_DOMAIN diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 94c2885882ee..0ac93bfaec61 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -86,7 +86,6 @@ obj-$(CONFIG_MVEBU_PIC) += irq-mvebu-pic.o obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o obj-$(CONFIG_LS_EXTIRQ) += irq-ls-extirq.o obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o -obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o diff --git a/drivers/irqchip/irq-eznps.c b/drivers/irqchip/irq-eznps.c deleted file mode 100644 index 2a7a38830a8d..000000000000 --- a/drivers/irqchip/irq-eznps.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2016, Mellanox Technologies. All rights reserved. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define NPS_NR_CPU_IRQS 8 /* number of interrupt lines of NPS400 CPU */ -#define NPS_TIMER0_IRQ 3 - -/* - * NPS400 core includes an Interrupt Controller (IC) support. - * All cores can deactivate level irqs at first level control - * at cores mesh layer called MTM. - * For devices out side chip e.g. uart, network there is another - * level called Global Interrupt Manager (GIM). - * This second level can control level and edge interrupt. - * - * NOTE: AUX_IENABLE and CTOP_AUX_IACK are auxiliary registers - * with private HW copy per CPU. - */ - -static void nps400_irq_mask(struct irq_data *irqd) -{ - unsigned int ienb; - unsigned int irq = irqd_to_hwirq(irqd); - - ienb = read_aux_reg(AUX_IENABLE); - ienb &= ~(1 << irq); - write_aux_reg(AUX_IENABLE, ienb); -} - -static void nps400_irq_unmask(struct irq_data *irqd) -{ - unsigned int ienb; - unsigned int irq = irqd_to_hwirq(irqd); - - ienb = read_aux_reg(AUX_IENABLE); - ienb |= (1 << irq); - write_aux_reg(AUX_IENABLE, ienb); -} - -static void nps400_irq_eoi_global(struct irq_data *irqd) -{ - unsigned int __maybe_unused irq = irqd_to_hwirq(irqd); - - write_aux_reg(CTOP_AUX_IACK, 1 << irq); - - /* Don't ack GIC before all device access attempts are done */ - mb(); - - nps_ack_gic(); -} - -static void nps400_irq_ack(struct irq_data *irqd) -{ - unsigned int __maybe_unused irq = irqd_to_hwirq(irqd); - - write_aux_reg(CTOP_AUX_IACK, 1 << irq); -} - -static struct irq_chip nps400_irq_chip_fasteoi = { - .name = "NPS400 IC Global", - .irq_mask = nps400_irq_mask, - .irq_unmask = nps400_irq_unmask, - .irq_eoi = nps400_irq_eoi_global, -}; - -static struct irq_chip nps400_irq_chip_percpu = { - .name = "NPS400 IC", - .irq_mask = nps400_irq_mask, - .irq_unmask = nps400_irq_unmask, - .irq_ack = nps400_irq_ack, -}; - -static int nps400_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) -{ - switch (hw) { - case NPS_TIMER0_IRQ: -#ifdef CONFIG_SMP - case NPS_IPI_IRQ: -#endif - irq_set_percpu_devid(virq); - irq_set_chip_and_handler(virq, &nps400_irq_chip_percpu, - handle_percpu_devid_irq); - break; - default: - irq_set_chip_and_handler(virq, &nps400_irq_chip_fasteoi, - handle_fasteoi_irq); - break; - } - - return 0; -} - -static const struct irq_domain_ops nps400_irq_ops = { - .xlate = irq_domain_xlate_onecell, - .map = nps400_irq_map, -}; - -static int __init nps400_of_init(struct device_node *node, - struct device_node *parent) -{ - struct irq_domain *nps400_root_domain; - - if (parent) { - pr_err("DeviceTree incore ic not a root irq controller\n"); - return -EINVAL; - } - - nps400_root_domain = irq_domain_add_linear(node, NPS_NR_CPU_IRQS, - &nps400_irq_ops, NULL); - - if (!nps400_root_domain) { - pr_err("nps400 root irq domain not avail\n"); - return -ENOMEM; - } - - /* - * Needed for primary domain lookup to succeed - * This is a primary irqchip, and can never have a parent - */ - irq_set_default_host(nps400_root_domain); - -#ifdef CONFIG_SMP - irq_create_mapping(nps400_root_domain, NPS_IPI_IRQ); -#endif - - return 0; -} -IRQCHIP_DECLARE(ezchip_nps400_ic, "ezchip,nps400-ic", nps400_of_init); -- cgit v1.2.3 From b10d5fd489b0c67f59cbdd28d95f4bd9f76a62f2 Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Mon, 2 Nov 2020 17:36:14 +0530 Subject: irqchip/ti-sci-inta: Fix printing of inta id on probe success On a successful probe, the driver tries to print a success message with INTA device id. It uses pdev->id for printing the id but id is stored in inta->ti_sci_id. Fix it by correcting the dev_info parameter. Fixes: 5c4b585d2910 ("irqchip/ti-sci-inta: Add support for INTA directly connecting to GIC") Signed-off-by: Lokesh Vutla Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201102120614.11109-1-lokeshvutla@ti.com --- drivers/irqchip/irq-ti-sci-inta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c index b2ab8db439d9..532d0ae172d9 100644 --- a/drivers/irqchip/irq-ti-sci-inta.c +++ b/drivers/irqchip/irq-ti-sci-inta.c @@ -726,7 +726,7 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev) INIT_LIST_HEAD(&inta->vint_list); mutex_init(&inta->vint_mutex); - dev_info(dev, "Interrupt Aggregator domain %d created\n", pdev->id); + dev_info(dev, "Interrupt Aggregator domain %d created\n", inta->ti_sci_id); return 0; } -- cgit v1.2.3 From fc6c7cd3878641fd43189f15697e7ad0871f5c1a Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Mon, 2 Nov 2020 17:36:31 +0530 Subject: irqchip/ti-sci-intr: Fix freeing of irqs ti_sci_intr_irq_domain_free() assumes that out_irq of intr is stored in data->chip_data and uses it for calling ti_sci irq_free() and then mark the out_irq as available resource. But ti_sci_intr_irq_domain_alloc() is storing p_hwirq(parent's hardware irq) which is translated from out_irq. This is causing resource leakage and eventually out_irq resources might be exhausted. Fix ti_sci_intr_irq_domain_alloc() by storing the out_irq in data->chip_data. Fixes: a5b659bd4bc7 ("irqchip/ti-sci-intr: Add support for INTR being a parent to INTR") Signed-off-by: Lokesh Vutla Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20201102120631.11165-1-lokeshvutla@ti.com --- drivers/irqchip/irq-ti-sci-intr.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-ti-sci-intr.c b/drivers/irqchip/irq-ti-sci-intr.c index ac9d6d658e65..fe8fad22bcf9 100644 --- a/drivers/irqchip/irq-ti-sci-intr.c +++ b/drivers/irqchip/irq-ti-sci-intr.c @@ -129,7 +129,7 @@ static void ti_sci_intr_irq_domain_free(struct irq_domain *domain, * @virq: Corresponding Linux virtual IRQ number * @hwirq: Corresponding hwirq for the IRQ within this IRQ domain * - * Returns parent irq if all went well else appropriate error pointer. + * Returns intr output irq if all went well else appropriate error pointer. */ static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain, unsigned int virq, u32 hwirq) @@ -173,7 +173,7 @@ static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain, if (err) goto err_msg; - return p_hwirq; + return out_irq; err_msg: irq_domain_free_irqs_parent(domain, virq, 1); @@ -198,19 +198,19 @@ static int ti_sci_intr_irq_domain_alloc(struct irq_domain *domain, struct irq_fwspec *fwspec = data; unsigned long hwirq; unsigned int flags; - int err, p_hwirq; + int err, out_irq; err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &flags); if (err) return err; - p_hwirq = ti_sci_intr_alloc_parent_irq(domain, virq, hwirq); - if (p_hwirq < 0) - return p_hwirq; + out_irq = ti_sci_intr_alloc_parent_irq(domain, virq, hwirq); + if (out_irq < 0) + return out_irq; irq_domain_set_hwirq_and_chip(domain, virq, hwirq, &ti_sci_intr_irq_chip, - (void *)(uintptr_t)p_hwirq); + (void *)(uintptr_t)out_irq); return 0; } -- cgit v1.2.3 From 91f90daa4fb2b77db7aa25ef2e0206f2e3962665 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 29 Nov 2020 13:52:06 +0000 Subject: platform-msi: Track shared domain allocation We have two flavours of platform-MSI: - MSIs generated by devices for themselves (the usual case) - MSIs generated on behalf of other devices, as the generating device is some form of bridge (either a wire-to-MSI bridge, or even a non-transparent PCI bridge that repaints the PCI requester ID). In the latter case, the underlying interrupt architecture may need to track this in order to keep the mapping alive even when no MSI are currently being generated. Add a set of flags to the generic msi_alloc_info_t structure, as well as the MSI_ALLOC_FLAGS_PROXY_DEVICE flag that will get advertized by the platform-MSI code when allocating an irqdomain for a device. Signed-off-by: Marc Zyngier Tested-by: John Garry Link: https://lore.kernel.org/r/20201129135208.680293-2-maz@kernel.org --- drivers/base/platform-msi.c | 7 +++++++ include/asm-generic/msi.h | 4 ++++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c index c4a17e5edf8b..2c1e2e0c1a59 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c @@ -59,9 +59,15 @@ static int platform_msi_init(struct irq_domain *domain, return irq_domain_set_hwirq_and_chip(domain, virq, hwirq, info->chip, info->chip_data); } + +static void platform_msi_set_proxy_dev(msi_alloc_info_t *arg) +{ + arg->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE; +} #else #define platform_msi_set_desc NULL #define platform_msi_init NULL +#define platform_msi_set_proxy_dev(x) do {} while(0) #endif static void platform_msi_update_dom_ops(struct msi_domain_info *info) @@ -343,6 +349,7 @@ __platform_msi_create_device_domain(struct device *dev, if (!domain) goto free_priv; + platform_msi_set_proxy_dev(&data->arg); err = msi_domain_prepare_irqs(domain->parent, dev, nvec, &data->arg); if (err) goto free_domain; diff --git a/include/asm-generic/msi.h b/include/asm-generic/msi.h index e6795f088bdd..1010e74cb8e0 100644 --- a/include/asm-generic/msi.h +++ b/include/asm-generic/msi.h @@ -22,12 +22,16 @@ struct msi_desc; typedef struct msi_alloc_info { struct msi_desc *desc; irq_hw_number_t hwirq; + unsigned long flags; union { unsigned long ul; void *ptr; } scratchpad[NUM_MSI_ALLOC_SCRATCHPAD_REGS]; } msi_alloc_info_t; +/* Device generating MSIs is proxying for another device */ +#define MSI_ALLOC_FLAGS_PROXY_DEVICE (1UL << 0) + #define GENERIC_MSI_DOMAIN_OPS 1 #endif -- cgit v1.2.3 From 5fe71d271df8c05e1060c0184764eba18b17a96f Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 29 Nov 2020 13:52:07 +0000 Subject: irqchip/gic-v3-its: Tag ITS device as shared if allocating for a proxy device The ITS already has some notion of "shared" devices. Let's map the MSI_ALLOC_FLAGS_PROXY_DEVICE flag onto this internal property. Signed-off-by: Marc Zyngier Tested-by: John Garry Link: https://lore.kernel.org/r/20201129135208.680293-3-maz@kernel.org --- drivers/irqchip/irq-gic-v3-its.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index d74ef418e386..c951ad24d377 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -3487,6 +3487,9 @@ static int its_msi_prepare(struct irq_domain *domain, struct device *dev, goto out; } + if (info->flags & MSI_ALLOC_FLAGS_PROXY_DEVICE) + its_dev->shared = true; + pr_debug("ITT %d entries, %d bits\n", nvec, ilog2(nvec)); out: mutex_unlock(&its->dev_alloc_lock); -- cgit v1.2.3 From 34dd263fce3114147f21698f8e55e05b9e8185bd Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 29 Nov 2020 13:52:08 +0000 Subject: irqchip/gic-v3-its: Flag device allocation as proxied if behind a PCI bridge An aliasing PCI bridge is another case where we should flag the corresponding allocation as "proxied", as MSIs are coming with the bridge's RID, and not the originating device's. Signed-off-by: Marc Zyngier Tested-by: John Garry Link: https://lore.kernel.org/r/20201129135208.680293-4-maz@kernel.org --- drivers/irqchip/irq-gic-v3-its-pci-msi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c index 87711e0f8014..ad2810c017ed 100644 --- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c @@ -67,11 +67,16 @@ static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, /* * If pdev is downstream of any aliasing bridges, take an upper * bound of how many other vectors could map to the same DevID. + * Also tell the ITS that the signalling will come from a proxy + * device, and that special allocation rules apply. */ pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev); - if (alias_dev != pdev && alias_dev->subordinate) - pci_walk_bus(alias_dev->subordinate, its_pci_msi_vec_count, - &alias_count); + if (alias_dev != pdev) { + if (alias_dev->subordinate) + pci_walk_bus(alias_dev->subordinate, + its_pci_msi_vec_count, &alias_count); + info->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE; + } /* ITS specific DeviceID, as the core ITS ignores dev. */ info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain, pdev); -- cgit v1.2.3 From 1c3f69b4543af0aad514c127298e5ea40392575d Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 2 Dec 2020 18:36:55 +0800 Subject: ACPI: Drop acpi_dev_irqresource_disabled() The functionality of acpi_dev_irqresource_disabled() is same as in common irqresource_disabled(), so drop acpi_dev_irqresource_disabled() in favour of that function. Signed-off-by: John Garry Signed-off-by: Marc Zyngier Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/1606905417-183214-4-git-send-email-john.garry@huawei.com --- drivers/acpi/resource.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index ad04824ca3ba..58203193417e 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -380,13 +380,6 @@ unsigned int acpi_dev_get_irq_type(int triggering, int polarity) } EXPORT_SYMBOL_GPL(acpi_dev_get_irq_type); -static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi) -{ - res->start = gsi; - res->end = gsi; - res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET; -} - static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, u8 triggering, u8 polarity, u8 shareable, bool legacy) @@ -394,7 +387,7 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, int irq, p, t; if (!valid_IRQ(gsi)) { - acpi_dev_irqresource_disabled(res, gsi); + irqresource_disabled(res, gsi); return; } @@ -426,7 +419,7 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, res->start = irq; res->end = irq; } else { - acpi_dev_irqresource_disabled(res, gsi); + irqresource_disabled(res, gsi); } } @@ -463,7 +456,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, */ irq = &ares->data.irq; if (index >= irq->interrupt_count) { - acpi_dev_irqresource_disabled(res, 0); + irqresource_disabled(res, 0); return false; } acpi_dev_get_irqresource(res, irq->interrupts[index], @@ -473,7 +466,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: ext_irq = &ares->data.extended_irq; if (index >= ext_irq->interrupt_count) { - acpi_dev_irqresource_disabled(res, 0); + irqresource_disabled(res, 0); return false; } if (is_gsi(ext_irq)) @@ -481,7 +474,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, ext_irq->triggering, ext_irq->polarity, ext_irq->shareable, false); else - acpi_dev_irqresource_disabled(res, 0); + irqresource_disabled(res, 0); break; default: res->flags = 0; -- cgit v1.2.3 From e15f2fa959f2cce8a05e8e3a596e75d068cd42c5 Mon Sep 17 00:00:00 2001 From: John Garry Date: Wed, 2 Dec 2020 18:36:56 +0800 Subject: driver core: platform: Add devm_platform_get_irqs_affinity() Drivers for multi-queue platform devices may also want managed interrupts for handling HW queue completion interrupts, so add support. The function accepts an affinity descriptor pointer, which covers all IRQs expected for the device. The function is devm class as the only current in-tree user will also use devm method for requesting the interrupts; as such, the function is made as devm as it can ensure ordering of freeing the irq and disposing of the mapping. Signed-off-by: John Garry Signed-off-by: Marc Zyngier Acked-by: Marc Zyngier Link: https://lore.kernel.org/r/1606905417-183214-5-git-send-email-john.garry@huawei.com --- drivers/base/platform.c | 121 ++++++++++++++++++++++++++++++++++++++++ include/linux/platform_device.h | 6 ++ 2 files changed, 127 insertions(+) (limited to 'drivers') diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 88aef93eb4dd..ea8add164b89 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include @@ -289,6 +291,125 @@ int platform_irq_count(struct platform_device *dev) } EXPORT_SYMBOL_GPL(platform_irq_count); +struct irq_affinity_devres { + unsigned int count; + unsigned int irq[]; +}; + +static void platform_disable_acpi_irq(struct platform_device *pdev, int index) +{ + struct resource *r; + + r = platform_get_resource(pdev, IORESOURCE_IRQ, index); + if (r) + irqresource_disabled(r, 0); +} + +static void devm_platform_get_irqs_affinity_release(struct device *dev, + void *res) +{ + struct irq_affinity_devres *ptr = res; + int i; + + for (i = 0; i < ptr->count; i++) { + irq_dispose_mapping(ptr->irq[i]); + + if (has_acpi_companion(dev)) + platform_disable_acpi_irq(to_platform_device(dev), i); + } +} + +/** + * devm_platform_get_irqs_affinity - devm method to get a set of IRQs for a + * device using an interrupt affinity descriptor + * @dev: platform device pointer + * @affd: affinity descriptor + * @minvec: minimum count of interrupt vectors + * @maxvec: maximum count of interrupt vectors + * @irqs: pointer holder for IRQ numbers + * + * Gets a set of IRQs for a platform device, and updates IRQ afffinty according + * to the passed affinity descriptor + * + * Return: Number of vectors on success, negative error number on failure. + */ +int devm_platform_get_irqs_affinity(struct platform_device *dev, + struct irq_affinity *affd, + unsigned int minvec, + unsigned int maxvec, + int **irqs) +{ + struct irq_affinity_devres *ptr; + struct irq_affinity_desc *desc; + size_t size; + int i, ret, nvec; + + if (!affd) + return -EPERM; + + if (maxvec < minvec) + return -ERANGE; + + nvec = platform_irq_count(dev); + + if (nvec < minvec) + return -ENOSPC; + + nvec = irq_calc_affinity_vectors(minvec, nvec, affd); + if (nvec < minvec) + return -ENOSPC; + + if (nvec > maxvec) + nvec = maxvec; + + size = sizeof(*ptr) + sizeof(unsigned int) * nvec; + ptr = devres_alloc(devm_platform_get_irqs_affinity_release, size, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ptr->count = nvec; + + for (i = 0; i < nvec; i++) { + int irq = platform_get_irq(dev, i); + if (irq < 0) { + ret = irq; + goto err_free_devres; + } + ptr->irq[i] = irq; + } + + desc = irq_create_affinity_masks(nvec, affd); + if (!desc) { + ret = -ENOMEM; + goto err_free_devres; + } + + for (i = 0; i < nvec; i++) { + ret = irq_update_affinity_desc(ptr->irq[i], &desc[i]); + if (ret) { + dev_err(&dev->dev, "failed to update irq%d affinity descriptor (%d)\n", + ptr->irq[i], ret); + goto err_free_desc; + } + } + + devres_add(&dev->dev, ptr); + + kfree(desc); + + *irqs = ptr->irq; + + return nvec; + +err_free_desc: + kfree(desc); +err_free_devres: + devres_free(ptr); + return ret; +} +EXPORT_SYMBOL_GPL(devm_platform_get_irqs_affinity); + /** * platform_get_resource_byname - get a resource for a device by name * @dev: platform device diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 77a2aada106d..4d75633e6735 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -15,6 +15,7 @@ #define PLATFORM_DEVID_NONE (-1) #define PLATFORM_DEVID_AUTO (-2) +struct irq_affinity; struct mfd_cell; struct property_entry; struct platform_device_id; @@ -70,6 +71,11 @@ devm_platform_ioremap_resource_byname(struct platform_device *pdev, extern int platform_get_irq(struct platform_device *, unsigned int); extern int platform_get_irq_optional(struct platform_device *, unsigned int); extern int platform_irq_count(struct platform_device *); +extern int devm_platform_get_irqs_affinity(struct platform_device *dev, + struct irq_affinity *affd, + unsigned int minvec, + unsigned int maxvec, + int **irqs); extern struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, const char *); -- cgit v1.2.3 From 2f5fbc4305d07725bfebaedb09e57271315691ef Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 11 Dec 2020 14:15:35 -0800 Subject: irqchip/qcom-pdc: Fix phantom irq when changing between rising/falling We have a problem if we use gpio-keys and configure wakeups such that we only want one edge to wake us up. AKA: wakeup-event-action = ; wakeup-source; Specifically we end up with a phantom interrupt that blocks suspend if the line was already high and we want wakeups on rising edges (AKA we want the GPIO to go low and then high again before we wake up). The opposite is also problematic. Specifically, here's what's happening today: 1. Normally, gpio-keys configures to look for both edges. Due to the current workaround introduced in commit c3c0c2e18d94 ("pinctrl: qcom: Handle broken/missing PDC dual edge IRQs on sc7180"), if the line was high we'd configure for falling edges. 2. At suspend time, we change to look for rising edges. 3. After qcom_pdc_gic_set_type() runs, we get a phantom interrupt. We can solve this by just clearing the phantom interrupt. NOTE: it is possible that this could cause problems for a client with very specific needs, but there's not much we can do with this hardware. As an example, let's say the interrupt signal is currently high and the client is looking for falling edges. The client now changes to look for rising edges. The client could possibly expect that if the line has a short pulse low (and back high) that it would always be detected. Specifically no matter when the pulse happened, it should either have tripped the (old) falling edge trigger or the (new) rising edge trigger. We will simply not trip it. We could narrow down the race a bit by polling our parent before changing types, but no matter what we do there will still be a period of time where we can't tell the difference between a real transition (or more than one transition) and the phantom. Fixes: f55c73aef890 ("irqchip/pdc: Add PDC interrupt controller for QCOM SoCs") Signed-off-by: Douglas Anderson Signed-off-by: Marc Zyngier Tested-by: Maulik Shah Reviewed-by: Maulik Shah Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20201211141514.v4.1.I2702919afc253e2a451bebc3b701b462b2d22344@changeid --- drivers/irqchip/qcom-pdc.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c index bd39e9de6ecf..5dc63c20b67e 100644 --- a/drivers/irqchip/qcom-pdc.c +++ b/drivers/irqchip/qcom-pdc.c @@ -159,6 +159,8 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) { int pin_out = d->hwirq; enum pdc_irq_config_bits pdc_type; + enum pdc_irq_config_bits old_pdc_type; + int ret; if (pin_out == GPIO_NO_WAKE_IRQ) return 0; @@ -187,9 +189,26 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } + old_pdc_type = pdc_reg_read(IRQ_i_CFG, pin_out); pdc_reg_write(IRQ_i_CFG, pin_out, pdc_type); - return irq_chip_set_type_parent(d, type); + ret = irq_chip_set_type_parent(d, type); + if (ret) + return ret; + + /* + * When we change types the PDC can give a phantom interrupt. + * Clear it. Specifically the phantom shows up when reconfiguring + * polarity of interrupt without changing the state of the signal + * but let's be consistent and clear it always. + * + * Doing this works because we have IRQCHIP_SET_TYPE_MASKED so the + * interrupt will be cleared before the rest of the system sees it. + */ + if (old_pdc_type != pdc_type) + irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, false); + + return 0; } static struct irq_chip qcom_pdc_gic_chip = { -- cgit v1.2.3