mbox series

[v2,00/13] of: property: add port base loop

Message ID 87fryhklhb.wl-kuninori.morimoto.gx@renesas.com
Headers show
Series of: property: add port base loop | expand

Message

Kuninori Morimoto Jan. 29, 2024, 12:54 a.m. UTC
Hi Rob

This is v2 of port base loop patch-set

We have endpoint base functions
	- of_graph_get_next_endpoint()
	- of_graph_get_endpoint_count()
	- for_each_endpoint_of_node()

But to handling "port" base things, it is not useful. We want to have
"port" base functions, too. This patch-set adds it.

Because current existing drivers couldn't use "port" base functions,
it were implemented in a different way. This patch-set doesn't try
to full-replace to avoid unknown bug, try easy / quick replace only
for now, but easy to know how "port" base functions are needed.

Because I can't test the driver which I can't use, non-ASoC drivers
needs Tested-by, Acked-by.

v1 -> v2
	- tidyup function explain
	- add missing header on each files

Kuninori Morimoto (13):
  of: property: add port base loop
  of: property: use of_graph_get_next_port() on of_graph_get_next_endpoint()
  of: property: add of_graph_get_next_endpoint_raw()
  drm: omapdrm: use of_graph_get_next_endpoint_raw()
  media: xilinx-tpg: use of_graph_get_next_endpoint_raw()
  ASoC: audio-graph-card: use of_graph_get_next_endpoint_raw()
  ASoC: audio-graph-card2: use of_graph_get_next_port()
  ASoC: audio-graph-card2: use of_graph_get_next_endpoint_raw()
  ASoC: test-component: use for_each_port_of_node()
  fbdev: omapfb: use of_graph_get_remote_port()
  fbdev: omapfb: use of_graph_get_next_port()
  fbdev: omapfb: use of_graph_get_next_endpoint_raw()
  fbdev: omapfb: use of_graph_get_next_endpoint()

 drivers/gpu/drm/omapdrm/dss/dpi.c             |   2 +-
 drivers/gpu/drm/omapdrm/dss/sdi.c             |   2 +-
 drivers/media/platform/xilinx/xilinx-tpg.c    |   2 +-
 drivers/of/property.c                         |  92 +++++++++++++---
 drivers/video/fbdev/omap2/omapfb/dss/dpi.c    |   3 +-
 drivers/video/fbdev/omap2/omapfb/dss/dsi.c    |   3 +-
 drivers/video/fbdev/omap2/omapfb/dss/dss-of.c | 101 +-----------------
 drivers/video/fbdev/omap2/omapfb/dss/dss.c    |   9 +-
 drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c  |   3 +-
 drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c  |   3 +-
 drivers/video/fbdev/omap2/omapfb/dss/sdi.c    |   3 +-
 drivers/video/fbdev/omap2/omapfb/dss/venc.c   |   3 +-
 include/linux/of_graph.h                      |  23 ++++
 include/video/omapfb_dss.h                    |  11 --
 sound/soc/generic/audio-graph-card.c          |   2 +-
 sound/soc/generic/audio-graph-card2.c         |  31 ++----
 sound/soc/generic/test-component.c            |   2 +-
 17 files changed, 133 insertions(+), 162 deletions(-)

Comments

Tomi Valkeinen Jan. 29, 2024, 12:16 p.m. UTC | #1
Hi,

