From b66231183a8542de1414e42326dd1c6bc4af75f4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 6 Jul 2015 15:32:25 +0200 Subject: irqchip/dw-apb-ictl: Fix generic domain chip wreckage The num_ct argument of irq_alloc_domain_generic_chips() tells the core code how many chip types (for different control flows, e.g. edge/level) should be allocated. It does not control how many generic chip instances are created because that's determined from the irq domain size and the number of interrupts per chip. The dw-apb init abuses the num_ct argument for allocating one or two chip types depending on the number of interrupts. That's completely wrong because the alternate type is never used. This code was obviously never tested on a system which has more than 32 interrupts as that would have never worked due to the unitialized second generic chip instance. Hand in the proper num_ct=1 and fixup the chip initialization along with the interrupt handler. Signed-off-by: Thomas Gleixner Tested-by: Jisheng Zhang Cc: Sebastian Hesselbarth Cc: Mark Rutland Cc: Jason Cooper Link: http://lkml.kernel.org/r/20150706101543.373582262@linutronix.de diff --git a/drivers/irqchip/irq-dw-apb-ictl.c b/drivers/irqchip/irq-dw-apb-ictl.c index 53bb732..ca22f4e 100644 --- a/drivers/irqchip/irq-dw-apb-ictl.c +++ b/drivers/irqchip/irq-dw-apb-ictl.c @@ -25,24 +25,25 @@ #define APB_INT_MASK_H 0x0c #define APB_INT_FINALSTATUS_L 0x30 #define APB_INT_FINALSTATUS_H 0x34 +#define APB_INT_BASE_OFFSET 0x04 static void dw_apb_ictl_handler(unsigned int irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct irq_chip_generic *gc = irq_get_handler_data(irq); - struct irq_domain *d = gc->private; - u32 stat; + struct irq_domain *d = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); int n; chained_irq_enter(chip, desc); - for (n = 0; n < gc->num_ct; n++) { - stat = readl_relaxed(gc->reg_base + - APB_INT_FINALSTATUS_L + 4 * n); + for (n = 0; n < d->revmap_size; n += 32) { + struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, n); + u32 stat = readl_relaxed(gc->reg_base + APB_INT_FINALSTATUS_L); + while (stat) { u32 hwirq = ffs(stat) - 1; - generic_handle_irq(irq_find_mapping(d, - gc->irq_base + hwirq + 32 * n)); + u32 virq = irq_find_mapping(d, gc->irq_base + hwirq); + + generic_handle_irq(virq); stat &= ~(1 << hwirq); } } @@ -73,7 +74,7 @@ static int __init dw_apb_ictl_init(struct device_node *np, struct irq_domain *domain; struct irq_chip_generic *gc; void __iomem *iobase; - int ret, nrirqs, irq; + int ret, nrirqs, irq, i; u32 reg; /* Map the parent interrupt for the chained handler */ @@ -128,35 +129,25 @@ static int __init dw_apb_ictl_init(struct device_node *np, goto err_unmap; } - ret = irq_alloc_domain_generic_chips(domain, 32, (nrirqs > 32) ? 2 : 1, - np->name, handle_level_irq, clr, 0, - IRQ_GC_MASK_CACHE_PER_TYPE | + ret = irq_alloc_domain_generic_chips(domain, 32, 1, np->name, + handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); if (ret) { pr_err("%s: unable to alloc irq domain gc\n", np->full_name); goto err_unmap; } - gc = irq_get_domain_generic_chip(domain, 0); - gc->private = domain; - gc->reg_base = iobase; - - gc->chip_types[0].regs.mask = APB_INT_MASK_L; - gc->chip_types[0].regs.enable = APB_INT_ENABLE_L; - gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; - gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit; - gc->chip_types[0].chip.irq_resume = dw_apb_ictl_resume; - - if (nrirqs > 32) { - gc->chip_types[1].regs.mask = APB_INT_MASK_H; - gc->chip_types[1].regs.enable = APB_INT_ENABLE_H; - gc->chip_types[1].chip.irq_mask = irq_gc_mask_set_bit; - gc->chip_types[1].chip.irq_unmask = irq_gc_mask_clr_bit; - gc->chip_types[1].chip.irq_resume = dw_apb_ictl_resume; + for (i = 0; i < DIV_ROUND_UP(nrirqs, 32); i++) { + gc = irq_get_domain_generic_chip(domain, i * 32); + gc->reg_base = iobase + i * APB_INT_BASE_OFFSET; + gc->chip_types[0].regs.mask = APB_INT_MASK_L; + gc->chip_types[0].regs.enable = APB_INT_ENABLE_L; + gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; + gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit; + gc->chip_types[0].chip.irq_resume = dw_apb_ictl_resume; } - irq_set_handler_data(irq, gc); - irq_set_chained_handler(irq, dw_apb_ictl_handler); + irq_set_chained_handler_and_data(irq, dw_apb_ictl_handler, domain); return 0; -- cgit v0.10.2 From d452bca82d9ff4f220afa4234418912623db4fe6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 6 Jul 2015 10:18:29 +0000 Subject: irqchip/sirfsoc: Fix generic chip allocation wreckage irq_alloc_domain_generic_chips() can only be called once for an irqdomain. The sirfsoc init calls it twice and because the return value is not checked it does not notice the wreckage. The code works by chance because the first call already allocates two chips and therefor the second call to sirfsoc_alloc_gc() operates on the proper generic chip instance. Use a single call and setup the two chips in the obvious correct way. Signed-off-by: Thomas Gleixner Cc: Jason Cooper Cc: Barry Song Cc: linux-arm-kernel@lists.infradead.org Cc: Olof Johansson Link: http://lkml.kernel.org/r/20150706101543.470696950@linutronix.de diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c index a469355..b930069 100644 --- a/drivers/irqchip/irq-sirfsoc.c +++ b/drivers/irqchip/irq-sirfsoc.c @@ -17,34 +17,38 @@ #include #include "irqchip.h" -#define SIRFSOC_INT_RISC_MASK0 0x0018 -#define SIRFSOC_INT_RISC_MASK1 0x001C -#define SIRFSOC_INT_RISC_LEVEL0 0x0020 -#define SIRFSOC_INT_RISC_LEVEL1 0x0024 +#define SIRFSOC_INT_RISC_MASK0 0x0018 +#define SIRFSOC_INT_RISC_MASK1 0x001C +#define SIRFSOC_INT_RISC_LEVEL0 0x0020 +#define SIRFSOC_INT_RISC_LEVEL1 0x0024 #define SIRFSOC_INIT_IRQ_ID 0x0038 +#define SIRFSOC_INT_BASE_OFFSET 0x0004 #define SIRFSOC_NUM_IRQS 64 +#define SIRFSOC_NUM_BANKS (SIRFSOC_NUM_IRQS / 32) static struct irq_domain *sirfsoc_irqdomain; -static __init void -sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num) +static __init void sirfsoc_alloc_gc(void __iomem *base) { - struct irq_chip_generic *gc; - struct irq_chip_type *ct; - int ret; unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; unsigned int set = IRQ_LEVEL; - - ret = irq_alloc_domain_generic_chips(sirfsoc_irqdomain, num, 1, "irq_sirfsoc", - handle_level_irq, clr, set, IRQ_GC_INIT_MASK_CACHE); - - gc = irq_get_domain_generic_chip(sirfsoc_irqdomain, irq_start); - gc->reg_base = base; - ct = gc->chip_types; - ct->chip.irq_mask = irq_gc_mask_clr_bit; - ct->chip.irq_unmask = irq_gc_mask_set_bit; - ct->regs.mask = SIRFSOC_INT_RISC_MASK0; + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + int i; + + irq_alloc_domain_generic_chips(sirfsoc_irqdomain, 32, 1, "irq_sirfsoc", + handle_level_irq, clr, set, + IRQ_GC_INIT_MASK_CACHE); + + for (i = 0; i < SIRFSOC_NUM_BANKS; i++) { + gc = irq_get_domain_generic_chip(sirfsoc_irqdomain, i * 32); + gc->reg_base = base + i * SIRFSOC_INT_BASE_OFFSET; + ct = gc->chip_types; + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + ct->regs.mask = SIRFSOC_INT_RISC_MASK0; + } } static void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs) @@ -64,10 +68,8 @@ static int __init sirfsoc_irq_init(struct device_node *np, panic("unable to map intc cpu registers\n"); sirfsoc_irqdomain = irq_domain_add_linear(np, SIRFSOC_NUM_IRQS, - &irq_generic_chip_ops, base); - - sirfsoc_alloc_gc(base, 0, 32); - sirfsoc_alloc_gc(base + 4, 32, SIRFSOC_NUM_IRQS - 32); + &irq_generic_chip_ops, base); + sirfsoc_alloc_gc(base); writel_relaxed(0, base + SIRFSOC_INT_RISC_LEVEL0); writel_relaxed(0, base + SIRFSOC_INT_RISC_LEVEL1); -- cgit v0.10.2 From 41a83e06e2bb9ac46731681fd44d1e6ab184dac5 Mon Sep 17 00:00:00 2001 From: Joel Porquet Date: Tue, 7 Jul 2015 17:11:46 -0400 Subject: irqchip: Prepare for local stub header removal The IRQCHIP_DECLARE macro moved to to 'include/linux/irqchip.h', so the local irqchip.h became an empty shell, which solely includes include/linux/irqchip.h Include the global header in all irqchip drivers instead of the local header, so we can remove it. Signed-off-by: Joel Porquet Cc: vgupta@synopsys.com Cc: monstr@monstr.eu Cc: ralf@linux-mips.org Cc: jason@lakedaemon.net Link: http://lkml.kernel.org/r/1882096.X39jVG8e0D@joel-zenbook Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 5c82e3b..05cdccc 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -15,13 +15,12 @@ #include #include #include +#include #include #include #include #include -#include "irqchip.h" - #define COMBINER_ENABLE_SET 0x0 #define COMBINER_ENABLE_CLEAR 0x4 #define COMBINER_INT_STATUS 0xC diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 0d3b0fe..73b73ac 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -33,8 +34,6 @@ #include #include -#include "irqchip.h" - /* Interrupt Controller Registers Map */ #define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48) #define ARMADA_370_XP_INT_CLEAR_MASK_OFFS (0x4C) diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c index dae3604..dbbf30a 100644 --- a/drivers/irqchip/irq-atmel-aic.c +++ b/drivers/irqchip/irq-atmel-aic.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,6 @@ #include #include "irq-atmel-aic-common.h" -#include "irqchip.h" /* Number of irq lines managed by AIC */ #define NR_AIC_IRQS 32 diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index 459bf44..ff2e832 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,6 @@ #include #include "irq-atmel-aic-common.h" -#include "irqchip.h" /* Number of irq lines managed by AIC */ #define NR_AIC5_IRQS 128 diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index e68c3b6..a36ba96 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -48,13 +48,12 @@ #include #include #include +#include #include #include #include -#include "irqchip.h" - /* Put the bank and irq (32 bits) into the hwirq */ #define MAKE_HWIRQ(b, n) ((b << 5) | (n)) #define HWIRQ_BANK(i) (i >> 5) diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index d3b8c8b..66850aa 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -29,10 +29,9 @@ #include #include #include +#include #include -#include "irqchip.h" - #define IRQS_PER_WORD 32 #define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 4) #define MAX_WORDS 8 diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index 3ba5cc7..7de378e 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -26,10 +26,9 @@ #include #include #include +#include #include -#include "irqchip.h" - /* Register offset in the L2 interrupt controller */ #define IRQEN 0x00 #define IRQSTAT 0x04 diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index d6bcc6b..4e60b88 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -32,8 +32,6 @@ #include #include -#include "irqchip.h" - /* Register offsets in the L2 interrupt controller */ #define CPU_STATUS 0x00 #define CPU_SET 0x04 diff --git a/drivers/irqchip/irq-clps711x.c b/drivers/irqchip/irq-clps711x.c index 33127f1..2dd929e 100644 --- a/drivers/irqchip/irq-clps711x.c +++ b/drivers/irqchip/irq-clps711x.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -19,8 +20,6 @@ #include #include -#include "irqchip.h" - #define CLPS711X_INTSR1 (0x0240) #define CLPS711X_INTMR1 (0x0280) #define CLPS711X_BLEOI (0x0600) diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c index 692fe2b..1240c4d 100644 --- a/drivers/irqchip/irq-crossbar.c +++ b/drivers/irqchip/irq-crossbar.c @@ -11,13 +11,12 @@ */ #include #include +#include #include #include #include #include -#include "irqchip.h" - #define IRQ_FREE -1 #define IRQ_RESERVED -2 #define IRQ_SKIP -3 diff --git a/drivers/irqchip/irq-digicolor.c b/drivers/irqchip/irq-digicolor.c index 3cbc658..dad85e7 100644 --- a/drivers/irqchip/irq-digicolor.c +++ b/drivers/irqchip/irq-digicolor.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -20,8 +21,6 @@ #include -#include "irqchip.h" - #define UC_IRQ_CONTROL 0x04 #define IC_FLAG_CLEAR_LO 0x00 diff --git a/drivers/irqchip/irq-dw-apb-ictl.c b/drivers/irqchip/irq-dw-apb-ictl.c index ca22f4e..efd95d9 100644 --- a/drivers/irqchip/irq-dw-apb-ictl.c +++ b/drivers/irqchip/irq-dw-apb-ictl.c @@ -13,12 +13,11 @@ #include #include +#include #include #include #include -#include "irqchip.h" - #define APB_INT_ENABLE_L 0x00 #define APB_INT_ENABLE_H 0x04 #define APB_INT_MASK_L 0x08 diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 1b7e155..63dbdec 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -30,14 +30,13 @@ #include #include +#include #include #include #include #include -#include "irqchip.h" - #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1 << 0) #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index c52f7ba..e406bc5 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -32,7 +33,6 @@ #include #include "irq-gic-common.h" -#include "irqchip.h" struct redist_region { void __iomem *redist_base; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 8d7e1c8..9be84bd 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -48,7 +49,6 @@ #include #include "irq-gic-common.h" -#include "irqchip.h" union gic_base { void __iomem *common_base; diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index 0cae45d..55c2c10 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -48,7 +49,6 @@ #include #include "irq-gic-common.h" -#include "irqchip.h" #define HIP04_MAX_IRQS 510 diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c index 005de3f..fc5953d 100644 --- a/drivers/irqchip/irq-ingenic.c +++ b/drivers/irqchip/irq-ingenic.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -28,8 +29,6 @@ #include #include -#include "irqchip.h" - struct ingenic_intc_data { void __iomem *base; unsigned num_chips; diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index 81e3cf5..d10244f 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -20,13 +20,12 @@ #include #include #include +#include #include #include #include #include #include -#include "irqchip.h" - /* The source ID bits start from 4 to 31 (total 28 bits)*/ #define BIT_OFS 4 diff --git a/drivers/irqchip/irq-mips-cpu.c b/drivers/irqchip/irq-mips-cpu.c index a43c419..8c504f5 100644 --- a/drivers/irqchip/irq-mips-cpu.c +++ b/drivers/irqchip/irq-mips-cpu.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -38,8 +39,6 @@ #include #include -#include "irqchip.h" - static inline void unmask_mips_irq(struct irq_data *d) { set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 4400edd..42dbebc 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -22,8 +23,6 @@ #include -#include "irqchip.h" - unsigned int gic_present; struct gic_pcpu_mask { diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c index c0da57b..c9c03a2 100644 --- a/drivers/irqchip/irq-mmp.c +++ b/drivers/irqchip/irq-mmp.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -24,8 +25,6 @@ #include #include -#include "irqchip.h" - #define MAX_ICU_NR 16 #define PJ1_INT_SEL 0x10c diff --git a/drivers/irqchip/irq-moxart.c b/drivers/irqchip/irq-moxart.c index 00b3cc9..a24b06a 100644 --- a/drivers/irqchip/irq-moxart.c +++ b/drivers/irqchip/irq-moxart.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -19,8 +20,6 @@ #include -#include "irqchip.h" - #define IRQ_SOURCE_REG 0 #define IRQ_MASK_REG 0x04 #define IRQ_CLEAR_REG 0x08 diff --git a/drivers/irqchip/irq-mtk-sysirq.c b/drivers/irqchip/irq-mtk-sysirq.c index 15c1303..c8753da 100644 --- a/drivers/irqchip/irq-mtk-sysirq.c +++ b/drivers/irqchip/irq-mtk-sysirq.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -21,8 +22,6 @@ #include #include -#include "irqchip.h" - struct mtk_sysirq_chip_data { spinlock_t lock; void __iomem *intpol_base; diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c index 04bf97b..1faf812 100644 --- a/drivers/irqchip/irq-mxs.c +++ b/drivers/irqchip/irq-mxs.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -27,8 +28,6 @@ #include #include -#include "irqchip.h" - #define HW_ICOLL_VECTOR 0x0000 #define HW_ICOLL_LEVELACK 0x0010 #define HW_ICOLL_CTRL 0x0020 diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c index 5fac910..a878b8d 100644 --- a/drivers/irqchip/irq-nvic.c +++ b/drivers/irqchip/irq-nvic.c @@ -21,13 +21,12 @@ #include #include #include +#include #include #include #include -#include "irqchip.h" - #define NVIC_ISER 0x000 #define NVIC_ICER 0x080 #define NVIC_IPR 0x300 diff --git a/drivers/irqchip/irq-omap-intc.c b/drivers/irqchip/irq-omap-intc.c index a569c6d..6cc0ad5 100644 --- a/drivers/irqchip/irq-omap-intc.c +++ b/drivers/irqchip/irq-omap-intc.c @@ -17,13 +17,12 @@ #include #include +#include #include #include #include #include -#include "irqchip.h" - /* Define these here for now until we drop all board-files */ #define OMAP24XX_IC_BASE 0x480fe000 #define OMAP34XX_IC_BASE 0x48200000 diff --git a/drivers/irqchip/irq-or1k-pic.c b/drivers/irqchip/irq-or1k-pic.c index e93d079..6a9a3e7 100644 --- a/drivers/irqchip/irq-or1k-pic.c +++ b/drivers/irqchip/irq-or1k-pic.c @@ -9,12 +9,11 @@ */ #include +#include #include #include #include -#include "irqchip.h" - /* OR1K PIC implementation */ struct or1k_pic_dev { diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c index ad0c0f6..995f66b 100644 --- a/drivers/irqchip/irq-orion.c +++ b/drivers/irqchip/irq-orion.c @@ -10,14 +10,13 @@ #include #include +#include #include #include #include #include #include -#include "irqchip.h" - /* * Orion SoC main interrupt controller */ diff --git a/drivers/irqchip/irq-renesas-h8300h.c b/drivers/irqchip/irq-renesas-h8300h.c index 1870e6b..6fd30d5 100644 --- a/drivers/irqchip/irq-renesas-h8300h.c +++ b/drivers/irqchip/irq-renesas-h8300h.c @@ -11,8 +11,6 @@ #include #include -#include "irqchip.h" - static const char ipr_bit[] = { 7, 6, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, diff --git a/drivers/irqchip/irq-renesas-h8s.c b/drivers/irqchip/irq-renesas-h8s.c index 64425f4..8098ead 100644 --- a/drivers/irqchip/irq-renesas-h8s.c +++ b/drivers/irqchip/irq-renesas-h8s.c @@ -5,10 +5,10 @@ */ #include +#include #include #include #include -#include "irqchip.h" static void *intc_baseaddr; #define IPRA ((unsigned long)intc_baseaddr) diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c index e96717f..aee4266 100644 --- a/drivers/irqchip/irq-s3c24xx.c +++ b/drivers/irqchip/irq-s3c24xx.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -40,8 +41,6 @@ #include #include -#include "irqchip.h" - #define S3C_IRQTYPE_NONE 0 #define S3C_IRQTYPE_EINT 1 #define S3C_IRQTYPE_EDGE 2 diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c index b930069..10cb21b 100644 --- a/drivers/irqchip/irq-sirfsoc.c +++ b/drivers/irqchip/irq-sirfsoc.c @@ -11,11 +11,11 @@ #include #include #include +#include #include #include #include #include -#include "irqchip.h" #define SIRFSOC_INT_RISC_MASK0 0x0018 #define SIRFSOC_INT_RISC_MASK1 0x001C diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index 83d6aa6..4ad3e7c 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -23,8 +24,6 @@ #include #include -#include "irqchip.h" - #define SUN4I_IRQ_VECTOR_REG 0x00 #define SUN4I_IRQ_PROTECTION_REG 0x08 #define SUN4I_IRQ_NMI_CTRL_REG 0x0c diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c index 6b2b582..2fb8c0e 100644 --- a/drivers/irqchip/irq-sunxi-nmi.c +++ b/drivers/irqchip/irq-sunxi-nmi.c @@ -17,8 +17,8 @@ #include #include #include +#include #include -#include "irqchip.h" #define SUNXI_NMI_SRC_TYPE_MASK 0x00000003 diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c index accc200..55dea55 100644 --- a/drivers/irqchip/irq-tb10x.c +++ b/drivers/irqchip/irq-tb10x.c @@ -22,13 +22,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include "irqchip.h" #define AB_IRQCTL_INT_ENABLE 0x00 #define AB_IRQCTL_INT_STATUS 0x04 diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c index f67bbd8..2fd89eb 100644 --- a/drivers/irqchip/irq-tegra.c +++ b/drivers/irqchip/irq-tegra.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -31,8 +32,6 @@ #include -#include "irqchip.h" - #define ICTLR_CPU_IEP_VFIQ 0x08 #define ICTLR_CPU_IEP_FIR 0x14 #define ICTLR_CPU_IEP_FIR_SET 0x18 diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index 888111b..4ba480b 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -14,8 +15,6 @@ #include #include -#include "irqchip.h" - #define IRQ_STATUS 0x00 #define IRQ_RAW_STATUS 0x04 #define IRQ_ENABLE_SET 0x08 diff --git a/drivers/irqchip/irq-vf610-mscm-ir.c b/drivers/irqchip/irq-vf610-mscm-ir.c index f5c01cb..2c22558 100644 --- a/drivers/irqchip/irq-vf610-mscm-ir.c +++ b/drivers/irqchip/irq-vf610-mscm-ir.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -34,8 +35,6 @@ #include #include -#include "irqchip.h" - #define MSCM_CPxNUM 0x4 #define MSCM_IRSPRC(n) (0x80 + 2 * (n)) diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index d4ce331..4cd65c1 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -37,8 +38,6 @@ #include #include -#include "irqchip.h" - #define VIC_IRQ_STATUS 0x00 #define VIC_FIQ_STATUS 0x04 #define VIC_INT_SELECT 0x0c /* 1 = FIQ, 0 = IRQ */ diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c index 0b29700..52c2800 100644 --- a/drivers/irqchip/irq-vt8500.c +++ b/drivers/irqchip/irq-vt8500.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -39,8 +40,6 @@ #include #include -#include "irqchip.h" - #define VT8500_ICPC_IRQ 0x20 #define VT8500_ICPC_FIQ 0x24 #define VT8500_ICDC 0x40 /* Destination Control 64*u32 */ diff --git a/drivers/irqchip/irq-xtensa-mx.c b/drivers/irqchip/irq-xtensa-mx.c index e1c2f96..bb3ac5f 100644 --- a/drivers/irqchip/irq-xtensa-mx.c +++ b/drivers/irqchip/irq-xtensa-mx.c @@ -11,12 +11,11 @@ #include #include #include +#include #include #include -#include "irqchip.h" - #define HW_IRQ_IPI_COUNT 2 #define HW_IRQ_MX_BASE 2 #define HW_IRQ_EXTERN_BASE 3 diff --git a/drivers/irqchip/irq-xtensa-pic.c b/drivers/irqchip/irq-xtensa-pic.c index 7d71126..472ae17 100644 --- a/drivers/irqchip/irq-xtensa-pic.c +++ b/drivers/irqchip/irq-xtensa-pic.c @@ -15,10 +15,9 @@ #include #include #include +#include #include -#include "irqchip.h" - unsigned int cached_irq_mask; /* diff --git a/drivers/irqchip/irq-zevio.c b/drivers/irqchip/irq-zevio.c index e4ef74e..4c48fa8 100644 --- a/drivers/irqchip/irq-zevio.c +++ b/drivers/irqchip/irq-zevio.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -18,8 +19,6 @@ #include #include -#include "irqchip.h" - #define IO_STATUS 0x000 #define IO_RAW_STATUS 0x004 #define IO_ENABLE 0x008 diff --git a/drivers/irqchip/spear-shirq.c b/drivers/irqchip/spear-shirq.c index a451215..3df144f 100644 --- a/drivers/irqchip/spear-shirq.c +++ b/drivers/irqchip/spear-shirq.c @@ -18,14 +18,13 @@ #include #include #include +#include #include #include #include #include #include -#include "irqchip.h" - /* * struct spear_shirq: shared irq structure * -- cgit v0.10.2 From b51bf95c583bba645974348666e9b5a14c7aa3ea Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 4 Jun 2015 12:13:25 +0800 Subject: genirq: Remove the parameter 'irq' of kstat_incr_irqs_this_cpu() The first parameter 'irq' is never used by kstat_incr_irqs_this_cpu(). Remove it. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Bjorn Helgaas Cc: Benjamin Herrenschmidt Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Link: http://lkml.kernel.org/r/1433391238-19471-16-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 27f4332..f3c3d55 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -315,7 +315,7 @@ void handle_nested_irq(unsigned int irq) raw_spin_lock_irq(&desc->lock); desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - kstat_incr_irqs_this_cpu(irq, desc); + kstat_incr_irqs_this_cpu(desc); action = desc->action; if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) { @@ -391,7 +391,7 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc) goto out_unlock; desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - kstat_incr_irqs_this_cpu(irq, desc); + kstat_incr_irqs_this_cpu(desc); if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { desc->istate |= IRQS_PENDING; @@ -443,7 +443,7 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) goto out_unlock; desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - kstat_incr_irqs_this_cpu(irq, desc); + kstat_incr_irqs_this_cpu(desc); /* * If its disabled or no action available @@ -515,7 +515,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) goto out; desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - kstat_incr_irqs_this_cpu(irq, desc); + kstat_incr_irqs_this_cpu(desc); /* * If its disabled or no action available @@ -583,7 +583,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc) goto out_unlock; } - kstat_incr_irqs_this_cpu(irq, desc); + kstat_incr_irqs_this_cpu(desc); /* Start handling the irq */ desc->irq_data.chip->irq_ack(&desc->irq_data); @@ -646,7 +646,7 @@ void handle_edge_eoi_irq(unsigned int irq, struct irq_desc *desc) goto out_eoi; } - kstat_incr_irqs_this_cpu(irq, desc); + kstat_incr_irqs_this_cpu(desc); do { if (unlikely(!desc->action)) @@ -675,7 +675,7 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); - kstat_incr_irqs_this_cpu(irq, desc); + kstat_incr_irqs_this_cpu(desc); if (chip->irq_ack) chip->irq_ack(&desc->irq_data); @@ -705,7 +705,7 @@ void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc) void *dev_id = raw_cpu_ptr(action->percpu_dev_id); irqreturn_t res; - kstat_incr_irqs_this_cpu(irq, desc); + kstat_incr_irqs_this_cpu(desc); if (chip->irq_ack) chip->irq_ack(&desc->irq_data); diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 6354802..4d37b96 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -30,7 +30,7 @@ void handle_bad_irq(unsigned int irq, struct irq_desc *desc) { print_irq_desc(irq, desc); - kstat_incr_irqs_this_cpu(irq, desc); + kstat_incr_irqs_this_cpu(desc); ack_bad_irq(irq); } diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 4834ee8..3e03824 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -191,7 +191,7 @@ static inline bool irqd_has_set(struct irq_data *d, unsigned int mask) return __irqd_to_state(d) & mask; } -static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *desc) +static inline void kstat_incr_irqs_this_cpu(struct irq_desc *desc) { __this_cpu_inc(*desc->kstat_irqs); __this_cpu_inc(kstat.irqs_sum); diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 4afc457..0a2a4b6 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -582,7 +582,7 @@ int irq_set_percpu_devid(unsigned int irq) void kstat_incr_irq_this_cpu(unsigned int irq) { - kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq)); + kstat_incr_irqs_this_cpu(irq_to_desc(irq)); } /** -- cgit v0.10.2 From 0798abeb7eec37dcc20f252c2195fc31c41561f9 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 4 Jun 2015 12:13:27 +0800 Subject: genirq: Remove the irq argument from check_irq_resend() It's only used in the software resend case and can be retrieved from irq_desc if necessary. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Bjorn Helgaas Cc: Benjamin Herrenschmidt Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Link: http://lkml.kernel.org/r/1433391238-19471-18-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index f3c3d55..0cfbd15 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -187,7 +187,7 @@ int irq_startup(struct irq_desc *desc, bool resend) irq_enable(desc); } if (resend) - check_irq_resend(desc, desc->irq_data.irq); + check_irq_resend(desc); return ret; } diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 3e03824..7054947e 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -90,7 +90,7 @@ irqreturn_t handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *act irqreturn_t handle_irq_event(struct irq_desc *desc); /* Resending of interrupts :*/ -void check_irq_resend(struct irq_desc *desc, unsigned int irq); +void check_irq_resend(struct irq_desc *desc); bool irq_wait_for_poll(struct irq_desc *desc); void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index f974485..c2e835d 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -516,7 +516,7 @@ void __enable_irq(struct irq_desc *desc, unsigned int irq) /* Prevent probing on this irq: */ irq_settings_set_noprobe(desc); irq_enable(desc); - check_irq_resend(desc, irq); + check_irq_resend(desc); /* fall-through */ } default: diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index 9065107..32fc47c 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c @@ -53,7 +53,7 @@ static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0); * * Is called with interrupts disabled and desc->lock held. */ -void check_irq_resend(struct irq_desc *desc, unsigned int irq) +void check_irq_resend(struct irq_desc *desc) { /* * We do not resend level type interrupts. Level type @@ -74,6 +74,8 @@ void check_irq_resend(struct irq_desc *desc, unsigned int irq) if (!desc->irq_data.chip->irq_retrigger || !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) { #ifdef CONFIG_HARDIRQS_SW_RESEND + unsigned int irq = irq_desc_get_irq(desc); + /* * If the interrupt has a parent irq and runs * in the thread context of the parent irq, -- cgit v0.10.2 From a1ff541a40e90df05f586bf6b157083b351c4a0c Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 23 Jun 2015 19:47:29 +0200 Subject: genirq: Remove irq arg from __irq_set_trigger() It's only required for debug output and can be retrieved from the irq descriptor if necessary. [ tglx: Split out from combo patch ] Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 0cfbd15..310d658 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -63,7 +63,7 @@ int irq_set_irq_type(unsigned int irq, unsigned int type) return -EINVAL; type &= IRQ_TYPE_SENSE_MASK; - ret = __irq_set_trigger(desc, irq, type); + ret = __irq_set_trigger(desc, type); irq_put_desc_busunlock(desc, flags); return ret; } diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 7054947e..429c5e3 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -59,8 +59,7 @@ enum { #include "debug.h" #include "settings.h" -extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, - unsigned long flags); +extern int __irq_set_trigger(struct irq_desc *desc, unsigned long flags); extern void __disable_irq(struct irq_desc *desc, unsigned int irq); extern void __enable_irq(struct irq_desc *desc, unsigned int irq); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index c2e835d..0559d9c 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -637,8 +637,7 @@ int can_request_irq(unsigned int irq, unsigned long irqflags) return canrequest; } -int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, - unsigned long flags) +int __irq_set_trigger(struct irq_desc *desc, unsigned long flags) { struct irq_chip *chip = desc->irq_data.chip; int ret, unmask = 0; @@ -648,7 +647,8 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, * IRQF_TRIGGER_* but the PIC does not support multiple * flow-types? */ - pr_debug("No set_type function for IRQ %d (%s)\n", irq, + pr_debug("No set_type function for IRQ %d (%s)\n", + irq_desc_get_irq(desc), chip ? (chip->name ? : "unknown") : "unknown"); return 0; } @@ -685,7 +685,7 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, break; default: pr_err("Setting trigger mode %lu for irq %u failed (%pF)\n", - flags, irq, chip->irq_set_type); + flags, irq_desc_get_irq(desc), chip->irq_set_type); } if (unmask) unmask_irq(desc); @@ -1221,8 +1221,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) /* Setup the type (level, edge polarity) if configured: */ if (new->flags & IRQF_TRIGGER_MASK) { - ret = __irq_set_trigger(desc, irq, - new->flags & IRQF_TRIGGER_MASK); + ret = __irq_set_trigger(desc, + new->flags & IRQF_TRIGGER_MASK); if (ret) goto out_mask; @@ -1650,7 +1650,7 @@ void enable_percpu_irq(unsigned int irq, unsigned int type) if (type != IRQ_TYPE_NONE) { int ret; - ret = __irq_set_trigger(desc, irq, type); + ret = __irq_set_trigger(desc, type); if (ret) { WARN(1, "failed to set type for IRQ%d\n", irq); -- cgit v0.10.2 From 79ff1cda320b81dfe5feae0c5da52f029561ce93 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 23 Jun 2015 19:52:36 +0200 Subject: genirq: Remove irq argument from __enable/__disable_irq() Solely used for debug output. Can be retrieved from irq descriptor if necessary. [ tglx: Split out from combo patch ] Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 429c5e3..c8dd8d7 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -60,8 +60,8 @@ enum { #include "settings.h" extern int __irq_set_trigger(struct irq_desc *desc, unsigned long flags); -extern void __disable_irq(struct irq_desc *desc, unsigned int irq); -extern void __enable_irq(struct irq_desc *desc, unsigned int irq); +extern void __disable_irq(struct irq_desc *desc); +extern void __enable_irq(struct irq_desc *desc); extern int irq_startup(struct irq_desc *desc, bool resend); extern void irq_shutdown(struct irq_desc *desc); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0559d9c..d526ac1 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -423,7 +423,7 @@ setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask) } #endif -void __disable_irq(struct irq_desc *desc, unsigned int irq) +void __disable_irq(struct irq_desc *desc) { if (!desc->depth++) irq_disable(desc); @@ -436,7 +436,7 @@ static int __disable_irq_nosync(unsigned int irq) if (!desc) return -EINVAL; - __disable_irq(desc, irq); + __disable_irq(desc); irq_put_desc_busunlock(desc, flags); return 0; } @@ -503,12 +503,13 @@ bool disable_hardirq(unsigned int irq) } EXPORT_SYMBOL_GPL(disable_hardirq); -void __enable_irq(struct irq_desc *desc, unsigned int irq) +void __enable_irq(struct irq_desc *desc) { switch (desc->depth) { case 0: err_out: - WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", irq); + WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", + irq_desc_get_irq(desc)); break; case 1: { if (desc->istate & IRQS_SUSPENDED) @@ -546,7 +547,7 @@ void enable_irq(unsigned int irq) KERN_ERR "enable_irq before setup/request_irq: irq %u\n", irq)) goto out; - __enable_irq(desc, irq); + __enable_irq(desc); out: irq_put_desc_busunlock(desc, flags); } @@ -1280,7 +1281,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) */ if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) { desc->istate &= ~IRQS_SPURIOUS_DISABLED; - __enable_irq(desc, irq); + __enable_irq(desc); } raw_spin_unlock_irqrestore(&desc->lock, flags); diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index d22786a..0e1c617 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -85,7 +85,7 @@ static bool suspend_device_irq(struct irq_desc *desc, int irq) } desc->istate |= IRQS_SUSPENDED; - __disable_irq(desc, irq); + __disable_irq(desc); /* * Hardware which has no wakeup source configuration facility @@ -150,7 +150,7 @@ static void resume_irq(struct irq_desc *desc, int irq) desc->depth++; resume: desc->istate &= ~IRQS_SUSPENDED; - __enable_irq(desc, irq); + __enable_irq(desc); } static void resume_irqs(bool want_early) -- cgit v0.10.2 From b80f5f3fc0dc5362eac19585c31a1cc414a6cf95 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 23 Jun 2015 19:58:45 +0200 Subject: genirq: Remove irq argument from suspend/resume_irq() Unused argument in both functions. [ tglx: Split out from combo patch ] Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index 0e1c617..21c6261 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -68,7 +68,7 @@ void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action) desc->cond_suspend_depth--; } -static bool suspend_device_irq(struct irq_desc *desc, int irq) +static bool suspend_device_irq(struct irq_desc *desc) { if (!desc->action || desc->no_suspend_depth) return false; @@ -126,7 +126,7 @@ void suspend_device_irqs(void) if (irq_settings_is_nested_thread(desc)) continue; raw_spin_lock_irqsave(&desc->lock, flags); - sync = suspend_device_irq(desc, irq); + sync = suspend_device_irq(desc); raw_spin_unlock_irqrestore(&desc->lock, flags); if (sync) @@ -135,7 +135,7 @@ void suspend_device_irqs(void) } EXPORT_SYMBOL_GPL(suspend_device_irqs); -static void resume_irq(struct irq_desc *desc, int irq) +static void resume_irq(struct irq_desc *desc) { irqd_clear(&desc->irq_data, IRQD_WAKEUP_ARMED); @@ -169,7 +169,7 @@ static void resume_irqs(bool want_early) continue; raw_spin_lock_irqsave(&desc->lock, flags); - resume_irq(desc, irq); + resume_irq(desc); raw_spin_unlock_irqrestore(&desc->lock, flags); } } -- cgit v0.10.2 From 02d00eaa64bfd57fcbefe848e46e5ddca62ed5e6 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 23 Jun 2015 20:02:43 +0200 Subject: genirq: Remove irq argument from report_bad_irq() Not really a hotpath, so __report_bad_irq() can retrieve the irq number from the irq descriptor. [ tglx: Split out from combo patch ] Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index e2514b0..c7699ec 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -188,10 +188,9 @@ static inline int bad_action_ret(irqreturn_t action_ret) * (The other 100-of-100,000 interrupts may have been a correctly * functioning device sharing an IRQ with the failing one) */ -static void -__report_bad_irq(unsigned int irq, struct irq_desc *desc, - irqreturn_t action_ret) +static void __report_bad_irq(struct irq_desc *desc, irqreturn_t action_ret) { + unsigned int irq = irq_desc_get_irq(desc); struct irqaction *action; unsigned long flags; @@ -224,14 +223,13 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc, raw_spin_unlock_irqrestore(&desc->lock, flags); } -static void -report_bad_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret) +static void report_bad_irq(struct irq_desc *desc, irqreturn_t action_ret) { static int count = 100; if (count > 0) { count--; - __report_bad_irq(irq, desc, action_ret); + __report_bad_irq(desc, action_ret); } } @@ -280,7 +278,7 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc, return; if (bad_action_ret(action_ret)) { - report_bad_irq(irq, desc, action_ret); + report_bad_irq(desc, action_ret); return; } @@ -413,7 +411,7 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc, /* * The interrupt is stuck */ - __report_bad_irq(irq, desc, action_ret); + __report_bad_irq(desc, action_ret); /* * Now kill the IRQ */ -- cgit v0.10.2 From c1e5bd8cc52ddc8c2998987c8806b999f09b064e Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 23 Jun 2015 20:07:35 +0200 Subject: genirq: Remove irq argument from try_one_irq() Unused argument. [ tglx: Split out from combo patch ] Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index c7699ec..5378c52 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -60,7 +60,7 @@ bool irq_wait_for_poll(struct irq_desc *desc) /* * Recovery handler for misrouted interrupts. */ -static int try_one_irq(int irq, struct irq_desc *desc, bool force) +static int try_one_irq(struct irq_desc *desc, bool force) { irqreturn_t ret = IRQ_NONE; struct irqaction *action; @@ -133,7 +133,7 @@ static int misrouted_irq(int irq) if (i == irq) /* Already tried */ continue; - if (try_one_irq(i, desc, false)) + if (try_one_irq(desc, false)) ok = 1; } out: @@ -164,7 +164,7 @@ static void poll_spurious_irqs(unsigned long dummy) continue; local_irq_disable(); - try_one_irq(i, desc, true); + try_one_irq(desc, true); local_irq_enable(); } out: -- cgit v0.10.2 From 0dcdbc97557fd8c297c4e38e9f66e304a64bae9d Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 4 Jun 2015 12:13:28 +0800 Subject: genirq: Remove the irq argument from note_interrupt() Only required for the slow path. Retrieve it from irq descriptor if necessary. [ tglx: Split out from combo patch. Left [try_]misrouted_irq() untouched as there is no win in the slow path ] Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Bjorn Helgaas Cc: Benjamin Herrenschmidt Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Cc: Jason Cooper Cc: Kevin Cernekee Cc: Arnd Bergmann Link: http://lkml.kernel.org/r/1433391238-19471-19-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/include/linux/irq.h b/include/linux/irq.h index 92188b0..429ac26 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -487,8 +487,7 @@ extern int irq_chip_set_vcpu_affinity_parent(struct irq_data *data, #endif /* Handling of unhandled and spurious interrupts: */ -extern void note_interrupt(unsigned int irq, struct irq_desc *desc, - irqreturn_t action_ret); +extern void note_interrupt(struct irq_desc *desc, irqreturn_t action_ret); /* Enable/disable irq debugging output: */ diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 310d658..76f199d 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -328,7 +328,7 @@ void handle_nested_irq(unsigned int irq) action_ret = action->thread_fn(action->irq, action->dev_id); if (!noirqdebug) - note_interrupt(irq, desc, action_ret); + note_interrupt(desc, action_ret); raw_spin_lock_irq(&desc->lock); irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 4d37b96..b6eeea8 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -176,7 +176,7 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action) add_interrupt_randomness(irq, flags); if (!noirqdebug) - note_interrupt(irq, desc, retval); + note_interrupt(desc, retval); return retval; } diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index 5378c52..3214417 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -270,9 +270,10 @@ try_misrouted_irq(unsigned int irq, struct irq_desc *desc, #define SPURIOUS_DEFERRED 0x80000000 -void note_interrupt(unsigned int irq, struct irq_desc *desc, - irqreturn_t action_ret) +void note_interrupt(struct irq_desc *desc, irqreturn_t action_ret) { + unsigned int irq; + if (desc->istate & IRQS_POLL_INPROGRESS || irq_settings_is_polled(desc)) return; @@ -396,6 +397,7 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc, desc->last_unhandled = jiffies; } + irq = irq_desc_get_irq(desc); if (unlikely(try_misrouted_irq(irq, desc, action_ret))) { int ok = misrouted_irq(irq); if (action_ret == IRQ_NONE) -- cgit v0.10.2 From e019c249a60fc50319c5897d21d36207c257cc9e Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 23 Jun 2015 20:29:34 +0200 Subject: genirq: Provide and use __irq_can_set_affinity() Provide a irq_desc based variant of irq_can_set_affinity() to avoid a redundant lookup for the core code users. [ tglx: Split out from combo patch ] Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index d526ac1..f5b7742 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -115,6 +115,14 @@ EXPORT_SYMBOL(synchronize_irq); #ifdef CONFIG_SMP cpumask_var_t irq_default_affinity; +static int __irq_can_set_affinity(struct irq_desc *desc) +{ + if (!desc || !irqd_can_balance(&desc->irq_data) || + !desc->irq_data.chip || !desc->irq_data.chip->irq_set_affinity) + return 0; + return 1; +} + /** * irq_can_set_affinity - Check if the affinity of a given irq can be set * @irq: Interrupt to check @@ -122,13 +130,7 @@ cpumask_var_t irq_default_affinity; */ int irq_can_set_affinity(unsigned int irq) { - struct irq_desc *desc = irq_to_desc(irq); - - if (!desc || !irqd_can_balance(&desc->irq_data) || - !desc->irq_data.chip || !desc->irq_data.chip->irq_set_affinity) - return 0; - - return 1; + return __irq_can_set_affinity(irq_to_desc(irq)); } /** @@ -366,7 +368,7 @@ setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask) int node = irq_desc_get_node(desc); /* Excludes PER_CPU and NO_BALANCE interrupts */ - if (!irq_can_set_affinity(irq)) + if (!__irq_can_set_affinity(desc)) return 0; /* -- cgit v0.10.2 From a8a98eac7b238beb49b479c164303651d5a37eb6 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 4 Jun 2015 12:13:30 +0800 Subject: genirq: Remove the irq argument from setup_affinity() Unused except for the alpha wrapper, which can retrieve if from the irq descriptor. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Bjorn Helgaas Cc: Benjamin Herrenschmidt Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Link: http://lkml.kernel.org/r/1433391238-19471-21-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index f5b7742..886f115 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -361,8 +361,7 @@ EXPORT_SYMBOL_GPL(irq_set_affinity_notifier); /* * Generic version of the affinity autoselector. */ -static int -setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask) +static int setup_affinity(struct irq_desc *desc, struct cpumask *mask) { struct cpumask *set = irq_default_affinity; int node = irq_desc_get_node(desc); @@ -395,10 +394,10 @@ setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask) return 0; } #else -static inline int -setup_affinity(unsigned int irq, struct irq_desc *d, struct cpumask *mask) +/* Wrapper for ALPHA specific affinity selector magic */ +static inline int setup_affinity(struct irq_desc *d, struct cpumask *mask) { - return irq_select_affinity(irq); + return irq_select_affinity(irq_desc_get_irq(d)); } #endif @@ -412,14 +411,14 @@ int irq_select_affinity_usr(unsigned int irq, struct cpumask *mask) int ret; raw_spin_lock_irqsave(&desc->lock, flags); - ret = setup_affinity(irq, desc, mask); + ret = setup_affinity(desc, mask); raw_spin_unlock_irqrestore(&desc->lock, flags); return ret; } #else static inline int -setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask) +setup_affinity(struct irq_desc *desc, struct cpumask *mask) { return 0; } @@ -1256,7 +1255,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) } /* Set default affinity mask once everything is setup */ - setup_affinity(irq, desc, mask); + setup_affinity(desc, mask); } else if (new->flags & IRQF_TRIGGER_MASK) { unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK; -- cgit v0.10.2 From 741ff9661337231233cd675df7726ffafe13c960 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:49 +0200 Subject: irqchip/exynos-combiner: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper Cc: Kukjin Kim Cc: Krzysztof Kozlowski Cc: linux-arm-kernel@lists.infradead.org Cc: linux-samsung-soc@vger.kernel.org diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 05cdccc..6ad04ac 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -121,9 +121,8 @@ static struct irq_chip combiner_chip = { static void __init combiner_cascade_irq(struct combiner_chip_data *combiner_data, unsigned int irq) { - if (irq_set_handler_data(irq, combiner_data) != 0) - BUG(); - irq_set_chained_handler(irq, combiner_handle_cascade_irq); + irq_set_chained_handler_and_data(irq, combiner_handle_cascade_irq, + combiner_data); } static void __init combiner_init_one(struct combiner_chip_data *combiner_data, -- cgit v0.10.2 From 3a7946eed85a1031120d2c946d6e8e8520b32827 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:50 +0200 Subject: irqchip/bcm7038-l1: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Kevin Cernekee Cc: Florian Fainelli Cc: Thomas Gleixner Cc: Jason Cooper Cc: linux-mips@linux-mips.org diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index 66850aa..409bdc6 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -256,8 +256,8 @@ static int __init bcm7038_l1_init_one(struct device_node *dn, pr_err("failed to map parent interrupt %d\n", parent_irq); return -EINVAL; } - irq_set_handler_data(parent_irq, intc); - irq_set_chained_handler(parent_irq, bcm7038_l1_irq_handle); + irq_set_chained_handler_and_data(parent_irq, bcm7038_l1_irq_handle, + intc); return 0; } -- cgit v0.10.2 From 99e32ab1732e8e66c775087f5361fca235bbee0e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:51 +0200 Subject: irqchip/bcm7120-l2: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Kevin Cernekee Cc: Florian Fainelli Cc: Thomas Gleixner Cc: Jason Cooper Cc: linux-mips@linux-mips.org diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index 7de378e..88c9719 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -130,8 +130,8 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, } } - irq_set_handler_data(parent_irq, data); - irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle); + irq_set_chained_handler_and_data(parent_irq, + bcm7120_l2_intc_irq_handle, data); return 0; } -- cgit v0.10.2 From f286c173593245d443e592edea2ec35ef4a7c7e8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:52 +0200 Subject: irqchip/brcmstb-l2: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Kevin Cernekee Cc: Florian Fainelli Cc: Thomas Gleixner Cc: Jason Cooper Cc: linux-mips@linux-mips.org diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index 4e60b88..cef1518 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -170,8 +170,8 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np, } /* Set the IRQ chaining logic */ - irq_set_handler_data(data->parent_irq, data); - irq_set_chained_handler(data->parent_irq, brcmstb_l2_intc_irq_handle); + irq_set_chained_handler_and_data(data->parent_irq, + brcmstb_l2_intc_irq_handle, data); gc = irq_get_domain_generic_chip(data->domain, 0); gc->reg_base = data->base; -- cgit v0.10.2 From 4d83fcf8d615e44ca3ce1ac5766ae121ce08161b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:53 +0200 Subject: irqchip/gic: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 9be84bd..2eaae9c 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -331,9 +331,8 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) { if (gic_nr >= MAX_GIC_NR) BUG(); - if (irq_set_handler_data(irq, &gic_data[gic_nr]) != 0) - BUG(); - irq_set_chained_handler(irq, gic_handle_cascade_irq); + irq_set_chained_handler_and_data(irq, gic_handle_cascade_irq, + &gic_data[gic_nr]); } static u8 gic_get_cpumask(struct gic_chip_data *gic) -- cgit v0.10.2 From bc4d2c074ac1b55a95a2011bffe1c5ebb590e886 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:54 +0200 Subject: irqchip/imgpdc: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c index 8071c2e..03d91cb 100644 --- a/drivers/irqchip/irq-imgpdc.c +++ b/drivers/irqchip/irq-imgpdc.c @@ -451,13 +451,13 @@ static int pdc_intc_probe(struct platform_device *pdev) /* Setup chained handlers for the peripheral IRQs */ for (i = 0; i < priv->nr_perips; ++i) { irq = priv->perip_irqs[i]; - irq_set_handler_data(irq, priv); - irq_set_chained_handler(irq, pdc_intc_perip_isr); + irq_set_chained_handler_and_data(irq, pdc_intc_perip_isr, + priv); } /* Setup chained handler for the syswake IRQ */ - irq_set_handler_data(priv->syswake_irq, priv); - irq_set_chained_handler(priv->syswake_irq, pdc_intc_syswake_isr); + irq_set_chained_handler_and_data(priv->syswake_irq, + pdc_intc_syswake_isr, priv); dev_info(&pdev->dev, "PDC IRQ controller initialised (%u perip IRQs, %u syswake IRQs)\n", -- cgit v0.10.2 From 832b404ea0f48a57f1099327cd3137e9a6a51f88 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:55 +0200 Subject: irqchip/metag: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: James Hogan Cc: Thomas Gleixner Cc: Jason Cooper Cc: linux-metag@vger.kernel.org diff --git a/drivers/irqchip/irq-metag.c b/drivers/irqchip/irq-metag.c index c16c186..3d23ce3 100644 --- a/drivers/irqchip/irq-metag.c +++ b/drivers/irqchip/irq-metag.c @@ -286,8 +286,7 @@ static void metag_internal_irq_init_cpu(struct metag_internal_irq_priv *priv, int irq = tbisig_map(signum); /* Register the multiplexed IRQ handler */ - irq_set_handler_data(irq, priv); - irq_set_chained_handler(irq, metag_internal_irq_demux); + irq_set_chained_handler_and_data(irq, metag_internal_irq_demux, priv); irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); } -- cgit v0.10.2 From 07d22c23d63a3dc08083fec7ce26562b05e7d24b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:57 +0200 Subject: irqchip/orion: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c index 995f66b..7fbae56 100644 --- a/drivers/irqchip/irq-orion.c +++ b/drivers/irqchip/irq-orion.c @@ -197,8 +197,8 @@ static int __init orion_bridge_irq_init(struct device_node *np, writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK); writel(0, gc->reg_base + ORION_BRIDGE_IRQ_CAUSE); - irq_set_handler_data(irq, domain); - irq_set_chained_handler(irq, orion_bridge_irq_handler); + irq_set_chained_handler_and_data(irq, orion_bridge_irq_handler, + domain); return 0; } -- cgit v0.10.2 From 3200a71207c7d4ec4e961c0ef7ac50361de30e9a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:58 +0200 Subject: irqchip/sunxi-nmi: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper Cc: Maxime Ripard Cc: linux-arm-kernel@lists.infradead.org diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c index 2fb8c0e..9186a11 100644 --- a/drivers/irqchip/irq-sunxi-nmi.c +++ b/drivers/irqchip/irq-sunxi-nmi.c @@ -182,8 +182,7 @@ static int __init sunxi_sc_nmi_irq_init(struct device_node *node, sunxi_sc_nmi_write(gc, reg_offs->enable, 0); sunxi_sc_nmi_write(gc, reg_offs->pend, 0x1); - irq_set_handler_data(irq, domain); - irq_set_chained_handler(irq, sunxi_sc_nmi_handle_irq); + irq_set_chained_handler_and_data(irq, sunxi_sc_nmi_handle_irq, domain); return 0; -- cgit v0.10.2 From 22890b0dbe233fa460d25762ab6a2f5c90f84d9c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:58 +0200 Subject: irqchip/tb10x: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c index 55dea55..c7e1407 100644 --- a/drivers/irqchip/irq-tb10x.c +++ b/drivers/irqchip/irq-tb10x.c @@ -173,8 +173,8 @@ static int __init of_tb10x_init_irq(struct device_node *ictl, for (i = 0; i < nrirqs; i++) { unsigned int irq = irq_of_parse_and_map(ictl, i); - irq_set_handler_data(irq, domain); - irq_set_chained_handler(irq, tb10x_irq_cascade); + irq_set_chained_handler_and_data(irq, tb10x_irq_cascade, + domain); } ab_irqctl_writereg(gc, AB_IRQCTL_INT_ENABLE, 0); -- cgit v0.10.2 From fcd3c5bee16a2c3c9cd6c4cb8e3e093d458d9f86 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:11:00 +0200 Subject: irqchip/versatile: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index 4ba480b..70088bb 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -155,8 +155,8 @@ void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start, f->valid = valid; if (parent_irq != -1) { - irq_set_handler_data(parent_irq, f); - irq_set_chained_handler(parent_irq, fpga_irq_handle); + irq_set_chained_handler_and_data(parent_irq, fpga_irq_handle, + f); } /* This will also allocate irq descriptors */ -- cgit v0.10.2 From 9f2135419ffb7601b6642147ae0e6ccc19a7d5be Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:11:00 +0200 Subject: irqchip/vic: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); | -irq_set_handler_data(E1, E2); ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); @@ expression E1, E2, E3; @@ ( -if (irq_set_handler_data(E1, E2) != 0) - BUG(); ... | -irq_set_handler_data(E1, E2); ... ) -irq_set_chained_handler(E1, E3); +irq_set_chained_handler_and_data(E1, E3, E2); Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index 4cd65c1..03846df 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -296,8 +296,8 @@ static void __init vic_register(void __iomem *base, unsigned int parent_irq, vic_id++; if (parent_irq) { - irq_set_handler_data(parent_irq, v); - irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded); + irq_set_chained_handler_and_data(parent_irq, + vic_handle_irq_cascaded, v); } v->domain = irq_domain_add_simple(node, fls(valid_sources), irq, -- cgit v0.10.2 From 72f86db4dd5eafbadd45c9092df73c49f320f638 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:38 +0800 Subject: irqchip/mips-gic: Use access helper irq_data_get_affinity_mask() Use access helper irq_data_get_affinity_mask() to hide implementation details of struct irq_desc. [ tglx: Verified with coccinelle ] Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Bjorn Helgaas Cc: Benjamin Herrenschmidt Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Cc: Jason Cooper Link: http://lkml.kernel.org/r/1433145945-789-30-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 42dbebc..e6c2df9 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -405,7 +405,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, clear_bit(irq, pcpu_masks[i].pcpu_mask); set_bit(irq, pcpu_masks[cpumask_first(&tmp)].pcpu_mask); - cpumask_copy(d->affinity, cpumask); + cpumask_copy(irq_data_get_affinity_mask(d), cpumask); spin_unlock_irqrestore(&gic_lock, flags); return IRQ_SET_MASK_OK_NOCOPY; -- cgit v0.10.2 From 5b29264c659c31bada65582005d99adb3bb41fea Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 4 Jun 2015 12:13:20 +0800 Subject: irqchip: Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc while we already have a pointer to corresponding irq_desc. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Bjorn Helgaas Cc: Benjamin Herrenschmidt Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Cc: Jason Cooper Cc: Kukjin Kim Cc: Krzysztof Kozlowski Cc: Maxime Ripard Link: http://lkml.kernel.org/r/1433391238-19471-11-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 6ad04ac..1a4a1b0 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -67,8 +67,8 @@ static void combiner_unmask_irq(struct irq_data *data) static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) { - struct combiner_chip_data *chip_data = irq_get_handler_data(irq); - struct irq_chip *chip = irq_get_chip(irq); + struct combiner_chip_data *chip_data = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int cascade_irq, combiner_irq; unsigned long status; diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 73b73ac..39b72da 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -450,7 +450,7 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {} static void armada_370_xp_mpic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); unsigned long irqmap, irqn, irqsrc, cpuid; unsigned int cascade_irq; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 2eaae9c..cadd862 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -288,8 +288,8 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) { - struct gic_chip_data *chip_data = irq_get_handler_data(irq); - struct irq_chip *chip = irq_get_chip(irq); + struct gic_chip_data *chip_data = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int cascade_irq, gic_irq; unsigned long status; diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c index 7fbae56..5ea999a 100644 --- a/drivers/irqchip/irq-orion.c +++ b/drivers/irqchip/irq-orion.c @@ -108,7 +108,7 @@ IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init); static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct irq_domain *d = irq_get_handler_data(irq); + struct irq_domain *d = irq_desc_get_handler_data(desc); struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0); u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) & diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c index 9186a11..772a82c 100644 --- a/drivers/irqchip/irq-sunxi-nmi.c +++ b/drivers/irqchip/irq-sunxi-nmi.c @@ -61,7 +61,7 @@ static inline u32 sunxi_sc_nmi_read(struct irq_chip_generic *gc, u32 off) static void sunxi_sc_nmi_handle_irq(unsigned int irq, struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int virq = irq_find_mapping(domain, 0); chained_irq_enter(chip, desc); diff --git a/drivers/irqchip/spear-shirq.c b/drivers/irqchip/spear-shirq.c index 3df144f..6171855 100644 --- a/drivers/irqchip/spear-shirq.c +++ b/drivers/irqchip/spear-shirq.c @@ -184,7 +184,7 @@ static struct spear_shirq *spear320_shirq_blocks[] = { static void shirq_handler(unsigned irq, struct irq_desc *desc) { - struct spear_shirq *shirq = irq_get_handler_data(irq); + struct spear_shirq *shirq = irq_desc_get_handler_data(desc); u32 pend; pend = readl(shirq->base + shirq->status_reg) & shirq->mask; -- cgit v0.10.2 From d2aa914d27f1fb9b7d4e4767c1698ed6a665cb1d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:41 +0200 Subject: irqchip/vt8500: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle: @@ struct irq_data *d; expression E1; @@ -__irq_set_handler_locked(d->irq, E1); +irq_set_handler_locked(d, E1); Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Thomas Gleixner Cc: Jason Cooper diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c index 52c2800..8371d99 100644 --- a/drivers/irqchip/irq-vt8500.c +++ b/drivers/irqchip/irq-vt8500.c @@ -126,15 +126,15 @@ static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type) return -EINVAL; case IRQF_TRIGGER_HIGH: dctr |= VT8500_TRIGGER_HIGH; - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); break; case IRQF_TRIGGER_FALLING: dctr |= VT8500_TRIGGER_FALLING; - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); break; case IRQF_TRIGGER_RISING: dctr |= VT8500_TRIGGER_RISING; - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); break; } writeb(dctr, base + VT8500_ICDC + d->hwirq); -- cgit v0.10.2 From 0a2b64979ab7f8d5325879bd552dcb85974b2980 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 14:39:45 +0200 Subject: irqchip/metag-ext: Use irq_set_chip_handler_name_locked() Hand in irq_data and avoid the redundant lookup of irq_desc. Originally-from: Jiang Liu Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-metag-ext.c b/drivers/irqchip/irq-metag-ext.c index 2cb474a..5f4c529 100644 --- a/drivers/irqchip/irq-metag-ext.c +++ b/drivers/irqchip/irq-metag-ext.c @@ -404,7 +404,6 @@ static int meta_intc_irq_set_type(struct irq_data *data, unsigned int flow_type) #ifdef CONFIG_METAG_SUSPEND_MEM struct meta_intc_priv *priv = &meta_intc_priv; #endif - unsigned int irq = data->irq; irq_hw_number_t hw = data->hwirq; unsigned int bit = 1 << meta_intc_offset(hw); void __iomem *level_addr = meta_intc_level_addr(hw); @@ -413,11 +412,11 @@ static int meta_intc_irq_set_type(struct irq_data *data, unsigned int flow_type) /* update the chip/handler */ if (flow_type & IRQ_TYPE_LEVEL_MASK) - __irq_set_chip_handler_name_locked(irq, &meta_intc_level_chip, - handle_level_irq, NULL); + irq_set_chip_handler_name_locked(data, &meta_intc_level_chip, + handle_level_irq, NULL); else - __irq_set_chip_handler_name_locked(irq, &meta_intc_edge_chip, - handle_edge_irq, NULL); + irq_set_chip_handler_name_locked(data, &meta_intc_edge_chip, + handle_edge_irq, NULL); /* and clear/set the bit in HWLEVELEXT */ __global_lock2(flags); -- cgit v0.10.2 From a595fc51a3417274acc1eee63967e9b9e657cc89 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 14:41:25 +0200 Subject: irqchip/mips-gic: Use irq_set_chip_handler_name_locked Use irq_set_handler_name_locked() as it avoids a redundant lookup of the irq descriptor. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Jason Cooper diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index e6c2df9..e670f65 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -367,15 +367,12 @@ static int gic_set_type(struct irq_data *d, unsigned int type) break; } - if (is_edge) { - __irq_set_chip_handler_name_locked(d->irq, - &gic_edge_irq_controller, - handle_edge_irq, NULL); - } else { - __irq_set_chip_handler_name_locked(d->irq, - &gic_level_irq_controller, - handle_level_irq, NULL); - } + if (is_edge) + irq_set_chip_handler_name_locked(d, &gic_edge_irq_controller, + handle_edge_irq, NULL); + else + irq_set_chip_handler_name_locked(d, &gic_level_irq_controller, + handle_level_irq, NULL); spin_unlock_irqrestore(&gic_lock, flags); return 0; -- cgit v0.10.2 From 77b563ed06a63e59ce1bf2803170898e852b3866 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:21:39 +0200 Subject: irqchip/exynos: Prepare combiner_handle_cascade_irq for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 1a4a1b0..04e0892 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -65,10 +65,12 @@ static void combiner_unmask_irq(struct irq_data *data) __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET); } -static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) +static void combiner_handle_cascade_irq(unsigned int __irq, + struct irq_desc *desc) { struct combiner_chip_data *chip_data = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int irq = irq_desc_get_irq(desc); unsigned int cascade_irq, combiner_irq; unsigned long status; -- cgit v0.10.2 From 00db2ae52a78f6ba23c16c22696da59f4f2a4da0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:35:20 +0200 Subject: irqchip/brcmstb-l2: Prepare brcmstb_l2_intc_irq_handle for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index cef1518..aedda06 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -49,11 +49,13 @@ struct brcmstb_l2_intc_data { u32 saved_mask; /* for suspend/resume */ }; -static void brcmstb_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) +static void brcmstb_l2_intc_irq_handle(unsigned int __irq, + struct irq_desc *desc) { struct brcmstb_l2_intc_data *b = irq_desc_get_handler_data(desc); struct irq_chip_generic *gc = irq_get_domain_generic_chip(b->domain, 0); struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int irq = irq_desc_get_irq(desc); u32 status; chained_irq_enter(chip, desc); -- cgit v0.10.2 From 99705f995a704fdf8625464d70ef5c5750ea55e2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:37:28 +0200 Subject: irqchip/imgpdc: Prepare pdc_intc_perip_isr for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c index 03d91cb..841604b 100644 --- a/drivers/irqchip/irq-imgpdc.c +++ b/drivers/irqchip/irq-imgpdc.c @@ -218,8 +218,9 @@ static int pdc_irq_set_wake(struct irq_data *data, unsigned int on) return 0; } -static void pdc_intc_perip_isr(unsigned int irq, struct irq_desc *desc) +static void pdc_intc_perip_isr(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct pdc_intc_priv *priv; unsigned int i, irq_no; -- cgit v0.10.2 From 283653a368f49773ee7242e2a03227d7de5d3a7e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:38:07 +0200 Subject: irqchip/keystone: Prepare keystone_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index d10244f..c151726 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -83,8 +83,9 @@ static void keystone_irq_ack(struct irq_data *d) /* nothing to do here */ } -static void keystone_irq_handler(unsigned irq, struct irq_desc *desc) +static void keystone_irq_handler(unsigned __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct keystone_irq_device *kirq = irq_desc_get_handler_data(desc); unsigned long pending; int src, virq; -- cgit v0.10.2 From 14873aa1d1c97a11cec57ae1345da467d4b6d4d7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:38:51 +0200 Subject: irqchip/mmp: Prepare icu_mux_irq_demux for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c index c9c03a2..781ed6e 100644 --- a/drivers/irqchip/irq-mmp.c +++ b/drivers/irqchip/irq-mmp.c @@ -129,8 +129,9 @@ struct irq_chip icu_irq_chip = { .irq_unmask = icu_unmask_irq, }; -static void icu_mux_irq_demux(unsigned int irq, struct irq_desc *desc) +static void icu_mux_irq_demux(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct irq_domain *domain; struct icu_chip_data *data; int i; -- cgit v0.10.2 From 4df18a668c45d2069d731eccb75b7558052c8718 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:39:29 +0200 Subject: irqchip/s3c24xx: Prepare s3c_irq_demux for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c index aee4266..506d9f2 100644 --- a/drivers/irqchip/irq-s3c24xx.c +++ b/drivers/irqchip/irq-s3c24xx.c @@ -298,16 +298,14 @@ static struct irq_chip s3c_irq_eint0t4 = { .irq_set_type = s3c_irqext0_type, }; -static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc) +static void s3c_irq_demux(unsigned int __irq, struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct s3c_irq_data *irq_data = irq_desc_get_chip_data(desc); struct s3c_irq_intc *intc = irq_data->intc; struct s3c_irq_intc *sub_intc = irq_data->sub_intc; - unsigned long src; - unsigned long msk; - unsigned int n; - unsigned int offset; + unsigned int n, offset, irq; + unsigned long src, msk; /* we're using individual domains for the non-dt case * and one big domain for the dt case where the subintc -- cgit v0.10.2 From e616e9af87206dfd00753c1546388210fe5d0002 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:40:58 +0200 Subject: irqchip/tb10x: Prepare tb10x_irq_cascade for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c index c7e1407..3318296 100644 --- a/drivers/irqchip/irq-tb10x.c +++ b/drivers/irqchip/irq-tb10x.c @@ -97,9 +97,10 @@ static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type) return IRQ_SET_MASK_OK; } -static void tb10x_irq_cascade(unsigned int irq, struct irq_desc *desc) +static void tb10x_irq_cascade(unsigned int __irq, struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); + unsigned int irq = irq_desc_get_irq(desc); generic_handle_irq(irq_find_mapping(domain, irq)); } -- cgit v0.10.2 From 71093eb2cf720a1eded53c0711c4fa691185e82c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:41:39 +0200 Subject: irqchip/versatile-fpga: Prepare fpga_irq_handle for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index 70088bb..16123f6 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -65,9 +65,10 @@ static void fpga_irq_unmask(struct irq_data *d) writel(mask, f->base + IRQ_ENABLE_SET); } -static void fpga_irq_handle(unsigned int irq, struct irq_desc *desc) +static void fpga_irq_handle(unsigned int __irq, struct irq_desc *desc) { struct fpga_irq_data *f = irq_desc_get_handler_data(desc); + unsigned int irq = irq_desc_get_irq(desc); u32 status = readl(f->base + IRQ_STATUS); if (status == 0) { -- cgit v0.10.2 From 9fc0fd6b052be4390138bb6c4bae07d6b7e1aa66 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 22:42:21 +0200 Subject: irqchip/spear-shirq: Prepare shirq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall diff --git a/drivers/irqchip/spear-shirq.c b/drivers/irqchip/spear-shirq.c index 6171855..ee175d2 100644 --- a/drivers/irqchip/spear-shirq.c +++ b/drivers/irqchip/spear-shirq.c @@ -182,7 +182,7 @@ static struct spear_shirq *spear320_shirq_blocks[] = { &spear320_shirq_intrcomm_ras, }; -static void shirq_handler(unsigned irq, struct irq_desc *desc) +static void shirq_handler(unsigned __irq, struct irq_desc *desc) { struct spear_shirq *shirq = irq_desc_get_handler_data(desc); u32 pend; -- cgit v0.10.2 From c391f262bee9d0d6424a99c85183a06c50e307ee Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:41 +0800 Subject: genirq: Rename irq_data_get_msi() as irq_data_get_msi_desc() Rename irq_data_get_msi() as irq_data_get_msi_desc() to keep consistency with other irq_data access helpers. Signed-off-by: Jiang Liu Acked-by: Bjorn Helgaas Cc: Jason Cooper Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 69486be..85c7735 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -326,7 +326,7 @@ static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev, static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq) { struct irq_data *data = irq_get_irq_data(irq); - struct msi_desc *msi = irq_data_get_msi(data); + struct msi_desc *msi = irq_data_get_msi_desc(data); struct pcie_port *pp = sys_to_pcie(msi->dev->bus->sysdata); clear_irq_range(pp, irq, 1, data->hwirq); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index f66be86..64673f1 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -249,7 +249,7 @@ static void msix_mask_irq(struct msi_desc *desc, u32 flag) static void msi_set_mask_bit(struct irq_data *data, u32 flag) { - struct msi_desc *desc = irq_data_get_msi(data); + struct msi_desc *desc = irq_data_get_msi_desc(data); if (desc->msi_attrib.is_msix) { msix_mask_irq(desc, flag); diff --git a/include/linux/irq.h b/include/linux/irq.h index 429ac26..5284cb1 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -638,7 +638,7 @@ static inline struct msi_desc *irq_get_msi_desc(unsigned int irq) return d ? d->msi_desc : NULL; } -static inline struct msi_desc *irq_data_get_msi(struct irq_data *d) +static inline struct msi_desc *irq_data_get_msi_desc(struct irq_data *d) { return d->msi_desc; } -- cgit v0.10.2 From 507a883ed5396825b88631b06cd27e050f5aa8fe Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:42 +0800 Subject: treewide: Use helper function to access irq_data->msi_desc Use irq_data access helper to access irq_data->msi_desc, so we can move msi_desc from struct irq_data into struct irq_common_data later. Signed-off-by: Jiang Liu Cc: Bjorn Helgaas Cc: Tony Luck Cc: Fenghua Yu Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Chris Metcalf Signed-off-by: Thomas Gleixner diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c index d70bf15..4d3053e 100644 --- a/arch/ia64/kernel/msi_ia64.c +++ b/arch/ia64/kernel/msi_ia64.c @@ -23,7 +23,7 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata, if (irq_prepare_move(irq, cpu)) return -1; - __get_cached_msi_msg(idata->msi_desc, &msg); + __get_cached_msi_msg(irq_data_get_msi_desc(idata), &msg); addr = msg.address_lo; addr &= MSI_ADDR_DEST_ID_MASK; diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c index a0eb27b..59ba632 100644 --- a/arch/ia64/sn/kernel/msi_sn.c +++ b/arch/ia64/sn/kernel/msi_sn.c @@ -175,7 +175,7 @@ static int sn_set_msi_irq_affinity(struct irq_data *data, * Release XIO resources for the old MSI PCI address */ - __get_cached_msi_msg(data->msi_desc, &msg); + __get_cached_msi_msg(irq_data_get_msi_desc(data), &msg); sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; pdev = sn_pdev->pdi_linux_pcidev; provider = SN_PCIDEV_BUSPROVIDER(pdev); diff --git a/arch/powerpc/sysdev/xics/ics-opal.c b/arch/powerpc/sysdev/xics/ics-opal.c index 68c7e5c..11ac964 100644 --- a/arch/powerpc/sysdev/xics/ics-opal.c +++ b/arch/powerpc/sysdev/xics/ics-opal.c @@ -72,7 +72,7 @@ static unsigned int ics_opal_startup(struct irq_data *d) * card, using the MSI mask bits. Firmware doesn't appear to unmask * at that level, so we do it here by hand. */ - if (d->msi_desc) + if (irq_data_get_msi_desc(d)) pci_msi_unmask_irq(d); #endif diff --git a/arch/powerpc/sysdev/xics/ics-rtas.c b/arch/powerpc/sysdev/xics/ics-rtas.c index 0af97de..d1c625c 100644 --- a/arch/powerpc/sysdev/xics/ics-rtas.c +++ b/arch/powerpc/sysdev/xics/ics-rtas.c @@ -75,7 +75,7 @@ static unsigned int ics_rtas_startup(struct irq_data *d) * card, using the MSI mask bits. Firmware doesn't appear to unmask * at that level, so we do it here by hand. */ - if (d->msi_desc) + if (irq_data_get_msi_desc(d)) pci_msi_unmask_irq(d); #endif /* unmask it */ diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c index b1df847..65b701b 100644 --- a/arch/tile/kernel/pci_gx.c +++ b/arch/tile/kernel/pci_gx.c @@ -1442,7 +1442,7 @@ static struct pci_ops tile_cfg_ops = { /* MSI support starts here. */ static unsigned int tilegx_msi_startup(struct irq_data *d) { - if (d->msi_desc) + if (irq_data_get_msi_desc(d)) pci_msi_unmask_irq(d); return 0; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 64673f1..157eb88 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1145,7 +1145,7 @@ EXPORT_SYMBOL(pci_enable_msix_range); */ void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg) { - struct msi_desc *desc = irq_data->msi_desc; + struct msi_desc *desc = irq_data_get_msi_desc(irq_data); /* * For MSI-X desc->irq is always equal to irq_data->irq. For -- cgit v0.10.2 From 40b6d3faef73e6a877fe157f48df1af90bddd9e5 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 4 Jun 2015 12:13:23 +0800 Subject: PCI/keystone: Use irq_data_get_msi_desc() to avoid redundant lookup of irq_data Use irq_data_get_msi_desc() to avoid redundant lookup of irq_data while we already have a pointer to corresponding irq_data. Signed-off-by: Jiang Liu Cc: Bjorn Helgaas Cc: Murali Karicheri Cc: linux-pci@vger.kernel.org Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c index f34892e..e42d077 100644 --- a/drivers/pci/host/pci-keystone-dw.c +++ b/drivers/pci/host/pci-keystone-dw.c @@ -104,14 +104,13 @@ static void ks_dw_pcie_msi_irq_ack(struct irq_data *d) { u32 offset, reg_offset, bit_pos; struct keystone_pcie *ks_pcie; - unsigned int irq = d->irq; struct msi_desc *msi; struct pcie_port *pp; - msi = irq_get_msi_desc(irq); + msi = irq_data_get_msi_desc(d); pp = sys_to_pcie(msi->dev->bus->sysdata); ks_pcie = to_keystone_pcie(pp); - offset = irq - irq_linear_revmap(pp->irq_domain, 0); + offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); update_reg_offset_bit_pos(offset, ®_offset, &bit_pos); writel(BIT(bit_pos), @@ -142,15 +141,14 @@ void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq) static void ks_dw_pcie_msi_irq_mask(struct irq_data *d) { struct keystone_pcie *ks_pcie; - unsigned int irq = d->irq; struct msi_desc *msi; struct pcie_port *pp; u32 offset; - msi = irq_get_msi_desc(irq); + msi = irq_data_get_msi_desc(d); pp = sys_to_pcie(msi->dev->bus->sysdata); ks_pcie = to_keystone_pcie(pp); - offset = irq - irq_linear_revmap(pp->irq_domain, 0); + offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); /* Mask the end point if PVM implemented */ if (IS_ENABLED(CONFIG_PCI_MSI)) { @@ -164,15 +162,14 @@ static void ks_dw_pcie_msi_irq_mask(struct irq_data *d) static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d) { struct keystone_pcie *ks_pcie; - unsigned int irq = d->irq; struct msi_desc *msi; struct pcie_port *pp; u32 offset; - msi = irq_get_msi_desc(irq); + msi = irq_data_get_msi_desc(d); pp = sys_to_pcie(msi->dev->bus->sysdata); ks_pcie = to_keystone_pcie(pp); - offset = irq - irq_linear_revmap(pp->irq_domain, 0); + offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); /* Mask the end point if PVM implemented */ if (IS_ENABLED(CONFIG_PCI_MSI)) { -- cgit v0.10.2 From 5168a73ce32d38170a943aab4ff3402e2ddce641 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:11:05 +0200 Subject: PCI/keystone: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Murali Karicheri Cc: Bjorn Helgaas Cc: linux-pci@vger.kernel.org Cc: Jiang Liu diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c index 734da58..5998e93 100644 --- a/drivers/pci/host/pci-keystone.c +++ b/drivers/pci/host/pci-keystone.c @@ -212,9 +212,9 @@ static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie) /* Legacy IRQ */ for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) { - irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie); - irq_set_chained_handler(ks_pcie->legacy_host_irqs[i], - ks_pcie_legacy_irq_handler); + irq_set_chained_handler_and_data(ks_pcie->legacy_host_irqs[i], + ks_pcie_legacy_irq_handler, + ks_pcie); } ks_dw_pcie_enable_legacy_irqs(ks_pcie); -- cgit v0.10.2 From 97a859641ba1a5d7adf547ab971ab1867b467493 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 16 Jul 2015 23:24:10 +0200 Subject: PCI/keystone: Prepare irq handlers for irq argument removal Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c index 5998e93..81253e7 100644 --- a/drivers/pci/host/pci-keystone.c +++ b/drivers/pci/host/pci-keystone.c @@ -110,8 +110,9 @@ static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie) return -EINVAL; } -static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc) +static void ks_pcie_msi_irq_handler(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); u32 offset = irq - ks_pcie->msi_host_irqs[0]; struct pcie_port *pp = &ks_pcie->pp; @@ -137,8 +138,10 @@ static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc) * Traverse through pending legacy interrupts and invoke handler for each. Also * takes care of interrupt controller level mask/ack operation. */ -static void ks_pcie_legacy_irq_handler(unsigned int irq, struct irq_desc *desc) +static void ks_pcie_legacy_irq_handler(unsigned int __irq, + struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc); struct pcie_port *pp = &ks_pcie->pp; u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0]; -- cgit v0.10.2 From 35c3f67f11849d80cc0e3cd3dd898977567c9c29 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 20 Jul 2015 19:06:14 +0900 Subject: irqchip/renesas-irqc: Get rid of IRQF_VALID IRQF_VALID is not needed on ARM anymore, so get rid of it. Signed-off-by: Magnus Damm Cc: jason@lakedaemon.net Cc: geert+renesas@glider.be Cc: horms@verge.net.au Cc: Magnus Damm Link: http://lkml.kernel.org/r/20150720100614.2552.86867.sendpatchset@little-apple Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 778bd07..74e980f 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -162,7 +162,6 @@ static int irqc_irq_domain_map(struct irq_domain *h, unsigned int virq, irqc_dbg(&p->irq[hw], "map"); irq_set_chip_data(virq, h->host_data); irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); /* kill me now */ return 0; } -- cgit v0.10.2 From 7d153751c79e84a88e8c80e82ee5293085b9081b Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 20 Jul 2015 19:06:25 +0900 Subject: irqchip/renesas-irqc: Use linear IRQ domain Use linear IRQ domain instead of irq_domain_add_simple() that also handles non-DT cases. This reduces the delta between the IRQC code and the generic chip implementation. Signed-off-by: Magnus Damm Cc: jason@lakedaemon.net Cc: geert+renesas@glider.be Cc: horms@verge.net.au Cc: Magnus Damm Link: http://lkml.kernel.org/r/20150720100625.2552.63939.sendpatchset@little-apple Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 74e980f..7f75092 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -242,8 +242,8 @@ static int irqc_probe(struct platform_device *pdev) irq_chip->irq_set_wake = irqc_irq_set_wake; irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND; - p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, - p->number_of_irqs, 0, + p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, + p->number_of_irqs, &irqc_irq_domain_ops, p); if (!p->irq_domain) { ret = -ENXIO; -- cgit v0.10.2 From e10fc03c4f89e5191f0ad2a3885d476f498bf131 Mon Sep 17 00:00:00 2001 From: Magnus Damm Date: Mon, 20 Jul 2015 19:06:35 +0900 Subject: irqchip/renesas-irqc: Make use of irq_find_mapping() Instead of locally caching the virq as domain_irq simply rely on the IRQ domain code and irq_find_mapping(). This reduces the delta between the IRQC driver and the generic chip implementation. Signed-off-by: Magnus Damm Cc: jason@lakedaemon.net Cc: geert+renesas@glider.be Cc: horms@verge.net.au Cc: Magnus Damm Link: http://lkml.kernel.org/r/20150720100635.2552.20906.sendpatchset@little-apple Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 7f75092..2aa3add 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -53,7 +53,6 @@ struct irqc_irq { int hw_irq; int requested_irq; - int domain_irq; struct irqc_priv *p; }; @@ -70,8 +69,8 @@ struct irqc_priv { static void irqc_dbg(struct irqc_irq *i, char *str) { - dev_dbg(&i->p->pdev->dev, "%s (%d:%d:%d)\n", - str, i->requested_irq, i->hw_irq, i->domain_irq); + dev_dbg(&i->p->pdev->dev, "%s (%d:%d)\n", + str, i->requested_irq, i->hw_irq); } static void irqc_irq_enable(struct irq_data *d) @@ -145,7 +144,7 @@ static irqreturn_t irqc_irq_handler(int irq, void *dev_id) if (ioread32(p->iomem + DETECT_STATUS) & bit) { iowrite32(bit, p->iomem + DETECT_STATUS); irqc_dbg(i, "demux2"); - generic_handle_irq(i->domain_irq); + generic_handle_irq(irq_find_mapping(p->irq_domain, i->hw_irq)); return IRQ_HANDLED; } return IRQ_NONE; @@ -156,9 +155,6 @@ static int irqc_irq_domain_map(struct irq_domain *h, unsigned int virq, { struct irqc_priv *p = h->host_data; - p->irq[hw].domain_irq = virq; - p->irq[hw].hw_irq = hw; - irqc_dbg(&p->irq[hw], "map"); irq_set_chip_data(virq, h->host_data); irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); @@ -214,6 +210,7 @@ static int irqc_probe(struct platform_device *pdev) break; p->irq[k].p = p; + p->irq[k].hw_irq = k; p->irq[k].requested_irq = irq->start; } -- cgit v0.10.2 From 6ed3464897cc825a75218653c710d673282dfcf8 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 2 Jan 2015 16:18:54 -0600 Subject: irqchip: omap-intc: Improve IRQ handler As it turns out the current IRQ number will *always* be available from SIR register which renders the reads of PENDING registers as plain unnecessary overhead. In order to catch any situation where SIR reads as zero, we're adding a WARN() to turn it into a very verbose error and users actually report it. With this patch average running time of omap_intc_handle_irq() reduced from about 28.5us to 19.8us as measured by the kernel function profiler. Tested with BeagleBoneBlack Rev A5C. Tested-by: Tony Lindgren Signed-off-by: Felipe Balbi Cc: Linux ARM Kernel Mailing List Link: http://lkml.kernel.org/r/20150720204910.GH5394@saruman.tx.rr.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-omap-intc.c b/drivers/irqchip/irq-omap-intc.c index 6cc0ad5..8587d0f 100644 --- a/drivers/irqchip/irq-omap-intc.c +++ b/drivers/irqchip/irq-omap-intc.c @@ -330,37 +330,12 @@ static int __init omap_init_irq(u32 base, struct device_node *node) static asmlinkage void __exception_irq_entry omap_intc_handle_irq(struct pt_regs *regs) { - u32 irqnr = 0; - int handled_irq = 0; - int i; - - do { - for (i = 0; i < omap_nr_pending; i++) { - irqnr = intc_readl(INTC_PENDING_IRQ0 + (0x20 * i)); - if (irqnr) - goto out; - } - -out: - if (!irqnr) - break; - - irqnr = intc_readl(INTC_SIR); - irqnr &= ACTIVEIRQ_MASK; + u32 irqnr; - if (irqnr) { - handle_domain_irq(domain, irqnr, regs); - handled_irq = 1; - } - } while (irqnr); - - /* - * If an irq is masked or deasserted while active, we will - * keep ending up here with no irq handled. So remove it from - * the INTC with an ack. - */ - if (!handled_irq) - omap_ack_irq(NULL); + irqnr = intc_readl(INTC_SIR); + irqnr &= ACTIVEIRQ_MASK; + WARN_ONCE(!irqnr, "Spurious IRQ ?\n"); + handle_domain_irq(domain, irqnr, regs); } void __init omap3_init_irq(void) -- cgit v0.10.2 From faca10b9e63e880c81388fbbedf7ede6dcd77c70 Mon Sep 17 00:00:00 2001 From: Wang Long Date: Tue, 21 Jul 2015 08:11:01 +0000 Subject: drivers/irqchip: Replace pr_warning by pr_warn Update the last pr_warning callsite in drivers/irqchip. Signed-off-by: Wang Long Cc: Cc: Cc: Cc: Cc: Cc: Link: http://lkml.kernel.org/r/1437466261-147373-1-git-send-email-long.wanglong@huawei.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 04e0892..e9c6f2a 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -185,14 +185,14 @@ static void __init combiner_init(void __iomem *combiner_base, combiner_data = kcalloc(max_nr, sizeof (*combiner_data), GFP_KERNEL); if (!combiner_data) { - pr_warning("%s: could not allocate combiner data\n", __func__); + pr_warn("%s: could not allocate combiner data\n", __func__); return; } combiner_irq_domain = irq_domain_add_linear(np, nr_irq, &combiner_irq_domain_ops, combiner_data); if (WARN_ON(!combiner_irq_domain)) { - pr_warning("%s: irq domain init failed\n", __func__); + pr_warn("%s: irq domain init failed\n", __func__); return; } -- cgit v0.10.2 From c179c9b978b90bdf9cb39f5b5716dede157f1eaf Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:36 +0800 Subject: PCI: Add helper function msi_desc_to_pci_sysdata() Add helper function msi_desc_to_pci_sysdata() to retrieve sysdata from an MSI descriptor. To avoid pulling include/linux/pci.h into include/linux/msi.h, msi_desc_to_pci_sysdata() is implemented as a normal function instead of an inline function. Signed-off-by: Jiang Liu Reviewed-by: Yijing Wang Acked-by: Bjorn Helgaas Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Grant Likely Cc: Marc Zyngier Cc: Stuart Yoder Cc: Borislav Petkov Cc: Alexander Gordeev Link: http://lkml.kernel.org/r/1436428847-8886-2-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 157eb88..ab41742 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1137,6 +1137,14 @@ int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, } EXPORT_SYMBOL(pci_enable_msix_range); +void *msi_desc_to_pci_sysdata(struct msi_desc *desc) +{ + struct pci_dev *dev = msi_desc_to_pci_dev(desc); + + return dev->bus->sysdata; +} +EXPORT_SYMBOL_GPL(msi_desc_to_pci_sysdata); + #ifdef CONFIG_PCI_MSI_IRQ_DOMAIN /** * pci_msi_domain_write_msg - Helper to write MSI message to PCI config space diff --git a/include/linux/msi.h b/include/linux/msi.h index 8ac4a68..cfbd2af 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -60,6 +60,13 @@ static inline struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc) { return desc->dev; } + +void *msi_desc_to_pci_sysdata(struct msi_desc *desc); +#else /* CONFIG_PCI_MSI */ +static inline void *msi_desc_to_pci_sysdata(struct msi_desc *desc) +{ + return NULL; +} #endif /* CONFIG_PCI_MSI */ void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg); -- cgit v0.10.2 From bbcffac3a8b60f2f01a3fcb322167f6b8aba3416 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:37 +0800 Subject: MIPS/PCI: Use for_pci_msi_entry() to access MSI device list Use accessor for_each_pci_msi_entry() to access MSI device list, so we could easily move msi_list from struct pci_dev into struct device later. Signed-off-by: Jiang Liu Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: linux-mips@linux-mips.org Cc: Bjorn Helgaas Cc: Grant Likely Cc: Marc Zyngier Cc: Stuart Yoder Cc: Yijing Wang Cc: Borislav Petkov Cc: Ralf Baechle Link: http://lkml.kernel.org/r/1436428847-8886-3-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c index cffaaf4..2a5bb84 100644 --- a/arch/mips/pci/msi-octeon.c +++ b/arch/mips/pci/msi-octeon.c @@ -200,7 +200,7 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) if (type == PCI_CAP_ID_MSI && nvec > 1) return 1; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { ret = arch_setup_msi_irq(dev, entry); if (ret < 0) return ret; -- cgit v0.10.2 From 2921d1790eeeaf574df94fc5b1aa066e7d86d8f7 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:38 +0800 Subject: powerpc/PCI: Use for_pci_msi_entry() to access MSI device list Use accessor for_each_pci_msi_entry() to access MSI device list, so we could easily move msi_list from struct pci_dev into struct device later. Signed-off-by: Jiang Liu Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: linuxppc-dev@lists.ozlabs.org Cc: Bjorn Helgaas Cc: Grant Likely Cc: Marc Zyngier Cc: Stuart Yoder Cc: Yijing Wang Cc: Borislav Petkov Cc: Arnd Bergmann Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: Olof Johansson Cc: Gavin Shan Cc: Alexey Kardashevskiy Cc: David Gibson Cc: Daniel Axtens Cc: Wei Yang Cc: Nishanth Aravamudan Cc: Alexander Gordeev Cc: Scott Wood Cc: Laurentiu Tudor Cc: Tudor Laurentiu Cc: Hongtao Jia Link: http://lkml.kernel.org/r/1436428847-8886-4-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index fe51de4..306888a 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c @@ -213,7 +213,7 @@ static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg) return -ENODEV; } - entry = list_first_entry(&dev->msi_list, struct msi_desc, list); + entry = first_pci_msi_entry(dev); for (; dn; dn = of_get_next_parent(dn)) { if (entry->msi_attrib.is_64) { @@ -269,7 +269,7 @@ static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) if (rc) return rc; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { virq = irq_create_direct_mapping(msic->irq_domain); if (virq == NO_IRQ) { dev_warn(&dev->dev, @@ -292,7 +292,7 @@ static void axon_msi_teardown_msi_irqs(struct pci_dev *dev) dev_dbg(&dev->dev, "axon_msi: tearing down msi irqs\n"); - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { if (entry->irq == NO_IRQ) continue; diff --git a/arch/powerpc/platforms/pasemi/msi.c b/arch/powerpc/platforms/pasemi/msi.c index 27f2b18..e66ef19 100644 --- a/arch/powerpc/platforms/pasemi/msi.c +++ b/arch/powerpc/platforms/pasemi/msi.c @@ -66,7 +66,7 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) pr_debug("pasemi_msi_teardown_msi_irqs, pdev %p\n", pdev); - list_for_each_entry(entry, &pdev->msi_list, list) { + for_each_pci_msi_entry(entry, pdev) { if (entry->irq == NO_IRQ) continue; @@ -94,7 +94,7 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) msg.address_hi = 0; msg.address_lo = PASEMI_MSI_ADDR; - list_for_each_entry(entry, &pdev->msi_list, list) { + for_each_pci_msi_entry(entry, pdev) { /* Allocate 16 interrupts for now, since that's the grouping for * affinity. This can be changed later if it turns out 32 is too * few MSIs for someone, but restrictions will apply to how the diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 765d8ed..bc6d4e0 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -61,7 +61,7 @@ int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) if (pdev->no_64bit_msi && !phb->msi32_support) return -ENODEV; - list_for_each_entry(entry, &pdev->msi_list, list) { + for_each_pci_msi_entry(entry, pdev) { if (!entry->msi_attrib.is_64 && !phb->msi32_support) { pr_warn("%s: Supports only 64-bit MSIs\n", pci_name(pdev)); @@ -103,7 +103,7 @@ void pnv_teardown_msi_irqs(struct pci_dev *pdev) if (WARN_ON(!phb)) return; - list_for_each_entry(entry, &pdev->msi_list, list) { + for_each_pci_msi_entry(entry, pdev) { if (entry->irq == NO_IRQ) continue; irq_set_msi_desc(entry->irq, NULL); diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index c22bb64..272e9ec 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -118,7 +118,7 @@ static void rtas_teardown_msi_irqs(struct pci_dev *pdev) { struct msi_desc *entry; - list_for_each_entry(entry, &pdev->msi_list, list) { + for_each_pci_msi_entry(entry, pdev) { if (entry->irq == NO_IRQ) continue; @@ -350,7 +350,7 @@ static int check_msix_entries(struct pci_dev *pdev) * So we must reject such requests. */ expected = 0; - list_for_each_entry(entry, &pdev->msi_list, list) { + for_each_pci_msi_entry(entry, pdev) { if (entry->msi_attrib.entry_nr != expected) { pr_debug("rtas_msi: bad MSI-X entries.\n"); return -EINVAL; @@ -462,7 +462,7 @@ again: } i = 0; - list_for_each_entry(entry, &pdev->msi_list, list) { + for_each_pci_msi_entry(entry, pdev) { hwirq = rtas_query_irq_number(pdn, i++); if (hwirq < 0) { pr_debug("rtas_msi: error (%d) getting hwirq\n", rc); diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 5236e54..5916da1 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -129,7 +129,7 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev) struct msi_desc *entry; struct fsl_msi *msi_data; - list_for_each_entry(entry, &pdev->msi_list, list) { + for_each_pci_msi_entry(entry, pdev) { if (entry->irq == NO_IRQ) continue; msi_data = irq_get_chip_data(entry->irq); @@ -219,7 +219,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) } } - list_for_each_entry(entry, &pdev->msi_list, list) { + for_each_pci_msi_entry(entry, pdev) { /* * Loop over all the MSI devices until we find one that has an * available interrupt. diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c index fc46ef3..70fbd56 100644 --- a/arch/powerpc/sysdev/mpic_u3msi.c +++ b/arch/powerpc/sysdev/mpic_u3msi.c @@ -108,7 +108,7 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev) { struct msi_desc *entry; - list_for_each_entry(entry, &pdev->msi_list, list) { + for_each_pci_msi_entry(entry, pdev) { if (entry->irq == NO_IRQ) continue; @@ -140,7 +140,7 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) return -ENXIO; } - list_for_each_entry(entry, &pdev->msi_list, list) { + for_each_pci_msi_entry(entry, pdev) { hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, 1); if (hwirq < 0) { pr_debug("u3msi: failed allocating hwirq\n"); diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c index 2bc3367..0d88ba2 100644 --- a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c +++ b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c @@ -50,7 +50,7 @@ static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) return -EINVAL; } - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { irq = msi_bitmap_alloc_hwirqs(&ppc4xx_hsta_msi.bmp, 1); if (irq < 0) { pr_debug("%s: Failed to allocate msi interrupt\n", @@ -108,7 +108,7 @@ static void hsta_teardown_msi_irqs(struct pci_dev *dev) struct msi_desc *entry; int irq; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { if (entry->irq == NO_IRQ) continue; diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c index 6eb21f2..24d0470 100644 --- a/arch/powerpc/sysdev/ppc4xx_msi.c +++ b/arch/powerpc/sysdev/ppc4xx_msi.c @@ -93,7 +93,7 @@ static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) if (!msi_data->msi_virqs) return -ENOMEM; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { int_no = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); if (int_no >= 0) break; @@ -127,7 +127,7 @@ void ppc4xx_teardown_msi_irqs(struct pci_dev *dev) dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n"); - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { if (entry->irq == NO_IRQ) continue; irq_set_msi_desc(entry->irq, NULL); -- cgit v0.10.2 From df516f4278c154f5bb5e594fd54c2b0cb0af7a7c Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:39 +0800 Subject: s390/pci: Use for_pci_msi_entry() to access MSI device list Use accessor for_each_pci_msi_entry() to access MSI device list, so we could easily move msi_list from struct pci_dev into struct device later. Signed-off-by: Jiang Liu Acked-by: Sebastian Ott Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Bjorn Helgaas Cc: Grant Likely Cc: Marc Zyngier Cc: Stuart Yoder Cc: Yijing Wang Cc: Borislav Petkov Cc: Gerald Schaefer Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Link: http://lkml.kernel.org/r/1436428847-8886-5-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 598f023..34f1627 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -414,7 +414,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) /* Request MSI interrupts */ hwirq = 0; - list_for_each_entry(msi, &pdev->msi_list, list) { + for_each_pci_msi_entry(msi, pdev) { rc = -EIO; irq = irq_alloc_desc(0); /* Alloc irq on node 0 */ if (irq < 0) @@ -440,7 +440,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) return (msi_vecs == nvec) ? 0 : msi_vecs; out_msi: - list_for_each_entry(msi, &pdev->msi_list, list) { + for_each_pci_msi_entry(msi, pdev) { if (hwirq-- == 0) break; irq_set_msi_desc(msi->irq, NULL); @@ -470,7 +470,7 @@ void arch_teardown_msi_irqs(struct pci_dev *pdev) return; /* Release MSI interrupts */ - list_for_each_entry(msi, &pdev->msi_list, list) { + for_each_pci_msi_entry(msi, pdev) { if (msi->msi_attrib.is_msix) __pci_msix_desc_mask_irq(msi, 1); else -- cgit v0.10.2 From 39118e31e1daae43048f5deaa3e0894d2732a7d6 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:40 +0800 Subject: x86/PCI: Use for_pci_msi_entry() to access MSI device list Use accessor for_each_pci_msi_entry() to access MSI device list, so we could easily move msi_list from struct pci_dev into struct device later. Signed-off-by: Jiang Liu Acked-by: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: xen-devel@lists.xenproject.org Cc: Bjorn Helgaas Cc: Grant Likely Cc: Marc Zyngier Cc: Stuart Yoder Cc: Yijing Wang Cc: Borislav Petkov Link: http://lkml.kernel.org/r/1436428847-8886-6-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index d22f4b5..ff31ab4 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -179,7 +179,7 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) if (ret) goto error; i = 0; - list_for_each_entry(msidesc, &dev->msi_list, list) { + for_each_pci_msi_entry(msidesc, dev) { irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], (type == PCI_CAP_ID_MSI) ? nvec : 1, (type == PCI_CAP_ID_MSIX) ? @@ -230,7 +230,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) if (type == PCI_CAP_ID_MSI && nvec > 1) return 1; - list_for_each_entry(msidesc, &dev->msi_list, list) { + for_each_pci_msi_entry(msidesc, dev) { __pci_read_msi_msg(msidesc, &msg); pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) | ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff); @@ -274,7 +274,7 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) int ret = 0; struct msi_desc *msidesc; - list_for_each_entry(msidesc, &dev->msi_list, list) { + for_each_pci_msi_entry(msidesc, dev) { struct physdev_map_pirq map_irq; domid_t domid; @@ -386,7 +386,7 @@ static void xen_teardown_msi_irqs(struct pci_dev *dev) { struct msi_desc *msidesc; - msidesc = list_entry(dev->msi_list.next, struct msi_desc, list); + msidesc = first_pci_msi_entry(dev); if (msidesc->msi_attrib.is_msix) xen_pci_frontend_disable_msix(dev); else -- cgit v0.10.2 From 5004e98a91e8ad600f5b00872e9ddad810258f08 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:41 +0800 Subject: PCI: Use for_each_pci_msi_entry() to access MSI device list Use accessor for_each_pci_msi_entry() to access MSI device list, so we could easily move msi_list from struct pci_dev into struct device later. Signed-off-by: Jiang Liu Reviewed-by: Yijing Wang Acked-by: Bjorn Helgaas Acked-by: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: xen-devel@lists.xenproject.org Cc: Grant Likely Cc: Marc Zyngier Cc: Stuart Yoder Cc: Borislav Petkov Cc: Boris Ostrovsky Cc: David Vrabel Link: http://lkml.kernel.org/r/1436428847-8886-7-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index ab41742..540613e 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -131,7 +131,7 @@ int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) if (type == PCI_CAP_ID_MSI && nvec > 1) return 1; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { ret = arch_setup_msi_irq(dev, entry); if (ret < 0) return ret; @@ -151,7 +151,7 @@ void default_teardown_msi_irqs(struct pci_dev *dev) int i; struct msi_desc *entry; - list_for_each_entry(entry, &dev->msi_list, list) + for_each_pci_msi_entry(entry, dev) if (entry->irq) for (i = 0; i < entry->nvec_used; i++) arch_teardown_msi_irq(entry->irq + i); @@ -168,7 +168,7 @@ static void default_restore_msi_irq(struct pci_dev *dev, int irq) entry = NULL; if (dev->msix_enabled) { - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { if (irq == entry->irq) break; } @@ -282,7 +282,7 @@ void default_restore_msi_irqs(struct pci_dev *dev) { struct msi_desc *entry; - list_for_each_entry(entry, &dev->msi_list, list) + for_each_pci_msi_entry(entry, dev) default_restore_msi_irq(dev, entry->irq); } @@ -363,21 +363,22 @@ EXPORT_SYMBOL_GPL(pci_write_msi_msg); static void free_msi_irqs(struct pci_dev *dev) { + struct list_head *msi_list = dev_to_msi_list(&dev->dev); struct msi_desc *entry, *tmp; struct attribute **msi_attrs; struct device_attribute *dev_attr; int i, count = 0; - list_for_each_entry(entry, &dev->msi_list, list) + for_each_pci_msi_entry(entry, dev) if (entry->irq) for (i = 0; i < entry->nvec_used; i++) BUG_ON(irq_has_action(entry->irq + i)); pci_msi_teardown_msi_irqs(dev); - list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) { + list_for_each_entry_safe(entry, tmp, msi_list, list) { if (entry->msi_attrib.is_msix) { - if (list_is_last(&entry->list, &dev->msi_list)) + if (list_is_last(&entry->list, msi_list)) iounmap(entry->mask_base); } @@ -448,7 +449,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev) if (!dev->msix_enabled) return; - BUG_ON(list_empty(&dev->msi_list)); + BUG_ON(list_empty(dev_to_msi_list(&dev->dev))); /* route the table */ pci_intx_for_msi(dev, 0); @@ -456,7 +457,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev) PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL); arch_restore_msi_irqs(dev); - list_for_each_entry(entry, &dev->msi_list, list) + for_each_pci_msi_entry(entry, dev) msix_mask_irq(entry, entry->masked); pci_msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0); @@ -501,7 +502,7 @@ static int populate_msi_sysfs(struct pci_dev *pdev) int count = 0; /* Determine how many msi entries we have */ - list_for_each_entry(entry, &pdev->msi_list, list) + for_each_pci_msi_entry(entry, pdev) ++num_msi; if (!num_msi) return 0; @@ -510,7 +511,7 @@ static int populate_msi_sysfs(struct pci_dev *pdev) msi_attrs = kzalloc(sizeof(void *) * (num_msi + 1), GFP_KERNEL); if (!msi_attrs) return -ENOMEM; - list_for_each_entry(entry, &pdev->msi_list, list) { + for_each_pci_msi_entry(entry, pdev) { msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL); if (!msi_dev_attr) goto error_attrs; @@ -599,7 +600,7 @@ static int msi_verify_entries(struct pci_dev *dev) { struct msi_desc *entry; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { if (!dev->no_64bit_msi || !entry->msg.address_hi) continue; dev_err(&dev->dev, "Device has broken 64-bit MSI but arch" @@ -636,7 +637,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) mask = msi_mask(entry->msi_attrib.multi_cap); msi_mask_irq(entry, mask, mask); - list_add_tail(&entry->list, &dev->msi_list); + list_add_tail(&entry->list, dev_to_msi_list(&dev->dev)); /* Configure MSI capability structure */ ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI); @@ -713,7 +714,7 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base, entry->mask_base = base; entry->nvec_used = 1; - list_add_tail(&entry->list, &dev->msi_list); + list_add_tail(&entry->list, dev_to_msi_list(&dev->dev)); } return 0; @@ -725,7 +726,7 @@ static void msix_program_entries(struct pci_dev *dev, struct msi_desc *entry; int i = 0; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { int offset = entries[i].entry * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; @@ -806,7 +807,7 @@ out_avail: struct msi_desc *entry; int avail = 0; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { if (entry->irq != 0) avail++; } @@ -895,8 +896,8 @@ void pci_msi_shutdown(struct pci_dev *dev) if (!pci_msi_enable || !dev || !dev->msi_enabled) return; - BUG_ON(list_empty(&dev->msi_list)); - desc = list_first_entry(&dev->msi_list, struct msi_desc, list); + BUG_ON(list_empty(dev_to_msi_list(&dev->dev))); + desc = first_msi_entry(dev); pci_msi_set_enable(dev, 0); pci_intx_for_msi(dev, 1); @@ -1001,7 +1002,7 @@ void pci_msix_shutdown(struct pci_dev *dev) return; /* Return the device with MSI-X masked as initial states */ - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { /* Keep cached states to be restored */ __pci_msix_desc_mask_irq(entry, 1); } diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 8b7a900..c777b97 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -265,7 +265,7 @@ static int pci_frontend_enable_msix(struct pci_dev *dev, } i = 0; - list_for_each_entry(entry, &dev->msi_list, list) { + for_each_pci_msi_entry(entry, dev) { op.msix_entries[i].entry = entry->msi_attrib.entry_nr; /* Vector is useless at this point. */ op.msix_entries[i].vector = -1; -- cgit v0.10.2 From 3bf15f53c963a43c317e65e1709e9f020c04f024 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:42 +0800 Subject: sparc/PCI: Use helper functions to access fields in struct msi_desc Use helper functions to access fields in struct msi_desc, so we could easily refine struct msi_desc later. Signed-off-by: Jiang Liu Acked-by: David S. Miller Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Bjorn Helgaas Cc: Grant Likely Cc: Marc Zyngier Cc: Stuart Yoder Cc: Yijing Wang Cc: Borislav Petkov Cc: Eric Snowberg Link: http://lkml.kernel.org/r/1436428847-8886-8-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index c928bc6..048b406 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -918,7 +918,7 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) void arch_teardown_msi_irq(unsigned int irq) { struct msi_desc *entry = irq_get_msi_desc(irq); - struct pci_dev *pdev = entry->dev; + struct pci_dev *pdev = msi_desc_to_pci_dev(entry); struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller; if (pbm->teardown_msi_irq) -- cgit v0.10.2 From e39758e0ea769e632e5e3c9f314160e55c2153ff Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:43 +0800 Subject: PCI: Use helper functions to access fields in struct msi_desc Use helper functions to access fields in struct msi_desc, so we could easily refine msi_desc later. Signed-off-by: Jiang Liu Reviewed-by: Yijing Wang Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Bjorn Helgaas Cc: Grant Likely Cc: Marc Zyngier Cc: Stuart Yoder Cc: Borislav Petkov Cc: Murali Karicheri Cc: Jingoo Han Cc: Pratyush Anand Cc: Michal Simek Cc: Soeren Brinkmann Cc: Srikanth Thokala Cc: Rob Herring Link: http://lkml.kernel.org/r/1436428847-8886-9-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c index e42d077..6f3abc2 100644 --- a/drivers/pci/host/pci-keystone-dw.c +++ b/drivers/pci/host/pci-keystone-dw.c @@ -108,7 +108,7 @@ static void ks_dw_pcie_msi_irq_ack(struct irq_data *d) struct pcie_port *pp; msi = irq_data_get_msi_desc(d); - pp = sys_to_pcie(msi->dev->bus->sysdata); + pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); ks_pcie = to_keystone_pcie(pp); offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); update_reg_offset_bit_pos(offset, ®_offset, &bit_pos); @@ -146,7 +146,7 @@ static void ks_dw_pcie_msi_irq_mask(struct irq_data *d) u32 offset; msi = irq_data_get_msi_desc(d); - pp = sys_to_pcie(msi->dev->bus->sysdata); + pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); ks_pcie = to_keystone_pcie(pp); offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); @@ -167,7 +167,7 @@ static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d) u32 offset; msi = irq_data_get_msi_desc(d); - pp = sys_to_pcie(msi->dev->bus->sysdata); + pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); ks_pcie = to_keystone_pcie(pp); offset = d->irq - irq_linear_revmap(pp->irq_domain, 0); diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 85c7735..aae6dcb 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -255,7 +255,7 @@ static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq) static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) { int irq, pos0, i; - struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata); + struct pcie_port *pp = sys_to_pcie(msi_desc_to_pci_sysdata(desc)); pos0 = bitmap_find_free_region(pp->msi_irq_in_use, MAX_MSI_IRQS, order_base_2(no_irqs)); @@ -327,7 +327,7 @@ static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq) { struct irq_data *data = irq_get_irq_data(irq); struct msi_desc *msi = irq_data_get_msi_desc(data); - struct pcie_port *pp = sys_to_pcie(msi->dev->bus->sysdata); + struct pcie_port *pp = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); clear_irq_range(pp, irq, 1, data->hwirq); } diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c index f1a06a0..64454f4 100644 --- a/drivers/pci/host/pcie-xilinx.c +++ b/drivers/pci/host/pcie-xilinx.c @@ -227,18 +227,16 @@ static struct pci_ops xilinx_pcie_ops = { */ static void xilinx_pcie_destroy_msi(unsigned int irq) { - struct irq_desc *desc; struct msi_desc *msi; struct xilinx_pcie_port *port; - desc = irq_to_desc(irq); - msi = irq_desc_get_msi_desc(desc); - port = sys_to_pcie(msi->dev->bus->sysdata); - - if (!test_bit(irq, msi_irq_in_use)) + if (!test_bit(irq, msi_irq_in_use)) { + msi = irq_get_msi_desc(irq); + port = sys_to_pcie(msi_desc_to_pci_sys_data(msi)); dev_err(port->dev, "Trying to free unused MSI#%d\n", irq); - else + } else { clear_bit(irq, msi_irq_in_use); + } } /** diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 540613e..f0714c3 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -208,7 +208,8 @@ u32 __pci_msi_desc_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) mask_bits &= ~mask; mask_bits |= flag; - pci_write_config_dword(desc->dev, desc->mask_pos, mask_bits); + pci_write_config_dword(msi_desc_to_pci_dev(desc), desc->mask_pos, + mask_bits); return mask_bits; } @@ -288,7 +289,9 @@ void default_restore_msi_irqs(struct pci_dev *dev) void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { - BUG_ON(entry->dev->current_state != PCI_D0); + struct pci_dev *dev = msi_desc_to_pci_dev(entry); + + BUG_ON(dev->current_state != PCI_D0); if (entry->msi_attrib.is_msix) { void __iomem *base = entry->mask_base + @@ -298,7 +301,6 @@ void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR); msg->data = readl(base + PCI_MSIX_ENTRY_DATA); } else { - struct pci_dev *dev = entry->dev; int pos = dev->msi_cap; u16 data; @@ -318,7 +320,9 @@ void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { - if (entry->dev->current_state != PCI_D0) { + struct pci_dev *dev = msi_desc_to_pci_dev(entry); + + if (dev->current_state != PCI_D0) { /* Don't touch the hardware now */ } else if (entry->msi_attrib.is_msix) { void __iomem *base; @@ -329,7 +333,6 @@ void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) writel(msg->address_hi, base + PCI_MSIX_ENTRY_UPPER_ADDR); writel(msg->data, base + PCI_MSIX_ENTRY_DATA); } else { - struct pci_dev *dev = entry->dev; int pos = dev->msi_cap; u16 msgctl; -- cgit v0.10.2 From 4a7cc831670550e6b48ef5760e7213f89935ff0d Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:44 +0800 Subject: genirq/MSI: Move msi_list from struct pci_dev to struct device Move msi_list from struct pci_dev into struct device, so we can support non-PCI-device based generic MSI interrupts. msi_list is now conditional under CONFIG_GENERIC_MSI_IRQ, which is selected from CONFIG_PCI_MSI, so no functional change for PCI MSI users. Signed-off-by: Jiang Liu Reviewed-by: Yijing Wang Acked-by: Bjorn Helgaas Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Grant Likely Cc: Marc Zyngier Cc: Stuart Yoder Cc: Borislav Petkov Cc: Greg Kroah-Hartman Cc: Joe Perches Cc: Dmitry Torokhov Cc: Paul Gortmaker Cc: Luis R. Rodriguez Cc: Rafael J. Wysocki Cc: Joerg Roedel Cc: Alexander Gordeev Link: http://lkml.kernel.org/r/1436428847-8886-10-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/drivers/base/core.c b/drivers/base/core.c index dafae6d..18e2a89 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -662,6 +662,9 @@ void device_initialize(struct device *dev) INIT_LIST_HEAD(&dev->devres_head); device_pm_init(dev); set_dev_node(dev, -1); +#ifdef CONFIG_GENERIC_MSI_IRQ + INIT_LIST_HEAD(&dev->msi_list); +#endif } EXPORT_SYMBOL_GPL(device_initialize); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index f0714c3..4ef5021 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -900,7 +900,7 @@ void pci_msi_shutdown(struct pci_dev *dev) return; BUG_ON(list_empty(dev_to_msi_list(&dev->dev))); - desc = first_msi_entry(dev); + desc = first_pci_msi_entry(dev); pci_msi_set_enable(dev, 0); pci_intx_for_msi(dev, 1); @@ -1044,7 +1044,6 @@ EXPORT_SYMBOL(pci_msi_enabled); void pci_msi_init_pci_dev(struct pci_dev *dev) { - INIT_LIST_HEAD(&dev->msi_list); } /** diff --git a/include/linux/device.h b/include/linux/device.h index 5a31bf3..22227e7 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -713,6 +713,7 @@ struct device_dma_parameters { * along with subsystem-level and driver-level callbacks. * @pins: For device pin management. * See Documentation/pinctrl.txt for details. + * @msi_list: Hosts MSI descriptors * @numa_node: NUMA node this device is close to. * @dma_mask: Dma mask (if dma'ble device). * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all @@ -776,6 +777,9 @@ struct device { #ifdef CONFIG_PINCTRL struct dev_pin_info *pins; #endif +#ifdef CONFIG_GENERIC_MSI_IRQ + struct list_head msi_list; +#endif #ifdef CONFIG_NUMA int numa_node; /* NUMA node this device is close to */ diff --git a/include/linux/msi.h b/include/linux/msi.h index cfbd2af..57fe766 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -45,7 +45,7 @@ struct msi_desc { /* Helpers to hide struct msi_desc implementation details */ #define msi_desc_to_dev(desc) (&(desc)->dev.dev) -#define dev_to_msi_list(dev) (&to_pci_dev((dev))->msi_list) +#define dev_to_msi_list(dev) (&(dev)->msi_list) #define first_msi_entry(dev) \ list_first_entry(dev_to_msi_list((dev)), struct msi_desc, list) #define for_each_msi_entry(desc, dev) \ diff --git a/include/linux/pci.h b/include/linux/pci.h index 8a0321a..fbf245f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -366,7 +366,6 @@ struct pci_dev { struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */ #ifdef CONFIG_PCI_MSI - struct list_head msi_list; const struct attribute_group **msi_irq_groups; #endif struct pci_vpd *vpd; -- cgit v0.10.2 From 25a98bd4ff9355a218d2e7aa4d6e3c9bc2c27d6f Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:45 +0800 Subject: genirq/MSI: Store 'struct device' instead of 'struct pci_dev' in struct msi_desc Store 'struct device *' instead of 'struct pci_dev *' in struct msi_desc, so struct msi_desc can be reused by non PCI based MSI drivers. Signed-off-by: Jiang Liu Reviewed-by: Yijing Wang Reviewed-by: Marc Zyngier Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Bjorn Helgaas Cc: Grant Likely Cc: Stuart Yoder Cc: Borislav Petkov Cc: Alexander Gordeev Link: http://lkml.kernel.org/r/1436428847-8886-11-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 4ef5021..897e1a4 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -413,7 +413,7 @@ static struct msi_desc *alloc_msi_entry(struct pci_dev *dev) return NULL; INIT_LIST_HEAD(&desc->list); - desc->dev = dev; + desc->dev = &dev->dev; return desc; } @@ -1140,6 +1140,11 @@ int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, } EXPORT_SYMBOL(pci_enable_msix_range); +struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc) +{ + return to_pci_dev(desc->dev); +} + void *msi_desc_to_pci_sysdata(struct msi_desc *desc) { struct pci_dev *dev = msi_desc_to_pci_dev(desc); diff --git a/include/linux/msi.h b/include/linux/msi.h index 57fe766..5f77e23 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -14,6 +14,7 @@ extern int pci_msi_ignore_mask; /* Helper functions */ struct irq_data; struct msi_desc; +struct pci_dev; void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg); void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg); @@ -37,14 +38,14 @@ struct msi_desc { void __iomem *mask_base; u8 mask_pos; }; - struct pci_dev *dev; + struct device *dev; /* Last set MSI message */ struct msi_msg msg; }; /* Helpers to hide struct msi_desc implementation details */ -#define msi_desc_to_dev(desc) (&(desc)->dev.dev) +#define msi_desc_to_dev(desc) ((desc)->dev) #define dev_to_msi_list(dev) (&(dev)->msi_list) #define first_msi_entry(dev) \ list_first_entry(dev_to_msi_list((dev)), struct msi_desc, list) @@ -56,11 +57,7 @@ struct msi_desc { #define for_each_pci_msi_entry(desc, pdev) \ for_each_msi_entry((desc), &(pdev)->dev) -static inline struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc) -{ - return desc->dev; -} - +struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc); void *msi_desc_to_pci_sysdata(struct msi_desc *desc); #else /* CONFIG_PCI_MSI */ static inline void *msi_desc_to_pci_sysdata(struct msi_desc *desc) -- cgit v0.10.2 From fc88419cfac50b05c7c1ea218b08e70c31d1b71f Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:46 +0800 Subject: genirq/MSI: Reorginize struct msi_desc to prepare for support of generic MSI Reorganize struct msi_desc so it could be reused by other MSI drivers. We have the following layout now: struct msi_desc { /* Shared device/bus independent data */ ... union { /* PCI specific data */ struct { ... }; }; }; We need to have anonymous union and a anonymous structure for the PCI fields, otherwise we would have to change all instances using these fields. For non PCI devices we will enforce a proper namespace and a non anonymous structure. [ tglx: Added proper comments to the structure and massaged changelog ] Signed-off-by: Jiang Liu Reviewed-by: Yijing Wang Reviewed-by: Marc Zyngier Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Bjorn Helgaas Cc: Grant Likely Cc: Stuart Yoder Cc: Borislav Petkov Cc: Alexander Gordeev Link: http://lkml.kernel.org/r/1436428847-8886-12-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/include/linux/msi.h b/include/linux/msi.h index 5f77e23..518e8c4 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -18,30 +18,60 @@ struct pci_dev; void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg); void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg); +/** + * struct msi_desc - Descriptor structure for MSI based interrupts + * @list: List head for management + * @irq: The base interrupt number + * @nvec_used: The number of vectors used + * @dev: Pointer to the device which uses this descriptor + * @msg: The last set MSI message cached for reuse + * + * @masked: [PCI MSI/X] Mask bits + * @is_msix: [PCI MSI/X] True if MSI-X + * @multiple: [PCI MSI/X] log2 num of messages allocated + * @multi_cap: [PCI MSI/X] log2 num of messages supported + * @maskbit: [PCI MSI/X] Mask-Pending bit supported? + * @is_64: [PCI MSI/X] Address size: 0=32bit 1=64bit + * @entry_nr: [PCI MSI/X] Entry which is described by this descriptor + * @default_irq:[PCI MSI/X] The default pre-assigned non-MSI irq + * @mask_pos: [PCI MSI] Mask register position + * @mask_base: [PCI MSI-X] Mask register base address + */ struct msi_desc { - struct { - __u8 is_msix : 1; - __u8 multiple: 3; /* log2 num of messages allocated */ - __u8 multi_cap : 3; /* log2 num of messages supported */ - __u8 maskbit : 1; /* mask-pending bit supported ? */ - __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */ - __u16 entry_nr; /* specific enabled entry */ - unsigned default_irq; /* default pre-assigned irq */ - } msi_attrib; - - u32 masked; /* mask bits */ - unsigned int irq; - unsigned int nvec_used; /* number of messages */ - struct list_head list; + /* Shared device/bus type independent data */ + struct list_head list; + unsigned int irq; + unsigned int nvec_used; + struct device *dev; + struct msi_msg msg; union { - void __iomem *mask_base; - u8 mask_pos; - }; - struct device *dev; + /* PCI MSI/X specific data */ + struct { + u32 masked; + struct { + __u8 is_msix : 1; + __u8 multiple : 3; + __u8 multi_cap : 3; + __u8 maskbit : 1; + __u8 is_64 : 1; + __u16 entry_nr; + unsigned default_irq; + } msi_attrib; + union { + u8 mask_pos; + void __iomem *mask_base; + }; + }; - /* Last set MSI message */ - struct msi_msg msg; + /* + * Non PCI variants add their data structure here. New + * entries need to use a named structure. We want + * proper name spaces for this. The PCI part is + * anonymous for now as it would require an immediate + * tree wide cleanup. + */ + }; }; /* Helpers to hide struct msi_desc implementation details */ -- cgit v0.10.2 From aa48b6f708868ab9c22ca737f27a0da832bf7f08 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 9 Jul 2015 16:00:47 +0800 Subject: genirq/MSI: Move alloc_msi_entry() from PCI into generic MSI code Move alloc_msi_entry() from PCI MSI code into generic MSI code, so it can be reused by other generic MSI drivers. Also introduce free_msi_entry() for completeness. Suggested-by: Stuart Yoder . Signed-off-by: Jiang Liu Reviewed-by: Marc Zyngier Reviewed-by: Yijing Wang Acked-by: Bjorn Helgaas Cc: Tony Luck Cc: linux-arm-kernel@lists.infradead.org Cc: Grant Likely Cc: Borislav Petkov Cc: Alexander Gordeev Link: http://lkml.kernel.org/r/1436428847-8886-13-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 897e1a4..cd4c78c 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -406,18 +406,6 @@ static void free_msi_irqs(struct pci_dev *dev) } } -static struct msi_desc *alloc_msi_entry(struct pci_dev *dev) -{ - struct msi_desc *desc = kzalloc(sizeof(*desc), GFP_KERNEL); - if (!desc) - return NULL; - - INIT_LIST_HEAD(&desc->list); - desc->dev = &dev->dev; - - return desc; -} - static void pci_intx_for_msi(struct pci_dev *dev, int enable) { if (!(dev->dev_flags & PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG)) @@ -572,7 +560,7 @@ static struct msi_desc *msi_setup_entry(struct pci_dev *dev, int nvec) struct msi_desc *entry; /* MSI Entry Initialization */ - entry = alloc_msi_entry(dev); + entry = alloc_msi_entry(&dev->dev); if (!entry) return NULL; @@ -700,7 +688,7 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base, int i; for (i = 0; i < nvec; i++) { - entry = alloc_msi_entry(dev); + entry = alloc_msi_entry(&dev->dev); if (!entry) { if (!i) iounmap(base); diff --git a/include/linux/msi.h b/include/linux/msi.h index 518e8c4..f83c87e 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -96,6 +96,8 @@ static inline void *msi_desc_to_pci_sysdata(struct msi_desc *desc) } #endif /* CONFIG_PCI_MSI */ +struct msi_desc *alloc_msi_entry(struct device *dev); +void free_msi_entry(struct msi_desc *entry); void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg); void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg); void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg); diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 7bf1f1b..7e6512b 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -18,6 +18,23 @@ /* Temparory solution for building, will be removed later */ #include +struct msi_desc *alloc_msi_entry(struct device *dev) +{ + struct msi_desc *desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return NULL; + + INIT_LIST_HEAD(&desc->list); + desc->dev = dev; + + return desc; +} + +void free_msi_entry(struct msi_desc *entry) +{ + kfree(entry); +} + void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { *msg = entry->msg; -- cgit v0.10.2 From 4365160def95ef2f5da9b5cc5660e5747e5e1956 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:31:09 +0000 Subject: avr32/at32ap: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Acked-by: Hans-Christian Egtvedt Cc: Haavard Skinnemoen Cc: Jiang Liu Cc: Julia Lawall Link: http://lkml.kernel.org/r/20150713100606.351640193@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c index 903c7d8..6c7035a 100644 --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c @@ -312,7 +312,6 @@ gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq) unsigned i; irq_set_chip_data(irq, pio); - irq_set_handler_data(irq, (void *)gpio_irq); for (i = 0; i < 32; i++, gpio_irq++) { irq_set_chip_data(gpio_irq, pio); @@ -320,7 +319,8 @@ gpio_irq_setup(struct pio_device *pio, int irq, int gpio_irq) handle_simple_irq); } - irq_set_chained_handler(irq, gpio_irq_handler); + irq_set_chained_handler_and_data(irq, gpio_irq_handler, + (void *)gpio_irq); } /*--------------------------------------------------------------------------*/ -- cgit v0.10.2 From 4f31dd63e050b777d3f3139197c4b3860aa89301 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:31:10 +0000 Subject: avr32/at32ap: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Acked-by: Hans-Christian Egtvedt Cc: Haavard Skinnemoen Cc: Jiang Liu Cc: Julia Lawall Link: http://lkml.kernel.org/r/20150713100606.448031045@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c index 2d48b6a..d51ff8f 100644 --- a/arch/avr32/mach-at32ap/extint.c +++ b/arch/avr32/mach-at32ap/extint.c @@ -128,9 +128,9 @@ static int eic_set_irq_type(struct irq_data *d, unsigned int flow_type) irqd_set_trigger_type(d, flow_type); if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else - __irq_set_handler_locked(irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); return IRQ_SET_MASK_OK_NOCOPY; } -- cgit v0.10.2 From df6e23ae62d46a524ba3db95a201904a01419bdc Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:31:12 +0000 Subject: avr32/irq: Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc while we already have a pointer to corresponding irq_desc. Signed-off-by: Jiang Liu Acked-by: Hans-Christian Egtvedt Cc: Haavard Skinnemoen Link: http://lkml.kernel.org/r/20150713100606.527106283@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/avr32/mach-at32ap/pio.c b/arch/avr32/mach-at32ap/pio.c index 6c7035a..157a5e0 100644 --- a/arch/avr32/mach-at32ap/pio.c +++ b/arch/avr32/mach-at32ap/pio.c @@ -286,7 +286,7 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) struct pio_device *pio = irq_desc_get_chip_data(desc); unsigned gpio_irq; - gpio_irq = (unsigned) irq_get_handler_data(irq); + gpio_irq = (unsigned) irq_desc_get_handler_data(desc); for (;;) { u32 isr; -- cgit v0.10.2 From aec89ef72ba6c94420f599dcb684ed66937cdacf Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 15 Jul 2015 15:38:28 +0100 Subject: irqchip/gic: Enable SKIP_SET_WAKE and MASK_ON_SUSPEND The GIC controller doesn't provides any facility to configure the wakeup sources. For the same reason, GIC chip implementation can't provide irq_set_wake functionality, but that results in the irqchip core preventing the systems from entering sleep states like "suspend to RAM". The GICv1/v2 controllers support wakeup events. They signal these wakeup events even when CPU interface is disabled which means the wakeup outputs are always enabled with the required logic in always-on domain. An implementation can powerdown the GIC completely, but then the wake-up must be relayed to some control logic within the power controller that acts as wake-up interrupt controller. Setting the IRQCHIP_SKIP_SET_WAKE flags will ensure that the interrupts from GIC can work as wakeup interrupts and resume from suspend-to-{idle, ram}. The wakeup interrupt sources need to use enable_irq_wake() and the irqchip core will then set the IRQD_WAKEUP_STATE flag. Also it's always safer to mask all the non wakeup interrupts are masked at the chip level when suspending. The irqchip infrastructure can handle masking of those interrupts at the chip level. The chip implementation just have to indicate that with IRQCHIP_MASK_ON_SUSPEND. This patch enables IRQCHIP_SKIP_SET_WAKE and IRQCHIP_MASK_ON_SUSPEND so that the irqchip core allows and handles the power managemant wake up modes. Signed-off-by: Sudeep Holla Cc: Marc Zyngier Cc: Simon Horman Cc: Jason Cooper Cc: Michal Simek Cc: Linus Walleij Cc: Magnus Damm Cc: Gregory CLEMENT Cc: Geert Uytterhoeven Cc: Lorenzo Pieralisi Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1436971109-20189-1-git-send-email-sudeep.holla@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index cadd862..39ff8df 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -324,7 +324,9 @@ static struct irq_chip gic_chip = { #endif .irq_get_irqchip_state = gic_irq_get_irqchip_state, .irq_set_irqchip_state = gic_irq_set_irqchip_state, - .flags = IRQCHIP_SET_TYPE_MASKED, + .flags = IRQCHIP_SET_TYPE_MASKED | + IRQCHIP_SKIP_SET_WAKE | + IRQCHIP_MASK_ON_SUSPEND, }; void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index 55c2c10..a0128c7 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -202,7 +202,9 @@ static struct irq_chip hip04_irq_chip = { #ifdef CONFIG_SMP .irq_set_affinity = hip04_irq_set_affinity, #endif - .flags = IRQCHIP_SET_TYPE_MASKED, + .flags = IRQCHIP_SET_TYPE_MASKED | + IRQCHIP_SKIP_SET_WAKE | + IRQCHIP_MASK_ON_SUSPEND, }; static u16 hip04_get_cpumask(struct hip04_irq_data *intc) -- cgit v0.10.2 From 0d3f2c92e004c67404fabea19728c1962b777bd6 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 15 Jul 2015 15:38:29 +0100 Subject: irqchip/gic: Remove redundant gic_set_irqchip_flags Now that the GIC chip implementation enables IRQCHIP_SKIP_SET_WAKE and IRQCHIP_MASK_ON_SUSPEND by default, the platforms requiring them need not override the irqchip flags as before. This patch removes all the users of gic_set_irqchip_flags and the function itself. Signed-off-by: Sudeep Holla Acked-by: Linus Walleij Cc: Marc Zyngier Cc: Simon Horman Cc: Jason Cooper Cc: Michal Simek Cc: Magnus Damm Cc: Gregory CLEMENT Cc: Geert Uytterhoeven Cc: Lorenzo Pieralisi Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1436971109-20189-2-git-send-email-sudeep.holla@arm.com Signed-off-by: Thomas Gleixner diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c index fd63ae6..151a71a 100644 --- a/arch/arm/mach-shmobile/intc-sh73a0.c +++ b/arch/arm/mach-shmobile/intc-sh73a0.c @@ -313,7 +313,6 @@ void __init sh73a0_init_irq(void) void __iomem *gic_cpu_base = IOMEM(0xf0000100); void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE); - gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE); gic_init(0, 29, gic_dist_base, gic_cpu_base); register_intc_controller(&intcs_desc); diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index c03e562..aea5cff 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c @@ -719,7 +719,6 @@ void __init r8a7779_init_irq_dt(void) void __iomem *gic_dist_base = ioremap_nocache(0xf0001000, 0x1000); void __iomem *gic_cpu_base = ioremap_nocache(0xf0000100, 0x1000); #endif - gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE); #ifdef CONFIG_ARCH_SHMOBILE_LEGACY gic_init(0, 29, gic_dist_base, gic_cpu_base); diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index e31d3d6..6cb10c7 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c @@ -56,7 +56,6 @@ void __init ux500_init_irq(void) struct device_node *np; struct resource r; - gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND); irqchip_init(); np = of_find_compatible_node(NULL, NULL, "stericsson,db8500-prcmu"); of_address_to_resource(np, 0, &r); diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 616d584..2ad1acc 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c @@ -186,7 +186,6 @@ static void __init zynq_map_io(void) static void __init zynq_irq_init(void) { - gic_set_irqchip_flags(IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND); irqchip_init(); } diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 39ff8df..80fde37 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -881,11 +881,6 @@ static const struct irq_domain_ops gic_irq_domain_ops = { .xlate = gic_irq_domain_xlate, }; -void gic_set_irqchip_flags(unsigned long flags) -{ - gic_chip.flags |= flags; -} - void __init gic_init_bases(unsigned int gic_nr, int irq_start, void __iomem *dist_base, void __iomem *cpu_base, u32 percpu_offset, struct device_node *node) diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 9de976b..61a2007 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -95,7 +95,6 @@ struct device_node; -void gic_set_irqchip_flags(unsigned long flags); void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *, u32 offset, struct device_node *); void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); -- cgit v0.10.2 From 1ee4fb3ee1e47f2b3c294ded383a3cd9cc2decd4 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 22 Jul 2015 12:43:04 -0700 Subject: genirq: Export irq_[get|set]_irqchip_state() Export these functions to be able to build the Qualcomm family A PMIC gpio and mpp drivers as modules. [ tglx: Made them GPL exports ] Signed-off-by: Bjorn Andersson Reviewed-by: Mark Brown Cc: Marc Zyngier Cc: Cc: Cc: Srinivas Kandagatla Cc: Linus Walleij Link: http://lkml.kernel.org/r/1437594184-22966-1-git-send-email-bjorn.andersson@sonymobile.com Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 886f115..ad1b064 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1877,6 +1877,7 @@ int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, irq_put_desc_busunlock(desc, flags); return err; } +EXPORT_SYMBOL_GPL(irq_get_irqchip_state); /** * irq_set_irqchip_state - set the state of a forwarded interrupt. @@ -1922,3 +1923,4 @@ int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, irq_put_desc_busunlock(desc, flags); return err; } +EXPORT_SYMBOL_GPL(irq_set_irqchip_state); -- cgit v0.10.2 From c376023b7096e76ac4d5526105cf9be8743bead9 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 24 Jul 2015 15:24:45 -0400 Subject: irqchip: Appropriate __init annotation for const data Init data marked const should be annotated with __initconst for correctness and not __initdata. And for those already __initconst, they should be qualified as const at the compiler level too. This also fixes LTO builds that otherwise fail with section mismatch errors. Signed-off-by: Nicolas Pitre Cc: Jason Cooper Link: http://lkml.kernel.org/r/alpine.LFD.2.20.1507241511551.1806@knanqh.ubzr Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c index dbbf30a..8a0c7f2 100644 --- a/drivers/irqchip/irq-atmel-aic.c +++ b/drivers/irqchip/irq-atmel-aic.c @@ -225,7 +225,7 @@ static void __init at91sam9g45_aic_irq_fixup(struct device_node *root) aic_common_rtt_irq_fixup(root); } -static const struct of_device_id __initdata aic_irq_fixups[] = { +static const struct of_device_id aic_irq_fixups[] __initconst = { { .compatible = "atmel,at91rm9200", .data = at91rm9200_aic_irq_fixup }, { .compatible = "atmel,at91sam9g45", .data = at91sam9g45_aic_irq_fixup }, { .compatible = "atmel,at91sam9n12", .data = at91rm9200_aic_irq_fixup }, diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index ff2e832..9da9942 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -290,7 +290,7 @@ static void __init sama5d3_aic_irq_fixup(struct device_node *root) aic_common_rtc_irq_fixup(root); } -static const struct of_device_id __initdata aic5_irq_fixups[] = { +static const struct of_device_id aic5_irq_fixups[] __initconst = { { .compatible = "atmel,sama5d3", .data = sama5d3_aic_irq_fixup }, { .compatible = "atmel,sama5d4", .data = sama5d3_aic_irq_fixup }, { /* sentinel */ }, diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index a36ba96..ca35171 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -75,10 +75,10 @@ #define NR_BANKS 3 #define IRQS_PER_BANK 32 -static int reg_pending[] __initconst = { 0x00, 0x04, 0x08 }; -static int reg_enable[] __initconst = { 0x18, 0x10, 0x14 }; -static int reg_disable[] __initconst = { 0x24, 0x1c, 0x20 }; -static int bank_irqs[] __initconst = { 8, 32, 32 }; +static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 }; +static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 }; +static const int reg_disable[] __initconst = { 0x24, 0x1c, 0x20 }; +static const int bank_irqs[] __initconst = { 8, 32, 32 }; static const int shortcuts[] = { 7, 9, 10, 18, 19, /* Bank 1 */ -- cgit v0.10.2 From be9b22b6a7e6725162c64155a08b71f0654b675c Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 22 Jul 2015 16:21:39 -0700 Subject: genirq: Add chip_[suspend|resume] PM support to irq_chip Some (admittedly odd) irqchips perform functions that are not directly related to any of their child IRQ lines, and therefore need to perform some tasks during suspend/resume regardless of whether there are any "installed" interrupts for the irqchip. However, the current generic-chip framework does not call the chip's irq_{suspend,resume} when there are no interrupts installed (this makes sense, because there are no irq_data objects for such a call to be made). More specifically, irq-bcm7120-l2 configures both a forwarding mask (which affects other top-level GIC IRQs) and a second-level interrupt mask (for managing its own child interrupts). The former must be saved/restored on suspend/resume, even when there's nothing to do for the latter. This patch adds a new set of suspend/resume hooks to irq_chip_generic, to help represent *chip* suspend/resume, rather than IRQ suspend/resume. These callbacks will always be called for an IRQ chip (regardless of the installed interrupts) and are based on the per-chip irq_chip_generic struct, rather than the per-IRQ irq_data struct. The original problem report is described in extra detail here: http://lkml.kernel.org/g/20150619224123.GL4917@ld-irv-0074 Signed-off-by: Brian Norris Tested-by: Florian Fainelli Cc: Gregory Fong Cc: bcm-kernel-feedback-list@broadcom.com Cc: linux-mips@linux-mips.org Cc: Kevin Cernekee Cc: Jason Cooper Link: http://lkml.kernel.org/r/1437607300-40858-1-git-send-email-computersforpeace@gmail.com Signed-off-by: Thomas Gleixner diff --git a/include/linux/irq.h b/include/linux/irq.h index 5284cb1..2c8730a 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -324,8 +324,10 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips * @irq_cpu_online: configure an interrupt source for a secondary CPU * @irq_cpu_offline: un-configure an interrupt source for a secondary CPU - * @irq_suspend: function called from core code on suspend once per chip - * @irq_resume: function called from core code on resume once per chip + * @irq_suspend: function called from core code on suspend once per + * chip, when one or more interrupts are installed + * @irq_resume: function called from core code on resume once per chip, + * when one ore more interrupts are installed * @irq_pm_shutdown: function called from core code on shutdown once per chip * @irq_calc_mask: Optional function to set irq_data.mask for special cases * @irq_print_chip: optional to print special chip info in show_interrupts @@ -760,6 +762,12 @@ struct irq_chip_type { * @reg_base: Register base address (virtual) * @reg_readl: Alternate I/O accessor (defaults to readl if NULL) * @reg_writel: Alternate I/O accessor (defaults to writel if NULL) + * @suspend: Function called from core code on suspend once per + * chip; can be useful instead of irq_chip::suspend to + * handle chip details even when no interrupts are in use + * @resume: Function called from core code on resume once per chip; + * can be useful instead of irq_chip::suspend to handle + * chip details even when no interrupts are in use * @irq_base: Interrupt base nr for this chip * @irq_cnt: Number of interrupts handled by this chip * @mask_cache: Cached mask register shared between all chip types @@ -786,6 +794,8 @@ struct irq_chip_generic { void __iomem *reg_base; u32 (*reg_readl)(void __iomem *addr); void (*reg_writel)(u32 val, void __iomem *addr); + void (*suspend)(struct irq_chip_generic *gc); + void (*resume)(struct irq_chip_generic *gc); unsigned int irq_base; unsigned int irq_cnt; u32 mask_cache; diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 15b370d..abd286a 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -553,6 +553,9 @@ static int irq_gc_suspend(void) if (data) ct->chip.irq_suspend(data); } + + if (gc->suspend) + gc->suspend(gc); } return 0; } @@ -564,6 +567,9 @@ static void irq_gc_resume(void) list_for_each_entry(gc, &gc_list, list) { struct irq_chip_type *ct = gc->chip_types; + if (gc->resume) + gc->resume(gc); + if (ct->chip.irq_resume) { struct irq_data *data = irq_gc_get_irq_data(gc); -- cgit v0.10.2 From fd537766715e9b6bf7ff07abb22f4817201433db Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 22 Jul 2015 16:21:40 -0700 Subject: irqchip/bcm7120-l2: Perform suspend/resume even without installed child IRQs Make use of the new irq_chip_generic suspend/resume callbacks. This is required because if there are no installed child IRQs for this chip, the irq_chip::irq_{suspend,resume} functions will not be called. However, we still need to save/restore the forwarding mask, to enable the top-level GIC interrupt; otherwise, we lose UART output after S3 resume. In addition to refactoring the callbacks, we have to self-initialize the mask cache, since the genirq core also doesn't initialize this until the first child IRQ is installed. The original problem report is described in extra detail here: http://lkml.kernel.org/g/20150619224123.GL4917@ld-irv-0074 Signed-off-by: Brian Norris Tested-by: Florian Fainelli Cc: Gregory Fong Cc: bcm-kernel-feedback-list@broadcom.com Cc: linux-mips@linux-mips.org Cc: Kevin Cernekee Cc: Jason Cooper Link: http://lkml.kernel.org/r/1437607300-40858-2-git-send-email-computersforpeace@gmail.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index 88c9719..c885a5c 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -80,11 +80,10 @@ static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) chained_irq_exit(chip, desc); } -static void bcm7120_l2_intc_suspend(struct irq_data *d) +static void bcm7120_l2_intc_suspend(struct irq_chip_generic *gc) { - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct irq_chip_type *ct = irq_data_get_chip_type(d); struct bcm7120_l2_intc_data *b = gc->private; + struct irq_chip_type *ct = gc->chip_types; irq_gc_lock(gc); if (b->can_wake) @@ -93,10 +92,9 @@ static void bcm7120_l2_intc_suspend(struct irq_data *d) irq_gc_unlock(gc); } -static void bcm7120_l2_intc_resume(struct irq_data *d) +static void bcm7120_l2_intc_resume(struct irq_chip_generic *gc) { - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct irq_chip_type *ct = irq_data_get_chip_type(d); + struct irq_chip_type *ct = gc->chip_types; /* Restore the saved mask */ irq_gc_lock(gc); @@ -279,8 +277,15 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn, ct->chip.irq_mask = irq_gc_mask_clr_bit; ct->chip.irq_unmask = irq_gc_mask_set_bit; ct->chip.irq_ack = irq_gc_noop; - ct->chip.irq_suspend = bcm7120_l2_intc_suspend; - ct->chip.irq_resume = bcm7120_l2_intc_resume; + gc->suspend = bcm7120_l2_intc_suspend; + gc->resume = bcm7120_l2_intc_resume; + + /* + * Initialize mask-cache, in case we need it for + * saving/restoring fwd mask even w/o any child interrupts + * installed + */ + gc->mask_cache = irq_reg_readl(gc, ct->regs.mask); if (data->can_wake) { /* This IRQ chip can wake the system, set all -- cgit v0.10.2 From 0aef3997e12a10d4dfb6e01133e2fe478b9aa5eb Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 23 Jul 2015 15:52:21 -0700 Subject: irqchip/bcm7120-l2: Fix interrupt status for multiple parent IRQs Our irq-bcm7120-l2 interrupt controller driver utilizes the same handler function for the different parent interrupts it services: UPG_MAIN, UPG_BSC for instance. The problem is that function reads the IRQSTAT register which can combine interrupt causes for different parent interrupts, such that we can end-up in the following situation: - CPU takes an interrupt - bcm7120_l2_intc_irq_handle() reads IRQSTAT - generic_handle_irq() is invoked - there are still pending interrupts flagged in IRQSTAT from a different parent - handle_bad_irq() is invoked for these since they come from a different irq_desc/irq In order to fix this, make sure that we always mask IRQSTAT with the appropriate bits that correspond go the parent interrupt source this is coming from. To simplify things, associate an unique structure per parent interrupt handler to avoid multiplying the number of lookups. Fixes: a5042de2688d ("irqchip: bcm7120-l2: Add Broadcom BCM7120-style Level 2 interrupt controller") Signed-off-by: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: cernekee@gmail.com Cc: jason@lakedaemon.net Cc: bcm-kernel-feedback-list@broadcom.com Cc: gregory.0xf0@gmail.com Cc: computersforpeace@gmail.com Link: http://lkml.kernel.org/r/1437691941-3100-1-git-send-email-f.fainelli@gmail.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index c885a5c..d3f9769 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -37,6 +37,11 @@ #define MAX_MAPPINGS (MAX_WORDS * 2) #define IRQS_PER_WORD 32 +struct bcm7120_l1_intc_data { + struct bcm7120_l2_intc_data *b; + u32 irq_map_mask[MAX_WORDS]; +}; + struct bcm7120_l2_intc_data { unsigned int n_words; void __iomem *map_base[MAX_MAPPINGS]; @@ -46,14 +51,15 @@ struct bcm7120_l2_intc_data { struct irq_domain *domain; bool can_wake; u32 irq_fwd_mask[MAX_WORDS]; - u32 irq_map_mask[MAX_WORDS]; + struct bcm7120_l1_intc_data *l1_data; int num_parent_irqs; const __be32 *map_mask_prop; }; static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) { - struct bcm7120_l2_intc_data *b = irq_desc_get_handler_data(desc); + struct bcm7120_l1_intc_data *data = irq_desc_get_handler_data(desc); + struct bcm7120_l2_intc_data *b = data->b; struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int idx; @@ -68,7 +74,8 @@ static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) irq_gc_lock(gc); pending = irq_reg_readl(gc, b->stat_offset[idx]) & - gc->mask_cache; + gc->mask_cache & + data->irq_map_mask[idx]; irq_gc_unlock(gc); for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) { @@ -104,8 +111,9 @@ static void bcm7120_l2_intc_resume(struct irq_chip_generic *gc) static int bcm7120_l2_intc_init_one(struct device_node *dn, struct bcm7120_l2_intc_data *data, - int irq) + int irq, u32 *valid_mask) { + struct bcm7120_l1_intc_data *l1_data = &data->l1_data[irq]; int parent_irq; unsigned int idx; @@ -117,20 +125,28 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, /* For multiple parent IRQs with multiple words, this looks like: * + * + * We need to associate a given parent interrupt with its corresponding + * map_mask in order to mask the status register with it because we + * have the same handler being called for multiple parent interrupts. + * + * This is typically something needed on BCM7xxx (STB chips). */ for (idx = 0; idx < data->n_words; idx++) { if (data->map_mask_prop) { - data->irq_map_mask[idx] |= + l1_data->irq_map_mask[idx] |= be32_to_cpup(data->map_mask_prop + irq * data->n_words + idx); } else { - data->irq_map_mask[idx] = 0xffffffff; + l1_data->irq_map_mask[idx] = 0xffffffff; } + valid_mask[idx] |= l1_data->irq_map_mask[idx]; } - irq_set_chained_handler_and_data(parent_irq, - bcm7120_l2_intc_irq_handle, data); + l1_data->b = data; + irq_set_chained_handler_and_data(parent_irq, + bcm7120_l2_intc_irq_handle, l1_data); return 0; } @@ -211,6 +227,7 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn, struct irq_chip_type *ct; int ret = 0; unsigned int idx, irq, flags; + u32 valid_mask[MAX_WORDS] = { }; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) @@ -223,9 +240,16 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn, goto out_unmap; } + data->l1_data = kcalloc(data->num_parent_irqs, sizeof(*data->l1_data), + GFP_KERNEL); + if (!data->l1_data) { + ret = -ENOMEM; + goto out_free_l1_data; + } + ret = iomap_regs_fn(dn, data); if (ret < 0) - goto out_unmap; + goto out_free_l1_data; for (idx = 0; idx < data->n_words; idx++) { __raw_writel(data->irq_fwd_mask[idx], @@ -234,16 +258,16 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn, } for (irq = 0; irq < data->num_parent_irqs; irq++) { - ret = bcm7120_l2_intc_init_one(dn, data, irq); + ret = bcm7120_l2_intc_init_one(dn, data, irq, valid_mask); if (ret) - goto out_unmap; + goto out_free_l1_data; } data->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * data->n_words, &irq_generic_chip_ops, NULL); if (!data->domain) { ret = -ENOMEM; - goto out_unmap; + goto out_free_l1_data; } /* MIPS chips strapped for BE will automagically configure the @@ -267,7 +291,7 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn, irq = idx * IRQS_PER_WORD; gc = irq_get_domain_generic_chip(data->domain, irq); - gc->unused = 0xffffffff & ~data->irq_map_mask[idx]; + gc->unused = 0xffffffff & ~valid_mask[idx]; gc->private = data; ct = gc->chip_types; @@ -304,6 +328,8 @@ int __init bcm7120_l2_intc_probe(struct device_node *dn, out_free_domain: irq_domain_remove(data->domain); +out_free_l1_data: + kfree(data->l1_data); out_unmap: for (idx = 0; idx < MAX_MAPPINGS; idx++) { if (data->map_base[idx]) -- cgit v0.10.2 From 95e432b91045f5dfa2115f943de4f44f0ea107ba Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:08:38 +0000 Subject: alpha/irq: Use access helper irq_data_get_affinity_mask() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Cc: Matt Turner Link: http://lkml.kernel.org/r/20150713075508.821878421@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index 51f2c86..2804648 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -59,7 +59,7 @@ int irq_select_affinity(unsigned int irq) cpu = (cpu < (NR_CPUS-1) ? cpu + 1 : 0); last_cpu = cpu; - cpumask_copy(data->affinity, cpumask_of(cpu)); + cpumask_copy(irq_data_get_affinity_mask(data), cpumask_of(cpu)); chip->irq_set_affinity(data, cpumask_of(cpu), false); return 0; } -- cgit v0.10.2 From 247bd4f1f11eb683bdb31850b525fb5e893bd49d Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:34:56 +0000 Subject: blackfin/irq: Use access helper irq_data_get_affinity_mask() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Cc: Steven Miao Cc: adi-buildroot-devel@lists.sourceforge.net Link: http://lkml.kernel.org/r/20150713125611.652550580@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index 7236bdf..332a434 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -194,7 +194,8 @@ void bfin_internal_unmask_irq(unsigned int irq) #ifdef CONFIG_SMP static void bfin_internal_unmask_irq_chip(struct irq_data *d) { - bfin_internal_unmask_irq_affinity(d->irq, d->affinity); + bfin_internal_unmask_irq_affinity(d->irq, + irq_data_get_affinity_mask(d)); } static int bfin_internal_set_affinity(struct irq_data *d, -- cgit v0.10.2 From 284384442fd44f6e01a157745b5549602e6a49f4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:34:57 +0000 Subject: blackfin/irq: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and update was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Steven Miao Cc: Jiang Liu Cc: Julia Lawall Cc: adi-buildroot-devel@lists.sourceforge.net Link: http://lkml.kernel.org/r/20150713125611.731615902@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index 332a434..2eaf83a 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -686,12 +686,12 @@ void bfin_demux_mac_status_irq(unsigned int int_err_irq, } #endif -static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle) +static inline void bfin_set_irq_handler(struct irq_data *d, irq_flow_handler_t handle) { #ifdef CONFIG_IPIPE handle = handle_level_irq; #endif - __irq_set_handler_locked(irq, handle); + irq_set_handler_locked(d, handle); } #ifdef CONFIG_GPIO_ADI @@ -803,9 +803,9 @@ static int bfin_gpio_irq_type(struct irq_data *d, unsigned int type) } if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) - bfin_set_irq_handler(irq, handle_edge_irq); + bfin_set_irq_handler(d, handle_edge_irq); else - bfin_set_irq_handler(irq, handle_level_irq); + bfin_set_irq_handler(d, handle_level_irq); return 0; } -- cgit v0.10.2 From bdf76e36765970c64624d32150b656dc6669ddc2 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:38:38 +0000 Subject: C6X/meagmod-pic: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Mark Salter Cc: Aurelien Jacquiot Cc: linux-c6x-dev@linux-c6x.org Cc: Julia Lawall Link: http://lkml.kernel.org/r/20150713130429.697731509@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/c6x/platforms/megamod-pic.c b/arch/c6x/platforms/megamod-pic.c index 74e3371..349bc01 100644 --- a/arch/c6x/platforms/megamod-pic.c +++ b/arch/c6x/platforms/megamod-pic.c @@ -282,8 +282,8 @@ static struct megamod_pic * __init init_megamod_pic(struct device_node *np) soc_writel(~0, &pic->regs->evtmask[i]); soc_writel(~0, &pic->regs->evtclr[i]); - irq_set_handler_data(irq, &cascade_data[i]); - irq_set_chained_handler(irq, megamod_irq_cascade); + irq_set_chained_handler_and_data(irq, megamod_irq_cascade, + &cascade_data[i]); } /* Finally, set up the MUX registers */ -- cgit v0.10.2 From c42574edc0e33227d4ce41ecc0a81a72f37e7ef4 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:42:46 +0000 Subject: ia64/irq: Use access helper irq_data_get_affinity_mask() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Cc: Cc: Tony Luck Cc: Fenghua Yu Link: http://lkml.kernel.org/r/20150713131034.630273860@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index bc9501e..4d2698d 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -838,7 +838,7 @@ iosapic_unregister_intr (unsigned int gsi) if (iosapic_intr_info[irq].count == 0) { #ifdef CONFIG_SMP /* Clear affinity */ - cpumask_setall(irq_get_irq_data(irq)->affinity); + cpumask_setall(irq_get_affinity_mask(irq)); #endif /* Clear the interrupt information */ iosapic_intr_info[irq].dest = 0; diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index 812a1e6..de4fc00 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -67,7 +67,7 @@ static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 }; void set_irq_affinity_info (unsigned int irq, int hwid, int redir) { if (irq < NR_IRQS) { - cpumask_copy(irq_get_irq_data(irq)->affinity, + cpumask_copy(irq_get_affinity_mask(irq), cpumask_of(cpu_logical_id(hwid))); irq_redir[irq] = (char) (redir & 0xff); } @@ -119,8 +119,8 @@ static void migrate_irqs(void) if (irqd_is_per_cpu(data)) continue; - if (cpumask_any_and(data->affinity, cpu_online_mask) - >= nr_cpu_ids) { + if (cpumask_any_and(irq_data_get_affinity_mask(data), + cpu_online_mask) >= nr_cpu_ids) { /* * Save it for phase 2 processing */ diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c index 4d3053e..af4eaec 100644 --- a/arch/ia64/kernel/msi_ia64.c +++ b/arch/ia64/kernel/msi_ia64.c @@ -36,7 +36,7 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata, msg.data = data; pci_write_msi_msg(irq, &msg); - cpumask_copy(idata->affinity, cpumask_of(cpu)); + cpumask_copy(irq_data_get_affinity_mask(idata), cpumask_of(cpu)); return 0; } @@ -148,7 +148,7 @@ static int dmar_msi_set_affinity(struct irq_data *data, msg.address_lo |= MSI_ADDR_DEST_ID_CPU(cpu_physical_id(cpu)); dmar_msi_write(irq, &msg); - cpumask_copy(data->affinity, mask); + cpumask_copy(irq_data_get_affinity_mask(data), mask); return 0; } diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c index 59ba632..fb25065 100644 --- a/arch/ia64/sn/kernel/msi_sn.c +++ b/arch/ia64/sn/kernel/msi_sn.c @@ -206,7 +206,7 @@ static int sn_set_msi_irq_affinity(struct irq_data *data, msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff); pci_write_msi_msg(irq, &msg); - cpumask_copy(data->affinity, cpu_mask); + cpumask_copy(irq_data_get_affinity_mask(data), cpu_mask); return 0; } -- cgit v0.10.2 From 59fb3d58c5284b42d93262a4690291e9c0e78fe6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:42:48 +0000 Subject: ia64/iosapic: Use irq_set_chip_handler_name_locked() __irq_set_chip_handler_name_locked() is about to be replaced. Use irq_set_chip_handler_name_locked() instead. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Tony Luck Cc: Fenghua Yu Link: http://lkml.kernel.org/r/20150713131034.723024979@linutronix.de Signed-off-by: Thomas Gleixner diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c index 4d2698d..d2fae05 100644 --- a/arch/ia64/kernel/iosapic.c +++ b/arch/ia64/kernel/iosapic.c @@ -610,9 +610,9 @@ register_intr (unsigned int gsi, int irq, unsigned char delivery, chip->name, irq_type->name); chip = irq_type; } - __irq_set_chip_handler_name_locked(irq, chip, trigger == IOSAPIC_EDGE ? - handle_edge_irq : handle_level_irq, - NULL); + irq_set_chip_handler_name_locked(irq_get_irq_data(irq), chip, + trigger == IOSAPIC_EDGE ? handle_edge_irq : handle_level_irq, + NULL); return 0; } -- cgit v0.10.2 From cde5c2756832089e35b0c50417cc2858630f2005 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:51:20 +0000 Subject: sh/irq: Use accessor irq_data_get_node() Use accessor irq_data_get_node() to hide struct irq_data implementation detail, so we can move irq_data->node to irq_data_common once all usage sites are fixed. Signed-off-by: Jiang Liu Cc: Simon Horman Cc: Magnus Damm Link: http://lkml.kernel.org/r/20150713151626.519112900@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index eb10ff8..8dc677c 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -227,7 +227,7 @@ void migrate_irqs(void) for_each_active_irq(irq) { struct irq_data *data = irq_get_irq_data(irq); - if (data->node == cpu) { + if (irq_data_get_node(data) == cpu) { unsigned int newcpu = cpumask_any_and(data->affinity, cpu_online_mask); if (newcpu >= nr_cpu_ids) { -- cgit v0.10.2 From d0abe2f3a9a541ded2e30ef7275f057fb7f0335a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:51:22 +0000 Subject: sh/irq: Use irq accessor functions instead of open coded access This is a preparatory patch for refactoring the internals if irq_data. Signed-off-by: Jiang Liu Cc: Simon Horman Cc: Magnus Damm Link: http://lkml.kernel.org/r/20150713151626.616384365@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c index f5f1b82..0f73530 100644 --- a/drivers/sh/intc/virq.c +++ b/drivers/sh/intc/virq.c @@ -83,12 +83,11 @@ EXPORT_SYMBOL_GPL(intc_irq_lookup); static int add_virq_to_pirq(unsigned int irq, unsigned int virq) { - struct intc_virq_list **last, *entry; - struct irq_data *data = irq_get_irq_data(irq); + struct intc_virq_list *entry; + struct intc_virq_list **last = NULL; /* scan for duplicates */ - last = (struct intc_virq_list **)&data->handler_data; - for_each_virq(entry, data->handler_data) { + for_each_virq(entry, irq_get_handler_data(irq)) { if (entry->irq == virq) return 0; last = &entry->next; @@ -102,7 +101,10 @@ static int add_virq_to_pirq(unsigned int irq, unsigned int virq) entry->irq = virq; - *last = entry; + if (last) + *last = entry; + else + irq_set_handler_data(irq, entry); return 0; } -- cgit v0.10.2 From 8b8149df9ce99e02cb2b4655bf20d0ce459b9076 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:51:23 +0000 Subject: sh/irq: Use access helper irq_data_get_affinity_mask() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Cc: Simon Horman Cc: Magnus Damm Link: http://lkml.kernel.org/r/20150713151626.713278346@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 8dc677c..6c0378c 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -228,15 +228,16 @@ void migrate_irqs(void) struct irq_data *data = irq_get_irq_data(irq); if (irq_data_get_node(data) == cpu) { - unsigned int newcpu = cpumask_any_and(data->affinity, + struct cpumask *mask = irq_data_get_affinity_mask(data); + unsigned int newcpu = cpumask_any_and(mask, cpu_online_mask); if (newcpu >= nr_cpu_ids) { pr_info_ratelimited("IRQ%u no longer affine to CPU%u\n", irq, cpu); - cpumask_setall(data->affinity); + cpumask_setall(mask); } - irq_set_affinity(irq, data->affinity); + irq_set_affinity(irq, mask); } } } diff --git a/drivers/sh/intc/chip.c b/drivers/sh/intc/chip.c index 46427b4..358df75 100644 --- a/drivers/sh/intc/chip.c +++ b/drivers/sh/intc/chip.c @@ -22,7 +22,7 @@ void _intc_enable(struct irq_data *data, unsigned long handle) for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_E(handle)); cpu++) { #ifdef CONFIG_SMP - if (!cpumask_test_cpu(cpu, data->affinity)) + if (!cpumask_test_cpu(cpu, irq_data_get_affinity_mask(data))) continue; #endif addr = INTC_REG(d, _INTC_ADDR_E(handle), cpu); @@ -50,7 +50,7 @@ static void intc_disable(struct irq_data *data) for (cpu = 0; cpu < SMP_NR(d, _INTC_ADDR_D(handle)); cpu++) { #ifdef CONFIG_SMP - if (!cpumask_test_cpu(cpu, data->affinity)) + if (!cpumask_test_cpu(cpu, irq_data_get_affinity_mask(data))) continue; #endif addr = INTC_REG(d, _INTC_ADDR_D(handle), cpu); @@ -72,7 +72,7 @@ static int intc_set_affinity(struct irq_data *data, if (!cpumask_intersects(cpumask, cpu_online_mask)) return -1; - cpumask_copy(data->affinity, cpumask); + cpumask_copy(irq_data_get_affinity_mask(data), cpumask); return IRQ_SET_MASK_OK_NOCOPY; } -- cgit v0.10.2 From 8228a048961a93e871779c658eaa801f747e6c1d Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:51:25 +0000 Subject: sh/intc: Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc while we already have a pointer to corresponding irq_desc. Also replace generic_handle_irq with generic_handle_irq_desc() to avoid looking up irq_desc again. Signed-off-by: Jiang Liu Cc: Simon Horman Cc: Magnus Damm Link: http://lkml.kernel.org/r/20150713151626.792845830@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/arch/sh/boards/mach-se/7343/irq.c b/arch/sh/boards/mach-se/7343/irq.c index 1087dba..6f97a8f 100644 --- a/arch/sh/boards/mach-se/7343/irq.c +++ b/arch/sh/boards/mach-se/7343/irq.c @@ -31,7 +31,7 @@ struct irq_domain *se7343_irq_domain; static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc) { - struct irq_data *data = irq_get_irq_data(irq); + struct irq_data *data = irq_desc_get_irq_data(desc); struct irq_chip *chip = irq_data_get_irq_chip(data); unsigned long mask; int bit; diff --git a/arch/sh/boards/mach-se/7722/irq.c b/arch/sh/boards/mach-se/7722/irq.c index 00e6992..60aebd1 100644 --- a/arch/sh/boards/mach-se/7722/irq.c +++ b/arch/sh/boards/mach-se/7722/irq.c @@ -30,7 +30,7 @@ struct irq_domain *se7722_irq_domain; static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc) { - struct irq_data *data = irq_get_irq_data(irq); + struct irq_data *data = irq_desc_get_irq_data(desc); struct irq_chip *chip = irq_data_get_irq_chip(data); unsigned long mask; int bit; diff --git a/arch/sh/boards/mach-x3proto/gpio.c b/arch/sh/boards/mach-x3proto/gpio.c index f035a7a..24555c3 100644 --- a/arch/sh/boards/mach-x3proto/gpio.c +++ b/arch/sh/boards/mach-x3proto/gpio.c @@ -62,7 +62,7 @@ static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct irq_data *data = irq_get_irq_data(irq); + struct irq_data *data = irq_desc_get_irq_data(desc); struct irq_chip *chip = irq_data_get_irq_chip(data); unsigned long mask; int pin; diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c index 156b790..043419d 100644 --- a/drivers/sh/intc/core.c +++ b/drivers/sh/intc/core.c @@ -67,7 +67,7 @@ void intc_set_prio_level(unsigned int irq, unsigned int level) static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc) { - generic_handle_irq((unsigned int)irq_get_handler_data(irq)); + generic_handle_irq((unsigned int)irq_desc_get_handler_data(desc)); } static void __init intc_register_irq(struct intc_desc *desc, diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c index 0f73530..503d95a 100644 --- a/drivers/sh/intc/virq.c +++ b/drivers/sh/intc/virq.c @@ -111,7 +111,7 @@ static int add_virq_to_pirq(unsigned int irq, unsigned int virq) static void intc_virq_handler(unsigned int irq, struct irq_desc *desc) { - struct irq_data *data = irq_get_irq_data(irq); + struct irq_data *data = irq_desc_get_irq_data(desc); struct irq_chip *chip = irq_data_get_irq_chip(data); struct intc_virq_list *entry, *vlist = irq_data_get_irq_handler_data(data); struct intc_desc_int *d = get_intc_desc(irq); @@ -120,12 +120,14 @@ static void intc_virq_handler(unsigned int irq, struct irq_desc *desc) for_each_virq(entry, vlist) { unsigned long addr, handle; + struct irq_desc *vdesc = irq_to_desc(entry->irq); - handle = (unsigned long)irq_get_handler_data(entry->irq); - addr = INTC_REG(d, _INTC_ADDR_E(handle), 0); - - if (intc_reg_fns[_INTC_FN(handle)](addr, handle, 0)) - generic_handle_irq(entry->irq); + if (vdesc) { + handle = (unsigned long)irq_desc_get_handler_data(vdesc); + addr = INTC_REG(d, _INTC_ADDR_E(handle), 0); + if (intc_reg_fns[_INTC_FN(handle)](addr, handle, 0)) + generic_handle_irq_desc(entry->irq, vdesc); + } } chip->irq_unmask(data); -- cgit v0.10.2 From c497615c0cb62ba0b06db9580911dcf6d612bdb9 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:51:26 +0000 Subject: sh/intc: Prepare irq flow handlers for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Simon Horman Cc: Magnus Damm Cc: Julia Lawall Link: http://lkml.kernel.org/r/20150713151626.872605327@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/arch/sh/boards/mach-se/7724/irq.c b/arch/sh/boards/mach-se/7724/irq.c index 5d1d3ec..9f20338 100644 --- a/arch/sh/boards/mach-se/7724/irq.c +++ b/arch/sh/boards/mach-se/7724/irq.c @@ -92,8 +92,9 @@ static struct irq_chip se7724_irq_chip __read_mostly = { .irq_unmask = enable_se7724_irq, }; -static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc) +static void se7724_irq_demux(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct fpga_irq set = get_fpga_irq(irq); unsigned short intv = __raw_readw(set.sraddr); unsigned int ext_irq = set.base; diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c index 503d95a..bafc51c 100644 --- a/drivers/sh/intc/virq.c +++ b/drivers/sh/intc/virq.c @@ -109,8 +109,9 @@ static int add_virq_to_pirq(unsigned int irq, unsigned int virq) return 0; } -static void intc_virq_handler(unsigned int irq, struct irq_desc *desc) +static void intc_virq_handler(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct irq_data *data = irq_desc_get_irq_data(desc); struct irq_chip *chip = irq_data_get_irq_chip(data); struct intc_virq_list *entry, *vlist = irq_data_get_irq_handler_data(data); -- cgit v0.10.2 From fb68ba6d0b06cf287e9081d60f705501c52124f6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:52:24 +0000 Subject: spmi/pmic_arb: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Greg Kroah-Hartman Cc: Jiang Liu Cc: Julia Lawall Link: http://lkml.kernel.org/r/20150713151750.831790045@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index d7119db..db2aac1 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -928,8 +928,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) goto err_put_ctrl; } - irq_set_handler_data(pa->irq, pa); - irq_set_chained_handler(pa->irq, pmic_arb_chained_irq); + irq_set_chained_handler_and_data(pa->irq, pmic_arb_chained_irq, pa); err = spmi_controller_add(ctrl); if (err) @@ -938,8 +937,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) return 0; err_domain_remove: - irq_set_chained_handler(pa->irq, NULL); - irq_set_handler_data(pa->irq, NULL); + irq_set_chained_handler_and_data(pa->irq, NULL, NULL); irq_domain_remove(pa->domain); err_put_ctrl: spmi_controller_put(ctrl); @@ -951,8 +949,7 @@ static int spmi_pmic_arb_remove(struct platform_device *pdev) struct spmi_controller *ctrl = platform_get_drvdata(pdev); struct spmi_pmic_arb_dev *pa = spmi_controller_get_drvdata(ctrl); spmi_controller_remove(ctrl); - irq_set_chained_handler(pa->irq, NULL); - irq_set_handler_data(pa->irq, NULL); + irq_set_chained_handler_and_data(pa->irq, NULL, NULL); irq_domain_remove(pa->domain); spmi_controller_put(ctrl); return 0; -- cgit v0.10.2 From 7fe88f3c00e7bfa44421681640fab3a9fadfef3b Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:52:25 +0000 Subject: spmi/pmic: Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc while we already have a pointer to corresponding irq_desc. Signed-off-by: Jiang Liu Cc: Greg Kroah-Hartman Link: http://lkml.kernel.org/r/20150713151750.915477120@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c index db2aac1..4839484 100644 --- a/drivers/spmi/spmi-pmic-arb.c +++ b/drivers/spmi/spmi-pmic-arb.c @@ -453,8 +453,8 @@ static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid) static void pmic_arb_chained_irq(unsigned int irq, struct irq_desc *desc) { - struct spmi_pmic_arb_dev *pa = irq_get_handler_data(irq); - struct irq_chip *chip = irq_get_chip(irq); + struct spmi_pmic_arb_dev *pa = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); void __iomem *intr = pa->intr; int first = pa->min_apid >> 5; int last = pa->max_apid >> 5; -- cgit v0.10.2 From 1559f3b8d0527e24219149c95b3de5e7b2924828 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:53:10 +0000 Subject: xtensa/irq: Use access helper irq_data_get_affinity_mask() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Cc: Chris Zankel Link: http://lkml.kernel.org/r/20150713172018.264485572@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c index 3eee94f..d7b5a4c8 100644 --- a/arch/xtensa/kernel/irq.c +++ b/arch/xtensa/kernel/irq.c @@ -166,23 +166,25 @@ void migrate_irqs(void) for_each_active_irq(i) { struct irq_data *data = irq_get_irq_data(i); + struct cpumask *mask; unsigned int newcpu; if (irqd_is_per_cpu(data)) continue; - if (!cpumask_test_cpu(cpu, data->affinity)) + mask = irq_data_get_affinity_mask(data); + if (!cpumask_test_cpu(cpu, mask)) continue; - newcpu = cpumask_any_and(data->affinity, cpu_online_mask); + newcpu = cpumask_any_and(mask, cpu_online_mask); if (newcpu >= nr_cpu_ids) { pr_info_ratelimited("IRQ%u no longer affine to CPU%u\n", i, cpu); - cpumask_setall(data->affinity); + cpumask_setall(mask); } - irq_set_affinity(i, data->affinity); + irq_set_affinity(i, mask); } } #endif /* CONFIG_HOTPLUG_CPU */ -- cgit v0.10.2 From 8505a81bb036253213b109baf4178ea6861e2888 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 29 Jul 2015 19:09:36 +0900 Subject: genirq: Use the proper parameter name in kernel doc The following warning is emitted for make xmldocs: Warning(.//kernel/irq/chip.c:1009): No description found for parameter 'vcpu_info' Warning(.//kernel/irq/chip.c:1009): Excess function parameter 'dest' description in 'irq_chip_set_vcpu_affinity_parent' Signed-off-by: Masanari Iida Link: http://lkml.kernel.org/r/1438164576-5945-1-git-send-email-standby24x7@gmail.com Signed-off-by: Thomas Gleixner diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 76f199d..09304a6 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -1003,7 +1003,7 @@ int irq_chip_retrigger_hierarchy(struct irq_data *data) /** * irq_chip_set_vcpu_affinity_parent - Set vcpu affinity on the parent interrupt * @data: Pointer to interrupt specific data - * @dest: The vcpu affinity information + * @vcpu_info: The vcpu affinity information */ int irq_chip_set_vcpu_affinity_parent(struct irq_data *data, void *vcpu_info) { -- cgit v0.10.2 From ad3aedfbb04b3a2af54473cfe31f13953cfe9d84 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:08 +0100 Subject: genirq/irqdomain: Allow irq domain aliasing It is not uncommon (at least with the ARM stuff) to have a piece of hardware that implements different flavours of "interrupts". A typical example of this is the GICv3 ITS, which implements standard PCI/MSI support, but also some form of "generic MSI". So far, the PCI/MSI domain is registered using the ITS device_node, so that irq_find_host can return it. On the contrary, the raw MSI domain is not registered with an device_node, making it impossible to be looked up by another subsystem (obviously, using the same device_node twice would only result in confusion, as it is not defined which one irq_find_host would return). A solution to this is to "type" domains that may be aliasing, and to be able to lookup an device_node that matches a given type. For this, we introduce irq_find_matching_host() as a superset of irq_find_host: struct irq_domain *irq_find_matching_host(struct device_node *node, enum irq_domain_bus_token bus_token); where bus_token is the "type" we want to match the domain against (so far, only DOMAIN_BUS_ANY is defined). This result in some moderately invasive changes on the PPC side (which is the only user of the .match method). This has otherwise no functionnal change. Reviewed-by: Hanjun Guo Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-2-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index ca3a062..11090ab 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -123,7 +123,8 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc *desc) } static int -cpld_pic_host_match(struct irq_domain *h, struct device_node *node) +cpld_pic_host_match(struct irq_domain *h, struct device_node *node, + enum irq_domain_bus_token bus_token) { return cpld_pic_node == node; } diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 3af8324..a15f1ef 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c @@ -222,7 +222,8 @@ void iic_request_IPIs(void) #endif /* CONFIG_SMP */ -static int iic_host_match(struct irq_domain *h, struct device_node *node) +static int iic_host_match(struct irq_domain *h, struct device_node *node, + enum irq_domain_bus_token bus_token) { return of_device_is_compatible(node, "IBM,CBEA-Internal-Interrupt-Controller"); diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c index 4cde8e7..b7866e0 100644 --- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c +++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c @@ -108,7 +108,8 @@ static int flipper_pic_map(struct irq_domain *h, unsigned int virq, return 0; } -static int flipper_pic_match(struct irq_domain *h, struct device_node *np) +static int flipper_pic_match(struct irq_domain *h, struct device_node *np, + enum irq_domain_bus_token bus_token) { return 1; } diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 59cfc9d..6f4f8b0 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -268,7 +268,8 @@ static struct irqaction gatwick_cascade_action = { .name = "cascade", }; -static int pmac_pic_host_match(struct irq_domain *h, struct device_node *node) +static int pmac_pic_host_match(struct irq_domain *h, struct device_node *node, + enum irq_domain_bus_token bus_token) { /* We match all, we don't always have a node anyway */ return 1; diff --git a/arch/powerpc/platforms/powernv/opal-irqchip.c b/arch/powerpc/platforms/powernv/opal-irqchip.c index e2e7d75..2c91ee7 100644 --- a/arch/powerpc/platforms/powernv/opal-irqchip.c +++ b/arch/powerpc/platforms/powernv/opal-irqchip.c @@ -134,7 +134,8 @@ static void opal_handle_irq_work(struct irq_work *work) opal_handle_events(be64_to_cpu(last_outstanding_events)); } -static int opal_event_match(struct irq_domain *h, struct device_node *node) +static int opal_event_match(struct irq_domain *h, struct device_node *node, + enum irq_domain_bus_token bus_token) { return h->of_node == node; } diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index a6c42f3..638c406 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -678,7 +678,8 @@ static int ps3_host_map(struct irq_domain *h, unsigned int virq, return 0; } -static int ps3_host_match(struct irq_domain *h, struct device_node *np) +static int ps3_host_match(struct irq_domain *h, struct device_node *np, + enum irq_domain_bus_token bus_token) { /* Match all */ return 1; diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c index 2d20f10..eca0b00 100644 --- a/arch/powerpc/sysdev/ehv_pic.c +++ b/arch/powerpc/sysdev/ehv_pic.c @@ -177,7 +177,8 @@ unsigned int ehv_pic_get_irq(void) return irq_linear_revmap(global_ehv_pic->irqhost, irq); } -static int ehv_pic_host_match(struct irq_domain *h, struct device_node *node) +static int ehv_pic_host_match(struct irq_domain *h, struct device_node *node, + enum irq_domain_bus_token bus_token) { /* Exact match, unless ehv_pic node is NULL */ return h->of_node == NULL || h->of_node == node; diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index 31c3347..e1a9c2c 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c @@ -162,7 +162,8 @@ static struct resource pic_edgectrl_iores = { .flags = IORESOURCE_BUSY, }; -static int i8259_host_match(struct irq_domain *h, struct device_node *node) +static int i8259_host_match(struct irq_domain *h, struct device_node *node, + enum irq_domain_bus_token bus_token) { return h->of_node == NULL || h->of_node == node; } diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index d78f136..6b2b689 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -671,7 +671,8 @@ static struct irq_chip ipic_edge_irq_chip = { .irq_set_type = ipic_set_irq_type, }; -static int ipic_host_match(struct irq_domain *h, struct device_node *node) +static int ipic_host_match(struct irq_domain *h, struct device_node *node, + enum irq_domain_bus_token bus_token) { /* Exact match, unless ipic node is NULL */ return h->of_node == NULL || h->of_node == node; diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index c8e7333..97a8ae8 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -1007,7 +1007,8 @@ static struct irq_chip mpic_irq_ht_chip = { #endif /* CONFIG_MPIC_U3_HT_IRQS */ -static int mpic_host_match(struct irq_domain *h, struct device_node *node) +static int mpic_host_match(struct irq_domain *h, struct device_node *node, + enum irq_domain_bus_token bus_token) { /* Exact match, unless mpic node is NULL */ return h->of_node == NULL || h->of_node == node; diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 6512cd8..47b352e 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -244,7 +244,8 @@ static struct irq_chip qe_ic_irq_chip = { .irq_mask_ack = qe_ic_mask_irq, }; -static int qe_ic_host_match(struct irq_domain *h, struct device_node *node) +static int qe_ic_host_match(struct irq_domain *h, struct device_node *node, + enum irq_domain_bus_token bus_token) { /* Exact match, unless qe_ic node is NULL */ return h->of_node == NULL || h->of_node == node; diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c index 08c248e..47e43b7 100644 --- a/arch/powerpc/sysdev/xics/xics-common.c +++ b/arch/powerpc/sysdev/xics/xics-common.c @@ -298,7 +298,8 @@ int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask, } #endif /* CONFIG_SMP */ -static int xics_host_match(struct irq_domain *h, struct device_node *node) +static int xics_host_match(struct irq_domain *h, struct device_node *node, + enum irq_domain_bus_token bus_token) { struct ics *ics; diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 744ac0e..91a83ad 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -45,6 +45,17 @@ struct irq_data; /* Number of irqs reserved for a legacy isa controller */ #define NUM_ISA_INTERRUPTS 16 +/* + * Should several domains have the same device node, but serve + * different purposes (for example one domain is for PCI/MSI, and the + * other for wired IRQs), they can be distinguished using a + * bus-specific token. Most domains are expected to only carry + * DOMAIN_BUS_ANY. + */ +enum irq_domain_bus_token { + DOMAIN_BUS_ANY = 0, +}; + /** * struct irq_domain_ops - Methods for irq_domain objects * @match: Match an interrupt controller device node to a host, returns @@ -61,7 +72,8 @@ struct irq_data; * to setup the irq_desc when returning from map(). */ struct irq_domain_ops { - int (*match)(struct irq_domain *d, struct device_node *node); + int (*match)(struct irq_domain *d, struct device_node *node, + enum irq_domain_bus_token bus_token); int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw); void (*unmap)(struct irq_domain *d, unsigned int virq); int (*xlate)(struct irq_domain *d, struct device_node *node, @@ -116,6 +128,7 @@ struct irq_domain { /* Optional data */ struct device_node *of_node; + enum irq_domain_bus_token bus_token; struct irq_domain_chip_generic *gc; #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY struct irq_domain *parent; @@ -161,9 +174,15 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, irq_hw_number_t first_hwirq, const struct irq_domain_ops *ops, void *host_data); -extern struct irq_domain *irq_find_host(struct device_node *node); +extern struct irq_domain *irq_find_matching_host(struct device_node *node, + enum irq_domain_bus_token bus_token); extern void irq_set_default_host(struct irq_domain *host); +static inline struct irq_domain *irq_find_host(struct device_node *node) +{ + return irq_find_matching_host(node, DOMAIN_BUS_ANY); +} + /** * irq_domain_add_linear() - Allocate and register a linear revmap irq_domain. * @of_node: pointer to interrupt controller's device tree node. diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 8c3577f..79baaf8 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -187,10 +187,12 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, EXPORT_SYMBOL_GPL(irq_domain_add_legacy); /** - * irq_find_host() - Locates a domain for a given device node + * irq_find_matching_host() - Locates a domain for a given device node * @node: device-tree node of the interrupt controller + * @bus_token: domain-specific data */ -struct irq_domain *irq_find_host(struct device_node *node) +struct irq_domain *irq_find_matching_host(struct device_node *node, + enum irq_domain_bus_token bus_token) { struct irq_domain *h, *found = NULL; int rc; @@ -199,13 +201,19 @@ struct irq_domain *irq_find_host(struct device_node *node) * it might potentially be set to match all interrupts in * the absence of a device node. This isn't a problem so far * yet though... + * + * bus_token == DOMAIN_BUS_ANY matches any domain, any other + * values must generate an exact match for the domain to be + * selected. */ mutex_lock(&irq_domain_mutex); list_for_each_entry(h, &irq_domain_list, link) { if (h->ops->match) - rc = h->ops->match(h, node); + rc = h->ops->match(h, node, bus_token); else - rc = (h->of_node != NULL) && (h->of_node == node); + rc = ((h->of_node != NULL) && (h->of_node == node) && + ((bus_token == DOMAIN_BUS_ANY) || + (h->bus_token == bus_token))); if (rc) { found = h; @@ -215,7 +223,7 @@ struct irq_domain *irq_find_host(struct device_node *node) mutex_unlock(&irq_domain_mutex); return found; } -EXPORT_SYMBOL_GPL(irq_find_host); +EXPORT_SYMBOL_GPL(irq_find_matching_host); /** * irq_set_default_host() - Set a "default" irq domain -- cgit v0.10.2 From 0380839dc90c53e24ddfa0f17ad909c2ddc345c2 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:09 +0100 Subject: PCI/MSI: Register irq domain with specific token When creating a PCI/MSI domain, tag it with DOMAIN_BUS_PCI_MSI so that it can be looked-up using irq_find_matching_host(). Acked-by: Bjorn Helgaas Reviewed-by: Hanjun Guo Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-3-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index cd4c78c..3aae7c9 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1273,12 +1273,19 @@ struct irq_domain *pci_msi_create_irq_domain(struct device_node *node, struct msi_domain_info *info, struct irq_domain *parent) { + struct irq_domain *domain; + if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) pci_msi_domain_update_dom_ops(info); if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) pci_msi_domain_update_chip_ops(info); - return msi_create_irq_domain(node, info, parent); + domain = msi_create_irq_domain(node, info, parent); + if (!domain) + return NULL; + + domain->bus_token = DOMAIN_BUS_PCI_MSI; + return domain; } /** diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 91a83ad..25e9e66 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -54,6 +54,7 @@ struct irq_data; */ enum irq_domain_bus_token { DOMAIN_BUS_ANY = 0, + DOMAIN_BUS_PCI_MSI, }; /** -- cgit v0.10.2 From f1421db8ca4c110144be97a5997ed83d34685db5 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:10 +0100 Subject: device core: Introduce per-device MSI domain pointer As MSI-type features are creeping into non-PCI devices, it is starting to make sense to give our struct device some form of support for this, by allowing a pointer to an MSI irq domain to be set/retrieved. Reviewed-by: Hanjun Guo Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-4-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/include/linux/device.h b/include/linux/device.h index 3d3139a..50e0005 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -715,6 +715,7 @@ struct device_dma_parameters { * @pins: For device pin management. * See Documentation/pinctrl.txt for details. * @msi_list: Hosts MSI descriptors + * @msi_domain: The generic MSI domain this device is using. * @numa_node: NUMA node this device is close to. * @dma_mask: Dma mask (if dma'ble device). * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all @@ -775,6 +776,9 @@ struct device { struct dev_pm_info power; struct dev_pm_domain *pm_domain; +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN + struct irq_domain *msi_domain; +#endif #ifdef CONFIG_PINCTRL struct dev_pin_info *pins; #endif @@ -865,6 +869,22 @@ static inline void set_dev_node(struct device *dev, int node) } #endif +static inline struct irq_domain *dev_get_msi_domain(const struct device *dev) +{ +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN + return dev->msi_domain; +#else + return NULL; +#endif +} + +static inline void dev_set_msi_domain(struct device *dev, struct irq_domain *d) +{ +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN + dev->msi_domain = d; +#endif +} + static inline void *dev_get_drvdata(const struct device *dev) { return dev->driver_data; -- cgit v0.10.2 From 44aa0c657e3e45795a92addeb0dce7d28d9b0bd2 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:11 +0100 Subject: PCI/MSI: Add hooks to populate the msi_domain field In order to be able to populate the device msi_domain field, add the necessary hooks to propagate the host bridge msi_domain across secondary busses to devices. So far, nobody populates the initial msi_domain. Acked-by: Bjorn Helgaas Reviewed-by: Hanjun Guo Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-5-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cefd636..c03ecbf 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -661,6 +661,32 @@ static void pci_set_bus_speed(struct pci_bus *bus) } } +static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus) +{ + /* + * Any firmware interface that can resolve the msi_domain + * should be called from here. + */ + + return NULL; +} + +static void pci_set_bus_msi_domain(struct pci_bus *bus) +{ + struct irq_domain *d; + + /* + * Either bus is the root, and we must obtain it from the + * firmware, or we inherit it from the bridge device. + */ + if (pci_is_root_bus(bus)) + d = pci_host_bridge_msi_domain(bus); + else + d = dev_get_msi_domain(&bus->self->dev); + + dev_set_msi_domain(&bus->dev, d); +} + static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) { @@ -714,6 +740,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, bridge->subordinate = child; add_dev: + pci_set_bus_msi_domain(child); ret = device_register(&child->dev); WARN_ON(ret < 0); @@ -1544,6 +1571,17 @@ static void pci_init_capabilities(struct pci_dev *dev) pci_enable_acs(dev); } +static void pci_set_msi_domain(struct pci_dev *dev) +{ + /* + * If no domain has been set through the pcibios_add_device + * callback, inherit the default from the bus device. + */ + if (!dev_get_msi_domain(&dev->dev)) + dev_set_msi_domain(&dev->dev, + dev_get_msi_domain(&dev->bus->dev)); +} + void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) { int ret; @@ -1585,6 +1623,9 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) ret = pcibios_add_device(dev); WARN_ON(ret < 0); + /* Setup MSI irq domain */ + pci_set_msi_domain(dev); + /* Notifier could use PCI capabilities */ dev->match_driver = false; ret = device_add(&dev->dev); @@ -1975,6 +2016,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, b->bridge = get_device(&bridge->dev); device_enable_async_suspend(b->bridge); pci_set_bus_of_node(b); + pci_set_bus_msi_domain(b); if (!parent) set_dev_node(b->bridge, pcibus_to_node(b)); -- cgit v0.10.2 From b165e2b60b39888a7ff8efbc1de40137471dda41 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:12 +0100 Subject: PCI/MSI: Add support for OF-provided msi_domain In order to populate the PCI host bridge msi_domain, use the "msi-parent" attribute to lookup a corresponding irq domain. If found, this is our MSI domain. This gets plugged into the core PCI code. Acked-by: Bjorn Helgaas Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-6-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/of.c b/drivers/pci/of.c index f092993..85844d8 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -9,6 +9,7 @@ * 2 of the License, or (at your option) any later version. */ +#include #include #include #include @@ -59,3 +60,27 @@ struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus) return of_node_get(bus->bridge->parent->of_node); return NULL; } + +struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus) +{ +#ifdef CONFIG_IRQ_DOMAIN + struct device_node *np; + struct irq_domain *d; + + if (!bus->dev.of_node) + return NULL; + + /* Start looking for a phandle to an MSI controller. */ + np = of_parse_phandle(bus->dev.of_node, "msi-parent", 0); + if (!np) + return NULL; + + d = irq_find_matching_host(np, DOMAIN_BUS_PCI_MSI); + if (d) + return d; + + return irq_find_host(np); +#else + return NULL; +#endif +} diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c03ecbf..a7afeac 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -663,12 +663,15 @@ static void pci_set_bus_speed(struct pci_bus *bus) static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus) { + struct irq_domain *d; + /* * Any firmware interface that can resolve the msi_domain * should be called from here. */ + d = pci_host_bridge_of_msi_domain(bus); - return NULL; + return d; } static void pci_set_bus_msi_domain(struct pci_bus *bus) diff --git a/include/linux/pci.h b/include/linux/pci.h index fbf245f..772616d 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1841,10 +1841,12 @@ int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off, /* PCI <-> OF binding helpers */ #ifdef CONFIG_OF struct device_node; +struct irq_domain; void pci_set_of_node(struct pci_dev *dev); void pci_release_of_node(struct pci_dev *dev); void pci_set_bus_of_node(struct pci_bus *bus); void pci_release_bus_of_node(struct pci_bus *bus); +struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus); /* Arch may override this (weak) */ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus); @@ -1867,6 +1869,8 @@ static inline void pci_set_bus_of_node(struct pci_bus *bus) { } static inline void pci_release_bus_of_node(struct pci_bus *bus) { } static inline struct device_node * pci_device_to_OF_node(const struct pci_dev *pdev) { return NULL; } +static inline struct irq_domain * +pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; } #endif /* CONFIG_OF */ #ifdef CONFIG_EEH -- cgit v0.10.2 From 471c931cb248ab7af0cd62503d811239b47f217b Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:13 +0100 Subject: PCI/MSI: Allow msi_domain lookup using the host bridge node A number of platforms do not need to use the msi-parent property, as the host bridge itself provides the MSI controller. Allow this configuration by performing an irq domain lookup based on the host bridge node if it doesn't have a valid msi-parent property. Acked-by: Bjorn Helgaas Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-7-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 85844d8..2e99a50 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -72,8 +72,13 @@ struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus) /* Start looking for a phandle to an MSI controller. */ np = of_parse_phandle(bus->dev.of_node, "msi-parent", 0); + + /* + * If we don't have an msi-parent property, look for a domain + * directly attached to the host bridge. + */ if (!np) - return NULL; + np = bus->dev.of_node; d = irq_find_matching_host(np, DOMAIN_BUS_PCI_MSI); if (d) -- cgit v0.10.2 From d8a1cb7575502d2be502a65ecb344ff05c8d9f44 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:14 +0100 Subject: PCI/MSI: Let pci_msi_get_domain use struct device::msi_domain Now that we can easily find which MSI domain a PCI device is using, use dev_get_msi_domain as a way to retrieve the information. The original code is still used as a fallback. Acked-by: Bjorn Helgaas Reviewed-by: Hanjun Guo Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-8-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 3aae7c9..4603344 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -39,14 +39,16 @@ struct irq_domain * __weak arch_get_pci_msi_domain(struct pci_dev *dev) static struct irq_domain *pci_msi_get_domain(struct pci_dev *dev) { - struct irq_domain *domain = NULL; + struct irq_domain *domain; - if (dev->bus->msi) - domain = dev->bus->msi->domain; - if (!domain) - domain = arch_get_pci_msi_domain(dev); + domain = dev_get_msi_domain(&dev->dev); + if (domain) + return domain; - return domain; + if (dev->bus->msi && (domain = dev->bus->msi->domain)) + return domain; + + return arch_get_pci_msi_domain(dev); } static int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) -- cgit v0.10.2 From c706c239af5bc297b5fbf1adc715632e1c222f7a Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:15 +0100 Subject: of/platform: Assign MSI domain to platform device As for PCI, we're able to populate the msi_domain field at probe time, provided that the device tree has an "msi-parent" property. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-9-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 3cf7a01..2956d72 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -18,6 +18,7 @@ * driver. */ +#include #include #include #include @@ -576,3 +577,23 @@ err: kfree(desc); } } + +/** + * of_msi_configure - Set the msi_domain field of a device + * @dev: device structure to associate with an MSI irq domain + * @np: device node for that device + */ +void of_msi_configure(struct device *dev, struct device_node *np) +{ + struct device_node *msi_np; + struct irq_domain *d; + + msi_np = of_parse_phandle(np, "msi-parent", 0); + if (!msi_np) + return; + + d = irq_find_matching_host(msi_np, DOMAIN_BUS_PLATFORM_MSI); + if (!d) + d = irq_find_host(msi_np); + dev_set_msi_domain(dev, d); +} diff --git a/drivers/of/platform.c b/drivers/of/platform.c index ddf8e42..8a002d6 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -184,6 +184,7 @@ static struct platform_device *of_platform_device_create_pdata( dev->dev.bus = &platform_bus_type; dev->dev.platform_data = platform_data; of_dma_configure(&dev->dev, dev->dev.of_node); + of_msi_configure(&dev->dev, dev->dev.of_node); if (of_device_add(dev) != 0) { of_dma_deconfigure(&dev->dev); diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 25e9e66..b4a74f7 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -55,6 +55,7 @@ struct irq_data; enum irq_domain_bus_token { DOMAIN_BUS_ANY = 0, DOMAIN_BUS_PCI_MSI, + DOMAIN_BUS_PLATFORM_MSI, }; /** diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index d884929..4bcbd58 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -74,6 +74,7 @@ static inline int of_irq_to_resource_table(struct device_node *dev, */ extern unsigned int irq_of_parse_and_map(struct device_node *node, int index); extern struct device_node *of_irq_find_parent(struct device_node *child); +extern void of_msi_configure(struct device *dev, struct device_node *np); #else /* !CONFIG_OF */ static inline unsigned int irq_of_parse_and_map(struct device_node *dev, -- cgit v0.10.2 From c09fcc4b2b48d58d769a8cff5041533535ece449 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:16 +0100 Subject: drivers/base: Add MSI domain support for non-PCI devices With the msi_list and the msi_domain properties now being at the generic device level, it is starting to be relatively easy to offer a generic way of providing non-PCI MSIs. The two major hurdles with this idea are: - Lack of global ID that identifies a device: this is worked around by having a global ID allocator for each device that gets enrolled in the platform MSI subsystem - Lack of standard way to write the message in the generating device. This is solved by mandating driver code to provide a write_msg callback, so that everyone can have their own square wheel Apart from that, the API is fairly straightforward: - platform_msi_create_irq_domain creates an MSI domain that gets tagged with DOMAIN_BUS_PLATFORM_MSI - platform_msi_domain_alloc_irqs allocate MSIs for a given device, populating the msi_list - platform_msi_domain_free_irqs does what is written on the tin [ tglx: Created a seperate struct platform_msi_desc and added kerneldoc entries ] Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-10-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 527d291..6b2a84e 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_REGMAP) += regmap/ obj-$(CONFIG_SOC_BUS) += soc.o obj-$(CONFIG_PINCTRL) += pinctrl.o obj-$(CONFIG_DEV_COREDUMP) += devcoredump.o +obj-$(CONFIG_GENERIC_MSI_IRQ_DOMAIN) += platform-msi.o ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c new file mode 100644 index 0000000..1857a5d --- /dev/null +++ b/drivers/base/platform-msi.c @@ -0,0 +1,282 @@ +/* + * MSI framework for platform devices + * + * Copyright (C) 2015 ARM Limited, All Rights Reserved. + * Author: Marc Zyngier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#define DEV_ID_SHIFT 24 + +/* + * Internal data structure containing a (made up, but unique) devid + * and the callback to write the MSI message. + */ +struct platform_msi_priv_data { + irq_write_msi_msg_t write_msg; + int devid; +}; + +/* The devid allocator */ +static DEFINE_IDA(platform_msi_devid_ida); + +#ifdef GENERIC_MSI_DOMAIN_OPS +/* + * Convert an msi_desc to a globaly unique identifier (per-device + * devid + msi_desc position in the msi_list). + */ +static irq_hw_number_t platform_msi_calc_hwirq(struct msi_desc *desc) +{ + u32 devid; + + devid = desc->platform.msi_priv_data->devid; + + return (devid << (32 - DEV_ID_SHIFT)) | desc->platform.msi_index; +} + +static void platform_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) +{ + arg->desc = desc; + arg->hwirq = platform_msi_calc_hwirq(desc); +} + +static int platform_msi_init(struct irq_domain *domain, + struct msi_domain_info *info, + unsigned int virq, irq_hw_number_t hwirq, + msi_alloc_info_t *arg) +{ + struct irq_data *data; + + irq_domain_set_hwirq_and_chip(domain, virq, hwirq, + info->chip, info->chip_data); + + /* + * Save the MSI descriptor in handler_data so that the + * irq_write_msi_msg callback can retrieve it (and the + * associated device). + */ + data = irq_domain_get_irq_data(domain, virq); + data->handler_data = arg->desc; + + return 0; +} +#else +#define platform_msi_set_desc NULL +#define platform_msi_init NULL +#endif + +static void platform_msi_update_dom_ops(struct msi_domain_info *info) +{ + struct msi_domain_ops *ops = info->ops; + + BUG_ON(!ops); + + if (ops->msi_init == NULL) + ops->msi_init = platform_msi_init; + if (ops->set_desc == NULL) + ops->set_desc = platform_msi_set_desc; +} + +static void platform_msi_write_msg(struct irq_data *data, struct msi_msg *msg) +{ + struct msi_desc *desc = irq_data_get_irq_handler_data(data); + struct platform_msi_priv_data *priv_data; + + priv_data = desc->platform.msi_priv_data; + + priv_data->write_msg(desc, msg); +} + +static void platform_msi_update_chip_ops(struct msi_domain_info *info) +{ + struct irq_chip *chip = info->chip; + + BUG_ON(!chip); + if (!chip->irq_mask) + chip->irq_mask = irq_chip_mask_parent; + if (!chip->irq_unmask) + chip->irq_unmask = irq_chip_unmask_parent; + if (!chip->irq_eoi) + chip->irq_eoi = irq_chip_eoi_parent; + if (!chip->irq_set_affinity) + chip->irq_set_affinity = msi_domain_set_affinity; + if (!chip->irq_write_msi_msg) + chip->irq_write_msi_msg = platform_msi_write_msg; +} + +static void platform_msi_free_descs(struct device *dev) +{ + struct msi_desc *desc, *tmp; + + list_for_each_entry_safe(desc, tmp, dev_to_msi_list(dev), list) { + list_del(&desc->list); + free_msi_entry(desc); + } +} + +static int platform_msi_alloc_descs(struct device *dev, int nvec, + struct platform_msi_priv_data *data) + +{ + int i; + + for (i = 0; i < nvec; i++) { + struct msi_desc *desc; + + desc = alloc_msi_entry(dev); + if (!desc) + break; + + desc->platform.msi_priv_data = data; + desc->platform.msi_index = i; + desc->nvec_used = 1; + + list_add_tail(&desc->list, dev_to_msi_list(dev)); + } + + if (i != nvec) { + /* Clean up the mess */ + platform_msi_free_descs(dev); + + return -ENOMEM; + } + + return 0; +} + +/** + * platform_msi_create_irq_domain - Create a platform MSI interrupt domain + * @np: Optional device-tree node of the interrupt controller + * @info: MSI domain info + * @parent: Parent irq domain + * + * Updates the domain and chip ops and creates a platform MSI + * interrupt domain. + * + * Returns: + * A domain pointer or NULL in case of failure. + */ +struct irq_domain *platform_msi_create_irq_domain(struct device_node *np, + struct msi_domain_info *info, + struct irq_domain *parent) +{ + struct irq_domain *domain; + + if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS) + platform_msi_update_dom_ops(info); + if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) + platform_msi_update_chip_ops(info); + + domain = msi_create_irq_domain(np, info, parent); + if (domain) + domain->bus_token = DOMAIN_BUS_PLATFORM_MSI; + + return domain; +} + +/** + * platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @dev + * @dev: The device for which to allocate interrupts + * @nvec: The number of interrupts to allocate + * @write_msi_msg: Callback to write an interrupt message for @dev + * + * Returns: + * Zero for success, or an error code in case of failure + */ +int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, + irq_write_msi_msg_t write_msi_msg) +{ + struct platform_msi_priv_data *priv_data; + int err; + + /* + * Limit the number of interrupts to 256 per device. Should we + * need to bump this up, DEV_ID_SHIFT should be adjusted + * accordingly (which would impact the max number of MSI + * capable devices). + */ + if (!dev->msi_domain || !write_msi_msg || !nvec || + nvec > (1 << (32 - DEV_ID_SHIFT))) + return -EINVAL; + + if (dev->msi_domain->bus_token != DOMAIN_BUS_PLATFORM_MSI) { + dev_err(dev, "Incompatible msi_domain, giving up\n"); + return -EINVAL; + } + + /* Already had a helping of MSI? Greed... */ + if (!list_empty(dev_to_msi_list(dev))) + return -EBUSY; + + priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL); + if (!priv_data) + return -ENOMEM; + + priv_data->devid = ida_simple_get(&platform_msi_devid_ida, + 0, 1 << DEV_ID_SHIFT, GFP_KERNEL); + if (priv_data->devid < 0) { + err = priv_data->devid; + goto out_free_data; + } + + priv_data->write_msg = write_msi_msg; + + err = platform_msi_alloc_descs(dev, nvec, priv_data); + if (err) + goto out_free_id; + + err = msi_domain_alloc_irqs(dev->msi_domain, dev, nvec); + if (err) + goto out_free_desc; + + return 0; + +out_free_desc: + platform_msi_free_descs(dev); +out_free_id: + ida_simple_remove(&platform_msi_devid_ida, priv_data->devid); +out_free_data: + kfree(priv_data); + + return err; +} + +/** + * platform_msi_domain_free_irqs - Free MSI interrupts for @dev + * @dev: The device for which to free interrupts + */ +void platform_msi_domain_free_irqs(struct device *dev) +{ + struct msi_desc *desc; + + desc = first_msi_entry(dev); + if (desc) { + struct platform_msi_priv_data *data; + + data = desc->platform.msi_priv_data; + + ida_simple_remove(&platform_msi_devid_ida, data->devid); + kfree(data); + } + + msi_domain_free_irqs(dev->msi_domain, dev); + platform_msi_free_descs(dev); +} diff --git a/include/linux/msi.h b/include/linux/msi.h index f83c87e..809b749 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -15,9 +15,23 @@ extern int pci_msi_ignore_mask; struct irq_data; struct msi_desc; struct pci_dev; +struct platform_msi_priv_data; void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg); void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg); +typedef void (*irq_write_msi_msg_t)(struct msi_desc *desc, + struct msi_msg *msg); + +/** + * platform_msi_desc - Platform device specific msi descriptor data + * @msi_priv_data: Pointer to platform private data + * @msi_index: The index of the MSI descriptor for multi MSI + */ +struct platform_msi_desc { + struct platform_msi_priv_data *msi_priv_data; + u16 msi_index; +}; + /** * struct msi_desc - Descriptor structure for MSI based interrupts * @list: List head for management @@ -36,6 +50,7 @@ void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg); * @default_irq:[PCI MSI/X] The default pre-assigned non-MSI irq * @mask_pos: [PCI MSI] Mask register position * @mask_base: [PCI MSI-X] Mask register base address + * @platform: [platform] Platform device specific msi descriptor data */ struct msi_desc { /* Shared device/bus type independent data */ @@ -71,6 +86,7 @@ struct msi_desc { * anonymous for now as it would require an immediate * tree wide cleanup. */ + struct platform_msi_desc platform; }; }; @@ -257,6 +273,12 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev); struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain); +struct irq_domain *platform_msi_create_irq_domain(struct device_node *np, + struct msi_domain_info *info, + struct irq_domain *parent); +int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, + irq_write_msi_msg_t write_msi_msg); +void platform_msi_domain_free_irqs(struct device *dev); #endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */ #ifdef CONFIG_PCI_MSI_IRQ_DOMAIN -- cgit v0.10.2 From a5716070d88cba1a0a8a18fea809ea6e3374e276 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:17 +0100 Subject: genirq: Add DOMAIN_BUS_NEXUS irqdomain property Some IRQ domains are not designed to directly provide interrupts to devices, but strictly to be used by other domains. An example of this is the GICv3 ITS, which is completely bus agnostic, and on which it is possible to implement a PCI/MSI domain. Just introduce the irq_domain_bus_token property for now. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-11-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index b4a74f7..d3ca792 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -56,6 +56,7 @@ enum irq_domain_bus_token { DOMAIN_BUS_ANY = 0, DOMAIN_BUS_PCI_MSI, DOMAIN_BUS_PLATFORM_MSI, + DOMAIN_BUS_NEXUS, }; /** -- cgit v0.10.2 From f130420e51df30891b55efcef24f5358b2fc2b97 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:18 +0100 Subject: irqchip/gicv3-its: Split PCI/MSI code from the core ITS driver It is becoming obvious that having the PCI/MSI code in the same file as the the core ITS code is giving people implementing non-PCI MSI support the wrong kind of idea. In order to make things a bit clearer, let's move the PCI/MSI code out to its own file. Hopefully it will make it clear that whoever thinks of hooking into the core ITS better have a very strong point. We use a temporary entry point that will get removed in a subsequent patch, once the proper infrastructure is added. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-12-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index b8d4e96..0d5f2a9 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o -obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o +obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o obj-$(CONFIG_ARM_NVIC) += irq-nvic.o obj-$(CONFIG_ARM_VIC) += irq-vic.o obj-$(CONFIG_ATMEL_AIC_IRQ) += irq-atmel-aic-common.o irq-atmel-aic.o diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c new file mode 100644 index 0000000..7614721 --- /dev/null +++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2013-2015 ARM Limited, All Rights Reserved. + * Author: Marc Zyngier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +#include + +static void its_mask_msi_irq(struct irq_data *d) +{ + pci_msi_mask_irq(d); + irq_chip_mask_parent(d); +} + +static void its_unmask_msi_irq(struct irq_data *d) +{ + pci_msi_unmask_irq(d); + irq_chip_unmask_parent(d); +} + +static struct irq_chip its_msi_irq_chip = { + .name = "ITS-MSI", + .irq_unmask = its_unmask_msi_irq, + .irq_mask = its_mask_msi_irq, + .irq_eoi = irq_chip_eoi_parent, + .irq_write_msi_msg = pci_msi_domain_write_msg, +}; + +struct its_pci_alias { + struct pci_dev *pdev; + u32 dev_id; + u32 count; +}; + +static int its_pci_msi_vec_count(struct pci_dev *pdev) +{ + int msi, msix; + + msi = max(pci_msi_vec_count(pdev), 0); + msix = max(pci_msix_vec_count(pdev), 0); + + return max(msi, msix); +} + +static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data) +{ + struct its_pci_alias *dev_alias = data; + + dev_alias->dev_id = alias; + if (pdev != dev_alias->pdev) + dev_alias->count += its_pci_msi_vec_count(dev_alias->pdev); + + return 0; +} + +static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, + int nvec, msi_alloc_info_t *info) +{ + struct pci_dev *pdev; + struct its_pci_alias dev_alias; + + if (!dev_is_pci(dev)) + return -EINVAL; + + pdev = to_pci_dev(dev); + dev_alias.pdev = pdev; + dev_alias.count = nvec; + + pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias); + + return its_msi_prepare(domain, dev_alias.dev_id, dev_alias.count, info); +} + +static struct msi_domain_ops its_pci_msi_ops = { + .msi_prepare = its_pci_msi_prepare, +}; + +static struct msi_domain_info its_pci_msi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | + MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), + .ops = &its_pci_msi_ops, + .chip = &its_msi_irq_chip, +}; + +struct irq_domain *its_pci_msi_alloc_domain(struct device_node *np, + struct irq_domain *parent) +{ + return pci_msi_create_irq_domain(np, &its_pci_msi_domain_info, parent); +} diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 1df956a..7f995d8 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -642,26 +642,6 @@ static struct irq_chip its_irq_chip = { .irq_compose_msi_msg = its_irq_compose_msi_msg, }; -static void its_mask_msi_irq(struct irq_data *d) -{ - pci_msi_mask_irq(d); - irq_chip_mask_parent(d); -} - -static void its_unmask_msi_irq(struct irq_data *d) -{ - pci_msi_unmask_irq(d); - irq_chip_unmask_parent(d); -} - -static struct irq_chip its_msi_irq_chip = { - .name = "ITS-MSI", - .irq_unmask = its_unmask_msi_irq, - .irq_mask = its_mask_msi_irq, - .irq_eoi = irq_chip_eoi_parent, - .irq_write_msi_msg = pci_msi_domain_write_msg, -}; - /* * How we allocate LPIs: * @@ -1208,85 +1188,34 @@ static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq) return 0; } -struct its_pci_alias { - struct pci_dev *pdev; - u32 dev_id; - u32 count; -}; - -static int its_pci_msi_vec_count(struct pci_dev *pdev) -{ - int msi, msix; - - msi = max(pci_msi_vec_count(pdev), 0); - msix = max(pci_msix_vec_count(pdev), 0); - - return max(msi, msix); -} - -static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data) +int its_msi_prepare(struct irq_domain *domain, u32 dev_id, + int nvec, msi_alloc_info_t *info) { - struct its_pci_alias *dev_alias = data; - - dev_alias->dev_id = alias; - if (pdev != dev_alias->pdev) - dev_alias->count += its_pci_msi_vec_count(dev_alias->pdev); - - return 0; -} - -static int its_msi_prepare(struct irq_domain *domain, struct device *dev, - int nvec, msi_alloc_info_t *info) -{ - struct pci_dev *pdev; struct its_node *its; struct its_device *its_dev; - struct its_pci_alias dev_alias; - - if (!dev_is_pci(dev)) - return -EINVAL; - - pdev = to_pci_dev(dev); - dev_alias.pdev = pdev; - dev_alias.count = nvec; - pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias); its = domain->parent->host_data; - - its_dev = its_find_device(its, dev_alias.dev_id); + its_dev = its_find_device(its, dev_id); if (its_dev) { /* * We already have seen this ID, probably through * another alias (PCI bridge of some sort). No need to * create the device. */ - dev_dbg(dev, "Reusing ITT for devID %x\n", dev_alias.dev_id); + pr_debug("Reusing ITT for devID %x\n", dev_id); goto out; } - its_dev = its_create_device(its, dev_alias.dev_id, dev_alias.count); + its_dev = its_create_device(its, dev_id, nvec); if (!its_dev) return -ENOMEM; - dev_dbg(&pdev->dev, "ITT %d entries, %d bits\n", - dev_alias.count, ilog2(dev_alias.count)); + pr_debug("ITT %d entries, %d bits\n", nvec, ilog2(nvec)); out: info->scratchpad[0].ptr = its_dev; - info->scratchpad[1].ptr = dev; return 0; } -static struct msi_domain_ops its_pci_msi_ops = { - .msi_prepare = its_msi_prepare, -}; - -static struct msi_domain_info its_pci_msi_domain_info = { - .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | - MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX), - .ops = &its_pci_msi_ops, - .chip = &its_msi_irq_chip, -}; - static int its_irq_gic_domain_alloc(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq) @@ -1322,9 +1251,9 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq, &its_irq_chip, its_dev); - dev_dbg(info->scratchpad[1].ptr, "ID:%d pID:%d vID:%d\n", - (int)(hwirq - its_dev->event_map.lpi_base), - (int)hwirq, virq + i); + pr_debug("ID:%d pID:%d vID:%d\n", + (int)(hwirq - its_dev->event_map.lpi_base), + (int) hwirq, virq + i); } return 0; @@ -1523,9 +1452,8 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) its->domain->parent = parent; - its->msi_chip.domain = pci_msi_create_irq_domain(node, - &its_pci_msi_domain_info, - its->domain); + its->msi_chip.domain = its_pci_msi_alloc_domain(node, + its->domain); if (!its->msi_chip.domain) { err = -ENOMEM; goto out_free_domains; diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index ffbc034..d6149ba 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -360,6 +360,7 @@ #ifndef __ASSEMBLY__ #include +#include /* * We need a value to serve as a irq-type for LPIs. Choose one that will @@ -388,6 +389,11 @@ struct irq_domain; int its_cpu_init(void); int its_init(struct device_node *node, struct rdists *rdists, struct irq_domain *domain); +int its_msi_prepare(struct irq_domain *domain, u32 dev_id, + int nvec, msi_alloc_info_t *info); + +struct irq_domain *its_pci_msi_alloc_domain(struct device_node *node, + struct irq_domain *parent); #endif -- cgit v0.10.2 From e55dcd4d8b8b82e4ecef2937c6d1dde7ba82916b Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:19 +0100 Subject: irqchip/gicv3-its: Register irq domain with NEXUS token Now that we can distinguish between multiple domains carrying the same device_node, tag the raw ITS domain with DOMAIN_BUS_NEXUS. This will allow MSI providers built on top of the raw ITS domain to identify it. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-13-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 7f995d8..58dc70e 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -1444,13 +1444,14 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); if (of_property_read_bool(its->msi_chip.of_node, "msi-controller")) { - its->domain = irq_domain_add_tree(NULL, &its_domain_ops, its); + its->domain = irq_domain_add_tree(node, &its_domain_ops, its); if (!its->domain) { err = -ENOMEM; goto out_free_tables; } its->domain->parent = parent; + its->domain->bus_token = DOMAIN_BUS_NEXUS; its->msi_chip.domain = its_pci_msi_alloc_domain(node, its->domain); -- cgit v0.10.2 From 841514ab41ced765158d71d818b1d564ebe9436d Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:20 +0100 Subject: irqchip/gicv3-its: Get rid of struct msi_controller The GICv3 ITS only uses the msi_controller structure as a way to match the host bridge with its MSI HW, and thus the msi_domain. But now that we can directly associate an msi_domain with a device, there is no use keeping this msi_controller around. Just remove all traces of msi_controller from the driver. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-14-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 58dc70e..dc4fbbf 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -53,13 +53,12 @@ struct its_collection { /* * The ITS structure - contains most of the infrastructure, with the - * msi_controller, the command queue, the collections, and the list of - * devices writing to it. + * top-level MSI domain, the command queue, the collections, and the + * list of devices writing to it. */ struct its_node { raw_spinlock_t lock; struct list_head entry; - struct msi_controller msi_chip; struct irq_domain *domain; void __iomem *base; unsigned long phys_base; @@ -810,7 +809,7 @@ static void its_free_tables(struct its_node *its) } } -static int its_alloc_tables(struct its_node *its) +static int its_alloc_tables(const char *node_name, struct its_node *its) { int err; int i; @@ -853,7 +852,7 @@ static int its_alloc_tables(struct its_node *its) if (order >= MAX_ORDER) { order = MAX_ORDER - 1; pr_warn("%s: Device Table too large, reduce its page order to %u\n", - its->msi_chip.of_node->full_name, order); + node_name, order); } } @@ -923,7 +922,7 @@ retry_baser: if (val != tmp) { pr_err("ITS: %s: GITS_BASER%d doesn't stick: %lx %lx\n", - its->msi_chip.of_node->full_name, i, + node_name, i, (unsigned long) val, (unsigned long) tmp); err = -ENXIO; goto out_free; @@ -1354,6 +1353,7 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) struct resource res; struct its_node *its; void __iomem *its_base; + struct irq_domain *inner_domain = NULL; u32 val; u64 baser, tmp; int err; @@ -1397,7 +1397,6 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) INIT_LIST_HEAD(&its->its_device_list); its->base = its_base; its->phys_base = res.start; - its->msi_chip.of_node = node; its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1; its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL); @@ -1407,7 +1406,7 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) } its->cmd_write = its->cmd_base; - err = its_alloc_tables(its); + err = its_alloc_tables(node->full_name, its); if (err) goto out_free_cmd; @@ -1443,26 +1442,21 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) writeq_relaxed(0, its->base + GITS_CWRITER); writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); - if (of_property_read_bool(its->msi_chip.of_node, "msi-controller")) { - its->domain = irq_domain_add_tree(node, &its_domain_ops, its); - if (!its->domain) { + if (of_property_read_bool(node, "msi-controller")) { + inner_domain = irq_domain_add_tree(node, &its_domain_ops, its); + if (!inner_domain) { err = -ENOMEM; goto out_free_tables; } - its->domain->parent = parent; - its->domain->bus_token = DOMAIN_BUS_NEXUS; + inner_domain->parent = parent; + inner_domain->bus_token = DOMAIN_BUS_NEXUS; - its->msi_chip.domain = its_pci_msi_alloc_domain(node, - its->domain); - if (!its->msi_chip.domain) { + its->domain = its_pci_msi_alloc_domain(node, inner_domain); + if (!its->domain) { err = -ENOMEM; goto out_free_domains; } - - err = of_pci_msi_chip_add(&its->msi_chip); - if (err) - goto out_free_domains; } spin_lock(&its_lock); @@ -1472,10 +1466,10 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) return 0; out_free_domains: - if (its->msi_chip.domain) - irq_domain_remove(its->msi_chip.domain); if (its->domain) irq_domain_remove(its->domain); + if (inner_domain) + irq_domain_remove(inner_domain); out_free_tables: its_free_tables(its); out_free_cmd: -- cgit v0.10.2 From 54456db9a23753b87ce4d49adabe7da853bf13a2 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:21 +0100 Subject: irqchip/gicv3-its: Make the PCI/MSI code standalone We can now lookup the base ITS domain, making it possible to initialize the PCI/MSI code independently from the main ITS subsystem. This allows us to remove all the previously add hooks. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-15-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c index 7614721..cf351c6 100644 --- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c @@ -20,8 +20,6 @@ #include #include -#include - static void its_mask_msi_irq(struct irq_data *d) { pci_msi_mask_irq(d); @@ -74,17 +72,24 @@ static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, { struct pci_dev *pdev; struct its_pci_alias dev_alias; + struct msi_domain_info *msi_info; if (!dev_is_pci(dev)) return -EINVAL; + msi_info = msi_get_domain_info(domain->parent); + pdev = to_pci_dev(dev); dev_alias.pdev = pdev; dev_alias.count = nvec; pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias); - return its_msi_prepare(domain, dev_alias.dev_id, dev_alias.count, info); + /* ITS specific DeviceID, as the core ITS ignores dev. */ + info->scratchpad[0].ul = dev_alias.dev_id; + + return msi_info->ops->msi_prepare(domain->parent, + dev, dev_alias.count, info); } static struct msi_domain_ops its_pci_msi_ops = { @@ -98,8 +103,38 @@ static struct msi_domain_info its_pci_msi_domain_info = { .chip = &its_msi_irq_chip, }; -struct irq_domain *its_pci_msi_alloc_domain(struct device_node *np, - struct irq_domain *parent) +static struct of_device_id its_device_id[] = { + { .compatible = "arm,gic-v3-its", }, + {}, +}; + +static int __init its_pci_msi_init(void) { - return pci_msi_create_irq_domain(np, &its_pci_msi_domain_info, parent); + struct device_node *np; + struct irq_domain *parent; + + for (np = of_find_matching_node(NULL, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { + if (!of_property_read_bool(np, "msi-controller")) + continue; + + parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS); + if (!parent || !msi_get_domain_info(parent)) { + pr_err("%s: unable to locate ITS domain\n", + np->full_name); + continue; + } + + if (!pci_msi_create_irq_domain(np, &its_pci_msi_domain_info, + parent)) { + pr_err("%s: unable to create PCI domain\n", + np->full_name); + continue; + } + + pr_info("PCI/MSI: %s domain created\n", np->full_name); + } + + return 0; } +early_initcall(its_pci_msi_init); diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index dc4fbbf..26b55c5 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -59,7 +59,6 @@ struct its_collection { struct its_node { raw_spinlock_t lock; struct list_head entry; - struct irq_domain *domain; void __iomem *base; unsigned long phys_base; struct its_cmd_block *cmd_base; @@ -1187,13 +1186,25 @@ static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq) return 0; } -int its_msi_prepare(struct irq_domain *domain, u32 dev_id, - int nvec, msi_alloc_info_t *info) +static int its_msi_prepare(struct irq_domain *domain, struct device *dev, + int nvec, msi_alloc_info_t *info) { struct its_node *its; struct its_device *its_dev; + struct msi_domain_info *msi_info; + u32 dev_id; + + /* + * We ignore "dev" entierely, and rely on the dev_id that has + * been passed via the scratchpad. This limits this domain's + * usefulness to upper layers that definitely know that they + * are built on top of the ITS. + */ + dev_id = info->scratchpad[0].ul; + + msi_info = msi_get_domain_info(domain); + its = msi_info->data; - its = domain->parent->host_data; its_dev = its_find_device(its, dev_id); if (its_dev) { /* @@ -1215,6 +1226,10 @@ out: return 0; } +static struct msi_domain_ops its_msi_domain_ops = { + .msi_prepare = its_msi_prepare, +}; + static int its_irq_gic_domain_alloc(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq) @@ -1353,7 +1368,7 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) struct resource res; struct its_node *its; void __iomem *its_base; - struct irq_domain *inner_domain = NULL; + struct irq_domain *inner_domain; u32 val; u64 baser, tmp; int err; @@ -1443,20 +1458,26 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) writel_relaxed(GITS_CTLR_ENABLE, its->base + GITS_CTLR); if (of_property_read_bool(node, "msi-controller")) { + struct msi_domain_info *info; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + err = -ENOMEM; + goto out_free_tables; + } + inner_domain = irq_domain_add_tree(node, &its_domain_ops, its); if (!inner_domain) { err = -ENOMEM; + kfree(info); goto out_free_tables; } inner_domain->parent = parent; inner_domain->bus_token = DOMAIN_BUS_NEXUS; - - its->domain = its_pci_msi_alloc_domain(node, inner_domain); - if (!its->domain) { - err = -ENOMEM; - goto out_free_domains; - } + info->ops = &its_msi_domain_ops; + info->data = its; + inner_domain->host_data = info; } spin_lock(&its_lock); @@ -1465,11 +1486,6 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) return 0; -out_free_domains: - if (its->domain) - irq_domain_remove(its->domain); - if (inner_domain) - irq_domain_remove(inner_domain); out_free_tables: its_free_tables(its); out_free_cmd: diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index d6149ba..bf982e0 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -389,11 +389,6 @@ struct irq_domain; int its_cpu_init(void); int its_init(struct device_node *node, struct rdists *rdists, struct irq_domain *domain); -int its_msi_prepare(struct irq_domain *domain, u32 dev_id, - int nvec, msi_alloc_info_t *info); - -struct irq_domain *its_pci_msi_alloc_domain(struct device_node *node, - struct irq_domain *parent); #endif -- cgit v0.10.2 From 1e6db000482fa65a419d1776f9ae1ff919afe605 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:22 +0100 Subject: irqchip/gicv3-its: Add platform MSI support In order to support non-PCI MSI with the GICv3 ITS, add the minimal required entry points for the MSI domain (an msi_prepare implementation). The rest is only boilerplate code to find the raw ITS domain. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-16-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 0d5f2a9..11d08c9 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o -obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o +obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o obj-$(CONFIG_ARM_NVIC) += irq-nvic.o obj-$(CONFIG_ARM_VIC) += irq-vic.o obj-$(CONFIG_ATMEL_AIC_IRQ) += irq-atmel-aic-common.o irq-atmel-aic.o diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c new file mode 100644 index 0000000..a865505 --- /dev/null +++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013-2015 ARM Limited, All Rights Reserved. + * Author: Marc Zyngier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +static struct irq_chip its_pmsi_irq_chip = { + .name = "ITS-pMSI", +}; + +static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev, + int nvec, msi_alloc_info_t *info) +{ + struct msi_domain_info *msi_info; + u32 dev_id; + int ret; + + msi_info = msi_get_domain_info(domain->parent); + + /* Suck the DeviceID out of the msi-parent property */ + ret = of_property_read_u32_index(dev->of_node, "msi-parent", + 1, &dev_id); + if (ret) + return ret; + + /* ITS specific DeviceID, as the core ITS ignores dev. */ + info->scratchpad[0].ul = dev_id; + + return msi_info->ops->msi_prepare(domain->parent, + dev, nvec, info); +} + +static struct msi_domain_ops its_pmsi_ops = { + .msi_prepare = its_pmsi_prepare, +}; + +static struct msi_domain_info its_pmsi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), + .ops = &its_pmsi_ops, + .chip = &its_pmsi_irq_chip, +}; + +static struct of_device_id its_device_id[] = { + { .compatible = "arm,gic-v3-its", }, + {}, +}; + +static int __init its_pmsi_init(void) +{ + struct device_node *np; + struct irq_domain *parent; + + for (np = of_find_matching_node(NULL, its_device_id); np; + np = of_find_matching_node(np, its_device_id)) { + if (!of_property_read_bool(np, "msi-controller")) + continue; + + parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS); + if (!parent || !msi_get_domain_info(parent)) { + pr_err("%s: unable to locate ITS domain\n", + np->full_name); + continue; + } + + if (!platform_msi_create_irq_domain(np, &its_pmsi_domain_info, + parent)) { + pr_err("%s: unable to create platform domain\n", + np->full_name); + continue; + } + + pr_info("Platform MSI: %s domain created\n", np->full_name); + } + + return 0; +} +early_initcall(its_pmsi_init); -- cgit v0.10.2 From 5cedceb37c253c6181dbdd4bfe1b9d792e51fd37 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:23 +0100 Subject: irqchip/GICv2m: Get rid of struct msi_controller GICv2m only uses the msi_controller structure as a way to match the host bridge with its MSI HW, and thus the msi_domain. But now that we can directly associate an msi_domain with a device, there is no use keeping this msi_controller around. Just remove all traces of msi_controller from the driver. Also tag the inner (non-PCI) domain with DOMAIN_BUS_NEXUS. Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-17-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index fdf7065..ec9c376 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -45,7 +45,6 @@ struct v2m_data { spinlock_t msi_cnt_lock; - struct msi_controller mchip; struct resource res; /* GICv2m resource */ void __iomem *base; /* GICv2m virt address */ u32 spi_start; /* The SPI number that MSIs start */ @@ -218,6 +217,7 @@ static int __init gicv2m_init_one(struct device_node *node, { int ret; struct v2m_data *v2m; + struct irq_domain *inner_domain; v2m = kzalloc(sizeof(struct v2m_data), GFP_KERNEL); if (!v2m) { @@ -261,19 +261,18 @@ static int __init gicv2m_init_one(struct device_node *node, goto err_iounmap; } - v2m->domain = irq_domain_add_tree(NULL, &gicv2m_domain_ops, v2m); - if (!v2m->domain) { + inner_domain = irq_domain_add_tree(node, &gicv2m_domain_ops, v2m); + if (!inner_domain) { pr_err("Failed to create GICv2m domain\n"); ret = -ENOMEM; goto err_free_bm; } - v2m->domain->parent = parent; - v2m->mchip.of_node = node; - v2m->mchip.domain = pci_msi_create_irq_domain(node, - &gicv2m_msi_domain_info, - v2m->domain); - if (!v2m->mchip.domain) { + inner_domain->bus_token = DOMAIN_BUS_NEXUS; + inner_domain->parent = parent; + v2m->domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info, + inner_domain); + if (!v2m->domain) { pr_err("Failed to create MSI domain\n"); ret = -ENOMEM; goto err_free_domains; @@ -281,12 +280,6 @@ static int __init gicv2m_init_one(struct device_node *node, spin_lock_init(&v2m->msi_cnt_lock); - ret = of_pci_msi_chip_add(&v2m->mchip); - if (ret) { - pr_err("Failed to add msi_chip.\n"); - goto err_free_domains; - } - pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name, (unsigned long)v2m->res.start, (unsigned long)v2m->res.end, v2m->spi_start, (v2m->spi_start + v2m->nr_spis)); @@ -294,10 +287,10 @@ static int __init gicv2m_init_one(struct device_node *node, return 0; err_free_domains: - if (v2m->mchip.domain) - irq_domain_remove(v2m->mchip.domain); if (v2m->domain) irq_domain_remove(v2m->domain); + if (inner_domain) + irq_domain_remove(inner_domain); err_free_bm: kfree(v2m->bm); err_iounmap: -- cgit v0.10.2 From ef50645aa32c6b55fe1445b5d06c73bfdf65019f Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:24 +0100 Subject: irqchip/GICv2m: Add platform MSI support In order to support non-PCI MSI with GICv2m, add the minimal required entry points for the MSI domain, which is actually almost nothing (we just use the defaults provided by the core code). Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-18-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index ec9c376..db04fc1 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -50,7 +50,6 @@ struct v2m_data { u32 spi_start; /* The SPI number that MSIs start */ u32 nr_spis; /* The number of SPIs for MSIs */ unsigned long *bm; /* MSI vector bitmap */ - struct irq_domain *domain; }; static void gicv2m_mask_msi_irq(struct irq_data *d) @@ -212,12 +211,25 @@ static bool is_msi_spi_valid(u32 base, u32 num) return true; } +static struct irq_chip gicv2m_pmsi_irq_chip = { + .name = "pMSI", +}; + +static struct msi_domain_ops gicv2m_pmsi_ops = { +}; + +static struct msi_domain_info gicv2m_pmsi_domain_info = { + .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), + .ops = &gicv2m_pmsi_ops, + .chip = &gicv2m_pmsi_irq_chip, +}; + static int __init gicv2m_init_one(struct device_node *node, struct irq_domain *parent) { int ret; struct v2m_data *v2m; - struct irq_domain *inner_domain; + struct irq_domain *inner_domain, *pci_domain, *plat_domain; v2m = kzalloc(sizeof(struct v2m_data), GFP_KERNEL); if (!v2m) { @@ -270,10 +282,13 @@ static int __init gicv2m_init_one(struct device_node *node, inner_domain->bus_token = DOMAIN_BUS_NEXUS; inner_domain->parent = parent; - v2m->domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info, - inner_domain); - if (!v2m->domain) { - pr_err("Failed to create MSI domain\n"); + pci_domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info, + inner_domain); + plat_domain = platform_msi_create_irq_domain(node, + &gicv2m_pmsi_domain_info, + inner_domain); + if (!pci_domain || !plat_domain) { + pr_err("Failed to create MSI domains\n"); ret = -ENOMEM; goto err_free_domains; } @@ -287,8 +302,10 @@ static int __init gicv2m_init_one(struct device_node *node, return 0; err_free_domains: - if (v2m->domain) - irq_domain_remove(v2m->domain); + if (plat_domain) + irq_domain_remove(plat_domain); + if (pci_domain) + irq_domain_remove(pci_domain); if (inner_domain) irq_domain_remove(inner_domain); err_free_bm: -- cgit v0.10.2 From 8d63bc7beaeecdc2dfafed69c3555471fbe4aee7 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:25 +0100 Subject: PCI/MSI: pci-xgene-msi: Get rid of struct msi_controller The X-Gene MSI driver only uses the msi_controller structure as a way to match the host bridge with its MSI HW, and thus the msi_domain. But now that we can directly associate an msi_domain with a device, there is no use keeping this msi_controller around. Just remove all traces of msi_controller from the driver. Tested-by: Duc Dang Acked-by: Bjorn Helgaas Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Hanjun Guo Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-19-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/host/pci-xgene-msi.c b/drivers/pci/host/pci-xgene-msi.c index 2d31d4d..ec5a14b 100644 --- a/drivers/pci/host/pci-xgene-msi.c +++ b/drivers/pci/host/pci-xgene-msi.c @@ -40,8 +40,8 @@ struct xgene_msi_group { struct xgene_msi { struct device_node *node; - struct msi_controller mchip; - struct irq_domain *domain; + struct irq_domain *inner_domain; + struct irq_domain *msi_domain; u64 msi_addr; void __iomem *msi_regs; unsigned long *bitmap; @@ -252,17 +252,17 @@ static const struct irq_domain_ops msi_domain_ops = { static int xgene_allocate_domains(struct xgene_msi *msi) { - msi->domain = irq_domain_add_linear(NULL, NR_MSI_VEC, - &msi_domain_ops, msi); - if (!msi->domain) + msi->inner_domain = irq_domain_add_linear(NULL, NR_MSI_VEC, + &msi_domain_ops, msi); + if (!msi->inner_domain) return -ENOMEM; - msi->mchip.domain = pci_msi_create_irq_domain(msi->mchip.of_node, - &xgene_msi_domain_info, - msi->domain); + msi->msi_domain = pci_msi_create_irq_domain(msi->node, + &xgene_msi_domain_info, + msi->inner_domain); - if (!msi->mchip.domain) { - irq_domain_remove(msi->domain); + if (!msi->msi_domain) { + irq_domain_remove(msi->inner_domain); return -ENOMEM; } @@ -271,10 +271,10 @@ static int xgene_allocate_domains(struct xgene_msi *msi) static void xgene_free_domains(struct xgene_msi *msi) { - if (msi->mchip.domain) - irq_domain_remove(msi->mchip.domain); - if (msi->domain) - irq_domain_remove(msi->domain); + if (msi->msi_domain) + irq_domain_remove(msi->msi_domain); + if (msi->inner_domain) + irq_domain_remove(msi->inner_domain); } static int xgene_msi_init_allocator(struct xgene_msi *xgene_msi) @@ -340,7 +340,7 @@ static void xgene_msi_isr(unsigned int irq, struct irq_desc *desc) * CPU0 */ hw_irq = hwirq_to_canonical_hwirq(hw_irq); - virq = irq_find_mapping(xgene_msi->domain, hw_irq); + virq = irq_find_mapping(xgene_msi->inner_domain, hw_irq); WARN_ON(!virq); if (virq != 0) generic_handle_irq(virq); @@ -497,7 +497,7 @@ static int xgene_msi_probe(struct platform_device *pdev) goto error; } xgene_msi->msi_addr = res->start; - + xgene_msi->node = pdev->dev.of_node; xgene_msi->num_cpus = num_possible_cpus(); rc = xgene_msi_init_allocator(xgene_msi); @@ -561,19 +561,10 @@ static int xgene_msi_probe(struct platform_device *pdev) cpu_notifier_register_done(); - xgene_msi->mchip.of_node = pdev->dev.of_node; - rc = of_pci_msi_chip_add(&xgene_msi->mchip); - if (rc) { - dev_err(&pdev->dev, "failed to add MSI controller chip\n"); - goto error_notifier; - } - dev_info(&pdev->dev, "APM X-Gene PCIe MSI driver loaded\n"); return 0; -error_notifier: - unregister_hotcpu_notifier(&xgene_msi_cpu_notifier); error: xgene_msi_remove(pdev); return rc; -- cgit v0.10.2 From f075915ac0b11847fcfc8c4d55526a317e71c4d1 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 28 Jul 2015 14:46:26 +0100 Subject: PCI/MSI: Drop domain field from msi_controller The only three users of that field are not using the msi_controller structure anymore, so drop it altogether. Acked-by: Bjorn Helgaas Signed-off-by: Marc Zyngier Cc: Cc: Yijing Wang Cc: Ma Jun Cc: Lorenzo Pieralisi Cc: Duc Dang Cc: Hanjun Guo Cc: Jiang Liu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438091186-10244-20-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 4603344..f70aa0f 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -45,9 +45,6 @@ static struct irq_domain *pci_msi_get_domain(struct pci_dev *dev) if (domain) return domain; - if (dev->bus->msi && (domain = dev->bus->msi->domain)) - return domain; - return arch_get_pci_msi_domain(dev); } diff --git a/include/linux/msi.h b/include/linux/msi.h index 809b749..ad939d0 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -160,9 +160,6 @@ struct msi_controller { struct device *dev; struct device_node *of_node; struct list_head list; -#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN - struct irq_domain *domain; -#endif int (*setup_irq)(struct msi_controller *chip, struct pci_dev *dev, struct msi_desc *desc); -- cgit v0.10.2 From fd4b267b3d30f4742bdf7586fed5193b67938e32 Mon Sep 17 00:00:00 2001 From: Joel Porquet Date: Tue, 7 Jul 2015 17:13:15 -0400 Subject: microblaze/irq: prepare for drivers/irqchip/irqchip.h removal The IRQCHIP_DECLARE macro migrated to 'include/linux/irqchip.h'. See commit 91e20b5040c67c51aad88cf87db4305c5bd7f79d ("irqchip: Move IRQCHIP_DECLARE macro to include/linux/irqchip.h"). This patch removes the inclusion of private header 'drivers/irqchip/irqchip.h' and replaces it with the inclusion of 'include/linux/irqchip.h'. Signed-off-by: Joel Porquet Cc: vgupta@synopsys.com Cc: monstr@monstr.eu Cc: ralf@linux-mips.org Cc: jason@lakedaemon.net Link: http://lkml.kernel.org/r/12384045.pHnZrl3CFY@joel-zenbook Signed-off-by: Thomas Gleixner diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c index 719feee..90bec7d 100644 --- a/arch/microblaze/kernel/intc.c +++ b/arch/microblaze/kernel/intc.c @@ -11,12 +11,11 @@ #include #include +#include #include #include #include -#include "../../drivers/irqchip/irqchip.h" - static void __iomem *intc_baseaddr; /* No one else should require these constants, so define them locally here. */ -- cgit v0.10.2 From 0a271c2a34deb98a81f94fc87380287f3a8c9c72 Mon Sep 17 00:00:00 2001 From: Joel Porquet Date: Tue, 7 Jul 2015 17:17:33 -0400 Subject: mips/irq: prepare for drivers/irqchip/irqchip.h removal The IRQCHIP_DECLARE macro migrated to 'include/linux/irqchip.h'. See commit 91e20b5040c67c51aad88cf87db4305c5bd7f79d ("irqchip: Move IRQCHIP_DECLARE macro to include/linux/irqchip.h"). This patch removes inclusions of private header 'drivers/irqchip/irqchip.h'and replaces them with the inclusion of 'include/linux/irqchip.h'. Signed-off-by: Joel Porquet Cc: vgupta@synopsys.com Cc: monstr@monstr.eu Cc: ralf@linux-mips.org Cc: jason@lakedaemon.net Link: http://lkml.kernel.org/r/3357968.0IznKtY3Q9@joel-zenbook Signed-off-by: Thomas Gleixner diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c index afb0096..2021be2 100644 --- a/arch/mips/ath79/irq.c +++ b/arch/mips/ath79/irq.c @@ -17,7 +17,6 @@ #include #include #include -#include "../../../drivers/irqchip/irqchip.h" #include #include diff --git a/arch/mips/bmips/irq.c b/arch/mips/bmips/irq.c index 14552e5..e7fc6f934 100644 --- a/arch/mips/bmips/irq.c +++ b/arch/mips/bmips/irq.c @@ -34,5 +34,5 @@ void __init arch_init_irq(void) irqchip_init(); } -OF_DECLARE_2(irqchip, mips_cpu_intc, "mti,cpu-interrupt-controller", +IRQCHIP_DECLARE(mips_cpu_intc, "mti,cpu-interrupt-controller", mips_cpu_irq_of_init); diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 74f6752..a8acee7 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c @@ -18,12 +18,11 @@ #include #include #include +#include #include #include -#include "../../drivers/irqchip/irqchip.h" - /* * This is the 'legacy' 8259A Programmable Interrupt Controller, * present in the majority of PC/AT boxes. -- cgit v0.10.2 From 0b7367017087cfe6f4514eb9e9c108ac8d6a101b Mon Sep 17 00:00:00 2001 From: Joel Porquet Date: Tue, 7 Jul 2015 17:18:23 -0400 Subject: irqchip: Remove header drivers/irqchip/irqchip.h All drivers using the macro IRQCHIP_DECLARE have been converted to using global header include/linux/irqchip.h. Local header drivers/irqchip/irqchip.h is now useless and can be removed. Signed-off-by: Joel Porquet Cc: vgupta@synopsys.com Cc: monstr@monstr.eu Cc: ralf@linux-mips.org Cc: jason@lakedaemon.net Link: http://lkml.kernel.org/r/2818400.nekF4hg2Ig@joel-zenbook Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irqchip.h b/drivers/irqchip/irqchip.h deleted file mode 100644 index 0f67ae3..0000000 --- a/drivers/irqchip/irqchip.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright (C) 2012 Thomas Petazzoni - * - * Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include -- cgit v0.10.2 From 0509cfde038d8afb0c1df1d52c90ae847b425d97 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 8 Jul 2015 14:46:08 +0200 Subject: MIPS/irqchip: Move i8259 irqchip driver to drivers/irqchip Signed-off-by: Ralf Baechle Signed-off-by: Thomas Gleixner diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index cee5f93..d612972 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1071,10 +1071,6 @@ config HOTPLUG_CPU config SYS_SUPPORTS_HOTPLUG_CPU bool -config I8259 - bool - select IRQ_DOMAIN - config MIPS_BONITO64 bool diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 3f5cf8a..3156c8d 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -61,7 +61,6 @@ obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o obj-$(CONFIG_MIPS_VPE_APSP_API_CMP) += rtlx-cmp.o obj-$(CONFIG_MIPS_VPE_APSP_API_MT) += rtlx-mt.o -obj-$(CONFIG_I8259) += i8259.o obj-$(CONFIG_IRQ_CPU_RM7K) += irq-rm7000.o obj-$(CONFIG_MIPS_MSC) += irq-msc01.o obj-$(CONFIG_IRQ_TXX9) += irq_txx9.o diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c deleted file mode 100644 index a8acee7..0000000 --- a/arch/mips/kernel/i8259.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Code to handle x86 style IRQs plus some generic interrupt stuff. - * - * Copyright (C) 1992 Linus Torvalds - * Copyright (C) 1994 - 2000 Ralf Baechle - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* - * This is the 'legacy' 8259A Programmable Interrupt Controller, - * present in the majority of PC/AT boxes. - * plus some generic x86 specific things if generic specifics makes - * any sense at all. - * this file should become arch/i386/kernel/irq.c when the old irq.c - * moves to arch independent land - */ - -static int i8259A_auto_eoi = -1; -DEFINE_RAW_SPINLOCK(i8259A_lock); -static void disable_8259A_irq(struct irq_data *d); -static void enable_8259A_irq(struct irq_data *d); -static void mask_and_ack_8259A(struct irq_data *d); -static void init_8259A(int auto_eoi); - -static struct irq_chip i8259A_chip = { - .name = "XT-PIC", - .irq_mask = disable_8259A_irq, - .irq_disable = disable_8259A_irq, - .irq_unmask = enable_8259A_irq, - .irq_mask_ack = mask_and_ack_8259A, -}; - -/* - * 8259A PIC functions to handle ISA devices: - */ - -/* - * This contains the irq mask for both 8259A irq controllers, - */ -static unsigned int cached_irq_mask = 0xffff; - -#define cached_master_mask (cached_irq_mask) -#define cached_slave_mask (cached_irq_mask >> 8) - -static void disable_8259A_irq(struct irq_data *d) -{ - unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; - unsigned long flags; - - mask = 1 << irq; - raw_spin_lock_irqsave(&i8259A_lock, flags); - cached_irq_mask |= mask; - if (irq & 8) - outb(cached_slave_mask, PIC_SLAVE_IMR); - else - outb(cached_master_mask, PIC_MASTER_IMR); - raw_spin_unlock_irqrestore(&i8259A_lock, flags); -} - -static void enable_8259A_irq(struct irq_data *d) -{ - unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; - unsigned long flags; - - mask = ~(1 << irq); - raw_spin_lock_irqsave(&i8259A_lock, flags); - cached_irq_mask &= mask; - if (irq & 8) - outb(cached_slave_mask, PIC_SLAVE_IMR); - else - outb(cached_master_mask, PIC_MASTER_IMR); - raw_spin_unlock_irqrestore(&i8259A_lock, flags); -} - -int i8259A_irq_pending(unsigned int irq) -{ - unsigned int mask; - unsigned long flags; - int ret; - - irq -= I8259A_IRQ_BASE; - mask = 1 << irq; - raw_spin_lock_irqsave(&i8259A_lock, flags); - if (irq < 8) - ret = inb(PIC_MASTER_CMD) & mask; - else - ret = inb(PIC_SLAVE_CMD) & (mask >> 8); - raw_spin_unlock_irqrestore(&i8259A_lock, flags); - - return ret; -} - -void make_8259A_irq(unsigned int irq) -{ - disable_irq_nosync(irq); - irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq); - enable_irq(irq); -} - -/* - * This function assumes to be called rarely. Switching between - * 8259A registers is slow. - * This has to be protected by the irq controller spinlock - * before being called. - */ -static inline int i8259A_irq_real(unsigned int irq) -{ - int value; - int irqmask = 1 << irq; - - if (irq < 8) { - outb(0x0B, PIC_MASTER_CMD); /* ISR register */ - value = inb(PIC_MASTER_CMD) & irqmask; - outb(0x0A, PIC_MASTER_CMD); /* back to the IRR register */ - return value; - } - outb(0x0B, PIC_SLAVE_CMD); /* ISR register */ - value = inb(PIC_SLAVE_CMD) & (irqmask >> 8); - outb(0x0A, PIC_SLAVE_CMD); /* back to the IRR register */ - return value; -} - -/* - * Careful! The 8259A is a fragile beast, it pretty - * much _has_ to be done exactly like this (mask it - * first, _then_ send the EOI, and the order of EOI - * to the two 8259s is important! - */ -static void mask_and_ack_8259A(struct irq_data *d) -{ - unsigned int irqmask, irq = d->irq - I8259A_IRQ_BASE; - unsigned long flags; - - irqmask = 1 << irq; - raw_spin_lock_irqsave(&i8259A_lock, flags); - /* - * Lightweight spurious IRQ detection. We do not want - * to overdo spurious IRQ handling - it's usually a sign - * of hardware problems, so we only do the checks we can - * do without slowing down good hardware unnecessarily. - * - * Note that IRQ7 and IRQ15 (the two spurious IRQs - * usually resulting from the 8259A-1|2 PICs) occur - * even if the IRQ is masked in the 8259A. Thus we - * can check spurious 8259A IRQs without doing the - * quite slow i8259A_irq_real() call for every IRQ. - * This does not cover 100% of spurious interrupts, - * but should be enough to warn the user that there - * is something bad going on ... - */ - if (cached_irq_mask & irqmask) - goto spurious_8259A_irq; - cached_irq_mask |= irqmask; - -handle_real_irq: - if (irq & 8) { - inb(PIC_SLAVE_IMR); /* DUMMY - (do we need this?) */ - outb(cached_slave_mask, PIC_SLAVE_IMR); - outb(0x60+(irq&7), PIC_SLAVE_CMD);/* 'Specific EOI' to slave */ - outb(0x60+PIC_CASCADE_IR, PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */ - } else { - inb(PIC_MASTER_IMR); /* DUMMY - (do we need this?) */ - outb(cached_master_mask, PIC_MASTER_IMR); - outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */ - } - raw_spin_unlock_irqrestore(&i8259A_lock, flags); - return; - -spurious_8259A_irq: - /* - * this is the slow path - should happen rarely. - */ - if (i8259A_irq_real(irq)) - /* - * oops, the IRQ _is_ in service according to the - * 8259A - not spurious, go handle it. - */ - goto handle_real_irq; - - { - static int spurious_irq_mask; - /* - * At this point we can be sure the IRQ is spurious, - * lets ACK and report it. [once per IRQ] - */ - if (!(spurious_irq_mask & irqmask)) { - printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq); - spurious_irq_mask |= irqmask; - } - atomic_inc(&irq_err_count); - /* - * Theoretically we do not have to handle this IRQ, - * but in Linux this does not cause problems and is - * simpler for us. - */ - goto handle_real_irq; - } -} - -static void i8259A_resume(void) -{ - if (i8259A_auto_eoi >= 0) - init_8259A(i8259A_auto_eoi); -} - -static void i8259A_shutdown(void) -{ - /* Put the i8259A into a quiescent state that - * the kernel initialization code can get it - * out of. - */ - if (i8259A_auto_eoi >= 0) { - outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ - outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ - } -} - -static struct syscore_ops i8259_syscore_ops = { - .resume = i8259A_resume, - .shutdown = i8259A_shutdown, -}; - -static int __init i8259A_init_sysfs(void) -{ - register_syscore_ops(&i8259_syscore_ops); - return 0; -} - -device_initcall(i8259A_init_sysfs); - -static void init_8259A(int auto_eoi) -{ - unsigned long flags; - - i8259A_auto_eoi = auto_eoi; - - raw_spin_lock_irqsave(&i8259A_lock, flags); - - outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ - outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ - - /* - * outb_p - this has to work on a wide range of PC hardware. - */ - outb_p(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */ - outb_p(I8259A_IRQ_BASE + 0, PIC_MASTER_IMR); /* ICW2: 8259A-1 IR0 mapped to I8259A_IRQ_BASE + 0x00 */ - outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); /* 8259A-1 (the master) has a slave on IR2 */ - if (auto_eoi) /* master does Auto EOI */ - outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR); - else /* master expects normal EOI */ - outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR); - - outb_p(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */ - outb_p(I8259A_IRQ_BASE + 8, PIC_SLAVE_IMR); /* ICW2: 8259A-2 IR0 mapped to I8259A_IRQ_BASE + 0x08 */ - outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR); /* 8259A-2 is a slave on master's IR2 */ - outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */ - if (auto_eoi) - /* - * In AEOI mode we just have to mask the interrupt - * when acking. - */ - i8259A_chip.irq_mask_ack = disable_8259A_irq; - else - i8259A_chip.irq_mask_ack = mask_and_ack_8259A; - - udelay(100); /* wait for 8259A to initialize */ - - outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */ - outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */ - - raw_spin_unlock_irqrestore(&i8259A_lock, flags); -} - -/* - * IRQ2 is cascade interrupt to second interrupt controller - */ -static struct irqaction irq2 = { - .handler = no_action, - .name = "cascade", - .flags = IRQF_NO_THREAD, -}; - -static struct resource pic1_io_resource = { - .name = "pic1", - .start = PIC_MASTER_CMD, - .end = PIC_MASTER_IMR, - .flags = IORESOURCE_BUSY -}; - -static struct resource pic2_io_resource = { - .name = "pic2", - .start = PIC_SLAVE_CMD, - .end = PIC_SLAVE_IMR, - .flags = IORESOURCE_BUSY -}; - -static int i8259A_irq_domain_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) -{ - irq_set_chip_and_handler(virq, &i8259A_chip, handle_level_irq); - irq_set_probe(virq); - return 0; -} - -static struct irq_domain_ops i8259A_ops = { - .map = i8259A_irq_domain_map, - .xlate = irq_domain_xlate_onecell, -}; - -/* - * On systems with i8259-style interrupt controllers we assume for - * driver compatibility reasons interrupts 0 - 15 to be the i8259 - * interrupts even if the hardware uses a different interrupt numbering. - */ -struct irq_domain * __init __init_i8259_irqs(struct device_node *node) -{ - struct irq_domain *domain; - - insert_resource(&ioport_resource, &pic1_io_resource); - insert_resource(&ioport_resource, &pic2_io_resource); - - init_8259A(0); - - domain = irq_domain_add_legacy(node, 16, I8259A_IRQ_BASE, 0, - &i8259A_ops, NULL); - if (!domain) - panic("Failed to add i8259 IRQ domain"); - - setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); - return domain; -} - -void __init init_i8259_irqs(void) -{ - __init_i8259_irqs(NULL); -} - -static void i8259_irq_dispatch(unsigned int irq, struct irq_desc *desc) -{ - struct irq_domain *domain = irq_get_handler_data(irq); - int hwirq = i8259_irq(); - - if (hwirq < 0) - return; - - irq = irq_linear_revmap(domain, hwirq); - generic_handle_irq(irq); -} - -int __init i8259_of_init(struct device_node *node, struct device_node *parent) -{ - struct irq_domain *domain; - unsigned int parent_irq; - - parent_irq = irq_of_parse_and_map(node, 0); - if (!parent_irq) { - pr_err("Failed to map i8259 parent IRQ\n"); - return -ENODEV; - } - - domain = __init_i8259_irqs(node); - irq_set_handler_data(parent_irq, domain); - irq_set_chained_handler(parent_irq, i8259_irq_dispatch); - return 0; -} -IRQCHIP_DECLARE(i8259, "intel,i8259", i8259_of_init); diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 120d815..5b85371 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -61,6 +61,10 @@ config ATMEL_AIC5_IRQ select MULTI_IRQ_HANDLER select SPARSE_IRQ +config I8259 + bool + select IRQ_DOMAIN + config BCM7038_L1_IRQ bool select GENERIC_IRQ_CHIP diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 11d08c9..d4c5e56 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_ARM_NVIC) += irq-nvic.o obj-$(CONFIG_ARM_VIC) += irq-vic.o obj-$(CONFIG_ATMEL_AIC_IRQ) += irq-atmel-aic-common.o irq-atmel-aic.o obj-$(CONFIG_ATMEL_AIC5_IRQ) += irq-atmel-aic-common.o irq-atmel-aic5.o +obj-$(CONFIG_I8259) += irq-i8259.o obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o obj-$(CONFIG_IRQ_MIPS_CPU) += irq-mips-cpu.o obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c new file mode 100644 index 0000000..a29638a --- /dev/null +++ b/drivers/irqchip/irq-i8259.c @@ -0,0 +1,383 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Code to handle x86 style IRQs plus some generic interrupt stuff. + * + * Copyright (C) 1992 Linus Torvalds + * Copyright (C) 1994 - 2000 Ralf Baechle + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * This is the 'legacy' 8259A Programmable Interrupt Controller, + * present in the majority of PC/AT boxes. + * plus some generic x86 specific things if generic specifics makes + * any sense at all. + * this file should become arch/i386/kernel/irq.c when the old irq.c + * moves to arch independent land + */ + +static int i8259A_auto_eoi = -1; +DEFINE_RAW_SPINLOCK(i8259A_lock); +static void disable_8259A_irq(struct irq_data *d); +static void enable_8259A_irq(struct irq_data *d); +static void mask_and_ack_8259A(struct irq_data *d); +static void init_8259A(int auto_eoi); + +static struct irq_chip i8259A_chip = { + .name = "XT-PIC", + .irq_mask = disable_8259A_irq, + .irq_disable = disable_8259A_irq, + .irq_unmask = enable_8259A_irq, + .irq_mask_ack = mask_and_ack_8259A, +}; + +/* + * 8259A PIC functions to handle ISA devices: + */ + +/* + * This contains the irq mask for both 8259A irq controllers, + */ +static unsigned int cached_irq_mask = 0xffff; + +#define cached_master_mask (cached_irq_mask) +#define cached_slave_mask (cached_irq_mask >> 8) + +static void disable_8259A_irq(struct irq_data *d) +{ + unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; + unsigned long flags; + + mask = 1 << irq; + raw_spin_lock_irqsave(&i8259A_lock, flags); + cached_irq_mask |= mask; + if (irq & 8) + outb(cached_slave_mask, PIC_SLAVE_IMR); + else + outb(cached_master_mask, PIC_MASTER_IMR); + raw_spin_unlock_irqrestore(&i8259A_lock, flags); +} + +static void enable_8259A_irq(struct irq_data *d) +{ + unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; + unsigned long flags; + + mask = ~(1 << irq); + raw_spin_lock_irqsave(&i8259A_lock, flags); + cached_irq_mask &= mask; + if (irq & 8) + outb(cached_slave_mask, PIC_SLAVE_IMR); + else + outb(cached_master_mask, PIC_MASTER_IMR); + raw_spin_unlock_irqrestore(&i8259A_lock, flags); +} + +int i8259A_irq_pending(unsigned int irq) +{ + unsigned int mask; + unsigned long flags; + int ret; + + irq -= I8259A_IRQ_BASE; + mask = 1 << irq; + raw_spin_lock_irqsave(&i8259A_lock, flags); + if (irq < 8) + ret = inb(PIC_MASTER_CMD) & mask; + else + ret = inb(PIC_SLAVE_CMD) & (mask >> 8); + raw_spin_unlock_irqrestore(&i8259A_lock, flags); + + return ret; +} + +void make_8259A_irq(unsigned int irq) +{ + disable_irq_nosync(irq); + irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq); + enable_irq(irq); +} + +/* + * This function assumes to be called rarely. Switching between + * 8259A registers is slow. + * This has to be protected by the irq controller spinlock + * before being called. + */ +static inline int i8259A_irq_real(unsigned int irq) +{ + int value; + int irqmask = 1 << irq; + + if (irq < 8) { + outb(0x0B, PIC_MASTER_CMD); /* ISR register */ + value = inb(PIC_MASTER_CMD) & irqmask; + outb(0x0A, PIC_MASTER_CMD); /* back to the IRR register */ + return value; + } + outb(0x0B, PIC_SLAVE_CMD); /* ISR register */ + value = inb(PIC_SLAVE_CMD) & (irqmask >> 8); + outb(0x0A, PIC_SLAVE_CMD); /* back to the IRR register */ + return value; +} + +/* + * Careful! The 8259A is a fragile beast, it pretty + * much _has_ to be done exactly like this (mask it + * first, _then_ send the EOI, and the order of EOI + * to the two 8259s is important! + */ +static void mask_and_ack_8259A(struct irq_data *d) +{ + unsigned int irqmask, irq = d->irq - I8259A_IRQ_BASE; + unsigned long flags; + + irqmask = 1 << irq; + raw_spin_lock_irqsave(&i8259A_lock, flags); + /* + * Lightweight spurious IRQ detection. We do not want + * to overdo spurious IRQ handling - it's usually a sign + * of hardware problems, so we only do the checks we can + * do without slowing down good hardware unnecessarily. + * + * Note that IRQ7 and IRQ15 (the two spurious IRQs + * usually resulting from the 8259A-1|2 PICs) occur + * even if the IRQ is masked in the 8259A. Thus we + * can check spurious 8259A IRQs without doing the + * quite slow i8259A_irq_real() call for every IRQ. + * This does not cover 100% of spurious interrupts, + * but should be enough to warn the user that there + * is something bad going on ... + */ + if (cached_irq_mask & irqmask) + goto spurious_8259A_irq; + cached_irq_mask |= irqmask; + +handle_real_irq: + if (irq & 8) { + inb(PIC_SLAVE_IMR); /* DUMMY - (do we need this?) */ + outb(cached_slave_mask, PIC_SLAVE_IMR); + outb(0x60+(irq&7), PIC_SLAVE_CMD);/* 'Specific EOI' to slave */ + outb(0x60+PIC_CASCADE_IR, PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */ + } else { + inb(PIC_MASTER_IMR); /* DUMMY - (do we need this?) */ + outb(cached_master_mask, PIC_MASTER_IMR); + outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */ + } + raw_spin_unlock_irqrestore(&i8259A_lock, flags); + return; + +spurious_8259A_irq: + /* + * this is the slow path - should happen rarely. + */ + if (i8259A_irq_real(irq)) + /* + * oops, the IRQ _is_ in service according to the + * 8259A - not spurious, go handle it. + */ + goto handle_real_irq; + + { + static int spurious_irq_mask; + /* + * At this point we can be sure the IRQ is spurious, + * lets ACK and report it. [once per IRQ] + */ + if (!(spurious_irq_mask & irqmask)) { + printk(KERN_DEBUG "spurious 8259A interrupt: IRQ%d.\n", irq); + spurious_irq_mask |= irqmask; + } + atomic_inc(&irq_err_count); + /* + * Theoretically we do not have to handle this IRQ, + * but in Linux this does not cause problems and is + * simpler for us. + */ + goto handle_real_irq; + } +} + +static void i8259A_resume(void) +{ + if (i8259A_auto_eoi >= 0) + init_8259A(i8259A_auto_eoi); +} + +static void i8259A_shutdown(void) +{ + /* Put the i8259A into a quiescent state that + * the kernel initialization code can get it + * out of. + */ + if (i8259A_auto_eoi >= 0) { + outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ + outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ + } +} + +static struct syscore_ops i8259_syscore_ops = { + .resume = i8259A_resume, + .shutdown = i8259A_shutdown, +}; + +static int __init i8259A_init_sysfs(void) +{ + register_syscore_ops(&i8259_syscore_ops); + return 0; +} + +device_initcall(i8259A_init_sysfs); + +static void init_8259A(int auto_eoi) +{ + unsigned long flags; + + i8259A_auto_eoi = auto_eoi; + + raw_spin_lock_irqsave(&i8259A_lock, flags); + + outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ + outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ + + /* + * outb_p - this has to work on a wide range of PC hardware. + */ + outb_p(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */ + outb_p(I8259A_IRQ_BASE + 0, PIC_MASTER_IMR); /* ICW2: 8259A-1 IR0 mapped to I8259A_IRQ_BASE + 0x00 */ + outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); /* 8259A-1 (the master) has a slave on IR2 */ + if (auto_eoi) /* master does Auto EOI */ + outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR); + else /* master expects normal EOI */ + outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR); + + outb_p(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */ + outb_p(I8259A_IRQ_BASE + 8, PIC_SLAVE_IMR); /* ICW2: 8259A-2 IR0 mapped to I8259A_IRQ_BASE + 0x08 */ + outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR); /* 8259A-2 is a slave on master's IR2 */ + outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */ + if (auto_eoi) + /* + * In AEOI mode we just have to mask the interrupt + * when acking. + */ + i8259A_chip.irq_mask_ack = disable_8259A_irq; + else + i8259A_chip.irq_mask_ack = mask_and_ack_8259A; + + udelay(100); /* wait for 8259A to initialize */ + + outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */ + outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */ + + raw_spin_unlock_irqrestore(&i8259A_lock, flags); +} + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ +static struct irqaction irq2 = { + .handler = no_action, + .name = "cascade", + .flags = IRQF_NO_THREAD, +}; + +static struct resource pic1_io_resource = { + .name = "pic1", + .start = PIC_MASTER_CMD, + .end = PIC_MASTER_IMR, + .flags = IORESOURCE_BUSY +}; + +static struct resource pic2_io_resource = { + .name = "pic2", + .start = PIC_SLAVE_CMD, + .end = PIC_SLAVE_IMR, + .flags = IORESOURCE_BUSY +}; + +static int i8259A_irq_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &i8259A_chip, handle_level_irq); + irq_set_probe(virq); + return 0; +} + +static struct irq_domain_ops i8259A_ops = { + .map = i8259A_irq_domain_map, + .xlate = irq_domain_xlate_onecell, +}; + +/* + * On systems with i8259-style interrupt controllers we assume for + * driver compatibility reasons interrupts 0 - 15 to be the i8259 + * interrupts even if the hardware uses a different interrupt numbering. + */ +struct irq_domain * __init __init_i8259_irqs(struct device_node *node) +{ + struct irq_domain *domain; + + insert_resource(&ioport_resource, &pic1_io_resource); + insert_resource(&ioport_resource, &pic2_io_resource); + + init_8259A(0); + + domain = irq_domain_add_legacy(node, 16, I8259A_IRQ_BASE, 0, + &i8259A_ops, NULL); + if (!domain) + panic("Failed to add i8259 IRQ domain"); + + setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); + return domain; +} + +void __init init_i8259_irqs(void) +{ + __init_i8259_irqs(NULL); +} + +static void i8259_irq_dispatch(unsigned int irq, struct irq_desc *desc) +{ + struct irq_domain *domain = irq_get_handler_data(irq); + int hwirq = i8259_irq(); + + if (hwirq < 0) + return; + + irq = irq_linear_revmap(domain, hwirq); + generic_handle_irq(irq); +} + +int __init i8259_of_init(struct device_node *node, struct device_node *parent) +{ + struct irq_domain *domain; + unsigned int parent_irq; + + parent_irq = irq_of_parse_and_map(node, 0); + if (!parent_irq) { + pr_err("Failed to map i8259 parent IRQ\n"); + return -ENODEV; + } + + domain = __init_i8259_irqs(node); + irq_set_handler_data(parent_irq, domain); + irq_set_chained_handler(parent_irq, i8259_irq_dispatch); + return 0; +} +IRQCHIP_DECLARE(i8259, "intel,i8259", i8259_of_init); -- cgit v0.10.2 From 4ba375016f0234f8d8e7572494eac09d0b1a7252 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 31 Jul 2015 21:59:10 +0200 Subject: irqchip/i8259: Prepare i8259_irq_dispatch for irq argument removal Make irq a local variable and retrieve domain from the irq descriptor which avoid a redundant lookup. Signed-off-by: Thomas Gleixner Cc: Ralf Baechle diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c index a29638a..4836102 100644 --- a/drivers/irqchip/irq-i8259.c +++ b/drivers/irqchip/irq-i8259.c @@ -352,10 +352,11 @@ void __init init_i8259_irqs(void) __init_i8259_irqs(NULL); } -static void i8259_irq_dispatch(unsigned int irq, struct irq_desc *desc) +static void i8259_irq_dispatch(unsigned int __irq, struct irq_desc *desc) { - struct irq_domain *domain = irq_get_handler_data(irq); + struct irq_domain *domain = irq_desc_get_handler_data(desc); int hwirq = i8259_irq(); + unsigned int irq; if (hwirq < 0) return; -- cgit v0.10.2 From 9d03e784bc225e7ccaa53bcdb64c8ebf96f153d7 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:31 +0800 Subject: mn10300/irq: Use access helper irq_data_get_affinity_mask() Use access helper irq_data_get_affinity_mask() to hide implementation details of struct irq_desc. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: linux-am33-list@redhat.com Cc: Bjorn Helgaas Cc: Benjamin Herrenschmidt Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Cc: David Howells Cc: Koichi Yasutake Link: http://lkml.kernel.org/r/1433145945-789-23-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/mn10300/kernel/cevt-mn10300.c b/arch/mn10300/kernel/cevt-mn10300.c index 60f64ca..326677d 100644 --- a/arch/mn10300/kernel/cevt-mn10300.c +++ b/arch/mn10300/kernel/cevt-mn10300.c @@ -123,7 +123,7 @@ int __init init_clockevents(void) { struct irq_data *data; data = irq_get_irq_data(cd->irq); - cpumask_copy(data->affinity, cpumask_of(cpu)); + cpumask_copy(irq_data_get_affinity_mask(data), cpumask_of(cpu)); iact->flags |= IRQF_NOBALANCING; } #endif diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c index 480de70..c716437 100644 --- a/arch/mn10300/kernel/irq.c +++ b/arch/mn10300/kernel/irq.c @@ -87,7 +87,8 @@ static void mn10300_cpupic_mask_ack(struct irq_data *d) tmp2 = GxICR(irq); irq_affinity_online[irq] = - cpumask_any_and(d->affinity, cpu_online_mask); + cpumask_any_and(irq_data_get_affinity_mask(d), + cpu_online_mask); CROSS_GxICR(irq, irq_affinity_online[irq]) = (tmp & (GxICR_LEVEL | GxICR_ENABLE)) | GxICR_DETECT; tmp = CROSS_GxICR(irq, irq_affinity_online[irq]); @@ -124,7 +125,7 @@ static void mn10300_cpupic_unmask_clear(struct irq_data *d) } else { tmp = GxICR(irq); - irq_affinity_online[irq] = cpumask_any_and(d->affinity, + irq_affinity_online[irq] = cpumask_any_and(irq_data_get_affinity_mask(d), cpu_online_mask); CROSS_GxICR(irq, irq_affinity_online[irq]) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT; tmp = CROSS_GxICR(irq, irq_affinity_online[irq]); @@ -316,15 +317,16 @@ void migrate_irqs(void) self = smp_processor_id(); for (irq = 0; irq < NR_IRQS; irq++) { struct irq_data *data = irq_get_irq_data(irq); + struct cpumask *mask = irq_data_get_affinity_mask(data); if (irqd_is_per_cpu(data)) continue; - if (cpumask_test_cpu(self, data->affinity) && + if (cpumask_test_cpu(self, mask) && !cpumask_intersects(&irq_affinity[irq], cpu_online_mask)) { int cpu_id; cpu_id = cpumask_first(cpu_online_mask); - cpumask_set_cpu(cpu_id, data->affinity); + cpumask_set_cpu(cpu_id, mask); } /* We need to operate irq_affinity_online atomically. */ arch_local_cli_save(flags); @@ -335,8 +337,7 @@ void migrate_irqs(void) GxICR(irq) = x & GxICR_LEVEL; tmp = GxICR(irq); - new = cpumask_any_and(data->affinity, - cpu_online_mask); + new = cpumask_any_and(mask, cpu_online_mask); irq_affinity_online[irq] = new; CROSS_GxICR(irq, new) = -- cgit v0.10.2 From d2109a12198edf22eb85e475c223eea14b9c3fbe Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:32 +0800 Subject: parisc/irq: Use access helper irq_data_get_affinity_mask() Use access helper irq_data_get_affinity_mask() to hide implementation details of struct irq_desc. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Bjorn Helgaas Cc: Benjamin Herrenschmidt Cc: Randy Dunlap Cc: Yinghai Lu Cc: Borislav Petkov Cc: James E.J. Bottomley Cc: Helge Deller Link: http://lkml.kernel.org/r/1433145945-789-24-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index f3191db..413ec3c 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -131,7 +131,7 @@ static int cpu_set_affinity_irq(struct irq_data *d, const struct cpumask *dest, if (cpu_dest < 0) return -1; - cpumask_copy(d->affinity, dest); + cpumask_copy(irq_data_get_affinity_mask(d), dest); return 0; } @@ -339,7 +339,7 @@ unsigned long txn_affinity_addr(unsigned int irq, int cpu) { #ifdef CONFIG_SMP struct irq_data *d = irq_get_irq_data(irq); - cpumask_copy(d->affinity, cpumask_of(cpu)); + cpumask_copy(irq_data_get_affinity_mask(d), cpumask_of(cpu)); #endif return per_cpu(cpu_data, cpu).txn_addr; @@ -508,7 +508,7 @@ void do_cpu_irq_mask(struct pt_regs *regs) unsigned long eirr_val; int irq, cpu = smp_processor_id(); #ifdef CONFIG_SMP - struct irq_desc *desc; + struct irq_data *irq_data; cpumask_t dest; #endif @@ -522,9 +522,9 @@ void do_cpu_irq_mask(struct pt_regs *regs) irq = eirr_to_irq(eirr_val); #ifdef CONFIG_SMP - desc = irq_to_desc(irq); - cpumask_copy(&dest, desc->irq_data.affinity); - if (irqd_is_per_cpu(&desc->irq_data) && + irq_data = irq_get_irq_data(irq); + cpumask_copy(&dest, irq_data_get_affinity_mask(irq_data)); + if (irqd_is_per_cpu(irq_data) && !cpumask_test_cpu(smp_processor_id(), &dest)) { int cpu = cpumask_first(&dest); diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 9ee04b4..144c77d 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -691,7 +691,7 @@ static int iosapic_set_affinity_irq(struct irq_data *d, if (dest_cpu < 0) return -1; - cpumask_copy(d->affinity, cpumask_of(dest_cpu)); + cpumask_copy(irq_data_get_affinity_mask(d), cpumask_of(dest_cpu)); vi->txn_addr = txn_affinity_addr(d->irq, dest_cpu); spin_lock_irqsave(&iosapic_lock, flags); -- cgit v0.10.2 From 6a4a5b34c315be04abdc366cda7a00b7249550f3 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:17 +0800 Subject: sparc/irq: Use helper irq_data_get_irq_handler_data() Use helper function irq_data_get_irq_handler_data() to hide irq_desc implementation details. This allows to move irq_data->handler_data to irq_data_common, once all usage sites are converted. Signed-off-by: Jiang Liu Cc: David S. Miller Link: http://lkml.kernel.org/r/1433145945-789-9-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index 4033c23..5130f6e 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c @@ -210,21 +210,21 @@ struct irq_handler_data { static inline unsigned int irq_data_to_handle(struct irq_data *data) { - struct irq_handler_data *ihd = data->handler_data; + struct irq_handler_data *ihd = irq_data_get_irq_handler_data(data); return ihd->dev_handle; } static inline unsigned int irq_data_to_ino(struct irq_data *data) { - struct irq_handler_data *ihd = data->handler_data; + struct irq_handler_data *ihd = irq_data_get_irq_handler_data(data); return ihd->dev_ino; } static inline unsigned long irq_data_to_sysino(struct irq_data *data) { - struct irq_handler_data *ihd = data->handler_data; + struct irq_handler_data *ihd = irq_data_get_irq_handler_data(data); return ihd->sysino; } @@ -370,8 +370,9 @@ static int irq_choose_cpu(unsigned int irq, const struct cpumask *affinity) static void sun4u_irq_enable(struct irq_data *data) { - struct irq_handler_data *handler_data = data->handler_data; + struct irq_handler_data *handler_data; + handler_data = irq_data_get_irq_handler_data(data); if (likely(handler_data)) { unsigned long cpuid, imap, val; unsigned int tid; @@ -393,8 +394,9 @@ static void sun4u_irq_enable(struct irq_data *data) static int sun4u_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force) { - struct irq_handler_data *handler_data = data->handler_data; + struct irq_handler_data *handler_data; + handler_data = irq_data_get_irq_handler_data(data); if (likely(handler_data)) { unsigned long cpuid, imap, val; unsigned int tid; @@ -438,8 +440,9 @@ static void sun4u_irq_disable(struct irq_data *data) static void sun4u_irq_eoi(struct irq_data *data) { - struct irq_handler_data *handler_data = data->handler_data; + struct irq_handler_data *handler_data; + handler_data = irq_data_get_irq_handler_data(data); if (likely(handler_data)) upa_writeq(ICLR_IDLE, handler_data->iclr); } diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index a1bb267..a87d0e4 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -188,7 +188,7 @@ void sun4d_handler_irq(unsigned int pil, struct pt_regs *regs) static void sun4d_mask_irq(struct irq_data *data) { - struct sun4d_handler_data *handler_data = data->handler_data; + struct sun4d_handler_data *handler_data = irq_data_get_irq_handler_data(data); unsigned int real_irq; #ifdef CONFIG_SMP int cpuid = handler_data->cpuid; @@ -206,7 +206,7 @@ static void sun4d_mask_irq(struct irq_data *data) static void sun4d_unmask_irq(struct irq_data *data) { - struct sun4d_handler_data *handler_data = data->handler_data; + struct sun4d_handler_data *handler_data = irq_data_get_irq_handler_data(data); unsigned int real_irq; #ifdef CONFIG_SMP int cpuid = handler_data->cpuid; diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 8bb3b3f..da737c7 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -188,9 +188,10 @@ static unsigned long sun4m_imask[0x50] = { static void sun4m_mask_irq(struct irq_data *data) { - struct sun4m_handler_data *handler_data = data->handler_data; + struct sun4m_handler_data *handler_data; int cpu = smp_processor_id(); + handler_data = irq_data_get_irq_handler_data(data); if (handler_data->mask) { unsigned long flags; @@ -206,9 +207,10 @@ static void sun4m_mask_irq(struct irq_data *data) static void sun4m_unmask_irq(struct irq_data *data) { - struct sun4m_handler_data *handler_data = data->handler_data; + struct sun4m_handler_data *handler_data; int cpu = smp_processor_id(); + handler_data = irq_data_get_irq_handler_data(data); if (handler_data->mask) { unsigned long flags; -- cgit v0.10.2 From d7185a98d576e33982cd28e65889b3e4122fe5d8 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:35 +0800 Subject: sparc/irq: Use access helper irq_data_get_affinity_mask() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Cc: David S. Miller Link: http://lkml.kernel.org/r/1433145945-789-27-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index 5130f6e..e22416c 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c @@ -377,7 +377,8 @@ static void sun4u_irq_enable(struct irq_data *data) unsigned long cpuid, imap, val; unsigned int tid; - cpuid = irq_choose_cpu(data->irq, data->affinity); + cpuid = irq_choose_cpu(data->irq, + irq_data_get_affinity_mask(data)); imap = handler_data->imap; tid = sun4u_compute_tid(imap, cpuid); @@ -449,7 +450,8 @@ static void sun4u_irq_eoi(struct irq_data *data) static void sun4v_irq_enable(struct irq_data *data) { - unsigned long cpuid = irq_choose_cpu(data->irq, data->affinity); + unsigned long cpuid = irq_choose_cpu(data->irq, + irq_data_get_affinity_mask(data)); unsigned int ino = irq_data_to_sysino(data); int err; @@ -511,7 +513,7 @@ static void sun4v_virq_enable(struct irq_data *data) unsigned long cpuid; int err; - cpuid = irq_choose_cpu(data->irq, data->affinity); + cpuid = irq_choose_cpu(data->irq, irq_data_get_affinity_mask(data)); err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid); if (err != HV_EOK) @@ -884,8 +886,8 @@ void fixup_irqs(void) if (desc->action && !irqd_is_per_cpu(data)) { if (data->chip->irq_set_affinity) data->chip->irq_set_affinity(data, - data->affinity, - false); + irq_data_get_affinity_mask(data), + false); } raw_spin_unlock_irqrestore(&desc->lock, flags); } diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 9bbb8f2..0299f05 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -126,7 +126,7 @@ static int leon_set_affinity(struct irq_data *data, const struct cpumask *dest, int oldcpu, newcpu; mask = (unsigned long)data->chip_data; - oldcpu = irq_choose_cpu(data->affinity); + oldcpu = irq_choose_cpu(irq_data_get_affinity_mask(data)); newcpu = irq_choose_cpu(dest); if (oldcpu == newcpu) @@ -149,7 +149,7 @@ static void leon_unmask_irq(struct irq_data *data) int cpu; mask = (unsigned long)data->chip_data; - cpu = irq_choose_cpu(data->affinity); + cpu = irq_choose_cpu(irq_data_get_affinity_mask(data)); spin_lock_irqsave(&leon_irq_lock, flags); oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(cpu)); LEON3_BYPASS_STORE_PA(LEON_IMASK(cpu), (oldmask | mask)); @@ -162,7 +162,7 @@ static void leon_mask_irq(struct irq_data *data) int cpu; mask = (unsigned long)data->chip_data; - cpu = irq_choose_cpu(data->affinity); + cpu = irq_choose_cpu(irq_data_get_affinity_mask(data)); spin_lock_irqsave(&leon_irq_lock, flags); oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(cpu)); LEON3_BYPASS_STORE_PA(LEON_IMASK(cpu), (oldmask & ~mask)); -- cgit v0.10.2 From badae6bc94ac0614240d93428350049fa891fcad Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 31 Jul 2015 21:47:35 +0200 Subject: arc/irq: Prepare idu_cascade_isr for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Vineet Gupta diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c index 2fb8658..d9e44b6 100644 --- a/arch/arc/kernel/mcip.c +++ b/arch/arc/kernel/mcip.c @@ -252,9 +252,10 @@ static struct irq_chip idu_irq_chip = { static int idu_first_irq; -static void idu_cascade_isr(unsigned int core_irq, struct irq_desc *desc) +static void idu_cascade_isr(unsigned int __core_irq, struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); + unsigned int core_irq = irq_desc_get_irq(desc); unsigned int idu_irq; idu_irq = core_irq - idu_first_irq; -- cgit v0.10.2 From 2b501769c442cf3d2abf388651fa17f46dcd0e5f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 31 Jul 2015 21:50:30 +0200 Subject: blackfin: Prepare irq handlers for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Steven Miao Cc: adi-buildroot-devel@lists.sourceforge.net diff --git a/arch/blackfin/mach-bf537/ints-priority.c b/arch/blackfin/mach-bf537/ints-priority.c index 2137a20..14b2f74 100644 --- a/arch/blackfin/mach-bf537/ints-priority.c +++ b/arch/blackfin/mach-bf537/ints-priority.c @@ -182,9 +182,11 @@ static struct irq_chip bf537_mac_rx_irqchip = { .irq_unmask = bf537_mac_rx_unmask_irq, }; -static void bf537_demux_mac_rx_irq(unsigned int int_irq, +static void bf537_demux_mac_rx_irq(unsigned int __int_irq, struct irq_desc *desc) { + unsigned int int_irq = irq_desc_get_irq(desc); + if (bfin_read_DMA1_IRQ_STATUS() & (DMA_DONE | DMA_ERR)) bfin_handle_irq(IRQ_MAC_RX); else diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index 2eaf83a..a6d1b03 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -825,9 +825,9 @@ static void bfin_demux_gpio_block(unsigned int irq) } } -void bfin_demux_gpio_irq(unsigned int inta_irq, - struct irq_desc *desc) +void bfin_demux_gpio_irq(unsigned int __inta_irq, struct irq_desc *desc) { + unsigned int inta_irq = irq_desc_get_irq(desc); unsigned int irq; switch (inta_irq) { -- cgit v0.10.2 From 88bd64628f4f170491b47b90d772a229b0082859 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 31 Jul 2015 21:53:12 +0200 Subject: C6X/megamode-pic: Prepare megamod_irq_cascade for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Mark Salter Cc: linux-c6x-dev@linux-c6x.org diff --git a/arch/c6x/platforms/megamod-pic.c b/arch/c6x/platforms/megamod-pic.c index 349bc01..d487698 100644 --- a/arch/c6x/platforms/megamod-pic.c +++ b/arch/c6x/platforms/megamod-pic.c @@ -93,10 +93,11 @@ static struct irq_chip megamod_chip = { .irq_unmask = unmask_megamod, }; -static void megamod_irq_cascade(unsigned int irq, struct irq_desc *desc) +static void megamod_irq_cascade(unsigned int __irq, struct irq_desc *desc) { struct megamod_cascade_data *cascade; struct megamod_pic *pic; + unsigned int irq; u32 events; int n, idx; -- cgit v0.10.2 From 625b86ad26ad35200adc34094c04e04672384735 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 31 Jul 2015 21:56:10 +0200 Subject: m68k/irq: Prepare irq handlers for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org diff --git a/arch/m68k/coldfire/intc-5272.c b/arch/m68k/coldfire/intc-5272.c index d1e2fba..47371de 100644 --- a/arch/m68k/coldfire/intc-5272.c +++ b/arch/m68k/coldfire/intc-5272.c @@ -143,8 +143,10 @@ static int intc_irq_set_type(struct irq_data *d, unsigned int type) * We need to be careful with the masking/acking due to the side effects * of masking an interrupt. */ -static void intc_external_irq(unsigned int irq, struct irq_desc *desc) +static void intc_external_irq(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); + irq_desc_get_chip(desc)->irq_ack(&desc->irq_data); handle_simple_irq(irq, desc); } diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c index bb11dce..191610d 100644 --- a/arch/m68k/mac/oss.c +++ b/arch/m68k/mac/oss.c @@ -63,13 +63,15 @@ void __init oss_nubus_init(void) * Handle miscellaneous OSS interrupts. */ -static void oss_irq(unsigned int irq, struct irq_desc *desc) +static void oss_irq(unsigned int __irq, struct irq_desc *desc) { int events = oss->irq_pending & - (OSS_IP_IOPSCC | OSS_IP_SCSI | OSS_IP_IOPISM); + (OSS_IP_IOPSCC | OSS_IP_SCSI | OSS_IP_IOPISM); #ifdef DEBUG_IRQS if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) { + unsigned int irq = irq_desc_get_irq(desc); + printk("oss_irq: irq %u events = 0x%04X\n", irq, (int) oss->irq_pending); } diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c index 272dde4..3b9e302 100644 --- a/arch/m68k/mac/psc.c +++ b/arch/m68k/mac/psc.c @@ -113,9 +113,10 @@ void __init psc_init(void) * PSC interrupt handler. It's a lot like the VIA interrupt handler. */ -static void psc_irq(unsigned int irq, struct irq_desc *desc) +static void psc_irq(unsigned int __irq, struct irq_desc *desc) { unsigned int offset = (unsigned int)irq_desc_get_handler_data(desc); + unsigned int irq = irq_desc_get_irq(desc); int pIFR = pIFRbase + offset; int pIER = pIERbase + offset; int irq_num; -- cgit v0.10.2 From f5dbdd429f044b9658e27e76a0e896a99f03170f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 31 Jul 2015 22:07:40 +0200 Subject: tile/pci_gx: Prepare trio_handle_level_irq for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Chris Metcalf diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c index 65b701b..b3f73fd 100644 --- a/arch/tile/kernel/pci_gx.c +++ b/arch/tile/kernel/pci_gx.c @@ -304,11 +304,12 @@ static struct irq_chip tilegx_legacy_irq_chip = { * to Linux which just calls handle_level_irq() after clearing the * MAC INTx Assert status bit associated with this interrupt. */ -static void trio_handle_level_irq(unsigned int irq, struct irq_desc *desc) +static void trio_handle_level_irq(unsigned int __irq, struct irq_desc *desc) { struct pci_controller *controller = irq_desc_get_handler_data(desc); gxio_trio_context_t *trio_context = controller->trio; uint64_t intx = (uint64_t)irq_desc_get_chip_data(desc); + unsigned int irq = irq_desc_get_irq(desc); int mac = controller->mac; unsigned int reg_offset; uint64_t level_mask; -- cgit v0.10.2 From f70229e2a342714c7431547676da2518a0a22b55 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 31 Jul 2015 22:09:38 +0200 Subject: unicore32/irq: Prepare puv3_gpio_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Guan Xuetao diff --git a/arch/unicore32/kernel/irq.c b/arch/unicore32/kernel/irq.c index 0be5ccd..c53729d 100644 --- a/arch/unicore32/kernel/irq.c +++ b/arch/unicore32/kernel/irq.c @@ -112,10 +112,9 @@ static struct irq_chip puv3_low_gpio_chip = { * irq_controller_lock held, and IRQs disabled. Decode the IRQ * and call the handler. */ -static void -puv3_gpio_handler(unsigned int irq, struct irq_desc *desc) +static void puv3_gpio_handler(unsigned int __irq, struct irq_desc *desc) { - unsigned int mask; + unsigned int mask, irq; mask = readl(GPIO_GEDR); do { -- cgit v0.10.2 From 36f024ed8fc96f50f01d171097237ebe51dadee7 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 31 Jul 2015 22:12:29 +0200 Subject: PCI/MSI: pci-xgene-msi: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Duc Dang diff --git a/drivers/pci/host/pci-xgene-msi.c b/drivers/pci/host/pci-xgene-msi.c index ec5a14b..23456b9 100644 --- a/drivers/pci/host/pci-xgene-msi.c +++ b/drivers/pci/host/pci-xgene-msi.c @@ -368,10 +368,8 @@ static int xgene_msi_remove(struct platform_device *pdev) for (i = 0; i < NR_HW_IRQS; i++) { virq = msi->msi_groups[i].gic_irq; - if (virq != 0) { - irq_set_chained_handler(virq, NULL); - irq_set_handler_data(virq, NULL); - } + if (virq != 0) + irq_set_chained_handler_and_data(virq, NULL, NULL); } kfree(msi->msi_groups); @@ -421,8 +419,8 @@ static int xgene_msi_hwirq_alloc(unsigned int cpu) } if (err) { - irq_set_chained_handler(msi_group->gic_irq, NULL); - irq_set_handler_data(msi_group->gic_irq, NULL); + irq_set_chained_handler_and_data(msi_group->gic_irq, + NULL, NULL); return err; } } @@ -441,8 +439,8 @@ static void xgene_msi_hwirq_free(unsigned int cpu) if (!msi_group->gic_irq) continue; - irq_set_chained_handler(msi_group->gic_irq, NULL); - irq_set_handler_data(msi_group->gic_irq, NULL); + irq_set_chained_handler_and_data(msi_group->gic_irq, NULL, + NULL); } } -- cgit v0.10.2 From 567e5a014848c6aeb1d6fc862b1b5d0183760259 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 31 Jul 2015 09:44:11 +0100 Subject: irqchip/gic: Only allow the primary GIC to set the CPU map The gic_init_bases() function initialises an array that stores the mapping between the GIC and CPUs. This array is a global array that is unconditionally initialised on every call to gic_init_bases(). Although, it is not common for there to be more than one GIC instance, there are some devices that do support nested GIC controllers and gic_init_bases() can be called more than once. A 2nd call to gic_init_bases() will clear the previous CPU mapping and will only setup the mapping again for the CPU calling gic_init_bases(). Fix this by only allowing the CPU map to be configured for the primary GIC. For secondary GICs the CPU map is not relevant because these GICs do not directly route the interrupts to the main CPU(s) but to other GICs or devices. Signed-off-by: Jon Hunter Reviewed-by: Marc Zyngier Cc: Cc: Russell King Cc: Nicolas Pitre Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438332252-25248-1-git-send-email-jonathanh@nvidia.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 29c544d..84fc622 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -402,19 +402,26 @@ static void gic_cpu_init(struct gic_chip_data *gic) int i; /* - * Get what the GIC says our CPU mask is. + * Setting up the CPU map is only relevant for the primary GIC + * because any nested/secondary GICs do not directly interface + * with the CPU(s). */ - BUG_ON(cpu >= NR_GIC_CPU_IF); - cpu_mask = gic_get_cpumask(gic); - gic_cpu_map[cpu] = cpu_mask; + if (gic == &gic_data[0]) { + /* + * Get what the GIC says our CPU mask is. + */ + BUG_ON(cpu >= NR_GIC_CPU_IF); + cpu_mask = gic_get_cpumask(gic); + gic_cpu_map[cpu] = cpu_mask; - /* - * Clear our mask from the other map entries in case they're - * still undefined. - */ - for (i = 0; i < NR_GIC_CPU_IF; i++) - if (i != cpu) - gic_cpu_map[i] &= ~cpu_mask; + /* + * Clear our mask from the other map entries in case they're + * still undefined. + */ + for (i = 0; i < NR_GIC_CPU_IF; i++) + if (i != cpu) + gic_cpu_map[i] &= ~cpu_mask; + } gic_cpu_config(dist_base, NULL); @@ -926,13 +933,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, } /* - * Initialize the CPU interface map to all CPUs. - * It will be refined as each CPU probes its ID. - */ - for (i = 0; i < NR_GIC_CPU_IF; i++) - gic_cpu_map[i] = 0xff; - - /* * Find out how many interrupts are supported. * The GIC only supports up to 1020 interrupt sources. */ @@ -977,6 +977,13 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, return; if (gic_nr == 0) { + /* + * Initialize the CPU interface map to all CPUs. + * It will be refined as each CPU probes its ID. + * This is only necessary for the primary GIC. + */ + for (i = 0; i < NR_GIC_CPU_IF; i++) + gic_cpu_map[i] = 0xff; #ifdef CONFIG_SMP set_smp_cross_call(gic_raise_softirq); register_cpu_notifier(&gic_cpu_notifier); -- cgit v0.10.2 From 4c2880b31c700b03f3f115b5ca64be615783aa9c Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 31 Jul 2015 09:44:12 +0100 Subject: irqchip/gic: Ensure gic_cpu_if_up/down() programs correct GIC instance Commit 3228950621d9 ("irqchip: gic: Preserve gic V2 bypass bits in cpu ctrl register") added a new function, gic_cpu_if_up(), to program the GIC CPU_CTRL register. This function assumes that there is only one GIC instance present and hence always uses the chip data for the primary GIC controller. Although it is not common for there to be a secondary, some devices do support a secondary. Therefore, fix this by passing gic_cpu_if_up() a pointer to the appropriate chip data structure. Similarly, the function gic_cpu_if_down() only assumes that there is a single GIC instance present. Update this function so that an instance number is passed for the appropriate GIC and return an error code on failure. The vexpress TC2 (which has a single GIC) is currently the only user of this function and so update it accordingly. Note that because the TC2 only has a single GIC, the call to gic_cpu_if_down() should always be successful. Signed-off-by: Jon Hunter Reviewed-by: Marc Zyngier Cc: Cc: Russell King Cc: Nicolas Pitre Cc: Jason Cooper Link: http://lkml.kernel.org/r/1438332252-25248-2-git-send-email-jonathanh@nvidia.com Signed-off-by: Thomas Gleixner diff --git a/arch/arm/mach-vexpress/tc2_pm.c b/arch/arm/mach-vexpress/tc2_pm.c index b3328cd..1aa4cce 100644 --- a/arch/arm/mach-vexpress/tc2_pm.c +++ b/arch/arm/mach-vexpress/tc2_pm.c @@ -80,7 +80,7 @@ static void tc2_pm_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster) * to the CPU by disabling the GIC CPU IF to prevent wfi * from completing execution behind power controller back */ - gic_cpu_if_down(); + gic_cpu_if_down(0); } static void tc2_pm_cluster_powerdown_prepare(unsigned int cluster) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 84fc622..aa3e7b8 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -356,9 +356,9 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic) return mask; } -static void gic_cpu_if_up(void) +static void gic_cpu_if_up(struct gic_chip_data *gic) { - void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]); + void __iomem *cpu_base = gic_data_cpu_base(gic); u32 bypass = 0; /* @@ -426,17 +426,23 @@ static void gic_cpu_init(struct gic_chip_data *gic) gic_cpu_config(dist_base, NULL); writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK); - gic_cpu_if_up(); + gic_cpu_if_up(gic); } -void gic_cpu_if_down(void) +int gic_cpu_if_down(unsigned int gic_nr) { - void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]); + void __iomem *cpu_base; u32 val = 0; + if (gic_nr >= MAX_GIC_NR) + return -EINVAL; + + cpu_base = gic_data_cpu_base(&gic_data[gic_nr]); val = readl(cpu_base + GIC_CPU_CTRL); val &= ~GICC_ENABLE; writel_relaxed(val, cpu_base + GIC_CPU_CTRL); + + return 0; } #ifdef CONFIG_CPU_PM @@ -572,7 +578,7 @@ static void gic_cpu_restore(unsigned int gic_nr) dist_base + GIC_DIST_PRI + i * 4); writel_relaxed(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK); - gic_cpu_if_up(); + gic_cpu_if_up(&gic_data[gic_nr]); } static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v) diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 61a2007..65da435 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -98,7 +98,7 @@ struct device_node; void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *, u32 offset, struct device_node *); void gic_cascade_irq(unsigned int gic_nr, unsigned int irq); -void gic_cpu_if_down(void); +int gic_cpu_if_down(unsigned int gic_nr); static inline void gic_init(unsigned int nr, int start, void __iomem *dist , void __iomem *cpu) -- cgit v0.10.2 From 649953b5b89dc308747797810812747333d971cd Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 18 Aug 2015 23:45:55 +0800 Subject: PCI: xilinx: Fix typo in function name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's a typo in commit e39758e0ea76 in linux-next, which incorrectly spells "msi_desc_to_pci_sysdata()" as "msi_desc_to_pci_sys_data()" and causes build failure: > ../drivers/pci/host/pcie-xilinx.c:235:3: error: implicit declaration of function 'msi_desc_to_pci_sys_data' [-Werror=implicit-function-declaration] Fixes: e39758e0ea76 "PCI: Use helper functions to access fields in struct msi_desc" Signed-off-by: Jiang Liu Cc: linux-arm-kernel@lists.infradead.org Cc: Mark Brown Cc: Stephen Rothwell Cc: Bjorn Helgaas Cc: Michal Simek Cc: Sören Brinkmann Cc: Srikanth Thokala Cc: Rob Herring Cc: Yijing Wang Link: http://lkml.kernel.org/r/1439912763-10645-1-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c index 64454f4..be494e4 100644 --- a/drivers/pci/host/pcie-xilinx.c +++ b/drivers/pci/host/pcie-xilinx.c @@ -232,7 +232,7 @@ static void xilinx_pcie_destroy_msi(unsigned int irq) if (!test_bit(irq, msi_irq_in_use)) { msi = irq_get_msi_desc(irq); - port = sys_to_pcie(msi_desc_to_pci_sys_data(msi)); + port = sys_to_pcie(msi_desc_to_pci_sysdata(msi)); dev_err(port->dev, "Trying to free unused MSI#%d\n", irq); } else { clear_bit(irq, msi_irq_in_use); -- cgit v0.10.2 From de58e52f207e3318cb1e1d43f951454e0c83827f Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 Aug 2015 16:00:30 -0700 Subject: irqchip/bcm2835: Refactor handle_IRQ() calls out of MAKE_HWIRQ For BCM2836, we want to chain into this IRQ chip from the root controller, and for chaining we need to do something else instead of handle_IRQ() once we have decoded the IRQ. Note that this changes the behavior a little bit: Previously for a non-shortcut IRQ, we'd loop reading and handling the second level IRQ status until it was cleared before returning to the loop reading the top level IRQ status (Note that the top level bit is just an OR of the low level bits). For the expected case of just one interrupt to be handled, this was an extra register read, so we're down from 4 to 3 reads. Signed-off-by: Eric Anholt Acked-by: Stephen Warren Cc: linux-rpi-kernel@lists.infradead.org Cc: Lee Jones Cc: Jason Cooper Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1438902033-31477-2-git-send-email-eric@anholt.net Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index ca35171..a40d972 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -178,44 +178,45 @@ static int __init armctrl_of_init(struct device_node *node, * handle_IRQ may briefly re-enable interrupts for soft IRQ handling. */ -static void armctrl_handle_bank(int bank, struct pt_regs *regs) +static u32 armctrl_translate_bank(int bank) { - u32 stat, irq; + u32 stat = readl_relaxed(intc.pending[bank]); - while ((stat = readl_relaxed(intc.pending[bank]))) { - irq = MAKE_HWIRQ(bank, ffs(stat) - 1); - handle_IRQ(irq_linear_revmap(intc.domain, irq), regs); - } + return MAKE_HWIRQ(bank, ffs(stat) - 1); +} + +static u32 armctrl_translate_shortcut(int bank, u32 stat) +{ + return MAKE_HWIRQ(bank, shortcuts[ffs(stat >> SHORTCUT_SHIFT) - 1]); } -static void armctrl_handle_shortcut(int bank, struct pt_regs *regs, - u32 stat) +static u32 get_next_armctrl_hwirq(void) { - u32 irq = MAKE_HWIRQ(bank, shortcuts[ffs(stat >> SHORTCUT_SHIFT) - 1]); - handle_IRQ(irq_linear_revmap(intc.domain, irq), regs); + u32 stat = readl_relaxed(intc.pending[0]) & BANK0_VALID_MASK; + + if (stat == 0) + return ~0; + else if (stat & BANK0_HWIRQ_MASK) + return MAKE_HWIRQ(0, ffs(stat & BANK0_HWIRQ_MASK) - 1); + else if (stat & SHORTCUT1_MASK) + return armctrl_translate_shortcut(1, stat & SHORTCUT1_MASK); + else if (stat & SHORTCUT2_MASK) + return armctrl_translate_shortcut(2, stat & SHORTCUT2_MASK); + else if (stat & BANK1_HWIRQ) + return armctrl_translate_bank(1); + else if (stat & BANK2_HWIRQ) + return armctrl_translate_bank(2); + else + BUG(); } static void __exception_irq_entry bcm2835_handle_irq( struct pt_regs *regs) { - u32 stat, irq; - - while ((stat = readl_relaxed(intc.pending[0]) & BANK0_VALID_MASK)) { - if (stat & BANK0_HWIRQ_MASK) { - irq = MAKE_HWIRQ(0, ffs(stat & BANK0_HWIRQ_MASK) - 1); - handle_IRQ(irq_linear_revmap(intc.domain, irq), regs); - } else if (stat & SHORTCUT1_MASK) { - armctrl_handle_shortcut(1, regs, stat & SHORTCUT1_MASK); - } else if (stat & SHORTCUT2_MASK) { - armctrl_handle_shortcut(2, regs, stat & SHORTCUT2_MASK); - } else if (stat & BANK1_HWIRQ) { - armctrl_handle_bank(1, regs); - } else if (stat & BANK2_HWIRQ) { - armctrl_handle_bank(2, regs); - } else { - BUG(); - } - } + u32 hwirq; + + while ((hwirq = get_next_armctrl_hwirq()) != ~0) + handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs); } IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic", armctrl_of_init); -- cgit v0.10.2 From a493f339a88ddd20693460c1dcf8230aa3732b8b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 Aug 2015 16:00:31 -0700 Subject: irqchip/bcm2835: Add support for being used as a second level controller The BCM2836 (Raspberry Pi 2) uses two levels of interrupt handling with the CPU-local interrupts being the root, so we need to register ours as chained off of the CPU's local interrupt. Signed-off-by: Eric Anholt Acked-by: Stephen Warren Cc: linux-rpi-kernel@lists.infradead.org Cc: Lee Jones Cc: Jason Cooper Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1438902033-31477-3-git-send-email-eric@anholt.net Signed-off-by: Thomas Gleixner diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt index 7da578d..2d6c8bb 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt @@ -5,9 +5,14 @@ The BCM2835 contains a custom top-level interrupt controller, which supports controller, or the HW block containing it, is referred to occasionally as "armctrl" in the SoC documentation, hence naming of this binding. +The BCM2836 contains the same interrupt controller with the same +interrupts, but the per-CPU interrupt controller is the root, and an +interrupt there indicates that the ARMCTRL has an interrupt to handle. + Required properties: -- compatible : should be "brcm,bcm2835-armctrl-ic" +- compatible : should be "brcm,bcm2835-armctrl-ic" or + "brcm,bcm2836-armctrl-ic" - reg : Specifies base physical address and size of the registers. - interrupt-controller : Identifies the node as an interrupt controller - #interrupt-cells : Specifies the number of cells needed to encode an @@ -20,6 +25,12 @@ Required properties: The 2nd cell contains the interrupt number within the bank. Valid values are 0..7 for bank 0, and 0..31 for bank 1. +Additional required properties for brcm,bcm2836-armctrl-ic: +- interrupt-parent : Specifies the parent interrupt controller when this + controller is the second level. +- interrupts : Specifies the interrupt on the parent for this interrupt + controller to handle. + The interrupt sources are as follows: Bank 0: @@ -102,9 +113,21 @@ Bank 2: Example: +/* BCM2835, first level */ intc: interrupt-controller { compatible = "brcm,bcm2835-armctrl-ic"; reg = <0x7e00b200 0x200>; interrupt-controller; #interrupt-cells = <2>; }; + +/* BCM2836, second level */ +intc: interrupt-controller { + compatible = "brcm,bcm2836-armctrl-ic"; + reg = <0x7e00b200 0x200>; + interrupt-controller; + #interrupt-cells = <2>; + + interrupt-parent = <&local_intc>; + interrupts = <8>; +}; diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index a40d972..ed4ca9d 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -96,6 +96,7 @@ struct armctrl_ic { static struct armctrl_ic intc __read_mostly; static void __exception_irq_entry bcm2835_handle_irq( struct pt_regs *regs); +static void bcm2836_chained_handle_irq(unsigned int irq, struct irq_desc *desc); static void armctrl_mask_irq(struct irq_data *d) { @@ -139,7 +140,8 @@ static const struct irq_domain_ops armctrl_ops = { }; static int __init armctrl_of_init(struct device_node *node, - struct device_node *parent) + struct device_node *parent, + bool is_2836) { void __iomem *base; int irq, b, i; @@ -168,10 +170,34 @@ static int __init armctrl_of_init(struct device_node *node, } } - set_handle_irq(bcm2835_handle_irq); + if (is_2836) { + int parent_irq = irq_of_parse_and_map(node, 0); + + if (!parent_irq) { + panic("%s: unable to get parent interrupt.\n", + node->full_name); + } + irq_set_chained_handler(parent_irq, bcm2836_chained_handle_irq); + } else { + set_handle_irq(bcm2835_handle_irq); + } + return 0; } +static int __init bcm2835_armctrl_of_init(struct device_node *node, + struct device_node *parent) +{ + return armctrl_of_init(node, parent, false); +} + +static int __init bcm2836_armctrl_of_init(struct device_node *node, + struct device_node *parent) +{ + return armctrl_of_init(node, parent, true); +} + + /* * Handle each interrupt across the entire interrupt controller. This reads the * status register before handling each interrupt, which is necessary given that @@ -219,4 +245,15 @@ static void __exception_irq_entry bcm2835_handle_irq( handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs); } -IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic", armctrl_of_init); +static void bcm2836_chained_handle_irq(unsigned int irq, struct irq_desc *desc) +{ + u32 hwirq; + + while ((hwirq = get_next_armctrl_hwirq()) != ~0) + generic_handle_irq(irq_linear_revmap(intc.domain, hwirq)); +} + +IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic", + bcm2835_armctrl_of_init); +IRQCHIP_DECLARE(bcm2836_armctrl_ic, "brcm,bcm2836-armctrl-ic", + bcm2836_armctrl_of_init); -- cgit v0.10.2 From 815e7a31c3f7929f371da9c7e9ee91cfd52ef453 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 Aug 2015 16:00:32 -0700 Subject: irqchip: Add documentation for the bcm2836 interrupt controller This is a new per-cpu root interrupt controller on the Raspberry Pi 2, which will chain to the bcm2835 interrupt controller for peripheral interrupts. Signed-off-by: Eric Anholt Acked-by: Stephen Warren Cc: linux-rpi-kernel@lists.infradead.org Cc: Lee Jones Cc: Jason Cooper Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1438902033-31477-4-git-send-email-eric@anholt.net Signed-off-by: Thomas Gleixner diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt new file mode 100644 index 0000000..f320dcd --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm2836-l1-intc.txt @@ -0,0 +1,37 @@ +BCM2836 per-CPU interrupt controller + +The BCM2836 has a per-cpu interrupt controller for the timer, PMU +events, and SMP IPIs. One of the CPUs may receive interrupts for the +peripheral (GPU) events, which chain to the BCM2835-style interrupt +controller. + +Required properties: + +- compatible: Should be "brcm,bcm2836-l1-intc" +- reg: Specifies base physical address and size of the + registers +- interrupt-controller: Identifies the node as an interrupt controller +- #interrupt-cells: Specifies the number of cells needed to encode an + interrupt source. The value shall be 1 + +Please refer to interrupts.txt in this directory for details of the common +Interrupt Controllers bindings used by client devices. + +The interrupt sources are as follows: + +0: CNTPSIRQ +1: CNTPNSIRQ +2: CNTHPIRQ +3: CNTVIRQ +8: GPU_FAST +9: PMU_FAST + +Example: + +local_intc: local_intc { + compatible = "brcm,bcm2836-l1-intc"; + reg = <0x40000000 0x100>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&local_intc>; +}; -- cgit v0.10.2 From 1a15aaa998dc3b51f7f8b9a820bc7a192a0c2f76 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 6 Aug 2015 16:00:33 -0700 Subject: irqchip: Add bcm2836 interrupt controller for Raspberry Pi 2 This interrupt controller is the new root interrupt controller with the timer, PMU events, and IPIs, and the bcm2835's interrupt controller is chained off of it to handle the peripherals. I wrote the interrupt chip support, while Andrea Merello wrote the IPI code. Signed-off-by: Andrea Merello Signed-off-by: Eric Anholt Acked-by: Stephen Warren Cc: linux-rpi-kernel@lists.infradead.org Cc: Lee Jones Cc: Jason Cooper Cc: linux-arm-kernel@lists.infradead.org Link: http://lkml.kernel.org/r/1438902033-31477-5-git-send-email-eric@anholt.net Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index d4c5e56..e5e0069 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_IRQCHIP) += irqchip.o obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o +obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o obj-$(CONFIG_ARCH_MMP) += irq-mmp.o diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c new file mode 100644 index 0000000..f687082 --- /dev/null +++ b/drivers/irqchip/irq-bcm2836.c @@ -0,0 +1,275 @@ +/* + * Root interrupt controller for the BCM2836 (Raspberry Pi 2). + * + * Copyright 2015 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +/* + * The low 2 bits identify the CPU that the GPU IRQ goes to, and the + * next 2 bits identify the CPU that the GPU FIQ goes to. + */ +#define LOCAL_GPU_ROUTING 0x00c +/* When setting bits 0-3, enables PMU interrupts on that CPU. */ +#define LOCAL_PM_ROUTING_SET 0x010 +/* When setting bits 0-3, disables PMU interrupts on that CPU. */ +#define LOCAL_PM_ROUTING_CLR 0x014 +/* + * The low 4 bits of this are the CPU's timer IRQ enables, and the + * next 4 bits are the CPU's timer FIQ enables (which override the IRQ + * bits). + */ +#define LOCAL_TIMER_INT_CONTROL0 0x040 +/* + * The low 4 bits of this are the CPU's per-mailbox IRQ enables, and + * the next 4 bits are the CPU's per-mailbox FIQ enables (which + * override the IRQ bits). + */ +#define LOCAL_MAILBOX_INT_CONTROL0 0x050 +/* + * The CPU's interrupt status register. Bits are defined by the the + * LOCAL_IRQ_* bits below. + */ +#define LOCAL_IRQ_PENDING0 0x060 +/* Same status bits as above, but for FIQ. */ +#define LOCAL_FIQ_PENDING0 0x070 +/* + * Mailbox0 write-to-set bits. There are 16 mailboxes, 4 per CPU, and + * these bits are organized by mailbox number and then CPU number. We + * use mailbox 0 for IPIs. The mailbox's interrupt is raised while + * any bit is set. + */ +#define LOCAL_MAILBOX0_SET0 0x080 +/* Mailbox0 write-to-clear bits. */ +#define LOCAL_MAILBOX0_CLR0 0x0c0 + +#define LOCAL_IRQ_CNTPSIRQ 0 +#define LOCAL_IRQ_CNTPNSIRQ 1 +#define LOCAL_IRQ_CNTHPIRQ 2 +#define LOCAL_IRQ_CNTVIRQ 3 +#define LOCAL_IRQ_MAILBOX0 4 +#define LOCAL_IRQ_MAILBOX1 5 +#define LOCAL_IRQ_MAILBOX2 6 +#define LOCAL_IRQ_MAILBOX3 7 +#define LOCAL_IRQ_GPU_FAST 8 +#define LOCAL_IRQ_PMU_FAST 9 +#define LAST_IRQ LOCAL_IRQ_PMU_FAST + +struct bcm2836_arm_irqchip_intc { + struct irq_domain *domain; + void __iomem *base; +}; + +static struct bcm2836_arm_irqchip_intc intc __read_mostly; + +static void bcm2836_arm_irqchip_mask_per_cpu_irq(unsigned int reg_offset, + unsigned int bit, + int cpu) +{ + void __iomem *reg = intc.base + reg_offset + 4 * cpu; + + writel(readl(reg) & ~BIT(bit), reg); +} + +static void bcm2836_arm_irqchip_unmask_per_cpu_irq(unsigned int reg_offset, + unsigned int bit, + int cpu) +{ + void __iomem *reg = intc.base + reg_offset + 4 * cpu; + + writel(readl(reg) | BIT(bit), reg); +} + +static void bcm2836_arm_irqchip_mask_timer_irq(struct irq_data *d) +{ + bcm2836_arm_irqchip_mask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0, + d->hwirq - LOCAL_IRQ_CNTPSIRQ, + smp_processor_id()); +} + +static void bcm2836_arm_irqchip_unmask_timer_irq(struct irq_data *d) +{ + bcm2836_arm_irqchip_unmask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0, + d->hwirq - LOCAL_IRQ_CNTPSIRQ, + smp_processor_id()); +} + +static struct irq_chip bcm2836_arm_irqchip_timer = { + .name = "bcm2836-timer", + .irq_mask = bcm2836_arm_irqchip_mask_timer_irq, + .irq_unmask = bcm2836_arm_irqchip_unmask_timer_irq, +}; + +static void bcm2836_arm_irqchip_mask_pmu_irq(struct irq_data *d) +{ + writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_CLR); +} + +static void bcm2836_arm_irqchip_unmask_pmu_irq(struct irq_data *d) +{ + writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_SET); +} + +static struct irq_chip bcm2836_arm_irqchip_pmu = { + .name = "bcm2836-pmu", + .irq_mask = bcm2836_arm_irqchip_mask_pmu_irq, + .irq_unmask = bcm2836_arm_irqchip_unmask_pmu_irq, +}; + +static void bcm2836_arm_irqchip_mask_gpu_irq(struct irq_data *d) +{ +} + +static void bcm2836_arm_irqchip_unmask_gpu_irq(struct irq_data *d) +{ +} + +static struct irq_chip bcm2836_arm_irqchip_gpu = { + .name = "bcm2836-gpu", + .irq_mask = bcm2836_arm_irqchip_mask_gpu_irq, + .irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq, +}; + +static void bcm2836_arm_irqchip_register_irq(int hwirq, struct irq_chip *chip) +{ + int irq = irq_create_mapping(intc.domain, hwirq); + + irq_set_percpu_devid(irq); + irq_set_chip_and_handler(irq, chip, handle_percpu_devid_irq); + irq_set_status_flags(irq, IRQ_NOAUTOEN); +} + +static void +__exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + u32 stat; + + stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu); + if (stat & 0x10) { +#ifdef CONFIG_SMP + void __iomem *mailbox0 = (intc.base + + LOCAL_MAILBOX0_CLR0 + 16 * cpu); + u32 mbox_val = readl(mailbox0); + u32 ipi = ffs(mbox_val) - 1; + + writel(1 << ipi, mailbox0); + handle_IPI(ipi, regs); +#endif + } else { + u32 hwirq = ffs(stat) - 1; + + handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs); + } +} + +#ifdef CONFIG_SMP +static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask, + unsigned int ipi) +{ + int cpu; + void __iomem *mailbox0_base = intc.base + LOCAL_MAILBOX0_SET0; + + /* + * Ensure that stores to normal memory are visible to the + * other CPUs before issuing the IPI. + */ + dsb(); + + for_each_cpu(cpu, mask) { + writel(1 << ipi, mailbox0_base + 16 * cpu); + } +} + +/* Unmasks the IPI on the CPU when it's online. */ +static int bcm2836_arm_irqchip_cpu_notify(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + unsigned int int_reg = LOCAL_MAILBOX_INT_CONTROL0; + unsigned int mailbox = 0; + + if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) + bcm2836_arm_irqchip_unmask_per_cpu_irq(int_reg, mailbox, cpu); + else if (action == CPU_DYING) + bcm2836_arm_irqchip_mask_per_cpu_irq(int_reg, mailbox, cpu); + + return NOTIFY_OK; +} + +static struct notifier_block bcm2836_arm_irqchip_cpu_notifier = { + .notifier_call = bcm2836_arm_irqchip_cpu_notify, + .priority = 100, +}; +#endif + +static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = { + .xlate = irq_domain_xlate_onecell +}; + +static void +bcm2836_arm_irqchip_smp_init(void) +{ +#ifdef CONFIG_SMP + /* Unmask IPIs to the boot CPU. */ + bcm2836_arm_irqchip_cpu_notify(&bcm2836_arm_irqchip_cpu_notifier, + CPU_STARTING, + (void *)smp_processor_id()); + register_cpu_notifier(&bcm2836_arm_irqchip_cpu_notifier); + + set_smp_cross_call(bcm2836_arm_irqchip_send_ipi); +#endif +} + +static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node, + struct device_node *parent) +{ + intc.base = of_iomap(node, 0); + if (!intc.base) { + panic("%s: unable to map local interrupt registers\n", + node->full_name); + } + + intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1, + &bcm2836_arm_irqchip_intc_ops, + NULL); + if (!intc.domain) + panic("%s: unable to create IRQ domain\n", node->full_name); + + bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTPSIRQ, + &bcm2836_arm_irqchip_timer); + bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTPNSIRQ, + &bcm2836_arm_irqchip_timer); + bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTHPIRQ, + &bcm2836_arm_irqchip_timer); + bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTVIRQ, + &bcm2836_arm_irqchip_timer); + bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_GPU_FAST, + &bcm2836_arm_irqchip_gpu); + bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_PMU_FAST, + &bcm2836_arm_irqchip_pmu); + + bcm2836_arm_irqchip_smp_init(); + + set_handle_irq(bcm2836_arm_irqchip_handle_irq); + return 0; +} + +IRQCHIP_DECLARE(bcm2836_arm_irqchip_l1_intc, "brcm,bcm2836-l1-intc", + bcm2836_arm_irqchip_l1_intc_of_init); -- cgit v0.10.2 From e324c4dc4a5991d5b1171f434884a4026345e4b4 Mon Sep 17 00:00:00 2001 From: Shenwei Wang Date: Mon, 24 Aug 2015 14:04:15 -0500 Subject: irqchip/imx-gpcv2: IMX GPCv2 driver for wakeup sources IMX7D contains a new version of GPC IP block (GPCv2). It has two major functions: power management and wakeup source management. When the system is in WFI (wait for interrupt) mode, the GPC block will be the first block on the platform to be activated and signaled. In normal wait mode during cpu idle, the system can be woken up by any enabled interrupts. In standby or suspend mode, the system can only be wokem up by the pre-defined wakeup sources. Based-on-patch-by: Anson Huang Signed-off-by: Shenwei Wang Cc: Cc: Cc: Link: http://lkml.kernel.org/r/1440443055-7291-1-git-send-email-shenwei.wang@freescale.com Signed-off-by: Thomas Gleixner diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 5b85371..27b52c8 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -181,3 +181,9 @@ config RENESAS_H8300H_INTC config RENESAS_H8S_INTC bool select IRQ_DOMAIN + +config IMX_GPCV2 + bool + select IRQ_DOMAIN + help + Enables the wakeup IRQs for IMX platforms with GPCv2 block diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index e5e0069..bb3048f 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -54,3 +54,4 @@ obj-$(CONFIG_RENESAS_H8300H_INTC) += irq-renesas-h8300h.o obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o +obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o diff --git a/drivers/irqchip/irq-imx-gpcv2.c b/drivers/irqchip/irq-imx-gpcv2.c new file mode 100644 index 0000000..e48d330 --- /dev/null +++ b/drivers/irqchip/irq-imx-gpcv2.c @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#define IMR_NUM 4 +#define GPC_MAX_IRQS (IMR_NUM * 32) + +#define GPC_IMR1_CORE0 0x30 +#define GPC_IMR1_CORE1 0x40 + +struct gpcv2_irqchip_data { + struct raw_spinlock rlock; + void __iomem *gpc_base; + u32 wakeup_sources[IMR_NUM]; + u32 saved_irq_mask[IMR_NUM]; + u32 cpu2wakeup; +}; + +static struct gpcv2_irqchip_data *imx_gpcv2_instance; + +/* + * Interface for the low level wakeup code. + */ +u32 imx_gpcv2_get_wakeup_source(u32 **sources) +{ + if (!imx_gpcv2_instance) + return 0; + + if (sources) + *sources = imx_gpcv2_instance->wakeup_sources; + + return IMR_NUM; +} + +static int gpcv2_wakeup_source_save(void) +{ + struct gpcv2_irqchip_data *cd; + void __iomem *reg; + int i; + + cd = imx_gpcv2_instance; + if (!cd) + return 0; + + for (i = 0; i < IMR_NUM; i++) { + reg = cd->gpc_base + cd->cpu2wakeup + i * 4; + cd->saved_irq_mask[i] = readl_relaxed(reg); + writel_relaxed(cd->wakeup_sources[i], reg); + } + + return 0; +} + +static void gpcv2_wakeup_source_restore(void) +{ + struct gpcv2_irqchip_data *cd; + void __iomem *reg; + int i; + + cd = imx_gpcv2_instance; + if (!cd) + return; + + for (i = 0; i < IMR_NUM; i++) { + reg = cd->gpc_base + cd->cpu2wakeup + i * 4; + writel_relaxed(cd->saved_irq_mask[i], reg); + } +} + +static struct syscore_ops imx_gpcv2_syscore_ops = { + .suspend = gpcv2_wakeup_source_save, + .resume = gpcv2_wakeup_source_restore, +}; + +static int imx_gpcv2_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct gpcv2_irqchip_data *cd = d->chip_data; + unsigned int idx = d->hwirq / 32; + unsigned long flags; + void __iomem *reg; + u32 mask, val; + + raw_spin_lock_irqsave(&cd->rlock, flags); + reg = cd->gpc_base + cd->cpu2wakeup + idx * 4; + mask = 1 << d->hwirq % 32; + val = cd->wakeup_sources[idx]; + + cd->wakeup_sources[idx] = on ? (val & ~mask) : (val | mask); + raw_spin_unlock_irqrestore(&cd->rlock, flags); + + /* + * Do *not* call into the parent, as the GIC doesn't have any + * wake-up facility... + */ + + return 0; +} + +static void imx_gpcv2_irq_unmask(struct irq_data *d) +{ + struct gpcv2_irqchip_data *cd = d->chip_data; + void __iomem *reg; + u32 val; + + raw_spin_lock(&cd->rlock); + reg = cd->gpc_base + cd->cpu2wakeup + d->hwirq / 32 * 4; + val = readl_relaxed(reg); + val &= ~(1 << d->hwirq % 32); + writel_relaxed(val, reg); + raw_spin_unlock(&cd->rlock); + + irq_chip_unmask_parent(d); +} + +static void imx_gpcv2_irq_mask(struct irq_data *d) +{ + struct gpcv2_irqchip_data *cd = d->chip_data; + void __iomem *reg; + u32 val; + + raw_spin_lock(&cd->rlock); + reg = cd->gpc_base + cd->cpu2wakeup + d->hwirq / 32 * 4; + val = readl_relaxed(reg); + val |= 1 << (d->hwirq % 32); + writel_relaxed(val, reg); + raw_spin_unlock(&cd->rlock); + + irq_chip_mask_parent(d); +} + +static struct irq_chip gpcv2_irqchip_data_chip = { + .name = "GPCv2", + .irq_eoi = irq_chip_eoi_parent, + .irq_mask = imx_gpcv2_irq_mask, + .irq_unmask = imx_gpcv2_irq_unmask, + .irq_set_wake = imx_gpcv2_irq_set_wake, + .irq_retrigger = irq_chip_retrigger_hierarchy, +#ifdef CONFIG_SMP + .irq_set_affinity = irq_chip_set_affinity_parent, +#endif +}; + +static int imx_gpcv2_domain_xlate(struct irq_domain *domain, + struct device_node *controller, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + /* Shouldn't happen, really... */ + if (domain->of_node != controller) + return -EINVAL; + + /* Not GIC compliant */ + if (intsize != 3) + return -EINVAL; + + /* No PPI should point to this domain */ + if (intspec[0] != 0) + return -EINVAL; + + *out_hwirq = intspec[1]; + *out_type = intspec[2]; + return 0; +} + +static int imx_gpcv2_domain_alloc(struct irq_domain *domain, + unsigned int irq, unsigned int nr_irqs, + void *data) +{ + struct of_phandle_args *args = data; + struct of_phandle_args parent_args; + irq_hw_number_t hwirq; + int i; + + /* Not GIC compliant */ + if (args->args_count != 3) + return -EINVAL; + + /* No PPI should point to this domain */ + if (args->args[0] != 0) + return -EINVAL; + + /* Can't deal with this */ + hwirq = args->args[1]; + if (hwirq >= GPC_MAX_IRQS) + return -EINVAL; + + for (i = 0; i < nr_irqs; i++) { + irq_domain_set_hwirq_and_chip(domain, irq + i, hwirq + i, + &gpcv2_irqchip_data_chip, domain->host_data); + } + + parent_args = *args; + parent_args.np = domain->parent->of_node; + return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, &parent_args); +} + +static struct irq_domain_ops gpcv2_irqchip_data_domain_ops = { + .xlate = imx_gpcv2_domain_xlate, + .alloc = imx_gpcv2_domain_alloc, + .free = irq_domain_free_irqs_common, +}; + +static int __init imx_gpcv2_irqchip_init(struct device_node *node, + struct device_node *parent) +{ + struct irq_domain *parent_domain, *domain; + struct gpcv2_irqchip_data *cd; + int i; + + if (!parent) { + pr_err("%s: no parent, giving up\n", node->full_name); + return -ENODEV; + } + + parent_domain = irq_find_host(parent); + if (!parent_domain) { + pr_err("%s: unable to get parent domain\n", node->full_name); + return -ENXIO; + } + + cd = kzalloc(sizeof(struct gpcv2_irqchip_data), GFP_KERNEL); + if (!cd) { + pr_err("kzalloc failed!\n"); + return -ENOMEM; + } + + cd->gpc_base = of_iomap(node, 0); + if (!cd->gpc_base) { + pr_err("fsl-gpcv2: unable to map gpc registers\n"); + kfree(cd); + return -ENOMEM; + } + + domain = irq_domain_add_hierarchy(parent_domain, 0, GPC_MAX_IRQS, + node, &gpcv2_irqchip_data_domain_ops, cd); + if (!domain) { + iounmap(cd->gpc_base); + kfree(cd); + return -ENOMEM; + } + irq_set_default_host(domain); + + /* Initially mask all interrupts */ + for (i = 0; i < IMR_NUM; i++) { + writel_relaxed(~0, cd->gpc_base + GPC_IMR1_CORE0 + i * 4); + writel_relaxed(~0, cd->gpc_base + GPC_IMR1_CORE1 + i * 4); + cd->wakeup_sources[i] = ~0; + } + + /* Let CORE0 as the default CPU to wake up by GPC */ + cd->cpu2wakeup = GPC_IMR1_CORE0; + + /* + * Due to hardware design failure, need to make sure GPR + * interrupt(#32) is unmasked during RUN mode to avoid entering + * DSM by mistake. + */ + writel_relaxed(~0x1, cd->gpc_base + cd->cpu2wakeup); + + imx_gpcv2_instance = cd; + register_syscore_ops(&imx_gpcv2_syscore_ops); + + return 0; +} + +IRQCHIP_DECLARE(imx_gpcv2, "fsl,imx7d-gpc", imx_gpcv2_irqchip_init); -- cgit v0.10.2