Skip to content

Commit d753f84

Browse files
James MorseMarc Zyngier
authored andcommitted
irqchip/gic-v3: Fix selection of partition domain for EPPIs
commit 5f51f80 ("irqchip/gic-v3: Add EPPI range support") added GIC_IRQ_TYPE_PARTITION support for EPPI to gic_irq_domain_translate(), and commit 52085d3 ("irqchip/gic-v3: Dynamically allocate PPI partition descriptors") made the gic_data.ppi_descs array big enough for EPPI, but neither gic_irq_domain_select() nor partition_domain_translate() were updated. This means partitions are created by partition_create_desc() for the EPPI range, but can't be registered as they will always match the root domain and map to the summary interrupt. Update gic_irq_domain_select() to match PPI and EPPI. The fwspec for PPI and EPPI both start from 0. Use gic_irq_domain_translate() to find the hwirq from the fwspec, then convert this to a ppi index. Reported-by: Valentin Schneider <[email protected]> Signed-off-by: James Morse <[email protected]> Reviewed-by: Valentin Schneider <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent bfa80ee commit d753f84

File tree

1 file changed

+41
-7
lines changed

1 file changed

+41
-7
lines changed

drivers/irqchip/irq-gic-v3.c

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,10 +1472,34 @@ static void gic_irq_domain_free(struct irq_domain *domain, unsigned int virq,
14721472
}
14731473
}
14741474

1475+
static bool fwspec_is_partitioned_ppi(struct irq_fwspec *fwspec,
1476+
irq_hw_number_t hwirq)
1477+
{
1478+
enum gic_intid_range range;
1479+
1480+
if (!gic_data.ppi_descs)
1481+
return false;
1482+
1483+
if (!is_of_node(fwspec->fwnode))
1484+
return false;
1485+
1486+
if (fwspec->param_count < 4 || !fwspec->param[3])
1487+
return false;
1488+
1489+
range = __get_intid_range(hwirq);
1490+
if (range != PPI_RANGE && range != EPPI_RANGE)
1491+
return false;
1492+
1493+
return true;
1494+
}
1495+
14751496
static int gic_irq_domain_select(struct irq_domain *d,
14761497
struct irq_fwspec *fwspec,
14771498
enum irq_domain_bus_token bus_token)
14781499
{
1500+
unsigned int type, ret, ppi_idx;
1501+
irq_hw_number_t hwirq;
1502+
14791503
/* Not for us */
14801504
if (fwspec->fwnode != d->fwnode)
14811505
return 0;
@@ -1484,16 +1508,19 @@ static int gic_irq_domain_select(struct irq_domain *d,
14841508
if (!is_of_node(fwspec->fwnode))
14851509
return 1;
14861510

1511+
ret = gic_irq_domain_translate(d, fwspec, &hwirq, &type);
1512+
if (WARN_ON_ONCE(ret))
1513+
return 0;
1514+
1515+
if (!fwspec_is_partitioned_ppi(fwspec, hwirq))
1516+
return d == gic_data.domain;
1517+
14871518
/*
14881519
* If this is a PPI and we have a 4th (non-null) parameter,
14891520
* then we need to match the partition domain.
14901521
*/
1491-
if (fwspec->param_count >= 4 &&
1492-
fwspec->param[0] == 1 && fwspec->param[3] != 0 &&
1493-
gic_data.ppi_descs)
1494-
return d == partition_get_domain(gic_data.ppi_descs[fwspec->param[1]]);
1495-
1496-
return d == gic_data.domain;
1522+
ppi_idx = __gic_get_ppi_index(hwirq);
1523+
return d == partition_get_domain(gic_data.ppi_descs[ppi_idx]);
14971524
}
14981525

14991526
static const struct irq_domain_ops gic_irq_domain_ops = {
@@ -1508,7 +1535,9 @@ static int partition_domain_translate(struct irq_domain *d,
15081535
unsigned long *hwirq,
15091536
unsigned int *type)
15101537
{
1538+
unsigned long ppi_intid;
15111539
struct device_node *np;
1540+
unsigned int ppi_idx;
15121541
int ret;
15131542

15141543
if (!gic_data.ppi_descs)
@@ -1518,7 +1547,12 @@ static int partition_domain_translate(struct irq_domain *d,
15181547
if (WARN_ON(!np))
15191548
return -EINVAL;
15201549

1521-
ret = partition_translate_id(gic_data.ppi_descs[fwspec->param[1]],
1550+
ret = gic_irq_domain_translate(d, fwspec, &ppi_intid, type);
1551+
if (WARN_ON_ONCE(ret))
1552+
return 0;
1553+
1554+
ppi_idx = __gic_get_ppi_index(ppi_intid);
1555+
ret = partition_translate_id(gic_data.ppi_descs[ppi_idx],
15221556
of_node_to_fwnode(np));
15231557
if (ret < 0)
15241558
return ret;

0 commit comments

Comments
 (0)