aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-10-09 06:42:04 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-10-09 06:42:04 -0400
commit782d59c5dfc5ac39ac8cfb4c6dd40597938dde9c (patch)
tree2d831c436a1962bfe5dfdb3afeaf87c7a3e82132
parent47137c6ba1bcde30215795f9594cea770946456b (diff)
parent2828c9cdb8bd30f49c48210c014ccdd4cb994931 (diff)
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: - a cleanup series to get rid of mindlessly copied code. - another bunch of new pointlessly different interrupt chip drivers. Adding homebrewn irq chips (and timers) to SoCs must provide a value add which is beyond the imagination of mere mortals. - the usual SoC irq controller updates, IOW my second cat herding project" * 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (44 commits) irqchip: gic-v3: Implement CPU PM notifier irqchip: gic-v3: Refactor gic_enable_redist to support both enabling and disabling irqchip: renesas-intc-irqpin: Add minimal runtime PM support irqchip: renesas-intc-irqpin: Add helper variable dev = &pdev->dev irqchip: atmel-aic5: Add sama5d4 support irqchip: atmel-aic5: The sama5d3 has 48 IRQs Documentation: bcm7120-l2: Add Broadcom BCM7120-style L2 binding irqchip: bcm7120-l2: Add Broadcom BCM7120-style Level 2 interrupt controller irqchip: renesas-irqc: Add binding docs for new R-Car Gen2 SoCs irqchip: renesas-irqc: Add DT binding documentation irqchip: renesas-intc-irqpin: Document SoC-specific bindings openrisc: Get rid of handle_IRQ arm64: Get rid of handle_IRQ ARM: omap2: irq: Convert to handle_domain_irq ARM: imx: tzic: Convert to handle_domain_irq ARM: imx: avic: Convert to handle_domain_irq irqchip: or1k-pic: Convert to handle_domain_irq irqchip: atmel-aic5: Convert to handle_domain_irq irqchip: atmel-aic: Convert to handle_domain_irq irqchip: gic-v3: Convert to handle_domain_irq ...
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt2
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt86
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt8
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt32
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/ti,keystone-irq.txt36
-rw-r--r--MAINTAINERS1
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/kernel/irq.c19
-rw-r--r--arch/arm/mach-imx/avic.c2
-rw-r--r--arch/arm/mach-imx/tzic.c3
-rw-r--r--arch/arm64/Kconfig1
-rw-r--r--arch/arm64/include/asm/hardirq.h2
-rw-r--r--arch/arm64/kernel/irq.c27
-rw-r--r--arch/openrisc/Kconfig1
-rw-r--r--arch/openrisc/include/asm/irq.h1
-rw-r--r--arch/openrisc/kernel/irq.c12
-rw-r--r--drivers/irqchip/Kconfig7
-rw-r--r--drivers/irqchip/Makefile5
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c19
-rw-r--r--drivers/irqchip/irq-atmel-aic.c4
-rw-r--r--drivers/irqchip/irq-atmel-aic5.c16
-rw-r--r--drivers/irqchip/irq-bcm7120-l2.c219
-rw-r--r--drivers/irqchip/irq-clps711x.c18
-rw-r--r--drivers/irqchip/irq-gic-common.c15
-rw-r--r--drivers/irqchip/irq-gic-v3.c100
-rw-r--r--drivers/irqchip/irq-gic.c49
-rw-r--r--drivers/irqchip/irq-hip04.c424
-rw-r--r--drivers/irqchip/irq-keystone.c232
-rw-r--r--drivers/irqchip/irq-mmp.c10
-rw-r--r--drivers/irqchip/irq-mxs.c3
-rw-r--r--drivers/irqchip/irq-omap-intc.c3
-rw-r--r--drivers/irqchip/irq-or1k-pic.c4
-rw-r--r--drivers/irqchip/irq-orion.c5
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c85
-rw-r--r--drivers/irqchip/irq-s3c24xx.c4
-rw-r--r--drivers/irqchip/irq-sirfsoc.c6
-rw-r--r--drivers/irqchip/irq-sun4i.c5
-rw-r--r--drivers/irqchip/irq-versatile-fpga.c2
-rw-r--r--drivers/irqchip/irq-vic.c2
-rw-r--r--drivers/irqchip/irq-vt8500.c5
-rw-r--r--drivers/irqchip/irq-zevio.c3
-rw-r--r--include/linux/irqchip/arm-gic.h16
-rw-r--r--include/linux/irqdesc.h19
-rw-r--r--kernel/irq/Kconfig3
-rw-r--r--kernel/irq/irqdesc.c42
45 files changed, 1356 insertions, 203 deletions
diff --git a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt
index 2742e9cfd6b1..f292917fa00d 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt
@@ -2,7 +2,7 @@
2 2
3Required properties: 3Required properties:
4- compatible: Should be "atmel,<chip>-aic" 4- compatible: Should be "atmel,<chip>-aic"
5 <chip> can be "at91rm9200" or "sama5d3" 5 <chip> can be "at91rm9200", "sama5d3" or "sama5d4"
6- interrupt-controller: Identifies the node as an interrupt controller. 6- interrupt-controller: Identifies the node as an interrupt controller.
7- interrupt-parent: For single AIC system, it is an empty property. 7- interrupt-parent: For single AIC system, it is an empty property.
8- #interrupt-cells: The number of cells to define the interrupts. It should be 3. 8- #interrupt-cells: The number of cells to define the interrupts. It should be 3.
diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt
new file mode 100644
index 000000000000..ff812a8a82bc
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt
@@ -0,0 +1,86 @@
1Broadcom BCM7120-style Level 2 interrupt controller
2
3This interrupt controller hardware is a second level interrupt controller that
4is hooked to a parent interrupt controller: e.g: ARM GIC for ARM-based
5platforms. It can be found on BCM7xxx products starting with BCM7120.
6
7Such an interrupt controller has the following hardware design:
8
9- outputs multiple interrupts signals towards its interrupt controller parent
10
11- controls how some of the interrupts will be flowing, whether they will
12 directly output an interrupt signal towards the interrupt controller parent,
13 or if they will output an interrupt signal at this 2nd level interrupt
14 controller, in particular for UARTs
15
16- not all 32-bits within the interrupt controller actually map to an interrupt
17
18The typical hardware layout for this controller is represented below:
19
202nd level interrupt line Outputs for the parent controller (e.g: ARM GIC)
21
220 -----[ MUX ] ------------|==========> GIC interrupt 75
23 \-----------\
24 |
251 -----[ MUX ] --------)---|==========> GIC interrupt 76
26 \------------|
27 |
282 -----[ MUX ] --------)---|==========> GIC interrupt 77
29 \------------|
30 |
313 ---------------------|
324 ---------------------|
335 ---------------------|
347 ---------------------|---|===========> GIC interrupt 66
359 ---------------------|
3610 --------------------|
3711 --------------------/
38
396 ------------------------\
40 |===========> GIC interrupt 64
418 ------------------------/
42
4312 ........................ X
4413 ........................ X (not connected)
45..
4631 ........................ X
47
48Required properties:
49
50- compatible: should be "brcm,bcm7120-l2-intc"
51- reg: specifies the base physical address and size of the registers
52- interrupt-controller: identifies the node as an interrupt controller
53- #interrupt-cells: specifies the number of cells needed to encode an interrupt
54 source, should be 1.
55- interrupt-parent: specifies the phandle to the parent interrupt controller
56 this one is cascaded from
57- interrupts: specifies the interrupt line(s) in the interrupt-parent controller
58 node, valid values depend on the type of parent interrupt controller
59- brcm,int-map-mask: 32-bits bit mask describing how many and which interrupts
60 are wired to this 2nd level interrupt controller, and how they match their
61 respective interrupt parents. Should match exactly the number of interrupts
62 specified in the 'interrupts' property.
63
64Optional properties:
65
66- brcm,irq-can-wake: if present, this means the L2 controller can be used as a
67 wakeup source for system suspend/resume.
68
69- brcm,int-fwd-mask: if present, a 32-bits bit mask to configure for the
70 interrupts which have a mux gate, typically UARTs. Setting these bits will
71 make their respective interrupts outputs bypass this 2nd level interrupt
72 controller completely, it completely transparent for the interrupt controller
73 parent
74
75Example:
76
77irq0_intc: interrupt-controller@f0406800 {
78 compatible = "brcm,bcm7120-l2-intc";
79 interrupt-parent = <&intc>;
80 #interrupt-cells = <1>;
81 reg = <0xf0406800 0x8>;
82 interrupt-controller;
83 interrupts = <0x0 0x42 0x0>, <0x0 0x40 0x0>;
84 brcm,int-map-mask = <0xeb8>, <0x140>;
85 brcm,int-fwd-mask = <0x7>;
86};
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt
index 1f8b0c507c26..c73acd060093 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,intc-irqpin.txt
@@ -2,7 +2,13 @@ DT bindings for the R-/SH-Mobile irqpin controller
2 2
3Required properties: 3Required properties:
4 4
5- compatible: has to be "renesas,intc-irqpin" 5- compatible: has to be "renesas,intc-irqpin-<soctype>", "renesas,intc-irqpin"
6 as fallback.
7 Examples with soctypes are:
8 - "renesas,intc-irqpin-r8a7740" (R-Mobile A1)
9 - "renesas,intc-irqpin-r8a7778" (R-Car M1A)
10 - "renesas,intc-irqpin-r8a7779" (R-Car H1)
11 - "renesas,intc-irqpin-sh73a0" (SH-Mobile AG5)
6- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in 12- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
7 interrupts.txt in this directory 13 interrupts.txt in this directory
8 14
diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt
new file mode 100644
index 000000000000..1a88e62228e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt
@@ -0,0 +1,32 @@
1DT bindings for the R-Mobile/R-Car interrupt controller
2
3Required properties:
4
5- compatible: has to be "renesas,irqc-<soctype>", "renesas,irqc" as fallback.
6 Examples with soctypes are:
7 - "renesas,irqc-r8a73a4" (R-Mobile AP6)
8 - "renesas,irqc-r8a7790" (R-Car H2)
9 - "renesas,irqc-r8a7791" (R-Car M2-W)
10 - "renesas,irqc-r8a7792" (R-Car V2H)
11 - "renesas,irqc-r8a7793" (R-Car M2-N)
12 - "renesas,irqc-r8a7794" (R-Car E2)
13- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
14 interrupts.txt in this directory
15
16Optional properties:
17
18- any properties, listed in interrupts.txt, and any standard resource allocation
19 properties
20
21Example:
22
23 irqc0: interrupt-controller@e61c0000 {
24 compatible = "renesas,irqc-r8a7790", "renesas,irqc";
25 #interrupt-cells = <2>;
26 interrupt-controller;
27 reg = <0 0xe61c0000 0 0x200>;
28 interrupts = <0 0 IRQ_TYPE_LEVEL_HIGH>,
29 <0 1 IRQ_TYPE_LEVEL_HIGH>,
30 <0 2 IRQ_TYPE_LEVEL_HIGH>,
31 <0 3 IRQ_TYPE_LEVEL_HIGH>;
32 };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/ti,keystone-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/ti,keystone-irq.txt
new file mode 100644
index 000000000000..d9bb106bdd16
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/ti,keystone-irq.txt
@@ -0,0 +1,36 @@
1Keystone 2 IRQ controller IP
2
3On Keystone SOCs, DSP cores can send interrupts to ARM
4host using the IRQ controller IP. It provides 28 IRQ signals to ARM.
5The IRQ handler running on HOST OS can identify DSP signal source by
6analyzing SRCCx bits in IPCARx registers. This is one of the component
7used by the IPC mechanism used on Keystone SOCs.
8
9Required Properties:
10- compatible: should be "ti,keystone-irq"
11- ti,syscon-dev : phandle and offset pair. The phandle to syscon used to
12 access device control registers and the offset inside
13 device control registers range.
14- interrupt-controller : Identifies the node as an interrupt controller
15- #interrupt-cells : Specifies the number of cells needed to encode interrupt
16 source should be 1.
17- interrupts: interrupt reference to primary interrupt controller
18
19Please refer to interrupts.txt in this directory for details of the common
20Interrupt Controllers bindings used by client devices.
21
22Example:
23 kirq0: keystone_irq0@026202a0 {
24 compatible = "ti,keystone-irq";
25 ti,syscon-dev = <&devctrl 0x2a0>;
26 interrupts = <GIC_SPI 4 IRQ_TYPE_EDGE_RISING>;
27 interrupt-controller;
28 #interrupt-cells = <1>;
29 };
30
31 dsp0: dsp0 {
32 compatible = "linux,rproc-user";
33 ...
34 interrupt-parent = <&kirq0>;
35 interrupts = <10 2>;
36 };
diff --git a/MAINTAINERS b/MAINTAINERS
index 9e315a44ae0c..0b23084070c2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5045,6 +5045,7 @@ L: linux-kernel@vger.kernel.org
5045S: Maintained 5045S: Maintained
5046T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core 5046T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
5047T: git git://git.infradead.org/users/jcooper/linux.git irqchip/core 5047T: git git://git.infradead.org/users/jcooper/linux.git irqchip/core
5048F: Documentation/devicetree/bindings/interrupt-controller/
5048F: drivers/irqchip/ 5049F: drivers/irqchip/
5049 5050
5050IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY) 5051IRQ DOMAINS (IRQ NUMBER MAPPING LIBRARY)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 82dfdeac3595..d9d32de9628c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -24,6 +24,7 @@ config ARM
24 select GENERIC_SMP_IDLE_THREAD 24 select GENERIC_SMP_IDLE_THREAD
25 select GENERIC_STRNCPY_FROM_USER 25 select GENERIC_STRNCPY_FROM_USER
26 select GENERIC_STRNLEN_USER 26 select GENERIC_STRNLEN_USER
27 select HANDLE_DOMAIN_IRQ
27 select HARDIRQS_SW_RESEND 28 select HARDIRQS_SW_RESEND
28 select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT) 29 select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT)
29 select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL 30 select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 88de943eebd6..7c81ec428b9b 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -65,24 +65,7 @@ int arch_show_interrupts(struct seq_file *p, int prec)
65 */ 65 */
66void handle_IRQ(unsigned int irq, struct pt_regs *regs) 66void handle_IRQ(unsigned int irq, struct pt_regs *regs)
67{ 67{
68 struct pt_regs *old_regs = set_irq_regs(regs); 68 __handle_domain_irq(NULL, irq, false, regs);
69
70 irq_enter();
71
72 /*
73 * Some hardware gives randomly wrong interrupts. Rather
74 * than crashing, do something sensible.
75 */
76 if (unlikely(irq >= nr_irqs)) {
77 if (printk_ratelimit())
78 printk(KERN_WARNING "Bad IRQ%u\n", irq);
79 ack_bad_irq(irq);
80 } else {
81 generic_handle_irq(irq);
82 }
83
84 irq_exit();
85 set_irq_regs(old_regs);
86} 69}
87 70
88/* 71/*
diff --git a/arch/arm/mach-imx/avic.c b/arch/arm/mach-imx/avic.c
index 24b103c67f82..1a8932335b21 100644
--- a/arch/arm/mach-imx/avic.c
+++ b/arch/arm/mach-imx/avic.c
@@ -144,7 +144,7 @@ static void __exception_irq_entry avic_handle_irq(struct pt_regs *regs)
144 if (nivector == 0xffff) 144 if (nivector == 0xffff)
145 break; 145 break;
146 146
147 handle_IRQ(irq_find_mapping(domain, nivector), regs); 147 handle_domain_irq(domain, nivector, regs);
148 } while (1); 148 } while (1);
149} 149}
150 150
diff --git a/arch/arm/mach-imx/tzic.c b/arch/arm/mach-imx/tzic.c
index 1d4f384ca773..4de65eeda1eb 100644
--- a/arch/arm/mach-imx/tzic.c
+++ b/arch/arm/mach-imx/tzic.c
@@ -141,8 +141,7 @@ static void __exception_irq_entry tzic_handle_irq(struct pt_regs *regs)
141 while (stat) { 141 while (stat) {
142 handled = 1; 142 handled = 1;
143 irqofs = fls(stat) - 1; 143 irqofs = fls(stat) - 1;
144 handle_IRQ(irq_find_mapping(domain, 144 handle_domain_irq(domain, irqofs + i * 32, regs);
145 irqofs + i * 32), regs);
146 stat &= ~(1 << irqofs); 145 stat &= ~(1 << irqofs);
147 } 146 }
148 } 147 }
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index d0543d90db8d..9746dc24a117 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -30,6 +30,7 @@ config ARM64
30 select GENERIC_STRNCPY_FROM_USER 30 select GENERIC_STRNCPY_FROM_USER
31 select GENERIC_STRNLEN_USER 31 select GENERIC_STRNLEN_USER
32 select GENERIC_TIME_VSYSCALL 32 select GENERIC_TIME_VSYSCALL
33 select HANDLE_DOMAIN_IRQ
33 select HARDIRQS_SW_RESEND 34 select HARDIRQS_SW_RESEND
34 select HAVE_ARCH_AUDITSYSCALL 35 select HAVE_ARCH_AUDITSYSCALL
35 select HAVE_ARCH_JUMP_LABEL 36 select HAVE_ARCH_JUMP_LABEL
diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h
index 0be67821f9ce..e8a3268a891c 100644
--- a/arch/arm64/include/asm/hardirq.h
+++ b/arch/arm64/include/asm/hardirq.h
@@ -47,8 +47,6 @@ static inline void ack_bad_irq(unsigned int irq)
47 irq_err_count++; 47 irq_err_count++;
48} 48}
49 49
50extern void handle_IRQ(unsigned int, struct pt_regs *);
51
52/* 50/*
53 * No arch-specific IRQ flags. 51 * No arch-specific IRQ flags.
54 */ 52 */
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c
index dfa6e3e74fdd..071a6ec13bd8 100644
--- a/arch/arm64/kernel/irq.c
+++ b/arch/arm64/kernel/irq.c
@@ -40,33 +40,6 @@ int arch_show_interrupts(struct seq_file *p, int prec)
40 return 0; 40 return 0;
41} 41}
42 42
43/*
44 * handle_IRQ handles all hardware IRQ's. Decoded IRQs should
45 * not come via this function. Instead, they should provide their
46 * own 'handler'. Used by platform code implementing C-based 1st
47 * level decoding.
48 */
49void handle_IRQ(unsigned int irq, struct pt_regs *regs)
50{
51 struct pt_regs *old_regs = set_irq_regs(regs);
52
53 irq_enter();
54
55 /*
56 * Some hardware gives randomly wrong interrupts. Rather
57 * than crashing, do something sensible.
58 */
59 if (unlikely(irq >= nr_irqs)) {
60 pr_warn_ratelimited("Bad IRQ%u\n", irq);
61 ack_bad_irq(irq);
62 } else {
63 generic_handle_irq(irq);
64 }
65
66 irq_exit();
67 set_irq_regs(old_regs);
68}
69
70void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) 43void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
71{ 44{
72 if (handle_arch_irq) 45 if (handle_arch_irq)
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 88e83368bbf5..e5a693b16da2 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -8,6 +8,7 @@ config OPENRISC
8 select OF 8 select OF
9 select OF_EARLY_FLATTREE 9 select OF_EARLY_FLATTREE
10 select IRQ_DOMAIN 10 select IRQ_DOMAIN
11 select HANDLE_DOMAIN_IRQ
11 select HAVE_MEMBLOCK 12 select HAVE_MEMBLOCK
12 select ARCH_REQUIRE_GPIOLIB 13 select ARCH_REQUIRE_GPIOLIB
13 select HAVE_ARCH_TRACEHOOK 14 select HAVE_ARCH_TRACEHOOK
diff --git a/arch/openrisc/include/asm/irq.h b/arch/openrisc/include/asm/irq.h
index b84634cc95eb..d9eee0a2b7b4 100644
--- a/arch/openrisc/include/asm/irq.h
+++ b/arch/openrisc/include/asm/irq.h
@@ -24,7 +24,6 @@
24 24
25#define NO_IRQ (-1) 25#define NO_IRQ (-1)
26 26
27void handle_IRQ(unsigned int, struct pt_regs *);
28extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); 27extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
29 28
30#endif /* __ASM_OPENRISC_IRQ_H__ */ 29#endif /* __ASM_OPENRISC_IRQ_H__ */
diff --git a/arch/openrisc/kernel/irq.c b/arch/openrisc/kernel/irq.c
index 967eb1430203..35e478a93116 100644
--- a/arch/openrisc/kernel/irq.c
+++ b/arch/openrisc/kernel/irq.c
@@ -48,18 +48,6 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
48 handle_arch_irq = handle_irq; 48 handle_arch_irq = handle_irq;
49} 49}
50 50
51void handle_IRQ(unsigned int irq, struct pt_regs *regs)
52{
53 struct pt_regs *old_regs = set_irq_regs(regs);
54
55 irq_enter();
56
57 generic_handle_irq(irq);
58
59 irq_exit();
60 set_irq_regs(old_regs);
61}
62
63void __irq_entry do_IRQ(struct pt_regs *regs) 51void __irq_entry do_IRQ(struct pt_regs *regs)
64{ 52{
65 handle_arch_irq(regs); 53 handle_arch_irq(regs);
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 78d4ff551590..b21f12f1766d 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -118,3 +118,10 @@ config IRQ_CROSSBAR
118 The primary irqchip invokes the crossbar's callback which inturn allocates 118 The primary irqchip invokes the crossbar's callback which inturn allocates
119 a free irq and configures the IP. Thus the peripheral interrupts are 119 a free irq and configures the IP. Thus the peripheral interrupts are
120 routed to one of the free irqchip interrupt lines. 120 routed to one of the free irqchip interrupt lines.
121
122config KEYSTONE_IRQ
123 tristate "Keystone 2 IRQ controller IP"
124 depends on ARCH_KEYSTONE
125 help
126 Support for Texas Instruments Keystone 2 IRQ controller IP which
127 is part of the Keystone 2 IPC mechanism
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index d0a2613c73bc..173bb5fa2cc9 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_IRQCHIP) += irqchip.o
2 2
3obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o 3obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o
4obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o 4obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o
5obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o
5obj-$(CONFIG_ARCH_MMP) += irq-mmp.o 6obj-$(CONFIG_ARCH_MMP) += irq-mmp.o
6obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o 7obj-$(CONFIG_ARCH_MVEBU) += irq-armada-370-xp.o
7obj-$(CONFIG_ARCH_MXS) += irq-mxs.o 8obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
@@ -34,4 +35,6 @@ obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
34obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o 35obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o
35obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o 36obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o
36obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o 37obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o
37obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o 38obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o \
39 irq-bcm7120-l2.o
40obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 574aba0eba4e..fa75a29a0408 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -393,13 +393,15 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
393 if (!(msimask & BIT(msinr))) 393 if (!(msimask & BIT(msinr)))
394 continue; 394 continue;
395 395
396 irq = irq_find_mapping(armada_370_xp_msi_domain, 396 if (is_chained) {
397 msinr - 16); 397 irq = irq_find_mapping(armada_370_xp_msi_domain,
398 398 msinr - 16);
399 if (is_chained)
400 generic_handle_irq(irq); 399 generic_handle_irq(irq);
401 else 400 } else {
402 handle_IRQ(irq, regs); 401 irq = msinr - 16;
402 handle_domain_irq(armada_370_xp_msi_domain,
403 irq, regs);
404 }
403 } 405 }
404} 406}
405#else 407#else
@@ -444,9 +446,8 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
444 break; 446 break;
445 447
446 if (irqnr > 1) { 448 if (irqnr > 1) {
447 irqnr = irq_find_mapping(armada_370_xp_mpic_domain, 449 handle_domain_irq(armada_370_xp_mpic_domain,
448 irqnr); 450 irqnr, regs);
449 handle_IRQ(irqnr, regs);
450 continue; 451 continue;
451 } 452 }
452 453
diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c
index a82869e9fb26..9a2cf3c1a3a5 100644
--- a/drivers/irqchip/irq-atmel-aic.c
+++ b/drivers/irqchip/irq-atmel-aic.c
@@ -68,12 +68,10 @@ aic_handle(struct pt_regs *regs)
68 irqnr = irq_reg_readl(gc->reg_base + AT91_AIC_IVR); 68 irqnr = irq_reg_readl(gc->reg_base + AT91_AIC_IVR);
69 irqstat = irq_reg_readl(gc->reg_base + AT91_AIC_ISR); 69 irqstat = irq_reg_readl(gc->reg_base + AT91_AIC_ISR);
70 70
71 irqnr = irq_find_mapping(aic_domain, irqnr);
72
73 if (!irqstat) 71 if (!irqstat)
74 irq_reg_writel(0, gc->reg_base + AT91_AIC_EOICR); 72 irq_reg_writel(0, gc->reg_base + AT91_AIC_EOICR);
75 else 73 else
76 handle_IRQ(irqnr, regs); 74 handle_domain_irq(aic_domain, irqnr, regs);
77} 75}
78 76
79static int aic_retrigger(struct irq_data *d) 77static int aic_retrigger(struct irq_data *d)
diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c
index edb227081524..a11aae8fb006 100644
--- a/drivers/irqchip/irq-atmel-aic5.c
+++ b/drivers/irqchip/irq-atmel-aic5.c
@@ -78,12 +78,10 @@ aic5_handle(struct pt_regs *regs)
78 irqnr = irq_reg_readl(gc->reg_base + AT91_AIC5_IVR); 78 irqnr = irq_reg_readl(gc->reg_base + AT91_AIC5_IVR);
79 irqstat = irq_reg_readl(gc->reg_base + AT91_AIC5_ISR); 79 irqstat = irq_reg_readl(gc->reg_base + AT91_AIC5_ISR);
80 80
81 irqnr = irq_find_mapping(aic5_domain, irqnr);
82
83 if (!irqstat) 81 if (!irqstat)
84 irq_reg_writel(0, gc->reg_base + AT91_AIC5_EOICR); 82 irq_reg_writel(0, gc->reg_base + AT91_AIC5_EOICR);
85 else 83 else
86 handle_IRQ(irqnr, regs); 84 handle_domain_irq(aic5_domain, irqnr, regs);
87} 85}
88 86
89static void aic5_mask(struct irq_data *d) 87static void aic5_mask(struct irq_data *d)
@@ -297,6 +295,7 @@ static void __init sama5d3_aic_irq_fixup(struct device_node *root)
297 295
298static const struct of_device_id __initdata aic5_irq_fixups[] = { 296static const struct of_device_id __initdata aic5_irq_fixups[] = {
299 { .compatible = "atmel,sama5d3", .data = sama5d3_aic_irq_fixup }, 297 { .compatible = "atmel,sama5d3", .data = sama5d3_aic_irq_fixup },
298 { .compatible = "atmel,sama5d4", .data = sama5d3_aic_irq_fixup },
300 { /* sentinel */ }, 299 { /* sentinel */ },
301}; 300};
302 301
@@ -343,7 +342,7 @@ static int __init aic5_of_init(struct device_node *node,
343 return 0; 342 return 0;
344} 343}
345 344
346#define NR_SAMA5D3_IRQS 50 345#define NR_SAMA5D3_IRQS 48
347 346
348static int __init sama5d3_aic5_of_init(struct device_node *node, 347static int __init sama5d3_aic5_of_init(struct device_node *node,
349 struct device_node *parent) 348 struct device_node *parent)
@@ -351,3 +350,12 @@ static int __init sama5d3_aic5_of_init(struct device_node *node,
351 return aic5_of_init(node, parent, NR_SAMA5D3_IRQS); 350 return aic5_of_init(node, parent, NR_SAMA5D3_IRQS);
352} 351}
353IRQCHIP_DECLARE(sama5d3_aic5, "atmel,sama5d3-aic", sama5d3_aic5_of_init); 352IRQCHIP_DECLARE(sama5d3_aic5, "atmel,sama5d3-aic", sama5d3_aic5_of_init);
353
354#define NR_SAMA5D4_IRQS 68
355
356static int __init sama5d4_aic5_of_init(struct device_node *node,
357 struct device_node *parent)
358{
359 return aic5_of_init(node, parent, NR_SAMA5D4_IRQS);
360}
361IRQCHIP_DECLARE(sama5d4_aic5, "atmel,sama5d4-aic", sama5d4_aic5_of_init);
diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c
new file mode 100644
index 000000000000..b9f4fb808e49
--- /dev/null
+++ b/drivers/irqchip/irq-bcm7120-l2.c
@@ -0,0 +1,219 @@
1/*
2 * Broadcom BCM7120 style Level 2 interrupt controller driver
3 *
4 * Copyright (C) 2014 Broadcom Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
13#include <linux/init.h>
14#include <linux/slab.h>
15#include <linux/module.h>
16#include <linux/platform_device.h>
17#include <linux/of.h>
18#include <linux/of_irq.h>
19#include <linux/of_address.h>
20#include <linux/of_platform.h>
21#include <linux/interrupt.h>
22#include <linux/irq.h>
23#include <linux/io.h>
24#include <linux/irqdomain.h>
25#include <linux/reboot.h>
26#include <linux/irqchip/chained_irq.h>
27
28#include "irqchip.h"
29
30#include <asm/mach/irq.h>
31
32/* Register offset in the L2 interrupt controller */
33#define IRQEN 0x00
34#define IRQSTAT 0x04
35
36struct bcm7120_l2_intc_data {
37 void __iomem *base;
38 struct irq_domain *domain;
39 bool can_wake;
40 u32 irq_fwd_mask;
41 u32 irq_map_mask;
42 u32 saved_mask;
43};
44
45static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
46{
47 struct bcm7120_l2_intc_data *b = irq_desc_get_handler_data(desc);
48 struct irq_chip *chip = irq_desc_get_chip(desc);
49 u32 status;
50
51 chained_irq_enter(chip, desc);
52
53 status = __raw_readl(b->base + IRQSTAT);
54
55 if (status == 0) {
56 do_bad_IRQ(irq, desc);
57 goto out;
58 }
59
60 do {
61 irq = ffs(status) - 1;
62 status &= ~(1 << irq);
63 generic_handle_irq(irq_find_mapping(b->domain, irq));
64 } while (status);
65
66out:
67 chained_irq_exit(chip, desc);
68}
69
70static void bcm7120_l2_intc_suspend(struct irq_data *d)
71{
72 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
73 struct bcm7120_l2_intc_data *b = gc->private;
74 u32 reg;
75
76 irq_gc_lock(gc);
77 /* Save the current mask and the interrupt forward mask */
78 b->saved_mask = __raw_readl(b->base) | b->irq_fwd_mask;
79 if (b->can_wake) {
80 reg = b->saved_mask | gc->wake_active;
81 __raw_writel(reg, b->base);
82 }
83 irq_gc_unlock(gc);
84}
85
86static void bcm7120_l2_intc_resume(struct irq_data *d)
87{
88 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
89 struct bcm7120_l2_intc_data *b = gc->private;
90
91 /* Restore the saved mask */
92 irq_gc_lock(gc);
93 __raw_writel(b->saved_mask, b->base);
94 irq_gc_unlock(gc);
95}
96
97static int bcm7120_l2_intc_init_one(struct device_node *dn,
98 struct bcm7120_l2_intc_data *data,
99 int irq, const __be32 *map_mask)
100{
101 int parent_irq;
102
103 parent_irq = irq_of_parse_and_map(dn, irq);
104 if (parent_irq < 0) {
105 pr_err("failed to map interrupt %d\n", irq);
106 return parent_irq;
107 }
108
109 data->irq_map_mask |= be32_to_cpup(map_mask + irq);
110
111 irq_set_handler_data(parent_irq, data);
112 irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle);
113
114 return 0;
115}
116
117int __init bcm7120_l2_intc_of_init(struct device_node *dn,
118 struct device_node *parent)
119{
120 unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
121 struct bcm7120_l2_intc_data *data;
122 struct irq_chip_generic *gc;
123 struct irq_chip_type *ct;
124 const __be32 *map_mask;
125 int num_parent_irqs;
126 int ret = 0, len, irq;
127
128 data = kzalloc(sizeof(*data), GFP_KERNEL);
129 if (!data)
130 return -ENOMEM;
131
132 data->base = of_iomap(dn, 0);
133 if (!data->base) {
134 pr_err("failed to remap intc L2 registers\n");
135 ret = -ENOMEM;
136 goto out_free;
137 }
138
139 if (of_property_read_u32(dn, "brcm,int-fwd-mask", &data->irq_fwd_mask))
140 data->irq_fwd_mask = 0;
141
142 /* Enable all interrupt specified in the interrupt forward mask and have
143 * the other disabled
144 */
145 __raw_writel(data->irq_fwd_mask, data->base + IRQEN);
146
147 num_parent_irqs = of_irq_count(dn);
148 if (num_parent_irqs <= 0) {
149 pr_err("invalid number of parent interrupts\n");
150 ret = -ENOMEM;
151 goto out_unmap;
152 }
153
154 map_mask = of_get_property(dn, "brcm,int-map-mask", &len);
155 if (!map_mask || (len != (sizeof(*map_mask) * num_parent_irqs))) {
156 pr_err("invalid brcm,int-map-mask property\n");
157 ret = -EINVAL;
158 goto out_unmap;
159 }
160
161 for (irq = 0; irq < num_parent_irqs; irq++) {
162 ret = bcm7120_l2_intc_init_one(dn, data, irq, map_mask);
163 if (ret)
164 goto out_unmap;
165 }
166
167 data->domain = irq_domain_add_linear(dn, 32,
168 &irq_generic_chip_ops, NULL);
169 if (!data->domain) {
170 ret = -ENOMEM;
171 goto out_unmap;
172 }
173
174 ret = irq_alloc_domain_generic_chips(data->domain, 32, 1,
175 dn->full_name, handle_level_irq, clr, 0,
176 IRQ_GC_INIT_MASK_CACHE);
177 if (ret) {
178 pr_err("failed to allocate generic irq chip\n");
179 goto out_free_domain;
180 }
181
182 gc = irq_get_domain_generic_chip(data->domain, 0);
183 gc->unused = 0xfffffff & ~data->irq_map_mask;
184 gc->reg_base = data->base;
185 gc->private = data;
186 ct = gc->chip_types;
187
188 ct->regs.mask = IRQEN;
189 ct->chip.irq_mask = irq_gc_mask_clr_bit;
190 ct->chip.irq_unmask = irq_gc_mask_set_bit;
191 ct->chip.irq_ack = irq_gc_noop;
192 ct->chip.irq_suspend = bcm7120_l2_intc_suspend;
193 ct->chip.irq_resume = bcm7120_l2_intc_resume;
194
195 if (of_property_read_bool(dn, "brcm,irq-can-wake")) {
196 data->can_wake = true;
197 /* This IRQ chip can wake the system, set all relevant child
198 * interupts in wake_enabled mask
199 */
200 gc->wake_enabled = 0xffffffff;
201 gc->wake_enabled &= ~gc->unused;
202 ct->chip.irq_set_wake = irq_gc_set_wake;
203 }
204
205 pr_info("registered BCM7120 L2 intc (mem: 0x%p, parent IRQ(s): %d)\n",
206 data->base, num_parent_irqs);
207
208 return 0;
209
210out_free_domain:
211 irq_domain_remove(data->domain);
212out_unmap:
213 iounmap(data->base);
214out_free:
215 kfree(data);
216 return ret;
217}
218IRQCHIP_DECLARE(brcmstb_l2_intc, "brcm,bcm7120-l2-intc",
219 bcm7120_l2_intc_of_init);
diff --git a/drivers/irqchip/irq-clps711x.c b/drivers/irqchip/irq-clps711x.c
index 33340dc97d1d..33127f131d78 100644
--- a/drivers/irqchip/irq-clps711x.c
+++ b/drivers/irqchip/irq-clps711x.c
@@ -76,24 +76,20 @@ static struct {
76 76
77static asmlinkage void __exception_irq_entry clps711x_irqh(struct pt_regs *regs) 77static asmlinkage void __exception_irq_entry clps711x_irqh(struct pt_regs *regs)
78{ 78{
79 u32 irqnr, irqstat; 79 u32 irqstat;
80 80
81 do { 81 do {
82 irqstat = readw_relaxed(clps711x_intc->intmr[0]) & 82 irqstat = readw_relaxed(clps711x_intc->intmr[0]) &
83 readw_relaxed(clps711x_intc->intsr[0]); 83 readw_relaxed(clps711x_intc->intsr[0]);
84 if (irqstat) { 84 if (irqstat)
85 irqnr = irq_find_mapping(clps711x_intc->domain, 85 handle_domain_irq(clps711x_intc->domain,
86 fls(irqstat) - 1); 86 fls(irqstat) - 1, regs);
87 handle_IRQ(irqnr, regs);
88 }
89 87
90 irqstat = readw_relaxed(clps711x_intc->intmr[1]) & 88 irqstat = readw_relaxed(clps711x_intc->intmr[1]) &
91 readw_relaxed(clps711x_intc->intsr[1]); 89 readw_relaxed(clps711x_intc->intsr[1]);
92 if (irqstat) { 90 if (irqstat)
93 irqnr = irq_find_mapping(clps711x_intc->domain, 91 handle_domain_irq(clps711x_intc->domain,
94 fls(irqstat) - 1 + 16); 92 fls(irqstat) - 1 + 16, regs);
95 handle_IRQ(irqnr, regs);
96 }
97 } while (irqstat); 93 } while (irqstat);
98} 94}
99 95
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index 60ac704d2090..61541ff24397 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -74,20 +74,22 @@ void __init gic_dist_config(void __iomem *base, int gic_irqs,
74 * Set all global interrupts to be level triggered, active low. 74 * Set all global interrupts to be level triggered, active low.
75 */ 75 */
76 for (i = 32; i < gic_irqs; i += 16) 76 for (i = 32; i < gic_irqs; i += 16)
77 writel_relaxed(0, base + GIC_DIST_CONFIG + i / 4); 77 writel_relaxed(GICD_INT_ACTLOW_LVLTRIG,
78 base + GIC_DIST_CONFIG + i / 4);
78 79
79 /* 80 /*
80 * Set priority on all global interrupts. 81 * Set priority on all global interrupts.
81 */ 82 */
82 for (i = 32; i < gic_irqs; i += 4) 83 for (i = 32; i < gic_irqs; i += 4)
83 writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i); 84 writel_relaxed(GICD_INT_DEF_PRI_X4, base + GIC_DIST_PRI + i);
84 85
85 /* 86 /*
86 * Disable all interrupts. Leave the PPI and SGIs alone 87 * Disable all interrupts. Leave the PPI and SGIs alone
87 * as they are enabled by redistributor registers. 88 * as they are enabled by redistributor registers.
88 */ 89 */
89 for (i = 32; i < gic_irqs; i += 32) 90 for (i = 32; i < gic_irqs; i += 32)
90 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i / 8); 91 writel_relaxed(GICD_INT_EN_CLR_X32,
92 base + GIC_DIST_ENABLE_CLEAR + i / 8);
91 93
92 if (sync_access) 94 if (sync_access)
93 sync_access(); 95 sync_access();
@@ -101,14 +103,15 @@ void gic_cpu_config(void __iomem *base, void (*sync_access)(void))
101 * Deal with the banked PPI and SGI interrupts - disable all 103 * Deal with the banked PPI and SGI interrupts - disable all
102 * PPI interrupts, ensure all SGI interrupts are enabled. 104 * PPI interrupts, ensure all SGI interrupts are enabled.
103 */ 105 */
104 writel_relaxed(0xffff0000, base + GIC_DIST_ENABLE_CLEAR); 106 writel_relaxed(GICD_INT_EN_CLR_PPI, base + GIC_DIST_ENABLE_CLEAR);
105 writel_relaxed(0x0000ffff, base + GIC_DIST_ENABLE_SET); 107 writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET);
106 108
107 /* 109 /*
108 * Set priority on PPI and SGI interrupts 110 * Set priority on PPI and SGI interrupts
109 */ 111 */
110 for (i = 0; i < 32; i += 4) 112 for (i = 0; i < 32; i += 4)
111 writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4); 113 writel_relaxed(GICD_INT_DEF_PRI_X4,
114 base + GIC_DIST_PRI + i * 4 / 4);
112 115
113 if (sync_access) 116 if (sync_access)
114 sync_access(); 117 sync_access();
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index a0698b4f0303..aa17ae805a70 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -16,6 +16,7 @@
16 */ 16 */
17 17
18#include <linux/cpu.h> 18#include <linux/cpu.h>
19#include <linux/cpu_pm.h>
19#include <linux/delay.h> 20#include <linux/delay.h>
20#include <linux/interrupt.h> 21#include <linux/interrupt.h>
21#include <linux/of.h> 22#include <linux/of.h>
@@ -155,7 +156,7 @@ static void gic_enable_sre(void)
155 pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n"); 156 pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n");
156} 157}
157 158
158static void gic_enable_redist(void) 159static void gic_enable_redist(bool enable)
159{ 160{
160 void __iomem *rbase; 161 void __iomem *rbase;
161 u32 count = 1000000; /* 1s! */ 162 u32 count = 1000000; /* 1s! */
@@ -163,20 +164,30 @@ static void gic_enable_redist(void)
163 164
164 rbase = gic_data_rdist_rd_base(); 165 rbase = gic_data_rdist_rd_base();
165 166
166 /* Wake up this CPU redistributor */
167 val = readl_relaxed(rbase + GICR_WAKER); 167 val = readl_relaxed(rbase + GICR_WAKER);
168 val &= ~GICR_WAKER_ProcessorSleep; 168 if (enable)
169 /* Wake up this CPU redistributor */
170 val &= ~GICR_WAKER_ProcessorSleep;
171 else
172 val |= GICR_WAKER_ProcessorSleep;
169 writel_relaxed(val, rbase + GICR_WAKER); 173 writel_relaxed(val, rbase + GICR_WAKER);
170 174
171 while (readl_relaxed(rbase + GICR_WAKER) & GICR_WAKER_ChildrenAsleep) { 175 if (!enable) { /* Check that GICR_WAKER is writeable */
172 count--; 176 val = readl_relaxed(rbase + GICR_WAKER);
173 if (!count) { 177 if (!(val & GICR_WAKER_ProcessorSleep))
174 pr_err_ratelimited("redist didn't wake up...\n"); 178 return; /* No PM support in this redistributor */
175 return; 179 }
176 } 180
181 while (count--) {
182 val = readl_relaxed(rbase + GICR_WAKER);
183 if (enable ^ (val & GICR_WAKER_ChildrenAsleep))
184 break;
177 cpu_relax(); 185 cpu_relax();
178 udelay(1); 186 udelay(1);
179 }; 187 };
188 if (!count)
189 pr_err_ratelimited("redistributor failed to %s...\n",
190 enable ? "wakeup" : "sleep");
180} 191}
181 192
182/* 193/*
@@ -261,14 +272,13 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
261 irqnr = gic_read_iar(); 272 irqnr = gic_read_iar();
262 273
263 if (likely(irqnr > 15 && irqnr < 1020)) { 274 if (likely(irqnr > 15 && irqnr < 1020)) {
264 u64 irq = irq_find_mapping(gic_data.domain, irqnr); 275 int err;
265 if (likely(irq)) { 276 err = handle_domain_irq(gic_data.domain, irqnr, regs);
266 handle_IRQ(irq, regs); 277 if (err) {
267 continue; 278 WARN_ONCE(true, "Unexpected SPI received!\n");
279 gic_write_eoir(irqnr);
268 } 280 }
269 281 continue;
270 WARN_ONCE(true, "Unexpected SPI received!\n");
271 gic_write_eoir(irqnr);
272 } 282 }
273 if (irqnr < 16) { 283 if (irqnr < 16) {
274 gic_write_eoir(irqnr); 284 gic_write_eoir(irqnr);
@@ -360,6 +370,21 @@ static int gic_populate_rdist(void)
360 return -ENODEV; 370 return -ENODEV;
361} 371}
362 372
373static void gic_cpu_sys_reg_init(void)
374{
375 /* Enable system registers */
376 gic_enable_sre();
377
378 /* Set priority mask register */
379 gic_write_pmr(DEFAULT_PMR_VALUE);
380
381 /* EOI deactivates interrupt too (mode 0) */
382 gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir);
383
384 /* ... and let's hit the road... */
385 gic_write_grpen1(1);
386}
387
363static void gic_cpu_init(void) 388static void gic_cpu_init(void)
364{ 389{
365 void __iomem *rbase; 390 void __iomem *rbase;
@@ -368,23 +393,14 @@ static void gic_cpu_init(void)
368 if (gic_populate_rdist()) 393 if (gic_populate_rdist())
369 return; 394 return;
370 395
371 gic_enable_redist(); 396 gic_enable_redist(true);
372 397
373 rbase = gic_data_rdist_sgi_base(); 398 rbase = gic_data_rdist_sgi_base();
374 399
375 gic_cpu_config(rbase, gic_redist_wait_for_rwp); 400 gic_cpu_config(rbase, gic_redist_wait_for_rwp);
376 401
377 /* Enable system registers */ 402 /* initialise system registers */
378 gic_enable_sre(); 403 gic_cpu_sys_reg_init();
379
380 /* Set priority mask register */
381 gic_write_pmr(DEFAULT_PMR_VALUE);
382
383 /* EOI deactivates interrupt too (mode 0) */
384 gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir);
385
386 /* ... and let's hit the road... */
387 gic_write_grpen1(1);
388} 404}
389 405
390#ifdef CONFIG_SMP 406#ifdef CONFIG_SMP
@@ -533,6 +549,33 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
533#define gic_smp_init() do { } while(0) 549#define gic_smp_init() do { } while(0)
534#endif 550#endif
535 551
552#ifdef CONFIG_CPU_PM
553static int gic_cpu_pm_notifier(struct notifier_block *self,
554 unsigned long cmd, void *v)
555{
556 if (cmd == CPU_PM_EXIT) {
557 gic_enable_redist(true);
558 gic_cpu_sys_reg_init();
559 } else if (cmd == CPU_PM_ENTER) {
560 gic_write_grpen1(0);
561 gic_enable_redist(false);
562 }
563 return NOTIFY_OK;
564}
565
566static struct notifier_block gic_cpu_pm_notifier_block = {
567 .notifier_call = gic_cpu_pm_notifier,
568};
569
570static void gic_cpu_pm_init(void)
571{
572 cpu_pm_register_notifier(&gic_cpu_pm_notifier_block);
573}
574
575#else
576static inline void gic_cpu_pm_init(void) { }
577#endif /* CONFIG_CPU_PM */
578
536static struct irq_chip gic_chip = { 579static struct irq_chip gic_chip = {
537 .name = "GICv3", 580 .name = "GICv3",
538 .irq_mask = gic_mask_irq, 581 .irq_mask = gic_mask_irq,
@@ -672,6 +715,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
672 gic_smp_init(); 715 gic_smp_init();
673 gic_dist_init(); 716 gic_dist_init();
674 gic_cpu_init(); 717 gic_cpu_init();
718 gic_cpu_pm_init();
675 719
676 return 0; 720 return 0;
677 721
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index dda6dbc23565..f0a4800a15b0 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -270,8 +270,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
270 irqnr = irqstat & GICC_IAR_INT_ID_MASK; 270 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
271 271
272 if (likely(irqnr > 15 && irqnr < 1021)) { 272 if (likely(irqnr > 15 && irqnr < 1021)) {
273 irqnr = irq_find_mapping(gic->domain, irqnr); 273 handle_domain_irq(gic->domain, irqnr, regs);
274 handle_IRQ(irqnr, regs);
275 continue; 274 continue;
276 } 275 }
277 if (irqnr < 16) { 276 if (irqnr < 16) {
@@ -298,8 +297,8 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
298 status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK); 297 status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK);
299 raw_spin_unlock(&irq_controller_lock); 298 raw_spin_unlock(&irq_controller_lock);
300 299
301 gic_irq = (status & 0x3ff); 300 gic_irq = (status & GICC_IAR_INT_ID_MASK);
302 if (gic_irq == 1023) 301 if (gic_irq == GICC_INT_SPURIOUS)
303 goto out; 302 goto out;
304 303
305 cascade_irq = irq_find_mapping(chip_data->domain, gic_irq); 304 cascade_irq = irq_find_mapping(chip_data->domain, gic_irq);
@@ -353,6 +352,21 @@ static u8 gic_get_cpumask(struct gic_chip_data *gic)
353 return mask; 352 return mask;
354} 353}
355 354
355static void gic_cpu_if_up(void)
356{
357 void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]);
358 u32 bypass = 0;
359
360 /*
361 * Preserve bypass disable bits to be written back later
362 */
363 bypass = readl(cpu_base + GIC_CPU_CTRL);
364 bypass &= GICC_DIS_BYPASS_MASK;
365
366 writel_relaxed(bypass | GICC_ENABLE, cpu_base + GIC_CPU_CTRL);
367}
368
369
356static void __init gic_dist_init(struct gic_chip_data *gic) 370static void __init gic_dist_init(struct gic_chip_data *gic)
357{ 371{
358 unsigned int i; 372 unsigned int i;
@@ -360,7 +374,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
360 unsigned int gic_irqs = gic->gic_irqs; 374 unsigned int gic_irqs = gic->gic_irqs;
361 void __iomem *base = gic_data_dist_base(gic); 375 void __iomem *base = gic_data_dist_base(gic);
362 376
363 writel_relaxed(0, base + GIC_DIST_CTRL); 377 writel_relaxed(GICD_DISABLE, base + GIC_DIST_CTRL);
364 378
365 /* 379 /*
366 * Set all global interrupts to this CPU only. 380 * Set all global interrupts to this CPU only.
@@ -373,7 +387,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
373 387
374 gic_dist_config(base, gic_irqs, NULL); 388 gic_dist_config(base, gic_irqs, NULL);
375 389
376 writel_relaxed(1, base + GIC_DIST_CTRL); 390 writel_relaxed(GICD_ENABLE, base + GIC_DIST_CTRL);
377} 391}
378 392
379static void gic_cpu_init(struct gic_chip_data *gic) 393static void gic_cpu_init(struct gic_chip_data *gic)
@@ -400,14 +414,18 @@ static void gic_cpu_init(struct gic_chip_data *gic)
400 414
401 gic_cpu_config(dist_base, NULL); 415 gic_cpu_config(dist_base, NULL);
402 416
403 writel_relaxed(0xf0, base + GIC_CPU_PRIMASK); 417 writel_relaxed(GICC_INT_PRI_THRESHOLD, base + GIC_CPU_PRIMASK);
404 writel_relaxed(1, base + GIC_CPU_CTRL); 418 gic_cpu_if_up();
405} 419}
406 420
407void gic_cpu_if_down(void) 421void gic_cpu_if_down(void)
408{ 422{
409 void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]); 423 void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]);
410 writel_relaxed(0, cpu_base + GIC_CPU_CTRL); 424 u32 val = 0;
425
426 val = readl(cpu_base + GIC_CPU_CTRL);
427 val &= ~GICC_ENABLE;
428 writel_relaxed(val, cpu_base + GIC_CPU_CTRL);
411} 429}
412 430
413#ifdef CONFIG_CPU_PM 431#ifdef CONFIG_CPU_PM
@@ -467,14 +485,14 @@ static void gic_dist_restore(unsigned int gic_nr)
467 if (!dist_base) 485 if (!dist_base)
468 return; 486 return;
469 487
470 writel_relaxed(0, dist_base + GIC_DIST_CTRL); 488 writel_relaxed(GICD_DISABLE, dist_base + GIC_DIST_CTRL);
471 489
472 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++) 490 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
473 writel_relaxed(gic_data[gic_nr].saved_spi_conf[i], 491 writel_relaxed(gic_data[gic_nr].saved_spi_conf[i],
474 dist_base + GIC_DIST_CONFIG + i * 4); 492 dist_base + GIC_DIST_CONFIG + i * 4);
475 493
476 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++) 494 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
477 writel_relaxed(0xa0a0a0a0, 495 writel_relaxed(GICD_INT_DEF_PRI_X4,
478 dist_base + GIC_DIST_PRI + i * 4); 496 dist_base + GIC_DIST_PRI + i * 4);
479 497
480 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++) 498 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
@@ -485,7 +503,7 @@ static void gic_dist_restore(unsigned int gic_nr)
485 writel_relaxed(gic_data[gic_nr].saved_spi_enable[i], 503 writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
486 dist_base + GIC_DIST_ENABLE_SET + i * 4); 504 dist_base + GIC_DIST_ENABLE_SET + i * 4);
487 505
488 writel_relaxed(1, dist_base + GIC_DIST_CTRL); 506 writel_relaxed(GICD_ENABLE, dist_base + GIC_DIST_CTRL);
489} 507}
490 508
491static void gic_cpu_save(unsigned int gic_nr) 509static void gic_cpu_save(unsigned int gic_nr)
@@ -539,10 +557,11 @@ static void gic_cpu_restore(unsigned int gic_nr)
539 writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4); 557 writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
540 558
541 for (i = 0; i < DIV_ROUND_UP(32, 4); i++) 559 for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
542 writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4); 560 writel_relaxed(GICD_INT_DEF_PRI_X4,
561 dist_base + GIC_DIST_PRI + i * 4);
543 562
544 writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK); 563 writel_relaxed(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK);
545 writel_relaxed(1, cpu_base + GIC_CPU_CTRL); 564 gic_cpu_if_up();
546} 565}
547 566
548static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v) 567static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c
new file mode 100644
index 000000000000..9c8f833522e6
--- /dev/null
+++ b/drivers/irqchip/irq-hip04.c
@@ -0,0 +1,424 @@
1/*
2 * Hisilicon HiP04 INTC
3 *
4 * Copyright (C) 2002-2014 ARM Limited.
5 * Copyright (c) 2013-2014 Hisilicon Ltd.
6 * Copyright (c) 2013-2014 Linaro Ltd.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 * Interrupt architecture for the HIP04 INTC:
13 *
14 * o There is one Interrupt Distributor, which receives interrupts
15 * from system devices and sends them to the Interrupt Controllers.
16 *
17 * o There is one CPU Interface per CPU, which sends interrupts sent
18 * by the Distributor, and interrupts generated locally, to the
19 * associated CPU. The base address of the CPU interface is usually
20 * aliased so that the same address points to different chips depending
21 * on the CPU it is accessed from.
22 *
23 * Note that IRQs 0-31 are special - they are local to each CPU.
24 * As such, the enable set/clear, pending set/clear and active bit
25 * registers are banked per-cpu for these sources.
26 */
27
28#include <linux/init.h>
29#include <linux/kernel.h>
30#include <linux/err.h>
31#include <linux/module.h>
32#include <linux/list.h>
33#include <linux/smp.h>
34#include <linux/cpu.h>
35#include <linux/cpu_pm.h>
36#include <linux/cpumask.h>
37#include <linux/io.h>
38#include <linux/of.h>
39#include <linux/of_address.h>
40#include <linux/of_irq.h>
41#include <linux/irqdomain.h>
42#include <linux/interrupt.h>
43#include <linux/slab.h>
44#include <linux/irqchip/arm-gic.h>
45
46#include <asm/irq.h>
47#include <asm/exception.h>
48#include <asm/smp_plat.h>
49
50#include "irq-gic-common.h"
51#include "irqchip.h"
52
53#define HIP04_MAX_IRQS 510
54
55struct hip04_irq_data {
56 void __iomem *dist_base;
57 void __iomem *cpu_base;
58 struct irq_domain *domain;
59 unsigned int nr_irqs;
60};
61
62static DEFINE_RAW_SPINLOCK(irq_controller_lock);
63
64/*
65 * The GIC mapping of CPU interfaces does not necessarily match
66 * the logical CPU numbering. Let's use a mapping as returned
67 * by the GIC itself.
68 */
69#define NR_HIP04_CPU_IF 16
70static u16 hip04_cpu_map[NR_HIP04_CPU_IF] __read_mostly;
71
72static struct hip04_irq_data hip04_data __read_mostly;
73
74static inline void __iomem *hip04_dist_base(struct irq_data *d)
75{
76 struct hip04_irq_data *hip04_data = irq_data_get_irq_chip_data(d);
77 return hip04_data->dist_base;
78}
79
80static inline void __iomem *hip04_cpu_base(struct irq_data *d)
81{
82 struct hip04_irq_data *hip04_data = irq_data_get_irq_chip_data(d);
83 return hip04_data->cpu_base;
84}
85
86static inline unsigned int hip04_irq(struct irq_data *d)
87{
88 return d->hwirq;
89}
90
91/*
92 * Routines to acknowledge, disable and enable interrupts
93 */
94static void hip04_mask_irq(struct irq_data *d)
95{
96 u32 mask = 1 << (hip04_irq(d) % 32);
97
98 raw_spin_lock(&irq_controller_lock);
99 writel_relaxed(mask, hip04_dist_base(d) + GIC_DIST_ENABLE_CLEAR +
100 (hip04_irq(d) / 32) * 4);
101 raw_spin_unlock(&irq_controller_lock);
102}
103
104static void hip04_unmask_irq(struct irq_data *d)
105{
106 u32 mask = 1 << (hip04_irq(d) % 32);
107
108 raw_spin_lock(&irq_controller_lock);
109 writel_relaxed(mask, hip04_dist_base(d) + GIC_DIST_ENABLE_SET +
110 (hip04_irq(d) / 32) * 4);
111 raw_spin_unlock(&irq_controller_lock);
112}
113
114static void hip04_eoi_irq(struct irq_data *d)
115{
116 writel_relaxed(hip04_irq(d), hip04_cpu_base(d) + GIC_CPU_EOI);
117}
118
119static int hip04_irq_set_type(struct irq_data *d, unsigned int type)
120{
121 void __iomem *base = hip04_dist_base(d);
122 unsigned int irq = hip04_irq(d);
123
124 /* Interrupt configuration for SGIs can't be changed */
125 if (irq < 16)
126 return -EINVAL;
127
128 if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
129 return -EINVAL;
130
131 raw_spin_lock(&irq_controller_lock);
132
133 gic_configure_irq(irq, type, base, NULL);
134
135 raw_spin_unlock(&irq_controller_lock);
136
137 return 0;
138}
139
140#ifdef CONFIG_SMP
141static int hip04_irq_set_affinity(struct irq_data *d,
142 const struct cpumask *mask_val,
143 bool force)
144{
145 void __iomem *reg;
146 unsigned int cpu, shift = (hip04_irq(d) % 2) * 16;
147 u32 val, mask, bit;
148
149 if (!force)
150 cpu = cpumask_any_and(mask_val, cpu_online_mask);
151 else
152 cpu = cpumask_first(mask_val);
153
154 if (cpu >= NR_HIP04_CPU_IF || cpu >= nr_cpu_ids)
155 return -EINVAL;
156
157 raw_spin_lock(&irq_controller_lock);
158 reg = hip04_dist_base(d) + GIC_DIST_TARGET + ((hip04_irq(d) * 2) & ~3);
159 mask = 0xffff << shift;
160 bit = hip04_cpu_map[cpu] << shift;
161 val = readl_relaxed(reg) & ~mask;
162 writel_relaxed(val | bit, reg);
163 raw_spin_unlock(&irq_controller_lock);
164
165 return IRQ_SET_MASK_OK;
166}
167#endif
168
169static void __exception_irq_entry hip04_handle_irq(struct pt_regs *regs)
170{
171 u32 irqstat, irqnr;
172 void __iomem *cpu_base = hip04_data.cpu_base;
173
174 do {
175 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
176 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
177
178 if (likely(irqnr > 15 && irqnr <= HIP04_MAX_IRQS)) {
179 irqnr = irq_find_mapping(hip04_data.domain, irqnr);
180 handle_IRQ(irqnr, regs);
181 continue;
182 }
183 if (irqnr < 16) {
184 writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
185#ifdef CONFIG_SMP
186 handle_IPI(irqnr, regs);
187#endif
188 continue;
189 }
190 break;
191 } while (1);
192}
193
194static struct irq_chip hip04_irq_chip = {
195 .name = "HIP04 INTC",
196 .irq_mask = hip04_mask_irq,
197 .irq_unmask = hip04_unmask_irq,
198 .irq_eoi = hip04_eoi_irq,
199 .irq_set_type = hip04_irq_set_type,
200#ifdef CONFIG_SMP
201 .irq_set_affinity = hip04_irq_set_affinity,
202#endif
203};
204
205static u16 hip04_get_cpumask(struct hip04_irq_data *intc)
206{
207 void __iomem *base = intc->dist_base;
208 u32 mask, i;
209
210 for (i = mask = 0; i < 32; i += 2) {
211 mask = readl_relaxed(base + GIC_DIST_TARGET + i * 2);
212 mask |= mask >> 16;
213 if (mask)
214 break;
215 }
216
217 if (!mask)
218 pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");
219
220 return mask;
221}
222
223static void __init hip04_irq_dist_init(struct hip04_irq_data *intc)
224{
225 unsigned int i;
226 u32 cpumask;
227 unsigned int nr_irqs = intc->nr_irqs;
228 void __iomem *base = intc->dist_base;
229
230 writel_relaxed(0, base + GIC_DIST_CTRL);
231
232 /*
233 * Set all global interrupts to this CPU only.
234 */
235 cpumask = hip04_get_cpumask(intc);
236 cpumask |= cpumask << 16;
237 for (i = 32; i < nr_irqs; i += 2)
238 writel_relaxed(cpumask, base + GIC_DIST_TARGET + ((i * 2) & ~3));
239
240 gic_dist_config(base, nr_irqs, NULL);
241
242 writel_relaxed(1, base + GIC_DIST_CTRL);
243}
244
245static void hip04_irq_cpu_init(struct hip04_irq_data *intc)
246{
247 void __iomem *dist_base = intc->dist_base;
248 void __iomem *base = intc->cpu_base;
249 unsigned int cpu_mask, cpu = smp_processor_id();
250 int i;
251
252 /*
253 * Get what the GIC says our CPU mask is.
254 */
255 BUG_ON(cpu >= NR_HIP04_CPU_IF);
256 cpu_mask = hip04_get_cpumask(intc);
257 hip04_cpu_map[cpu] = cpu_mask;
258
259 /*
260 * Clear our mask from the other map entries in case they're
261 * still undefined.
262 */
263 for (i = 0; i < NR_HIP04_CPU_IF; i++)
264 if (i != cpu)
265 hip04_cpu_map[i] &= ~cpu_mask;
266
267 gic_cpu_config(dist_base, NULL);
268
269 writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
270 writel_relaxed(1, base + GIC_CPU_CTRL);
271}
272
273#ifdef CONFIG_SMP
274static void hip04_raise_softirq(const struct cpumask *mask, unsigned int irq)
275{
276 int cpu;
277 unsigned long flags, map = 0;
278
279 raw_spin_lock_irqsave(&irq_controller_lock, flags);
280
281 /* Convert our logical CPU mask into a physical one. */
282 for_each_cpu(cpu, mask)
283 map |= hip04_cpu_map[cpu];
284
285 /*
286 * Ensure that stores to Normal memory are visible to the
287 * other CPUs before they observe us issuing the IPI.
288 */
289 dmb(ishst);
290
291 /* this always happens on GIC0 */
292 writel_relaxed(map << 8 | irq, hip04_data.dist_base + GIC_DIST_SOFTINT);
293
294 raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
295}
296#endif
297
298static int hip04_irq_domain_map(struct irq_domain *d, unsigned int irq,
299 irq_hw_number_t hw)
300{
301 if (hw < 32) {
302 irq_set_percpu_devid(irq);
303 irq_set_chip_and_handler(irq, &hip04_irq_chip,
304 handle_percpu_devid_irq);
305 set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
306 } else {
307 irq_set_chip_and_handler(irq, &hip04_irq_chip,
308 handle_fasteoi_irq);
309 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
310 }
311 irq_set_chip_data(irq, d->host_data);
312 return 0;
313}
314
315static int hip04_irq_domain_xlate(struct irq_domain *d,
316 struct device_node *controller,
317 const u32 *intspec, unsigned int intsize,
318 unsigned long *out_hwirq,
319 unsigned int *out_type)
320{
321 unsigned long ret = 0;
322
323 if (d->of_node != controller)
324 return -EINVAL;
325 if (intsize < 3)
326 return -EINVAL;
327
328 /* Get the interrupt number and add 16 to skip over SGIs */
329 *out_hwirq = intspec[1] + 16;
330
331 /* For SPIs, we need to add 16 more to get the irq ID number */
332 if (!intspec[0])
333 *out_hwirq += 16;
334
335 *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
336
337 return ret;
338}
339
340#ifdef CONFIG_SMP
341static int hip04_irq_secondary_init(struct notifier_block *nfb,
342 unsigned long action,
343 void *hcpu)
344{
345 if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
346 hip04_irq_cpu_init(&hip04_data);
347 return NOTIFY_OK;
348}
349
350/*
351 * Notifier for enabling the INTC CPU interface. Set an arbitrarily high
352 * priority because the GIC needs to be up before the ARM generic timers.
353 */
354static struct notifier_block hip04_irq_cpu_notifier = {
355 .notifier_call = hip04_irq_secondary_init,
356 .priority = 100,
357};
358#endif
359
360static const struct irq_domain_ops hip04_irq_domain_ops = {
361 .map = hip04_irq_domain_map,
362 .xlate = hip04_irq_domain_xlate,
363};
364
365static int __init
366hip04_of_init(struct device_node *node, struct device_node *parent)
367{
368 irq_hw_number_t hwirq_base = 16;
369 int nr_irqs, irq_base, i;
370
371 if (WARN_ON(!node))
372 return -ENODEV;
373
374 hip04_data.dist_base = of_iomap(node, 0);
375 WARN(!hip04_data.dist_base, "fail to map hip04 intc dist registers\n");
376
377 hip04_data.cpu_base = of_iomap(node, 1);
378 WARN(!hip04_data.cpu_base, "unable to map hip04 intc cpu registers\n");
379
380 /*
381 * Initialize the CPU interface map to all CPUs.
382 * It will be refined as each CPU probes its ID.
383 */
384 for (i = 0; i < NR_HIP04_CPU_IF; i++)
385 hip04_cpu_map[i] = 0xff;
386
387 /*
388 * Find out how many interrupts are supported.
389 * The HIP04 INTC only supports up to 510 interrupt sources.
390 */
391 nr_irqs = readl_relaxed(hip04_data.dist_base + GIC_DIST_CTR) & 0x1f;
392 nr_irqs = (nr_irqs + 1) * 32;
393 if (nr_irqs > HIP04_MAX_IRQS)
394 nr_irqs = HIP04_MAX_IRQS;
395 hip04_data.nr_irqs = nr_irqs;
396
397 nr_irqs -= hwirq_base; /* calculate # of irqs to allocate */
398
399 irq_base = irq_alloc_descs(-1, hwirq_base, nr_irqs, numa_node_id());
400 if (IS_ERR_VALUE(irq_base)) {
401 pr_err("failed to allocate IRQ numbers\n");
402 return -EINVAL;
403 }
404
405 hip04_data.domain = irq_domain_add_legacy(node, nr_irqs, irq_base,
406 hwirq_base,
407 &hip04_irq_domain_ops,
408 &hip04_data);
409
410 if (WARN_ON(!hip04_data.domain))
411 return -EINVAL;
412
413#ifdef CONFIG_SMP
414 set_smp_cross_call(hip04_raise_softirq);
415 register_cpu_notifier(&hip04_irq_cpu_notifier);
416#endif
417 set_handle_irq(hip04_handle_irq);
418
419 hip04_irq_dist_init(&hip04_data);
420 hip04_irq_cpu_init(&hip04_data);
421
422 return 0;
423}
424IRQCHIP_DECLARE(hip04_intc, "hisilicon,hip04-intc", hip04_of_init);
diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c
new file mode 100644
index 000000000000..608abf9c9283
--- /dev/null
+++ b/drivers/irqchip/irq-keystone.c
@@ -0,0 +1,232 @@
1/*
2 * Texas Instruments Keystone IRQ controller IP driver
3 *
4 * Copyright (C) 2014 Texas Instruments, Inc.
5 * Author: Sajesh Kumar Saran <sajesh@ti.com>
6 * Grygorii Strashko <grygorii.strashko@ti.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation version 2.
11 *
12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
13 * kind, whether express or implied; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <linux/irq.h>
19#include <linux/bitops.h>
20#include <linux/module.h>
21#include <linux/moduleparam.h>
22#include <linux/irqdomain.h>
23#include <linux/irqchip/chained_irq.h>
24#include <linux/of.h>
25#include <linux/of_platform.h>
26#include <linux/mfd/syscon.h>
27#include <linux/regmap.h>
28#include "irqchip.h"
29
30
31/* The source ID bits start from 4 to 31 (total 28 bits)*/
32#define BIT_OFS 4
33#define KEYSTONE_N_IRQ (32 - BIT_OFS)
34
35struct keystone_irq_device {
36 struct device *dev;
37 struct irq_chip chip;
38 u32 mask;
39 int irq;
40 struct irq_domain *irqd;
41 struct regmap *devctrl_regs;
42 u32 devctrl_offset;
43};
44
45static inline u32 keystone_irq_readl(struct keystone_irq_device *kirq)
46{
47 int ret;
48 u32 val = 0;
49
50 ret = regmap_read(kirq->devctrl_regs, kirq->devctrl_offset, &val);
51 if (ret < 0)
52 dev_dbg(kirq->dev, "irq read failed ret(%d)\n", ret);
53 return val;
54}
55
56static inline void
57keystone_irq_writel(struct keystone_irq_device *kirq, u32 value)
58{
59 int ret;
60
61 ret = regmap_write(kirq->devctrl_regs, kirq->devctrl_offset, value);
62 if (ret < 0)
63 dev_dbg(kirq->dev, "irq write failed ret(%d)\n", ret);
64}
65
66static void keystone_irq_setmask(struct irq_data *d)
67{
68 struct keystone_irq_device *kirq = irq_data_get_irq_chip_data(d);
69
70 kirq->mask |= BIT(d->hwirq);
71 dev_dbg(kirq->dev, "mask %lu [%x]\n", d->hwirq, kirq->mask);
72}
73
74static void keystone_irq_unmask(struct irq_data *d)
75{
76 struct keystone_irq_device *kirq = irq_data_get_irq_chip_data(d);
77
78 kirq->mask &= ~BIT(d->hwirq);
79 dev_dbg(kirq->dev, "unmask %lu [%x]\n", d->hwirq, kirq->mask);
80}
81
82static void keystone_irq_ack(struct irq_data *d)
83{
84 /* nothing to do here */
85}
86
87static void keystone_irq_handler(unsigned irq, struct irq_desc *desc)
88{
89 struct keystone_irq_device *kirq = irq_desc_get_handler_data(desc);
90 unsigned long pending;
91 int src, virq;
92
93 dev_dbg(kirq->dev, "start irq %d\n", irq);
94
95 chained_irq_enter(irq_desc_get_chip(desc), desc);
96
97 pending = keystone_irq_readl(kirq);
98 keystone_irq_writel(kirq, pending);
99
100 dev_dbg(kirq->dev, "pending 0x%lx, mask 0x%x\n", pending, kirq->mask);
101
102 pending = (pending >> BIT_OFS) & ~kirq->mask;
103
104 dev_dbg(kirq->dev, "pending after mask 0x%lx\n", pending);
105
106 for (src = 0; src < KEYSTONE_N_IRQ; src++) {
107 if (BIT(src) & pending) {
108 virq = irq_find_mapping(kirq->irqd, src);
109 dev_dbg(kirq->dev, "dispatch bit %d, virq %d\n",
110 src, virq);
111 if (!virq)
112 dev_warn(kirq->dev, "sporious irq detected hwirq %d, virq %d\n",
113 src, virq);
114 generic_handle_irq(virq);
115 }
116 }
117
118 chained_irq_exit(irq_desc_get_chip(desc), desc);
119
120 dev_dbg(kirq->dev, "end irq %d\n", irq);
121}
122
123static int keystone_irq_map(struct irq_domain *h, unsigned int virq,
124 irq_hw_number_t hw)
125{
126 struct keystone_irq_device *kirq = h->host_data;
127
128 irq_set_chip_data(virq, kirq);
129 irq_set_chip_and_handler(virq, &kirq->chip, handle_level_irq);
130 set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
131 return 0;
132}
133
134static struct irq_domain_ops keystone_irq_ops = {
135 .map = keystone_irq_map,
136 .xlate = irq_domain_xlate_onecell,
137};
138
139static int keystone_irq_probe(struct platform_device *pdev)
140{
141 struct device *dev = &pdev->dev;
142 struct device_node *np = dev->of_node;
143 struct keystone_irq_device *kirq;
144 int ret;
145
146 if (np == NULL)
147 return -EINVAL;
148
149 kirq = devm_kzalloc(dev, sizeof(*kirq), GFP_KERNEL);
150 if (!kirq)
151 return -ENOMEM;
152
153 kirq->devctrl_regs =
154 syscon_regmap_lookup_by_phandle(np, "ti,syscon-dev");
155 if (IS_ERR(kirq->devctrl_regs))
156 return PTR_ERR(kirq->devctrl_regs);
157
158 ret = of_property_read_u32_index(np, "ti,syscon-dev", 1,
159 &kirq->devctrl_offset);
160 if (ret) {
161 dev_err(dev, "couldn't read the devctrl_offset offset!\n");
162 return ret;
163 }
164
165 kirq->irq = platform_get_irq(pdev, 0);
166 if (kirq->irq < 0) {
167 dev_err(dev, "no irq resource %d\n", kirq->irq);
168 return kirq->irq;
169 }
170
171 kirq->dev = dev;
172 kirq->mask = ~0x0;
173 kirq->chip.name = "keystone-irq";
174 kirq->chip.irq_ack = keystone_irq_ack;
175 kirq->chip.irq_mask = keystone_irq_setmask;
176 kirq->chip.irq_unmask = keystone_irq_unmask;
177
178 kirq->irqd = irq_domain_add_linear(np, KEYSTONE_N_IRQ,
179 &keystone_irq_ops, kirq);
180 if (!kirq->irqd) {
181 dev_err(dev, "IRQ domain registration failed\n");
182 return -ENODEV;
183 }
184
185 platform_set_drvdata(pdev, kirq);
186
187 irq_set_chained_handler(kirq->irq, keystone_irq_handler);
188 irq_set_handler_data(kirq->irq, kirq);
189
190 /* clear all source bits */
191 keystone_irq_writel(kirq, ~0x0);
192
193 dev_info(dev, "irqchip registered, nr_irqs %u\n", KEYSTONE_N_IRQ);
194
195 return 0;
196}
197
198static int keystone_irq_remove(struct platform_device *pdev)
199{
200 struct keystone_irq_device *kirq = platform_get_drvdata(pdev);
201 int hwirq;
202
203 for (hwirq = 0; hwirq < KEYSTONE_N_IRQ; hwirq++)
204 irq_dispose_mapping(irq_find_mapping(kirq->irqd, hwirq));
205
206 irq_domain_remove(kirq->irqd);
207 return 0;
208}
209
210static const struct of_device_id keystone_irq_dt_ids[] = {
211 { .compatible = "ti,keystone-irq", },
212 {},
213};
214MODULE_DEVICE_TABLE(of, keystone_irq_dt_ids);
215
216static struct platform_driver keystone_irq_device_driver = {
217 .probe = keystone_irq_probe,
218 .remove = keystone_irq_remove,
219 .driver = {
220 .name = "keystone_irq",
221 .owner = THIS_MODULE,
222 .of_match_table = of_match_ptr(keystone_irq_dt_ids),
223 }
224};
225
226module_platform_driver(keystone_irq_device_driver);
227
228MODULE_AUTHOR("Texas Instruments");
229MODULE_AUTHOR("Sajesh Kumar Saran");
230MODULE_AUTHOR("Grygorii Strashko");
231MODULE_DESCRIPTION("Keystone IRQ chip");
232MODULE_LICENSE("GPL v2");
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 1c3e2c9b46ba..c0da57bdb89d 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -196,26 +196,24 @@ static struct mmp_intc_conf mmp2_conf = {
196 196
197static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs) 197static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
198{ 198{
199 int irq, hwirq; 199 int hwirq;
200 200
201 hwirq = readl_relaxed(mmp_icu_base + PJ1_INT_SEL); 201 hwirq = readl_relaxed(mmp_icu_base + PJ1_INT_SEL);
202 if (!(hwirq & SEL_INT_PENDING)) 202 if (!(hwirq & SEL_INT_PENDING))
203 return; 203 return;
204 hwirq &= SEL_INT_NUM_MASK; 204 hwirq &= SEL_INT_NUM_MASK;
205 irq = irq_find_mapping(icu_data[0].domain, hwirq); 205 handle_domain_irq(icu_data[0].domain, hwirq, regs);
206 handle_IRQ(irq, regs);
207} 206}
208 207
209static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs) 208static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs)
210{ 209{
211 int irq, hwirq; 210 int hwirq;
212 211
213 hwirq = readl_relaxed(mmp_icu_base + PJ4_INT_SEL); 212 hwirq = readl_relaxed(mmp_icu_base + PJ4_INT_SEL);
214 if (!(hwirq & SEL_INT_PENDING)) 213 if (!(hwirq & SEL_INT_PENDING))
215 return; 214 return;
216 hwirq &= SEL_INT_NUM_MASK; 215 hwirq &= SEL_INT_NUM_MASK;
217 irq = irq_find_mapping(icu_data[0].domain, hwirq); 216 handle_domain_irq(icu_data[0].domain, hwirq, regs);
218 handle_IRQ(irq, regs);
219} 217}
220 218
221/* MMP (ARMv5) */ 219/* MMP (ARMv5) */
diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c
index 4044ff287663..e4acf1e3f8e3 100644
--- a/drivers/irqchip/irq-mxs.c
+++ b/drivers/irqchip/irq-mxs.c
@@ -78,8 +78,7 @@ asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs)
78 78
79 irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET); 79 irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET);
80 __raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR); 80 __raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR);
81 irqnr = irq_find_mapping(icoll_domain, irqnr); 81 handle_domain_irq(icoll_domain, irqnr, regs);
82 handle_IRQ(irqnr, regs);
83} 82}
84 83
85static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq, 84static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq,
diff --git a/drivers/irqchip/irq-omap-intc.c b/drivers/irqchip/irq-omap-intc.c
index f3814e79192d..28718d3e8281 100644
--- a/drivers/irqchip/irq-omap-intc.c
+++ b/drivers/irqchip/irq-omap-intc.c
@@ -334,8 +334,7 @@ out:
334 irqnr &= ACTIVEIRQ_MASK; 334 irqnr &= ACTIVEIRQ_MASK;
335 335
336 if (irqnr) { 336 if (irqnr) {
337 irqnr = irq_find_mapping(domain, irqnr); 337 handle_domain_irq(domain, irqnr, regs);
338 handle_IRQ(irqnr, regs);
339 handled_irq = 1; 338 handled_irq = 1;
340 } 339 }
341 } while (irqnr); 340 } while (irqnr);
diff --git a/drivers/irqchip/irq-or1k-pic.c b/drivers/irqchip/irq-or1k-pic.c
index 17ff033d9925..e93d079fe069 100644
--- a/drivers/irqchip/irq-or1k-pic.c
+++ b/drivers/irqchip/irq-or1k-pic.c
@@ -113,7 +113,7 @@ static inline int pic_get_irq(int first)
113 else 113 else
114 hwirq = hwirq + first - 1; 114 hwirq = hwirq + first - 1;
115 115
116 return irq_find_mapping(root_domain, hwirq); 116 return hwirq;
117} 117}
118 118
119static void or1k_pic_handle_irq(struct pt_regs *regs) 119static void or1k_pic_handle_irq(struct pt_regs *regs)
@@ -121,7 +121,7 @@ static void or1k_pic_handle_irq(struct pt_regs *regs)
121 int irq = -1; 121 int irq = -1;
122 122
123 while ((irq = pic_get_irq(irq + 1)) != NO_IRQ) 123 while ((irq = pic_get_irq(irq + 1)) != NO_IRQ)
124 handle_IRQ(irq, regs); 124 handle_domain_irq(root_domain, irq, regs);
125} 125}
126 126
127static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) 127static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c
index 34d18b48bb78..ad0c0f6f1d65 100644
--- a/drivers/irqchip/irq-orion.c
+++ b/drivers/irqchip/irq-orion.c
@@ -43,9 +43,8 @@ __exception_irq_entry orion_handle_irq(struct pt_regs *regs)
43 gc->mask_cache; 43 gc->mask_cache;
44 while (stat) { 44 while (stat) {
45 u32 hwirq = __fls(stat); 45 u32 hwirq = __fls(stat);
46 u32 irq = irq_find_mapping(orion_irq_domain, 46 handle_domain_irq(orion_irq_domain,
47 gc->irq_base + hwirq); 47 gc->irq_base + hwirq, regs);
48 handle_IRQ(irq, regs);
49 stat &= ~(1 << hwirq); 48 stat &= ~(1 << hwirq);
50 } 49 }
51 } 50 }
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
index 3ee78f02e5d7..542e850f4946 100644
--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -17,6 +17,7 @@
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */ 18 */
19 19
20#include <linux/clk.h>
20#include <linux/init.h> 21#include <linux/init.h>
21#include <linux/of.h> 22#include <linux/of.h>
22#include <linux/platform_device.h> 23#include <linux/platform_device.h>
@@ -30,6 +31,7 @@
30#include <linux/slab.h> 31#include <linux/slab.h>
31#include <linux/module.h> 32#include <linux/module.h>
32#include <linux/platform_data/irq-renesas-intc-irqpin.h> 33#include <linux/platform_data/irq-renesas-intc-irqpin.h>
34#include <linux/pm_runtime.h>
33 35
34#define INTC_IRQPIN_MAX 8 /* maximum 8 interrupts per driver instance */ 36#define INTC_IRQPIN_MAX 8 /* maximum 8 interrupts per driver instance */
35 37
@@ -75,6 +77,7 @@ struct intc_irqpin_priv {
75 struct platform_device *pdev; 77 struct platform_device *pdev;
76 struct irq_chip irq_chip; 78 struct irq_chip irq_chip;
77 struct irq_domain *irq_domain; 79 struct irq_domain *irq_domain;
80 struct clk *clk;
78 bool shared_irqs; 81 bool shared_irqs;
79 u8 shared_irq_mask; 82 u8 shared_irq_mask;
80}; 83};
@@ -270,6 +273,21 @@ static int intc_irqpin_irq_set_type(struct irq_data *d, unsigned int type)
270 value ^ INTC_IRQ_SENSE_VALID); 273 value ^ INTC_IRQ_SENSE_VALID);
271} 274}
272 275
276static int intc_irqpin_irq_set_wake(struct irq_data *d, unsigned int on)
277{
278 struct intc_irqpin_priv *p = irq_data_get_irq_chip_data(d);
279
280 if (!p->clk)
281 return 0;
282
283 if (on)
284 clk_enable(p->clk);
285 else
286 clk_disable(p->clk);
287
288 return 0;
289}
290
273static irqreturn_t intc_irqpin_irq_handler(int irq, void *dev_id) 291static irqreturn_t intc_irqpin_irq_handler(int irq, void *dev_id)
274{ 292{
275 struct intc_irqpin_irq *i = dev_id; 293 struct intc_irqpin_irq *i = dev_id;
@@ -329,7 +347,8 @@ static struct irq_domain_ops intc_irqpin_irq_domain_ops = {
329 347
330static int intc_irqpin_probe(struct platform_device *pdev) 348static int intc_irqpin_probe(struct platform_device *pdev)
331{ 349{
332 struct renesas_intc_irqpin_config *pdata = pdev->dev.platform_data; 350 struct device *dev = &pdev->dev;
351 struct renesas_intc_irqpin_config *pdata = dev->platform_data;
333 struct intc_irqpin_priv *p; 352 struct intc_irqpin_priv *p;
334 struct intc_irqpin_iomem *i; 353 struct intc_irqpin_iomem *i;
335 struct resource *io[INTC_IRQPIN_REG_NR]; 354 struct resource *io[INTC_IRQPIN_REG_NR];
@@ -337,25 +356,24 @@ static int intc_irqpin_probe(struct platform_device *pdev)
337 struct irq_chip *irq_chip; 356 struct irq_chip *irq_chip;
338 void (*enable_fn)(struct irq_data *d); 357 void (*enable_fn)(struct irq_data *d);
339 void (*disable_fn)(struct irq_data *d); 358 void (*disable_fn)(struct irq_data *d);
340 const char *name = dev_name(&pdev->dev); 359 const char *name = dev_name(dev);
341 int ref_irq; 360 int ref_irq;
342 int ret; 361 int ret;
343 int k; 362 int k;
344 363
345 p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); 364 p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
346 if (!p) { 365 if (!p) {
347 dev_err(&pdev->dev, "failed to allocate driver data\n"); 366 dev_err(dev, "failed to allocate driver data\n");
348 ret = -ENOMEM; 367 return -ENOMEM;
349 goto err0;
350 } 368 }
351 369
352 /* deal with driver instance configuration */ 370 /* deal with driver instance configuration */
353 if (pdata) { 371 if (pdata) {
354 memcpy(&p->config, pdata, sizeof(*pdata)); 372 memcpy(&p->config, pdata, sizeof(*pdata));
355 } else { 373 } else {
356 of_property_read_u32(pdev->dev.of_node, "sense-bitfield-width", 374 of_property_read_u32(dev->of_node, "sense-bitfield-width",
357 &p->config.sense_bitfield_width); 375 &p->config.sense_bitfield_width);
358 p->config.control_parent = of_property_read_bool(pdev->dev.of_node, 376 p->config.control_parent = of_property_read_bool(dev->of_node,
359 "control-parent"); 377 "control-parent");
360 } 378 }
361 if (!p->config.sense_bitfield_width) 379 if (!p->config.sense_bitfield_width)
@@ -364,11 +382,20 @@ static int intc_irqpin_probe(struct platform_device *pdev)
364 p->pdev = pdev; 382 p->pdev = pdev;
365 platform_set_drvdata(pdev, p); 383 platform_set_drvdata(pdev, p);
366 384
385 p->clk = devm_clk_get(dev, NULL);
386 if (IS_ERR(p->clk)) {
387 dev_warn(dev, "unable to get clock\n");
388 p->clk = NULL;
389 }
390
391 pm_runtime_enable(dev);
392 pm_runtime_get_sync(dev);
393
367 /* get hold of manadatory IOMEM */ 394 /* get hold of manadatory IOMEM */
368 for (k = 0; k < INTC_IRQPIN_REG_NR; k++) { 395 for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
369 io[k] = platform_get_resource(pdev, IORESOURCE_MEM, k); 396 io[k] = platform_get_resource(pdev, IORESOURCE_MEM, k);
370 if (!io[k]) { 397 if (!io[k]) {
371 dev_err(&pdev->dev, "not enough IOMEM resources\n"); 398 dev_err(dev, "not enough IOMEM resources\n");
372 ret = -EINVAL; 399 ret = -EINVAL;
373 goto err0; 400 goto err0;
374 } 401 }
@@ -386,7 +413,7 @@ static int intc_irqpin_probe(struct platform_device *pdev)
386 413
387 p->number_of_irqs = k; 414 p->number_of_irqs = k;
388 if (p->number_of_irqs < 1) { 415 if (p->number_of_irqs < 1) {
389 dev_err(&pdev->dev, "not enough IRQ resources\n"); 416 dev_err(dev, "not enough IRQ resources\n");
390 ret = -EINVAL; 417 ret = -EINVAL;
391 goto err0; 418 goto err0;
392 } 419 }
@@ -407,15 +434,15 @@ static int intc_irqpin_probe(struct platform_device *pdev)
407 i->write = intc_irqpin_write32; 434 i->write = intc_irqpin_write32;
408 break; 435 break;
409 default: 436 default:
410 dev_err(&pdev->dev, "IOMEM size mismatch\n"); 437 dev_err(dev, "IOMEM size mismatch\n");
411 ret = -EINVAL; 438 ret = -EINVAL;
412 goto err0; 439 goto err0;
413 } 440 }
414 441
415 i->iomem = devm_ioremap_nocache(&pdev->dev, io[k]->start, 442 i->iomem = devm_ioremap_nocache(dev, io[k]->start,
416 resource_size(io[k])); 443 resource_size(io[k]));
417 if (!i->iomem) { 444 if (!i->iomem) {
418 dev_err(&pdev->dev, "failed to remap IOMEM\n"); 445 dev_err(dev, "failed to remap IOMEM\n");
419 ret = -ENXIO; 446 ret = -ENXIO;
420 goto err0; 447 goto err0;
421 } 448 }
@@ -454,39 +481,36 @@ static int intc_irqpin_probe(struct platform_device *pdev)
454 irq_chip->name = name; 481 irq_chip->name = name;
455 irq_chip->irq_mask = disable_fn; 482 irq_chip->irq_mask = disable_fn;
456 irq_chip->irq_unmask = enable_fn; 483 irq_chip->irq_unmask = enable_fn;
457 irq_chip->irq_enable = enable_fn;
458 irq_chip->irq_disable = disable_fn;
459 irq_chip->irq_set_type = intc_irqpin_irq_set_type; 484 irq_chip->irq_set_type = intc_irqpin_irq_set_type;
460 irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; 485 irq_chip->irq_set_wake = intc_irqpin_irq_set_wake;
486 irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND;
461 487
462 p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, 488 p->irq_domain = irq_domain_add_simple(dev->of_node,
463 p->number_of_irqs, 489 p->number_of_irqs,
464 p->config.irq_base, 490 p->config.irq_base,
465 &intc_irqpin_irq_domain_ops, p); 491 &intc_irqpin_irq_domain_ops, p);
466 if (!p->irq_domain) { 492 if (!p->irq_domain) {
467 ret = -ENXIO; 493 ret = -ENXIO;
468 dev_err(&pdev->dev, "cannot initialize irq domain\n"); 494 dev_err(dev, "cannot initialize irq domain\n");
469 goto err0; 495 goto err0;
470 } 496 }
471 497
472 if (p->shared_irqs) { 498 if (p->shared_irqs) {
473 /* request one shared interrupt */ 499 /* request one shared interrupt */
474 if (devm_request_irq(&pdev->dev, p->irq[0].requested_irq, 500 if (devm_request_irq(dev, p->irq[0].requested_irq,
475 intc_irqpin_shared_irq_handler, 501 intc_irqpin_shared_irq_handler,
476 IRQF_SHARED, name, p)) { 502 IRQF_SHARED, name, p)) {
477 dev_err(&pdev->dev, "failed to request low IRQ\n"); 503 dev_err(dev, "failed to request low IRQ\n");
478 ret = -ENOENT; 504 ret = -ENOENT;
479 goto err1; 505 goto err1;
480 } 506 }
481 } else { 507 } else {
482 /* request interrupts one by one */ 508 /* request interrupts one by one */
483 for (k = 0; k < p->number_of_irqs; k++) { 509 for (k = 0; k < p->number_of_irqs; k++) {
484 if (devm_request_irq(&pdev->dev, 510 if (devm_request_irq(dev, p->irq[k].requested_irq,
485 p->irq[k].requested_irq, 511 intc_irqpin_irq_handler, 0, name,
486 intc_irqpin_irq_handler, 512 &p->irq[k])) {
487 0, name, &p->irq[k])) { 513 dev_err(dev, "failed to request low IRQ\n");
488 dev_err(&pdev->dev,
489 "failed to request low IRQ\n");
490 ret = -ENOENT; 514 ret = -ENOENT;
491 goto err1; 515 goto err1;
492 } 516 }
@@ -497,12 +521,12 @@ static int intc_irqpin_probe(struct platform_device *pdev)
497 for (k = 0; k < p->number_of_irqs; k++) 521 for (k = 0; k < p->number_of_irqs; k++)
498 intc_irqpin_mask_unmask_prio(p, k, 0); 522 intc_irqpin_mask_unmask_prio(p, k, 0);
499 523
500 dev_info(&pdev->dev, "driving %d irqs\n", p->number_of_irqs); 524 dev_info(dev, "driving %d irqs\n", p->number_of_irqs);
501 525
502 /* warn in case of mismatch if irq base is specified */ 526 /* warn in case of mismatch if irq base is specified */
503 if (p->config.irq_base) { 527 if (p->config.irq_base) {
504 if (p->config.irq_base != p->irq[0].domain_irq) 528 if (p->config.irq_base != p->irq[0].domain_irq)
505 dev_warn(&pdev->dev, "irq base mismatch (%d/%d)\n", 529 dev_warn(dev, "irq base mismatch (%d/%d)\n",
506 p->config.irq_base, p->irq[0].domain_irq); 530 p->config.irq_base, p->irq[0].domain_irq);
507 } 531 }
508 532
@@ -511,6 +535,8 @@ static int intc_irqpin_probe(struct platform_device *pdev)
511err1: 535err1:
512 irq_domain_remove(p->irq_domain); 536 irq_domain_remove(p->irq_domain);
513err0: 537err0:
538 pm_runtime_put(dev);
539 pm_runtime_disable(dev);
514 return ret; 540 return ret;
515} 541}
516 542
@@ -519,7 +545,8 @@ static int intc_irqpin_remove(struct platform_device *pdev)
519 struct intc_irqpin_priv *p = platform_get_drvdata(pdev); 545 struct intc_irqpin_priv *p = platform_get_drvdata(pdev);
520 546
521 irq_domain_remove(p->irq_domain); 547 irq_domain_remove(p->irq_domain);
522 548 pm_runtime_put(&pdev->dev);
549 pm_runtime_disable(&pdev->dev);
523 return 0; 550 return 0;
524} 551}
525 552
diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c
index 78a6accd205f..c8d373fcd823 100644
--- a/drivers/irqchip/irq-s3c24xx.c
+++ b/drivers/irqchip/irq-s3c24xx.c
@@ -339,7 +339,6 @@ static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc,
339{ 339{
340 int pnd; 340 int pnd;
341 int offset; 341 int offset;
342 int irq;
343 342
344 pnd = __raw_readl(intc->reg_intpnd); 343 pnd = __raw_readl(intc->reg_intpnd);
345 if (!pnd) 344 if (!pnd)
@@ -365,8 +364,7 @@ static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc,
365 if (!(pnd & (1 << offset))) 364 if (!(pnd & (1 << offset)))
366 offset = __ffs(pnd); 365 offset = __ffs(pnd);
367 366
368 irq = irq_find_mapping(intc->domain, intc_offset + offset); 367 handle_domain_irq(intc->domain, intc_offset + offset, regs);
369 handle_IRQ(irq, regs);
370 return true; 368 return true;
371} 369}
372 370
diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c
index 5e54f6d71e77..a469355df352 100644
--- a/drivers/irqchip/irq-sirfsoc.c
+++ b/drivers/irqchip/irq-sirfsoc.c
@@ -50,12 +50,10 @@ sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
50static void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs) 50static void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
51{ 51{
52 void __iomem *base = sirfsoc_irqdomain->host_data; 52 void __iomem *base = sirfsoc_irqdomain->host_data;
53 u32 irqstat, irqnr; 53 u32 irqstat;
54 54
55 irqstat = readl_relaxed(base + SIRFSOC_INIT_IRQ_ID); 55 irqstat = readl_relaxed(base + SIRFSOC_INIT_IRQ_ID);
56 irqnr = irq_find_mapping(sirfsoc_irqdomain, irqstat & 0xff); 56 handle_domain_irq(sirfsoc_irqdomain, irqstat & 0xff, regs);
57
58 handle_IRQ(irqnr, regs);
59} 57}
60 58
61static int __init sirfsoc_irq_init(struct device_node *np, 59static int __init sirfsoc_irq_init(struct device_node *np,
diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
index 6fcef4a95a18..64155b686081 100644
--- a/drivers/irqchip/irq-sun4i.c
+++ b/drivers/irqchip/irq-sun4i.c
@@ -136,7 +136,7 @@ IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-a10-ic", sun4i_of_init);
136 136
137static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs) 137static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
138{ 138{
139 u32 irq, hwirq; 139 u32 hwirq;
140 140
141 /* 141 /*
142 * hwirq == 0 can mean one of 3 things: 142 * hwirq == 0 can mean one of 3 things:
@@ -154,8 +154,7 @@ static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
154 return; 154 return;
155 155
156 do { 156 do {
157 irq = irq_find_mapping(sun4i_irq_domain, hwirq); 157 handle_domain_irq(sun4i_irq_domain, hwirq, regs);
158 handle_IRQ(irq, regs);
159 hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; 158 hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
160 } while (hwirq != 0); 159 } while (hwirq != 0);
161} 160}
diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c
index ccf58548b161..1ab451729a5c 100644
--- a/drivers/irqchip/irq-versatile-fpga.c
+++ b/drivers/irqchip/irq-versatile-fpga.c
@@ -96,7 +96,7 @@ static int handle_one_fpga(struct fpga_irq_data *f, struct pt_regs *regs)
96 96
97 while ((status = readl(f->base + IRQ_STATUS))) { 97 while ((status = readl(f->base + IRQ_STATUS))) {
98 irq = ffs(status) - 1; 98 irq = ffs(status) - 1;
99 handle_IRQ(irq_find_mapping(f->domain, irq), regs); 99 handle_domain_irq(f->domain, irq, regs);
100 handled = 1; 100 handled = 1;
101 } 101 }
102 102
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287f9e90..54089debf2dc 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -219,7 +219,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
219 219
220 while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) { 220 while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
221 irq = ffs(stat) - 1; 221 irq = ffs(stat) - 1;
222 handle_IRQ(irq_find_mapping(vic->domain, irq), regs); 222 handle_domain_irq(vic->domain, irq, regs);
223 handled = 1; 223 handled = 1;
224 } 224 }
225 225
diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c
index eb6e91efdec8..b7af816f2769 100644
--- a/drivers/irqchip/irq-vt8500.c
+++ b/drivers/irqchip/irq-vt8500.c
@@ -181,7 +181,7 @@ static struct irq_domain_ops vt8500_irq_domain_ops = {
181static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs) 181static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
182{ 182{
183 u32 stat, i; 183 u32 stat, i;
184 int irqnr, virq; 184 int irqnr;
185 void __iomem *base; 185 void __iomem *base;
186 186
187 /* Loop through each active controller */ 187 /* Loop through each active controller */
@@ -198,8 +198,7 @@ static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
198 continue; 198 continue;
199 } 199 }
200 200
201 virq = irq_find_mapping(intc[i].domain, irqnr); 201 handle_domain_irq(intc[i].domain, irqnr, regs);
202 handle_IRQ(virq, regs);
203 } 202 }
204} 203}
205 204
diff --git a/drivers/irqchip/irq-zevio.c b/drivers/irqchip/irq-zevio.c
index ceb3a4318f73..e4ef74ed454a 100644
--- a/drivers/irqchip/irq-zevio.c
+++ b/drivers/irqchip/irq-zevio.c
@@ -56,8 +56,7 @@ static void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
56 56
57 while (readl(zevio_irq_io + IO_STATUS)) { 57 while (readl(zevio_irq_io + IO_STATUS)) {
58 irqnr = readl(zevio_irq_io + IO_CURRENT); 58 irqnr = readl(zevio_irq_io + IO_CURRENT);
59 irqnr = irq_find_mapping(zevio_irq_domain, irqnr); 59 handle_domain_irq(zevio_irq_domain, irqnr, regs);
60 handle_IRQ(irqnr, regs);
61 }; 60 };
62} 61}
63 62
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 45e2d8c15bd2..13eed92c7d24 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -21,7 +21,11 @@
21#define GIC_CPU_ACTIVEPRIO 0xd0 21#define GIC_CPU_ACTIVEPRIO 0xd0
22#define GIC_CPU_IDENT 0xfc 22#define GIC_CPU_IDENT 0xfc
23 23
24#define GICC_ENABLE 0x1
25#define GICC_INT_PRI_THRESHOLD 0xf0
24#define GICC_IAR_INT_ID_MASK 0x3ff 26#define GICC_IAR_INT_ID_MASK 0x3ff
27#define GICC_INT_SPURIOUS 1023
28#define GICC_DIS_BYPASS_MASK 0x1e0
25 29
26#define GIC_DIST_CTRL 0x000 30#define GIC_DIST_CTRL 0x000
27#define GIC_DIST_CTR 0x004 31#define GIC_DIST_CTR 0x004
@@ -39,6 +43,18 @@
39#define GIC_DIST_SGI_PENDING_CLEAR 0xf10 43#define GIC_DIST_SGI_PENDING_CLEAR 0xf10
40#define GIC_DIST_SGI_PENDING_SET 0xf20 44#define GIC_DIST_SGI_PENDING_SET 0xf20
41 45
46#define GICD_ENABLE 0x1
47#define GICD_DISABLE 0x0
48#define GICD_INT_ACTLOW_LVLTRIG 0x0
49#define GICD_INT_EN_CLR_X32 0xffffffff
50#define GICD_INT_EN_SET_SGI 0x0000ffff
51#define GICD_INT_EN_CLR_PPI 0xffff0000
52#define GICD_INT_DEF_PRI 0xa0
53#define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\
54 (GICD_INT_DEF_PRI << 16) |\
55 (GICD_INT_DEF_PRI << 8) |\
56 GICD_INT_DEF_PRI)
57
42#define GICH_HCR 0x0 58#define GICH_HCR 0x0
43#define GICH_VTR 0x4 59#define GICH_VTR 0x4
44#define GICH_VMCR 0x8 60#define GICH_VMCR 0x8
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index 472c021a2d4f..ff24667cd86c 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -12,6 +12,8 @@ struct irq_affinity_notify;
12struct proc_dir_entry; 12struct proc_dir_entry;
13struct module; 13struct module;
14struct irq_desc; 14struct irq_desc;
15struct irq_domain;
16struct pt_regs;
15 17
16/** 18/**
17 * struct irq_desc - interrupt descriptor 19 * struct irq_desc - interrupt descriptor
@@ -118,6 +120,23 @@ static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *de
118 120
119int generic_handle_irq(unsigned int irq); 121int generic_handle_irq(unsigned int irq);
120 122
123#ifdef CONFIG_HANDLE_DOMAIN_IRQ
124/*
125 * Convert a HW interrupt number to a logical one using a IRQ domain,
126 * and handle the result interrupt number. Return -EINVAL if
127 * conversion failed. Providing a NULL domain indicates that the
128 * conversion has already been done.
129 */
130int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,
131 bool lookup, struct pt_regs *regs);
132
133static inline int handle_domain_irq(struct irq_domain *domain,
134 unsigned int hwirq, struct pt_regs *regs)
135{
136 return __handle_domain_irq(domain, hwirq, true, regs);
137}
138#endif
139
121/* Test to see if a driver has successfully requested an irq */ 140/* Test to see if a driver has successfully requested an irq */
122static inline int irq_has_action(unsigned int irq) 141static inline int irq_has_action(unsigned int irq)
123{ 142{
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index d269cecdfbf0..225086b2652e 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -55,6 +55,9 @@ config GENERIC_IRQ_CHIP
55config IRQ_DOMAIN 55config IRQ_DOMAIN
56 bool 56 bool
57 57
58config HANDLE_DOMAIN_IRQ
59 bool
60
58config IRQ_DOMAIN_DEBUG 61config IRQ_DOMAIN_DEBUG
59 bool "Expose hardware/virtual IRQ mapping via debugfs" 62 bool "Expose hardware/virtual IRQ mapping via debugfs"
60 depends on IRQ_DOMAIN && DEBUG_FS 63 depends on IRQ_DOMAIN && DEBUG_FS
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index 1487a123db5c..a1782f88f0af 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -14,6 +14,7 @@
14#include <linux/kernel_stat.h> 14#include <linux/kernel_stat.h>
15#include <linux/radix-tree.h> 15#include <linux/radix-tree.h>
16#include <linux/bitmap.h> 16#include <linux/bitmap.h>
17#include <linux/irqdomain.h>
17 18
18#include "internals.h" 19#include "internals.h"
19 20
@@ -336,6 +337,47 @@ int generic_handle_irq(unsigned int irq)
336} 337}
337EXPORT_SYMBOL_GPL(generic_handle_irq); 338EXPORT_SYMBOL_GPL(generic_handle_irq);
338 339
340#ifdef CONFIG_HANDLE_DOMAIN_IRQ
341/**
342 * __handle_domain_irq - Invoke the handler for a HW irq belonging to a domain
343 * @domain: The domain where to perform the lookup
344 * @hwirq: The HW irq number to convert to a logical one
345 * @lookup: Whether to perform the domain lookup or not
346 * @regs: Register file coming from the low-level handling code
347 *
348 * Returns: 0 on success, or -EINVAL if conversion has failed
349 */
350int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,
351 bool lookup, struct pt_regs *regs)
352{
353 struct pt_regs *old_regs = set_irq_regs(regs);
354 unsigned int irq = hwirq;
355 int ret = 0;
356
357 irq_enter();
358
359#ifdef CONFIG_IRQ_DOMAIN
360 if (lookup)
361 irq = irq_find_mapping(domain, hwirq);
362#endif
363
364 /*
365 * Some hardware gives randomly wrong interrupts. Rather
366 * than crashing, do something sensible.
367 */
368 if (unlikely(!irq || irq >= nr_irqs)) {
369 ack_bad_irq(irq);
370 ret = -EINVAL;
371 } else {
372 generic_handle_irq(irq);
373 }
374
375 irq_exit();
376 set_irq_regs(old_regs);
377 return ret;
378}
379#endif
380
339/* Dynamic interrupt handling */ 381/* Dynamic interrupt handling */
340 382
341/** 383/**