This source file includes following definitions.
- live_tree_max_phandle
- adjust_overlay_phandles
- update_usages_of_a_phandle_reference
- node_name_cmp
- adjust_local_phandle_references
- of_resolve_phandles
1
2
3
4
5
6
7
8
9 #define pr_fmt(fmt) "OF: resolver: " fmt
10
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/of_device.h>
15 #include <linux/string.h>
16 #include <linux/ctype.h>
17 #include <linux/errno.h>
18 #include <linux/slab.h>
19
20 #include "of_private.h"
21
22 static phandle live_tree_max_phandle(void)
23 {
24 struct device_node *node;
25 phandle phandle;
26 unsigned long flags;
27
28 raw_spin_lock_irqsave(&devtree_lock, flags);
29 phandle = 0;
30 for_each_of_allnodes(node) {
31 if (node->phandle != OF_PHANDLE_ILLEGAL &&
32 node->phandle > phandle)
33 phandle = node->phandle;
34 }
35 raw_spin_unlock_irqrestore(&devtree_lock, flags);
36
37 return phandle;
38 }
39
40 static void adjust_overlay_phandles(struct device_node *overlay,
41 int phandle_delta)
42 {
43 struct device_node *child;
44 struct property *prop;
45 phandle phandle;
46
47
48 if (overlay->phandle != 0 && overlay->phandle != OF_PHANDLE_ILLEGAL)
49 overlay->phandle += phandle_delta;
50
51
52 for_each_property_of_node(overlay, prop) {
53
54 if (of_prop_cmp(prop->name, "phandle") &&
55 of_prop_cmp(prop->name, "linux,phandle"))
56 continue;
57
58 if (prop->length < 4)
59 continue;
60
61 phandle = be32_to_cpup(prop->value);
62 if (phandle == OF_PHANDLE_ILLEGAL)
63 continue;
64
65 *(__be32 *)prop->value = cpu_to_be32(overlay->phandle);
66 }
67
68 for_each_child_of_node(overlay, child)
69 adjust_overlay_phandles(child, phandle_delta);
70 }
71
72 static int update_usages_of_a_phandle_reference(struct device_node *overlay,
73 struct property *prop_fixup, phandle phandle)
74 {
75 struct device_node *refnode;
76 struct property *prop;
77 char *value, *cur, *end, *node_path, *prop_name, *s;
78 int offset, len;
79 int err = 0;
80
81 value = kmemdup(prop_fixup->value, prop_fixup->length, GFP_KERNEL);
82 if (!value)
83 return -ENOMEM;
84
85
86 end = value + prop_fixup->length;
87 for (cur = value; cur < end; cur += len + 1) {
88 len = strlen(cur);
89
90 node_path = cur;
91 s = strchr(cur, ':');
92 if (!s) {
93 err = -EINVAL;
94 goto err_fail;
95 }
96 *s++ = '\0';
97
98 prop_name = s;
99 s = strchr(s, ':');
100 if (!s) {
101 err = -EINVAL;
102 goto err_fail;
103 }
104 *s++ = '\0';
105
106 err = kstrtoint(s, 10, &offset);
107 if (err)
108 goto err_fail;
109
110 refnode = __of_find_node_by_full_path(of_node_get(overlay), node_path);
111 if (!refnode)
112 continue;
113
114 for_each_property_of_node(refnode, prop) {
115 if (!of_prop_cmp(prop->name, prop_name))
116 break;
117 }
118 of_node_put(refnode);
119
120 if (!prop) {
121 err = -ENOENT;
122 goto err_fail;
123 }
124
125 if (offset < 0 || offset + sizeof(__be32) > prop->length) {
126 err = -EINVAL;
127 goto err_fail;
128 }
129
130 *(__be32 *)(prop->value + offset) = cpu_to_be32(phandle);
131 }
132
133 err_fail:
134 kfree(value);
135 return err;
136 }
137
138
139 static int node_name_cmp(const struct device_node *dn1,
140 const struct device_node *dn2)
141 {
142 const char *n1 = kbasename(dn1->full_name);
143 const char *n2 = kbasename(dn2->full_name);
144
145 return of_node_cmp(n1, n2);
146 }
147
148
149
150
151
152
153
154
155
156
157
158
159 static int adjust_local_phandle_references(struct device_node *local_fixups,
160 struct device_node *overlay, int phandle_delta)
161 {
162 struct device_node *child, *overlay_child;
163 struct property *prop_fix, *prop;
164 int err, i, count;
165 unsigned int off;
166
167 if (!local_fixups)
168 return 0;
169
170 for_each_property_of_node(local_fixups, prop_fix) {
171
172
173 if (!of_prop_cmp(prop_fix->name, "name") ||
174 !of_prop_cmp(prop_fix->name, "phandle") ||
175 !of_prop_cmp(prop_fix->name, "linux,phandle"))
176 continue;
177
178 if ((prop_fix->length % 4) != 0 || prop_fix->length == 0)
179 return -EINVAL;
180 count = prop_fix->length / sizeof(__be32);
181
182 for_each_property_of_node(overlay, prop) {
183 if (!of_prop_cmp(prop->name, prop_fix->name))
184 break;
185 }
186
187 if (!prop)
188 return -EINVAL;
189
190 for (i = 0; i < count; i++) {
191 off = be32_to_cpu(((__be32 *)prop_fix->value)[i]);
192 if ((off + 4) > prop->length)
193 return -EINVAL;
194
195 be32_add_cpu(prop->value + off, phandle_delta);
196 }
197 }
198
199
200
201
202
203
204
205
206 for_each_child_of_node(local_fixups, child) {
207
208 for_each_child_of_node(overlay, overlay_child)
209 if (!node_name_cmp(child, overlay_child)) {
210 of_node_put(overlay_child);
211 break;
212 }
213
214 if (!overlay_child) {
215 of_node_put(child);
216 return -EINVAL;
217 }
218
219 err = adjust_local_phandle_references(child, overlay_child,
220 phandle_delta);
221 if (err) {
222 of_node_put(child);
223 return err;
224 }
225 }
226
227 return 0;
228 }
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263 int of_resolve_phandles(struct device_node *overlay)
264 {
265 struct device_node *child, *local_fixups, *refnode;
266 struct device_node *tree_symbols, *overlay_fixups;
267 struct property *prop;
268 const char *refpath;
269 phandle phandle, phandle_delta;
270 int err;
271
272 tree_symbols = NULL;
273
274 if (!overlay) {
275 pr_err("null overlay\n");
276 err = -EINVAL;
277 goto out;
278 }
279
280 if (!of_node_check_flag(overlay, OF_DETACHED)) {
281 pr_err("overlay not detached\n");
282 err = -EINVAL;
283 goto out;
284 }
285
286 phandle_delta = live_tree_max_phandle() + 1;
287 adjust_overlay_phandles(overlay, phandle_delta);
288
289 for_each_child_of_node(overlay, local_fixups)
290 if (of_node_name_eq(local_fixups, "__local_fixups__"))
291 break;
292
293 err = adjust_local_phandle_references(local_fixups, overlay, phandle_delta);
294 if (err)
295 goto out;
296
297 overlay_fixups = NULL;
298
299 for_each_child_of_node(overlay, child) {
300 if (of_node_name_eq(child, "__fixups__"))
301 overlay_fixups = child;
302 }
303
304 if (!overlay_fixups) {
305 err = 0;
306 goto out;
307 }
308
309 tree_symbols = of_find_node_by_path("/__symbols__");
310 if (!tree_symbols) {
311 pr_err("no symbols in root of device tree.\n");
312 err = -EINVAL;
313 goto out;
314 }
315
316 for_each_property_of_node(overlay_fixups, prop) {
317
318
319 if (!of_prop_cmp(prop->name, "name"))
320 continue;
321
322 err = of_property_read_string(tree_symbols,
323 prop->name, &refpath);
324 if (err)
325 goto out;
326
327 refnode = of_find_node_by_path(refpath);
328 if (!refnode) {
329 err = -ENOENT;
330 goto out;
331 }
332
333 phandle = refnode->phandle;
334 of_node_put(refnode);
335
336 err = update_usages_of_a_phandle_reference(overlay, prop, phandle);
337 if (err)
338 break;
339 }
340
341 out:
342 if (err)
343 pr_err("overlay phandle fixup failed: %d\n", err);
344 of_node_put(tree_symbols);
345
346 return err;
347 }
348 EXPORT_SYMBOL_GPL(of_resolve_phandles);