]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
irqdomain: Add support for generic irq chips creation before publishing a domain
authorHerve Codina <herve.codina@bootlin.com>
Fri, 14 Jun 2024 17:32:16 +0000 (19:32 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Mon, 17 Jun 2024 13:48:14 +0000 (15:48 +0200)
The current API functions create an irq_domain and also publish this
newly created to domain. Once an irq_domain is published, consumers can
request IRQ in order to use them.

Some interrupt controller drivers have to perform some more operations
with the created irq_domain in order to have it ready to be used.
For instance:
   - Allocate generic irq chips with irq_alloc_domain_generic_chips()
   - Retrieve the generic irq chips with irq_get_domain_generic_chip()
   - Initialize retrieved chips: set register base address and offsets,
     set several hooks such as irq_mask, irq_unmask, ...

With the newly introduced irq_domain_alloc_generic_chips(), an interrupt
controller driver can use the irq_domain_chip_generic_info structure and
set the init() hook to perform its generic chips initialization.

In order to avoid a window where the domain is published but not yet
ready to be used, handle the generic chip creation (i.e the
irq_domain_alloc_generic_chips() call) before the domain is published.

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-16-herve.codina@bootlin.com
include/linux/irqdomain.h
kernel/irq/irqdomain.c

index 2c927edc4d4331c102875ed2bcf04ff0018e7862..5540b22a755c538f442ed72445d2f99213768645 100644 (file)
@@ -210,6 +210,9 @@ enum {
        /* Irq domain is a MSI device domain */
        IRQ_DOMAIN_FLAG_MSI_DEVICE      = (1 << 9),
 
+       /* Irq domain must destroy generic chips when removed */
+       IRQ_DOMAIN_FLAG_DESTROY_GC      = (1 << 10),
+
        /*
         * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
         * for implementation specific purposes and ignored by the
@@ -259,6 +262,9 @@ static inline struct fwnode_handle *irq_domain_alloc_fwnode(phys_addr_t *pa)
 }
 
 void irq_domain_free_fwnode(struct fwnode_handle *fwnode);
+
+struct irq_domain_chip_generic_info;
+
 /**
  * struct irq_domain_info - Domain information structure
  * @fwnode:            firmware node for the interrupt controller
@@ -270,6 +276,8 @@ void irq_domain_free_fwnode(struct fwnode_handle *fwnode);
  * @bus_token:         Domain bus token
  * @ops:               Domain operation callbacks
  * @host_data:         Controller private data pointer
+ * @dgc_info:          Geneneric chip information structure pointer used to
+ *                     create generic chips for the domain if not NULL.
  * @init:              Function called when the domain is created.
  *                     Allow to do some additional domain initialisation.
  * @exit:              Function called when the domain is destroyed.
@@ -290,6 +298,7 @@ struct irq_domain_info {
         */
        struct irq_domain                       *parent;
 #endif
+       struct irq_domain_chip_generic_info     *dgc_info;
        int                                     (*init)(struct irq_domain *d);
        void                                    (*exit)(struct irq_domain *d);
 };
index a0324d8e6dab846f354ca78a3880903d8dadeb0e..4d2a40359eb2bd302e18ba27f64f18fa4854c39e 100644 (file)
@@ -292,16 +292,25 @@ struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
        }
 #endif
 
+       if (info->dgc_info) {
+               err = irq_domain_alloc_generic_chips(domain, info->dgc_info);
+               if (err)
+                       goto err_domain_free;
+       }
+
        if (info->init) {
                err = info->init(domain);
                if (err)
-                       goto err_domain_free;
+                       goto err_domain_gc_remove;
        }
 
        __irq_domain_publish(domain);
 
        return domain;
 
+err_domain_gc_remove:
+       if (info->dgc_info)
+               irq_domain_remove_generic_chips(domain);
 err_domain_free:
        irq_domain_free(domain);
        return ERR_PTR(err);
@@ -369,6 +378,9 @@ void irq_domain_remove(struct irq_domain *domain)
 
        mutex_unlock(&irq_domain_mutex);
 
+       if (domain->flags & IRQ_DOMAIN_FLAG_DESTROY_GC)
+               irq_domain_remove_generic_chips(domain);
+
        pr_debug("Removed domain %s\n", domain->name);
        irq_domain_free(domain);
 }