1af6074fcSRob Herring // SPDX-License-Identifier: GPL-2.0
27941b27bSPantelis Antoniou /*
37941b27bSPantelis Antoniou * Functions for dealing with DT resolution
47941b27bSPantelis Antoniou *
57941b27bSPantelis Antoniou * Copyright (C) 2012 Pantelis Antoniou <[email protected]>
67941b27bSPantelis Antoniou * Copyright (C) 2012 Texas Instruments Inc.
77941b27bSPantelis Antoniou */
87941b27bSPantelis Antoniou
9606ad42aSRob Herring #define pr_fmt(fmt) "OF: resolver: " fmt
10606ad42aSRob Herring
1140b0f174SRob Herring #include <linux/cleanup.h>
127941b27bSPantelis Antoniou #include <linux/kernel.h>
137941b27bSPantelis Antoniou #include <linux/module.h>
147941b27bSPantelis Antoniou #include <linux/of.h>
157941b27bSPantelis Antoniou #include <linux/of_device.h>
167941b27bSPantelis Antoniou #include <linux/string.h>
177941b27bSPantelis Antoniou #include <linux/ctype.h>
187941b27bSPantelis Antoniou #include <linux/errno.h>
197941b27bSPantelis Antoniou #include <linux/slab.h>
207941b27bSPantelis Antoniou
2127497e11SRob Herring #include "of_private.h"
2227497e11SRob Herring
live_tree_max_phandle(void)23f94823f2SFrank Rowand static phandle live_tree_max_phandle(void)
247941b27bSPantelis Antoniou {
257941b27bSPantelis Antoniou struct device_node *node;
267941b27bSPantelis Antoniou phandle phandle;
277941b27bSPantelis Antoniou unsigned long flags;
287941b27bSPantelis Antoniou
297941b27bSPantelis Antoniou raw_spin_lock_irqsave(&devtree_lock, flags);
307941b27bSPantelis Antoniou phandle = 0;
317941b27bSPantelis Antoniou for_each_of_allnodes(node) {
327941b27bSPantelis Antoniou if (node->phandle != OF_PHANDLE_ILLEGAL &&
337941b27bSPantelis Antoniou node->phandle > phandle)
347941b27bSPantelis Antoniou phandle = node->phandle;
357941b27bSPantelis Antoniou }
367941b27bSPantelis Antoniou raw_spin_unlock_irqrestore(&devtree_lock, flags);
377941b27bSPantelis Antoniou
387941b27bSPantelis Antoniou return phandle;
397941b27bSPantelis Antoniou }
407941b27bSPantelis Antoniou
adjust_overlay_phandles(struct device_node * overlay,int phandle_delta)4125e16877SFrank Rowand static void adjust_overlay_phandles(struct device_node *overlay,
427941b27bSPantelis Antoniou int phandle_delta)
437941b27bSPantelis Antoniou {
447941b27bSPantelis Antoniou struct device_node *child;
459c63fea9SRob Herring (Arm) const struct property *prop;
467941b27bSPantelis Antoniou phandle phandle;
477941b27bSPantelis Antoniou
48269f1a67SFrank Rowand /* adjust node's phandle in node */
4925e16877SFrank Rowand if (overlay->phandle != 0 && overlay->phandle != OF_PHANDLE_ILLEGAL)
5025e16877SFrank Rowand overlay->phandle += phandle_delta;
517941b27bSPantelis Antoniou
52269f1a67SFrank Rowand /* copy adjusted phandle into *phandle properties */
5325e16877SFrank Rowand for_each_property_of_node(overlay, prop) {
547941b27bSPantelis Antoniou
559f27ede4SFrank Rowand if (of_prop_cmp(prop->name, "phandle") &&
569f27ede4SFrank Rowand of_prop_cmp(prop->name, "linux,phandle"))
577941b27bSPantelis Antoniou continue;
587941b27bSPantelis Antoniou
597941b27bSPantelis Antoniou if (prop->length < 4)
607941b27bSPantelis Antoniou continue;
617941b27bSPantelis Antoniou
627941b27bSPantelis Antoniou phandle = be32_to_cpup(prop->value);
63a67976ecSFrank Rowand if (phandle == OF_PHANDLE_ILLEGAL)
647941b27bSPantelis Antoniou continue;
657941b27bSPantelis Antoniou
6617a70355SRob Herring *(__be32 *)prop->value = cpu_to_be32(overlay->phandle);
677941b27bSPantelis Antoniou }
687941b27bSPantelis Antoniou
6925e16877SFrank Rowand for_each_child_of_node(overlay, child)
70f94823f2SFrank Rowand adjust_overlay_phandles(child, phandle_delta);
717941b27bSPantelis Antoniou }
727941b27bSPantelis Antoniou
update_usages_of_a_phandle_reference(struct device_node * overlay,const struct property * prop_fixup,phandle phandle)7325e16877SFrank Rowand static int update_usages_of_a_phandle_reference(struct device_node *overlay,
749c63fea9SRob Herring (Arm) const struct property *prop_fixup, phandle phandle)
757941b27bSPantelis Antoniou {
767941b27bSPantelis Antoniou struct device_node *refnode;
779c63fea9SRob Herring (Arm) const struct property *prop;
7840b0f174SRob Herring char *value __free(kfree) = kmemdup(prop_fixup->value, prop_fixup->length, GFP_KERNEL);
7940b0f174SRob Herring char *cur, *end, *node_path, *prop_name, *s;
8025e16877SFrank Rowand int offset, len;
817941b27bSPantelis Antoniou int err = 0;
827941b27bSPantelis Antoniou
8325e16877SFrank Rowand if (!value)
847941b27bSPantelis Antoniou return -ENOMEM;
857941b27bSPantelis Antoniou
86269f1a67SFrank Rowand /* prop_fixup contains a list of tuples of path:property_name:offset */
8725e16877SFrank Rowand end = value + prop_fixup->length;
8825e16877SFrank Rowand for (cur = value; cur < end; cur += len + 1) {
8925e16877SFrank Rowand len = strlen(cur);
907941b27bSPantelis Antoniou
9125e16877SFrank Rowand node_path = cur;
9225e16877SFrank Rowand s = strchr(cur, ':');
9340b0f174SRob Herring if (!s)
9440b0f174SRob Herring return -EINVAL;
957941b27bSPantelis Antoniou *s++ = '\0';
967941b27bSPantelis Antoniou
9725e16877SFrank Rowand prop_name = s;
987941b27bSPantelis Antoniou s = strchr(s, ':');
9940b0f174SRob Herring if (!s)
10040b0f174SRob Herring return -EINVAL;
1017941b27bSPantelis Antoniou *s++ = '\0';
102624ab2a4SFrank Rowand
1037941b27bSPantelis Antoniou err = kstrtoint(s, 10, &offset);
1049f27ede4SFrank Rowand if (err)
10540b0f174SRob Herring return err;
1067941b27bSPantelis Antoniou
10727497e11SRob Herring refnode = __of_find_node_by_full_path(of_node_get(overlay), node_path);
10896d1c8e8SFrank Rowand if (!refnode)
1097941b27bSPantelis Antoniou continue;
1107941b27bSPantelis Antoniou
11125e16877SFrank Rowand for_each_property_of_node(refnode, prop) {
11225e16877SFrank Rowand if (!of_prop_cmp(prop->name, prop_name))
1137941b27bSPantelis Antoniou break;
1147941b27bSPantelis Antoniou }
11582f68756SAmitoj Kaur Chawla of_node_put(refnode);
1167941b27bSPantelis Antoniou
11740b0f174SRob Herring if (!prop)
11840b0f174SRob Herring return -ENOENT;
1197941b27bSPantelis Antoniou
12040b0f174SRob Herring if (offset < 0 || offset + sizeof(__be32) > prop->length)
12140b0f174SRob Herring return -EINVAL;
122482137bfSFrank Rowand
12325e16877SFrank Rowand *(__be32 *)(prop->value + offset) = cpu_to_be32(phandle);
1247941b27bSPantelis Antoniou }
1257941b27bSPantelis Antoniou
12640b0f174SRob Herring return 0;
1277941b27bSPantelis Antoniou }
1287941b27bSPantelis Antoniou
129da56d04cSPantelis Antoniou /* compare nodes taking into account that 'name' strips out the @ part */
node_name_cmp(const struct device_node * dn1,const struct device_node * dn2)130fad556bfSFrank Rowand static int node_name_cmp(const struct device_node *dn1,
131da56d04cSPantelis Antoniou const struct device_node *dn2)
132da56d04cSPantelis Antoniou {
13395e6b1faSRob Herring const char *n1 = kbasename(dn1->full_name);
13495e6b1faSRob Herring const char *n2 = kbasename(dn2->full_name);
135da56d04cSPantelis Antoniou
136da56d04cSPantelis Antoniou return of_node_cmp(n1, n2);
137da56d04cSPantelis Antoniou }
138da56d04cSPantelis Antoniou
1397941b27bSPantelis Antoniou /*
1407941b27bSPantelis Antoniou * Adjust the local phandle references by the given phandle delta.
141269f1a67SFrank Rowand *
142269f1a67SFrank Rowand * Subtree @local_fixups, which is overlay node __local_fixups__,
143269f1a67SFrank Rowand * mirrors the fragment node structure at the root of the overlay.
144269f1a67SFrank Rowand *
145269f1a67SFrank Rowand * For each property in the fragments that contains a phandle reference,
146269f1a67SFrank Rowand * @local_fixups has a property of the same name that contains a list
147269f1a67SFrank Rowand * of offsets of the phandle reference(s) within the respective property
148269f1a67SFrank Rowand * value(s). The values at these offsets will be fixed up.
1497941b27bSPantelis Antoniou */
adjust_local_phandle_references(const struct device_node * local_fixups,const struct device_node * overlay,int phandle_delta)150ec8c2329SRob Herring (Arm) static int adjust_local_phandle_references(const struct device_node *local_fixups,
151ec8c2329SRob Herring (Arm) const struct device_node *overlay, int phandle_delta)
1527941b27bSPantelis Antoniou {
15397c5aac4SJinjie Ruan struct device_node *overlay_child;
1549c63fea9SRob Herring (Arm) const struct property *prop_fix, *prop;
155da56d04cSPantelis Antoniou int err, i, count;
156da56d04cSPantelis Antoniou unsigned int off;
1577941b27bSPantelis Antoniou
15825e16877SFrank Rowand if (!local_fixups)
1597941b27bSPantelis Antoniou return 0;
1607941b27bSPantelis Antoniou
16125e16877SFrank Rowand for_each_property_of_node(local_fixups, prop_fix) {
162da56d04cSPantelis Antoniou
1637941b27bSPantelis Antoniou /* skip properties added automatically */
164*f443029cSZijun Hu if (is_pseudo_property(prop_fix->name))
1657941b27bSPantelis Antoniou continue;
1667941b27bSPantelis Antoniou
16725e16877SFrank Rowand if ((prop_fix->length % 4) != 0 || prop_fix->length == 0)
168da56d04cSPantelis Antoniou return -EINVAL;
16925e16877SFrank Rowand count = prop_fix->length / sizeof(__be32);
170da56d04cSPantelis Antoniou
17125e16877SFrank Rowand for_each_property_of_node(overlay, prop) {
17225e16877SFrank Rowand if (!of_prop_cmp(prop->name, prop_fix->name))
173da56d04cSPantelis Antoniou break;
174da56d04cSPantelis Antoniou }
175da56d04cSPantelis Antoniou
17625e16877SFrank Rowand if (!prop)
177da56d04cSPantelis Antoniou return -EINVAL;
178da56d04cSPantelis Antoniou
179da56d04cSPantelis Antoniou for (i = 0; i < count; i++) {
18025e16877SFrank Rowand off = be32_to_cpu(((__be32 *)prop_fix->value)[i]);
181ea8229b7SFrank Rowand if ((off + 4) > prop->length)
182da56d04cSPantelis Antoniou return -EINVAL;
183da56d04cSPantelis Antoniou
184d35d623fSStephen Boyd be32_add_cpu(prop->value + off, phandle_delta);
185da56d04cSPantelis Antoniou }
186da56d04cSPantelis Antoniou }
187da56d04cSPantelis Antoniou
188269f1a67SFrank Rowand /*
189269f1a67SFrank Rowand * These nested loops recurse down two subtrees in parallel, where the
190269f1a67SFrank Rowand * node names in the two subtrees match.
191269f1a67SFrank Rowand *
192269f1a67SFrank Rowand * The roots of the subtrees are the overlay's __local_fixups__ node
193269f1a67SFrank Rowand * and the overlay's root node.
194269f1a67SFrank Rowand */
19597c5aac4SJinjie Ruan for_each_child_of_node_scoped(local_fixups, child) {
196da56d04cSPantelis Antoniou
19725e16877SFrank Rowand for_each_child_of_node(overlay, overlay_child)
19860d437bbSNishka Dasgupta if (!node_name_cmp(child, overlay_child)) {
19960d437bbSNishka Dasgupta of_node_put(overlay_child);
200da56d04cSPantelis Antoniou break;
20160d437bbSNishka Dasgupta }
202da56d04cSPantelis Antoniou
20397c5aac4SJinjie Ruan if (!overlay_child)
204da56d04cSPantelis Antoniou return -EINVAL;
205da56d04cSPantelis Antoniou
20625e16877SFrank Rowand err = adjust_local_phandle_references(child, overlay_child,
207da56d04cSPantelis Antoniou phandle_delta);
20897c5aac4SJinjie Ruan if (err)
2097941b27bSPantelis Antoniou return err;
2107941b27bSPantelis Antoniou }
2117941b27bSPantelis Antoniou
2127941b27bSPantelis Antoniou return 0;
2137941b27bSPantelis Antoniou }
2147941b27bSPantelis Antoniou
2157941b27bSPantelis Antoniou /**
216269f1a67SFrank Rowand * of_resolve_phandles - Relocate and resolve overlay against live tree
2177941b27bSPantelis Antoniou *
218269f1a67SFrank Rowand * @overlay: Pointer to devicetree overlay to relocate and resolve
2197941b27bSPantelis Antoniou *
220269f1a67SFrank Rowand * Modify (relocate) values of local phandles in @overlay to a range that
221269f1a67SFrank Rowand * does not conflict with the live expanded devicetree. Update references
222269f1a67SFrank Rowand * to the local phandles in @overlay. Update (resolve) phandle references
223269f1a67SFrank Rowand * in @overlay that refer to the live expanded devicetree.
224269f1a67SFrank Rowand *
225269f1a67SFrank Rowand * Phandle values in the live tree are in the range of
226269f1a67SFrank Rowand * 1 .. live_tree_max_phandle(). The range of phandle values in the overlay
227269f1a67SFrank Rowand * also begin with at 1. Adjust the phandle values in the overlay to begin
228269f1a67SFrank Rowand * at live_tree_max_phandle() + 1. Update references to the phandles to
229269f1a67SFrank Rowand * the adjusted phandle values.
230269f1a67SFrank Rowand *
231269f1a67SFrank Rowand * The name of each property in the "__fixups__" node in the overlay matches
232269f1a67SFrank Rowand * the name of a symbol (a label) in the live tree. The values of each
233269f1a67SFrank Rowand * property in the "__fixups__" node is a list of the property values in the
234269f1a67SFrank Rowand * overlay that need to be updated to contain the phandle reference
235269f1a67SFrank Rowand * corresponding to that symbol in the live tree. Update the references in
236269f1a67SFrank Rowand * the overlay with the phandle values in the live tree.
237269f1a67SFrank Rowand *
238269f1a67SFrank Rowand * @overlay must be detached.
239269f1a67SFrank Rowand *
240269f1a67SFrank Rowand * Resolving and applying @overlay to the live expanded devicetree must be
241269f1a67SFrank Rowand * protected by a mechanism to ensure that multiple overlays are processed
242269f1a67SFrank Rowand * in a single threaded manner so that multiple overlays will not relocate
243269f1a67SFrank Rowand * phandles to overlapping ranges. The mechanism to enforce this is not
244269f1a67SFrank Rowand * yet implemented.
245269f1a67SFrank Rowand *
246269f1a67SFrank Rowand * Return: %0 on success or a negative error value on error.
2477941b27bSPantelis Antoniou */
of_resolve_phandles(struct device_node * overlay)24825e16877SFrank Rowand int of_resolve_phandles(struct device_node *overlay)
2497941b27bSPantelis Antoniou {
250a46a0805SZijun Hu struct device_node *child, *refnode;
2515275e8b5SRob Herring (Arm) struct device_node *overlay_fixups;
252a46a0805SZijun Hu struct device_node __free(device_node) *local_fixups = NULL;
25325e16877SFrank Rowand struct property *prop;
2547941b27bSPantelis Antoniou const char *refpath;
2557941b27bSPantelis Antoniou phandle phandle, phandle_delta;
2567941b27bSPantelis Antoniou int err;
2577941b27bSPantelis Antoniou
258624ab2a4SFrank Rowand if (!overlay) {
259624ab2a4SFrank Rowand pr_err("null overlay\n");
2605275e8b5SRob Herring (Arm) return -EINVAL;
261624ab2a4SFrank Rowand }
262f948d6d8SFrank Rowand
263624ab2a4SFrank Rowand if (!of_node_check_flag(overlay, OF_DETACHED)) {
264624ab2a4SFrank Rowand pr_err("overlay not detached\n");
2655275e8b5SRob Herring (Arm) return -EINVAL;
266624ab2a4SFrank Rowand }
2677941b27bSPantelis Antoniou
268f94823f2SFrank Rowand phandle_delta = live_tree_max_phandle() + 1;
26925e16877SFrank Rowand adjust_overlay_phandles(overlay, phandle_delta);
270da56d04cSPantelis Antoniou
27125e16877SFrank Rowand for_each_child_of_node(overlay, local_fixups)
272b3e46d1aSRob Herring if (of_node_name_eq(local_fixups, "__local_fixups__"))
273da56d04cSPantelis Antoniou break;
274da56d04cSPantelis Antoniou
275624ab2a4SFrank Rowand err = adjust_local_phandle_references(local_fixups, overlay, phandle_delta);
2769f27ede4SFrank Rowand if (err)
2775275e8b5SRob Herring (Arm) return err;
2787941b27bSPantelis Antoniou
27925e16877SFrank Rowand overlay_fixups = NULL;
2807941b27bSPantelis Antoniou
28125e16877SFrank Rowand for_each_child_of_node(overlay, child) {
282b3e46d1aSRob Herring if (of_node_name_eq(child, "__fixups__"))
28325e16877SFrank Rowand overlay_fixups = child;
2847941b27bSPantelis Antoniou }
2857941b27bSPantelis Antoniou
2865275e8b5SRob Herring (Arm) if (!overlay_fixups)
2875275e8b5SRob Herring (Arm) return 0;
2887941b27bSPantelis Antoniou
2895275e8b5SRob Herring (Arm) struct device_node __free(device_node) *tree_symbols = of_find_node_by_path("/__symbols__");
29025e16877SFrank Rowand if (!tree_symbols) {
291624ab2a4SFrank Rowand pr_err("no symbols in root of device tree.\n");
2925275e8b5SRob Herring (Arm) return -EINVAL;
2937941b27bSPantelis Antoniou }
2947941b27bSPantelis Antoniou
29525e16877SFrank Rowand for_each_property_of_node(overlay_fixups, prop) {
2967941b27bSPantelis Antoniou
2977941b27bSPantelis Antoniou /* skip properties added automatically */
29825e16877SFrank Rowand if (!of_prop_cmp(prop->name, "name"))
2997941b27bSPantelis Antoniou continue;
3007941b27bSPantelis Antoniou
30125e16877SFrank Rowand err = of_property_read_string(tree_symbols,
30225e16877SFrank Rowand prop->name, &refpath);
303a3958323SLuca Ceresoli if (err) {
304a3958323SLuca Ceresoli pr_err("node label '%s' not found in live devicetree symbols table\n",
305a3958323SLuca Ceresoli prop->name);
3065275e8b5SRob Herring (Arm) return err;
307a3958323SLuca Ceresoli }
3087941b27bSPantelis Antoniou
3097941b27bSPantelis Antoniou refnode = of_find_node_by_path(refpath);
3105275e8b5SRob Herring (Arm) if (!refnode)
3115275e8b5SRob Herring (Arm) return -ENOENT;
3127941b27bSPantelis Antoniou
3137941b27bSPantelis Antoniou phandle = refnode->phandle;
3147941b27bSPantelis Antoniou of_node_put(refnode);
3157941b27bSPantelis Antoniou
31625e16877SFrank Rowand err = update_usages_of_a_phandle_reference(overlay, prop, phandle);
3177941b27bSPantelis Antoniou if (err)
3187941b27bSPantelis Antoniou break;
3197941b27bSPantelis Antoniou }
3207941b27bSPantelis Antoniou
32132bed310SMoritz Fischer if (err)
32232bed310SMoritz Fischer pr_err("overlay phandle fixup failed: %d\n", err);
3237941b27bSPantelis Antoniou return err;
3247941b27bSPantelis Antoniou }
3257941b27bSPantelis Antoniou EXPORT_SYMBOL_GPL(of_resolve_phandles);
326