17941b27bSPantelis Antoniou /* 27941b27bSPantelis Antoniou * Functions for dealing with DT resolution 37941b27bSPantelis Antoniou * 47941b27bSPantelis Antoniou * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com> 57941b27bSPantelis Antoniou * Copyright (C) 2012 Texas Instruments Inc. 67941b27bSPantelis Antoniou * 77941b27bSPantelis Antoniou * This program is free software; you can redistribute it and/or 87941b27bSPantelis Antoniou * modify it under the terms of the GNU General Public License 97941b27bSPantelis Antoniou * version 2 as published by the Free Software Foundation. 107941b27bSPantelis Antoniou */ 117941b27bSPantelis Antoniou 12606ad42aSRob Herring #define pr_fmt(fmt) "OF: resolver: " fmt 13606ad42aSRob Herring 147941b27bSPantelis Antoniou #include <linux/kernel.h> 157941b27bSPantelis Antoniou #include <linux/module.h> 167941b27bSPantelis Antoniou #include <linux/of.h> 177941b27bSPantelis Antoniou #include <linux/of_device.h> 187941b27bSPantelis Antoniou #include <linux/string.h> 197941b27bSPantelis Antoniou #include <linux/ctype.h> 207941b27bSPantelis Antoniou #include <linux/errno.h> 217941b27bSPantelis Antoniou #include <linux/slab.h> 227941b27bSPantelis Antoniou 2327497e11SRob Herring #include "of_private.h" 2427497e11SRob Herring 257941b27bSPantelis Antoniou /* illegal phandle value (set when unresolved) */ 267941b27bSPantelis Antoniou #define OF_PHANDLE_ILLEGAL 0xdeadbeef 277941b27bSPantelis Antoniou 28f94823f2SFrank Rowand static phandle live_tree_max_phandle(void) 297941b27bSPantelis Antoniou { 307941b27bSPantelis Antoniou struct device_node *node; 317941b27bSPantelis Antoniou phandle phandle; 327941b27bSPantelis Antoniou unsigned long flags; 337941b27bSPantelis Antoniou 347941b27bSPantelis Antoniou raw_spin_lock_irqsave(&devtree_lock, flags); 357941b27bSPantelis Antoniou phandle = 0; 367941b27bSPantelis Antoniou for_each_of_allnodes(node) { 377941b27bSPantelis Antoniou if (node->phandle != OF_PHANDLE_ILLEGAL && 387941b27bSPantelis Antoniou node->phandle > phandle) 397941b27bSPantelis Antoniou phandle = node->phandle; 407941b27bSPantelis Antoniou } 417941b27bSPantelis Antoniou raw_spin_unlock_irqrestore(&devtree_lock, flags); 427941b27bSPantelis Antoniou 437941b27bSPantelis Antoniou return phandle; 447941b27bSPantelis Antoniou } 457941b27bSPantelis Antoniou 4625e16877SFrank Rowand static void adjust_overlay_phandles(struct device_node *overlay, 477941b27bSPantelis Antoniou int phandle_delta) 487941b27bSPantelis Antoniou { 497941b27bSPantelis Antoniou struct device_node *child; 507941b27bSPantelis Antoniou struct property *prop; 517941b27bSPantelis Antoniou phandle phandle; 527941b27bSPantelis Antoniou 53269f1a67SFrank Rowand /* adjust node's phandle in node */ 5425e16877SFrank Rowand if (overlay->phandle != 0 && overlay->phandle != OF_PHANDLE_ILLEGAL) 5525e16877SFrank Rowand overlay->phandle += phandle_delta; 567941b27bSPantelis Antoniou 57269f1a67SFrank Rowand /* copy adjusted phandle into *phandle properties */ 5825e16877SFrank Rowand for_each_property_of_node(overlay, prop) { 597941b27bSPantelis Antoniou 609f27ede4SFrank Rowand if (of_prop_cmp(prop->name, "phandle") && 619f27ede4SFrank Rowand of_prop_cmp(prop->name, "linux,phandle")) 627941b27bSPantelis Antoniou continue; 637941b27bSPantelis Antoniou 647941b27bSPantelis Antoniou if (prop->length < 4) 657941b27bSPantelis Antoniou continue; 667941b27bSPantelis Antoniou 677941b27bSPantelis Antoniou phandle = be32_to_cpup(prop->value); 68a67976ecSFrank Rowand if (phandle == OF_PHANDLE_ILLEGAL) 697941b27bSPantelis Antoniou continue; 707941b27bSPantelis Antoniou 7117a70355SRob Herring *(__be32 *)prop->value = cpu_to_be32(overlay->phandle); 727941b27bSPantelis Antoniou } 737941b27bSPantelis Antoniou 7425e16877SFrank Rowand for_each_child_of_node(overlay, child) 75f94823f2SFrank Rowand adjust_overlay_phandles(child, phandle_delta); 767941b27bSPantelis Antoniou } 777941b27bSPantelis Antoniou 7825e16877SFrank Rowand static int update_usages_of_a_phandle_reference(struct device_node *overlay, 7925e16877SFrank Rowand struct property *prop_fixup, phandle phandle) 807941b27bSPantelis Antoniou { 817941b27bSPantelis Antoniou struct device_node *refnode; 8225e16877SFrank Rowand struct property *prop; 8325e16877SFrank Rowand char *value, *cur, *end, *node_path, *prop_name, *s; 8425e16877SFrank Rowand int offset, len; 857941b27bSPantelis Antoniou int err = 0; 867941b27bSPantelis Antoniou 87eeb09506SStephen Boyd value = kmemdup(prop_fixup->value, prop_fixup->length, GFP_KERNEL); 8825e16877SFrank Rowand if (!value) 897941b27bSPantelis Antoniou return -ENOMEM; 907941b27bSPantelis Antoniou 91269f1a67SFrank Rowand /* prop_fixup contains a list of tuples of path:property_name:offset */ 9225e16877SFrank Rowand end = value + prop_fixup->length; 9325e16877SFrank Rowand for (cur = value; cur < end; cur += len + 1) { 9425e16877SFrank Rowand len = strlen(cur); 957941b27bSPantelis Antoniou 9625e16877SFrank Rowand node_path = cur; 9725e16877SFrank Rowand s = strchr(cur, ':'); 987941b27bSPantelis Antoniou if (!s) { 997941b27bSPantelis Antoniou err = -EINVAL; 1007941b27bSPantelis Antoniou goto err_fail; 1017941b27bSPantelis Antoniou } 1027941b27bSPantelis Antoniou *s++ = '\0'; 1037941b27bSPantelis Antoniou 10425e16877SFrank Rowand prop_name = s; 1057941b27bSPantelis Antoniou s = strchr(s, ':'); 1067941b27bSPantelis Antoniou if (!s) { 1077941b27bSPantelis Antoniou err = -EINVAL; 1087941b27bSPantelis Antoniou goto err_fail; 1097941b27bSPantelis Antoniou } 1107941b27bSPantelis Antoniou *s++ = '\0'; 111624ab2a4SFrank Rowand 1127941b27bSPantelis Antoniou err = kstrtoint(s, 10, &offset); 1139f27ede4SFrank Rowand if (err) 1147941b27bSPantelis Antoniou goto err_fail; 1157941b27bSPantelis Antoniou 11627497e11SRob Herring refnode = __of_find_node_by_full_path(of_node_get(overlay), node_path); 11796d1c8e8SFrank Rowand if (!refnode) 1187941b27bSPantelis Antoniou continue; 1197941b27bSPantelis Antoniou 12025e16877SFrank Rowand for_each_property_of_node(refnode, prop) { 12125e16877SFrank Rowand if (!of_prop_cmp(prop->name, prop_name)) 1227941b27bSPantelis Antoniou break; 1237941b27bSPantelis Antoniou } 12482f68756SAmitoj Kaur Chawla of_node_put(refnode); 1257941b27bSPantelis Antoniou 12625e16877SFrank Rowand if (!prop) { 1277941b27bSPantelis Antoniou err = -ENOENT; 1287941b27bSPantelis Antoniou goto err_fail; 1297941b27bSPantelis Antoniou } 1307941b27bSPantelis Antoniou 13125e16877SFrank Rowand *(__be32 *)(prop->value + offset) = cpu_to_be32(phandle); 1327941b27bSPantelis Antoniou } 1337941b27bSPantelis Antoniou 1347941b27bSPantelis Antoniou err_fail: 13525e16877SFrank Rowand kfree(value); 1367941b27bSPantelis Antoniou return err; 1377941b27bSPantelis Antoniou } 1387941b27bSPantelis Antoniou 139da56d04cSPantelis Antoniou /* compare nodes taking into account that 'name' strips out the @ part */ 140fad556bfSFrank Rowand static int node_name_cmp(const struct device_node *dn1, 141da56d04cSPantelis Antoniou const struct device_node *dn2) 142da56d04cSPantelis Antoniou { 14395e6b1faSRob Herring const char *n1 = kbasename(dn1->full_name); 14495e6b1faSRob Herring const char *n2 = kbasename(dn2->full_name); 145da56d04cSPantelis Antoniou 146da56d04cSPantelis Antoniou return of_node_cmp(n1, n2); 147da56d04cSPantelis Antoniou } 148da56d04cSPantelis Antoniou 1497941b27bSPantelis Antoniou /* 1507941b27bSPantelis Antoniou * Adjust the local phandle references by the given phandle delta. 151269f1a67SFrank Rowand * 152269f1a67SFrank Rowand * Subtree @local_fixups, which is overlay node __local_fixups__, 153269f1a67SFrank Rowand * mirrors the fragment node structure at the root of the overlay. 154269f1a67SFrank Rowand * 155269f1a67SFrank Rowand * For each property in the fragments that contains a phandle reference, 156269f1a67SFrank Rowand * @local_fixups has a property of the same name that contains a list 157269f1a67SFrank Rowand * of offsets of the phandle reference(s) within the respective property 158269f1a67SFrank Rowand * value(s). The values at these offsets will be fixed up. 1597941b27bSPantelis Antoniou */ 16025e16877SFrank Rowand static int adjust_local_phandle_references(struct device_node *local_fixups, 16125e16877SFrank Rowand struct device_node *overlay, int phandle_delta) 1627941b27bSPantelis Antoniou { 16325e16877SFrank Rowand struct device_node *child, *overlay_child; 16425e16877SFrank Rowand struct property *prop_fix, *prop; 165da56d04cSPantelis Antoniou int err, i, count; 166da56d04cSPantelis Antoniou unsigned int off; 1677941b27bSPantelis Antoniou 16825e16877SFrank Rowand if (!local_fixups) 1697941b27bSPantelis Antoniou return 0; 1707941b27bSPantelis Antoniou 17125e16877SFrank Rowand for_each_property_of_node(local_fixups, prop_fix) { 172da56d04cSPantelis Antoniou 1737941b27bSPantelis Antoniou /* skip properties added automatically */ 17425e16877SFrank Rowand if (!of_prop_cmp(prop_fix->name, "name") || 17525e16877SFrank Rowand !of_prop_cmp(prop_fix->name, "phandle") || 17625e16877SFrank Rowand !of_prop_cmp(prop_fix->name, "linux,phandle")) 1777941b27bSPantelis Antoniou continue; 1787941b27bSPantelis Antoniou 17925e16877SFrank Rowand if ((prop_fix->length % 4) != 0 || prop_fix->length == 0) 180da56d04cSPantelis Antoniou return -EINVAL; 18125e16877SFrank Rowand count = prop_fix->length / sizeof(__be32); 182da56d04cSPantelis Antoniou 18325e16877SFrank Rowand for_each_property_of_node(overlay, prop) { 18425e16877SFrank Rowand if (!of_prop_cmp(prop->name, prop_fix->name)) 185da56d04cSPantelis Antoniou break; 186da56d04cSPantelis Antoniou } 187da56d04cSPantelis Antoniou 18825e16877SFrank Rowand if (!prop) 189da56d04cSPantelis Antoniou return -EINVAL; 190da56d04cSPantelis Antoniou 191da56d04cSPantelis Antoniou for (i = 0; i < count; i++) { 19225e16877SFrank Rowand off = be32_to_cpu(((__be32 *)prop_fix->value)[i]); 193ea8229b7SFrank Rowand if ((off + 4) > prop->length) 194da56d04cSPantelis Antoniou return -EINVAL; 195da56d04cSPantelis Antoniou 196d35d623fSStephen Boyd be32_add_cpu(prop->value + off, phandle_delta); 197da56d04cSPantelis Antoniou } 198da56d04cSPantelis Antoniou } 199da56d04cSPantelis Antoniou 200269f1a67SFrank Rowand /* 201269f1a67SFrank Rowand * These nested loops recurse down two subtrees in parallel, where the 202269f1a67SFrank Rowand * node names in the two subtrees match. 203269f1a67SFrank Rowand * 204269f1a67SFrank Rowand * The roots of the subtrees are the overlay's __local_fixups__ node 205269f1a67SFrank Rowand * and the overlay's root node. 206269f1a67SFrank Rowand */ 20725e16877SFrank Rowand for_each_child_of_node(local_fixups, child) { 208da56d04cSPantelis Antoniou 20925e16877SFrank Rowand for_each_child_of_node(overlay, overlay_child) 21025e16877SFrank Rowand if (!node_name_cmp(child, overlay_child)) 211da56d04cSPantelis Antoniou break; 212da56d04cSPantelis Antoniou 21325e16877SFrank Rowand if (!overlay_child) 214da56d04cSPantelis Antoniou return -EINVAL; 215da56d04cSPantelis Antoniou 21625e16877SFrank Rowand err = adjust_local_phandle_references(child, overlay_child, 217da56d04cSPantelis Antoniou phandle_delta); 2189f27ede4SFrank Rowand if (err) 2197941b27bSPantelis Antoniou return err; 2207941b27bSPantelis Antoniou } 2217941b27bSPantelis Antoniou 2227941b27bSPantelis Antoniou return 0; 2237941b27bSPantelis Antoniou } 2247941b27bSPantelis Antoniou 2257941b27bSPantelis Antoniou /** 226269f1a67SFrank Rowand * of_resolve_phandles - Relocate and resolve overlay against live tree 2277941b27bSPantelis Antoniou * 228269f1a67SFrank Rowand * @overlay: Pointer to devicetree overlay to relocate and resolve 2297941b27bSPantelis Antoniou * 230269f1a67SFrank Rowand * Modify (relocate) values of local phandles in @overlay to a range that 231269f1a67SFrank Rowand * does not conflict with the live expanded devicetree. Update references 232269f1a67SFrank Rowand * to the local phandles in @overlay. Update (resolve) phandle references 233269f1a67SFrank Rowand * in @overlay that refer to the live expanded devicetree. 234269f1a67SFrank Rowand * 235269f1a67SFrank Rowand * Phandle values in the live tree are in the range of 236269f1a67SFrank Rowand * 1 .. live_tree_max_phandle(). The range of phandle values in the overlay 237269f1a67SFrank Rowand * also begin with at 1. Adjust the phandle values in the overlay to begin 238269f1a67SFrank Rowand * at live_tree_max_phandle() + 1. Update references to the phandles to 239269f1a67SFrank Rowand * the adjusted phandle values. 240269f1a67SFrank Rowand * 241269f1a67SFrank Rowand * The name of each property in the "__fixups__" node in the overlay matches 242269f1a67SFrank Rowand * the name of a symbol (a label) in the live tree. The values of each 243269f1a67SFrank Rowand * property in the "__fixups__" node is a list of the property values in the 244269f1a67SFrank Rowand * overlay that need to be updated to contain the phandle reference 245269f1a67SFrank Rowand * corresponding to that symbol in the live tree. Update the references in 246269f1a67SFrank Rowand * the overlay with the phandle values in the live tree. 247269f1a67SFrank Rowand * 248269f1a67SFrank Rowand * @overlay must be detached. 249269f1a67SFrank Rowand * 250269f1a67SFrank Rowand * Resolving and applying @overlay to the live expanded devicetree must be 251269f1a67SFrank Rowand * protected by a mechanism to ensure that multiple overlays are processed 252269f1a67SFrank Rowand * in a single threaded manner so that multiple overlays will not relocate 253269f1a67SFrank Rowand * phandles to overlapping ranges. The mechanism to enforce this is not 254269f1a67SFrank Rowand * yet implemented. 255269f1a67SFrank Rowand * 256269f1a67SFrank Rowand * Return: %0 on success or a negative error value on error. 2577941b27bSPantelis Antoniou */ 25825e16877SFrank Rowand int of_resolve_phandles(struct device_node *overlay) 2597941b27bSPantelis Antoniou { 26025e16877SFrank Rowand struct device_node *child, *local_fixups, *refnode; 2615581a95fSFrank Rowand struct device_node *tree_symbols, *overlay_fixups; 26225e16877SFrank Rowand struct property *prop; 2637941b27bSPantelis Antoniou const char *refpath; 2647941b27bSPantelis Antoniou phandle phandle, phandle_delta; 2657941b27bSPantelis Antoniou int err; 2667941b27bSPantelis Antoniou 267d9181b20SFrank Rowand tree_symbols = NULL; 268d9181b20SFrank Rowand 269624ab2a4SFrank Rowand if (!overlay) { 270624ab2a4SFrank Rowand pr_err("null overlay\n"); 271d9181b20SFrank Rowand err = -EINVAL; 27232bed310SMoritz Fischer goto out; 273624ab2a4SFrank Rowand } 274f948d6d8SFrank Rowand 275f948d6d8SFrank Rowand #if 0 276f948d6d8SFrank Rowand Temporarily disable check so that old style overlay unittests 277f948d6d8SFrank Rowand do not fail when of_resolve_phandles() is moved into 278f948d6d8SFrank Rowand of_overlay_apply(). 279f948d6d8SFrank Rowand 280624ab2a4SFrank Rowand if (!of_node_check_flag(overlay, OF_DETACHED)) { 281624ab2a4SFrank Rowand pr_err("overlay not detached\n"); 282d9181b20SFrank Rowand err = -EINVAL; 28332bed310SMoritz Fischer goto out; 284624ab2a4SFrank Rowand } 285f948d6d8SFrank Rowand #endif 2867941b27bSPantelis Antoniou 287f94823f2SFrank Rowand phandle_delta = live_tree_max_phandle() + 1; 28825e16877SFrank Rowand adjust_overlay_phandles(overlay, phandle_delta); 289da56d04cSPantelis Antoniou 29025e16877SFrank Rowand for_each_child_of_node(overlay, local_fixups) 29125e16877SFrank Rowand if (!of_node_cmp(local_fixups->name, "__local_fixups__")) 292da56d04cSPantelis Antoniou break; 293da56d04cSPantelis Antoniou 294624ab2a4SFrank Rowand err = adjust_local_phandle_references(local_fixups, overlay, phandle_delta); 2959f27ede4SFrank Rowand if (err) 29632bed310SMoritz Fischer goto out; 2977941b27bSPantelis Antoniou 29825e16877SFrank Rowand overlay_fixups = NULL; 2997941b27bSPantelis Antoniou 30025e16877SFrank Rowand for_each_child_of_node(overlay, child) { 301624ab2a4SFrank Rowand if (!of_node_cmp(child->name, "__fixups__")) 30225e16877SFrank Rowand overlay_fixups = child; 3037941b27bSPantelis Antoniou } 3047941b27bSPantelis Antoniou 30525e16877SFrank Rowand if (!overlay_fixups) { 306a67976ecSFrank Rowand err = 0; 3077941b27bSPantelis Antoniou goto out; 3087941b27bSPantelis Antoniou } 3097941b27bSPantelis Antoniou 3104458db4cSFrank Rowand tree_symbols = of_find_node_by_path("/__symbols__"); 31125e16877SFrank Rowand if (!tree_symbols) { 312624ab2a4SFrank Rowand pr_err("no symbols in root of device tree.\n"); 3137941b27bSPantelis Antoniou err = -EINVAL; 31432bed310SMoritz Fischer goto out; 3157941b27bSPantelis Antoniou } 3167941b27bSPantelis Antoniou 31725e16877SFrank Rowand for_each_property_of_node(overlay_fixups, prop) { 3187941b27bSPantelis Antoniou 3197941b27bSPantelis Antoniou /* skip properties added automatically */ 32025e16877SFrank Rowand if (!of_prop_cmp(prop->name, "name")) 3217941b27bSPantelis Antoniou continue; 3227941b27bSPantelis Antoniou 32325e16877SFrank Rowand err = of_property_read_string(tree_symbols, 32425e16877SFrank Rowand prop->name, &refpath); 3259f27ede4SFrank Rowand if (err) 32632bed310SMoritz Fischer goto out; 3277941b27bSPantelis Antoniou 3287941b27bSPantelis Antoniou refnode = of_find_node_by_path(refpath); 3297941b27bSPantelis Antoniou if (!refnode) { 3307941b27bSPantelis Antoniou err = -ENOENT; 33132bed310SMoritz Fischer goto out; 3327941b27bSPantelis Antoniou } 3337941b27bSPantelis Antoniou 3347941b27bSPantelis Antoniou phandle = refnode->phandle; 3357941b27bSPantelis Antoniou of_node_put(refnode); 3367941b27bSPantelis Antoniou 33725e16877SFrank Rowand err = update_usages_of_a_phandle_reference(overlay, prop, phandle); 3387941b27bSPantelis Antoniou if (err) 3397941b27bSPantelis Antoniou break; 3407941b27bSPantelis Antoniou } 3417941b27bSPantelis Antoniou 3427941b27bSPantelis Antoniou out: 34332bed310SMoritz Fischer if (err) 34432bed310SMoritz Fischer pr_err("overlay phandle fixup failed: %d\n", err); 34525e16877SFrank Rowand of_node_put(tree_symbols); 3467941b27bSPantelis Antoniou 3477941b27bSPantelis Antoniou return err; 3487941b27bSPantelis Antoniou } 3497941b27bSPantelis Antoniou EXPORT_SYMBOL_GPL(of_resolve_phandles); 350