Plug the new .get_info() callback into the GICv3 core driver, using some of the existing PPI affinity handling infrastructure. Signed-off-by: Marc Zyngier <maz@xxxxxxxxxx> --- drivers/irqchip/irq-gic-v3.c | 55 ++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index dbeb85677b08c..4a90dbf9daedb 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -69,6 +69,8 @@ struct gic_chip_data { bool has_rss; unsigned int ppi_nr; struct partition_desc **ppi_descs; + struct partition_affinity *parts; + unsigned int nr_parts; }; #define T241_CHIPS_MAX 4 @@ -1796,11 +1798,60 @@ static int gic_irq_domain_select(struct irq_domain *d, return d == partition_get_domain(gic_data.ppi_descs[ppi_idx]); } +static int gic_irq_get_info(struct irq_fwspec_info *info) +{ + struct irq_fwspec *fwspec = &info->fwspec; + const struct cpumask *mask = NULL; + + info->flags = 0; + info->affinity = NULL; + + /* ACPI is not capable of describing PPI affinity -- yet */ + if (!is_of_node(fwspec->fwnode)) + goto out; + + /* If the specifier provides an affinity, use it */ + if (fwspec->param_count == 4 && fwspec->param[3]) { + struct fwnode_handle *fw; + + switch (fwspec->param[0]) { + case 1: /* PPI */ + case 3: /* EPPI */ + break; + default: + goto out; + } + + fw = of_node_to_fwnode(of_find_node_by_phandle(fwspec->param[3])); + if (!fw) + goto out; + + for (int i = 0; i < gic_data.nr_parts; i++) { + if (gic_data.parts[i].partition_id == fw) { + mask = &gic_data.parts[i].mask; + break; + } + } + + if (!mask) + goto out; + } else { + mask = cpu_possible_mask; + } + + info->affinity = mask; + info->flags = (IRQ_FWSPEC_INFO_FWSPEC_VALID | + IRQ_FWSPEC_INFO_AFFINITY_VALID); +out: + return 0; +} + static const struct irq_domain_ops gic_irq_domain_ops = { .translate = gic_irq_domain_translate, .alloc = gic_irq_domain_alloc, .free = gic_irq_domain_free, .select = gic_irq_domain_select, + .get_info = gic_irq_get_info, }; static int partition_domain_translate(struct irq_domain *d, @@ -1839,6 +1890,7 @@ static int partition_domain_translate(struct irq_domain *d, static const struct irq_domain_ops partition_domain_ops = { .translate = partition_domain_translate, .select = gic_irq_domain_select, + .get_info = gic_irq_get_info, }; static bool gic_enable_quirk_msm8996(void *data) @@ -2231,6 +2283,9 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) part_idx++; } + gic_data.parts = parts; + gic_data.nr_parts = nr_parts; + for (i = 0; i < gic_data.ppi_nr; i++) { unsigned int irq; struct partition_desc *desc; -- 2.39.2