Commit 4c0946c4 authored by Grant Likely's avatar Grant Likely

irqdomain: eliminate slow-path revmap lookups

With the current state of irq_domain, the reverse map is always updated
when new IRQs get mapped.  This means that the irq_find_mapping() function
can be simplified to execute the revmap lookup functions unconditionally

This patch adds lookup functions for the revmaps that don't yet have one
and removes the slow path lookup code path.

v8: Broke out unrelated changes into separate patches.  Rebased on Paul's irq
    association patches.
v7: Rebased to irqdomain/next for v3.4 and applied before the removal of 'hint'
v6: Remove the slow path entirely.  The only place where the slow path
    could get called is for a linear mapping if the hwirq number is larger
    than the linear revmap size.  There shouldn't be any interrupt
    controllers that do that.
v5: rewrite to not use a ->revmap() callback.  It is simpler, smaller,
    safer and faster to open code each of the revmap lookups directly into
    irq_find_mapping() via a switch statement.
v4: Fix build failure on incorrect variable reference.
Signed-off-by: default avatarGrant Likely <grant.likely@secretlab.ca>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Milton Miller <miltonm@bga.com>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Rob Herring <rob.herring@calxeda.com>
parent 6aeea3ec
...@@ -686,16 +686,11 @@ EXPORT_SYMBOL_GPL(irq_dispose_mapping); ...@@ -686,16 +686,11 @@ EXPORT_SYMBOL_GPL(irq_dispose_mapping);
* irq_find_mapping() - Find a linux irq from an hw irq number. * irq_find_mapping() - Find a linux irq from an hw irq number.
* @domain: domain owning this hardware interrupt * @domain: domain owning this hardware interrupt
* @hwirq: hardware irq number in that domain space * @hwirq: hardware irq number in that domain space
*
* This is a slow path, for use by generic code. It's expected that an
* irq controller implementation directly calls the appropriate low level
* mapping function.
*/ */
unsigned int irq_find_mapping(struct irq_domain *domain, unsigned int irq_find_mapping(struct irq_domain *domain,
irq_hw_number_t hwirq) irq_hw_number_t hwirq)
{ {
unsigned int i; struct irq_data *data;
unsigned int hint = hwirq % nr_irqs;
/* Look for default domain if nececssary */ /* Look for default domain if nececssary */
if (domain == NULL) if (domain == NULL)
...@@ -703,22 +698,25 @@ unsigned int irq_find_mapping(struct irq_domain *domain, ...@@ -703,22 +698,25 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
if (domain == NULL) if (domain == NULL)
return 0; return 0;
/* legacy -> bail early */ switch (domain->revmap_type) {
if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY) case IRQ_DOMAIN_MAP_LEGACY:
return irq_domain_legacy_revmap(domain, hwirq); return irq_domain_legacy_revmap(domain, hwirq);
case IRQ_DOMAIN_MAP_LINEAR:
/* Slow path does a linear search of the map */ return irq_linear_revmap(domain, hwirq);
if (hint == 0) case IRQ_DOMAIN_MAP_TREE:
hint = 1; rcu_read_lock();
i = hint; data = radix_tree_lookup(&domain->revmap_data.tree, hwirq);
do { rcu_read_unlock();
struct irq_data *data = irq_get_irq_data(i); if (data)
return data->irq;
break;
case IRQ_DOMAIN_MAP_NOMAP:
data = irq_get_irq_data(hwirq);
if (data && (data->domain == domain) && (data->hwirq == hwirq)) if (data && (data->domain == domain) && (data->hwirq == hwirq))
return i; return hwirq;
i++; break;
if (i >= nr_irqs) }
i = 1;
} while(i != hint);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(irq_find_mapping); EXPORT_SYMBOL_GPL(irq_find_mapping);
...@@ -728,32 +726,19 @@ EXPORT_SYMBOL_GPL(irq_find_mapping); ...@@ -728,32 +726,19 @@ EXPORT_SYMBOL_GPL(irq_find_mapping);
* @domain: domain owning this hardware interrupt * @domain: domain owning this hardware interrupt
* @hwirq: hardware irq number in that domain space * @hwirq: hardware irq number in that domain space
* *
* This is a fast path, for use by irq controller code that uses linear * This is a fast path that can be called directly by irq controller code to
* revmaps. It does fallback to the slow path if the revmap doesn't exist * save a handful of instructions.
* yet and will create the revmap entry with appropriate locking
*/ */
unsigned int irq_linear_revmap(struct irq_domain *domain, unsigned int irq_linear_revmap(struct irq_domain *domain,
irq_hw_number_t hwirq) irq_hw_number_t hwirq)
{ {
unsigned int *revmap; BUG_ON(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR);
if (WARN_ON_ONCE(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR)) /* Check revmap bounds; complain if exceeded */
return irq_find_mapping(domain, hwirq); if (WARN_ON(hwirq >= domain->revmap_data.linear.size))
return 0;
/* Check revmap bounds */
if (unlikely(hwirq >= domain->revmap_data.linear.size))
return irq_find_mapping(domain, hwirq);
/* Check if revmap was allocated */
revmap = domain->revmap_data.linear.revmap;
if (unlikely(revmap == NULL))
return irq_find_mapping(domain, hwirq);
/* Fill up revmap with slow path if no mapping found */
if (unlikely(!revmap[hwirq]))
revmap[hwirq] = irq_find_mapping(domain, hwirq);
return revmap[hwirq]; return domain->revmap_data.linear.revmap[hwirq];
} }
EXPORT_SYMBOL_GPL(irq_linear_revmap); EXPORT_SYMBOL_GPL(irq_linear_revmap);
......
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