irqdomain: Look for existing mapping only once
authorJohan Hovold <johan+linaro@kernel.org>
Mon, 13 Feb 2023 10:42:46 +0000 (11:42 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 10 Mar 2023 08:34:19 +0000 (09:34 +0100)
commit 6e6f75c9c98d2d246d90411ff2b6f0cd271f4cba upstream.

Avoid looking for an existing mapping twice when creating a new mapping
using irq_create_fwspec_mapping() by factoring out the actual allocation
which is shared with irq_create_mapping_affinity().

The new helper function will also be used to fix a shared-interrupt
mapping race, hence the Fixes tag.

Fixes: b62b2cf5759b ("irqdomain: Fix handling of type settings for existing mappings")
Cc: stable@vger.kernel.org # 4.8
Tested-by: Hsin-Yi Wang <hsinyi@chromium.org>
Tested-by: Mark-PK Tsai <mark-pk.tsai@mediatek.com>
Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20230213104302.17307-5-johan+linaro@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
kernel/irq/irqdomain.c

index 3887882..d49f9a2 100644 (file)
@@ -682,6 +682,34 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
 EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
 #endif
 
+static unsigned int __irq_create_mapping_affinity(struct irq_domain *domain,
+                                                 irq_hw_number_t hwirq,
+                                                 const struct irq_affinity_desc *affinity)
+{
+       struct device_node *of_node = irq_domain_get_of_node(domain);
+       int virq;
+
+       pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
+
+       /* Allocate a virtual interrupt number */
+       virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node),
+                                     affinity);
+       if (virq <= 0) {
+               pr_debug("-> virq allocation failed\n");
+               return 0;
+       }
+
+       if (irq_domain_associate(domain, virq, hwirq)) {
+               irq_free_desc(virq);
+               return 0;
+       }
+
+       pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
+               hwirq, of_node_full_name(of_node), virq);
+
+       return virq;
+}
+
 /**
  * irq_create_mapping_affinity() - Map a hardware interrupt into linux irq space
  * @domain: domain owning this hardware interrupt or NULL for default domain
@@ -694,14 +722,11 @@ EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
  * on the number returned from that call.
  */
 unsigned int irq_create_mapping_affinity(struct irq_domain *domain,
-                                      irq_hw_number_t hwirq,
-                                      const struct irq_affinity_desc *affinity)
+                                        irq_hw_number_t hwirq,
+                                        const struct irq_affinity_desc *affinity)
 {
-       struct device_node *of_node;
        int virq;
 
-       pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
-
        /* Look for default domain if necessary */
        if (domain == NULL)
                domain = irq_default_domain;
@@ -709,34 +734,15 @@ unsigned int irq_create_mapping_affinity(struct irq_domain *domain,
                WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
                return 0;
        }
-       pr_debug("-> using domain @%p\n", domain);
-
-       of_node = irq_domain_get_of_node(domain);
 
        /* Check if mapping already exists */
        virq = irq_find_mapping(domain, hwirq);
        if (virq) {
-               pr_debug("-> existing mapping on virq %d\n", virq);
+               pr_debug("existing mapping on virq %d\n", virq);
                return virq;
        }
 
-       /* Allocate a virtual interrupt number */
-       virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node),
-                                     affinity);
-       if (virq <= 0) {
-               pr_debug("-> virq allocation failed\n");
-               return 0;
-       }
-
-       if (irq_domain_associate(domain, virq, hwirq)) {
-               irq_free_desc(virq);
-               return 0;
-       }
-
-       pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
-               hwirq, of_node_full_name(of_node), virq);
-
-       return virq;
+       return __irq_create_mapping_affinity(domain, hwirq, affinity);
 }
 EXPORT_SYMBOL_GPL(irq_create_mapping_affinity);
 
@@ -841,7 +847,7 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
                        return 0;
        } else {
                /* Create mapping */
-               virq = irq_create_mapping(domain, hwirq);
+               virq = __irq_create_mapping_affinity(domain, hwirq, NULL);
                if (!virq)
                        return virq;
        }