diff mbox series

[RFC] dm: uclass: add functions to get device by platdata

Message ID 20200304194006.30924-1-walter.lozano@collabora.com
State New
Headers show
Series [RFC] dm: uclass: add functions to get device by platdata | expand

Commit Message

Walter Lozano March 4, 2020, 7:40 p.m. UTC
When OF_PLATDATA is enabled DT information is parsed and platdata
structures are populated. In this context the links between DT nodes are
represented as pointers to platdata structures, and there is no clear way
to access to the device which owns the structure.

This patch implements a set of functions:

- device_find_by_platdata
- uclass_find_device_by_platdata

to access to the device.

Signed-off-by: Walter Lozano <walter.lozano at collabora.com>
---
 drivers/core/device.c        | 19 +++++++++++++++++++
 drivers/core/uclass.c        | 34 ++++++++++++++++++++++++++++++++++
 include/dm/device.h          |  2 ++
 include/dm/uclass-internal.h |  3 +++
 include/dm/uclass.h          |  2 ++
 5 files changed, 60 insertions(+)

Comments

Simon Glass March 4, 2020, 11:11 p.m. UTC | #1
Hi Walter,

On Wed, 4 Mar 2020 at 12:40, Walter Lozano <walter.lozano at collabora.com> wrote:
>
> When OF_PLATDATA is enabled DT information is parsed and platdata
> structures are populated. In this context the links between DT nodes are
> represented as pointers to platdata structures, and there is no clear way
> to access to the device which owns the structure.
>
> This patch implements a set of functions:
>
> - device_find_by_platdata
> - uclass_find_device_by_platdata
>
> to access to the device.
>
> Signed-off-by: Walter Lozano <walter.lozano at collabora.com>
> ---
>  drivers/core/device.c        | 19 +++++++++++++++++++
>  drivers/core/uclass.c        | 34 ++++++++++++++++++++++++++++++++++
>  include/dm/device.h          |  2 ++
>  include/dm/uclass-internal.h |  3 +++
>  include/dm/uclass.h          |  2 ++
>  5 files changed, 60 insertions(+)

This is interesting. Could you also add the motivation for this? It's
not clear to me who would call this function.

Also it relates to another thing I've been thinking about for a while,
which is to validate that all the structs pointed to are correct.

E.g. if every struct had a magic number like:

struct tpm_platdata {
    DM_STRUCT(UCLASS_TPM, DM_STRUCT_PLATDATA, ...)
    fields here
};

then we could check the structure pointers are correct.

DM_STRUCT() would define to nothing if we were not building with
CONFIG_DM_DEBUG or similar.

Anyway, I wonder whether you could expand your definition a bit so you
have an enum for the different types of struct you can request:

enum dm_struct_t {
   DM_STRUCT_PLATDATA,
 ...

   DM_STRUCT_COUNT,
};

and modify the function so it can request it via the enum?

Regards,
Simon
Walter Lozano March 5, 2020, 1:54 p.m. UTC | #2
Hi Simon,

Thanks for taking the time to check for my comments

On 4/3/20 20:11, Simon Glass wrote:

> Hi Walter,
>
> On Wed, 4 Mar 2020 at 12:40, Walter Lozano <walter.lozano at collabora.com> wrote:
>> When OF_PLATDATA is enabled DT information is parsed and platdata
>> structures are populated. In this context the links between DT nodes are
>> represented as pointers to platdata structures, and there is no clear way
>> to access to the device which owns the structure.
>>
>> This patch implements a set of functions:
>>
>> - device_find_by_platdata
>> - uclass_find_device_by_platdata
>>
>> to access to the device.
>>
>> Signed-off-by: Walter Lozano <walter.lozano at collabora.com>
>> ---
>>   drivers/core/device.c        | 19 +++++++++++++++++++
>>   drivers/core/uclass.c        | 34 ++++++++++++++++++++++++++++++++++
>>   include/dm/device.h          |  2 ++
>>   include/dm/uclass-internal.h |  3 +++
>>   include/dm/uclass.h          |  2 ++
>>   5 files changed, 60 insertions(+)
> This is interesting. Could you also add the motivation for this? It's
> not clear to me who would call this function.

