Patchwork [V4,1/3] of: introduce for_each_matching_node_and_match()

login
register
mail settings
Submitter Stephen Warren
Date Nov. 20, 2012, 11:12 p.m.
Message ID <1353453142-4973-1-git-send-email-swarren@wwwdotorg.org>
Download mbox | patch
Permalink /patch/200528/
State Not Applicable, archived
Headers show

Comments

Stephen Warren - Nov. 20, 2012, 11:12 p.m.
From: Stephen Warren <swarren@nvidia.com>

The following pattern of code is tempting:

    for_each_matching_node(np, table) {
        match = of_match_node(table, np);

However, this results in iterating over table twice; the second time
inside of_match_node(). The implementation of for_each_matching_node()
already found the match, so this is redundant. Invent new function
of_find_matching_node_and_match() and macro
for_each_matching_node_and_match() to remove the double iteration,
thus transforming the above code to:

    for_each_matching_node_and_match(np, table, &match)

Signed-off-by: Stephen Warren <swarren@nvidia.com>
---
v4: New patch.

This series is based on the ARM sys_timer rework that I posted yesterday,
although patch 1/3 should be completely independant of that, and could
perhaps even be applied for 3.8 right now.

I hope that these patches can be taken through arm-soc tree for 3.9;
I will repost them based on 3.8-rc1 at the appropriate time.
---
 drivers/of/base.c  |   18 +++++++++++++-----
 include/linux/of.h |   15 +++++++++++++--
 2 files changed, 26 insertions(+), 7 deletions(-)
Rob Herring - Nov. 20, 2012, 11:52 p.m.
On 11/20/2012 05:12 PM, Stephen Warren wrote:
> From: Stephen Warren <swarren@nvidia.com>
> 
> The following pattern of code is tempting:
> 
>     for_each_matching_node(np, table) {
>         match = of_match_node(table, np);
> 
> However, this results in iterating over table twice; the second time
> inside of_match_node(). The implementation of for_each_matching_node()
> already found the match, so this is redundant. Invent new function
> of_find_matching_node_and_match() and macro
> for_each_matching_node_and_match() to remove the double iteration,
> thus transforming the above code to:
> 
>     for_each_matching_node_and_match(np, table, &match)
> 
> Signed-off-by: Stephen Warren <swarren@nvidia.com>
> ---
> v4: New patch.
> 
> This series is based on the ARM sys_timer rework that I posted yesterday,
> although patch 1/3 should be completely independant of that, and could
> perhaps even be applied for 3.8 right now.

Agreed. I will apply for 3.8 assuming no further comments in the next
few days.

Rob

> I hope that these patches can be taken through arm-soc tree for 3.9;
> I will repost them based on 3.8-rc1 at the appropriate time.
> ---
>  drivers/of/base.c  |   18 +++++++++++++-----
>  include/linux/of.h |   15 +++++++++++++--
>  2 files changed, 26 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index f2f63c8..094271e 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -594,27 +594,35 @@ const struct of_device_id *of_match_node(const struct of_device_id *matches,
>  EXPORT_SYMBOL(of_match_node);
>  
>  /**
> - *	of_find_matching_node - Find a node based on an of_device_id match
> - *				table.
> + *	of_find_matching_node_and_match - Find a node based on an of_device_id
> + *					  match table.
>   *	@from:		The node to start searching from or NULL, the node
>   *			you pass will not be searched, only the next one
>   *			will; typically, you pass what the previous call
>   *			returned. of_node_put() will be called on it
>   *	@matches:	array of of device match structures to search in
> + *	@match		Updated to point at the matches entry which matched
>   *
>   *	Returns a node pointer with refcount incremented, use
>   *	of_node_put() on it when done.
>   */
> -struct device_node *of_find_matching_node(struct device_node *from,
> -					  const struct of_device_id *matches)
> +struct device_node *of_find_matching_node_and_match(struct device_node *from,
> +					const struct of_device_id *matches,
> +					const struct of_device_id **match)
>  {
>  	struct device_node *np;
>  
> +	if (match)
> +		*match = NULL;
> +
>  	read_lock(&devtree_lock);
>  	np = from ? from->allnext : allnodes;
>  	for (; np; np = np->allnext) {
> -		if (of_match_node(matches, np) && of_node_get(np))
> +		if (of_match_node(matches, np) && of_node_get(np)) {
> +			if (match)
> +				*match = matches;
>  			break;
> +		}
>  	}
>  	of_node_put(from);
>  	read_unlock(&devtree_lock);
> diff --git a/include/linux/of.h b/include/linux/of.h
> index 681a6c8..1000496 100644
> --- a/include/linux/of.h
> +++ b/include/linux/of.h
> @@ -180,11 +180,22 @@ extern struct device_node *of_find_compatible_node(struct device_node *from,
>  #define for_each_compatible_node(dn, type, compatible) \
>  	for (dn = of_find_compatible_node(NULL, type, compatible); dn; \
>  	     dn = of_find_compatible_node(dn, type, compatible))
> -extern struct device_node *of_find_matching_node(struct device_node *from,
> -	const struct of_device_id *matches);
> +extern struct device_node *of_find_matching_node_and_match(
> +	struct device_node *from,
> +	const struct of_device_id *matches,
> +	const struct of_device_id **match);
> +static inline struct device_node *of_find_matching_node(
> +	struct device_node *from,
> +	const struct of_device_id *matches)
> +{
> +	return of_find_matching_node_and_match(from, matches, NULL);
> +}
>  #define for_each_matching_node(dn, matches) \
>  	for (dn = of_find_matching_node(NULL, matches); dn; \
>  	     dn = of_find_matching_node(dn, matches))
> +#define for_each_matching_node_and_match(dn, matches, match) \
> +	for (dn = of_find_matching_node_and_match(NULL, matches, match); \
> +	     dn; dn = of_find_matching_node_and_match(dn, matches, match))
>  extern struct device_node *of_find_node_by_path(const char *path);
>  extern struct device_node *of_find_node_by_phandle(phandle handle);
>  extern struct device_node *of_get_parent(const struct device_node *node);
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Arnd Bergmann - Nov. 21, 2012, 9:53 a.m.
On Tuesday 20 November 2012, Stephen Warren wrote:
> However, this results in iterating over table twice; the second time
> inside of_match_node(). The implementation of for_each_matching_node()
> already found the match, so this is redundant. Invent new function
> of_find_matching_node_and_match() and macro
> for_each_matching_node_and_match() to remove the double iteration,
> thus transforming the above code to:
> 
>     for_each_matching_node_and_match(np, table, &match)
> 
> Signed-off-by: Stephen Warren <swarren@nvidia.com>

This look useful, but I wonder if the interface would make more sense if you
make the last argument to the macro a normal pointer, rather than a
pointer-to-pointer. You can take the reference as part of the macro.

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Grant Likely - Nov. 21, 2012, 10:06 a.m.
On Wed, Nov 21, 2012 at 9:53 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Tuesday 20 November 2012, Stephen Warren wrote:
>> However, this results in iterating over table twice; the second time
>> inside of_match_node(). The implementation of for_each_matching_node()
>> already found the match, so this is redundant. Invent new function
>> of_find_matching_node_and_match() and macro
>> for_each_matching_node_and_match() to remove the double iteration,
>> thus transforming the above code to:
>>
>>     for_each_matching_node_and_match(np, table, &match)
>>
>> Signed-off-by: Stephen Warren <swarren@nvidia.com>
>
> This look useful, but I wonder if the interface would make more sense if you
> make the last argument to the macro a normal pointer, rather than a
> pointer-to-pointer. You can take the reference as part of the macro.

To me that makes for harder to understand code. It *looks* like an
argument to a normal function call, but it gets changed by the caller.

g.
--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Thomas Petazzoni - Nov. 21, 2012, 10:09 a.m.
On Wed, 21 Nov 2012 10:06:16 +0000, Grant Likely wrote:
> On Wed, Nov 21, 2012 at 9:53 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Tuesday 20 November 2012, Stephen Warren wrote:
> >> However, this results in iterating over table twice; the second time
> >> inside of_match_node(). The implementation of for_each_matching_node()
> >> already found the match, so this is redundant. Invent new function
> >> of_find_matching_node_and_match() and macro
> >> for_each_matching_node_and_match() to remove the double iteration,
> >> thus transforming the above code to:
> >>
> >>     for_each_matching_node_and_match(np, table, &match)
> >>
> >> Signed-off-by: Stephen Warren <swarren@nvidia.com>
> >
> > This look useful, but I wonder if the interface would make more sense if you
> > make the last argument to the macro a normal pointer, rather than a
> > pointer-to-pointer. You can take the reference as part of the macro.
> 
> To me that makes for harder to understand code. It *looks* like an
> argument to a normal function call, but it gets changed by the caller.

Agreed. Too much magic is too much.

Thomas

Patch

diff --git a/drivers/of/base.c b/drivers/of/base.c
index f2f63c8..094271e 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -594,27 +594,35 @@  const struct of_device_id *of_match_node(const struct of_device_id *matches,
 EXPORT_SYMBOL(of_match_node);
 
 /**
- *	of_find_matching_node - Find a node based on an of_device_id match
- *				table.
+ *	of_find_matching_node_and_match - Find a node based on an of_device_id
+ *					  match table.
  *	@from:		The node to start searching from or NULL, the node
  *			you pass will not be searched, only the next one
  *			will; typically, you pass what the previous call
  *			returned. of_node_put() will be called on it
  *	@matches:	array of of device match structures to search in
+ *	@match		Updated to point at the matches entry which matched
  *
  *	Returns a node pointer with refcount incremented, use
  *	of_node_put() on it when done.
  */
-struct device_node *of_find_matching_node(struct device_node *from,
-					  const struct of_device_id *matches)
+struct device_node *of_find_matching_node_and_match(struct device_node *from,
+					const struct of_device_id *matches,
+					const struct of_device_id **match)
 {
 	struct device_node *np;
 
+	if (match)
+		*match = NULL;
+
 	read_lock(&devtree_lock);
 	np = from ? from->allnext : allnodes;
 	for (; np; np = np->allnext) {
-		if (of_match_node(matches, np) && of_node_get(np))
+		if (of_match_node(matches, np) && of_node_get(np)) {
+			if (match)
+				*match = matches;
 			break;
+		}
 	}
 	of_node_put(from);
 	read_unlock(&devtree_lock);
diff --git a/include/linux/of.h b/include/linux/of.h
index 681a6c8..1000496 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -180,11 +180,22 @@  extern struct device_node *of_find_compatible_node(struct device_node *from,
 #define for_each_compatible_node(dn, type, compatible) \
 	for (dn = of_find_compatible_node(NULL, type, compatible); dn; \
 	     dn = of_find_compatible_node(dn, type, compatible))
-extern struct device_node *of_find_matching_node(struct device_node *from,
-	const struct of_device_id *matches);
+extern struct device_node *of_find_matching_node_and_match(
+	struct device_node *from,
+	const struct of_device_id *matches,
+	const struct of_device_id **match);
+static inline struct device_node *of_find_matching_node(
+	struct device_node *from,
+	const struct of_device_id *matches)
+{
+	return of_find_matching_node_and_match(from, matches, NULL);
+}
 #define for_each_matching_node(dn, matches) \
 	for (dn = of_find_matching_node(NULL, matches); dn; \
 	     dn = of_find_matching_node(dn, matches))
+#define for_each_matching_node_and_match(dn, matches, match) \
+	for (dn = of_find_matching_node_and_match(NULL, matches, match); \
+	     dn; dn = of_find_matching_node_and_match(dn, matches, match))
 extern struct device_node *of_find_node_by_path(const char *path);
 extern struct device_node *of_find_node_by_phandle(phandle handle);
 extern struct device_node *of_get_parent(const struct device_node *node);