|
@@ -686,16 +686,11 @@ EXPORT_SYMBOL_GPL(irq_dispose_mapping);
|
|
|
* irq_find_mapping() - Find a linux irq from an hw irq number.
|
|
|
* @domain: domain owning this hardware interrupt
|
|
|
* @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,
|
|
|
irq_hw_number_t hwirq)
|
|
|
{
|
|
|
- unsigned int i;
|
|
|
- unsigned int hint = hwirq % nr_irqs;
|
|
|
+ struct irq_data *data;
|
|
|
|
|
|
/* Look for default domain if nececssary */
|
|
|
if (domain == NULL)
|
|
@@ -703,22 +698,25 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
|
|
|
if (domain == NULL)
|
|
|
return 0;
|
|
|
|
|
|
- /* legacy -> bail early */
|
|
|
- if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
|
|
|
+ switch (domain->revmap_type) {
|
|
|
+ case IRQ_DOMAIN_MAP_LEGACY:
|
|
|
return irq_domain_legacy_revmap(domain, hwirq);
|
|
|
-
|
|
|
- /* Slow path does a linear search of the map */
|
|
|
- if (hint == 0)
|
|
|
- hint = 1;
|
|
|
- i = hint;
|
|
|
- do {
|
|
|
- struct irq_data *data = irq_get_irq_data(i);
|
|
|
+ case IRQ_DOMAIN_MAP_LINEAR:
|
|
|
+ return irq_linear_revmap(domain, hwirq);
|
|
|
+ case IRQ_DOMAIN_MAP_TREE:
|
|
|
+ rcu_read_lock();
|
|
|
+ data = radix_tree_lookup(&domain->revmap_data.tree, hwirq);
|
|
|
+ rcu_read_unlock();
|
|
|
+ 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))
|
|
|
- return i;
|
|
|
- i++;
|
|
|
- if (i >= nr_irqs)
|
|
|
- i = 1;
|
|
|
- } while(i != hint);
|
|
|
+ return hwirq;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(irq_find_mapping);
|
|
@@ -728,32 +726,19 @@ EXPORT_SYMBOL_GPL(irq_find_mapping);
|
|
|
* @domain: domain owning this hardware interrupt
|
|
|
* @hwirq: hardware irq number in that domain space
|
|
|
*
|
|
|
- * This is a fast path, for use by irq controller code that uses linear
|
|
|
- * revmaps. It does fallback to the slow path if the revmap doesn't exist
|
|
|
- * yet and will create the revmap entry with appropriate locking
|
|
|
+ * This is a fast path that can be called directly by irq controller code to
|
|
|
+ * save a handful of instructions.
|
|
|
*/
|
|
|
unsigned int irq_linear_revmap(struct irq_domain *domain,
|
|
|
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))
|
|
|
- return irq_find_mapping(domain, hwirq);
|
|
|
-
|
|
|
- /* 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);
|
|
|
+ /* Check revmap bounds; complain if exceeded */
|
|
|
+ if (WARN_ON(hwirq >= domain->revmap_data.linear.size))
|
|
|
+ return 0;
|
|
|
|
|
|
- return revmap[hwirq];
|
|
|
+ return domain->revmap_data.linear.revmap[hwirq];
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(irq_linear_revmap);
|
|
|
|