aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);