Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0+
2 : : /*
3 : : * Derived from arch/i386/kernel/irq.c
4 : : * Copyright (C) 1992 Linus Torvalds
5 : : * Adapted from arch/i386 by Gary Thomas
6 : : * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
7 : : * Updated and modified by Cort Dougan <cort@fsmlabs.com>
8 : : * Copyright (C) 1996-2001 Cort Dougan
9 : : * Adapted for Power Macintosh by Paul Mackerras
10 : : * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
11 : : *
12 : : * This file contains the code used to make IRQ descriptions in the
13 : : * device tree to actual irq numbers on an interrupt controller
14 : : * driver.
15 : : */
16 : :
17 : : #define pr_fmt(fmt) "OF: " fmt
18 : :
19 : : #include <linux/device.h>
20 : : #include <linux/errno.h>
21 : : #include <linux/list.h>
22 : : #include <linux/module.h>
23 : : #include <linux/of.h>
24 : : #include <linux/of_irq.h>
25 : : #include <linux/string.h>
26 : : #include <linux/slab.h>
27 : :
28 : : /**
29 : : * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
30 : : * @dev: Device node of the device whose interrupt is to be mapped
31 : : * @index: Index of the interrupt to map
32 : : *
33 : : * This function is a wrapper that chains of_irq_parse_one() and
34 : : * irq_create_of_mapping() to make things easier to callers
35 : : */
36 : 6868 : unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
37 : : {
38 : : struct of_phandle_args oirq;
39 : :
40 [ + + ]: 6868 : if (of_irq_parse_one(dev, index, &oirq))
41 : : return 0;
42 : :
43 : 3232 : return irq_create_of_mapping(&oirq);
44 : : }
45 : : EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
46 : :
47 : : /**
48 : : * of_irq_find_parent - Given a device node, find its interrupt parent node
49 : : * @child: pointer to device node
50 : : *
51 : : * Returns a pointer to the interrupt parent node, or NULL if the interrupt
52 : : * parent could not be determined.
53 : : */
54 : 48076 : struct device_node *of_irq_find_parent(struct device_node *child)
55 : : {
56 : : struct device_node *p;
57 : : phandle parent;
58 : :
59 [ + - ]: 48076 : if (!of_node_get(child))
60 : : return NULL;
61 : :
62 : : do {
63 [ + + ]: 124836 : if (of_property_read_u32(child, "interrupt-parent", &parent)) {
64 : 76760 : p = of_get_parent(child);
65 : : } else {
66 : : if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
67 : : p = of_node_get(of_irq_dflt_pic);
68 : : else
69 : 48076 : p = of_find_node_by_phandle(parent);
70 : : }
71 : 124836 : of_node_put(child);
72 : : child = p;
73 [ + - + + ]: 124836 : } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
74 : :
75 : 48076 : return p;
76 : : }
77 : : EXPORT_SYMBOL_GPL(of_irq_find_parent);
78 : :
79 : : /**
80 : : * of_irq_parse_raw - Low level interrupt tree parsing
81 : : * @addr: address specifier (start of "reg" property of the device) in be32 format
82 : : * @out_irq: structure of_phandle_args updated by this function
83 : : *
84 : : * Returns 0 on success and a negative number on error
85 : : *
86 : : * This function is a low-level interrupt tree walking function. It
87 : : * can be used to do a partial walk with synthetized reg and interrupts
88 : : * properties, for example when resolving PCI interrupts when no device
89 : : * node exist for the parent. It takes an interrupt specifier structure as
90 : : * input, walks the tree looking for any interrupt-map properties, translates
91 : : * the specifier for each map, and then returns the translated map.
92 : : */
93 : 33532 : int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
94 : : {
95 : : struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
96 : : __be32 initial_match_array[MAX_PHANDLE_ARGS];
97 : : const __be32 *match_array = initial_match_array;
98 : 33532 : const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
99 : 33532 : u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
100 : : int imaplen, match, i, rc = -EINVAL;
101 : :
102 : : #ifdef DEBUG
103 : : of_print_phandle_args("of_irq_parse_raw: ", out_irq);
104 : : #endif
105 : :
106 : 33532 : ipar = of_node_get(out_irq->np);
107 : :
108 : : /* First get the #interrupt-cells property of the current cursor
109 : : * that tells us how to interpret the passed-in intspec. If there
110 : : * is none, we are nice and just walk up the tree
111 : : */
112 : : do {
113 [ - + ]: 33532 : if (!of_property_read_u32(ipar, "#interrupt-cells", &intsize))
114 : : break;
115 : : tnode = ipar;
116 : 0 : ipar = of_irq_find_parent(ipar);
117 : 0 : of_node_put(tnode);
118 [ # # ]: 0 : } while (ipar);
119 [ + - ]: 33532 : if (ipar == NULL) {
120 : : pr_debug(" -> no parent found !\n");
121 : : goto fail;
122 : : }
123 : :
124 : : pr_debug("of_irq_parse_raw: ipar=%pOF, size=%d\n", ipar, intsize);
125 : :
126 [ + - ]: 33532 : if (out_irq->args_count != intsize)
127 : : goto fail;
128 : :
129 : : /* Look for this #address-cells. We have to implement the old linux
130 : : * trick of looking for the parent here as some device-trees rely on it
131 : : */
132 : 33532 : old = of_node_get(ipar);
133 : : do {
134 : 67064 : tmp = of_get_property(old, "#address-cells", NULL);
135 : 67064 : tnode = of_get_parent(old);
136 : 67064 : of_node_put(old);
137 : : old = tnode;
138 [ + + ]: 67064 : } while (old && tmp == NULL);
139 : 33532 : of_node_put(old);
140 : : old = NULL;
141 [ + - ]: 33532 : addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp);
142 : :
143 : : pr_debug(" -> addrsize=%d\n", addrsize);
144 : :
145 : : /* Range check so that the temporary buffer doesn't overflow */
146 [ - + + - ]: 33532 : if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS)) {
147 : : rc = -EFAULT;
148 : : goto fail;
149 : : }
150 : :
151 : : /* Precalculate the match array - this simplifies match loop */
152 [ + + ]: 33532 : for (i = 0; i < addrsize; i++)
153 [ + + ]: 33532 : initial_match_array[i] = addr ? addr[i] : 0;
154 [ + + ]: 67064 : for (i = 0; i < intsize; i++)
155 : 67064 : initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]);
156 : :
157 : : /* Now start the actual "proper" walk of the interrupt tree */
158 [ + - ]: 33532 : while (ipar != NULL) {
159 : : /* Now check if cursor is an interrupt-controller and if it is
160 : : * then we are done
161 : : */
162 [ - + ]: 33532 : if (of_property_read_bool(ipar, "interrupt-controller")) {
163 : : pr_debug(" -> got it !\n");
164 : : return 0;
165 : : }
166 : :
167 : : /*
168 : : * interrupt-map parsing does not work without a reg
169 : : * property when #address-cells != 0
170 : : */
171 [ # # ]: 0 : if (addrsize && !addr) {
172 : : pr_debug(" -> no reg passed in when needed !\n");
173 : : goto fail;
174 : : }
175 : :
176 : : /* Now look for an interrupt-map */
177 : 0 : imap = of_get_property(ipar, "interrupt-map", &imaplen);
178 : : /* No interrupt map, check for an interrupt parent */
179 [ # # ]: 0 : if (imap == NULL) {
180 : : pr_debug(" -> no map, getting parent\n");
181 : 0 : newpar = of_irq_find_parent(ipar);
182 : 0 : goto skiplevel;
183 : : }
184 : 0 : imaplen /= sizeof(u32);
185 : :
186 : : /* Look for a mask */
187 : 0 : imask = of_get_property(ipar, "interrupt-map-mask", NULL);
188 [ # # ]: 0 : if (!imask)
189 : : imask = dummy_imask;
190 : :
191 : : /* Parse interrupt-map */
192 : : match = 0;
193 [ # # # # ]: 0 : while (imaplen > (addrsize + intsize + 1) && !match) {
194 : : /* Compare specifiers */
195 : : match = 1;
196 [ # # ]: 0 : for (i = 0; i < (addrsize + intsize); i++, imaplen--)
197 : 0 : match &= !((match_array[i] ^ *imap++) & imask[i]);
198 : :
199 : : pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
200 : :
201 : : /* Get the interrupt parent */
202 : : if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
203 : : newpar = of_node_get(of_irq_dflt_pic);
204 : : else
205 : 0 : newpar = of_find_node_by_phandle(be32_to_cpup(imap));
206 : : imap++;
207 : 0 : --imaplen;
208 : :
209 : : /* Check if not found */
210 [ # # ]: 0 : if (newpar == NULL) {
211 : : pr_debug(" -> imap parent not found !\n");
212 : : goto fail;
213 : : }
214 : :
215 [ # # ]: 0 : if (!of_device_is_available(newpar))
216 : : match = 0;
217 : :
218 : : /* Get #interrupt-cells and #address-cells of new
219 : : * parent
220 : : */
221 [ # # ]: 0 : if (of_property_read_u32(newpar, "#interrupt-cells",
222 : : &newintsize)) {
223 : : pr_debug(" -> parent lacks #interrupt-cells!\n");
224 : : goto fail;
225 : : }
226 [ # # ]: 0 : if (of_property_read_u32(newpar, "#address-cells",
227 : : &newaddrsize))
228 : 0 : newaddrsize = 0;
229 : :
230 : : pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
231 : : newintsize, newaddrsize);
232 : :
233 : : /* Check for malformed properties */
234 [ # # # # ]: 0 : if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS)
235 [ # # ]: 0 : || (imaplen < (newaddrsize + newintsize))) {
236 : : rc = -EFAULT;
237 : : goto fail;
238 : : }
239 : :
240 : 0 : imap += newaddrsize + newintsize;
241 : 0 : imaplen -= newaddrsize + newintsize;
242 : :
243 : : pr_debug(" -> imaplen=%d\n", imaplen);
244 : : }
245 [ # # ]: 0 : if (!match)
246 : : goto fail;
247 : :
248 : : /*
249 : : * Successfully parsed an interrrupt-map translation; copy new
250 : : * interrupt specifier into the out_irq structure
251 : : */
252 : 0 : match_array = imap - newaddrsize - newintsize;
253 [ # # ]: 0 : for (i = 0; i < newintsize; i++)
254 : 0 : out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
255 : 0 : out_irq->args_count = intsize = newintsize;
256 : : addrsize = newaddrsize;
257 : :
258 : : skiplevel:
259 : : /* Iterate again with new parent */
260 : 0 : out_irq->np = newpar;
261 : : pr_debug(" -> new parent: %pOF\n", newpar);
262 : 0 : of_node_put(ipar);
263 : : ipar = newpar;
264 : : newpar = NULL;
265 : : }
266 : : rc = -ENOENT; /* No interrupt-map found */
267 : :
268 : : fail:
269 : 0 : of_node_put(ipar);
270 : 0 : of_node_put(newpar);
271 : :
272 : 0 : return rc;
273 : : }
274 : : EXPORT_SYMBOL_GPL(of_irq_parse_raw);
275 : :
276 : : /**
277 : : * of_irq_parse_one - Resolve an interrupt for a device
278 : : * @device: the device whose interrupt is to be resolved
279 : : * @index: index of the interrupt to resolve
280 : : * @out_irq: structure of_phandle_args filled by this function
281 : : *
282 : : * This function resolves an interrupt for a node by walking the interrupt tree,
283 : : * finding which interrupt controller node it is attached to, and returning the
284 : : * interrupt specifier that can be used to retrieve a Linux IRQ number.
285 : : */
286 : 47268 : int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
287 : : {
288 : : struct device_node *p;
289 : : const __be32 *addr;
290 : : u32 intsize;
291 : : int i, res;
292 : :
293 : : pr_debug("of_irq_parse_one: dev=%pOF, index=%d\n", device, index);
294 : :
295 : : /* OldWorld mac stuff is "special", handle out of line */
296 : : if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
297 : : return of_irq_parse_oldworld(device, index, out_irq);
298 : :
299 : : /* Get the reg property (if any) */
300 : 47268 : addr = of_get_property(device, "reg", NULL);
301 : :
302 : : /* Try the new-style interrupts-extended first */
303 : 47268 : res = of_parse_phandle_with_args(device, "interrupts-extended",
304 : : "#interrupt-cells", index, out_irq);
305 [ - + ]: 47268 : if (!res)
306 : 0 : return of_irq_parse_raw(addr, out_irq);
307 : :
308 : : /* Look for the interrupt parent. */
309 : 47268 : p = of_irq_find_parent(device);
310 [ + - ]: 47268 : if (p == NULL)
311 : : return -EINVAL;
312 : :
313 : : /* Get size of interrupt specifier */
314 [ + - ]: 47268 : if (of_property_read_u32(p, "#interrupt-cells", &intsize)) {
315 : : res = -EINVAL;
316 : : goto out;
317 : : }
318 : :
319 : : pr_debug(" parent=%pOF, intsize=%d\n", p, intsize);
320 : :
321 : : /* Copy intspec into irq structure */
322 : 47268 : out_irq->np = p;
323 : 47268 : out_irq->args_count = intsize;
324 [ + + ]: 114332 : for (i = 0; i < intsize; i++) {
325 : 161600 : res = of_property_read_u32_index(device, "interrupts",
326 : 80800 : (index * intsize) + i,
327 : 80800 : out_irq->args + i);
328 [ + + ]: 80800 : if (res)
329 : : goto out;
330 : : }
331 : :
332 : : pr_debug(" intspec=%d\n", *out_irq->args);
333 : :
334 : :
335 : : /* Check if there are any interrupt-map translations to process */
336 : 33532 : res = of_irq_parse_raw(addr, out_irq);
337 : : out:
338 : 47268 : of_node_put(p);
339 : 47268 : return res;
340 : : }
341 : : EXPORT_SYMBOL_GPL(of_irq_parse_one);
342 : :
343 : : /**
344 : : * of_irq_to_resource - Decode a node's IRQ and return it as a resource
345 : : * @dev: pointer to device tree node
346 : : * @index: zero-based index of the irq
347 : : * @r: pointer to resource structure to return result into.
348 : : */
349 : 11716 : int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
350 : : {
351 : 11716 : int irq = of_irq_get(dev, index);
352 : :
353 [ + - ]: 11716 : if (irq < 0)
354 : : return irq;
355 : :
356 : : /* Only dereference the resource if both the
357 : : * resource and the irq are valid. */
358 [ + - ]: 11716 : if (r && irq) {
359 : 11716 : const char *name = NULL;
360 : :
361 : 11716 : memset(r, 0, sizeof(*r));
362 : : /*
363 : : * Get optional "interrupt-names" property to add a name
364 : : * to the resource.
365 : : */
366 : : of_property_read_string_index(dev, "interrupt-names", index,
367 : : &name);
368 : :
369 : 11716 : r->start = r->end = irq;
370 : 23432 : r->flags = IORESOURCE_IRQ | irqd_get_trigger_type(irq_get_irq_data(irq));
371 [ + + ]: 23432 : r->name = name ? name : of_node_full_name(dev);
372 : : }
373 : :
374 : : return irq;
375 : : }
376 : : EXPORT_SYMBOL_GPL(of_irq_to_resource);
377 : :
378 : : /**
379 : : * of_irq_get - Decode a node's IRQ and return it as a Linux IRQ number
380 : : * @dev: pointer to device tree node
381 : : * @index: zero-based index of the IRQ
382 : : *
383 : : * Returns Linux IRQ number on success, or 0 on the IRQ mapping failure, or
384 : : * -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
385 : : * of any other failure.
386 : : */
387 : 18988 : int of_irq_get(struct device_node *dev, int index)
388 : : {
389 : : int rc;
390 : : struct of_phandle_args oirq;
391 : : struct irq_domain *domain;
392 : :
393 : 18988 : rc = of_irq_parse_one(dev, index, &oirq);
394 [ + + ]: 18988 : if (rc)
395 : : return rc;
396 : :
397 : 18584 : domain = irq_find_host(oirq.np);
398 [ + - ]: 18584 : if (!domain)
399 : : return -EPROBE_DEFER;
400 : :
401 : 18584 : return irq_create_of_mapping(&oirq);
402 : : }
403 : : EXPORT_SYMBOL_GPL(of_irq_get);
404 : :
405 : : /**
406 : : * of_irq_get_byname - Decode a node's IRQ and return it as a Linux IRQ number
407 : : * @dev: pointer to device tree node
408 : : * @name: IRQ name
409 : : *
410 : : * Returns Linux IRQ number on success, or 0 on the IRQ mapping failure, or
411 : : * -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
412 : : * of any other failure.
413 : : */
414 : 4848 : int of_irq_get_byname(struct device_node *dev, const char *name)
415 : : {
416 : : int index;
417 : :
418 [ + - ]: 4848 : if (unlikely(!name))
419 : : return -EINVAL;
420 : :
421 : 4848 : index = of_property_match_string(dev, "interrupt-names", name);
422 [ + - ]: 4848 : if (index < 0)
423 : : return index;
424 : :
425 : 4848 : return of_irq_get(dev, index);
426 : : }
427 : : EXPORT_SYMBOL_GPL(of_irq_get_byname);
428 : :
429 : : /**
430 : : * of_irq_count - Count the number of IRQs a node uses
431 : : * @dev: pointer to device tree node
432 : : */
433 : 9696 : int of_irq_count(struct device_node *dev)
434 : : {
435 : : struct of_phandle_args irq;
436 : : int nr = 0;
437 : :
438 [ + + ]: 31108 : while (of_irq_parse_one(dev, nr, &irq) == 0)
439 : 11716 : nr++;
440 : :
441 : 9696 : return nr;
442 : : }
443 : :
444 : : /**
445 : : * of_irq_to_resource_table - Fill in resource table with node's IRQ info
446 : : * @dev: pointer to device tree node
447 : : * @res: array of resources to fill in
448 : : * @nr_irqs: the number of IRQs (and upper bound for num of @res elements)
449 : : *
450 : : * Returns the size of the filled in table (up to @nr_irqs).
451 : : */
452 : 5656 : int of_irq_to_resource_table(struct device_node *dev, struct resource *res,
453 : : int nr_irqs)
454 : : {
455 : : int i;
456 : :
457 [ + + ]: 17372 : for (i = 0; i < nr_irqs; i++, res++)
458 [ + - ]: 11716 : if (of_irq_to_resource(dev, i, res) <= 0)
459 : : break;
460 : :
461 : 5656 : return i;
462 : : }
463 : : EXPORT_SYMBOL_GPL(of_irq_to_resource_table);
464 : :
465 : : struct of_intc_desc {
466 : : struct list_head list;
467 : : of_irq_init_cb_t irq_init_cb;
468 : : struct device_node *dev;
469 : : struct device_node *interrupt_parent;
470 : : };
471 : :
472 : : /**
473 : : * of_irq_init - Scan and init matching interrupt controllers in DT
474 : : * @matches: 0 terminated array of nodes to match and init function to call
475 : : *
476 : : * This function scans the device tree for matching interrupt controller nodes,
477 : : * and calls their initialization functions in order with parents first.
478 : : */
479 : 404 : void __init of_irq_init(const struct of_device_id *matches)
480 : : {
481 : : const struct of_device_id *match;
482 : : struct device_node *np, *parent = NULL;
483 : : struct of_intc_desc *desc, *temp_desc;
484 : : struct list_head intc_desc_list, intc_parent_list;
485 : :
486 : : INIT_LIST_HEAD(&intc_desc_list);
487 : : INIT_LIST_HEAD(&intc_parent_list);
488 : :
489 [ + + ]: 1212 : for_each_matching_node_and_match(np, matches, &match) {
490 [ + - - + ]: 1616 : if (!of_property_read_bool(np, "interrupt-controller") ||
491 : 808 : !of_device_is_available(np))
492 : 0 : continue;
493 : :
494 [ - + - + ]: 808 : if (WARN(!match->data, "of_irq_init: no init function for %s\n",
495 : : match->compatible))
496 : 0 : continue;
497 : :
498 : : /*
499 : : * Here, we allocate and populate an of_intc_desc with the node
500 : : * pointer, interrupt-parent device_node etc.
501 : : */
502 : 808 : desc = kzalloc(sizeof(*desc), GFP_KERNEL);
503 [ - + ]: 808 : if (!desc) {
504 : 0 : of_node_put(np);
505 : 0 : goto err;
506 : : }
507 : :
508 : 808 : desc->irq_init_cb = match->data;
509 : 808 : desc->dev = of_node_get(np);
510 : 808 : desc->interrupt_parent = of_irq_find_parent(np);
511 [ + + ]: 808 : if (desc->interrupt_parent == np)
512 : 404 : desc->interrupt_parent = NULL;
513 : 808 : list_add_tail(&desc->list, &intc_desc_list);
514 : : }
515 : :
516 : : /*
517 : : * The root irq controller is the one without an interrupt-parent.
518 : : * That one goes first, followed by the controllers that reference it,
519 : : * followed by the ones that reference the 2nd level controllers, etc.
520 : : */
521 [ + + ]: 1212 : while (!list_empty(&intc_desc_list)) {
522 : : /*
523 : : * Process all controllers with the current 'parent'.
524 : : * First pass will be looking for NULL as the parent.
525 : : * The assumption is that NULL parent means a root controller.
526 : : */
527 [ + + ]: 2020 : list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
528 : : int ret;
529 : :
530 [ + + ]: 1212 : if (desc->interrupt_parent != parent)
531 : 404 : continue;
532 : :
533 : : list_del(&desc->list);
534 : :
535 : 808 : of_node_set_flag(desc->dev, OF_POPULATED);
536 : :
537 : : pr_debug("of_irq_init: init %pOF (%p), parent %p\n",
538 : : desc->dev,
539 : : desc->dev, desc->interrupt_parent);
540 : 808 : ret = desc->irq_init_cb(desc->dev,
541 : : desc->interrupt_parent);
542 [ - + ]: 808 : if (ret) {
543 : 0 : of_node_clear_flag(desc->dev, OF_POPULATED);
544 : 0 : kfree(desc);
545 : 0 : continue;
546 : : }
547 : :
548 : : /*
549 : : * This one is now set up; add it to the parent list so
550 : : * its children can get processed in a subsequent pass.
551 : : */
552 : : list_add_tail(&desc->list, &intc_parent_list);
553 : : }
554 : :
555 : : /* Get the next pending parent that might have children */
556 [ + - ]: 808 : desc = list_first_entry_or_null(&intc_parent_list,
557 : : typeof(*desc), list);
558 [ - + ]: 808 : if (!desc) {
559 : 0 : pr_err("of_irq_init: children remain, but no parents\n");
560 : 0 : break;
561 : : }
562 : : list_del(&desc->list);
563 : 808 : parent = desc->dev;
564 : 808 : kfree(desc);
565 : : }
566 : :
567 [ - + ]: 404 : list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {
568 : : list_del(&desc->list);
569 : 0 : kfree(desc);
570 : : }
571 : : err:
572 [ - + ]: 404 : list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
573 : : list_del(&desc->list);
574 : 0 : of_node_put(desc->dev);
575 : 0 : kfree(desc);
576 : : }
577 : 404 : }
578 : :
579 : 0 : static u32 __of_msi_map_rid(struct device *dev, struct device_node **np,
580 : : u32 rid_in)
581 : : {
582 : : struct device *parent_dev;
583 : 0 : u32 rid_out = rid_in;
584 : :
585 : : /*
586 : : * Walk up the device parent links looking for one with a
587 : : * "msi-map" property.
588 : : */
589 [ # # ]: 0 : for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent)
590 [ # # ]: 0 : if (!of_map_rid(parent_dev->of_node, rid_in, "msi-map",
591 : : "msi-map-mask", np, &rid_out))
592 : : break;
593 : 0 : return rid_out;
594 : : }
595 : :
596 : : /**
597 : : * of_msi_map_rid - Map a MSI requester ID for a device.
598 : : * @dev: device for which the mapping is to be done.
599 : : * @msi_np: device node of the expected msi controller.
600 : : * @rid_in: unmapped MSI requester ID for the device.
601 : : *
602 : : * Walk up the device hierarchy looking for devices with a "msi-map"
603 : : * property. If found, apply the mapping to @rid_in.
604 : : *
605 : : * Returns the mapped MSI requester ID.
606 : : */
607 : 0 : u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in)
608 : : {
609 : 0 : return __of_msi_map_rid(dev, &msi_np, rid_in);
610 : : }
611 : :
612 : : /**
613 : : * of_msi_map_get_device_domain - Use msi-map to find the relevant MSI domain
614 : : * @dev: device for which the mapping is to be done.
615 : : * @rid: Requester ID for the device.
616 : : *
617 : : * Walk up the device hierarchy looking for devices with a "msi-map"
618 : : * property.
619 : : *
620 : : * Returns: the MSI domain for this device (or NULL on failure)
621 : : */
622 : 0 : struct irq_domain *of_msi_map_get_device_domain(struct device *dev, u32 rid)
623 : : {
624 : 0 : struct device_node *np = NULL;
625 : :
626 : 0 : __of_msi_map_rid(dev, &np, rid);
627 : 0 : return irq_find_matching_host(np, DOMAIN_BUS_PCI_MSI);
628 : : }
629 : :
630 : : /**
631 : : * of_msi_get_domain - Use msi-parent to find the relevant MSI domain
632 : : * @dev: device for which the domain is requested
633 : : * @np: device node for @dev
634 : : * @token: bus type for this domain
635 : : *
636 : : * Parse the msi-parent property (both the simple and the complex
637 : : * versions), and returns the corresponding MSI domain.
638 : : *
639 : : * Returns: the MSI domain for this device (or NULL on failure).
640 : : */
641 : 9696 : struct irq_domain *of_msi_get_domain(struct device *dev,
642 : : struct device_node *np,
643 : : enum irq_domain_bus_token token)
644 : : {
645 : : struct device_node *msi_np;
646 : : struct irq_domain *d;
647 : :
648 : : /* Check for a single msi-parent property */
649 : 9696 : msi_np = of_parse_phandle(np, "msi-parent", 0);
650 [ - + # # ]: 9696 : if (msi_np && !of_property_read_bool(msi_np, "#msi-cells")) {
651 : 0 : d = irq_find_matching_host(msi_np, token);
652 [ # # ]: 0 : if (!d)
653 : 0 : of_node_put(msi_np);
654 : 0 : return d;
655 : : }
656 : :
657 [ + - ]: 9696 : if (token == DOMAIN_BUS_PLATFORM_MSI) {
658 : : /* Check for the complex msi-parent version */
659 : : struct of_phandle_args args;
660 : : int index = 0;
661 : :
662 [ - + ]: 9696 : while (!of_parse_phandle_with_args(np, "msi-parent",
663 : : "#msi-cells",
664 : : index, &args)) {
665 : 0 : d = irq_find_matching_host(args.np, token);
666 [ # # ]: 0 : if (d)
667 : 0 : return d;
668 : :
669 : 0 : of_node_put(args.np);
670 : 0 : index++;
671 : : }
672 : : }
673 : :
674 : : return NULL;
675 : : }
676 : :
677 : : /**
678 : : * of_msi_configure - Set the msi_domain field of a device
679 : : * @dev: device structure to associate with an MSI irq domain
680 : : * @np: device node for that device
681 : : */
682 : 9696 : void of_msi_configure(struct device *dev, struct device_node *np)
683 : : {
684 : 9696 : dev_set_msi_domain(dev,
685 : : of_msi_get_domain(dev, np, DOMAIN_BUS_PLATFORM_MSI));
686 : 9696 : }
687 : : EXPORT_SYMBOL_GPL(of_msi_configure);
|