aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPantelis Antoniou <pantelis.antoniou@konsulko.com>2014-07-04 12:58:46 -0400
committerGrant Likely <grant.likely@linaro.org>2014-07-16 10:16:52 -0400
commitd8c50088417ebf61ad8b132caad20d10f7736034 (patch)
tree40f3105ec3c03601e22301f36d207362e6d1226e
parent698433963b98d6de7b102c242805c99fda4fa1fb (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>
-rw-r--r--drivers/of/base.c91
-rw-r--r--drivers/of/dynamic.c63
-rw-r--r--drivers/of/of_private.h8
3 files changed, 96 insertions, 66 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 0d8955605738..b403f9d98461 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1659,7 +1659,7 @@ EXPORT_SYMBOL(of_count_phandle_with_args);
1659/** 1659/**
1660 * __of_add_property - Add a property to a node without lock operations 1660 * __of_add_property - Add a property to a node without lock operations
1661 */ 1661 */
1662static int __of_add_property(struct device_node *np, struct property *prop) 1662int __of_add_property(struct device_node *np, struct property *prop)
1663{ 1663{
1664 struct property **next; 1664 struct property **next;
1665 1665
@@ -1701,6 +1701,25 @@ int of_add_property(struct device_node *np, struct property *prop)
1701 return rc; 1701 return rc;
1702} 1702}
1703 1703
1704int __of_remove_property(struct device_node *np, struct property *prop)
1705{
1706 struct property **next;
1707
1708 for (next = &np->properties; *next; next = &(*next)->next) {
1709 if (*next == prop)
1710 break;
1711 }
1712 if (*next == NULL)
1713 return -ENODEV;
1714
1715 /* found the node */
1716 *next = prop->next;
1717 prop->next = np->deadprops;
1718 np->deadprops = prop;
1719
1720 return 0;
1721}
1722
1704/** 1723/**
1705 * of_remove_property - Remove a property from a node. 1724 * of_remove_property - Remove a property from a node.
1706 * 1725 *
@@ -1711,9 +1730,7 @@ int of_add_property(struct device_node *np, struct property *prop)
1711 */ 1730 */
1712int of_remove_property(struct device_node *np, struct property *prop) 1731int of_remove_property(struct device_node *np, struct property *prop)
1713{ 1732{
1714 struct property **next;
1715 unsigned long flags; 1733 unsigned long flags;
1716 int found = 0;
1717 int rc; 1734 int rc;
1718 1735
1719 rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop); 1736 rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop);
@@ -1721,22 +1738,11 @@ int of_remove_property(struct device_node *np, struct property *prop)
1721 return rc; 1738 return rc;
1722 1739
1723 raw_spin_lock_irqsave(&devtree_lock, flags); 1740 raw_spin_lock_irqsave(&devtree_lock, flags);
1724 next = &np->properties; 1741 rc = __of_remove_property(np, prop);
1725 while (*next) {
1726 if (*next == prop) {
1727 /* found the node */
1728 *next = prop->next;
1729 prop->next = np->deadprops;
1730 np->deadprops = prop;
1731 found = 1;
1732 break;
1733 }
1734 next = &(*next)->next;
1735 }
1736 raw_spin_unlock_irqrestore(&devtree_lock, flags); 1742 raw_spin_unlock_irqrestore(&devtree_lock, flags);
1737 1743
1738 if (!found) 1744 if (rc)
1739 return -ENODEV; 1745 return rc;
1740 1746
1741 /* at early boot, bail hear and defer setup to of_init() */ 1747 /* at early boot, bail hear and defer setup to of_init() */
1742 if (!of_kset) 1748 if (!of_kset)
@@ -1747,6 +1753,32 @@ int of_remove_property(struct device_node *np, struct property *prop)
1747 return 0; 1753 return 0;
1748} 1754}
1749 1755
1756int __of_update_property(struct device_node *np, struct property *newprop,
1757 struct property **oldpropp)
1758{
1759 struct property **next, *oldprop;
1760
1761 for (next = &np->properties; *next; next = &(*next)->next) {
1762 if (of_prop_cmp((*next)->name, newprop->name) == 0)
1763 break;
1764 }
1765 *oldpropp = oldprop = *next;
1766
1767 if (oldprop) {
1768 /* replace the node */
1769 newprop->next = oldprop->next;
1770 *next = newprop;
1771 oldprop->next = np->deadprops;
1772 np->deadprops = oldprop;
1773 } else {
1774 /* new node */
1775 newprop->next = NULL;
1776 *next = newprop;
1777 }
1778
1779 return 0;
1780}
1781
1750/* 1782/*
1751 * of_update_property - Update a property in a node, if the property does 1783 * of_update_property - Update a property in a node, if the property does
1752 * not exist, add it. 1784 * not exist, add it.
@@ -1758,34 +1790,19 @@ int of_remove_property(struct device_node *np, struct property *prop)
1758 */ 1790 */
1759int of_update_property(struct device_node *np, struct property *newprop) 1791int of_update_property(struct device_node *np, struct property *newprop)
1760{ 1792{
1761 struct property **next, *oldprop; 1793 struct property *oldprop;
1762 unsigned long flags; 1794 unsigned long flags;
1763 int rc; 1795 int rc;
1764 1796
1797 if (!newprop->name)
1798 return -EINVAL;
1799
1765 rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop); 1800 rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop);
1766 if (rc) 1801 if (rc)
1767 return rc; 1802 return rc;
1768 1803
1769 if (!newprop->name)
1770 return -EINVAL;
1771
1772 raw_spin_lock_irqsave(&devtree_lock, flags); 1804 raw_spin_lock_irqsave(&devtree_lock, flags);
1773 next = &np->properties; 1805 rc = __of_update_property(np, newprop, &oldprop);
1774 oldprop = __of_find_property(np, newprop->name, NULL);
1775 if (!oldprop) {
1776 /* add the new node */
1777 rc = __of_add_property(np, newprop);
1778 } else while (*next) {
1779 /* replace the node */
1780 if (*next == oldprop) {
1781 newprop->next = oldprop->next;
1782 *next = newprop;
1783 oldprop->next = np->deadprops;
1784 np->deadprops = oldprop;
1785 break;
1786 }
1787 next = &(*next)->next;
1788 }
1789 raw_spin_unlock_irqrestore(&devtree_lock, flags); 1806 raw_spin_unlock_irqrestore(&devtree_lock, flags);
1790 if (rc) 1807 if (rc)
1791 return rc; 1808 return rc;
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index e0c4c6e25980..75fcc66fcefd 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,
94 return of_reconfig_notify(action, &pr); 94 return of_reconfig_notify(action, &pr);
95} 95}
96 96
97void __of_attach_node(struct device_node *np)
98{
99 np->sibling = np->parent->child;
100 np->allnext = np->parent->allnext;
101 np->parent->allnext = np;
102 np->parent->child = np;
103 of_node_clear_flag(np, OF_DETACHED);
104}
105
97/** 106/**
98 * of_attach_node() - Plug a device node into the tree and global list. 107 * of_attach_node() - Plug a device node into the tree and global list.
99 */ 108 */
@@ -107,46 +116,23 @@ int of_attach_node(struct device_node *np)
107 return rc; 116 return rc;
108 117
109 raw_spin_lock_irqsave(&devtree_lock, flags); 118 raw_spin_lock_irqsave(&devtree_lock, flags);
110 np->sibling = np->parent->child; 119 __of_attach_node(np);
111 np->allnext = np->parent->allnext;
112 np->parent->allnext = np;
113 np->parent->child = np;
114 of_node_clear_flag(np, OF_DETACHED);
115 raw_spin_unlock_irqrestore(&devtree_lock, flags); 120 raw_spin_unlock_irqrestore(&devtree_lock, flags);
116 121
117 of_node_add(np); 122 of_node_add(np);
118 return 0; 123 return 0;
119} 124}
120 125
121/** 126void __of_detach_node(struct device_node *np)
122 * of_detach_node() - "Unplug" a node from the device tree.
123 *
124 * The caller must hold a reference to the node. The memory associated with
125 * the node is not freed until its refcount goes to zero.
126 */
127int of_detach_node(struct device_node *np)
128{ 127{
129 struct device_node *parent; 128 struct device_node *parent;
130 unsigned long flags;
131 int rc = 0;
132
133 rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np);
134 if (rc)
135 return rc;
136 129
137 raw_spin_lock_irqsave(&devtree_lock, flags); 130 if (WARN_ON(of_node_check_flag(np, OF_DETACHED)))
138 131 return;
139 if (of_node_check_flag(np, OF_DETACHED)) {
140 /* someone already detached it */
141 raw_spin_unlock_irqrestore(&devtree_lock, flags);
142 return rc;
143 }
144 132
145 parent = np->parent; 133 parent = np->parent;
146 if (!parent) { 134 if (WARN_ON(!parent))
147 raw_spin_unlock_irqrestore(&devtree_lock, flags); 135 return;
148 return rc;
149 }
150 136
151 if (of_allnodes == np) 137 if (of_allnodes == np)
152 of_allnodes = np->allnext; 138 of_allnodes = np->allnext;
@@ -171,6 +157,25 @@ int of_detach_node(struct device_node *np)
171 } 157 }
172 158
173 of_node_set_flag(np, OF_DETACHED); 159 of_node_set_flag(np, OF_DETACHED);
160}
161
162/**
163 * of_detach_node() - "Unplug" a node from the device tree.
164 *
165 * The caller must hold a reference to the node. The memory associated with
166 * the node is not freed until its refcount goes to zero.
167 */
168int of_detach_node(struct device_node *np)
169{
170 unsigned long flags;
171 int rc = 0;
172
173 rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np);
174 if (rc)
175 return rc;
176
177 raw_spin_lock_irqsave(&devtree_lock, flags);
178 __of_detach_node(np);
174 raw_spin_unlock_irqrestore(&devtree_lock, flags); 179 raw_spin_unlock_irqrestore(&devtree_lock, flags);
175 180
176 of_node_remove(np); 181 of_node_remove(np);
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 1799ed2b3808..0f6089722af9 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -61,4 +61,12 @@ static inline int of_property_notify(int action, struct device_node *np,
61struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags); 61struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags);
62struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags); 62struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags);
63 63
64extern int __of_add_property(struct device_node *np, struct property *prop);
65extern int __of_remove_property(struct device_node *np, struct property *prop);
66extern int __of_update_property(struct device_node *np,
67 struct property *newprop, struct property **oldprop);
68
69extern void __of_attach_node(struct device_node *np);
70extern void __of_detach_node(struct device_node *np);
71
64#endif /* _LINUX_OF_PRIVATE_H */ 72#endif /* _LINUX_OF_PRIVATE_H */