forked from mirrors/linux
		
	irqdomain: Add support for generic irq chips creation before publishing a domain
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
			
			
This commit is contained in:
		
							parent
							
								
									fea922ee9f
								
							
						
					
					
						commit
						e6f67ce32e
					
				
					 2 changed files with 22 additions and 1 deletions
				
			
		| 
						 | 
					@ -210,6 +210,9 @@ enum {
 | 
				
			||||||
	/* Irq domain is a MSI device domain */
 | 
						/* Irq domain is a MSI device domain */
 | 
				
			||||||
	IRQ_DOMAIN_FLAG_MSI_DEVICE	= (1 << 9),
 | 
						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
 | 
						 * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
 | 
				
			||||||
	 * for implementation specific purposes and ignored by the
 | 
						 * 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);
 | 
					void irq_domain_free_fwnode(struct fwnode_handle *fwnode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct irq_domain_chip_generic_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * struct irq_domain_info - Domain information structure
 | 
					 * struct irq_domain_info - Domain information structure
 | 
				
			||||||
 * @fwnode:		firmware node for the interrupt controller
 | 
					 * @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
 | 
					 * @bus_token:		Domain bus token
 | 
				
			||||||
 * @ops:		Domain operation callbacks
 | 
					 * @ops:		Domain operation callbacks
 | 
				
			||||||
 * @host_data:		Controller private data pointer
 | 
					 * @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.
 | 
					 * @init:		Function called when the domain is created.
 | 
				
			||||||
 *			Allow to do some additional domain initialisation.
 | 
					 *			Allow to do some additional domain initialisation.
 | 
				
			||||||
 * @exit:		Function called when the domain is destroyed.
 | 
					 * @exit:		Function called when the domain is destroyed.
 | 
				
			||||||
| 
						 | 
					@ -290,6 +298,7 @@ struct irq_domain_info {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	struct irq_domain			*parent;
 | 
						struct irq_domain			*parent;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						struct irq_domain_chip_generic_info	*dgc_info;
 | 
				
			||||||
	int					(*init)(struct irq_domain *d);
 | 
						int					(*init)(struct irq_domain *d);
 | 
				
			||||||
	void					(*exit)(struct irq_domain *d);
 | 
						void					(*exit)(struct irq_domain *d);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -292,16 +292,25 @@ struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (info->dgc_info) {
 | 
				
			||||||
 | 
							err = irq_domain_alloc_generic_chips(domain, info->dgc_info);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								goto err_domain_free;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (info->init) {
 | 
						if (info->init) {
 | 
				
			||||||
		err = info->init(domain);
 | 
							err = info->init(domain);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			goto err_domain_free;
 | 
								goto err_domain_gc_remove;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__irq_domain_publish(domain);
 | 
						__irq_domain_publish(domain);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return domain;
 | 
						return domain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_domain_gc_remove:
 | 
				
			||||||
 | 
						if (info->dgc_info)
 | 
				
			||||||
 | 
							irq_domain_remove_generic_chips(domain);
 | 
				
			||||||
err_domain_free:
 | 
					err_domain_free:
 | 
				
			||||||
	irq_domain_free(domain);
 | 
						irq_domain_free(domain);
 | 
				
			||||||
	return ERR_PTR(err);
 | 
						return ERR_PTR(err);
 | 
				
			||||||
| 
						 | 
					@ -369,6 +378,9 @@ void irq_domain_remove(struct irq_domain *domain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_unlock(&irq_domain_mutex);
 | 
						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);
 | 
						pr_debug("Removed domain %s\n", domain->name);
 | 
				
			||||||
	irq_domain_free(domain);
 | 
						irq_domain_free(domain);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue