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 *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) 37 return NULL; 38 39 if (!of_node_cmp(node->full_name, full_name)) 40 return of_node_get(node); 41 42 for_each_child_of_node(node, child) { 43 found = find_node_by_full_name(child, full_name); 44 if (found != NULL) { 45 of_node_put(child); 46 return found; 47 } 48 } 49 50 return NULL; 51 } 52 53 /* 54 * Find live tree's maximum phandle value. 55 */ 56 static phandle live_tree_max_phandle(void) 57 { 58 struct device_node *node; 59 phandle phandle; 60 unsigned long flags; 61 62 raw_spin_lock_irqsave(&devtree_lock, flags); 63 phandle = 0; 64 for_each_of_allnodes(node) { 65 if (node->phandle != OF_PHANDLE_ILLEGAL && 66 node->phandle > phandle) 67 phandle = node->phandle; 68 } 69 raw_spin_unlock_irqrestore(&devtree_lock, flags); 70 71 return phandle; 72 } 73 74 /* 75 * Adjust a subtree's phandle values by a given delta. 76 */ 77 static void adjust_overlay_phandles(struct device_node *overlay, 78 int phandle_delta) 79 { 80 struct device_node *child; 81 struct property *prop; 82 phandle phandle; 83 84 if (overlay->phandle != 0 && overlay->phandle != OF_PHANDLE_ILLEGAL) 85 overlay->phandle += phandle_delta; 86 87 for_each_property_of_node(overlay, prop) { 88 89 if (of_prop_cmp(prop->name, "phandle") && 90 of_prop_cmp(prop->name, "linux,phandle")) 91 continue; 92 93 if (prop->length < 4) 94 continue; 95 96 phandle = be32_to_cpup(prop->value); 97 if (phandle == OF_PHANDLE_ILLEGAL) 98 continue; 99 100 *(uint32_t *)prop->value = cpu_to_be32(overlay->phandle); 101 } 102 103 for_each_child_of_node(overlay, child) 104 adjust_overlay_phandles(child, phandle_delta); 105 } 106 107 static int update_usages_of_a_phandle_reference(struct device_node *overlay, 108 struct property *prop_fixup, phandle phandle) 109 { 110 struct device_node *refnode; 111 struct property *prop; 112 char *value, *cur, *end, *node_path, *prop_name, *s; 113 int offset, len; 114 int err = 0; 115 116 value = kmalloc(prop_fixup->length, GFP_KERNEL); 117 if (!value) 118 return -ENOMEM; 119 memcpy(value, prop_fixup->value, prop_fixup->length); 120 121 end = value + prop_fixup->length; 122 for (cur = value; cur < end; cur += len + 1) { 123 len = strlen(cur); 124 125 node_path = cur; 126 s = strchr(cur, ':'); 127 if (!s) { 128 err = -EINVAL; 129 goto err_fail; 130 } 131 *s++ = '\0'; 132 133 prop_name = s; 134 s = strchr(s, ':'); 135 if (!s) { 136 err = -EINVAL; 137 goto err_fail; 138 } 139 *s++ = '\0'; 140 141 err = kstrtoint(s, 10, &offset); 142 if (err) 143 goto err_fail; 144 145 refnode = find_node_by_full_name(overlay, node_path); 146 if (!refnode) 147 continue; 148 149 for_each_property_of_node(refnode, prop) { 150 if (!of_prop_cmp(prop->name, prop_name)) 151 break; 152 } 153 of_node_put(refnode); 154 155 if (!prop) { 156 err = -ENOENT; 157 goto err_fail; 158 } 159 160 *(__be32 *)(prop->value + offset) = cpu_to_be32(phandle); 161 } 162 163 err_fail: 164 kfree(value); 165 return err; 166 } 167 168 /* compare nodes taking into account that 'name' strips out the @ part */ 169 static int node_name_cmp(const struct device_node *dn1, 170 const struct device_node *dn2) 171 { 172 const char *n1 = strrchr(dn1->full_name, '/') ? : "/"; 173 const char *n2 = strrchr(dn2->full_name, '/') ? : "/"; 174 175 return of_node_cmp(n1, n2); 176 } 177 178 /* 179 * Adjust the local phandle references by the given phandle delta. 180 * Assumes the existances of a __local_fixups__ node at the root. 181 * Assumes that __of_verify_tree_phandle_references has been called. 182 * Does not take any devtree locks so make sure you call this on a tree 183 * which is at the detached state. 184 */ 185 static int adjust_local_phandle_references(struct device_node *local_fixups, 186 struct device_node *overlay, int phandle_delta) 187 { 188 struct device_node *child, *overlay_child; 189 struct property *prop_fix, *prop; 190 int err, i, count; 191 unsigned int off; 192 phandle phandle; 193 194 if (!local_fixups) 195 return 0; 196 197 for_each_property_of_node(local_fixups, prop_fix) { 198 199 /* skip properties added automatically */ 200 if (!of_prop_cmp(prop_fix->name, "name") || 201 !of_prop_cmp(prop_fix->name, "phandle") || 202 !of_prop_cmp(prop_fix->name, "linux,phandle")) 203 continue; 204 205 if ((prop_fix->length % 4) != 0 || prop_fix->length == 0) 206 return -EINVAL; 207 count = prop_fix->length / sizeof(__be32); 208 209 for_each_property_of_node(overlay, prop) { 210 if (!of_prop_cmp(prop->name, prop_fix->name)) 211 break; 212 } 213 214 if (!prop) 215 return -EINVAL; 216 217 for (i = 0; i < count; i++) { 218 off = be32_to_cpu(((__be32 *)prop_fix->value)[i]); 219 if ((off + 4) > prop->length) 220 return -EINVAL; 221 222 phandle = be32_to_cpu(*(__be32 *)(prop->value + off)); 223 phandle += phandle_delta; 224 *(__be32 *)(prop->value + off) = cpu_to_be32(phandle); 225 } 226 } 227 228 for_each_child_of_node(local_fixups, child) { 229 230 for_each_child_of_node(overlay, overlay_child) 231 if (!node_name_cmp(child, overlay_child)) 232 break; 233 234 if (!overlay_child) 235 return -EINVAL; 236 237 err = adjust_local_phandle_references(child, overlay_child, 238 phandle_delta); 239 if (err) 240 return err; 241 } 242 243 return 0; 244 } 245 246 /** 247 * of_resolve - Resolve the given node against the live tree. 248 * 249 * @resolve: Node to resolve 250 * 251 * Perform dynamic Device Tree resolution against the live tree 252 * to the given node to resolve. This depends on the live tree 253 * having a __symbols__ node, and the resolve node the __fixups__ & 254 * __local_fixups__ nodes (if needed). 255 * The result of the operation is a resolve node that it's contents 256 * are fit to be inserted or operate upon the live tree. 257 * Returns 0 on success or a negative error value on error. 258 */ 259 int of_resolve_phandles(struct device_node *overlay) 260 { 261 struct device_node *child, *local_fixups, *refnode; 262 struct device_node *tree_symbols, *overlay_symbols, *overlay_fixups; 263 struct property *prop; 264 const char *refpath; 265 phandle phandle, phandle_delta; 266 int err; 267 268 if (!overlay) { 269 pr_err("null overlay\n"); 270 return -EINVAL; 271 } 272 if (!of_node_check_flag(overlay, OF_DETACHED)) { 273 pr_err("overlay not detached\n"); 274 return -EINVAL; 275 } 276 277 phandle_delta = live_tree_max_phandle() + 1; 278 adjust_overlay_phandles(overlay, phandle_delta); 279 280 for_each_child_of_node(overlay, local_fixups) 281 if (!of_node_cmp(local_fixups->name, "__local_fixups__")) 282 break; 283 284 err = adjust_local_phandle_references(local_fixups, overlay, phandle_delta); 285 if (err) 286 return err; 287 288 overlay_symbols = NULL; 289 overlay_fixups = NULL; 290 291 tree_symbols = of_find_node_by_path("/__symbols__"); 292 293 for_each_child_of_node(overlay, child) { 294 if (!of_node_cmp(child->name, "__symbols__")) 295 overlay_symbols = child; 296 if (!of_node_cmp(child->name, "__fixups__")) 297 overlay_fixups = child; 298 } 299 300 if (!overlay_fixups) { 301 err = 0; 302 goto out; 303 } 304 305 if (!tree_symbols) { 306 pr_err("no symbols in root of device tree.\n"); 307 err = -EINVAL; 308 goto out; 309 } 310 311 for_each_property_of_node(overlay_fixups, prop) { 312 313 /* skip properties added automatically */ 314 if (!of_prop_cmp(prop->name, "name")) 315 continue; 316 317 err = of_property_read_string(tree_symbols, 318 prop->name, &refpath); 319 if (err) 320 goto out; 321 322 refnode = of_find_node_by_path(refpath); 323 if (!refnode) { 324 err = -ENOENT; 325 goto out; 326 } 327 328 phandle = refnode->phandle; 329 of_node_put(refnode); 330 331 err = update_usages_of_a_phandle_reference(overlay, prop, phandle); 332 if (err) 333 break; 334 } 335 336 out: 337 of_node_put(tree_symbols); 338 339 return err; 340 } 341 EXPORT_SYMBOL_GPL(of_resolve_phandles); 342