]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/of/resolver.c
of: Remove excessive printks to reduce clutter.
[mirror_ubuntu-artful-kernel.git] / drivers / of / resolver.c
CommitLineData
7941b27b
PA
1/*
2 * Functions for dealing with DT resolution
3 *
4 * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
5 * Copyright (C) 2012 Texas Instruments Inc.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation.
10 */
11
606ad42a
RH
12#define pr_fmt(fmt) "OF: resolver: " fmt
13
7941b27b
PA
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/of.h>
17#include <linux/of_device.h>
18#include <linux/string.h>
19#include <linux/ctype.h>
20#include <linux/errno.h>
21#include <linux/string.h>
22#include <linux/slab.h>
23
24/* illegal phandle value (set when unresolved) */
25#define OF_PHANDLE_ILLEGAL 0xdeadbeef
26
27/**
28 * Find a node with the give full name by recursively following any of
29 * the child node links.
30 */
31static struct device_node *__of_find_node_by_full_name(struct device_node *node,
32 const char *full_name)
33{
34 struct device_node *child, *found;
35
36 if (node == NULL)
37 return NULL;
38
7941b27b 39 if (of_node_cmp(node->full_name, full_name) == 0)
82f68756 40 return of_node_get(node);
7941b27b
PA
41
42 for_each_child_of_node(node, child) {
43 found = __of_find_node_by_full_name(child, full_name);
82f68756
AKC
44 if (found != NULL) {
45 of_node_put(child);
7941b27b 46 return found;
82f68756 47 }
7941b27b
PA
48 }
49
50 return NULL;
51}
52
53/*
54 * Find live tree's maximum phandle value.
55 */
56static phandle of_get_tree_max_phandle(void)
57{
58 struct device_node *node;
59 phandle phandle;
60 unsigned long flags;
61
7941b27b
PA
62 raw_spin_lock_irqsave(&devtree_lock, flags);
63 phandle = 0;
64 for_each_of_allnodes(node) {
65 if (node->phandle != OF_PHANDLE_ILLEGAL &&
66 node->phandle > phandle)
67 phandle = node->phandle;
68 }
69 raw_spin_unlock_irqrestore(&devtree_lock, flags);
70
71 return phandle;
72}
73
74/*
75 * Adjust a subtree's phandle values by a given delta.
7941b27b
PA
76 */
77static void __of_adjust_tree_phandles(struct device_node *node,
78 int phandle_delta)
79{
80 struct device_node *child;
81 struct property *prop;
82 phandle phandle;
83
7941b27b
PA
84 if (node->phandle != 0 && node->phandle != OF_PHANDLE_ILLEGAL)
85 node->phandle += phandle_delta;
86
7941b27b
PA
87 for_each_property_of_node(node, prop) {
88
7941b27b
PA
89 if (of_prop_cmp(prop->name, "phandle") != 0 &&
90 of_prop_cmp(prop->name, "linux,phandle") != 0)
91 continue;
92
7941b27b
PA
93 if (prop->length < 4)
94 continue;
95
7941b27b 96 phandle = be32_to_cpup(prop->value);
a67976ec 97 if (phandle == OF_PHANDLE_ILLEGAL)
7941b27b
PA
98 continue;
99
7941b27b
PA
100 *(uint32_t *)prop->value = cpu_to_be32(node->phandle);
101 }
102
7941b27b
PA
103 for_each_child_of_node(node, child)
104 __of_adjust_tree_phandles(child, phandle_delta);
105}
106
da56d04c
PA
107static int __of_adjust_phandle_ref(struct device_node *node,
108 struct property *rprop, int value)
7941b27b
PA
109{
110 phandle phandle;
111 struct device_node *refnode;
112 struct property *sprop;
113 char *propval, *propcur, *propend, *nodestr, *propstr, *s;
114 int offset, propcurlen;
115 int err = 0;
116
7941b27b 117 propval = kmalloc(rprop->length, GFP_KERNEL);
96d1c8e8 118 if (!propval)
7941b27b 119 return -ENOMEM;
7941b27b
PA
120 memcpy(propval, rprop->value, rprop->length);
121
122 propend = propval + rprop->length;
123 for (propcur = propval; propcur < propend; propcur += propcurlen + 1) {
124 propcurlen = strlen(propcur);
125
126 nodestr = propcur;
127 s = strchr(propcur, ':');
128 if (!s) {
7941b27b
PA
129 err = -EINVAL;
130 goto err_fail;
131 }
132 *s++ = '\0';
133
134 propstr = s;
135 s = strchr(s, ':');
136 if (!s) {
7941b27b
PA
137 err = -EINVAL;
138 goto err_fail;
139 }
140
141 *s++ = '\0';
142 err = kstrtoint(s, 10, &offset);
96d1c8e8 143 if (err != 0)
7941b27b 144 goto err_fail;
7941b27b 145
7941b27b 146 refnode = __of_find_node_by_full_name(node, nodestr);
96d1c8e8 147 if (!refnode)
7941b27b 148 continue;
7941b27b 149
7941b27b
PA
150 for_each_property_of_node(refnode, sprop) {
151 if (of_prop_cmp(sprop->name, propstr) == 0)
152 break;
153 }
82f68756 154 of_node_put(refnode);
7941b27b
PA
155
156 if (!sprop) {
7941b27b
PA
157 err = -ENOENT;
158 goto err_fail;
159 }
160
da56d04c 161 phandle = value;
7941b27b
PA
162 *(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle);
163 }
164
165err_fail:
166 kfree(propval);
167 return err;
168}
169
da56d04c
PA
170/* compare nodes taking into account that 'name' strips out the @ part */
171static int __of_node_name_cmp(const struct device_node *dn1,
172 const struct device_node *dn2)
173{
174 const char *n1 = strrchr(dn1->full_name, '/') ? : "/";
175 const char *n2 = strrchr(dn2->full_name, '/') ? : "/";
176
177 return of_node_cmp(n1, n2);
178}
179
7941b27b
PA
180/*
181 * Adjust the local phandle references by the given phandle delta.
da56d04c
PA
182 * Assumes the existances of a __local_fixups__ node at the root.
183 * Assumes that __of_verify_tree_phandle_references has been called.
184 * Does not take any devtree locks so make sure you call this on a tree
185 * which is at the detached state.
7941b27b
PA
186 */
187static int __of_adjust_tree_phandle_references(struct device_node *node,
da56d04c 188 struct device_node *target, int phandle_delta)
7941b27b 189{
da56d04c
PA
190 struct device_node *child, *childtarget;
191 struct property *rprop, *sprop;
192 int err, i, count;
193 unsigned int off;
194 phandle phandle;
7941b27b 195
da56d04c 196 if (node == NULL)
7941b27b
PA
197 return 0;
198
da56d04c
PA
199 for_each_property_of_node(node, rprop) {
200
7941b27b 201 /* skip properties added automatically */
da56d04c
PA
202 if (of_prop_cmp(rprop->name, "name") == 0 ||
203 of_prop_cmp(rprop->name, "phandle") == 0 ||
204 of_prop_cmp(rprop->name, "linux,phandle") == 0)
7941b27b
PA
205 continue;
206
96d1c8e8 207 if ((rprop->length % 4) != 0 || rprop->length == 0)
da56d04c 208 return -EINVAL;
da56d04c
PA
209 count = rprop->length / sizeof(__be32);
210
da56d04c
PA
211 for_each_property_of_node(target, sprop) {
212 if (of_prop_cmp(sprop->name, rprop->name) == 0)
213 break;
214 }
215
96d1c8e8 216 if (sprop == NULL)
da56d04c 217 return -EINVAL;
da56d04c
PA
218
219 for (i = 0; i < count; i++) {
220 off = be32_to_cpu(((__be32 *)rprop->value)[i]);
96d1c8e8 221 if (off >= sprop->length || (off + 4) > sprop->length)
da56d04c 222 return -EINVAL;
da56d04c
PA
223
224 if (phandle_delta) {
da56d04c
PA
225 phandle = be32_to_cpu(*(__be32 *)(sprop->value + off));
226 phandle += phandle_delta;
227 *(__be32 *)(sprop->value + off) = cpu_to_be32(phandle);
228 }
229 }
230 }
231
232 for_each_child_of_node(node, child) {
233
234 for_each_child_of_node(target, childtarget)
235 if (__of_node_name_cmp(child, childtarget) == 0)
236 break;
237
96d1c8e8 238 if (!childtarget)
da56d04c 239 return -EINVAL;
da56d04c
PA
240
241 err = __of_adjust_tree_phandle_references(child, childtarget,
242 phandle_delta);
243 if (err != 0)
7941b27b
PA
244 return err;
245 }
246
247 return 0;
248}
249
250/**
251 * of_resolve - Resolve the given node against the live tree.
252 *
253 * @resolve: Node to resolve
254 *
255 * Perform dynamic Device Tree resolution against the live tree
256 * to the given node to resolve. This depends on the live tree
257 * having a __symbols__ node, and the resolve node the __fixups__ &
258 * __local_fixups__ nodes (if needed).
259 * The result of the operation is a resolve node that it's contents
260 * are fit to be inserted or operate upon the live tree.
261 * Returns 0 on success or a negative error value on error.
262 */
263int of_resolve_phandles(struct device_node *resolve)
264{
da56d04c 265 struct device_node *child, *childroot, *refnode;
7941b27b
PA
266 struct device_node *root_sym, *resolve_sym, *resolve_fix;
267 struct property *rprop;
268 const char *refpath;
269 phandle phandle, phandle_delta;
270 int err;
271
5de3bbc8
MS
272 if (!resolve)
273 pr_err("%s: null node\n", __func__);
274 if (resolve && !of_node_check_flag(resolve, OF_DETACHED))
275 pr_err("%s: node %s not detached\n", __func__,
276 resolve->full_name);
7941b27b
PA
277 if (!resolve || !of_node_check_flag(resolve, OF_DETACHED))
278 return -EINVAL;
279
7941b27b
PA
280 phandle_delta = of_get_tree_max_phandle() + 1;
281 __of_adjust_tree_phandles(resolve, phandle_delta);
da56d04c 282
da56d04c
PA
283 childroot = NULL;
284 for_each_child_of_node(resolve, childroot)
285 if (of_node_cmp(childroot->name, "__local_fixups__") == 0)
286 break;
287
288 if (childroot != NULL) {
da56d04c
PA
289 err = __of_adjust_tree_phandle_references(childroot,
290 resolve, 0);
291 if (err != 0)
292 return err;
293
294 BUG_ON(__of_adjust_tree_phandle_references(childroot,
295 resolve, phandle_delta));
296 }
7941b27b
PA
297
298 root_sym = NULL;
299 resolve_sym = NULL;
300 resolve_fix = NULL;
301
7941b27b
PA
302 root_sym = of_find_node_by_path("/__symbols__");
303
7941b27b
PA
304 for_each_child_of_node(resolve, child) {
305
306 if (!resolve_sym &&
307 of_node_cmp(child->name, "__symbols__") == 0)
308 resolve_sym = child;
309
310 if (!resolve_fix &&
311 of_node_cmp(child->name, "__fixups__") == 0)
312 resolve_fix = child;
313
7941b27b
PA
314 if (resolve_sym && resolve_fix)
315 break;
316 }
317
7941b27b 318 if (!resolve_fix) {
a67976ec 319 err = 0;
7941b27b
PA
320 goto out;
321 }
322
7941b27b 323 if (!root_sym) {
5de3bbc8 324 pr_err("%s: no symbols in root of device tree.\n", __func__);
7941b27b
PA
325 err = -EINVAL;
326 goto out;
327 }
328
329 for_each_property_of_node(resolve_fix, rprop) {
330
331 /* skip properties added automatically */
332 if (of_prop_cmp(rprop->name, "name") == 0)
333 continue;
334
335 err = of_property_read_string(root_sym,
336 rprop->name, &refpath);
96d1c8e8 337 if (err != 0)
7941b27b 338 goto out;
7941b27b
PA
339
340 refnode = of_find_node_by_path(refpath);
341 if (!refnode) {
7941b27b
PA
342 err = -ENOENT;
343 goto out;
344 }
345
346 phandle = refnode->phandle;
347 of_node_put(refnode);
348
da56d04c 349 err = __of_adjust_phandle_ref(resolve, rprop, phandle);
7941b27b
PA
350 if (err)
351 break;
352 }
353
354out:
7941b27b
PA
355 of_node_put(root_sym);
356
357 return err;
358}
359EXPORT_SYMBOL_GPL(of_resolve_phandles);