int of_node_add(struct device_node *np)
{
int rc = 0;
- kobject_init(&np->kobj, &of_node_ktype);
+
+ BUG_ON(!of_node_is_initialized(np));
+
+ /*
+ * Grab the mutex here so that in a race condition between of_init() and
+ * of_node_add(), node addition will still be consistent.
+ */
mutex_lock(&of_aliases_mutex);
if (of_kset)
rc = __of_node_add(np);
+ else
+ /* This scenario may be perfectly valid, but report it anyway */
+ pr_info("of_node_add(%s) before of_init()\n", np->full_name);
mutex_unlock(&of_aliases_mutex);
return rc;
}
{
struct property *pp;
- for_each_property_of_node(np, pp)
- sysfs_remove_bin_file(&np->kobj, &pp->attr);
+ BUG_ON(!of_node_is_initialized(np));
+
+ /* only remove properties if on sysfs */
+ if (of_node_is_attached(np)) {
+ for_each_property_of_node(np, pp)
+ sysfs_remove_bin_file(&np->kobj, &pp->attr);
+ kobject_del(&np->kobj);
+ }
- kobject_del(&np->kobj);
+ /* finally remove the kobj_init ref */
+ of_node_put(np);
}
#endif
{
struct of_prop_reconfig pr;
+ /* only call notifiers if the node is attached */
+ if (!of_node_is_attached(np))
+ return 0;
+
pr.dn = np;
pr.prop = prop;
return of_reconfig_notify(action, &pr);
if (rc)
return rc;
- /* at early boot, bail hear and defer setup to of_init() */
- if (!of_kset)
- return 0;
-
- __of_add_property_sysfs(np, prop);
+ if (of_node_is_attached(np))
+ __of_add_property_sysfs(np, prop);
return rc;
}
return NULL;
dp = prom_early_alloc(sizeof(*dp));
+ of_node_init(dp);
of_pdt_incr_unique_id(dp);
dp->parent = parent;
*nextp = &dp->allnext;
dp->full_name = of_pdt_build_full_name(dp);
- of_node_add(dp);
dp->child = of_pdt_build_tree(dp,
of_pdt_prom_ops->getchild(node), nextp);
of_allnodes->path_component_name = "";
#endif
of_allnodes->full_name = "/";
- of_node_add(of_allnodes);
nextp = &of_allnodes->allnext;
of_allnodes->child = of_pdt_build_tree(of_allnodes,
extern int of_node_add(struct device_node *node);
+/* initialize a node */
+extern struct kobj_type of_node_ktype;
+static inline void of_node_init(struct device_node *node)
+{
+ kobject_init(&node->kobj, &of_node_ktype);
+}
+
+/* true when node is initialized */
+static inline int of_node_is_initialized(struct device_node *node)
+{
+ return node && node->kobj.state_initialized;
+}
+
+/* true when node is attached (i.e. present on sysfs) */
+static inline int of_node_is_attached(struct device_node *node)
+{
+ return node && node->kobj.state_in_sysfs;
+}
+
#ifdef CONFIG_OF_DYNAMIC
extern struct device_node *of_node_get(struct device_node *node);
extern void of_node_put(struct device_node *node);