diff options
author | Pantelis Antoniou <pantelis.antoniou@konsulko.com> | 2014-10-28 16:33:49 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@linaro.org> | 2014-11-24 17:24:50 -0500 |
commit | da56d04c806a3e9986c66a061d7363ca3157c37b (patch) | |
tree | 933409b0e629c36a56f5471f7719351938136417 | |
parent | e51795815ef1a7adc018cbaf05aac46e3d24eda8 (diff) |
of/resolver: Switch to new local fixups format.
The original resolver format is way too cryptic, switch
to using a tree based format that gets rid of repetitions,
is more compact and readable.
At the same time, update the selftests to using the new local fixups
format.
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
[grant.likely: Squashed in testcase changes and merged similar functions]
Signed-off-by: Grant Likely <grant.likely@linaro.org>
-rw-r--r-- | drivers/of/resolver.c | 128 | ||||
-rw-r--r-- | drivers/of/unittest-data/testcases.dts | 61 |
2 files changed, 139 insertions, 50 deletions
diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index aed7959f800d..640eb4cb46e3 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c | |||
@@ -111,7 +111,8 @@ static void __of_adjust_tree_phandles(struct device_node *node, | |||
111 | __of_adjust_tree_phandles(child, phandle_delta); | 111 | __of_adjust_tree_phandles(child, phandle_delta); |
112 | } | 112 | } |
113 | 113 | ||
114 | static int __of_adjust_phandle_ref(struct device_node *node, struct property *rprop, int value, bool is_delta) | 114 | static int __of_adjust_phandle_ref(struct device_node *node, |
115 | struct property *rprop, int value) | ||
115 | { | 116 | { |
116 | phandle phandle; | 117 | phandle phandle; |
117 | struct device_node *refnode; | 118 | struct device_node *refnode; |
@@ -181,7 +182,7 @@ static int __of_adjust_phandle_ref(struct device_node *node, struct property *rp | |||
181 | goto err_fail; | 182 | goto err_fail; |
182 | } | 183 | } |
183 | 184 | ||
184 | phandle = is_delta ? be32_to_cpup(sprop->value + offset) + value : value; | 185 | phandle = value; |
185 | *(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle); | 186 | *(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle); |
186 | } | 187 | } |
187 | 188 | ||
@@ -190,36 +191,97 @@ err_fail: | |||
190 | return err; | 191 | return err; |
191 | } | 192 | } |
192 | 193 | ||
194 | /* compare nodes taking into account that 'name' strips out the @ part */ | ||
195 | static int __of_node_name_cmp(const struct device_node *dn1, | ||
196 | const struct device_node *dn2) | ||
197 | { | ||
198 | const char *n1 = strrchr(dn1->full_name, '/') ? : "/"; | ||
199 | const char *n2 = strrchr(dn2->full_name, '/') ? : "/"; | ||
200 | |||
201 | return of_node_cmp(n1, n2); | ||
202 | } | ||
203 | |||
193 | /* | 204 | /* |
194 | * Adjust the local phandle references by the given phandle delta. | 205 | * Adjust the local phandle references by the given phandle delta. |
195 | * Assumes the existances of a __local_fixups__ node at the root | 206 | * Assumes the existances of a __local_fixups__ node at the root. |
196 | * of the tree. Does not take any devtree locks so make sure you | 207 | * Assumes that __of_verify_tree_phandle_references has been called. |
197 | * call this on a tree which is at the detached state. | 208 | * Does not take any devtree locks so make sure you call this on a tree |
209 | * which is at the detached state. | ||
198 | */ | 210 | */ |
199 | static int __of_adjust_tree_phandle_references(struct device_node *node, | 211 | static int __of_adjust_tree_phandle_references(struct device_node *node, |
200 | int phandle_delta) | 212 | struct device_node *target, int phandle_delta) |
201 | { | 213 | { |
202 | struct device_node *child; | 214 | struct device_node *child, *childtarget; |
203 | struct property *rprop; | 215 | struct property *rprop, *sprop; |
204 | int err; | 216 | int err, i, count; |
205 | 217 | unsigned int off; | |
206 | /* locate the symbols & fixups nodes on resolve */ | 218 | phandle phandle; |
207 | for_each_child_of_node(node, child) | ||
208 | if (of_node_cmp(child->name, "__local_fixups__") == 0) | ||
209 | break; | ||
210 | 219 | ||
211 | /* no local fixups */ | 220 | if (node == NULL) |
212 | if (!child) | ||
213 | return 0; | 221 | return 0; |
214 | 222 | ||
215 | /* find the local fixups property */ | 223 | for_each_property_of_node(node, rprop) { |
216 | for_each_property_of_node(child, rprop) { | 224 | |
217 | /* skip properties added automatically */ | 225 | /* skip properties added automatically */ |
218 | if (of_prop_cmp(rprop->name, "name") == 0) | 226 | if (of_prop_cmp(rprop->name, "name") == 0 || |
227 | of_prop_cmp(rprop->name, "phandle") == 0 || | ||
228 | of_prop_cmp(rprop->name, "linux,phandle") == 0) | ||
219 | continue; | 229 | continue; |
220 | 230 | ||
221 | err = __of_adjust_phandle_ref(node, rprop, phandle_delta, true); | 231 | if ((rprop->length % 4) != 0 || rprop->length == 0) { |
222 | if (err) | 232 | pr_err("%s: Illegal property (size) '%s' @%s\n", |
233 | __func__, rprop->name, node->full_name); | ||
234 | return -EINVAL; | ||
235 | } | ||
236 | count = rprop->length / sizeof(__be32); | ||
237 | |||
238 | /* now find the target property */ | ||
239 | for_each_property_of_node(target, sprop) { | ||
240 | if (of_prop_cmp(sprop->name, rprop->name) == 0) | ||
241 | break; | ||
242 | } | ||
243 | |||
244 | if (sprop == NULL) { | ||
245 | pr_err("%s: Could not find target property '%s' @%s\n", | ||
246 | __func__, rprop->name, node->full_name); | ||
247 | return -EINVAL; | ||
248 | } | ||
249 | |||
250 | for (i = 0; i < count; i++) { | ||
251 | off = be32_to_cpu(((__be32 *)rprop->value)[i]); | ||
252 | /* make sure the offset doesn't overstep (even wrap) */ | ||
253 | if (off >= sprop->length || | ||
254 | (off + 4) > sprop->length) { | ||
255 | pr_err("%s: Illegal property '%s' @%s\n", | ||
256 | __func__, rprop->name, | ||
257 | node->full_name); | ||
258 | return -EINVAL; | ||
259 | } | ||
260 | |||
261 | if (phandle_delta) { | ||
262 | /* adjust */ | ||
263 | phandle = be32_to_cpu(*(__be32 *)(sprop->value + off)); | ||
264 | phandle += phandle_delta; | ||
265 | *(__be32 *)(sprop->value + off) = cpu_to_be32(phandle); | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | |||
270 | for_each_child_of_node(node, child) { | ||
271 | |||
272 | for_each_child_of_node(target, childtarget) | ||
273 | if (__of_node_name_cmp(child, childtarget) == 0) | ||
274 | break; | ||
275 | |||
276 | if (!childtarget) { | ||
277 | pr_err("%s: Could not find target child '%s' @%s\n", | ||
278 | __func__, child->name, node->full_name); | ||
279 | return -EINVAL; | ||
280 | } | ||
281 | |||
282 | err = __of_adjust_tree_phandle_references(child, childtarget, | ||
283 | phandle_delta); | ||
284 | if (err != 0) | ||
223 | return err; | 285 | return err; |
224 | } | 286 | } |
225 | 287 | ||
@@ -241,7 +303,7 @@ static int __of_adjust_tree_phandle_references(struct device_node *node, | |||
241 | */ | 303 | */ |
242 | int of_resolve_phandles(struct device_node *resolve) | 304 | int of_resolve_phandles(struct device_node *resolve) |
243 | { | 305 | { |
244 | struct device_node *child, *refnode; | 306 | struct device_node *child, *childroot, *refnode; |
245 | struct device_node *root_sym, *resolve_sym, *resolve_fix; | 307 | struct device_node *root_sym, *resolve_sym, *resolve_fix; |
246 | struct property *rprop; | 308 | struct property *rprop; |
247 | const char *refpath; | 309 | const char *refpath; |
@@ -255,9 +317,23 @@ int of_resolve_phandles(struct device_node *resolve) | |||
255 | /* first we need to adjust the phandles */ | 317 | /* first we need to adjust the phandles */ |
256 | phandle_delta = of_get_tree_max_phandle() + 1; | 318 | phandle_delta = of_get_tree_max_phandle() + 1; |
257 | __of_adjust_tree_phandles(resolve, phandle_delta); | 319 | __of_adjust_tree_phandles(resolve, phandle_delta); |
258 | err = __of_adjust_tree_phandle_references(resolve, phandle_delta); | 320 | |
259 | if (err != 0) | 321 | /* locate the local fixups */ |
260 | return err; | 322 | childroot = NULL; |
323 | for_each_child_of_node(resolve, childroot) | ||
324 | if (of_node_cmp(childroot->name, "__local_fixups__") == 0) | ||
325 | break; | ||
326 | |||
327 | if (childroot != NULL) { | ||
328 | /* resolve root is guaranteed to be the '/' */ | ||
329 | err = __of_adjust_tree_phandle_references(childroot, | ||
330 | resolve, 0); | ||
331 | if (err != 0) | ||
332 | return err; | ||
333 | |||
334 | BUG_ON(__of_adjust_tree_phandle_references(childroot, | ||
335 | resolve, phandle_delta)); | ||
336 | } | ||
261 | 337 | ||
262 | root_sym = NULL; | 338 | root_sym = NULL; |
263 | resolve_sym = NULL; | 339 | resolve_sym = NULL; |
@@ -322,7 +398,7 @@ int of_resolve_phandles(struct device_node *resolve) | |||
322 | pr_debug("%s: %s phandle is 0x%08x\n", | 398 | pr_debug("%s: %s phandle is 0x%08x\n", |
323 | __func__, rprop->name, phandle); | 399 | __func__, rprop->name, phandle); |
324 | 400 | ||
325 | err = __of_adjust_phandle_ref(resolve, rprop, phandle, false); | 401 | err = __of_adjust_phandle_ref(resolve, rprop, phandle); |
326 | if (err) | 402 | if (err) |
327 | break; | 403 | break; |
328 | } | 404 | } |
diff --git a/drivers/of/unittest-data/testcases.dts b/drivers/of/unittest-data/testcases.dts index 6994e15c24bf..b6bc41b2a185 100644 --- a/drivers/of/unittest-data/testcases.dts +++ b/drivers/of/unittest-data/testcases.dts | |||
@@ -23,28 +23,41 @@ | |||
23 | * this a kernel-internal data format. | 23 | * this a kernel-internal data format. |
24 | */ | 24 | */ |
25 | / { __local_fixups__ { | 25 | / { __local_fixups__ { |
26 | fixup = "/testcase-data/testcase-device2:interrupt-parent:0", | 26 | testcase-data { |
27 | "/testcase-data/testcase-device1:interrupt-parent:0", | 27 | phandle-tests { |
28 | "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:60", | 28 | consumer-a { |
29 | "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:52", | 29 | phandle-list = <0x00000000 0x00000008 |
30 | "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:44", | 30 | 0x00000018 0x00000028 |
31 | "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:36", | 31 | 0x00000034 0x00000038>; |
32 | "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:24", | 32 | phandle-list-bad-args = <0x00000000 0x0000000c>; |
33 | "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:8", | 33 | }; |
34 | "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:0", | 34 | }; |
35 | "/testcase-data/interrupts/interrupts1:interrupt-parent:0", | 35 | interrupts { |
36 | "/testcase-data/interrupts/interrupts0:interrupt-parent:0", | 36 | intmap0 { |
37 | "/testcase-data/interrupts/intmap1:interrupt-map:12", | 37 | interrupt-map = <0x00000004 0x00000010 |
38 | "/testcase-data/interrupts/intmap0:interrupt-map:52", | 38 | 0x00000024 0x00000034>; |
39 | "/testcase-data/interrupts/intmap0:interrupt-map:36", | 39 | }; |
40 | "/testcase-data/interrupts/intmap0:interrupt-map:16", | 40 | intmap1 { |
41 | "/testcase-data/interrupts/intmap0:interrupt-map:4", | 41 | interrupt-map = <0x0000000c>; |
42 | "/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:12", | 42 | }; |
43 | "/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:0", | 43 | interrupts0 { |
44 | "/testcase-data/phandle-tests/consumer-a:phandle-list:56", | 44 | interrupt-parent = <0x00000000>; |
45 | "/testcase-data/phandle-tests/consumer-a:phandle-list:52", | 45 | }; |
46 | "/testcase-data/phandle-tests/consumer-a:phandle-list:40", | 46 | interrupts1 { |
47 | "/testcase-data/phandle-tests/consumer-a:phandle-list:24", | 47 | interrupt-parent = <0x00000000>; |
48 | "/testcase-data/phandle-tests/consumer-a:phandle-list:8", | 48 | }; |
49 | "/testcase-data/phandle-tests/consumer-a:phandle-list:0"; | 49 | interrupts-extended0 { |
50 | interrupts-extended = <0x00000000 0x00000008 | ||
51 | 0x00000018 0x00000024 | ||
52 | 0x0000002c 0x00000034 | ||
53 | 0x0000003c>; | ||
54 | }; | ||
55 | }; | ||
56 | testcase-device1 { | ||
57 | interrupt-parent = <0x00000000>; | ||
58 | }; | ||
59 | testcase-device2 { | ||
60 | interrupt-parent = <0x00000000>; | ||
61 | }; | ||
62 | }; | ||
50 | }; }; | 63 | }; }; |