| 1 | |
| 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 ([email protected])
|
| 7 | * Updated and modified by Cort Dougan <[email protected]>
|
| 8 | * Copyright (C) 1996-2001 Cort Dougan
|
| 9 | * Adapted for Power Macintosh by Paul Mackerras
|
| 10 | * Copyright (C) 1996 Paul Mackerras ([email protected])
|
| 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/cleanup.h>
|
| 20 | #include <linux/device.h>
|
| 21 | #include <linux/errno.h>
|
| 22 | #include <linux/list.h>
|
| 23 | #include <linux/module.h>
|
| 24 | #include <linux/of.h>
|
| 25 | #include <linux/of_irq.h>
|
| 26 | #include <linux/string.h>
|
| 27 | #include <linux/slab.h>
|
| 28 |
|
| 29 | #include "of_private.h"
|
| 30 |
|
| 31 | |
| 32 | * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
|
| 33 | * @dev: Device node of the device whose interrupt is to be mapped
|
| 34 | * @index: Index of the interrupt to map
|
| 35 | *
|
| 36 | * This function is a wrapper that chains of_irq_parse_one() and
|
| 37 | * irq_create_of_mapping() to make things easier to callers
|
| 38 |
|
| 39 | unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
|
| 40 | {
|
| 41 | struct of_phandle_args oirq;
|
| 42 | unsigned int ret;
|
| 43 |
|
| 44 | if (of_irq_parse_one(dev, index, &oirq))
|
| 45 | return 0;
|
| 46 |
|
| 47 | ret = irq_create_of_mapping(&oirq);
|
| 48 | of_node_put(oirq.np);
|
| 49 |
|
| 50 | return ret;
|
| 51 | }
|
| 52 | EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
|
| 53 |
|
| 54 | |
| 55 | * of_irq_find_parent - Given a device node, find its interrupt parent node
|
| 56 | * @child: pointer to device node
|
| 57 | *
|
| 58 | * Return: A pointer to the interrupt parent node with refcount increased
|
| 59 | * or NULL if the interrupt parent could not be determined.
|
| 60 |
|
| 61 | struct device_node *of_irq_find_parent(struct device_node *child)
|
| 62 | {
|
| 63 | struct device_node *p;
|
| 64 | phandle parent;
|
| 65 |
|
| 66 | if (!of_node_get(child))
|
| 67 | return NULL;
|
| 68 |
|
| 69 | do {
|
| 70 | if (of_property_read_u32(child, "interrupt-parent", &parent)) {
|
| 71 | p = of_get_parent(child);
|
| 72 | } else {
|
| 73 | if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
|
| 74 | p = of_node_get(of_irq_dflt_pic);
|
| 75 | else
|
| 76 | p = of_find_node_by_phandle(parent);
|
| 77 | }
|
| 78 | of_node_put(child);
|
| 79 | child = p;
|
| 80 | } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
|
| 81 |
|
| 82 | return p;
|
| 83 | }
|
| 84 | EXPORT_SYMBOL_GPL(of_irq_find_parent);
|
| 85 |
|
| 86 | |
| 87 | * These interrupt controllers abuse interrupt-map for unspeakable
|
| 88 | * reasons and rely on the core code to *ignore* it (the drivers do
|
| 89 | * their own parsing of the property). The PAsemi entry covers a
|
| 90 | * non-sensical interrupt-map that is better left ignored.
|
| 91 | *
|
| 92 | * If you think of adding to the list for something *new*, think
|
| 93 | * again. There is a high chance that you will be sent back to the
|
| 94 | * drawing board.
|
| 95 |
|
| 96 | static const char * const of_irq_imap_abusers[] = {
|
| 97 | "CBEA,platform-spider-pic",
|
| 98 | "sti,platform-spider-pic",
|
| 99 | "realtek,rtl-intc",
|
| 100 | "fsl,ls1021a-extirq",
|
| 101 | "fsl,ls1043a-extirq",
|
| 102 | "fsl,ls1088a-extirq",
|
| 103 | "renesas,rza1-irqc",
|
| 104 | "pasemi,rootbus",
|
| 105 | NULL,
|
| 106 | };
|
| 107 |
|
| 108 | const __be32 *of_irq_parse_imap_parent(const __be32 *imap, int len, struct of_phandle_args *out_irq)
|
| 109 | {
|
| 110 | u32 intsize, addrsize;
|
| 111 | struct device_node *np;
|
| 112 |
|
| 113 |
|
| 114 | if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
|
| 115 | np = of_node_get(of_irq_dflt_pic);
|
| 116 | else
|
| 117 | np = of_find_node_by_phandle(be32_to_cpup(imap));
|
| 118 | imap++;
|
| 119 | len--;
|
| 120 |
|
| 121 |
|
| 122 | if (!np) {
|
| 123 | pr_debug(" -> imap parent not found !\n");
|
| 124 | return NULL;
|
| 125 | }
|
| 126 |
|
| 127 |
|
| 128 | if (of_property_read_u32(np, "#interrupt-cells",
|
| 129 | &intsize)) {
|
| 130 | pr_debug(" -> parent lacks #interrupt-cells!\n");
|
| 131 | of_node_put(np);
|
| 132 | return NULL;
|
| 133 | }
|
| 134 | if (of_property_read_u32(np, "#address-cells",
|
| 135 | &addrsize))
|
| 136 | addrsize = 0;
|
| 137 |
|
| 138 | pr_debug(" -> intsize=%d, addrsize=%d\n",
|
| 139 | intsize, addrsize);
|
| 140 |
|
| 141 |
|
| 142 | if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS)
|
| 143 | || (len < (addrsize + intsize))) {
|
| 144 | of_node_put(np);
|
| 145 | return NULL;
|
| 146 | }
|
| 147 |
|
| 148 | pr_debug(" -> imaplen=%d\n", len);
|
| 149 |
|
| 150 | imap += addrsize + intsize;
|
| 151 |
|
| 152 | out_irq->np = np;
|
| 153 | for (int i = 0; i < intsize; i++)
|
| 154 | out_irq->args[i] = be32_to_cpup(imap - intsize + i);
|
| 155 | out_irq->args_count = intsize;
|
| 156 |
|
| 157 | return imap;
|
| 158 | }
|
| 159 |
|
| 160 | int of_imap_parser_init(struct of_imap_parser *parser, struct device_node *node,
|
| 161 | struct of_imap_item *item)
|
| 162 | {
|
| 163 | int imaplen;
|
| 164 | u32 tmp;
|
| 165 | int ret;
|
| 166 |
|
| 167 | |
| 168 | * parent_offset is the offset where the parent part is starting.
|
| 169 | * In other words, the offset where the parent interrupt controller
|
| 170 | * phandle is present.
|
| 171 | *
|
| 172 | * Compute this offset (child #interrupt-cells + child #address-cells)
|
| 173 |
|
| 174 | parser->parent_offset = of_bus_n_addr_cells(node);
|
| 175 |
|
| 176 | ret = of_property_read_u32(node, "#interrupt-cells", &tmp);
|
| 177 | if (ret)
|
| 178 | return ret;
|
| 179 |
|
| 180 | parser->parent_offset += tmp;
|
| 181 |
|
| 182 | if (WARN(parser->parent_offset > ARRAY_SIZE(item->child_imap),
|
| 183 | "child part size = %u, cannot fit in array of %zu items",
|
| 184 | parser->parent_offset, ARRAY_SIZE(item->child_imap)))
|
| 185 | return -EINVAL;
|
| 186 |
|
| 187 | parser->imap = of_get_property(node, "interrupt-map", &imaplen);
|
| 188 | if (!parser->imap)
|
| 189 | return -ENOENT;
|
| 190 |
|
| 191 | imaplen /= sizeof(*parser->imap);
|
| 192 | parser->imap_end = parser->imap + imaplen;
|
| 193 |
|
| 194 | memset(item, 0, sizeof(*item));
|
| 195 | item->child_imap_count = parser->parent_offset;
|
| 196 |
|
| 197 | return 0;
|
| 198 | }
|
| 199 | EXPORT_SYMBOL_GPL(of_imap_parser_init);
|
| 200 |
|
| 201 | struct of_imap_item *of_imap_parser_one(struct of_imap_parser *parser,
|
| 202 | struct of_imap_item *item)
|
| 203 | {
|
| 204 | const __be32 *imap_parent, *imap_next;
|
| 205 | int i;
|
| 206 |
|
| 207 |
|
| 208 | of_node_put(item->parent_args.np);
|
| 209 |
|
| 210 | if (parser->imap + parser->parent_offset + 1 >= parser->imap_end)
|
| 211 | return NULL;
|
| 212 |
|
| 213 | imap_parent = parser->imap + parser->parent_offset;
|
| 214 |
|
| 215 | imap_next = of_irq_parse_imap_parent(imap_parent,
|
| 216 | parser->imap_end - imap_parent,
|
| 217 | &item->parent_args);
|
| 218 | if (!imap_next)
|
| 219 | return NULL;
|
| 220 |
|
| 221 | for (i = 0; i < parser->parent_offset; i++)
|
| 222 | item->child_imap[i] = be32_to_cpu(*(parser->imap + i));
|
| 223 |
|
| 224 | parser->imap = imap_next;
|
| 225 |
|
| 226 | return item;
|
| 227 | }
|
| 228 | EXPORT_SYMBOL_GPL(of_imap_parser_one);
|
| 229 |
|
| 230 | |
| 231 | * of_irq_parse_raw - Low level interrupt tree parsing
|
| 232 | * @addr: address specifier (start of "reg" property of the device) in be32 format
|
| 233 | * @out_irq: structure of_phandle_args updated by this function
|
| 234 | *
|
| 235 | * This function is a low-level interrupt tree walking function. It
|
| 236 | * can be used to do a partial walk with synthesized reg and interrupts
|
| 237 | * properties, for example when resolving PCI interrupts when no device
|
| 238 | * node exist for the parent. It takes an interrupt specifier structure as
|
| 239 | * input, walks the tree looking for any interrupt-map properties, translates
|
| 240 | * the specifier for each map, and then returns the translated map.
|
| 241 | *
|
| 242 | * Return: 0 on success and a negative number on error
|
| 243 | *
|
| 244 | * Note: refcount of node @out_irq->np is increased by 1 on success.
|
| 245 |
|
| 246 | int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
|
| 247 | {
|
| 248 | struct device_node *ipar, *tnode, *old = NULL;
|
| 249 | __be32 initial_match_array[MAX_PHANDLE_ARGS];
|
| 250 | const __be32 *match_array = initial_match_array;
|
| 251 | const __be32 *tmp, dummy_imask[] = { [0 ... (MAX_PHANDLE_ARGS - 1)] = cpu_to_be32(~0) };
|
| 252 | u32 intsize = 1, addrsize;
|
| 253 | int i, rc = -EINVAL;
|
| 254 |
|
| 255 | #ifdef DEBUG
|
| 256 | of_print_phandle_args("of_irq_parse_raw: ", out_irq);
|
| 257 | #endif
|
| 258 |
|
| 259 | ipar = of_node_get(out_irq->np);
|
| 260 |
|
| 261 | |
| 262 | * that tells us how to interpret the passed-in intspec. If there
|
| 263 | * is none, we are nice and just walk up the tree
|
| 264 |
|
| 265 | do {
|
| 266 | if (!of_property_read_u32(ipar, "#interrupt-cells", &intsize))
|
| 267 | break;
|
| 268 | tnode = ipar;
|
| 269 | ipar = of_irq_find_parent(ipar);
|
| 270 | of_node_put(tnode);
|
| 271 | } while (ipar);
|
| 272 | if (ipar == NULL) {
|
| 273 | pr_debug(" -> no parent found !\n");
|
| 274 | goto fail;
|
| 275 | }
|
| 276 |
|
| 277 | pr_debug("of_irq_parse_raw: ipar=%pOF, size=%d\n", ipar, intsize);
|
| 278 |
|
| 279 | if (out_irq->args_count != intsize)
|
| 280 | goto fail;
|
| 281 |
|
| 282 | |
| 283 | * trick of looking for the parent here as some device-trees rely on it
|
| 284 |
|
| 285 | old = of_node_get(ipar);
|
| 286 | do {
|
| 287 | tmp = of_get_property(old, "#address-cells", NULL);
|
| 288 | tnode = of_get_parent(old);
|
| 289 | of_node_put(old);
|
| 290 | old = tnode;
|
| 291 | } while (old && tmp == NULL);
|
| 292 | of_node_put(old);
|
| 293 | old = NULL;
|
| 294 | addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp);
|
| 295 |
|
| 296 | pr_debug(" -> addrsize=%d\n", addrsize);
|
| 297 |
|
| 298 |
|
| 299 | if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS)) {
|
| 300 | rc = -EFAULT;
|
| 301 | goto fail;
|
| 302 | }
|
| 303 |
|
| 304 |
|
| 305 | for (i = 0; i < addrsize; i++)
|
| 306 | initial_match_array[i] = addr ? addr[i] : 0;
|
| 307 | for (i = 0; i < intsize; i++)
|
| 308 | initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]);
|
| 309 |
|
| 310 |
|
| 311 | while (ipar != NULL) {
|
| 312 | int imaplen, match;
|
| 313 | const __be32 *imap, *oldimap, *imask;
|
| 314 | struct device_node *newpar;
|
| 315 | |
| 316 | * Now check if cursor is an interrupt-controller and
|
| 317 | * if it is then we are done, unless there is an
|
| 318 | * interrupt-map which takes precedence except on one
|
| 319 | * of these broken platforms that want to parse
|
| 320 | * interrupt-map themselves for $reason.
|
| 321 |
|
| 322 | bool intc = of_property_read_bool(ipar, "interrupt-controller");
|
| 323 |
|
| 324 | imap = of_get_property(ipar, "interrupt-map", &imaplen);
|
| 325 | if (intc &&
|
| 326 | (!imap || of_device_compatible_match(ipar, of_irq_imap_abusers))) {
|
| 327 | pr_debug(" -> got it !\n");
|
| 328 | return 0;
|
| 329 | }
|
| 330 |
|
| 331 | |
| 332 | * interrupt-map parsing does not work without a reg
|
| 333 | * property when #address-cells != 0
|
| 334 |
|
| 335 | if (addrsize && !addr) {
|
| 336 | pr_debug(" -> no reg passed in when needed !\n");
|
| 337 | goto fail;
|
| 338 | }
|
| 339 |
|
| 340 |
|
| 341 | if (imap == NULL) {
|
| 342 | pr_debug(" -> no map, getting parent\n");
|
| 343 | newpar = of_irq_find_parent(ipar);
|
| 344 | goto skiplevel;
|
| 345 | }
|
| 346 | imaplen /= sizeof(u32);
|
| 347 |
|
| 348 |
|
| 349 | imask = of_get_property(ipar, "interrupt-map-mask", NULL);
|
| 350 | if (!imask)
|
| 351 | imask = dummy_imask;
|
| 352 |
|
| 353 |
|
| 354 | match = 0;
|
| 355 | while (imaplen > (addrsize + intsize + 1)) {
|
| 356 |
|
| 357 | match = 1;
|
| 358 | for (i = 0; i < (addrsize + intsize); i++, imaplen--)
|
| 359 | match &= !((match_array[i] ^ *imap++) & imask[i]);
|
| 360 |
|
| 361 | pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
|
| 362 |
|
| 363 | oldimap = imap;
|
| 364 | imap = of_irq_parse_imap_parent(oldimap, imaplen, out_irq);
|
| 365 | if (!imap)
|
| 366 | goto fail;
|
| 367 |
|
| 368 | match &= of_device_is_available(out_irq->np);
|
| 369 | if (match)
|
| 370 | break;
|
| 371 |
|
| 372 | of_node_put(out_irq->np);
|
| 373 | imaplen -= imap - oldimap;
|
| 374 | pr_debug(" -> imaplen=%d\n", imaplen);
|
| 375 | }
|
| 376 | if (!match)
|
| 377 | goto fail;
|
| 378 |
|
| 379 | |
| 380 | * Successfully parsed an interrupt-map translation; copy new
|
| 381 | * interrupt specifier into the out_irq structure
|
| 382 |
|
| 383 | match_array = oldimap + 1;
|
| 384 |
|
| 385 | newpar = out_irq->np;
|
| 386 | intsize = out_irq->args_count;
|
| 387 | addrsize = (imap - match_array) - intsize;
|
| 388 |
|
| 389 | if (ipar == newpar) {
|
| 390 | |
| 391 | * We got @ipar's refcount, but the refcount was
|
| 392 | * gotten again by of_irq_parse_imap_parent() via its
|
| 393 | * alias @newpar.
|
| 394 |
|
| 395 | of_node_put(ipar);
|
| 396 | pr_debug("%pOF interrupt-map entry to self\n", ipar);
|
| 397 | return 0;
|
| 398 | }
|
| 399 |
|
| 400 | skiplevel:
|
| 401 |
|
| 402 | pr_debug(" -> new parent: %pOF\n", newpar);
|
| 403 | of_node_put(ipar);
|
| 404 | ipar = newpar;
|
| 405 | newpar = NULL;
|
| 406 | }
|
| 407 | rc = -ENOENT;
|
| 408 |
|
| 409 | fail:
|
| 410 | of_node_put(ipar);
|
| 411 |
|
| 412 | return rc;
|
| 413 | }
|
| 414 | EXPORT_SYMBOL_GPL(of_irq_parse_raw);
|
| 415 |
|
| 416 | |
| 417 | * of_irq_parse_one - Resolve an interrupt for a device
|
| 418 | * @device: the device whose interrupt is to be resolved
|
| 419 | * @index: index of the interrupt to resolve
|
| 420 | * @out_irq: structure of_phandle_args filled by this function
|
| 421 | *
|
| 422 | * This function resolves an interrupt for a node by walking the interrupt tree,
|
| 423 | * finding which interrupt controller node it is attached to, and returning the
|
| 424 | * interrupt specifier that can be used to retrieve a Linux IRQ number.
|
| 425 | *
|
| 426 | * Note: refcount of node @out_irq->np is increased by 1 on success.
|
| 427 |
|
| 428 | int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
|
| 429 | {
|
| 430 | struct device_node __free(device_node) *p = NULL;
|
| 431 | const __be32 *addr;
|
| 432 | u32 intsize;
|
| 433 | int i, res, addr_len;
|
| 434 | __be32 addr_buf[3] = { 0 };
|
| 435 |
|
| 436 | pr_debug("of_irq_parse_one: dev=%pOF, index=%d\n", device, index);
|
| 437 |
|
| 438 |
|
| 439 | if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
|
| 440 | return of_irq_parse_oldworld(device, index, out_irq);
|
| 441 |
|
| 442 |
|
| 443 | addr_len = 0;
|
| 444 | addr = of_get_property(device, "reg", &addr_len);
|
| 445 |
|
| 446 |
|
| 447 | if (addr_len > sizeof(addr_buf))
|
| 448 | addr_len = sizeof(addr_buf);
|
| 449 | if (addr)
|
| 450 | memcpy(addr_buf, addr, addr_len);
|
| 451 |
|
| 452 |
|
| 453 | res = of_parse_phandle_with_args(device, "interrupts-extended",
|
| 454 | "#interrupt-cells", index, out_irq);
|
| 455 | if (!res) {
|
| 456 | p = out_irq->np;
|
| 457 | } else {
|
| 458 |
|
| 459 | p = of_irq_find_parent(device);
|
| 460 |
|
| 461 | if (!p || of_property_read_u32(p, "#interrupt-cells", &intsize))
|
| 462 | return -EINVAL;
|
| 463 |
|
| 464 | pr_debug(" parent=%pOF, intsize=%d\n", p, intsize);
|
| 465 |
|
| 466 |
|
| 467 | out_irq->np = p;
|
| 468 | out_irq->args_count = intsize;
|
| 469 | for (i = 0; i < intsize; i++) {
|
| 470 | res = of_property_read_u32_index(device, "interrupts",
|
| 471 | (index * intsize) + i,
|
| 472 | out_irq->args + i);
|
| 473 | if (res)
|
| 474 | return res;
|
| 475 | }
|
| 476 |
|
| 477 | pr_debug(" intspec=%d\n", *out_irq->args);
|
| 478 | }
|
| 479 |
|
| 480 |
|
| 481 | return of_irq_parse_raw(addr_buf, out_irq);
|
| 482 | }
|
| 483 | EXPORT_SYMBOL_GPL(of_irq_parse_one);
|
| 484 |
|
| 485 | |
| 486 | * of_irq_to_resource - Decode a node's IRQ and return it as a resource
|
| 487 | * @dev: pointer to device tree node
|
| 488 | * @index: zero-based index of the irq
|
| 489 | * @r: pointer to resource structure to return result into.
|
| 490 |
|
| 491 | int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
|
| 492 | {
|
| 493 | int irq = of_irq_get(dev, index);
|
| 494 |
|
| 495 | if (irq < 0)
|
| 496 | return irq;
|
| 497 |
|
| 498 | |
| 499 | * resource and the irq are valid.
|
| 500 | if (r && irq) {
|
| 501 | const char *name = NULL;
|
| 502 |
|
| 503 | memset(r, 0, sizeof(*r));
|
| 504 | |
| 505 | * Get optional "interrupt-names" property to add a name
|
| 506 | * to the resource.
|
| 507 |
|
| 508 | of_property_read_string_index(dev, "interrupt-names", index,
|
| 509 | &name);
|
| 510 |
|
| 511 | *r = DEFINE_RES_IRQ_NAMED(irq, name ?: of_node_full_name(dev));
|
| 512 | r->flags |= irq_get_trigger_type(irq);
|
| 513 | }
|
| 514 |
|
| 515 | return irq;
|
| 516 | }
|
| 517 | EXPORT_SYMBOL_GPL(of_irq_to_resource);
|
| 518 |
|
| 519 | |
| 520 | * of_irq_get - Decode a node's IRQ and return it as a Linux IRQ number
|
| 521 | * @dev: pointer to device tree node
|
| 522 | * @index: zero-based index of the IRQ
|
| 523 | *
|
| 524 | * Return: Linux IRQ number on success, or 0 on the IRQ mapping failure, or
|
| 525 | * -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
|
| 526 | * of any other failure.
|
| 527 |
|
| 528 | int of_irq_get(struct device_node *dev, int index)
|
| 529 | {
|
| 530 | int rc;
|
| 531 | struct of_phandle_args oirq;
|
| 532 | struct irq_domain *domain;
|
| 533 |
|
| 534 | rc = of_irq_parse_one(dev, index, &oirq);
|
| 535 | if (rc)
|
| 536 | return rc;
|
| 537 |
|
| 538 | domain = irq_find_host(oirq.np);
|
| 539 | if (!domain) {
|
| 540 | rc = -EPROBE_DEFER;
|
| 541 | goto out;
|
| 542 | }
|
| 543 |
|
| 544 | rc = irq_create_of_mapping(&oirq);
|
| 545 | out:
|
| 546 | of_node_put(oirq.np);
|
| 547 |
|
| 548 | return rc;
|
| 549 | }
|
| 550 | EXPORT_SYMBOL_GPL(of_irq_get);
|
| 551 |
|
| 552 | const struct cpumask *of_irq_get_affinity(struct device_node *dev, int index)
|
| 553 | {
|
| 554 | struct of_phandle_args oirq;
|
| 555 | struct irq_fwspec_info info;
|
| 556 | struct irq_fwspec fwspec;
|
| 557 | int rc;
|
| 558 |
|
| 559 | rc = of_irq_parse_one(dev, index, &oirq);
|
| 560 | if (rc)
|
| 561 | return NULL;
|
| 562 |
|
| 563 | of_phandle_args_to_fwspec(oirq.np, oirq.args, oirq.args_count,
|
| 564 | &fwspec);
|
| 565 |
|
| 566 | rc = irq_populate_fwspec_info(&fwspec, &info);
|
| 567 | of_node_put(oirq.np);
|
| 568 | if (rc)
|
| 569 | return NULL;
|
| 570 |
|
| 571 | return info.affinity;
|
| 572 | }
|
| 573 |
|
| 574 | |
| 575 | * of_irq_get_byname - Decode a node's IRQ and return it as a Linux IRQ number
|
| 576 | * @dev: pointer to device tree node
|
| 577 | * @name: IRQ name
|
| 578 | *
|
| 579 | * Return: Linux IRQ number on success, or 0 on the IRQ mapping failure, or
|
| 580 | * -EPROBE_DEFER if the IRQ domain is not yet created, or error code in case
|
| 581 | * of any other failure.
|
| 582 |
|
| 583 | int of_irq_get_byname(struct device_node *dev, const char *name)
|
| 584 | {
|
| 585 | int index;
|
| 586 |
|
| 587 | if (unlikely(!name))
|
| 588 | return -EINVAL;
|
| 589 |
|
| 590 | index = of_property_match_string(dev, "interrupt-names", name);
|
| 591 | if (index < 0)
|
| 592 | return index;
|
| 593 |
|
| 594 | return of_irq_get(dev, index);
|
| 595 | }
|
| 596 | EXPORT_SYMBOL_GPL(of_irq_get_byname);
|
| 597 |
|
| 598 | |
| 599 | * of_irq_count - Count the number of IRQs a node uses
|
| 600 | * @dev: pointer to device tree node
|
| 601 |
|
| 602 | int of_irq_count(struct device_node *dev)
|
| 603 | {
|
| 604 | struct of_phandle_args irq;
|
| 605 | int nr = 0;
|
| 606 |
|
| 607 | while (of_irq_parse_one(dev, nr, &irq) == 0) {
|
| 608 | of_node_put(irq.np);
|
| 609 | nr++;
|
| 610 | }
|
| 611 |
|
| 612 | return nr;
|
| 613 | }
|
| 614 | EXPORT_SYMBOL_GPL(of_irq_count);
|
| 615 |
|
| 616 | |
| 617 | * of_irq_to_resource_table - Fill in resource table with node's IRQ info
|
| 618 | * @dev: pointer to device tree node
|
| 619 | * @res: array of resources to fill in
|
| 620 | * @nr_irqs: the number of IRQs (and upper bound for num of @res elements)
|
| 621 | *
|
| 622 | * Return: The size of the filled in table (up to @nr_irqs).
|
| 623 |
|
| 624 | int of_irq_to_resource_table(struct device_node *dev, struct resource *res,
|
| 625 | int nr_irqs)
|
| 626 | {
|
| 627 | int i;
|
| 628 |
|
| 629 | for (i = 0; i < nr_irqs; i++, res++)
|
| 630 | if (of_irq_to_resource(dev, i, res) <= 0)
|
| 631 | break;
|
| 632 |
|
| 633 | return i;
|
| 634 | }
|
| 635 | EXPORT_SYMBOL_GPL(of_irq_to_resource_table);
|
| 636 |
|
| 637 | struct of_intc_desc {
|
| 638 | struct list_head list;
|
| 639 | of_irq_init_cb_t irq_init_cb;
|
| 640 | struct device_node *dev;
|
| 641 | struct device_node *interrupt_parent;
|
| 642 | };
|
| 643 |
|
| 644 | |
| 645 | * of_irq_init - Scan and init matching interrupt controllers in DT
|
| 646 | * @matches: 0 terminated array of nodes to match and init function to call
|
| 647 | *
|
| 648 | * This function scans the device tree for matching interrupt controller nodes,
|
| 649 | * and calls their initialization functions in order with parents first.
|
| 650 |
|
| 651 | void __init of_irq_init(const struct of_device_id *matches)
|
| 652 | {
|
| 653 | const struct of_device_id *match;
|
| 654 | struct device_node *np, *parent = NULL;
|
| 655 | struct of_intc_desc *desc, *temp_desc;
|
| 656 | struct list_head intc_desc_list, intc_parent_list;
|
| 657 |
|
| 658 | INIT_LIST_HEAD(&intc_desc_list);
|
| 659 | INIT_LIST_HEAD(&intc_parent_list);
|
| 660 |
|
| 661 | for_each_matching_node_and_match(np, matches, &match) {
|
| 662 | if (!of_property_read_bool(np, "interrupt-controller") ||
|
| 663 | !of_device_is_available(np))
|
| 664 | continue;
|
| 665 |
|
| 666 | if (WARN(!match->data, "of_irq_init: no init function for %s\n",
|
| 667 | match->compatible))
|
| 668 | continue;
|
| 669 |
|
| 670 | |
| 671 | * Here, we allocate and populate an of_intc_desc with the node
|
| 672 | * pointer, interrupt-parent device_node etc.
|
| 673 |
|
| 674 | desc = kzalloc_obj(*desc);
|
| 675 | if (!desc) {
|
| 676 | of_node_put(np);
|
| 677 | goto err;
|
| 678 | }
|
| 679 |
|
| 680 | desc->irq_init_cb = match->data;
|
| 681 | desc->dev = of_node_get(np);
|
| 682 | |
| 683 | * interrupts-extended can reference multiple parent domains.
|
| 684 | * Arbitrarily pick the first one; assume any other parents
|
| 685 | * are the same distance away from the root irq controller.
|
| 686 |
|
| 687 | desc->interrupt_parent = of_parse_phandle(np, "interrupts-extended", 0);
|
| 688 | if (!desc->interrupt_parent && of_property_present(np, "interrupts"))
|
| 689 | desc->interrupt_parent = of_irq_find_parent(np);
|
| 690 | else if (!desc->interrupt_parent)
|
| 691 | desc->interrupt_parent = of_parse_phandle(np, "interrupt-parent", 0);
|
| 692 | if (desc->interrupt_parent == np) {
|
| 693 | of_node_put(desc->interrupt_parent);
|
| 694 | desc->interrupt_parent = NULL;
|
| 695 | }
|
| 696 | list_add_tail(&desc->list, &intc_desc_list);
|
| 697 | }
|
| 698 |
|
| 699 | |
| 700 | * The root irq controller is the one without an interrupt-parent.
|
| 701 | * That one goes first, followed by the controllers that reference it,
|
| 702 | * followed by the ones that reference the 2nd level controllers, etc.
|
| 703 |
|
| 704 | while (!list_empty(&intc_desc_list)) {
|
| 705 | |
| 706 | * Process all controllers with the current 'parent'.
|
| 707 | * First pass will be looking for NULL as the parent.
|
| 708 | * The assumption is that NULL parent means a root controller.
|
| 709 |
|
| 710 | list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
|
| 711 | int ret;
|
| 712 |
|
| 713 | if (desc->interrupt_parent != parent)
|
| 714 | continue;
|
| 715 |
|
| 716 | list_del(&desc->list);
|
| 717 |
|
| 718 | of_node_set_flag(desc->dev, OF_POPULATED);
|
| 719 |
|
| 720 | pr_debug("of_irq_init: init %pOF (%p), parent %p\n",
|
| 721 | desc->dev,
|
| 722 | desc->dev, desc->interrupt_parent);
|
| 723 | ret = desc->irq_init_cb(desc->dev,
|
| 724 | desc->interrupt_parent);
|
| 725 | if (ret) {
|
| 726 | pr_err("%s: Failed to init %pOF (%p), parent %p\n",
|
| 727 | __func__, desc->dev, desc->dev,
|
| 728 | desc->interrupt_parent);
|
| 729 | of_node_clear_flag(desc->dev, OF_POPULATED);
|
| 730 | of_node_put(desc->interrupt_parent);
|
| 731 | of_node_put(desc->dev);
|
| 732 | kfree(desc);
|
| 733 | continue;
|
| 734 | }
|
| 735 |
|
| 736 | |
| 737 | * This one is now set up; add it to the parent list so
|
| 738 | * its children can get processed in a subsequent pass.
|
| 739 |
|
| 740 | list_add_tail(&desc->list, &intc_parent_list);
|
| 741 | }
|
| 742 |
|
| 743 |
|
| 744 | desc = list_first_entry_or_null(&intc_parent_list,
|
| 745 | typeof(*desc), list);
|
| 746 | if (!desc) {
|
| 747 | pr_err("of_irq_init: children remain, but no parents\n");
|
| 748 | break;
|
| 749 | }
|
| 750 | list_del(&desc->list);
|
| 751 | parent = desc->dev;
|
| 752 | kfree(desc);
|
| 753 | }
|
| 754 |
|
| 755 | list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {
|
| 756 | list_del(&desc->list);
|
| 757 | of_node_put(desc->interrupt_parent);
|
| 758 | of_node_put(desc->dev);
|
| 759 | kfree(desc);
|
| 760 | }
|
| 761 | err:
|
| 762 | list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
|
| 763 | list_del(&desc->list);
|
| 764 | of_node_put(desc->interrupt_parent);
|
| 765 | of_node_put(desc->dev);
|
| 766 | kfree(desc);
|
| 767 | }
|
| 768 | }
|
| 769 |
|
| 770 | static int of_check_msi_parent(struct device_node *dev_node, struct device_node **msi_node)
|
| 771 | {
|
| 772 | struct of_phandle_args msi_spec;
|
| 773 | int ret;
|
| 774 |
|
| 775 | |
| 776 | * An msi-parent phandle with a missing or == 0 #msi-cells
|
| 777 | * property identifies a 1:1 ID translation mapping.
|
| 778 | *
|
| 779 | * Set the msi controller node if the firmware matches this
|
| 780 | * condition.
|
| 781 |
|
| 782 | ret = of_parse_phandle_with_optional_args(dev_node, "msi-parent", "#msi-cells",
|
| 783 | 0, &msi_spec);
|
| 784 | if (ret)
|
| 785 | return ret;
|
| 786 |
|
| 787 | if ((*msi_node && *msi_node != msi_spec.np) || msi_spec.args_count != 0)
|
| 788 | ret = -EINVAL;
|
| 789 |
|
| 790 | if (!ret) {
|
| 791 |
|
| 792 | *msi_node = msi_spec.np;
|
| 793 | return 0;
|
| 794 | }
|
| 795 | of_node_put(msi_spec.np);
|
| 796 |
|
| 797 | return ret;
|
| 798 | }
|
| 799 |
|
| 800 | |
| 801 | * of_msi_xlate - map a MSI ID and find relevant MSI controller node
|
| 802 | * @dev: device for which the mapping is to be done.
|
| 803 | * @msi_np: Pointer to target MSI controller node, or NULL if the caller
|
| 804 | * only needs the translated ID without receiving the controller node.
|
| 805 | * If non-NULL and pointing to a non-NULL node, only entries targeting
|
| 806 | * that node will be matched. If non-NULL and pointing to NULL, it will
|
| 807 | * receive the first matching target node with a reference held.
|
| 808 | * @id_in: Device ID.
|
| 809 | *
|
| 810 | * Walk up the device hierarchy looking for devices with a "msi-map"
|
| 811 | * or "msi-parent" property. If found, apply the mapping to @id_in.
|
| 812 | *
|
| 813 | * Returns: The mapped MSI id.
|
| 814 |
|
| 815 | u32 of_msi_xlate(struct device *dev, struct device_node **msi_np, u32 id_in)
|
| 816 | {
|
| 817 | struct device *parent_dev;
|
| 818 | u32 id_out = id_in;
|
| 819 |
|
| 820 | |
| 821 | * Walk up the device parent links looking for one with a
|
| 822 | * "msi-map" or an "msi-parent" property.
|
| 823 |
|
| 824 | for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent) {
|
| 825 | struct of_phandle_args msi_spec = {};
|
| 826 |
|
| 827 | if (!of_map_msi_id(parent_dev->of_node, id_in, msi_np, &msi_spec)) {
|
| 828 | if (msi_spec.np) {
|
| 829 |
|
| 830 | if (msi_spec.args_count > 0)
|
| 831 | id_out = msi_spec.args[0];
|
| 832 | if (msi_np && !*msi_np)
|
| 833 | *msi_np = of_node_get(msi_spec.np);
|
| 834 | of_node_put(msi_spec.np);
|
| 835 | }
|
| 836 |
|
| 837 | break;
|
| 838 | }
|
| 839 |
|
| 840 | if (msi_np && !of_check_msi_parent(parent_dev->of_node, msi_np))
|
| 841 | break;
|
| 842 | }
|
| 843 | return id_out;
|
| 844 | }
|
| 845 | EXPORT_SYMBOL_GPL(of_msi_xlate);
|
| 846 |
|
| 847 | |
| 848 | * of_msi_map_get_device_domain - Use msi-map to find the relevant MSI domain
|
| 849 | * @dev: device for which the mapping is to be done.
|
| 850 | * @id: Device ID.
|
| 851 | * @bus_token: Bus token
|
| 852 | *
|
| 853 | * Walk up the device hierarchy looking for devices with a "msi-map"
|
| 854 | * property.
|
| 855 | *
|
| 856 | * Returns: the MSI domain for this device (or NULL on failure)
|
| 857 |
|
| 858 | struct irq_domain *of_msi_map_get_device_domain(struct device *dev, u32 id,
|
| 859 | u32 bus_token)
|
| 860 | {
|
| 861 | struct device_node *np = NULL;
|
| 862 | struct irq_domain *d;
|
| 863 |
|
| 864 | of_msi_xlate(dev, &np, id);
|
| 865 | d = irq_find_matching_host(np, bus_token);
|
| 866 | of_node_put(np);
|
| 867 | return d;
|
| 868 | }
|
| 869 |
|
| 870 | |
| 871 | * of_msi_get_domain - Use msi-parent to find the relevant MSI domain
|
| 872 | * @dev: device for which the domain is requested
|
| 873 | * @np: device node for @dev
|
| 874 | * @token: bus type for this domain
|
| 875 | *
|
| 876 | * Parse the msi-parent property and returns the corresponding MSI domain.
|
| 877 | *
|
| 878 | * Returns: the MSI domain for this device (or NULL on failure).
|
| 879 |
|
| 880 | struct irq_domain *of_msi_get_domain(struct device *dev,
|
| 881 | const struct device_node *np,
|
| 882 | enum irq_domain_bus_token token)
|
| 883 | {
|
| 884 | struct of_phandle_iterator it;
|
| 885 | struct irq_domain *d;
|
| 886 | int err;
|
| 887 |
|
| 888 | of_for_each_phandle(&it, err, np, "msi-parent", "#msi-cells", 0) {
|
| 889 | d = irq_find_matching_host(it.node, token);
|
| 890 | if (d) {
|
| 891 | of_node_put(it.node);
|
| 892 | return d;
|
| 893 | }
|
| 894 | }
|
| 895 |
|
| 896 | return NULL;
|
| 897 | }
|
| 898 | EXPORT_SYMBOL_GPL(of_msi_get_domain);
|
| 899 |
|
| 900 | |
| 901 | * of_msi_configure - Set the msi_domain field of a device
|
| 902 | * @dev: device structure to associate with an MSI irq domain
|
| 903 | * @np: device node for that device
|
| 904 |
|
| 905 | void of_msi_configure(struct device *dev, const struct device_node *np)
|
| 906 | {
|
| 907 | dev_set_msi_domain(dev,
|
| 908 | of_msi_get_domain(dev, np, DOMAIN_BUS_PLATFORM_MSI));
|
| 909 | }
|
| 910 | EXPORT_SYMBOL_GPL(of_msi_configure);
|