summaryrefslogtreecommitdiffstats
path: root/kernel/irq
diff options
context:
space:
mode:
authorHerve Codina <herve.codina@bootlin.com>2024-06-14 19:32:15 +0200
committerThomas Gleixner <tglx@linutronix.de>2024-06-17 15:48:14 +0200
commitfea922ee9f8ffd3c2a8e8dfbc68de42905a3982a (patch)
treede3bc75ac6cd6d3d5c560ba7d5a5c391b826b3d0 /kernel/irq
parente25f553a92973eaf59ff3a00fe7f61ab01b2877f (diff)
downloadlinux-fea922ee9f8ffd3c2a8e8dfbc68de42905a3982a.tar.gz
linux-fea922ee9f8ffd3c2a8e8dfbc68de42905a3982a.tar.bz2
linux-fea922ee9f8ffd3c2a8e8dfbc68de42905a3982a.zip
genirq/generic_chip: Introduce init() and exit() hooks
Most of generic chip drivers need to perform some more additional initializations on the generic chips allocated before they can be fully ready. These additional initializations need to be performed before the IRQ domain is published to avoid a race condition between IRQ consumers and suppliers. Introduce the init() hook to perform these initializations at the right place just after the generic chip creation. Also introduce the exit() hook to allow reverting operations done by the init() hook just before the generic chip is destroyed. Suggested-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Herve Codina <herve.codina@bootlin.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lore.kernel.org/r/20240614173232.1184015-15-herve.codina@bootlin.com
Diffstat (limited to 'kernel/irq')
-rw-r--r--kernel/irq/generic-chip.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c
index d9696f5dcc38..32ffcbb87fa1 100644
--- a/kernel/irq/generic-chip.c
+++ b/kernel/irq/generic-chip.c
@@ -293,6 +293,7 @@ int irq_domain_alloc_generic_chips(struct irq_domain *d,
size_t gc_sz;
size_t sz;
void *tmp;
+ int ret;
if (d->gc)
return -EBUSY;
@@ -314,6 +315,7 @@ int irq_domain_alloc_generic_chips(struct irq_domain *d,
dgc->irq_flags_to_set = info->irq_flags_to_set;
dgc->irq_flags_to_clear = info->irq_flags_to_clear;
dgc->gc_flags = info->gc_flags;
+ dgc->exit = info->exit;
d->gc = dgc;
/* Calc pointer to the first generic chip */
@@ -331,6 +333,12 @@ int irq_domain_alloc_generic_chips(struct irq_domain *d,
gc->reg_writel = &irq_writel_be;
}
+ if (info->init) {
+ ret = info->init(gc);
+ if (ret)
+ goto err;
+ }
+
raw_spin_lock_irqsave(&gc_lock, flags);
list_add_tail(&gc->list, &gc_list);
raw_spin_unlock_irqrestore(&gc_lock, flags);
@@ -338,6 +346,16 @@ int irq_domain_alloc_generic_chips(struct irq_domain *d,
tmp += gc_sz;
}
return 0;
+
+err:
+ while (i--) {
+ if (dgc->exit)
+ dgc->exit(dgc->gc[i]);
+ irq_remove_generic_chip(dgc->gc[i], ~0U, 0, 0);
+ }
+ d->gc = NULL;
+ kfree(dgc);
+ return ret;
}
EXPORT_SYMBOL_GPL(irq_domain_alloc_generic_chips);
@@ -353,9 +371,11 @@ void irq_domain_remove_generic_chips(struct irq_domain *d)
if (!dgc)
return;
- for (i = 0; i < dgc->num_chips; i++)
+ for (i = 0; i < dgc->num_chips; i++) {
+ if (dgc->exit)
+ dgc->exit(dgc->gc[i]);
irq_remove_generic_chip(dgc->gc[i], ~0U, 0, 0);
-
+ }
d->gc = NULL;
kfree(dgc);
}