diff options
author | Yingjoe Chen <yingjoe.chen@mediatek.com> | 2014-11-25 03:04:19 -0500 |
---|---|---|
committer | Jason Cooper <jason@lakedaemon.net> | 2014-11-26 10:55:16 -0500 |
commit | 9a1091ef0017c40ab63e7fc0326b2dcfd4dde3a4 (patch) | |
tree | ddc2b61bfff72f1d9955b7fae88350740cf46408 /drivers/irqchip/irq-gic.c | |
parent | b3a92e2c4441affceca9e05905723532e4a61e4d (diff) |
irqchip: gic: Support hierarchy irq domain.
Add support to use gic as a parent for stacked irq domain.
Signed-off-by: Yingjoe Chen <yingjoe.chen@mediatek.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Link: https://lkml.kernel.org/r/1416902662-19281-2-git-send-email-yingjoe.chen@mediatek.com
Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Diffstat (limited to 'drivers/irqchip/irq-gic.c')
-rw-r--r-- | drivers/irqchip/irq-gic.c | 77 |
1 files changed, 53 insertions, 24 deletions
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 38493ff28fa5..ab6069b09c94 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c | |||
@@ -788,17 +788,16 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, | |||
788 | { | 788 | { |
789 | if (hw < 32) { | 789 | if (hw < 32) { |
790 | irq_set_percpu_devid(irq); | 790 | irq_set_percpu_devid(irq); |
791 | irq_set_chip_and_handler(irq, &gic_chip, | 791 | irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data, |
792 | handle_percpu_devid_irq); | 792 | handle_percpu_devid_irq, NULL, NULL); |
793 | set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); | 793 | set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); |
794 | } else { | 794 | } else { |
795 | irq_set_chip_and_handler(irq, &gic_chip, | 795 | irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data, |
796 | handle_fasteoi_irq); | 796 | handle_fasteoi_irq, NULL, NULL); |
797 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 797 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
798 | 798 | ||
799 | gic_routable_irq_domain_ops->map(d, irq, hw); | 799 | gic_routable_irq_domain_ops->map(d, irq, hw); |
800 | } | 800 | } |
801 | irq_set_chip_data(irq, d->host_data); | ||
802 | return 0; | 801 | return 0; |
803 | } | 802 | } |
804 | 803 | ||
@@ -858,6 +857,31 @@ static struct notifier_block gic_cpu_notifier = { | |||
858 | }; | 857 | }; |
859 | #endif | 858 | #endif |
860 | 859 | ||
860 | static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, | ||
861 | unsigned int nr_irqs, void *arg) | ||
862 | { | ||
863 | int i, ret; | ||
864 | irq_hw_number_t hwirq; | ||
865 | unsigned int type = IRQ_TYPE_NONE; | ||
866 | struct of_phandle_args *irq_data = arg; | ||
867 | |||
868 | ret = gic_irq_domain_xlate(domain, irq_data->np, irq_data->args, | ||
869 | irq_data->args_count, &hwirq, &type); | ||
870 | if (ret) | ||
871 | return ret; | ||
872 | |||
873 | for (i = 0; i < nr_irqs; i++) | ||
874 | gic_irq_domain_map(domain, virq + i, hwirq + i); | ||
875 | |||
876 | return 0; | ||
877 | } | ||
878 | |||
879 | static const struct irq_domain_ops gic_irq_domain_hierarchy_ops = { | ||
880 | .xlate = gic_irq_domain_xlate, | ||
881 | .alloc = gic_irq_domain_alloc, | ||
882 | .free = irq_domain_free_irqs_top, | ||
883 | }; | ||
884 | |||
861 | static const struct irq_domain_ops gic_irq_domain_ops = { | 885 | static const struct irq_domain_ops gic_irq_domain_ops = { |
862 | .map = gic_irq_domain_map, | 886 | .map = gic_irq_domain_map, |
863 | .unmap = gic_irq_domain_unmap, | 887 | .unmap = gic_irq_domain_unmap, |
@@ -948,18 +972,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, | |||
948 | gic_cpu_map[i] = 0xff; | 972 | gic_cpu_map[i] = 0xff; |
949 | 973 | ||
950 | /* | 974 | /* |
951 | * For primary GICs, skip over SGIs. | ||
952 | * For secondary GICs, skip over PPIs, too. | ||
953 | */ | ||
954 | if (gic_nr == 0 && (irq_start & 31) > 0) { | ||
955 | hwirq_base = 16; | ||
956 | if (irq_start != -1) | ||
957 | irq_start = (irq_start & ~31) + 16; | ||
958 | } else { | ||
959 | hwirq_base = 32; | ||
960 | } | ||
961 | |||
962 | /* | ||
963 | * Find out how many interrupts are supported. | 975 | * Find out how many interrupts are supported. |
964 | * The GIC only supports up to 1020 interrupt sources. | 976 | * The GIC only supports up to 1020 interrupt sources. |
965 | */ | 977 | */ |
@@ -969,10 +981,31 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, | |||
969 | gic_irqs = 1020; | 981 | gic_irqs = 1020; |
970 | gic->gic_irqs = gic_irqs; | 982 | gic->gic_irqs = gic_irqs; |
971 | 983 | ||
972 | gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ | 984 | if (node) { /* DT case */ |
985 | const struct irq_domain_ops *ops = &gic_irq_domain_hierarchy_ops; | ||
986 | |||
987 | if (!of_property_read_u32(node, "arm,routable-irqs", | ||
988 | &nr_routable_irqs)) { | ||
989 | ops = &gic_irq_domain_ops; | ||
990 | gic_irqs = nr_routable_irqs; | ||
991 | } | ||
992 | |||
993 | gic->domain = irq_domain_add_linear(node, gic_irqs, ops, gic); | ||
994 | } else { /* Non-DT case */ | ||
995 | /* | ||
996 | * For primary GICs, skip over SGIs. | ||
997 | * For secondary GICs, skip over PPIs, too. | ||
998 | */ | ||
999 | if (gic_nr == 0 && (irq_start & 31) > 0) { | ||
1000 | hwirq_base = 16; | ||
1001 | if (irq_start != -1) | ||
1002 | irq_start = (irq_start & ~31) + 16; | ||
1003 | } else { | ||
1004 | hwirq_base = 32; | ||
1005 | } | ||
1006 | |||
1007 | gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */ | ||
973 | 1008 | ||
974 | if (of_property_read_u32(node, "arm,routable-irqs", | ||
975 | &nr_routable_irqs)) { | ||
976 | irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, | 1009 | irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, |
977 | numa_node_id()); | 1010 | numa_node_id()); |
978 | if (IS_ERR_VALUE(irq_base)) { | 1011 | if (IS_ERR_VALUE(irq_base)) { |
@@ -983,10 +1016,6 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, | |||
983 | 1016 | ||
984 | gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, | 1017 | gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base, |
985 | hwirq_base, &gic_irq_domain_ops, gic); | 1018 | hwirq_base, &gic_irq_domain_ops, gic); |
986 | } else { | ||
987 | gic->domain = irq_domain_add_linear(node, nr_routable_irqs, | ||
988 | &gic_irq_domain_ops, | ||
989 | gic); | ||
990 | } | 1019 | } |
991 | 1020 | ||
992 | if (WARN_ON(!gic->domain)) | 1021 | if (WARN_ON(!gic->domain)) |