diff mbox

of/platform: Fix no irq domain found errors when populating interrupts

Message ID 20131128154622.GB23201@ulmo.nvidia.com (mailing list archive)
State New, archived
Headers show

Commit Message

Thierry Reding Nov. 28, 2013, 3:46 p.m. UTC
On Wed, Nov 27, 2013 at 03:56:29PM +0000, Grant Likely wrote:
> On Mon, 25 Nov 2013 10:49:55 +0100, Thierry Reding <thierry.reding@gmail.com> wrote:
> > On Mon, Nov 25, 2013 at 10:25:50AM +0100, Thierry Reding wrote:
> > > On Sun, Nov 24, 2013 at 09:36:51PM +0000, Grant Likely wrote:
> > > > On Fri, 22 Nov 2013 16:43:35 -0800, Tony Lindgren <tony@atomide.com> wrote:
> > > > > 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 !
> > > > > 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 populating the interrupt resources based
> > > > > on a notifier call instead.
> > > > > 
> > > > > Signed-off-by: Tony Lindgren <tony@atomide.com>
> > > > > 
> > > > > ---
> > > > > 
> > > > > Rob & Grant, care to merge this for the -rc if this looks OK to you?
> > > > > 
> > > > > These happen for example when using interrupts-extended for omap
> > > > > wake-up interrupts where the irq domain is created by pinctrl-single.c
> > > > > at module_init time.
> > > > > 
> > > > > --- a/drivers/of/platform.c
> > > > > +++ b/drivers/of/platform.c
> > > > > @@ -130,6 +130,56 @@ void of_device_make_bus_id(struct device *dev)
> > > > >  	dev_set_name(dev, "%s.%d", node->name, magic - 1);
> > > > >  }
> > > > >  
> > > > > +/*
> > > > > + * The device interrupts are not necessarily available for all
> > > > > + * irqdomains initially so we need to populate them using a
> > > > > + * notifier.
> > > > > + */
> > > > > +static int of_device_resource_notify(struct notifier_block *nb,
> > > > > +				     unsigned long event, void *dev)
> > > > > +{
> > > > > +	struct platform_device *pdev = to_platform_device(dev);
> > > > > +	struct device_node *np = pdev->dev.of_node;
> > > > > +	struct resource *res = pdev->resource;
> > > > > +	struct resource *irqr = NULL;
> > > > > +	int num_irq, i, found = 0;
> > > > > +
> > > > > +	if (event != BUS_NOTIFY_BIND_DRIVER)
> > > > > +		return 0;
> > > > > +
> > > > > +	if (!np)
> > > > > +		goto out;
> > > > > +
> > > > > +	num_irq = of_irq_count(np);
> > > > > +	if (!num_irq)
> > > > > +		goto out;
> > > > > +
> > > > > +	for (i = 0; i < pdev->num_resources; i++, res++) {
> > > > > +		if (res->flags != IORESOURCE_IRQ ||
> > > > > +		    res->start != -EPROBE_DEFER ||
> > > > > +		    res->end != -EPROBE_DEFER)
> > > > > +			continue;
> > > > > +
> > > > > +		if (!irqr)
> > > > > +			irqr = res;
> > > > > +		found++;
> > > > > +	}
> > > > > +
> > > > > +	if (!found)
> > > > > +		goto out;
> > > > > +
> > > > > +	if (found != num_irq) {
> > > > > +		dev_WARN(dev, "error populating irq resources: %i != %i\n",
> > > > > +			 found, num_irq);
> > > > > +		goto out;
> > > > > +	}
> > > > > +
> > > > > +	WARN_ON(of_irq_to_resource_table(np, irqr, num_irq) != num_irq);
> > > > > +
> > > > > +out:
> > > > > +	return NOTIFY_DONE;
> > > > > +}
> > > > > +
> > > > >  /**
> > > > >   * of_device_alloc - Allocate and initialize an of_device
> > > > >   * @np: device node to assign to device
> > > > > @@ -168,7 +218,13 @@ struct platform_device *of_device_alloc(struct device_node *np,
> > > > >  			rc = of_address_to_resource(np, i, res);
> > > > >  			WARN_ON(rc);
> > > > >  		}
> > > > > -		WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq);
> > > > > +
> > > > > +		/* See of_device_resource_notify for populating interrupts */
> > > > > +		for (i = 0; i < num_irq; i++, res++) {
> > > > > +			res->flags = IORESOURCE_IRQ;
> > > > > +			res->start = -EPROBE_DEFER;
> > > > > +			res->end = -EPROBE_DEFER;
> > > > > +		}
> > > > 
> > > > I actually like the idea of completely allocating the resource structure
> > > > but leaving some entries empty. However, I agree with rmk that putting
> > > > garbage into a resource structure is a bad idea. What about changing the
> > > > value of flags to 0 or some other value to be obviously an empty
> > > > property and give the follow up parsing some context about which ones it
> > > > needs to attempt to recalculate?
> > > 
> > > When I worked on this a while back I came to the same conclusion. It's
> > > nice to allocate all the resources at once, because the number of them
> > > doesn't change, only their actually values.
> > 
> > I should maybe add: one issue that was raised during review of my
> > initial patch series was that we'll also need to cope with situations
> > like the following:
> > 
> > 	1) device's interrupt parent is probed (assigned IRQ base X)
> > 	2) device is probed (interrupt parent there, therefore gets
> > 	   assigned IRQ (X + z)
> > 	3) device in removed
> > 	4) device's interrupt parent is removed
> > 	5) device is probed (deferred because interrupt parent isn't
> > 	   there)
> > 	6) device's interrupt parent is probed (assigned IRQ base Y)
> > 	7) device is probed, gets assigned IRQ (Y + z)
> > 
> > So not only do we have to track which resources are interrupt resources,
> > but we also need to have them reassigned everytime the device is probed,
> > therefore interrupt mappings need to be properly disposed and the values
> > invalidated when probing is deferred or the device removed.
> 
> Yes, that is a problem, but the only way to handle that is to always
> recalcuate all resource references at probe time. I don't feel good
> about handling that in the core. I'd rather move drivers away from
> referencing the resources table directly and instead use an API. Then
> the resources table could be missing entirely.

