irqdomain: Cache irq_data instead of a virq number in the revmap
authorMarc Zyngier <maz@kernel.org>
Mon, 5 Apr 2021 10:46:53 +0000 (11:46 +0100)
committerMarc Zyngier <maz@kernel.org>
Thu, 10 Jun 2021 12:09:18 +0000 (13:09 +0100)
Caching a virq number in the revmap is pretty inefficient, as
it means we will need to convert it back to either an irq_data
or irq_desc to do anything with it.

It is also a bit odd, as the radix tree does cache irq_data
pointers.

Change the revmap type to be an irq_data pointer instead of
an unsigned int, and preserve the current API for now.

Signed-off-by: Marc Zyngier <maz@kernel.org>
include/linux/irqdomain.h
kernel/irq/irqdomain.c

index 0916cf9c6e208168cc9a7d9e02255940a13d2398..340cc04611dd8061e6707226fd539d5c4ab3e1e4 100644 (file)
@@ -151,7 +151,7 @@ struct irq_domain_chip_generic;
  * Revmap data, used internally by irq_domain
  * @revmap_size: Size of the linear map table @revmap[]
  * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map
- * @revmap: Linear table of hwirq->virq reverse mappings
+ * @revmap: Linear table of irq_data pointers
  */
 struct irq_domain {
        struct list_head link;
@@ -174,7 +174,7 @@ struct irq_domain {
        unsigned int revmap_size;
        struct radix_tree_root revmap_tree;
        struct mutex revmap_tree_mutex;
-       unsigned int revmap[];
+       struct irq_data *revmap[];
 };
 
 /* Irq domain flags */
index cdcb1989cd20cc9a82ae8296c8fb2da5a986ce2a..7a4e38804487d363e64c357d18161f729c5f862c 100644 (file)
@@ -505,7 +505,7 @@ static void irq_domain_clear_mapping(struct irq_domain *domain,
                return;
 
        if (hwirq < domain->revmap_size) {
-               domain->revmap[hwirq] = 0;
+               domain->revmap[hwirq] = NULL;
        } else {
                mutex_lock(&domain->revmap_tree_mutex);
                radix_tree_delete(&domain->revmap_tree, hwirq);
@@ -521,7 +521,7 @@ static void irq_domain_set_mapping(struct irq_domain *domain,
                return;
 
        if (hwirq < domain->revmap_size) {
-               domain->revmap[hwirq] = irq_data->irq;
+               domain->revmap[hwirq] = irq_data;
        } else {
                mutex_lock(&domain->revmap_tree_mutex);
                radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
@@ -913,7 +913,7 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
 
        /* Check if the hwirq is in the linear revmap. */
        if (hwirq < domain->revmap_size)
-               return domain->revmap[hwirq];
+               return domain->revmap[hwirq]->irq;
 
        rcu_read_lock();
        data = radix_tree_lookup(&domain->revmap_tree, hwirq);
@@ -1496,8 +1496,14 @@ static void irq_domain_fix_revmap(struct irq_data *d)
 {
        void __rcu **slot;
 
-       if (irq_domain_is_nomap(d->domain) || d->hwirq < d->domain->revmap_size)
-               return; /* Not using radix tree. */
+       if (irq_domain_is_nomap(d->domain))
+               return;
+
+       if (d->hwirq < d->domain->revmap_size) {
+               /* Not using radix tree */
+               d->domain->revmap[d->hwirq] = d;
+               return;
+       }
 
        /* Fix up the revmap. */
        mutex_lock(&d->domain->revmap_tree_mutex);