On 29/01/2024 02:54, Kuninori Morimoto wrote:
> We have endpoint base functions
> 	- of_graph_get_next_endpoint()
> 	- of_graph_get_endpoint_count()
> 	- for_each_endpoint_of_node()
> 
> Here, for_each_endpoint_of_node() loop finds each endpoints
> 
> 	ports {
> 		port@0 {
> (1)			endpoint {...};
> 		};
> 		port@1 {
> (2)			endpoint {...};
> 		};
> 		...
> 	};
> 
> In above case, for_each_endpoint_of_node() loop finds endpoint as
> (1) -> (2) -> ...
> 
> Basically, user/driver knows which port is used for what, but not in
> all cases. For example on flexible/generic driver case, how many ports
> are used is not fixed.
> 
> For example Sound Generic Card driver which is used from many venders
> can't know how many ports are used. Because the driver is very
> flexible/generic, it is impossible to know how many ports are used,
> it depends on each vender SoC and/or its used board.
> 
> And more, the port can have multi endpoints. For example Generic Sound
> Card case, it supports many type of connection between CPU / Codec, and
> some of them uses multi endpoint in one port.
> Then, Generic Sound Card want to handle each connection via "port"
> instead of "endpoint".
> But, it is very difficult to handle each "port" by
> for_each_endpoint_of_node(). Getting "port" by using of_get_parent()
> from "endpoint" doesn't work. see below.
> 
> 	ports {
> 		port@0 {
> (1)			endpoint@0 {...};
> (2)			endpoint@1 {...};
> 		};
> 		port@1 {
> (3)			endpoint {...};
> 		};
> 		...
> 	};
> 
> Add "port" base functions.
> 
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> ---
>   drivers/of/property.c    | 48 ++++++++++++++++++++++++++++++++++++++++
>   include/linux/of_graph.h | 21 ++++++++++++++++++
>   2 files changed, 69 insertions(+)
> 
> diff --git a/drivers/of/property.c b/drivers/of/property.c
> index afdaefbd03f6..9e670e99dbbb 100644
> --- a/drivers/of/property.c
> +++ b/drivers/of/property.c
> @@ -631,6 +631,42 @@ struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
>   }
>   EXPORT_SYMBOL(of_graph_get_port_by_id);
>   
> +/**
> + * of_graph_get_next_port() - get next port node
> + * @parent: pointer to the parent device node
> + * @port: current port node, or NULL to get first
> + *
> + * Return: An 'port' node pointer with refcount incremented. Refcount

"A 'port'".

> + * of the passed @prev node is decremented.
> + */
> +struct device_node *of_graph_get_next_port(const struct device_node *parent,
> +					   struct device_node *port)
> +{
> +	if (!parent)
> +		return NULL;
> +
> +	if (!port) {
> +		struct device_node *node;
> +
> +		node = of_get_child_by_name(parent, "ports");
> +		if (node) {
> +			parent = node;
> +			of_node_put(node);

Here you of_node_put() the node, but use it below.

> +		}
> +
> +		return of_get_child_by_name(parent, "port");
> +	}

Maybe you can do:

	node = of_get_child_by_name(parent, "ports");
	if (node)
		parent = node;
	port = of_get_child_by_name(parent, "port");
	of_node_put(node);
	return port;

> +
> +	do {
> +		port = of_get_next_child(parent, port);
> +		if (!port)
> +			break;
> +	} while (!of_node_name_eq(port, "port"));
> +
> +	return port;
> +}
> +EXPORT_SYMBOL(of_graph_get_next_port);
> +
>   /**
>    * of_graph_get_next_endpoint() - get next endpoint node
>    * @parent: pointer to the parent device node
> @@ -823,6 +859,18 @@ int of_graph_get_endpoint_count(const struct device_node *np)
>   }
>   EXPORT_SYMBOL(of_graph_get_endpoint_count);
>   
> +int of_graph_get_port_count(const struct device_node *np)

The kerneldoc is missing for this func.

The return type and the variable below should be unsigned.

I can see these are wrong with of_graph_get_endpoint_count() too, so 
maybe that should be fixed also.

> +{
> +	struct device_node *port;
> +	int num = 0;
> +
> +	for_each_port_of_node(np, port)
> +		num++;
> +
> +	return num;
> +}
> +EXPORT_SYMBOL(of_graph_get_port_count);
> +
>   /**
>    * of_graph_get_remote_node() - get remote parent device_node for given port/endpoint
>    * @node: pointer to parent device_node containing graph port/endpoint
> diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h
> index 4d7756087b6b..fff598640e93 100644
> --- a/include/linux/of_graph.h
> +++ b/include/linux/of_graph.h
> @@ -37,14 +37,28 @@ struct of_endpoint {
>   	for (child = of_graph_get_next_endpoint(parent, NULL); child != NULL; \
>   	     child = of_graph_get_next_endpoint(parent, child))
>   
> +/**
> + * for_each_port_of_node - iterate over every port in a device node
> + * @parent: parent device node containing ports/port
> + * @child: loop variable pointing to the current port node
> + *
> + * When breaking out of the loop, of_node_put(child) has to be called manually.
> + */
> +#define for_each_port_of_node(parent, child)			\
> +	for (child = of_graph_get_next_port(parent, NULL); child != NULL; \
> +	     child = of_graph_get_next_port(parent, child))
> +
>   #ifdef CONFIG_OF
>   bool of_graph_is_present(const struct device_node *node);
>   int of_graph_parse_endpoint(const struct device_node *node,
>   				struct of_endpoint *endpoint);
>   int of_graph_get_endpoint_count(const struct device_node *np);
> +int of_graph_get_port_count(const struct device_node *np);
>   struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id);
>   struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
>   					struct device_node *previous);
> +struct device_node *of_graph_get_next_port(const struct device_node *parent,
> +					   struct device_node *previous);
>   struct device_node *of_graph_get_endpoint_by_regs(
>   		const struct device_node *parent, int port_reg, int reg);
>   struct device_node *of_graph_get_remote_endpoint(
> @@ -86,6 +100,13 @@ static inline struct device_node *of_graph_get_next_endpoint(
>   	return NULL;
>   }
>   
> +static inline struct device_node *of_graph_get_next_port(
> +					const struct device_node *parent,
> +					struct device_node *previous)
> +{
> +	return NULL;
> +}
> +
>   static inline struct device_node *of_graph_get_endpoint_by_regs(
>   		const struct device_node *parent, int port_reg, int reg)
>   {
Laurent Pinchart Jan. 29, 2024, 12:27 p.m. UTC | #2
Hello Morimoto-san,

(CC'ing Sakari Ailus)

On Mon, Jan 29, 2024 at 12:54:24AM +0000, Kuninori Morimoto wrote:
> 
> Hi Rob
> 
> This is v2 of port base loop patch-set
> 
> We have endpoint base functions
> 	- of_graph_get_next_endpoint()
> 	- of_graph_get_endpoint_count()
> 	- for_each_endpoint_of_node()
> 
> But to handling "port" base things, it is not useful. We want to have
> "port" base functions, too. This patch-set adds it.
> 
> Because current existing drivers couldn't use "port" base functions,
> it were implemented in a different way. This patch-set doesn't try
> to full-replace to avoid unknown bug, try easy / quick replace only
> for now, but easy to know how "port" base functions are needed.
> 
> Because I can't test the driver which I can't use, non-ASoC drivers
> needs Tested-by, Acked-by.

The strategy sounds good to me. However, I'm wondering if you shouldn't
take one more step in the core, and implement these as fwnode
operations. Or is there a reason why OF is special, and iterating over
ports would be useful for drivers on OF systems but not on other types
of systems ?

> v1 -> v2
> 	- tidyup function explain
> 	- add missing header on each files
> 
> Kuninori Morimoto (13):
>   of: property: add port base loop
>   of: property: use of_graph_get_next_port() on of_graph_get_next_endpoint()
>   of: property: add of_graph_get_next_endpoint_raw()
>   drm: omapdrm: use of_graph_get_next_endpoint_raw()
>   media: xilinx-tpg: use of_graph_get_next_endpoint_raw()
>   ASoC: audio-graph-card: use of_graph_get_next_endpoint_raw()
>   ASoC: audio-graph-card2: use of_graph_get_next_port()
>   ASoC: audio-graph-card2: use of_graph_get_next_endpoint_raw()
>   ASoC: test-component: use for_each_port_of_node()
>   fbdev: omapfb: use of_graph_get_remote_port()
>   fbdev: omapfb: use of_graph_get_next_port()
>   fbdev: omapfb: use of_graph_get_next_endpoint_raw()
>   fbdev: omapfb: use of_graph_get_next_endpoint()
> 
>  drivers/gpu/drm/omapdrm/dss/dpi.c             |   2 +-
>  drivers/gpu/drm/omapdrm/dss/sdi.c             |   2 +-
>  drivers/media/platform/xilinx/xilinx-tpg.c    |   2 +-
>  drivers/of/property.c                         |  92 +++++++++++++---
>  drivers/video/fbdev/omap2/omapfb/dss/dpi.c    |   3 +-
>  drivers/video/fbdev/omap2/omapfb/dss/dsi.c    |   3 +-
>  drivers/video/fbdev/omap2/omapfb/dss/dss-of.c | 101 +-----------------
>  drivers/video/fbdev/omap2/omapfb/dss/dss.c    |   9 +-
>  drivers/video/fbdev/omap2/omapfb/dss/hdmi4.c  |   3 +-
>  drivers/video/fbdev/omap2/omapfb/dss/hdmi5.c  |   3 +-
>  drivers/video/fbdev/omap2/omapfb/dss/sdi.c    |   3 +-
>  drivers/video/fbdev/omap2/omapfb/dss/venc.c   |   3 +-
>  include/linux/of_graph.h                      |  23 ++++
>  include/video/omapfb_dss.h                    |  11 --
>  sound/soc/generic/audio-graph-card.c          |   2 +-
>  sound/soc/generic/audio-graph-card2.c         |  31 ++----
>  sound/soc/generic/test-component.c            |   2 +-
>  17 files changed, 133 insertions(+), 162 deletions(-)
Tomi Valkeinen Jan. 29, 2024, 12:29 p.m. UTC | #3
On 29/01/2024 02:54, Kuninori Morimoto wrote:
> We already have of_graph_get_next_endpoint(), but it is not intuitive
> to use.
> 
> (X)	node {
> (Y)		ports {
> 			port@0 { endpoint { remote-endpoint = ...; };};
> (A1)			port@1 { endpoint { remote-endpoint = ...; };
> (A2)				 endpoint { remote-endpoint = ...; };};
> (B)			port@2 { endpoint { remote-endpoint = ...; };};
> 		};
> 	};
> 
> For example, if I want to handle port@1's 2 endpoints (= A1, A2),
> I want to use like below
> 
> 	A1 = of_graph_get_next_endpoint(port1, NULL);
> 	A2 = of_graph_get_next_endpoint(port1, A1);
> 
> But 1st one will be error, because of_graph_get_next_endpoint() requested
> "parent" means "node" (X) or "ports" (Y), not "port".
> Below are OK
> 
> 	of_graph_get_next_endpoint(node,  NULL); // node/ports/port@0/endpoint
> 	of_graph_get_next_endpoint(ports, NULL); // node/ports/port@0/endpoint
> 
> In other words, we can't handle A1/A2 directly via
> of_graph_get_next_endpoint() so far.
> 
> There is another non intuitive behavior on of_graph_get_next_endpoint().
> In case of if I could get A1 pointer for some way, and if I want to
> handle port@1 things, I would like use it like below
> 
> 	/*
> 	 * "endpoint" is now A1, and handle port1 things here,
> 	 * but we don't know how many endpoints port1 has.
> 	 *
> 	 * Because "endpoint" is non NULL, we can use port1
> 	 * as of_graph_get_next_endpoint(port1, xxx)
> 	 */
> 	do {
> 		/* do something for port1 specific things here */
> 	} while (endpoint = of_graph_get_next_endpoint(port1, endpoint))
> 
> But it also not worked as I expected.
> I expect it will be A1 -> A2 -> NULL,
> but      it will be A1 -> A2 -> B,    because of_graph_get_next_endpoint()
> will fetch endpoint beyond the port.
> 
> It is not useful on generic driver like Generic Sound Card.
> It uses of_get_next_child() instead for now, but it is not intuitive,
> and not check node name (= "endpoint").
> 
> To handle endpoint more intuitive, create of_graph_get_next_endpoint_raw()
> 
> 	of_graph_get_next_endpoint_raw(port1, NULL); // A1
> 	of_graph_get_next_endpoint_raw(port1, A1);   // A2
> 	of_graph_get_next_endpoint_raw(port1, A2);   // NULL
> 
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> ---
>   drivers/of/property.c    | 26 +++++++++++++++++++++++++-
>   include/linux/of_graph.h |  2 ++
>   2 files changed, 27 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/of/property.c b/drivers/of/property.c
> index 14ffd199c9b1..37dbb1b0e742 100644
> --- a/drivers/of/property.c
> +++ b/drivers/of/property.c
> @@ -667,6 +667,30 @@ struct device_node *of_graph_get_next_port(const struct device_node *parent,
>   }
>   EXPORT_SYMBOL(of_graph_get_next_port);
>   
> +/**
> + * of_graph_get_next_endpoint_raw() - get next endpoint node

How about "of_graph_get_next_port_endpoint()"?

> + * @port: pointer to the target port node
> + * @endpoint: current endpoint node, or NULL to get first
> + *
> + * Return: An 'endpoint' node pointer with refcount incremented. Refcount
> + * of the passed @prev node is decremented.
> + */

It might be good to highlight here the difference to the 
of_graph_get_next_endpoint().

> +struct device_node *of_graph_get_next_endpoint_raw(const struct device_node *port,
> +						   struct device_node *endpoint)
> +{
> +	if (!port)
> +		return NULL;
> +
> +	do {
> +		endpoint = of_get_next_child(port, endpoint);
> +		if (!endpoint)
> +			break;
> +	} while (!of_node_name_eq(endpoint, "endpoint"));
> +
> +	return endpoint;
> +}
> +EXPORT_SYMBOL(of_graph_get_next_endpoint_raw);
> +
>   /**
>    * of_graph_get_next_endpoint() - get next endpoint node
>    * @parent: pointer to the parent device node
> @@ -708,7 +732,7 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
>   		 * getting the next child. If the previous endpoint is NULL this
>   		 * will return the first child.
>   		 */
> -		endpoint = of_get_next_child(port, prev);
> +		endpoint = of_graph_get_next_endpoint_raw(port, prev);
>   		if (endpoint) {
>   			of_node_put(port);
>   			return endpoint;
> diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h
> index fff598640e93..427905a6e8c3 100644
> --- a/include/linux/of_graph.h
> +++ b/include/linux/of_graph.h
> @@ -57,6 +57,8 @@ int of_graph_get_port_count(const struct device_node *np);
>   struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id);
>   struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
>   					struct device_node *previous);
> +struct device_node *of_graph_get_next_endpoint_raw(const struct device_node *port,
> +						   struct device_node *prev);
>   struct device_node *of_graph_get_next_port(const struct device_node *parent,
>   					   struct device_node *previous);
>   struct device_node *of_graph_get_endpoint_by_regs(
Laurent Pinchart Jan. 29, 2024, 1:02 p.m. UTC | #4
On Mon, Jan 29, 2024 at 02:29:22PM +0200, Tomi Valkeinen wrote:
> On 29/01/2024 02:54, Kuninori Morimoto wrote:
> > We already have of_graph_get_next_endpoint(), but it is not intuitive
> > to use.
> > 
> > (X)	node {
> > (Y)		ports {
> > 			port@0 { endpoint { remote-endpoint = ...; };};
> > (A1)			port@1 { endpoint { remote-endpoint = ...; };
> > (A2)				 endpoint { remote-endpoint = ...; };};
> > (B)			port@2 { endpoint { remote-endpoint = ...; };};
> > 		};
> > 	};
> > 
> > For example, if I want to handle port@1's 2 endpoints (= A1, A2),
> > I want to use like below
> > 
> > 	A1 = of_graph_get_next_endpoint(port1, NULL);
> > 	A2 = of_graph_get_next_endpoint(port1, A1);
> > 
> > But 1st one will be error, because of_graph_get_next_endpoint() requested
> > "parent" means "node" (X) or "ports" (Y), not "port".
> > Below are OK
> > 
> > 	of_graph_get_next_endpoint(node,  NULL); // node/ports/port@0/endpoint
> > 	of_graph_get_next_endpoint(ports, NULL); // node/ports/port@0/endpoint
> > 
> > In other words, we can't handle A1/A2 directly via
> > of_graph_get_next_endpoint() so far.
> > 
> > There is another non intuitive behavior on of_graph_get_next_endpoint().
> > In case of if I could get A1 pointer for some way, and if I want to
> > handle port@1 things, I would like use it like below
> > 
> > 	/*
> > 	 * "endpoint" is now A1, and handle port1 things here,
> > 	 * but we don't know how many endpoints port1 has.
> > 	 *
> > 	 * Because "endpoint" is non NULL, we can use port1
> > 	 * as of_graph_get_next_endpoint(port1, xxx)
> > 	 */
> > 	do {
> > 		/* do something for port1 specific things here */
> > 	} while (endpoint = of_graph_get_next_endpoint(port1, endpoint))
> > 
> > But it also not worked as I expected.
> > I expect it will be A1 -> A2 -> NULL,
> > but      it will be A1 -> A2 -> B,    because of_graph_get_next_endpoint()
> > will fetch endpoint beyond the port.
> > 
> > It is not useful on generic driver like Generic Sound Card.
> > It uses of_get_next_child() instead for now, but it is not intuitive,
> > and not check node name (= "endpoint").
> > 
> > To handle endpoint more intuitive, create of_graph_get_next_endpoint_raw()
> > 
> > 	of_graph_get_next_endpoint_raw(port1, NULL); // A1
> > 	of_graph_get_next_endpoint_raw(port1, A1);   // A2
> > 	of_graph_get_next_endpoint_raw(port1, A2);   // NULL
> > 
> > Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> > ---
> >   drivers/of/property.c    | 26 +++++++++++++++++++++++++-
> >   include/linux/of_graph.h |  2 ++
> >   2 files changed, 27 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/of/property.c b/drivers/of/property.c
> > index 14ffd199c9b1..37dbb1b0e742 100644
> > --- a/drivers/of/property.c
> > +++ b/drivers/of/property.c
> > @@ -667,6 +667,30 @@ struct device_node *of_graph_get_next_port(const struct device_node *parent,
> >   }
> >   EXPORT_SYMBOL(of_graph_get_next_port);
> >   
> > +/**
> > + * of_graph_get_next_endpoint_raw() - get next endpoint node
> 
> How about "of_graph_get_next_port_endpoint()"?

We may want to also rename the existing of_graph_get_next_endpoint()
function to of_graph_next_dev_endpoint() then. It would be a tree-wide
patch, which is always annoying to get reviewed and merged, so if Rob
would prefer avoiding the rename, I'm fine with that.

> > + * @port: pointer to the target port node
> > + * @endpoint: current endpoint node, or NULL to get first
> > + *
> > + * Return: An 'endpoint' node pointer with refcount incremented. Refcount
> > + * of the passed @prev node is decremented.
> > + */
> 
> It might be good to highlight here the difference to the 
> of_graph_get_next_endpoint().

Yes, and the documentation of of_graph_get_next_endpoint() shoul also be
improved.

> > +struct device_node *of_graph_get_next_endpoint_raw(const struct device_node *port,
> > +						   struct device_node *endpoint)
> > +{
> > +	if (!port)
> > +		return NULL;
> > +
> > +	do {
> > +		endpoint = of_get_next_child(port, endpoint);
> > +		if (!endpoint)
> > +			break;
> > +	} while (!of_node_name_eq(endpoint, "endpoint"));
> > +
> > +	return endpoint;
> > +}
> > +EXPORT_SYMBOL(of_graph_get_next_endpoint_raw);
> > +
> >   /**
> >    * of_graph_get_next_endpoint() - get next endpoint node
> >    * @parent: pointer to the parent device node
> > @@ -708,7 +732,7 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
> >   		 * getting the next child. If the previous endpoint is NULL this
> >   		 * will return the first child.
> >   		 */
> > -		endpoint = of_get_next_child(port, prev);
> > +		endpoint = of_graph_get_next_endpoint_raw(port, prev);
> >   		if (endpoint) {
> >   			of_node_put(port);
> >   			return endpoint;
> > diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h
> > index fff598640e93..427905a6e8c3 100644
> > --- a/include/linux/of_graph.h
> > +++ b/include/linux/of_graph.h
> > @@ -57,6 +57,8 @@ int of_graph_get_port_count(const struct device_node *np);
> >   struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id);
> >   struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
> >   					struct device_node *previous);
> > +struct device_node *of_graph_get_next_endpoint_raw(const struct device_node *port,
> > +						   struct device_node *prev);
> >   struct device_node *of_graph_get_next_port(const struct device_node *parent,
> >   					   struct device_node *previous);
> >   struct device_node *of_graph_get_endpoint_by_regs(
Sakari Ailus Jan. 29, 2024, 1:29 p.m. UTC | #5
Hi Laurent, Morimoto-san,

On Mon, Jan 29, 2024 at 02:27:36PM +0200, Laurent Pinchart wrote:
> Hello Morimoto-san,
> 
> (CC'ing Sakari Ailus)

Thanks for cc'ing me.

> 
> On Mon, Jan 29, 2024 at 12:54:24AM +0000, Kuninori Morimoto wrote:
> > 
> > Hi Rob
> > 
> > This is v2 of port base loop patch-set
> > 
> > We have endpoint base functions
> > 	- of_graph_get_next_endpoint()
> > 	- of_graph_get_endpoint_count()
> > 	- for_each_endpoint_of_node()
> > 
> > But to handling "port" base things, it is not useful. We want to have
> > "port" base functions, too. This patch-set adds it.
> > 
> > Because current existing drivers couldn't use "port" base functions,
> > it were implemented in a different way. This patch-set doesn't try
> > to full-replace to avoid unknown bug, try easy / quick replace only
> > for now, but easy to know how "port" base functions are needed.
> > 
> > Because I can't test the driver which I can't use, non-ASoC drivers
> > needs Tested-by, Acked-by.
> 
> The strategy sounds good to me. However, I'm wondering if you shouldn't
> take one more step in the core, and implement these as fwnode
> operations. Or is there a reason why OF is special, and iterating over
> ports would be useful for drivers on OF systems but not on other types
> of systems ?

I'd prefer that, too.

Probably we could use the existing callbacks for endpoint enumeration, for
port enumeration, too, as I don't think this is performance critical in any
way.
Sakari Ailus Jan. 29, 2024, 1:37 p.m. UTC | #6
Hi Morimoto-san,

On Mon, Jan 29, 2024 at 12:54:59AM +0000, Kuninori Morimoto wrote:
> We already have of_graph_get_next_endpoint(), but it is not intuitive
> to use.
> 
> (X)	node {
> (Y)		ports {
> 			port@0 { endpoint { remote-endpoint = ...; };};
> (A1)			port@1 { endpoint { remote-endpoint = ...; };
> (A2)				 endpoint { remote-endpoint = ...; };};
> (B)			port@2 { endpoint { remote-endpoint = ...; };};
> 		};
> 	};
> 
> For example, if I want to handle port@1's 2 endpoints (= A1, A2),
> I want to use like below
> 
> 	A1 = of_graph_get_next_endpoint(port1, NULL);
> 	A2 = of_graph_get_next_endpoint(port1, A1);
> 
> But 1st one will be error, because of_graph_get_next_endpoint() requested
> "parent" means "node" (X) or "ports" (Y), not "port".
> Below are OK
> 
> 	of_graph_get_next_endpoint(node,  NULL); // node/ports/port@0/endpoint
> 	of_graph_get_next_endpoint(ports, NULL); // node/ports/port@0/endpoint
> 
> In other words, we can't handle A1/A2 directly via
> of_graph_get_next_endpoint() so far.
> 
> There is another non intuitive behavior on of_graph_get_next_endpoint().
> In case of if I could get A1 pointer for some way, and if I want to
> handle port@1 things, I would like use it like below
> 
> 	/*
> 	 * "endpoint" is now A1, and handle port1 things here,
> 	 * but we don't know how many endpoints port1 has.
> 	 *
> 	 * Because "endpoint" is non NULL, we can use port1
> 	 * as of_graph_get_next_endpoint(port1, xxx)
> 	 */
> 	do {
> 		/* do something for port1 specific things here */
> 	} while (endpoint = of_graph_get_next_endpoint(port1, endpoint))
> 
> But it also not worked as I expected.
> I expect it will be A1 -> A2 -> NULL,
> but      it will be A1 -> A2 -> B,    because of_graph_get_next_endpoint()
> will fetch endpoint beyond the port.
> 
> It is not useful on generic driver like Generic Sound Card.
> It uses of_get_next_child() instead for now, but it is not intuitive,
> and not check node name (= "endpoint").
> 
> To handle endpoint more intuitive, create of_graph_get_next_endpoint_raw()
> 
> 	of_graph_get_next_endpoint_raw(port1, NULL); // A1
> 	of_graph_get_next_endpoint_raw(port1, A1);   // A2
> 	of_graph_get_next_endpoint_raw(port1, A2);   // NULL
> 
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> ---
>  drivers/of/property.c    | 26 +++++++++++++++++++++++++-
>  include/linux/of_graph.h |  2 ++
>  2 files changed, 27 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/of/property.c b/drivers/of/property.c
> index 14ffd199c9b1..37dbb1b0e742 100644
> --- a/drivers/of/property.c
> +++ b/drivers/of/property.c
> @@ -667,6 +667,30 @@ struct device_node *of_graph_get_next_port(const struct device_node *parent,
>  }
>  EXPORT_SYMBOL(of_graph_get_next_port);
>  
> +/**
> + * of_graph_get_next_endpoint_raw() - get next endpoint node
> + * @port: pointer to the target port node
> + * @endpoint: current endpoint node, or NULL to get first
> + *
> + * Return: An 'endpoint' node pointer with refcount incremented. Refcount
> + * of the passed @prev node is decremented.
> + */
> +struct device_node *of_graph_get_next_endpoint_raw(const struct device_node *port,
> +						   struct device_node *endpoint)
> +{
> +	if (!port)
> +		return NULL;

of_get_next_child() returns NULL if node is NULL, hence there's no need to
check this.

> +
> +	do {
> +		endpoint = of_get_next_child(port, endpoint);
> +		if (!endpoint)
> +			break;
> +	} while (!of_node_name_eq(endpoint, "endpoint"));
> +
> +	return endpoint;
> +}
> +EXPORT_SYMBOL(of_graph_get_next_endpoint_raw);
> +
>  /**
>   * of_graph_get_next_endpoint() - get next endpoint node
>   * @parent: pointer to the parent device node
> @@ -708,7 +732,7 @@ struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
>  		 * getting the next child. If the previous endpoint is NULL this
>  		 * will return the first child.
>  		 */
> -		endpoint = of_get_next_child(port, prev);
> +		endpoint = of_graph_get_next_endpoint_raw(port, prev);
>  		if (endpoint) {
>  			of_node_put(port);
>  			return endpoint;
> diff --git a/include/linux/of_graph.h b/include/linux/of_graph.h
> index fff598640e93..427905a6e8c3 100644
> --- a/include/linux/of_graph.h
> +++ b/include/linux/of_graph.h
> @@ -57,6 +57,8 @@ int of_graph_get_port_count(const struct device_node *np);
>  struct device_node *of_graph_get_port_by_id(struct device_node *node, u32 id);
>  struct device_node *of_graph_get_next_endpoint(const struct device_node *parent,
>  					struct device_node *previous);
> +struct device_node *of_graph_get_next_endpoint_raw(const struct device_node *port,
> +						   struct device_node *prev);
>  struct device_node *of_graph_get_next_port(const struct device_node *parent,
>  					   struct device_node *previous);
>  struct device_node *of_graph_get_endpoint_by_regs(
Kuninori Morimoto Jan. 30, 2024, 12:08 a.m. UTC | #7
Hi Laurent, Tomi

Thank you for your review

> > > +/**
> > > + * of_graph_get_next_endpoint_raw() - get next endpoint node
> > 
> > How about "of_graph_get_next_port_endpoint()"?
> 
> We may want to also rename the existing of_graph_get_next_endpoint()
> function to of_graph_next_dev_endpoint() then. It would be a tree-wide
> patch, which is always annoying to get reviewed and merged, so if Rob
> would prefer avoiding the rename, I'm fine with that.

To be honest, from intuitive function naming point of view,
I prefer rename existing function name. But yes, it will be big patch.

Current of_graph_get_next_endpoint() will get next endpoint
beyond the port (A)
New function is not get next endpoint beyond the port (B)

Something like

(A) of_graph_get_next_endpoint() -> of_graph_get_next_port_endpoint()
(B)                                 of_graph_get_next_endpoint()

> > > + * @port: pointer to the target port node
> > > + * @endpoint: current endpoint node, or NULL to get first
> > > + *
> > > + * Return: An 'endpoint' node pointer with refcount incremented. Refcount
> > > + * of the passed @prev node is decremented.
> > > + */
> > 
> > It might be good to highlight here the difference to the 
> > of_graph_get_next_endpoint().
> 
> Yes, and the documentation of of_graph_get_next_endpoint() shoul also be
> improved.

Yes, Indeed.




Thank you for your help !!

Best regards
---
Renesas Electronics
Ph.D. Kuninori Morimoto
Kuninori Morimoto Jan. 30, 2024, 12:34 a.m. UTC | #8
Hi Laurent, Sakari

Thank you for your review

> > The strategy sounds good to me. However, I'm wondering if you shouldn't
> > take one more step in the core, and implement these as fwnode
> > operations. Or is there a reason why OF is special, and iterating over
> > ports would be useful for drivers on OF systems but not on other types
> > of systems ?
> 
> I'd prefer that, too.

It is very easy reason, because I'm not fwnode user ;P
I'm not familiar with fwnode, but in my quick check, it seems it is easy
to expand fwnode side functions if of_graph side function exist ?

Thank you for your help !!

Best regards
---
Renesas Electronics
Ph.D. Kuninori Morimoto
Kuninori Morimoto Jan. 30, 2024, 12:37 a.m. UTC | #9
Hi Sakari

> > +struct device_node *of_graph_get_next_endpoint_raw(const struct device_node *port,
> > +						   struct device_node *endpoint)
> > +{
> > +	if (!port)
> > +		return NULL;
> 
> of_get_next_child() returns NULL if node is NULL, hence there's no need to
> check this.

Thanks, will fix in v3


Thank you for your help !!

Best regards
---
Renesas Electronics
Ph.D. Kuninori Morimoto
Sakari Ailus Jan. 30, 2024, 7:31 a.m. UTC | #10
Hi Morimoto-san,

On Tue, Jan 30, 2024 at 12:34:55AM +0000, Kuninori Morimoto wrote:
> 
> Hi Laurent, Sakari
> 
> Thank you for your review
> 
> > > The strategy sounds good to me. However, I'm wondering if you shouldn't
> > > take one more step in the core, and implement these as fwnode
> > > operations. Or is there a reason why OF is special, and iterating over
> > > ports would be useful for drivers on OF systems but not on other types
> > > of systems ?
> > 
> > I'd prefer that, too.
> 
> It is very easy reason, because I'm not fwnode user ;P
> I'm not familiar with fwnode, but in my quick check, it seems it is easy
> to expand fwnode side functions if of_graph side function exist ?

That would be one way to do that, yes, but I suggested using the existing
endpoint iterators as that would keep the firmware specific implementation
more simple. The (slight) drawback is that for each node returned, you'd
need to check its parent (i.e. port node) is the same as the port you're
interested in. The alternative may involve reworking the struct
fwnode_operations interface somewhat, including swnode, DT and ACPI
implementations.
Tomi Valkeinen Jan. 30, 2024, 7:37 a.m. UTC | #11
On 30/01/2024 09:31, Sakari Ailus wrote:
> Hi Morimoto-san,
> 
> On Tue, Jan 30, 2024 at 12:34:55AM +0000, Kuninori Morimoto wrote:
>>
>> Hi Laurent, Sakari
>>
>> Thank you for your review
>>
>>>> The strategy sounds good to me. However, I'm wondering if you shouldn't
>>>> take one more step in the core, and implement these as fwnode
>>>> operations. Or is there a reason why OF is special, and iterating over
>>>> ports would be useful for drivers on OF systems but not on other types
>>>> of systems ?
>>>
>>> I'd prefer that, too.
>>
>> It is very easy reason, because I'm not fwnode user ;P
>> I'm not familiar with fwnode, but in my quick check, it seems it is easy
>> to expand fwnode side functions if of_graph side function exist ?
> 
> That would be one way to do that, yes, but I suggested using the existing
> endpoint iterators as that would keep the firmware specific implementation
> more simple. The (slight) drawback is that for each node returned, you'd
> need to check its parent (i.e. port node) is the same as the port you're
> interested in. The alternative may involve reworking the struct
> fwnode_operations interface somewhat, including swnode, DT and ACPI
> implementations.
> 

But we still need the of_* versions, don't we, for patches 4 to 13?

  Tomi
Sakari Ailus Jan. 30, 2024, 7:40 a.m. UTC | #12
On Tue, Jan 30, 2024 at 09:37:42AM +0200, Tomi Valkeinen wrote:
> On 30/01/2024 09:31, Sakari Ailus wrote:
> > Hi Morimoto-san,
> > 
> > On Tue, Jan 30, 2024 at 12:34:55AM +0000, Kuninori Morimoto wrote:
> > > 
> > > Hi Laurent, Sakari
> > > 
> > > Thank you for your review
> > > 
> > > > > The strategy sounds good to me. However, I'm wondering if you shouldn't
> > > > > take one more step in the core, and implement these as fwnode
> > > > > operations. Or is there a reason why OF is special, and iterating over
> > > > > ports would be useful for drivers on OF systems but not on other types
> > > > > of systems ?
> > > > 
> > > > I'd prefer that, too.
> > > 
> > > It is very easy reason, because I'm not fwnode user ;P
> > > I'm not familiar with fwnode, but in my quick check, it seems it is easy
> > > to expand fwnode side functions if of_graph side function exist ?
> > 
> > That would be one way to do that, yes, but I suggested using the existing
> > endpoint iterators as that would keep the firmware specific implementation
> > more simple. The (slight) drawback is that for each node returned, you'd
> > need to check its parent (i.e. port node) is the same as the port you're
> > interested in. The alternative may involve reworking the struct
> > fwnode_operations interface somewhat, including swnode, DT and ACPI
> > implementations.
> > 
> 
> But we still need the of_* versions, don't we, for patches 4 to 13?

Yes, my comment was indeed about the fwnode property API only.
Kuninori Morimoto Jan. 30, 2024, 11:24 p.m. UTC | #13
Hi Sakari

> > > > I'm not familiar with fwnode, but in my quick check, it seems it is easy
> > > > to expand fwnode side functions if of_graph side function exist ?
> > > 
> > > That would be one way to do that, yes, but I suggested using the existing
> > > endpoint iterators as that would keep the firmware specific implementation
> > > more simple. The (slight) drawback is that for each node returned, you'd
> > > need to check its parent (i.e. port node) is the same as the port you're
> > > interested in. The alternative may involve reworking the struct
> > > fwnode_operations interface somewhat, including swnode, DT and ACPI
> > > implementations.
> > > 
> > 
> > But we still need the of_* versions, don't we, for patches 4 to 13?
> 
> Yes, my comment was indeed about the fwnode property API only.

Thank you for your suggestion.
But I'm not familiar with fwnode, and it seems we still need of_*,
I will keep current style (= non fwnode) in v3



Thank you for your help !!

Best regards
---
Renesas Electronics
Ph.D. Kuninori Morimoto
Rob Herring Jan. 31, 2024, 6:43 p.m. UTC | #14
On Mon, Jan 29, 2024 at 03:02:19PM +0200, Laurent Pinchart wrote:
> On Mon, Jan 29, 2024 at 02:29:22PM +0200, Tomi Valkeinen wrote:
> > On 29/01/2024 02:54, Kuninori Morimoto wrote:
> > > We already have of_graph_get_next_endpoint(), but it is not intuitive
> > > to use.
> > > 
> > > (X)	node {
> > > (Y)		ports {
> > > 			port@0 { endpoint { remote-endpoint = ...; };};
> > > (A1)			port@1 { endpoint { remote-endpoint = ...; };
> > > (A2)				 endpoint { remote-endpoint = ...; };};
> > > (B)			port@2 { endpoint { remote-endpoint = ...; };};
> > > 		};
> > > 	};
> > > 
> > > For example, if I want to handle port@1's 2 endpoints (= A1, A2),
> > > I want to use like below
> > > 
> > > 	A1 = of_graph_get_next_endpoint(port1, NULL);
> > > 	A2 = of_graph_get_next_endpoint(port1, A1);
> > > 
> > > But 1st one will be error, because of_graph_get_next_endpoint() requested
> > > "parent" means "node" (X) or "ports" (Y), not "port".
> > > Below are OK
> > > 
> > > 	of_graph_get_next_endpoint(node,  NULL); // node/ports/port@0/endpoint
> > > 	of_graph_get_next_endpoint(ports, NULL); // node/ports/port@0/endpoint
> > > 
> > > In other words, we can't handle A1/A2 directly via
> > > of_graph_get_next_endpoint() so far.
> > > 
> > > There is another non intuitive behavior on of_graph_get_next_endpoint().
> > > In case of if I could get A1 pointer for some way, and if I want to
> > > handle port@1 things, I would like use it like below
> > > 
> > > 	/*
> > > 	 * "endpoint" is now A1, and handle port1 things here,
> > > 	 * but we don't know how many endpoints port1 has.
> > > 	 *
> > > 	 * Because "endpoint" is non NULL, we can use port1
> > > 	 * as of_graph_get_next_endpoint(port1, xxx)
> > > 	 */
> > > 	do {
> > > 		/* do something for port1 specific things here */
> > > 	} while (endpoint = of_graph_get_next_endpoint(port1, endpoint))
> > > 
> > > But it also not worked as I expected.
> > > I expect it will be A1 -> A2 -> NULL,
> > > but      it will be A1 -> A2 -> B,    because of_graph_get_next_endpoint()
> > > will fetch endpoint beyond the port.
> > > 
> > > It is not useful on generic driver like Generic Sound Card.
> > > It uses of_get_next_child() instead for now, but it is not intuitive,
> > > and not check node name (= "endpoint").
> > > 
> > > To handle endpoint more intuitive, create of_graph_get_next_endpoint_raw()
> > > 
> > > 	of_graph_get_next_endpoint_raw(port1, NULL); // A1
> > > 	of_graph_get_next_endpoint_raw(port1, A1);   // A2
> > > 	of_graph_get_next_endpoint_raw(port1, A2);   // NULL
> > > 
> > > Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> > > ---
> > >   drivers/of/property.c    | 26 +++++++++++++++++++++++++-
> > >   include/linux/of_graph.h |  2 ++
> > >   2 files changed, 27 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/of/property.c b/drivers/of/property.c
> > > index 14ffd199c9b1..37dbb1b0e742 100644
> > > --- a/drivers/of/property.c
> > > +++ b/drivers/of/property.c
> > > @@ -667,6 +667,30 @@ struct device_node *of_graph_get_next_port(const struct device_node *parent,
> > >   }
> > >   EXPORT_SYMBOL(of_graph_get_next_port);
> > >   
> > > +/**
> > > + * of_graph_get_next_endpoint_raw() - get next endpoint node
> > 
> > How about "of_graph_get_next_port_endpoint()"?
> 
> We may want to also rename the existing of_graph_get_next_endpoint()
> function to of_graph_next_dev_endpoint() then. It would be a tree-wide
> patch, which is always annoying to get reviewed and merged, so if Rob
> would prefer avoiding the rename, I'm fine with that.

I think we should get rid of or minimize of_graph_get_next_endpoint() in 
its current form. In general, drivers should be asking for a specific 
port number because their function is fixed in the binding. Iterating 
over endpoints within a port is okay as that's usually a selecting 1 of 
N operation. 

Most cases are in the form of of_graph_get_next_endpoint(dev, NULL) 
which is equivalent to of_graph_get_endpoint_by_regs(dev, 0, 0). 
Technically, -1 instead of 0 is equivalent, but I'd argue is sloppy and 
wrong.

I also added of_graph_get_remote_node() for this reason and cleaned a 
lot of these (in DRM) up some time ago. Because in the end, a driver 
generally just wants the remote device it is connected to and details of 
parsing the graph should be mostly opaque.

Wouldn't something like this work for this case:

#define for_each_port_endpoint_of_node(parent, port, child) \
	for (child = of_graph_get_endpoint_by_regs(parent, port, -1); child != NULL; \
	     child = of_get_next_child(parent, child))

Rob
Rob Herring Jan. 31, 2024, 6:52 p.m. UTC | #15
On Mon, Jan 29, 2024 at 12:54:44AM +0000, Kuninori Morimoto wrote:
> We have endpoint base functions
> 	- of_graph_get_next_endpoint()
> 	- of_graph_get_endpoint_count()
> 	- for_each_endpoint_of_node()
> 
> Here, for_each_endpoint_of_node() loop finds each endpoints
> 
> 	ports {
> 		port@0 {
> (1)			endpoint {...};
> 		};
> 		port@1 {
> (2)			endpoint {...};
> 		};
> 		...
> 	};
> 
> In above case, for_each_endpoint_of_node() loop finds endpoint as
> (1) -> (2) -> ...
> 
> Basically, user/driver knows which port is used for what, but not in
> all cases. For example on flexible/generic driver case, how many ports
> are used is not fixed.
> 
> For example Sound Generic Card driver which is used from many venders
> can't know how many ports are used. Because the driver is very
> flexible/generic, it is impossible to know how many ports are used,
> it depends on each vender SoC and/or its used board.
> 
> And more, the port can have multi endpoints. For example Generic Sound
> Card case, it supports many type of connection between CPU / Codec, and
> some of them uses multi endpoint in one port.
> Then, Generic Sound Card want to handle each connection via "port"
> instead of "endpoint".
> But, it is very difficult to handle each "port" by
> for_each_endpoint_of_node(). Getting "port" by using of_get_parent()
> from "endpoint" doesn't work. see below.
> 
> 	ports {
> 		port@0 {
> (1)			endpoint@0 {...};
> (2)			endpoint@1 {...};
> 		};
> 		port@1 {
> (3)			endpoint {...};
> 		};
> 		...
> 	};
> 
> Add "port" base functions.
> 
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> ---
>  drivers/of/property.c    | 48 ++++++++++++++++++++++++++++++++++++++++
>  include/linux/of_graph.h | 21 ++++++++++++++++++
>  2 files changed, 69 insertions(+)
> 
> diff --git a/drivers/of/property.c b/drivers/of/property.c
> index afdaefbd03f6..9e670e99dbbb 100644
> --- a/drivers/of/property.c
> +++ b/drivers/of/property.c
> @@ -631,6 +631,42 @@ struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id)
>  }
>  EXPORT_SYMBOL(of_graph_get_port_by_id);
>  
> +/**
> + * of_graph_get_next_port() - get next port node
> + * @parent: pointer to the parent device node
> + * @port: current port node, or NULL to get first
> + *
> + * Return: An 'port' node pointer with refcount incremented. Refcount
> + * of the passed @prev node is decremented.
> + */
> +struct device_node *of_graph_get_next_port(const struct device_node *parent,
> +					   struct device_node *port)
> +{
> +	if (!parent)
> +		return NULL;
> +
> +	if (!port) {
> +		struct device_node *node;
> +
> +		node = of_get_child_by_name(parent, "ports");
> +		if (node) {
> +			parent = node;
> +			of_node_put(node);

The original code had this right, but here you have it wrong.

You are releasing ports here, but then using it...

> +		}
> +
> +		return of_get_child_by_name(parent, "port");

...here. You have to get the child before you can put the parent.

> +	}
> +
> +	do {
> +		port = of_get_next_child(parent, port);
> +		if (!port)
> +			break;
> +	} while (!of_node_name_eq(port, "port"));
> +
> +	return port;
> +}
> +EXPORT_SYMBOL(of_graph_get_next_port);
> +
Rob Herring Jan. 31, 2024, 6:59 p.m. UTC | #16
On Mon, Jan 29, 2024 at 12:54:44AM +0000, Kuninori Morimoto wrote:
> We have endpoint base functions
> 	- of_graph_get_next_endpoint()
> 	- of_graph_get_endpoint_count()
> 	- for_each_endpoint_of_node()

I also noticed that your mail setup has an issue. You have some utf-8 
encoded email names, but the headers say it is ascii. git-send-email 
should do the right thing here, but maybe Exchange is messing things up.

Rob
Kuninori Morimoto Jan. 31, 2024, 11:25 p.m. UTC | #17
Hi Rob

Thank you for review

> > +/**
> > + * of_graph_get_next_port() - get next port node
> > + * @parent: pointer to the parent device node
> > + * @port: current port node, or NULL to get first
> > + *
> > + * Return: An 'port' node pointer with refcount incremented. Refcount
> > + * of the passed @prev node is decremented.
> > + */
> > +struct device_node *of_graph_get_next_port(const struct device_node *parent,
> > +					   struct device_node *port)
> > +{
> > +	if (!parent)
> > +		return NULL;
> > +
> > +	if (!port) {
> > +		struct device_node *node;
> > +
> > +		node = of_get_child_by_name(parent, "ports");
> > +		if (node) {
> > +			parent = node;
> > +			of_node_put(node);
> 
> The original code had this right, but here you have it wrong.
> 
> You are releasing ports here, but then using it...
> 
> > +		}
> > +
> > +		return of_get_child_by_name(parent, "port");
> 
> ...here. You have to get the child before you can put the parent.

You are reviewing v2, and it was already fixed in v3

Thank you for your help !!

Best regards
---
Renesas Electronics
Ph.D. Kuninori Morimoto
Kuninori Morimoto Feb. 1, 2024, 12:43 a.m. UTC | #18
Hi Rob

> I think we should get rid of or minimize of_graph_get_next_endpoint() in 
> its current form. In general, drivers should be asking for a specific 
> port number because their function is fixed in the binding. Iterating 
> over endpoints within a port is okay as that's usually a selecting 1 of 
> N operation. 
> 
> Most cases are in the form of of_graph_get_next_endpoint(dev, NULL) 
> which is equivalent to of_graph_get_endpoint_by_regs(dev, 0, 0). 
> Technically, -1 instead of 0 is equivalent, but I'd argue is sloppy and 
> wrong.
> 
> I also added of_graph_get_remote_node() for this reason and cleaned a 
> lot of these (in DRM) up some time ago. Because in the end, a driver 
> generally just wants the remote device it is connected to and details of 
> parsing the graph should be mostly opaque.
> 
> Wouldn't something like this work for this case:
> 
> #define for_each_port_endpoint_of_node(parent, port, child) \
> 	for (child = of_graph_get_endpoint_by_regs(parent, port, -1); child != NULL; \
> 	     child = of_get_next_child(parent, child))

I see.
I will split this patch-set to like below

	- patch-set for reduce/remove to using current next_endpoint()
	- patch-set for rename current next_endpoint() to next_device_endpoint()
	- patch-set for adding new next_port_endpoint()


Thank you for your help !!

Best regards
---
Renesas Electronics
Ph.D. Kuninori Morimoto
Kuninori Morimoto Feb. 1, 2024, 1:48 a.m. UTC | #19
Hi Rob

> > #define for_each_port_endpoint_of_node(parent, port, child) \
> > 	for (child = of_graph_get_endpoint_by_regs(parent, port, -1); child != NULL; \
> > 	     child = of_get_next_child(parent, child))

Hmm... I noticed it is impossible so for.
of_graph_get_endpoint_by_regs() (A) is based on for_each_endpoint_of_node() (B).
Thus, we can't replace for_each_endpoint_of_node() (B) with by_regs (A)

(A)	struct device_node *of_graph_get_endpoint_by_regs(...)
	{
		...
(B)		for_each_endpoint_of_node(parent, node) {
			...
		}

		return NULL;
	}

> 	- patch-set for reduce/remove to using current next_endpoint()
> 	- patch-set for rename current next_endpoint() to next_device_endpoint()
> 	- patch-set for adding new next_port_endpoint()

So, maybe we can do is,

	0) rename current endpoint functions to device_endpoint

	1) add new port base functions (port_endpoint) which has
	   for_each_of_graph_port_endpoint() loop. It is for port base endpoint loop
	   (I want to use new naming, using of_graph instead of _of_node).

	2) replace above (B) part with port base loops 

	-	for_each_endpoint_of_node(parent, node) {
	+	for_each_of_gprah_port(parent, port) {
	+		for_each_of_graph_port_endpoint(port, endpoint) {

	3) replace current next_endpoint() by next_endpoint_by_regs(),
	   and remove next_endpoint()

What do you think ?

Thank you for your help !!

Best regards
---
Renesas Electronics
Ph.D. Kuninori Morimoto
Sakari Ailus Feb. 1, 2024, 9:18 a.m. UTC | #20
Hi Morimoto-san,

On Tue, Jan 30, 2024 at 11:24:07PM +0000, Kuninori Morimoto wrote:
> 
> Hi Sakari
> 
> > > > > I'm not familiar with fwnode, but in my quick check, it seems it is easy
> > > > > to expand fwnode side functions if of_graph side function exist ?
> > > > 
> > > > That would be one way to do that, yes, but I suggested using the existing
> > > > endpoint iterators as that would keep the firmware specific implementation
> > > > more simple. The (slight) drawback is that for each node returned, you'd
> > > > need to check its parent (i.e. port node) is the same as the port you're
> > > > interested in. The alternative may involve reworking the struct
> > > > fwnode_operations interface somewhat, including swnode, DT and ACPI
> > > > implementations.
> > > > 
> > > 
> > > But we still need the of_* versions, don't we, for patches 4 to 13?
> > 
> > Yes, my comment was indeed about the fwnode property API only.
> 
> Thank you for your suggestion.
> But I'm not familiar with fwnode, and it seems we still need of_*,
> I will keep current style (= non fwnode) in v3

The fwnode API should be kept in sync with the OF (and other firmware
specific) API. Merging your set in its current form would leave fwnode API
impaired. Therefore I'd very much prefer to see this set add similar fwnode
APIs, too.
Kuninori Morimoto Feb. 5, 2024, 5:31 a.m. UTC | #21
Hi Sakari

> > Thank you for your suggestion.
> > But I'm not familiar with fwnode, and it seems we still need of_*,
> > I will keep current style (= non fwnode) in v3
> 
> The fwnode API should be kept in sync with the OF (and other firmware
> specific) API. Merging your set in its current form would leave fwnode API
> impaired. Therefore I'd very much prefer to see this set add similar fwnode
> APIs, too.

I will keep current fwnode API behavior, but I can't test it.
Now, I'm separating the patch-set into small stages.
There is no problem for a while, but I think I will ask you to test it in the
final stage.


Thank you for your help !!

Best regards
---
Renesas Electronics
Ph.D. Kuninori Morimoto