Are you suggesting something like this?

---

Comments

Grant Likely Dec. 11, 2013, 1:45 p.m. UTC | #1
On Thu, 28 Nov 2013 16:46:23 +0100, Thierry Reding <thierry.reding@gmail.com> wrote:
> On Wed, Nov 27, 2013 at 03:56:29PM +0000, Grant Likely wrote:
> > On Mon, 25 Nov 2013 10:49:55 +0100, Thierry Reding <thierry.reding@gmail.com> wrote:
> > > 
> > > I should maybe add: one issue that was raised during review of my
> > > initial patch series was that we'll also need to cope with situations
> > > like the following:
> > > 
> > > 	1) device's interrupt parent is probed (assigned IRQ base X)
> > > 	2) device is probed (interrupt parent there, therefore gets
> > > 	   assigned IRQ (X + z)
> > > 	3) device in removed
> > > 	4) device's interrupt parent is removed
> > > 	5) device is probed (deferred because interrupt parent isn't
> > > 	   there)
> > > 	6) device's interrupt parent is probed (assigned IRQ base Y)
> > > 	7) device is probed, gets assigned IRQ (Y + z)
> > > 
> > > So not only do we have to track which resources are interrupt resources,
> > > but we also need to have them reassigned everytime the device is probed,
> > > therefore interrupt mappings need to be properly disposed and the values
> > > invalidated when probing is deferred or the device removed.
> > 
> > Yes, that is a problem, but the only way to handle that is to always
> > recalcuate all resource references at probe time. I don't feel good
> > about handling that in the core. I'd rather move drivers away from
> > referencing the resources table directly and instead use an API. Then
> > the resources table could be missing entirely.
> 
> Are you suggesting something like this?
> 
> ---
> 
> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> index 3a94b799f166..c894d1af3a5e 100644
> --- a/drivers/base/platform.c
> +++ b/drivers/base/platform.c
> @@ -13,6 +13,7 @@
>  #include <linux/string.h>
>  #include <linux/platform_device.h>
>  #include <linux/of_device.h>
> +#include <linux/of_irq.h>
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/dma-mapping.h>
> @@ -87,7 +88,12 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
>                 return -ENXIO;
>         return dev->archdata.irqs[num];
>  #else
> -       struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
> +       struct resource *r;
> +
> +       if (IS_ENABLED(CONFIG_OF) && dev->dev.of_node)
> +               return irq_of_parse_and_map(dev->dev.of_node, num);
> +
> +       r = platform_get_resource(dev, IORESOURCE_IRQ, num);

