xref: /openbmc/linux/drivers/of/overlay.c (revision 5d007ffd)
1af6074fcSRob Herring // SPDX-License-Identifier: GPL-2.0
27518b589SPantelis Antoniou /*
37518b589SPantelis Antoniou  * Functions for working with device tree overlays
47518b589SPantelis Antoniou  *
57518b589SPantelis Antoniou  * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
67518b589SPantelis Antoniou  * Copyright (C) 2012 Texas Instruments Inc.
77518b589SPantelis Antoniou  */
8606ad42aSRob Herring 
9606ad42aSRob Herring #define pr_fmt(fmt)	"OF: overlay: " fmt
10606ad42aSRob Herring 
117518b589SPantelis Antoniou #include <linux/kernel.h>
127518b589SPantelis Antoniou #include <linux/module.h>
137518b589SPantelis Antoniou #include <linux/of.h>
147518b589SPantelis Antoniou #include <linux/of_device.h>
1539a751a4SFrank Rowand #include <linux/of_fdt.h>
167518b589SPantelis Antoniou #include <linux/string.h>
177518b589SPantelis Antoniou #include <linux/ctype.h>
187518b589SPantelis Antoniou #include <linux/errno.h>
197518b589SPantelis Antoniou #include <linux/slab.h>
2039a751a4SFrank Rowand #include <linux/libfdt.h>
217518b589SPantelis Antoniou #include <linux/err.h>
220d1886dfSMark Brown #include <linux/idr.h>
237518b589SPantelis Antoniou 
247518b589SPantelis Antoniou #include "of_private.h"
257518b589SPantelis Antoniou 
267518b589SPantelis Antoniou /**
276b4955baSFrank Rowand  * struct target - info about current target node as recursing through overlay
286b4955baSFrank Rowand  * @np:			node where current level of overlay will be applied
296b4955baSFrank Rowand  * @in_livetree:	@np is a node in the live devicetree
306b4955baSFrank Rowand  *
316b4955baSFrank Rowand  * Used in the algorithm to create the portion of a changeset that describes
326b4955baSFrank Rowand  * an overlay fragment, which is a devicetree subtree.  Initially @np is a node
336b4955baSFrank Rowand  * in the live devicetree where the overlay subtree is targeted to be grafted
346b4955baSFrank Rowand  * into.  When recursing to the next level of the overlay subtree, the target
356b4955baSFrank Rowand  * also recurses to the next level of the live devicetree, as long as overlay
366b4955baSFrank Rowand  * subtree node also exists in the live devicetree.  When a node in the overlay
376b4955baSFrank Rowand  * subtree does not exist at the same level in the live devicetree, target->np
386b4955baSFrank Rowand  * points to a newly allocated node, and all subsequent targets in the subtree
396b4955baSFrank Rowand  * will be newly allocated nodes.
406b4955baSFrank Rowand  */
416b4955baSFrank Rowand struct target {
426b4955baSFrank Rowand 	struct device_node *np;
436b4955baSFrank Rowand 	bool in_livetree;
446b4955baSFrank Rowand };
456b4955baSFrank Rowand 
466b4955baSFrank Rowand /**
470290c4caSFrank Rowand  * struct fragment - info about fragment nodes in overlay expanded device tree
480290c4caSFrank Rowand  * @overlay:	pointer to the __overlay__ node
49*5d007ffdSGeert Uytterhoeven  * @target:	target of the overlay operation
507518b589SPantelis Antoniou  */
510290c4caSFrank Rowand struct fragment {
527518b589SPantelis Antoniou 	struct device_node *overlay;
5381225ea6SFrank Rowand 	struct device_node *target;
547518b589SPantelis Antoniou };
557518b589SPantelis Antoniou 
567518b589SPantelis Antoniou /**
570290c4caSFrank Rowand  * struct overlay_changeset
5839a751a4SFrank Rowand  * @id:			changeset identifier
590290c4caSFrank Rowand  * @ovcs_list:		list on which we are located
601e408966SFrank Rowand  * @new_fdt:		Memory allocated to hold unflattened aligned FDT
61067c0987SFrank Rowand  * @overlay_mem:	the memory chunk that contains @overlay_root
621e408966SFrank Rowand  * @overlay_root:	expanded device tree that contains the fragment nodes
63067c0987SFrank Rowand  * @notify_state:	most recent notify action used on overlay
643912b791SFrank Rowand  * @count:		count of fragment structures
653912b791SFrank Rowand  * @fragments:		fragment nodes in the overlay expanded device tree
663912b791SFrank Rowand  * @symbols_fragment:	last element of @fragments[] is the  __symbols__ node
670290c4caSFrank Rowand  * @cset:		changeset to apply fragments to live device tree
687518b589SPantelis Antoniou  */
690290c4caSFrank Rowand struct overlay_changeset {
707518b589SPantelis Antoniou 	int id;
710290c4caSFrank Rowand 	struct list_head ovcs_list;
721e408966SFrank Rowand 	const void *new_fdt;
73067c0987SFrank Rowand 	const void *overlay_mem;
741e408966SFrank Rowand 	struct device_node *overlay_root;
75067c0987SFrank Rowand 	enum of_overlay_notify_action notify_state;
767518b589SPantelis Antoniou 	int count;
770290c4caSFrank Rowand 	struct fragment *fragments;
783912b791SFrank Rowand 	bool symbols_fragment;
797518b589SPantelis Antoniou 	struct of_changeset cset;
807518b589SPantelis Antoniou };
817518b589SPantelis Antoniou 
8224789c5cSFrank Rowand /* flags are sticky - once set, do not reset */
8324789c5cSFrank Rowand static int devicetree_state_flags;
8424789c5cSFrank Rowand #define DTSF_APPLY_FAIL		0x01
8524789c5cSFrank Rowand #define DTSF_REVERT_FAIL	0x02
8624789c5cSFrank Rowand 
8724789c5cSFrank Rowand /*
8824789c5cSFrank Rowand  * If a changeset apply or revert encounters an error, an attempt will
8924789c5cSFrank Rowand  * be made to undo partial changes, but may fail.  If the undo fails
9024789c5cSFrank Rowand  * we do not know the state of the devicetree.
9124789c5cSFrank Rowand  */
devicetree_corrupt(void)9224789c5cSFrank Rowand static int devicetree_corrupt(void)
9324789c5cSFrank Rowand {
9424789c5cSFrank Rowand 	return devicetree_state_flags &
9524789c5cSFrank Rowand 		(DTSF_APPLY_FAIL | DTSF_REVERT_FAIL);
9624789c5cSFrank Rowand }
9724789c5cSFrank Rowand 
980290c4caSFrank Rowand static int build_changeset_next_level(struct overlay_changeset *ovcs,
996b4955baSFrank Rowand 		struct target *target, const struct device_node *overlay_node);
1007518b589SPantelis Antoniou 
101f948d6d8SFrank Rowand /*
102f948d6d8SFrank Rowand  * of_resolve_phandles() finds the largest phandle in the live tree.
103f948d6d8SFrank Rowand  * of_overlay_apply() may add a larger phandle to the live tree.
104f948d6d8SFrank Rowand  * Do not allow race between two overlays being applied simultaneously:
105f948d6d8SFrank Rowand  *    mutex_lock(&of_overlay_phandle_mutex)
106f948d6d8SFrank Rowand  *    of_resolve_phandles()
107f948d6d8SFrank Rowand  *    of_overlay_apply()
108f948d6d8SFrank Rowand  *    mutex_unlock(&of_overlay_phandle_mutex)
109f948d6d8SFrank Rowand  */
110f948d6d8SFrank Rowand static DEFINE_MUTEX(of_overlay_phandle_mutex);
111f948d6d8SFrank Rowand 
of_overlay_mutex_lock(void)112f948d6d8SFrank Rowand void of_overlay_mutex_lock(void)
113f948d6d8SFrank Rowand {
114f948d6d8SFrank Rowand 	mutex_lock(&of_overlay_phandle_mutex);
115f948d6d8SFrank Rowand }
116f948d6d8SFrank Rowand 
of_overlay_mutex_unlock(void)117f948d6d8SFrank Rowand void of_overlay_mutex_unlock(void)
118f948d6d8SFrank Rowand {
119f948d6d8SFrank Rowand 	mutex_unlock(&of_overlay_phandle_mutex);
120f948d6d8SFrank Rowand }
121f948d6d8SFrank Rowand 
12261b4de4eSFrank Rowand static LIST_HEAD(ovcs_list);
12361b4de4eSFrank Rowand static DEFINE_IDR(ovcs_idr);
12461b4de4eSFrank Rowand 
1250290c4caSFrank Rowand static BLOCKING_NOTIFIER_HEAD(overlay_notify_chain);
12639a842e2SAlan Tull 
12783ef4777SJan Kiszka /**
12883ef4777SJan Kiszka  * of_overlay_notifier_register() - Register notifier for overlay operations
12983ef4777SJan Kiszka  * @nb:		Notifier block to register
13083ef4777SJan Kiszka  *
13183ef4777SJan Kiszka  * Register for notification on overlay operations on device tree nodes. The
13283ef4777SJan Kiszka  * reported actions definied by @of_reconfig_change. The notifier callback
13383ef4777SJan Kiszka  * furthermore receives a pointer to the affected device tree node.
13483ef4777SJan Kiszka  *
13583ef4777SJan Kiszka  * Note that a notifier callback is not supposed to store pointers to a device
13683ef4777SJan Kiszka  * tree node or its content beyond @OF_OVERLAY_POST_REMOVE corresponding to the
13783ef4777SJan Kiszka  * respective node it received.
13883ef4777SJan Kiszka  */
of_overlay_notifier_register(struct notifier_block * nb)13939a842e2SAlan Tull int of_overlay_notifier_register(struct notifier_block *nb)
14039a842e2SAlan Tull {
1410290c4caSFrank Rowand 	return blocking_notifier_chain_register(&overlay_notify_chain, nb);
14239a842e2SAlan Tull }
14339a842e2SAlan Tull EXPORT_SYMBOL_GPL(of_overlay_notifier_register);
14439a842e2SAlan Tull 
14583ef4777SJan Kiszka /**
146f957d5b7SLee Jones  * of_overlay_notifier_unregister() - Unregister notifier for overlay operations
14783ef4777SJan Kiszka  * @nb:		Notifier block to unregister
14883ef4777SJan Kiszka  */
of_overlay_notifier_unregister(struct notifier_block * nb)14939a842e2SAlan Tull int of_overlay_notifier_unregister(struct notifier_block *nb)
15039a842e2SAlan Tull {
1510290c4caSFrank Rowand 	return blocking_notifier_chain_unregister(&overlay_notify_chain, nb);
15239a842e2SAlan Tull }
15339a842e2SAlan Tull EXPORT_SYMBOL_GPL(of_overlay_notifier_unregister);
15439a842e2SAlan Tull 
overlay_notify(struct overlay_changeset * ovcs,enum of_overlay_notify_action action)1550290c4caSFrank Rowand static int overlay_notify(struct overlay_changeset *ovcs,
15639a842e2SAlan Tull 		enum of_overlay_notify_action action)
15739a842e2SAlan Tull {
15839a842e2SAlan Tull 	struct of_overlay_notify_data nd;
15939a842e2SAlan Tull 	int i, ret;
16039a842e2SAlan Tull 
161067c0987SFrank Rowand 	ovcs->notify_state = action;
162067c0987SFrank Rowand 
1630290c4caSFrank Rowand 	for (i = 0; i < ovcs->count; i++) {
1640290c4caSFrank Rowand 		struct fragment *fragment = &ovcs->fragments[i];
16539a842e2SAlan Tull 
1660290c4caSFrank Rowand 		nd.target = fragment->target;
1670290c4caSFrank Rowand 		nd.overlay = fragment->overlay;
16839a842e2SAlan Tull 
1690290c4caSFrank Rowand 		ret = blocking_notifier_call_chain(&overlay_notify_chain,
17039a842e2SAlan Tull 						   action, &nd);
1715f756a2eSNuno Sá 		if (notifier_to_errno(ret)) {
17224789c5cSFrank Rowand 			ret = notifier_to_errno(ret);
17324789c5cSFrank Rowand 			pr_err("overlay changeset %s notifier error %d, target: %pOF\n",
1741ac17586SFrank Rowand 			       of_overlay_action_name(action), ret, nd.target);
17524789c5cSFrank Rowand 			return ret;
17624789c5cSFrank Rowand 		}
17739a842e2SAlan Tull 	}
17839a842e2SAlan Tull 
17939a842e2SAlan Tull 	return 0;
18039a842e2SAlan Tull }
18139a842e2SAlan Tull 
18242b2e94fSFrank Rowand /*
183e0a58f3eSFrank Rowand  * The values of properties in the "/__symbols__" node are paths in
1841e408966SFrank Rowand  * the ovcs->overlay_root.  When duplicating the properties, the paths
185e0a58f3eSFrank Rowand  * need to be adjusted to be the correct path for the live device tree.
18642b2e94fSFrank Rowand  *
187e0a58f3eSFrank Rowand  * The paths refer to a node in the subtree of a fragment node's "__overlay__"
188e0a58f3eSFrank Rowand  * node, for example "/fragment@0/__overlay__/symbol_path_tail",
189e0a58f3eSFrank Rowand  * where symbol_path_tail can be a single node or it may be a multi-node path.
19042b2e94fSFrank Rowand  *
19142b2e94fSFrank Rowand  * The duplicated property value will be modified by replacing the
19242b2e94fSFrank Rowand  * "/fragment_name/__overlay/" portion of the value  with the target
19342b2e94fSFrank Rowand  * path from the fragment node.
19442b2e94fSFrank Rowand  */
dup_and_fixup_symbol_prop(struct overlay_changeset * ovcs,const struct property * prop)1950290c4caSFrank Rowand static struct property *dup_and_fixup_symbol_prop(
1960290c4caSFrank Rowand 		struct overlay_changeset *ovcs, const struct property *prop)
1977518b589SPantelis Antoniou {
1980290c4caSFrank Rowand 	struct fragment *fragment;
199e0a58f3eSFrank Rowand 	struct property *new_prop;
200e0a58f3eSFrank Rowand 	struct device_node *fragment_node;
201e0a58f3eSFrank Rowand 	struct device_node *overlay_node;
202e0a58f3eSFrank Rowand 	const char *path;
203e0a58f3eSFrank Rowand 	const char *path_tail;
204d1651b03SFrank Rowand 	const char *target_path;
205d1651b03SFrank Rowand 	int k;
206d1651b03SFrank Rowand 	int overlay_name_len;
207e0a58f3eSFrank Rowand 	int path_len;
208e0a58f3eSFrank Rowand 	int path_tail_len;
209d1651b03SFrank Rowand 	int target_path_len;
210d1651b03SFrank Rowand 
211d1651b03SFrank Rowand 	if (!prop->value)
212d1651b03SFrank Rowand 		return NULL;
213e0a58f3eSFrank Rowand 	if (strnlen(prop->value, prop->length) >= prop->length)
214d1651b03SFrank Rowand 		return NULL;
215e0a58f3eSFrank Rowand 	path = prop->value;
216e0a58f3eSFrank Rowand 	path_len = strlen(path);
217e0a58f3eSFrank Rowand 
218e0a58f3eSFrank Rowand 	if (path_len < 1)
219e0a58f3eSFrank Rowand 		return NULL;
2201e408966SFrank Rowand 	fragment_node = __of_find_node_by_path(ovcs->overlay_root, path + 1);
221e0a58f3eSFrank Rowand 	overlay_node = __of_find_node_by_path(fragment_node, "__overlay__/");
222e0a58f3eSFrank Rowand 	of_node_put(fragment_node);
223e0a58f3eSFrank Rowand 	of_node_put(overlay_node);
224d1651b03SFrank Rowand 
2250290c4caSFrank Rowand 	for (k = 0; k < ovcs->count; k++) {
2260290c4caSFrank Rowand 		fragment = &ovcs->fragments[k];
227e0a58f3eSFrank Rowand 		if (fragment->overlay == overlay_node)
228d1651b03SFrank Rowand 			break;
229d1651b03SFrank Rowand 	}
2300290c4caSFrank Rowand 	if (k >= ovcs->count)
231e0a58f3eSFrank Rowand 		return NULL;
232d1651b03SFrank Rowand 
233e0a58f3eSFrank Rowand 	overlay_name_len = snprintf(NULL, 0, "%pOF", fragment->overlay);
234e0a58f3eSFrank Rowand 
235e0a58f3eSFrank Rowand 	if (overlay_name_len > path_len)
236e0a58f3eSFrank Rowand 		return NULL;
237e0a58f3eSFrank Rowand 	path_tail = path + overlay_name_len;
238e0a58f3eSFrank Rowand 	path_tail_len = strlen(path_tail);
239e0a58f3eSFrank Rowand 
240e0a58f3eSFrank Rowand 	target_path = kasprintf(GFP_KERNEL, "%pOF", fragment->target);
241e0a58f3eSFrank Rowand 	if (!target_path)
242e0a58f3eSFrank Rowand 		return NULL;
243d1651b03SFrank Rowand 	target_path_len = strlen(target_path);
244d1651b03SFrank Rowand 
245e0a58f3eSFrank Rowand 	new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
246e0a58f3eSFrank Rowand 	if (!new_prop)
247e0a58f3eSFrank Rowand 		goto err_free_target_path;
248d1651b03SFrank Rowand 
249e0a58f3eSFrank Rowand 	new_prop->name = kstrdup(prop->name, GFP_KERNEL);
250e0a58f3eSFrank Rowand 	new_prop->length = target_path_len + path_tail_len + 1;
251e0a58f3eSFrank Rowand 	new_prop->value = kzalloc(new_prop->length, GFP_KERNEL);
252e0a58f3eSFrank Rowand 	if (!new_prop->name || !new_prop->value)
253e0a58f3eSFrank Rowand 		goto err_free_new_prop;
254d1651b03SFrank Rowand 
255e0a58f3eSFrank Rowand 	strcpy(new_prop->value, target_path);
256e0a58f3eSFrank Rowand 	strcpy(new_prop->value + target_path_len, path_tail);
257d1651b03SFrank Rowand 
258e0a58f3eSFrank Rowand 	of_property_set_flag(new_prop, OF_DYNAMIC);
259d1651b03SFrank Rowand 
260478ff649SFrank Rowand 	kfree(target_path);
261478ff649SFrank Rowand 
262e0a58f3eSFrank Rowand 	return new_prop;
263d1651b03SFrank Rowand 
264e0a58f3eSFrank Rowand err_free_new_prop:
265e0a58f3eSFrank Rowand 	kfree(new_prop->name);
266e0a58f3eSFrank Rowand 	kfree(new_prop->value);
267e0a58f3eSFrank Rowand 	kfree(new_prop);
268e0a58f3eSFrank Rowand err_free_target_path:
269e0a58f3eSFrank Rowand 	kfree(target_path);
270d1651b03SFrank Rowand 
271d1651b03SFrank Rowand 	return NULL;
272d1651b03SFrank Rowand }
273d1651b03SFrank Rowand 
2740290c4caSFrank Rowand /**
2750290c4caSFrank Rowand  * add_changeset_property() - add @overlay_prop to overlay changeset
2760290c4caSFrank Rowand  * @ovcs:		overlay changeset
2776b4955baSFrank Rowand  * @target:		where @overlay_prop will be placed
2780290c4caSFrank Rowand  * @overlay_prop:	property to add or update, from overlay tree
2793912b791SFrank Rowand  * @is_symbols_prop:	1 if @overlay_prop is from node "/__symbols__"
2800290c4caSFrank Rowand  *
2816b4955baSFrank Rowand  * If @overlay_prop does not already exist in live devicetree, add changeset
2826b4955baSFrank Rowand  * entry to add @overlay_prop in @target, else add changeset entry to update
2830290c4caSFrank Rowand  * value of @overlay_prop.
2840290c4caSFrank Rowand  *
2856b4955baSFrank Rowand  * @target may be either in the live devicetree or in a new subtree that
2866b4955baSFrank Rowand  * is contained in the changeset.
2876b4955baSFrank Rowand  *
2886f751188SFrank Rowand  * Some special properties are not added or updated (no error returned):
2896f751188SFrank Rowand  * "name", "phandle", "linux,phandle".
2906f751188SFrank Rowand  *
2916f751188SFrank Rowand  * Properties "#address-cells" and "#size-cells" are not updated if they
2926f751188SFrank Rowand  * are already in the live tree, but if present in the live tree, the values
2936f751188SFrank Rowand  * in the overlay must match the values in the live tree.
2940290c4caSFrank Rowand  *
295646afc4aSFrank Rowand  * Update of property in symbols node is not allowed.
2960290c4caSFrank Rowand  *
2978c8239c2SRob Herring  * Return: 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
2980290c4caSFrank Rowand  * invalid @overlay.
299646afc4aSFrank Rowand  */
add_changeset_property(struct overlay_changeset * ovcs,struct target * target,struct property * overlay_prop,bool is_symbols_prop)3000290c4caSFrank Rowand static int add_changeset_property(struct overlay_changeset *ovcs,
3016b4955baSFrank Rowand 		struct target *target, struct property *overlay_prop,
3023912b791SFrank Rowand 		bool is_symbols_prop)
303d1651b03SFrank Rowand {
3040290c4caSFrank Rowand 	struct property *new_prop = NULL, *prop;
305ac0f3e30SLixin Wang 	int ret = 0;
3067518b589SPantelis Antoniou 
307f9627881SFrank Rowand 	if (target->in_livetree)
3080290c4caSFrank Rowand 		if (!of_prop_cmp(overlay_prop->name, "name") ||
3090290c4caSFrank Rowand 		    !of_prop_cmp(overlay_prop->name, "phandle") ||
3100290c4caSFrank Rowand 		    !of_prop_cmp(overlay_prop->name, "linux,phandle"))
3117518b589SPantelis Antoniou 			return 0;
3127518b589SPantelis Antoniou 
3136b4955baSFrank Rowand 	if (target->in_livetree)
3146b4955baSFrank Rowand 		prop = of_find_property(target->np, overlay_prop->name, NULL);
3156b4955baSFrank Rowand 	else
3166b4955baSFrank Rowand 		prop = NULL;
3176b4955baSFrank Rowand 
318637392a8SFrank Rowand 	if (prop) {
319637392a8SFrank Rowand 		if (!of_prop_cmp(prop->name, "#address-cells")) {
320637392a8SFrank Rowand 			if (!of_prop_val_eq(prop, overlay_prop)) {
321637392a8SFrank Rowand 				pr_err("ERROR: changing value of #address-cells is not allowed in %pOF\n",
322637392a8SFrank Rowand 				       target->np);
323637392a8SFrank Rowand 				ret = -EINVAL;
324637392a8SFrank Rowand 			}
325637392a8SFrank Rowand 			return ret;
326637392a8SFrank Rowand 
327637392a8SFrank Rowand 		} else if (!of_prop_cmp(prop->name, "#size-cells")) {
328637392a8SFrank Rowand 			if (!of_prop_val_eq(prop, overlay_prop)) {
329637392a8SFrank Rowand 				pr_err("ERROR: changing value of #size-cells is not allowed in %pOF\n",
330637392a8SFrank Rowand 				       target->np);
331637392a8SFrank Rowand 				ret = -EINVAL;
332637392a8SFrank Rowand 			}
333637392a8SFrank Rowand 			return ret;
334637392a8SFrank Rowand 		}
335637392a8SFrank Rowand 	}
336637392a8SFrank Rowand 
3373912b791SFrank Rowand 	if (is_symbols_prop) {
3380290c4caSFrank Rowand 		if (prop)
339d1651b03SFrank Rowand 			return -EINVAL;
3400290c4caSFrank Rowand 		new_prop = dup_and_fixup_symbol_prop(ovcs, overlay_prop);
341d1651b03SFrank Rowand 	} else {
3420290c4caSFrank Rowand 		new_prop = __of_prop_dup(overlay_prop, GFP_KERNEL);
343d1651b03SFrank Rowand 	}
344d1651b03SFrank Rowand 
3450290c4caSFrank Rowand 	if (!new_prop)
3467518b589SPantelis Antoniou 		return -ENOMEM;
3477518b589SPantelis Antoniou 
3486f751188SFrank Rowand 	if (!prop) {
349f9627881SFrank Rowand 		if (!target->in_livetree) {
350f9627881SFrank Rowand 			new_prop->next = target->np->deadprops;
351f9627881SFrank Rowand 			target->np->deadprops = new_prop;
352f9627881SFrank Rowand 		}
3536b4955baSFrank Rowand 		ret = of_changeset_add_property(&ovcs->cset, target->np,
3540290c4caSFrank Rowand 						new_prop);
3556f751188SFrank Rowand 	} else {
3566b4955baSFrank Rowand 		ret = of_changeset_update_property(&ovcs->cset, target->np,
3570290c4caSFrank Rowand 						   new_prop);
3586f751188SFrank Rowand 	}
3596f751188SFrank Rowand 
360637392a8SFrank Rowand 	if (!of_node_check_flag(target->np, OF_OVERLAY))
3616f751188SFrank Rowand 		pr_err("WARNING: memory leak will occur if overlay removed, property: %pOF/%s\n",
3626f751188SFrank Rowand 		       target->np, new_prop->name);
3637518b589SPantelis Antoniou 
364ac0f3e30SLixin Wang 	if (ret) {
3650290c4caSFrank Rowand 		kfree(new_prop->name);
3660290c4caSFrank Rowand 		kfree(new_prop->value);
3670290c4caSFrank Rowand 		kfree(new_prop);
368ac0f3e30SLixin Wang 	}
369ac0f3e30SLixin Wang 	return ret;
3707518b589SPantelis Antoniou }
3717518b589SPantelis Antoniou 
3720290c4caSFrank Rowand /**
3730290c4caSFrank Rowand  * add_changeset_node() - add @node (and children) to overlay changeset
3740290c4caSFrank Rowand  * @ovcs:	overlay changeset
3756b4955baSFrank Rowand  * @target:	where @node will be placed in live tree or changeset
3760290c4caSFrank Rowand  * @node:	node from within overlay device tree fragment
3770290c4caSFrank Rowand  *
3786b4955baSFrank Rowand  * If @node does not already exist in @target, add changeset entry
3796b4955baSFrank Rowand  * to add @node in @target.
3800290c4caSFrank Rowand  *
3816b4955baSFrank Rowand  * If @node already exists in @target, and the existing node has
3820290c4caSFrank Rowand  * a phandle, the overlay node is not allowed to have a phandle.
3830290c4caSFrank Rowand  *
3840290c4caSFrank Rowand  * If @node has child nodes, add the children recursively via
3850290c4caSFrank Rowand  * build_changeset_next_level().
3860290c4caSFrank Rowand  *
387b89dae18SFrank Rowand  * NOTE_1: A live devicetree created from a flattened device tree (FDT) will
388b89dae18SFrank Rowand  *       not contain the full path in node->full_name.  Thus an overlay
389b89dae18SFrank Rowand  *       created from an FDT also will not contain the full path in
390b89dae18SFrank Rowand  *       node->full_name.  However, a live devicetree created from Open
391b89dae18SFrank Rowand  *       Firmware may have the full path in node->full_name.
392b89dae18SFrank Rowand  *
393b89dae18SFrank Rowand  *       add_changeset_node() follows the FDT convention and does not include
394b89dae18SFrank Rowand  *       the full path in node->full_name.  Even though it expects the overlay
395b89dae18SFrank Rowand  *       to not contain the full path, it uses kbasename() to remove the
396b89dae18SFrank Rowand  *       full path should it exist.  It also uses kbasename() in comparisons
397b89dae18SFrank Rowand  *       to nodes in the live devicetree so that it can apply an overlay to
398b89dae18SFrank Rowand  *       a live devicetree created from Open Firmware.
399b89dae18SFrank Rowand  *
400b89dae18SFrank Rowand  * NOTE_2: Multiple mods of created nodes not supported.
4010290c4caSFrank Rowand  *
4028c8239c2SRob Herring  * Return: 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
4030290c4caSFrank Rowand  * invalid @overlay.
4040290c4caSFrank Rowand  */
add_changeset_node(struct overlay_changeset * ovcs,struct target * target,struct device_node * node)4050290c4caSFrank Rowand static int add_changeset_node(struct overlay_changeset *ovcs,
4066b4955baSFrank Rowand 		struct target *target, struct device_node *node)
4077518b589SPantelis Antoniou {
4080290c4caSFrank Rowand 	const char *node_kbasename;
409f9627881SFrank Rowand 	const __be32 *phandle;
410d3a89165SFabio Estevam 	struct device_node *tchild;
4116b4955baSFrank Rowand 	struct target target_child;
412f9627881SFrank Rowand 	int ret = 0, size;
4137518b589SPantelis Antoniou 
4140290c4caSFrank Rowand 	node_kbasename = kbasename(node->full_name);
4157518b589SPantelis Antoniou 
4166b4955baSFrank Rowand 	for_each_child_of_node(target->np, tchild)
4170290c4caSFrank Rowand 		if (!of_node_cmp(node_kbasename, kbasename(tchild->full_name)))
418c1cd1e01SFrank Rowand 			break;
419c1cd1e01SFrank Rowand 
42061b4de4eSFrank Rowand 	if (!tchild) {
4218814dc46SFrank Rowand 		tchild = __of_node_dup(NULL, node_kbasename);
4227518b589SPantelis Antoniou 		if (!tchild)
4237518b589SPantelis Antoniou 			return -ENOMEM;
4247518b589SPantelis Antoniou 
4256b4955baSFrank Rowand 		tchild->parent = target->np;
426f9627881SFrank Rowand 		tchild->name = __of_get_property(node, "name", NULL);
427f9627881SFrank Rowand 
428f9627881SFrank Rowand 		if (!tchild->name)
429f9627881SFrank Rowand 			tchild->name = "<NULL>";
430f9627881SFrank Rowand 
431f9627881SFrank Rowand 		/* ignore obsolete "linux,phandle" */
432f9627881SFrank Rowand 		phandle = __of_get_property(node, "phandle", &size);
433f9627881SFrank Rowand 		if (phandle && (size == 4))
434f9627881SFrank Rowand 			tchild->phandle = be32_to_cpup(phandle);
435f9627881SFrank Rowand 
436144552c7SFrank Rowand 		of_node_set_flag(tchild, OF_OVERLAY);
4377518b589SPantelis Antoniou 
4380290c4caSFrank Rowand 		ret = of_changeset_attach_node(&ovcs->cset, tchild);
4397518b589SPantelis Antoniou 		if (ret)
4407518b589SPantelis Antoniou 			return ret;
4417518b589SPantelis Antoniou 
4426b4955baSFrank Rowand 		target_child.np = tchild;
4436b4955baSFrank Rowand 		target_child.in_livetree = false;
4446b4955baSFrank Rowand 
4456b4955baSFrank Rowand 		ret = build_changeset_next_level(ovcs, &target_child, node);
4467c528e45SFrank Rowand 		of_node_put(tchild);
4477c528e45SFrank Rowand 		return ret;
4487518b589SPantelis Antoniou 	}
4497518b589SPantelis Antoniou 
4506b4955baSFrank Rowand 	if (node->phandle && tchild->phandle) {
4516d0f5470SFrank Rowand 		ret = -EINVAL;
4526b4955baSFrank Rowand 	} else {
4536b4955baSFrank Rowand 		target_child.np = tchild;
4546b4955baSFrank Rowand 		target_child.in_livetree = target->in_livetree;
4556b4955baSFrank Rowand 		ret = build_changeset_next_level(ovcs, &target_child, node);
4566b4955baSFrank Rowand 	}
45761b4de4eSFrank Rowand 	of_node_put(tchild);
45861b4de4eSFrank Rowand 
4597518b589SPantelis Antoniou 	return ret;
4607518b589SPantelis Antoniou }
4617518b589SPantelis Antoniou 
4620290c4caSFrank Rowand /**
4630290c4caSFrank Rowand  * build_changeset_next_level() - add level of overlay changeset
4640290c4caSFrank Rowand  * @ovcs:		overlay changeset
4656b4955baSFrank Rowand  * @target:		where to place @overlay_node in live tree
4660290c4caSFrank Rowand  * @overlay_node:	node from within an overlay device tree fragment
4677518b589SPantelis Antoniou  *
4680290c4caSFrank Rowand  * Add the properties (if any) and nodes (if any) from @overlay_node to the
4690290c4caSFrank Rowand  * @ovcs->cset changeset.  If an added node has child nodes, they will
4700290c4caSFrank Rowand  * be added recursively.
471646afc4aSFrank Rowand  *
472646afc4aSFrank Rowand  * Do not allow symbols node to have any children.
4730290c4caSFrank Rowand  *
4748c8239c2SRob Herring  * Return: 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
4750290c4caSFrank Rowand  * invalid @overlay_node.
4767518b589SPantelis Antoniou  */
build_changeset_next_level(struct overlay_changeset * ovcs,struct target * target,const struct device_node * overlay_node)4770290c4caSFrank Rowand static int build_changeset_next_level(struct overlay_changeset *ovcs,
4786b4955baSFrank Rowand 		struct target *target, const struct device_node *overlay_node)
4797518b589SPantelis Antoniou {
4807518b589SPantelis Antoniou 	struct device_node *child;
4817518b589SPantelis Antoniou 	struct property *prop;
4827518b589SPantelis Antoniou 	int ret;
4837518b589SPantelis Antoniou 
4840290c4caSFrank Rowand 	for_each_property_of_node(overlay_node, prop) {
4856b4955baSFrank Rowand 		ret = add_changeset_property(ovcs, target, prop, 0);
4867518b589SPantelis Antoniou 		if (ret) {
48724789c5cSFrank Rowand 			pr_debug("Failed to apply prop @%pOF/%s, err=%d\n",
4886b4955baSFrank Rowand 				 target->np, prop->name, ret);
4897518b589SPantelis Antoniou 			return ret;
4907518b589SPantelis Antoniou 		}
4917518b589SPantelis Antoniou 	}
4927518b589SPantelis Antoniou 
4930290c4caSFrank Rowand 	for_each_child_of_node(overlay_node, child) {
4946b4955baSFrank Rowand 		ret = add_changeset_node(ovcs, target, child);
495bbed8794SFrank Rowand 		if (ret) {
496a613b26aSRob Herring 			pr_debug("Failed to apply node @%pOF/%pOFn, err=%d\n",
4976b4955baSFrank Rowand 				 target->np, child, ret);
498001cf504SJulia Lawall 			of_node_put(child);
4997518b589SPantelis Antoniou 			return ret;
5007518b589SPantelis Antoniou 		}
5017518b589SPantelis Antoniou 	}
5027518b589SPantelis Antoniou 
5037518b589SPantelis Antoniou 	return 0;
5047518b589SPantelis Antoniou }
5057518b589SPantelis Antoniou 
5063912b791SFrank Rowand /*
5073912b791SFrank Rowand  * Add the properties from __overlay__ node to the @ovcs->cset changeset.
5083912b791SFrank Rowand  */
build_changeset_symbols_node(struct overlay_changeset * ovcs,struct target * target,const struct device_node * overlay_symbols_node)5093912b791SFrank Rowand static int build_changeset_symbols_node(struct overlay_changeset *ovcs,
5106b4955baSFrank Rowand 		struct target *target,
5113912b791SFrank Rowand 		const struct device_node *overlay_symbols_node)
5123912b791SFrank Rowand {
5133912b791SFrank Rowand 	struct property *prop;
5143912b791SFrank Rowand 	int ret;
5153912b791SFrank Rowand 
5163912b791SFrank Rowand 	for_each_property_of_node(overlay_symbols_node, prop) {
5176b4955baSFrank Rowand 		ret = add_changeset_property(ovcs, target, prop, 1);
5183912b791SFrank Rowand 		if (ret) {
519a15e824fSFrank Rowand 			pr_debug("Failed to apply symbols prop @%pOF/%s, err=%d\n",
5206b4955baSFrank Rowand 				 target->np, prop->name, ret);
5213912b791SFrank Rowand 			return ret;
5223912b791SFrank Rowand 		}
5233912b791SFrank Rowand 	}
5243912b791SFrank Rowand 
5253912b791SFrank Rowand 	return 0;
5263912b791SFrank Rowand }
5273912b791SFrank Rowand 
find_dup_cset_node_entry(struct overlay_changeset * ovcs,struct of_changeset_entry * ce_1)5282fe0e876SFrank Rowand static int find_dup_cset_node_entry(struct overlay_changeset *ovcs,
5292fe0e876SFrank Rowand 		struct of_changeset_entry *ce_1)
530c168263bSFrank Rowand {
5312fe0e876SFrank Rowand 	struct of_changeset_entry *ce_2;
532c168263bSFrank Rowand 	char *fn_1, *fn_2;
5332fe0e876SFrank Rowand 	int node_path_match;
534c168263bSFrank Rowand 
5352fe0e876SFrank Rowand 	if (ce_1->action != OF_RECONFIG_ATTACH_NODE &&
5362fe0e876SFrank Rowand 	    ce_1->action != OF_RECONFIG_DETACH_NODE)
5372fe0e876SFrank Rowand 		return 0;
538c168263bSFrank Rowand 
539c168263bSFrank Rowand 	ce_2 = ce_1;
540c168263bSFrank Rowand 	list_for_each_entry_continue(ce_2, &ovcs->cset.entries, node) {
5412fe0e876SFrank Rowand 		if ((ce_2->action != OF_RECONFIG_ATTACH_NODE &&
5422fe0e876SFrank Rowand 		     ce_2->action != OF_RECONFIG_DETACH_NODE) ||
5432fe0e876SFrank Rowand 		    of_node_cmp(ce_1->np->full_name, ce_2->np->full_name))
5442fe0e876SFrank Rowand 			continue;
5452fe0e876SFrank Rowand 
546c168263bSFrank Rowand 		fn_1 = kasprintf(GFP_KERNEL, "%pOF", ce_1->np);
547c168263bSFrank Rowand 		fn_2 = kasprintf(GFP_KERNEL, "%pOF", ce_2->np);
548ee9d7a0eSruanjinjie 		node_path_match = !fn_1 || !fn_2 || !strcmp(fn_1, fn_2);
549c168263bSFrank Rowand 		kfree(fn_1);
550c168263bSFrank Rowand 		kfree(fn_2);
5512fe0e876SFrank Rowand 		if (node_path_match) {
5522fe0e876SFrank Rowand 			pr_err("ERROR: multiple fragments add and/or delete node %pOF\n",
553c168263bSFrank Rowand 			       ce_1->np);
554c168263bSFrank Rowand 			return -EINVAL;
555c168263bSFrank Rowand 		}
556c168263bSFrank Rowand 	}
5572fe0e876SFrank Rowand 
5582fe0e876SFrank Rowand 	return 0;
559c168263bSFrank Rowand }
5602fe0e876SFrank Rowand 
find_dup_cset_prop(struct overlay_changeset * ovcs,struct of_changeset_entry * ce_1)5612fe0e876SFrank Rowand static int find_dup_cset_prop(struct overlay_changeset *ovcs,
5622fe0e876SFrank Rowand 		struct of_changeset_entry *ce_1)
5632fe0e876SFrank Rowand {
5642fe0e876SFrank Rowand 	struct of_changeset_entry *ce_2;
5652fe0e876SFrank Rowand 	char *fn_1, *fn_2;
5662fe0e876SFrank Rowand 	int node_path_match;
5672fe0e876SFrank Rowand 
5682fe0e876SFrank Rowand 	if (ce_1->action != OF_RECONFIG_ADD_PROPERTY &&
5692fe0e876SFrank Rowand 	    ce_1->action != OF_RECONFIG_REMOVE_PROPERTY &&
5702fe0e876SFrank Rowand 	    ce_1->action != OF_RECONFIG_UPDATE_PROPERTY)
5712fe0e876SFrank Rowand 		return 0;
5722fe0e876SFrank Rowand 
5732fe0e876SFrank Rowand 	ce_2 = ce_1;
5742fe0e876SFrank Rowand 	list_for_each_entry_continue(ce_2, &ovcs->cset.entries, node) {
5752fe0e876SFrank Rowand 		if ((ce_2->action != OF_RECONFIG_ADD_PROPERTY &&
5762fe0e876SFrank Rowand 		     ce_2->action != OF_RECONFIG_REMOVE_PROPERTY &&
5772fe0e876SFrank Rowand 		     ce_2->action != OF_RECONFIG_UPDATE_PROPERTY) ||
5782fe0e876SFrank Rowand 		    of_node_cmp(ce_1->np->full_name, ce_2->np->full_name))
5792fe0e876SFrank Rowand 			continue;
5802fe0e876SFrank Rowand 
5812fe0e876SFrank Rowand 		fn_1 = kasprintf(GFP_KERNEL, "%pOF", ce_1->np);
5822fe0e876SFrank Rowand 		fn_2 = kasprintf(GFP_KERNEL, "%pOF", ce_2->np);
583ee9d7a0eSruanjinjie 		node_path_match = !fn_1 || !fn_2 || !strcmp(fn_1, fn_2);
5842fe0e876SFrank Rowand 		kfree(fn_1);
5852fe0e876SFrank Rowand 		kfree(fn_2);
5862fe0e876SFrank Rowand 		if (node_path_match &&
5872fe0e876SFrank Rowand 		    !of_prop_cmp(ce_1->prop->name, ce_2->prop->name)) {
5882fe0e876SFrank Rowand 			pr_err("ERROR: multiple fragments add, update, and/or delete property %pOF/%s\n",
5892fe0e876SFrank Rowand 			       ce_1->np, ce_1->prop->name);
5902fe0e876SFrank Rowand 			return -EINVAL;
591c168263bSFrank Rowand 		}
592c168263bSFrank Rowand 	}
593c168263bSFrank Rowand 
594c168263bSFrank Rowand 	return 0;
595c168263bSFrank Rowand }
596c168263bSFrank Rowand 
597c168263bSFrank Rowand /**
5982fe0e876SFrank Rowand  * changeset_dup_entry_check() - check for duplicate entries
5992fe0e876SFrank Rowand  * @ovcs:	Overlay changeset
6002fe0e876SFrank Rowand  *
6012fe0e876SFrank Rowand  * Check changeset @ovcs->cset for multiple {add or delete} node entries for
6022fe0e876SFrank Rowand  * the same node or duplicate {add, delete, or update} properties entries
6032fe0e876SFrank Rowand  * for the same property.
6042fe0e876SFrank Rowand  *
6058c8239c2SRob Herring  * Return: 0 on success, or -EINVAL if duplicate changeset entry found.
6062fe0e876SFrank Rowand  */
changeset_dup_entry_check(struct overlay_changeset * ovcs)6072fe0e876SFrank Rowand static int changeset_dup_entry_check(struct overlay_changeset *ovcs)
6082fe0e876SFrank Rowand {
6092fe0e876SFrank Rowand 	struct of_changeset_entry *ce_1;
6102fe0e876SFrank Rowand 	int dup_entry = 0;
6112fe0e876SFrank Rowand 
6122fe0e876SFrank Rowand 	list_for_each_entry(ce_1, &ovcs->cset.entries, node) {
6132fe0e876SFrank Rowand 		dup_entry |= find_dup_cset_node_entry(ovcs, ce_1);
6142fe0e876SFrank Rowand 		dup_entry |= find_dup_cset_prop(ovcs, ce_1);
6152fe0e876SFrank Rowand 	}
6162fe0e876SFrank Rowand 
6172fe0e876SFrank Rowand 	return dup_entry ? -EINVAL : 0;
6182fe0e876SFrank Rowand }
6192fe0e876SFrank Rowand 
6202fe0e876SFrank Rowand /**
6210290c4caSFrank Rowand  * build_changeset() - populate overlay changeset in @ovcs from @ovcs->fragments
6220290c4caSFrank Rowand  * @ovcs:	Overlay changeset
6237518b589SPantelis Antoniou  *
6240290c4caSFrank Rowand  * Create changeset @ovcs->cset to contain the nodes and properties of the
6250290c4caSFrank Rowand  * overlay device tree fragments in @ovcs->fragments[].  If an error occurs,
6260290c4caSFrank Rowand  * any portions of the changeset that were successfully created will remain
6270290c4caSFrank Rowand  * in @ovcs->cset.
6280290c4caSFrank Rowand  *
6298c8239c2SRob Herring  * Return: 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
6300290c4caSFrank Rowand  * invalid overlay in @ovcs->fragments[].
6317518b589SPantelis Antoniou  */
build_changeset(struct overlay_changeset * ovcs)6320290c4caSFrank Rowand static int build_changeset(struct overlay_changeset *ovcs)
6337518b589SPantelis Antoniou {
6343912b791SFrank Rowand 	struct fragment *fragment;
6356b4955baSFrank Rowand 	struct target target;
6363912b791SFrank Rowand 	int fragments_count, i, ret;
6377518b589SPantelis Antoniou 
6383912b791SFrank Rowand 	/*
6393912b791SFrank Rowand 	 * if there is a symbols fragment in ovcs->fragments[i] it is
6403912b791SFrank Rowand 	 * the final element in the array
6413912b791SFrank Rowand 	 */
6423912b791SFrank Rowand 	if (ovcs->symbols_fragment)
6433912b791SFrank Rowand 		fragments_count = ovcs->count - 1;
6443912b791SFrank Rowand 	else
6453912b791SFrank Rowand 		fragments_count = ovcs->count;
6463912b791SFrank Rowand 
6473912b791SFrank Rowand 	for (i = 0; i < fragments_count; i++) {
6483912b791SFrank Rowand 		fragment = &ovcs->fragments[i];
6497518b589SPantelis Antoniou 
6506b4955baSFrank Rowand 		target.np = fragment->target;
6516b4955baSFrank Rowand 		target.in_livetree = true;
6526b4955baSFrank Rowand 		ret = build_changeset_next_level(ovcs, &target,
6533912b791SFrank Rowand 						 fragment->overlay);
6543912b791SFrank Rowand 		if (ret) {
655a15e824fSFrank Rowand 			pr_debug("fragment apply failed '%pOF'\n",
656a15e824fSFrank Rowand 				 fragment->target);
6573912b791SFrank Rowand 			return ret;
6583912b791SFrank Rowand 		}
6593912b791SFrank Rowand 	}
6603912b791SFrank Rowand 
6613912b791SFrank Rowand 	if (ovcs->symbols_fragment) {
6623912b791SFrank Rowand 		fragment = &ovcs->fragments[ovcs->count - 1];
6636b4955baSFrank Rowand 
6646b4955baSFrank Rowand 		target.np = fragment->target;
6656b4955baSFrank Rowand 		target.in_livetree = true;
6666b4955baSFrank Rowand 		ret = build_changeset_symbols_node(ovcs, &target,
6673912b791SFrank Rowand 						   fragment->overlay);
6680290c4caSFrank Rowand 		if (ret) {
669a15e824fSFrank Rowand 			pr_debug("symbols fragment apply failed '%pOF'\n",
670a15e824fSFrank Rowand 				 fragment->target);
6710290c4caSFrank Rowand 			return ret;
6727518b589SPantelis Antoniou 		}
6737518b589SPantelis Antoniou 	}
6747518b589SPantelis Antoniou 
6752fe0e876SFrank Rowand 	return changeset_dup_entry_check(ovcs);
6767518b589SPantelis Antoniou }
6777518b589SPantelis Antoniou 
6787518b589SPantelis Antoniou /*
6797518b589SPantelis Antoniou  * Find the target node using a number of different strategies
680646afc4aSFrank Rowand  * in order of preference:
6817518b589SPantelis Antoniou  *
682646afc4aSFrank Rowand  * 1) "target" property containing the phandle of the target
683646afc4aSFrank Rowand  * 2) "target-path" property containing the path of the target
6847518b589SPantelis Antoniou  */
find_target(struct device_node * info_node,struct device_node * target_base)68547284862SLizhi Hou static struct device_node *find_target(struct device_node *info_node,
68647284862SLizhi Hou 				       struct device_node *target_base)
6877518b589SPantelis Antoniou {
688e547c003SFrank Rowand 	struct device_node *node;
68947284862SLizhi Hou 	char *target_path;
6907518b589SPantelis Antoniou 	const char *path;
6917518b589SPantelis Antoniou 	u32 val;
6927518b589SPantelis Antoniou 	int ret;
6937518b589SPantelis Antoniou 
6947518b589SPantelis Antoniou 	ret = of_property_read_u32(info_node, "target", &val);
695e547c003SFrank Rowand 	if (!ret) {
696e547c003SFrank Rowand 		node = of_find_node_by_phandle(val);
697e547c003SFrank Rowand 		if (!node)
698e547c003SFrank Rowand 			pr_err("find target, node: %pOF, phandle 0x%x not found\n",
699e547c003SFrank Rowand 			       info_node, val);
700e547c003SFrank Rowand 		return node;
701e547c003SFrank Rowand 	}
7027518b589SPantelis Antoniou 
7037518b589SPantelis Antoniou 	ret = of_property_read_string(info_node, "target-path", &path);
704e547c003SFrank Rowand 	if (!ret) {
70547284862SLizhi Hou 		if (target_base) {
70647284862SLizhi Hou 			target_path = kasprintf(GFP_KERNEL, "%pOF%s", target_base, path);
70747284862SLizhi Hou 			if (!target_path)
70847284862SLizhi Hou 				return NULL;
70947284862SLizhi Hou 			node = of_find_node_by_path(target_path);
71047284862SLizhi Hou 			if (!node) {
71147284862SLizhi Hou 				pr_err("find target, node: %pOF, path '%s' not found\n",
71247284862SLizhi Hou 				       info_node, target_path);
71347284862SLizhi Hou 			}
71447284862SLizhi Hou 			kfree(target_path);
71547284862SLizhi Hou 		} else {
716e547c003SFrank Rowand 			node =  of_find_node_by_path(path);
71747284862SLizhi Hou 			if (!node) {
718e547c003SFrank Rowand 				pr_err("find target, node: %pOF, path '%s' not found\n",
719e547c003SFrank Rowand 				       info_node, path);
72047284862SLizhi Hou 			}
72147284862SLizhi Hou 		}
722e547c003SFrank Rowand 		return node;
723e547c003SFrank Rowand 	}
7247518b589SPantelis Antoniou 
725e547c003SFrank Rowand 	pr_err("find target, node: %pOF, no target property\n", info_node);
7267518b589SPantelis Antoniou 
7277518b589SPantelis Antoniou 	return NULL;
7287518b589SPantelis Antoniou }
7297518b589SPantelis Antoniou 
7307518b589SPantelis Antoniou /**
7310290c4caSFrank Rowand  * init_overlay_changeset() - initialize overlay changeset from overlay tree
73239a751a4SFrank Rowand  * @ovcs:		Overlay changeset to build
73347284862SLizhi Hou  * @target_base:	Point to the target node to apply overlay
7347518b589SPantelis Antoniou  *
7350290c4caSFrank Rowand  * Initialize @ovcs.  Populate @ovcs->fragments with node information from
7361e408966SFrank Rowand  * the top level of @overlay_root.  The relevant top level nodes are the
7371e408966SFrank Rowand  * fragment nodes and the __symbols__ node.  Any other top level node will
738067c0987SFrank Rowand  * be ignored.  Populate other @ovcs fields.
7397518b589SPantelis Antoniou  *
7408c8239c2SRob Herring  * Return: 0 on success, -ENOMEM if memory allocation failure, -EINVAL if error
741067c0987SFrank Rowand  * detected in @overlay_root.  On error return, the caller of
742067c0987SFrank Rowand  * init_overlay_changeset() must call free_overlay_changeset().
7437518b589SPantelis Antoniou  */
init_overlay_changeset(struct overlay_changeset * ovcs,struct device_node * target_base)74447284862SLizhi Hou static int init_overlay_changeset(struct overlay_changeset *ovcs,
74547284862SLizhi Hou 				  struct device_node *target_base)
7467518b589SPantelis Antoniou {
74761b4de4eSFrank Rowand 	struct device_node *node, *overlay_node;
7480290c4caSFrank Rowand 	struct fragment *fragment;
7490290c4caSFrank Rowand 	struct fragment *fragments;
750067c0987SFrank Rowand 	int cnt, ret;
751067c0987SFrank Rowand 
752067c0987SFrank Rowand 	/*
753067c0987SFrank Rowand 	 * None of the resources allocated by this function will be freed in
754067c0987SFrank Rowand 	 * the error paths.  Instead the caller of this function is required
755067c0987SFrank Rowand 	 * to call free_overlay_changeset() (which will free the resources)
756067c0987SFrank Rowand 	 * if error return.
757067c0987SFrank Rowand 	 */
7587518b589SPantelis Antoniou 
75924789c5cSFrank Rowand 	/*
76024789c5cSFrank Rowand 	 * Warn for some issues.  Can not return -EINVAL for these until
76124789c5cSFrank Rowand 	 * of_unittest_apply_overlay() is fixed to pass these checks.
76224789c5cSFrank Rowand 	 */
763067c0987SFrank Rowand 	if (!of_node_check_flag(ovcs->overlay_root, OF_DYNAMIC))
764067c0987SFrank Rowand 		pr_debug("%s() ovcs->overlay_root is not dynamic\n", __func__);
76524789c5cSFrank Rowand 
766067c0987SFrank Rowand 	if (!of_node_check_flag(ovcs->overlay_root, OF_DETACHED))
767067c0987SFrank Rowand 		pr_debug("%s() ovcs->overlay_root is not detached\n", __func__);
76824789c5cSFrank Rowand 
769067c0987SFrank Rowand 	if (!of_node_is_root(ovcs->overlay_root))
770067c0987SFrank Rowand 		pr_debug("%s() ovcs->overlay_root is not root\n", __func__);
7717518b589SPantelis Antoniou 
77261b4de4eSFrank Rowand 	cnt = 0;
77361b4de4eSFrank Rowand 
77461b4de4eSFrank Rowand 	/* fragment nodes */
775067c0987SFrank Rowand 	for_each_child_of_node(ovcs->overlay_root, node) {
77661b4de4eSFrank Rowand 		overlay_node = of_get_child_by_name(node, "__overlay__");
77761b4de4eSFrank Rowand 		if (overlay_node) {
778d1651b03SFrank Rowand 			cnt++;
77961b4de4eSFrank Rowand 			of_node_put(overlay_node);
78061b4de4eSFrank Rowand 		}
78161b4de4eSFrank Rowand 	}
78261b4de4eSFrank Rowand 
783067c0987SFrank Rowand 	node = of_get_child_by_name(ovcs->overlay_root, "__symbols__");
78461b4de4eSFrank Rowand 	if (node) {
78561b4de4eSFrank Rowand 		cnt++;
78661b4de4eSFrank Rowand 		of_node_put(node);
78761b4de4eSFrank Rowand 	}
788d1651b03SFrank Rowand 
7890290c4caSFrank Rowand 	fragments = kcalloc(cnt, sizeof(*fragments), GFP_KERNEL);
79061b4de4eSFrank Rowand 	if (!fragments) {
79161b4de4eSFrank Rowand 		ret = -ENOMEM;
792067c0987SFrank Rowand 		goto err_out;
79361b4de4eSFrank Rowand 	}
794067c0987SFrank Rowand 	ovcs->fragments = fragments;
7957518b589SPantelis Antoniou 
7967518b589SPantelis Antoniou 	cnt = 0;
797067c0987SFrank Rowand 	for_each_child_of_node(ovcs->overlay_root, node) {
79835e691edSGeert Uytterhoeven 		overlay_node = of_get_child_by_name(node, "__overlay__");
799589b754dSGeert Uytterhoeven 		if (!overlay_node)
800589b754dSGeert Uytterhoeven 			continue;
801589b754dSGeert Uytterhoeven 
80261b4de4eSFrank Rowand 		fragment = &fragments[cnt];
80335e691edSGeert Uytterhoeven 		fragment->overlay = overlay_node;
80447284862SLizhi Hou 		fragment->target = find_target(node, target_base);
80561b4de4eSFrank Rowand 		if (!fragment->target) {
80661b4de4eSFrank Rowand 			of_node_put(fragment->overlay);
80761b4de4eSFrank Rowand 			ret = -EINVAL;
808c4d74f0fSkernel test robot 			of_node_put(node);
809067c0987SFrank Rowand 			goto err_out;
8107518b589SPantelis Antoniou 		}
8116de67de3SGeert Uytterhoeven 
8126de67de3SGeert Uytterhoeven 		cnt++;
81361b4de4eSFrank Rowand 	}
8147518b589SPantelis Antoniou 
8153912b791SFrank Rowand 	/*
8163912b791SFrank Rowand 	 * if there is a symbols fragment in ovcs->fragments[i] it is
8173912b791SFrank Rowand 	 * the final element in the array
8183912b791SFrank Rowand 	 */
819067c0987SFrank Rowand 	node = of_get_child_by_name(ovcs->overlay_root, "__symbols__");
820d1651b03SFrank Rowand 	if (node) {
8213912b791SFrank Rowand 		ovcs->symbols_fragment = 1;
8220290c4caSFrank Rowand 		fragment = &fragments[cnt];
8230290c4caSFrank Rowand 		fragment->overlay = node;
8240290c4caSFrank Rowand 		fragment->target = of_find_node_by_path("/__symbols__");
825d1651b03SFrank Rowand 
8260290c4caSFrank Rowand 		if (!fragment->target) {
8274ee7c0d9SFrank Rowand 			pr_err("symbols in overlay, but not in live tree\n");
82861b4de4eSFrank Rowand 			ret = -EINVAL;
82939affd1fSKunihiko Hayashi 			of_node_put(node);
830067c0987SFrank Rowand 			goto err_out;
831d1651b03SFrank Rowand 		}
832d1651b03SFrank Rowand 
833d1651b03SFrank Rowand 		cnt++;
834d1651b03SFrank Rowand 	}
835d1651b03SFrank Rowand 
836bbed8794SFrank Rowand 	if (!cnt) {
83739a751a4SFrank Rowand 		pr_err("no fragments or symbols in overlay\n");
83861b4de4eSFrank Rowand 		ret = -EINVAL;
839067c0987SFrank Rowand 		goto err_out;
8407518b589SPantelis Antoniou 	}
8417518b589SPantelis Antoniou 
8420290c4caSFrank Rowand 	ovcs->count = cnt;
8437518b589SPantelis Antoniou 
8447518b589SPantelis Antoniou 	return 0;
84561b4de4eSFrank Rowand 
846067c0987SFrank Rowand err_out:
84724789c5cSFrank Rowand 	pr_err("%s() failed, ret = %d\n", __func__, ret);
84824789c5cSFrank Rowand 
84961b4de4eSFrank Rowand 	return ret;
8507518b589SPantelis Antoniou }
8517518b589SPantelis Antoniou 
free_overlay_changeset(struct overlay_changeset * ovcs)85261b4de4eSFrank Rowand static void free_overlay_changeset(struct overlay_changeset *ovcs)
8537518b589SPantelis Antoniou {
8547518b589SPantelis Antoniou 	int i;
8557518b589SPantelis Antoniou 
8561352f09bSGeert Uytterhoeven 	if (ovcs->cset.entries.next)
85761b4de4eSFrank Rowand 		of_changeset_destroy(&ovcs->cset);
85861b4de4eSFrank Rowand 
859067c0987SFrank Rowand 	if (ovcs->id) {
86061b4de4eSFrank Rowand 		idr_remove(&ovcs_idr, ovcs->id);
861067c0987SFrank Rowand 		list_del(&ovcs->ovcs_list);
862067c0987SFrank Rowand 		ovcs->id = 0;
863067c0987SFrank Rowand 	}
864067c0987SFrank Rowand 
86561b4de4eSFrank Rowand 
86661b4de4eSFrank Rowand 	for (i = 0; i < ovcs->count; i++) {
8670290c4caSFrank Rowand 		of_node_put(ovcs->fragments[i].target);
8680290c4caSFrank Rowand 		of_node_put(ovcs->fragments[i].overlay);
8697518b589SPantelis Antoniou 	}
8700290c4caSFrank Rowand 	kfree(ovcs->fragments);
871067c0987SFrank Rowand 
87239a751a4SFrank Rowand 	/*
873067c0987SFrank Rowand 	 * There should be no live pointers into ovcs->overlay_mem and
8741e408966SFrank Rowand 	 * ovcs->new_fdt due to the policy that overlay notifiers are not
875067c0987SFrank Rowand 	 * allowed to retain pointers into the overlay devicetree other
876067c0987SFrank Rowand 	 * than during the window from OF_OVERLAY_PRE_APPLY overlay
877067c0987SFrank Rowand 	 * notifiers until the OF_OVERLAY_POST_REMOVE overlay notifiers.
878067c0987SFrank Rowand 	 *
879067c0987SFrank Rowand 	 * A memory leak will occur here if within the window.
88039a751a4SFrank Rowand 	 */
881067c0987SFrank Rowand 
882067c0987SFrank Rowand 	if (ovcs->notify_state == OF_OVERLAY_INIT ||
883067c0987SFrank Rowand 	    ovcs->notify_state == OF_OVERLAY_POST_REMOVE) {
884067c0987SFrank Rowand 		kfree(ovcs->overlay_mem);
8851e408966SFrank Rowand 		kfree(ovcs->new_fdt);
886067c0987SFrank Rowand 	}
88761b4de4eSFrank Rowand 	kfree(ovcs);
88861b4de4eSFrank Rowand }
8897518b589SPantelis Antoniou 
89039a751a4SFrank Rowand /*
89139a751a4SFrank Rowand  * internal documentation
89239a751a4SFrank Rowand  *
8930290c4caSFrank Rowand  * of_overlay_apply() - Create and apply an overlay changeset
894067c0987SFrank Rowand  * @ovcs:	overlay changeset
89547284862SLizhi Hou  * @base:	point to the target node to apply overlay
8967518b589SPantelis Antoniou  *
89724789c5cSFrank Rowand  * Creates and applies an overlay changeset.
8987518b589SPantelis Antoniou  *
89924789c5cSFrank Rowand  * If an error is returned by an overlay changeset pre-apply notifier
90024789c5cSFrank Rowand  * then no further overlay changeset pre-apply notifier will be called.
90124789c5cSFrank Rowand  *
90224789c5cSFrank Rowand  * If an error is returned by an overlay changeset post-apply notifier
90324789c5cSFrank Rowand  * then no further overlay changeset post-apply notifier will be called.
90424789c5cSFrank Rowand  *
90524789c5cSFrank Rowand  * If more than one notifier returns an error, then the last notifier
90624789c5cSFrank Rowand  * error to occur is returned.
90724789c5cSFrank Rowand  *
90824789c5cSFrank Rowand  * If an error occurred while applying the overlay changeset, then an
90924789c5cSFrank Rowand  * attempt is made to revert any changes that were made to the
91024789c5cSFrank Rowand  * device tree.  If there were any errors during the revert attempt
91124789c5cSFrank Rowand  * then the state of the device tree can not be determined, and any
91224789c5cSFrank Rowand  * following attempt to apply or remove an overlay changeset will be
91324789c5cSFrank Rowand  * refused.
91424789c5cSFrank Rowand  *
915067c0987SFrank Rowand  * Returns 0 on success, or a negative error number.  On error return,
916067c0987SFrank Rowand  * the caller of of_overlay_apply() must call free_overlay_changeset().
9177518b589SPantelis Antoniou  */
91824789c5cSFrank Rowand 
of_overlay_apply(struct overlay_changeset * ovcs,struct device_node * base)91947284862SLizhi Hou static int of_overlay_apply(struct overlay_changeset *ovcs,
92047284862SLizhi Hou 			    struct device_node *base)
9217518b589SPantelis Antoniou {
92224789c5cSFrank Rowand 	int ret = 0, ret_revert, ret_tmp;
92324789c5cSFrank Rowand 
924067c0987SFrank Rowand 	ret = of_resolve_phandles(ovcs->overlay_root);
925067c0987SFrank Rowand 	if (ret)
92624789c5cSFrank Rowand 		goto out;
9277518b589SPantelis Antoniou 
92847284862SLizhi Hou 	ret = init_overlay_changeset(ovcs, base);
929f948d6d8SFrank Rowand 	if (ret)
930067c0987SFrank Rowand 		goto out;
9317518b589SPantelis Antoniou 
9320290c4caSFrank Rowand 	ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY);
9331ac17586SFrank Rowand 	if (ret)
934067c0987SFrank Rowand 		goto out;
93539a842e2SAlan Tull 
9360290c4caSFrank Rowand 	ret = build_changeset(ovcs);
9370290c4caSFrank Rowand 	if (ret)
938067c0987SFrank Rowand 		goto out;
9397518b589SPantelis Antoniou 
94024789c5cSFrank Rowand 	ret_revert = 0;
94124789c5cSFrank Rowand 	ret = __of_changeset_apply_entries(&ovcs->cset, &ret_revert);
94224789c5cSFrank Rowand 	if (ret) {
94324789c5cSFrank Rowand 		if (ret_revert) {
94424789c5cSFrank Rowand 			pr_debug("overlay changeset revert error %d\n",
94524789c5cSFrank Rowand 				 ret_revert);
94624789c5cSFrank Rowand 			devicetree_state_flags |= DTSF_APPLY_FAIL;
94724789c5cSFrank Rowand 		}
948067c0987SFrank Rowand 		goto out;
9496de67de3SGeert Uytterhoeven 	}
9506de67de3SGeert Uytterhoeven 
95124789c5cSFrank Rowand 	ret = __of_changeset_apply_notify(&ovcs->cset);
95224789c5cSFrank Rowand 	if (ret)
953a15e824fSFrank Rowand 		pr_err("overlay apply changeset entry notify error %d\n", ret);
9546de67de3SGeert Uytterhoeven 	/* notify failure is not fatal, continue */
955606ad42aSRob Herring 
95624789c5cSFrank Rowand 	ret_tmp = overlay_notify(ovcs, OF_OVERLAY_POST_APPLY);
9571ac17586SFrank Rowand 	if (ret_tmp)
95824789c5cSFrank Rowand 		if (!ret)
95924789c5cSFrank Rowand 			ret = ret_tmp;
96039a842e2SAlan Tull 
96124789c5cSFrank Rowand out:
96224789c5cSFrank Rowand 	pr_debug("%s() err=%d\n", __func__, ret);
96324789c5cSFrank Rowand 
9640290c4caSFrank Rowand 	return ret;
9657518b589SPantelis Antoniou }
96639a751a4SFrank Rowand 
967421f4d14SFrank Rowand /*
968421f4d14SFrank Rowand  * of_overlay_fdt_apply() - Create and apply an overlay changeset
969421f4d14SFrank Rowand  * @overlay_fdt:	pointer to overlay FDT
970421f4d14SFrank Rowand  * @overlay_fdt_size:	number of bytes in @overlay_fdt
971421f4d14SFrank Rowand  * @ret_ovcs_id:	pointer for returning created changeset id
97247284862SLizhi Hou  * @base:		pointer for the target node to apply overlay
973421f4d14SFrank Rowand  *
974421f4d14SFrank Rowand  * Creates and applies an overlay changeset.
975421f4d14SFrank Rowand  *
976421f4d14SFrank Rowand  * See of_overlay_apply() for important behavior information.
977421f4d14SFrank Rowand  *
978421f4d14SFrank Rowand  * Return: 0 on success, or a negative error number.  *@ret_ovcs_id is set to
979421f4d14SFrank Rowand  * the value of overlay changeset id, which can be passed to of_overlay_remove()
980421f4d14SFrank Rowand  * to remove the overlay.
981421f4d14SFrank Rowand  *
982421f4d14SFrank Rowand  * On error return, the changeset may be partially applied.  This is especially
983421f4d14SFrank Rowand  * likely if an OF_OVERLAY_POST_APPLY notifier returns an error.  In this case
984421f4d14SFrank Rowand  * the caller should call of_overlay_remove() with the value in *@ret_ovcs_id.
985421f4d14SFrank Rowand  */
986421f4d14SFrank Rowand 
of_overlay_fdt_apply(const void * overlay_fdt,u32 overlay_fdt_size,int * ret_ovcs_id,struct device_node * base)98739a751a4SFrank Rowand int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
98847284862SLizhi Hou 			 int *ret_ovcs_id, struct device_node *base)
98939a751a4SFrank Rowand {
99048d499bdSFrank Rowand 	void *new_fdt;
99148d499bdSFrank Rowand 	void *new_fdt_align;
992067c0987SFrank Rowand 	void *overlay_mem;
99339a751a4SFrank Rowand 	int ret;
99439a751a4SFrank Rowand 	u32 size;
995067c0987SFrank Rowand 	struct overlay_changeset *ovcs;
99639a751a4SFrank Rowand 
997067c0987SFrank Rowand 	*ret_ovcs_id = 0;
99839a751a4SFrank Rowand 
999e385b0baSGeert Uytterhoeven 	if (devicetree_corrupt()) {
1000e385b0baSGeert Uytterhoeven 		pr_err("devicetree state suspect, refuse to apply overlay\n");
1001e385b0baSGeert Uytterhoeven 		return -EBUSY;
1002e385b0baSGeert Uytterhoeven 	}
1003e385b0baSGeert Uytterhoeven 
100439a751a4SFrank Rowand 	if (overlay_fdt_size < sizeof(struct fdt_header) ||
100539a751a4SFrank Rowand 	    fdt_check_header(overlay_fdt)) {
100639a751a4SFrank Rowand 		pr_err("Invalid overlay_fdt header\n");
100739a751a4SFrank Rowand 		return -EINVAL;
100839a751a4SFrank Rowand 	}
100939a751a4SFrank Rowand 
101039a751a4SFrank Rowand 	size = fdt_totalsize(overlay_fdt);
101139a751a4SFrank Rowand 	if (overlay_fdt_size < size)
101239a751a4SFrank Rowand 		return -EINVAL;
101339a751a4SFrank Rowand 
1014067c0987SFrank Rowand 	ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL);
1015067c0987SFrank Rowand 	if (!ovcs)
1016067c0987SFrank Rowand 		return -ENOMEM;
1017067c0987SFrank Rowand 
1018067c0987SFrank Rowand 	of_overlay_mutex_lock();
1019067c0987SFrank Rowand 	mutex_lock(&of_mutex);
1020067c0987SFrank Rowand 
1021067c0987SFrank Rowand 	/*
1022067c0987SFrank Rowand 	 * ovcs->notify_state must be set to OF_OVERLAY_INIT before allocating
1023067c0987SFrank Rowand 	 * ovcs resources, implicitly set by kzalloc() of ovcs
1024067c0987SFrank Rowand 	 */
1025067c0987SFrank Rowand 
1026067c0987SFrank Rowand 	ovcs->id = idr_alloc(&ovcs_idr, ovcs, 1, 0, GFP_KERNEL);
1027067c0987SFrank Rowand 	if (ovcs->id <= 0) {
1028067c0987SFrank Rowand 		ret = ovcs->id;
1029067c0987SFrank Rowand 		goto err_free_ovcs;
1030067c0987SFrank Rowand 	}
1031067c0987SFrank Rowand 
1032067c0987SFrank Rowand 	INIT_LIST_HEAD(&ovcs->ovcs_list);
1033067c0987SFrank Rowand 	list_add_tail(&ovcs->ovcs_list, &ovcs_list);
1034a9515ff4SGeert Uytterhoeven 	of_changeset_init(&ovcs->cset);
1035067c0987SFrank Rowand 
103639a751a4SFrank Rowand 	/*
103739a751a4SFrank Rowand 	 * Must create permanent copy of FDT because of_fdt_unflatten_tree()
103839a751a4SFrank Rowand 	 * will create pointers to the passed in FDT in the unflattened tree.
103939a751a4SFrank Rowand 	 */
104048d499bdSFrank Rowand 	new_fdt = kmalloc(size + FDT_ALIGN_SIZE, GFP_KERNEL);
1041067c0987SFrank Rowand 	if (!new_fdt) {
1042067c0987SFrank Rowand 		ret = -ENOMEM;
1043067c0987SFrank Rowand 		goto err_free_ovcs;
1044067c0987SFrank Rowand 	}
1045067c0987SFrank Rowand 	ovcs->new_fdt = new_fdt;
104639a751a4SFrank Rowand 
104748d499bdSFrank Rowand 	new_fdt_align = PTR_ALIGN(new_fdt, FDT_ALIGN_SIZE);
104848d499bdSFrank Rowand 	memcpy(new_fdt_align, overlay_fdt, size);
104948d499bdSFrank Rowand 
1050067c0987SFrank Rowand 	overlay_mem = of_fdt_unflatten_tree(new_fdt_align, NULL,
1051067c0987SFrank Rowand 					    &ovcs->overlay_root);
1052067c0987SFrank Rowand 	if (!overlay_mem) {
105339a751a4SFrank Rowand 		pr_err("unable to unflatten overlay_fdt\n");
105439a751a4SFrank Rowand 		ret = -EINVAL;
1055067c0987SFrank Rowand 		goto err_free_ovcs;
105639a751a4SFrank Rowand 	}
1057067c0987SFrank Rowand 	ovcs->overlay_mem = overlay_mem;
105839a751a4SFrank Rowand 
105947284862SLizhi Hou 	ret = of_overlay_apply(ovcs, base);
1060421f4d14SFrank Rowand 	/*
1061421f4d14SFrank Rowand 	 * If of_overlay_apply() error, calling free_overlay_changeset() may
1062421f4d14SFrank Rowand 	 * result in a memory leak if the apply partly succeeded, so do NOT
1063421f4d14SFrank Rowand 	 * goto err_free_ovcs.  Instead, the caller of of_overlay_fdt_apply()
1064421f4d14SFrank Rowand 	 * can call of_overlay_remove();
1065421f4d14SFrank Rowand 	 */
1066067c0987SFrank Rowand 	*ret_ovcs_id = ovcs->id;
1067e76f4a61SGeert Uytterhoeven 	goto out_unlock;
106839a751a4SFrank Rowand 
1069067c0987SFrank Rowand err_free_ovcs:
1070067c0987SFrank Rowand 	free_overlay_changeset(ovcs);
107139a751a4SFrank Rowand 
1072e76f4a61SGeert Uytterhoeven out_unlock:
1073067c0987SFrank Rowand 	mutex_unlock(&of_mutex);
1074067c0987SFrank Rowand 	of_overlay_mutex_unlock();
107539a751a4SFrank Rowand 	return ret;
107639a751a4SFrank Rowand }
107739a751a4SFrank Rowand EXPORT_SYMBOL_GPL(of_overlay_fdt_apply);
10787518b589SPantelis Antoniou 
1079646afc4aSFrank Rowand /*
10800290c4caSFrank Rowand  * Find @np in @tree.
10810290c4caSFrank Rowand  *
10820290c4caSFrank Rowand  * Returns 1 if @np is @tree or is contained in @tree, else 0
1083646afc4aSFrank Rowand  */
find_node(struct device_node * tree,struct device_node * np)10840290c4caSFrank Rowand static int find_node(struct device_node *tree, struct device_node *np)
10857518b589SPantelis Antoniou {
10867518b589SPantelis Antoniou 	struct device_node *child;
10877518b589SPantelis Antoniou 
10880290c4caSFrank Rowand 	if (tree == np)
10897518b589SPantelis Antoniou 		return 1;
10907518b589SPantelis Antoniou 
10917518b589SPantelis Antoniou 	for_each_child_of_node(tree, child) {
10920290c4caSFrank Rowand 		if (find_node(child, np)) {
1093001cf504SJulia Lawall 			of_node_put(child);
10947518b589SPantelis Antoniou 			return 1;
10957518b589SPantelis Antoniou 		}
1096001cf504SJulia Lawall 	}
10977518b589SPantelis Antoniou 
10987518b589SPantelis Antoniou 	return 0;
10997518b589SPantelis Antoniou }
11007518b589SPantelis Antoniou 
1101646afc4aSFrank Rowand /*
110287f242c1SFrank Rowand  * Is @remove_ce_node a child of, a parent of, or the same as any
11030290c4caSFrank Rowand  * node in an overlay changeset more topmost than @remove_ovcs?
11040290c4caSFrank Rowand  *
11050290c4caSFrank Rowand  * Returns 1 if found, else 0
1106646afc4aSFrank Rowand  */
node_overlaps_later_cs(struct overlay_changeset * remove_ovcs,struct device_node * remove_ce_node)110787f242c1SFrank Rowand static int node_overlaps_later_cs(struct overlay_changeset *remove_ovcs,
110887f242c1SFrank Rowand 		struct device_node *remove_ce_node)
11097518b589SPantelis Antoniou {
11100290c4caSFrank Rowand 	struct overlay_changeset *ovcs;
11117518b589SPantelis Antoniou 	struct of_changeset_entry *ce;
11127518b589SPantelis Antoniou 
11130290c4caSFrank Rowand 	list_for_each_entry_reverse(ovcs, &ovcs_list, ovcs_list) {
11140290c4caSFrank Rowand 		if (ovcs == remove_ovcs)
11157518b589SPantelis Antoniou 			break;
11167518b589SPantelis Antoniou 
11170290c4caSFrank Rowand 		list_for_each_entry(ce, &ovcs->cset.entries, node) {
111887f242c1SFrank Rowand 			if (find_node(ce->np, remove_ce_node)) {
111987f242c1SFrank Rowand 				pr_err("%s: #%d overlaps with #%d @%pOF\n",
11200290c4caSFrank Rowand 					__func__, remove_ovcs->id, ovcs->id,
112187f242c1SFrank Rowand 					remove_ce_node);
112287f242c1SFrank Rowand 				return 1;
112387f242c1SFrank Rowand 			}
112487f242c1SFrank Rowand 			if (find_node(remove_ce_node, ce->np)) {
112587f242c1SFrank Rowand 				pr_err("%s: #%d overlaps with #%d @%pOF\n",
112687f242c1SFrank Rowand 					__func__, remove_ovcs->id, ovcs->id,
112787f242c1SFrank Rowand 					remove_ce_node);
11280290c4caSFrank Rowand 				return 1;
11297518b589SPantelis Antoniou 			}
11307518b589SPantelis Antoniou 		}
11317518b589SPantelis Antoniou 	}
11327518b589SPantelis Antoniou 
11330290c4caSFrank Rowand 	return 0;
11347518b589SPantelis Antoniou }
11357518b589SPantelis Antoniou 
11367518b589SPantelis Antoniou /*
11377518b589SPantelis Antoniou  * We can safely remove the overlay only if it's the top-most one.
11387518b589SPantelis Antoniou  * Newly applied overlays are inserted at the tail of the overlay list,
11397518b589SPantelis Antoniou  * so a top most overlay is the one that is closest to the tail.
11407518b589SPantelis Antoniou  *
11417518b589SPantelis Antoniou  * The topmost check is done by exploiting this property. For each
11427518b589SPantelis Antoniou  * affected device node in the log list we check if this overlay is
11437518b589SPantelis Antoniou  * the one closest to the tail. If another overlay has affected this
11448e5d0c68SRicardo Ribalda  * device node and is closest to the tail, then removal is not permitted.
11457518b589SPantelis Antoniou  */
overlay_removal_is_ok(struct overlay_changeset * remove_ovcs)11460290c4caSFrank Rowand static int overlay_removal_is_ok(struct overlay_changeset *remove_ovcs)
11477518b589SPantelis Antoniou {
11480290c4caSFrank Rowand 	struct of_changeset_entry *remove_ce;
11497518b589SPantelis Antoniou 
11500290c4caSFrank Rowand 	list_for_each_entry(remove_ce, &remove_ovcs->cset.entries, node) {
115187f242c1SFrank Rowand 		if (node_overlaps_later_cs(remove_ovcs, remove_ce->np)) {
11520290c4caSFrank Rowand 			pr_err("overlay #%d is not topmost\n", remove_ovcs->id);
11537518b589SPantelis Antoniou 			return 0;
11547518b589SPantelis Antoniou 		}
11557518b589SPantelis Antoniou 	}
11567518b589SPantelis Antoniou 
11577518b589SPantelis Antoniou 	return 1;
11587518b589SPantelis Antoniou }
11597518b589SPantelis Antoniou 
11607518b589SPantelis Antoniou /**
11610290c4caSFrank Rowand  * of_overlay_remove() - Revert and free an overlay changeset
116224789c5cSFrank Rowand  * @ovcs_id:	Pointer to overlay changeset id
11637518b589SPantelis Antoniou  *
116424789c5cSFrank Rowand  * Removes an overlay if it is permissible.  @ovcs_id was previously returned
1165a514266bSGeert Uytterhoeven  * by of_overlay_fdt_apply().
11667518b589SPantelis Antoniou  *
116724789c5cSFrank Rowand  * If an error occurred while attempting to revert the overlay changeset,
116824789c5cSFrank Rowand  * then an attempt is made to re-apply any changeset entry that was
116924789c5cSFrank Rowand  * reverted.  If an error occurs on re-apply then the state of the device
117024789c5cSFrank Rowand  * tree can not be determined, and any following attempt to apply or remove
117124789c5cSFrank Rowand  * an overlay changeset will be refused.
117224789c5cSFrank Rowand  *
117324789c5cSFrank Rowand  * A non-zero return value will not revert the changeset if error is from:
117424789c5cSFrank Rowand  *   - parameter checks
1175e9d92e40SGeert Uytterhoeven  *   - overlay changeset pre-remove notifier
117624789c5cSFrank Rowand  *   - overlay changeset entry revert
117724789c5cSFrank Rowand  *
117824789c5cSFrank Rowand  * If an error is returned by an overlay changeset pre-remove notifier
117924789c5cSFrank Rowand  * then no further overlay changeset pre-remove notifier will be called.
118024789c5cSFrank Rowand  *
118124789c5cSFrank Rowand  * If more than one notifier returns an error, then the last notifier
118224789c5cSFrank Rowand  * error to occur is returned.
118324789c5cSFrank Rowand  *
118424789c5cSFrank Rowand  * A non-zero return value will revert the changeset if error is from:
118524789c5cSFrank Rowand  *   - overlay changeset entry notifier
1186e9d92e40SGeert Uytterhoeven  *   - overlay changeset post-remove notifier
118724789c5cSFrank Rowand  *
118824789c5cSFrank Rowand  * If an error is returned by an overlay changeset post-remove notifier
118924789c5cSFrank Rowand  * then no further overlay changeset post-remove notifier will be called.
119024789c5cSFrank Rowand  *
1191aed4349cSRob Herring  * Return: 0 on success, or a negative error number.  *@ovcs_id is set to
119224789c5cSFrank Rowand  * zero after reverting the changeset, even if a subsequent error occurs.
11937518b589SPantelis Antoniou  */
of_overlay_remove(int * ovcs_id)119424789c5cSFrank Rowand int of_overlay_remove(int *ovcs_id)
11957518b589SPantelis Antoniou {
11960290c4caSFrank Rowand 	struct overlay_changeset *ovcs;
119724789c5cSFrank Rowand 	int ret, ret_apply, ret_tmp;
11987518b589SPantelis Antoniou 
119924789c5cSFrank Rowand 	if (devicetree_corrupt()) {
120024789c5cSFrank Rowand 		pr_err("suspect devicetree state, refuse to remove overlay\n");
12010290c4caSFrank Rowand 		ret = -EBUSY;
12027518b589SPantelis Antoniou 		goto out;
12037518b589SPantelis Antoniou 	}
12047518b589SPantelis Antoniou 
120524789c5cSFrank Rowand 	mutex_lock(&of_mutex);
120624789c5cSFrank Rowand 
120724789c5cSFrank Rowand 	ovcs = idr_find(&ovcs_idr, *ovcs_id);
120824789c5cSFrank Rowand 	if (!ovcs) {
120924789c5cSFrank Rowand 		ret = -ENODEV;
121024789c5cSFrank Rowand 		pr_err("remove: Could not find overlay #%d\n", *ovcs_id);
1211067c0987SFrank Rowand 		goto err_unlock;
121224789c5cSFrank Rowand 	}
121324789c5cSFrank Rowand 
121424789c5cSFrank Rowand 	if (!overlay_removal_is_ok(ovcs)) {
121524789c5cSFrank Rowand 		ret = -EBUSY;
1216067c0987SFrank Rowand 		goto err_unlock;
121724789c5cSFrank Rowand 	}
121824789c5cSFrank Rowand 
121924789c5cSFrank Rowand 	ret = overlay_notify(ovcs, OF_OVERLAY_PRE_REMOVE);
12201ac17586SFrank Rowand 	if (ret)
1221067c0987SFrank Rowand 		goto err_unlock;
122261b4de4eSFrank Rowand 
122324789c5cSFrank Rowand 	ret_apply = 0;
122424789c5cSFrank Rowand 	ret = __of_changeset_revert_entries(&ovcs->cset, &ret_apply);
122524789c5cSFrank Rowand 	if (ret) {
122624789c5cSFrank Rowand 		if (ret_apply)
122724789c5cSFrank Rowand 			devicetree_state_flags |= DTSF_REVERT_FAIL;
1228067c0987SFrank Rowand 		goto err_unlock;
12296de67de3SGeert Uytterhoeven 	}
12306de67de3SGeert Uytterhoeven 
123124789c5cSFrank Rowand 	ret = __of_changeset_revert_notify(&ovcs->cset);
12326de67de3SGeert Uytterhoeven 	if (ret)
1233a15e824fSFrank Rowand 		pr_err("overlay remove changeset entry notify error %d\n", ret);
12346de67de3SGeert Uytterhoeven 	/* notify failure is not fatal, continue */
123561b4de4eSFrank Rowand 
123624789c5cSFrank Rowand 	*ovcs_id = 0;
123724789c5cSFrank Rowand 
1238067c0987SFrank Rowand 	/*
1239067c0987SFrank Rowand 	 * Note that the overlay memory will be kfree()ed by
1240067c0987SFrank Rowand 	 * free_overlay_changeset() even if the notifier for
1241067c0987SFrank Rowand 	 * OF_OVERLAY_POST_REMOVE returns an error.
1242067c0987SFrank Rowand 	 */
124324789c5cSFrank Rowand 	ret_tmp = overlay_notify(ovcs, OF_OVERLAY_POST_REMOVE);
12441ac17586SFrank Rowand 	if (ret_tmp)
124524789c5cSFrank Rowand 		if (!ret)
124624789c5cSFrank Rowand 			ret = ret_tmp;
124761b4de4eSFrank Rowand 
124861b4de4eSFrank Rowand 	free_overlay_changeset(ovcs);
12497518b589SPantelis Antoniou 
1250067c0987SFrank Rowand err_unlock:
1251067c0987SFrank Rowand 	/*
1252067c0987SFrank Rowand 	 * If jumped over free_overlay_changeset(), then did not kfree()
1253067c0987SFrank Rowand 	 * overlay related memory.  This is a memory leak unless a subsequent
1254067c0987SFrank Rowand 	 * of_overlay_remove() of this overlay is successful.
1255067c0987SFrank Rowand 	 */
12567518b589SPantelis Antoniou 	mutex_unlock(&of_mutex);
12577518b589SPantelis Antoniou 
125824789c5cSFrank Rowand out:
125924789c5cSFrank Rowand 	pr_debug("%s() err=%d\n", __func__, ret);
126024789c5cSFrank Rowand 
12610290c4caSFrank Rowand 	return ret;
12627518b589SPantelis Antoniou }
12630290c4caSFrank Rowand EXPORT_SYMBOL_GPL(of_overlay_remove);
12647518b589SPantelis Antoniou 
12657518b589SPantelis Antoniou /**
12660290c4caSFrank Rowand  * of_overlay_remove_all() - Reverts and frees all overlay changesets
12677518b589SPantelis Antoniou  *
12687518b589SPantelis Antoniou  * Removes all overlays from the system in the correct order.
12697518b589SPantelis Antoniou  *
12708c8239c2SRob Herring  * Return: 0 on success, or a negative error number
12717518b589SPantelis Antoniou  */
of_overlay_remove_all(void)12720290c4caSFrank Rowand int of_overlay_remove_all(void)
12737518b589SPantelis Antoniou {
12740290c4caSFrank Rowand 	struct overlay_changeset *ovcs, *ovcs_n;
127561b4de4eSFrank Rowand 	int ret;
12767518b589SPantelis Antoniou 
12777518b589SPantelis Antoniou 	/* the tail of list is guaranteed to be safe to remove */
12780290c4caSFrank Rowand 	list_for_each_entry_safe_reverse(ovcs, ovcs_n, &ovcs_list, ovcs_list) {
127924789c5cSFrank Rowand 		ret = of_overlay_remove(&ovcs->id);
128061b4de4eSFrank Rowand 		if (ret)
128161b4de4eSFrank Rowand 			return ret;
12827518b589SPantelis Antoniou 	}
12837518b589SPantelis Antoniou 
12847518b589SPantelis Antoniou 	return 0;
12857518b589SPantelis Antoniou }
12860290c4caSFrank Rowand EXPORT_SYMBOL_GPL(of_overlay_remove_all);
1287