summaryrefslogtreecommitdiffstats
path: root/kernel/irq
diff options
context:
space:
mode:
authorHerve Codina <herve.codina@bootlin.com>2024-06-14 19:32:13 +0200
committerThomas Gleixner <tglx@linutronix.de>2024-06-17 15:48:14 +0200
commit44b68de9b8e3dfde12308e8567548799d7ded0de (patch)
treeb3f27be988a06f03060d176d1c3c694ed94eb83a /kernel/irq
parentirqdomain: Handle domain bus token in irq_domain_create() (diff)
downloadlinux-44b68de9b8e3dfde12308e8567548799d7ded0de.tar.xz
linux-44b68de9b8e3dfde12308e8567548799d7ded0de.zip
irqdomain: Introduce init() and exit() hooks
The current API does not allow additional initialization before the domain is published. This can lead to a race condition between consumers and supplier as a domain can be available for consumers before being fully ready. Introduce the init() hook to allow additional initialization before plublishing the domain. Also introduce the exit() hook to revert operations done in init() on domain removal. 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-13-herve.codina@bootlin.com
Diffstat (limited to 'kernel/irq')
-rw-r--r--kernel/irq/irqdomain.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index a21648c76336..a0324d8e6dab 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -276,12 +276,14 @@ static void irq_domain_free(struct irq_domain *domain)
struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
{
struct irq_domain *domain;
+ int err;
domain = __irq_domain_create(info);
if (IS_ERR(domain))
return domain;
domain->flags |= info->domain_flags;
+ domain->exit = info->exit;
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
if (info->parent) {
@@ -290,9 +292,19 @@ struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
}
#endif
+ if (info->init) {
+ err = info->init(domain);
+ if (err)
+ goto err_domain_free;
+ }
+
__irq_domain_publish(domain);
return domain;
+
+err_domain_free:
+ irq_domain_free(domain);
+ return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(irq_domain_instantiate);
@@ -339,6 +351,9 @@ EXPORT_SYMBOL_GPL(__irq_domain_add);
*/
void irq_domain_remove(struct irq_domain *domain)
{
+ if (domain->exit)
+ domain->exit(domain);
+
mutex_lock(&irq_domain_mutex);
debugfs_remove_domain_dir(domain);