diff options
author | Herve Codina <herve.codina@bootlin.com> | 2024-06-14 19:32:13 +0200 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2024-06-17 15:48:14 +0200 |
commit | 44b68de9b8e3dfde12308e8567548799d7ded0de (patch) | |
tree | b3f27be988a06f03060d176d1c3c694ed94eb83a /kernel/irq | |
parent | irqdomain: Handle domain bus token in irq_domain_create() (diff) | |
download | linux-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.c | 15 |
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); |