Yes. Or even more generically we could have a device_get_irq() function:

int device_get_irq(struct device *dev, unsigned int num)
{
	if (IS_ENABLED(CONFIG_OF) && dev->of_node)
		return irq_of_parse_and_map(dev->of_node, num);
	/* An ACPI hook could go here */
	return 0
}

It would be callable by any device driver, and platform_get_irq() could
call it too.

g.
Thierry Reding Dec. 11, 2013, 3:12 p.m. UTC | #2
On Wed, Dec 11, 2013 at 01:45:53PM +0000, Grant Likely wrote:
> On Thu, 28 Nov 2013 16:46:23 +0100, Thierry Reding <thierry.reding@gmail.com> wrote:
> > On Wed, Nov 27, 2013 at 03:56:29PM +0000, Grant Likely wrote:
> > > On Mon, 25 Nov 2013 10:49:55 +0100, Thierry Reding <thierry.reding@gmail.com> wrote:
> > > > 
> > > > I should maybe add: one issue that was raised during review of my
> > > > initial patch series was that we'll also need to cope with situations
> > > > like the following:
> > > > 
> > > > 	1) device's interrupt parent is probed (assigned IRQ base X)
> > > > 	2) device is probed (interrupt parent there, therefore gets
> > > > 	   assigned IRQ (X + z)
> > > > 	3) device in removed
> > > > 	4) device's interrupt parent is removed
> > > > 	5) device is probed (deferred because interrupt parent isn't
> > > > 	   there)
> > > > 	6) device's interrupt parent is probed (assigned IRQ base Y)
> > > > 	7) device is probed, gets assigned IRQ (Y + z)
> > > > 
> > > > So not only do we have to track which resources are interrupt resources,
> > > > but we also need to have them reassigned everytime the device is probed,
> > > > therefore interrupt mappings need to be properly disposed and the values
> > > > invalidated when probing is deferred or the device removed.
> > > 
> > > Yes, that is a problem, but the only way to handle that is to always
> > > recalcuate all resource references at probe time. I don't feel good
> > > about handling that in the core. I'd rather move drivers away from
> > > referencing the resources table directly and instead use an API. Then
> > > the resources table could be missing entirely.
> > 
> > Are you suggesting something like this?
> > 
> > ---
> > 
> > diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> > index 3a94b799f166..c894d1af3a5e 100644
> > --- a/drivers/base/platform.c
> > +++ b/drivers/base/platform.c
> > @@ -13,6 +13,7 @@
> >  #include <linux/string.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/of_device.h>
> > +#include <linux/of_irq.h>
> >  #include <linux/module.h>
> >  #include <linux/init.h>
> >  #include <linux/dma-mapping.h>
> > @@ -87,7 +88,12 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
> >                 return -ENXIO;
> >         return dev->archdata.irqs[num];
> >  #else
> > -       struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
> > +       struct resource *r;
> > +
> > +       if (IS_ENABLED(CONFIG_OF) && dev->dev.of_node)
> > +               return irq_of_parse_and_map(dev->dev.of_node, num);
> > +
> > +       r = platform_get_resource(dev, IORESOURCE_IRQ, num);
> 
> Yes. Or even more generically we could have a device_get_irq() function:
> 
> int device_get_irq(struct device *dev, unsigned int num)
> {
> 	if (IS_ENABLED(CONFIG_OF) && dev->of_node)
> 		return irq_of_parse_and_map(dev->of_node, num);
> 	/* An ACPI hook could go here */
> 	return 0
> }
> 
> It would be callable by any device driver, and platform_get_irq() could
> call it too.

So how about we make the platform_get_irq() modification for starters,
so that the OMAP issues can be resolved and then turn our attention to
coming up with a more generic approach. If indeed we end up with what
you're proposing we can easily switch platform_get_irq() to use it.

One of the things I'm not so sure about is how to handle other types of
resources, since they'll be somewhat more specific to the type of
device. That's true also for devices other than platform devices. Let's
look at I2C devices for instance. The way to get at the IRQ number is
via the i2c_client->irq member.

