summaryrefslogtreecommitdiff
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)
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;
}
@@ -259,10 +268,17 @@ static void of_node_remove(struct device_node *np)
{
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
@@ -1631,6 +1647,10 @@ static int of_property_notify(int action, struct device_node *np,
{
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);
@@ -1682,11 +1702,8 @@ int of_add_property(struct device_node *np, struct property *prop)
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;
}
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,
__alignof__(struct device_node));
if (allnextpp) {
char *fn;
+ of_node_init(np);
np->full_name = fn = ((char *)np) + sizeof(*np);
if (new_format) {
/* rebuild full path for new format */
@@ -326,8 +327,6 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
np->name = "<NULL>";
if (!np->type)
np->type = "<NULL>";
-
- of_node_add(np);
}
while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) {
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,
return NULL;
dp = prom_early_alloc(sizeof(*dp));
+ of_node_init(dp);
of_pdt_incr_unique_id(dp);
dp->parent = parent;
@@ -213,7 +214,6 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *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);
@@ -244,7 +244,6 @@ void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
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,
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 {
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);