Skip to content

Commit e3825ba

Browse files
Marc ZyngierKAGA-KOKO
authored andcommitted
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 <[email protected]> Cc: Mark Rutland <[email protected]> Cc: [email protected] Cc: Jason Cooper <[email protected]> Cc: Will Deacon <[email protected]> Cc: Rob Herring <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thomas Gleixner <[email protected]>
1 parent 9e2c986 commit e3825ba

File tree

2 files changed

+175
-2
lines changed

2 files changed

+175
-2
lines changed

drivers/irqchip/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ config ARM_GIC_V3
2727
select IRQ_DOMAIN
2828
select MULTI_IRQ_HANDLER
2929
select IRQ_DOMAIN_HIERARCHY
30+
select PARTITION_PERCPU
3031

3132
config ARM_GIC_V3_ITS
3233
bool

drivers/irqchip/irq-gic-v3.c

Lines changed: 174 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include <linux/irqchip.h>
3131
#include <linux/irqchip/arm-gic-v3.h>
32+
#include <linux/irqchip/irq-partition-percpu.h>
3233

3334
#include <asm/cputype.h>
3435
#include <asm/exception.h>
@@ -44,13 +45,15 @@ struct redist_region {
4445
};
4546

4647
struct gic_chip_data {
48+
struct fwnode_handle *fwnode;
4749
void __iomem *dist_base;
4850
struct redist_region *redist_regions;
4951
struct rdists rdists;
5052
struct irq_domain *domain;
5153
u64 redist_stride;
5254
u32 nr_redist_regions;
5355
unsigned int irq_nr;
56+
struct partition_desc *ppi_descs[16];
5457
};
5558

5659
static 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,
812815
}
813816
}
814817

818+
static 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+
815841
static const struct irq_domain_ops gic_irq_domain_ops = {
816842
.translate = gic_irq_domain_translate,
817843
.alloc = gic_irq_domain_alloc,
818844
.free = gic_irq_domain_free,
845+
.select = gic_irq_domain_select,
846+
};
847+
848+
static 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+
871+
static const struct irq_domain_ops partition_domain_ops = {
872+
.translate = partition_domain_translate,
873+
.select = gic_irq_domain_select,
819874
};
820875

821876
static void gicv3_enable_quirks(void)
@@ -843,6 +898,7 @@ static int __init gic_init_bases(void __iomem *dist_base,
843898
if (static_key_true(&supports_deactivate))
844899
pr_info("GIC: Using split EOI/Deactivate mode\n");
845900

901+
gic_data.fwnode = handle;
846902
gic_data.dist_base = dist_base;
847903
gic_data.redist_regions = rdist_regs;
848904
gic_data.nr_redist_regions = nr_redist_regions;
@@ -901,6 +957,119 @@ static int __init gic_validate_dist_version(void __iomem *dist_base)
901957
return 0;
902958
}
903959

960+
static 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 */
986+
static 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+
9041073
static int __init gic_of_init(struct device_node *node, struct device_node *parent)
9051074
{
9061075
void __iomem *dist_base;
@@ -952,8 +1121,11 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
9521121

9531122
err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions,
9541123
redist_stride, &node->fwnode);
955-
if (!err)
956-
return 0;
1124+
if (err)
1125+
goto out_unmap_rdist;
1126+
1127+
gic_populate_ppi_partitions(node);
1128+
return 0;
9571129

9581130
out_unmap_rdist:
9591131
for (i = 0; i < nr_redist_regions; i++)

0 commit comments

Comments
 (0)