[U-Boot] [RFC PATCH] dm: ensure device names are unique

Joe Hershberger joe.hershberger at gmail.com
Thu Apr 28 06:42:47 CEST 2016


On Tue, Apr 26, 2016 at 4:30 PM, Stephen Warren <swarren at wwwdotorg.org> wrote:
> From: Stephen Warren <swarren at nvidia.com>
>
> It is possible for HW to contain multiple instances of the same device. In
> this case, the name passed to device_bind() may not be unique across all
> devices within its uclass. One example is a system with multiple identical
> PCI Ethernet devices. Another might be a system with multiple identical
> I2C GPIO expanders, each connected to a separate I2C bus, yet using the
> same I2C address on that bus and hence having the same DT node name.
>
> Enhance the code to detect this situation, and append a sequence number so
> the device name to ensure uniqueness.
>
> Signed-off-by: Stephen Warren <swarren at nvidia.com>
> ---
> Some possible issues with this patch:
>
> 1) Doing this in bind() rather than probe() means dev->seq isn't
> available, so can't be used to generate the unique name. This process
> should be done during bind() rather than probe() though, since devices can
> be seen (e.g. by running "dm tree") before they're probed. Perhaps the
> uclass_resolve_seq() should be called by bind() not probe().

We (Simon and I) had discussion about this when I first added support
for eth devices. He convinced me the correct time for seq to be
evaluated is at probe time. I can dig through the mail history for
reasons if you're interested.

> 2) uclass_find_device_by_name() needs to look up the uclass pointer again
> even though device_bind() already knows it.

Maybe we could add a parameter to provide the pointer and if it's
NULL, then it gets looked up. Might be a bit noisy change, though. Is
that optimization very valuable?

> 3) Iterating over the list to find the count of devices in the uclass is a
> bit annoying. Should the uclass maintain this count so it doesn't need to
> be re-calculated each time?

These lists aren't long, right? It seems like the optimization to
store the value is only helpful if the lists could be expected to be
long, or the size is looked up many times.

>  drivers/core/device-remove.c |  4 ++++
>  drivers/core/device.c        | 23 ++++++++++++++++++++++-
>  include/dm/device.h          |  3 +++
>  3 files changed, 29 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
> index e1714b2202b6..a2400989024a 100644
> --- a/drivers/core/device-remove.c
> +++ b/drivers/core/device-remove.c
> @@ -112,6 +112,10 @@ int device_unbind(struct udevice *dev)
>
>         devres_release_all(dev);
>
> +       if (dev->flags & DM_FLAG_ALLOC_NAME) {
> +               free((char *)dev->name);
> +               dev->name = NULL;
> +       }
>         free(dev);
>
>         return 0;
> diff --git a/drivers/core/device.c b/drivers/core/device.c
> index 269087a084cf..fcac0073c642 100644
> --- a/drivers/core/device.c
> +++ b/drivers/core/device.c
> @@ -30,7 +30,7 @@ int device_bind(struct udevice *parent, const struct driver *drv,
>                 const char *name, void *platdata, int of_offset,
>                 struct udevice **devp)
>  {
> -       struct udevice *dev;
> +       struct udevice *dev, *dev2;
>         struct uclass *uc;
>         int size, ret = 0;
>
> @@ -62,6 +62,23 @@ int device_bind(struct udevice *parent, const struct driver *drv,
>         dev->driver = drv;
>         dev->uclass = uc;
>
> +       if (!uclass_find_device_by_name(uc->uc_drv->id, dev->name, &dev2)) {
> +               char *unique_name;
> +               int count;
> +               size = strlen(name) + 4 + 1;
> +               unique_name = malloc(size);
> +               if (!unique_name) {
> +                       ret = -ENOMEM;
> +                       goto fail_alloc1;
> +               }
> +               dev->flags |= DM_FLAG_ALLOC_NAME;
> +               dev->name = unique_name;
> +               count = 0;
> +               list_for_each_entry(dev2, &uc->dev_head, uclass_node)
> +                       count++;
> +               snprintf(unique_name, size, "%s.%d", name, count);
> +       }
> +
>         dev->seq = -1;
>         dev->req_seq = -1;
>         if (CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DM_SEQ_ALIAS)) {
> @@ -186,6 +203,10 @@ fail_alloc2:
>                 dev->platdata = NULL;
>         }
>  fail_alloc1:
> +       if (dev->flags & DM_FLAG_ALLOC_NAME) {
> +               free((char *)dev->name);
> +               dev->name = NULL;
> +       }
>         devres_release_all(dev);
>
>         free(dev);
> diff --git a/include/dm/device.h b/include/dm/device.h
> index dad7591dfacb..976ba72a550c 100644
> --- a/include/dm/device.h
> +++ b/include/dm/device.h
> @@ -41,6 +41,9 @@ struct driver_info;
>  /* Device is bound */
>  #define DM_FLAG_BOUND                  (1 << 6)
>
> +/* DM is responsible for allocating and freeing device name */
> +#define DM_FLAG_ALLOC_NAME             (1 << 7)
> +
>  /**
>   * struct udevice - An instance of a driver
>   *
> --
> 2.8.1
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot


More information about the U-Boot mailing list