[PATCH 11/22] OF: base: import of_find_matching_node_and_match from Linux OF API
NISHIMOTO Hiroki
hiroki.nishimoto.if at gmail.com
Tue Jul 2 14:35:01 EDT 2013
Hi,
on master/next branch,
of_find_matching_node_and_match macro can make infinite loop.
This is because, of_tree_for_each_node traverse all nodes each time.
But a callee of of_find_matching_node_and_match,
such as for_each_matching_node, calls it by changing "from" arg.
So if "matches" have two or more nodes, previously matched node can be re-matched.
Below change can fix the issue.
Or is it better to port node->allnext from linux kernel?
Signed-off-by: NISHIMOTO Hiroki <hiroki.nishimoto.if at gmail.com>
---
drivers/of/base.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 63ff647..36774de 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -36,6 +36,9 @@
#define of_tree_for_each_node(node, root) \
list_for_each_entry(node, &root->list, list)
+#define of_get_next_node(np) \
+ list_first_entry(&np->list, typeof(*np), list)
+
/**
* struct alias_prop - Alias property in 'aliases' node
* @link: List node to link the structure in aliases_lookup list
@@ -444,17 +447,20 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from,
if (match)
*match = NULL;
- if (!from)
- from = root_node;
+ np = from ? of_get_next_node(from) : root_node;
- of_tree_for_each_node(np, from) {
+ if (from != NULL && np == root_node)
+ return NULL;
+
+ do {
const struct of_device_id *m = of_match_node(matches, np);
if (m) {
if (match)
*match = m;
return np;
}
- }
+ np = of_get_next_node(np);
+ } while (np != root_node);
return NULL;
}
--
1.8.1.2
> This imports of_find_matching_node_and_match and corresponding helpers
> from Linux OF API.
>
> Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth at xxxxxxxxx>
> ---
> Cc: barebox at xxxxxxxxxxxxxxxxxxx
> ---
> drivers/of/base.c | 37 +++++++++++++++++++++++++++++++++++++
> include/of.h | 24 ++++++++++++++++++++++++
> 2 files changed, 61 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index 50a3c22..218cb5a 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -389,6 +389,43 @@ const struct of_device_id *of_match_node(const struct of_device_id *matches,
> return NULL;
> }
>
> +/**
> + * 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.
> + * @matches: array of of device match structures to search in
> + * @match Updated to point at the matches entry which matched
> + *
> + * Returns a pointer to the node found or NULL.
> + */
> +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;
> +
> + if (!from)
> + from = root_node;
> +
> + of_tree_for_each_node(np, from) {
> + const struct of_device_id *m = of_match_node(matches, np);
> + if (m) {
> + if (match)
> + *match = m;
> + return np;
> + }
> + }
> +
> + return NULL;
> +}
> +EXPORT_SYMBOL(of_find_matching_node_and_match);
> +
> int of_match(struct device_d *dev, struct driver_d *drv)
> {
> const struct of_device_id *id;
> diff --git a/include/of.h b/include/of.h
> index e170e2b..c21e73d 100644
> --- a/include/of.h
> +++ b/include/of.h
> @@ -187,6 +187,10 @@ extern struct device_node *of_find_node_by_name(struct device_node *from,
> extern struct device_node *of_find_node_by_path(const char *path);
> extern struct device_node *of_find_compatible_node(struct device_node *from,
> const char *type, const char *compat);
> +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);
> extern int of_device_is_available(const struct device_node *device);
>
> extern void of_alias_scan(void);
> @@ -259,6 +263,14 @@ static inline struct device_node *of_find_compatible_node(
> return NULL;
> }
>
> +static inline 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)
> +{
> + return NULL;
> +}
> +
> static inline int of_device_is_available(const struct device_node *device)
> {
> return 0;
> @@ -285,5 +297,17 @@ static inline const char *of_alias_get(struct device_node *np)
> #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))
> +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))
>
> #endif /* __OF_H */
> --
> 1.7.2.5
More information about the barebox
mailing list