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>
This commit is contained in:
parent
8357041a69
commit
0829f6d1f6
@ -246,10 +246,19 @@ static int __of_node_add(struct device_node *np)
|
|||||||
int of_node_add(struct device_node *np)
|
int of_node_add(struct device_node *np)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
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);
|
mutex_lock(&of_aliases_mutex);
|
||||||
if (of_kset)
|
if (of_kset)
|
||||||
rc = __of_node_add(np);
|
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);
|
mutex_unlock(&of_aliases_mutex);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -259,10 +268,17 @@ static void of_node_remove(struct device_node *np)
|
|||||||
{
|
{
|
||||||
struct property *pp;
|
struct property *pp;
|
||||||
|
|
||||||
for_each_property_of_node(np, pp)
|
BUG_ON(!of_node_is_initialized(np));
|
||||||
sysfs_remove_bin_file(&np->kobj, &pp->attr);
|
|
||||||
|
|
||||||
kobject_del(&np->kobj);
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finally remove the kobj_init ref */
|
||||||
|
of_node_put(np);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1631,6 +1647,10 @@ static int of_property_notify(int action, struct device_node *np,
|
|||||||
{
|
{
|
||||||
struct of_prop_reconfig pr;
|
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.dn = np;
|
||||||
pr.prop = prop;
|
pr.prop = prop;
|
||||||
return of_reconfig_notify(action, &pr);
|
return of_reconfig_notify(action, &pr);
|
||||||
@ -1682,11 +1702,8 @@ int of_add_property(struct device_node *np, struct property *prop)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* at early boot, bail hear and defer setup to of_init() */
|
if (of_node_is_attached(np))
|
||||||
if (!of_kset)
|
__of_add_property_sysfs(np, prop);
|
||||||
return 0;
|
|
||||||
|
|
||||||
__of_add_property_sysfs(np, prop);
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -202,6 +202,7 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
|
|||||||
__alignof__(struct device_node));
|
__alignof__(struct device_node));
|
||||||
if (allnextpp) {
|
if (allnextpp) {
|
||||||
char *fn;
|
char *fn;
|
||||||
|
of_node_init(np);
|
||||||
np->full_name = fn = ((char *)np) + sizeof(*np);
|
np->full_name = fn = ((char *)np) + sizeof(*np);
|
||||||
if (new_format) {
|
if (new_format) {
|
||||||
/* rebuild full path for 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>";
|
np->name = "<NULL>";
|
||||||
if (!np->type)
|
if (!np->type)
|
||||||
np->type = "<NULL>";
|
np->type = "<NULL>";
|
||||||
|
|
||||||
of_node_add(np);
|
|
||||||
}
|
}
|
||||||
while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) {
|
while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) {
|
||||||
if (tag == OF_DT_NOP)
|
if (tag == OF_DT_NOP)
|
||||||
|
@ -176,6 +176,7 @@ static struct device_node * __init of_pdt_create_node(phandle node,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
dp = prom_early_alloc(sizeof(*dp));
|
dp = prom_early_alloc(sizeof(*dp));
|
||||||
|
of_node_init(dp);
|
||||||
of_pdt_incr_unique_id(dp);
|
of_pdt_incr_unique_id(dp);
|
||||||
dp->parent = parent;
|
dp->parent = parent;
|
||||||
|
|
||||||
@ -213,7 +214,6 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
|
|||||||
*nextp = &dp->allnext;
|
*nextp = &dp->allnext;
|
||||||
|
|
||||||
dp->full_name = of_pdt_build_full_name(dp);
|
dp->full_name = of_pdt_build_full_name(dp);
|
||||||
of_node_add(dp);
|
|
||||||
|
|
||||||
dp->child = of_pdt_build_tree(dp,
|
dp->child = of_pdt_build_tree(dp,
|
||||||
of_pdt_prom_ops->getchild(node), nextp);
|
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 = "";
|
of_allnodes->path_component_name = "";
|
||||||
#endif
|
#endif
|
||||||
of_allnodes->full_name = "/";
|
of_allnodes->full_name = "/";
|
||||||
of_node_add(of_allnodes);
|
|
||||||
|
|
||||||
nextp = &of_allnodes->allnext;
|
nextp = &of_allnodes->allnext;
|
||||||
of_allnodes->child = of_pdt_build_tree(of_allnodes,
|
of_allnodes->child = of_pdt_build_tree(of_allnodes,
|
||||||
|
@ -76,6 +76,25 @@ struct of_phandle_args {
|
|||||||
|
|
||||||
extern int of_node_add(struct device_node *node);
|
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
|
#ifdef CONFIG_OF_DYNAMIC
|
||||||
extern struct device_node *of_node_get(struct device_node *node);
|
extern struct device_node *of_node_get(struct device_node *node);
|
||||||
extern void of_node_put(struct device_node *node);
|
extern void of_node_put(struct device_node *node);
|
||||||
|
Loading…
Reference in New Issue
Block a user