aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSricharan R <r.sricharan@ti.com>2013-12-03 05:27:22 -0500
committerSricharan R <r.sricharan@ti.com>2014-02-05 09:38:00 -0500
commit006e983bbc805431c44e2135e13841f66059a045 (patch)
tree9dc934900b47f2cb9ca0c3f297ad672924a786b5
parent38dbfb59d1175ef458d006556061adeaa8751b72 (diff)
DRIVERS: IRQCHIP: IRQ-GIC: Add support for routable irqs
In some socs the gic can be preceded by a crossbar IP which routes the peripheral interrupts to the gic inputs. The peripheral interrupts are associated with a fixed crossbar input line and the crossbar routes that to one of the free gic input line. The DT entries for peripherals provides the fixed crossbar input line as its interrupt number and the mapping code should associate this with a free gic input line. This patch adds the support inside the gic irqchip to handle such routable irqs. The routable irqs are registered in a linear domain. The registered routable domain's callback should be implemented to get a free irq and to configure the IP to route it. Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Linus Walleij <linus.walleij@linaro.org> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Russell King <linux@arm.linux.org.uk> Cc: Tony Lindgren <tony@atomide.com> Cc: Rajendra Nayak <rnayak@ti.com> Cc: Marc Zyngier <marc.zyngier@arm.com> Cc: Grant Likely <grant.likely@linaro.org> Cc: Rob Herring <rob.herring@calxeda.com> Signed-off-by: Sricharan R <r.sricharan@ti.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Acked-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/arm/gic.txt6
-rw-r--r--drivers/irqchip/irq-gic.c82
-rw-r--r--include/linux/irqchip/arm-gic.h7
3 files changed, 84 insertions, 11 deletions
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
index bae0d87a38b2..5573c08d3180 100644
--- a/Documentation/devicetree/bindings/arm/gic.txt
+++ b/Documentation/devicetree/bindings/arm/gic.txt
@@ -50,6 +50,11 @@ Optional
50 regions, used when the GIC doesn't have banked registers. The offset is 50 regions, used when the GIC doesn't have banked registers. The offset is
51 cpu-offset * cpu-nr. 51 cpu-offset * cpu-nr.
52 52
53- arm,routable-irqs : Total number of gic irq inputs which are not directly
54 connected from the peripherals, but are routed dynamically
55 by a crossbar/multiplexer preceding the GIC. The GIC irq
56 input line is assigned dynamically when the corresponding
57 peripheral's crossbar line is mapped.
53Example: 58Example:
54 59
55 intc: interrupt-controller@fff11000 { 60 intc: interrupt-controller@fff11000 {
@@ -57,6 +62,7 @@ Example:
57 #interrupt-cells = <3>; 62 #interrupt-cells = <3>;
58 #address-cells = <1>; 63 #address-cells = <1>;
59 interrupt-controller; 64 interrupt-controller;
65 arm,routable-irqs = <160>;
60 reg = <0xfff11000 0x1000>, 66 reg = <0xfff11000 0x1000>,
61 <0xfff10100 0x100>; 67 <0xfff10100 0x100>;
62 }; 68 };
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 341c6016812d..07a7050841ec 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -824,16 +824,25 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
824 irq_set_chip_and_handler(irq, &gic_chip, 824 irq_set_chip_and_handler(irq, &gic_chip,
825 handle_fasteoi_irq); 825 handle_fasteoi_irq);
826 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); 826 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
827
828 gic_routable_irq_domain_ops->map(d, irq, hw);
827 } 829 }
828 irq_set_chip_data(irq, d->host_data); 830 irq_set_chip_data(irq, d->host_data);
829 return 0; 831 return 0;
830} 832}
831 833
834static void gic_irq_domain_unmap(struct irq_domain *d, unsigned int irq)
835{
836 gic_routable_irq_domain_ops->unmap(d, irq);
837}
838
832static int gic_irq_domain_xlate(struct irq_domain *d, 839static int gic_irq_domain_xlate(struct irq_domain *d,
833 struct device_node *controller, 840 struct device_node *controller,
834 const u32 *intspec, unsigned int intsize, 841 const u32 *intspec, unsigned int intsize,
835 unsigned long *out_hwirq, unsigned int *out_type) 842 unsigned long *out_hwirq, unsigned int *out_type)
836{ 843{
844 unsigned long ret = 0;
845
837 if (d->of_node != controller) 846 if (d->of_node != controller)
838 return -EINVAL; 847 return -EINVAL;
839 if (intsize < 3) 848 if (intsize < 3)
@@ -843,11 +852,20 @@ static int gic_irq_domain_xlate(struct irq_domain *d,
843 *out_hwirq = intspec[1] + 16; 852 *out_hwirq = intspec[1] + 16;
844 853
845 /* For SPIs, we need to add 16 more to get the GIC irq ID number */ 854 /* For SPIs, we need to add 16 more to get the GIC irq ID number */
846 if (!intspec[0]) 855 if (!intspec[0]) {
847 *out_hwirq += 16; 856 ret = gic_routable_irq_domain_ops->xlate(d, controller,
857 intspec,
858 intsize,
859 out_hwirq,
860 out_type);
861
862 if (IS_ERR_VALUE(ret))
863 return ret;
864 }
848 865
849 *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; 866 *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
850 return 0; 867
868 return ret;
851} 869}
852 870
853#ifdef CONFIG_SMP 871#ifdef CONFIG_SMP
@@ -871,9 +889,41 @@ static struct notifier_block gic_cpu_notifier = {
871 889
872const struct irq_domain_ops gic_irq_domain_ops = { 890const struct irq_domain_ops gic_irq_domain_ops = {
873 .map = gic_irq_domain_map, 891 .map = gic_irq_domain_map,
892 .unmap = gic_irq_domain_unmap,
874 .xlate = gic_irq_domain_xlate, 893 .xlate = gic_irq_domain_xlate,
875}; 894};
876 895
896/* Default functions for routable irq domain */
897static int gic_routable_irq_domain_map(struct irq_domain *d, unsigned int irq,
898 irq_hw_number_t hw)
899{
900 return 0;
901}
902
903static void gic_routable_irq_domain_unmap(struct irq_domain *d,
904 unsigned int irq)
905{
906}
907
908static int gic_routable_irq_domain_xlate(struct irq_domain *d,
909 struct device_node *controller,
910 const u32 *intspec, unsigned int intsize,
911 unsigned long *out_hwirq,
912 unsigned int *out_type)
913{
914 *out_hwirq += 16;
915 return 0;
916}
917
918const struct irq_domain_ops gic_default_routable_irq_domain_ops = {
919 .map = gic_routable_irq_domain_map,
920 .unmap = gic_routable_irq_domain_unmap,
921 .xlate = gic_routable_irq_domain_xlate,
922};
923
924const struct irq_domain_ops *gic_routable_irq_domain_ops =
925 &gic_default_routable_irq_domain_ops;
926
877void __init gic_init_bases(unsigned int gic_nr, int irq_start, 927void __init gic_init_bases(unsigned int gic_nr, int irq_start,
878 void __iomem *dist_base, void __iomem *cpu_base, 928 void __iomem *dist_base, void __iomem *cpu_base,
879 u32 percpu_offset, struct device_node *node) 929 u32 percpu_offset, struct device_node *node)
@@ -881,6 +931,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
881 irq_hw_number_t hwirq_base; 931 irq_hw_number_t hwirq_base;
882 struct gic_chip_data *gic; 932 struct gic_chip_data *gic;
883 int gic_irqs, irq_base, i; 933 int gic_irqs, irq_base, i;
934 int nr_routable_irqs;
884 935
885 BUG_ON(gic_nr >= MAX_GIC_NR); 936 BUG_ON(gic_nr >= MAX_GIC_NR);
886 937
@@ -946,14 +997,25 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
946 gic->gic_irqs = gic_irqs; 997 gic->gic_irqs = gic_irqs;
947 998
948 gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ 999 gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
949 irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id()); 1000
950 if (IS_ERR_VALUE(irq_base)) { 1001 if (of_property_read_u32(node, "arm,routable-irqs",
951 WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", 1002 &nr_routable_irqs)) {
952 irq_start); 1003 irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
953 irq_base = irq_start; 1004 numa_node_id());
1005 if (IS_ERR_VALUE(irq_base)) {
1006 WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
1007 irq_start);
1008 irq_base = irq_start;
1009 }
1010
1011 gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
1012 hwirq_base, &gic_irq_domain_ops, gic);
1013 } else {
1014 gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
1015 &gic_irq_domain_ops,
1016 gic);
954 } 1017 }
955 gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, 1018
956 hwirq_base, &gic_irq_domain_ops, gic);
957 if (WARN_ON(!gic->domain)) 1019 if (WARN_ON(!gic->domain))
958 return; 1020 return;
959 1021
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index 0ceb389dba6c..7ed92d0560d5 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -93,6 +93,11 @@ int gic_get_cpu_id(unsigned int cpu);
93void gic_migrate_target(unsigned int new_cpu_id); 93void gic_migrate_target(unsigned int new_cpu_id);
94unsigned long gic_get_sgir_physaddr(void); 94unsigned long gic_get_sgir_physaddr(void);
95 95
96extern const struct irq_domain_ops *gic_routable_irq_domain_ops;
97static inline void __init register_routable_domain_ops
98 (const struct irq_domain_ops *ops)
99{
100 gic_routable_irq_domain_ops = ops;
101}
96#endif /* __ASSEMBLY */ 102#endif /* __ASSEMBLY */
97
98#endif 103#endif