Commit 6e6f75c9 authored by Johan Hovold's avatar Johan Hovold Committed by Marc Zyngier

irqdomain: Look for existing mapping only once

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: b62b2cf5 ("irqdomain: Fix handling of type settings for existing mappings")
Cc: stable@vger.kernel.org      # 4.8
Tested-by: default avatarHsin-Yi Wang <hsinyi@chromium.org>
Tested-by: default avatarMark-PK Tsai <mark-pk.tsai@mediatek.com>
Signed-off-by: default avatarJohan Hovold <johan+linaro@kernel.org>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20230213104302.17307-5-johan+linaro@kernel.org
parent e3b7ab02
...@@ -682,6 +682,34 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain) ...@@ -682,6 +682,34 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
EXPORT_SYMBOL_GPL(irq_create_direct_mapping); EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
#endif #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 * irq_create_mapping_affinity() - Map a hardware interrupt into linux irq space
* @domain: domain owning this hardware interrupt or NULL for default domain * @domain: domain owning this hardware interrupt or NULL for default domain
...@@ -697,11 +725,8 @@ unsigned int irq_create_mapping_affinity(struct irq_domain *domain, ...@@ -697,11 +725,8 @@ unsigned int irq_create_mapping_affinity(struct irq_domain *domain,
irq_hw_number_t hwirq, irq_hw_number_t hwirq,
const struct irq_affinity_desc *affinity) const struct irq_affinity_desc *affinity)
{ {
struct device_node *of_node;
int virq; int virq;
pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
/* Look for default domain if necessary */ /* Look for default domain if necessary */
if (domain == NULL) if (domain == NULL)
domain = irq_default_domain; domain = irq_default_domain;
...@@ -709,34 +734,15 @@ unsigned int irq_create_mapping_affinity(struct irq_domain *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); WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
return 0; return 0;
} }
pr_debug("-> using domain @%p\n", domain);
of_node = irq_domain_get_of_node(domain);
/* Check if mapping already exists */ /* Check if mapping already exists */
virq = irq_find_mapping(domain, hwirq); virq = irq_find_mapping(domain, hwirq);
if (virq) { if (virq) {
pr_debug("-> existing mapping on virq %d\n", virq); pr_debug("existing mapping on virq %d\n", virq);
return virq; return virq;
} }
/* Allocate a virtual interrupt number */ return __irq_create_mapping_affinity(domain, hwirq, affinity);
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;
} }
EXPORT_SYMBOL_GPL(irq_create_mapping_affinity); EXPORT_SYMBOL_GPL(irq_create_mapping_affinity);
...@@ -841,7 +847,7 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec) ...@@ -841,7 +847,7 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
return 0; return 0;
} else { } else {
/* Create mapping */ /* Create mapping */
virq = irq_create_mapping(domain, hwirq); virq = __irq_create_mapping_affinity(domain, hwirq, NULL);
if (!virq) if (!virq)
return virq; return virq;
} }
......
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