Commit 53b13565 authored by Marc Zyngier's avatar Marc Zyngier

Merge branch irq/gicv3-eppi-partition into irq/irqchip-next

- Add support for partitionned EPPIs, modeled after the existing
  partitioned PPI support

* irq/gicv3-eppi-partition:
  irqchip/gic-v3: Fix selection of partition domain for EPPIs
  irqchip/gic-v3: Add __gic_get_ppi_index() to find the PPI number from hwirq
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parents 00a2b7c7 d753f849
...@@ -446,18 +446,23 @@ static void gic_irq_set_prio(struct irq_data *d, u8 prio) ...@@ -446,18 +446,23 @@ static void gic_irq_set_prio(struct irq_data *d, u8 prio)
writeb_relaxed(prio, base + offset + index); writeb_relaxed(prio, base + offset + index);
} }
static u32 gic_get_ppi_index(struct irq_data *d) static u32 __gic_get_ppi_index(irq_hw_number_t hwirq)
{ {
switch (get_intid_range(d)) { switch (__get_intid_range(hwirq)) {
case PPI_RANGE: case PPI_RANGE:
return d->hwirq - 16; return hwirq - 16;
case EPPI_RANGE: case EPPI_RANGE:
return d->hwirq - EPPI_BASE_INTID + 16; return hwirq - EPPI_BASE_INTID + 16;
default: default:
unreachable(); unreachable();
} }
} }
static u32 gic_get_ppi_index(struct irq_data *d)
{
return __gic_get_ppi_index(d->hwirq);
}
static int gic_irq_nmi_setup(struct irq_data *d) static int gic_irq_nmi_setup(struct irq_data *d)
{ {
struct irq_desc *desc = irq_to_desc(d->irq); struct irq_desc *desc = irq_to_desc(d->irq);
...@@ -1467,10 +1472,34 @@ static void gic_irq_domain_free(struct irq_domain *domain, unsigned int virq, ...@@ -1467,10 +1472,34 @@ static void gic_irq_domain_free(struct irq_domain *domain, unsigned int virq,
} }
} }
static bool fwspec_is_partitioned_ppi(struct irq_fwspec *fwspec,
irq_hw_number_t hwirq)
{
enum gic_intid_range range;
if (!gic_data.ppi_descs)
return false;
if (!is_of_node(fwspec->fwnode))
return false;
if (fwspec->param_count < 4 || !fwspec->param[3])
return false;
range = __get_intid_range(hwirq);
if (range != PPI_RANGE && range != EPPI_RANGE)
return false;
return true;
}
static int gic_irq_domain_select(struct irq_domain *d, static int gic_irq_domain_select(struct irq_domain *d,
struct irq_fwspec *fwspec, struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token) enum irq_domain_bus_token bus_token)
{ {
unsigned int type, ret, ppi_idx;
irq_hw_number_t hwirq;
/* Not for us */ /* Not for us */
if (fwspec->fwnode != d->fwnode) if (fwspec->fwnode != d->fwnode)
return 0; return 0;
...@@ -1479,16 +1508,19 @@ static int gic_irq_domain_select(struct irq_domain *d, ...@@ -1479,16 +1508,19 @@ static int gic_irq_domain_select(struct irq_domain *d,
if (!is_of_node(fwspec->fwnode)) if (!is_of_node(fwspec->fwnode))
return 1; return 1;
ret = gic_irq_domain_translate(d, fwspec, &hwirq, &type);
if (WARN_ON_ONCE(ret))
return 0;
if (!fwspec_is_partitioned_ppi(fwspec, hwirq))
return d == gic_data.domain;
/* /*
* If this is a PPI and we have a 4th (non-null) parameter, * If this is a PPI and we have a 4th (non-null) parameter,
* then we need to match the partition domain. * then we need to match the partition domain.
*/ */
if (fwspec->param_count >= 4 && ppi_idx = __gic_get_ppi_index(hwirq);
fwspec->param[0] == 1 && fwspec->param[3] != 0 && return d == partition_get_domain(gic_data.ppi_descs[ppi_idx]);
gic_data.ppi_descs)
return d == partition_get_domain(gic_data.ppi_descs[fwspec->param[1]]);
return d == gic_data.domain;
} }
static const struct irq_domain_ops gic_irq_domain_ops = { static const struct irq_domain_ops gic_irq_domain_ops = {
...@@ -1503,7 +1535,9 @@ static int partition_domain_translate(struct irq_domain *d, ...@@ -1503,7 +1535,9 @@ static int partition_domain_translate(struct irq_domain *d,
unsigned long *hwirq, unsigned long *hwirq,
unsigned int *type) unsigned int *type)
{ {
unsigned long ppi_intid;
struct device_node *np; struct device_node *np;
unsigned int ppi_idx;
int ret; int ret;
if (!gic_data.ppi_descs) if (!gic_data.ppi_descs)
...@@ -1513,7 +1547,12 @@ static int partition_domain_translate(struct irq_domain *d, ...@@ -1513,7 +1547,12 @@ static int partition_domain_translate(struct irq_domain *d,
if (WARN_ON(!np)) if (WARN_ON(!np))
return -EINVAL; return -EINVAL;
ret = partition_translate_id(gic_data.ppi_descs[fwspec->param[1]], ret = gic_irq_domain_translate(d, fwspec, &ppi_intid, type);
if (WARN_ON_ONCE(ret))
return 0;
ppi_idx = __gic_get_ppi_index(ppi_intid);
ret = partition_translate_id(gic_data.ppi_descs[ppi_idx],
of_node_to_fwnode(np)); of_node_to_fwnode(np));
if (ret < 0) if (ret < 0)
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment