Merge tag 'trace-v4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux...
[cascardo/linux.git] / drivers / of / resolver.c
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
12 #define pr_fmt(fmt)     "OF: resolver: " fmt
13
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  */
31 static 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
39         /* check */
40         if (of_node_cmp(node->full_name, full_name) == 0)
41                 return of_node_get(node);
42
43         for_each_child_of_node(node, child) {
44                 found = __of_find_node_by_full_name(child, full_name);
45                 if (found != NULL) {
46                         of_node_put(child);
47                         return found;
48                 }
49         }
50
51         return NULL;
52 }
53
54 /*
55  * Find live tree's maximum phandle value.
56  */
57 static phandle of_get_tree_max_phandle(void)
58 {
59         struct device_node *node;
60         phandle phandle;
61         unsigned long flags;
62
63         /* now search recursively */
64         raw_spin_lock_irqsave(&devtree_lock, flags);
65         phandle = 0;
66         for_each_of_allnodes(node) {
67                 if (node->phandle != OF_PHANDLE_ILLEGAL &&
68                                 node->phandle > phandle)
69                         phandle = node->phandle;
70         }
71         raw_spin_unlock_irqrestore(&devtree_lock, flags);
72
73         return phandle;
74 }
75
76 /*
77  * Adjust a subtree's phandle values by a given delta.
78  * Makes sure not to just adjust the device node's phandle value,
79  * but modify the phandle properties values as well.
80  */
81 static void __of_adjust_tree_phandles(struct device_node *node,
82                 int phandle_delta)
83 {
84         struct device_node *child;
85         struct property *prop;
86         phandle phandle;
87
88         /* first adjust the node's phandle direct value */
89         if (node->phandle != 0 && node->phandle != OF_PHANDLE_ILLEGAL)
90                 node->phandle += phandle_delta;
91
92         /* now adjust phandle & linux,phandle values */
93         for_each_property_of_node(node, prop) {
94
95                 /* only look for these two */
96                 if (of_prop_cmp(prop->name, "phandle") != 0 &&
97                     of_prop_cmp(prop->name, "linux,phandle") != 0)
98                         continue;
99
100                 /* must be big enough */
101                 if (prop->length < 4)
102                         continue;
103
104                 /* read phandle value */
105                 phandle = be32_to_cpup(prop->value);
106                 if (phandle == OF_PHANDLE_ILLEGAL)      /* unresolved */
107                         continue;
108
109                 /* adjust */
110                 *(uint32_t *)prop->value = cpu_to_be32(node->phandle);
111         }
112
113         /* now do the children recursively */
114         for_each_child_of_node(node, child)
115                 __of_adjust_tree_phandles(child, phandle_delta);
116 }
117
118 static int __of_adjust_phandle_ref(struct device_node *node,
119                 struct property *rprop, int value)
120 {
121         phandle phandle;
122         struct device_node *refnode;
123         struct property *sprop;
124         char *propval, *propcur, *propend, *nodestr, *propstr, *s;
125         int offset, propcurlen;
126         int err = 0;
127
128         /* make a copy */
129         propval = kmalloc(rprop->length, GFP_KERNEL);
130         if (!propval) {
131                 pr_err("%s: Could not copy value of '%s'\n",
132                                 __func__, rprop->name);
133                 return -ENOMEM;
134         }
135         memcpy(propval, rprop->value, rprop->length);
136
137         propend = propval + rprop->length;
138         for (propcur = propval; propcur < propend; propcur += propcurlen + 1) {
139                 propcurlen = strlen(propcur);
140
141                 nodestr = propcur;
142                 s = strchr(propcur, ':');
143                 if (!s) {
144                         pr_err("%s: Illegal symbol entry '%s' (1)\n",
145                                 __func__, propcur);
146                         err = -EINVAL;
147                         goto err_fail;
148                 }
149                 *s++ = '\0';
150
151                 propstr = s;
152                 s = strchr(s, ':');
153                 if (!s) {
154                         pr_err("%s: Illegal symbol entry '%s' (2)\n",
155                                 __func__, (char *)rprop->value);
156                         err = -EINVAL;
157                         goto err_fail;
158                 }
159
160                 *s++ = '\0';
161                 err = kstrtoint(s, 10, &offset);
162                 if (err != 0) {
163                         pr_err("%s: Could get offset '%s'\n",
164                                 __func__, (char *)rprop->value);
165                         goto err_fail;
166                 }
167
168                 /* look into the resolve node for the full path */
169                 refnode = __of_find_node_by_full_name(node, nodestr);
170                 if (!refnode) {
171                         pr_warn("%s: Could not find refnode '%s'\n",
172                                 __func__, (char *)rprop->value);
173                         continue;
174                 }
175
176                 /* now find the property */
177                 for_each_property_of_node(refnode, sprop) {
178                         if (of_prop_cmp(sprop->name, propstr) == 0)
179                                 break;
180                 }
181                 of_node_put(refnode);
182
183                 if (!sprop) {
184                         pr_err("%s: Could not find property '%s'\n",
185                                 __func__, (char *)rprop->value);
186                         err = -ENOENT;
187                         goto err_fail;
188                 }
189
190                 phandle = value;
191                 *(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle);
192         }
193
194 err_fail:
195         kfree(propval);
196         return err;
197 }
198
199 /* compare nodes taking into account that 'name' strips out the @ part */
200 static int __of_node_name_cmp(const struct device_node *dn1,
201                 const struct device_node *dn2)
202 {
203         const char *n1 = strrchr(dn1->full_name, '/') ? : "/";
204         const char *n2 = strrchr(dn2->full_name, '/') ? : "/";
205
206         return of_node_cmp(n1, n2);
207 }
208
209 /*
210  * Adjust the local phandle references by the given phandle delta.
211  * Assumes the existances of a __local_fixups__ node at the root.
212  * Assumes that __of_verify_tree_phandle_references has been called.
213  * Does not take any devtree locks so make sure you call this on a tree
214  * which is at the detached state.
215  */
216 static int __of_adjust_tree_phandle_references(struct device_node *node,
217                 struct device_node *target, int phandle_delta)
218 {
219         struct device_node *child, *childtarget;
220         struct property *rprop, *sprop;
221         int err, i, count;
222         unsigned int off;
223         phandle phandle;
224
225         if (node == NULL)
226                 return 0;
227
228         for_each_property_of_node(node, rprop) {
229
230                 /* skip properties added automatically */
231                 if (of_prop_cmp(rprop->name, "name") == 0 ||
232                     of_prop_cmp(rprop->name, "phandle") == 0 ||
233                     of_prop_cmp(rprop->name, "linux,phandle") == 0)
234                         continue;
235
236                 if ((rprop->length % 4) != 0 || rprop->length == 0) {
237                         pr_err("%s: Illegal property (size) '%s' @%s\n",
238                                         __func__, rprop->name, node->full_name);
239                         return -EINVAL;
240                 }
241                 count = rprop->length / sizeof(__be32);
242
243                 /* now find the target property */
244                 for_each_property_of_node(target, sprop) {
245                         if (of_prop_cmp(sprop->name, rprop->name) == 0)
246                                 break;
247                 }
248
249                 if (sprop == NULL) {
250                         pr_err("%s: Could not find target property '%s' @%s\n",
251                                         __func__, rprop->name, node->full_name);
252                         return -EINVAL;
253                 }
254
255                 for (i = 0; i < count; i++) {
256                         off = be32_to_cpu(((__be32 *)rprop->value)[i]);
257                         /* make sure the offset doesn't overstep (even wrap) */
258                         if (off >= sprop->length ||
259                                         (off + 4) > sprop->length) {
260                                 pr_err("%s: Illegal property '%s' @%s\n",
261                                                 __func__, rprop->name,
262                                                 node->full_name);
263                                 return -EINVAL;
264                         }
265
266                         if (phandle_delta) {
267                                 /* adjust */
268                                 phandle = be32_to_cpu(*(__be32 *)(sprop->value + off));
269                                 phandle += phandle_delta;
270                                 *(__be32 *)(sprop->value + off) = cpu_to_be32(phandle);
271                         }
272                 }
273         }
274
275         for_each_child_of_node(node, child) {
276
277                 for_each_child_of_node(target, childtarget)
278                         if (__of_node_name_cmp(child, childtarget) == 0)
279                                 break;
280
281                 if (!childtarget) {
282                         pr_err("%s: Could not find target child '%s' @%s\n",
283                                         __func__, child->name, node->full_name);
284                         return -EINVAL;
285                 }
286
287                 err = __of_adjust_tree_phandle_references(child, childtarget,
288                                 phandle_delta);
289                 if (err != 0)
290                         return err;
291         }
292
293         return 0;
294 }
295
296 /**
297  * of_resolve   - Resolve the given node against the live tree.
298  *
299  * @resolve:    Node to resolve
300  *
301  * Perform dynamic Device Tree resolution against the live tree
302  * to the given node to resolve. This depends on the live tree
303  * having a __symbols__ node, and the resolve node the __fixups__ &
304  * __local_fixups__ nodes (if needed).
305  * The result of the operation is a resolve node that it's contents
306  * are fit to be inserted or operate upon the live tree.
307  * Returns 0 on success or a negative error value on error.
308  */
309 int of_resolve_phandles(struct device_node *resolve)
310 {
311         struct device_node *child, *childroot, *refnode;
312         struct device_node *root_sym, *resolve_sym, *resolve_fix;
313         struct property *rprop;
314         const char *refpath;
315         phandle phandle, phandle_delta;
316         int err;
317
318         if (!resolve)
319                 pr_err("%s: null node\n", __func__);
320         if (resolve && !of_node_check_flag(resolve, OF_DETACHED))
321                 pr_err("%s: node %s not detached\n", __func__,
322                          resolve->full_name);
323         /* the resolve node must exist, and be detached */
324         if (!resolve || !of_node_check_flag(resolve, OF_DETACHED))
325                 return -EINVAL;
326
327         /* first we need to adjust the phandles */
328         phandle_delta = of_get_tree_max_phandle() + 1;
329         __of_adjust_tree_phandles(resolve, phandle_delta);
330
331         /* locate the local fixups */
332         childroot = NULL;
333         for_each_child_of_node(resolve, childroot)
334                 if (of_node_cmp(childroot->name, "__local_fixups__") == 0)
335                         break;
336
337         if (childroot != NULL) {
338                 /* resolve root is guaranteed to be the '/' */
339                 err = __of_adjust_tree_phandle_references(childroot,
340                                 resolve, 0);
341                 if (err != 0)
342                         return err;
343
344                 BUG_ON(__of_adjust_tree_phandle_references(childroot,
345                                 resolve, phandle_delta));
346         }
347
348         root_sym = NULL;
349         resolve_sym = NULL;
350         resolve_fix = NULL;
351
352         /* this may fail (if no fixups are required) */
353         root_sym = of_find_node_by_path("/__symbols__");
354
355         /* locate the symbols & fixups nodes on resolve */
356         for_each_child_of_node(resolve, child) {
357
358                 if (!resolve_sym &&
359                                 of_node_cmp(child->name, "__symbols__") == 0)
360                         resolve_sym = child;
361
362                 if (!resolve_fix &&
363                                 of_node_cmp(child->name, "__fixups__") == 0)
364                         resolve_fix = child;
365
366                 /* both found, don't bother anymore */
367                 if (resolve_sym && resolve_fix)
368                         break;
369         }
370
371         /* we do allow for the case where no fixups are needed */
372         if (!resolve_fix) {
373                 err = 0;        /* no error */
374                 goto out;
375         }
376
377         /* we need to fixup, but no root symbols... */
378         if (!root_sym) {
379                 pr_err("%s: no symbols in root of device tree.\n", __func__);
380                 err = -EINVAL;
381                 goto out;
382         }
383
384         for_each_property_of_node(resolve_fix, rprop) {
385
386                 /* skip properties added automatically */
387                 if (of_prop_cmp(rprop->name, "name") == 0)
388                         continue;
389
390                 err = of_property_read_string(root_sym,
391                                 rprop->name, &refpath);
392                 if (err != 0) {
393                         pr_err("%s: Could not find symbol '%s'\n",
394                                         __func__, rprop->name);
395                         goto out;
396                 }
397
398                 refnode = of_find_node_by_path(refpath);
399                 if (!refnode) {
400                         pr_err("%s: Could not find node by path '%s'\n",
401                                         __func__, refpath);
402                         err = -ENOENT;
403                         goto out;
404                 }
405
406                 phandle = refnode->phandle;
407                 of_node_put(refnode);
408
409                 pr_debug("%s: %s phandle is 0x%08x\n",
410                                 __func__, rprop->name, phandle);
411
412                 err = __of_adjust_phandle_ref(resolve, rprop, phandle);
413                 if (err)
414                         break;
415         }
416
417 out:
418         /* NULL is handled by of_node_put as NOP */
419         of_node_put(root_sym);
420
421         return err;
422 }
423 EXPORT_SYMBOL_GPL(of_resolve_phandles);