Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Pantelis Antoniou and committed by
Grant Likely
da56d04c e5179581

+139 -50
+102 -26
drivers/of/resolver.c
··· 111 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 117 phandle phandle; 117 118 struct device_node *refnode; ··· 182 181 goto err_fail; 183 182 } 184 183 185 - phandle = is_delta ? be32_to_cpup(sprop->value + offset) + value : value; 184 + phandle = value; 186 185 *(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle); 187 186 } 188 187 ··· 191 190 return err; 192 191 } 193 192 193 + /* compare nodes taking into account that 'name' strips out the @ part */ 194 + static int __of_node_name_cmp(const struct device_node *dn1, 195 + const struct device_node *dn2) 196 + { 197 + const char *n1 = strrchr(dn1->full_name, '/') ? : "/"; 198 + const char *n2 = strrchr(dn2->full_name, '/') ? : "/"; 199 + 200 + return of_node_cmp(n1, n2); 201 + } 202 + 194 203 /* 195 204 * Adjust the local phandle references by the given phandle delta. 196 - * Assumes the existances of a __local_fixups__ node at the root 197 - * of the tree. Does not take any devtree locks so make sure you 198 - * call this on a tree which is at the detached state. 205 + * Assumes the existances of a __local_fixups__ node at the root. 206 + * Assumes that __of_verify_tree_phandle_references has been called. 207 + * Does not take any devtree locks so make sure you call this on a tree 208 + * which is at the detached state. 199 209 */ 200 210 static int __of_adjust_tree_phandle_references(struct device_node *node, 201 - int phandle_delta) 211 + struct device_node *target, int phandle_delta) 202 212 { 203 - struct device_node *child; 204 - struct property *rprop; 205 - int err; 213 + struct device_node *child, *childtarget; 214 + struct property *rprop, *sprop; 215 + int err, i, count; 216 + unsigned int off; 217 + phandle phandle; 206 218 207 - /* locate the symbols & fixups nodes on resolve */ 208 - for_each_child_of_node(node, child) 209 - if (of_node_cmp(child->name, "__local_fixups__") == 0) 210 - break; 211 - 212 - /* no local fixups */ 213 - if (!child) 219 + if (node == NULL) 214 220 return 0; 215 221 216 - /* find the local fixups property */ 217 - for_each_property_of_node(child, rprop) { 222 + for_each_property_of_node(node, rprop) { 223 + 218 224 /* skip properties added automatically */ 219 - if (of_prop_cmp(rprop->name, "name") == 0) 225 + if (of_prop_cmp(rprop->name, "name") == 0 || 226 + of_prop_cmp(rprop->name, "phandle") == 0 || 227 + of_prop_cmp(rprop->name, "linux,phandle") == 0) 220 228 continue; 221 229 222 - err = __of_adjust_phandle_ref(node, rprop, phandle_delta, true); 223 - if (err) 230 + if ((rprop->length % 4) != 0 || rprop->length == 0) { 231 + pr_err("%s: Illegal property (size) '%s' @%s\n", 232 + __func__, rprop->name, node->full_name); 233 + return -EINVAL; 234 + } 235 + count = rprop->length / sizeof(__be32); 236 + 237 + /* now find the target property */ 238 + for_each_property_of_node(target, sprop) { 239 + if (of_prop_cmp(sprop->name, rprop->name) == 0) 240 + break; 241 + } 242 + 243 + if (sprop == NULL) { 244 + pr_err("%s: Could not find target property '%s' @%s\n", 245 + __func__, rprop->name, node->full_name); 246 + return -EINVAL; 247 + } 248 + 249 + for (i = 0; i < count; i++) { 250 + off = be32_to_cpu(((__be32 *)rprop->value)[i]); 251 + /* make sure the offset doesn't overstep (even wrap) */ 252 + if (off >= sprop->length || 253 + (off + 4) > sprop->length) { 254 + pr_err("%s: Illegal property '%s' @%s\n", 255 + __func__, rprop->name, 256 + node->full_name); 257 + return -EINVAL; 258 + } 259 + 260 + if (phandle_delta) { 261 + /* adjust */ 262 + phandle = be32_to_cpu(*(__be32 *)(sprop->value + off)); 263 + phandle += phandle_delta; 264 + *(__be32 *)(sprop->value + off) = cpu_to_be32(phandle); 265 + } 266 + } 267 + } 268 + 269 + for_each_child_of_node(node, child) { 270 + 271 + for_each_child_of_node(target, childtarget) 272 + if (__of_node_name_cmp(child, childtarget) == 0) 273 + break; 274 + 275 + if (!childtarget) { 276 + pr_err("%s: Could not find target child '%s' @%s\n", 277 + __func__, child->name, node->full_name); 278 + return -EINVAL; 279 + } 280 + 281 + err = __of_adjust_tree_phandle_references(child, childtarget, 282 + phandle_delta); 283 + if (err != 0) 224 284 return err; 225 285 } 226 286 ··· 303 241 */ 304 242 int of_resolve_phandles(struct device_node *resolve) 305 243 { 306 - struct device_node *child, *refnode; 244 + struct device_node *child, *childroot, *refnode; 307 245 struct device_node *root_sym, *resolve_sym, *resolve_fix; 308 246 struct property *rprop; 309 247 const char *refpath; ··· 317 255 /* first we need to adjust the phandles */ 318 256 phandle_delta = of_get_tree_max_phandle() + 1; 319 257 __of_adjust_tree_phandles(resolve, phandle_delta); 320 - err = __of_adjust_tree_phandle_references(resolve, phandle_delta); 321 - if (err != 0) 322 - return err; 258 + 259 + /* locate the local fixups */ 260 + childroot = NULL; 261 + for_each_child_of_node(resolve, childroot) 262 + if (of_node_cmp(childroot->name, "__local_fixups__") == 0) 263 + break; 264 + 265 + if (childroot != NULL) { 266 + /* resolve root is guaranteed to be the '/' */ 267 + err = __of_adjust_tree_phandle_references(childroot, 268 + resolve, 0); 269 + if (err != 0) 270 + return err; 271 + 272 + BUG_ON(__of_adjust_tree_phandle_references(childroot, 273 + resolve, phandle_delta)); 274 + } 323 275 324 276 root_sym = NULL; 325 277 resolve_sym = NULL; ··· 398 322 pr_debug("%s: %s phandle is 0x%08x\n", 399 323 __func__, rprop->name, phandle); 400 324 401 - err = __of_adjust_phandle_ref(resolve, rprop, phandle, false); 325 + err = __of_adjust_phandle_ref(resolve, rprop, phandle); 402 326 if (err) 403 327 break; 404 328 }
+37 -24
drivers/of/unittest-data/testcases.dts
··· 23 23 * this a kernel-internal data format. 24 24 */ 25 25 / { __local_fixups__ { 26 - fixup = "/testcase-data/testcase-device2:interrupt-parent:0", 27 - "/testcase-data/testcase-device1:interrupt-parent:0", 28 - "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:60", 29 - "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:52", 30 - "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:44", 31 - "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:36", 32 - "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:24", 33 - "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:8", 34 - "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:0", 35 - "/testcase-data/interrupts/interrupts1:interrupt-parent:0", 36 - "/testcase-data/interrupts/interrupts0:interrupt-parent:0", 37 - "/testcase-data/interrupts/intmap1:interrupt-map:12", 38 - "/testcase-data/interrupts/intmap0:interrupt-map:52", 39 - "/testcase-data/interrupts/intmap0:interrupt-map:36", 40 - "/testcase-data/interrupts/intmap0:interrupt-map:16", 41 - "/testcase-data/interrupts/intmap0:interrupt-map:4", 42 - "/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:12", 43 - "/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:0", 44 - "/testcase-data/phandle-tests/consumer-a:phandle-list:56", 45 - "/testcase-data/phandle-tests/consumer-a:phandle-list:52", 46 - "/testcase-data/phandle-tests/consumer-a:phandle-list:40", 47 - "/testcase-data/phandle-tests/consumer-a:phandle-list:24", 48 - "/testcase-data/phandle-tests/consumer-a:phandle-list:8", 49 - "/testcase-data/phandle-tests/consumer-a:phandle-list:0"; 26 + testcase-data { 27 + phandle-tests { 28 + consumer-a { 29 + phandle-list = <0x00000000 0x00000008 30 + 0x00000018 0x00000028 31 + 0x00000034 0x00000038>; 32 + phandle-list-bad-args = <0x00000000 0x0000000c>; 33 + }; 34 + }; 35 + interrupts { 36 + intmap0 { 37 + interrupt-map = <0x00000004 0x00000010 38 + 0x00000024 0x00000034>; 39 + }; 40 + intmap1 { 41 + interrupt-map = <0x0000000c>; 42 + }; 43 + interrupts0 { 44 + interrupt-parent = <0x00000000>; 45 + }; 46 + interrupts1 { 47 + interrupt-parent = <0x00000000>; 48 + }; 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 }; };