I have been reviewing the OF_PLATDATA support as an R&D project, in this context, in order to have
a better understanding on the possibilities and limitations I decided to add its support to iMX6,
more particularly to the MMC drivers. The link issue arises when I tried to setup the GPIO for
Card Detection, which is trivial when DT is available. However, when OF_PLATDATA is enabled
this seems, at least for me, not straightforward.

In order to overcome this limitation I think that having a set of functions to find/get devices
based on platdata could be useful. Of course, there might be a better approach/idea, so that is
the motivation for this RFC.

An example of the usage could be

#if CONFIG_IS_ENABLED(DM_GPIO)

 ??????? struct udevice *gpiodev;

 ??????? ret = uclass_get_device_by_platdata(UCLASS_GPIO, (void *)dtplat->cd_gpios->node, &gpiodev);

 ??????? if (ret)
 ??????????????? return ret;

 ??????? ret = gpio_dev_request_index(gpiodev, gpiodev->name, "cd-gpios",
                                      dtplat->cd_gpios->arg[0], GPIOD_IS_IN,
 ???????????????????????????????????? dtplat->cd_gpios->arg[1], &priv->cd_gpio);

 ??????? if (ret)
 ??????????????? return ret;

#endif

This is part of my current work, a series of patches to add OF_PLATDATA support as explained.

Does this make sense to you?

> Also it relates to another thing I've been thinking about for a while,
> which is to validate that all the structs pointed to are correct.
>
> E.g. if every struct had a magic number like:
>
> struct tpm_platdata {
>      DM_STRUCT(UCLASS_TPM, DM_STRUCT_PLATDATA, ...)
>      fields here
> };
>
> then we could check the structure pointers are correct.
>
> DM_STRUCT() would define to nothing if we were not building with
> CONFIG_DM_DEBUG or similar.

Interesting, I think it could be useful and save us from headaches while debugging.

Thanks for sharing this idea.

> Anyway, I wonder whether you could expand your definition a bit so you
> have an enum for the different types of struct you can request:
>
> enum dm_struct_t {
>     DM_STRUCT_PLATDATA,
>   ...
>
>     DM_STRUCT_COUNT,
> };
>
> and modify the function so it can request it via the enum?

Let me check if I understand correctly, your suggestion is to do 
something like diff --git a/include/dm/uclass.h b/include/dm/uclass.h 
index 92c07f8426..bf09dadf3f 100644 --- a/include/dm/uclass.h +++ 
b/include/dm/uclass.h

@@ -167,8 +167,8 @@ int uclass_get_device(enum uclass_id id, int index, 
struct udevice **devp);

 ?int uclass_get_device_by_name(enum uclass_id id, const char *name, 
 ????????????????????????????? struct udevice **devp); -int 
uclass_get_device_by_platdata(enum uclass_id id, void *platdata, 
-???????????????????????????? struct udevice **devp);

