aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPantelis Antoniou <pantelis.antoniou@konsulko.com>2014-07-04 19:58:46 +0300
committerMark Brown <broonie@kernel.org>2015-02-19 22:40:41 +0900
commit967758472ad2cb976d8317e141f3395c38213a0e (patch)
treedf014479e6724844f0a7b19d4139ca4236c1388d
parentffefdf1ee69f78759a9c0bdeca1cd020143996e5 (diff)
of: Create unlocked versions of node and property add/remove functions
The DT overlay code will need to manipulate nodes and properties while already holding the devicetree lock, or on nodes that are not yet attached to the tree, but the current helper functions don't allow that. Extract the core behaviour from the accessors and create the following unlocked variants. The unlocked variants require either the lock to already be held or for the nodes to be detached from the tree. Changes to live nodes will not get updated in sysfs, so the caller must arrange for housekeeping to take place after dropping the lock. The new functions are: __of_add_property(), __of_remove_property(), __of_update_property(), __of_attach_node() and __of_detach_node(). Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com> [Remove unnecessary diff hunks and rewrite commit text] Signed-off-by: Grant Likely <grant.likely@linaro.org> (cherry picked from commit d8c50088417ebf61ad8b132caad20d10f7736034) Signed-off-by: Mark Brown <broonie@kernel.org> Conflicts: drivers/of/base.c drivers/of/of_private.h
-rw-r--r--drivers/of/base.c92
-rw-r--r--drivers/of/dynamic.c63
-rw-r--r--drivers/of/of_private.h18
3 files changed, 106 insertions, 67 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c
index e653e658e76e..a2f4be16f100 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1585,7 +1585,7 @@ EXPORT_SYMBOL(of_count_phandle_with_args);
/**
* __of_add_property - Add a property to a node without lock operations
*/
-static int __of_add_property(struct device_node *np, struct property *prop)
+int __of_add_property(struct device_node *np, struct property *prop)
{
struct property **next;
@@ -1624,6 +1624,25 @@ int of_add_property(struct device_node *np, struct property *prop)
return rc;
}
+int __of_remove_property(struct device_node *np, struct property *prop)
+{
+ struct property **next;
+
+ for (next = &np->properties; *next; next = &(*next)->next) {
+ if (*next == prop)
+ break;
+ }
+ if (*next == NULL)
+ return -ENODEV;
+
+ /* found the node */
+ *next = prop->next;
+ prop->next = np->deadprops;
+ np->deadprops = prop;
+
+ return 0;
+}
+
/**
* of_remove_property - Remove a property from a node.
*
@@ -1634,9 +1653,7 @@ int of_add_property(struct device_node *np, struct property *prop)
*/
int of_remove_property(struct device_node *np, struct property *prop)
{
- struct property **next;
unsigned long flags;
- int found = 0;
int rc;
rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop);
@@ -1644,22 +1661,11 @@ int of_remove_property(struct device_node *np, struct property *prop)
return rc;
raw_spin_lock_irqsave(&devtree_lock, flags);
- next = &np->properties;
- while (*next) {
- if (*next == prop) {
- /* found the node */
- *next = prop->next;
- prop->next = np->deadprops;
- np->deadprops = prop;
- found = 1;
- break;
- }
- next = &(*next)->next;
- }
+ rc = __of_remove_property(np, prop);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
- if (!found)
- return -ENODEV;
+ if (rc)
+ return rc;
/* at early boot, bail hear and defer setup to of_init() */
if (!of_kset)
@@ -1670,6 +1676,32 @@ int of_remove_property(struct device_node *np, struct property *prop)
return 0;
}
+int __of_update_property(struct device_node *np, struct property *newprop,
+ struct property **oldpropp)
+{
+ struct property **next, *oldprop;
+
+ for (next = &np->properties; *next; next = &(*next)->next) {
+ if (of_prop_cmp((*next)->name, newprop->name) == 0)
+ break;
+ }
+ *oldpropp = oldprop = *next;
+
+ if (oldprop) {
+ /* replace the node */
+ newprop->next = oldprop->next;
+ *next = newprop;
+ oldprop->next = np->deadprops;
+ np->deadprops = oldprop;
+ } else {
+ /* new node */
+ newprop->next = NULL;
+ *next = newprop;
+ }
+
+ return 0;
+}
+
/*
* of_update_property - Update a property in a node, if the property does
* not exist, add it.
@@ -1681,35 +1713,19 @@ int of_remove_property(struct device_node *np, struct property *prop)
*/
int of_update_property(struct device_node *np, struct property *newprop)
{
- struct property **next, *oldprop;
+ struct property *oldprop;
unsigned long flags;
int rc, found = 0;
- rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop);
- if (rc)
- return rc;
-
if (!newprop->name)
return -EINVAL;
- oldprop = of_find_property(np, newprop->name, NULL);
- if (!oldprop)
- return of_add_property(np, newprop);
+ rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop);
+ if (rc)
+ return rc;
raw_spin_lock_irqsave(&devtree_lock, flags);
- next = &np->properties;
- while (*next) {
- if (*next == oldprop) {
- /* found the node */
- newprop->next = oldprop->next;
- *next = newprop;
- oldprop->next = np->deadprops;
- np->deadprops = oldprop;
- found = 1;
- break;
- }
- next = &(*next)->next;
- }
+ rc = __of_update_property(np, newprop, &oldprop);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (rc)
return rc;
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 125994330437..2f1c84eb3dba 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -94,6 +94,15 @@ int of_property_notify(int action, struct device_node *np,
return of_reconfig_notify(action, &pr);
}
+void __of_attach_node(struct device_node *np)
+{
+ np->sibling = np->parent->child;
+ np->allnext = np->parent->allnext;
+ np->parent->allnext = np;
+ np->parent->child = np;
+ of_node_clear_flag(np, OF_DETACHED);
+}
+
/**
* of_attach_node() - Plug a device node into the tree and global list.
*/
@@ -107,46 +116,23 @@ int of_attach_node(struct device_node *np)
return rc;
raw_spin_lock_irqsave(&devtree_lock, flags);
- np->sibling = np->parent->child;
- np->allnext = np->parent->allnext;
- np->parent->allnext = np;
- np->parent->child = np;
- of_node_clear_flag(np, OF_DETACHED);
+ __of_attach_node(np);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
of_node_add(np);
return 0;
}
-/**
- * of_detach_node() - "Unplug" a node from the device tree.
- *
- * The caller must hold a reference to the node. The memory associated with
- * the node is not freed until its refcount goes to zero.
- */
-int of_detach_node(struct device_node *np)
+void __of_detach_node(struct device_node *np)
{
struct device_node *parent;
- unsigned long flags;
- int rc = 0;
-
- rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np);
- if (rc)
- return rc;
- raw_spin_lock_irqsave(&devtree_lock, flags);
-
- if (of_node_check_flag(np, OF_DETACHED)) {
- /* someone already detached it */
- raw_spin_unlock_irqrestore(&devtree_lock, flags);
- return rc;
- }
+ if (WARN_ON(of_node_check_flag(np, OF_DETACHED)))
+ return;
parent = np->parent;
- if (!parent) {
- raw_spin_unlock_irqrestore(&devtree_lock, flags);
- return rc;
- }
+ if (WARN_ON(!parent))
+ return;
if (of_allnodes == np)
of_allnodes = np->allnext;
@@ -171,6 +157,25 @@ int of_detach_node(struct device_node *np)
}
of_node_set_flag(np, OF_DETACHED);
+}
+
+/**
+ * of_detach_node() - "Unplug" a node from the device tree.
+ *
+ * The caller must hold a reference to the node. The memory associated with
+ * the node is not freed until its refcount goes to zero.
+ */
+int of_detach_node(struct device_node *np)
+{
+ unsigned long flags;
+ int rc = 0;
+
+ rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np);
+ if (rc)
+ return rc;
+
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+ __of_detach_node(np);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
of_node_remove(np);
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index aade823aa1cc..0384f097bcc8 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -51,4 +51,22 @@ static inline int of_property_notify(int action, struct device_node *np,
}
#endif /* CONFIG_OF_DYNAMIC */
+/**
+ * General utilities for working with live trees.
+ *
+ * All functions with two leading underscores operate
+ * without taking node references, so you either have to
+ * own the devtree lock or work on detached trees only.
+ */
+struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags);
+struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags);
+
+extern int __of_add_property(struct device_node *np, struct property *prop);
+extern int __of_remove_property(struct device_node *np, struct property *prop);
+extern int __of_update_property(struct device_node *np,
+ struct property *newprop, struct property **oldprop);
+
+extern void __of_attach_node(struct device_node *np);
+extern void __of_detach_node(struct device_node *np);
+
#endif /* _LINUX_OF_PRIVATE_H */