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: 101*0d638a07SRob Herring pr_debug("notify %-15s %pOF\n", action_names[action], 102*0d638a07SRob Herring pr->dn); 10300aa3720SGrant Likely break; 10400aa3720SGrant Likely case OF_RECONFIG_ADD_PROPERTY: 10500aa3720SGrant Likely case OF_RECONFIG_REMOVE_PROPERTY: 10600aa3720SGrant Likely case OF_RECONFIG_UPDATE_PROPERTY: 107*0d638a07SRob Herring pr_debug("notify %-15s %pOF:%s\n", action_names[action], 108*0d638a07SRob Herring pr->dn, 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 21924996951SFrank 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)) { 331*0d638a07SRob Herring pr_err("ERROR: Bad of_node_put() on %pOF\n", node); 3326afc0dc3SGrant Likely dump_stack(); 3336afc0dc3SGrant Likely return; 3346afc0dc3SGrant Likely } 3356afc0dc3SGrant Likely if (!of_node_check_flag(node, OF_DYNAMIC)) 3366afc0dc3SGrant Likely return; 3376afc0dc3SGrant Likely 3386afc0dc3SGrant Likely while (prop) { 3396afc0dc3SGrant Likely struct property *next = prop->next; 3406afc0dc3SGrant Likely kfree(prop->name); 3416afc0dc3SGrant Likely kfree(prop->value); 3426afc0dc3SGrant Likely kfree(prop); 3436afc0dc3SGrant Likely prop = next; 3446afc0dc3SGrant Likely 3456afc0dc3SGrant Likely if (!prop) { 3466afc0dc3SGrant Likely prop = node->deadprops; 3476afc0dc3SGrant Likely node->deadprops = NULL; 3486afc0dc3SGrant Likely } 3496afc0dc3SGrant Likely } 3506afc0dc3SGrant Likely kfree(node->full_name); 3516afc0dc3SGrant Likely kfree(node->data); 3526afc0dc3SGrant Likely kfree(node); 3536afc0dc3SGrant Likely } 35469843396SPantelis Antoniou 35569843396SPantelis Antoniou /** 35669843396SPantelis Antoniou * __of_prop_dup - Copy a property dynamically. 35769843396SPantelis Antoniou * @prop: Property to copy 35869843396SPantelis Antoniou * @allocflags: Allocation flags (typically pass GFP_KERNEL) 35969843396SPantelis Antoniou * 36069843396SPantelis Antoniou * Copy a property by dynamically allocating the memory of both the 36127b3383aSGeert Uytterhoeven * property structure and the property name & contents. The property's 36269843396SPantelis Antoniou * flags have the OF_DYNAMIC bit set so that we can differentiate between 36369843396SPantelis Antoniou * dynamically allocated properties and not. 36469843396SPantelis Antoniou * Returns the newly allocated property or NULL on out of memory error. 36569843396SPantelis Antoniou */ 36669843396SPantelis Antoniou struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags) 36769843396SPantelis Antoniou { 36869843396SPantelis Antoniou struct property *new; 36969843396SPantelis Antoniou 37069843396SPantelis Antoniou new = kzalloc(sizeof(*new), allocflags); 37169843396SPantelis Antoniou if (!new) 37269843396SPantelis Antoniou return NULL; 37369843396SPantelis Antoniou 37469843396SPantelis Antoniou /* 37569843396SPantelis Antoniou * NOTE: There is no check for zero length value. 376b6ae5dc5SGrant Likely * In case of a boolean property, this will allocate a value 37769843396SPantelis Antoniou * of zero bytes. We do this to work around the use 37869843396SPantelis Antoniou * of of_get_property() calls on boolean values. 37969843396SPantelis Antoniou */ 38069843396SPantelis Antoniou new->name = kstrdup(prop->name, allocflags); 38169843396SPantelis Antoniou new->value = kmemdup(prop->value, prop->length, allocflags); 38269843396SPantelis Antoniou new->length = prop->length; 38369843396SPantelis Antoniou if (!new->name || !new->value) 38469843396SPantelis Antoniou goto err_free; 38569843396SPantelis Antoniou 38669843396SPantelis Antoniou /* mark the property as dynamic */ 38769843396SPantelis Antoniou of_property_set_flag(new, OF_DYNAMIC); 38869843396SPantelis Antoniou 38969843396SPantelis Antoniou return new; 39069843396SPantelis Antoniou 39169843396SPantelis Antoniou err_free: 39269843396SPantelis Antoniou kfree(new->name); 39369843396SPantelis Antoniou kfree(new->value); 39469843396SPantelis Antoniou kfree(new); 39569843396SPantelis Antoniou return NULL; 39669843396SPantelis Antoniou } 39769843396SPantelis Antoniou 39869843396SPantelis Antoniou /** 399e5179581SGrant Likely * __of_node_dup() - Duplicate or create an empty device node dynamically. 400e5179581SGrant Likely * @fmt: Format string (plus vargs) for new full name of the device node 40169843396SPantelis Antoniou * 402e5179581SGrant Likely * Create an device tree node, either by duplicating an empty node or by allocating 403e5179581SGrant Likely * an empty one suitable for further modification. The node data are 404e5179581SGrant Likely * dynamically allocated and all the node flags have the OF_DYNAMIC & 405e5179581SGrant Likely * OF_DETACHED bits set. Returns the newly allocated node or NULL on out of 406e5179581SGrant Likely * memory error. 40769843396SPantelis Antoniou */ 408e5179581SGrant Likely struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...) 40969843396SPantelis Antoniou { 410ef8bbd73SGrant Likely va_list vargs; 41169843396SPantelis Antoniou struct device_node *node; 41269843396SPantelis Antoniou 413ef8bbd73SGrant Likely node = kzalloc(sizeof(*node), GFP_KERNEL); 41469843396SPantelis Antoniou if (!node) 41569843396SPantelis Antoniou return NULL; 416ef8bbd73SGrant Likely va_start(vargs, fmt); 417ef8bbd73SGrant Likely node->full_name = kvasprintf(GFP_KERNEL, fmt, vargs); 418ef8bbd73SGrant Likely va_end(vargs); 419e5179581SGrant Likely if (!node->full_name) { 420e5179581SGrant Likely kfree(node); 421e5179581SGrant Likely return NULL; 422e5179581SGrant Likely } 42369843396SPantelis Antoniou 424ef8bbd73SGrant Likely of_node_set_flag(node, OF_DYNAMIC); 425ef8bbd73SGrant Likely of_node_set_flag(node, OF_DETACHED); 42669843396SPantelis Antoniou of_node_init(node); 42769843396SPantelis Antoniou 428e5179581SGrant Likely /* Iterate over and duplicate all properties */ 429e5179581SGrant Likely if (np) { 430e5179581SGrant Likely struct property *pp, *new_pp; 431e5179581SGrant Likely for_each_property_of_node(np, pp) { 432e5179581SGrant Likely new_pp = __of_prop_dup(pp, GFP_KERNEL); 433e5179581SGrant Likely if (!new_pp) 434e5179581SGrant Likely goto err_prop; 435e5179581SGrant Likely if (__of_add_property(node, new_pp)) { 436e5179581SGrant Likely kfree(new_pp->name); 437e5179581SGrant Likely kfree(new_pp->value); 438e5179581SGrant Likely kfree(new_pp); 439e5179581SGrant Likely goto err_prop; 440e5179581SGrant Likely } 441e5179581SGrant Likely } 442e5179581SGrant Likely } 44369843396SPantelis Antoniou return node; 44469843396SPantelis Antoniou 445e5179581SGrant Likely err_prop: 446e5179581SGrant Likely of_node_put(node); /* Frees the node and properties */ 44769843396SPantelis Antoniou return NULL; 44869843396SPantelis Antoniou } 449201c910bSPantelis Antoniou 450201c910bSPantelis Antoniou static void __of_changeset_entry_destroy(struct of_changeset_entry *ce) 451201c910bSPantelis Antoniou { 452201c910bSPantelis Antoniou of_node_put(ce->np); 453201c910bSPantelis Antoniou list_del(&ce->node); 454201c910bSPantelis Antoniou kfree(ce); 455201c910bSPantelis Antoniou } 456201c910bSPantelis Antoniou 457201c910bSPantelis Antoniou #ifdef DEBUG 458201c910bSPantelis Antoniou static void __of_changeset_entry_dump(struct of_changeset_entry *ce) 459201c910bSPantelis Antoniou { 460201c910bSPantelis Antoniou switch (ce->action) { 461201c910bSPantelis Antoniou case OF_RECONFIG_ADD_PROPERTY: 462201c910bSPantelis Antoniou case OF_RECONFIG_REMOVE_PROPERTY: 463201c910bSPantelis Antoniou case OF_RECONFIG_UPDATE_PROPERTY: 464*0d638a07SRob Herring pr_debug("cset<%p> %-15s %pOF/%s\n", ce, action_names[ce->action], 465*0d638a07SRob Herring ce->np, ce->prop->name); 466201c910bSPantelis Antoniou break; 467201c910bSPantelis Antoniou case OF_RECONFIG_ATTACH_NODE: 468201c910bSPantelis Antoniou case OF_RECONFIG_DETACH_NODE: 469*0d638a07SRob Herring pr_debug("cset<%p> %-15s %pOF\n", ce, action_names[ce->action], 470*0d638a07SRob Herring ce->np); 471201c910bSPantelis Antoniou break; 472201c910bSPantelis Antoniou } 473201c910bSPantelis Antoniou } 474201c910bSPantelis Antoniou #else 475201c910bSPantelis Antoniou static inline void __of_changeset_entry_dump(struct of_changeset_entry *ce) 476201c910bSPantelis Antoniou { 477201c910bSPantelis Antoniou /* empty */ 478201c910bSPantelis Antoniou } 479201c910bSPantelis Antoniou #endif 480201c910bSPantelis Antoniou 481201c910bSPantelis Antoniou static void __of_changeset_entry_invert(struct of_changeset_entry *ce, 482201c910bSPantelis Antoniou struct of_changeset_entry *rce) 483201c910bSPantelis Antoniou { 484201c910bSPantelis Antoniou memcpy(rce, ce, sizeof(*rce)); 485201c910bSPantelis Antoniou 486201c910bSPantelis Antoniou switch (ce->action) { 487201c910bSPantelis Antoniou case OF_RECONFIG_ATTACH_NODE: 488201c910bSPantelis Antoniou rce->action = OF_RECONFIG_DETACH_NODE; 489201c910bSPantelis Antoniou break; 490201c910bSPantelis Antoniou case OF_RECONFIG_DETACH_NODE: 491201c910bSPantelis Antoniou rce->action = OF_RECONFIG_ATTACH_NODE; 492201c910bSPantelis Antoniou break; 493201c910bSPantelis Antoniou case OF_RECONFIG_ADD_PROPERTY: 494201c910bSPantelis Antoniou rce->action = OF_RECONFIG_REMOVE_PROPERTY; 495201c910bSPantelis Antoniou break; 496201c910bSPantelis Antoniou case OF_RECONFIG_REMOVE_PROPERTY: 497201c910bSPantelis Antoniou rce->action = OF_RECONFIG_ADD_PROPERTY; 498201c910bSPantelis Antoniou break; 499201c910bSPantelis Antoniou case OF_RECONFIG_UPDATE_PROPERTY: 500201c910bSPantelis Antoniou rce->old_prop = ce->prop; 501201c910bSPantelis Antoniou rce->prop = ce->old_prop; 502b9c43856SPantelis Antoniou /* update was used but original property did not exist */ 503b9c43856SPantelis Antoniou if (!rce->prop) { 504b9c43856SPantelis Antoniou rce->action = OF_RECONFIG_REMOVE_PROPERTY; 505b9c43856SPantelis Antoniou rce->prop = ce->prop; 506b9c43856SPantelis Antoniou } 507201c910bSPantelis Antoniou break; 508201c910bSPantelis Antoniou } 509201c910bSPantelis Antoniou } 510201c910bSPantelis Antoniou 511201c910bSPantelis Antoniou static void __of_changeset_entry_notify(struct of_changeset_entry *ce, bool revert) 512201c910bSPantelis Antoniou { 513f5242e5aSGrant Likely struct of_reconfig_data rd; 514201c910bSPantelis Antoniou struct of_changeset_entry ce_inverted; 515201c910bSPantelis Antoniou int ret; 516201c910bSPantelis Antoniou 517201c910bSPantelis Antoniou if (revert) { 518201c910bSPantelis Antoniou __of_changeset_entry_invert(ce, &ce_inverted); 519201c910bSPantelis Antoniou ce = &ce_inverted; 520201c910bSPantelis Antoniou } 521201c910bSPantelis Antoniou 522201c910bSPantelis Antoniou switch (ce->action) { 523201c910bSPantelis Antoniou case OF_RECONFIG_ATTACH_NODE: 524201c910bSPantelis Antoniou case OF_RECONFIG_DETACH_NODE: 525f5242e5aSGrant Likely memset(&rd, 0, sizeof(rd)); 526f5242e5aSGrant Likely rd.dn = ce->np; 527f5242e5aSGrant Likely ret = of_reconfig_notify(ce->action, &rd); 528201c910bSPantelis Antoniou break; 529201c910bSPantelis Antoniou case OF_RECONFIG_ADD_PROPERTY: 530201c910bSPantelis Antoniou case OF_RECONFIG_REMOVE_PROPERTY: 531201c910bSPantelis Antoniou case OF_RECONFIG_UPDATE_PROPERTY: 532201c910bSPantelis Antoniou ret = of_property_notify(ce->action, ce->np, ce->prop, ce->old_prop); 533201c910bSPantelis Antoniou break; 534201c910bSPantelis Antoniou default: 535606ad42aSRob Herring pr_err("invalid devicetree changeset action: %i\n", 536201c910bSPantelis Antoniou (int)ce->action); 537201c910bSPantelis Antoniou return; 538201c910bSPantelis Antoniou } 539201c910bSPantelis Antoniou 540201c910bSPantelis Antoniou if (ret) 541*0d638a07SRob Herring pr_err("changeset notifier error @%pOF\n", ce->np); 542201c910bSPantelis Antoniou } 543201c910bSPantelis Antoniou 544201c910bSPantelis Antoniou static int __of_changeset_entry_apply(struct of_changeset_entry *ce) 545201c910bSPantelis Antoniou { 546201c910bSPantelis Antoniou struct property *old_prop, **propp; 547201c910bSPantelis Antoniou unsigned long flags; 548201c910bSPantelis Antoniou int ret = 0; 549201c910bSPantelis Antoniou 550201c910bSPantelis Antoniou __of_changeset_entry_dump(ce); 551201c910bSPantelis Antoniou 552201c910bSPantelis Antoniou raw_spin_lock_irqsave(&devtree_lock, flags); 553201c910bSPantelis Antoniou switch (ce->action) { 554201c910bSPantelis Antoniou case OF_RECONFIG_ATTACH_NODE: 555201c910bSPantelis Antoniou __of_attach_node(ce->np); 556201c910bSPantelis Antoniou break; 557201c910bSPantelis Antoniou case OF_RECONFIG_DETACH_NODE: 558201c910bSPantelis Antoniou __of_detach_node(ce->np); 559201c910bSPantelis Antoniou break; 560201c910bSPantelis Antoniou case OF_RECONFIG_ADD_PROPERTY: 561201c910bSPantelis Antoniou /* If the property is in deadprops then it must be removed */ 562201c910bSPantelis Antoniou for (propp = &ce->np->deadprops; *propp; propp = &(*propp)->next) { 563201c910bSPantelis Antoniou if (*propp == ce->prop) { 564201c910bSPantelis Antoniou *propp = ce->prop->next; 565201c910bSPantelis Antoniou ce->prop->next = NULL; 566201c910bSPantelis Antoniou break; 567201c910bSPantelis Antoniou } 568201c910bSPantelis Antoniou } 569201c910bSPantelis Antoniou 570201c910bSPantelis Antoniou ret = __of_add_property(ce->np, ce->prop); 571201c910bSPantelis Antoniou if (ret) { 572*0d638a07SRob Herring pr_err("changeset: add_property failed @%pOF/%s\n", 573*0d638a07SRob Herring ce->np, 574201c910bSPantelis Antoniou ce->prop->name); 575201c910bSPantelis Antoniou break; 576201c910bSPantelis Antoniou } 577201c910bSPantelis Antoniou break; 578201c910bSPantelis Antoniou case OF_RECONFIG_REMOVE_PROPERTY: 579201c910bSPantelis Antoniou ret = __of_remove_property(ce->np, ce->prop); 580201c910bSPantelis Antoniou if (ret) { 581*0d638a07SRob Herring pr_err("changeset: remove_property failed @%pOF/%s\n", 582*0d638a07SRob Herring ce->np, 583201c910bSPantelis Antoniou ce->prop->name); 584201c910bSPantelis Antoniou break; 585201c910bSPantelis Antoniou } 586201c910bSPantelis Antoniou break; 587201c910bSPantelis Antoniou 588201c910bSPantelis Antoniou case OF_RECONFIG_UPDATE_PROPERTY: 589201c910bSPantelis Antoniou /* If the property is in deadprops then it must be removed */ 590201c910bSPantelis Antoniou for (propp = &ce->np->deadprops; *propp; propp = &(*propp)->next) { 591201c910bSPantelis Antoniou if (*propp == ce->prop) { 592201c910bSPantelis Antoniou *propp = ce->prop->next; 593201c910bSPantelis Antoniou ce->prop->next = NULL; 594201c910bSPantelis Antoniou break; 595201c910bSPantelis Antoniou } 596201c910bSPantelis Antoniou } 597201c910bSPantelis Antoniou 598201c910bSPantelis Antoniou ret = __of_update_property(ce->np, ce->prop, &old_prop); 599201c910bSPantelis Antoniou if (ret) { 600*0d638a07SRob Herring pr_err("changeset: update_property failed @%pOF/%s\n", 601*0d638a07SRob Herring ce->np, 602201c910bSPantelis Antoniou ce->prop->name); 603201c910bSPantelis Antoniou break; 604201c910bSPantelis Antoniou } 605201c910bSPantelis Antoniou break; 606201c910bSPantelis Antoniou default: 607201c910bSPantelis Antoniou ret = -EINVAL; 608201c910bSPantelis Antoniou } 609201c910bSPantelis Antoniou raw_spin_unlock_irqrestore(&devtree_lock, flags); 610201c910bSPantelis Antoniou 611201c910bSPantelis Antoniou if (ret) 612201c910bSPantelis Antoniou return ret; 613201c910bSPantelis Antoniou 614201c910bSPantelis Antoniou switch (ce->action) { 615201c910bSPantelis Antoniou case OF_RECONFIG_ATTACH_NODE: 616201c910bSPantelis Antoniou __of_attach_node_sysfs(ce->np); 617201c910bSPantelis Antoniou break; 618201c910bSPantelis Antoniou case OF_RECONFIG_DETACH_NODE: 619201c910bSPantelis Antoniou __of_detach_node_sysfs(ce->np); 620201c910bSPantelis Antoniou break; 621201c910bSPantelis Antoniou case OF_RECONFIG_ADD_PROPERTY: 622201c910bSPantelis Antoniou /* ignore duplicate names */ 623201c910bSPantelis Antoniou __of_add_property_sysfs(ce->np, ce->prop); 624201c910bSPantelis Antoniou break; 625201c910bSPantelis Antoniou case OF_RECONFIG_REMOVE_PROPERTY: 626201c910bSPantelis Antoniou __of_remove_property_sysfs(ce->np, ce->prop); 627201c910bSPantelis Antoniou break; 628201c910bSPantelis Antoniou case OF_RECONFIG_UPDATE_PROPERTY: 629201c910bSPantelis Antoniou __of_update_property_sysfs(ce->np, ce->prop, ce->old_prop); 630201c910bSPantelis Antoniou break; 631201c910bSPantelis Antoniou } 632201c910bSPantelis Antoniou 633201c910bSPantelis Antoniou return 0; 634201c910bSPantelis Antoniou } 635201c910bSPantelis Antoniou 636201c910bSPantelis Antoniou static inline int __of_changeset_entry_revert(struct of_changeset_entry *ce) 637201c910bSPantelis Antoniou { 638201c910bSPantelis Antoniou struct of_changeset_entry ce_inverted; 639201c910bSPantelis Antoniou 640201c910bSPantelis Antoniou __of_changeset_entry_invert(ce, &ce_inverted); 641201c910bSPantelis Antoniou return __of_changeset_entry_apply(&ce_inverted); 642201c910bSPantelis Antoniou } 643201c910bSPantelis Antoniou 644201c910bSPantelis Antoniou /** 645201c910bSPantelis Antoniou * of_changeset_init - Initialize a changeset for use 646201c910bSPantelis Antoniou * 647201c910bSPantelis Antoniou * @ocs: changeset pointer 648201c910bSPantelis Antoniou * 649201c910bSPantelis Antoniou * Initialize a changeset structure 650201c910bSPantelis Antoniou */ 651201c910bSPantelis Antoniou void of_changeset_init(struct of_changeset *ocs) 652201c910bSPantelis Antoniou { 653201c910bSPantelis Antoniou memset(ocs, 0, sizeof(*ocs)); 654201c910bSPantelis Antoniou INIT_LIST_HEAD(&ocs->entries); 655201c910bSPantelis Antoniou } 65618322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_init); 657201c910bSPantelis Antoniou 658201c910bSPantelis Antoniou /** 659201c910bSPantelis Antoniou * of_changeset_destroy - Destroy a changeset 660201c910bSPantelis Antoniou * 661201c910bSPantelis Antoniou * @ocs: changeset pointer 662201c910bSPantelis Antoniou * 663201c910bSPantelis Antoniou * Destroys a changeset. Note that if a changeset is applied, 664201c910bSPantelis Antoniou * its changes to the tree cannot be reverted. 665201c910bSPantelis Antoniou */ 666201c910bSPantelis Antoniou void of_changeset_destroy(struct of_changeset *ocs) 667201c910bSPantelis Antoniou { 668201c910bSPantelis Antoniou struct of_changeset_entry *ce, *cen; 669201c910bSPantelis Antoniou 670201c910bSPantelis Antoniou list_for_each_entry_safe_reverse(ce, cen, &ocs->entries, node) 671201c910bSPantelis Antoniou __of_changeset_entry_destroy(ce); 672201c910bSPantelis Antoniou } 67318322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_destroy); 674201c910bSPantelis Antoniou 67518322377SGavin Shan int __of_changeset_apply(struct of_changeset *ocs) 676201c910bSPantelis Antoniou { 677201c910bSPantelis Antoniou struct of_changeset_entry *ce; 678201c910bSPantelis Antoniou int ret; 679201c910bSPantelis Antoniou 680201c910bSPantelis Antoniou /* perform the rest of the work */ 681606ad42aSRob Herring pr_debug("changeset: applying...\n"); 682201c910bSPantelis Antoniou list_for_each_entry(ce, &ocs->entries, node) { 683201c910bSPantelis Antoniou ret = __of_changeset_entry_apply(ce); 684201c910bSPantelis Antoniou if (ret) { 685606ad42aSRob Herring pr_err("Error applying changeset (%d)\n", ret); 686201c910bSPantelis Antoniou list_for_each_entry_continue_reverse(ce, &ocs->entries, node) 687201c910bSPantelis Antoniou __of_changeset_entry_revert(ce); 688201c910bSPantelis Antoniou return ret; 689201c910bSPantelis Antoniou } 690201c910bSPantelis Antoniou } 691606ad42aSRob Herring pr_debug("changeset: applied, emitting notifiers.\n"); 692201c910bSPantelis Antoniou 693201c910bSPantelis Antoniou /* drop the global lock while emitting notifiers */ 694201c910bSPantelis Antoniou mutex_unlock(&of_mutex); 695201c910bSPantelis Antoniou list_for_each_entry(ce, &ocs->entries, node) 696201c910bSPantelis Antoniou __of_changeset_entry_notify(ce, 0); 697201c910bSPantelis Antoniou mutex_lock(&of_mutex); 698606ad42aSRob Herring pr_debug("changeset: notifiers sent.\n"); 699201c910bSPantelis Antoniou 700201c910bSPantelis Antoniou return 0; 701201c910bSPantelis Antoniou } 702201c910bSPantelis Antoniou 703201c910bSPantelis Antoniou /** 70418322377SGavin Shan * of_changeset_apply - Applies a changeset 705201c910bSPantelis Antoniou * 706201c910bSPantelis Antoniou * @ocs: changeset pointer 707201c910bSPantelis Antoniou * 70818322377SGavin Shan * Applies a changeset to the live tree. 70918322377SGavin Shan * Any side-effects of live tree state changes are applied here on 71018322377SGavin Shan * success, like creation/destruction of devices and side-effects 71118322377SGavin Shan * like creation of sysfs properties and directories. 712201c910bSPantelis Antoniou * Returns 0 on success, a negative error value in case of an error. 71318322377SGavin Shan * On error the partially applied effects are reverted. 714201c910bSPantelis Antoniou */ 71518322377SGavin Shan int of_changeset_apply(struct of_changeset *ocs) 71618322377SGavin Shan { 71718322377SGavin Shan int ret; 71818322377SGavin Shan 71918322377SGavin Shan mutex_lock(&of_mutex); 72018322377SGavin Shan ret = __of_changeset_apply(ocs); 72118322377SGavin Shan mutex_unlock(&of_mutex); 72218322377SGavin Shan 72318322377SGavin Shan return ret; 72418322377SGavin Shan } 72518322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_apply); 72618322377SGavin Shan 72718322377SGavin Shan int __of_changeset_revert(struct of_changeset *ocs) 728201c910bSPantelis Antoniou { 729201c910bSPantelis Antoniou struct of_changeset_entry *ce; 730201c910bSPantelis Antoniou int ret; 731201c910bSPantelis Antoniou 732606ad42aSRob Herring pr_debug("changeset: reverting...\n"); 733201c910bSPantelis Antoniou list_for_each_entry_reverse(ce, &ocs->entries, node) { 734201c910bSPantelis Antoniou ret = __of_changeset_entry_revert(ce); 735201c910bSPantelis Antoniou if (ret) { 736606ad42aSRob Herring pr_err("Error reverting changeset (%d)\n", ret); 737201c910bSPantelis Antoniou list_for_each_entry_continue(ce, &ocs->entries, node) 738201c910bSPantelis Antoniou __of_changeset_entry_apply(ce); 739201c910bSPantelis Antoniou return ret; 740201c910bSPantelis Antoniou } 741201c910bSPantelis Antoniou } 742606ad42aSRob Herring pr_debug("changeset: reverted, emitting notifiers.\n"); 743201c910bSPantelis Antoniou 744201c910bSPantelis Antoniou /* drop the global lock while emitting notifiers */ 745201c910bSPantelis Antoniou mutex_unlock(&of_mutex); 746201c910bSPantelis Antoniou list_for_each_entry_reverse(ce, &ocs->entries, node) 747201c910bSPantelis Antoniou __of_changeset_entry_notify(ce, 1); 748201c910bSPantelis Antoniou mutex_lock(&of_mutex); 749606ad42aSRob Herring pr_debug("changeset: notifiers sent.\n"); 750201c910bSPantelis Antoniou 751201c910bSPantelis Antoniou return 0; 752201c910bSPantelis Antoniou } 753201c910bSPantelis Antoniou 754201c910bSPantelis Antoniou /** 75518322377SGavin Shan * of_changeset_revert - Reverts an applied changeset 75618322377SGavin Shan * 75718322377SGavin Shan * @ocs: changeset pointer 75818322377SGavin Shan * 75918322377SGavin Shan * Reverts a changeset returning the state of the tree to what it 76018322377SGavin Shan * was before the application. 76118322377SGavin Shan * Any side-effects like creation/destruction of devices and 76218322377SGavin Shan * removal of sysfs properties and directories are applied. 76318322377SGavin Shan * Returns 0 on success, a negative error value in case of an error. 76418322377SGavin Shan */ 76518322377SGavin Shan int of_changeset_revert(struct of_changeset *ocs) 76618322377SGavin Shan { 76718322377SGavin Shan int ret; 76818322377SGavin Shan 76918322377SGavin Shan mutex_lock(&of_mutex); 77018322377SGavin Shan ret = __of_changeset_revert(ocs); 77118322377SGavin Shan mutex_unlock(&of_mutex); 77218322377SGavin Shan 77318322377SGavin Shan return ret; 77418322377SGavin Shan } 77518322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_revert); 77618322377SGavin Shan 77718322377SGavin Shan /** 778201c910bSPantelis Antoniou * of_changeset_action - Perform a changeset action 779201c910bSPantelis Antoniou * 780201c910bSPantelis Antoniou * @ocs: changeset pointer 781201c910bSPantelis Antoniou * @action: action to perform 782201c910bSPantelis Antoniou * @np: Pointer to device node 783201c910bSPantelis Antoniou * @prop: Pointer to property 784201c910bSPantelis Antoniou * 785201c910bSPantelis Antoniou * On action being one of: 786201c910bSPantelis Antoniou * + OF_RECONFIG_ATTACH_NODE 787201c910bSPantelis Antoniou * + OF_RECONFIG_DETACH_NODE, 788201c910bSPantelis Antoniou * + OF_RECONFIG_ADD_PROPERTY 789201c910bSPantelis Antoniou * + OF_RECONFIG_REMOVE_PROPERTY, 790201c910bSPantelis Antoniou * + OF_RECONFIG_UPDATE_PROPERTY 791201c910bSPantelis Antoniou * Returns 0 on success, a negative error value in case of an error. 792201c910bSPantelis Antoniou */ 793201c910bSPantelis Antoniou int of_changeset_action(struct of_changeset *ocs, unsigned long action, 794201c910bSPantelis Antoniou struct device_node *np, struct property *prop) 795201c910bSPantelis Antoniou { 796201c910bSPantelis Antoniou struct of_changeset_entry *ce; 797201c910bSPantelis Antoniou 798201c910bSPantelis Antoniou ce = kzalloc(sizeof(*ce), GFP_KERNEL); 799606ad42aSRob Herring if (!ce) 800201c910bSPantelis Antoniou return -ENOMEM; 801606ad42aSRob Herring 802201c910bSPantelis Antoniou /* get a reference to the node */ 803201c910bSPantelis Antoniou ce->action = action; 804201c910bSPantelis Antoniou ce->np = of_node_get(np); 805201c910bSPantelis Antoniou ce->prop = prop; 806201c910bSPantelis Antoniou 807201c910bSPantelis Antoniou if (action == OF_RECONFIG_UPDATE_PROPERTY && prop) 808201c910bSPantelis Antoniou ce->old_prop = of_find_property(np, prop->name, NULL); 809201c910bSPantelis Antoniou 810201c910bSPantelis Antoniou /* add it to the list */ 811201c910bSPantelis Antoniou list_add_tail(&ce->node, &ocs->entries); 812201c910bSPantelis Antoniou return 0; 813201c910bSPantelis Antoniou } 81418322377SGavin Shan EXPORT_SYMBOL_GPL(of_changeset_action); 815