Make of_find_node_by_path() handle aliases as prefixes. To make this
work the name search is refactored to search by path component instead
of by full string. This should be a more efficient search, and it makes
it possible to start a search at a subnode of a tree.

Signed-off-by: David Daney <david.da...@cavium.com>
Signed-off-by: Pantelis Antoniou <pantelis.anton...@konsulko.com>
[grant.likely: Rework to not require allocating at runtime]
Signed-off-by: Grant Likely <grant.lik...@linaro.org>
---
 drivers/of/base.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 56 insertions(+), 4 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 7083fad079a6..b8b673526dbd 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -770,9 +770,38 @@ struct device_node *of_get_child_by_name(const struct 
device_node *node,
 }
 EXPORT_SYMBOL(of_get_child_by_name);
 
+static struct device_node *__of_find_node_by_path(struct device_node *parent,
+                                               const char *path)
+{
+       struct device_node *child;
+       int len = strchrnul(path, '/') - path;
+
+       if (!len)
+               return parent;
+
+       for_each_child_of_node(parent, child) {
+               const char *name = strrchr(child->full_name, '/');
+               if (WARN(!name, "malformed device_node %s\n", child->full_name))
+                       continue;
+               name++;
+               if (strncmp(path, name, len) == 0 && (strlen(name) == len))
+                       return child;
+       }
+       return NULL;
+}
+
 /**
  *     of_find_node_by_path - Find a node matching a full OF path
  *     @path:  The full path to match
+ *     @path: Either the full path to match, or if the path does not
+ *            start with '/', the name of a property of the /aliases
+ *            node (an alias).  In the case of an alias, the node
+ *            matching the alias' value will be returned.
+ *
+ *     Valid paths:
+ *             /foo/bar        Full path
+ *             foo             Valid alias
+ *             foo/bar         Valid alias + relative path
  *
  *     Returns a node pointer with refcount incremented, use
  *     of_node_put() on it when done.
@@ -780,13 +809,36 @@ EXPORT_SYMBOL(of_get_child_by_name);
 struct device_node *of_find_node_by_path(const char *path)
 {
        struct device_node *np = of_allnodes;
+       struct property *pp;
        unsigned long flags;
 
+       /* The path could begin with an alias */
+       if (*path != '/') {
+               char *p = strchrnul(path, '/');
+               int len = p - path;
+
+               /* of_aliases must not be NULL */
+               if (!of_aliases)
+                       return NULL;
+
+               np = NULL;
+               for_each_property_of_node(of_aliases, pp) {
+                       if (strlen(pp->name) == len && !strncmp(pp->name, path, 
len)) {
+                               np = of_find_node_by_path(pp->value);
+                               break;
+                       }
+               }
+               if (!np)
+                       return NULL;
+               path = p;
+       }
+
+       /* Step down the tree matching path components */
        raw_spin_lock_irqsave(&devtree_lock, flags);
-       for (; np; np = np->allnext) {
-               if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
-                   && of_node_get(np))
-                       break;
+       while (np && *path == '/') {
+               path++; /* Increment past '/' delimiter */
+               np = __of_find_node_by_path(np, path);
+               path = strchrnul(path, '/');
        }
        raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return np;
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to