Commit 9ec36cafe43bf835f8f29273597a5b0cbc8267ef

Authored by Rob Herring
Committed by Grant Likely
1 parent 82c0f5897a

of/irq: do irq resolution in platform_get_irq

Currently we get the following kind of errors if we try to use interrupt
phandles to irqchips that have not yet initialized:

irq: no irq domain found for /ocp/pinmux@48002030 !
------------[ cut here ]------------
WARNING: CPU: 0 PID: 1 at drivers/of/platform.c:171 of_device_alloc+0x144/0x184()
Modules linked in:
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.12.0-00038-g42a9708 #1012
(show_stack+0x14/0x1c)
(dump_stack+0x6c/0xa0)
(warn_slowpath_common+0x64/0x84)
(warn_slowpath_null+0x1c/0x24)
(of_device_alloc+0x144/0x184)
(of_platform_device_create_pdata+0x44/0x9c)
(of_platform_bus_create+0xd0/0x170)
(of_platform_bus_create+0x12c/0x170)
(of_platform_populate+0x60/0x98)

This is because we're wrongly trying to populate resources that are not
yet available. It's perfectly valid to create irqchips dynamically, so
let's fix up the issue by resolving the interrupt resources when
platform_get_irq is called.

And then we also need to accept the fact that some irqdomains do not
exist that early on, and only get initialized later on. So we can
make the current WARN_ON into just into a pr_debug().

We still attempt to populate irq resources when we create the devices.
This allows current drivers which don't use platform_get_irq to continue
to function. Once all drivers are fixed, this code can be removed.

Suggested-by: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Rob Herring <robh@kernel.org>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Tested-by: Tony Lindgren <tony@atomide.com>
Cc: stable@vger.kernel.org # v3.10+
Signed-off-by: Grant Likely <grant.likely@linaro.org>

Showing 4 changed files with 40 additions and 2 deletions Side-by-side Diff

drivers/base/platform.c
... ... @@ -13,6 +13,7 @@
13 13 #include <linux/string.h>
14 14 #include <linux/platform_device.h>
15 15 #include <linux/of_device.h>
  16 +#include <linux/of_irq.h>
16 17 #include <linux/module.h>
17 18 #include <linux/init.h>
18 19 #include <linux/dma-mapping.h>
... ... @@ -87,7 +88,11 @@
87 88 return -ENXIO;
88 89 return dev->archdata.irqs[num];
89 90 #else
90   - struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
  91 + struct resource *r;
  92 + if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node)
  93 + return of_irq_get(dev->dev.of_node, num);
  94 +
  95 + r = platform_get_resource(dev, IORESOURCE_IRQ, num);
91 96  
92 97 return r ? r->start : -ENXIO;
93 98 #endif
... ... @@ -380,6 +380,32 @@
380 380 EXPORT_SYMBOL_GPL(of_irq_to_resource);
381 381  
382 382 /**
  383 + * of_irq_get - Decode a node's IRQ and return it as a Linux irq number
  384 + * @dev: pointer to device tree node
  385 + * @index: zero-based index of the irq
  386 + *
  387 + * Returns Linux irq number on success, or -EPROBE_DEFER if the irq domain
  388 + * is not yet created.
  389 + *
  390 + */
  391 +int of_irq_get(struct device_node *dev, int index)
  392 +{
  393 + int rc;
  394 + struct of_phandle_args oirq;
  395 + struct irq_domain *domain;
  396 +
  397 + rc = of_irq_parse_one(dev, index, &oirq);
  398 + if (rc)
  399 + return rc;
  400 +
  401 + domain = irq_find_host(oirq.np);
  402 + if (!domain)
  403 + return -EPROBE_DEFER;
  404 +
  405 + return irq_create_of_mapping(&oirq);
  406 +}
  407 +
  408 +/**
383 409 * of_irq_count - Count the number of IRQs a node uses
384 410 * @dev: pointer to device tree node
385 411 */
drivers/of/platform.c
... ... @@ -168,7 +168,9 @@
168 168 rc = of_address_to_resource(np, i, res);
169 169 WARN_ON(rc);
170 170 }
171   - WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq);
  171 + if (of_irq_to_resource_table(np, res, num_irq) != num_irq)
  172 + pr_debug("not all legacy IRQ resources mapped for %s\n",
  173 + np->name);
172 174 }
173 175  
174 176 dev->dev.of_node = of_node_get(np);
include/linux/of_irq.h
... ... @@ -44,8 +44,13 @@
44 44  
45 45 #ifdef CONFIG_OF_IRQ
46 46 extern int of_irq_count(struct device_node *dev);
  47 +extern int of_irq_get(struct device_node *dev, int index);
47 48 #else
48 49 static inline int of_irq_count(struct device_node *dev)
  50 +{
  51 + return 0;
  52 +}
  53 +static inline int of_irq_get(struct device_node *dev, int index)
49 54 {
50 55 return 0;
51 56 }