xref: /linux/drivers/of/dynamic.c (revision 249969514e23b07d1872fc614bb5cfd3577bde35)
16afc0dc3SGrant Likely /*
26afc0dc3SGrant Likely  * Support for dynamic device trees.
36afc0dc3SGrant Likely  *
46afc0dc3SGrant Likely  * On some platforms, the device tree can be manipulated at runtime.
56afc0dc3SGrant Likely  * The routines in this section support adding, removing and changing
66afc0dc3SGrant Likely  * device tree nodes.
76afc0dc3SGrant Likely  */
86afc0dc3SGrant Likely 
9606ad42aSRob Herring #define pr_fmt(fmt)	"OF: " fmt
10606ad42aSRob Herring 
116afc0dc3SGrant Likely #include <linux/of.h>
126afc0dc3SGrant Likely #include <linux/spinlock.h>
136afc0dc3SGrant Likely #include <linux/slab.h>
146afc0dc3SGrant Likely #include <linux/string.h>
156afc0dc3SGrant Likely #include <linux/proc_fs.h>
166afc0dc3SGrant Likely 
176afc0dc3SGrant Likely #include "of_private.h"
186afc0dc3SGrant Likely 
196afc0dc3SGrant Likely /**
206afc0dc3SGrant Likely  * of_node_get() - Increment refcount of a node
216afc0dc3SGrant Likely  * @node:	Node to inc refcount, NULL is supported to simplify writing of
226afc0dc3SGrant Likely  *		callers
236afc0dc3SGrant Likely  *
246afc0dc3SGrant Likely  * Returns node.
256afc0dc3SGrant Likely  */
266afc0dc3SGrant Likely struct device_node *of_node_get(struct device_node *node)
276afc0dc3SGrant Likely {
286afc0dc3SGrant Likely 	if (node)
296afc0dc3SGrant Likely 		kobject_get(&node->kobj);
306afc0dc3SGrant Likely 	return node;
316afc0dc3SGrant Likely }
326afc0dc3SGrant Likely EXPORT_SYMBOL(of_node_get);
336afc0dc3SGrant Likely 
346afc0dc3SGrant Likely /**
356afc0dc3SGrant Likely  * of_node_put() - Decrement refcount of a node
366afc0dc3SGrant Likely  * @node:	Node to dec refcount, NULL is supported to simplify writing of
376afc0dc3SGrant Likely  *		callers
386afc0dc3SGrant Likely  */
396afc0dc3SGrant Likely void of_node_put(struct device_node *node)
406afc0dc3SGrant Likely {
416afc0dc3SGrant Likely 	if (node)
426afc0dc3SGrant Likely 		kobject_put(&node->kobj);
436afc0dc3SGrant Likely }
446afc0dc3SGrant Likely EXPORT_SYMBOL(of_node_put);
456afc0dc3SGrant Likely 
468a2b22a2SGrant Likely void __of_detach_node_sysfs(struct device_node *np)
476afc0dc3SGrant Likely {
486afc0dc3SGrant Likely 	struct property *pp;
496afc0dc3SGrant Likely 
50ef69d740SGaurav Minocha 	if (!IS_ENABLED(CONFIG_SYSFS))
51ef69d740SGaurav Minocha 		return;
52ef69d740SGaurav Minocha 
536afc0dc3SGrant Likely 	BUG_ON(!of_node_is_initialized(np));
548a2b22a2SGrant Likely 	if (!of_kset)
558a2b22a2SGrant Likely 		return;
566afc0dc3SGrant Likely 
576afc0dc3SGrant Likely 	/* only remove properties if on sysfs */
586afc0dc3SGrant Likely 	if (of_node_is_attached(np)) {
596afc0dc3SGrant Likely 		for_each_property_of_node(np, pp)
60d9fc8807SFrank Rowand 			__of_sysfs_remove_bin_file(np, pp);
616afc0dc3SGrant Likely 		kobject_del(&np->kobj);
626afc0dc3SGrant Likely 	}
636afc0dc3SGrant Likely 
646afc0dc3SGrant Likely 	/* finally remove the kobj_init ref */
656afc0dc3SGrant Likely 	of_node_put(np);
666afc0dc3SGrant Likely }
676afc0dc3SGrant Likely 
686afc0dc3SGrant Likely static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain);
696afc0dc3SGrant Likely 
706afc0dc3SGrant Likely int of_reconfig_notifier_register(struct notifier_block *nb)
716afc0dc3SGrant Likely {
726afc0dc3SGrant Likely 	return blocking_notifier_chain_register(&of_reconfig_chain, nb);
736afc0dc3SGrant Likely }
746afc0dc3SGrant Likely EXPORT_SYMBOL_GPL(of_reconfig_notifier_register);
756afc0dc3SGrant Likely 
766afc0dc3SGrant Likely int of_reconfig_notifier_unregister(struct notifier_block *nb)
776afc0dc3SGrant Likely {
786afc0dc3SGrant Likely 	return blocking_notifier_chain_unregister(&of_reconfig_chain, nb);
796afc0dc3SGrant Likely }
806afc0dc3SGrant Likely EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister);
816afc0dc3SGrant Likely 
8200aa3720SGrant Likely #ifdef DEBUG
8300aa3720SGrant Likely const char *action_names[] = {
8400aa3720SGrant Likely 	[OF_RECONFIG_ATTACH_NODE] = "ATTACH_NODE",
8500aa3720SGrant Likely 	[OF_RECONFIG_DETACH_NODE] = "DETACH_NODE",
8600aa3720SGrant Likely 	[OF_RECONFIG_ADD_PROPERTY] = "ADD_PROPERTY",
8700aa3720SGrant Likely 	[OF_RECONFIG_REMOVE_PROPERTY] = "REMOVE_PROPERTY",
8800aa3720SGrant Likely 	[OF_RECONFIG_UPDATE_PROPERTY] = "UPDATE_PROPERTY",
8900aa3720SGrant Likely };
9000aa3720SGrant Likely #endif
9100aa3720SGrant Likely 
92f5242e5aSGrant Likely int of_reconfig_notify(unsigned long action, struct of_reconfig_data *p)
936afc0dc3SGrant Likely {
946afc0dc3SGrant Likely 	int rc;
9500aa3720SGrant Likely #ifdef DEBUG
96f5242e5aSGrant Likely 	struct of_reconfig_data *pr = p;
976afc0dc3SGrant Likely 
9800aa3720SGrant Likely 	switch (action) {
9900aa3720SGrant Likely 	case OF_RECONFIG_ATTACH_NODE:
10000aa3720SGrant Likely 	case OF_RECONFIG_DETACH_NODE:
101606ad42aSRob Herring 		pr_debug("notify %-15s %s\n", action_names[action],
102f5242e5aSGrant Likely 			pr->dn->full_name);
10300aa3720SGrant Likely 		break;
10400aa3720SGrant Likely 	case OF_RECONFIG_ADD_PROPERTY:
10500aa3720SGrant Likely 	case OF_RECONFIG_REMOVE_PROPERTY:
10600aa3720SGrant Likely 	case OF_RECONFIG_UPDATE_PROPERTY:
107606ad42aSRob Herring 		pr_debug("notify %-15s %s:%s\n", action_names[action],
10800aa3720SGrant Likely 			pr->dn->full_name, pr->prop->name);
10900aa3720SGrant Likely 		break;
11000aa3720SGrant Likely 
11100aa3720SGrant Likely 	}
11200aa3720SGrant Likely #endif
1136afc0dc3SGrant Likely 	rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p);
1146afc0dc3SGrant Likely 	return notifier_to_errno(rc);
1156afc0dc3SGrant Likely }
1166afc0dc3SGrant Likely 
117b53a2340SPantelis Antoniou /*
118b53a2340SPantelis Antoniou  * of_reconfig_get_state_change()	- Returns new state of device
119b53a2340SPantelis Antoniou  * @action	- action of the of notifier
120b53a2340SPantelis Antoniou  * @arg		- argument of the of notifier
121b53a2340SPantelis Antoniou  *
122b53a2340SPantelis Antoniou  * Returns the new state of a device based on the notifier used.
123b53a2340SPantelis Antoniou  * Returns 0 on device going from enabled to disabled, 1 on device
124b53a2340SPantelis Antoniou  * going from disabled to enabled and -1 on no change.
125b53a2340SPantelis Antoniou  */
126f5242e5aSGrant Likely int of_reconfig_get_state_change(unsigned long action, struct of_reconfig_data *pr)
127b53a2340SPantelis Antoniou {
128f5242e5aSGrant Likely 	struct property *prop, *old_prop = NULL;
129b53a2340SPantelis Antoniou 	int is_status, status_state, old_status_state, prev_state, new_state;
130b53a2340SPantelis Antoniou 
131b53a2340SPantelis Antoniou 	/* figure out if a device should be created or destroyed */
132b53a2340SPantelis Antoniou 	switch (action) {
133b53a2340SPantelis Antoniou 	case OF_RECONFIG_ATTACH_NODE:
134b53a2340SPantelis Antoniou 	case OF_RECONFIG_DETACH_NODE:
135f5242e5aSGrant Likely 		prop = of_find_property(pr->dn, "status", NULL);
136b53a2340SPantelis Antoniou 		break;
137b53a2340SPantelis Antoniou 	case OF_RECONFIG_ADD_PROPERTY:
138b53a2340SPantelis Antoniou 	case OF_RECONFIG_REMOVE_PROPERTY:
139b53a2340SPantelis Antoniou 		prop = pr->prop;
140b53a2340SPantelis Antoniou 		break;
141b53a2340SPantelis Antoniou 	case OF_RECONFIG_UPDATE_PROPERTY:
142b53a2340SPantelis Antoniou 		prop = pr->prop;
143b53a2340SPantelis Antoniou 		old_prop = pr->old_prop;
144b53a2340SPantelis Antoniou 		break;
145b53a2340SPantelis Antoniou 	default:
146b53a2340SPantelis Antoniou 		return OF_RECONFIG_NO_CHANGE;
147b53a2340SPantelis Antoniou 	}
148b53a2340SPantelis Antoniou 
149b53a2340SPantelis Antoniou 	is_status = 0;
150b53a2340SPantelis Antoniou 	status_state = -1;
151b53a2340SPantelis Antoniou 	old_status_state = -1;
152b53a2340SPantelis Antoniou 	prev_state = -1;
153b53a2340SPantelis Antoniou 	new_state = -1;
154b53a2340SPantelis Antoniou 
155b53a2340SPantelis Antoniou 	if (prop && !strcmp(prop->name, "status")) {
156b53a2340SPantelis Antoniou 		is_status = 1;
157b53a2340SPantelis Antoniou 		status_state = !strcmp(prop->value, "okay") ||
158b53a2340SPantelis Antoniou 			       !strcmp(prop->value, "ok");
159b53a2340SPantelis Antoniou 		if (old_prop)
160b53a2340SPantelis Antoniou 			old_status_state = !strcmp(old_prop->value, "okay") ||
161b53a2340SPantelis Antoniou 					   !strcmp(old_prop->value, "ok");
162b53a2340SPantelis Antoniou 	}
163b53a2340SPantelis Antoniou 
164b53a2340SPantelis Antoniou 	switch (action) {
165b53a2340SPantelis Antoniou 	case OF_RECONFIG_ATTACH_NODE:
166b53a2340SPantelis Antoniou 		prev_state = 0;
167b53a2340SPantelis Antoniou 		/* -1 & 0 status either missing or okay */
168b53a2340SPantelis Antoniou 		new_state = status_state != 0;
169b53a2340SPantelis Antoniou 		break;
170b53a2340SPantelis Antoniou 	case OF_RECONFIG_DETACH_NODE:
171b53a2340SPantelis Antoniou 		/* -1 & 0 status either missing or okay */
172b53a2340SPantelis Antoniou 		prev_state = status_state != 0;
173b53a2340SPantelis Antoniou 		new_state = 0;
174b53a2340SPantelis Antoniou 		break;
175b53a2340SPantelis Antoniou 	case OF_RECONFIG_ADD_PROPERTY:
176b53a2340SPantelis Antoniou 		if (is_status) {
177b53a2340SPantelis Antoniou 			/* no status property -> enabled (legacy) */
178b53a2340SPantelis Antoniou 			prev_state = 1;
179b53a2340SPantelis Antoniou 			new_state = status_state;
180b53a2340SPantelis Antoniou 		}
181b53a2340SPantelis Antoniou 		break;
182b53a2340SPantelis Antoniou 	case OF_RECONFIG_REMOVE_PROPERTY:
183b53a2340SPantelis Antoniou 		if (is_status) {
184b53a2340SPantelis Antoniou 			prev_state = status_state;
185b53a2340SPantelis Antoniou 			/* no status property -> enabled (legacy) */
186b53a2340SPantelis Antoniou 			new_state = 1;
187b53a2340SPantelis Antoniou 		}
188b53a2340SPantelis Antoniou 		break;
189b53a2340SPantelis Antoniou 	case OF_RECONFIG_UPDATE_PROPERTY:
190b53a2340SPantelis Antoniou 		if (is_status) {
191b53a2340SPantelis Antoniou 			prev_state = old_status_state != 0;
192b53a2340SPantelis Antoniou 			new_state = status_state != 0;
193b53a2340SPantelis Antoniou 		}
194b53a2340SPantelis Antoniou 		break;
195b53a2340SPantelis Antoniou 	}
196b53a2340SPantelis Antoniou 
197b53a2340SPantelis Antoniou 	if (prev_state == new_state)
198b53a2340SPantelis Antoniou 		return OF_RECONFIG_NO_CHANGE;
199b53a2340SPantelis Antoniou 
200b53a2340SPantelis Antoniou 	return new_state ? OF_RECONFIG_CHANGE_ADD : OF_RECONFIG_CHANGE_REMOVE;
201b53a2340SPantelis Antoniou }
202b53a2340SPantelis Antoniou EXPORT_SYMBOL_GPL(of_reconfig_get_state_change);
203b53a2340SPantelis Antoniou 
2046afc0dc3SGrant Likely int of_property_notify(int action, struct device_node *np,
205259092a3SGrant Likely 		       struct property *prop, struct property *oldprop)
2066afc0dc3SGrant Likely {
207f5242e5aSGrant Likely 	struct of_reconfig_data pr;
2086afc0dc3SGrant Likely 
2096afc0dc3SGrant Likely 	/* only call notifiers if the node is attached */
2106afc0dc3SGrant Likely 	if (!of_node_is_attached(np))
2116afc0dc3SGrant Likely 		return 0;
2126afc0dc3SGrant Likely 
2136afc0dc3SGrant Likely 	pr.dn = np;
2146afc0dc3SGrant Likely 	pr.prop = prop;
215259092a3SGrant Likely 	pr.old_prop = oldprop;
2166afc0dc3SGrant Likely 	return of_reconfig_notify(action, &pr);
2176afc0dc3SGrant Likely }
2186afc0dc3SGrant Likely 
219*24996951SFrank Rowand static void __of_attach_node(struct device_node *np)
220d8c50088SPantelis Antoniou {
221a25095d4SGrant Likely 	const __be32 *phandle;
222a25095d4SGrant Likely 	int sz;
223a25095d4SGrant Likely 
224a25095d4SGrant Likely 	np->name = __of_get_property(np, "name", NULL) ? : "<NULL>";
225a25095d4SGrant Likely 	np->type = __of_get_property(np, "device_type", NULL) ? : "<NULL>";
226a25095d4SGrant Likely 
227a25095d4SGrant Likely 	phandle = __of_get_property(np, "phandle", &sz);
228a25095d4SGrant Likely 	if (!phandle)
229a25095d4SGrant Likely 		phandle = __of_get_property(np, "linux,phandle", &sz);
230f76502aaSGeert Uytterhoeven 	if (IS_ENABLED(CONFIG_PPC_PSERIES) && !phandle)
231a25095d4SGrant Likely 		phandle = __of_get_property(np, "ibm,phandle", &sz);
232a25095d4SGrant Likely 	np->phandle = (phandle && (sz >= 4)) ? be32_to_cpup(phandle) : 0;
233a25095d4SGrant Likely 
2346162dbe4SGrant Likely 	np->child = NULL;
235d8c50088SPantelis Antoniou 	np->sibling = np->parent->child;
236d8c50088SPantelis Antoniou 	np->parent->child = np;
237d8c50088SPantelis Antoniou 	of_node_clear_flag(np, OF_DETACHED);
238d8c50088SPantelis Antoniou }
239d8c50088SPantelis Antoniou 
2406afc0dc3SGrant Likely /**
2416afc0dc3SGrant Likely  * of_attach_node() - Plug a device node into the tree and global list.
2426afc0dc3SGrant Likely  */
2436afc0dc3SGrant Likely int of_attach_node(struct device_node *np)
2446afc0dc3SGrant Likely {
245f5242e5aSGrant Likely 	struct of_reconfig_data rd;
2466afc0dc3SGrant Likely 	unsigned long flags;
2476afc0dc3SGrant Likely 
248f5242e5aSGrant Likely 	memset(&rd, 0, sizeof(rd));
249f5242e5aSGrant Likely 	rd.dn = np;
250f5242e5aSGrant Likely 
2518a2b22a2SGrant Likely 	mutex_lock(&of_mutex);
2526afc0dc3SGrant Likely 	raw_spin_lock_irqsave(&devtree_lock, flags);
253d8c50088SPantelis Antoniou 	__of_attach_node(np);
2546afc0dc3SGrant Likely 	raw_spin_unlock_irqrestore(&devtree_lock, flags);
2556afc0dc3SGrant Likely 
2568a2b22a2SGrant Likely 	__of_attach_node_sysfs(np);
2578a2b22a2SGrant Likely 	mutex_unlock(&of_mutex);
258259092a3SGrant Likely 
259f5242e5aSGrant Likely 	of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, &rd);
260259092a3SGrant Likely 
2616afc0dc3SGrant Likely 	return 0;
2626afc0dc3SGrant Likely }
2636afc0dc3SGrant Likely 
264d8c50088SPantelis Antoniou void __of_detach_node(struct device_node *np)
2656afc0dc3SGrant Likely {
2666afc0dc3SGrant Likely 	struct device_node *parent;
2676afc0dc3SGrant Likely 
268d8c50088SPantelis Antoniou 	if (WARN_ON(of_node_check_flag(np, OF_DETACHED)))
269d8c50088SPantelis Antoniou 		return;
2706afc0dc3SGrant Likely 
2716afc0dc3SGrant Likely 	parent = np->parent;
272d8c50088SPantelis Antoniou 	if (WARN_ON(!parent))
273d8c50088SPantelis Antoniou 		return;
2746afc0dc3SGrant Likely 
2756afc0dc3SGrant Likely 	if (parent->child == np)
2766afc0dc3SGrant Likely 		parent->child = np->sibling;
2776afc0dc3SGrant Likely 	else {
2786afc0dc3SGrant Likely 		struct device_node *prevsib;
2796afc0dc3SGrant Likely 		for (prevsib = np->parent->child;
2806afc0dc3SGrant Likely 		     prevsib->sibling != np;
2816afc0dc3SGrant Likely 		     prevsib = prevsib->sibling)
2826afc0dc3SGrant Likely 			;
2836afc0dc3SGrant Likely 		prevsib->sibling = np->sibling;
2846afc0dc3SGrant Likely 	}
2856afc0dc3SGrant Likely 
2866afc0dc3SGrant Likely 	of_node_set_flag(np, OF_DETACHED);
287d8c50088SPantelis Antoniou }
288d8c50088SPantelis Antoniou 
289d8c50088SPantelis Antoniou /**
290d8c50088SPantelis Antoniou  * of_detach_node() - "Unplug" a node from the device tree.
291d8c50088SPantelis Antoniou  *
292d8c50088SPantelis Antoniou  * The caller must hold a reference to the node.  The memory associated with
293d8c50088SPantelis Antoniou  * the node is not freed until its refcount goes to zero.
294d8c50088SPantelis Antoniou  */
295d8c50088SPantelis Antoniou int of_detach_node(struct device_node *np)
296d8c50088SPantelis Antoniou {
297f5242e5aSGrant Likely 	struct of_reconfig_data rd;
298d8c50088SPantelis Antoniou 	unsigned long flags;
299d8c50088SPantelis Antoniou 	int rc = 0;
300d8c50088SPantelis Antoniou 
301f5242e5aSGrant Likely 	memset(&rd, 0, sizeof(rd));
302f5242e5aSGrant Likely 	rd.dn = np;
303f5242e5aSGrant Likely 
3048a2b22a2SGrant Likely 	mutex_lock(&of_mutex);
305d8c50088SPantelis Antoniou 	raw_spin_lock_irqsave(&devtree_lock, flags);
306d8c50088SPantelis Antoniou 	__of_detach_node(np);
3076afc0dc3SGrant Likely 	raw_spin_unlock_irqrestore(&devtree_lock, flags);
3086afc0dc3SGrant Likely 
3098a2b22a2SGrant Likely 	__of_detach_node_sysfs(np);
3108a2b22a2SGrant Likely 	mutex_unlock(&of_mutex);
311259092a3SGrant Likely 
312f5242e5aSGrant Likely 	of_reconfig_notify(OF_RECONFIG_DETACH_NODE, &rd);
313259092a3SGrant Likely 
3146afc0dc3SGrant Likely 	return rc;
3156afc0dc3SGrant Likely }
316bb91f923SGavin Shan EXPORT_SYMBOL_GPL(of_detach_node);
3176afc0dc3SGrant Likely 
3186afc0dc3SGrant Likely /**
3196afc0dc3SGrant Likely  * of_node_release() - release a dynamically allocated node
3206afc0dc3SGrant Likely  * @kref: kref element of the node to be released
3216afc0dc3SGrant Likely  *
3226afc0dc3SGrant Likely  * In of_node_put() this function is passed to kref_put() as the destructor.
3236afc0dc3SGrant Likely  */
3246afc0dc3SGrant Likely void of_node_release(struct kobject *kobj)
3256afc0dc3SGrant Likely {
3266afc0dc3SGrant Likely 	struct device_node *node = kobj_to_device_node(kobj);
3276afc0dc3SGrant Likely 	struct property *prop = node->properties;
3286afc0dc3SGrant Likely 
3296afc0dc3SGrant Likely 	/* We should never be releasing nodes that haven't been detached. */
3306afc0dc3SGrant Likely 	if (!of_node_check_flag(node, OF_DETACHED)) {
3316afc0dc3SGrant Likely 		pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name);
3326afc0dc3SGrant Likely 		dump_stack();
3336afc0dc3SGrant Likely 		return;
3346afc0dc3SGrant Likely 	}
3356afc0dc3SGrant Likely 
3366afc0dc3SGrant Likely 	if (!of_node_check_flag(node, OF_DYNAMIC))
3376afc0dc3SGrant Likely 		return;
3386afc0dc3SGrant Likely 
3396afc0dc3SGrant Likely 	while (prop) {
3406afc0dc3SGrant Likely 		struct property *next = prop->next;
3416afc0dc3SGrant Likely 		kfree(prop->name);
3426afc0dc3SGrant Likely 		kfree(prop->value);
3436afc0dc3SGrant Likely 		kfree(prop);
3446afc0dc3SGrant Likely 		prop = next;
3456afc0dc3SGrant Likely 
3466afc0dc3SGrant Likely 		if (!prop) {
3476afc0dc3SGrant Likely 			prop = node->deadprops;
3486afc0dc3SGrant Likely 			node->deadprops = NULL;
3496afc0dc3SGrant Likely 		}
3506afc0dc3SGrant Likely 	}
3516afc0dc3SGrant Likely 	kfree(node->full_name);
3526afc0dc3SGrant Likely 	kfree(node->data);
3536afc0dc3SGrant Likely 	kfree(node);
3546afc0dc3SGrant Likely }
35569843396SPantelis Antoniou 
35669843396SPantelis Antoniou /**
35769843396SPantelis Antoniou  * __of_prop_dup - Copy a property dynamically.
35869843396SPantelis Antoniou  * @prop:	Property to copy
35969843396SPantelis Antoniou  * @allocflags:	Allocation flags (typically pass GFP_KERNEL)
36069843396SPantelis Antoniou  *
36169843396SPantelis Antoniou  * Copy a property by dynamically allocating the memory of both the
36227b3383aSGeert Uytterhoeven  * property structure and the property name & contents. The property's
36369843396SPantelis Antoniou  * flags have the OF_DYNAMIC bit set so that we can differentiate between
36469843396SPantelis Antoniou  * dynamically allocated properties and not.
36569843396SPantelis Antoniou  * Returns the newly allocated property or NULL on out of memory error.
36669843396SPantelis Antoniou  */
36769843396SPantelis Antoniou struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
36869843396SPantelis Antoniou {
36969843396SPantelis Antoniou 	struct property *new;
37069843396SPantelis Antoniou 
37169843396SPantelis Antoniou 	new = kzalloc(sizeof(*new), allocflags);
37269843396SPantelis Antoniou 	if (!new)
37369843396SPantelis Antoniou 		return NULL;
37469843396SPantelis Antoniou 
37569843396SPantelis Antoniou 	/*
37669843396SPantelis Antoniou 	 * NOTE: There is no check for zero length value.
377b6ae5dc5SGrant Likely 	 * In case of a boolean property, this will allocate a value
37869843396SPantelis Antoniou 	 * of zero bytes. We do this to work around the use
37969843396SPantelis Antoniou 	 * of of_get_property() calls on boolean values.
38069843396SPantelis Antoniou 	 */
38169843396SPantelis Antoniou 	new->name = kstrdup(prop->name, allocflags);
38269843396SPantelis Antoniou 	new->value = kmemdup(prop->value, prop->length, allocflags);
38369843396SPantelis Antoniou 	new->length = prop->length;
38469843396SPantelis Antoniou 	if (!new->name || !new->value)
38569843396SPantelis Antoniou 		goto err_free;
38669843396SPantelis Antoniou 
38769843396SPantelis Antoniou 	/* mark the property as dynamic */
38869843396SPantelis Antoniou 	of_property_set_flag(new, OF_DYNAMIC);
38969843396SPantelis Antoniou 
39069843396SPantelis Antoniou 	return new;
39169843396SPantelis Antoniou 
39269843396SPantelis Antoniou  err_free:
39369843396SPantelis Antoniou 	kfree(new->name);
39469843396SPantelis Antoniou 	kfree(new->value);
39569843396SPantelis Antoniou 	kfree(new);
39669843396SPantelis Antoniou 	return NULL;
39769843396SPantelis Antoniou }
39869843396SPantelis Antoniou 
39969843396SPantelis Antoniou /**
400e5179581SGrant Likely  * __of_node_dup() - Duplicate or create an empty device node dynamically.
401e5179581SGrant Likely  * @fmt: Format string (plus vargs) for new full name of the device node
40269843396SPantelis Antoniou  *
403e5179581SGrant Likely  * Create an device tree node, either by duplicating an empty node or by allocating
404e5179581SGrant Likely  * an empty one suitable for further modification.  The node data are
405e5179581SGrant Likely  * dynamically allocated and all the node flags have the OF_DYNAMIC &
406e5179581SGrant Likely  * OF_DETACHED bits set. Returns the newly allocated node or NULL on out of
407e5179581SGrant Likely  * memory error.
40869843396SPantelis Antoniou  */
409e5179581SGrant Likely struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...)
41069843396SPantelis Antoniou {
411ef8bbd73SGrant Likely 	va_list vargs;
41269843396SPantelis Antoniou 	struct device_node *node;
41369843396SPantelis Antoniou 
414ef8bbd73SGrant Likely 	node = kzalloc(sizeof(*node), GFP_KERNEL);
41569843396SPantelis Antoniou 	if (!node)
41669843396SPantelis Antoniou 		return NULL;
417ef8bbd73SGrant Likely 	va_start(vargs, fmt);
418ef8bbd73SGrant Likely 	node->full_name = kvasprintf(GFP_KERNEL, fmt, vargs);
419ef8bbd73SGrant Likely 	va_end(vargs);
420e5179581SGrant Likely 	if (!node->full_name) {
421e5179581SGrant Likely 		kfree(node);
422e5179581SGrant Likely 		return NULL;
423e5179581SGrant Likely 	}
42469843396SPantelis Antoniou 
425ef8bbd73SGrant Likely 	of_node_set_flag(node, OF_DYNAMIC);
426ef8bbd73SGrant Likely 	of_node_set_flag(node, OF_DETACHED);
42769843396SPantelis Antoniou 	of_node_init(node);
42869843396SPantelis Antoniou 
429e5179581SGrant Likely 	/* Iterate over and duplicate all properties */
430e5179581SGrant Likely 	if (np) {
431e5179581SGrant Likely 		struct property *pp, *new_pp;
432e5179581SGrant Likely 		for_each_property_of_node(np, pp) {
433e5179581SGrant Likely 			new_pp = __of_prop_dup(pp, GFP_KERNEL);
434e5179581SGrant Likely 			if (!new_pp)
435e5179581SGrant Likely 				goto err_prop;
436e5179581SGrant Likely 			if (__of_add_property(node, new_pp)) {
437e5179581SGrant Likely 				kfree(new_pp->name);
438e5179581SGrant Likely 				kfree(new_pp->value);
439e5179581SGrant Likely 				kfree(new_pp);
440e5179581SGrant Likely 				goto err_prop;
441e5179581SGrant Likely 			}
442e5179581SGrant Likely 		}
443e5179581SGrant Likely 	}
44469843396SPantelis Antoniou 	return node;
44569843396SPantelis Antoniou 
446e5179581SGrant Likely  err_prop:
447e5179581SGrant Likely 	of_node_put(node); /* Frees the node and properties */
44869843396SPantelis Antoniou 	return NULL;
44969843396SPantelis Antoniou }
450201c910bSPantelis Antoniou 
451201c910bSPantelis Antoniou static void __of_changeset_entry_destroy(struct of_changeset_entry *ce)
452201c910bSPantelis Antoniou {
453201c910bSPantelis Antoniou 	of_node_put(ce->np);
454201c910bSPantelis Antoniou 	list_del(&ce->node);
455201c910bSPantelis Antoniou 	kfree(ce);
456201c910bSPantelis Antoniou }
457201c910bSPantelis Antoniou 
458201c910bSPantelis Antoniou #ifdef DEBUG
459201c910bSPantelis Antoniou static void __of_changeset_entry_dump(struct of_changeset_entry *ce)
460201c910bSPantelis Antoniou {
461201c910bSPantelis Antoniou 	switch (ce->action) {
462201c910bSPantelis Antoniou 	case OF_RECONFIG_ADD_PROPERTY:
463201c910bSPantelis Antoniou 	case OF_RECONFIG_REMOVE_PROPERTY:
464201c910bSPantelis Antoniou 	case OF_RECONFIG_UPDATE_PROPERTY:
465606ad42aSRob Herring 		pr_debug("cset<%p> %-15s %s/%s\n", ce, action_names[ce->action],
46600aa3720SGrant Likely 			ce->np->full_name, ce->prop->name);
467201c910bSPantelis Antoniou 		break;
468201c910bSPantelis Antoniou 	case OF_RECONFIG_ATTACH_NODE:
469201c910bSPantelis Antoniou 	case OF_RECONFIG_DETACH_NODE:
470606ad42aSRob Herring 		pr_debug("cset<%p> %-15s %s\n", ce, action_names[ce->action],
47100aa3720SGrant Likely 			ce->np->full_name);
472201c910bSPantelis Antoniou 		break;
473201c910bSPantelis Antoniou 	}
474201c910bSPantelis Antoniou }
475201c910bSPantelis Antoniou #else
476201c910bSPantelis Antoniou static inline void __of_changeset_entry_dump(struct of_changeset_entry *ce)
477201c910bSPantelis Antoniou {
478201c910bSPantelis Antoniou 	/* empty */
479201c910bSPantelis Antoniou }
480201c910bSPantelis Antoniou #endif
481201c910bSPantelis Antoniou 
482201c910bSPantelis Antoniou static void __of_changeset_entry_invert(struct of_changeset_entry *ce,
483201c910bSPantelis Antoniou 					  struct of_changeset_entry *rce)
484201c910bSPantelis Antoniou {
485201c910bSPantelis Antoniou 	memcpy(rce, ce, sizeof(*rce));
486201c910bSPantelis Antoniou 
487201c910bSPantelis Antoniou 	switch (ce->action) {
488201c910bSPantelis Antoniou 	case OF_RECONFIG_ATTACH_NODE:
489201c910bSPantelis Antoniou 		rce->action = OF_RECONFIG_DETACH_NODE;
490201c910bSPantelis Antoniou 		break;
491201c910bSPantelis Antoniou 	case OF_RECONFIG_DETACH_NODE:
492201c910bSPantelis Antoniou 		rce->action = OF_RECONFIG_ATTACH_NODE;
493201c910bSPantelis Antoniou 		break;
494201c910bSPantelis Antoniou 	case OF_RECONFIG_ADD_PROPERTY:
495201c910bSPantelis Antoniou 		rce->action = OF_RECONFIG_REMOVE_PROPERTY;
496201c910bSPantelis Antoniou 		break;
497201c910bSPantelis Antoniou 	case OF_RECONFIG_REMOVE_PROPERTY:
498201c910bSPantelis Antoniou 		rce->action = OF_RECONFIG_ADD_PROPERTY;
499201c910bSPantelis Antoniou 		break;
500201c910bSPantelis Antoniou 	case OF_RECONFIG_UPDATE_PROPERTY:
501201c910bSPantelis Antoniou 		rce->old_prop = ce->prop;
502201c910bSPantelis Antoniou 		rce->prop = ce->old_prop;
503b9c43856SPantelis Antoniou 		/* update was used but original property did not exist */
504b9c43856SPantelis Antoniou 		if (!rce->prop) {
505b9c43856SPantelis Antoniou 			rce->action = OF_RECONFIG_REMOVE_PROPERTY;
506b9c43856SPantelis Antoniou 			rce->prop = ce->prop;
507b9c43856SPantelis Antoniou 		}
508201c910bSPantelis Antoniou 		break;
509201c910bSPantelis Antoniou 	}
510201c910bSPantelis Antoniou }
511201c910bSPantelis Antoniou 
512201c910bSPantelis Antoniou static void __of_changeset_entry_notify(struct of_changeset_entry *ce, bool revert)
513201c910bSPantelis Antoniou {
514f5242e5aSGrant Likely 	struct of_reconfig_data rd;
515201c910bSPantelis Antoniou 	struct of_changeset_entry ce_inverted;
516201c910bSPantelis Antoniou 	int ret;
517201c910bSPantelis Antoniou 
518201c910bSPantelis Antoniou 	if (revert) {
519201c910bSPantelis Antoniou 		__of_changeset_entry_invert(ce, &ce_inverted);
520201c910bSPantelis Antoniou 		ce = &ce_inverted;
521201c910bSPantelis Antoniou 	}
522201c910bSPantelis Antoniou 
523201c910bSPantelis Antoniou 	switch (ce->action) {
524201c910bSPantelis Antoniou 	case OF_RECONFIG_ATTACH_NODE:
525201c910bSPantelis Antoniou 	case OF_RECONFIG_DETACH_NODE:
526f5242e5aSGrant Likely 		memset(&rd, 0, sizeof(rd));
527f5242e5aSGrant Likely 		rd.dn = ce->np;
528f5242e5aSGrant Likely 		ret = of_reconfig_notify(ce->action, &rd);
529201c910bSPantelis Antoniou 		break;
530201c910bSPantelis Antoniou 	case OF_RECONFIG_ADD_PROPERTY:
531201c910bSPantelis Antoniou 	case OF_RECONFIG_REMOVE_PROPERTY:
532201c910bSPantelis Antoniou 	case OF_RECONFIG_UPDATE_PROPERTY:
533201c910bSPantelis Antoniou 		ret = of_property_notify(ce->action, ce->np, ce->prop, ce->old_prop);
534201c910bSPantelis Antoniou 		break;
535201c910bSPantelis Antoniou 	default:
536606ad42aSRob Herring 		pr_err("invalid devicetree changeset action: %i\n",
537201c910bSPantelis Antoniou 			(int)ce->action);
538201c910bSPantelis Antoniou 		return;
539201c910bSPantelis Antoniou 	}
540201c910bSPantelis Antoniou 
541201c910bSPantelis Antoniou 	if (ret)
542606ad42aSRob Herring 		pr_err("changeset notifier error @%s\n", ce->np->full_name);
543201c910bSPantelis Antoniou }
544201c910bSPantelis Antoniou 
545201c910bSPantelis Antoniou static int __of_changeset_entry_apply(struct of_changeset_entry *ce)
546201c910bSPantelis Antoniou {
547201c910bSPantelis Antoniou 	struct property *old_prop, **propp;
548201c910bSPantelis Antoniou 	unsigned long flags;
549201c910bSPantelis Antoniou 	int ret = 0;
550201c910bSPantelis Antoniou 
551201c910bSPantelis Antoniou 	__of_changeset_entry_dump(ce);
552201c910bSPantelis Antoniou 
553201c910bSPantelis Antoniou 	raw_spin_lock_irqsave(&devtree_lock, flags);
554201c910bSPantelis Antoniou 	switch (ce->action) {
555201c910bSPantelis Antoniou 	case OF_RECONFIG_ATTACH_NODE:
556201c910bSPantelis Antoniou 		__of_attach_node(ce->np);
557201c910bSPantelis Antoniou 		break;
558201c910bSPantelis Antoniou 	case OF_RECONFIG_DETACH_NODE:
559201c910bSPantelis Antoniou 		__of_detach_node(ce->np);
560201c910bSPantelis Antoniou 		break;
561201c910bSPantelis Antoniou 	case OF_RECONFIG_ADD_PROPERTY:
562201c910bSPantelis Antoniou 		/* If the property is in deadprops then it must be removed */
563201c910bSPantelis Antoniou 		for (propp = &ce->np->deadprops; *propp; propp = &(*propp)->next) {
564201c910bSPantelis Antoniou 			if (*propp == ce->prop) {
565201c910bSPantelis Antoniou 				*propp = ce->prop->next;
566201c910bSPantelis Antoniou 				ce->prop->next = NULL;
567201c910bSPantelis Antoniou 				break;
568201c910bSPantelis Antoniou 			}
569201c910bSPantelis Antoniou 		}
570201c910bSPantelis Antoniou 
571201c910bSPantelis Antoniou 		ret = __of_add_property(ce->np, ce->prop);
572201c910bSPantelis Antoniou 		if (ret) {
573606ad42aSRob Herring 			pr_err("changeset: add_property failed @%s/%s\n",
574606ad42aSRob Herring 				ce->np->full_name,
575201c910bSPantelis Antoniou 				ce->prop->name);
576201c910bSPantelis Antoniou 			break;
577201c910bSPantelis Antoniou 		}
578201c910bSPantelis Antoniou 		break;
579201c910bSPantelis Antoniou 	case OF_RECONFIG_REMOVE_PROPERTY:
580201c910bSPantelis Antoniou 		ret = __of_remove_property(ce->np, ce->prop);
581201c910bSPantelis Antoniou 		if (ret) {
582606ad42aSRob Herring 			pr_err("changeset: remove_property failed @%s/%s\n",
583606ad42aSRob Herring 				ce->np->full_name,
584201c910bSPantelis Antoniou 				ce->prop->name);
585201c910bSPantelis Antoniou 			break;
586201c910bSPantelis Antoniou 		}
587201c910bSPantelis Antoniou 		break;
588201c910bSPantelis Antoniou 
589201c910bSPantelis Antoniou 	case OF_RECONFIG_UPDATE_PROPERTY:
590201c910bSPantelis Antoniou 		/* If the property is in deadprops then it must be removed */
591201c910bSPantelis Antoniou 		for (propp = &ce->np->deadprops; *propp; propp = &(*propp)->next) {
592201c910bSPantelis Antoniou 			if (*propp == ce->prop) {
593201c910bSPantelis Antoniou 				*propp = ce->prop->next;
594201c910bSPantelis Antoniou 				ce->prop->next = NULL;
595201c910bSPantelis Antoniou 				break;
596201c910bSPantelis Antoniou 			}
597201c910bSPantelis Antoniou 		}
598201c910bSPantelis Antoniou 
599201c910bSPantelis Antoniou 		ret = __of_update_property(ce->np, ce->prop, &old_prop);
600201c910bSPantelis Antoniou 		if (ret) {
601606ad42aSRob Herring 			pr_err("changeset: update_property failed @%s/%s\n",
602606ad42aSRob Herring 				ce->np->full_name,
603201c910bSPantelis Antoniou 				ce->prop->name);
604201c910bSPantelis Antoniou 			break;
605201c910bSPantelis Antoniou 		}
606201c910bSPantelis Antoniou 		break;
607201c910bSPantelis Antoniou 	default:
608201c910bSPantelis Antoniou 		ret = -EINVAL;
609201c910bSPantelis Antoniou 	}
610201c910bSPantelis Antoniou 	raw_spin_unlock_irqrestore(&devtree_lock, flags);
611201c910bSPantelis Antoniou 
612201c910bSPantelis Antoniou 	if (ret)
613201c910bSPantelis Antoniou 		return ret;
614201c910bSPantelis Antoniou 
615201c910bSPantelis Antoniou 	switch (ce->action) {
616201c910bSPantelis Antoniou 	case OF_RECONFIG_ATTACH_NODE:
617201c910bSPantelis Antoniou 		__of_attach_node_sysfs(ce->np);
618201c910bSPantelis Antoniou 		break;
619201c910bSPantelis Antoniou 	case OF_RECONFIG_DETACH_NODE:
620201c910bSPantelis Antoniou 		__of_detach_node_sysfs(ce->np);
621201c910bSPantelis Antoniou 		break;
622201c910bSPantelis Antoniou 	case OF_RECONFIG_ADD_PROPERTY:
623201c910bSPantelis Antoniou 		/* ignore duplicate names */
624201c910bSPantelis Antoniou 		__of_add_property_sysfs(ce->np, ce->prop);
625201c910bSPantelis Antoniou 		break;
626201c910bSPantelis Antoniou 	case OF_RECONFIG_REMOVE_PROPERTY:
627201c910bSPantelis Antoniou 		__of_remove_property_sysfs(ce->np, ce->prop);
628201c910bSPantelis Antoniou 		break;
629201c910bSPantelis Antoniou 	case OF_RECONFIG_UPDATE_PROPERTY:
630201c910bSPantelis Antoniou 		__of_update_property_sysfs(ce->np, ce->prop, ce->old_prop);
631201c910bSPantelis Antoniou 		break;
632201c910bSPantelis Antoniou 	}
633201c910bSPantelis Antoniou 
634201c910bSPantelis Antoniou 	return 0;
635201c910bSPantelis Antoniou }
636201c910bSPantelis Antoniou 
637201c910bSPantelis Antoniou static inline int __of_changeset_entry_revert(struct of_changeset_entry *ce)
638201c910bSPantelis Antoniou {
639201c910bSPantelis Antoniou 	struct of_changeset_entry ce_inverted;
640201c910bSPantelis Antoniou 
641201c910bSPantelis Antoniou 	__of_changeset_entry_invert(ce, &ce_inverted);
642201c910bSPantelis Antoniou 	return __of_changeset_entry_apply(&ce_inverted);
643201c910bSPantelis Antoniou }
644201c910bSPantelis Antoniou 
645201c910bSPantelis Antoniou /**
646201c910bSPantelis Antoniou  * of_changeset_init - Initialize a changeset for use
647201c910bSPantelis Antoniou  *
648201c910bSPantelis Antoniou  * @ocs:	changeset pointer
649201c910bSPantelis Antoniou  *
650201c910bSPantelis Antoniou  * Initialize a changeset structure
651201c910bSPantelis Antoniou  */
652201c910bSPantelis Antoniou void of_changeset_init(struct of_changeset *ocs)
653201c910bSPantelis Antoniou {
654201c910bSPantelis Antoniou 	memset(ocs, 0, sizeof(*ocs));
655201c910bSPantelis Antoniou 	INIT_LIST_HEAD(&ocs->entries);
656201c910bSPantelis Antoniou }
65718322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_init);
658201c910bSPantelis Antoniou 
659201c910bSPantelis Antoniou /**
660201c910bSPantelis Antoniou  * of_changeset_destroy - Destroy a changeset
661201c910bSPantelis Antoniou  *
662201c910bSPantelis Antoniou  * @ocs:	changeset pointer
663201c910bSPantelis Antoniou  *
664201c910bSPantelis Antoniou  * Destroys a changeset. Note that if a changeset is applied,
665201c910bSPantelis Antoniou  * its changes to the tree cannot be reverted.
666201c910bSPantelis Antoniou  */
667201c910bSPantelis Antoniou void of_changeset_destroy(struct of_changeset *ocs)
668201c910bSPantelis Antoniou {
669201c910bSPantelis Antoniou 	struct of_changeset_entry *ce, *cen;
670201c910bSPantelis Antoniou 
671201c910bSPantelis Antoniou 	list_for_each_entry_safe_reverse(ce, cen, &ocs->entries, node)
672201c910bSPantelis Antoniou 		__of_changeset_entry_destroy(ce);
673201c910bSPantelis Antoniou }
67418322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_destroy);
675201c910bSPantelis Antoniou 
67618322377SGavin Shan int __of_changeset_apply(struct of_changeset *ocs)
677201c910bSPantelis Antoniou {
678201c910bSPantelis Antoniou 	struct of_changeset_entry *ce;
679201c910bSPantelis Antoniou 	int ret;
680201c910bSPantelis Antoniou 
681201c910bSPantelis Antoniou 	/* perform the rest of the work */
682606ad42aSRob Herring 	pr_debug("changeset: applying...\n");
683201c910bSPantelis Antoniou 	list_for_each_entry(ce, &ocs->entries, node) {
684201c910bSPantelis Antoniou 		ret = __of_changeset_entry_apply(ce);
685201c910bSPantelis Antoniou 		if (ret) {
686606ad42aSRob Herring 			pr_err("Error applying changeset (%d)\n", ret);
687201c910bSPantelis Antoniou 			list_for_each_entry_continue_reverse(ce, &ocs->entries, node)
688201c910bSPantelis Antoniou 				__of_changeset_entry_revert(ce);
689201c910bSPantelis Antoniou 			return ret;
690201c910bSPantelis Antoniou 		}
691201c910bSPantelis Antoniou 	}
692606ad42aSRob Herring 	pr_debug("changeset: applied, emitting notifiers.\n");
693201c910bSPantelis Antoniou 
694201c910bSPantelis Antoniou 	/* drop the global lock while emitting notifiers */
695201c910bSPantelis Antoniou 	mutex_unlock(&of_mutex);
696201c910bSPantelis Antoniou 	list_for_each_entry(ce, &ocs->entries, node)
697201c910bSPantelis Antoniou 		__of_changeset_entry_notify(ce, 0);
698201c910bSPantelis Antoniou 	mutex_lock(&of_mutex);
699606ad42aSRob Herring 	pr_debug("changeset: notifiers sent.\n");
700201c910bSPantelis Antoniou 
701201c910bSPantelis Antoniou 	return 0;
702201c910bSPantelis Antoniou }
703201c910bSPantelis Antoniou 
704201c910bSPantelis Antoniou /**
70518322377SGavin Shan  * of_changeset_apply - Applies a changeset
706201c910bSPantelis Antoniou  *
707201c910bSPantelis Antoniou  * @ocs:	changeset pointer
708201c910bSPantelis Antoniou  *
70918322377SGavin Shan  * Applies a changeset to the live tree.
71018322377SGavin Shan  * Any side-effects of live tree state changes are applied here on
71118322377SGavin Shan  * success, like creation/destruction of devices and side-effects
71218322377SGavin Shan  * like creation of sysfs properties and directories.
713201c910bSPantelis Antoniou  * Returns 0 on success, a negative error value in case of an error.
71418322377SGavin Shan  * On error the partially applied effects are reverted.
715201c910bSPantelis Antoniou  */
71618322377SGavin Shan int of_changeset_apply(struct of_changeset *ocs)
71718322377SGavin Shan {
71818322377SGavin Shan 	int ret;
71918322377SGavin Shan 
72018322377SGavin Shan 	mutex_lock(&of_mutex);
72118322377SGavin Shan 	ret = __of_changeset_apply(ocs);
72218322377SGavin Shan 	mutex_unlock(&of_mutex);
72318322377SGavin Shan 
72418322377SGavin Shan 	return ret;
72518322377SGavin Shan }
72618322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_apply);
72718322377SGavin Shan 
72818322377SGavin Shan int __of_changeset_revert(struct of_changeset *ocs)
729201c910bSPantelis Antoniou {
730201c910bSPantelis Antoniou 	struct of_changeset_entry *ce;
731201c910bSPantelis Antoniou 	int ret;
732201c910bSPantelis Antoniou 
733606ad42aSRob Herring 	pr_debug("changeset: reverting...\n");
734201c910bSPantelis Antoniou 	list_for_each_entry_reverse(ce, &ocs->entries, node) {
735201c910bSPantelis Antoniou 		ret = __of_changeset_entry_revert(ce);
736201c910bSPantelis Antoniou 		if (ret) {
737606ad42aSRob Herring 			pr_err("Error reverting changeset (%d)\n", ret);
738201c910bSPantelis Antoniou 			list_for_each_entry_continue(ce, &ocs->entries, node)
739201c910bSPantelis Antoniou 				__of_changeset_entry_apply(ce);
740201c910bSPantelis Antoniou 			return ret;
741201c910bSPantelis Antoniou 		}
742201c910bSPantelis Antoniou 	}
743606ad42aSRob Herring 	pr_debug("changeset: reverted, emitting notifiers.\n");
744201c910bSPantelis Antoniou 
745201c910bSPantelis Antoniou 	/* drop the global lock while emitting notifiers */
746201c910bSPantelis Antoniou 	mutex_unlock(&of_mutex);
747201c910bSPantelis Antoniou 	list_for_each_entry_reverse(ce, &ocs->entries, node)
748201c910bSPantelis Antoniou 		__of_changeset_entry_notify(ce, 1);
749201c910bSPantelis Antoniou 	mutex_lock(&of_mutex);
750606ad42aSRob Herring 	pr_debug("changeset: notifiers sent.\n");
751201c910bSPantelis Antoniou 
752201c910bSPantelis Antoniou 	return 0;
753201c910bSPantelis Antoniou }
754201c910bSPantelis Antoniou 
755201c910bSPantelis Antoniou /**
75618322377SGavin Shan  * of_changeset_revert - Reverts an applied changeset
75718322377SGavin Shan  *
75818322377SGavin Shan  * @ocs:	changeset pointer
75918322377SGavin Shan  *
76018322377SGavin Shan  * Reverts a changeset returning the state of the tree to what it
76118322377SGavin Shan  * was before the application.
76218322377SGavin Shan  * Any side-effects like creation/destruction of devices and
76318322377SGavin Shan  * removal of sysfs properties and directories are applied.
76418322377SGavin Shan  * Returns 0 on success, a negative error value in case of an error.
76518322377SGavin Shan  */
76618322377SGavin Shan int of_changeset_revert(struct of_changeset *ocs)
76718322377SGavin Shan {
76818322377SGavin Shan 	int ret;
76918322377SGavin Shan 
77018322377SGavin Shan 	mutex_lock(&of_mutex);
77118322377SGavin Shan 	ret = __of_changeset_revert(ocs);
77218322377SGavin Shan 	mutex_unlock(&of_mutex);
77318322377SGavin Shan 
77418322377SGavin Shan 	return ret;
77518322377SGavin Shan }
77618322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_revert);
77718322377SGavin Shan 
77818322377SGavin Shan /**
779201c910bSPantelis Antoniou  * of_changeset_action - Perform a changeset action
780201c910bSPantelis Antoniou  *
781201c910bSPantelis Antoniou  * @ocs:	changeset pointer
782201c910bSPantelis Antoniou  * @action:	action to perform
783201c910bSPantelis Antoniou  * @np:		Pointer to device node
784201c910bSPantelis Antoniou  * @prop:	Pointer to property
785201c910bSPantelis Antoniou  *
786201c910bSPantelis Antoniou  * On action being one of:
787201c910bSPantelis Antoniou  * + OF_RECONFIG_ATTACH_NODE
788201c910bSPantelis Antoniou  * + OF_RECONFIG_DETACH_NODE,
789201c910bSPantelis Antoniou  * + OF_RECONFIG_ADD_PROPERTY
790201c910bSPantelis Antoniou  * + OF_RECONFIG_REMOVE_PROPERTY,
791201c910bSPantelis Antoniou  * + OF_RECONFIG_UPDATE_PROPERTY
792201c910bSPantelis Antoniou  * Returns 0 on success, a negative error value in case of an error.
793201c910bSPantelis Antoniou  */
794201c910bSPantelis Antoniou int of_changeset_action(struct of_changeset *ocs, unsigned long action,
795201c910bSPantelis Antoniou 		struct device_node *np, struct property *prop)
796201c910bSPantelis Antoniou {
797201c910bSPantelis Antoniou 	struct of_changeset_entry *ce;
798201c910bSPantelis Antoniou 
799201c910bSPantelis Antoniou 	ce = kzalloc(sizeof(*ce), GFP_KERNEL);
800606ad42aSRob Herring 	if (!ce)
801201c910bSPantelis Antoniou 		return -ENOMEM;
802606ad42aSRob Herring 
803201c910bSPantelis Antoniou 	/* get a reference to the node */
804201c910bSPantelis Antoniou 	ce->action = action;
805201c910bSPantelis Antoniou 	ce->np = of_node_get(np);
806201c910bSPantelis Antoniou 	ce->prop = prop;
807201c910bSPantelis Antoniou 
808201c910bSPantelis Antoniou 	if (action == OF_RECONFIG_UPDATE_PROPERTY && prop)
809201c910bSPantelis Antoniou 		ce->old_prop = of_find_property(np, prop->name, NULL);
810201c910bSPantelis Antoniou 
811201c910bSPantelis Antoniou 	/* add it to the list */
812201c910bSPantelis Antoniou 	list_add_tail(&ce->node, &ocs->entries);
813201c910bSPantelis Antoniou 	return 0;
814201c910bSPantelis Antoniou }
81518322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_action);
816