irqdomain: Fix association race
The sanity check for an already mapped virq is done outside of the irq_domain_mutex-protected section which means that an (unlikely) racing association may not be detected. Fix this by factoring out the association implementation, which will also be used in a follow-on change to fix a shared-interrupt mapping race. Fixes: ddaf144c61da ("irqdomain: Refactor irq_domain_associate_many()") Cc: stable@vger.kernel.org # 3.11 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-2-johan+linaro@kernel.org
This commit is contained in:
parent
5dc4c995db
commit
b06730a571
@ -559,8 +559,8 @@ static void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq)
|
||||
irq_domain_clear_mapping(domain, hwirq);
|
||||
}
|
||||
|
||||
int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
|
||||
irq_hw_number_t hwirq)
|
||||
static int irq_domain_associate_locked(struct irq_domain *domain, unsigned int virq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
struct irq_data *irq_data = irq_get_irq_data(virq);
|
||||
int ret;
|
||||
@ -573,7 +573,6 @@ int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
|
||||
if (WARN(irq_data->domain, "error: virq%i is already associated", virq))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&irq_domain_mutex);
|
||||
irq_data->hwirq = hwirq;
|
||||
irq_data->domain = domain;
|
||||
if (domain->ops->map) {
|
||||
@ -590,7 +589,6 @@ int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
|
||||
}
|
||||
irq_data->domain = NULL;
|
||||
irq_data->hwirq = 0;
|
||||
mutex_unlock(&irq_domain_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -601,12 +599,23 @@ int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
|
||||
|
||||
domain->mapcount++;
|
||||
irq_domain_set_mapping(domain, hwirq, irq_data);
|
||||
mutex_unlock(&irq_domain_mutex);
|
||||
|
||||
irq_clear_status_flags(virq, IRQ_NOREQUEST);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&irq_domain_mutex);
|
||||
ret = irq_domain_associate_locked(domain, virq, hwirq);
|
||||
mutex_unlock(&irq_domain_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_associate);
|
||||
|
||||
void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
|
||||
|
Loading…
x
Reference in New Issue
Block a user