aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2016-04-11 04:57:54 -0400
committerThomas Gleixner <tglx@linutronix.de>2016-05-02 07:42:51 -0400
commite3825ba1af3a27d7522c9f5f929f5a13b8b138ae (patch)
tree3e534ebf9898015be66b10a3d3ca1cbcc74302d1
parent9e2c986cb460bf97154f18e85aa833739a1e8dc7 (diff)
irqchip/gic-v3: Add support for partitioned PPIs
Plug the partitioning layer into the GICv3 PPI code, parsing the DT and building the partition affinities and providing the generic code with partition data and callbacks. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: devicetree@vger.kernel.org Cc: Jason Cooper <jason@lakedaemon.net> Cc: Will Deacon <will.deacon@arm.com> Cc: Rob Herring <robh+dt@kernel.org> Link: http://lkml.kernel.org/r/1460365075-7316-5-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--drivers/irqchip/Kconfig1
-rw-r--r--drivers/irqchip/irq-gic-v3.c176
2 files changed, 175 insertions, 2 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index ea1836b25156..6c17de7997b9 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -27,6 +27,7 @@ config ARM_GIC_V3
27 select IRQ_DOMAIN 27 select IRQ_DOMAIN
28 select MULTI_IRQ_HANDLER 28 select MULTI_IRQ_HANDLER
29 select IRQ_DOMAIN_HIERARCHY 29 select IRQ_DOMAIN_HIERARCHY
30 select PARTITION_PERCPU
30 31
31config ARM_GIC_V3_ITS 32config ARM_GIC_V3_ITS
32 bool 33 bool
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 5b7d3c2129d8..f83e5f4ec701 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -29,6 +29,7 @@
29 29
30#include <linux/irqchip.h> 30#include <linux/irqchip.h>
31#include <linux/irqchip/arm-gic-v3.h> 31#include <linux/irqchip/arm-gic-v3.h>
32#include <linux/irqchip/irq-partition-percpu.h>
32 33
33#include <asm/cputype.h> 34#include <asm/cputype.h>
34#include <asm/exception.h> 35#include <asm/exception.h>
@@ -44,6 +45,7 @@ struct redist_region {
44}; 45};
45 46
46struct gic_chip_data { 47struct gic_chip_data {
48 struct fwnode_handle *fwnode;
47 void __iomem *dist_base; 49 void __iomem *dist_base;
48 struct redist_region *redist_regions; 50 struct redist_region *redist_regions;
49 struct rdists rdists; 51 struct rdists rdists;
@@ -51,6 +53,7 @@ struct gic_chip_data {
51 u64 redist_stride; 53 u64 redist_stride;
52 u32 nr_redist_regions; 54 u32 nr_redist_regions;
53 unsigned int irq_nr; 55 unsigned int irq_nr;
56 struct partition_desc *ppi_descs[16];
54}; 57};
55 58
56static struct gic_chip_data gic_data __read_mostly; 59static struct gic_chip_data gic_data __read_mostly;
@@ -812,10 +815,62 @@ static void gic_irq_domain_free(struct irq_domain *domain, unsigned int virq,
812 } 815 }
813} 816}
814 817
818static int gic_irq_domain_select(struct irq_domain *d,
819 struct irq_fwspec *fwspec,
820 enum irq_domain_bus_token bus_token)
821{
822 /* Not for us */
823 if (fwspec->fwnode != d->fwnode)
824 return 0;
825
826 /* If this is not DT, then we have a single domain */
827 if (!is_of_node(fwspec->fwnode))
828 return 1;
829
830 /*
831 * If this is a PPI and we have a 4th (non-null) parameter,
832 * then we need to match the partition domain.
833 */
834 if (fwspec->param_count >= 4 &&
835 fwspec->param[0] == 1 && fwspec->param[3] != 0)
836 return d == partition_get_domain(gic_data.ppi_descs[fwspec->param[1]]);
837
838 return d == gic_data.domain;
839}
840
815static const struct irq_domain_ops gic_irq_domain_ops = { 841static const struct irq_domain_ops gic_irq_domain_ops = {
816 .translate = gic_irq_domain_translate, 842 .translate = gic_irq_domain_translate,
817 .alloc = gic_irq_domain_alloc, 843 .alloc = gic_irq_domain_alloc,
818 .free = gic_irq_domain_free, 844 .free = gic_irq_domain_free,
845 .select = gic_irq_domain_select,
846};
847
848static int partition_domain_translate(struct irq_domain *d,
849 struct irq_fwspec *fwspec,
850 unsigned long *hwirq,
851 unsigned int *type)
852{
853 struct device_node *np;
854 int ret;
855
856 np = of_find_node_by_phandle(fwspec->param[3]);
857 if (WARN_ON(!np))
858 return -EINVAL;
859
860 ret = partition_translate_id(gic_data.ppi_descs[fwspec->param[1]],
861 of_node_to_fwnode(np));
862 if (ret < 0)
863 return ret;
864
865 *hwirq = ret;
866 *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
867
868 return 0;
869}
870
871static const struct irq_domain_ops partition_domain_ops = {
872 .translate = partition_domain_translate,
873 .select = gic_irq_domain_select,
819}; 874};
820 875
821static void gicv3_enable_quirks(void) 876static void gicv3_enable_quirks(void)
@@ -843,6 +898,7 @@ static int __init gic_init_bases(void __iomem *dist_base,
843 if (static_key_true(&supports_deactivate)) 898 if (static_key_true(&supports_deactivate))
844 pr_info("GIC: Using split EOI/Deactivate mode\n"); 899 pr_info("GIC: Using split EOI/Deactivate mode\n");
845 900
901 gic_data.fwnode = handle;
846 gic_data.dist_base = dist_base; 902 gic_data.dist_base = dist_base;
847 gic_data.redist_regions = rdist_regs; 903 gic_data.redist_regions = rdist_regs;
848 gic_data.nr_redist_regions = nr_redist_regions; 904 gic_data.nr_redist_regions = nr_redist_regions;
@@ -901,6 +957,119 @@ static int __init gic_validate_dist_version(void __iomem *dist_base)
901 return 0; 957 return 0;
902} 958}
903 959
960static int get_cpu_number(struct device_node *dn)
961{
962 const __be32 *cell;
963 u64 hwid;
964 int i;
965
966 cell = of_get_property(dn, "reg", NULL);
967 if (!cell)
968 return -1;
969
970 hwid = of_read_number(cell, of_n_addr_cells(dn));
971
972 /*
973 * Non affinity bits must be set to 0 in the DT
974 */
975 if (hwid & ~MPIDR_HWID_BITMASK)
976 return -1;
977
978 for (i = 0; i < num_possible_cpus(); i++)
979 if (cpu_logical_map(i) == hwid)
980 return i;
981
982 return -1;
983}
984
985/* Create all possible partitions at boot time */
986static void gic_populate_ppi_partitions(struct device_node *gic_node)
987{
988 struct device_node *parts_node, *child_part;
989 int part_idx = 0, i;
990 int nr_parts;
991 struct partition_affinity *parts;
992
993 parts_node = of_find_node_by_name(gic_node, "ppi-partitions");
994 if (!parts_node)
995 return;
996
997 nr_parts = of_get_child_count(parts_node);
998
999 if (!nr_parts)
1000 return;
1001
1002 parts = kzalloc(sizeof(*parts) * nr_parts, GFP_KERNEL);
1003 if (WARN_ON(!parts))
1004 return;
1005
1006 for_each_child_of_node(parts_node, child_part) {
1007 struct partition_affinity *part;
1008 int n;
1009
1010 part = &parts[part_idx];
1011
1012 part->partition_id = of_node_to_fwnode(child_part);
1013
1014 pr_info("GIC: PPI partition %s[%d] { ",
1015 child_part->name, part_idx);
1016
1017 n = of_property_count_elems_of_size(child_part, "affinity",
1018 sizeof(u32));
1019 WARN_ON(n <= 0);
1020
1021 for (i = 0; i < n; i++) {
1022 int err, cpu;
1023 u32 cpu_phandle;
1024 struct device_node *cpu_node;
1025
1026 err = of_property_read_u32_index(child_part, "affinity",
1027 i, &cpu_phandle);
1028 if (WARN_ON(err))
1029 continue;
1030
1031 cpu_node = of_find_node_by_phandle(cpu_phandle);
1032 if (WARN_ON(!cpu_node))
1033 continue;
1034
1035 cpu = get_cpu_number(cpu_node);
1036 if (WARN_ON(cpu == -1))
1037 continue;
1038
1039 pr_cont("%s[%d] ", cpu_node->full_name, cpu);
1040
1041 cpumask_set_cpu(cpu, &part->mask);
1042 }
1043
1044 pr_cont("}\n");
1045 part_idx++;
1046 }
1047
1048 for (i = 0; i < 16; i++) {
1049 unsigned int irq;
1050 struct partition_desc *desc;
1051 struct irq_fwspec ppi_fwspec = {
1052 .fwnode = gic_data.fwnode,
1053 .param_count = 3,
1054 .param = {
1055 [0] = 1,
1056 [1] = i,
1057 [2] = IRQ_TYPE_NONE,
1058 },
1059 };
1060
1061 irq = irq_create_fwspec_mapping(&ppi_fwspec);
1062 if (WARN_ON(!irq))
1063 continue;
1064 desc = partition_create_desc(gic_data.fwnode, parts, nr_parts,
1065 irq, &partition_domain_ops);
1066 if (WARN_ON(!desc))
1067 continue;
1068
1069 gic_data.ppi_descs[i] = desc;
1070 }
1071}
1072
904static int __init gic_of_init(struct device_node *node, struct device_node *parent) 1073static int __init gic_of_init(struct device_node *node, struct device_node *parent)
905{ 1074{
906 void __iomem *dist_base; 1075 void __iomem *dist_base;
@@ -952,8 +1121,11 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
952 1121
953 err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions, 1122 err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions,
954 redist_stride, &node->fwnode); 1123 redist_stride, &node->fwnode);
955 if (!err) 1124 if (err)
956 return 0; 1125 goto out_unmap_rdist;
1126
1127 gic_populate_ppi_partitions(node);
1128 return 0;
957 1129
958out_unmap_rdist: 1130out_unmap_rdist:
959 for (i = 0; i < nr_redist_regions; i++) 1131 for (i = 0; i < nr_redist_regions; i++)