diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-22 19:42:56 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-06-22 19:42:56 -0700 |
commit | 407a2c720556e8e340e06f6a7174f5d6d80cf9ea (patch) | |
tree | b78ba543dbef195909611448ca833348581b63a6 | |
parent | 3a95398f54cbd664c749fe9f1bfc7e7dbace92d0 (diff) | |
parent | f05218651be1ac6a6088e226bd7350fb6c154414 (diff) | |
download | lwn-407a2c720556e8e340e06f6a7174f5d6d80cf9ea.tar.gz lwn-407a2c720556e8e340e06f6a7174f5d6d80cf9ea.zip |
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq updates from Thomas Gleixner:
"The irq departement delivers:
- plug a potential race related to chained interrupt handlers
- core updates which address the needs of the x86 irqdomain conversion
- new irqchip callback to support affinity settings for VCPUs
- the usual pile of updates to interrupt chip drivers
- a few helper functions to allow further cleanups and
simplifications
I have a largish pile of coccinelle scripted/verified cleanups and
simplifications pending on top of that, but I prefer to send that
towards the end of the merge window when the arch/driver changes have
hit your tree to avoid API change wreckage as far as possible"
* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (34 commits)
genirq: Remove bogus restriction in irq_move_mask_irq()
irqchip: atmel-aic5: Add sama5d2 support
irq: spear-shirq: Fix race in installing chained IRQ handler
irq: irq-keystone: Fix race in installing chained IRQ handler
gpio: gpio-tegra: Fix race in installing chained IRQ handler
gpio: gpio-mxs: Fix race in installing chained IRQ handler
gpio: gpio-mxc: Fix race in installing chained IRQ handler
ARM: gemini: Fix race in installing GPIO chained IRQ handler
GPU: ipu: Fix race in installing IPU chained IRQ handler
ARM: sa1100: convert SA11x0 related code to use new chained handler helper
irq: Add irq_set_chained_handler_and_data()
irqchip: exynos-combiner: Save IRQ enable set on suspend
genirq: Introduce helper function irq_data_get_affinity_mask()
genirq: Introduce helper function irq_data_get_node()
genirq: Introduce struct irq_common_data to host shared irq data
genirq: Prevent crash in irq_move_irq()
genirq: Enhance irq_data_to_desc() to support hierarchy irqdomain
irqchip: gic: Simplify gic_configure_irq by using IRQCHIP_SET_TYPE_MASKED
irqchip: renesas: intc-irqpin: Improve binding documentation
genirq: Set IRQCHIP_SKIP_SET_WAKE for no_irq_chip
...
49 files changed, 378 insertions, 191 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt index f292917fa00d..0e9f09a6a2fe 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt @@ -2,7 +2,7 @@ Required properties: - compatible: Should be "atmel,<chip>-aic" - <chip> can be "at91rm9200", "sama5d3" or "sama5d4" + <chip> can be "at91rm9200", "sama5d2", "sama5d3" or "sama5d4" - interrupt-controller: Identifies the node as an interrupt controller. - interrupt-parent: For single AIC system, it is an empty property. - #interrupt-cells: The number of cells to define the interrupts. It should be 3. diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt index 4f7946ae8adc..772c550d3b4b 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt @@ -13,9 +13,12 @@ Required properties: - reg: Base address and length of each register bank used by the external IRQ pins driven by the interrupt controller hardware module. The base addresses, length and number of required register banks varies with soctype. - +- interrupt-controller: Identifies the node as an interrupt controller. - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in - interrupts.txt in this directory + interrupts.txt in this directory. +- interrupts: Must contain a list of interrupt specifiers. For each interrupt + provided by this irqpin controller instance, there must be one entry, + referring to the corresponding parent interrupt. Optional properties: @@ -25,3 +28,35 @@ Optional properties: if different from the default 4 bits - control-parent: disable and enable interrupts on the parent interrupt controller, needed for some broken implementations +- clocks: Must contain a reference to the functional clock. This property is + mandatory if the hardware implements a controllable functional clock for + the irqpin controller instance. +- power-domains: Must contain a reference to the power domain. This property is + mandatory if the irqpin controller instance is part of a controllable power + domain. + + +Example +------- + + irqpin1: interrupt-controller@e6900004 { + compatible = "renesas,intc-irqpin-r8a7740", + "renesas,intc-irqpin"; + #interrupt-cells = <2>; + interrupt-controller; + reg = <0xe6900004 4>, + <0xe6900014 4>, + <0xe6900024 1>, + <0xe6900044 1>, + <0xe6900064 1>; + interrupts = <0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH + 0 149 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp2_clks R8A7740_CLK_INTCA>; + power-domains = <&pd_a4s>; + }; diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c index 5cc779c8e9c6..93ee70dbbdd3 100644 --- a/arch/arm/common/sa1111.c +++ b/arch/arm/common/sa1111.c @@ -501,8 +501,8 @@ static int sa1111_setup_irq(struct sa1111 *sachip, unsigned irq_base) * Register SA1111 interrupt */ irq_set_irq_type(sachip->irq, IRQ_TYPE_EDGE_RISING); - irq_set_handler_data(sachip->irq, sachip); - irq_set_chained_handler(sachip->irq, sa1111_irq_handler); + irq_set_chained_handler_and_data(sachip->irq, sa1111_irq_handler, + sachip); dev_info(sachip->dev, "Providing IRQ%u-%u\n", sachip->irq_base, sachip->irq_base + SA1111_IRQ_NR - 1); @@ -836,8 +836,7 @@ static void __sa1111_remove(struct sa1111 *sachip) clk_unprepare(sachip->clk); if (sachip->irq != NO_IRQ) { - irq_set_chained_handler(sachip->irq, NULL); - irq_set_handler_data(sachip->irq, NULL); + irq_set_chained_handler_and_data(sachip->irq, NULL, NULL); irq_free_descs(sachip->irq_base, SA1111_IRQ_NR); release_mem_region(sachip->phys + SA1111_INTC, 512); diff --git a/arch/arm/mach-gemini/gpio.c b/arch/arm/mach-gemini/gpio.c index f8cb5710d6ee..3292f2e6ed6f 100644 --- a/arch/arm/mach-gemini/gpio.c +++ b/arch/arm/mach-gemini/gpio.c @@ -223,8 +223,8 @@ void __init gemini_gpio_init(void) set_irq_flags(j, IRQF_VALID); } - irq_set_chained_handler(IRQ_GPIO(i), gpio_irq_handler); - irq_set_handler_data(IRQ_GPIO(i), (void *)i); + irq_set_chained_handler_and_data(IRQ_GPIO(i), gpio_irq_handler, + (void *)i); } BUG_ON(gpiochip_add(&gemini_gpio_chip)); diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c index af868d258e66..99d9a3b1bf34 100644 --- a/arch/arm/mach-sa1100/neponset.c +++ b/arch/arm/mach-sa1100/neponset.c @@ -327,8 +327,7 @@ static int neponset_probe(struct platform_device *dev) irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip); irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING); - irq_set_handler_data(irq, d); - irq_set_chained_handler(irq, neponset_irq_handler); + irq_set_chained_handler_and_data(irq, neponset_irq_handler, d); /* * We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 9f7446a7ac64..e4f42c95c320 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -437,14 +437,13 @@ static int mxc_gpio_probe(struct platform_device *pdev) irq_set_chained_handler(port->irq, mx2_gpio_irq_handler); } else { /* setup one handler for each entry */ - irq_set_chained_handler(port->irq, mx3_gpio_irq_handler); - irq_set_handler_data(port->irq, port); - if (port->irq_high > 0) { + irq_set_chained_handler_and_data(port->irq, + mx3_gpio_irq_handler, port); + if (port->irq_high > 0) /* setup handler for GPIO 16 to 31 */ - irq_set_chained_handler(port->irq_high, - mx3_gpio_irq_handler); - irq_set_handler_data(port->irq_high, port); - } + irq_set_chained_handler_and_data(port->irq_high, + mx3_gpio_irq_handler, + port); } err = bgpio_init(&port->bgc, &pdev->dev, 4, diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 84cbda6acdda..eac872748ee7 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -320,8 +320,8 @@ static int mxs_gpio_probe(struct platform_device *pdev) mxs_gpio_init_gc(port, irq_base); /* setup one handler for each entry */ - irq_set_chained_handler(port->irq, mxs_gpio_irq_handler); - irq_set_handler_data(port->irq, port); + irq_set_chained_handler_and_data(port->irq, mxs_gpio_irq_handler, + port); err = bgpio_init(&port->bgc, &pdev->dev, 4, port->base + PINCTRL_DIN(port), diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 1741981d53c8..56dcc8ed98de 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -515,8 +515,8 @@ static int tegra_gpio_probe(struct platform_device *pdev) for (i = 0; i < tegra_gpio_bank_count; i++) { bank = &tegra_gpio_banks[i]; - irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler); - irq_set_handler_data(bank->irq, bank); + irq_set_chained_handler_and_data(bank->irq, + tegra_gpio_irq_handler, bank); for (j = 0; j < 4; j++) spin_lock_init(&bank->lvl_lock[j]); diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 67bab5c36056..6d2f39d36e44 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -1119,10 +1119,9 @@ static int ipu_irq_init(struct ipu_soc *ipu) ct->regs.mask = IPU_INT_CTRL(i / 32); } - irq_set_chained_handler(ipu->irq_sync, ipu_irq_handler); - irq_set_handler_data(ipu->irq_sync, ipu); - irq_set_chained_handler(ipu->irq_err, ipu_err_irq_handler); - irq_set_handler_data(ipu->irq_err, ipu); + irq_set_chained_handler_and_data(ipu->irq_sync, ipu_irq_handler, ipu); + irq_set_chained_handler_and_data(ipu->irq_err, ipu_err_irq_handler, + ipu); return 0; } @@ -1131,10 +1130,8 @@ static void ipu_irq_exit(struct ipu_soc *ipu) { int i, irq; - irq_set_chained_handler(ipu->irq_err, NULL); - irq_set_handler_data(ipu->irq_err, NULL); - irq_set_chained_handler(ipu->irq_sync, NULL); - irq_set_handler_data(ipu->irq_sync, NULL); + irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL); + irq_set_chained_handler_and_data(ipu->irq_sync, NULL, NULL); /* TODO: remove irq_domain_generic_chips */ diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 6de62a96e79c..99b9a9792975 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -30,6 +30,7 @@ config ARM_GIC_V3_ITS config ARM_NVIC bool select IRQ_DOMAIN + select IRQ_DOMAIN_HIERARCHY select GENERIC_IRQ_CHIP config ARM_VIC diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 5945223b73fa..5c82e3bdafdf 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/syscore_ops.h> #include <linux/irqdomain.h> #include <linux/irqchip/chained_irq.h> #include <linux/interrupt.h> @@ -34,9 +35,14 @@ struct combiner_chip_data { unsigned int irq_mask; void __iomem *base; unsigned int parent_irq; +#ifdef CONFIG_PM + u32 pm_save; +#endif }; +static struct combiner_chip_data *combiner_data; static struct irq_domain *combiner_irq_domain; +static unsigned int max_nr = 20; static inline void __iomem *combiner_base(struct irq_data *data) { @@ -164,18 +170,16 @@ static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq, return 0; } -static struct irq_domain_ops combiner_irq_domain_ops = { +static const struct irq_domain_ops combiner_irq_domain_ops = { .xlate = combiner_irq_domain_xlate, .map = combiner_irq_domain_map, }; static void __init combiner_init(void __iomem *combiner_base, - struct device_node *np, - unsigned int max_nr) + struct device_node *np) { int i, irq; unsigned int nr_irq; - struct combiner_chip_data *combiner_data; nr_irq = max_nr * IRQ_IN_COMBINER; @@ -201,11 +205,59 @@ static void __init combiner_init(void __iomem *combiner_base, } } +#ifdef CONFIG_PM + +/** + * combiner_suspend - save interrupt combiner state before suspend + * + * Save the interrupt enable set register for all combiner groups since + * the state is lost when the system enters into a sleep state. + * + */ +static int combiner_suspend(void) +{ + int i; + + for (i = 0; i < max_nr; i++) + combiner_data[i].pm_save = + __raw_readl(combiner_data[i].base + COMBINER_ENABLE_SET); + + return 0; +} + +/** + * combiner_resume - restore interrupt combiner state after resume + * + * Restore the interrupt enable set register for all combiner groups since + * the state is lost when the system enters into a sleep state on suspend. + * + */ +static void combiner_resume(void) +{ + int i; + + for (i = 0; i < max_nr; i++) { + __raw_writel(combiner_data[i].irq_mask, + combiner_data[i].base + COMBINER_ENABLE_CLEAR); + __raw_writel(combiner_data[i].pm_save, + combiner_data[i].base + COMBINER_ENABLE_SET); + } +} + +#else +#define combiner_suspend NULL +#define combiner_resume NULL +#endif + +static struct syscore_ops combiner_syscore_ops = { + .suspend = combiner_suspend, + .resume = combiner_resume, +}; + static int __init combiner_of_init(struct device_node *np, struct device_node *parent) { void __iomem *combiner_base; - unsigned int max_nr = 20; combiner_base = of_iomap(np, 0); if (!combiner_base) { @@ -219,7 +271,9 @@ static int __init combiner_of_init(struct device_node *np, __func__, max_nr); } - combiner_init(combiner_base, np, max_nr); + combiner_init(combiner_base, np); + + register_syscore_ops(&combiner_syscore_ops); return 0; } diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index daccc8bdbb42..0d3b0fe2f175 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -409,7 +409,7 @@ static struct notifier_block mpic_cascaded_cpu_notifier = { }; #endif /* CONFIG_SMP */ -static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { +static const struct irq_domain_ops armada_370_xp_mpic_irq_ops = { .map = armada_370_xp_mpic_irq_map, .xlate = irq_domain_xlate_onecell, }; diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index a2e8c3f876cb..459bf4429d36 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -339,6 +339,15 @@ static int __init aic5_of_init(struct device_node *node, return 0; } +#define NR_SAMA5D2_IRQS 77 + +static int __init sama5d2_aic5_of_init(struct device_node *node, + struct device_node *parent) +{ + return aic5_of_init(node, parent, NR_SAMA5D2_IRQS); +} +IRQCHIP_DECLARE(sama5d2_aic5, "atmel,sama5d2-aic", sama5d2_aic5_of_init); + #define NR_SAMA5D3_IRQS 48 static int __init sama5d3_aic5_of_init(struct device_node *node, diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index 5916d6cdafa1..e68c3b60a681 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -135,7 +135,7 @@ static int armctrl_xlate(struct irq_domain *d, struct device_node *ctrlr, return 0; } -static struct irq_domain_ops armctrl_ops = { +static const struct irq_domain_ops armctrl_ops = { .xlate = armctrl_xlate }; diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index ad96ebb0c7ab..9448e391cb71 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -24,11 +24,8 @@ int gic_configure_irq(unsigned int irq, unsigned int type, void __iomem *base, void (*sync_access)(void)) { - u32 enablemask = 1 << (irq % 32); - u32 enableoff = (irq / 32) * 4; u32 confmask = 0x2 << ((irq % 16) * 2); u32 confoff = (irq / 16) * 4; - bool enabled = false; u32 val, oldval; int ret = 0; @@ -43,17 +40,6 @@ int gic_configure_irq(unsigned int irq, unsigned int type, val |= confmask; /* - * As recommended by the spec, disable the interrupt before changing - * the configuration - */ - if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) { - writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff); - if (sync_access) - sync_access(); - enabled = true; - } - - /* * Write back the new configuration, and possibly re-enable * the interrupt. If we tried to write a new configuration and failed, * return an error. @@ -62,9 +48,6 @@ int gic_configure_irq(unsigned int irq, unsigned int type, if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val && val != oldval) ret = -EINVAL; - if (enabled) - writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff); - if (sync_access) sync_access(); diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 49875adb6b44..c52f7ba205b4 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -658,6 +658,7 @@ static struct irq_chip gic_chip = { .irq_set_affinity = gic_set_affinity, .irq_get_irqchip_state = gic_irq_get_irqchip_state, .irq_set_irqchip_state = gic_irq_set_irqchip_state, + .flags = IRQCHIP_SET_TYPE_MASKED, }; #define GIC_ID_NR (1U << gic_data.rdists.id_bits) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 01999d74bd3a..8d7e1c8b6d56 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -324,6 +324,7 @@ static struct irq_chip gic_chip = { #endif .irq_get_irqchip_state = gic_irq_get_irqchip_state, .irq_set_irqchip_state = gic_irq_set_irqchip_state, + .flags = IRQCHIP_SET_TYPE_MASKED, }; void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c index 7d6ffb5de84f..0cae45d10695 100644 --- a/drivers/irqchip/irq-hip04.c +++ b/drivers/irqchip/irq-hip04.c @@ -202,6 +202,7 @@ static struct irq_chip hip04_irq_chip = { #ifdef CONFIG_SMP .irq_set_affinity = hip04_irq_set_affinity, #endif + .flags = IRQCHIP_SET_TYPE_MASKED, }; static u16 hip04_get_cpumask(struct hip04_irq_data *intc) diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index 78e8b3ce5252..81e3cf5b9a1f 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -131,7 +131,7 @@ static int keystone_irq_map(struct irq_domain *h, unsigned int virq, return 0; } -static struct irq_domain_ops keystone_irq_ops = { +static const struct irq_domain_ops keystone_irq_ops = { .map = keystone_irq_map, .xlate = irq_domain_xlate_onecell, }; @@ -184,8 +184,7 @@ static int keystone_irq_probe(struct platform_device *pdev) platform_set_drvdata(pdev, kirq); - irq_set_chained_handler(kirq->irq, keystone_irq_handler); - irq_set_handler_data(kirq->irq, kirq); + irq_set_chained_handler_and_data(kirq->irq, keystone_irq_handler, kirq); /* clear all source bits */ keystone_irq_writel(kirq, ~0x0); diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 269c2354c431..4400edd1a6c7 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -746,7 +746,7 @@ static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, return 0; } -static struct irq_domain_ops gic_irq_domain_ops = { +static const struct irq_domain_ops gic_irq_domain_ops = { .map = gic_irq_domain_map, .xlate = gic_irq_domain_xlate, }; diff --git a/drivers/irqchip/irq-mtk-sysirq.c b/drivers/irqchip/irq-mtk-sysirq.c index eaf0a710e98a..15c13039bba2 100644 --- a/drivers/irqchip/irq-mtk-sysirq.c +++ b/drivers/irqchip/irq-mtk-sysirq.c @@ -111,7 +111,7 @@ static int mtk_sysirq_domain_alloc(struct irq_domain *domain, unsigned int virq, return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_data); } -static struct irq_domain_ops sysirq_domain_ops = { +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, @@ -144,7 +144,7 @@ static int __init mtk_sysirq_of_init(struct device_node *node, chip_data->intpol_base = ioremap(res.start, size); if (!chip_data->intpol_base) { pr_err("mtk_sysirq: unable to map sysirq register\n"); - ret = PTR_ERR(chip_data->intpol_base); + ret = -ENXIO; goto out_free; } diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c index e4acf1e3f8e3..04bf97b289cf 100644 --- a/drivers/irqchip/irq-mxs.c +++ b/drivers/irqchip/irq-mxs.c @@ -90,7 +90,7 @@ static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq, return 0; } -static struct irq_domain_ops icoll_irq_domain_ops = { +static const struct irq_domain_ops icoll_irq_domain_ops = { .map = icoll_irq_domain_map, .xlate = irq_domain_xlate_onecell, }; diff --git a/drivers/irqchip/irq-nvic.c b/drivers/irqchip/irq-nvic.c index 4ff0805fca01..5fac9100f6cb 100644 --- a/drivers/irqchip/irq-nvic.c +++ b/drivers/irqchip/irq-nvic.c @@ -49,6 +49,31 @@ nvic_handle_irq(irq_hw_number_t hwirq, struct pt_regs *regs) handle_IRQ(irq, regs); } +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; + + ret = irq_domain_xlate_onecell(domain, irq_data->np, irq_data->args, + irq_data->args_count, &hwirq, &type); + if (ret) + return ret; + + for (i = 0; i < nr_irqs; i++) + irq_map_generic_chip(domain, virq + i, hwirq + i); + + return 0; +} + +static const struct irq_domain_ops nvic_irq_domain_ops = { + .xlate = irq_domain_xlate_onecell, + .alloc = nvic_irq_domain_alloc, + .free = irq_domain_free_irqs_top, +}; + static int __init nvic_of_init(struct device_node *node, struct device_node *parent) { @@ -70,7 +95,8 @@ static int __init nvic_of_init(struct device_node *node, irqs = NVIC_MAX_IRQ; nvic_irq_domain = - irq_domain_add_linear(node, irqs, &irq_generic_chip_ops, NULL); + irq_domain_add_linear(node, irqs, &nvic_irq_domain_ops, NULL); + if (!nvic_irq_domain) { pr_warn("Failed to allocate irq domain\n"); return -ENOMEM; diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c index 9a0767b9c89d..0670ab4e3897 100644 --- a/drivers/irqchip/irq-renesas-intc-irqpin.c +++ b/drivers/irqchip/irq-renesas-intc-irqpin.c @@ -347,7 +347,7 @@ static int intc_irqpin_irq_domain_map(struct irq_domain *h, unsigned int virq, return 0; } -static struct irq_domain_ops intc_irqpin_irq_domain_ops = { +static const struct irq_domain_ops intc_irqpin_irq_domain_ops = { .map = intc_irqpin_irq_domain_map, .xlate = irq_domain_xlate_twocell, }; diff --git a/drivers/irqchip/irq-renesas-irqc.c b/drivers/irqchip/irq-renesas-irqc.c index cdf80b7794cd..778bd076aeea 100644 --- a/drivers/irqchip/irq-renesas-irqc.c +++ b/drivers/irqchip/irq-renesas-irqc.c @@ -29,7 +29,6 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/module.h> -#include <linux/platform_data/irq-renesas-irqc.h> #include <linux/pm_runtime.h> #define IRQC_IRQ_MAX 32 /* maximum 32 interrupts per driver instance */ @@ -62,7 +61,6 @@ struct irqc_priv { void __iomem *iomem; void __iomem *cpu_int_base; struct irqc_irq irq[IRQC_IRQ_MAX]; - struct renesas_irqc_config config; unsigned int number_of_irqs; struct platform_device *pdev; struct irq_chip irq_chip; @@ -168,14 +166,13 @@ static int irqc_irq_domain_map(struct irq_domain *h, unsigned int virq, return 0; } -static struct irq_domain_ops irqc_irq_domain_ops = { +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 renesas_irqc_config *pdata = pdev->dev.platform_data; struct irqc_priv *p; struct resource *io; struct resource *irq; @@ -191,10 +188,6 @@ static int irqc_probe(struct platform_device *pdev) goto err0; } - /* deal with driver instance configuration */ - if (pdata) - memcpy(&p->config, pdata, sizeof(*pdata)); - p->pdev = pdev; platform_set_drvdata(pdev, p); @@ -251,8 +244,7 @@ static int irqc_probe(struct platform_device *pdev) irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND; p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, - p->number_of_irqs, - p->config.irq_base, + p->number_of_irqs, 0, &irqc_irq_domain_ops, p); if (!p->irq_domain) { ret = -ENXIO; @@ -272,13 +264,6 @@ static int irqc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs); - /* warn in case of mismatch if irq base is specified */ - if (p->config.irq_base) { - if (p->config.irq_base != p->irq[0].domain_irq) - dev_warn(&pdev->dev, "irq base mismatch (%d/%d)\n", - p->config.irq_base, p->irq[0].domain_irq); - } - return 0; err3: while (--k >= 0) diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c index c8d373fcd823..e96717f45ea1 100644 --- a/drivers/irqchip/irq-s3c24xx.c +++ b/drivers/irqchip/irq-s3c24xx.c @@ -502,7 +502,7 @@ err: return -EINVAL; } -static struct irq_domain_ops s3c24xx_irq_ops = { +static const struct irq_domain_ops s3c24xx_irq_ops = { .map = s3c24xx_irq_map, .xlate = irq_domain_xlate_twocell, }; @@ -1228,7 +1228,7 @@ static int s3c24xx_irq_xlate_of(struct irq_domain *d, struct device_node *n, return 0; } -static struct irq_domain_ops s3c24xx_irq_ops_of = { +static const struct irq_domain_ops s3c24xx_irq_ops_of = { .map = s3c24xx_irq_map_of, .xlate = s3c24xx_irq_xlate_of, }; diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c index 64155b686081..83d6aa6464ee 100644 --- a/drivers/irqchip/irq-sun4i.c +++ b/drivers/irqchip/irq-sun4i.c @@ -89,7 +89,7 @@ static int sun4i_irq_map(struct irq_domain *d, unsigned int virq, return 0; } -static struct irq_domain_ops sun4i_irq_ops = { +static const struct irq_domain_ops sun4i_irq_ops = { .map = sun4i_irq_map, .xlate = irq_domain_xlate_onecell, }; diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index 1ab451729a5c..888111b76ea0 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -132,7 +132,7 @@ static int fpga_irqdomain_map(struct irq_domain *d, unsigned int irq, return 0; } -static struct irq_domain_ops fpga_irqdomain_ops = { +static const struct irq_domain_ops fpga_irqdomain_ops = { .map = fpga_irqdomain_map, .xlate = irq_domain_xlate_onetwocell, }; diff --git a/drivers/irqchip/irq-vf610-mscm-ir.c b/drivers/irqchip/irq-vf610-mscm-ir.c index 9521057d4744..f5c01cbcc73a 100644 --- a/drivers/irqchip/irq-vf610-mscm-ir.c +++ b/drivers/irqchip/irq-vf610-mscm-ir.c @@ -47,6 +47,7 @@ struct vf610_mscm_ir_chip_data { void __iomem *mscm_ir_base; u16 cpu_mask; u16 saved_irsprc[MSCM_IRSPRC_NUM]; + bool is_nvic; }; static struct vf610_mscm_ir_chip_data *mscm_ir_data; @@ -101,7 +102,7 @@ static void vf610_mscm_ir_enable(struct irq_data *data) writew_relaxed(chip_data->cpu_mask, chip_data->mscm_ir_base + MSCM_IRSPRC(hwirq)); - irq_chip_unmask_parent(data); + irq_chip_enable_parent(data); } static void vf610_mscm_ir_disable(struct irq_data *data) @@ -111,7 +112,7 @@ static void vf610_mscm_ir_disable(struct irq_data *data) writew_relaxed(0x0, chip_data->mscm_ir_base + MSCM_IRSPRC(hwirq)); - irq_chip_mask_parent(data); + irq_chip_disable_parent(data); } static struct irq_chip vf610_mscm_ir_irq_chip = { @@ -143,10 +144,17 @@ static int vf610_mscm_ir_domain_alloc(struct irq_domain *domain, unsigned int vi domain->host_data); gic_data.np = domain->parent->of_node; - 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]; + + if (mscm_ir_data->is_nvic) { + gic_data.args_count = 1; + gic_data.args[0] = irq_data->args[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]; + } + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &gic_data); } @@ -174,10 +182,9 @@ static int __init vf610_mscm_ir_of_init(struct device_node *node, return -ENOMEM; mscm_ir_data->mscm_ir_base = of_io_request_and_map(node, 0, "mscm-ir"); - - if (!mscm_ir_data->mscm_ir_base) { + if (IS_ERR(mscm_ir_data->mscm_ir_base)) { pr_err("vf610_mscm_ir: unable to map mscm register\n"); - ret = -ENOMEM; + ret = PTR_ERR(mscm_ir_data->mscm_ir_base); goto out_free; } @@ -199,6 +206,9 @@ 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")) + mscm_ir_data->is_nvic = true; + cpu_pm_register_notifier(&mscm_ir_notifier_block); return 0; diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index 54089debf2dc..d4ce331ea4a0 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -256,7 +256,7 @@ static void __exception_irq_entry vic_handle_irq(struct pt_regs *regs) } while (handled); } -static struct irq_domain_ops vic_irqdomain_ops = { +static const struct irq_domain_ops vic_irqdomain_ops = { .map = vic_irqdomain_map, .xlate = irq_domain_xlate_onetwocell, }; diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c index b7af816f2769..0b297009b856 100644 --- a/drivers/irqchip/irq-vt8500.c +++ b/drivers/irqchip/irq-vt8500.c @@ -173,7 +173,7 @@ static int vt8500_irq_map(struct irq_domain *h, unsigned int virq, return 0; } -static struct irq_domain_ops vt8500_irq_domain_ops = { +static const struct irq_domain_ops vt8500_irq_domain_ops = { .map = vt8500_irq_map, .xlate = irq_domain_xlate_onecell, }; diff --git a/drivers/irqchip/spear-shirq.c b/drivers/irqchip/spear-shirq.c index 9c145a7cb056..a45121546caf 100644 --- a/drivers/irqchip/spear-shirq.c +++ b/drivers/irqchip/spear-shirq.c @@ -207,8 +207,7 @@ static void __init spear_shirq_register(struct spear_shirq *shirq, if (!shirq->irq_chip) return; - irq_set_chained_handler(parent_irq, shirq_handler); - irq_set_handler_data(parent_irq, shirq); + irq_set_chained_handler_and_data(parent_irq, shirq_handler, shirq); for (i = 0; i < shirq->nr_irqs; i++) { irq_set_chip_and_handler(shirq->virq_base + i, diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index 58ea9fdd3a15..3591550598ad 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -566,8 +566,7 @@ static int ucb1x00_probe(struct mcp *mcp) } irq_set_irq_type(ucb->irq, IRQ_TYPE_EDGE_RISING); - irq_set_handler_data(ucb->irq, ucb); - irq_set_chained_handler(ucb->irq, ucb1x00_irq); + irq_set_chained_handler_and_data(ucb->irq, ucb1x00_irq, ucb); if (pdata && pdata->gpio_base) { ucb->gpio.label = dev_name(&ucb->dev); diff --git a/include/linux/irq.h b/include/linux/irq.h index 48cb7d1aa58f..812149160d3b 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -126,13 +126,21 @@ struct msi_desc; struct irq_domain; /** - * struct irq_data - per irq and irq chip data passed down to chip functions + * struct irq_common_data - per irq data shared by all irqchips + * @state_use_accessors: status information for irq chip functions. + * Use accessor functions to deal with it + */ +struct irq_common_data { + unsigned int state_use_accessors; +}; + +/** + * struct irq_data - per irq chip data passed down to chip functions * @mask: precomputed bitmask for accessing the chip registers * @irq: interrupt number * @hwirq: hardware interrupt number, local to the interrupt domain * @node: node index useful for balancing - * @state_use_accessors: status information for irq chip functions. - * Use accessor functions to deal with it + * @common: point to data shared by all irqchips * @chip: low level interrupt hardware access * @domain: Interrupt translation domain; responsible for mapping * between hwirq number and linux irq number. @@ -153,7 +161,7 @@ struct irq_data { unsigned int irq; unsigned long hwirq; unsigned int node; - unsigned int state_use_accessors; + struct irq_common_data *common; struct irq_chip *chip; struct irq_domain *domain; #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY @@ -166,7 +174,7 @@ struct irq_data { }; /* - * Bit masks for irq_data.state + * Bit masks for irq_common_data.state_use_accessors * * IRQD_TRIGGER_MASK - Mask for the trigger type bits * IRQD_SETAFFINITY_PENDING - Affinity setting is pending @@ -198,34 +206,36 @@ enum { IRQD_WAKEUP_ARMED = (1 << 19), }; +#define __irqd_to_state(d) ((d)->common->state_use_accessors) + static inline bool irqd_is_setaffinity_pending(struct irq_data *d) { - return d->state_use_accessors & IRQD_SETAFFINITY_PENDING; + return __irqd_to_state(d) & IRQD_SETAFFINITY_PENDING; } static inline bool irqd_is_per_cpu(struct irq_data *d) { - return d->state_use_accessors & IRQD_PER_CPU; + return __irqd_to_state(d) & IRQD_PER_CPU; } static inline bool irqd_can_balance(struct irq_data *d) { - return !(d->state_use_accessors & (IRQD_PER_CPU | IRQD_NO_BALANCING)); + return !(__irqd_to_state(d) & (IRQD_PER_CPU | IRQD_NO_BALANCING)); } static inline bool irqd_affinity_was_set(struct irq_data *d) { - return d->state_use_accessors & IRQD_AFFINITY_SET; + return __irqd_to_state(d) & IRQD_AFFINITY_SET; } static inline void irqd_mark_affinity_was_set(struct irq_data *d) { - d->state_use_accessors |= IRQD_AFFINITY_SET; + __irqd_to_state(d) |= IRQD_AFFINITY_SET; } static inline u32 irqd_get_trigger_type(struct irq_data *d) { - return d->state_use_accessors & IRQD_TRIGGER_MASK; + return __irqd_to_state(d) & IRQD_TRIGGER_MASK; } /* @@ -233,43 +243,43 @@ static inline u32 irqd_get_trigger_type(struct irq_data *d) */ static inline void irqd_set_trigger_type(struct irq_data *d, u32 type) { - d->state_use_accessors &= ~IRQD_TRIGGER_MASK; - d->state_use_accessors |= type & IRQD_TRIGGER_MASK; + __irqd_to_state(d) &= ~IRQD_TRIGGER_MASK; + __irqd_to_state(d) |= type & IRQD_TRIGGER_MASK; } static inline bool irqd_is_level_type(struct irq_data *d) { - return d->state_use_accessors & IRQD_LEVEL; + return __irqd_to_state(d) & IRQD_LEVEL; } static inline bool irqd_is_wakeup_set(struct irq_data *d) { - return d->state_use_accessors & IRQD_WAKEUP_STATE; + return __irqd_to_state(d) & IRQD_WAKEUP_STATE; } static inline bool irqd_can_move_in_process_context(struct irq_data *d) { - return d->state_use_accessors & IRQD_MOVE_PCNTXT; + return __irqd_to_state(d) & IRQD_MOVE_PCNTXT; } static inline bool irqd_irq_disabled(struct irq_data *d) { - return d->state_use_accessors & IRQD_IRQ_DISABLED; + return __irqd_to_state(d) & IRQD_IRQ_DISABLED; } static inline bool irqd_irq_masked(struct irq_data *d) { - return d->state_use_accessors & IRQD_IRQ_MASKED; + return __irqd_to_state(d) & IRQD_IRQ_MASKED; } static inline bool irqd_irq_inprogress(struct irq_data *d) { - return d->state_use_accessors & IRQD_IRQ_INPROGRESS; + return __irqd_to_state(d) & IRQD_IRQ_INPROGRESS; } static inline bool irqd_is_wakeup_armed(struct irq_data *d) { - return d->state_use_accessors & IRQD_WAKEUP_ARMED; + return __irqd_to_state(d) & IRQD_WAKEUP_ARMED; } @@ -280,12 +290,12 @@ static inline bool irqd_is_wakeup_armed(struct irq_data *d) */ static inline void irqd_set_chained_irq_inprogress(struct irq_data *d) { - d->state_use_accessors |= IRQD_IRQ_INPROGRESS; + __irqd_to_state(d) |= IRQD_IRQ_INPROGRESS; } static inline void irqd_clr_chained_irq_inprogress(struct irq_data *d) { - d->state_use_accessors &= ~IRQD_IRQ_INPROGRESS; + __irqd_to_state(d) &= ~IRQD_IRQ_INPROGRESS; } static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) @@ -462,6 +472,8 @@ extern void handle_nested_irq(unsigned int irq); extern int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg); #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY +extern void irq_chip_enable_parent(struct irq_data *data); +extern void irq_chip_disable_parent(struct irq_data *data); extern void irq_chip_ack_parent(struct irq_data *data); extern int irq_chip_retrigger_hierarchy(struct irq_data *data); extern void irq_chip_mask_parent(struct irq_data *data); @@ -523,6 +535,15 @@ irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle) __irq_set_handler(irq, handle, 1, NULL); } +/* + * Set a highlevel chained flow handler and its data for a given IRQ. + * (a chained handler is automatically enabled and set to + * IRQ_NOREQUEST, IRQ_NOPROBE, and IRQ_NOTHREAD) + */ +void +irq_set_chained_handler_and_data(unsigned int irq, irq_flow_handler_t handle, + void *data); + void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set); static inline void irq_set_status_flags(unsigned int irq, unsigned long set) @@ -630,6 +651,23 @@ static inline u32 irq_get_trigger_type(unsigned int irq) return d ? irqd_get_trigger_type(d) : 0; } +static inline int irq_data_get_node(struct irq_data *d) +{ + return d->node; +} + +static inline struct cpumask *irq_get_affinity_mask(int irq) +{ + struct irq_data *d = irq_get_irq_data(irq); + + return d ? d->affinity : NULL; +} + +static inline struct cpumask *irq_data_get_affinity_mask(struct irq_data *d) +{ + return d->affinity; +} + unsigned int arch_dynirq_lower_bound(unsigned int from); int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index a113a8dc7438..c52d1480f272 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -17,7 +17,7 @@ struct pt_regs; /** * struct irq_desc - interrupt descriptor - * @irq_data: per irq and chip data passed down to chip functions + * @irq_common_data: per irq and chip data passed down to chip functions * @kstat_irqs: irq stats per cpu * @handle_irq: highlevel irq-events handler * @preflow_handler: handler called before the flow handler (currently used by sparc) @@ -47,6 +47,7 @@ struct pt_regs; * @name: flow handler name for /proc/interrupts output */ struct irq_desc { + struct irq_common_data irq_common_data; struct irq_data irq_data; unsigned int __percpu *kstat_irqs; irq_flow_handler_t handle_irq; diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 676d7306a360..744ac0ec98eb 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -258,6 +258,10 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr, /* V2 interfaces to support hierarchy IRQ domains. */ extern struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain, unsigned int virq); +extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq, + irq_hw_number_t hwirq, struct irq_chip *chip, + void *chip_data, irq_flow_handler_t handler, + void *handler_data, const char *handler_name); #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY extern struct irq_domain *irq_domain_add_hierarchy(struct irq_domain *parent, unsigned int flags, unsigned int size, @@ -281,10 +285,6 @@ extern int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, irq_hw_number_t hwirq, struct irq_chip *chip, void *chip_data); -extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq, - irq_hw_number_t hwirq, struct irq_chip *chip, - void *chip_data, irq_flow_handler_t handler, - void *handler_data, const char *handler_name); extern void irq_domain_reset_irq_data(struct irq_data *irq_data); extern void irq_domain_free_irqs_common(struct irq_domain *domain, unsigned int virq, diff --git a/include/linux/platform_data/irq-renesas-irqc.h b/include/linux/platform_data/irq-renesas-irqc.h deleted file mode 100644 index 3ae17b3e00ed..000000000000 --- a/include/linux/platform_data/irq-renesas-irqc.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Renesas IRQC Driver - * - * Copyright (C) 2013 Magnus Damm - * - * 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 - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __IRQ_RENESAS_IRQC_H__ -#define __IRQ_RENESAS_IRQC_H__ - -struct renesas_irqc_config { - unsigned int irq_base; -}; - -#endif /* __IRQ_RENESAS_IRQC_H__ */ diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 55016b2151f3..27f4332c7f84 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -719,15 +719,9 @@ void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc) } void -__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, - const char *name) +__irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle, + int is_chained, const char *name) { - unsigned long flags; - struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0); - - if (!desc) - return; - if (!handle) { handle = handle_bad_irq; } else { @@ -749,13 +743,13 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, * right away. */ if (WARN_ON(is_chained)) - goto out; + return; /* Try the parent */ irq_data = irq_data->parent_data; } #endif if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip)) - goto out; + return; } /* Uninstall? */ @@ -774,12 +768,41 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, irq_settings_set_nothread(desc); irq_startup(desc, true); } -out: +} + +void +__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, + const char *name) +{ + unsigned long flags; + struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0); + + if (!desc) + return; + + __irq_do_set_handler(desc, handle, is_chained, name); irq_put_desc_busunlock(desc, flags); } EXPORT_SYMBOL_GPL(__irq_set_handler); void +irq_set_chained_handler_and_data(unsigned int irq, irq_flow_handler_t handle, + void *data) +{ + unsigned long flags; + struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0); + + if (!desc) + return; + + __irq_do_set_handler(desc, handle, 1, NULL); + desc->irq_data.handler_data = data; + + irq_put_desc_busunlock(desc, flags); +} +EXPORT_SYMBOL_GPL(irq_set_chained_handler_and_data); + +void irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, irq_flow_handler_t handle, const char *name) { @@ -876,6 +899,34 @@ void irq_cpu_offline(void) #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY /** + * irq_chip_enable_parent - Enable the parent interrupt (defaults to unmask if + * NULL) + * @data: Pointer to interrupt specific data + */ +void irq_chip_enable_parent(struct irq_data *data) +{ + data = data->parent_data; + if (data->chip->irq_enable) + data->chip->irq_enable(data); + else + data->chip->irq_unmask(data); +} + +/** + * irq_chip_disable_parent - Disable the parent interrupt (defaults to mask if + * NULL) + * @data: Pointer to interrupt specific data + */ +void irq_chip_disable_parent(struct irq_data *data) +{ + data = data->parent_data; + if (data->chip->irq_disable) + data->chip->irq_disable(data); + else + data->chip->irq_mask(data); +} + +/** * irq_chip_ack_parent - Acknowledge the parent interrupt * @data: Pointer to interrupt specific data */ diff --git a/kernel/irq/devres.c b/kernel/irq/devres.c index d5d0f7345c54..74d90a754268 100644 --- a/kernel/irq/devres.c +++ b/kernel/irq/devres.c @@ -104,7 +104,7 @@ int devm_request_any_context_irq(struct device *dev, unsigned int irq, return -ENOMEM; rc = request_any_context_irq(irq, handler, irqflags, devname, dev_id); - if (rc) { + if (rc < 0) { devres_free(dr); return rc; } @@ -113,7 +113,7 @@ int devm_request_any_context_irq(struct device *dev, unsigned int irq, dr->dev_id = dev_id; devres_add(dev, dr); - return 0; + return rc; } EXPORT_SYMBOL(devm_request_any_context_irq); diff --git a/kernel/irq/dummychip.c b/kernel/irq/dummychip.c index 2feb6feca0cc..326a67f2410b 100644 --- a/kernel/irq/dummychip.c +++ b/kernel/irq/dummychip.c @@ -42,6 +42,7 @@ struct irq_chip no_irq_chip = { .irq_enable = noop, .irq_disable = noop, .irq_ack = ack_bad, + .flags = IRQCHIP_SKIP_SET_WAKE, }; /* diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c index 61024e8abdef..15b370daf234 100644 --- a/kernel/irq/generic-chip.c +++ b/kernel/irq/generic-chip.c @@ -360,7 +360,7 @@ static struct lock_class_key irq_nested_lock_class; int irq_map_generic_chip(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw_irq) { - struct irq_data *data = irq_get_irq_data(virq); + struct irq_data *data = irq_domain_get_irq_data(d, virq); struct irq_domain_chip_generic *dgc = d->gc; struct irq_chip_generic *gc; struct irq_chip_type *ct; @@ -405,8 +405,7 @@ int irq_map_generic_chip(struct irq_domain *d, unsigned int virq, else data->mask = 1 << idx; - irq_set_chip_and_handler(virq, chip, ct->handler); - irq_set_chip_data(virq, gc); + irq_domain_set_info(d, virq, hw_irq, chip, gc, ct->handler, NULL, NULL); irq_modify_status(virq, dgc->irq_flags_to_clear, dgc->irq_flags_to_set); return 0; } diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index b93d434e70bd..4834ee828c41 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -168,27 +168,27 @@ irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags) */ static inline void irqd_set_move_pending(struct irq_data *d) { - d->state_use_accessors |= IRQD_SETAFFINITY_PENDING; + __irqd_to_state(d) |= IRQD_SETAFFINITY_PENDING; } static inline void irqd_clr_move_pending(struct irq_data *d) { - d->state_use_accessors &= ~IRQD_SETAFFINITY_PENDING; + __irqd_to_state(d) &= ~IRQD_SETAFFINITY_PENDING; } static inline void irqd_clear(struct irq_data *d, unsigned int mask) { - d->state_use_accessors &= ~mask; + __irqd_to_state(d) &= ~mask; } static inline void irqd_set(struct irq_data *d, unsigned int mask) { - d->state_use_accessors |= mask; + __irqd_to_state(d) |= mask; } static inline bool irqd_has_set(struct irq_data *d, unsigned int mask) { - return d->state_use_accessors & mask; + return __irqd_to_state(d) & mask; } static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *desc) @@ -197,6 +197,11 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq, struct irq_desc *d __this_cpu_inc(kstat.irqs_sum); } +static inline int irq_desc_get_node(struct irq_desc *desc) +{ + return irq_data_get_node(&desc->irq_data); +} + #ifdef CONFIG_PM_SLEEP bool irq_pm_check_wakeup(struct irq_desc *desc); void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action); diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c index 99793b9b6d23..4afc457613dd 100644 --- a/kernel/irq/irqdesc.c +++ b/kernel/irq/irqdesc.c @@ -59,16 +59,10 @@ static void desc_smp_init(struct irq_desc *desc, int node) #endif } -static inline int desc_node(struct irq_desc *desc) -{ - return desc->irq_data.node; -} - #else static inline int alloc_masks(struct irq_desc *desc, gfp_t gfp, int node) { return 0; } static inline void desc_smp_init(struct irq_desc *desc, int node) { } -static inline int desc_node(struct irq_desc *desc) { return 0; } #endif static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node, @@ -76,6 +70,7 @@ static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node, { int cpu; + desc->irq_data.common = &desc->irq_common_data; desc->irq_data.irq = irq; desc->irq_data.chip = &no_irq_chip; desc->irq_data.chip_data = NULL; @@ -299,7 +294,7 @@ static void free_desc(unsigned int irq) unsigned long flags; raw_spin_lock_irqsave(&desc->lock, flags); - desc_set_defaults(irq, desc, desc_node(desc), NULL); + desc_set_defaults(irq, desc, irq_desc_get_node(desc), NULL); raw_spin_unlock_irqrestore(&desc->lock, flags); } @@ -619,7 +614,7 @@ unsigned int kstat_irqs(unsigned int irq) { struct irq_desc *desc = irq_to_desc(irq); int cpu; - int sum = 0; + unsigned int sum = 0; if (!desc || !desc->kstat_irqs) return 0; @@ -639,7 +634,7 @@ unsigned int kstat_irqs(unsigned int irq) */ unsigned int kstat_irqs_usr(unsigned int irq) { - int sum; + unsigned int sum; irq_lock_sparse(); sum = kstat_irqs(irq); diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 7fac311057b8..8c3577fef78c 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -830,10 +830,12 @@ static struct irq_data *irq_domain_insert_irq_data(struct irq_domain *domain, { struct irq_data *irq_data; - irq_data = kzalloc_node(sizeof(*irq_data), GFP_KERNEL, child->node); + irq_data = kzalloc_node(sizeof(*irq_data), GFP_KERNEL, + irq_data_get_node(child)); if (irq_data) { child->parent_data = irq_data; irq_data->irq = child->irq; + irq_data->common = child->common; irq_data->node = child->node; irq_data->domain = domain; } @@ -1232,6 +1234,27 @@ struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain, return (irq_data && irq_data->domain == domain) ? irq_data : NULL; } +/** + * irq_domain_set_info - Set the complete data for a @virq in @domain + * @domain: Interrupt domain to match + * @virq: IRQ number + * @hwirq: The hardware interrupt number + * @chip: The associated interrupt chip + * @chip_data: The associated interrupt chip data + * @handler: The interrupt flow handler + * @handler_data: The interrupt flow handler data + * @handler_name: The interrupt handler name + */ +void irq_domain_set_info(struct irq_domain *domain, unsigned int virq, + irq_hw_number_t hwirq, struct irq_chip *chip, + void *chip_data, irq_flow_handler_t handler, + void *handler_data, const char *handler_name) +{ + irq_set_chip_and_handler_name(virq, chip, handler, handler_name); + irq_set_chip_data(virq, chip_data); + irq_set_handler_data(virq, handler_data); +} + static void irq_domain_check_hierarchy(struct irq_domain *domain) { } diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index b1c7e8f46bfb..f9744853b656 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -363,7 +363,7 @@ static int setup_affinity(unsigned int irq, struct irq_desc *desc, struct cpumask *mask) { struct cpumask *set = irq_default_affinity; - int node = desc->irq_data.node; + int node = irq_desc_get_node(desc); /* Excludes PER_CPU and NO_BALANCE interrupts */ if (!irq_can_set_affinity(irq)) diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c index dd203e276b07..37ddb7bda651 100644 --- a/kernel/irq/migration.c +++ b/kernel/irq/migration.c @@ -12,16 +12,16 @@ void irq_move_masked_irq(struct irq_data *idata) if (likely(!irqd_is_setaffinity_pending(&desc->irq_data))) return; + irqd_clr_move_pending(&desc->irq_data); + /* * Paranoia: cpu-local interrupts shouldn't be calling in here anyway. */ - if (!irqd_can_balance(&desc->irq_data)) { + if (irqd_is_per_cpu(&desc->irq_data)) { WARN_ON(1); return; } - irqd_clr_move_pending(&desc->irq_data); - if (unlikely(cpumask_empty(desc->pending_mask))) return; diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c index 474de5cb394d..7bf1f1bbb7fa 100644 --- a/kernel/irq/msi.c +++ b/kernel/irq/msi.c @@ -124,7 +124,7 @@ static void msi_domain_free(struct irq_domain *domain, unsigned int virq, irq_domain_free_irqs_top(domain, virq, nr_irqs); } -static struct irq_domain_ops msi_domain_ops = { +static const struct irq_domain_ops msi_domain_ops = { .alloc = msi_domain_alloc, .free = msi_domain_free, .activate = msi_domain_activate, diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index 5204a6d1b985..d22786a6dbde 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -123,6 +123,8 @@ void suspend_device_irqs(void) unsigned long flags; bool sync; + if (irq_settings_is_nested_thread(desc)) + continue; raw_spin_lock_irqsave(&desc->lock, flags); sync = suspend_device_irq(desc, irq); raw_spin_unlock_irqrestore(&desc->lock, flags); @@ -163,6 +165,8 @@ static void resume_irqs(bool want_early) if (!is_early && want_early) continue; + if (irq_settings_is_nested_thread(desc)) + continue; raw_spin_lock_irqsave(&desc->lock, flags); resume_irq(desc, irq); diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c index df2f4642d1e7..0e97c142ce40 100644 --- a/kernel/irq/proc.c +++ b/kernel/irq/proc.c @@ -241,7 +241,7 @@ static int irq_node_proc_show(struct seq_file *m, void *v) { struct irq_desc *desc = irq_to_desc((long) m->private); - seq_printf(m, "%d\n", desc->irq_data.node); + seq_printf(m, "%d\n", irq_desc_get_node(desc)); return 0; } |