+int uclass_get_device_by_struct(enum uclass_id id, enum dm_struct_t 
struct_id, +???????????????????????????? void *struct_pointer, struct 
udevice **devp); ?/** ? * uclass_get_device_by_seq() - Get a uclass 
device based on an ID and sequence ? *

If that is the case, I would be happy to help.

Also, if my understanding is correct, could you elaborate which cases 
are you trying to cover with this approach? Regards,

Walter
Simon Glass March 6, 2020, 1:17 p.m. UTC | #3
Hi Walter,

On Thu, 5 Mar 2020 at 06:54, Walter Lozano <walter.lozano at collabora.com> wrote:
>
> Hi Simon,
>
> Thanks for taking the time to check for my comments
>
> On 4/3/20 20:11, Simon Glass wrote:
>
> > Hi Walter,
> >
> > On Wed, 4 Mar 2020 at 12:40, Walter Lozano <walter.lozano at collabora.com> wrote:
> >> When OF_PLATDATA is enabled DT information is parsed and platdata
> >> structures are populated. In this context the links between DT nodes are
> >> represented as pointers to platdata structures, and there is no clear way
> >> to access to the device which owns the structure.
> >>
> >> This patch implements a set of functions:
> >>
> >> - device_find_by_platdata
> >> - uclass_find_device_by_platdata
> >>
> >> to access to the device.
> >>
> >> Signed-off-by: Walter Lozano <walter.lozano at collabora.com>
> >> ---
> >>   drivers/core/device.c        | 19 +++++++++++++++++++
> >>   drivers/core/uclass.c        | 34 ++++++++++++++++++++++++++++++++++
> >>   include/dm/device.h          |  2 ++
> >>   include/dm/uclass-internal.h |  3 +++
> >>   include/dm/uclass.h          |  2 ++
> >>   5 files changed, 60 insertions(+)
> > This is interesting. Could you also add the motivation for this? It's
> > not clear to me who would call this function.
>
> I have been reviewing the OF_PLATDATA support as an R&D project, in this context, in order to have
> a better understanding on the possibilities and limitations I decided to add its support to iMX6,
> more particularly to the MMC drivers. The link issue arises when I tried to setup the GPIO for
> Card Detection, which is trivial when DT is available. However, when OF_PLATDATA is enabled
> this seems, at least for me, not straightforward.
>
> In order to overcome this limitation I think that having a set of functions to find/get devices
> based on platdata could be useful. Of course, there might be a better approach/idea, so that is
> the motivation for this RFC.
>
> An example of the usage could be
>
> #if CONFIG_IS_ENABLED(DM_GPIO)
>
>          struct udevice *gpiodev;
>
>          ret = uclass_get_device_by_platdata(UCLASS_GPIO, (void *)dtplat->cd_gpios->node, &gpiodev);
>
>          if (ret)
>                  return ret;
>
>          ret = gpio_dev_request_index(gpiodev, gpiodev->name, "cd-gpios",
>                                       dtplat->cd_gpios->arg[0], GPIOD_IS_IN,
>                                       dtplat->cd_gpios->arg[1], &priv->cd_gpio);
>
>          if (ret)
>                  return ret;
>
> #endif
>
> This is part of my current work, a series of patches to add OF_PLATDATA support as explained.
>
> Does this make sense to you?

Not yet :-)

What is the context of this call? Typically dtplat is only available
in the driver that includes it.

What driver is the above code in? Is it for MMC that needs a GPIO to
function? I'll assume it is for now.

Then the weird thing is that we are accessing the dtplat of another
device. It's a clever technique but I wonder if we can find another
way.

If you see drivers/mmc/rockchip_sdhci.c it has:

ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &clk);

So I wonder if we need gpio_dev_request_by_platdata()?

>
> > Also it relates to another thing I've been thinking about for a while,
> > which is to validate that all the structs pointed to are correct.
> >
> > E.g. if every struct had a magic number like:
> >
> > struct tpm_platdata {
> >      DM_STRUCT(UCLASS_TPM, DM_STRUCT_PLATDATA, ...)
> >      fields here
> > };
> >
> > then we could check the structure pointers are correct.
> >
> > DM_STRUCT() would define to nothing if we were not building with
> > CONFIG_DM_DEBUG or similar.
>
> Interesting, I think it could be useful and save us from headaches while debugging.
>
> Thanks for sharing this idea.
>
> > Anyway, I wonder whether you could expand your definition a bit so you
> > have an enum for the different types of struct you can request:
> >
> > enum dm_struct_t {
> >     DM_STRUCT_PLATDATA,
> >   ...
> >
> >     DM_STRUCT_COUNT,
> > };
> >
> > and modify the function so it can request it via the enum?
>
> Let me check if I understand correctly, your suggestion is to do
> something like diff --git a/include/dm/uclass.h b/include/dm/uclass.h
> index 92c07f8426..bf09dadf3f 100644 --- a/include/dm/uclass.h +++
> b/include/dm/uclass.h
>
> @@ -167,8 +167,8 @@ int uclass_get_device(enum uclass_id id, int index,
> struct udevice **devp);
>
>   int uclass_get_device_by_name(enum uclass_id id, const char *name,
>                                struct udevice **devp); -int
> uclass_get_device_by_platdata(enum uclass_id id, void *platdata,
> -                             struct udevice **devp);
>
> +int uclass_get_device_by_struct(enum uclass_id id, enum dm_struct_t
> struct_id, +                             void *struct_pointer, struct
> udevice **devp);  /**   * uclass_get_device_by_seq() - Get a uclass
> device based on an ID and sequence   *
>
> If that is the case, I would be happy to help.
>
> Also, if my understanding is correct, could you elaborate which cases
> are you trying to cover with this approach? Regards,

This is just so that in dev_get_priv(), for example, we can write a
check that dev->privdata is actually the expected struct. We can check
the uclass and the dm_struct_t.

It is really just a run-time assert to help with getting these things mixed up.

Regards,
Simon
diff mbox series

Patch

diff --git a/drivers/core/device.c b/drivers/core/device.c
index 89ea820d48..54a3a8d870 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -591,6 +591,25 @@  static int device_find_by_ofnode(ofnode node, struct udevice **devp)
 }
 #endif
 
+
+int device_find_by_platdata(void *platdata, struct udevice **devp)
+{
+	struct uclass *uc;
+	struct udevice *dev;
+	int ret;
+
+	list_for_each_entry(uc, &gd->uclass_root, sibling_node) {
+		ret = uclass_find_device_by_platdata(uc->uc_drv->id, platdata,
+						   &dev);
+		if (!ret || dev) {
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
 int device_get_child(const struct udevice *parent, int index,
 		     struct udevice **devp)
 {
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 58b19a4210..7b0ae5b122 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -271,6 +271,29 @@  int uclass_find_device_by_name(enum uclass_id id, const char *name,
 	return -ENODEV;
 }
 
+int uclass_find_device_by_platdata(enum uclass_id id, void * platdata, struct udevice **devp)
+{
+	struct uclass *uc;
+	struct udevice *dev;
+	int ret;
+
+	*devp = NULL;
+	ret = uclass_get(id, &uc);
+	if (ret)
+		return ret;
+	if (list_empty(&uc->dev_head))
+		return -ENODEV;
+
+	uclass_foreach_dev(dev, uc) {
+		if (dev->platdata == platdata) {
+			*devp = dev;
+			return 0;
+		}
+	}
+
+	return -ENODEV;
+}
+
 int uclass_find_next_free_req_seq(enum uclass_id id)
 {
 	struct uclass *uc;
@@ -466,6 +489,17 @@  int uclass_get_device_by_name(enum uclass_id id, const char *name,
 	return uclass_get_device_tail(dev, ret, devp);
 }
 
+int uclass_get_device_by_platdata(enum uclass_id id, void * platdata,
+			      struct udevice **devp)
+{
+	struct udevice *dev;
+	int ret;
+
+	*devp = NULL;
+	ret = uclass_find_device_by_platdata(id, platdata, &dev);
+	return uclass_get_device_tail(dev, ret, devp);
+}
+
 int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp)
 {
 	struct udevice *dev;
diff --git a/include/dm/device.h b/include/dm/device.h
index ab806d0b7e..3c043a3127 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -396,6 +396,8 @@  enum uclass_id device_get_uclass_id(const struct udevice *dev);
  */
 const char *dev_get_uclass_name(const struct udevice *dev);
 
+int device_find_by_platdata(void *platdata, struct udevice **devp);
+
 /**
  * device_get_child() - Get the child of a device by index
  *
diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h
index 6e3f15c2b0..f643fc95da 100644
--- a/include/dm/uclass-internal.h
+++ b/include/dm/uclass-internal.h
@@ -100,6 +100,9 @@  int uclass_find_next_device(struct udevice **devp);
 int uclass_find_device_by_name(enum uclass_id id, const char *name,
 			       struct udevice **devp);
 
+int uclass_find_device_by_platdata(enum uclass_id id, void *platdata,
+			       struct udevice **devp);
+
 /**
  * uclass_find_device_by_seq() - Find uclass device based on ID and sequence
  *
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 70fca79b44..92c07f8426 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -167,6 +167,8 @@  int uclass_get_device(enum uclass_id id, int index, struct udevice **devp);
 int uclass_get_device_by_name(enum uclass_id id, const char *name,
 			      struct udevice **devp);
 
+int uclass_get_device_by_platdata(enum uclass_id id, void *platdata,
+			      struct udevice **devp);
 /**
  * uclass_get_device_by_seq() - Get a uclass device based on an ID and sequence
  *