brcm63xx: Add DT support for A4001N
[openwrt/svn-archive/archive.git] / target / linux / brcm63xx / patches-3.14 / 003-of-Make-of_find_node_by_path-handle-aliases.patch
1 From c22e650e66b862babe9c00bebb20b8029c7b0362 Mon Sep 17 00:00:00 2001
2 From: Grant Likely <grant.likely@linaro.org>
3 Date: Fri, 14 Mar 2014 17:07:12 +0000
4 Subject: [PATCH] of: Make of_find_node_by_path() handle /aliases
5
6 Make of_find_node_by_path() handle aliases as prefixes. To make this
7 work the name search is refactored to search by path component instead
8 of by full string. This should be a more efficient search, and it makes
9 it possible to start a search at a subnode of a tree.
10
11 Signed-off-by: David Daney <david.daney@cavium.com>
12 Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
13 [grant.likely: Rework to not require allocating at runtime]
14 Acked-by: Rob Herring <robh@kernel.org>
15 Signed-off-by: Grant Likely <grant.likely@linaro.org>
16 ---
17 drivers/of/base.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
18 1 file changed, 61 insertions(+), 6 deletions(-)
19
20 --- a/drivers/of/base.c
21 +++ b/drivers/of/base.c
22 @@ -633,23 +633,78 @@ struct device_node *of_get_child_by_name
23 }
24 EXPORT_SYMBOL(of_get_child_by_name);
25
26 +static struct device_node *__of_find_node_by_path(struct device_node *parent,
27 + const char *path)
28 +{
29 + struct device_node *child;
30 + int len = strchrnul(path, '/') - path;
31 +
32 + if (!len)
33 + return NULL;
34 +
35 + __for_each_child_of_node(parent, child) {
36 + const char *name = strrchr(child->full_name, '/');
37 + if (WARN(!name, "malformed device_node %s\n", child->full_name))
38 + continue;
39 + name++;
40 + if (strncmp(path, name, len) == 0 && (strlen(name) == len))
41 + return child;
42 + }
43 + return NULL;
44 +}
45 +
46 /**
47 * of_find_node_by_path - Find a node matching a full OF path
48 - * @path: The full path to match
49 + * @path: Either the full path to match, or if the path does not
50 + * start with '/', the name of a property of the /aliases
51 + * node (an alias). In the case of an alias, the node
52 + * matching the alias' value will be returned.
53 + *
54 + * Valid paths:
55 + * /foo/bar Full path
56 + * foo Valid alias
57 + * foo/bar Valid alias + relative path
58 *
59 * Returns a node pointer with refcount incremented, use
60 * of_node_put() on it when done.
61 */
62 struct device_node *of_find_node_by_path(const char *path)
63 {
64 - struct device_node *np = of_allnodes;
65 + struct device_node *np = NULL;
66 + struct property *pp;
67 unsigned long flags;
68
69 + if (strcmp(path, "/") == 0)
70 + return of_node_get(of_allnodes);
71 +
72 + /* The path could begin with an alias */
73 + if (*path != '/') {
74 + char *p = strchrnul(path, '/');
75 + int len = p - path;
76 +
77 + /* of_aliases must not be NULL */
78 + if (!of_aliases)
79 + return NULL;
80 +
81 + for_each_property_of_node(of_aliases, pp) {
82 + if (strlen(pp->name) == len && !strncmp(pp->name, path, len)) {
83 + np = of_find_node_by_path(pp->value);
84 + break;
85 + }
86 + }
87 + if (!np)
88 + return NULL;
89 + path = p;
90 + }
91 +
92 + /* Step down the tree matching path components */
93 raw_spin_lock_irqsave(&devtree_lock, flags);
94 - for (; np; np = np->allnext) {
95 - if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
96 - && of_node_get(np))
97 - break;
98 + if (!np)
99 + np = of_node_get(of_allnodes);
100 + while (np && *path == '/') {
101 + path++; /* Increment past '/' delimiter */
102 + np = __of_find_node_by_path(np, path);
103 + path = strchrnul(path, '/');
104 }
105 raw_spin_unlock_irqrestore(&devtree_lock, flags);
106 return np;