diff options
-rw-r--r-- | drivers/of/base.c | 96 | ||||
-rw-r--r-- | drivers/of/dynamic.c | 12 | ||||
-rw-r--r-- | drivers/of/of_private.h | 10 | ||||
-rw-r--r-- | include/linux/of.h | 2 |
4 files changed, 69 insertions, 51 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index b403f9d98461..ad4929cbd876 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -37,10 +37,13 @@ struct device_node *of_chosen; | |||
37 | struct device_node *of_aliases; | 37 | struct device_node *of_aliases; |
38 | static struct device_node *of_stdout; | 38 | static struct device_node *of_stdout; |
39 | 39 | ||
40 | static struct kset *of_kset; | 40 | struct kset *of_kset; |
41 | 41 | ||
42 | /* | 42 | /* |
43 | * Used to protect the of_aliases, to hold off addition of nodes to sysfs | 43 | * Used to protect the of_aliases, to hold off addition of nodes to sysfs. |
44 | * This mutex must be held whenever modifications are being made to the | ||
45 | * device tree. The of_{attach,detach}_node() and | ||
46 | * of_{add,remove,update}_property() helpers make sure this happens. | ||
44 | */ | 47 | */ |
45 | DEFINE_MUTEX(of_mutex); | 48 | DEFINE_MUTEX(of_mutex); |
46 | 49 | ||
@@ -127,13 +130,16 @@ static const char *safe_name(struct kobject *kobj, const char *orig_name) | |||
127 | return name; | 130 | return name; |
128 | } | 131 | } |
129 | 132 | ||
130 | static int __of_add_property_sysfs(struct device_node *np, struct property *pp) | 133 | int __of_add_property_sysfs(struct device_node *np, struct property *pp) |
131 | { | 134 | { |
132 | int rc; | 135 | int rc; |
133 | 136 | ||
134 | /* Important: Don't leak passwords */ | 137 | /* Important: Don't leak passwords */ |
135 | bool secure = strncmp(pp->name, "security-", 9) == 0; | 138 | bool secure = strncmp(pp->name, "security-", 9) == 0; |
136 | 139 | ||
140 | if (!of_kset || !of_node_is_attached(np)) | ||
141 | return 0; | ||
142 | |||
137 | sysfs_bin_attr_init(&pp->attr); | 143 | sysfs_bin_attr_init(&pp->attr); |
138 | pp->attr.attr.name = safe_name(&np->kobj, pp->name); | 144 | pp->attr.attr.name = safe_name(&np->kobj, pp->name); |
139 | pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO; | 145 | pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO; |
@@ -145,12 +151,15 @@ static int __of_add_property_sysfs(struct device_node *np, struct property *pp) | |||
145 | return rc; | 151 | return rc; |
146 | } | 152 | } |
147 | 153 | ||
148 | static int __of_node_add(struct device_node *np) | 154 | int __of_attach_node_sysfs(struct device_node *np) |
149 | { | 155 | { |
150 | const char *name; | 156 | const char *name; |
151 | struct property *pp; | 157 | struct property *pp; |
152 | int rc; | 158 | int rc; |
153 | 159 | ||
160 | if (!of_kset) | ||
161 | return 0; | ||
162 | |||
154 | np->kobj.kset = of_kset; | 163 | np->kobj.kset = of_kset; |
155 | if (!np->parent) { | 164 | if (!np->parent) { |
156 | /* Nodes without parents are new top level trees */ | 165 | /* Nodes without parents are new top level trees */ |
@@ -172,26 +181,6 @@ static int __of_node_add(struct device_node *np) | |||
172 | return 0; | 181 | return 0; |
173 | } | 182 | } |
174 | 183 | ||
175 | int of_node_add(struct device_node *np) | ||
176 | { | ||
177 | int rc = 0; | ||
178 | |||
179 | BUG_ON(!of_node_is_initialized(np)); | ||
180 | |||
181 | /* | ||
182 | * Grab the mutex here so that in a race condition between of_init() and | ||
183 | * of_node_add(), node addition will still be consistent. | ||
184 | */ | ||
185 | mutex_lock(&of_mutex); | ||
186 | if (of_kset) | ||
187 | rc = __of_node_add(np); | ||
188 | else | ||
189 | /* This scenario may be perfectly valid, but report it anyway */ | ||
190 | pr_info("of_node_add(%s) before of_init()\n", np->full_name); | ||
191 | mutex_unlock(&of_mutex); | ||
192 | return rc; | ||
193 | } | ||
194 | |||
195 | static int __init of_init(void) | 184 | static int __init of_init(void) |
196 | { | 185 | { |
197 | struct device_node *np; | 186 | struct device_node *np; |
@@ -204,7 +193,7 @@ static int __init of_init(void) | |||
204 | return -ENOMEM; | 193 | return -ENOMEM; |
205 | } | 194 | } |
206 | for_each_of_allnodes(np) | 195 | for_each_of_allnodes(np) |
207 | __of_node_add(np); | 196 | __of_attach_node_sysfs(np); |
208 | mutex_unlock(&of_mutex); | 197 | mutex_unlock(&of_mutex); |
209 | 198 | ||
210 | /* Symlink in /proc as required by userspace ABI */ | 199 | /* Symlink in /proc as required by userspace ABI */ |
@@ -1689,15 +1678,17 @@ int of_add_property(struct device_node *np, struct property *prop) | |||
1689 | if (rc) | 1678 | if (rc) |
1690 | return rc; | 1679 | return rc; |
1691 | 1680 | ||
1681 | mutex_lock(&of_mutex); | ||
1682 | |||
1692 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1683 | raw_spin_lock_irqsave(&devtree_lock, flags); |
1693 | rc = __of_add_property(np, prop); | 1684 | rc = __of_add_property(np, prop); |
1694 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1685 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
1695 | if (rc) | ||
1696 | return rc; | ||
1697 | 1686 | ||
1698 | if (of_node_is_attached(np)) | 1687 | if (!rc) |
1699 | __of_add_property_sysfs(np, prop); | 1688 | __of_add_property_sysfs(np, prop); |
1700 | 1689 | ||
1690 | mutex_unlock(&of_mutex); | ||
1691 | |||
1701 | return rc; | 1692 | return rc; |
1702 | } | 1693 | } |
1703 | 1694 | ||
@@ -1720,6 +1711,13 @@ int __of_remove_property(struct device_node *np, struct property *prop) | |||
1720 | return 0; | 1711 | return 0; |
1721 | } | 1712 | } |
1722 | 1713 | ||
1714 | void __of_remove_property_sysfs(struct device_node *np, struct property *prop) | ||
1715 | { | ||
1716 | /* at early boot, bail here and defer setup to of_init() */ | ||
1717 | if (of_kset && of_node_is_attached(np)) | ||
1718 | sysfs_remove_bin_file(&np->kobj, &prop->attr); | ||
1719 | } | ||
1720 | |||
1723 | /** | 1721 | /** |
1724 | * of_remove_property - Remove a property from a node. | 1722 | * of_remove_property - Remove a property from a node. |
1725 | * | 1723 | * |
@@ -1737,20 +1735,18 @@ int of_remove_property(struct device_node *np, struct property *prop) | |||
1737 | if (rc) | 1735 | if (rc) |
1738 | return rc; | 1736 | return rc; |
1739 | 1737 | ||
1738 | mutex_lock(&of_mutex); | ||
1739 | |||
1740 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1740 | raw_spin_lock_irqsave(&devtree_lock, flags); |
1741 | rc = __of_remove_property(np, prop); | 1741 | rc = __of_remove_property(np, prop); |
1742 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1742 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
1743 | 1743 | ||
1744 | if (rc) | 1744 | if (!rc) |
1745 | return rc; | 1745 | __of_remove_property_sysfs(np, prop); |
1746 | |||
1747 | /* at early boot, bail hear and defer setup to of_init() */ | ||
1748 | if (!of_kset) | ||
1749 | return 0; | ||
1750 | 1746 | ||
1751 | sysfs_remove_bin_file(&np->kobj, &prop->attr); | 1747 | mutex_unlock(&of_mutex); |
1752 | 1748 | ||
1753 | return 0; | 1749 | return rc; |
1754 | } | 1750 | } |
1755 | 1751 | ||
1756 | int __of_update_property(struct device_node *np, struct property *newprop, | 1752 | int __of_update_property(struct device_node *np, struct property *newprop, |
@@ -1779,6 +1775,18 @@ int __of_update_property(struct device_node *np, struct property *newprop, | |||
1779 | return 0; | 1775 | return 0; |
1780 | } | 1776 | } |
1781 | 1777 | ||
1778 | void __of_update_property_sysfs(struct device_node *np, struct property *newprop, | ||
1779 | struct property *oldprop) | ||
1780 | { | ||
1781 | /* At early boot, bail out and defer setup to of_init() */ | ||
1782 | if (!of_kset) | ||
1783 | return; | ||
1784 | |||
1785 | if (oldprop) | ||
1786 | sysfs_remove_bin_file(&np->kobj, &oldprop->attr); | ||
1787 | __of_add_property_sysfs(np, newprop); | ||
1788 | } | ||
1789 | |||
1782 | /* | 1790 | /* |
1783 | * of_update_property - Update a property in a node, if the property does | 1791 | * of_update_property - Update a property in a node, if the property does |
1784 | * not exist, add it. | 1792 | * not exist, add it. |
@@ -1801,22 +1809,18 @@ int of_update_property(struct device_node *np, struct property *newprop) | |||
1801 | if (rc) | 1809 | if (rc) |
1802 | return rc; | 1810 | return rc; |
1803 | 1811 | ||
1812 | mutex_lock(&of_mutex); | ||
1813 | |||
1804 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1814 | raw_spin_lock_irqsave(&devtree_lock, flags); |
1805 | rc = __of_update_property(np, newprop, &oldprop); | 1815 | rc = __of_update_property(np, newprop, &oldprop); |
1806 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1816 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
1807 | if (rc) | ||
1808 | return rc; | ||
1809 | 1817 | ||
1810 | /* At early boot, bail out and defer setup to of_init() */ | 1818 | if (!rc) |
1811 | if (!of_kset) | 1819 | __of_update_property_sysfs(np, newprop, oldprop); |
1812 | return 0; | ||
1813 | 1820 | ||
1814 | /* Update the sysfs attribute */ | 1821 | mutex_unlock(&of_mutex); |
1815 | if (oldprop) | ||
1816 | sysfs_remove_bin_file(&np->kobj, &oldprop->attr); | ||
1817 | __of_add_property_sysfs(np, newprop); | ||
1818 | 1822 | ||
1819 | return 0; | 1823 | return rc; |
1820 | } | 1824 | } |
1821 | 1825 | ||
1822 | static void of_alias_add(struct alias_prop *ap, struct device_node *np, | 1826 | static void of_alias_add(struct alias_prop *ap, struct device_node *np, |
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index 75fcc66fcefd..c875787fa394 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c | |||
@@ -41,11 +41,13 @@ void of_node_put(struct device_node *node) | |||
41 | } | 41 | } |
42 | EXPORT_SYMBOL(of_node_put); | 42 | EXPORT_SYMBOL(of_node_put); |
43 | 43 | ||
44 | static void of_node_remove(struct device_node *np) | 44 | void __of_detach_node_sysfs(struct device_node *np) |
45 | { | 45 | { |
46 | struct property *pp; | 46 | struct property *pp; |
47 | 47 | ||
48 | BUG_ON(!of_node_is_initialized(np)); | 48 | BUG_ON(!of_node_is_initialized(np)); |
49 | if (!of_kset) | ||
50 | return; | ||
49 | 51 | ||
50 | /* only remove properties if on sysfs */ | 52 | /* only remove properties if on sysfs */ |
51 | if (of_node_is_attached(np)) { | 53 | if (of_node_is_attached(np)) { |
@@ -115,11 +117,13 @@ int of_attach_node(struct device_node *np) | |||
115 | if (rc) | 117 | if (rc) |
116 | return rc; | 118 | return rc; |
117 | 119 | ||
120 | mutex_lock(&of_mutex); | ||
118 | raw_spin_lock_irqsave(&devtree_lock, flags); | 121 | raw_spin_lock_irqsave(&devtree_lock, flags); |
119 | __of_attach_node(np); | 122 | __of_attach_node(np); |
120 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 123 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
121 | 124 | ||
122 | of_node_add(np); | 125 | __of_attach_node_sysfs(np); |
126 | mutex_unlock(&of_mutex); | ||
123 | return 0; | 127 | return 0; |
124 | } | 128 | } |
125 | 129 | ||
@@ -174,11 +178,13 @@ int of_detach_node(struct device_node *np) | |||
174 | if (rc) | 178 | if (rc) |
175 | return rc; | 179 | return rc; |
176 | 180 | ||
181 | mutex_lock(&of_mutex); | ||
177 | raw_spin_lock_irqsave(&devtree_lock, flags); | 182 | raw_spin_lock_irqsave(&devtree_lock, flags); |
178 | __of_detach_node(np); | 183 | __of_detach_node(np); |
179 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 184 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
180 | 185 | ||
181 | of_node_remove(np); | 186 | __of_detach_node_sysfs(np); |
187 | mutex_unlock(&of_mutex); | ||
182 | return rc; | 188 | return rc; |
183 | } | 189 | } |
184 | 190 | ||
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index 0f6089722af9..0d99ba8caeed 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h | |||
@@ -33,6 +33,8 @@ struct alias_prop { | |||
33 | 33 | ||
34 | extern struct mutex of_mutex; | 34 | extern struct mutex of_mutex; |
35 | extern struct list_head aliases_lookup; | 35 | extern struct list_head aliases_lookup; |
36 | extern struct kset *of_kset; | ||
37 | |||
36 | 38 | ||
37 | static inline struct device_node *kobj_to_device_node(struct kobject *kobj) | 39 | static inline struct device_node *kobj_to_device_node(struct kobject *kobj) |
38 | { | 40 | { |
@@ -62,11 +64,19 @@ 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); | 64 | struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags); |
63 | 65 | ||
64 | extern int __of_add_property(struct device_node *np, struct property *prop); | 66 | extern int __of_add_property(struct device_node *np, struct property *prop); |
67 | extern int __of_add_property_sysfs(struct device_node *np, | ||
68 | struct property *prop); | ||
65 | extern int __of_remove_property(struct device_node *np, struct property *prop); | 69 | extern int __of_remove_property(struct device_node *np, struct property *prop); |
70 | extern void __of_remove_property_sysfs(struct device_node *np, | ||
71 | struct property *prop); | ||
66 | extern int __of_update_property(struct device_node *np, | 72 | extern int __of_update_property(struct device_node *np, |
67 | struct property *newprop, struct property **oldprop); | 73 | struct property *newprop, struct property **oldprop); |
74 | extern void __of_update_property_sysfs(struct device_node *np, | ||
75 | struct property *newprop, struct property *oldprop); | ||
68 | 76 | ||
69 | extern void __of_attach_node(struct device_node *np); | 77 | extern void __of_attach_node(struct device_node *np); |
78 | extern int __of_attach_node_sysfs(struct device_node *np); | ||
70 | extern void __of_detach_node(struct device_node *np); | 79 | extern void __of_detach_node(struct device_node *np); |
80 | extern void __of_detach_node_sysfs(struct device_node *np); | ||
71 | 81 | ||
72 | #endif /* _LINUX_OF_PRIVATE_H */ | 82 | #endif /* _LINUX_OF_PRIVATE_H */ |
diff --git a/include/linux/of.h b/include/linux/of.h index abf829a1f150..705fa12fca7f 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
@@ -74,8 +74,6 @@ struct of_phandle_args { | |||
74 | uint32_t args[MAX_PHANDLE_ARGS]; | 74 | uint32_t args[MAX_PHANDLE_ARGS]; |
75 | }; | 75 | }; |
76 | 76 | ||
77 | extern int of_node_add(struct device_node *node); | ||
78 | |||
79 | /* initialize a node */ | 77 | /* initialize a node */ |
80 | extern struct kobj_type of_node_ktype; | 78 | extern struct kobj_type of_node_ktype; |
81 | static inline void of_node_init(struct device_node *node) | 79 | static inline void of_node_init(struct device_node *node) |