xref: /openbmc/linux/drivers/of/resolver.c (revision a67976ec)
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/string.h>
227941b27bSPantelis Antoniou #include <linux/slab.h>
237941b27bSPantelis Antoniou 
247941b27bSPantelis Antoniou /* illegal phandle value (set when unresolved) */
257941b27bSPantelis Antoniou #define OF_PHANDLE_ILLEGAL	0xdeadbeef
267941b27bSPantelis Antoniou 
277941b27bSPantelis Antoniou /**
287941b27bSPantelis Antoniou  * Find a node with the give full name by recursively following any of
297941b27bSPantelis Antoniou  * the child node links.
307941b27bSPantelis Antoniou  */
317941b27bSPantelis Antoniou static struct device_node *__of_find_node_by_full_name(struct device_node *node,
327941b27bSPantelis Antoniou 		const char *full_name)
337941b27bSPantelis Antoniou {
347941b27bSPantelis Antoniou 	struct device_node *child, *found;
357941b27bSPantelis Antoniou 
367941b27bSPantelis Antoniou 	if (node == NULL)
377941b27bSPantelis Antoniou 		return NULL;
387941b27bSPantelis Antoniou 
397941b27bSPantelis Antoniou 	if (of_node_cmp(node->full_name, full_name) == 0)
4082f68756SAmitoj Kaur Chawla 		return of_node_get(node);
417941b27bSPantelis Antoniou 
427941b27bSPantelis Antoniou 	for_each_child_of_node(node, child) {
437941b27bSPantelis Antoniou 		found = __of_find_node_by_full_name(child, full_name);
4482f68756SAmitoj Kaur Chawla 		if (found != NULL) {
4582f68756SAmitoj Kaur Chawla 			of_node_put(child);
467941b27bSPantelis Antoniou 			return found;
477941b27bSPantelis Antoniou 		}
4882f68756SAmitoj Kaur Chawla 	}
497941b27bSPantelis Antoniou 
507941b27bSPantelis Antoniou 	return NULL;
517941b27bSPantelis Antoniou }
527941b27bSPantelis Antoniou 
537941b27bSPantelis Antoniou /*
547941b27bSPantelis Antoniou  * Find live tree's maximum phandle value.
557941b27bSPantelis Antoniou  */
567941b27bSPantelis Antoniou static phandle of_get_tree_max_phandle(void)
577941b27bSPantelis Antoniou {
587941b27bSPantelis Antoniou 	struct device_node *node;
597941b27bSPantelis Antoniou 	phandle phandle;
607941b27bSPantelis Antoniou 	unsigned long flags;
617941b27bSPantelis Antoniou 
627941b27bSPantelis Antoniou 	raw_spin_lock_irqsave(&devtree_lock, flags);
637941b27bSPantelis Antoniou 	phandle = 0;
647941b27bSPantelis Antoniou 	for_each_of_allnodes(node) {
657941b27bSPantelis Antoniou 		if (node->phandle != OF_PHANDLE_ILLEGAL &&
667941b27bSPantelis Antoniou 				node->phandle > phandle)
677941b27bSPantelis Antoniou 			phandle = node->phandle;
687941b27bSPantelis Antoniou 	}
697941b27bSPantelis Antoniou 	raw_spin_unlock_irqrestore(&devtree_lock, flags);
707941b27bSPantelis Antoniou 
717941b27bSPantelis Antoniou 	return phandle;
727941b27bSPantelis Antoniou }
737941b27bSPantelis Antoniou 
747941b27bSPantelis Antoniou /*
757941b27bSPantelis Antoniou  * Adjust a subtree's phandle values by a given delta.
767941b27bSPantelis Antoniou  */
777941b27bSPantelis Antoniou static void __of_adjust_tree_phandles(struct device_node *node,
787941b27bSPantelis Antoniou 		int phandle_delta)
797941b27bSPantelis Antoniou {
807941b27bSPantelis Antoniou 	struct device_node *child;
817941b27bSPantelis Antoniou 	struct property *prop;
827941b27bSPantelis Antoniou 	phandle phandle;
837941b27bSPantelis Antoniou 
847941b27bSPantelis Antoniou 	if (node->phandle != 0 && node->phandle != OF_PHANDLE_ILLEGAL)
857941b27bSPantelis Antoniou 		node->phandle += phandle_delta;
867941b27bSPantelis Antoniou 
877941b27bSPantelis Antoniou 	for_each_property_of_node(node, prop) {
887941b27bSPantelis Antoniou 
897941b27bSPantelis Antoniou 		if (of_prop_cmp(prop->name, "phandle") != 0 &&
907941b27bSPantelis Antoniou 		    of_prop_cmp(prop->name, "linux,phandle") != 0)
917941b27bSPantelis Antoniou 			continue;
927941b27bSPantelis Antoniou 
937941b27bSPantelis Antoniou 		if (prop->length < 4)
947941b27bSPantelis Antoniou 			continue;
957941b27bSPantelis Antoniou 
967941b27bSPantelis Antoniou 		phandle = be32_to_cpup(prop->value);
97a67976ecSFrank Rowand 		if (phandle == OF_PHANDLE_ILLEGAL)
987941b27bSPantelis Antoniou 			continue;
997941b27bSPantelis Antoniou 
1007941b27bSPantelis Antoniou 		*(uint32_t *)prop->value = cpu_to_be32(node->phandle);
1017941b27bSPantelis Antoniou 	}
1027941b27bSPantelis Antoniou 
1037941b27bSPantelis Antoniou 	for_each_child_of_node(node, child)
1047941b27bSPantelis Antoniou 		__of_adjust_tree_phandles(child, phandle_delta);
1057941b27bSPantelis Antoniou }
1067941b27bSPantelis Antoniou 
107da56d04cSPantelis Antoniou static int __of_adjust_phandle_ref(struct device_node *node,
108da56d04cSPantelis Antoniou 		struct property *rprop, int value)
1097941b27bSPantelis Antoniou {
1107941b27bSPantelis Antoniou 	phandle phandle;
1117941b27bSPantelis Antoniou 	struct device_node *refnode;
1127941b27bSPantelis Antoniou 	struct property *sprop;
1137941b27bSPantelis Antoniou 	char *propval, *propcur, *propend, *nodestr, *propstr, *s;
1147941b27bSPantelis Antoniou 	int offset, propcurlen;
1157941b27bSPantelis Antoniou 	int err = 0;
1167941b27bSPantelis Antoniou 
1177941b27bSPantelis Antoniou 	propval = kmalloc(rprop->length, GFP_KERNEL);
1187941b27bSPantelis Antoniou 	if (!propval) {
1197941b27bSPantelis Antoniou 		pr_err("%s: Could not copy value of '%s'\n",
1207941b27bSPantelis Antoniou 				__func__, rprop->name);
1217941b27bSPantelis Antoniou 		return -ENOMEM;
1227941b27bSPantelis Antoniou 	}
1237941b27bSPantelis Antoniou 	memcpy(propval, rprop->value, rprop->length);
1247941b27bSPantelis Antoniou 
1257941b27bSPantelis Antoniou 	propend = propval + rprop->length;
1267941b27bSPantelis Antoniou 	for (propcur = propval; propcur < propend; propcur += propcurlen + 1) {
1277941b27bSPantelis Antoniou 		propcurlen = strlen(propcur);
1287941b27bSPantelis Antoniou 
1297941b27bSPantelis Antoniou 		nodestr = propcur;
1307941b27bSPantelis Antoniou 		s = strchr(propcur, ':');
1317941b27bSPantelis Antoniou 		if (!s) {
1327941b27bSPantelis Antoniou 			pr_err("%s: Illegal symbol entry '%s' (1)\n",
1337941b27bSPantelis Antoniou 				__func__, propcur);
1347941b27bSPantelis Antoniou 			err = -EINVAL;
1357941b27bSPantelis Antoniou 			goto err_fail;
1367941b27bSPantelis Antoniou 		}
1377941b27bSPantelis Antoniou 		*s++ = '\0';
1387941b27bSPantelis Antoniou 
1397941b27bSPantelis Antoniou 		propstr = s;
1407941b27bSPantelis Antoniou 		s = strchr(s, ':');
1417941b27bSPantelis Antoniou 		if (!s) {
1427941b27bSPantelis Antoniou 			pr_err("%s: Illegal symbol entry '%s' (2)\n",
1437941b27bSPantelis Antoniou 				__func__, (char *)rprop->value);
1447941b27bSPantelis Antoniou 			err = -EINVAL;
1457941b27bSPantelis Antoniou 			goto err_fail;
1467941b27bSPantelis Antoniou 		}
1477941b27bSPantelis Antoniou 
1487941b27bSPantelis Antoniou 		*s++ = '\0';
1497941b27bSPantelis Antoniou 		err = kstrtoint(s, 10, &offset);
1507941b27bSPantelis Antoniou 		if (err != 0) {
1517941b27bSPantelis Antoniou 			pr_err("%s: Could get offset '%s'\n",
1527941b27bSPantelis Antoniou 				__func__, (char *)rprop->value);
1537941b27bSPantelis Antoniou 			goto err_fail;
1547941b27bSPantelis Antoniou 		}
1557941b27bSPantelis Antoniou 
1567941b27bSPantelis Antoniou 		refnode = __of_find_node_by_full_name(node, nodestr);
1577941b27bSPantelis Antoniou 		if (!refnode) {
1587941b27bSPantelis Antoniou 			pr_warn("%s: Could not find refnode '%s'\n",
1597941b27bSPantelis Antoniou 				__func__, (char *)rprop->value);
1607941b27bSPantelis Antoniou 			continue;
1617941b27bSPantelis Antoniou 		}
1627941b27bSPantelis Antoniou 
1637941b27bSPantelis Antoniou 		for_each_property_of_node(refnode, sprop) {
1647941b27bSPantelis Antoniou 			if (of_prop_cmp(sprop->name, propstr) == 0)
1657941b27bSPantelis Antoniou 				break;
1667941b27bSPantelis Antoniou 		}
16782f68756SAmitoj Kaur Chawla 		of_node_put(refnode);
1687941b27bSPantelis Antoniou 
1697941b27bSPantelis Antoniou 		if (!sprop) {
1707941b27bSPantelis Antoniou 			pr_err("%s: Could not find property '%s'\n",
1717941b27bSPantelis Antoniou 				__func__, (char *)rprop->value);
1727941b27bSPantelis Antoniou 			err = -ENOENT;
1737941b27bSPantelis Antoniou 			goto err_fail;
1747941b27bSPantelis Antoniou 		}
1757941b27bSPantelis Antoniou 
176da56d04cSPantelis Antoniou 		phandle = value;
1777941b27bSPantelis Antoniou 		*(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle);
1787941b27bSPantelis Antoniou 	}
1797941b27bSPantelis Antoniou 
1807941b27bSPantelis Antoniou err_fail:
1817941b27bSPantelis Antoniou 	kfree(propval);
1827941b27bSPantelis Antoniou 	return err;
1837941b27bSPantelis Antoniou }
1847941b27bSPantelis Antoniou 
185da56d04cSPantelis Antoniou /* compare nodes taking into account that 'name' strips out the @ part */
186da56d04cSPantelis Antoniou static int __of_node_name_cmp(const struct device_node *dn1,
187da56d04cSPantelis Antoniou 		const struct device_node *dn2)
188da56d04cSPantelis Antoniou {
189da56d04cSPantelis Antoniou 	const char *n1 = strrchr(dn1->full_name, '/') ? : "/";
190da56d04cSPantelis Antoniou 	const char *n2 = strrchr(dn2->full_name, '/') ? : "/";
191da56d04cSPantelis Antoniou 
192da56d04cSPantelis Antoniou 	return of_node_cmp(n1, n2);
193da56d04cSPantelis Antoniou }
194da56d04cSPantelis Antoniou 
1957941b27bSPantelis Antoniou /*
1967941b27bSPantelis Antoniou  * Adjust the local phandle references by the given phandle delta.
197da56d04cSPantelis Antoniou  * Assumes the existances of a __local_fixups__ node at the root.
198da56d04cSPantelis Antoniou  * Assumes that __of_verify_tree_phandle_references has been called.
199da56d04cSPantelis Antoniou  * Does not take any devtree locks so make sure you call this on a tree
200da56d04cSPantelis Antoniou  * which is at the detached state.
2017941b27bSPantelis Antoniou  */
2027941b27bSPantelis Antoniou static int __of_adjust_tree_phandle_references(struct device_node *node,
203da56d04cSPantelis Antoniou 		struct device_node *target, int phandle_delta)
2047941b27bSPantelis Antoniou {
205da56d04cSPantelis Antoniou 	struct device_node *child, *childtarget;
206da56d04cSPantelis Antoniou 	struct property *rprop, *sprop;
207da56d04cSPantelis Antoniou 	int err, i, count;
208da56d04cSPantelis Antoniou 	unsigned int off;
209da56d04cSPantelis Antoniou 	phandle phandle;
2107941b27bSPantelis Antoniou 
211da56d04cSPantelis Antoniou 	if (node == NULL)
2127941b27bSPantelis Antoniou 		return 0;
2137941b27bSPantelis Antoniou 
214da56d04cSPantelis Antoniou 	for_each_property_of_node(node, rprop) {
215da56d04cSPantelis Antoniou 
2167941b27bSPantelis Antoniou 		/* skip properties added automatically */
217da56d04cSPantelis Antoniou 		if (of_prop_cmp(rprop->name, "name") == 0 ||
218da56d04cSPantelis Antoniou 		    of_prop_cmp(rprop->name, "phandle") == 0 ||
219da56d04cSPantelis Antoniou 		    of_prop_cmp(rprop->name, "linux,phandle") == 0)
2207941b27bSPantelis Antoniou 			continue;
2217941b27bSPantelis Antoniou 
222da56d04cSPantelis Antoniou 		if ((rprop->length % 4) != 0 || rprop->length == 0) {
223da56d04cSPantelis Antoniou 			pr_err("%s: Illegal property (size) '%s' @%s\n",
224da56d04cSPantelis Antoniou 					__func__, rprop->name, node->full_name);
225da56d04cSPantelis Antoniou 			return -EINVAL;
226da56d04cSPantelis Antoniou 		}
227da56d04cSPantelis Antoniou 		count = rprop->length / sizeof(__be32);
228da56d04cSPantelis Antoniou 
229da56d04cSPantelis Antoniou 		for_each_property_of_node(target, sprop) {
230da56d04cSPantelis Antoniou 			if (of_prop_cmp(sprop->name, rprop->name) == 0)
231da56d04cSPantelis Antoniou 				break;
232da56d04cSPantelis Antoniou 		}
233da56d04cSPantelis Antoniou 
234da56d04cSPantelis Antoniou 		if (sprop == NULL) {
235da56d04cSPantelis Antoniou 			pr_err("%s: Could not find target property '%s' @%s\n",
236da56d04cSPantelis Antoniou 					__func__, rprop->name, node->full_name);
237da56d04cSPantelis Antoniou 			return -EINVAL;
238da56d04cSPantelis Antoniou 		}
239da56d04cSPantelis Antoniou 
240da56d04cSPantelis Antoniou 		for (i = 0; i < count; i++) {
241da56d04cSPantelis Antoniou 			off = be32_to_cpu(((__be32 *)rprop->value)[i]);
242da56d04cSPantelis Antoniou 			if (off >= sprop->length ||
243da56d04cSPantelis Antoniou 					(off + 4) > sprop->length) {
244da56d04cSPantelis Antoniou 				pr_err("%s: Illegal property '%s' @%s\n",
245da56d04cSPantelis Antoniou 						__func__, rprop->name,
246da56d04cSPantelis Antoniou 						node->full_name);
247da56d04cSPantelis Antoniou 				return -EINVAL;
248da56d04cSPantelis Antoniou 			}
249da56d04cSPantelis Antoniou 
250da56d04cSPantelis Antoniou 			if (phandle_delta) {
251da56d04cSPantelis Antoniou 				phandle = be32_to_cpu(*(__be32 *)(sprop->value + off));
252da56d04cSPantelis Antoniou 				phandle += phandle_delta;
253da56d04cSPantelis Antoniou 				*(__be32 *)(sprop->value + off) = cpu_to_be32(phandle);
254da56d04cSPantelis Antoniou 			}
255da56d04cSPantelis Antoniou 		}
256da56d04cSPantelis Antoniou 	}
257da56d04cSPantelis Antoniou 
258da56d04cSPantelis Antoniou 	for_each_child_of_node(node, child) {
259da56d04cSPantelis Antoniou 
260da56d04cSPantelis Antoniou 		for_each_child_of_node(target, childtarget)
261da56d04cSPantelis Antoniou 			if (__of_node_name_cmp(child, childtarget) == 0)
262da56d04cSPantelis Antoniou 				break;
263da56d04cSPantelis Antoniou 
264da56d04cSPantelis Antoniou 		if (!childtarget) {
265da56d04cSPantelis Antoniou 			pr_err("%s: Could not find target child '%s' @%s\n",
266da56d04cSPantelis Antoniou 					__func__, child->name, node->full_name);
267da56d04cSPantelis Antoniou 			return -EINVAL;
268da56d04cSPantelis Antoniou 		}
269da56d04cSPantelis Antoniou 
270da56d04cSPantelis Antoniou 		err = __of_adjust_tree_phandle_references(child, childtarget,
271da56d04cSPantelis Antoniou 				phandle_delta);
272da56d04cSPantelis Antoniou 		if (err != 0)
2737941b27bSPantelis Antoniou 			return err;
2747941b27bSPantelis Antoniou 	}
2757941b27bSPantelis Antoniou 
2767941b27bSPantelis Antoniou 	return 0;
2777941b27bSPantelis Antoniou }
2787941b27bSPantelis Antoniou 
2797941b27bSPantelis Antoniou /**
2807941b27bSPantelis Antoniou  * of_resolve	- Resolve the given node against the live tree.
2817941b27bSPantelis Antoniou  *
2827941b27bSPantelis Antoniou  * @resolve:	Node to resolve
2837941b27bSPantelis Antoniou  *
2847941b27bSPantelis Antoniou  * Perform dynamic Device Tree resolution against the live tree
2857941b27bSPantelis Antoniou  * to the given node to resolve. This depends on the live tree
2867941b27bSPantelis Antoniou  * having a __symbols__ node, and the resolve node the __fixups__ &
2877941b27bSPantelis Antoniou  * __local_fixups__ nodes (if needed).
2887941b27bSPantelis Antoniou  * The result of the operation is a resolve node that it's contents
2897941b27bSPantelis Antoniou  * are fit to be inserted or operate upon the live tree.
2907941b27bSPantelis Antoniou  * Returns 0 on success or a negative error value on error.
2917941b27bSPantelis Antoniou  */
2927941b27bSPantelis Antoniou int of_resolve_phandles(struct device_node *resolve)
2937941b27bSPantelis Antoniou {
294da56d04cSPantelis Antoniou 	struct device_node *child, *childroot, *refnode;
2957941b27bSPantelis Antoniou 	struct device_node *root_sym, *resolve_sym, *resolve_fix;
2967941b27bSPantelis Antoniou 	struct property *rprop;
2977941b27bSPantelis Antoniou 	const char *refpath;
2987941b27bSPantelis Antoniou 	phandle phandle, phandle_delta;
2997941b27bSPantelis Antoniou 	int err;
3007941b27bSPantelis Antoniou 
3015de3bbc8SMichal Suchanek 	if (!resolve)
3025de3bbc8SMichal Suchanek 		pr_err("%s: null node\n", __func__);
3035de3bbc8SMichal Suchanek 	if (resolve && !of_node_check_flag(resolve, OF_DETACHED))
3045de3bbc8SMichal Suchanek 		pr_err("%s: node %s not detached\n", __func__,
3055de3bbc8SMichal Suchanek 			 resolve->full_name);
3067941b27bSPantelis Antoniou 	if (!resolve || !of_node_check_flag(resolve, OF_DETACHED))
3077941b27bSPantelis Antoniou 		return -EINVAL;
3087941b27bSPantelis Antoniou 
3097941b27bSPantelis Antoniou 	phandle_delta = of_get_tree_max_phandle() + 1;
3107941b27bSPantelis Antoniou 	__of_adjust_tree_phandles(resolve, phandle_delta);
311da56d04cSPantelis Antoniou 
312da56d04cSPantelis Antoniou 	childroot = NULL;
313da56d04cSPantelis Antoniou 	for_each_child_of_node(resolve, childroot)
314da56d04cSPantelis Antoniou 		if (of_node_cmp(childroot->name, "__local_fixups__") == 0)
315da56d04cSPantelis Antoniou 			break;
316da56d04cSPantelis Antoniou 
317da56d04cSPantelis Antoniou 	if (childroot != NULL) {
318da56d04cSPantelis Antoniou 		err = __of_adjust_tree_phandle_references(childroot,
319da56d04cSPantelis Antoniou 				resolve, 0);
3207941b27bSPantelis Antoniou 		if (err != 0)
3217941b27bSPantelis Antoniou 			return err;
3227941b27bSPantelis Antoniou 
323da56d04cSPantelis Antoniou 		BUG_ON(__of_adjust_tree_phandle_references(childroot,
324da56d04cSPantelis Antoniou 				resolve, phandle_delta));
325da56d04cSPantelis Antoniou 	}
326da56d04cSPantelis Antoniou 
3277941b27bSPantelis Antoniou 	root_sym = NULL;
3287941b27bSPantelis Antoniou 	resolve_sym = NULL;
3297941b27bSPantelis Antoniou 	resolve_fix = NULL;
3307941b27bSPantelis Antoniou 
3317941b27bSPantelis Antoniou 	root_sym = of_find_node_by_path("/__symbols__");
3327941b27bSPantelis Antoniou 
3337941b27bSPantelis Antoniou 	for_each_child_of_node(resolve, child) {
3347941b27bSPantelis Antoniou 
3357941b27bSPantelis Antoniou 		if (!resolve_sym &&
3367941b27bSPantelis Antoniou 				of_node_cmp(child->name, "__symbols__") == 0)
3377941b27bSPantelis Antoniou 			resolve_sym = child;
3387941b27bSPantelis Antoniou 
3397941b27bSPantelis Antoniou 		if (!resolve_fix &&
3407941b27bSPantelis Antoniou 				of_node_cmp(child->name, "__fixups__") == 0)
3417941b27bSPantelis Antoniou 			resolve_fix = child;
3427941b27bSPantelis Antoniou 
3437941b27bSPantelis Antoniou 		if (resolve_sym && resolve_fix)
3447941b27bSPantelis Antoniou 			break;
3457941b27bSPantelis Antoniou 	}
3467941b27bSPantelis Antoniou 
3477941b27bSPantelis Antoniou 	if (!resolve_fix) {
348a67976ecSFrank Rowand 		err = 0;
3497941b27bSPantelis Antoniou 		goto out;
3507941b27bSPantelis Antoniou 	}
3517941b27bSPantelis Antoniou 
3527941b27bSPantelis Antoniou 	if (!root_sym) {
3535de3bbc8SMichal Suchanek 		pr_err("%s: no symbols in root of device tree.\n", __func__);
3547941b27bSPantelis Antoniou 		err = -EINVAL;
3557941b27bSPantelis Antoniou 		goto out;
3567941b27bSPantelis Antoniou 	}
3577941b27bSPantelis Antoniou 
3587941b27bSPantelis Antoniou 	for_each_property_of_node(resolve_fix, rprop) {
3597941b27bSPantelis Antoniou 
3607941b27bSPantelis Antoniou 		/* skip properties added automatically */
3617941b27bSPantelis Antoniou 		if (of_prop_cmp(rprop->name, "name") == 0)
3627941b27bSPantelis Antoniou 			continue;
3637941b27bSPantelis Antoniou 
3647941b27bSPantelis Antoniou 		err = of_property_read_string(root_sym,
3657941b27bSPantelis Antoniou 				rprop->name, &refpath);
3667941b27bSPantelis Antoniou 		if (err != 0) {
3677941b27bSPantelis Antoniou 			pr_err("%s: Could not find symbol '%s'\n",
3687941b27bSPantelis Antoniou 					__func__, rprop->name);
3697941b27bSPantelis Antoniou 			goto out;
3707941b27bSPantelis Antoniou 		}
3717941b27bSPantelis Antoniou 
3727941b27bSPantelis Antoniou 		refnode = of_find_node_by_path(refpath);
3737941b27bSPantelis Antoniou 		if (!refnode) {
3747941b27bSPantelis Antoniou 			pr_err("%s: Could not find node by path '%s'\n",
3757941b27bSPantelis Antoniou 					__func__, refpath);
3767941b27bSPantelis Antoniou 			err = -ENOENT;
3777941b27bSPantelis Antoniou 			goto out;
3787941b27bSPantelis Antoniou 		}
3797941b27bSPantelis Antoniou 
3807941b27bSPantelis Antoniou 		phandle = refnode->phandle;
3817941b27bSPantelis Antoniou 		of_node_put(refnode);
3827941b27bSPantelis Antoniou 
3837941b27bSPantelis Antoniou 		pr_debug("%s: %s phandle is 0x%08x\n",
3847941b27bSPantelis Antoniou 				__func__, rprop->name, phandle);
3857941b27bSPantelis Antoniou 
386da56d04cSPantelis Antoniou 		err = __of_adjust_phandle_ref(resolve, rprop, phandle);
3877941b27bSPantelis Antoniou 		if (err)
3887941b27bSPantelis Antoniou 			break;
3897941b27bSPantelis Antoniou 	}
3907941b27bSPantelis Antoniou 
3917941b27bSPantelis Antoniou out:
3927941b27bSPantelis Antoniou 	of_node_put(root_sym);
3937941b27bSPantelis Antoniou 
3947941b27bSPantelis Antoniou 	return err;
3957941b27bSPantelis Antoniou }
3967941b27bSPantelis Antoniou EXPORT_SYMBOL_GPL(of_resolve_phandles);
397