diff mbox

[v3,2/2] dt: platform driver: Fill the resources before probe and defer if needed

Message ID 1395413185-29763-3-git-send-email-jjhiblot@traphandler.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jean-Jacques Hiblot March 21, 2014, 2:46 p.m. UTC
The goal of this patch is to allow drivers to be probed even if at the time of
the DT parsing some of their IRQ ressources are not available yet.

In the current situation, the IRQ resources of a platform device are filled from
the DT at the time the device is created (of_device_alloc()). The drawback of
this is that a device sitting close to the top of the DT (ahb for example) but
depending on ressources that are initialized later (IRQ domain dynamically
created for example) will fail to probe because the ressources don't exist
at this time.

This patch fills the resource structure only before the device is probed and
will defer the probe if the IRQ resource is not yet available.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
---
 drivers/base/platform.c     |   5 ++
 drivers/of/platform.c       | 114 ++++++++++++++++++++++++++++++++++----------
 include/linux/device.h      |   1 +
 include/linux/of_platform.h |  10 ++++
 4 files changed, 105 insertions(+), 25 deletions(-)

Comments

Rob Herring April 11, 2014, 5:28 p.m. UTC | #1
On Fri, Mar 21, 2014 at 9:46 AM, Jean-Jacques Hiblot
<jjhiblot@traphandler.com> wrote:
> The goal of this patch is to allow drivers to be probed even if at the time of
> the DT parsing some of their IRQ ressources are not available yet.
>
> In the current situation, the IRQ resources of a platform device are filled from
> the DT at the time the device is created (of_device_alloc()). The drawback of
> this is that a device sitting close to the top of the DT (ahb for example) but
> depending on ressources that are initialized later (IRQ domain dynamically
> created for example) will fail to probe because the ressources don't exist
> at this time.

s/ressources/resources/

>
> This patch fills the resource structure only before the device is probed and
> will defer the probe if the IRQ resource is not yet available.
>
> Signed-off-by: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
> ---
>  drivers/base/platform.c     |   5 ++
>  drivers/of/platform.c       | 114 ++++++++++++++++++++++++++++++++++----------
>  include/linux/device.h      |   1 +
>  include/linux/of_platform.h |  10 ++++
>  4 files changed, 105 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> index bc78848..cee9b8d 100644
> --- a/drivers/base/platform.c
> +++ b/drivers/base/platform.c
> @@ -481,6 +481,10 @@ static int platform_drv_probe(struct device *_dev)
>         struct platform_device *dev = to_platform_device(_dev);
>         int ret;
>
> +       ret = of_platform_device_prepare(dev);
> +       if (ret)
> +               goto error;
> +
>         if (ACPI_HANDLE(_dev))
>                 acpi_dev_pm_attach(_dev, true);
>
> @@ -488,6 +492,7 @@ static int platform_drv_probe(struct device *_dev)
>         if (ret && ACPI_HANDLE(_dev))
>                 acpi_dev_pm_detach(_dev, true);
>
> +error:
>         if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
>                 dev_warn(_dev, "probe deferral not supported\n");
>                 ret = -ENXIO;
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index 404d1da..ba6be4a 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -141,41 +141,17 @@ struct platform_device *of_device_alloc(struct device_node *np,
>                                   struct device *parent)
>  {
>         struct platform_device *dev;
> -       int rc, i, num_reg = 0, num_irq;
> -       struct resource *res, temp_res;
>
>         dev = platform_device_alloc("", -1);
>         if (!dev)
>                 return NULL;
>
> -       /* count the io and irq resources */
> -       if (of_can_translate_address(np))
> -               while (of_address_to_resource(np, num_reg, &temp_res) == 0)
> -                       num_reg++;
> -       num_irq = of_irq_count(np);
> -
> -       /* Populate the resource table */
> -       if (num_irq || num_reg) {
> -               res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
> -               if (!res) {
> -                       platform_device_put(dev);
> -                       return NULL;
> -               }
> -
> -               dev->num_resources = num_reg + num_irq;
> -               dev->resource = res;
> -               for (i = 0; i < num_reg; i++, res++) {
> -                       rc = of_address_to_resource(np, i, res);
> -                       WARN_ON(rc);
> -               }
> -               WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq);
> -       }
> -
>         dev->dev.of_node = of_node_get(np);
>  #if defined(CONFIG_MICROBLAZE)
>         dev->dev.dma_mask = &dev->archdata.dma_mask;
>  #endif
>         dev->dev.parent = parent;
> +       dev->dev.of_device = 1;
>
>         if (bus_id)
>                 dev_set_name(&dev->dev, "%s", bus_id);
> @@ -233,6 +209,94 @@ static struct platform_device *of_platform_device_create_pdata(
>         return dev;
>  }
>
> +static int of_reg_count(struct device_node *np)

