diff options
| -rw-r--r-- | drivers/of/base.c | 35 | ||||
| -rw-r--r-- | drivers/of/fdt.c | 3 | ||||
| -rw-r--r-- | drivers/of/pdt.c | 3 | ||||
| -rw-r--r-- | include/linux/of.h | 19 |
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) | |||
| 246 | int of_node_add(struct device_node *np) | 246 | int 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 | ||
| 77 | extern int of_node_add(struct device_node *node); | 77 | extern int of_node_add(struct device_node *node); |
| 78 | 78 | ||
| 79 | /* initialize a node */ | ||
| 80 | extern struct kobj_type of_node_ktype; | ||
| 81 | static 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 */ | ||
| 87 | static 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) */ | ||
| 93 | static 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 |
| 80 | extern struct device_node *of_node_get(struct device_node *node); | 99 | extern struct device_node *of_node_get(struct device_node *node); |
| 81 | extern void of_node_put(struct device_node *node); | 100 | extern void of_node_put(struct device_node *node); |
