0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #define pr_fmt(fmt) "OF: " fmt
0018
0019 #include <linux/device.h>
0020 #include <linux/errno.h>
0021 #include <linux/list.h>
0022 #include <linux/module.h>
0023 #include <linux/of.h>
0024 #include <linux/of_irq.h>
0025 #include <linux/string.h>
0026 #include <linux/slab.h>
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
0037 {
0038 struct of_phandle_args oirq;
0039
0040 if (of_irq_parse_one(dev, index, &oirq))
0041 return 0;
0042
0043 return irq_create_of_mapping(&oirq);
0044 }
0045 EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
0046
0047
0048
0049
0050
0051
0052
0053
0054 struct device_node *of_irq_find_parent(struct device_node *child)
0055 {
0056 struct device_node *p;
0057 phandle parent;
0058
0059 if (!of_node_get(child))
0060 return NULL;
0061
0062 do {
0063 if (of_property_read_u32(child, "interrupt-parent", &parent)) {
0064 p = of_get_parent(child);
0065 } else {
0066 if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
0067 p = of_node_get(of_irq_dflt_pic);
0068 else
0069 p = of_find_node_by_phandle(parent);
0070 }
0071 of_node_put(child);
0072 child = p;
0073 } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
0074
0075 return p;
0076 }
0077 EXPORT_SYMBOL_GPL(of_irq_find_parent);
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088 static const char * const of_irq_imap_abusers[] = {
0089 "CBEA,platform-spider-pic",
0090 "sti,platform-spider-pic",
0091 "realtek,rtl-intc",
0092 "fsl,ls1021a-extirq",
0093 "fsl,ls1043a-extirq",
0094 "fsl,ls1088a-extirq",
0095 "renesas,rza1-irqc",
0096 NULL,
0097 };
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113 int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
0114 {
0115 struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
0116 __be32 initial_match_array[MAX_PHANDLE_ARGS];
0117 const __be32 *match_array = initial_match_array;
0118 const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = cpu_to_be32(~0) };
0119 u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
0120 int imaplen, match, i, rc = -EINVAL;
0121
0122 #ifdef DEBUG
0123 of_print_phandle_args("of_irq_parse_raw: ", out_irq);
0124 #endif
0125
0126 ipar = of_node_get(out_irq->np);
0127
0128
0129
0130
0131
0132 do {
0133 if (!of_property_read_u32(ipar, "#interrupt-cells", &intsize))
0134 break;
0135 tnode = ipar;
0136 ipar = of_irq_find_parent(ipar);
0137 of_node_put(tnode);
0138 } while (ipar);
0139 if (ipar == NULL) {
0140 pr_debug(" -> no parent found !\n");
0141 goto fail;
0142 }
0143
0144 pr_debug("of_irq_parse_raw: ipar=%pOF, size=%d\n", ipar, intsize);
0145
0146 if (out_irq->args_count != intsize)
0147 goto fail;
0148
0149
0150
0151
0152 old = of_node_get(ipar);
0153 do {
0154 tmp = of_get_property(old, "#address-cells", NULL);
0155 tnode = of_get_parent(old);
0156 of_node_put(old);
0157 old = tnode;
0158 } while (old && tmp == NULL);
0159 of_node_put(old);
0160 old = NULL;
0161 addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp);
0162
0163 pr_debug(" -> addrsize=%d\n", addrsize);
0164
0165
0166 if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS)) {
0167 rc = -EFAULT;
0168 goto fail;
0169 }
0170
0171
0172 for (i = 0; i < addrsize; i++)
0173 initial_match_array[i] = addr ? addr[i] : 0;
0174 for (i = 0; i < intsize; i++)
0175 initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]);
0176
0177
0178 while (ipar != NULL) {
0179
0180
0181
0182
0183
0184
0185
0186 bool intc = of_property_read_bool(ipar, "interrupt-controller");
0187
0188 imap = of_get_property(ipar, "interrupt-map", &imaplen);
0189 if (intc &&
0190 (!imap || of_device_compatible_match(ipar, of_irq_imap_abusers))) {
0191 pr_debug(" -> got it !\n");
0192 return 0;
0193 }
0194
0195
0196
0197
0198
0199 if (addrsize && !addr) {
0200 pr_debug(" -> no reg passed in when needed !\n");
0201 goto fail;
0202 }
0203
0204
0205 if (imap == NULL) {
0206 pr_debug(" -> no map, getting parent\n");
0207 newpar = of_irq_find_parent(ipar);
0208 goto skiplevel;
0209 }
0210 imaplen /= sizeof(u32);
0211
0212
0213 imask = of_get_property(ipar, "interrupt-map-mask", NULL);
0214 if (!imask)
0215 imask = dummy_imask;
0216
0217
0218 match = 0;
0219 while (imaplen > (addrsize + intsize + 1) && !match) {
0220
0221 match = 1;
0222 for (i = 0; i < (addrsize + intsize); i++, imaplen--)
0223 match &= !((match_array[i] ^ *imap++) & imask[i]);
0224
0225 pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
0226
0227
0228 if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
0229 newpar = of_node_get(of_irq_dflt_pic);
0230 else
0231 newpar = of_find_node_by_phandle(be32_to_cpup(imap));
0232 imap++;
0233 --imaplen;
0234
0235
0236 if (newpar == NULL) {
0237 pr_debug(" -> imap parent not found !\n");
0238 goto fail;
0239 }
0240
0241 if (!of_device_is_available(newpar))
0242 match = 0;
0243
0244
0245
0246
0247 if (of_property_read_u32(newpar, "#interrupt-cells",
0248 &newintsize)) {
0249 pr_debug(" -> parent lacks #interrupt-cells!\n");
0250 goto fail;
0251 }
0252 if (of_property_read_u32(newpar, "#address-cells",
0253 &newaddrsize))
0254 newaddrsize = 0;
0255
0256 pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
0257 newintsize, newaddrsize);
0258
0259
0260 if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS)
0261 || (imaplen < (newaddrsize + newintsize))) {
0262 rc = -EFAULT;
0263 goto fail;
0264 }
0265
0266 imap += newaddrsize + newintsize;
0267 imaplen -= newaddrsize + newintsize;
0268
0269 pr_debug(" -> imaplen=%d\n", imaplen);
0270 }
0271 if (!match) {
0272 if (intc) {
0273
0274
0275
0276
0277 WARN(!IS_ENABLED(CONFIG_PPC_PASEMI),
0278 "%pOF interrupt-map failed, using interrupt-controller\n",
0279 ipar);
0280 return 0;
0281 }
0282
0283 goto fail;
0284 }
0285
0286
0287
0288
0289
0290 match_array = imap - newaddrsize - newintsize;
0291 for (i = 0; i < newintsize; i++)
0292 out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
0293 out_irq->args_count = intsize = newintsize;
0294 addrsize = newaddrsize;
0295
0296 if (ipar == newpar) {
0297 pr_debug("%pOF interrupt-map entry to self\n", ipar);
0298 return 0;
0299 }
0300
0301 skiplevel:
0302
0303 out_irq->np = newpar;
0304 pr_debug(" -> new parent: %pOF\n", newpar);
0305 of_node_put(ipar);
0306 ipar = newpar;
0307 newpar = NULL;
0308 }
0309 rc = -ENOENT;
0310
0311 fail:
0312 of_node_put(ipar);
0313 of_node_put(newpar);
0314
0315 return rc;
0316 }
0317 EXPORT_SYMBOL_GPL(of_irq_parse_raw);
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329 int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
0330 {
0331 struct device_node *p;
0332 const __be32 *addr;
0333 u32 intsize;
0334 int i, res;
0335
0336 pr_debug("of_irq_parse_one: dev=%pOF, index=%d\n", device, index);
0337
0338
0339 if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
0340 return of_irq_parse_oldworld(device, index, out_irq);
0341
0342
0343 addr = of_get_property(device, "reg", NULL);
0344
0345
0346 res = of_parse_phandle_with_args(device, "interrupts-extended",
0347 "#interrupt-cells", index, out_irq);
0348 if (!res)
0349 return of_irq_parse_raw(addr, out_irq);
0350
0351
0352 p = of_irq_find_parent(device);
0353 if (p == NULL)
0354 return -EINVAL;
0355
0356
0357 if (of_property_read_u32(p, "#interrupt-cells", &intsize)) {
0358 res = -EINVAL;
0359 goto out;
0360 }
0361
0362 pr_debug(" parent=%pOF, intsize=%d\n", p, intsize);
0363
0364
0365 out_irq->np = p;
0366 out_irq->args_count = intsize;
0367 for (i = 0; i < intsize; i++) {
0368 res = of_property_read_u32_index(device, "interrupts",
0369 (index * intsize) + i,
0370 out_irq->args + i);
0371 if (res)
0372 goto out;
0373 }
0374
0375 pr_debug(" intspec=%d\n", *out_irq->args);
0376
0377
0378
0379 res = of_irq_parse_raw(addr, out_irq);
0380 out:
0381 of_node_put(p);
0382 return res;
0383 }
0384 EXPORT_SYMBOL_GPL(of_irq_parse_one);
0385
0386
0387
0388
0389
0390
0391
0392 int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
0393 {
0394 int irq = of_irq_get(dev, index);
0395
0396 if (irq < 0)
0397 return irq;
0398
0399
0400
0401 if (r && irq) {
0402 const char *name = NULL;
0403
0404 memset(r, 0, sizeof(*r));
0405
0406
0407
0408
0409 of_property_read_string_index(dev, "interrupt-names", index,
0410 &name);
0411
0412 r->start = r->end = irq;
0413 r->flags = IORESOURCE_IRQ | irqd_get_trigger_type(irq_get_irq_data(irq));
0414 r->name = name ? name : of_node_full_name(dev);
0415 }
0416
0417 return irq;
0418 }
0419 EXPORT_SYMBOL_GPL(of_irq_to_resource);
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430 int of_irq_get(struct device_node *dev, int index)
0431 {
0432 int rc;
0433 struct of_phandle_args oirq;
0434 struct irq_domain *domain;
0435
0436 rc = of_irq_parse_one(dev, index, &oirq);
0437 if (rc)
0438 return rc;
0439
0440 domain = irq_find_host(oirq.np);
0441 if (!domain)
0442 return -EPROBE_DEFER;
0443
0444 return irq_create_of_mapping(&oirq);
0445 }
0446 EXPORT_SYMBOL_GPL(of_irq_get);
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457 int of_irq_get_byname(struct device_node *dev, const char *name)
0458 {
0459 int index;
0460
0461 if (unlikely(!name))
0462 return -EINVAL;
0463
0464 index = of_property_match_string(dev, "interrupt-names", name);
0465 if (index < 0)
0466 return index;
0467
0468 return of_irq_get(dev, index);
0469 }
0470 EXPORT_SYMBOL_GPL(of_irq_get_byname);
0471
0472
0473
0474
0475
0476 int of_irq_count(struct device_node *dev)
0477 {
0478 struct of_phandle_args irq;
0479 int nr = 0;
0480
0481 while (of_irq_parse_one(dev, nr, &irq) == 0)
0482 nr++;
0483
0484 return nr;
0485 }
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495 int of_irq_to_resource_table(struct device_node *dev, struct resource *res,
0496 int nr_irqs)
0497 {
0498 int i;
0499
0500 for (i = 0; i < nr_irqs; i++, res++)
0501 if (of_irq_to_resource(dev, i, res) <= 0)
0502 break;
0503
0504 return i;
0505 }
0506 EXPORT_SYMBOL_GPL(of_irq_to_resource_table);
0507
0508 struct of_intc_desc {
0509 struct list_head list;
0510 of_irq_init_cb_t irq_init_cb;
0511 struct device_node *dev;
0512 struct device_node *interrupt_parent;
0513 };
0514
0515
0516
0517
0518
0519
0520
0521
0522 void __init of_irq_init(const struct of_device_id *matches)
0523 {
0524 const struct of_device_id *match;
0525 struct device_node *np, *parent = NULL;
0526 struct of_intc_desc *desc, *temp_desc;
0527 struct list_head intc_desc_list, intc_parent_list;
0528
0529 INIT_LIST_HEAD(&intc_desc_list);
0530 INIT_LIST_HEAD(&intc_parent_list);
0531
0532 for_each_matching_node_and_match(np, matches, &match) {
0533 if (!of_property_read_bool(np, "interrupt-controller") ||
0534 !of_device_is_available(np))
0535 continue;
0536
0537 if (WARN(!match->data, "of_irq_init: no init function for %s\n",
0538 match->compatible))
0539 continue;
0540
0541
0542
0543
0544
0545 desc = kzalloc(sizeof(*desc), GFP_KERNEL);
0546 if (!desc) {
0547 of_node_put(np);
0548 goto err;
0549 }
0550
0551 desc->irq_init_cb = match->data;
0552 desc->dev = of_node_get(np);
0553
0554
0555
0556
0557
0558 desc->interrupt_parent = of_parse_phandle(np, "interrupts-extended", 0);
0559 if (!desc->interrupt_parent)
0560 desc->interrupt_parent = of_irq_find_parent(np);
0561 if (desc->interrupt_parent == np) {
0562 of_node_put(desc->interrupt_parent);
0563 desc->interrupt_parent = NULL;
0564 }
0565 list_add_tail(&desc->list, &intc_desc_list);
0566 }
0567
0568
0569
0570
0571
0572
0573 while (!list_empty(&intc_desc_list)) {
0574
0575
0576
0577
0578
0579 list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
0580 int ret;
0581
0582 if (desc->interrupt_parent != parent)
0583 continue;
0584
0585 list_del(&desc->list);
0586
0587 of_node_set_flag(desc->dev, OF_POPULATED);
0588
0589 pr_debug("of_irq_init: init %pOF (%p), parent %p\n",
0590 desc->dev,
0591 desc->dev, desc->interrupt_parent);
0592 ret = desc->irq_init_cb(desc->dev,
0593 desc->interrupt_parent);
0594 if (ret) {
0595 of_node_clear_flag(desc->dev, OF_POPULATED);
0596 kfree(desc);
0597 continue;
0598 }
0599
0600
0601
0602
0603
0604 list_add_tail(&desc->list, &intc_parent_list);
0605 }
0606
0607
0608 desc = list_first_entry_or_null(&intc_parent_list,
0609 typeof(*desc), list);
0610 if (!desc) {
0611 pr_err("of_irq_init: children remain, but no parents\n");
0612 break;
0613 }
0614 list_del(&desc->list);
0615 parent = desc->dev;
0616 kfree(desc);
0617 }
0618
0619 list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {
0620 list_del(&desc->list);
0621 kfree(desc);
0622 }
0623 err:
0624 list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
0625 list_del(&desc->list);
0626 of_node_put(desc->dev);
0627 kfree(desc);
0628 }
0629 }
0630
0631 static u32 __of_msi_map_id(struct device *dev, struct device_node **np,
0632 u32 id_in)
0633 {
0634 struct device *parent_dev;
0635 u32 id_out = id_in;
0636
0637
0638
0639
0640
0641 for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent)
0642 if (!of_map_id(parent_dev->of_node, id_in, "msi-map",
0643 "msi-map-mask", np, &id_out))
0644 break;
0645 return id_out;
0646 }
0647
0648
0649
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659 u32 of_msi_map_id(struct device *dev, struct device_node *msi_np, u32 id_in)
0660 {
0661 return __of_msi_map_id(dev, &msi_np, id_in);
0662 }
0663
0664
0665
0666
0667
0668
0669
0670
0671
0672
0673
0674
0675 struct irq_domain *of_msi_map_get_device_domain(struct device *dev, u32 id,
0676 u32 bus_token)
0677 {
0678 struct device_node *np = NULL;
0679
0680 __of_msi_map_id(dev, &np, id);
0681 return irq_find_matching_host(np, bus_token);
0682 }
0683
0684
0685
0686
0687
0688
0689
0690
0691
0692
0693
0694
0695 struct irq_domain *of_msi_get_domain(struct device *dev,
0696 struct device_node *np,
0697 enum irq_domain_bus_token token)
0698 {
0699 struct device_node *msi_np;
0700 struct irq_domain *d;
0701
0702
0703 msi_np = of_parse_phandle(np, "msi-parent", 0);
0704 if (msi_np && !of_property_read_bool(msi_np, "#msi-cells")) {
0705 d = irq_find_matching_host(msi_np, token);
0706 if (!d)
0707 of_node_put(msi_np);
0708 return d;
0709 }
0710
0711 if (token == DOMAIN_BUS_PLATFORM_MSI) {
0712
0713 struct of_phandle_args args;
0714 int index = 0;
0715
0716 while (!of_parse_phandle_with_args(np, "msi-parent",
0717 "#msi-cells",
0718 index, &args)) {
0719 d = irq_find_matching_host(args.np, token);
0720 if (d)
0721 return d;
0722
0723 of_node_put(args.np);
0724 index++;
0725 }
0726 }
0727
0728 return NULL;
0729 }
0730
0731
0732
0733
0734
0735
0736 void of_msi_configure(struct device *dev, struct device_node *np)
0737 {
0738 dev_set_msi_domain(dev,
0739 of_msi_get_domain(dev, np, DOMAIN_BUS_PLATFORM_MSI));
0740 }
0741 EXPORT_SYMBOL_GPL(of_msi_configure);