aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/irqdomain.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/irqdomain.h')
-rw-r--r--include/linux/irqdomain.h109
1 files changed, 87 insertions, 22 deletions
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index d3ca79236fb0..d5e5c5bef28c 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -5,9 +5,10 @@
5 * helpful for interrupt controllers to implement mapping between hardware 5 * helpful for interrupt controllers to implement mapping between hardware
6 * irq numbers and the Linux irq number space. 6 * irq numbers and the Linux irq number space.
7 * 7 *
8 * irq_domains also have a hook for translating device tree interrupt 8 * irq_domains also have hooks for translating device tree or other
9 * representation into a hardware irq number that can be mapped back to a 9 * firmware interrupt representations into a hardware irq number that
10 * Linux irq number without any extra platform support code. 10 * can be mapped back to a Linux irq number without any extra platform
11 * support code.
11 * 12 *
12 * Interrupt controller "domain" data structure. This could be defined as a 13 * Interrupt controller "domain" data structure. This could be defined as a
13 * irq domain controller. That is, it handles the mapping between hardware 14 * irq domain controller. That is, it handles the mapping between hardware
@@ -17,16 +18,12 @@
17 * model). It's the domain callbacks that are responsible for setting the 18 * model). It's the domain callbacks that are responsible for setting the
18 * irq_chip on a given irq_desc after it's been mapped. 19 * irq_chip on a given irq_desc after it's been mapped.
19 * 20 *
20 * The host code and data structures are agnostic to whether or not 21 * The host code and data structures use a fwnode_handle pointer to
21 * we use an open firmware device-tree. We do have references to struct 22 * identify the domain. In some cases, and in order to preserve source
22 * device_node in two places: in irq_find_host() to find the host matching 23 * code compatibility, this fwnode pointer is "upgraded" to a DT
23 * a given interrupt controller node, and of course as an argument to its 24 * device_node. For those firmware infrastructures that do not provide
24 * counterpart domain->ops->match() callback. However, those are treated as 25 * a unique identifier for an interrupt controller, the irq_domain
25 * generic pointers by the core and the fact that it's actually a device-node 26 * code offers a fwnode allocator.
26 * pointer is purely a convention between callers and implementation. This
27 * code could thus be used on other architectures by replacing those two
28 * by some sort of arch-specific void * "token" used to identify interrupt
29 * controllers.
30 */ 27 */
31 28
32#ifndef _LINUX_IRQDOMAIN_H 29#ifndef _LINUX_IRQDOMAIN_H
@@ -34,6 +31,7 @@
34 31
35#include <linux/types.h> 32#include <linux/types.h>
36#include <linux/irqhandler.h> 33#include <linux/irqhandler.h>
34#include <linux/of.h>
37#include <linux/radix-tree.h> 35#include <linux/radix-tree.h>
38 36
39struct device_node; 37struct device_node;
@@ -45,6 +43,24 @@ struct irq_data;
45/* Number of irqs reserved for a legacy isa controller */ 43/* Number of irqs reserved for a legacy isa controller */
46#define NUM_ISA_INTERRUPTS 16 44#define NUM_ISA_INTERRUPTS 16
47 45
46#define IRQ_DOMAIN_IRQ_SPEC_PARAMS 16
47
48/**
49 * struct irq_fwspec - generic IRQ specifier structure
50 *
51 * @fwnode: Pointer to a firmware-specific descriptor
52 * @param_count: Number of device-specific parameters
53 * @param: Device-specific parameters
54 *
55 * This structure, directly modeled after of_phandle_args, is used to
56 * pass a device-specific description of an interrupt.
57 */
58struct irq_fwspec {
59 struct fwnode_handle *fwnode;
60 int param_count;
61 u32 param[IRQ_DOMAIN_IRQ_SPEC_PARAMS];
62};
63
48/* 64/*
49 * Should several domains have the same device node, but serve 65 * Should several domains have the same device node, but serve
50 * different purposes (for example one domain is for PCI/MSI, and the 66 * different purposes (for example one domain is for PCI/MSI, and the
@@ -91,6 +107,8 @@ struct irq_domain_ops {
91 unsigned int nr_irqs); 107 unsigned int nr_irqs);
92 void (*activate)(struct irq_domain *d, struct irq_data *irq_data); 108 void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
93 void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data); 109 void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
110 int (*translate)(struct irq_domain *d, struct irq_fwspec *fwspec,
111 unsigned long *out_hwirq, unsigned int *out_type);
94#endif 112#endif
95}; 113};
96 114
@@ -130,7 +148,7 @@ struct irq_domain {
130 unsigned int flags; 148 unsigned int flags;
131 149
132 /* Optional data */ 150 /* Optional data */
133 struct device_node *of_node; 151 struct fwnode_handle *fwnode;
134 enum irq_domain_bus_token bus_token; 152 enum irq_domain_bus_token bus_token;
135 struct irq_domain_chip_generic *gc; 153 struct irq_domain_chip_generic *gc;
136#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY 154#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
@@ -161,8 +179,15 @@ enum {
161 IRQ_DOMAIN_FLAG_NONCORE = (1 << 16), 179 IRQ_DOMAIN_FLAG_NONCORE = (1 << 16),
162}; 180};
163 181
182static inline struct device_node *irq_domain_get_of_node(struct irq_domain *d)
183{
184 return to_of_node(d->fwnode);
185}
186
164#ifdef CONFIG_IRQ_DOMAIN 187#ifdef CONFIG_IRQ_DOMAIN
165struct irq_domain *__irq_domain_add(struct device_node *of_node, int size, 188struct fwnode_handle *irq_domain_alloc_fwnode(void *data);
189void irq_domain_free_fwnode(struct fwnode_handle *fwnode);
190struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
166 irq_hw_number_t hwirq_max, int direct_max, 191 irq_hw_number_t hwirq_max, int direct_max,
167 const struct irq_domain_ops *ops, 192 const struct irq_domain_ops *ops,
168 void *host_data); 193 void *host_data);
@@ -177,10 +202,21 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
177 irq_hw_number_t first_hwirq, 202 irq_hw_number_t first_hwirq,
178 const struct irq_domain_ops *ops, 203 const struct irq_domain_ops *ops,
179 void *host_data); 204 void *host_data);
180extern struct irq_domain *irq_find_matching_host(struct device_node *node, 205extern struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode,
181 enum irq_domain_bus_token bus_token); 206 enum irq_domain_bus_token bus_token);
182extern void irq_set_default_host(struct irq_domain *host); 207extern void irq_set_default_host(struct irq_domain *host);
183 208
209static inline struct fwnode_handle *of_node_to_fwnode(struct device_node *node)
210{
211 return node ? &node->fwnode : NULL;
212}
213
214static inline struct irq_domain *irq_find_matching_host(struct device_node *node,
215 enum irq_domain_bus_token bus_token)
216{
217 return irq_find_matching_fwnode(of_node_to_fwnode(node), bus_token);
218}
219
184static inline struct irq_domain *irq_find_host(struct device_node *node) 220static inline struct irq_domain *irq_find_host(struct device_node *node)
185{ 221{
186 return irq_find_matching_host(node, DOMAIN_BUS_ANY); 222 return irq_find_matching_host(node, DOMAIN_BUS_ANY);
@@ -198,14 +234,14 @@ static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_no
198 const struct irq_domain_ops *ops, 234 const struct irq_domain_ops *ops,
199 void *host_data) 235 void *host_data)
200{ 236{
201 return __irq_domain_add(of_node, size, size, 0, ops, host_data); 237 return __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops, host_data);
202} 238}
203static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, 239static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
204 unsigned int max_irq, 240 unsigned int max_irq,
205 const struct irq_domain_ops *ops, 241 const struct irq_domain_ops *ops,
206 void *host_data) 242 void *host_data)
207{ 243{
208 return __irq_domain_add(of_node, 0, max_irq, max_irq, ops, host_data); 244 return __irq_domain_add(of_node_to_fwnode(of_node), 0, max_irq, max_irq, ops, host_data);
209} 245}
210static inline struct irq_domain *irq_domain_add_legacy_isa( 246static inline struct irq_domain *irq_domain_add_legacy_isa(
211 struct device_node *of_node, 247 struct device_node *of_node,
@@ -219,7 +255,22 @@ static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node
219 const struct irq_domain_ops *ops, 255 const struct irq_domain_ops *ops,
220 void *host_data) 256 void *host_data)
221{ 257{
222 return __irq_domain_add(of_node, 0, ~0, 0, ops, host_data); 258 return __irq_domain_add(of_node_to_fwnode(of_node), 0, ~0, 0, ops, host_data);
259}
260
261static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle *fwnode,
262 unsigned int size,
263 const struct irq_domain_ops *ops,
264 void *host_data)
265{
266 return __irq_domain_add(fwnode, size, size, 0, ops, host_data);
267}
268
269static inline struct irq_domain *irq_domain_create_tree(struct fwnode_handle *fwnode,
270 const struct irq_domain_ops *ops,
271 void *host_data)
272{
273 return __irq_domain_add(fwnode, 0, ~0, 0, ops, host_data);
223} 274}
224 275
225extern void irq_domain_remove(struct irq_domain *host); 276extern void irq_domain_remove(struct irq_domain *host);
@@ -234,6 +285,7 @@ extern void irq_domain_disassociate(struct irq_domain *domain,
234 285
235extern unsigned int irq_create_mapping(struct irq_domain *host, 286extern unsigned int irq_create_mapping(struct irq_domain *host,
236 irq_hw_number_t hwirq); 287 irq_hw_number_t hwirq);
288extern unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec);
237extern void irq_dispose_mapping(unsigned int virq); 289extern void irq_dispose_mapping(unsigned int virq);
238 290
239/** 291/**
@@ -285,10 +337,23 @@ extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
285 void *chip_data, irq_flow_handler_t handler, 337 void *chip_data, irq_flow_handler_t handler,
286 void *handler_data, const char *handler_name); 338 void *handler_data, const char *handler_name);
287#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY 339#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
288extern struct irq_domain *irq_domain_add_hierarchy(struct irq_domain *parent, 340extern struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent,
289 unsigned int flags, unsigned int size, 341 unsigned int flags, unsigned int size,
290 struct device_node *node, 342 struct fwnode_handle *fwnode,
291 const struct irq_domain_ops *ops, void *host_data); 343 const struct irq_domain_ops *ops, void *host_data);
344
345static inline struct irq_domain *irq_domain_add_hierarchy(struct irq_domain *parent,
346 unsigned int flags,
347 unsigned int size,
348 struct device_node *node,
349 const struct irq_domain_ops *ops,
350 void *host_data)
351{
352 return irq_domain_create_hierarchy(parent, flags, size,
353 of_node_to_fwnode(node),
354 ops, host_data);
355}
356
292extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, 357extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
293 unsigned int nr_irqs, int node, void *arg, 358 unsigned int nr_irqs, int node, void *arg,
294 bool realloc); 359 bool realloc);