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 /drivers | |
| 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>
Diffstat (limited to 'drivers')
| -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 | }; }; |