device_get_irq() breaks down at that point because unless you want to
add special cases for all sorts of devices you have no way of getting at
the data if it hasn't been instantiated from DT (or ACPI). Actually, all
devices instantiated from platform data will suffer from this if I'm not
mistaken.

If you're saying that the device_get_irq() API should only cover cases
where some sort of firmware interface exists such as DT or ACPI, then I
suppose it could be made to work and drivers could rely on the subsystem
specific locations as fallback. I guess for I2C drivers you'd have to do
something like this:

	err = device_get_irq(&client->dev, 0);
	if (err >= 0)
		client->irq = err;

And then continue to use client->irq as usual. That obviously has the
side-effect of having to do this for every single driver, whereas the
original patches were meant to solve this in the core.

Given enough time we could probably migrate everyone to the new
interfaces, but it certainly is a lot of churn. Perhaps another
alternative would be to unify this some more by making each subsystem
provide special hooks that device_get_irq() and friends can call for
fallback when none of the "firmware" functions were successful.

Thierry
Tony Lindgren Dec. 11, 2013, 4:43 p.m. UTC | #3
* Thierry Reding <thierry.reding@gmail.com> [131211 07:14]:
> 
> So how about we make the platform_get_irq() modification for starters,
> so that the OMAP issues can be resolved and then turn our attention to
> coming up with a more generic approach. If indeed we end up with what
> you're proposing we can easily switch platform_get_irq() to use it.

Yeah we should do the minimal fix for the $Subject bug for the -rc cycle
so I can fix the PM test regression fix for the few omap3 platforms
already made DT only.
 
> One of the things I'm not so sure about is how to handle other types of
> resources, since they'll be somewhat more specific to the type of
> device. That's true also for devices other than platform devices. Let's
> look at I2C devices for instance. The way to get at the IRQ number is
> via the i2c_client->irq member.

Yes. And BTW, there's also another related glitch where there's no easy
way to configure auxdata from arch/arm/mach code for some devices.

For example, consider something like this that's fairly common:

1. i2c bus driver configured with DT and can take board specific auxdata

2. i2c bus intializes connected devices as configured with DT but
   cannot pass board specific auxdata as the auxdata for the i2c bus
   is empty

3. i2c connected pmic driver intializes as configured with DT, but
   cannot get board specifc auxdata

So we should probably add some parent or master auxdata table that's
also checked if the bus specific auxdata table is empty.
 
> device_get_irq() breaks down at that point because unless you want to
> add special cases for all sorts of devices you have no way of getting at
> the data if it hasn't been instantiated from DT (or ACPI). Actually, all
> devices instantiated from platform data will suffer from this if I'm not
> mistaken.
> 
> If you're saying that the device_get_irq() API should only cover cases
> where some sort of firmware interface exists such as DT or ACPI, then I
> suppose it could be made to work and drivers could rely on the subsystem
> specific locations as fallback. I guess for I2C drivers you'd have to do
> something like this:
> 
> 	err = device_get_irq(&client->dev, 0);
> 	if (err >= 0)
> 		client->irq = err;
> 
> And then continue to use client->irq as usual. That obviously has the
> side-effect of having to do this for every single driver, whereas the
> original patches were meant to solve this in the core.
> 
> Given enough time we could probably migrate everyone to the new
> interfaces, but it certainly is a lot of churn. Perhaps another
> alternative would be to unify this some more by making each subsystem
> provide special hooks that device_get_irq() and friends can call for
> fallback when none of the "firmware" functions were successful.

Ideally of course we'd have Linux generic way of doing this that works
for platform data, DT and ACPI without changing the existing interfaces :)

Regards,

Tony
diff mbox

Patch

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 3a94b799f166..c894d1af3a5e 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -13,6 +13,7 @@ 
 #include <linux/string.h>
 #include <linux/platform_device.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
@@ -87,7 +88,12 @@  int platform_get_irq(struct platform_device *dev, unsigned int num)
                return -ENXIO;
        return dev->archdata.irqs[num];
 #else
-       struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
+       struct resource *r;
+
+       if (IS_ENABLED(CONFIG_OF) && dev->dev.of_node)
+               return irq_of_parse_and_map(dev->dev.of_node, num);
+
+       r = platform_get_resource(dev, IORESOURCE_IRQ, num);
 
        return r ? r->start : -ENXIO;
 #endif