aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 */