aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/of
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@linaro.org>2014-07-23 19:05:06 -0400
committerGrant Likely <grant.likely@linaro.org>2014-07-23 19:05:06 -0400
commit8a2b22a2595bf89d4396530edf8388159fad9d83 (patch)
treec07a9d0afabc92e922f0894e2cc13245a8c58ab4 /drivers/of
parentd8c50088417ebf61ad8b132caad20d10f7736034 (diff)
of: Make devicetree sysfs update functions consistent.
All of the DT modification functions are split into two parts, the first part manipulates the DT data structure, and the second part updates sysfs, but the code isn't very consistent about how the second half is called. They don't all enforce the same rules about when it is valid to update sysfs, and there isn't any clarity on locking. The transactional DT modification feature that is coming also needs access to these functions so that it can perform all the structure changes together, and then all the sysfs updates as a second stage instead of doing each one at a time. Fix up the second have by creating a separate __of_*_sysfs() function for each of the helpers. The new functions have consistent naming (ie. of_node_add() becomes __of_attach_node_sysfs()) and all of them now defer if of_init hasn't been called yet. Callers of the new functions must hold the of_mutex to ensure there are no race conditions with of_init(). The mutex ensures that there will only ever be one writer to the tree at any given time. There can still be any number of readers and the raw_spin_lock is still used to make sure access to the data structure is still consistent. Finally, put the function prototypes into of_private.h so they are accessible to the transaction code. Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com> [grant.likely: Changed suffix from _post to _sysfs to match existing code] [grant.likely: Reorganized to eliminate trivial wrappers] Signed-off-by: Grant Likely <grant.likely@linaro.org>
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/base.c96
-rw-r--r--drivers/of/dynamic.c12
-rw-r--r--drivers/of/of_private.h10
3 files changed, 69 insertions, 49 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;
37struct device_node *of_aliases; 37struct device_node *of_aliases;
38static struct device_node *of_stdout; 38static struct device_node *of_stdout;
39 39
40static struct kset *of_kset; 40struct 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 */
45DEFINE_MUTEX(of_mutex); 48DEFINE_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
130static int __of_add_property_sysfs(struct device_node *np, struct property *pp) 133int __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
148static int __of_node_add(struct device_node *np) 154int __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
175int 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
195static int __init of_init(void) 184static 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
1714void __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
1756int __of_update_property(struct device_node *np, struct property *newprop, 1752int __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
1778void __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
1822static void of_alias_add(struct alias_prop *ap, struct device_node *np, 1826static 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}
42EXPORT_SYMBOL(of_node_put); 42EXPORT_SYMBOL(of_node_put);
43 43
44static void of_node_remove(struct device_node *np) 44void __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
34extern struct mutex of_mutex; 34extern struct mutex of_mutex;
35extern struct list_head aliases_lookup; 35extern struct list_head aliases_lookup;
36extern struct kset *of_kset;
37
36 38
37static inline struct device_node *kobj_to_device_node(struct kobject *kobj) 39static 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);
62struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags); 64struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags);
63 65
64extern int __of_add_property(struct device_node *np, struct property *prop); 66extern int __of_add_property(struct device_node *np, struct property *prop);
67extern int __of_add_property_sysfs(struct device_node *np,
68 struct property *prop);
65extern int __of_remove_property(struct device_node *np, struct property *prop); 69extern int __of_remove_property(struct device_node *np, struct property *prop);
70extern void __of_remove_property_sysfs(struct device_node *np,
71 struct property *prop);
66extern int __of_update_property(struct device_node *np, 72extern int __of_update_property(struct device_node *np,
67 struct property *newprop, struct property **oldprop); 73 struct property *newprop, struct property **oldprop);
74extern void __of_update_property_sysfs(struct device_node *np,
75 struct property *newprop, struct property *oldprop);
68 76
69extern void __of_attach_node(struct device_node *np); 77extern void __of_attach_node(struct device_node *np);
78extern int __of_attach_node_sysfs(struct device_node *np);
70extern void __of_detach_node(struct device_node *np); 79extern void __of_detach_node(struct device_node *np);
80extern void __of_detach_node_sysfs(struct device_node *np);
71 81
72#endif /* _LINUX_OF_PRIVATE_H */ 82#endif /* _LINUX_OF_PRIVATE_H */