diff options
-rw-r--r-- | drivers/of/base.c | 91 | ||||
-rw-r--r-- | drivers/of/dynamic.c | 63 | ||||
-rw-r--r-- | drivers/of/of_private.h | 8 |
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 | */ |
1662 | static int __of_add_property(struct device_node *np, struct property *prop) | 1662 | int __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 | ||
1704 | int __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 | */ |
1712 | int of_remove_property(struct device_node *np, struct property *prop) | 1731 | int 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 | ||
1756 | int __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 | */ |
1759 | int of_update_property(struct device_node *np, struct property *newprop) | 1791 | int 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 | ||
97 | void __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 | /** | 126 | void __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 | */ | ||
127 | int 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 | */ | ||
168 | int 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, | |||
61 | struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags); | 61 | struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags); |
62 | struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags); | 62 | struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags); |
63 | 63 | ||
64 | extern int __of_add_property(struct device_node *np, struct property *prop); | ||
65 | extern int __of_remove_property(struct device_node *np, struct property *prop); | ||
66 | extern int __of_update_property(struct device_node *np, | ||
67 | struct property *newprop, struct property **oldprop); | ||
68 | |||
69 | extern void __of_attach_node(struct device_node *np); | ||
70 | extern void __of_detach_node(struct device_node *np); | ||
71 | |||
64 | #endif /* _LINUX_OF_PRIVATE_H */ | 72 | #endif /* _LINUX_OF_PRIVATE_H */ |