| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 
|---|
| 2 | /* | 
|---|
| 3 | * irq_domain - IRQ Translation Domains | 
|---|
| 4 | * | 
|---|
| 5 | * See Documentation/core-api/irq/irq-domain.rst for the details. | 
|---|
| 6 | */ | 
|---|
| 7 |  | 
|---|
| 8 | #ifndef _LINUX_IRQDOMAIN_H | 
|---|
| 9 | #define _LINUX_IRQDOMAIN_H | 
|---|
| 10 |  | 
|---|
| 11 | #include <linux/types.h> | 
|---|
| 12 | #include <linux/irqdomain_defs.h> | 
|---|
| 13 | #include <linux/irqhandler.h> | 
|---|
| 14 | #include <linux/of.h> | 
|---|
| 15 | #include <linux/mutex.h> | 
|---|
| 16 | #include <linux/radix-tree.h> | 
|---|
| 17 |  | 
|---|
| 18 | struct device_node; | 
|---|
| 19 | struct fwnode_handle; | 
|---|
| 20 | struct irq_domain; | 
|---|
| 21 | struct irq_chip; | 
|---|
| 22 | struct irq_data; | 
|---|
| 23 | struct irq_desc; | 
|---|
| 24 | struct cpumask; | 
|---|
| 25 | struct seq_file; | 
|---|
| 26 | struct irq_affinity_desc; | 
|---|
| 27 | struct msi_parent_ops; | 
|---|
| 28 |  | 
|---|
| 29 | #define IRQ_DOMAIN_IRQ_SPEC_PARAMS 16 | 
|---|
| 30 |  | 
|---|
| 31 | /** | 
|---|
| 32 | * struct irq_fwspec - generic IRQ specifier structure | 
|---|
| 33 | * | 
|---|
| 34 | * @fwnode:		Pointer to a firmware-specific descriptor | 
|---|
| 35 | * @param_count:	Number of device-specific parameters | 
|---|
| 36 | * @param:		Device-specific parameters | 
|---|
| 37 | * | 
|---|
| 38 | * This structure, directly modeled after of_phandle_args, is used to | 
|---|
| 39 | * pass a device-specific description of an interrupt. | 
|---|
| 40 | */ | 
|---|
| 41 | struct irq_fwspec { | 
|---|
| 42 | struct fwnode_handle	*fwnode; | 
|---|
| 43 | int			param_count; | 
|---|
| 44 | u32			param[IRQ_DOMAIN_IRQ_SPEC_PARAMS]; | 
|---|
| 45 | }; | 
|---|
| 46 |  | 
|---|
| 47 | /* Conversion function from of_phandle_args fields to fwspec  */ | 
|---|
| 48 | void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args, | 
|---|
| 49 | unsigned int count, struct irq_fwspec *fwspec); | 
|---|
| 50 |  | 
|---|
| 51 | /** | 
|---|
| 52 | * struct irq_domain_ops - Methods for irq_domain objects | 
|---|
| 53 | * @match:	Match an interrupt controller device node to a domain, returns | 
|---|
| 54 | *		1 on a match | 
|---|
| 55 | * @select:	Match an interrupt controller fw specification. It is more generic | 
|---|
| 56 | *		than @match as it receives a complete struct irq_fwspec. Therefore, | 
|---|
| 57 | *		@select is preferred if provided. Returns 1 on a match. | 
|---|
| 58 | * @map:	Create or update a mapping between a virtual irq number and a hw | 
|---|
| 59 | *		irq number. This is called only once for a given mapping. | 
|---|
| 60 | * @unmap:	Dispose of such a mapping | 
|---|
| 61 | * @xlate:	Given a device tree node and interrupt specifier, decode | 
|---|
| 62 | *		the hardware irq number and linux irq type value. | 
|---|
| 63 | * @alloc:	Allocate @nr_irqs interrupts starting from @virq. | 
|---|
| 64 | * @free:	Free @nr_irqs interrupts starting from @virq. | 
|---|
| 65 | * @activate:	Activate one interrupt in HW (@irqd). If @reserve is set, only | 
|---|
| 66 | *		reserve the vector. If unset, assign the vector (called from | 
|---|
| 67 | *		request_irq()). | 
|---|
| 68 | * @deactivate:	Disarm one interrupt (@irqd). | 
|---|
| 69 | * @translate:	Given @fwspec, decode the hardware irq number (@out_hwirq) and | 
|---|
| 70 | *		linux irq type value (@out_type). This is a generalised @xlate | 
|---|
| 71 | *		(over struct irq_fwspec) and is preferred if provided. | 
|---|
| 72 | * @debug_show:	For domains to show specific data for an interrupt in debugfs. | 
|---|
| 73 | * | 
|---|
| 74 | * Functions below are provided by the driver and called whenever a new mapping | 
|---|
| 75 | * is created or an old mapping is disposed. The driver can then proceed to | 
|---|
| 76 | * whatever internal data structures management is required. It also needs | 
|---|
| 77 | * to setup the irq_desc when returning from map(). | 
|---|
| 78 | */ | 
|---|
| 79 | struct irq_domain_ops { | 
|---|
| 80 | int	(*match)(struct irq_domain *d, struct device_node *node, | 
|---|
| 81 | enum irq_domain_bus_token bus_token); | 
|---|
| 82 | int	(*select)(struct irq_domain *d, struct irq_fwspec *fwspec, | 
|---|
| 83 | enum irq_domain_bus_token bus_token); | 
|---|
| 84 | int	(*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw); | 
|---|
| 85 | void	(*unmap)(struct irq_domain *d, unsigned int virq); | 
|---|
| 86 | int	(*xlate)(struct irq_domain *d, struct device_node *node, | 
|---|
| 87 | const u32 *intspec, unsigned int intsize, | 
|---|
| 88 | unsigned long *out_hwirq, unsigned int *out_type); | 
|---|
| 89 | #ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY | 
|---|
| 90 | /* extended V2 interfaces to support hierarchy irq_domains */ | 
|---|
| 91 | int	(*alloc)(struct irq_domain *d, unsigned int virq, | 
|---|
| 92 | unsigned int nr_irqs, void *arg); | 
|---|
| 93 | void	(*free)(struct irq_domain *d, unsigned int virq, | 
|---|
| 94 | unsigned int nr_irqs); | 
|---|
| 95 | int	(*activate)(struct irq_domain *d, struct irq_data *irqd, bool reserve); | 
|---|
| 96 | void	(*deactivate)(struct irq_domain *d, struct irq_data *irq_data); | 
|---|
| 97 | int	(*translate)(struct irq_domain *d, struct irq_fwspec *fwspec, | 
|---|
| 98 | unsigned long *out_hwirq, unsigned int *out_type); | 
|---|
| 99 | #endif | 
|---|
| 100 | #ifdef CONFIG_GENERIC_IRQ_DEBUGFS | 
|---|
| 101 | void	(*debug_show)(struct seq_file *m, struct irq_domain *d, | 
|---|
| 102 | struct irq_data *irqd, int ind); | 
|---|
| 103 | #endif | 
|---|
| 104 | }; | 
|---|
| 105 |  | 
|---|
| 106 | extern const struct irq_domain_ops irq_generic_chip_ops; | 
|---|
| 107 |  | 
|---|
| 108 | struct irq_domain_chip_generic; | 
|---|
| 109 |  | 
|---|
| 110 | /** | 
|---|
| 111 | * struct irq_domain - Hardware interrupt number translation object | 
|---|
| 112 | * @link:	Element in global irq_domain list. | 
|---|
| 113 | * @name:	Name of interrupt domain | 
|---|
| 114 | * @ops:	Pointer to irq_domain methods | 
|---|
| 115 | * @host_data:	Private data pointer for use by owner.  Not touched by irq_domain | 
|---|
| 116 | *		core code. | 
|---|
| 117 | * @flags:	Per irq_domain flags | 
|---|
| 118 | * @mapcount:	The number of mapped interrupts | 
|---|
| 119 | * @mutex:	Domain lock, hierarchical domains use root domain's lock | 
|---|
| 120 | * @root:	Pointer to root domain, or containing structure if non-hierarchical | 
|---|
| 121 | * | 
|---|
| 122 | * Optional elements: | 
|---|
| 123 | * @fwnode:	Pointer to firmware node associated with the irq_domain. Pretty easy | 
|---|
| 124 | *		to swap it for the of_node via the irq_domain_get_of_node accessor | 
|---|
| 125 | * @bus_token:	@fwnode's device_node might be used for several irq domains. But | 
|---|
| 126 | *		in connection with @bus_token, the pair shall be unique in a | 
|---|
| 127 | *		system. | 
|---|
| 128 | * @gc:		Pointer to a list of generic chips. There is a helper function for | 
|---|
| 129 | *		setting up one or more generic chips for interrupt controllers | 
|---|
| 130 | *		drivers using the generic chip library which uses this pointer. | 
|---|
| 131 | * @dev:	Pointer to the device which instantiated the irqdomain | 
|---|
| 132 | *		With per device irq domains this is not necessarily the same | 
|---|
| 133 | *		as @pm_dev. | 
|---|
| 134 | * @pm_dev:	Pointer to a device that can be utilized for power management | 
|---|
| 135 | *		purposes related to the irq domain. | 
|---|
| 136 | * @parent:	Pointer to parent irq_domain to support hierarchy irq_domains | 
|---|
| 137 | * @msi_parent_ops: Pointer to MSI parent domain methods for per device domain init | 
|---|
| 138 | * @exit:	Function called when the domain is destroyed | 
|---|
| 139 | * | 
|---|
| 140 | * Revmap data, used internally by the irq domain code: | 
|---|
| 141 | * @hwirq_max:		Top limit for the HW irq number. Especially to avoid | 
|---|
| 142 | *			conflicts/failures with reserved HW irqs. Can be ~0. | 
|---|
| 143 | * @revmap_size:	Size of the linear map table @revmap | 
|---|
| 144 | * @revmap_tree:	Radix map tree for hwirqs that don't fit in the linear map | 
|---|
| 145 | * @revmap:		Linear table of irq_data pointers | 
|---|
| 146 | */ | 
|---|
| 147 | struct irq_domain { | 
|---|
| 148 | struct list_head		link; | 
|---|
| 149 | const char			*name; | 
|---|
| 150 | const struct irq_domain_ops	*ops; | 
|---|
| 151 | void				*host_data; | 
|---|
| 152 | unsigned int			flags; | 
|---|
| 153 | unsigned int			mapcount; | 
|---|
| 154 | struct mutex			mutex; | 
|---|
| 155 | struct irq_domain		*root; | 
|---|
| 156 |  | 
|---|
| 157 | /* Optional data */ | 
|---|
| 158 | struct fwnode_handle		*fwnode; | 
|---|
| 159 | enum irq_domain_bus_token	bus_token; | 
|---|
| 160 | struct irq_domain_chip_generic	*gc; | 
|---|
| 161 | struct device			*dev; | 
|---|
| 162 | struct device			*pm_dev; | 
|---|
| 163 | #ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY | 
|---|
| 164 | struct irq_domain		*parent; | 
|---|
| 165 | #endif | 
|---|
| 166 | #ifdef CONFIG_GENERIC_MSI_IRQ | 
|---|
| 167 | const struct msi_parent_ops	*msi_parent_ops; | 
|---|
| 168 | #endif | 
|---|
| 169 | void				(*exit)(struct irq_domain *d); | 
|---|
| 170 |  | 
|---|
| 171 | /* reverse map data. The linear map gets appended to the irq_domain */ | 
|---|
| 172 | irq_hw_number_t			hwirq_max; | 
|---|
| 173 | unsigned int			revmap_size; | 
|---|
| 174 | struct radix_tree_root		revmap_tree; | 
|---|
| 175 | struct irq_data __rcu		*revmap[] __counted_by(revmap_size); | 
|---|
| 176 | }; | 
|---|
| 177 |  | 
|---|
| 178 | /* Irq domain flags */ | 
|---|
| 179 | enum { | 
|---|
| 180 | /* Irq domain is hierarchical */ | 
|---|
| 181 | IRQ_DOMAIN_FLAG_HIERARCHY	= (1 << 0), | 
|---|
| 182 |  | 
|---|
| 183 | /* Irq domain name was allocated internally */ | 
|---|
| 184 | IRQ_DOMAIN_NAME_ALLOCATED	= (1 << 1), | 
|---|
| 185 |  | 
|---|
| 186 | /* Irq domain is an IPI domain with virq per cpu */ | 
|---|
| 187 | IRQ_DOMAIN_FLAG_IPI_PER_CPU	= (1 << 2), | 
|---|
| 188 |  | 
|---|
| 189 | /* Irq domain is an IPI domain with single virq */ | 
|---|
| 190 | IRQ_DOMAIN_FLAG_IPI_SINGLE	= (1 << 3), | 
|---|
| 191 |  | 
|---|
| 192 | /* Irq domain implements MSIs */ | 
|---|
| 193 | IRQ_DOMAIN_FLAG_MSI		= (1 << 4), | 
|---|
| 194 |  | 
|---|
| 195 | /* | 
|---|
| 196 | * Irq domain implements isolated MSI, see msi_device_has_isolated_msi() | 
|---|
| 197 | */ | 
|---|
| 198 | IRQ_DOMAIN_FLAG_ISOLATED_MSI	= (1 << 5), | 
|---|
| 199 |  | 
|---|
| 200 | /* Irq domain doesn't translate anything */ | 
|---|
| 201 | IRQ_DOMAIN_FLAG_NO_MAP		= (1 << 6), | 
|---|
| 202 |  | 
|---|
| 203 | /* Irq domain is a MSI parent domain */ | 
|---|
| 204 | IRQ_DOMAIN_FLAG_MSI_PARENT	= (1 << 8), | 
|---|
| 205 |  | 
|---|
| 206 | /* Irq domain is a MSI device domain */ | 
|---|
| 207 | IRQ_DOMAIN_FLAG_MSI_DEVICE	= (1 << 9), | 
|---|
| 208 |  | 
|---|
| 209 | /* Irq domain must destroy generic chips when removed */ | 
|---|
| 210 | IRQ_DOMAIN_FLAG_DESTROY_GC	= (1 << 10), | 
|---|
| 211 |  | 
|---|
| 212 | /* Address and data pair is mutable when irq_set_affinity() */ | 
|---|
| 213 | IRQ_DOMAIN_FLAG_MSI_IMMUTABLE	= (1 << 11), | 
|---|
| 214 |  | 
|---|
| 215 | /* IRQ domain requires parent fwnode matching */ | 
|---|
| 216 | IRQ_DOMAIN_FLAG_FWNODE_PARENT	= (1 << 12), | 
|---|
| 217 |  | 
|---|
| 218 | /* | 
|---|
| 219 | * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved | 
|---|
| 220 | * for implementation specific purposes and ignored by the | 
|---|
| 221 | * core code. | 
|---|
| 222 | */ | 
|---|
| 223 | IRQ_DOMAIN_FLAG_NONCORE		= (1 << 16), | 
|---|
| 224 | }; | 
|---|
| 225 |  | 
|---|
| 226 | static inline struct device_node *irq_domain_get_of_node(struct irq_domain *d) | 
|---|
| 227 | { | 
|---|
| 228 | return to_of_node(fwnode: d->fwnode); | 
|---|
| 229 | } | 
|---|
| 230 |  | 
|---|
| 231 | static inline void irq_domain_set_pm_device(struct irq_domain *d, struct device *dev) | 
|---|
| 232 | { | 
|---|
| 233 | if (d) | 
|---|
| 234 | d->pm_dev = dev; | 
|---|
| 235 | } | 
|---|
| 236 |  | 
|---|
| 237 | #ifdef CONFIG_IRQ_DOMAIN | 
|---|
| 238 | struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id, | 
|---|
| 239 | const char *name, phys_addr_t *pa); | 
|---|
| 240 |  | 
|---|
| 241 | enum { | 
|---|
| 242 | IRQCHIP_FWNODE_REAL, | 
|---|
| 243 | IRQCHIP_FWNODE_NAMED, | 
|---|
| 244 | IRQCHIP_FWNODE_NAMED_ID, | 
|---|
| 245 | }; | 
|---|
| 246 |  | 
|---|
| 247 | static inline struct fwnode_handle *irq_domain_alloc_named_fwnode(const char *name) | 
|---|
| 248 | { | 
|---|
| 249 | return __irq_domain_alloc_fwnode(type: IRQCHIP_FWNODE_NAMED, id: 0, name, NULL); | 
|---|
| 250 | } | 
|---|
| 251 |  | 
|---|
| 252 | static inline struct fwnode_handle *irq_domain_alloc_named_id_fwnode(const char *name, int id) | 
|---|
| 253 | { | 
|---|
| 254 | return __irq_domain_alloc_fwnode(type: IRQCHIP_FWNODE_NAMED_ID, id, name, | 
|---|
| 255 | NULL); | 
|---|
| 256 | } | 
|---|
| 257 |  | 
|---|
| 258 | static inline struct fwnode_handle *irq_domain_alloc_fwnode(phys_addr_t *pa) | 
|---|
| 259 | { | 
|---|
| 260 | return __irq_domain_alloc_fwnode(type: IRQCHIP_FWNODE_REAL, id: 0, NULL, pa); | 
|---|
| 261 | } | 
|---|
| 262 |  | 
|---|
| 263 | void irq_domain_free_fwnode(struct fwnode_handle *fwnode); | 
|---|
| 264 |  | 
|---|
| 265 | DEFINE_FREE(irq_domain_free_fwnode, struct fwnode_handle *, if (_T) irq_domain_free_fwnode(_T)) | 
|---|
| 266 |  | 
|---|
| 267 | struct irq_domain_chip_generic_info; | 
|---|
| 268 |  | 
|---|
| 269 | /** | 
|---|
| 270 | * struct irq_domain_info - Domain information structure | 
|---|
| 271 | * @fwnode:		firmware node for the interrupt controller | 
|---|
| 272 | * @domain_flags:	Additional flags to add to the domain flags | 
|---|
| 273 | * @size:		Size of linear map; 0 for radix mapping only | 
|---|
| 274 | * @hwirq_max:		Maximum number of interrupts supported by controller | 
|---|
| 275 | * @direct_max:		Maximum value of direct maps; | 
|---|
| 276 | *			Use ~0 for no limit; 0 for no direct mapping | 
|---|
| 277 | * @hwirq_base:		The first hardware interrupt number (legacy domains only) | 
|---|
| 278 | * @virq_base:		The first Linux interrupt number for legacy domains to | 
|---|
| 279 | *			immediately associate the interrupts after domain creation | 
|---|
| 280 | * @bus_token:		Domain bus token | 
|---|
| 281 | * @name_suffix:	Optional name suffix to avoid collisions when multiple | 
|---|
| 282 | *			domains are added using same fwnode | 
|---|
| 283 | * @ops:		Domain operation callbacks | 
|---|
| 284 | * @host_data:		Controller private data pointer | 
|---|
| 285 | * @dev:		Device which creates the domain | 
|---|
| 286 | * @dgc_info:		Geneneric chip information structure pointer used to | 
|---|
| 287 | *			create generic chips for the domain if not NULL. | 
|---|
| 288 | * @init:		Function called when the domain is created. | 
|---|
| 289 | *			Allow to do some additional domain initialisation. | 
|---|
| 290 | * @exit:		Function called when the domain is destroyed. | 
|---|
| 291 | *			Allow to do some additional cleanup operation. | 
|---|
| 292 | */ | 
|---|
| 293 | struct irq_domain_info { | 
|---|
| 294 | struct fwnode_handle			*fwnode; | 
|---|
| 295 | unsigned int				domain_flags; | 
|---|
| 296 | unsigned int				size; | 
|---|
| 297 | irq_hw_number_t				hwirq_max; | 
|---|
| 298 | int					direct_max; | 
|---|
| 299 | unsigned int				hwirq_base; | 
|---|
| 300 | unsigned int				virq_base; | 
|---|
| 301 | enum irq_domain_bus_token		bus_token; | 
|---|
| 302 | const char				*name_suffix; | 
|---|
| 303 | const struct irq_domain_ops		*ops; | 
|---|
| 304 | void					*host_data; | 
|---|
| 305 | struct device				*dev; | 
|---|
| 306 | #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY | 
|---|
| 307 | /** | 
|---|
| 308 | * @parent: Pointer to the parent irq domain used in a hierarchy domain | 
|---|
| 309 | */ | 
|---|
| 310 | struct irq_domain			*parent; | 
|---|
| 311 | #endif | 
|---|
| 312 | struct irq_domain_chip_generic_info	*dgc_info; | 
|---|
| 313 | int					(*init)(struct irq_domain *d); | 
|---|
| 314 | void					(*exit)(struct irq_domain *d); | 
|---|
| 315 | }; | 
|---|
| 316 |  | 
|---|
| 317 | struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info); | 
|---|
| 318 | struct irq_domain *devm_irq_domain_instantiate(struct device *dev, | 
|---|
| 319 | const struct irq_domain_info *info); | 
|---|
| 320 |  | 
|---|
| 321 | struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode, unsigned int size, | 
|---|
| 322 | unsigned int first_irq, | 
|---|
| 323 | const struct irq_domain_ops *ops, void *host_data); | 
|---|
| 324 | struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode, unsigned int size, | 
|---|
| 325 | unsigned int first_irq, irq_hw_number_t first_hwirq, | 
|---|
| 326 | const struct irq_domain_ops *ops, void *host_data); | 
|---|
| 327 | struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec, | 
|---|
| 328 | enum irq_domain_bus_token bus_token); | 
|---|
| 329 | void irq_set_default_domain(struct irq_domain *domain); | 
|---|
| 330 | struct irq_domain *irq_get_default_domain(void); | 
|---|
| 331 | int irq_domain_alloc_descs(int virq, unsigned int nr_irqs, irq_hw_number_t hwirq, int node, | 
|---|
| 332 | const struct irq_affinity_desc *affinity); | 
|---|
| 333 |  | 
|---|
| 334 | extern const struct fwnode_operations irqchip_fwnode_ops; | 
|---|
| 335 |  | 
|---|
| 336 | static inline bool is_fwnode_irqchip(const struct fwnode_handle *fwnode) | 
|---|
| 337 | { | 
|---|
| 338 | return fwnode && fwnode->ops == &irqchip_fwnode_ops; | 
|---|
| 339 | } | 
|---|
| 340 |  | 
|---|
| 341 | void irq_domain_update_bus_token(struct irq_domain *domain, enum irq_domain_bus_token bus_token); | 
|---|
| 342 |  | 
|---|
| 343 | static inline struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, | 
|---|
| 344 | enum irq_domain_bus_token bus_token) | 
|---|
| 345 | { | 
|---|
| 346 | struct irq_fwspec fwspec = { | 
|---|
| 347 | .fwnode = fwnode, | 
|---|
| 348 | }; | 
|---|
| 349 |  | 
|---|
| 350 | return irq_find_matching_fwspec(fwspec: &fwspec, bus_token); | 
|---|
| 351 | } | 
|---|
| 352 |  | 
|---|
| 353 | static inline struct irq_domain *irq_find_matching_host(struct device_node *node, | 
|---|
| 354 | enum irq_domain_bus_token bus_token) | 
|---|
| 355 | { | 
|---|
| 356 | return irq_find_matching_fwnode(of_fwnode_handle(node), bus_token); | 
|---|
| 357 | } | 
|---|
| 358 |  | 
|---|
| 359 | static inline struct irq_domain *irq_find_host(struct device_node *node) | 
|---|
| 360 | { | 
|---|
| 361 | struct irq_domain *d; | 
|---|
| 362 |  | 
|---|
| 363 | d = irq_find_matching_host(node, bus_token: DOMAIN_BUS_WIRED); | 
|---|
| 364 | if (!d) | 
|---|
| 365 | d = irq_find_matching_host(node, bus_token: DOMAIN_BUS_ANY); | 
|---|
| 366 |  | 
|---|
| 367 | return d; | 
|---|
| 368 | } | 
|---|
| 369 |  | 
|---|
| 370 | #ifdef CONFIG_IRQ_DOMAIN_NOMAP | 
|---|
| 371 | static inline struct irq_domain *irq_domain_create_nomap(struct fwnode_handle *fwnode, | 
|---|
| 372 | unsigned int max_irq, | 
|---|
| 373 | const struct irq_domain_ops *ops, | 
|---|
| 374 | void *host_data) | 
|---|
| 375 | { | 
|---|
| 376 | const struct irq_domain_info info = { | 
|---|
| 377 | .fwnode		= fwnode, | 
|---|
| 378 | .hwirq_max	= max_irq, | 
|---|
| 379 | .direct_max	= max_irq, | 
|---|
| 380 | .ops		= ops, | 
|---|
| 381 | .host_data	= host_data, | 
|---|
| 382 | }; | 
|---|
| 383 | struct irq_domain *d = irq_domain_instantiate(&info); | 
|---|
| 384 |  | 
|---|
| 385 | return IS_ERR(d) ? NULL : d; | 
|---|
| 386 | } | 
|---|
| 387 |  | 
|---|
| 388 | unsigned int irq_create_direct_mapping(struct irq_domain *domain); | 
|---|
| 389 | #endif | 
|---|
| 390 |  | 
|---|
| 391 | /** | 
|---|
| 392 | * irq_domain_create_linear - Allocate and register a linear revmap irq_domain. | 
|---|
| 393 | * @fwnode:	pointer to interrupt controller's FW node. | 
|---|
| 394 | * @size:	Number of interrupts in the domain. | 
|---|
| 395 | * @ops:	map/unmap domain callbacks | 
|---|
| 396 | * @host_data:	Controller private data pointer | 
|---|
| 397 | * | 
|---|
| 398 | * Returns: Newly created irq_domain | 
|---|
| 399 | */ | 
|---|
| 400 | static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle *fwnode, | 
|---|
| 401 | unsigned int size, | 
|---|
| 402 | const struct irq_domain_ops *ops, | 
|---|
| 403 | void *host_data) | 
|---|
| 404 | { | 
|---|
| 405 | const struct irq_domain_info info = { | 
|---|
| 406 | .fwnode		= fwnode, | 
|---|
| 407 | .size		= size, | 
|---|
| 408 | .hwirq_max	= size, | 
|---|
| 409 | .ops		= ops, | 
|---|
| 410 | .host_data	= host_data, | 
|---|
| 411 | }; | 
|---|
| 412 | struct irq_domain *d = irq_domain_instantiate(info: &info); | 
|---|
| 413 |  | 
|---|
| 414 | return IS_ERR(ptr: d) ? NULL : d; | 
|---|
| 415 | } | 
|---|
| 416 |  | 
|---|
| 417 | static inline struct irq_domain *irq_domain_create_tree(struct fwnode_handle *fwnode, | 
|---|
| 418 | const struct irq_domain_ops *ops, | 
|---|
| 419 | void *host_data) | 
|---|
| 420 | { | 
|---|
| 421 | const struct irq_domain_info info = { | 
|---|
| 422 | .fwnode		= fwnode, | 
|---|
| 423 | .hwirq_max	= ~0, | 
|---|
| 424 | .ops		= ops, | 
|---|
| 425 | .host_data	= host_data, | 
|---|
| 426 | }; | 
|---|
| 427 | struct irq_domain *d = irq_domain_instantiate(info: &info); | 
|---|
| 428 |  | 
|---|
| 429 | return IS_ERR(ptr: d) ? NULL : d; | 
|---|
| 430 | } | 
|---|
| 431 |  | 
|---|
| 432 | void irq_domain_remove(struct irq_domain *domain); | 
|---|
| 433 |  | 
|---|
| 434 | int irq_domain_associate(struct irq_domain *domain, unsigned int irq, irq_hw_number_t hwirq); | 
|---|
| 435 | void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base, | 
|---|
| 436 | irq_hw_number_t hwirq_base, int count); | 
|---|
| 437 |  | 
|---|
| 438 | unsigned int irq_create_mapping_affinity(struct irq_domain *domain, irq_hw_number_t hwirq, | 
|---|
| 439 | const struct irq_affinity_desc *affinity); | 
|---|
| 440 | unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec); | 
|---|
| 441 | void irq_dispose_mapping(unsigned int virq); | 
|---|
| 442 |  | 
|---|
| 443 | /** | 
|---|
| 444 | * irq_create_mapping - Map a hardware interrupt into linux irq space | 
|---|
| 445 | * @domain:	domain owning this hardware interrupt or NULL for default domain | 
|---|
| 446 | * @hwirq:	hardware irq number in that domain space | 
|---|
| 447 | * | 
|---|
| 448 | * Only one mapping per hardware interrupt is permitted. | 
|---|
| 449 | * | 
|---|
| 450 | * If the sense/trigger is to be specified, set_irq_type() should be called | 
|---|
| 451 | * on the number returned from that call. | 
|---|
| 452 | * | 
|---|
| 453 | * Returns: Linux irq number or 0 on error | 
|---|
| 454 | */ | 
|---|
| 455 | static inline unsigned int irq_create_mapping(struct irq_domain *domain, irq_hw_number_t hwirq) | 
|---|
| 456 | { | 
|---|
| 457 | return irq_create_mapping_affinity(domain, hwirq, NULL); | 
|---|
| 458 | } | 
|---|
| 459 |  | 
|---|
| 460 | struct irq_desc *__irq_resolve_mapping(struct irq_domain *domain, | 
|---|
| 461 | irq_hw_number_t hwirq, | 
|---|
| 462 | unsigned int *irq); | 
|---|
| 463 |  | 
|---|
| 464 | /** | 
|---|
| 465 | * irq_resolve_mapping - Find a linux irq from a hw irq number. | 
|---|
| 466 | * @domain:	domain owning this hardware interrupt | 
|---|
| 467 | * @hwirq:	hardware irq number in that domain space | 
|---|
| 468 | * | 
|---|
| 469 | * Returns: Interrupt descriptor | 
|---|
| 470 | */ | 
|---|
| 471 | static inline struct irq_desc *irq_resolve_mapping(struct irq_domain *domain, | 
|---|
| 472 | irq_hw_number_t hwirq) | 
|---|
| 473 | { | 
|---|
| 474 | return __irq_resolve_mapping(domain, hwirq, NULL); | 
|---|
| 475 | } | 
|---|
| 476 |  | 
|---|
| 477 | /** | 
|---|
| 478 | * irq_find_mapping() - Find a linux irq from a hw irq number. | 
|---|
| 479 | * @domain:	domain owning this hardware interrupt | 
|---|
| 480 | * @hwirq:	hardware irq number in that domain space | 
|---|
| 481 | * | 
|---|
| 482 | * Returns: Linux irq number or 0 if not found | 
|---|
| 483 | */ | 
|---|
| 484 | static inline unsigned int irq_find_mapping(struct irq_domain *domain, | 
|---|
| 485 | irq_hw_number_t hwirq) | 
|---|
| 486 | { | 
|---|
| 487 | unsigned int irq; | 
|---|
| 488 |  | 
|---|
| 489 | if (__irq_resolve_mapping(domain, hwirq, irq: &irq)) | 
|---|
| 490 | return irq; | 
|---|
| 491 |  | 
|---|
| 492 | return 0; | 
|---|
| 493 | } | 
|---|
| 494 |  | 
|---|
| 495 | extern const struct irq_domain_ops irq_domain_simple_ops; | 
|---|
| 496 |  | 
|---|
| 497 | /* stock xlate functions */ | 
|---|
| 498 | int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr, | 
|---|
| 499 | const u32 *intspec, unsigned int intsize, | 
|---|
| 500 | irq_hw_number_t *out_hwirq, unsigned int *out_type); | 
|---|
| 501 | int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr, | 
|---|
| 502 | const u32 *intspec, unsigned int intsize, | 
|---|
| 503 | irq_hw_number_t *out_hwirq, unsigned int *out_type); | 
|---|
| 504 | int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr, | 
|---|
| 505 | const u32 *intspec, unsigned int intsize, | 
|---|
| 506 | irq_hw_number_t *out_hwirq, unsigned int *out_type); | 
|---|
| 507 | int irq_domain_xlate_twothreecell(struct irq_domain *d, struct device_node *ctrlr, | 
|---|
| 508 | const u32 *intspec, unsigned int intsize, | 
|---|
| 509 | irq_hw_number_t *out_hwirq, unsigned int *out_type); | 
|---|
| 510 |  | 
|---|
| 511 | int irq_domain_translate_onecell(struct irq_domain *d, struct irq_fwspec *fwspec, | 
|---|
| 512 | unsigned long *out_hwirq, unsigned int *out_type); | 
|---|
| 513 | int irq_domain_translate_twocell(struct irq_domain *d, struct irq_fwspec *fwspec, | 
|---|
| 514 | unsigned long *out_hwirq, unsigned int *out_type); | 
|---|
| 515 | int irq_domain_translate_twothreecell(struct irq_domain *d, struct irq_fwspec *fwspec, | 
|---|
| 516 | unsigned long *out_hwirq, unsigned int *out_type); | 
|---|
| 517 |  | 
|---|
| 518 | /* IPI functions */ | 
|---|
| 519 | int irq_reserve_ipi(struct irq_domain *domain, const struct cpumask *dest); | 
|---|
| 520 | int irq_destroy_ipi(unsigned int irq, const struct cpumask *dest); | 
|---|
| 521 |  | 
|---|
| 522 | /* V2 interfaces to support hierarchy IRQ domains. */ | 
|---|
| 523 | struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain, unsigned int virq); | 
|---|
| 524 | void irq_domain_set_info(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq, | 
|---|
| 525 | const struct irq_chip *chip, void *chip_data, irq_flow_handler_t handler, | 
|---|
| 526 | void *handler_data, const char *handler_name); | 
|---|
| 527 | void irq_domain_reset_irq_data(struct irq_data *irq_data); | 
|---|
| 528 | #ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY | 
|---|
| 529 | /** | 
|---|
| 530 | * irq_domain_create_hierarchy - Add a irqdomain into the hierarchy | 
|---|
| 531 | * @parent:	Parent irq domain to associate with the new domain | 
|---|
| 532 | * @flags:	Irq domain flags associated to the domain | 
|---|
| 533 | * @size:	Size of the domain. See below | 
|---|
| 534 | * @fwnode:	Optional fwnode of the interrupt controller | 
|---|
| 535 | * @ops:	Pointer to the interrupt domain callbacks | 
|---|
| 536 | * @host_data:	Controller private data pointer | 
|---|
| 537 | * | 
|---|
| 538 | * If @size is 0 a tree domain is created, otherwise a linear domain. | 
|---|
| 539 | * | 
|---|
| 540 | * If successful the parent is associated to the new domain and the | 
|---|
| 541 | * domain flags are set. | 
|---|
| 542 | * | 
|---|
| 543 | * Returns: A pointer to IRQ domain, or %NULL on failure. | 
|---|
| 544 | */ | 
|---|
| 545 | static inline struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent, | 
|---|
| 546 | unsigned int flags, unsigned int size, | 
|---|
| 547 | struct fwnode_handle *fwnode, | 
|---|
| 548 | const struct irq_domain_ops *ops, | 
|---|
| 549 | void *host_data) | 
|---|
| 550 | { | 
|---|
| 551 | const struct irq_domain_info info = { | 
|---|
| 552 | .fwnode		= fwnode, | 
|---|
| 553 | .size		= size, | 
|---|
| 554 | .hwirq_max	= size ? : ~0U, | 
|---|
| 555 | .ops		= ops, | 
|---|
| 556 | .host_data	= host_data, | 
|---|
| 557 | .domain_flags	= flags, | 
|---|
| 558 | .parent		= parent, | 
|---|
| 559 | }; | 
|---|
| 560 | struct irq_domain *d = irq_domain_instantiate(info: &info); | 
|---|
| 561 |  | 
|---|
| 562 | return IS_ERR(ptr: d) ? NULL : d; | 
|---|
| 563 | } | 
|---|
| 564 |  | 
|---|
| 565 | int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, unsigned int nr_irqs, | 
|---|
| 566 | int node, void *arg, bool realloc, | 
|---|
| 567 | const struct irq_affinity_desc *affinity); | 
|---|
| 568 | void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs); | 
|---|
| 569 | int irq_domain_activate_irq(struct irq_data *irq_data, bool early); | 
|---|
| 570 | void irq_domain_deactivate_irq(struct irq_data *irq_data); | 
|---|
| 571 |  | 
|---|
| 572 | /** | 
|---|
| 573 | * irq_domain_alloc_irqs - Allocate IRQs from domain | 
|---|
| 574 | * @domain:	domain to allocate from | 
|---|
| 575 | * @nr_irqs:	number of IRQs to allocate | 
|---|
| 576 | * @node:	NUMA node id for memory allocation | 
|---|
| 577 | * @arg:	domain specific argument | 
|---|
| 578 | * | 
|---|
| 579 | * See __irq_domain_alloc_irqs()' documentation. | 
|---|
| 580 | */ | 
|---|
| 581 | static inline int irq_domain_alloc_irqs(struct irq_domain *domain, unsigned int nr_irqs, | 
|---|
| 582 | int node, void *arg) | 
|---|
| 583 | { | 
|---|
| 584 | return __irq_domain_alloc_irqs(domain, irq_base: -1, nr_irqs, node, arg, realloc: false, NULL); | 
|---|
| 585 | } | 
|---|
| 586 |  | 
|---|
| 587 | int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, unsigned int virq, | 
|---|
| 588 | irq_hw_number_t hwirq, const struct irq_chip *chip, | 
|---|
| 589 | void *chip_data); | 
|---|
| 590 | void irq_domain_free_irqs_common(struct irq_domain *domain, unsigned int virq, | 
|---|
| 591 | unsigned int nr_irqs); | 
|---|
| 592 | void irq_domain_free_irqs_top(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs); | 
|---|
| 593 |  | 
|---|
| 594 | int irq_domain_push_irq(struct irq_domain *domain, int virq, void *arg); | 
|---|
| 595 | int irq_domain_pop_irq(struct irq_domain *domain, int virq); | 
|---|
| 596 |  | 
|---|
| 597 | int irq_domain_alloc_irqs_parent(struct irq_domain *domain, unsigned int irq_base, | 
|---|
| 598 | unsigned int nr_irqs, void *arg); | 
|---|
| 599 |  | 
|---|
| 600 | void irq_domain_free_irqs_parent(struct irq_domain *domain, unsigned int irq_base, | 
|---|
| 601 | unsigned int nr_irqs); | 
|---|
| 602 |  | 
|---|
| 603 | int irq_domain_disconnect_hierarchy(struct irq_domain *domain, unsigned int virq); | 
|---|
| 604 |  | 
|---|
| 605 | static inline bool irq_domain_is_hierarchy(struct irq_domain *domain) | 
|---|
| 606 | { | 
|---|
| 607 | return domain->flags & IRQ_DOMAIN_FLAG_HIERARCHY; | 
|---|
| 608 | } | 
|---|
| 609 |  | 
|---|
| 610 | static inline bool irq_domain_is_ipi(struct irq_domain *domain) | 
|---|
| 611 | { | 
|---|
| 612 | return domain->flags & (IRQ_DOMAIN_FLAG_IPI_PER_CPU | IRQ_DOMAIN_FLAG_IPI_SINGLE); | 
|---|
| 613 | } | 
|---|
| 614 |  | 
|---|
| 615 | static inline bool irq_domain_is_ipi_per_cpu(struct irq_domain *domain) | 
|---|
| 616 | { | 
|---|
| 617 | return domain->flags & IRQ_DOMAIN_FLAG_IPI_PER_CPU; | 
|---|
| 618 | } | 
|---|
| 619 |  | 
|---|
| 620 | static inline bool irq_domain_is_ipi_single(struct irq_domain *domain) | 
|---|
| 621 | { | 
|---|
| 622 | return domain->flags & IRQ_DOMAIN_FLAG_IPI_SINGLE; | 
|---|
| 623 | } | 
|---|
| 624 |  | 
|---|
| 625 | static inline bool irq_domain_is_msi(struct irq_domain *domain) | 
|---|
| 626 | { | 
|---|
| 627 | return domain->flags & IRQ_DOMAIN_FLAG_MSI; | 
|---|
| 628 | } | 
|---|
| 629 |  | 
|---|
| 630 | static inline bool irq_domain_is_msi_parent(struct irq_domain *domain) | 
|---|
| 631 | { | 
|---|
| 632 | return domain->flags & IRQ_DOMAIN_FLAG_MSI_PARENT; | 
|---|
| 633 | } | 
|---|
| 634 |  | 
|---|
| 635 | static inline bool irq_domain_is_msi_device(struct irq_domain *domain) | 
|---|
| 636 | { | 
|---|
| 637 | return domain->flags & IRQ_DOMAIN_FLAG_MSI_DEVICE; | 
|---|
| 638 | } | 
|---|
| 639 |  | 
|---|
| 640 | static inline bool irq_domain_is_msi_immutable(struct irq_domain *domain) | 
|---|
| 641 | { | 
|---|
| 642 | return domain->flags & IRQ_DOMAIN_FLAG_MSI_IMMUTABLE; | 
|---|
| 643 | } | 
|---|
| 644 | #else	/* CONFIG_IRQ_DOMAIN_HIERARCHY */ | 
|---|
| 645 | static inline int irq_domain_alloc_irqs(struct irq_domain *domain, unsigned int nr_irqs, | 
|---|
| 646 | int node, void *arg) | 
|---|
| 647 | { | 
|---|
| 648 | return -1; | 
|---|
| 649 | } | 
|---|
| 650 |  | 
|---|
| 651 | static inline void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs) { } | 
|---|
| 652 |  | 
|---|
| 653 | static inline bool irq_domain_is_hierarchy(struct irq_domain *domain) | 
|---|
| 654 | { | 
|---|
| 655 | return false; | 
|---|
| 656 | } | 
|---|
| 657 |  | 
|---|
| 658 | static inline bool irq_domain_is_ipi(struct irq_domain *domain) | 
|---|
| 659 | { | 
|---|
| 660 | return false; | 
|---|
| 661 | } | 
|---|
| 662 |  | 
|---|
| 663 | static inline bool irq_domain_is_ipi_per_cpu(struct irq_domain *domain) | 
|---|
| 664 | { | 
|---|
| 665 | return false; | 
|---|
| 666 | } | 
|---|
| 667 |  | 
|---|
| 668 | static inline bool irq_domain_is_ipi_single(struct irq_domain *domain) | 
|---|
| 669 | { | 
|---|
| 670 | return false; | 
|---|
| 671 | } | 
|---|
| 672 |  | 
|---|
| 673 | static inline bool irq_domain_is_msi(struct irq_domain *domain) | 
|---|
| 674 | { | 
|---|
| 675 | return false; | 
|---|
| 676 | } | 
|---|
| 677 |  | 
|---|
| 678 | static inline bool irq_domain_is_msi_parent(struct irq_domain *domain) | 
|---|
| 679 | { | 
|---|
| 680 | return false; | 
|---|
| 681 | } | 
|---|
| 682 |  | 
|---|
| 683 | static inline bool irq_domain_is_msi_device(struct irq_domain *domain) | 
|---|
| 684 | { | 
|---|
| 685 | return false; | 
|---|
| 686 | } | 
|---|
| 687 |  | 
|---|
| 688 | #endif	/* CONFIG_IRQ_DOMAIN_HIERARCHY */ | 
|---|
| 689 |  | 
|---|
| 690 | #ifdef CONFIG_GENERIC_MSI_IRQ | 
|---|
| 691 | int msi_device_domain_alloc_wired(struct irq_domain *domain, unsigned int hwirq, unsigned int type); | 
|---|
| 692 | void msi_device_domain_free_wired(struct irq_domain *domain, unsigned int virq); | 
|---|
| 693 | #else | 
|---|
| 694 | static inline int msi_device_domain_alloc_wired(struct irq_domain *domain, unsigned int hwirq, | 
|---|
| 695 | unsigned int type) | 
|---|
| 696 | { | 
|---|
| 697 | WARN_ON_ONCE(1); | 
|---|
| 698 | return -EINVAL; | 
|---|
| 699 | } | 
|---|
| 700 | static inline void msi_device_domain_free_wired(struct irq_domain *domain, unsigned int virq) | 
|---|
| 701 | { | 
|---|
| 702 | WARN_ON_ONCE(1); | 
|---|
| 703 | } | 
|---|
| 704 | #endif | 
|---|
| 705 |  | 
|---|
| 706 | /* Deprecated functions. Will be removed in the merge window */ | 
|---|
| 707 | static inline struct fwnode_handle *of_node_to_fwnode(struct device_node *node) | 
|---|
| 708 | { | 
|---|
| 709 | return node ? &node->fwnode : NULL; | 
|---|
| 710 | } | 
|---|
| 711 |  | 
|---|
| 712 | static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node, | 
|---|
| 713 | const struct irq_domain_ops *ops, | 
|---|
| 714 | void *host_data) | 
|---|
| 715 | { | 
|---|
| 716 | struct irq_domain_info info = { | 
|---|
| 717 | .fwnode		= of_fwnode_handle(of_node), | 
|---|
| 718 | .hwirq_max	= ~0U, | 
|---|
| 719 | .ops		= ops, | 
|---|
| 720 | .host_data	= host_data, | 
|---|
| 721 | }; | 
|---|
| 722 | struct irq_domain *d; | 
|---|
| 723 |  | 
|---|
| 724 | d = irq_domain_instantiate(info: &info); | 
|---|
| 725 | return IS_ERR(ptr: d) ? NULL : d; | 
|---|
| 726 | } | 
|---|
| 727 |  | 
|---|
| 728 | static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_node, | 
|---|
| 729 | unsigned int size, | 
|---|
| 730 | const struct irq_domain_ops *ops, | 
|---|
| 731 | void *host_data) | 
|---|
| 732 | { | 
|---|
| 733 | struct irq_domain_info info = { | 
|---|
| 734 | .fwnode		= of_fwnode_handle(of_node), | 
|---|
| 735 | .size		= size, | 
|---|
| 736 | .hwirq_max	= size, | 
|---|
| 737 | .ops		= ops, | 
|---|
| 738 | .host_data	= host_data, | 
|---|
| 739 | }; | 
|---|
| 740 | struct irq_domain *d; | 
|---|
| 741 |  | 
|---|
| 742 | d = irq_domain_instantiate(info: &info); | 
|---|
| 743 | return IS_ERR(ptr: d) ? NULL : d; | 
|---|
| 744 | } | 
|---|
| 745 |  | 
|---|
| 746 | #else /* CONFIG_IRQ_DOMAIN */ | 
|---|
| 747 | static inline void irq_dispose_mapping(unsigned int virq) { } | 
|---|
| 748 | static inline struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, | 
|---|
| 749 | enum irq_domain_bus_token bus_token) | 
|---|
| 750 | { | 
|---|
| 751 | return NULL; | 
|---|
| 752 | } | 
|---|
| 753 | #endif /* !CONFIG_IRQ_DOMAIN */ | 
|---|
| 754 |  | 
|---|
| 755 | #endif /* _LINUX_IRQDOMAIN_H */ | 
|---|
| 756 |  | 
|---|