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); 424