mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 06:02:05 +00:00
irqdomain: Refactor __irq_domain_alloc_irqs()
Refactor __irq_domain_alloc_irqs() so that it can be called internally
while holding the irq_domain_mutex.
This will be used to fix a shared-interrupt mapping race, hence the
Fixes tag.
Fixes: b62b2cf575
("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-6-johan+linaro@kernel.org
This commit is contained in:
parent
6e6f75c9c9
commit
d55f7f4c58
@ -1441,6 +1441,52 @@ int irq_domain_alloc_irqs_hierarchy(struct irq_domain *domain,
|
||||
return domain->ops->alloc(domain, irq_base, nr_irqs, arg);
|
||||
}
|
||||
|
||||
static int irq_domain_alloc_irqs_locked(struct irq_domain *domain, int irq_base,
|
||||
unsigned int nr_irqs, int node, void *arg,
|
||||
bool realloc, const struct irq_affinity_desc *affinity)
|
||||
{
|
||||
int i, ret, virq;
|
||||
|
||||
if (realloc && irq_base >= 0) {
|
||||
virq = irq_base;
|
||||
} else {
|
||||
virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node,
|
||||
affinity);
|
||||
if (virq < 0) {
|
||||
pr_debug("cannot allocate IRQ(base %d, count %d)\n",
|
||||
irq_base, nr_irqs);
|
||||
return virq;
|
||||
}
|
||||
}
|
||||
|
||||
if (irq_domain_alloc_irq_data(domain, virq, nr_irqs)) {
|
||||
pr_debug("cannot allocate memory for IRQ%d\n", virq);
|
||||
ret = -ENOMEM;
|
||||
goto out_free_desc;
|
||||
}
|
||||
|
||||
ret = irq_domain_alloc_irqs_hierarchy(domain, virq, nr_irqs, arg);
|
||||
if (ret < 0)
|
||||
goto out_free_irq_data;
|
||||
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
ret = irq_domain_trim_hierarchy(virq + i);
|
||||
if (ret)
|
||||
goto out_free_irq_data;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_irqs; i++)
|
||||
irq_domain_insert_irq(virq + i);
|
||||
|
||||
return virq;
|
||||
|
||||
out_free_irq_data:
|
||||
irq_domain_free_irq_data(virq, nr_irqs);
|
||||
out_free_desc:
|
||||
irq_free_descs(virq, nr_irqs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* __irq_domain_alloc_irqs - Allocate IRQs from domain
|
||||
* @domain: domain to allocate from
|
||||
@ -1467,7 +1513,7 @@ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
|
||||
unsigned int nr_irqs, int node, void *arg,
|
||||
bool realloc, const struct irq_affinity_desc *affinity)
|
||||
{
|
||||
int i, ret, virq;
|
||||
int ret;
|
||||
|
||||
if (domain == NULL) {
|
||||
domain = irq_default_domain;
|
||||
@ -1475,49 +1521,11 @@ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (realloc && irq_base >= 0) {
|
||||
virq = irq_base;
|
||||
} else {
|
||||
virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node,
|
||||
affinity);
|
||||
if (virq < 0) {
|
||||
pr_debug("cannot allocate IRQ(base %d, count %d)\n",
|
||||
irq_base, nr_irqs);
|
||||
return virq;
|
||||
}
|
||||
}
|
||||
|
||||
if (irq_domain_alloc_irq_data(domain, virq, nr_irqs)) {
|
||||
pr_debug("cannot allocate memory for IRQ%d\n", virq);
|
||||
ret = -ENOMEM;
|
||||
goto out_free_desc;
|
||||
}
|
||||
|
||||
mutex_lock(&irq_domain_mutex);
|
||||
ret = irq_domain_alloc_irqs_hierarchy(domain, virq, nr_irqs, arg);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&irq_domain_mutex);
|
||||
goto out_free_irq_data;
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_irqs; i++) {
|
||||
ret = irq_domain_trim_hierarchy(virq + i);
|
||||
if (ret) {
|
||||
mutex_unlock(&irq_domain_mutex);
|
||||
goto out_free_irq_data;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < nr_irqs; i++)
|
||||
irq_domain_insert_irq(virq + i);
|
||||
ret = irq_domain_alloc_irqs_locked(domain, irq_base, nr_irqs, node, arg,
|
||||
realloc, affinity);
|
||||
mutex_unlock(&irq_domain_mutex);
|
||||
|
||||
return virq;
|
||||
|
||||
out_free_irq_data:
|
||||
irq_domain_free_irq_data(virq, nr_irqs);
|
||||
out_free_desc:
|
||||
irq_free_descs(virq, nr_irqs);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__irq_domain_alloc_irqs);
|
||||
|
Loading…
Reference in New Issue
Block a user