This belongs in of/address.c. It can be more efficiently written as:

int of_reg_count(struct device_node *dev)
{
const __be32 *prop;
unsigned int psize;
struct device_node *parent;
struct of_bus *bus;
int na, ns;

/* Get parent & match bus type */
parent = of_get_parent(dev);
if (!parent)
  return 0;
bus = of_match_bus(parent);
bus->count_cells(dev, &na, &ns);
of_node_put(parent);
if (!OF_CHECK_COUNTS(na, ns))
  return 0;

/* Get "reg" or "assigned-addresses" property */
prop = of_get_property(dev, bus->addresses, &psize);
if (!prop)
  return 0;
psize /= 4;

return psize / (na + ns);
}


> +{
> +       int nreg = 0;
> +       if (of_can_translate_address(np)) {
> +               struct resource temp_res;
> +               while (of_address_to_resource(np, nreg, &temp_res) == 0)
> +                       nreg++;
> +       }
> +       return nreg;
> +}
> +
> +int of_platform_device_prepare(struct platform_device *dev)
> +{
> +       struct device_node *np;
> +       int i, irq_index;
> +       struct resource *res;
> +
> +       /*
> +        * This function applies only devices described in the DT and
> +        * created by of_device_alloc().
> +        * Other platform devices have their ressources already populated.
> +        */
> +       np = dev->dev.of_node;
> +       if (!np || !dev->dev.of_device)
> +               return 0;
> +
> +       /* Populate the resource table */
> +       if (!dev->resource) {
> +               int rc, nreg = 0, nirq;
> +               /* count the io and irq resources */
> +               nreg = of_reg_count(np);
> +               nirq = of_irq_count(np);

I think of_irq_count should be changed to return errors from
of_irq_parse_one. It's complicated by the fact you want to distinguish
checking the index is too big versus all other errors.

> +
> +               if (!nirq && !nreg)
> +                       return 0;
> +
> +               res = kzalloc(sizeof(*res) * (nirq + nreg), GFP_KERNEL);
> +               if (!res)
> +                       return -ENOMEM;
> +
> +               dev->resource = res;
> +               dev->num_resources = nreg + nirq;
> +
> +               for (i = 0; i < nreg; i++, res++) {
> +                       rc = of_address_to_resource(np, i, res);
> +                       if (WARN_ON(rc)) {
> +                               /* THIS IS BAD; don't try to defer probing */
> +                               dev->num_resources = 0;
> +                               dev->resource = NULL;
> +                               kfree(res);

You are incrementing res, so this kfree is wrong. Using "res + i"
instead would work, but...

> +                               return rc;
> +                       }
> +               }
> +
> +               if (!rc && of_irq_to_resource_table(np, res, nirq) != nirq)

...then res needs to change here.

Doesn't this give a rc may not be initialized warning? You don't need
to check rc. You need to check !nirq instead.

> +                       /*
> +                        * Not all irqs can be translated. redo the irq
> +                        * resources to check if the probe can be deferred
> +                        */
> +                       goto redo_irq_resources;
> +
> +               return 0;

But then, you don't really need any of this. You can just fall-thru
and the code below will work.

> +       }
> +
> +redo_irq_resources:
> +       /* See which IRQ resources need to be redone */
> +       irq_index = 0;
> +       for (i = 0, res = dev->resource; i < dev->num_resources; i++, res++) {
> +               if (!res->flags) {
> +                       int rc;
> +                       /*
> +                        * If the IRQ can't be translated to a resource, check
> +                        * if its IRQ domain exists.
> +                        */
> +                       rc = of_irq_to_resource(np, irq_index, res);
> +                       if (!rc) {
> +                               if (of_find_irq_domain(np, irq_index) == NULL)
> +                                       return -EPROBE_DEFER;
> +                               return rc;
> +                       }

I would move this check into of_irq_to_resource_table and also make it
skip entries with IORESOURCE_IRQ set. Then this can become:

for (i = 0, res = dev->resource; i < dev->num_resources; i++, res++) {
  if (resource_type(res) != IORESOURCE_MEM)
    break;
}
rc = of_irq_to_resource_table(np, res, dev->num_resources - i);
return (rc < 0) ? rc : 0;


Rob
Tony Lindgren April 18, 2014, 8:52 p.m. UTC | #2
* Rob Herring <robherring2@gmail.com> [140411 10:33]:
> On Fri, Mar 21, 2014 at 9:46 AM, Jean-Jacques Hiblot
> <jjhiblot@traphandler.com> wrote:
> > The goal of this patch is to allow drivers to be probed even if at the time of
> > the DT parsing some of their IRQ ressources are not available yet.
> >
> > In the current situation, the IRQ resources of a platform device are filled from
> > the DT at the time the device is created (of_device_alloc()). The drawback of
> > this is that a device sitting close to the top of the DT (ahb for example) but
> > depending on ressources that are initialized later (IRQ domain dynamically
> > created for example) will fail to probe because the ressources don't exist
> > at this time.
> 
> s/ressources/resources/

While I've tested these two patches and they fix the issue for me. I have
some serious doubts again about this whole ------ up string parsing
pile of ---- called device tree.

Do we really need to sprinkle more of_* hacks to the irq subsystem?

There's nothing wrong with with the irq subsystem. Platform bus is just
calling the irq subsystem at the wrong time with uninitialized data.

It seems that we're again papering over the fact that there's nothing
coordinating the setting up of various resources with device tree.
That seems to be the repeating never ending pattern as we've already
seen with GPIOs, pinctrl, and IRQchips. We end up adding all kinds of
cross subsystem calls that were never needed earlier.

Regards,

Tony
Rob Herring April 18, 2014, 9:39 p.m. UTC | #3
On Fri, Apr 18, 2014 at 3:52 PM, Tony Lindgren <tony@atomide.com> wrote:
> * Rob Herring <robherring2@gmail.com> [140411 10:33]:
>> On Fri, Mar 21, 2014 at 9:46 AM, Jean-Jacques Hiblot
>> <jjhiblot@traphandler.com> wrote:
>> > The goal of this patch is to allow drivers to be probed even if at the time of
>> > the DT parsing some of their IRQ ressources are not available yet.
>> >
>> > In the current situation, the IRQ resources of a platform device are filled from
>> > the DT at the time the device is created (of_device_alloc()). The drawback of
>> > this is that a device sitting close to the top of the DT (ahb for example) but
>> > depending on ressources that are initialized later (IRQ domain dynamically
>> > created for example) will fail to probe because the ressources don't exist
>> > at this time.
>>
>> s/ressources/resources/
>
> While I've tested these two patches and they fix the issue for me. I have
> some serious doubts again about this whole ------ up string parsing
> pile of ---- called device tree.
>
> Do we really need to sprinkle more of_* hacks to the irq subsystem?
>
> There's nothing wrong with with the irq subsystem. Platform bus is just
> calling the irq subsystem at the wrong time with uninitialized data.

This patch doesn't even touch the irq subsystem.

> It seems that we're again papering over the fact that there's nothing
> coordinating the setting up of various resources with device tree.
> That seems to be the repeating never ending pattern as we've already
> seen with GPIOs, pinctrl, and IRQchips. We end up adding all kinds of
> cross subsystem calls that were never needed earlier.

This problem may be made worse with DT, but this problem has existed
for as long as I have worked on the kernel. It is worse with DT since
platforms have less control over the init ordering and loose some
ability to do tricks like changing the initcall levels. We didn't even
try to do pinctrl in any generic way before DT.

Rob
Tony Lindgren April 18, 2014, 9:58 p.m. UTC | #4
* Rob Herring <robherring2@gmail.com> [140418 14:39]:
> On Fri, Apr 18, 2014 at 3:52 PM, Tony Lindgren <tony@atomide.com> wrote:
> > * Rob Herring <robherring2@gmail.com> [140411 10:33]:
> >> On Fri, Mar 21, 2014 at 9:46 AM, Jean-Jacques Hiblot
> >> <jjhiblot@traphandler.com> wrote:
> >> > The goal of this patch is to allow drivers to be probed even if at the time of
> >> > the DT parsing some of their IRQ ressources are not available yet.
> >> >
> >> > In the current situation, the IRQ resources of a platform device are filled from
> >> > the DT at the time the device is created (of_device_alloc()). The drawback of
> >> > this is that a device sitting close to the top of the DT (ahb for example) but
> >> > depending on ressources that are initialized later (IRQ domain dynamically
> >> > created for example) will fail to probe because the ressources don't exist
> >> > at this time.
> >>
> >> s/ressources/resources/
> >
> > While I've tested these two patches and they fix the issue for me. I have
> > some serious doubts again about this whole ------ up string parsing
> > pile of ---- called device tree.
> >
> > Do we really need to sprinkle more of_* hacks to the irq subsystem?
> >
> > There's nothing wrong with with the irq subsystem. Platform bus is just
> > calling the irq subsystem at the wrong time with uninitialized data.
> 
> This patch doesn't even touch the irq subsystem.

Heh, it depends on the previous patch in this series adding another
of_blah_blah function to drivers/of/irq.c.
 
> > It seems that we're again papering over the fact that there's nothing
> > coordinating the setting up of various resources with device tree.
> > That seems to be the repeating never ending pattern as we've already
> > seen with GPIOs, pinctrl, and IRQchips. We end up adding all kinds of
> > cross subsystem calls that were never needed earlier.
> 
> This problem may be made worse with DT, but this problem has existed
> for as long as I have worked on the kernel. It is worse with DT since
> platforms have less control over the init ordering and loose some
> ability to do tricks like changing the initcall levels. We didn't even
> try to do pinctrl in any generic way before DT.

Oh come on, let's stop pretending it's not broken. And it's way worse with
device tree as there's nothing making sure the resources for a driver
are set up before the driver probes. And we've been unable to fix just
this issue alone for about six months now. It's also broken beyond that.
It's called of_platform_bus yet it won't even pass the platform_data
as auxdata to the devices on a sub-bus instantatiated like I2C.

Regards,

Tony
Russell King - ARM Linux April 18, 2014, 11:03 p.m. UTC | #5
On Fri, Apr 18, 2014 at 02:58:48PM -0700, Tony Lindgren wrote:
> Oh come on, let's stop pretending it's not broken. And it's way worse with
> device tree as there's nothing making sure the resources for a driver
> are set up before the driver probes. And we've been unable to fix just
> this issue alone for about six months now. It's also broken beyond that.
> It's called of_platform_bus yet it won't even pass the platform_data
> as auxdata to the devices on a sub-bus instantatiated like I2C.

Isn't there a much simpler solution to the platform device IRQ problem?

Rather than trying to fix it at the point where the resources are
created, why not just *not* have DT create the IRQ resources in the
first place, and instead have platform_get_irq() (which is the function
which should be used to get an IRQ) be the actor to do whatever is
necessary to return the IRQ(s) ?

Yes, I know we have some drivers which use platform_get_resources() with
IORESOURCE_IRQ, but they should really use the right accessor.  And those
who just dereference the resource array directly... get what's coming
(though of course they have to be fixed.)

It has the benefit that you're in a path where you /can/ return
-EPROBE_DEFER too and not have to mess around with notifiers or other
silly stuff like that.
Tony Lindgren April 18, 2014, 11:24 p.m. UTC | #6
* Russell King - ARM Linux <linux@arm.linux.org.uk> [140418 16:04]:
> On Fri, Apr 18, 2014 at 02:58:48PM -0700, Tony Lindgren wrote:
> > Oh come on, let's stop pretending it's not broken. And it's way worse with
> > device tree as there's nothing making sure the resources for a driver
> > are set up before the driver probes. And we've been unable to fix just
> > this issue alone for about six months now. It's also broken beyond that.
> > It's called of_platform_bus yet it won't even pass the platform_data
> > as auxdata to the devices on a sub-bus instantatiated like I2C.
> 
> Isn't there a much simpler solution to the platform device IRQ problem?
> 
> Rather than trying to fix it at the point where the resources are
> created, why not just *not* have DT create the IRQ resources in the
> first place, and instead have platform_get_irq() (which is the function
> which should be used to get an IRQ) be the actor to do whatever is
> necessary to return the IRQ(s) ?

Yeah why not. I don't see why we would need to do all this of_* special
trickery for much anything beyond parsing the binding.
 
> Yes, I know we have some drivers which use platform_get_resources() with
> IORESOURCE_IRQ, but they should really use the right accessor.  And those
> who just dereference the resource array directly... get what's coming
> (though of course they have to be fixed.)

$ git grep IORESOURCE_IRQ drivers/ | grep platform_get_resource | wc -l
179

But might be scriptable to some extent..
 
> It has the benefit that you're in a path where you /can/ return
> -EPROBE_DEFER too and not have to mess around with notifiers or other
> silly stuff like that.

And then maybe we can make of_platform_probe() or some bus function
do the most of the -EPROBE_DEFER ping pong before the driver even
probes?

Regards,

Tony
Rob Herring April 21, 2014, 1:47 p.m. UTC | #7
On Fri, Apr 18, 2014 at 6:24 PM, Tony Lindgren <tony@atomide.com> wrote:
> * Russell King - ARM Linux <linux@arm.linux.org.uk> [140418 16:04]:
>> On Fri, Apr 18, 2014 at 02:58:48PM -0700, Tony Lindgren wrote:
>> > Oh come on, let's stop pretending it's not broken. And it's way worse with
>> > device tree as there's nothing making sure the resources for a driver
>> > are set up before the driver probes. And we've been unable to fix just
>> > this issue alone for about six months now. It's also broken beyond that.
>> > It's called of_platform_bus yet it won't even pass the platform_data
>> > as auxdata to the devices on a sub-bus instantatiated like I2C.
>>
>> Isn't there a much simpler solution to the platform device IRQ problem?
>>
>> Rather than trying to fix it at the point where the resources are
>> created, why not just *not* have DT create the IRQ resources in the
>> first place, and instead have platform_get_irq() (which is the function
>> which should be used to get an IRQ) be the actor to do whatever is
>> necessary to return the IRQ(s) ?
>
> Yeah why not. I don't see why we would need to do all this of_* special
> trickery for much anything beyond parsing the binding.

That can work, but it will still need something like
of_find_irq_domain() to determine whether to return -EPROBE_DEFER or
not.

You could also go in the other direction and don't create the device
until the resources can be resolved. Unlike any of the other
solutions, that would work for amba bus as well although we may never
have a case where we need this with the amba bus. This would require
making of_platform_populate be callable multiple times, but there are
already some other reasons for wanting to do that. Specifically, I
would like the core code to call of_platform_populate with default
options and then only platforms with non-default options need a call
to of_platform_populate.


>> Yes, I know we have some drivers which use platform_get_resources() with
>> IORESOURCE_IRQ, but they should really use the right accessor.  And those
>> who just dereference the resource array directly... get what's coming
>> (though of course they have to be fixed.)
>
> $ git grep IORESOURCE_IRQ drivers/ | grep platform_get_resource | wc -l
> 179

Certainly, this is worthwhile clean-up no matter what the solution.

Rob
Tony Lindgren April 21, 2014, 3:54 p.m. UTC | #8
* Rob Herring <robherring2@gmail.com> [140421 06:47]:
> On Fri, Apr 18, 2014 at 6:24 PM, Tony Lindgren <tony@atomide.com> wrote:
> > * Russell King - ARM Linux <linux@arm.linux.org.uk> [140418 16:04]:
> >> On Fri, Apr 18, 2014 at 02:58:48PM -0700, Tony Lindgren wrote:
> >> > Oh come on, let's stop pretending it's not broken. And it's way worse with
> >> > device tree as there's nothing making sure the resources for a driver
> >> > are set up before the driver probes. And we've been unable to fix just
> >> > this issue alone for about six months now. It's also broken beyond that.
> >> > It's called of_platform_bus yet it won't even pass the platform_data
> >> > as auxdata to the devices on a sub-bus instantatiated like I2C.
> >>
> >> Isn't there a much simpler solution to the platform device IRQ problem?
> >>
> >> Rather than trying to fix it at the point where the resources are
> >> created, why not just *not* have DT create the IRQ resources in the
> >> first place, and instead have platform_get_irq() (which is the function
> >> which should be used to get an IRQ) be the actor to do whatever is
> >> necessary to return the IRQ(s) ?
> >
> > Yeah why not. I don't see why we would need to do all this of_* special
> > trickery for much anything beyond parsing the binding.
> 
> That can work, but it will still need something like
> of_find_irq_domain() to determine whether to return -EPROBE_DEFER or
> not.

Right. Naturally let's do whatever it takes to first fix this issue
in a minimal way first for the -rc cycle so we can do the longer term
changes needed.
 
> You could also go in the other direction and don't create the device
> until the resources can be resolved. Unlike any of the other
> solutions, that would work for amba bus as well although we may never
> have a case where we need this with the amba bus. This would require
> making of_platform_populate be callable multiple times, but there are
> already some other reasons for wanting to do that. Specifically, I
> would like the core code to call of_platform_populate with default
> options and then only platforms with non-default options need a call
> to of_platform_populate.

I like this idea as this would also probably remove the the numerous
dmesg errors we are currently getting for drivers reprobing with
-EPROBE_DEFER.

In the long term we should have platform bus just call a set of
standardized functions implemented by whatever the data source might
be. That way we can limit the use of of_* functions in device drivers
to just parsing of custom bindings in the drivers and use bus specific
functions for everything else.

> >> Yes, I know we have some drivers which use platform_get_resources() with
> >> IORESOURCE_IRQ, but they should really use the right accessor.  And those
> >> who just dereference the resource array directly... get what's coming
> >> (though of course they have to be fixed.)
> >
> > $ git grep IORESOURCE_IRQ drivers/ | grep platform_get_resource | wc -l
> > 179
> 
> Certainly, this is worthwhile clean-up no matter what the solution.

Yeah agreed. But let's also consider the IORESOURCE_IRQ as just another
source for for the bus or driver data in addition to the DT parsed data.
Both sources of data should work just fine with platform_bus even
without cleaning up the drivers.

Regards,

Tony
Grant Likely April 23, 2014, 3:02 p.m. UTC | #9
On Mon, 21 Apr 2014 08:47:41 -0500, Rob Herring <robherring2@gmail.com> wrote:
> On Fri, Apr 18, 2014 at 6:24 PM, Tony Lindgren <tony@atomide.com> wrote:
> > * Russell King - ARM Linux <linux@arm.linux.org.uk> [140418 16:04]:
> >> On Fri, Apr 18, 2014 at 02:58:48PM -0700, Tony Lindgren wrote:
> >> > Oh come on, let's stop pretending it's not broken. And it's way worse with
> >> > device tree as there's nothing making sure the resources for a driver
> >> > are set up before the driver probes. And we've been unable to fix just
> >> > this issue alone for about six months now. It's also broken beyond that.
> >> > It's called of_platform_bus yet it won't even pass the platform_data
> >> > as auxdata to the devices on a sub-bus instantatiated like I2C.
> >>
> >> Isn't there a much simpler solution to the platform device IRQ problem?
> >>
> >> Rather than trying to fix it at the point where the resources are
> >> created, why not just *not* have DT create the IRQ resources in the
> >> first place, and instead have platform_get_irq() (which is the function
> >> which should be used to get an IRQ) be the actor to do whatever is
> >> necessary to return the IRQ(s) ?
> >
> > Yeah why not. I don't see why we would need to do all this of_* special
> > trickery for much anything beyond parsing the binding.
> 
> That can work, but it will still need something like
> of_find_irq_domain() to determine whether to return -EPROBE_DEFER or
> not.
> 
> You could also go in the other direction and don't create the device
> until the resources can be resolved. Unlike any of the other
> solutions, that would work for amba bus as well although we may never
> have a case where we need this with the amba bus. This would require
> making of_platform_populate be callable multiple times, but there are
> already some other reasons for wanting to do that. Specifically, I
> would like the core code to call of_platform_populate with default
> options and then only platforms with non-default options need a call
> to of_platform_populate.

No it wouldn't. It would require of_platform_populate to do the right
thing internally and know when to create devices from nodes that get
flagged by calling of_platform_populate().

> >> Yes, I know we have some drivers which use platform_get_resources() with
> >> IORESOURCE_IRQ, but they should really use the right accessor.  And those
> >> who just dereference the resource array directly... get what's coming
> >> (though of course they have to be fixed.)
> >
> > $ git grep IORESOURCE_IRQ drivers/ | grep platform_get_resource | wc -l
> > 179
> 
> Certainly, this is worthwhile clean-up no matter what the solution.

Yes, and it works no matter what the data source is; platform_data, dt,
acpi, and works on any platform.

g.
diff mbox

Patch

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index bc78848..cee9b8d 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -481,6 +481,10 @@  static int platform_drv_probe(struct device *_dev)
 	struct platform_device *dev = to_platform_device(_dev);
 	int ret;
 
+	ret = of_platform_device_prepare(dev);
+	if (ret)
+		goto error;
+
 	if (ACPI_HANDLE(_dev))
 		acpi_dev_pm_attach(_dev, true);
 
@@ -488,6 +492,7 @@  static int platform_drv_probe(struct device *_dev)
 	if (ret && ACPI_HANDLE(_dev))
 		acpi_dev_pm_detach(_dev, true);
 
+error:
 	if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) {
 		dev_warn(_dev, "probe deferral not supported\n");
 		ret = -ENXIO;
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 404d1da..ba6be4a 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -141,41 +141,17 @@  struct platform_device *of_device_alloc(struct device_node *np,
 				  struct device *parent)
 {
 	struct platform_device *dev;
-	int rc, i, num_reg = 0, num_irq;
-	struct resource *res, temp_res;
 
 	dev = platform_device_alloc("", -1);
 	if (!dev)
 		return NULL;
 
-	/* count the io and irq resources */
-	if (of_can_translate_address(np))
-		while (of_address_to_resource(np, num_reg, &temp_res) == 0)
-			num_reg++;
-	num_irq = of_irq_count(np);
-
-	/* Populate the resource table */
-	if (num_irq || num_reg) {
-		res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
-		if (!res) {
-			platform_device_put(dev);
-			return NULL;
-		}
-
-		dev->num_resources = num_reg + num_irq;
-		dev->resource = res;
-		for (i = 0; i < num_reg; i++, res++) {
-			rc = of_address_to_resource(np, i, res);
-			WARN_ON(rc);
-		}
-		WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq);
-	}
-
 	dev->dev.of_node = of_node_get(np);
 #if defined(CONFIG_MICROBLAZE)
 	dev->dev.dma_mask = &dev->archdata.dma_mask;
 #endif
 	dev->dev.parent = parent;
+	dev->dev.of_device = 1;
 
 	if (bus_id)
 		dev_set_name(&dev->dev, "%s", bus_id);
@@ -233,6 +209,94 @@  static struct platform_device *of_platform_device_create_pdata(
 	return dev;
 }
 
+static int of_reg_count(struct device_node *np)
+{
+	int nreg = 0;
+	if (of_can_translate_address(np)) {
+		struct resource temp_res;
+		while (of_address_to_resource(np, nreg, &temp_res) == 0)
+			nreg++;
+	}
+	return nreg;
+}
+
+int of_platform_device_prepare(struct platform_device *dev)
+{
+	struct device_node *np;
+	int i, irq_index;
+	struct resource *res;
+
+	/*
+	 * This function applies only devices described in the DT and
+	 * created by of_device_alloc().
+	 * Other platform devices have their ressources already populated.
+	 */
+	np = dev->dev.of_node;
+	if (!np || !dev->dev.of_device)
+		return 0;
+
+	/* Populate the resource table */
+	if (!dev->resource) {
+		int rc, nreg = 0, nirq;
+		/* count the io and irq resources */
+		nreg = of_reg_count(np);
+		nirq = of_irq_count(np);
+
+		if (!nirq && !nreg)
+			return 0;
+
+		res = kzalloc(sizeof(*res) * (nirq + nreg), GFP_KERNEL);
+		if (!res)
+			return -ENOMEM;
+
+		dev->resource = res;
+		dev->num_resources = nreg + nirq;
+
+		for (i = 0; i < nreg; i++, res++) {
+			rc = of_address_to_resource(np, i, res);
+			if (WARN_ON(rc)) {
+				/* THIS IS BAD; don't try to defer probing */
+				dev->num_resources = 0;
+				dev->resource = NULL;
+				kfree(res);
+				return rc;
+			}
+		}
+
+		if (!rc && of_irq_to_resource_table(np, res, nirq) != nirq)
+			/*
+			 * Not all irqs can be translated. redo the irq
+			 * resources to check if the probe can be deferred
+			 */
+			goto redo_irq_resources;
+
+		return 0;
+	}
+
+redo_irq_resources:
+	/* See which IRQ resources need to be redone */
+	irq_index = 0;
+	for (i = 0, res = dev->resource; i < dev->num_resources; i++, res++) {
+		if (!res->flags) {
+			int rc;
+			/*
+			 * If the IRQ can't be translated to a resource, check
+			 * if its IRQ domain exists.
+			 */
+			rc = of_irq_to_resource(np, irq_index, res);
+			if (!rc) {
+				if (of_find_irq_domain(np, irq_index) == NULL)
+					return -EPROBE_DEFER;
+				return rc;
+			}
+			irq_index++;
+		} else if (res->flags & IORESOURCE_IRQ)
+			irq_index++;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(of_platform_device_prepare);
+
 /**
  * of_platform_device_create - Alloc, initialize and register an of_device
  * @np: pointer to node to create device for
diff --git a/include/linux/device.h b/include/linux/device.h
index 952b010..eb6ac66 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -785,6 +785,7 @@  struct device {
 
 	bool			offline_disabled:1;
 	bool			offline:1;
+	bool			of_device:1;
 };
 
 static inline struct device *kobj_to_dev(struct kobject *kobj)
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index 05cb4a9..4e487ff 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -53,6 +53,16 @@  struct of_dev_auxdata {
 
 extern const struct of_device_id of_default_bus_match_table[];
 
+/* Populate the resource for a platform device */
+#ifdef CONFIG_OF
+int of_platform_device_prepare(struct platform_device *dev);
+#else
+static inline int of_platform_device_prepare(
+	struct platform_device *dev)
+{
+	return 0;
+}
+#endif
 /* Platform drivers register/unregister */
 extern struct platform_device *of_device_alloc(struct device_node *np,
 					 const char *bus_id,