1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * irq_domain - IRQ translation domains
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Translation infrastructure between hw and linux irq numbers. This is
6*4882a593Smuzhiyun * helpful for interrupt controllers to implement mapping between hardware
7*4882a593Smuzhiyun * irq numbers and the Linux irq number space.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * irq_domains also have hooks for translating device tree or other
10*4882a593Smuzhiyun * firmware interrupt representations into a hardware irq number that
11*4882a593Smuzhiyun * can be mapped back to a Linux irq number without any extra platform
12*4882a593Smuzhiyun * support code.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * Interrupt controller "domain" data structure. This could be defined as a
15*4882a593Smuzhiyun * irq domain controller. That is, it handles the mapping between hardware
16*4882a593Smuzhiyun * and virtual interrupt numbers for a given interrupt domain. The domain
17*4882a593Smuzhiyun * structure is generally created by the PIC code for a given PIC instance
18*4882a593Smuzhiyun * (though a domain can cover more than one PIC if they have a flat number
19*4882a593Smuzhiyun * model). It's the domain callbacks that are responsible for setting the
20*4882a593Smuzhiyun * irq_chip on a given irq_desc after it's been mapped.
21*4882a593Smuzhiyun *
22*4882a593Smuzhiyun * The host code and data structures use a fwnode_handle pointer to
23*4882a593Smuzhiyun * identify the domain. In some cases, and in order to preserve source
24*4882a593Smuzhiyun * code compatibility, this fwnode pointer is "upgraded" to a DT
25*4882a593Smuzhiyun * device_node. For those firmware infrastructures that do not provide
26*4882a593Smuzhiyun * a unique identifier for an interrupt controller, the irq_domain
27*4882a593Smuzhiyun * code offers a fwnode allocator.
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #ifndef _LINUX_IRQDOMAIN_H
31*4882a593Smuzhiyun #define _LINUX_IRQDOMAIN_H
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #include <linux/types.h>
34*4882a593Smuzhiyun #include <linux/irqhandler.h>
35*4882a593Smuzhiyun #include <linux/of.h>
36*4882a593Smuzhiyun #include <linux/mutex.h>
37*4882a593Smuzhiyun #include <linux/radix-tree.h>
38*4882a593Smuzhiyun #include <linux/android_kabi.h>
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun struct device_node;
41*4882a593Smuzhiyun struct irq_domain;
42*4882a593Smuzhiyun struct of_device_id;
43*4882a593Smuzhiyun struct irq_chip;
44*4882a593Smuzhiyun struct irq_data;
45*4882a593Smuzhiyun struct cpumask;
46*4882a593Smuzhiyun struct seq_file;
47*4882a593Smuzhiyun struct irq_affinity_desc;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun /* Number of irqs reserved for a legacy isa controller */
50*4882a593Smuzhiyun #define NUM_ISA_INTERRUPTS 16
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #define IRQ_DOMAIN_IRQ_SPEC_PARAMS 16
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun /**
55*4882a593Smuzhiyun * struct irq_fwspec - generic IRQ specifier structure
56*4882a593Smuzhiyun *
57*4882a593Smuzhiyun * @fwnode: Pointer to a firmware-specific descriptor
58*4882a593Smuzhiyun * @param_count: Number of device-specific parameters
59*4882a593Smuzhiyun * @param: Device-specific parameters
60*4882a593Smuzhiyun *
61*4882a593Smuzhiyun * This structure, directly modeled after of_phandle_args, is used to
62*4882a593Smuzhiyun * pass a device-specific description of an interrupt.
63*4882a593Smuzhiyun */
64*4882a593Smuzhiyun struct irq_fwspec {
65*4882a593Smuzhiyun struct fwnode_handle *fwnode;
66*4882a593Smuzhiyun int param_count;
67*4882a593Smuzhiyun u32 param[IRQ_DOMAIN_IRQ_SPEC_PARAMS];
68*4882a593Smuzhiyun };
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /*
71*4882a593Smuzhiyun * Should several domains have the same device node, but serve
72*4882a593Smuzhiyun * different purposes (for example one domain is for PCI/MSI, and the
73*4882a593Smuzhiyun * other for wired IRQs), they can be distinguished using a
74*4882a593Smuzhiyun * bus-specific token. Most domains are expected to only carry
75*4882a593Smuzhiyun * DOMAIN_BUS_ANY.
76*4882a593Smuzhiyun */
77*4882a593Smuzhiyun enum irq_domain_bus_token {
78*4882a593Smuzhiyun DOMAIN_BUS_ANY = 0,
79*4882a593Smuzhiyun DOMAIN_BUS_WIRED,
80*4882a593Smuzhiyun DOMAIN_BUS_GENERIC_MSI,
81*4882a593Smuzhiyun DOMAIN_BUS_PCI_MSI,
82*4882a593Smuzhiyun DOMAIN_BUS_PLATFORM_MSI,
83*4882a593Smuzhiyun DOMAIN_BUS_NEXUS,
84*4882a593Smuzhiyun DOMAIN_BUS_IPI,
85*4882a593Smuzhiyun DOMAIN_BUS_FSL_MC_MSI,
86*4882a593Smuzhiyun DOMAIN_BUS_TI_SCI_INTA_MSI,
87*4882a593Smuzhiyun DOMAIN_BUS_WAKEUP,
88*4882a593Smuzhiyun DOMAIN_BUS_VMD_MSI,
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun /**
92*4882a593Smuzhiyun * struct irq_domain_ops - Methods for irq_domain objects
93*4882a593Smuzhiyun * @match: Match an interrupt controller device node to a host, returns
94*4882a593Smuzhiyun * 1 on a match
95*4882a593Smuzhiyun * @map: Create or update a mapping between a virtual irq number and a hw
96*4882a593Smuzhiyun * irq number. This is called only once for a given mapping.
97*4882a593Smuzhiyun * @unmap: Dispose of such a mapping
98*4882a593Smuzhiyun * @xlate: Given a device tree node and interrupt specifier, decode
99*4882a593Smuzhiyun * the hardware irq number and linux irq type value.
100*4882a593Smuzhiyun *
101*4882a593Smuzhiyun * Functions below are provided by the driver and called whenever a new mapping
102*4882a593Smuzhiyun * is created or an old mapping is disposed. The driver can then proceed to
103*4882a593Smuzhiyun * whatever internal data structures management is required. It also needs
104*4882a593Smuzhiyun * to setup the irq_desc when returning from map().
105*4882a593Smuzhiyun */
106*4882a593Smuzhiyun struct irq_domain_ops {
107*4882a593Smuzhiyun int (*match)(struct irq_domain *d, struct device_node *node,
108*4882a593Smuzhiyun enum irq_domain_bus_token bus_token);
109*4882a593Smuzhiyun int (*select)(struct irq_domain *d, struct irq_fwspec *fwspec,
110*4882a593Smuzhiyun enum irq_domain_bus_token bus_token);
111*4882a593Smuzhiyun int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);
112*4882a593Smuzhiyun void (*unmap)(struct irq_domain *d, unsigned int virq);
113*4882a593Smuzhiyun int (*xlate)(struct irq_domain *d, struct device_node *node,
114*4882a593Smuzhiyun const u32 *intspec, unsigned int intsize,
115*4882a593Smuzhiyun unsigned long *out_hwirq, unsigned int *out_type);
116*4882a593Smuzhiyun #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
117*4882a593Smuzhiyun /* extended V2 interfaces to support hierarchy irq_domains */
118*4882a593Smuzhiyun int (*alloc)(struct irq_domain *d, unsigned int virq,
119*4882a593Smuzhiyun unsigned int nr_irqs, void *arg);
120*4882a593Smuzhiyun void (*free)(struct irq_domain *d, unsigned int virq,
121*4882a593Smuzhiyun unsigned int nr_irqs);
122*4882a593Smuzhiyun int (*activate)(struct irq_domain *d, struct irq_data *irqd, bool reserve);
123*4882a593Smuzhiyun void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
124*4882a593Smuzhiyun int (*translate)(struct irq_domain *d, struct irq_fwspec *fwspec,
125*4882a593Smuzhiyun unsigned long *out_hwirq, unsigned int *out_type);
126*4882a593Smuzhiyun #endif
127*4882a593Smuzhiyun #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
128*4882a593Smuzhiyun void (*debug_show)(struct seq_file *m, struct irq_domain *d,
129*4882a593Smuzhiyun struct irq_data *irqd, int ind);
130*4882a593Smuzhiyun #endif
131*4882a593Smuzhiyun };
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun extern struct irq_domain_ops irq_generic_chip_ops;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun struct irq_domain_chip_generic;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun /**
138*4882a593Smuzhiyun * struct irq_domain - Hardware interrupt number translation object
139*4882a593Smuzhiyun * @link: Element in global irq_domain list.
140*4882a593Smuzhiyun * @name: Name of interrupt domain
141*4882a593Smuzhiyun * @ops: pointer to irq_domain methods
142*4882a593Smuzhiyun * @host_data: private data pointer for use by owner. Not touched by irq_domain
143*4882a593Smuzhiyun * core code.
144*4882a593Smuzhiyun * @flags: host per irq_domain flags
145*4882a593Smuzhiyun * @mapcount: The number of mapped interrupts
146*4882a593Smuzhiyun *
147*4882a593Smuzhiyun * Optional elements
148*4882a593Smuzhiyun * @fwnode: Pointer to firmware node associated with the irq_domain. Pretty easy
149*4882a593Smuzhiyun * to swap it for the of_node via the irq_domain_get_of_node accessor
150*4882a593Smuzhiyun * @gc: Pointer to a list of generic chips. There is a helper function for
151*4882a593Smuzhiyun * setting up one or more generic chips for interrupt controllers
152*4882a593Smuzhiyun * drivers using the generic chip library which uses this pointer.
153*4882a593Smuzhiyun * @parent: Pointer to parent irq_domain to support hierarchy irq_domains
154*4882a593Smuzhiyun * @debugfs_file: dentry for the domain debugfs file
155*4882a593Smuzhiyun *
156*4882a593Smuzhiyun * Revmap data, used internally by irq_domain
157*4882a593Smuzhiyun * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that
158*4882a593Smuzhiyun * support direct mapping
159*4882a593Smuzhiyun * @revmap_size: Size of the linear map table @linear_revmap[]
160*4882a593Smuzhiyun * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map
161*4882a593Smuzhiyun * @linear_revmap: Linear table of hwirq->virq reverse mappings
162*4882a593Smuzhiyun */
163*4882a593Smuzhiyun struct irq_domain {
164*4882a593Smuzhiyun struct list_head link;
165*4882a593Smuzhiyun const char *name;
166*4882a593Smuzhiyun const struct irq_domain_ops *ops;
167*4882a593Smuzhiyun void *host_data;
168*4882a593Smuzhiyun unsigned int flags;
169*4882a593Smuzhiyun unsigned int mapcount;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* Optional data */
172*4882a593Smuzhiyun struct fwnode_handle *fwnode;
173*4882a593Smuzhiyun enum irq_domain_bus_token bus_token;
174*4882a593Smuzhiyun struct irq_domain_chip_generic *gc;
175*4882a593Smuzhiyun #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
176*4882a593Smuzhiyun struct irq_domain *parent;
177*4882a593Smuzhiyun #endif
178*4882a593Smuzhiyun #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
179*4882a593Smuzhiyun struct dentry *debugfs_file;
180*4882a593Smuzhiyun #endif
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun ANDROID_KABI_RESERVE(1);
183*4882a593Smuzhiyun ANDROID_KABI_RESERVE(2);
184*4882a593Smuzhiyun ANDROID_KABI_RESERVE(3);
185*4882a593Smuzhiyun ANDROID_KABI_RESERVE(4);
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun /* reverse map data. The linear map gets appended to the irq_domain */
188*4882a593Smuzhiyun irq_hw_number_t hwirq_max;
189*4882a593Smuzhiyun unsigned int revmap_direct_max_irq;
190*4882a593Smuzhiyun unsigned int revmap_size;
191*4882a593Smuzhiyun struct radix_tree_root revmap_tree;
192*4882a593Smuzhiyun struct mutex revmap_tree_mutex;
193*4882a593Smuzhiyun unsigned int linear_revmap[];
194*4882a593Smuzhiyun };
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /* Irq domain flags */
197*4882a593Smuzhiyun enum {
198*4882a593Smuzhiyun /* Irq domain is hierarchical */
199*4882a593Smuzhiyun IRQ_DOMAIN_FLAG_HIERARCHY = (1 << 0),
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun /* Irq domain name was allocated in __irq_domain_add() */
202*4882a593Smuzhiyun IRQ_DOMAIN_NAME_ALLOCATED = (1 << 1),
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun /* Irq domain is an IPI domain with virq per cpu */
205*4882a593Smuzhiyun IRQ_DOMAIN_FLAG_IPI_PER_CPU = (1 << 2),
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /* Irq domain is an IPI domain with single virq */
208*4882a593Smuzhiyun IRQ_DOMAIN_FLAG_IPI_SINGLE = (1 << 3),
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun /* Irq domain implements MSIs */
211*4882a593Smuzhiyun IRQ_DOMAIN_FLAG_MSI = (1 << 4),
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /* Irq domain implements MSI remapping */
214*4882a593Smuzhiyun IRQ_DOMAIN_FLAG_MSI_REMAP = (1 << 5),
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun /*
217*4882a593Smuzhiyun * Quirk to handle MSI implementations which do not provide
218*4882a593Smuzhiyun * masking. Currently known to affect x86, but partially
219*4882a593Smuzhiyun * handled in core code.
220*4882a593Smuzhiyun */
221*4882a593Smuzhiyun IRQ_DOMAIN_MSI_NOMASK_QUIRK = (1 << 6),
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /*
224*4882a593Smuzhiyun * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
225*4882a593Smuzhiyun * for implementation specific purposes and ignored by the
226*4882a593Smuzhiyun * core code.
227*4882a593Smuzhiyun */
228*4882a593Smuzhiyun IRQ_DOMAIN_FLAG_NONCORE = (1 << 16),
229*4882a593Smuzhiyun };
230*4882a593Smuzhiyun
irq_domain_get_of_node(struct irq_domain * d)231*4882a593Smuzhiyun static inline struct device_node *irq_domain_get_of_node(struct irq_domain *d)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun return to_of_node(d->fwnode);
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun #ifdef CONFIG_IRQ_DOMAIN
237*4882a593Smuzhiyun struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id,
238*4882a593Smuzhiyun const char *name, phys_addr_t *pa);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun enum {
241*4882a593Smuzhiyun IRQCHIP_FWNODE_REAL,
242*4882a593Smuzhiyun IRQCHIP_FWNODE_NAMED,
243*4882a593Smuzhiyun IRQCHIP_FWNODE_NAMED_ID,
244*4882a593Smuzhiyun };
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun static inline
irq_domain_alloc_named_fwnode(const char * name)247*4882a593Smuzhiyun struct fwnode_handle *irq_domain_alloc_named_fwnode(const char *name)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED, 0, name, NULL);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun static inline
irq_domain_alloc_named_id_fwnode(const char * name,int id)253*4882a593Smuzhiyun struct fwnode_handle *irq_domain_alloc_named_id_fwnode(const char *name, int id)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED_ID, id, name,
256*4882a593Smuzhiyun NULL);
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun
irq_domain_alloc_fwnode(phys_addr_t * pa)259*4882a593Smuzhiyun static inline struct fwnode_handle *irq_domain_alloc_fwnode(phys_addr_t *pa)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_REAL, 0, NULL, pa);
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun void irq_domain_free_fwnode(struct fwnode_handle *fwnode);
265*4882a593Smuzhiyun struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
266*4882a593Smuzhiyun irq_hw_number_t hwirq_max, int direct_max,
267*4882a593Smuzhiyun const struct irq_domain_ops *ops,
268*4882a593Smuzhiyun void *host_data);
269*4882a593Smuzhiyun struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
270*4882a593Smuzhiyun unsigned int size,
271*4882a593Smuzhiyun unsigned int first_irq,
272*4882a593Smuzhiyun const struct irq_domain_ops *ops,
273*4882a593Smuzhiyun void *host_data);
274*4882a593Smuzhiyun struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
275*4882a593Smuzhiyun unsigned int size,
276*4882a593Smuzhiyun unsigned int first_irq,
277*4882a593Smuzhiyun irq_hw_number_t first_hwirq,
278*4882a593Smuzhiyun const struct irq_domain_ops *ops,
279*4882a593Smuzhiyun void *host_data);
280*4882a593Smuzhiyun extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
281*4882a593Smuzhiyun enum irq_domain_bus_token bus_token);
282*4882a593Smuzhiyun extern bool irq_domain_check_msi_remap(void);
283*4882a593Smuzhiyun extern void irq_set_default_host(struct irq_domain *host);
284*4882a593Smuzhiyun extern struct irq_domain *irq_get_default_host(void);
285*4882a593Smuzhiyun extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs,
286*4882a593Smuzhiyun irq_hw_number_t hwirq, int node,
287*4882a593Smuzhiyun const struct irq_affinity_desc *affinity);
288*4882a593Smuzhiyun
of_node_to_fwnode(struct device_node * node)289*4882a593Smuzhiyun static inline struct fwnode_handle *of_node_to_fwnode(struct device_node *node)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun return node ? &node->fwnode : NULL;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun extern const struct fwnode_operations irqchip_fwnode_ops;
295*4882a593Smuzhiyun
is_fwnode_irqchip(struct fwnode_handle * fwnode)296*4882a593Smuzhiyun static inline bool is_fwnode_irqchip(struct fwnode_handle *fwnode)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun return fwnode && fwnode->ops == &irqchip_fwnode_ops;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun extern void irq_domain_update_bus_token(struct irq_domain *domain,
302*4882a593Smuzhiyun enum irq_domain_bus_token bus_token);
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun static inline
irq_find_matching_fwnode(struct fwnode_handle * fwnode,enum irq_domain_bus_token bus_token)305*4882a593Smuzhiyun struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode,
306*4882a593Smuzhiyun enum irq_domain_bus_token bus_token)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun struct irq_fwspec fwspec = {
309*4882a593Smuzhiyun .fwnode = fwnode,
310*4882a593Smuzhiyun };
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun return irq_find_matching_fwspec(&fwspec, bus_token);
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
irq_find_matching_host(struct device_node * node,enum irq_domain_bus_token bus_token)315*4882a593Smuzhiyun static inline struct irq_domain *irq_find_matching_host(struct device_node *node,
316*4882a593Smuzhiyun enum irq_domain_bus_token bus_token)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun return irq_find_matching_fwnode(of_node_to_fwnode(node), bus_token);
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
irq_find_host(struct device_node * node)321*4882a593Smuzhiyun static inline struct irq_domain *irq_find_host(struct device_node *node)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun struct irq_domain *d;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun d = irq_find_matching_host(node, DOMAIN_BUS_WIRED);
326*4882a593Smuzhiyun if (!d)
327*4882a593Smuzhiyun d = irq_find_matching_host(node, DOMAIN_BUS_ANY);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun return d;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun /**
333*4882a593Smuzhiyun * irq_domain_add_linear() - Allocate and register a linear revmap irq_domain.
334*4882a593Smuzhiyun * @of_node: pointer to interrupt controller's device tree node.
335*4882a593Smuzhiyun * @size: Number of interrupts in the domain.
336*4882a593Smuzhiyun * @ops: map/unmap domain callbacks
337*4882a593Smuzhiyun * @host_data: Controller private data pointer
338*4882a593Smuzhiyun */
irq_domain_add_linear(struct device_node * of_node,unsigned int size,const struct irq_domain_ops * ops,void * host_data)339*4882a593Smuzhiyun static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
340*4882a593Smuzhiyun unsigned int size,
341*4882a593Smuzhiyun const struct irq_domain_ops *ops,
342*4882a593Smuzhiyun void *host_data)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun return __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops, host_data);
345*4882a593Smuzhiyun }
irq_domain_add_nomap(struct device_node * of_node,unsigned int max_irq,const struct irq_domain_ops * ops,void * host_data)346*4882a593Smuzhiyun static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
347*4882a593Smuzhiyun unsigned int max_irq,
348*4882a593Smuzhiyun const struct irq_domain_ops *ops,
349*4882a593Smuzhiyun void *host_data)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun return __irq_domain_add(of_node_to_fwnode(of_node), 0, max_irq, max_irq, ops, host_data);
352*4882a593Smuzhiyun }
irq_domain_add_legacy_isa(struct device_node * of_node,const struct irq_domain_ops * ops,void * host_data)353*4882a593Smuzhiyun static inline struct irq_domain *irq_domain_add_legacy_isa(
354*4882a593Smuzhiyun struct device_node *of_node,
355*4882a593Smuzhiyun const struct irq_domain_ops *ops,
356*4882a593Smuzhiyun void *host_data)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops,
359*4882a593Smuzhiyun host_data);
360*4882a593Smuzhiyun }
irq_domain_add_tree(struct device_node * of_node,const struct irq_domain_ops * ops,void * host_data)361*4882a593Smuzhiyun static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
362*4882a593Smuzhiyun const struct irq_domain_ops *ops,
363*4882a593Smuzhiyun void *host_data)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun return __irq_domain_add(of_node_to_fwnode(of_node), 0, ~0, 0, ops, host_data);
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun
irq_domain_create_linear(struct fwnode_handle * fwnode,unsigned int size,const struct irq_domain_ops * ops,void * host_data)368*4882a593Smuzhiyun static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle *fwnode,
369*4882a593Smuzhiyun unsigned int size,
370*4882a593Smuzhiyun const struct irq_domain_ops *ops,
371*4882a593Smuzhiyun void *host_data)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun return __irq_domain_add(fwnode, size, size, 0, ops, host_data);
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
irq_domain_create_tree(struct fwnode_handle * fwnode,const struct irq_domain_ops * ops,void * host_data)376*4882a593Smuzhiyun static inline struct irq_domain *irq_domain_create_tree(struct fwnode_handle *fwnode,
377*4882a593Smuzhiyun const struct irq_domain_ops *ops,
378*4882a593Smuzhiyun void *host_data)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun return __irq_domain_add(fwnode, 0, ~0, 0, ops, host_data);
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun extern void irq_domain_remove(struct irq_domain *host);
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun extern int irq_domain_associate(struct irq_domain *domain, unsigned int irq,
386*4882a593Smuzhiyun irq_hw_number_t hwirq);
387*4882a593Smuzhiyun extern void irq_domain_associate_many(struct irq_domain *domain,
388*4882a593Smuzhiyun unsigned int irq_base,
389*4882a593Smuzhiyun irq_hw_number_t hwirq_base, int count);
390*4882a593Smuzhiyun extern void irq_domain_disassociate(struct irq_domain *domain,
391*4882a593Smuzhiyun unsigned int irq);
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun extern unsigned int irq_create_mapping_affinity(struct irq_domain *host,
394*4882a593Smuzhiyun irq_hw_number_t hwirq,
395*4882a593Smuzhiyun const struct irq_affinity_desc *affinity);
396*4882a593Smuzhiyun extern unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec);
397*4882a593Smuzhiyun extern void irq_dispose_mapping(unsigned int virq);
398*4882a593Smuzhiyun
irq_create_mapping(struct irq_domain * host,irq_hw_number_t hwirq)399*4882a593Smuzhiyun static inline unsigned int irq_create_mapping(struct irq_domain *host,
400*4882a593Smuzhiyun irq_hw_number_t hwirq)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun return irq_create_mapping_affinity(host, hwirq, NULL);
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun /**
407*4882a593Smuzhiyun * irq_linear_revmap() - Find a linux irq from a hw irq number.
408*4882a593Smuzhiyun * @domain: domain owning this hardware interrupt
409*4882a593Smuzhiyun * @hwirq: hardware irq number in that domain space
410*4882a593Smuzhiyun *
411*4882a593Smuzhiyun * This is a fast path alternative to irq_find_mapping() that can be
412*4882a593Smuzhiyun * called directly by irq controller code to save a handful of
413*4882a593Smuzhiyun * instructions. It is always safe to call, but won't find irqs mapped
414*4882a593Smuzhiyun * using the radix tree.
415*4882a593Smuzhiyun */
irq_linear_revmap(struct irq_domain * domain,irq_hw_number_t hwirq)416*4882a593Smuzhiyun static inline unsigned int irq_linear_revmap(struct irq_domain *domain,
417*4882a593Smuzhiyun irq_hw_number_t hwirq)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun return hwirq < domain->revmap_size ? domain->linear_revmap[hwirq] : 0;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun extern unsigned int irq_find_mapping(struct irq_domain *host,
422*4882a593Smuzhiyun irq_hw_number_t hwirq);
423*4882a593Smuzhiyun extern unsigned int irq_create_direct_mapping(struct irq_domain *host);
424*4882a593Smuzhiyun extern int irq_create_strict_mappings(struct irq_domain *domain,
425*4882a593Smuzhiyun unsigned int irq_base,
426*4882a593Smuzhiyun irq_hw_number_t hwirq_base, int count);
427*4882a593Smuzhiyun
irq_create_identity_mapping(struct irq_domain * host,irq_hw_number_t hwirq)428*4882a593Smuzhiyun static inline int irq_create_identity_mapping(struct irq_domain *host,
429*4882a593Smuzhiyun irq_hw_number_t hwirq)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun return irq_create_strict_mappings(host, hwirq, hwirq, 1);
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun extern const struct irq_domain_ops irq_domain_simple_ops;
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun /* stock xlate functions */
437*4882a593Smuzhiyun int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr,
438*4882a593Smuzhiyun const u32 *intspec, unsigned int intsize,
439*4882a593Smuzhiyun irq_hw_number_t *out_hwirq, unsigned int *out_type);
440*4882a593Smuzhiyun int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr,
441*4882a593Smuzhiyun const u32 *intspec, unsigned int intsize,
442*4882a593Smuzhiyun irq_hw_number_t *out_hwirq, unsigned int *out_type);
443*4882a593Smuzhiyun int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr,
444*4882a593Smuzhiyun const u32 *intspec, unsigned int intsize,
445*4882a593Smuzhiyun irq_hw_number_t *out_hwirq, unsigned int *out_type);
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun int irq_domain_translate_twocell(struct irq_domain *d,
448*4882a593Smuzhiyun struct irq_fwspec *fwspec,
449*4882a593Smuzhiyun unsigned long *out_hwirq,
450*4882a593Smuzhiyun unsigned int *out_type);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun int irq_domain_translate_onecell(struct irq_domain *d,
453*4882a593Smuzhiyun struct irq_fwspec *fwspec,
454*4882a593Smuzhiyun unsigned long *out_hwirq,
455*4882a593Smuzhiyun unsigned int *out_type);
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun /* IPI functions */
458*4882a593Smuzhiyun int irq_reserve_ipi(struct irq_domain *domain, const struct cpumask *dest);
459*4882a593Smuzhiyun int irq_destroy_ipi(unsigned int irq, const struct cpumask *dest);
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun /* V2 interfaces to support hierarchy IRQ domains. */
462*4882a593Smuzhiyun extern struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
463*4882a593Smuzhiyun unsigned int virq);
464*4882a593Smuzhiyun extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
465*4882a593Smuzhiyun irq_hw_number_t hwirq, struct irq_chip *chip,
466*4882a593Smuzhiyun void *chip_data, irq_flow_handler_t handler,
467*4882a593Smuzhiyun void *handler_data, const char *handler_name);
468*4882a593Smuzhiyun extern void irq_domain_reset_irq_data(struct irq_data *irq_data);
469*4882a593Smuzhiyun #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
470*4882a593Smuzhiyun extern struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent,
471*4882a593Smuzhiyun unsigned int flags, unsigned int size,
472*4882a593Smuzhiyun struct fwnode_handle *fwnode,
473*4882a593Smuzhiyun const struct irq_domain_ops *ops, void *host_data);
474*4882a593Smuzhiyun
irq_domain_add_hierarchy(struct irq_domain * parent,unsigned int flags,unsigned int size,struct device_node * node,const struct irq_domain_ops * ops,void * host_data)475*4882a593Smuzhiyun static inline struct irq_domain *irq_domain_add_hierarchy(struct irq_domain *parent,
476*4882a593Smuzhiyun unsigned int flags,
477*4882a593Smuzhiyun unsigned int size,
478*4882a593Smuzhiyun struct device_node *node,
479*4882a593Smuzhiyun const struct irq_domain_ops *ops,
480*4882a593Smuzhiyun void *host_data)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun return irq_domain_create_hierarchy(parent, flags, size,
483*4882a593Smuzhiyun of_node_to_fwnode(node),
484*4882a593Smuzhiyun ops, host_data);
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
488*4882a593Smuzhiyun unsigned int nr_irqs, int node, void *arg,
489*4882a593Smuzhiyun bool realloc,
490*4882a593Smuzhiyun const struct irq_affinity_desc *affinity);
491*4882a593Smuzhiyun extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs);
492*4882a593Smuzhiyun extern int irq_domain_activate_irq(struct irq_data *irq_data, bool early);
493*4882a593Smuzhiyun extern void irq_domain_deactivate_irq(struct irq_data *irq_data);
494*4882a593Smuzhiyun
irq_domain_alloc_irqs(struct irq_domain * domain,unsigned int nr_irqs,int node,void * arg)495*4882a593Smuzhiyun static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
496*4882a593Smuzhiyun unsigned int nr_irqs, int node, void *arg)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false,
499*4882a593Smuzhiyun NULL);
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun extern int irq_domain_alloc_irqs_hierarchy(struct irq_domain *domain,
503*4882a593Smuzhiyun unsigned int irq_base,
504*4882a593Smuzhiyun unsigned int nr_irqs, void *arg);
505*4882a593Smuzhiyun extern int irq_domain_set_hwirq_and_chip(struct irq_domain *domain,
506*4882a593Smuzhiyun unsigned int virq,
507*4882a593Smuzhiyun irq_hw_number_t hwirq,
508*4882a593Smuzhiyun struct irq_chip *chip,
509*4882a593Smuzhiyun void *chip_data);
510*4882a593Smuzhiyun extern void irq_domain_free_irqs_common(struct irq_domain *domain,
511*4882a593Smuzhiyun unsigned int virq,
512*4882a593Smuzhiyun unsigned int nr_irqs);
513*4882a593Smuzhiyun extern void irq_domain_free_irqs_top(struct irq_domain *domain,
514*4882a593Smuzhiyun unsigned int virq, unsigned int nr_irqs);
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun extern int irq_domain_push_irq(struct irq_domain *domain, int virq, void *arg);
517*4882a593Smuzhiyun extern int irq_domain_pop_irq(struct irq_domain *domain, int virq);
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun extern int irq_domain_alloc_irqs_parent(struct irq_domain *domain,
520*4882a593Smuzhiyun unsigned int irq_base,
521*4882a593Smuzhiyun unsigned int nr_irqs, void *arg);
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun extern void irq_domain_free_irqs_parent(struct irq_domain *domain,
524*4882a593Smuzhiyun unsigned int irq_base,
525*4882a593Smuzhiyun unsigned int nr_irqs);
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun extern int irq_domain_disconnect_hierarchy(struct irq_domain *domain,
528*4882a593Smuzhiyun unsigned int virq);
529*4882a593Smuzhiyun
irq_domain_is_hierarchy(struct irq_domain * domain)530*4882a593Smuzhiyun static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
531*4882a593Smuzhiyun {
532*4882a593Smuzhiyun return domain->flags & IRQ_DOMAIN_FLAG_HIERARCHY;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun
irq_domain_is_ipi(struct irq_domain * domain)535*4882a593Smuzhiyun static inline bool irq_domain_is_ipi(struct irq_domain *domain)
536*4882a593Smuzhiyun {
537*4882a593Smuzhiyun return domain->flags &
538*4882a593Smuzhiyun (IRQ_DOMAIN_FLAG_IPI_PER_CPU | IRQ_DOMAIN_FLAG_IPI_SINGLE);
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
irq_domain_is_ipi_per_cpu(struct irq_domain * domain)541*4882a593Smuzhiyun static inline bool irq_domain_is_ipi_per_cpu(struct irq_domain *domain)
542*4882a593Smuzhiyun {
543*4882a593Smuzhiyun return domain->flags & IRQ_DOMAIN_FLAG_IPI_PER_CPU;
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun
irq_domain_is_ipi_single(struct irq_domain * domain)546*4882a593Smuzhiyun static inline bool irq_domain_is_ipi_single(struct irq_domain *domain)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun return domain->flags & IRQ_DOMAIN_FLAG_IPI_SINGLE;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun
irq_domain_is_msi(struct irq_domain * domain)551*4882a593Smuzhiyun static inline bool irq_domain_is_msi(struct irq_domain *domain)
552*4882a593Smuzhiyun {
553*4882a593Smuzhiyun return domain->flags & IRQ_DOMAIN_FLAG_MSI;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun
irq_domain_is_msi_remap(struct irq_domain * domain)556*4882a593Smuzhiyun static inline bool irq_domain_is_msi_remap(struct irq_domain *domain)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun return domain->flags & IRQ_DOMAIN_FLAG_MSI_REMAP;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun extern bool irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain);
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun #else /* CONFIG_IRQ_DOMAIN_HIERARCHY */
irq_domain_alloc_irqs(struct irq_domain * domain,unsigned int nr_irqs,int node,void * arg)564*4882a593Smuzhiyun static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
565*4882a593Smuzhiyun unsigned int nr_irqs, int node, void *arg)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun return -1;
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun
irq_domain_free_irqs(unsigned int virq,unsigned int nr_irqs)570*4882a593Smuzhiyun static inline void irq_domain_free_irqs(unsigned int virq,
571*4882a593Smuzhiyun unsigned int nr_irqs) { }
572*4882a593Smuzhiyun
irq_domain_is_hierarchy(struct irq_domain * domain)573*4882a593Smuzhiyun static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun return false;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
irq_domain_is_ipi(struct irq_domain * domain)578*4882a593Smuzhiyun static inline bool irq_domain_is_ipi(struct irq_domain *domain)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun return false;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun
irq_domain_is_ipi_per_cpu(struct irq_domain * domain)583*4882a593Smuzhiyun static inline bool irq_domain_is_ipi_per_cpu(struct irq_domain *domain)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun return false;
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun
irq_domain_is_ipi_single(struct irq_domain * domain)588*4882a593Smuzhiyun static inline bool irq_domain_is_ipi_single(struct irq_domain *domain)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun return false;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
irq_domain_is_msi(struct irq_domain * domain)593*4882a593Smuzhiyun static inline bool irq_domain_is_msi(struct irq_domain *domain)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun return false;
596*4882a593Smuzhiyun }
597*4882a593Smuzhiyun
irq_domain_is_msi_remap(struct irq_domain * domain)598*4882a593Smuzhiyun static inline bool irq_domain_is_msi_remap(struct irq_domain *domain)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun return false;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun static inline bool
irq_domain_hierarchical_is_msi_remap(struct irq_domain * domain)604*4882a593Smuzhiyun irq_domain_hierarchical_is_msi_remap(struct irq_domain *domain)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun return false;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun #endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun #else /* CONFIG_IRQ_DOMAIN */
irq_dispose_mapping(unsigned int virq)611*4882a593Smuzhiyun static inline void irq_dispose_mapping(unsigned int virq) { }
irq_find_matching_fwnode(struct fwnode_handle * fwnode,enum irq_domain_bus_token bus_token)612*4882a593Smuzhiyun static inline struct irq_domain *irq_find_matching_fwnode(
613*4882a593Smuzhiyun struct fwnode_handle *fwnode, enum irq_domain_bus_token bus_token)
614*4882a593Smuzhiyun {
615*4882a593Smuzhiyun return NULL;
616*4882a593Smuzhiyun }
irq_domain_check_msi_remap(void)617*4882a593Smuzhiyun static inline bool irq_domain_check_msi_remap(void)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun return false;
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun #endif /* !CONFIG_IRQ_DOMAIN */
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun #endif /* _LINUX_IRQDOMAIN_H */
624