diff options
Diffstat (limited to 'drivers/irqchip')
48 files changed, 1066 insertions, 626 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 27b52c8729cd..4d7294e5d982 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -123,6 +123,7 @@ config RENESAS_INTC_IRQPIN config RENESAS_IRQC bool + select GENERIC_IRQ_CHIP select IRQ_DOMAIN config ST_IRQCHIP @@ -187,3 +188,8 @@ config IMX_GPCV2 select IRQ_DOMAIN help Enables the wakeup IRQs for IMX platforms with GPCv2 block + +config IRQ_MXS + def_bool y if MACH_ASM9260 || ARCH_MXS + select IRQ_DOMAIN + select STMP_DEVICE diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index bb3048f00e64..177f78f6e6d6 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o obj-$(CONFIG_ARCH_MMP) += irq-mmp.o obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o -obj-$(CONFIG_ARCH_MXS) += irq-mxs.o +obj-$(CONFIG_IRQ_MXS) += irq-mxs.o obj-$(CONFIG_ARCH_TEGRA) += irq-tegra.o obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o diff --git a/drivers/irqchip/alphascale_asm9260-icoll.h b/drivers/irqchip/alphascale_asm9260-icoll.h new file mode 100644 index 000000000000..5cec108ee204 --- /dev/null +++ b/drivers/irqchip/alphascale_asm9260-icoll.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 Oleksij Rempel <linux@rempel-privat.de> + * + * 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. + */ + +#ifndef _ALPHASCALE_ASM9260_ICOLL_H +#define _ALPHASCALE_ASM9260_ICOLL_H + +#define ASM9260_NUM_IRQS 64 +/* + * this device provide 4 offsets for each register: + * 0x0 - plain read write mode + * 0x4 - set mode, OR logic. + * 0x8 - clr mode, XOR logic. + * 0xc - togle mode. + */ + +#define ASM9260_HW_ICOLL_VECTOR 0x0000 +/* + * bits 31:2 + * This register presents the vector address for the interrupt currently + * active on the CPU IRQ input. Writing to this register notifies the + * interrupt collector that the interrupt service routine for the current + * interrupt has been entered. + * The exception trap should have a LDPC instruction from this address: + * LDPC ASM9260_HW_ICOLL_VECTOR_ADDR; IRQ exception at 0xffff0018 + */ + +/* + * The Interrupt Collector Level Acknowledge Register is used by software to + * indicate the completion of an interrupt on a specific level. + * This register is written at the very end of an interrupt service routine. If + * nesting is used then the CPU irq must be turned on before writing to this + * register to avoid a race condition in the CPU interrupt hardware. + */ +#define ASM9260_HW_ICOLL_LEVELACK 0x0010 +#define ASM9260_BM_LEVELn(nr) BIT(nr) + +#define ASM9260_HW_ICOLL_CTRL 0x0020 +/* + * ASM9260_BM_CTRL_SFTRST and ASM9260_BM_CTRL_CLKGATE are not available on + * asm9260. + */ +#define ASM9260_BM_CTRL_SFTRST BIT(31) +#define ASM9260_BM_CTRL_CLKGATE BIT(30) +/* disable interrupt level nesting */ +#define ASM9260_BM_CTRL_NO_NESTING BIT(19) +/* + * Set this bit to one enable the RISC32-style read side effect associated with + * the vector address register. In this mode, interrupt in-service is signaled + * by the read of the ASM9260_HW_ICOLL_VECTOR register to acquire the interrupt + * vector address. Set this bit to zero for normal operation, in which the ISR + * signals in-service explicitly by means of a write to the + * ASM9260_HW_ICOLL_VECTOR register. + * 0 - Must Write to Vector register to go in-service. + * 1 - Go in-service as a read side effect + */ +#define ASM9260_BM_CTRL_ARM_RSE_MODE BIT(18) +#define ASM9260_BM_CTRL_IRQ_ENABLE BIT(16) + +#define ASM9260_HW_ICOLL_STAT_OFFSET 0x0030 +/* + * bits 5:0 + * Vector number of current interrupt. Multiply by 4 and add to vector base + * address to obtain the value in ASM9260_HW_ICOLL_VECTOR. + */ + +/* + * RAW0 and RAW1 provides a read-only view of the raw interrupt request lines + * coming from various parts of the chip. Its purpose is to improve diagnostic + * observability. + */ +#define ASM9260_HW_ICOLL_RAW0 0x0040 +#define ASM9260_HW_ICOLL_RAW1 0x0050 + +#define ASM9260_HW_ICOLL_INTERRUPT0 0x0060 +#define ASM9260_HW_ICOLL_INTERRUPTn(n) (0x0060 + ((n) >> 2) * 0x10) +/* + * WARNING: Modifying the priority of an enabled interrupt may result in + * undefined behavior. + */ +#define ASM9260_BM_INT_PRIORITY_MASK 0x3 +#define ASM9260_BM_INT_ENABLE BIT(2) +#define ASM9260_BM_INT_SOFTIRQ BIT(3) + +#define ASM9260_BM_ICOLL_INTERRUPTn_SHIFT(n) (((n) & 0x3) << 3) +#define ASM9260_BM_ICOLL_INTERRUPTn_ENABLE(n) (1 << (2 + \ + ASM9260_BM_ICOLL_INTERRUPTn_SHIFT(n))) + +#define ASM9260_HW_ICOLL_VBASE 0x0160 +/* + * bits 31:2 + * This bitfield holds the upper 30 bits of the base address of the vector + * table. + */ + +#define ASM9260_HW_ICOLL_CLEAR0 0x01d0 +#define ASM9260_HW_ICOLL_CLEAR1 0x01e0 +#define ASM9260_HW_ICOLL_CLEARn(n) (((n >> 5) * 0x10) \ + + SET_REG) +#define ASM9260_BM_CLEAR_BIT(n) BIT(n & 0x1f) + +/* Scratchpad */ +#define ASM9260_HW_ICOLL_UNDEF_VECTOR 0x01f0 +#endif diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index e9c6f2a5b52d..ead15be2d20a 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -65,12 +65,10 @@ 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(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; @@ -88,7 +86,7 @@ static void combiner_handle_cascade_irq(unsigned int __irq, cascade_irq = irq_find_mapping(combiner_irq_domain, combiner_irq); if (unlikely(!cascade_irq)) - handle_bad_irq(irq, desc); + handle_bad_irq(desc); else generic_handle_irq(cascade_irq); @@ -146,7 +144,7 @@ static int combiner_irq_domain_xlate(struct irq_domain *d, unsigned long *out_hwirq, unsigned int *out_type) { - if (d->of_node != controller) + if (irq_domain_get_of_node(d) != controller) return -EINVAL; if (intsize < 2) @@ -165,7 +163,7 @@ static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq); irq_set_chip_data(irq, &combiner_data[hw >> 3]); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(irq); return 0; } diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 39b72da0c143..3f3a8c3d2175 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -56,9 +56,6 @@ #define ARMADA_370_XP_MAX_PER_CPU_IRQS (28) -#define ARMADA_370_XP_TIMER0_PER_CPU_IRQ (5) -#define ARMADA_370_XP_FABRIC_IRQ (3) - #define IPI_DOORBELL_START (0) #define IPI_DOORBELL_END (8) #define IPI_DOORBELL_MASK 0xFF @@ -81,13 +78,10 @@ static phys_addr_t msi_doorbell_addr; static inline bool is_percpu_irq(irq_hw_number_t irq) { - switch (irq) { - case ARMADA_370_XP_TIMER0_PER_CPU_IRQ: - case ARMADA_370_XP_FABRIC_IRQ: + if (irq <= ARMADA_370_XP_MAX_PER_CPU_IRQS) return true; - default: - return false; - } + + return false; } /* @@ -200,7 +194,6 @@ static int armada_370_xp_msi_map(struct irq_domain *domain, unsigned int virq, { irq_set_chip_and_handler(virq, &armada_370_xp_msi_irq_chip, handle_simple_irq); - set_irq_flags(virq, IRQF_VALID); return 0; } @@ -317,7 +310,8 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h, irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip, handle_level_irq); } - set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(virq); + irq_clear_status_flags(virq, IRQ_NOAUTOEN); return 0; } @@ -447,8 +441,7 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained) static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {} #endif -static void armada_370_xp_mpic_handle_cascade_irq(unsigned int irq, - struct irq_desc *desc) +static void armada_370_xp_mpic_handle_cascade_irq(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); unsigned long irqmap, irqn, irqsrc, cpuid; @@ -551,7 +544,7 @@ static void armada_370_xp_mpic_resume(void) if (virq == 0) continue; - if (irq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ) + if (!is_percpu_irq(irq)) writel(irq, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); else diff --git a/drivers/irqchip/irq-atmel-aic-common.c b/drivers/irqchip/irq-atmel-aic-common.c index 63cd031b2c28..b12a5d58546f 100644 --- a/drivers/irqchip/irq-atmel-aic-common.c +++ b/drivers/irqchip/irq-atmel-aic-common.c @@ -114,7 +114,7 @@ int aic_common_irq_domain_xlate(struct irq_domain *d, static void __init aic_common_ext_irq_of_init(struct irq_domain *domain) { - struct device_node *node = domain->of_node; + struct device_node *node = irq_domain_get_of_node(domain); struct irq_chip_generic *gc; struct aic_chip_data *aic; struct property *prop; diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index 9da9942ac83c..62bb840c613f 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -70,16 +70,15 @@ static struct irq_domain *aic5_domain; static asmlinkage void __exception_irq_entry aic5_handle(struct pt_regs *regs) { - struct irq_domain_chip_generic *dgc = aic5_domain->gc; - struct irq_chip_generic *gc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(aic5_domain, 0); u32 irqnr; u32 irqstat; - irqnr = irq_reg_readl(gc, AT91_AIC5_IVR); - irqstat = irq_reg_readl(gc, AT91_AIC5_ISR); + irqnr = irq_reg_readl(bgc, AT91_AIC5_IVR); + irqstat = irq_reg_readl(bgc, AT91_AIC5_ISR); if (!irqstat) - irq_reg_writel(gc, 0, AT91_AIC5_EOICR); + irq_reg_writel(bgc, 0, AT91_AIC5_EOICR); else handle_domain_irq(aic5_domain, irqnr, regs); } @@ -87,42 +86,47 @@ aic5_handle(struct pt_regs *regs) static void aic5_mask(struct irq_data *d) { struct irq_domain *domain = d->domain; - struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *gc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - /* Disable interrupt on AIC5 */ - irq_gc_lock(gc); + /* + * Disable interrupt on AIC5. We always take the lock of the + * first irq chip as all chips share the same registers. + */ + irq_gc_lock(bgc); irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR); irq_reg_writel(gc, 1, AT91_AIC5_IDCR); gc->mask_cache &= ~d->mask; - irq_gc_unlock(gc); + irq_gc_unlock(bgc); } static void aic5_unmask(struct irq_data *d) { struct irq_domain *domain = d->domain; - struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *gc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - /* Enable interrupt on AIC5 */ - irq_gc_lock(gc); + /* + * Enable interrupt on AIC5. We always take the lock of the + * first irq chip as all chips share the same registers. + */ + irq_gc_lock(bgc); irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR); irq_reg_writel(gc, 1, AT91_AIC5_IECR); gc->mask_cache |= d->mask; - irq_gc_unlock(gc); + irq_gc_unlock(bgc); } static int aic5_retrigger(struct irq_data *d) { struct irq_domain *domain = d->domain; - struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *gc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); /* Enable interrupt on AIC5 */ - irq_gc_lock(gc); - irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR); - irq_reg_writel(gc, 1, AT91_AIC5_ISCR); - irq_gc_unlock(gc); + irq_gc_lock(bgc); + irq_reg_writel(bgc, d->hwirq, AT91_AIC5_SSR); + irq_reg_writel(bgc, 1, AT91_AIC5_ISCR); + irq_gc_unlock(bgc); return 0; } @@ -130,18 +134,17 @@ static int aic5_retrigger(struct irq_data *d) static int aic5_set_type(struct irq_data *d, unsigned type) { struct irq_domain *domain = d->domain; - struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *gc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); unsigned int smr; int ret; - irq_gc_lock(gc); - irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR); - smr = irq_reg_readl(gc, AT91_AIC5_SMR); + irq_gc_lock(bgc); + irq_reg_writel(bgc, d->hwirq, AT91_AIC5_SSR); + smr = irq_reg_readl(bgc, AT91_AIC5_SMR); ret = aic_common_set_type(d, type, &smr); if (!ret) - irq_reg_writel(gc, smr, AT91_AIC5_SMR); - irq_gc_unlock(gc); + irq_reg_writel(bgc, smr, AT91_AIC5_SMR); + irq_gc_unlock(bgc); return ret; } @@ -151,7 +154,7 @@ static void aic5_suspend(struct irq_data *d) { struct irq_domain *domain = d->domain; struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); int i; u32 mask; @@ -175,7 +178,7 @@ static void aic5_resume(struct irq_data *d) { struct irq_domain *domain = d->domain; struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); int i; u32 mask; @@ -199,7 +202,7 @@ static void aic5_pm_shutdown(struct irq_data *d) { struct irq_domain *domain = d->domain; struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); int i; @@ -254,12 +257,11 @@ static int aic5_irq_domain_xlate(struct irq_domain *d, irq_hw_number_t *out_hwirq, unsigned int *out_type) { - struct irq_domain_chip_generic *dgc = d->gc; - struct irq_chip_generic *gc; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(d, 0); unsigned smr; int ret; - if (!dgc) + if (!bgc) return -EINVAL; ret = aic_common_irq_domain_xlate(d, ctrlr, intspec, intsize, @@ -267,15 +269,13 @@ static int aic5_irq_domain_xlate(struct irq_domain *d, if (ret) return ret; - gc = dgc->gc[0]; - - irq_gc_lock(gc); - irq_reg_writel(gc, *out_hwirq, AT91_AIC5_SSR); - smr = irq_reg_readl(gc, AT91_AIC5_SMR); + irq_gc_lock(bgc); + irq_reg_writel(bgc, *out_hwirq, AT91_AIC5_SSR); + smr = irq_reg_readl(bgc, AT91_AIC5_SMR); ret = aic_common_set_priority(intspec[2], &smr); if (!ret) - irq_reg_writel(gc, intspec[2] | smr, AT91_AIC5_SMR); - irq_gc_unlock(gc); + irq_reg_writel(bgc, intspec[2] | smr, AT91_AIC5_SMR); + irq_gc_unlock(bgc); return ret; } diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index ed4ca9deca70..bf9cc5f2e839 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -96,7 +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 bcm2836_chained_handle_irq(struct irq_desc *desc); static void armctrl_mask_irq(struct irq_data *d) { @@ -166,7 +166,7 @@ static int __init armctrl_of_init(struct device_node *node, BUG_ON(irq <= 0); irq_set_chip_and_handler(irq, &armctrl_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(irq); } } @@ -245,7 +245,7 @@ static void __exception_irq_entry bcm2835_handle_irq( handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs); } -static void bcm2836_chained_handle_irq(unsigned int irq, struct irq_desc *desc) +static void bcm2836_chained_handle_irq(struct irq_desc *desc) { u32 hwirq; diff --git a/drivers/irqchip/irq-bcm7038-l1.c b/drivers/irqchip/irq-bcm7038-l1.c index 409bdc6366c2..0fea985ef1dc 100644 --- a/drivers/irqchip/irq-bcm7038-l1.c +++ b/drivers/irqchip/irq-bcm7038-l1.c @@ -115,7 +115,7 @@ static inline void l1_writel(u32 val, void __iomem *reg) writel(val, reg); } -static void bcm7038_l1_irq_handle(unsigned int irq, struct irq_desc *desc) +static void bcm7038_l1_irq_handle(struct irq_desc *desc) { struct bcm7038_l1_chip *intc = irq_desc_get_handler_data(desc); struct bcm7038_l1_cpu *cpu; diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index d3f976913a6f..61b18ab33ad9 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c @@ -56,7 +56,7 @@ struct bcm7120_l2_intc_data { const __be32 *map_mask_prop; }; -static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc) +static void bcm7120_l2_intc_irq_handle(struct irq_desc *desc) { struct bcm7120_l1_intc_data *data = irq_desc_get_handler_data(desc); struct bcm7120_l2_intc_data *b = data->b; diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index aedda06191eb..65cd341f331a 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c @@ -49,13 +49,12 @@ 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(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); + unsigned int irq; u32 status; chained_irq_enter(chip, desc); @@ -65,7 +64,7 @@ static void brcmstb_l2_intc_irq_handle(unsigned int __irq, if (status == 0) { raw_spin_lock(&desc->lock); - handle_bad_irq(irq, desc); + handle_bad_irq(desc); raw_spin_unlock(&desc->lock); goto out; } diff --git a/drivers/irqchip/irq-clps711x.c b/drivers/irqchip/irq-clps711x.c index 2dd929eed9e0..eb5eb0cd414d 100644 --- a/drivers/irqchip/irq-clps711x.c +++ b/drivers/irqchip/irq-clps711x.c @@ -132,14 +132,14 @@ static int __init clps711x_intc_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { irq_flow_handler_t handler = handle_level_irq; - unsigned int flags = IRQF_VALID | IRQF_PROBE; + unsigned int flags = 0; if (!clps711x_irqs[hw].flags) return 0; if (clps711x_irqs[hw].flags & CLPS711X_FLAG_FIQ) { handler = handle_bad_irq; - flags |= IRQF_NOAUTOEN; + flags |= IRQ_NOAUTOEN; } else if (clps711x_irqs[hw].eoi) { handler = handle_fasteoi_irq; } @@ -149,7 +149,7 @@ static int __init clps711x_intc_irq_map(struct irq_domain *h, unsigned int virq, writel_relaxed(0, clps711x_intc->base + clps711x_irqs[hw].eoi); irq_set_chip_and_handler(virq, &clps711x_intc_chip, handler); - set_irq_flags(virq, flags); + irq_modify_status(virq, IRQ_NOPROBE, flags); return 0; } diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c index a7f5626930f5..75573fa431ba 100644 --- a/drivers/irqchip/irq-crossbar.c +++ b/drivers/irqchip/irq-crossbar.c @@ -78,10 +78,13 @@ static struct irq_chip crossbar_chip = { static int allocate_gic_irq(struct irq_domain *domain, unsigned virq, irq_hw_number_t hwirq) { - struct of_phandle_args args; + struct irq_fwspec fwspec; int i; int err; + if (!irq_domain_get_of_node(domain->parent)) + return -EINVAL; + raw_spin_lock(&cb->lock); for (i = cb->int_max - 1; i >= 0; i--) { if (cb->irq_map[i] == IRQ_FREE) { @@ -94,13 +97,13 @@ static int allocate_gic_irq(struct irq_domain *domain, unsigned virq, if (i < 0) return -ENODEV; - args.np = domain->parent->of_node; - args.args_count = 3; - args.args[0] = 0; /* SPI */ - args.args[1] = i; - args.args[2] = IRQ_TYPE_LEVEL_HIGH; + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count = 3; + fwspec.param[0] = 0; /* SPI */ + fwspec.param[1] = i; + fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH; - err = irq_domain_alloc_irqs_parent(domain, virq, 1, &args); + err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); if (err) cb->irq_map[i] = IRQ_FREE; else @@ -112,16 +115,16 @@ static int allocate_gic_irq(struct irq_domain *domain, unsigned virq, static int crossbar_domain_alloc(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs, void *data) { - struct of_phandle_args *args = data; + struct irq_fwspec *fwspec = data; irq_hw_number_t hwirq; int i; - if (args->args_count != 3) + if (fwspec->param_count != 3) return -EINVAL; /* Not GIC compliant */ - if (args->args[0] != 0) + if (fwspec->param[0] != 0) return -EINVAL; /* No PPI should point to this domain */ - hwirq = args->args[1]; + hwirq = fwspec->param[1]; if ((hwirq + nr_irqs) > cb->max_crossbar_sources) return -EINVAL; /* Can't deal with this */ @@ -166,28 +169,31 @@ static void crossbar_domain_free(struct irq_domain *domain, unsigned int virq, raw_spin_unlock(&cb->lock); } -static int crossbar_domain_xlate(struct irq_domain *d, - struct device_node *controller, - const u32 *intspec, unsigned int intsize, - unsigned long *out_hwirq, - unsigned int *out_type) +static int crossbar_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) { - if (d->of_node != controller) - return -EINVAL; /* Shouldn't happen, really... */ - if (intsize != 3) - return -EINVAL; /* Not GIC compliant */ - if (intspec[0] != 0) - return -EINVAL; /* No PPI should point to this domain */ + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count != 3) + return -EINVAL; - *out_hwirq = intspec[1]; - *out_type = intspec[2]; - return 0; + /* No PPI should point to this domain */ + if (fwspec->param[0] != 0) + return -EINVAL; + + *hwirq = fwspec->param[1]; + *type = fwspec->param[2]; + return 0; + } + + return -EINVAL; } static const struct irq_domain_ops crossbar_domain_ops = { - .alloc = crossbar_domain_alloc, - .free = crossbar_domain_free, - .xlate = crossbar_domain_xlate, + .alloc = crossbar_domain_alloc, + .free = crossbar_domain_free, + .translate = crossbar_domain_translate, }; static int __init crossbar_of_init(struct device_node *node) diff --git a/drivers/irqchip/irq-dw-apb-ictl.c b/drivers/irqchip/irq-dw-apb-ictl.c index efd95d9955e7..052f266364c0 100644 --- a/drivers/irqchip/irq-dw-apb-ictl.c +++ b/drivers/irqchip/irq-dw-apb-ictl.c @@ -26,7 +26,7 @@ #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) +static void dw_apb_ictl_handler(struct irq_desc *desc) { struct irq_domain *d = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 9448e391cb71..44a077f3a4a2 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -21,6 +21,17 @@ #include "irq-gic-common.h" +void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, + void *data) +{ + for (; quirks->desc; quirks++) { + if (quirks->iidr != (quirks->mask & iidr)) + continue; + quirks->init(data); + pr_info("GIC: enabling workaround for %s\n", quirks->desc); + } +} + int gic_configure_irq(unsigned int irq, unsigned int type, void __iomem *base, void (*sync_access)(void)) { diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h index 35a9884778bd..fff697db8e22 100644 --- a/drivers/irqchip/irq-gic-common.h +++ b/drivers/irqchip/irq-gic-common.h @@ -20,10 +20,19 @@ #include <linux/of.h> #include <linux/irqdomain.h> +struct gic_quirk { + const char *desc; + void (*init)(void *data); + u32 iidr; + u32 mask; +}; + int gic_configure_irq(unsigned int irq, unsigned int type, void __iomem *base, void (*sync_access)(void)); void gic_dist_config(void __iomem *base, int gic_irqs, void (*sync_access)(void)); void gic_cpu_config(void __iomem *base, void (*sync_access)(void)); +void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks, + void *data); #endif /* _IRQ_GIC_COMMON_H */ diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c index db04fc1f56b2..87f8d104acab 100644 --- a/drivers/irqchip/irq-gic-v2m.c +++ b/drivers/irqchip/irq-gic-v2m.c @@ -37,19 +37,31 @@ #define V2M_MSI_SETSPI_NS 0x040 #define V2M_MIN_SPI 32 #define V2M_MAX_SPI 1019 +#define V2M_MSI_IIDR 0xFCC #define V2M_MSI_TYPER_BASE_SPI(x) \ (((x) >> V2M_MSI_TYPER_BASE_SHIFT) & V2M_MSI_TYPER_BASE_MASK) #define V2M_MSI_TYPER_NUM_SPI(x) ((x) & V2M_MSI_TYPER_NUM_MASK) +/* APM X-Gene with GICv2m MSI_IIDR register value */ +#define XGENE_GICV2M_MSI_IIDR 0x06000170 + +/* List of flags for specific v2m implementation */ +#define GICV2M_NEEDS_SPI_OFFSET 0x00000001 + +static LIST_HEAD(v2m_nodes); +static DEFINE_SPINLOCK(v2m_lock); + struct v2m_data { - spinlock_t msi_cnt_lock; + struct list_head entry; + struct device_node *node; struct resource res; /* GICv2m resource */ void __iomem *base; /* GICv2m virt address */ u32 spi_start; /* The SPI number that MSIs start */ u32 nr_spis; /* The number of SPIs for MSIs */ unsigned long *bm; /* MSI vector bitmap */ + u32 flags; /* v2m flags for specific implementation */ }; static void gicv2m_mask_msi_irq(struct irq_data *d) @@ -95,9 +107,12 @@ static void gicv2m_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) struct v2m_data *v2m = irq_data_get_irq_chip_data(data); phys_addr_t addr = v2m->res.start + V2M_MSI_SETSPI_NS; - msg->address_hi = (u32) (addr >> 32); - msg->address_lo = (u32) (addr); + msg->address_hi = upper_32_bits(addr); + msg->address_lo = lower_32_bits(addr); msg->data = data->hwirq; + + if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET) + msg->data -= v2m->spi_start; } static struct irq_chip gicv2m_irq_chip = { @@ -113,17 +128,21 @@ static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq) { - struct of_phandle_args args; + struct irq_fwspec fwspec; struct irq_data *d; int err; - args.np = domain->parent->of_node; - args.args_count = 3; - args.args[0] = 0; - args.args[1] = hwirq - 32; - args.args[2] = IRQ_TYPE_EDGE_RISING; + if (is_of_node(domain->parent->fwnode)) { + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count = 3; + fwspec.param[0] = 0; + fwspec.param[1] = hwirq - 32; + fwspec.param[2] = IRQ_TYPE_EDGE_RISING; + } else { + return -EINVAL; + } - err = irq_domain_alloc_irqs_parent(domain, virq, 1, &args); + err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); if (err) return err; @@ -143,27 +162,30 @@ static void gicv2m_unalloc_msi(struct v2m_data *v2m, unsigned int hwirq) return; } - spin_lock(&v2m->msi_cnt_lock); + spin_lock(&v2m_lock); __clear_bit(pos, v2m->bm); - spin_unlock(&v2m->msi_cnt_lock); + spin_unlock(&v2m_lock); } static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *args) { - struct v2m_data *v2m = domain->host_data; + struct v2m_data *v2m = NULL, *tmp; int hwirq, offset, err = 0; - spin_lock(&v2m->msi_cnt_lock); - offset = find_first_zero_bit(v2m->bm, v2m->nr_spis); - if (offset < v2m->nr_spis) - __set_bit(offset, v2m->bm); - else - err = -ENOSPC; - spin_unlock(&v2m->msi_cnt_lock); + spin_lock(&v2m_lock); + list_for_each_entry(tmp, &v2m_nodes, entry) { + offset = find_first_zero_bit(tmp->bm, tmp->nr_spis); + if (offset < tmp->nr_spis) { + __set_bit(offset, tmp->bm); + v2m = tmp; + break; + } + } + spin_unlock(&v2m_lock); - if (err) - return err; + if (!v2m) + return -ENOSPC; hwirq = v2m->spi_start + offset; @@ -224,12 +246,61 @@ static struct msi_domain_info gicv2m_pmsi_domain_info = { .chip = &gicv2m_pmsi_irq_chip, }; +static void gicv2m_teardown(void) +{ + struct v2m_data *v2m, *tmp; + + list_for_each_entry_safe(v2m, tmp, &v2m_nodes, entry) { + list_del(&v2m->entry); + kfree(v2m->bm); + iounmap(v2m->base); + of_node_put(v2m->node); + kfree(v2m); + } +} + +static int gicv2m_allocate_domains(struct irq_domain *parent) +{ + struct irq_domain *inner_domain, *pci_domain, *plat_domain; + struct v2m_data *v2m; + + v2m = list_first_entry_or_null(&v2m_nodes, struct v2m_data, entry); + if (!v2m) + return 0; + + inner_domain = irq_domain_create_tree(of_node_to_fwnode(v2m->node), + &gicv2m_domain_ops, v2m); + if (!inner_domain) { + pr_err("Failed to create GICv2m domain\n"); + return -ENOMEM; + } + + inner_domain->bus_token = DOMAIN_BUS_NEXUS; + inner_domain->parent = parent; + pci_domain = pci_msi_create_irq_domain(of_node_to_fwnode(v2m->node), + &gicv2m_msi_domain_info, + inner_domain); + plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(v2m->node), + &gicv2m_pmsi_domain_info, + inner_domain); + if (!pci_domain || !plat_domain) { + pr_err("Failed to create MSI domains\n"); + if (plat_domain) + irq_domain_remove(plat_domain); + if (pci_domain) + irq_domain_remove(pci_domain); + irq_domain_remove(inner_domain); + return -ENOMEM; + } + + return 0; +} + 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, *pci_domain, *plat_domain; v2m = kzalloc(sizeof(struct v2m_data), GFP_KERNEL); if (!v2m) { @@ -237,6 +308,9 @@ static int __init gicv2m_init_one(struct device_node *node, return -ENOMEM; } + INIT_LIST_HEAD(&v2m->entry); + v2m->node = node; + ret = of_address_to_resource(node, 0, &v2m->res); if (ret) { pr_err("Failed to allocate v2m resource.\n"); @@ -266,6 +340,17 @@ static int __init gicv2m_init_one(struct device_node *node, goto err_iounmap; } + /* + * APM X-Gene GICv2m implementation has an erratum where + * the MSI data needs to be the offset from the spi_start + * in order to trigger the correct MSI interrupt. This is + * different from the standard GICv2m implementation where + * the MSI data is the absolute value within the range from + * spi_start to (spi_start + num_spis). + */ + if (readl_relaxed(v2m->base + V2M_MSI_IIDR) == XGENE_GICV2M_MSI_IIDR) + v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; + v2m->bm = kzalloc(sizeof(long) * BITS_TO_LONGS(v2m->nr_spis), GFP_KERNEL); if (!v2m->bm) { @@ -273,43 +358,13 @@ static int __init gicv2m_init_one(struct device_node *node, goto err_iounmap; } - 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; - } - - inner_domain->bus_token = DOMAIN_BUS_NEXUS; - inner_domain->parent = parent; - 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; - } - - spin_lock_init(&v2m->msi_cnt_lock); - + list_add_tail(&v2m->entry, &v2m_nodes); 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)); return 0; -err_free_domains: - 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: - kfree(v2m->bm); err_iounmap: iounmap(v2m->base); err_free_v2m: @@ -339,5 +394,9 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent) } } + if (!ret) + ret = gicv2m_allocate_domains(parent); + if (ret) + gicv2m_teardown(); return ret; } diff --git a/drivers/irqchip/irq-gic-v3-its-pci-msi.c b/drivers/irqchip/irq-gic-v3-its-pci-msi.c index cf351c637464..aee60ed025dc 100644 --- a/drivers/irqchip/irq-gic-v3-its-pci-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-pci-msi.c @@ -42,7 +42,6 @@ static struct irq_chip its_msi_irq_chip = { struct its_pci_alias { struct pci_dev *pdev; - u32 dev_id; u32 count; }; @@ -60,9 +59,8 @@ 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); + dev_alias->count += its_pci_msi_vec_count(pdev); return 0; } @@ -86,7 +84,7 @@ static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev, pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias); /* ITS specific DeviceID, as the core ITS ignores dev. */ - info->scratchpad[0].ul = dev_alias.dev_id; + info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain, pdev); return msi_info->ops->msi_prepare(domain->parent, dev, dev_alias.count, info); @@ -125,7 +123,8 @@ static int __init its_pci_msi_init(void) continue; } - if (!pci_msi_create_irq_domain(np, &its_pci_msi_domain_info, + if (!pci_msi_create_irq_domain(of_node_to_fwnode(np), + &its_pci_msi_domain_info, parent)) { pr_err("%s: unable to create PCI domain\n", np->full_name); diff --git a/drivers/irqchip/irq-gic-v3-its-platform-msi.c b/drivers/irqchip/irq-gic-v3-its-platform-msi.c index a86550562779..470b4aa7d62c 100644 --- a/drivers/irqchip/irq-gic-v3-its-platform-msi.c +++ b/drivers/irqchip/irq-gic-v3-its-platform-msi.c @@ -29,13 +29,25 @@ static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev, { struct msi_domain_info *msi_info; u32 dev_id; - int ret; + int ret, index = 0; 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); + do { + struct of_phandle_args args; + + ret = of_parse_phandle_with_args(dev->of_node, + "msi-parent", "#msi-cells", + index, &args); + if (args.np == irq_domain_get_of_node(domain)) { + if (WARN_ON(args.args_count != 1)) + return -EINVAL; + dev_id = args.args[0]; + break; + } + } while (!ret); + if (ret) return ret; @@ -78,7 +90,8 @@ static int __init its_pmsi_init(void) continue; } - if (!platform_msi_create_irq_domain(np, &its_pmsi_domain_info, + if (!platform_msi_create_irq_domain(of_node_to_fwnode(np), + &its_pmsi_domain_info, parent)) { pr_err("%s: unable to create platform domain\n", np->full_name); diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 26b55c53755f..e23d1d18f9d6 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -37,7 +37,10 @@ #include <asm/cputype.h> #include <asm/exception.h> -#define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1 << 0) +#include "irq-gic-common.h" + +#define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0) +#define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) #define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) @@ -719,6 +722,9 @@ static unsigned long *its_lpi_alloc_chunks(int nr_irqs, int *base, int *nr_ids) out: spin_unlock(&lpi_lock); + if (!bitmap) + *base = *nr_ids = 0; + return bitmap; } @@ -814,7 +820,22 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) int i; int psz = SZ_64K; u64 shr = GITS_BASER_InnerShareable; - u64 cache = GITS_BASER_WaWb; + u64 cache; + u64 typer; + u32 ids; + + if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_22375) { + /* + * erratum 22375: only alloc 8MB table size + * erratum 24313: ignore memory access type + */ + cache = 0; + ids = 0x14; /* 20 bits, 8MB */ + } else { + cache = GITS_BASER_WaWb; + typer = readq_relaxed(its->base + GITS_TYPER); + ids = GITS_TYPER_DEVBITS(typer); + } for (i = 0; i < GITS_BASER_NR_REGS; i++) { u64 val = readq_relaxed(its->base + GITS_BASER + i * 8); @@ -822,6 +843,7 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) u64 entry_size = GITS_BASER_ENTRY_SIZE(val); int order = get_order(psz); int alloc_size; + int alloc_pages; u64 tmp; void *base; @@ -837,9 +859,6 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) * For other tables, only allocate a single page. */ if (type == GITS_BASER_TYPE_DEVICE) { - u64 typer = readq_relaxed(its->base + GITS_TYPER); - u32 ids = GITS_TYPER_DEVBITS(typer); - /* * 'order' was initialized earlier to the default page * granule of the the ITS. We can't have an allocation @@ -856,6 +875,14 @@ static int its_alloc_tables(const char *node_name, struct its_node *its) } alloc_size = (1 << order) * PAGE_SIZE; + alloc_pages = (alloc_size / psz); + if (alloc_pages > GITS_BASER_PAGES_MAX) { + alloc_pages = GITS_BASER_PAGES_MAX; + order = get_order(GITS_BASER_PAGES_MAX * psz); + pr_warn("%s: Device Table too large, reduce its page order to %u (%u pages)\n", + node_name, order, alloc_pages); + } + base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order); if (!base) { err = -ENOMEM; @@ -884,7 +911,7 @@ retry_baser: break; } - val |= (alloc_size / psz) - 1; + val |= alloc_pages - 1; writeq_relaxed(val, its->base + GITS_BASER + i * 8); tmp = readq_relaxed(its->base + GITS_BASER + i * 8); @@ -898,8 +925,10 @@ retry_baser: * non-cacheable as well. */ shr = tmp & GITS_BASER_SHAREABILITY_MASK; - if (!shr) + if (!shr) { cache = GITS_BASER_nC; + __flush_dcache_area(base, alloc_size); + } goto retry_baser; } @@ -1140,6 +1169,8 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, return NULL; } + __flush_dcache_area(itt, sz); + dev->its = its; dev->itt = itt; dev->nr_ites = nr_ites; @@ -1234,15 +1265,19 @@ static int its_irq_gic_domain_alloc(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq) { - struct of_phandle_args args; + struct irq_fwspec fwspec; - args.np = domain->parent->of_node; - args.args_count = 3; - args.args[0] = GIC_IRQ_TYPE_LPI; - args.args[1] = hwirq; - args.args[2] = IRQ_TYPE_EDGE_RISING; + if (irq_domain_get_of_node(domain->parent)) { + fwspec.fwnode = domain->parent->fwnode; + fwspec.param_count = 3; + fwspec.param[0] = GIC_IRQ_TYPE_LPI; + fwspec.param[1] = hwirq; + fwspec.param[2] = IRQ_TYPE_EDGE_RISING; + } else { + return -EINVAL; + } - return irq_domain_alloc_irqs_parent(domain, virq, 1, &args); + return irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec); } static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, @@ -1363,6 +1398,33 @@ static int its_force_quiescent(void __iomem *base) } } +static void __maybe_unused its_enable_quirk_cavium_22375(void *data) +{ + struct its_node *its = data; + + its->flags |= ITS_FLAGS_WORKAROUND_CAVIUM_22375; +} + +static const struct gic_quirk its_quirks[] = { +#ifdef CONFIG_CAVIUM_ERRATUM_22375 + { + .desc = "ITS: Cavium errata 22375, 24313", + .iidr = 0xa100034c, /* ThunderX pass 1.x */ + .mask = 0xffff0fff, + .init = its_enable_quirk_cavium_22375, + }, +#endif + { + } +}; + +static void its_enable_quirks(struct its_node *its) +{ + u32 iidr = readl_relaxed(its->base + GITS_IIDR); + + gic_enable_quirks(iidr, its_quirks, its); +} + static int its_probe(struct device_node *node, struct irq_domain *parent) { struct resource res; @@ -1421,6 +1483,8 @@ static int its_probe(struct device_node *node, struct irq_domain *parent) } its->cmd_write = its->cmd_base; + its_enable_quirks(its); + err = its_alloc_tables(node->full_name, its); if (err) goto out_free_cmd; diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 7deed6ef54c2..d7be6ddc34f6 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -70,11 +70,6 @@ static inline int gic_irq_in_rdist(struct irq_data *d) return gic_irq(d) < 32; } -static inline bool forwarded_irq(struct irq_data *d) -{ - return d->handler_data != NULL; -} - static inline void __iomem *gic_dist_base(struct irq_data *d) { if (gic_irq_in_rdist(d)) /* SGI+PPI -> SGI_base for this CPU */ @@ -113,57 +108,17 @@ static void gic_redist_wait_for_rwp(void) gic_do_wait_for_rwp(gic_data_rdist_rd_base()); } -/* Low level accessors */ -static u64 __maybe_unused gic_read_iar(void) -{ - u64 irqstat; - - asm volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat)); - return irqstat; -} - -static void __maybe_unused gic_write_pmr(u64 val) -{ - asm volatile("msr_s " __stringify(ICC_PMR_EL1) ", %0" : : "r" (val)); -} - -static void __maybe_unused gic_write_ctlr(u64 val) -{ - asm volatile("msr_s " __stringify(ICC_CTLR_EL1) ", %0" : : "r" (val)); - isb(); -} - -static void __maybe_unused gic_write_grpen1(u64 val) -{ - asm volatile("msr_s " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" (val)); - isb(); -} - -static void __maybe_unused gic_write_sgi1r(u64 val) -{ - asm volatile("msr_s " __stringify(ICC_SGI1R_EL1) ", %0" : : "r" (val)); -} +#ifdef CONFIG_ARM64 +static DEFINE_STATIC_KEY_FALSE(is_cavium_thunderx); -static void gic_enable_sre(void) +static u64 __maybe_unused gic_read_iar(void) { - u64 val; - - asm volatile("mrs_s %0, " __stringify(ICC_SRE_EL1) : "=r" (val)); - val |= ICC_SRE_EL1_SRE; - asm volatile("msr_s " __stringify(ICC_SRE_EL1) ", %0" : : "r" (val)); - isb(); - - /* - * Need to check that the SRE bit has actually been set. If - * not, it means that SRE is disabled at EL2. We're going to - * die painfully, and there is nothing we can do about it. - * - * Kindly inform the luser. - */ - asm volatile("mrs_s %0, " __stringify(ICC_SRE_EL1) : "=r" (val)); - if (!(val & ICC_SRE_EL1_SRE)) - pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n"); + if (static_branch_unlikely(&is_cavium_thunderx)) + return gic_read_iar_cavium_thunderx(); + else + return gic_read_iar_common(); } +#endif static void gic_enable_redist(bool enable) { @@ -249,7 +204,7 @@ static void gic_eoimode1_mask_irq(struct irq_data *d) * disabled/masked will not get "stuck", because there is * noone to deactivate it (guest is being terminated). */ - if (forwarded_irq(d)) + if (irqd_is_forwarded_to_vcpu(d)) gic_poke_irq(d, GICD_ICACTIVER); } @@ -324,7 +279,7 @@ static void gic_eoimode1_eoi_irq(struct irq_data *d) * No need to deactivate an LPI, or an interrupt that * is is getting forwarded to a vcpu. */ - if (gic_irq(d) >= 8192 || forwarded_irq(d)) + if (gic_irq(d) >= 8192 || irqd_is_forwarded_to_vcpu(d)) return; gic_write_dir(gic_irq(d)); } @@ -357,15 +312,18 @@ static int gic_set_type(struct irq_data *d, unsigned int type) static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) { - d->handler_data = vcpu; + if (vcpu) + irqd_set_forwarded_to_vcpu(d); + else + irqd_clr_forwarded_to_vcpu(d); return 0; } -static u64 gic_mpidr_to_affinity(u64 mpidr) +static u64 gic_mpidr_to_affinity(unsigned long mpidr) { u64 aff; - aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 | + aff = ((u64)MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 | MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 | MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 | MPIDR_AFFINITY_LEVEL(mpidr, 0)); @@ -375,7 +333,7 @@ static u64 gic_mpidr_to_affinity(u64 mpidr) static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) { - u64 irqnr; + u32 irqnr; do { irqnr = gic_read_iar(); @@ -434,12 +392,12 @@ static void __init gic_dist_init(void) */ affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id())); for (i = 32; i < gic_data.irq_nr; i++) - writeq_relaxed(affinity, base + GICD_IROUTER + i * 8); + gic_write_irouter(affinity, base + GICD_IROUTER + i * 8); } static int gic_populate_rdist(void) { - u64 mpidr = cpu_logical_map(smp_processor_id()); + unsigned long mpidr = cpu_logical_map(smp_processor_id()); u64 typer; u32 aff; int i; @@ -465,15 +423,14 @@ static int gic_populate_rdist(void) } do { - typer = readq_relaxed(ptr + GICR_TYPER); + typer = gic_read_typer(ptr + GICR_TYPER); if ((typer >> 32) == aff) { u64 offset = ptr - gic_data.redist_regions[i].redist_base; gic_data_rdist_rd_base() = ptr; gic_data_rdist()->phys_base = gic_data.redist_regions[i].phys_base + offset; - pr_info("CPU%d: found redistributor %llx region %d:%pa\n", - smp_processor_id(), - (unsigned long long)mpidr, - i, &gic_data_rdist()->phys_base); + pr_info("CPU%d: found redistributor %lx region %d:%pa\n", + smp_processor_id(), mpidr, i, + &gic_data_rdist()->phys_base); return 0; } @@ -488,15 +445,22 @@ static int gic_populate_rdist(void) } /* We couldn't even deal with ourselves... */ - WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n", - smp_processor_id(), (unsigned long long)mpidr); + WARN(true, "CPU%d: mpidr %lx has no re-distributor!\n", + smp_processor_id(), mpidr); return -ENODEV; } static void gic_cpu_sys_reg_init(void) { - /* Enable system registers */ - gic_enable_sre(); + /* + * Need to check that the SRE bit has actually been set. If + * not, it means that SRE is disabled at EL2. We're going to + * die painfully, and there is nothing we can do about it. + * + * Kindly inform the luser. + */ + if (!gic_enable_sre()) + pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n"); /* Set priority mask register */ gic_write_pmr(DEFAULT_PMR_VALUE); @@ -559,10 +523,10 @@ static struct notifier_block gic_cpu_notifier = { }; static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask, - u64 cluster_id) + unsigned long cluster_id) { int cpu = *base_cpu; - u64 mpidr = cpu_logical_map(cpu); + unsigned long mpidr = cpu_logical_map(cpu); u16 tlist = 0; while (cpu < nr_cpu_ids) { @@ -623,7 +587,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) smp_wmb(); for_each_cpu(cpu, mask) { - u64 cluster_id = cpu_logical_map(cpu) & ~0xffUL; + unsigned long cluster_id = cpu_logical_map(cpu) & ~0xffUL; u16 tlist; tlist = gic_compute_target_list(&cpu, mask, cluster_id); @@ -659,7 +623,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, reg = gic_dist_base(d) + GICD_IROUTER + (gic_irq(d) * 8); val = gic_mpidr_to_affinity(cpu_logical_map(cpu)); - writeq_relaxed(val, reg); + gic_write_irouter(val, reg); /* * If the interrupt was enabled, enabled it again. Otherwise, @@ -754,13 +718,13 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_set_percpu_devid(irq); irq_domain_set_info(d, irq, hw, chip, d->host_data, handle_percpu_devid_irq, NULL, NULL); - set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); + irq_set_status_flags(irq, IRQ_NOAUTOEN); } /* SPIs */ if (hw >= 32 && hw < gic_data.irq_nr) { irq_domain_set_info(d, irq, hw, chip, d->host_data, handle_fasteoi_irq, NULL, NULL); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(irq); } /* LPIs */ if (hw >= 8192 && hw < GIC_ID_NR) { @@ -768,38 +732,39 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, return -EPERM; irq_domain_set_info(d, irq, hw, chip, d->host_data, handle_fasteoi_irq, NULL, NULL); - set_irq_flags(irq, IRQF_VALID); } return 0; } -static int gic_irq_domain_xlate(struct irq_domain *d, - struct device_node *controller, - const u32 *intspec, unsigned int intsize, - unsigned long *out_hwirq, unsigned int *out_type) +static int gic_irq_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) { - if (d->of_node != controller) - return -EINVAL; - if (intsize < 3) - return -EINVAL; + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count < 3) + return -EINVAL; - switch(intspec[0]) { - case 0: /* SPI */ - *out_hwirq = intspec[1] + 32; - break; - case 1: /* PPI */ - *out_hwirq = intspec[1] + 16; - break; - case GIC_IRQ_TYPE_LPI: /* LPI */ - *out_hwirq = intspec[1]; - break; - default: - return -EINVAL; + switch (fwspec->param[0]) { + case 0: /* SPI */ + *hwirq = fwspec->param[1] + 32; + break; + case 1: /* PPI */ + *hwirq = fwspec->param[1] + 16; + break; + case GIC_IRQ_TYPE_LPI: /* LPI */ + *hwirq = fwspec->param[1]; + break; + default: + return -EINVAL; + } + + *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; + return 0; } - *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; - return 0; + return -EINVAL; } static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, @@ -808,10 +773,9 @@ static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, int i, ret; irq_hw_number_t hwirq; unsigned int type = IRQ_TYPE_NONE; - struct of_phandle_args *irq_data = arg; + struct irq_fwspec *fwspec = arg; - ret = gic_irq_domain_xlate(domain, irq_data->np, irq_data->args, - irq_data->args_count, &hwirq, &type); + ret = gic_irq_domain_translate(domain, fwspec, &hwirq, &type); if (ret) return ret; @@ -834,11 +798,19 @@ static void gic_irq_domain_free(struct irq_domain *domain, unsigned int virq, } static const struct irq_domain_ops gic_irq_domain_ops = { - .xlate = gic_irq_domain_xlate, + .translate = gic_irq_domain_translate, .alloc = gic_irq_domain_alloc, .free = gic_irq_domain_free, }; +static void gicv3_enable_quirks(void) +{ +#ifdef CONFIG_ARM64 + if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_23154)) + static_branch_enable(&is_cavium_thunderx); +#endif +} + static int __init gic_of_init(struct device_node *node, struct device_node *parent) { void __iomem *dist_base; @@ -904,6 +876,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare gic_data.nr_redist_regions = nr_redist_regions; gic_data.redist_stride = redist_stride; + gicv3_enable_quirks(); + /* * Find out how many interrupts are supported. * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index e6b7ed537952..515c823c1c95 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -41,7 +41,6 @@ #include <linux/irqchip.h> #include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> -#include <linux/irqchip/arm-gic-acpi.h> #include <asm/cputype.h> #include <asm/irq.h> @@ -51,6 +50,19 @@ #include "irq-gic-common.h" +#ifdef CONFIG_ARM64 +#include <asm/cpufeature.h> + +static void gic_check_cpu_features(void) +{ + WARN_TAINT_ONCE(cpus_have_cap(ARM64_HAS_SYSREG_GIC_CPUIF), + TAINT_CPU_OUT_OF_SPEC, + "GICv3 system registers enabled, broken firmware!\n"); +} +#else +#define gic_check_cpu_features() do { } while(0) +#endif + union gic_base { void __iomem *common_base; void __percpu * __iomem *percpu_base; @@ -145,29 +157,10 @@ static inline bool cascading_gic_irq(struct irq_data *d) void *data = irq_data_get_irq_handler_data(d); /* - * If handler_data pointing to one of the secondary GICs, then - * this is a cascading interrupt, and it cannot possibly be - * forwarded. + * If handler_data is set, this is a cascading interrupt, and + * it cannot possibly be forwarded. */ - if (data >= (void *)(gic_data + 1) && - data < (void *)(gic_data + MAX_GIC_NR)) - return true; - - return false; -} - -static inline bool forwarded_irq(struct irq_data *d) -{ - /* - * A forwarded interrupt: - * - is on the primary GIC - * - has its handler_data set to a value - * - that isn't a secondary GIC - */ - if (d->handler_data && !cascading_gic_irq(d)) - return true; - - return false; + return data != NULL; } /* @@ -201,7 +194,7 @@ static void gic_eoimode1_mask_irq(struct irq_data *d) * disabled/masked will not get "stuck", because there is * noone to deactivate it (guest is being terminated). */ - if (forwarded_irq(d)) + if (irqd_is_forwarded_to_vcpu(d)) gic_poke_irq(d, GIC_DIST_ACTIVE_CLEAR); } @@ -218,7 +211,7 @@ static void gic_eoi_irq(struct irq_data *d) static void gic_eoimode1_eoi_irq(struct irq_data *d) { /* Do not deactivate an IRQ forwarded to a vcpu. */ - if (forwarded_irq(d)) + if (irqd_is_forwarded_to_vcpu(d)) return; writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_DEACTIVATE); @@ -296,7 +289,10 @@ static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) if (cascading_gic_irq(d)) return -EINVAL; - d->handler_data = vcpu; + if (vcpu) + irqd_set_forwarded_to_vcpu(d); + else + irqd_clr_forwarded_to_vcpu(d); return 0; } @@ -357,7 +353,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) } while (1); } -static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) +static void gic_handle_cascade_irq(struct irq_desc *desc) { struct gic_chip_data *chip_data = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); @@ -376,7 +372,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) cascade_irq = irq_find_mapping(chip_data->domain, gic_irq); if (unlikely(gic_irq < 32 || gic_irq > 1020)) - handle_bad_irq(cascade_irq, desc); + handle_bad_irq(desc); else generic_handle_irq(cascade_irq); @@ -906,11 +902,11 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_set_percpu_devid(irq); irq_domain_set_info(d, irq, hw, chip, d->host_data, handle_percpu_devid_irq, NULL, NULL); - set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); + irq_set_status_flags(irq, IRQ_NOAUTOEN); } else { irq_domain_set_info(d, irq, hw, chip, d->host_data, handle_fasteoi_irq, NULL, NULL); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(irq); } return 0; } @@ -919,28 +915,39 @@ static void gic_irq_domain_unmap(struct irq_domain *d, unsigned int irq) { } -static int gic_irq_domain_xlate(struct irq_domain *d, - struct device_node *controller, - const u32 *intspec, unsigned int intsize, - unsigned long *out_hwirq, unsigned int *out_type) +static int gic_irq_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) { - unsigned long ret = 0; + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count < 3) + return -EINVAL; - if (d->of_node != controller) - return -EINVAL; - if (intsize < 3) - return -EINVAL; + /* Get the interrupt number and add 16 to skip over SGIs */ + *hwirq = fwspec->param[1] + 16; - /* Get the interrupt number and add 16 to skip over SGIs */ - *out_hwirq = intspec[1] + 16; + /* + * For SPIs, we need to add 16 more to get the GIC irq + * ID number + */ + if (!fwspec->param[0]) + *hwirq += 16; + + *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; + return 0; + } - /* For SPIs, we need to add 16 more to get the GIC irq ID number */ - if (!intspec[0]) - *out_hwirq += 16; + if (fwspec->fwnode->type == FWNODE_IRQCHIP) { + if(fwspec->param_count != 2) + return -EINVAL; - *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; + *hwirq = fwspec->param[0]; + *type = fwspec->param[1]; + return 0; + } - return ret; + return -EINVAL; } #ifdef CONFIG_SMP @@ -968,10 +975,9 @@ static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, int i, ret; irq_hw_number_t hwirq; unsigned int type = IRQ_TYPE_NONE; - struct of_phandle_args *irq_data = arg; + struct irq_fwspec *fwspec = arg; - ret = gic_irq_domain_xlate(domain, irq_data->np, irq_data->args, - irq_data->args_count, &hwirq, &type); + ret = gic_irq_domain_translate(domain, fwspec, &hwirq, &type); if (ret) return ret; @@ -982,7 +988,7 @@ static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, } static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = { - .xlate = gic_irq_domain_xlate, + .translate = gic_irq_domain_translate, .alloc = gic_irq_domain_alloc, .free = irq_domain_free_irqs_top, }; @@ -990,12 +996,11 @@ static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = { static const struct irq_domain_ops gic_irq_domain_ops = { .map = gic_irq_domain_map, .unmap = gic_irq_domain_unmap, - .xlate = gic_irq_domain_xlate, }; static 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) + u32 percpu_offset, struct fwnode_handle *handle) { irq_hw_number_t hwirq_base; struct gic_chip_data *gic; @@ -1003,6 +1008,8 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start, BUG_ON(gic_nr >= MAX_GIC_NR); + gic_check_cpu_features(); + gic = &gic_data[gic_nr]; #ifdef CONFIG_GIC_NON_BANKED if (percpu_offset) { /* Frankein-GIC without banked registers... */ @@ -1047,11 +1054,11 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start, gic_irqs = 1020; gic->gic_irqs = gic_irqs; - if (node) { /* DT case */ - gic->domain = irq_domain_add_linear(node, gic_irqs, - &gic_irq_domain_hierarchy_ops, - gic); - } else { /* Non-DT case */ + if (handle) { /* DT/ACPI */ + gic->domain = irq_domain_create_linear(handle, gic_irqs, + &gic_irq_domain_hierarchy_ops, + gic); + } else { /* Legacy support */ /* * For primary GICs, skip over SGIs. * For secondary GICs, skip over PPIs, too. @@ -1074,7 +1081,7 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start, irq_base = irq_start; } - gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, + gic->domain = irq_domain_add_legacy(NULL, gic_irqs, irq_base, hwirq_base, &gic_irq_domain_ops, gic); } @@ -1103,28 +1110,63 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start, gic_pm_init(gic); } -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) +void __init gic_init(unsigned int gic_nr, int irq_start, + void __iomem *dist_base, void __iomem *cpu_base) { /* * Non-DT/ACPI systems won't run a hypervisor, so let's not * bother with these... */ static_key_slow_dec(&supports_deactivate); - __gic_init_bases(gic_nr, irq_start, dist_base, cpu_base, - percpu_offset, node); + __gic_init_bases(gic_nr, irq_start, dist_base, cpu_base, 0, NULL); } #ifdef CONFIG_OF static int gic_cnt __initdata; +static bool gic_check_eoimode(struct device_node *node, void __iomem **base) +{ + struct resource cpuif_res; + + of_address_to_resource(node, 1, &cpuif_res); + + if (!is_hyp_mode_available()) + return false; + if (resource_size(&cpuif_res) < SZ_8K) + return false; + if (resource_size(&cpuif_res) == SZ_128K) { + u32 val_low, val_high; + + /* + * Verify that we have the first 4kB of a GIC400 + * aliased over the first 64kB by checking the + * GICC_IIDR register on both ends. + */ + val_low = readl_relaxed(*base + GIC_CPU_IDENT); + val_high = readl_relaxed(*base + GIC_CPU_IDENT + 0xf000); + if ((val_low & 0xffff0fff) != 0x0202043B || + val_low != val_high) + return false; + + /* + * Move the base up by 60kB, so that we have a 8kB + * contiguous region, which allows us to use GICC_DIR + * at its normal offset. Please pass me that bucket. + */ + *base += 0xf000; + cpuif_res.start += 0xf000; + pr_warn("GIC: Adjusting CPU interface base to %pa", + &cpuif_res.start); + } + + return true; +} + static int __init gic_of_init(struct device_node *node, struct device_node *parent) { void __iomem *cpu_base; void __iomem *dist_base; - struct resource cpu_res; u32 percpu_offset; int irq; @@ -1137,20 +1179,18 @@ gic_of_init(struct device_node *node, struct device_node *parent) cpu_base = of_iomap(node, 1); WARN(!cpu_base, "unable to map gic cpu registers\n"); - of_address_to_resource(node, 1, &cpu_res); - /* * Disable split EOI/Deactivate if either HYP is not available * or the CPU interface is too small. */ - if (gic_cnt == 0 && (!is_hyp_mode_available() || - resource_size(&cpu_res) < SZ_8K)) + if (gic_cnt == 0 && !gic_check_eoimode(node, &cpu_base)) static_key_slow_dec(&supports_deactivate); if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) percpu_offset = 0; - __gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node); + __gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, + &node->fwnode); if (!gic_cnt) gic_init_physaddr(node); @@ -1173,11 +1213,12 @@ IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init); IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init); IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init); IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init); +IRQCHIP_DECLARE(pl390, "arm,pl390", gic_of_init); #endif #ifdef CONFIG_ACPI -static phys_addr_t dist_phy_base, cpu_phy_base __initdata; +static phys_addr_t cpu_phy_base __initdata; static int __init gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, @@ -1205,60 +1246,57 @@ gic_acpi_parse_madt_cpu(struct acpi_subtable_header *header, return 0; } -static int __init -gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, - const unsigned long end) +/* The things you have to do to just *count* something... */ +static int __init acpi_dummy_func(struct acpi_subtable_header *header, + const unsigned long end) { - struct acpi_madt_generic_distributor *dist; + return 0; +} - dist = (struct acpi_madt_generic_distributor *)header; +static bool __init acpi_gic_redist_is_present(void) +{ + return acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR, + acpi_dummy_func, 0) > 0; +} - if (BAD_MADT_ENTRY(dist, end)) - return -EINVAL; +static bool __init gic_validate_dist(struct acpi_subtable_header *header, + struct acpi_probe_entry *ape) +{ + struct acpi_madt_generic_distributor *dist; + dist = (struct acpi_madt_generic_distributor *)header; - dist_phy_base = dist->base_address; - return 0; + return (dist->version == ape->driver_data && + (dist->version != ACPI_MADT_GIC_VERSION_NONE || + !acpi_gic_redist_is_present())); } -int __init -gic_v2_acpi_init(struct acpi_table_header *table) +#define ACPI_GICV2_DIST_MEM_SIZE (SZ_4K) +#define ACPI_GIC_CPU_IF_MEM_SIZE (SZ_8K) + +static int __init gic_v2_acpi_init(struct acpi_subtable_header *header, + const unsigned long end) { + struct acpi_madt_generic_distributor *dist; void __iomem *cpu_base, *dist_base; + struct fwnode_handle *domain_handle; int count; /* Collect CPU base addresses */ - count = acpi_parse_entries(ACPI_SIG_MADT, - sizeof(struct acpi_table_madt), - gic_acpi_parse_madt_cpu, table, - ACPI_MADT_TYPE_GENERIC_INTERRUPT, 0); + count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT, + gic_acpi_parse_madt_cpu, 0); if (count <= 0) { pr_err("No valid GICC entries exist\n"); return -EINVAL; } - /* - * Find distributor base address. We expect one distributor entry since - * ACPI 5.1 spec neither support multi-GIC instances nor GIC cascade. - */ - count = acpi_parse_entries(ACPI_SIG_MADT, - sizeof(struct acpi_table_madt), - gic_acpi_parse_madt_distributor, table, - ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, 0); - if (count <= 0) { - pr_err("No valid GICD entries exist\n"); - return -EINVAL; - } else if (count > 1) { - pr_err("More than one GICD entry detected\n"); - return -EINVAL; - } - cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE); if (!cpu_base) { pr_err("Unable to map GICC registers\n"); return -ENOMEM; } - dist_base = ioremap(dist_phy_base, ACPI_GICV2_DIST_MEM_SIZE); + dist = (struct acpi_madt_generic_distributor *)header; + dist_base = ioremap(dist->base_address, ACPI_GICV2_DIST_MEM_SIZE); if (!dist_base) { pr_err("Unable to map GICD registers\n"); iounmap(cpu_base); @@ -1274,14 +1312,25 @@ gic_v2_acpi_init(struct acpi_table_header *table) static_key_slow_dec(&supports_deactivate); /* - * Initialize zero GIC instance (no multi-GIC support). Also, set GIC - * as default IRQ domain to allow for GSI registration and GSI to IRQ - * number translation (see acpi_register_gsi() and acpi_gsi_to_irq()). + * Initialize GIC instance zero (no multi-GIC support). */ - __gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); - irq_set_default_host(gic_data[0].domain); + domain_handle = irq_domain_alloc_fwnode(dist_base); + if (!domain_handle) { + pr_err("Unable to allocate domain handle\n"); + iounmap(cpu_base); + iounmap(dist_base); + return -ENOMEM; + } + + __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle); - acpi_irq_model = ACPI_IRQ_MODEL_GIC; + acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle); return 0; } +IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, + gic_validate_dist, ACPI_MADT_GIC_VERSION_V2, + gic_v2_acpi_init); +IRQCHIP_ACPI_DECLARE(gic_v2_maybe, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR, + gic_validate_dist, ACPI_MADT_GIC_VERSION_NONE, + gic_v2_acpi_init); #endif diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index a0128c7c98dd..9688d2e2a636 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -307,11 +307,11 @@ static int hip04_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_set_percpu_devid(irq); irq_set_chip_and_handler(irq, &hip04_irq_chip, handle_percpu_devid_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); + irq_set_status_flags(irq, IRQ_NOAUTOEN); } else { irq_set_chip_and_handler(irq, &hip04_irq_chip, handle_fasteoi_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(irq); } irq_set_chip_data(irq, d->host_data); return 0; @@ -325,7 +325,7 @@ static int hip04_irq_domain_xlate(struct irq_domain *d, { unsigned long ret = 0; - if (d->of_node != controller) + if (irq_domain_get_of_node(d) != controller) return -EINVAL; if (intsize < 3) return -EINVAL; diff --git a/drivers/irqchip/irq-i8259.c b/drivers/irqchip/irq-i8259.c index 4836102ba312..6b304eb39bd2 100644 --- a/drivers/irqchip/irq-i8259.c +++ b/drivers/irqchip/irq-i8259.c @@ -352,7 +352,7 @@ 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(struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); int hwirq = i8259_irq(); @@ -377,8 +377,8 @@ int __init i8259_of_init(struct device_node *node, struct device_node *parent) } domain = __init_i8259_irqs(node); - irq_set_handler_data(parent_irq, domain); - irq_set_chained_handler(parent_irq, i8259_irq_dispatch); + irq_set_chained_handler_and_data(parent_irq, i8259_irq_dispatch, + domain); return 0; } IRQCHIP_DECLARE(i8259, "intel,i8259", i8259_of_init); diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c index 841604b81004..c02d29c9dc05 100644 --- a/drivers/irqchip/irq-imgpdc.c +++ b/drivers/irqchip/irq-imgpdc.c @@ -218,7 +218,7 @@ 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(struct irq_desc *desc) { unsigned int irq = irq_desc_get_irq(desc); struct pdc_intc_priv *priv; @@ -240,7 +240,7 @@ found: generic_handle_irq(irq_no); } -static void pdc_intc_syswake_isr(unsigned int irq, struct irq_desc *desc) +static void pdc_intc_syswake_isr(struct irq_desc *desc) { struct pdc_intc_priv *priv; unsigned int syswake, irq_no; diff --git a/drivers/irqchip/irq-imx-gpcv2.c b/drivers/irqchip/irq-imx-gpcv2.c index e48d3305456f..15af9a9753e5 100644 --- a/drivers/irqchip/irq-imx-gpcv2.c +++ b/drivers/irqchip/irq-imx-gpcv2.c @@ -150,49 +150,42 @@ static struct irq_chip gpcv2_irqchip_data_chip = { #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) +static int imx_gpcv2_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) { - /* Shouldn't happen, really... */ - if (domain->of_node != controller) - return -EINVAL; + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count != 3) + return -EINVAL; - /* Not GIC compliant */ - if (intsize != 3) - return -EINVAL; + /* No PPI should point to this domain */ + if (fwspec->param[0] != 0) + return -EINVAL; - /* No PPI should point to this domain */ - if (intspec[0] != 0) - return -EINVAL; + *hwirq = fwspec->param[1]; + *type = fwspec->param[2]; + return 0; + } - *out_hwirq = intspec[1]; - *out_type = intspec[2]; - return 0; + return -EINVAL; } 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; + struct irq_fwspec *fwspec = data; + struct irq_fwspec parent_fwspec; irq_hw_number_t hwirq; + unsigned int type; + int err; 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; + err = imx_gpcv2_domain_translate(domain, fwspec, &hwirq, &type); + if (err) + return err; - /* Can't deal with this */ - hwirq = args->args[1]; if (hwirq >= GPC_MAX_IRQS) return -EINVAL; @@ -201,15 +194,16 @@ static int imx_gpcv2_domain_alloc(struct irq_domain *domain, &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); + parent_fwspec = *fwspec; + parent_fwspec.fwnode = domain->parent->fwnode; + return irq_domain_alloc_irqs_parent(domain, irq, nr_irqs, + &parent_fwspec); } 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, + .translate = imx_gpcv2_domain_translate, + .alloc = imx_gpcv2_domain_alloc, + .free = irq_domain_free_irqs_common, }; static int __init imx_gpcv2_irqchip_init(struct device_node *node, diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index c1517267b5db..deb89d63a728 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -83,7 +83,7 @@ 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(struct irq_desc *desc) { unsigned int irq = irq_desc_get_irq(desc); struct keystone_irq_device *kirq = irq_desc_get_handler_data(desc); @@ -127,7 +127,7 @@ static int keystone_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_data(virq, kirq); irq_set_chip_and_handler(virq, &kirq->chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(virq); return 0; } diff --git a/drivers/irqchip/irq-metag-ext.c b/drivers/irqchip/irq-metag-ext.c index 5f4c52928d16..8c38b3d92e1c 100644 --- a/drivers/irqchip/irq-metag-ext.c +++ b/drivers/irqchip/irq-metag-ext.c @@ -446,7 +446,7 @@ static int meta_intc_irq_set_type(struct irq_data *data, unsigned int flow_type) * Whilst using TR2 to detect external interrupts is a software convention it is * (hopefully) unlikely to change. */ -static void meta_intc_irq_demux(unsigned int irq, struct irq_desc *desc) +static void meta_intc_irq_demux(struct irq_desc *desc) { struct meta_intc_priv *priv = &meta_intc_priv; irq_hw_number_t hw; diff --git a/drivers/irqchip/irq-metag.c b/drivers/irqchip/irq-metag.c index 3d23ce3edb5c..a5f053bd2f44 100644 --- a/drivers/irqchip/irq-metag.c +++ b/drivers/irqchip/irq-metag.c @@ -220,7 +220,7 @@ static int metag_internal_irq_set_affinity(struct irq_data *data, * occurred. It is this function's job to demux this irq and * figure out exactly which trigger needs servicing. */ -static void metag_internal_irq_demux(unsigned int irq, struct irq_desc *desc) +static void metag_internal_irq_demux(struct irq_desc *desc) { struct metag_internal_irq_priv *priv = irq_desc_get_handler_data(desc); irq_hw_number_t hw; diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 1764bcf8ee6b..aeaa061f0dbf 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -320,6 +320,14 @@ static void gic_handle_shared_int(bool chained) intrmask[i] = gic_read(intrmask_reg); pending_reg += gic_reg_step; intrmask_reg += gic_reg_step; + + if (!config_enabled(CONFIG_64BIT) || mips_cm_is64) + continue; + + pending[i] |= (u64)gic_read(pending_reg) << 32; + intrmask[i] |= (u64)gic_read(intrmask_reg) << 32; + pending_reg += gic_reg_step; + intrmask_reg += gic_reg_step; } bitmap_and(pending, pending, intrmask, gic_shared_intrs); @@ -426,7 +434,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, spin_lock_irqsave(&gic_lock, flags); /* Re-route this IRQ */ - gic_map_to_vpe(irq, cpumask_first(&tmp)); + gic_map_to_vpe(irq, mips_cm_vp_id(cpumask_first(&tmp))); /* Update the pcpu_masks */ for (i = 0; i < NR_CPUS; i++) @@ -546,7 +554,7 @@ static void __gic_irq_dispatch(void) gic_handle_shared_int(false); } -static void gic_irq_dispatch(unsigned int irq, struct irq_desc *desc) +static void gic_irq_dispatch(struct irq_desc *desc) { gic_handle_local_int(true); gic_handle_shared_int(true); @@ -599,7 +607,7 @@ static __init void gic_ipi_init_one(unsigned int intr, int cpu, GIC_SHARED_TO_HWIRQ(intr)); int i; - gic_map_to_vpe(intr, cpu); + gic_map_to_vpe(intr, mips_cm_vp_id(cpu)); for (i = 0; i < NR_CPUS; i++) clear_bit(intr, pcpu_masks[i].pcpu_mask); set_bit(intr, pcpu_masks[cpu].pcpu_mask); diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c index 781ed6e71dbb..013fc9659a84 100644 --- a/drivers/irqchip/irq-mmp.c +++ b/drivers/irqchip/irq-mmp.c @@ -129,7 +129,7 @@ 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(struct irq_desc *desc) { unsigned int irq = irq_desc_get_irq(desc); struct irq_domain *domain; @@ -164,7 +164,6 @@ static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); return 0; } @@ -234,7 +233,6 @@ void __init icu_init_irq(void) for (irq = 0; irq < 64; irq++) { icu_mask_irq(irq_get_irq_data(irq)); irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); } irq_set_default_host(icu_data[0].domain); set_handle_irq(mmp_handle_irq); @@ -337,7 +335,6 @@ void __init mmp2_init_icu(void) irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq); } - set_irq_flags(irq, IRQF_VALID); } irq_set_default_host(icu_data[0].domain); set_handle_irq(mmp2_handle_irq); diff --git a/drivers/irqchip/irq-mtk-sysirq.c b/drivers/irqchip/irq-mtk-sysirq.c index c8753da4c156..63ac73b1d9c8 100644 --- a/drivers/irqchip/irq-mtk-sysirq.c +++ b/drivers/irqchip/irq-mtk-sysirq.c @@ -67,22 +67,25 @@ static struct irq_chip mtk_sysirq_chip = { .irq_set_affinity = irq_chip_set_affinity_parent, }; -static int mtk_sysirq_domain_xlate(struct irq_domain *d, - struct device_node *controller, - const u32 *intspec, unsigned int intsize, - unsigned long *out_hwirq, - unsigned int *out_type) +static int mtk_sysirq_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) { - if (intsize != 3) - return -EINVAL; + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count != 3) + return -EINVAL; - /* sysirq doesn't support PPI */ - if (intspec[0]) - return -EINVAL; + /* No PPI should point to this domain */ + if (fwspec->param[0] != 0) + return -EINVAL; - *out_hwirq = intspec[1]; - *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; - return 0; + *hwirq = fwspec->param[1]; + *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; + return 0; + } + + return -EINVAL; } static int mtk_sysirq_domain_alloc(struct irq_domain *domain, unsigned int virq, @@ -90,30 +93,30 @@ static int mtk_sysirq_domain_alloc(struct irq_domain *domain, unsigned int virq, { int i; irq_hw_number_t hwirq; - struct of_phandle_args *irq_data = arg; - struct of_phandle_args gic_data = *irq_data; + struct irq_fwspec *fwspec = arg; + struct irq_fwspec gic_fwspec = *fwspec; - if (irq_data->args_count != 3) + if (fwspec->param_count != 3) return -EINVAL; /* sysirq doesn't support PPI */ - if (irq_data->args[0]) + if (fwspec->param[0]) return -EINVAL; - hwirq = irq_data->args[1]; + hwirq = fwspec->param[1]; for (i = 0; i < nr_irqs; i++) irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, &mtk_sysirq_chip, domain->host_data); - gic_data.np = domain->parent->of_node; - return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_data); + gic_fwspec.fwnode = domain->parent->fwnode; + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_fwspec); } static const struct irq_domain_ops sysirq_domain_ops = { - .xlate = mtk_sysirq_domain_xlate, - .alloc = mtk_sysirq_domain_alloc, - .free = irq_domain_free_irqs_common, + .translate = mtk_sysirq_domain_translate, + .alloc = mtk_sysirq_domain_alloc, + .free = irq_domain_free_irqs_common, }; static int __init mtk_sysirq_of_init(struct device_node *node, diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c index 1faf812f3dc8..c22e2d40cb30 100644 --- a/drivers/irqchip/irq-mxs.c +++ b/drivers/irqchip/irq-mxs.c @@ -1,5 +1,7 @@ /* * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2014 Oleksij Rempel <linux@rempel-privat.de> + * Add Alphascale ASM9260 support. * * 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 @@ -28,20 +30,64 @@ #include <linux/stmp_device.h> #include <asm/exception.h> +#include "alphascale_asm9260-icoll.h" + +/* + * this device provide 4 offsets for each register: + * 0x0 - plain read write mode + * 0x4 - set mode, OR logic. + * 0x8 - clr mode, XOR logic. + * 0xc - togle mode. + */ +#define SET_REG 4 +#define CLR_REG 8 + #define HW_ICOLL_VECTOR 0x0000 #define HW_ICOLL_LEVELACK 0x0010 #define HW_ICOLL_CTRL 0x0020 #define HW_ICOLL_STAT_OFFSET 0x0070 -#define HW_ICOLL_INTERRUPTn_SET(n) (0x0124 + (n) * 0x10) -#define HW_ICOLL_INTERRUPTn_CLR(n) (0x0128 + (n) * 0x10) -#define BM_ICOLL_INTERRUPTn_ENABLE 0x00000004 +#define HW_ICOLL_INTERRUPT0 0x0120 +#define HW_ICOLL_INTERRUPTn(n) ((n) * 0x10) +#define BM_ICOLL_INTR_ENABLE BIT(2) #define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 0x1 #define ICOLL_NUM_IRQS 128 -static void __iomem *icoll_base; +enum icoll_type { + ICOLL, + ASM9260_ICOLL, +}; + +struct icoll_priv { + void __iomem *vector; + void __iomem *levelack; + void __iomem *ctrl; + void __iomem *stat; + void __iomem *intr; + void __iomem *clear; + enum icoll_type type; +}; + +static struct icoll_priv icoll_priv; static struct irq_domain *icoll_domain; +/* calculate bit offset depending on number of intterupt per register */ +static u32 icoll_intr_bitshift(struct irq_data *d, u32 bit) +{ + /* + * mask lower part of hwirq to convert it + * in 0, 1, 2 or 3 and then multiply it by 8 (or shift by 3) + */ + return bit << ((d->hwirq & 3) << 3); +} + +/* calculate mem offset depending on number of intterupt per register */ +static void __iomem *icoll_intr_reg(struct irq_data *d) +{ + /* offset = hwirq / intr_per_reg * 0x10 */ + return icoll_priv.intr + ((d->hwirq >> 2) * 0x10); +} + static void icoll_ack_irq(struct irq_data *d) { /* @@ -50,19 +96,35 @@ static void icoll_ack_irq(struct irq_data *d) * BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 unconditionally. */ __raw_writel(BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0, - icoll_base + HW_ICOLL_LEVELACK); + icoll_priv.levelack); } static void icoll_mask_irq(struct irq_data *d) { - __raw_writel(BM_ICOLL_INTERRUPTn_ENABLE, - icoll_base + HW_ICOLL_INTERRUPTn_CLR(d->hwirq)); + __raw_writel(BM_ICOLL_INTR_ENABLE, + icoll_priv.intr + CLR_REG + HW_ICOLL_INTERRUPTn(d->hwirq)); } static void icoll_unmask_irq(struct irq_data *d) { - __raw_writel(BM_ICOLL_INTERRUPTn_ENABLE, - icoll_base + HW_ICOLL_INTERRUPTn_SET(d->hwirq)); + __raw_writel(BM_ICOLL_INTR_ENABLE, + icoll_priv.intr + SET_REG + HW_ICOLL_INTERRUPTn(d->hwirq)); +} + +static void asm9260_mask_irq(struct irq_data *d) +{ + __raw_writel(icoll_intr_bitshift(d, BM_ICOLL_INTR_ENABLE), + icoll_intr_reg(d) + CLR_REG); +} + +static void asm9260_unmask_irq(struct irq_data *d) +{ + __raw_writel(ASM9260_BM_CLEAR_BIT(d->hwirq), + icoll_priv.clear + + ASM9260_HW_ICOLL_CLEARn(d->hwirq)); + + __raw_writel(icoll_intr_bitshift(d, BM_ICOLL_INTR_ENABLE), + icoll_intr_reg(d) + SET_REG); } static struct irq_chip mxs_icoll_chip = { @@ -71,20 +133,32 @@ static struct irq_chip mxs_icoll_chip = { .irq_unmask = icoll_unmask_irq, }; +static struct irq_chip asm9260_icoll_chip = { + .irq_ack = icoll_ack_irq, + .irq_mask = asm9260_mask_irq, + .irq_unmask = asm9260_unmask_irq, +}; + asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs) { u32 irqnr; - irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET); - __raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR); + irqnr = __raw_readl(icoll_priv.stat); + __raw_writel(irqnr, icoll_priv.vector); handle_domain_irq(icoll_domain, irqnr, regs); } static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) { - irq_set_chip_and_handler(virq, &mxs_icoll_chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); + struct irq_chip *chip; + + if (icoll_priv.type == ICOLL) + chip = &mxs_icoll_chip; + else + chip = &asm9260_icoll_chip; + + irq_set_chip_and_handler(virq, chip, handle_level_irq); return 0; } @@ -94,20 +168,80 @@ static const struct irq_domain_ops icoll_irq_domain_ops = { .xlate = irq_domain_xlate_onecell, }; +static void __init icoll_add_domain(struct device_node *np, + int num) +{ + icoll_domain = irq_domain_add_linear(np, num, + &icoll_irq_domain_ops, NULL); + + if (!icoll_domain) + panic("%s: unable to create irq domain", np->full_name); +} + +static void __iomem * __init icoll_init_iobase(struct device_node *np) +{ + void __iomem *icoll_base; + + icoll_base = of_io_request_and_map(np, 0, np->name); + if (!icoll_base) + panic("%s: unable to map resource", np->full_name); + return icoll_base; +} + static int __init icoll_of_init(struct device_node *np, struct device_node *interrupt_parent) { - icoll_base = of_iomap(np, 0); - WARN_ON(!icoll_base); + void __iomem *icoll_base; + + icoll_priv.type = ICOLL; + + icoll_base = icoll_init_iobase(np); + icoll_priv.vector = icoll_base + HW_ICOLL_VECTOR; + icoll_priv.levelack = icoll_base + HW_ICOLL_LEVELACK; + icoll_priv.ctrl = icoll_base + HW_ICOLL_CTRL; + icoll_priv.stat = icoll_base + HW_ICOLL_STAT_OFFSET; + icoll_priv.intr = icoll_base + HW_ICOLL_INTERRUPT0; + icoll_priv.clear = NULL; /* * Interrupt Collector reset, which initializes the priority * for each irq to level 0. */ - stmp_reset_block(icoll_base + HW_ICOLL_CTRL); + stmp_reset_block(icoll_priv.ctrl); - icoll_domain = irq_domain_add_linear(np, ICOLL_NUM_IRQS, - &icoll_irq_domain_ops, NULL); - return icoll_domain ? 0 : -ENODEV; + icoll_add_domain(np, ICOLL_NUM_IRQS); + + return 0; } IRQCHIP_DECLARE(mxs, "fsl,icoll", icoll_of_init); + +static int __init asm9260_of_init(struct device_node *np, + struct device_node *interrupt_parent) +{ + void __iomem *icoll_base; + int i; + + icoll_priv.type = ASM9260_ICOLL; + + icoll_base = icoll_init_iobase(np); + icoll_priv.vector = icoll_base + ASM9260_HW_ICOLL_VECTOR; + icoll_priv.levelack = icoll_base + ASM9260_HW_ICOLL_LEVELACK; + icoll_priv.ctrl = icoll_base + ASM9260_HW_ICOLL_CTRL; + icoll_priv.stat = icoll_base + ASM9260_HW_ICOLL_STAT_OFFSET; + icoll_priv.intr = icoll_base + ASM9260_HW_ICOLL_INTERRUPT0; + icoll_priv.clear = icoll_base + ASM9260_HW_ICOLL_CLEAR0; + + writel_relaxed(ASM9260_BM_CTRL_IRQ_ENABLE, + icoll_priv.ctrl); + /* + * ASM9260 don't provide reset bit. So, we need to set level 0 + * manually. + */ + for (i = 0; i < 16 * 0x10; i += 0x10) + writel(0, icoll_priv.intr + i); + + icoll_add_domain(np, ASM9260_NUM_IRQS); + + return 0; +} +IRQCHIP_DECLARE(asm9260, "alphascale,asm9260-icoll", asm9260_of_init); diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c index a878b8d03868..b1777104fd9f 100644 --- a/drivers/irqchip/irq-nvic.c +++ b/drivers/irqchip/irq-nvic.c @@ -48,16 +48,26 @@ nvic_handle_irq(irq_hw_number_t hwirq, struct pt_regs *regs) handle_IRQ(irq, regs); } +static int nvic_irq_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, unsigned int *type) +{ + if (WARN_ON(fwspec->param_count < 1)) + return -EINVAL; + *hwirq = fwspec->param[0]; + *type = IRQ_TYPE_NONE; + return 0; +} + static int nvic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *arg) { int i, ret; irq_hw_number_t hwirq; unsigned int type = IRQ_TYPE_NONE; - struct of_phandle_args *irq_data = arg; + struct irq_fwspec *fwspec = arg; - ret = irq_domain_xlate_onecell(domain, irq_data->np, irq_data->args, - irq_data->args_count, &hwirq, &type); + ret = nvic_irq_domain_translate(domain, fwspec, &hwirq, &type); if (ret) return ret; @@ -68,7 +78,7 @@ static int nvic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, } static const struct irq_domain_ops nvic_irq_domain_ops = { - .xlate = irq_domain_xlate_onecell, + .translate = nvic_irq_domain_translate, .alloc = nvic_irq_domain_alloc, .free = irq_domain_free_irqs_top, }; diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c index 5ea999a724b5..be4c5a8c9659 100644 --- a/drivers/irqchip/irq-orion.c +++ b/drivers/irqchip/irq-orion.c @@ -106,7 +106,7 @@ IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init); #define ORION_BRIDGE_IRQ_CAUSE 0x00 #define ORION_BRIDGE_IRQ_MASK 0x04 -static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc) +static void orion_bridge_irq_handler(struct irq_desc *desc) { struct irq_domain *d = irq_desc_get_handler_data(desc); diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c index 0670ab4e3897..c325806561be 100644 --- a/drivers/irqchip/irq-renesas-intc-irqpin.c +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c @@ -283,6 +283,9 @@ static int intc_irqpin_irq_set_type(struct irq_data *d, unsigned int type) static int intc_irqpin_irq_set_wake(struct irq_data *d, unsigned int on) { struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d); + int hw_irq = irqd_to_hwirq(d); + + irq_set_irq_wake(p->irq[hw_irq].requested_irq, on); if (!p->clk) return 0; @@ -332,6 +335,12 @@ static irqreturn_t intc_irqpin_shared_irq_handler(int irq, void *dev_id) return status; } +/* + * This lock class tells lockdep that INTC External IRQ Pin irqs are in a + * different category than their parents, so it won't report false recursion. + */ +static struct lock_class_key intc_irqpin_irq_lock_class; + static int intc_irqpin_irq_domain_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { @@ -342,8 +351,8 @@ static int intc_irqpin_irq_domain_map(struct irq_domain *h, unsigned int virq, intc_irqpin_dbg(&p->irq[hw], "map"); irq_set_chip_data(virq, h->host_data); + irq_set_lockdep_class(virq, &intc_irqpin_irq_lock_class); irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); /* kill me now */ return 0; } @@ -352,14 +361,16 @@ static const struct irq_domain_ops intc_irqpin_irq_domain_ops = { .xlate = irq_domain_xlate_twocell, }; -static const struct intc_irqpin_irlm_config intc_irqpin_irlm_r8a7779 = { +static const struct intc_irqpin_irlm_config intc_irqpin_irlm_r8a777x = { .irlm_bit = 23, /* ICR0.IRLM0 */ }; static const struct of_device_id intc_irqpin_dt_ids[] = { { .compatible = "renesas,intc-irqpin", }, + { .compatible = "renesas,intc-irqpin-r8a7778", + .data = &intc_irqpin_irlm_r8a777x }, { .compatible = "renesas,intc-irqpin-r8a7779", - .data = &intc_irqpin_irlm_r8a7779 }, + .data = &intc_irqpin_irlm_r8a777x }, {}, }; MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids); diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index 2aa3add711a6..52304b139aa4 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -62,33 +62,20 @@ struct irqc_priv { struct irqc_irq irq[IRQC_IRQ_MAX]; unsigned int number_of_irqs; struct platform_device *pdev; - struct irq_chip irq_chip; + struct irq_chip_generic *gc; struct irq_domain *irq_domain; struct clk *clk; }; -static void irqc_dbg(struct irqc_irq *i, char *str) +static struct irqc_priv *irq_data_to_priv(struct irq_data *data) { - 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) -{ - struct irqc_priv *p = irq_data_get_irq_chip_data(d); - int hw_irq = irqd_to_hwirq(d); - - irqc_dbg(&p->irq[hw_irq], "enable"); - iowrite32(BIT(hw_irq), p->cpu_int_base + IRQC_EN_SET); + return data->domain->host_data; } -static void irqc_irq_disable(struct irq_data *d) +static void irqc_dbg(struct irqc_irq *i, char *str) { - struct irqc_priv *p = irq_data_get_irq_chip_data(d); - int hw_irq = irqd_to_hwirq(d); - - irqc_dbg(&p->irq[hw_irq], "disable"); - iowrite32(BIT(hw_irq), p->cpu_int_base + IRQC_EN_STS); + dev_dbg(&i->p->pdev->dev, "%s (%d:%d)\n", + str, i->requested_irq, i->hw_irq); } static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = { @@ -101,7 +88,7 @@ static unsigned char irqc_sense[IRQ_TYPE_SENSE_MASK + 1] = { static int irqc_irq_set_type(struct irq_data *d, unsigned int type) { - struct irqc_priv *p = irq_data_get_irq_chip_data(d); + struct irqc_priv *p = irq_data_to_priv(d); int hw_irq = irqd_to_hwirq(d); unsigned char value = irqc_sense[type & IRQ_TYPE_SENSE_MASK]; u32 tmp; @@ -120,7 +107,10 @@ static int irqc_irq_set_type(struct irq_data *d, unsigned int type) static int irqc_irq_set_wake(struct irq_data *d, unsigned int on) { - struct irqc_priv *p = irq_data_get_irq_chip_data(d); + struct irqc_priv *p = irq_data_to_priv(d); + int hw_irq = irqd_to_hwirq(d); + + irq_set_irq_wake(p->irq[hw_irq].requested_irq, on); if (!p->clk) return 0; @@ -150,28 +140,11 @@ static irqreturn_t irqc_irq_handler(int irq, void *dev_id) return IRQ_NONE; } -static int irqc_irq_domain_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - struct irqc_priv *p = h->host_data; - - 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); - return 0; -} - -static const struct irq_domain_ops irqc_irq_domain_ops = { - .map = irqc_irq_domain_map, - .xlate = irq_domain_xlate_twocell, -}; - static int irqc_probe(struct platform_device *pdev) { struct irqc_priv *p; struct resource *io; struct resource *irq; - struct irq_chip *irq_chip; const char *name = dev_name(&pdev->dev); int ret; int k; @@ -231,40 +204,51 @@ static int irqc_probe(struct platform_device *pdev) p->cpu_int_base = p->iomem + IRQC_INT_CPU_BASE(0); /* SYS-SPI */ - irq_chip = &p->irq_chip; - irq_chip->name = name; - irq_chip->irq_mask = irqc_irq_disable; - irq_chip->irq_unmask = irqc_irq_enable; - irq_chip->irq_set_type = irqc_irq_set_type; - irq_chip->irq_set_wake = irqc_irq_set_wake; - irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND; - p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, p->number_of_irqs, - &irqc_irq_domain_ops, p); + &irq_generic_chip_ops, p); if (!p->irq_domain) { ret = -ENXIO; dev_err(&pdev->dev, "cannot initialize irq domain\n"); goto err2; } + ret = irq_alloc_domain_generic_chips(p->irq_domain, p->number_of_irqs, + 1, name, handle_level_irq, + 0, 0, IRQ_GC_INIT_NESTED_LOCK); + if (ret) { + dev_err(&pdev->dev, "cannot allocate generic chip\n"); + goto err3; + } + + p->gc = irq_get_domain_generic_chip(p->irq_domain, 0); + p->gc->reg_base = p->cpu_int_base; + p->gc->chip_types[0].regs.enable = IRQC_EN_SET; + p->gc->chip_types[0].regs.disable = IRQC_EN_STS; + p->gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; + p->gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; + p->gc->chip_types[0].chip.irq_set_type = irqc_irq_set_type; + p->gc->chip_types[0].chip.irq_set_wake = irqc_irq_set_wake; + p->gc->chip_types[0].chip.flags = IRQCHIP_MASK_ON_SUSPEND; + /* request interrupts one by one */ for (k = 0; k < p->number_of_irqs; k++) { if (request_irq(p->irq[k].requested_irq, irqc_irq_handler, 0, name, &p->irq[k])) { dev_err(&pdev->dev, "failed to request IRQ\n"); ret = -ENOENT; - goto err3; + goto err4; } } dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs); return 0; -err3: +err4: while (--k >= 0) free_irq(p->irq[k].requested_irq, &p->irq[k]); +err3: irq_domain_remove(p->irq_domain); err2: iounmap(p->iomem); diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c index 506d9f20ca51..c71914e8f596 100644 --- a/drivers/irqchip/irq-s3c24xx.c +++ b/drivers/irqchip/irq-s3c24xx.c @@ -298,7 +298,7 @@ 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(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); @@ -311,7 +311,7 @@ static void s3c_irq_demux(unsigned int __irq, struct irq_desc *desc) * and one big domain for the dt case where the subintc * starts at hwirq number 32. */ - offset = (intc->domain->of_node) ? 32 : 0; + offset = irq_domain_get_of_node(intc->domain) ? 32 : 0; chained_irq_enter(chip, desc); @@ -342,7 +342,7 @@ static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc, return false; /* non-dt machines use individual domains */ - if (!intc->domain->of_node) + if (!irq_domain_get_of_node(intc->domain)) intc_offset = 0; /* We have a problem that the INTOFFSET register does not always @@ -466,13 +466,11 @@ static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_data(virq, irq_data); - set_irq_flags(virq, IRQF_VALID); - if (parent_intc && irq_data->type != S3C_IRQTYPE_NONE) { if (irq_data->parent_irq > 31) { pr_err("irq-s3c24xx: parent irq %lu is out of range\n", irq_data->parent_irq); - goto err; + return -EINVAL; } parent_irq_data = &parent_intc->irqs[irq_data->parent_irq]; @@ -485,18 +483,12 @@ static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq, if (!irqno) { pr_err("irq-s3c24xx: could not find mapping for parent irq %lu\n", irq_data->parent_irq); - goto err; + return -EINVAL; } irq_set_chained_handler(irqno, s3c_irq_demux); } return 0; - -err: - set_irq_flags(virq, 0); - - /* the only error can result from bad mapping data*/ - return -EINVAL; } static const struct irq_domain_ops s3c24xx_irq_ops = { @@ -1174,8 +1166,6 @@ static int s3c24xx_irq_map_of(struct irq_domain *h, unsigned int virq, irq_set_chip_data(virq, irq_data); - set_irq_flags(virq, IRQF_VALID); - return 0; } diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index 4ad3e7c69aa7..0704362f4c82 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -83,7 +83,7 @@ static int sun4i_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw) { irq_set_chip_and_handler(virq, &sun4i_irq_chip, handle_fasteoi_irq); - set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(virq); return 0; } diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c index 772a82cacbf7..4ef178078e5b 100644 --- a/drivers/irqchip/irq-sunxi-nmi.c +++ b/drivers/irqchip/irq-sunxi-nmi.c @@ -8,6 +8,9 @@ * warranty of any kind, whether express or implied. */ +#define DRV_NAME "sunxi-nmi" +#define pr_fmt(fmt) DRV_NAME ": " fmt + #include <linux/bitops.h> #include <linux/device.h> #include <linux/io.h> @@ -58,7 +61,7 @@ static inline u32 sunxi_sc_nmi_read(struct irq_chip_generic *gc, u32 off) return irq_reg_readl(gc, off); } -static void sunxi_sc_nmi_handle_irq(unsigned int irq, struct irq_desc *desc) +static void sunxi_sc_nmi_handle_irq(struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); @@ -96,8 +99,8 @@ static int sunxi_sc_nmi_set_type(struct irq_data *data, unsigned int flow_type) break; default: irq_gc_unlock(gc); - pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n", - __func__, data->irq); + pr_err("Cannot assign multiple trigger modes to IRQ %d.\n", + data->irq); return -EBADR; } @@ -130,30 +133,29 @@ static int __init sunxi_sc_nmi_irq_init(struct device_node *node, domain = irq_domain_add_linear(node, 1, &irq_generic_chip_ops, NULL); if (!domain) { - pr_err("%s: Could not register interrupt domain.\n", node->name); + pr_err("Could not register interrupt domain.\n"); return -ENOMEM; } - ret = irq_alloc_domain_generic_chips(domain, 1, 2, node->name, + ret = irq_alloc_domain_generic_chips(domain, 1, 2, DRV_NAME, handle_fasteoi_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); if (ret) { - pr_err("%s: Could not allocate generic interrupt chip.\n", - node->name); - goto fail_irqd_remove; + pr_err("Could not allocate generic interrupt chip.\n"); + goto fail_irqd_remove; } irq = irq_of_parse_and_map(node, 0); if (irq <= 0) { - pr_err("%s: unable to parse irq\n", node->name); + pr_err("unable to parse irq\n"); ret = -EINVAL; goto fail_irqd_remove; } gc = irq_get_domain_generic_chip(domain, 0); - gc->reg_base = of_iomap(node, 0); + gc->reg_base = of_io_request_and_map(node, 0, of_node_full_name(node)); if (!gc->reg_base) { - pr_err("%s: unable to map resource\n", node->name); + pr_err("unable to map resource\n"); ret = -ENOMEM; goto fail_irqd_remove; } diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c index 331829661366..848d782a2a3b 100644 --- a/drivers/irqchip/irq-tb10x.c +++ b/drivers/irqchip/irq-tb10x.c @@ -97,7 +97,7 @@ 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(struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); unsigned int irq = irq_desc_get_irq(desc); diff --git a/drivers/irqchip/irq-tegra.c b/drivers/irqchip/irq-tegra.c index 2fd89eb88f3a..121ec301372e 100644 --- a/drivers/irqchip/irq-tegra.c +++ b/drivers/irqchip/irq-tegra.c @@ -214,47 +214,50 @@ static struct irq_chip tegra_ictlr_chip = { .irq_unmask = tegra_unmask, .irq_retrigger = tegra_retrigger, .irq_set_wake = tegra_set_wake, + .irq_set_type = irq_chip_set_type_parent, .flags = IRQCHIP_MASK_ON_SUSPEND, #ifdef CONFIG_SMP .irq_set_affinity = irq_chip_set_affinity_parent, #endif }; -static int tegra_ictlr_domain_xlate(struct irq_domain *domain, - struct device_node *controller, - const u32 *intspec, - unsigned int intsize, - unsigned long *out_hwirq, - unsigned int *out_type) +static int tegra_ictlr_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) { - if (domain->of_node != controller) - return -EINVAL; /* Shouldn't happen, really... */ - if (intsize != 3) - return -EINVAL; /* Not GIC compliant */ - if (intspec[0] != GIC_SPI) - return -EINVAL; /* No PPI should point to this domain */ + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count != 3) + return -EINVAL; - *out_hwirq = intspec[1]; - *out_type = intspec[2]; - return 0; + /* No PPI should point to this domain */ + if (fwspec->param[0] != 0) + return -EINVAL; + + *hwirq = fwspec->param[1]; + *type = fwspec->param[2]; + return 0; + } + + return -EINVAL; } static int tegra_ictlr_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *data) { - struct of_phandle_args *args = data; - struct of_phandle_args parent_args; + struct irq_fwspec *fwspec = data; + struct irq_fwspec parent_fwspec; struct tegra_ictlr_info *info = domain->host_data; irq_hw_number_t hwirq; unsigned int i; - if (args->args_count != 3) + if (fwspec->param_count != 3) return -EINVAL; /* Not GIC compliant */ - if (args->args[0] != GIC_SPI) + if (fwspec->param[0] != GIC_SPI) return -EINVAL; /* No PPI should point to this domain */ - hwirq = args->args[1]; + hwirq = fwspec->param[1]; if (hwirq >= (num_ictlrs * 32)) return -EINVAL; @@ -266,9 +269,10 @@ static int tegra_ictlr_domain_alloc(struct irq_domain *domain, info->base[ictlr]); } - parent_args = *args; - parent_args.np = domain->parent->of_node; - return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_args); + parent_fwspec = *fwspec; + parent_fwspec.fwnode = domain->parent->fwnode; + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, + &parent_fwspec); } static void tegra_ictlr_domain_free(struct irq_domain *domain, @@ -284,9 +288,9 @@ static void tegra_ictlr_domain_free(struct irq_domain *domain, } static const struct irq_domain_ops tegra_ictlr_domain_ops = { - .xlate = tegra_ictlr_domain_xlate, - .alloc = tegra_ictlr_domain_alloc, - .free = tegra_ictlr_domain_free, + .translate = tegra_ictlr_domain_translate, + .alloc = tegra_ictlr_domain_alloc, + .free = tegra_ictlr_domain_free, }; static int __init tegra_ictlr_init(struct device_node *node, diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index 16123f688768..598ab3f0e0ac 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -65,19 +65,19 @@ 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(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) { - do_bad_IRQ(irq, desc); + do_bad_IRQ(desc); return; } do { - irq = ffs(status) - 1; + unsigned int irq = ffs(status) - 1; + status &= ~(1 << irq); generic_handle_irq(irq_find_mapping(f->domain, irq)); } while (status); @@ -128,7 +128,7 @@ static int fpga_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_set_chip_data(irq, f); irq_set_chip_and_handler(irq, &f->chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(irq); return 0; } diff --git a/drivers/irqchip/irq-vf610-mscm-ir.c b/drivers/irqchip/irq-vf610-mscm-ir.c index 2c2255886401..56b5e3cb9de2 100644 --- a/drivers/irqchip/irq-vf610-mscm-ir.c +++ b/drivers/irqchip/irq-vf610-mscm-ir.c @@ -130,35 +130,51 @@ static int vf610_mscm_ir_domain_alloc(struct irq_domain *domain, unsigned int vi { int i; irq_hw_number_t hwirq; - struct of_phandle_args *irq_data = arg; - struct of_phandle_args gic_data; + struct irq_fwspec *fwspec = arg; + struct irq_fwspec parent_fwspec; - if (irq_data->args_count != 2) + if (!irq_domain_get_of_node(domain->parent)) return -EINVAL; - hwirq = irq_data->args[0]; + if (fwspec->param_count != 2) + return -EINVAL; + + hwirq = fwspec->param[0]; for (i = 0; i < nr_irqs; i++) irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i, &vf610_mscm_ir_irq_chip, domain->host_data); - gic_data.np = domain->parent->of_node; + parent_fwspec.fwnode = domain->parent->fwnode; if (mscm_ir_data->is_nvic) { - gic_data.args_count = 1; - gic_data.args[0] = irq_data->args[0]; + parent_fwspec.param_count = 1; + parent_fwspec.param[0] = fwspec->param[0]; } else { - gic_data.args_count = 3; - gic_data.args[0] = GIC_SPI; - gic_data.args[1] = irq_data->args[0]; - gic_data.args[2] = irq_data->args[1]; + parent_fwspec.param_count = 3; + parent_fwspec.param[0] = GIC_SPI; + parent_fwspec.param[1] = fwspec->param[0]; + parent_fwspec.param[2] = fwspec->param[1]; } - return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_data); + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, + &parent_fwspec); +} + +static int vf610_mscm_ir_domain_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + if (WARN_ON(fwspec->param_count < 2)) + return -EINVAL; + *hwirq = fwspec->param[0]; + *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; + return 0; } static const struct irq_domain_ops mscm_irq_domain_ops = { - .xlate = irq_domain_xlate_twocell, + .translate = vf610_mscm_ir_domain_translate, .alloc = vf610_mscm_ir_domain_alloc, .free = irq_domain_free_irqs_common, }; @@ -205,7 +221,8 @@ static int __init vf610_mscm_ir_of_init(struct device_node *node, goto out_unmap; } - if (of_device_is_compatible(domain->parent->of_node, "arm,armv7m-nvic")) + if (of_device_is_compatible(irq_domain_get_of_node(domain->parent), + "arm,armv7m-nvic")) mscm_ir_data->is_nvic = true; cpu_pm_register_notifier(&mscm_ir_notifier_block); diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index 03846dff4212..b956dfffe78c 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -201,7 +201,7 @@ static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq, return -EPERM; irq_set_chip_and_handler(irq, &vic_chip, handle_level_irq); irq_set_chip_data(irq, v->base); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(irq); return 0; } @@ -225,7 +225,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs) return handled; } -static void vic_handle_irq_cascaded(unsigned int irq, struct irq_desc *desc) +static void vic_handle_irq_cascaded(struct irq_desc *desc) { u32 stat, hwirq; struct irq_chip *host_chip = irq_desc_get_chip(desc); diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c index 8371d9978d31..f9af0af21751 100644 --- a/drivers/irqchip/irq-vt8500.c +++ b/drivers/irqchip/irq-vt8500.c @@ -167,7 +167,6 @@ static int vt8500_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { irq_set_chip_and_handler(virq, &vt8500_irq_chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); return 0; } diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c index afd1af3dfe5a..2b35e68bea82 100644 --- a/drivers/irqchip/irqchip.c +++ b/drivers/irqchip/irqchip.c @@ -8,7 +8,7 @@ * warranty of any kind, whether express or implied. */ -#include <linux/acpi_irq.h> +#include <linux/acpi.h> #include <linux/init.h> #include <linux/of_irq.h> #include <linux/irqchip.h> @@ -27,6 +27,5 @@ extern struct of_device_id __irqchip_of_table[]; void __init irqchip_init(void) { of_irq_init(__irqchip_of_table); - - acpi_irq_init(); + acpi_probe_device_table(irqchip); } diff --git a/drivers/irqchip/spear-shirq.c b/drivers/irqchip/spear-shirq.c index 4cbd9c5dc1e6..1ccd2abed65f 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(struct irq_desc *desc) { struct spear_shirq *shirq = irq_desc_get_handler_data(desc); u32 pend; @@ -211,7 +211,6 @@ static void __init spear_shirq_register(struct spear_shirq *shirq, for (i = 0; i < shirq->nr_irqs; i++) { irq_set_chip_and_handler(shirq->virq_base + i, shirq->irq_chip, handle_simple_irq); - set_irq_flags(shirq->virq_base + i, IRQF_VALID); irq_set_chip_data(shirq->virq_base + i, shirq); } } |