1af6074fcSRob Herring // SPDX-License-Identifier: GPL-2.0 26afc0dc3SGrant Likely /* 36afc0dc3SGrant Likely * Support for dynamic device trees. 46afc0dc3SGrant Likely * 56afc0dc3SGrant Likely * On some platforms, the device tree can be manipulated at runtime. 66afc0dc3SGrant Likely * The routines in this section support adding, removing and changing 76afc0dc3SGrant Likely * device tree nodes. 86afc0dc3SGrant Likely */ 96afc0dc3SGrant Likely 10606ad42aSRob Herring #define pr_fmt(fmt) "OF: " fmt 11606ad42aSRob Herring 126afc0dc3SGrant Likely #include <linux/of.h> 136afc0dc3SGrant Likely #include <linux/spinlock.h> 146afc0dc3SGrant Likely #include <linux/slab.h> 156afc0dc3SGrant Likely #include <linux/string.h> 166afc0dc3SGrant Likely #include <linux/proc_fs.h> 176afc0dc3SGrant Likely 186afc0dc3SGrant Likely #include "of_private.h" 196afc0dc3SGrant Likely 204c2bb574SRob Herring static struct device_node *kobj_to_device_node(struct kobject *kobj) 214c2bb574SRob Herring { 224c2bb574SRob Herring return container_of(kobj, struct device_node, kobj); 234c2bb574SRob Herring } 244c2bb574SRob Herring 256afc0dc3SGrant Likely /** 266afc0dc3SGrant Likely * of_node_get() - Increment refcount of a node 276afc0dc3SGrant Likely * @node: Node to inc refcount, NULL is supported to simplify writing of 286afc0dc3SGrant Likely * callers 296afc0dc3SGrant Likely * 308c8239c2SRob Herring * Return: The node with refcount incremented. 316afc0dc3SGrant Likely */ 326afc0dc3SGrant Likely struct device_node *of_node_get(struct device_node *node) 336afc0dc3SGrant Likely { 346afc0dc3SGrant Likely if (node) 356afc0dc3SGrant Likely kobject_get(&node->kobj); 366afc0dc3SGrant Likely return node; 376afc0dc3SGrant Likely } 386afc0dc3SGrant Likely EXPORT_SYMBOL(of_node_get); 396afc0dc3SGrant Likely 406afc0dc3SGrant Likely /** 416afc0dc3SGrant Likely * of_node_put() - Decrement refcount of a node 426afc0dc3SGrant Likely * @node: Node to dec refcount, NULL is supported to simplify writing of 436afc0dc3SGrant Likely * callers 446afc0dc3SGrant Likely */ 456afc0dc3SGrant Likely void of_node_put(struct device_node *node) 466afc0dc3SGrant Likely { 476afc0dc3SGrant Likely if (node) 486afc0dc3SGrant Likely kobject_put(&node->kobj); 496afc0dc3SGrant Likely } 506afc0dc3SGrant Likely EXPORT_SYMBOL(of_node_put); 516afc0dc3SGrant Likely 526afc0dc3SGrant Likely static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); 536afc0dc3SGrant Likely 546afc0dc3SGrant Likely int of_reconfig_notifier_register(struct notifier_block *nb) 556afc0dc3SGrant Likely { 566afc0dc3SGrant Likely return blocking_notifier_chain_register(&of_reconfig_chain, nb); 576afc0dc3SGrant Likely } 586afc0dc3SGrant Likely EXPORT_SYMBOL_GPL(of_reconfig_notifier_register); 596afc0dc3SGrant Likely 606afc0dc3SGrant Likely int of_reconfig_notifier_unregister(struct notifier_block *nb) 616afc0dc3SGrant Likely { 626afc0dc3SGrant Likely return blocking_notifier_chain_unregister(&of_reconfig_chain, nb); 636afc0dc3SGrant Likely } 646afc0dc3SGrant Likely EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister); 656afc0dc3SGrant Likely 6600aa3720SGrant Likely #ifdef DEBUG 6700aa3720SGrant Likely const char *action_names[] = { 6800aa3720SGrant Likely [OF_RECONFIG_ATTACH_NODE] = "ATTACH_NODE", 6900aa3720SGrant Likely [OF_RECONFIG_DETACH_NODE] = "DETACH_NODE", 7000aa3720SGrant Likely [OF_RECONFIG_ADD_PROPERTY] = "ADD_PROPERTY", 7100aa3720SGrant Likely [OF_RECONFIG_REMOVE_PROPERTY] = "REMOVE_PROPERTY", 7200aa3720SGrant Likely [OF_RECONFIG_UPDATE_PROPERTY] = "UPDATE_PROPERTY", 7300aa3720SGrant Likely }; 7400aa3720SGrant Likely #endif 7500aa3720SGrant Likely 76f5242e5aSGrant Likely int of_reconfig_notify(unsigned long action, struct of_reconfig_data *p) 776afc0dc3SGrant Likely { 786afc0dc3SGrant Likely int rc; 7900aa3720SGrant Likely #ifdef DEBUG 80f5242e5aSGrant Likely struct of_reconfig_data *pr = p; 816afc0dc3SGrant Likely 8200aa3720SGrant Likely switch (action) { 8300aa3720SGrant Likely case OF_RECONFIG_ATTACH_NODE: 8400aa3720SGrant Likely case OF_RECONFIG_DETACH_NODE: 850d638a07SRob Herring pr_debug("notify %-15s %pOF\n", action_names[action], 860d638a07SRob Herring pr->dn); 8700aa3720SGrant Likely break; 8800aa3720SGrant Likely case OF_RECONFIG_ADD_PROPERTY: 8900aa3720SGrant Likely case OF_RECONFIG_REMOVE_PROPERTY: 9000aa3720SGrant Likely case OF_RECONFIG_UPDATE_PROPERTY: 910d638a07SRob Herring pr_debug("notify %-15s %pOF:%s\n", action_names[action], 920d638a07SRob Herring pr->dn, pr->prop->name); 9300aa3720SGrant Likely break; 9400aa3720SGrant Likely 9500aa3720SGrant Likely } 9600aa3720SGrant Likely #endif 976afc0dc3SGrant Likely rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); 986afc0dc3SGrant Likely return notifier_to_errno(rc); 996afc0dc3SGrant Likely } 1006afc0dc3SGrant Likely 101b53a2340SPantelis Antoniou /* 102b53a2340SPantelis Antoniou * of_reconfig_get_state_change() - Returns new state of device 103b53a2340SPantelis Antoniou * @action - action of the of notifier 104b53a2340SPantelis Antoniou * @arg - argument of the of notifier 105b53a2340SPantelis Antoniou * 106b53a2340SPantelis Antoniou * Returns the new state of a device based on the notifier used. 1078c8239c2SRob Herring * 1088c8239c2SRob Herring * Return: 0 on device going from enabled to disabled, 1 on device 109b53a2340SPantelis Antoniou * going from disabled to enabled and -1 on no change. 110b53a2340SPantelis Antoniou */ 111f5242e5aSGrant Likely int of_reconfig_get_state_change(unsigned long action, struct of_reconfig_data *pr) 112b53a2340SPantelis Antoniou { 113f5242e5aSGrant Likely struct property *prop, *old_prop = NULL; 114b53a2340SPantelis Antoniou int is_status, status_state, old_status_state, prev_state, new_state; 115b53a2340SPantelis Antoniou 116b53a2340SPantelis Antoniou /* figure out if a device should be created or destroyed */ 117b53a2340SPantelis Antoniou switch (action) { 118b53a2340SPantelis Antoniou case OF_RECONFIG_ATTACH_NODE: 119b53a2340SPantelis Antoniou case OF_RECONFIG_DETACH_NODE: 120f5242e5aSGrant Likely prop = of_find_property(pr->dn, "status", NULL); 121b53a2340SPantelis Antoniou break; 122b53a2340SPantelis Antoniou case OF_RECONFIG_ADD_PROPERTY: 123b53a2340SPantelis Antoniou case OF_RECONFIG_REMOVE_PROPERTY: 124b53a2340SPantelis Antoniou prop = pr->prop; 125b53a2340SPantelis Antoniou break; 126b53a2340SPantelis Antoniou case OF_RECONFIG_UPDATE_PROPERTY: 127b53a2340SPantelis Antoniou prop = pr->prop; 128b53a2340SPantelis Antoniou old_prop = pr->old_prop; 129b53a2340SPantelis Antoniou break; 130b53a2340SPantelis Antoniou default: 131b53a2340SPantelis Antoniou return OF_RECONFIG_NO_CHANGE; 132b53a2340SPantelis Antoniou } 133b53a2340SPantelis Antoniou 134b53a2340SPantelis Antoniou is_status = 0; 135b53a2340SPantelis Antoniou status_state = -1; 136b53a2340SPantelis Antoniou old_status_state = -1; 137b53a2340SPantelis Antoniou prev_state = -1; 138b53a2340SPantelis Antoniou new_state = -1; 139b53a2340SPantelis Antoniou 140b53a2340SPantelis Antoniou if (prop && !strcmp(prop->name, "status")) { 141b53a2340SPantelis Antoniou is_status = 1; 142b53a2340SPantelis Antoniou status_state = !strcmp(prop->value, "okay") || 143b53a2340SPantelis Antoniou !strcmp(prop->value, "ok"); 144b53a2340SPantelis Antoniou if (old_prop) 145b53a2340SPantelis Antoniou old_status_state = !strcmp(old_prop->value, "okay") || 146b53a2340SPantelis Antoniou !strcmp(old_prop->value, "ok"); 147b53a2340SPantelis Antoniou } 148b53a2340SPantelis Antoniou 149b53a2340SPantelis Antoniou switch (action) { 150b53a2340SPantelis Antoniou case OF_RECONFIG_ATTACH_NODE: 151b53a2340SPantelis Antoniou prev_state = 0; 152b53a2340SPantelis Antoniou /* -1 & 0 status either missing or okay */ 153b53a2340SPantelis Antoniou new_state = status_state != 0; 154b53a2340SPantelis Antoniou break; 155b53a2340SPantelis Antoniou case OF_RECONFIG_DETACH_NODE: 156b53a2340SPantelis Antoniou /* -1 & 0 status either missing or okay */ 157b53a2340SPantelis Antoniou prev_state = status_state != 0; 158b53a2340SPantelis Antoniou new_state = 0; 159b53a2340SPantelis Antoniou break; 160b53a2340SPantelis Antoniou case OF_RECONFIG_ADD_PROPERTY: 161b53a2340SPantelis Antoniou if (is_status) { 162b53a2340SPantelis Antoniou /* no status property -> enabled (legacy) */ 163b53a2340SPantelis Antoniou prev_state = 1; 164b53a2340SPantelis Antoniou new_state = status_state; 165b53a2340SPantelis Antoniou } 166b53a2340SPantelis Antoniou break; 167b53a2340SPantelis Antoniou case OF_RECONFIG_REMOVE_PROPERTY: 168b53a2340SPantelis Antoniou if (is_status) { 169b53a2340SPantelis Antoniou prev_state = status_state; 170b53a2340SPantelis Antoniou /* no status property -> enabled (legacy) */ 171b53a2340SPantelis Antoniou new_state = 1; 172b53a2340SPantelis Antoniou } 173b53a2340SPantelis Antoniou break; 174b53a2340SPantelis Antoniou case OF_RECONFIG_UPDATE_PROPERTY: 175b53a2340SPantelis Antoniou if (is_status) { 176b53a2340SPantelis Antoniou prev_state = old_status_state != 0; 177b53a2340SPantelis Antoniou new_state = status_state != 0; 178b53a2340SPantelis Antoniou } 179b53a2340SPantelis Antoniou break; 180b53a2340SPantelis Antoniou } 181b53a2340SPantelis Antoniou 182b53a2340SPantelis Antoniou if (prev_state == new_state) 183b53a2340SPantelis Antoniou return OF_RECONFIG_NO_CHANGE; 184b53a2340SPantelis Antoniou 185b53a2340SPantelis Antoniou return new_state ? OF_RECONFIG_CHANGE_ADD : OF_RECONFIG_CHANGE_REMOVE; 186b53a2340SPantelis Antoniou } 187b53a2340SPantelis Antoniou EXPORT_SYMBOL_GPL(of_reconfig_get_state_change); 188b53a2340SPantelis Antoniou 1896afc0dc3SGrant Likely int of_property_notify(int action, struct device_node *np, 190259092a3SGrant Likely struct property *prop, struct property *oldprop) 1916afc0dc3SGrant Likely { 192f5242e5aSGrant Likely struct of_reconfig_data pr; 1936afc0dc3SGrant Likely 1946afc0dc3SGrant Likely /* only call notifiers if the node is attached */ 1956afc0dc3SGrant Likely if (!of_node_is_attached(np)) 1966afc0dc3SGrant Likely return 0; 1976afc0dc3SGrant Likely 1986afc0dc3SGrant Likely pr.dn = np; 1996afc0dc3SGrant Likely pr.prop = prop; 200259092a3SGrant Likely pr.old_prop = oldprop; 2016afc0dc3SGrant Likely return of_reconfig_notify(action, &pr); 2026afc0dc3SGrant Likely } 2036afc0dc3SGrant Likely 20424996951SFrank Rowand static void __of_attach_node(struct device_node *np) 205d8c50088SPantelis Antoniou { 206a25095d4SGrant Likely const __be32 *phandle; 207a25095d4SGrant Likely int sz; 208a25095d4SGrant Likely 209f9627881SFrank Rowand if (!of_node_check_flag(np, OF_OVERLAY)) { 210f9627881SFrank Rowand np->name = __of_get_property(np, "name", NULL); 211f9627881SFrank Rowand if (!np->name) 212f9627881SFrank Rowand np->name = "<NULL>"; 213a25095d4SGrant Likely 214a25095d4SGrant Likely phandle = __of_get_property(np, "phandle", &sz); 215a25095d4SGrant Likely if (!phandle) 216a25095d4SGrant Likely phandle = __of_get_property(np, "linux,phandle", &sz); 217f76502aaSGeert Uytterhoeven if (IS_ENABLED(CONFIG_PPC_PSERIES) && !phandle) 218a25095d4SGrant Likely phandle = __of_get_property(np, "ibm,phandle", &sz); 219f9627881SFrank Rowand if (phandle && (sz >= 4)) 220f9627881SFrank Rowand np->phandle = be32_to_cpup(phandle); 221f9627881SFrank Rowand else 222f9627881SFrank Rowand np->phandle = 0; 223f9627881SFrank Rowand } 224a25095d4SGrant Likely 2256162dbe4SGrant Likely np->child = NULL; 226d8c50088SPantelis Antoniou np->sibling = np->parent->child; 227d8c50088SPantelis Antoniou np->parent->child = np; 228d8c50088SPantelis Antoniou of_node_clear_flag(np, OF_DETACHED); 229d8c50088SPantelis Antoniou } 230d8c50088SPantelis Antoniou 2316afc0dc3SGrant Likely /** 2326afc0dc3SGrant Likely * of_attach_node() - Plug a device node into the tree and global list. 2333cb025d9SLee Jones * @np: Pointer to the caller's Device Node 2346afc0dc3SGrant Likely */ 2356afc0dc3SGrant Likely int of_attach_node(struct device_node *np) 2366afc0dc3SGrant Likely { 237f5242e5aSGrant Likely struct of_reconfig_data rd; 2386afc0dc3SGrant Likely unsigned long flags; 2396afc0dc3SGrant Likely 240f5242e5aSGrant Likely memset(&rd, 0, sizeof(rd)); 241f5242e5aSGrant Likely rd.dn = np; 242f5242e5aSGrant Likely 2438a2b22a2SGrant Likely mutex_lock(&of_mutex); 2446afc0dc3SGrant Likely raw_spin_lock_irqsave(&devtree_lock, flags); 245d8c50088SPantelis Antoniou __of_attach_node(np); 2466afc0dc3SGrant Likely raw_spin_unlock_irqrestore(&devtree_lock, flags); 2476afc0dc3SGrant Likely 2488a2b22a2SGrant Likely __of_attach_node_sysfs(np); 2498a2b22a2SGrant Likely mutex_unlock(&of_mutex); 250259092a3SGrant Likely 251f5242e5aSGrant Likely of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, &rd); 252259092a3SGrant Likely 2536afc0dc3SGrant Likely return 0; 2546afc0dc3SGrant Likely } 2556afc0dc3SGrant Likely 256d8c50088SPantelis Antoniou void __of_detach_node(struct device_node *np) 2576afc0dc3SGrant Likely { 2586afc0dc3SGrant Likely struct device_node *parent; 2596afc0dc3SGrant Likely 260d8c50088SPantelis Antoniou if (WARN_ON(of_node_check_flag(np, OF_DETACHED))) 261d8c50088SPantelis Antoniou return; 2626afc0dc3SGrant Likely 2636afc0dc3SGrant Likely parent = np->parent; 264d8c50088SPantelis Antoniou if (WARN_ON(!parent)) 265d8c50088SPantelis Antoniou return; 2666afc0dc3SGrant Likely 2676afc0dc3SGrant Likely if (parent->child == np) 2686afc0dc3SGrant Likely parent->child = np->sibling; 2696afc0dc3SGrant Likely else { 2706afc0dc3SGrant Likely struct device_node *prevsib; 2716afc0dc3SGrant Likely for (prevsib = np->parent->child; 2726afc0dc3SGrant Likely prevsib->sibling != np; 2736afc0dc3SGrant Likely prevsib = prevsib->sibling) 2746afc0dc3SGrant Likely ; 2756afc0dc3SGrant Likely prevsib->sibling = np->sibling; 2766afc0dc3SGrant Likely } 2776afc0dc3SGrant Likely 2786afc0dc3SGrant Likely of_node_set_flag(np, OF_DETACHED); 2795801169aSFrank Rowand 2805801169aSFrank Rowand /* race with of_find_node_by_phandle() prevented by devtree_lock */ 28190dc0d1cSRob Herring __of_phandle_cache_inv_entry(np->phandle); 282d8c50088SPantelis Antoniou } 283d8c50088SPantelis Antoniou 284d8c50088SPantelis Antoniou /** 285d8c50088SPantelis Antoniou * of_detach_node() - "Unplug" a node from the device tree. 2863cb025d9SLee Jones * @np: Pointer to the caller's Device Node 287d8c50088SPantelis Antoniou */ 288d8c50088SPantelis Antoniou int of_detach_node(struct device_node *np) 289d8c50088SPantelis Antoniou { 290f5242e5aSGrant Likely struct of_reconfig_data rd; 291d8c50088SPantelis Antoniou unsigned long flags; 292d8c50088SPantelis Antoniou 293f5242e5aSGrant Likely memset(&rd, 0, sizeof(rd)); 294f5242e5aSGrant Likely rd.dn = np; 295f5242e5aSGrant Likely 2968a2b22a2SGrant Likely mutex_lock(&of_mutex); 297d8c50088SPantelis Antoniou raw_spin_lock_irqsave(&devtree_lock, flags); 298d8c50088SPantelis Antoniou __of_detach_node(np); 2996afc0dc3SGrant Likely raw_spin_unlock_irqrestore(&devtree_lock, flags); 3006afc0dc3SGrant Likely 3018a2b22a2SGrant Likely __of_detach_node_sysfs(np); 3028a2b22a2SGrant Likely mutex_unlock(&of_mutex); 303259092a3SGrant Likely 304f5242e5aSGrant Likely of_reconfig_notify(OF_RECONFIG_DETACH_NODE, &rd); 305259092a3SGrant Likely 30658fb82ccSDing Xiang return 0; 3076afc0dc3SGrant Likely } 308bb91f923SGavin Shan EXPORT_SYMBOL_GPL(of_detach_node); 3096afc0dc3SGrant Likely 310070ea018SLixin Wang static void property_list_free(struct property *prop_list) 311070ea018SLixin Wang { 312070ea018SLixin Wang struct property *prop, *next; 313070ea018SLixin Wang 314070ea018SLixin Wang for (prop = prop_list; prop != NULL; prop = next) { 315070ea018SLixin Wang next = prop->next; 316070ea018SLixin Wang kfree(prop->name); 317070ea018SLixin Wang kfree(prop->value); 318070ea018SLixin Wang kfree(prop); 319070ea018SLixin Wang } 320070ea018SLixin Wang } 321070ea018SLixin Wang 3226afc0dc3SGrant Likely /** 3236afc0dc3SGrant Likely * of_node_release() - release a dynamically allocated node 3243cb025d9SLee Jones * @kobj: kernel object of the node to be released 3256afc0dc3SGrant Likely * 3266afc0dc3SGrant Likely * In of_node_put() this function is passed to kref_put() as the destructor. 3276afc0dc3SGrant Likely */ 3286afc0dc3SGrant Likely void of_node_release(struct kobject *kobj) 3296afc0dc3SGrant Likely { 3306afc0dc3SGrant Likely struct device_node *node = kobj_to_device_node(kobj); 3316afc0dc3SGrant Likely 3326afc0dc3SGrant Likely /* We should never be releasing nodes that haven't been detached. */ 3336afc0dc3SGrant Likely if (!of_node_check_flag(node, OF_DETACHED)) { 3340d638a07SRob Herring pr_err("ERROR: Bad of_node_put() on %pOF\n", node); 335*74df14cdSFrank Rowand 336*74df14cdSFrank Rowand /* 337*74df14cdSFrank Rowand * of unittests will test this path. Do not print the stack 338*74df14cdSFrank Rowand * trace when the error is caused by unittest so that we do 339*74df14cdSFrank Rowand * not display what a normal developer might reasonably 340*74df14cdSFrank Rowand * consider a real bug. 341*74df14cdSFrank Rowand */ 342*74df14cdSFrank Rowand if (!IS_ENABLED(CONFIG_OF_UNITTEST) || 343*74df14cdSFrank Rowand strcmp(node->parent->full_name, "testcase-data")) { 3446afc0dc3SGrant Likely dump_stack(); 345*74df14cdSFrank Rowand pr_err("ERROR: next of_node_put() on this node will result in a kboject warning 'refcount_t: underflow; use-after-free.'\n"); 346*74df14cdSFrank Rowand } 347*74df14cdSFrank Rowand 3486afc0dc3SGrant Likely return; 3496afc0dc3SGrant Likely } 3506afc0dc3SGrant Likely if (!of_node_check_flag(node, OF_DYNAMIC)) 3516afc0dc3SGrant Likely return; 3526afc0dc3SGrant Likely 353144552c7SFrank Rowand if (of_node_check_flag(node, OF_OVERLAY)) { 354144552c7SFrank Rowand 355144552c7SFrank Rowand if (!of_node_check_flag(node, OF_OVERLAY_FREE_CSET)) { 356144552c7SFrank Rowand /* premature refcount of zero, do not free memory */ 357144552c7SFrank Rowand pr_err("ERROR: memory leak before free overlay changeset, %pOF\n", 358144552c7SFrank Rowand node); 359144552c7SFrank Rowand return; 360144552c7SFrank Rowand } 361144552c7SFrank Rowand 362144552c7SFrank Rowand /* 363144552c7SFrank Rowand * If node->properties non-empty then properties were added 364144552c7SFrank Rowand * to this node either by different overlay that has not 365144552c7SFrank Rowand * yet been removed, or by a non-overlay mechanism. 366144552c7SFrank Rowand */ 367144552c7SFrank Rowand if (node->properties) 368144552c7SFrank Rowand pr_err("ERROR: %s(), unexpected properties in %pOF\n", 369144552c7SFrank Rowand __func__, node); 370144552c7SFrank Rowand } 371144552c7SFrank Rowand 372070ea018SLixin Wang property_list_free(node->properties); 373070ea018SLixin Wang property_list_free(node->deadprops); 3747b337cb3SSaravana Kannan fwnode_links_purge(of_fwnode_handle(node)); 3756afc0dc3SGrant Likely 3766afc0dc3SGrant Likely kfree(node->full_name); 3776afc0dc3SGrant Likely kfree(node->data); 3786afc0dc3SGrant Likely kfree(node); 3796afc0dc3SGrant Likely } 38069843396SPantelis Antoniou 38169843396SPantelis Antoniou /** 38269843396SPantelis Antoniou * __of_prop_dup - Copy a property dynamically. 38369843396SPantelis Antoniou * @prop: Property to copy 38469843396SPantelis Antoniou * @allocflags: Allocation flags (typically pass GFP_KERNEL) 38569843396SPantelis Antoniou * 38669843396SPantelis Antoniou * Copy a property by dynamically allocating the memory of both the 38727b3383aSGeert Uytterhoeven * property structure and the property name & contents. The property's 38869843396SPantelis Antoniou * flags have the OF_DYNAMIC bit set so that we can differentiate between 38969843396SPantelis Antoniou * dynamically allocated properties and not. 3908c8239c2SRob Herring * 3918c8239c2SRob Herring * Return: The newly allocated property or NULL on out of memory error. 39269843396SPantelis Antoniou */ 39369843396SPantelis Antoniou struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags) 39469843396SPantelis Antoniou { 39569843396SPantelis Antoniou struct property *new; 39669843396SPantelis Antoniou 39769843396SPantelis Antoniou new = kzalloc(sizeof(*new), allocflags); 39869843396SPantelis Antoniou if (!new) 39969843396SPantelis Antoniou return NULL; 40069843396SPantelis Antoniou 40169843396SPantelis Antoniou /* 40269843396SPantelis Antoniou * NOTE: There is no check for zero length value. 403b6ae5dc5SGrant Likely * In case of a boolean property, this will allocate a value 40469843396SPantelis Antoniou * of zero bytes. We do this to work around the use 40569843396SPantelis Antoniou * of of_get_property() calls on boolean values. 40669843396SPantelis Antoniou */ 40769843396SPantelis Antoniou new->name = kstrdup(prop->name, allocflags); 40869843396SPantelis Antoniou new->value = kmemdup(prop->value, prop->length, allocflags); 40969843396SPantelis Antoniou new->length = prop->length; 41069843396SPantelis Antoniou if (!new->name || !new->value) 41169843396SPantelis Antoniou goto err_free; 41269843396SPantelis Antoniou 41369843396SPantelis Antoniou /* mark the property as dynamic */ 41469843396SPantelis Antoniou of_property_set_flag(new, OF_DYNAMIC); 41569843396SPantelis Antoniou 41669843396SPantelis Antoniou return new; 41769843396SPantelis Antoniou 41869843396SPantelis Antoniou err_free: 41969843396SPantelis Antoniou kfree(new->name); 42069843396SPantelis Antoniou kfree(new->value); 42169843396SPantelis Antoniou kfree(new); 42269843396SPantelis Antoniou return NULL; 42369843396SPantelis Antoniou } 42469843396SPantelis Antoniou 42569843396SPantelis Antoniou /** 426e5179581SGrant Likely * __of_node_dup() - Duplicate or create an empty device node dynamically. 427b89dae18SFrank Rowand * @np: if not NULL, contains properties to be duplicated in new node 428b89dae18SFrank Rowand * @full_name: string value to be duplicated into new node's full_name field 42969843396SPantelis Antoniou * 430b89dae18SFrank Rowand * Create a device tree node, optionally duplicating the properties of 431b89dae18SFrank Rowand * another node. The node data are dynamically allocated and all the node 432b89dae18SFrank Rowand * flags have the OF_DYNAMIC & OF_DETACHED bits set. 433b89dae18SFrank Rowand * 4348c8239c2SRob Herring * Return: The newly allocated node or NULL on out of memory error. 43569843396SPantelis Antoniou */ 436b89dae18SFrank Rowand struct device_node *__of_node_dup(const struct device_node *np, 437b89dae18SFrank Rowand const char *full_name) 43869843396SPantelis Antoniou { 43969843396SPantelis Antoniou struct device_node *node; 44069843396SPantelis Antoniou 441ef8bbd73SGrant Likely node = kzalloc(sizeof(*node), GFP_KERNEL); 44269843396SPantelis Antoniou if (!node) 44369843396SPantelis Antoniou return NULL; 444b89dae18SFrank Rowand node->full_name = kstrdup(full_name, GFP_KERNEL); 445e5179581SGrant Likely if (!node->full_name) { 446e5179581SGrant Likely kfree(node); 447e5179581SGrant Likely return NULL; 448e5179581SGrant Likely } 44969843396SPantelis Antoniou 450ef8bbd73SGrant Likely of_node_set_flag(node, OF_DYNAMIC); 451ef8bbd73SGrant Likely of_node_set_flag(node, OF_DETACHED); 45269843396SPantelis Antoniou of_node_init(node); 45369843396SPantelis Antoniou 454e5179581SGrant Likely /* Iterate over and duplicate all properties */ 455e5179581SGrant Likely if (np) { 456e5179581SGrant Likely struct property *pp, *new_pp; 457e5179581SGrant Likely for_each_property_of_node(np, pp) { 458e5179581SGrant Likely new_pp = __of_prop_dup(pp, GFP_KERNEL); 459e5179581SGrant Likely if (!new_pp) 460e5179581SGrant Likely goto err_prop; 461e5179581SGrant Likely if (__of_add_property(node, new_pp)) { 462e5179581SGrant Likely kfree(new_pp->name); 463e5179581SGrant Likely kfree(new_pp->value); 464e5179581SGrant Likely kfree(new_pp); 465e5179581SGrant Likely goto err_prop; 466e5179581SGrant Likely } 467e5179581SGrant Likely } 468e5179581SGrant Likely } 46969843396SPantelis Antoniou return node; 47069843396SPantelis Antoniou 471e5179581SGrant Likely err_prop: 472e5179581SGrant Likely of_node_put(node); /* Frees the node and properties */ 47369843396SPantelis Antoniou return NULL; 47469843396SPantelis Antoniou } 475201c910bSPantelis Antoniou 476201c910bSPantelis Antoniou static void __of_changeset_entry_destroy(struct of_changeset_entry *ce) 477201c910bSPantelis Antoniou { 478144552c7SFrank Rowand if (ce->action == OF_RECONFIG_ATTACH_NODE && 479144552c7SFrank Rowand of_node_check_flag(ce->np, OF_OVERLAY)) { 480144552c7SFrank Rowand if (kref_read(&ce->np->kobj.kref) > 1) { 481144552c7SFrank Rowand pr_err("ERROR: memory leak, expected refcount 1 instead of %d, of_node_get()/of_node_put() unbalanced - destroy cset entry: attach overlay node %pOF\n", 482144552c7SFrank Rowand kref_read(&ce->np->kobj.kref), ce->np); 483144552c7SFrank Rowand } else { 484144552c7SFrank Rowand of_node_set_flag(ce->np, OF_OVERLAY_FREE_CSET); 485144552c7SFrank Rowand } 486144552c7SFrank Rowand } 487144552c7SFrank Rowand 488201c910bSPantelis Antoniou of_node_put(ce->np); 489201c910bSPantelis Antoniou list_del(&ce->node); 490201c910bSPantelis Antoniou kfree(ce); 491201c910bSPantelis Antoniou } 492201c910bSPantelis Antoniou 493201c910bSPantelis Antoniou #ifdef DEBUG 494201c910bSPantelis Antoniou static void __of_changeset_entry_dump(struct of_changeset_entry *ce) 495201c910bSPantelis Antoniou { 496201c910bSPantelis Antoniou switch (ce->action) { 497201c910bSPantelis Antoniou case OF_RECONFIG_ADD_PROPERTY: 498201c910bSPantelis Antoniou case OF_RECONFIG_REMOVE_PROPERTY: 499201c910bSPantelis Antoniou case OF_RECONFIG_UPDATE_PROPERTY: 5000d638a07SRob Herring pr_debug("cset<%p> %-15s %pOF/%s\n", ce, action_names[ce->action], 5010d638a07SRob Herring ce->np, ce->prop->name); 502201c910bSPantelis Antoniou break; 503201c910bSPantelis Antoniou case OF_RECONFIG_ATTACH_NODE: 504201c910bSPantelis Antoniou case OF_RECONFIG_DETACH_NODE: 5050d638a07SRob Herring pr_debug("cset<%p> %-15s %pOF\n", ce, action_names[ce->action], 5060d638a07SRob Herring ce->np); 507201c910bSPantelis Antoniou break; 508201c910bSPantelis Antoniou } 509201c910bSPantelis Antoniou } 510201c910bSPantelis Antoniou #else 511201c910bSPantelis Antoniou static inline void __of_changeset_entry_dump(struct of_changeset_entry *ce) 512201c910bSPantelis Antoniou { 513201c910bSPantelis Antoniou /* empty */ 514201c910bSPantelis Antoniou } 515201c910bSPantelis Antoniou #endif 516201c910bSPantelis Antoniou 517201c910bSPantelis Antoniou static void __of_changeset_entry_invert(struct of_changeset_entry *ce, 518201c910bSPantelis Antoniou struct of_changeset_entry *rce) 519201c910bSPantelis Antoniou { 520201c910bSPantelis Antoniou memcpy(rce, ce, sizeof(*rce)); 521201c910bSPantelis Antoniou 522201c910bSPantelis Antoniou switch (ce->action) { 523201c910bSPantelis Antoniou case OF_RECONFIG_ATTACH_NODE: 524201c910bSPantelis Antoniou rce->action = OF_RECONFIG_DETACH_NODE; 525201c910bSPantelis Antoniou break; 526201c910bSPantelis Antoniou case OF_RECONFIG_DETACH_NODE: 527201c910bSPantelis Antoniou rce->action = OF_RECONFIG_ATTACH_NODE; 528201c910bSPantelis Antoniou break; 529201c910bSPantelis Antoniou case OF_RECONFIG_ADD_PROPERTY: 530201c910bSPantelis Antoniou rce->action = OF_RECONFIG_REMOVE_PROPERTY; 531201c910bSPantelis Antoniou break; 532201c910bSPantelis Antoniou case OF_RECONFIG_REMOVE_PROPERTY: 533201c910bSPantelis Antoniou rce->action = OF_RECONFIG_ADD_PROPERTY; 534201c910bSPantelis Antoniou break; 535201c910bSPantelis Antoniou case OF_RECONFIG_UPDATE_PROPERTY: 536201c910bSPantelis Antoniou rce->old_prop = ce->prop; 537201c910bSPantelis Antoniou rce->prop = ce->old_prop; 538b9c43856SPantelis Antoniou /* update was used but original property did not exist */ 539b9c43856SPantelis Antoniou if (!rce->prop) { 540b9c43856SPantelis Antoniou rce->action = OF_RECONFIG_REMOVE_PROPERTY; 541b9c43856SPantelis Antoniou rce->prop = ce->prop; 542b9c43856SPantelis Antoniou } 543201c910bSPantelis Antoniou break; 544201c910bSPantelis Antoniou } 545201c910bSPantelis Antoniou } 546201c910bSPantelis Antoniou 54724789c5cSFrank Rowand static int __of_changeset_entry_notify(struct of_changeset_entry *ce, 54824789c5cSFrank Rowand bool revert) 549201c910bSPantelis Antoniou { 550f5242e5aSGrant Likely struct of_reconfig_data rd; 551201c910bSPantelis Antoniou struct of_changeset_entry ce_inverted; 55224789c5cSFrank Rowand int ret = 0; 553201c910bSPantelis Antoniou 554201c910bSPantelis Antoniou if (revert) { 555201c910bSPantelis Antoniou __of_changeset_entry_invert(ce, &ce_inverted); 556201c910bSPantelis Antoniou ce = &ce_inverted; 557201c910bSPantelis Antoniou } 558201c910bSPantelis Antoniou 559201c910bSPantelis Antoniou switch (ce->action) { 560201c910bSPantelis Antoniou case OF_RECONFIG_ATTACH_NODE: 561201c910bSPantelis Antoniou case OF_RECONFIG_DETACH_NODE: 562f5242e5aSGrant Likely memset(&rd, 0, sizeof(rd)); 563f5242e5aSGrant Likely rd.dn = ce->np; 564f5242e5aSGrant Likely ret = of_reconfig_notify(ce->action, &rd); 565201c910bSPantelis Antoniou break; 566201c910bSPantelis Antoniou case OF_RECONFIG_ADD_PROPERTY: 567201c910bSPantelis Antoniou case OF_RECONFIG_REMOVE_PROPERTY: 568201c910bSPantelis Antoniou case OF_RECONFIG_UPDATE_PROPERTY: 569201c910bSPantelis Antoniou ret = of_property_notify(ce->action, ce->np, ce->prop, ce->old_prop); 570201c910bSPantelis Antoniou break; 571201c910bSPantelis Antoniou default: 572606ad42aSRob Herring pr_err("invalid devicetree changeset action: %i\n", 573201c910bSPantelis Antoniou (int)ce->action); 57424789c5cSFrank Rowand ret = -EINVAL; 575201c910bSPantelis Antoniou } 576201c910bSPantelis Antoniou 577201c910bSPantelis Antoniou if (ret) 5780d638a07SRob Herring pr_err("changeset notifier error @%pOF\n", ce->np); 57924789c5cSFrank Rowand return ret; 580201c910bSPantelis Antoniou } 581201c910bSPantelis Antoniou 582201c910bSPantelis Antoniou static int __of_changeset_entry_apply(struct of_changeset_entry *ce) 583201c910bSPantelis Antoniou { 584201c910bSPantelis Antoniou struct property *old_prop, **propp; 585201c910bSPantelis Antoniou unsigned long flags; 586201c910bSPantelis Antoniou int ret = 0; 587201c910bSPantelis Antoniou 588201c910bSPantelis Antoniou __of_changeset_entry_dump(ce); 589201c910bSPantelis Antoniou 590201c910bSPantelis Antoniou raw_spin_lock_irqsave(&devtree_lock, flags); 591201c910bSPantelis Antoniou switch (ce->action) { 592201c910bSPantelis Antoniou case OF_RECONFIG_ATTACH_NODE: 593201c910bSPantelis Antoniou __of_attach_node(ce->np); 594201c910bSPantelis Antoniou break; 595201c910bSPantelis Antoniou case OF_RECONFIG_DETACH_NODE: 596201c910bSPantelis Antoniou __of_detach_node(ce->np); 597201c910bSPantelis Antoniou break; 598201c910bSPantelis Antoniou case OF_RECONFIG_ADD_PROPERTY: 599201c910bSPantelis Antoniou /* If the property is in deadprops then it must be removed */ 600201c910bSPantelis Antoniou for (propp = &ce->np->deadprops; *propp; propp = &(*propp)->next) { 601201c910bSPantelis Antoniou if (*propp == ce->prop) { 602201c910bSPantelis Antoniou *propp = ce->prop->next; 603201c910bSPantelis Antoniou ce->prop->next = NULL; 604201c910bSPantelis Antoniou break; 605201c910bSPantelis Antoniou } 606201c910bSPantelis Antoniou } 607201c910bSPantelis Antoniou 608201c910bSPantelis Antoniou ret = __of_add_property(ce->np, ce->prop); 609201c910bSPantelis Antoniou if (ret) { 6100d638a07SRob Herring pr_err("changeset: add_property failed @%pOF/%s\n", 6110d638a07SRob Herring ce->np, 612201c910bSPantelis Antoniou ce->prop->name); 613201c910bSPantelis Antoniou break; 614201c910bSPantelis Antoniou } 615201c910bSPantelis Antoniou break; 616201c910bSPantelis Antoniou case OF_RECONFIG_REMOVE_PROPERTY: 617201c910bSPantelis Antoniou ret = __of_remove_property(ce->np, ce->prop); 618201c910bSPantelis Antoniou if (ret) { 6190d638a07SRob Herring pr_err("changeset: remove_property failed @%pOF/%s\n", 6200d638a07SRob Herring ce->np, 621201c910bSPantelis Antoniou ce->prop->name); 622201c910bSPantelis Antoniou break; 623201c910bSPantelis Antoniou } 624201c910bSPantelis Antoniou break; 625201c910bSPantelis Antoniou 626201c910bSPantelis Antoniou case OF_RECONFIG_UPDATE_PROPERTY: 627201c910bSPantelis Antoniou /* If the property is in deadprops then it must be removed */ 628201c910bSPantelis Antoniou for (propp = &ce->np->deadprops; *propp; propp = &(*propp)->next) { 629201c910bSPantelis Antoniou if (*propp == ce->prop) { 630201c910bSPantelis Antoniou *propp = ce->prop->next; 631201c910bSPantelis Antoniou ce->prop->next = NULL; 632201c910bSPantelis Antoniou break; 633201c910bSPantelis Antoniou } 634201c910bSPantelis Antoniou } 635201c910bSPantelis Antoniou 636201c910bSPantelis Antoniou ret = __of_update_property(ce->np, ce->prop, &old_prop); 637201c910bSPantelis Antoniou if (ret) { 6380d638a07SRob Herring pr_err("changeset: update_property failed @%pOF/%s\n", 6390d638a07SRob Herring ce->np, 640201c910bSPantelis Antoniou ce->prop->name); 641201c910bSPantelis Antoniou break; 642201c910bSPantelis Antoniou } 643201c910bSPantelis Antoniou break; 644201c910bSPantelis Antoniou default: 645201c910bSPantelis Antoniou ret = -EINVAL; 646201c910bSPantelis Antoniou } 647201c910bSPantelis Antoniou raw_spin_unlock_irqrestore(&devtree_lock, flags); 648201c910bSPantelis Antoniou 649201c910bSPantelis Antoniou if (ret) 650201c910bSPantelis Antoniou return ret; 651201c910bSPantelis Antoniou 652201c910bSPantelis Antoniou switch (ce->action) { 653201c910bSPantelis Antoniou case OF_RECONFIG_ATTACH_NODE: 654201c910bSPantelis Antoniou __of_attach_node_sysfs(ce->np); 655201c910bSPantelis Antoniou break; 656201c910bSPantelis Antoniou case OF_RECONFIG_DETACH_NODE: 657201c910bSPantelis Antoniou __of_detach_node_sysfs(ce->np); 658201c910bSPantelis Antoniou break; 659201c910bSPantelis Antoniou case OF_RECONFIG_ADD_PROPERTY: 660201c910bSPantelis Antoniou /* ignore duplicate names */ 661201c910bSPantelis Antoniou __of_add_property_sysfs(ce->np, ce->prop); 662201c910bSPantelis Antoniou break; 663201c910bSPantelis Antoniou case OF_RECONFIG_REMOVE_PROPERTY: 664201c910bSPantelis Antoniou __of_remove_property_sysfs(ce->np, ce->prop); 665201c910bSPantelis Antoniou break; 666201c910bSPantelis Antoniou case OF_RECONFIG_UPDATE_PROPERTY: 667201c910bSPantelis Antoniou __of_update_property_sysfs(ce->np, ce->prop, ce->old_prop); 668201c910bSPantelis Antoniou break; 669201c910bSPantelis Antoniou } 670201c910bSPantelis Antoniou 671201c910bSPantelis Antoniou return 0; 672201c910bSPantelis Antoniou } 673201c910bSPantelis Antoniou 674201c910bSPantelis Antoniou static inline int __of_changeset_entry_revert(struct of_changeset_entry *ce) 675201c910bSPantelis Antoniou { 676201c910bSPantelis Antoniou struct of_changeset_entry ce_inverted; 677201c910bSPantelis Antoniou 678201c910bSPantelis Antoniou __of_changeset_entry_invert(ce, &ce_inverted); 679201c910bSPantelis Antoniou return __of_changeset_entry_apply(&ce_inverted); 680201c910bSPantelis Antoniou } 681201c910bSPantelis Antoniou 682201c910bSPantelis Antoniou /** 683201c910bSPantelis Antoniou * of_changeset_init - Initialize a changeset for use 684201c910bSPantelis Antoniou * 685201c910bSPantelis Antoniou * @ocs: changeset pointer 686201c910bSPantelis Antoniou * 687201c910bSPantelis Antoniou * Initialize a changeset structure 688201c910bSPantelis Antoniou */ 689201c910bSPantelis Antoniou void of_changeset_init(struct of_changeset *ocs) 690201c910bSPantelis Antoniou { 691201c910bSPantelis Antoniou memset(ocs, 0, sizeof(*ocs)); 692201c910bSPantelis Antoniou INIT_LIST_HEAD(&ocs->entries); 693201c910bSPantelis Antoniou } 69418322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_init); 695201c910bSPantelis Antoniou 696201c910bSPantelis Antoniou /** 697201c910bSPantelis Antoniou * of_changeset_destroy - Destroy a changeset 698201c910bSPantelis Antoniou * 699201c910bSPantelis Antoniou * @ocs: changeset pointer 700201c910bSPantelis Antoniou * 701201c910bSPantelis Antoniou * Destroys a changeset. Note that if a changeset is applied, 702201c910bSPantelis Antoniou * its changes to the tree cannot be reverted. 703201c910bSPantelis Antoniou */ 704201c910bSPantelis Antoniou void of_changeset_destroy(struct of_changeset *ocs) 705201c910bSPantelis Antoniou { 706201c910bSPantelis Antoniou struct of_changeset_entry *ce, *cen; 707201c910bSPantelis Antoniou 708201c910bSPantelis Antoniou list_for_each_entry_safe_reverse(ce, cen, &ocs->entries, node) 709201c910bSPantelis Antoniou __of_changeset_entry_destroy(ce); 710201c910bSPantelis Antoniou } 71118322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_destroy); 712201c910bSPantelis Antoniou 71324789c5cSFrank Rowand /* 71424789c5cSFrank Rowand * Apply the changeset entries in @ocs. 71524789c5cSFrank Rowand * If apply fails, an attempt is made to revert the entries that were 71624789c5cSFrank Rowand * successfully applied. 71724789c5cSFrank Rowand * 71824789c5cSFrank Rowand * If multiple revert errors occur then only the final revert error is reported. 71924789c5cSFrank Rowand * 72024789c5cSFrank Rowand * Returns 0 on success, a negative error value in case of an error. 72124789c5cSFrank Rowand * If a revert error occurs, it is returned in *ret_revert. 72224789c5cSFrank Rowand */ 72324789c5cSFrank Rowand int __of_changeset_apply_entries(struct of_changeset *ocs, int *ret_revert) 724201c910bSPantelis Antoniou { 725201c910bSPantelis Antoniou struct of_changeset_entry *ce; 72624789c5cSFrank Rowand int ret, ret_tmp; 727201c910bSPantelis Antoniou 728606ad42aSRob Herring pr_debug("changeset: applying...\n"); 729201c910bSPantelis Antoniou list_for_each_entry(ce, &ocs->entries, node) { 730201c910bSPantelis Antoniou ret = __of_changeset_entry_apply(ce); 731201c910bSPantelis Antoniou if (ret) { 732606ad42aSRob Herring pr_err("Error applying changeset (%d)\n", ret); 73324789c5cSFrank Rowand list_for_each_entry_continue_reverse(ce, &ocs->entries, 73424789c5cSFrank Rowand node) { 73524789c5cSFrank Rowand ret_tmp = __of_changeset_entry_revert(ce); 73624789c5cSFrank Rowand if (ret_tmp) 73724789c5cSFrank Rowand *ret_revert = ret_tmp; 73824789c5cSFrank Rowand } 739201c910bSPantelis Antoniou return ret; 740201c910bSPantelis Antoniou } 741201c910bSPantelis Antoniou } 74224789c5cSFrank Rowand 74324789c5cSFrank Rowand return 0; 74424789c5cSFrank Rowand } 74524789c5cSFrank Rowand 74624789c5cSFrank Rowand /* 74724789c5cSFrank Rowand * Returns 0 on success, a negative error value in case of an error. 74824789c5cSFrank Rowand * 749e9d92e40SGeert Uytterhoeven * If multiple changeset entry notification errors occur then only the 75024789c5cSFrank Rowand * final notification error is reported. 75124789c5cSFrank Rowand */ 75224789c5cSFrank Rowand int __of_changeset_apply_notify(struct of_changeset *ocs) 75324789c5cSFrank Rowand { 75424789c5cSFrank Rowand struct of_changeset_entry *ce; 75524789c5cSFrank Rowand int ret = 0, ret_tmp; 75624789c5cSFrank Rowand 75724789c5cSFrank Rowand pr_debug("changeset: emitting notifiers.\n"); 758201c910bSPantelis Antoniou 759201c910bSPantelis Antoniou /* drop the global lock while emitting notifiers */ 760201c910bSPantelis Antoniou mutex_unlock(&of_mutex); 76124789c5cSFrank Rowand list_for_each_entry(ce, &ocs->entries, node) { 76224789c5cSFrank Rowand ret_tmp = __of_changeset_entry_notify(ce, 0); 76324789c5cSFrank Rowand if (ret_tmp) 76424789c5cSFrank Rowand ret = ret_tmp; 76524789c5cSFrank Rowand } 766201c910bSPantelis Antoniou mutex_lock(&of_mutex); 767606ad42aSRob Herring pr_debug("changeset: notifiers sent.\n"); 768201c910bSPantelis Antoniou 76924789c5cSFrank Rowand return ret; 77024789c5cSFrank Rowand } 77124789c5cSFrank Rowand 77224789c5cSFrank Rowand /* 77324789c5cSFrank Rowand * Returns 0 on success, a negative error value in case of an error. 77424789c5cSFrank Rowand * 77524789c5cSFrank Rowand * If a changeset entry apply fails, an attempt is made to revert any 77624789c5cSFrank Rowand * previous entries in the changeset. If any of the reverts fails, 77724789c5cSFrank Rowand * that failure is not reported. Thus the state of the device tree 77824789c5cSFrank Rowand * is unknown if an apply error occurs. 77924789c5cSFrank Rowand */ 78024789c5cSFrank Rowand static int __of_changeset_apply(struct of_changeset *ocs) 78124789c5cSFrank Rowand { 78224789c5cSFrank Rowand int ret, ret_revert = 0; 78324789c5cSFrank Rowand 78424789c5cSFrank Rowand ret = __of_changeset_apply_entries(ocs, &ret_revert); 78524789c5cSFrank Rowand if (!ret) 78624789c5cSFrank Rowand ret = __of_changeset_apply_notify(ocs); 78724789c5cSFrank Rowand 78824789c5cSFrank Rowand return ret; 789201c910bSPantelis Antoniou } 790201c910bSPantelis Antoniou 791201c910bSPantelis Antoniou /** 79218322377SGavin Shan * of_changeset_apply - Applies a changeset 793201c910bSPantelis Antoniou * 794201c910bSPantelis Antoniou * @ocs: changeset pointer 795201c910bSPantelis Antoniou * 79618322377SGavin Shan * Applies a changeset to the live tree. 79718322377SGavin Shan * Any side-effects of live tree state changes are applied here on 79818322377SGavin Shan * success, like creation/destruction of devices and side-effects 79918322377SGavin Shan * like creation of sysfs properties and directories. 8008c8239c2SRob Herring * 8018c8239c2SRob Herring * Return: 0 on success, a negative error value in case of an error. 80218322377SGavin Shan * On error the partially applied effects are reverted. 803201c910bSPantelis Antoniou */ 80418322377SGavin Shan int of_changeset_apply(struct of_changeset *ocs) 80518322377SGavin Shan { 80618322377SGavin Shan int ret; 80718322377SGavin Shan 80818322377SGavin Shan mutex_lock(&of_mutex); 80918322377SGavin Shan ret = __of_changeset_apply(ocs); 81018322377SGavin Shan mutex_unlock(&of_mutex); 81118322377SGavin Shan 81218322377SGavin Shan return ret; 81318322377SGavin Shan } 81418322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_apply); 81518322377SGavin Shan 81624789c5cSFrank Rowand /* 81724789c5cSFrank Rowand * Revert the changeset entries in @ocs. 81824789c5cSFrank Rowand * If revert fails, an attempt is made to re-apply the entries that were 81924789c5cSFrank Rowand * successfully removed. 82024789c5cSFrank Rowand * 82124789c5cSFrank Rowand * If multiple re-apply errors occur then only the final apply error is 82224789c5cSFrank Rowand * reported. 82324789c5cSFrank Rowand * 82424789c5cSFrank Rowand * Returns 0 on success, a negative error value in case of an error. 82524789c5cSFrank Rowand * If an apply error occurs, it is returned in *ret_apply. 82624789c5cSFrank Rowand */ 82724789c5cSFrank Rowand int __of_changeset_revert_entries(struct of_changeset *ocs, int *ret_apply) 828201c910bSPantelis Antoniou { 829201c910bSPantelis Antoniou struct of_changeset_entry *ce; 83024789c5cSFrank Rowand int ret, ret_tmp; 831201c910bSPantelis Antoniou 832606ad42aSRob Herring pr_debug("changeset: reverting...\n"); 833201c910bSPantelis Antoniou list_for_each_entry_reverse(ce, &ocs->entries, node) { 834201c910bSPantelis Antoniou ret = __of_changeset_entry_revert(ce); 835201c910bSPantelis Antoniou if (ret) { 836606ad42aSRob Herring pr_err("Error reverting changeset (%d)\n", ret); 83724789c5cSFrank Rowand list_for_each_entry_continue(ce, &ocs->entries, node) { 83824789c5cSFrank Rowand ret_tmp = __of_changeset_entry_apply(ce); 83924789c5cSFrank Rowand if (ret_tmp) 84024789c5cSFrank Rowand *ret_apply = ret_tmp; 84124789c5cSFrank Rowand } 842201c910bSPantelis Antoniou return ret; 843201c910bSPantelis Antoniou } 844201c910bSPantelis Antoniou } 84524789c5cSFrank Rowand 84624789c5cSFrank Rowand return 0; 84724789c5cSFrank Rowand } 84824789c5cSFrank Rowand 84924789c5cSFrank Rowand /* 850e9d92e40SGeert Uytterhoeven * If multiple changeset entry notification errors occur then only the 85124789c5cSFrank Rowand * final notification error is reported. 85224789c5cSFrank Rowand */ 85324789c5cSFrank Rowand int __of_changeset_revert_notify(struct of_changeset *ocs) 85424789c5cSFrank Rowand { 85524789c5cSFrank Rowand struct of_changeset_entry *ce; 85624789c5cSFrank Rowand int ret = 0, ret_tmp; 85724789c5cSFrank Rowand 85824789c5cSFrank Rowand pr_debug("changeset: emitting notifiers.\n"); 859201c910bSPantelis Antoniou 860201c910bSPantelis Antoniou /* drop the global lock while emitting notifiers */ 861201c910bSPantelis Antoniou mutex_unlock(&of_mutex); 86224789c5cSFrank Rowand list_for_each_entry_reverse(ce, &ocs->entries, node) { 86324789c5cSFrank Rowand ret_tmp = __of_changeset_entry_notify(ce, 1); 86424789c5cSFrank Rowand if (ret_tmp) 86524789c5cSFrank Rowand ret = ret_tmp; 86624789c5cSFrank Rowand } 867201c910bSPantelis Antoniou mutex_lock(&of_mutex); 868606ad42aSRob Herring pr_debug("changeset: notifiers sent.\n"); 869201c910bSPantelis Antoniou 87024789c5cSFrank Rowand return ret; 87124789c5cSFrank Rowand } 87224789c5cSFrank Rowand 87324789c5cSFrank Rowand static int __of_changeset_revert(struct of_changeset *ocs) 87424789c5cSFrank Rowand { 87524789c5cSFrank Rowand int ret, ret_reply; 87624789c5cSFrank Rowand 87724789c5cSFrank Rowand ret_reply = 0; 87824789c5cSFrank Rowand ret = __of_changeset_revert_entries(ocs, &ret_reply); 87924789c5cSFrank Rowand 88024789c5cSFrank Rowand if (!ret) 88124789c5cSFrank Rowand ret = __of_changeset_revert_notify(ocs); 88224789c5cSFrank Rowand 88324789c5cSFrank Rowand return ret; 884201c910bSPantelis Antoniou } 885201c910bSPantelis Antoniou 886201c910bSPantelis Antoniou /** 88718322377SGavin Shan * of_changeset_revert - Reverts an applied changeset 88818322377SGavin Shan * 88918322377SGavin Shan * @ocs: changeset pointer 89018322377SGavin Shan * 89118322377SGavin Shan * Reverts a changeset returning the state of the tree to what it 89218322377SGavin Shan * was before the application. 89318322377SGavin Shan * Any side-effects like creation/destruction of devices and 89418322377SGavin Shan * removal of sysfs properties and directories are applied. 8958c8239c2SRob Herring * 8968c8239c2SRob Herring * Return: 0 on success, a negative error value in case of an error. 89718322377SGavin Shan */ 89818322377SGavin Shan int of_changeset_revert(struct of_changeset *ocs) 89918322377SGavin Shan { 90018322377SGavin Shan int ret; 90118322377SGavin Shan 90218322377SGavin Shan mutex_lock(&of_mutex); 90318322377SGavin Shan ret = __of_changeset_revert(ocs); 90418322377SGavin Shan mutex_unlock(&of_mutex); 90518322377SGavin Shan 90618322377SGavin Shan return ret; 90718322377SGavin Shan } 90818322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_revert); 90918322377SGavin Shan 91018322377SGavin Shan /** 9110290c4caSFrank Rowand * of_changeset_action - Add an action to the tail of the changeset list 912201c910bSPantelis Antoniou * 913201c910bSPantelis Antoniou * @ocs: changeset pointer 914201c910bSPantelis Antoniou * @action: action to perform 915201c910bSPantelis Antoniou * @np: Pointer to device node 916201c910bSPantelis Antoniou * @prop: Pointer to property 917201c910bSPantelis Antoniou * 918201c910bSPantelis Antoniou * On action being one of: 919201c910bSPantelis Antoniou * + OF_RECONFIG_ATTACH_NODE 920201c910bSPantelis Antoniou * + OF_RECONFIG_DETACH_NODE, 921201c910bSPantelis Antoniou * + OF_RECONFIG_ADD_PROPERTY 922201c910bSPantelis Antoniou * + OF_RECONFIG_REMOVE_PROPERTY, 923201c910bSPantelis Antoniou * + OF_RECONFIG_UPDATE_PROPERTY 9248c8239c2SRob Herring * 9258c8239c2SRob Herring * Return: 0 on success, a negative error value in case of an error. 926201c910bSPantelis Antoniou */ 927201c910bSPantelis Antoniou int of_changeset_action(struct of_changeset *ocs, unsigned long action, 928201c910bSPantelis Antoniou struct device_node *np, struct property *prop) 929201c910bSPantelis Antoniou { 930201c910bSPantelis Antoniou struct of_changeset_entry *ce; 931201c910bSPantelis Antoniou 932201c910bSPantelis Antoniou ce = kzalloc(sizeof(*ce), GFP_KERNEL); 933606ad42aSRob Herring if (!ce) 934201c910bSPantelis Antoniou return -ENOMEM; 935606ad42aSRob Herring 936201c910bSPantelis Antoniou /* get a reference to the node */ 937201c910bSPantelis Antoniou ce->action = action; 938201c910bSPantelis Antoniou ce->np = of_node_get(np); 939201c910bSPantelis Antoniou ce->prop = prop; 940201c910bSPantelis Antoniou 941201c910bSPantelis Antoniou if (action == OF_RECONFIG_UPDATE_PROPERTY && prop) 942201c910bSPantelis Antoniou ce->old_prop = of_find_property(np, prop->name, NULL); 943201c910bSPantelis Antoniou 944201c910bSPantelis Antoniou /* add it to the list */ 945201c910bSPantelis Antoniou list_add_tail(&ce->node, &ocs->entries); 946201c910bSPantelis Antoniou return 0; 947201c910bSPantelis Antoniou } 94818322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_action); 949