aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2015-03-11 11:43:44 -0400
committerJason Cooper <jason@lakedaemon.net>2015-03-14 20:55:24 -0400
commit783d31863fb826f1a3754a2d5959a022a1b12d54 (patch)
tree4610918642e934e9b3d0260a9d33bd569b89d55b
parent08b55e2a9208e4841a17c9d9c2c454986392977d (diff)
irqchip: crossbar: Convert dra7 crossbar to stacked domains
Support for the TI crossbar used on the DRA7 family of chips is implemented as an ugly hack on the side of the GIC. Converting it to stacked domains makes it slightly more palatable, as it results in a cleanup. Unfortunately, as the DT bindings failed to acknowledge the fact that this is actually yet another interrupt controller (the third, actually), we have yet another breakage. Oh well. Acked-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Link: https://lkml.kernel.org/r/1426088629-15377-3-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper <jason@lakedaemon.net>
-rw-r--r--arch/arm/boot/dts/am57xx-beagle-x15.dts3
-rw-r--r--arch/arm/boot/dts/dra7-evm.dts2
-rw-r--r--arch/arm/boot/dts/dra7.dtsi35
-rw-r--r--arch/arm/boot/dts/dra72-evm.dts1
-rw-r--r--arch/arm/boot/dts/dra72x.dtsi3
-rw-r--r--arch/arm/boot/dts/dra74x.dtsi5
-rw-r--r--arch/arm/mach-omap2/omap4-common.c4
-rw-r--r--drivers/irqchip/irq-crossbar.c210
-rw-r--r--include/linux/irqchip/irq-crossbar.h11
9 files changed, 149 insertions, 125 deletions
diff --git a/arch/arm/boot/dts/am57xx-beagle-x15.dts b/arch/arm/boot/dts/am57xx-beagle-x15.dts
index 03750af3b49a..170fbf953e5d 100644
--- a/arch/arm/boot/dts/am57xx-beagle-x15.dts
+++ b/arch/arm/boot/dts/am57xx-beagle-x15.dts
@@ -454,7 +454,6 @@
454 mcp_rtc: rtc@6f { 454 mcp_rtc: rtc@6f {
455 compatible = "microchip,mcp7941x"; 455 compatible = "microchip,mcp7941x";
456 reg = <0x6f>; 456 reg = <0x6f>;
457 interrupt-parent = <&gic>;
458 interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_LOW>; /* IRQ_SYS_1N */ 457 interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_LOW>; /* IRQ_SYS_1N */
459 458
460 pinctrl-names = "default"; 459 pinctrl-names = "default";
@@ -477,7 +476,7 @@
477 476
478&uart3 { 477&uart3 {
479 status = "okay"; 478 status = "okay";
480 interrupts-extended = <&gic GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>, 479 interrupts-extended = <&crossbar_mpu GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
481 <&dra7_pmx_core 0x248>; 480 <&dra7_pmx_core 0x248>;
482 481
483 pinctrl-names = "default"; 482 pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts
index 746cddb1b8f5..789ee58ba47e 100644
--- a/arch/arm/boot/dts/dra7-evm.dts
+++ b/arch/arm/boot/dts/dra7-evm.dts
@@ -446,7 +446,7 @@
446 status = "okay"; 446 status = "okay";
447 pinctrl-names = "default"; 447 pinctrl-names = "default";
448 pinctrl-0 = <&uart1_pins>; 448 pinctrl-0 = <&uart1_pins>;
449 interrupts-extended = <&gic GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>, 449 interrupts-extended = <&crossbar_mpu GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
450 <&dra7_pmx_core 0x3e0>; 450 <&dra7_pmx_core 0x3e0>;
451}; 451};
452 452
diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index 5827fedafd43..850f949d409a 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -13,14 +13,13 @@
13#include "skeleton.dtsi" 13#include "skeleton.dtsi"
14 14
15#define MAX_SOURCES 400 15#define MAX_SOURCES 400
16#define DIRECT_IRQ(irq) (MAX_SOURCES + irq)
17 16
18/ { 17/ {
19 #address-cells = <1>; 18 #address-cells = <1>;
20 #size-cells = <1>; 19 #size-cells = <1>;
21 20
22 compatible = "ti,dra7xx"; 21 compatible = "ti,dra7xx";
23 interrupt-parent = <&gic>; 22 interrupt-parent = <&crossbar_mpu>;
24 23
25 aliases { 24 aliases {
26 i2c0 = &i2c1; 25 i2c0 = &i2c1;
@@ -50,18 +49,19 @@
50 <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, 49 <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
51 <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, 50 <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
52 <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>; 51 <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
52 interrupt-parent = <&gic>;
53 }; 53 };
54 54
55 gic: interrupt-controller@48211000 { 55 gic: interrupt-controller@48211000 {
56 compatible = "arm,cortex-a15-gic"; 56 compatible = "arm,cortex-a15-gic";
57 interrupt-controller; 57 interrupt-controller;
58 #interrupt-cells = <3>; 58 #interrupt-cells = <3>;
59 arm,routable-irqs = <192>;
60 reg = <0x48211000 0x1000>, 59 reg = <0x48211000 0x1000>,
61 <0x48212000 0x1000>, 60 <0x48212000 0x1000>,
62 <0x48214000 0x2000>, 61 <0x48214000 0x2000>,
63 <0x48216000 0x2000>; 62 <0x48216000 0x2000>;
64 interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>; 63 interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
64 interrupt-parent = <&gic>;
65 }; 65 };
66 66
67 /* 67 /*
@@ -91,8 +91,8 @@
91 ti,hwmods = "l3_main_1", "l3_main_2"; 91 ti,hwmods = "l3_main_1", "l3_main_2";
92 reg = <0x44000000 0x1000000>, 92 reg = <0x44000000 0x1000000>,
93 <0x45000000 0x1000>; 93 <0x45000000 0x1000>;
94 interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>, 94 interrupts-extended = <&crossbar_mpu GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
95 <GIC_SPI DIRECT_IRQ(10) IRQ_TYPE_LEVEL_HIGH>; 95 <&gic GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
96 96
97 prm: prm@4ae06000 { 97 prm: prm@4ae06000 {
98 compatible = "ti,dra7-prm"; 98 compatible = "ti,dra7-prm";
@@ -344,7 +344,7 @@
344 uart1: serial@4806a000 { 344 uart1: serial@4806a000 {
345 compatible = "ti,omap4-uart"; 345 compatible = "ti,omap4-uart";
346 reg = <0x4806a000 0x100>; 346 reg = <0x4806a000 0x100>;
347 interrupts-extended = <&gic GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; 347 interrupts-extended = <&crossbar_mpu GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
348 ti,hwmods = "uart1"; 348 ti,hwmods = "uart1";
349 clock-frequency = <48000000>; 349 clock-frequency = <48000000>;
350 status = "disabled"; 350 status = "disabled";
@@ -355,7 +355,7 @@
355 uart2: serial@4806c000 { 355 uart2: serial@4806c000 {
356 compatible = "ti,omap4-uart"; 356 compatible = "ti,omap4-uart";
357 reg = <0x4806c000 0x100>; 357 reg = <0x4806c000 0x100>;
358 interrupts-extended = <&gic GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>; 358 interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
359 ti,hwmods = "uart2"; 359 ti,hwmods = "uart2";
360 clock-frequency = <48000000>; 360 clock-frequency = <48000000>;
361 status = "disabled"; 361 status = "disabled";
@@ -366,7 +366,7 @@
366 uart3: serial@48020000 { 366 uart3: serial@48020000 {
367 compatible = "ti,omap4-uart"; 367 compatible = "ti,omap4-uart";
368 reg = <0x48020000 0x100>; 368 reg = <0x48020000 0x100>;
369 interrupts-extended = <&gic GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; 369 interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
370 ti,hwmods = "uart3"; 370 ti,hwmods = "uart3";
371 clock-frequency = <48000000>; 371 clock-frequency = <48000000>;
372 status = "disabled"; 372 status = "disabled";
@@ -377,7 +377,7 @@
377 uart4: serial@4806e000 { 377 uart4: serial@4806e000 {
378 compatible = "ti,omap4-uart"; 378 compatible = "ti,omap4-uart";
379 reg = <0x4806e000 0x100>; 379 reg = <0x4806e000 0x100>;
380 interrupts-extended = <&gic GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; 380 interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
381 ti,hwmods = "uart4"; 381 ti,hwmods = "uart4";
382 clock-frequency = <48000000>; 382 clock-frequency = <48000000>;
383 status = "disabled"; 383 status = "disabled";
@@ -388,7 +388,7 @@
388 uart5: serial@48066000 { 388 uart5: serial@48066000 {
389 compatible = "ti,omap4-uart"; 389 compatible = "ti,omap4-uart";
390 reg = <0x48066000 0x100>; 390 reg = <0x48066000 0x100>;
391 interrupts-extended = <&gic GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>; 391 interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
392 ti,hwmods = "uart5"; 392 ti,hwmods = "uart5";
393 clock-frequency = <48000000>; 393 clock-frequency = <48000000>;
394 status = "disabled"; 394 status = "disabled";
@@ -399,7 +399,7 @@
399 uart6: serial@48068000 { 399 uart6: serial@48068000 {
400 compatible = "ti,omap4-uart"; 400 compatible = "ti,omap4-uart";
401 reg = <0x48068000 0x100>; 401 reg = <0x48068000 0x100>;
402 interrupts-extended = <&gic GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>; 402 interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
403 ti,hwmods = "uart6"; 403 ti,hwmods = "uart6";
404 clock-frequency = <48000000>; 404 clock-frequency = <48000000>;
405 status = "disabled"; 405 status = "disabled";
@@ -410,7 +410,7 @@
410 uart7: serial@48420000 { 410 uart7: serial@48420000 {
411 compatible = "ti,omap4-uart"; 411 compatible = "ti,omap4-uart";
412 reg = <0x48420000 0x100>; 412 reg = <0x48420000 0x100>;
413 interrupts-extended = <&gic GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>; 413 interrupts = <GIC_SPI 218 IRQ_TYPE_LEVEL_HIGH>;
414 ti,hwmods = "uart7"; 414 ti,hwmods = "uart7";
415 clock-frequency = <48000000>; 415 clock-frequency = <48000000>;
416 status = "disabled"; 416 status = "disabled";
@@ -419,7 +419,7 @@
419 uart8: serial@48422000 { 419 uart8: serial@48422000 {
420 compatible = "ti,omap4-uart"; 420 compatible = "ti,omap4-uart";
421 reg = <0x48422000 0x100>; 421 reg = <0x48422000 0x100>;
422 interrupts-extended = <&gic GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>; 422 interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>;
423 ti,hwmods = "uart8"; 423 ti,hwmods = "uart8";
424 clock-frequency = <48000000>; 424 clock-frequency = <48000000>;
425 status = "disabled"; 425 status = "disabled";
@@ -428,7 +428,7 @@
428 uart9: serial@48424000 { 428 uart9: serial@48424000 {
429 compatible = "ti,omap4-uart"; 429 compatible = "ti,omap4-uart";
430 reg = <0x48424000 0x100>; 430 reg = <0x48424000 0x100>;
431 interrupts-extended = <&gic GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>; 431 interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
432 ti,hwmods = "uart9"; 432 ti,hwmods = "uart9";
433 clock-frequency = <48000000>; 433 clock-frequency = <48000000>;
434 status = "disabled"; 434 status = "disabled";
@@ -437,7 +437,7 @@
437 uart10: serial@4ae2b000 { 437 uart10: serial@4ae2b000 {
438 compatible = "ti,omap4-uart"; 438 compatible = "ti,omap4-uart";
439 reg = <0x4ae2b000 0x100>; 439 reg = <0x4ae2b000 0x100>;
440 interrupts-extended = <&gic GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>; 440 interrupts = <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>;
441 ti,hwmods = "uart10"; 441 ti,hwmods = "uart10";
442 clock-frequency = <48000000>; 442 clock-frequency = <48000000>;
443 status = "disabled"; 443 status = "disabled";
@@ -1337,9 +1337,12 @@
1337 status = "disabled"; 1337 status = "disabled";
1338 }; 1338 };
1339 1339
1340 crossbar_mpu: crossbar@4a020000 { 1340 crossbar_mpu: crossbar@4a002a48 {
1341 compatible = "ti,irq-crossbar"; 1341 compatible = "ti,irq-crossbar";
1342 reg = <0x4a002a48 0x130>; 1342 reg = <0x4a002a48 0x130>;
1343 interrupt-controller;
1344 interrupt-parent = <&gic>;
1345 #interrupt-cells = <3>;
1343 ti,max-irqs = <160>; 1346 ti,max-irqs = <160>;
1344 ti,max-crossbar-sources = <MAX_SOURCES>; 1347 ti,max-crossbar-sources = <MAX_SOURCES>;
1345 ti,reg-size = <2>; 1348 ti,reg-size = <2>;
diff --git a/arch/arm/boot/dts/dra72-evm.dts b/arch/arm/boot/dts/dra72-evm.dts
index 4d8711713610..2373054f588d 100644
--- a/arch/arm/boot/dts/dra72-evm.dts
+++ b/arch/arm/boot/dts/dra72-evm.dts
@@ -160,7 +160,6 @@
160 pinctrl-0 = <&tps65917_pins_default>; 160 pinctrl-0 = <&tps65917_pins_default>;
161 161
162 interrupts = <GIC_SPI 2 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */ 162 interrupts = <GIC_SPI 2 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */
163 interrupt-parent = <&gic>;
164 interrupt-controller; 163 interrupt-controller;
165 #interrupt-cells = <2>; 164 #interrupt-cells = <2>;
166 165
diff --git a/arch/arm/boot/dts/dra72x.dtsi b/arch/arm/boot/dts/dra72x.dtsi
index e5a3d23a3df1..e782bf1dd863 100644
--- a/arch/arm/boot/dts/dra72x.dtsi
+++ b/arch/arm/boot/dts/dra72x.dtsi
@@ -25,6 +25,7 @@
25 25
26 pmu { 26 pmu {
27 compatible = "arm,cortex-a15-pmu"; 27 compatible = "arm,cortex-a15-pmu";
28 interrupts = <GIC_SPI DIRECT_IRQ(131) IRQ_TYPE_LEVEL_HIGH>; 28 interrupt-parent = <&gic>;
29 interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>;
29 }; 30 };
30}; 31};
diff --git a/arch/arm/boot/dts/dra74x.dtsi b/arch/arm/boot/dts/dra74x.dtsi
index 10173fab1a15..0fc758db55f5 100644
--- a/arch/arm/boot/dts/dra74x.dtsi
+++ b/arch/arm/boot/dts/dra74x.dtsi
@@ -41,8 +41,9 @@
41 41
42 pmu { 42 pmu {
43 compatible = "arm,cortex-a15-pmu"; 43 compatible = "arm,cortex-a15-pmu";
44 interrupts = <GIC_SPI DIRECT_IRQ(131) IRQ_TYPE_LEVEL_HIGH>, 44 interrupt-parent = <&gic>;
45 <GIC_SPI DIRECT_IRQ(132) IRQ_TYPE_LEVEL_HIGH>; 45 interrupts = <GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
46 <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>;
46 }; 47 };
47 48
48 ocp { 49 ocp {
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index cee0fe1ee6ff..cf7aafb27fd1 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -22,7 +22,6 @@
22#include <linux/of_platform.h> 22#include <linux/of_platform.h>
23#include <linux/export.h> 23#include <linux/export.h>
24#include <linux/irqchip/arm-gic.h> 24#include <linux/irqchip/arm-gic.h>
25#include <linux/irqchip/irq-crossbar.h>
26#include <linux/of_address.h> 25#include <linux/of_address.h>
27#include <linux/reboot.h> 26#include <linux/reboot.h>
28#include <linux/genalloc.h> 27#include <linux/genalloc.h>
@@ -292,8 +291,5 @@ void __init omap_gic_of_init(void)
292 291
293skip_errata_init: 292skip_errata_init:
294 omap_wakeupgen_init(); 293 omap_wakeupgen_init();
295#ifdef CONFIG_IRQ_CROSSBAR
296 irqcrossbar_init();
297#endif
298 irqchip_init(); 294 irqchip_init();
299} 295}
diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c
index bbbaf5de65d2..692fe2bc8197 100644
--- a/drivers/irqchip/irq-crossbar.c
+++ b/drivers/irqchip/irq-crossbar.c
@@ -11,11 +11,12 @@
11 */ 11 */
12#include <linux/err.h> 12#include <linux/err.h>
13#include <linux/io.h> 13#include <linux/io.h>
14#include <linux/irqdomain.h>
14#include <linux/of_address.h> 15#include <linux/of_address.h>
15#include <linux/of_irq.h> 16#include <linux/of_irq.h>
16#include <linux/slab.h> 17#include <linux/slab.h>
17#include <linux/irqchip/arm-gic.h> 18
18#include <linux/irqchip/irq-crossbar.h> 19#include "irqchip.h"
19 20
20#define IRQ_FREE -1 21#define IRQ_FREE -1
21#define IRQ_RESERVED -2 22#define IRQ_RESERVED -2
@@ -24,6 +25,7 @@
24 25
25/** 26/**
26 * struct crossbar_device - crossbar device description 27 * struct crossbar_device - crossbar device description
28 * @lock: spinlock serializing access to @irq_map
27 * @int_max: maximum number of supported interrupts 29 * @int_max: maximum number of supported interrupts
28 * @safe_map: safe default value to initialize the crossbar 30 * @safe_map: safe default value to initialize the crossbar
29 * @max_crossbar_sources: Maximum number of crossbar sources 31 * @max_crossbar_sources: Maximum number of crossbar sources
@@ -33,6 +35,7 @@
33 * @write: register write function pointer 35 * @write: register write function pointer
34 */ 36 */
35struct crossbar_device { 37struct crossbar_device {
38 raw_spinlock_t lock;
36 uint int_max; 39 uint int_max;
37 uint safe_map; 40 uint safe_map;
38 uint max_crossbar_sources; 41 uint max_crossbar_sources;
@@ -44,72 +47,101 @@ struct crossbar_device {
44 47
45static struct crossbar_device *cb; 48static struct crossbar_device *cb;
46 49
47static inline void crossbar_writel(int irq_no, int cb_no) 50static void crossbar_writel(int irq_no, int cb_no)
48{ 51{
49 writel(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); 52 writel(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]);
50} 53}
51 54
52static inline void crossbar_writew(int irq_no, int cb_no) 55static void crossbar_writew(int irq_no, int cb_no)
53{ 56{
54 writew(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); 57 writew(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]);
55} 58}
56 59
57static inline void crossbar_writeb(int irq_no, int cb_no) 60static void crossbar_writeb(int irq_no, int cb_no)
58{ 61{
59 writeb(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); 62 writeb(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]);
60} 63}
61 64
62static inline int get_prev_map_irq(int cb_no) 65static struct irq_chip crossbar_chip = {
63{ 66 .name = "CBAR",
64 int i; 67 .irq_eoi = irq_chip_eoi_parent,
65 68 .irq_mask = irq_chip_mask_parent,
66 for (i = cb->int_max - 1; i >= 0; i--) 69 .irq_unmask = irq_chip_unmask_parent,
67 if (cb->irq_map[i] == cb_no) 70 .irq_retrigger = irq_chip_retrigger_hierarchy,
68 return i; 71 .irq_set_wake = irq_chip_set_wake_parent,
69 72#ifdef CONFIG_SMP
70 return -ENODEV; 73 .irq_set_affinity = irq_chip_set_affinity_parent,
71} 74#endif
75};
72 76
73static inline int allocate_free_irq(int cb_no) 77static int allocate_gic_irq(struct irq_domain *domain, unsigned virq,
78 irq_hw_number_t hwirq)
74{ 79{
80 struct of_phandle_args args;
75 int i; 81 int i;
82 int err;
76 83
84 raw_spin_lock(&cb->lock);
77 for (i = cb->int_max - 1; i >= 0; i--) { 85 for (i = cb->int_max - 1; i >= 0; i--) {
78 if (cb->irq_map[i] == IRQ_FREE) { 86 if (cb->irq_map[i] == IRQ_FREE) {
79 cb->irq_map[i] = cb_no; 87 cb->irq_map[i] = hwirq;
80 return i; 88 break;
81 } 89 }
82 } 90 }
91 raw_spin_unlock(&cb->lock);
83 92
84 return -ENODEV; 93 if (i < 0)
85} 94 return -ENODEV;
86 95
87static inline bool needs_crossbar_write(irq_hw_number_t hw) 96 args.np = domain->parent->of_node;
88{ 97 args.args_count = 3;
89 int cb_no; 98 args.args[0] = 0; /* SPI */
99 args.args[1] = i;
100 args.args[2] = IRQ_TYPE_LEVEL_HIGH;
90 101
91 if (hw > GIC_IRQ_START) { 102 err = irq_domain_alloc_irqs_parent(domain, virq, 1, &args);
92 cb_no = cb->irq_map[hw - GIC_IRQ_START]; 103 if (err)
93 if (cb_no != IRQ_RESERVED && cb_no != IRQ_SKIP) 104 cb->irq_map[i] = IRQ_FREE;
94 return true; 105 else
95 } 106 cb->write(i, hwirq);
96 107
97 return false; 108 return err;
98} 109}
99 110
100static int crossbar_domain_map(struct irq_domain *d, unsigned int irq, 111static int crossbar_domain_alloc(struct irq_domain *d, unsigned int virq,
101 irq_hw_number_t hw) 112 unsigned int nr_irqs, void *data)
102{ 113{
103 if (needs_crossbar_write(hw)) 114 struct of_phandle_args *args = data;
104 cb->write(hw - GIC_IRQ_START, cb->irq_map[hw - GIC_IRQ_START]); 115 irq_hw_number_t hwirq;
116 int i;
117
118 if (args->args_count != 3)
119 return -EINVAL; /* Not GIC compliant */
120 if (args->args[0] != 0)
121 return -EINVAL; /* No PPI should point to this domain */
122
123 hwirq = args->args[1];
124 if ((hwirq + nr_irqs) > cb->max_crossbar_sources)
125 return -EINVAL; /* Can't deal with this */
126
127 for (i = 0; i < nr_irqs; i++) {
128 int err = allocate_gic_irq(d, virq + i, hwirq + i);
129
130 if (err)
131 return err;
132
133 irq_domain_set_hwirq_and_chip(d, virq + i, hwirq + i,
134 &crossbar_chip, NULL);
135 }
105 136
106 return 0; 137 return 0;
107} 138}
108 139
109/** 140/**
110 * crossbar_domain_unmap - unmap a crossbar<->irq connection 141 * crossbar_domain_free - unmap/free a crossbar<->irq connection
111 * @d: domain of irq to unmap 142 * @domain: domain of irq to unmap
112 * @irq: virq number 143 * @virq: virq number
144 * @nr_irqs: number of irqs to free
113 * 145 *
114 * We do not maintain a use count of total number of map/unmap 146 * We do not maintain a use count of total number of map/unmap
115 * calls for a particular irq to find out if a irq can be really 147 * calls for a particular irq to find out if a irq can be really
@@ -117,14 +149,20 @@ static int crossbar_domain_map(struct irq_domain *d, unsigned int irq,
117 * after which irq is anyways unusable. So an explicit map has to be called 149 * after which irq is anyways unusable. So an explicit map has to be called
118 * after that. 150 * after that.
119 */ 151 */
120static void crossbar_domain_unmap(struct irq_domain *d, unsigned int irq) 152static void crossbar_domain_free(struct irq_domain *domain, unsigned int virq,
153 unsigned int nr_irqs)
121{ 154{
122 irq_hw_number_t hw = irq_get_irq_data(irq)->hwirq; 155 int i;
123 156
124 if (needs_crossbar_write(hw)) { 157 raw_spin_lock(&cb->lock);
125 cb->irq_map[hw - GIC_IRQ_START] = IRQ_FREE; 158 for (i = 0; i < nr_irqs; i++) {
126 cb->write(hw - GIC_IRQ_START, cb->safe_map); 159 struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
160
161 irq_domain_reset_irq_data(d);
162 cb->irq_map[d->hwirq] = IRQ_FREE;
163 cb->write(d->hwirq, cb->safe_map);
127 } 164 }
165 raw_spin_unlock(&cb->lock);
128} 166}
129 167
130static int crossbar_domain_xlate(struct irq_domain *d, 168static int crossbar_domain_xlate(struct irq_domain *d,
@@ -133,44 +171,22 @@ static int crossbar_domain_xlate(struct irq_domain *d,
133 unsigned long *out_hwirq, 171 unsigned long *out_hwirq,
134 unsigned int *out_type) 172 unsigned int *out_type)
135{ 173{
136 int ret; 174 if (d->of_node != controller)
137 int req_num = intspec[1]; 175 return -EINVAL; /* Shouldn't happen, really... */
138 int direct_map_num; 176 if (intsize != 3)
139 177 return -EINVAL; /* Not GIC compliant */
140 if (req_num >= cb->max_crossbar_sources) { 178 if (intspec[0] != 0)
141 direct_map_num = req_num - cb->max_crossbar_sources; 179 return -EINVAL; /* No PPI should point to this domain */
142 if (direct_map_num < cb->int_max) { 180
143 ret = cb->irq_map[direct_map_num]; 181 *out_hwirq = intspec[1];
144 if (ret == IRQ_RESERVED || ret == IRQ_SKIP) { 182 *out_type = intspec[2];
145 /* We use the interrupt num as h/w irq num */
146 ret = direct_map_num;
147 goto found;
148 }
149 }
150
151 pr_err("%s: requested crossbar number %d > max %d\n",
152 __func__, req_num, cb->max_crossbar_sources);
153 return -EINVAL;
154 }
155
156 ret = get_prev_map_irq(req_num);
157 if (ret >= 0)
158 goto found;
159
160 ret = allocate_free_irq(req_num);
161
162 if (ret < 0)
163 return ret;
164
165found:
166 *out_hwirq = ret + GIC_IRQ_START;
167 return 0; 183 return 0;
168} 184}
169 185
170static const struct irq_domain_ops routable_irq_domain_ops = { 186static const struct irq_domain_ops crossbar_domain_ops = {
171 .map = crossbar_domain_map, 187 .alloc = crossbar_domain_alloc,
172 .unmap = crossbar_domain_unmap, 188 .free = crossbar_domain_free,
173 .xlate = crossbar_domain_xlate 189 .xlate = crossbar_domain_xlate,
174}; 190};
175 191
176static int __init crossbar_of_init(struct device_node *node) 192static int __init crossbar_of_init(struct device_node *node)
@@ -293,7 +309,8 @@ static int __init crossbar_of_init(struct device_node *node)
293 cb->write(i, cb->safe_map); 309 cb->write(i, cb->safe_map);
294 } 310 }
295 311
296 register_routable_domain_ops(&routable_irq_domain_ops); 312 raw_spin_lock_init(&cb->lock);
313
297 return 0; 314 return 0;
298 315
299err_reg_offset: 316err_reg_offset:
@@ -309,18 +326,37 @@ err_cb:
309 return ret; 326 return ret;
310} 327}
311 328
312static const struct of_device_id crossbar_match[] __initconst = { 329static int __init irqcrossbar_init(struct device_node *node,
313 { .compatible = "ti,irq-crossbar" }, 330 struct device_node *parent)
314 {}
315};
316
317int __init irqcrossbar_init(void)
318{ 331{
319 struct device_node *np; 332 struct irq_domain *parent_domain, *domain;
320 np = of_find_matching_node(NULL, crossbar_match); 333 int err;
321 if (!np) 334
335 if (!parent) {
336 pr_err("%s: no parent, giving up\n", node->full_name);
322 return -ENODEV; 337 return -ENODEV;
338 }
339
340 parent_domain = irq_find_host(parent);
341 if (!parent_domain) {
342 pr_err("%s: unable to obtain parent domain\n", node->full_name);
343 return -ENXIO;
344 }
345
346 err = crossbar_of_init(node);
347 if (err)
348 return err;
349
350 domain = irq_domain_add_hierarchy(parent_domain, 0,
351 cb->max_crossbar_sources,
352 node, &crossbar_domain_ops,
353 NULL);
354 if (!domain) {
355 pr_err("%s: failed to allocated domain\n", node->full_name);
356 return -ENOMEM;
357 }
323 358
324 crossbar_of_init(np);
325 return 0; 359 return 0;
326} 360}
361
362IRQCHIP_DECLARE(ti_irqcrossbar, "ti,irq-crossbar", irqcrossbar_init);
diff --git a/include/linux/irqchip/irq-crossbar.h b/include/linux/irqchip/irq-crossbar.h
deleted file mode 100644
index e5537b81df8d..000000000000
--- a/include/linux/irqchip/irq-crossbar.h
+++ /dev/null
@@ -1,11 +0,0 @@
1/*
2 * drivers/irqchip/irq-crossbar.h
3 *
4 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
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 */
11int irqcrossbar_init(void);