aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPantelis Antoniou <panto@antoniou-consulting.com>2013-12-13 13:08:59 -0500
committerGrant Likely <grant.likely@linaro.org>2014-03-19 10:58:40 -0400
commit0829f6d1f69e4f2fae4062987ae6531a9af1a2e3 (patch)
tree4081a4bee4a9e193b4de690735b5a3782d100eac
parent8357041a69b368991d1b04d9f1d297f8d71e1314 (diff)
of: device_node kobject lifecycle fixes
After the move to having device nodes be proper kobjects the lifecycle of the node needs to be controlled better. At first convert of_add_node() in the unflattened functions to of_init_node() which initializes the kobject so that of_node_get/put work correctly even before of_init is called. Afterwards introduce of_node_is_initialized & of_node_is_attached that query the underlying kobject about the state (attached means kobj is visible in sysfs) Using that make sure the lifecycle of the tree is correct at all times. Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com> [grant.likely: moved of_node_init() calls, fixed up locking, and dropped __of_populate() hunks] Signed-off-by: Grant Likely <grant.likely@linaro.org>
-rw-r--r--drivers/of/base.c35
-rw-r--r--drivers/of/fdt.c3
-rw-r--r--drivers/of/pdt.c3
-rw-r--r--include/linux/of.h19
4 files changed, 47 insertions, 13 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c
index ed3e70b84957..418a4ff9d97c 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -246,10 +246,19 @@ static int __of_node_add(struct device_node *np)
246int of_node_add(struct device_node *np) 246int of_node_add(struct device_node *np)
247{ 247{
248 int rc = 0; 248 int rc = 0;
249 kobject_init(&np->kobj, &of_node_ktype); 249
250 BUG_ON(!of_node_is_initialized(np));
251
252 /*
253 * Grab the mutex here so that in a race condition between of_init() and
254 * of_node_add(), node addition will still be consistent.
255 */
250 mutex_lock(&of_aliases_mutex); 256 mutex_lock(&of_aliases_mutex);
251 if (of_kset) 257 if (of_kset)
252 rc = __of_node_add(np); 258 rc = __of_node_add(np);
259 else
260 /* This scenario may be perfectly valid, but report it anyway */
261 pr_info("of_node_add(%s) before of_init()\n", np->full_name);
253 mutex_unlock(&of_aliases_mutex); 262 mutex_unlock(&of_aliases_mutex);
254 return rc; 263 return rc;
255} 264}
@@ -259,10 +268,17 @@ static void of_node_remove(struct device_node *np)
259{ 268{
260 struct property *pp; 269 struct property *pp;
261 270
262 for_each_property_of_node(np, pp) 271 BUG_ON(!of_node_is_initialized(np));
263 sysfs_remove_bin_file(&np->kobj, &pp->attr); 272
273 /* only remove properties if on sysfs */
274 if (of_node_is_attached(np)) {
275 for_each_property_of_node(np, pp)
276 sysfs_remove_bin_file(&np->kobj, &pp->attr);
277 kobject_del(&np->kobj);
278 }
264 279
265 kobject_del(&np->kobj); 280 /* finally remove the kobj_init ref */
281 of_node_put(np);
266} 282}
267#endif 283#endif
268 284
@@ -1631,6 +1647,10 @@ static int of_property_notify(int action, struct device_node *np,
1631{ 1647{
1632 struct of_prop_reconfig pr; 1648 struct of_prop_reconfig pr;
1633 1649
1650 /* only call notifiers if the node is attached */
1651 if (!of_node_is_attached(np))
1652 return 0;
1653
1634 pr.dn = np; 1654 pr.dn = np;
1635 pr.prop = prop; 1655 pr.prop = prop;
1636 return of_reconfig_notify(action, &pr); 1656 return of_reconfig_notify(action, &pr);
@@ -1682,11 +1702,8 @@ int of_add_property(struct device_node *np, struct property *prop)
1682 if (rc) 1702 if (rc)
1683 return rc; 1703 return rc;
1684 1704
1685 /* at early boot, bail hear and defer setup to of_init() */ 1705 if (of_node_is_attached(np))
1686 if (!of_kset) 1706 __of_add_property_sysfs(np, prop);
1687 return 0;
1688
1689 __of_add_property_sysfs(np, prop);
1690 1707
1691 return rc; 1708 return rc;
1692} 1709}
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 96ad1ab7f9d6..70ccc36513e7 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -202,6 +202,7 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
202 __alignof__(struct device_node)); 202 __alignof__(struct device_node));
203 if (allnextpp) { 203 if (allnextpp) {
204 char *fn; 204 char *fn;
205 of_node_init(np);
205 np->full_name = fn = ((char *)np) + sizeof(*np); 206 np->full_name = fn = ((char *)np) + sizeof(*np);
206 if (new_format) { 207 if (new_format) {
207 /* rebuild full path for new format */ 208 /* rebuild full path for new format */
@@ -326,8 +327,6 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
326 np->name = "<NULL>"; 327 np->name = "<NULL>";
327 if (!np->type) 328 if (!np->type)
328 np->type = "<NULL>"; 329 np->type = "<NULL>";
329
330 of_node_add(np);
331 } 330 }
332 while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) { 331 while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) {
333 if (tag == OF_DT_NOP) 332 if (tag == OF_DT_NOP)
diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c
index e64fa3d3da5f..36b4035881b0 100644
--- a/drivers/of/pdt.c
+++ b/drivers/of/pdt.c
@@ -176,6 +176,7 @@ static struct device_node * __init of_pdt_create_node(phandle node,
176 return NULL; 176 return NULL;
177 177
178 dp = prom_early_alloc(sizeof(*dp)); 178 dp = prom_early_alloc(sizeof(*dp));
179 of_node_init(dp);
179 of_pdt_incr_unique_id(dp); 180 of_pdt_incr_unique_id(dp);
180 dp->parent = parent; 181 dp->parent = parent;
181 182
@@ -213,7 +214,6 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
213 *nextp = &dp->allnext; 214 *nextp = &dp->allnext;
214 215
215 dp->full_name = of_pdt_build_full_name(dp); 216 dp->full_name = of_pdt_build_full_name(dp);
216 of_node_add(dp);
217 217
218 dp->child = of_pdt_build_tree(dp, 218 dp->child = of_pdt_build_tree(dp,
219 of_pdt_prom_ops->getchild(node), nextp); 219 of_pdt_prom_ops->getchild(node), nextp);
@@ -244,7 +244,6 @@ void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
244 of_allnodes->path_component_name = ""; 244 of_allnodes->path_component_name = "";
245#endif 245#endif
246 of_allnodes->full_name = "/"; 246 of_allnodes->full_name = "/";
247 of_node_add(of_allnodes);
248 247
249 nextp = &of_allnodes->allnext; 248 nextp = &of_allnodes->allnext;
250 of_allnodes->child = of_pdt_build_tree(of_allnodes, 249 of_allnodes->child = of_pdt_build_tree(of_allnodes,
diff --git a/include/linux/of.h b/include/linux/of.h
index 257994a420f3..a8b9dad90c64 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -76,6 +76,25 @@ struct of_phandle_args {
76 76
77extern int of_node_add(struct device_node *node); 77extern int of_node_add(struct device_node *node);
78 78
79/* initialize a node */
80extern struct kobj_type of_node_ktype;
81static inline void of_node_init(struct device_node *node)
82{
83 kobject_init(&node->kobj, &of_node_ktype);
84}
85
86/* true when node is initialized */
87static inline int of_node_is_initialized(struct device_node *node)
88{
89 return node && node->kobj.state_initialized;
90}
91
92/* true when node is attached (i.e. present on sysfs) */
93static inline int of_node_is_attached(struct device_node *node)
94{
95 return node && node->kobj.state_in_sysfs;
96}
97
79#ifdef CONFIG_OF_DYNAMIC 98#ifdef CONFIG_OF_DYNAMIC
80extern struct device_node *of_node_get(struct device_node *node); 99extern struct device_node *of_node_get(struct device_node *node);
81extern void of_node_put(struct device_node *node); 100extern void of_node_put(struct device_node *node);