diff options
Diffstat (limited to 'include/linux/irqdomain.h')
-rw-r--r-- | include/linux/irqdomain.h | 109 |
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 | ||
39 | struct device_node; | 37 | struct 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 | */ | ||
58 | struct 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 | ||
182 | static 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 |
165 | struct irq_domain *__irq_domain_add(struct device_node *of_node, int size, | 188 | struct fwnode_handle *irq_domain_alloc_fwnode(void *data); |
189 | void irq_domain_free_fwnode(struct fwnode_handle *fwnode); | ||
190 | struct 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); |
180 | extern struct irq_domain *irq_find_matching_host(struct device_node *node, | 205 | extern 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); |
182 | extern void irq_set_default_host(struct irq_domain *host); | 207 | extern void irq_set_default_host(struct irq_domain *host); |
183 | 208 | ||
209 | static inline struct fwnode_handle *of_node_to_fwnode(struct device_node *node) | ||
210 | { | ||
211 | return node ? &node->fwnode : NULL; | ||
212 | } | ||
213 | |||
214 | static 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 | |||
184 | static inline struct irq_domain *irq_find_host(struct device_node *node) | 220 | static 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 | } |
203 | static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, | 239 | static 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 | } |
210 | static inline struct irq_domain *irq_domain_add_legacy_isa( | 246 | static 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 | |||
261 | static 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 | |||
269 | static 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 | ||
225 | extern void irq_domain_remove(struct irq_domain *host); | 276 | extern void irq_domain_remove(struct irq_domain *host); |
@@ -234,6 +285,7 @@ extern void irq_domain_disassociate(struct irq_domain *domain, | |||
234 | 285 | ||
235 | extern unsigned int irq_create_mapping(struct irq_domain *host, | 286 | extern unsigned int irq_create_mapping(struct irq_domain *host, |
236 | irq_hw_number_t hwirq); | 287 | irq_hw_number_t hwirq); |
288 | extern unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec); | ||
237 | extern void irq_dispose_mapping(unsigned int virq); | 289 | extern 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 |
288 | extern struct irq_domain *irq_domain_add_hierarchy(struct irq_domain *parent, | 340 | extern 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 | |||
345 | static 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 | |||
292 | extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, | 357 | extern 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); |