From e81b3295bc54eb0d03f4cdfc8cbf72e731d1b402 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 2 Oct 2012 16:55:01 +0000 Subject: powerpc+of: Add /proc device tree updating to of node add/remove When adding or removing a device tree node we should also update the device tree in /proc/device-tree. This action is already done in the generic OF code for adding/removing properties of a node. This patch adds this functionality for nodes. Signed-off-by: Nathan Fontenot Acked-by: Rob Herring Acked-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt --- drivers/of/base.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 4 deletions(-) (limited to 'drivers/of') diff --git a/drivers/of/base.c b/drivers/of/base.c index af3b22ac762..bbd073f53c9 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1160,6 +1160,22 @@ int prom_update_property(struct device_node *np, * device tree nodes. */ +#ifdef CONFIG_PROC_DEVICETREE +static void of_add_proc_dt_entry(struct device_node *dn) +{ + struct proc_dir_entry *ent; + + ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde); + if (ent) + proc_device_tree_add_node(dn, ent); +} +#else +static void of_add_proc_dt_entry(struct device_node *dn) +{ + return; +} +#endif + /** * of_attach_node - Plug a device node into the tree and global list. */ @@ -1173,8 +1189,31 @@ void of_attach_node(struct device_node *np) np->parent->child = np; allnodes = np; write_unlock_irqrestore(&devtree_lock, flags); + + of_add_proc_dt_entry(np); } +#ifdef CONFIG_PROC_DEVICETREE +static void of_remove_proc_dt_entry(struct device_node *dn) +{ + struct device_node *parent = dn->parent; + struct property *prop = dn->properties; + + while (prop) { + remove_proc_entry(prop->name, dn->pde); + prop = prop->next; + } + + if (dn->pde) + remove_proc_entry(dn->pde->name, parent->pde); +} +#else +static void of_remove_proc_dt_entry(struct device_node *dn) +{ + return; +} +#endif + /** * of_detach_node - "Unplug" a node from the device tree. * @@ -1188,9 +1227,17 @@ void of_detach_node(struct device_node *np) write_lock_irqsave(&devtree_lock, flags); + if (of_node_check_flag(np, OF_DETACHED)) { + /* someone already detached it */ + write_unlock_irqrestore(&devtree_lock, flags); + return; + } + parent = np->parent; - if (!parent) - goto out_unlock; + if (!parent) { + write_unlock_irqrestore(&devtree_lock, flags); + return; + } if (allnodes == np) allnodes = np->allnext; @@ -1215,9 +1262,9 @@ void of_detach_node(struct device_node *np) } of_node_set_flag(np, OF_DETACHED); - -out_unlock: write_unlock_irqrestore(&devtree_lock, flags); + + of_remove_proc_dt_entry(np); } #endif /* defined(CONFIG_OF_DYNAMIC) */ -- cgit v1.2.3 From 1cf3d8b3d24cd383ddfd5442c83ec5c355ffc2f7 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 2 Oct 2012 16:57:57 +0000 Subject: powerpc+of: Add of node/property notification chain for adds and removes This patch moves the notification chain for updates to the device tree from the powerpc/pseries code to the base OF code. This makes this functionality available to all architectures. Additionally the notification chain is updated to allow notifications for property add/remove/update. To make this work a pointer to a new struct (of_prop_reconfig) is passed to the routines in the notification chain. The of_prop_reconfig property contains a pointer to the node containing the property and a pointer to the property itself. In the case of property updates, the property pointer refers to the new property. Signed-off-by: Nathan Fontenot Acked-by: Rob Herring Acked-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt --- drivers/of/base.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 5 deletions(-) (limited to 'drivers/of') diff --git a/drivers/of/base.c b/drivers/of/base.c index bbd073f53c9..87b63850e8d 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1028,6 +1028,24 @@ int of_parse_phandle_with_args(struct device_node *np, const char *list_name, } EXPORT_SYMBOL(of_parse_phandle_with_args); +#if defined(CONFIG_OF_DYNAMIC) +static int of_property_notify(int action, struct device_node *np, + struct property *prop) +{ + struct of_prop_reconfig pr; + + pr.dn = np; + pr.prop = prop; + return of_reconfig_notify(action, &pr); +} +#else +static int of_property_notify(int action, struct device_node *np, + struct property *prop) +{ + return 0; +} +#endif + /** * prom_add_property - Add a property to a node */ @@ -1035,6 +1053,11 @@ int prom_add_property(struct device_node *np, struct property *prop) { struct property **next; unsigned long flags; + int rc; + + rc = of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop); + if (rc) + return rc; prop->next = NULL; write_lock_irqsave(&devtree_lock, flags); @@ -1072,6 +1095,11 @@ int prom_remove_property(struct device_node *np, struct property *prop) struct property **next; unsigned long flags; int found = 0; + int rc; + + rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop); + if (rc) + return rc; write_lock_irqsave(&devtree_lock, flags); next = &np->properties; @@ -1114,7 +1142,11 @@ int prom_update_property(struct device_node *np, { struct property **next, *oldprop; unsigned long flags; - int found = 0; + int rc, found = 0; + + rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop); + if (rc) + return rc; if (!newprop->name) return -EINVAL; @@ -1160,6 +1192,26 @@ int prom_update_property(struct device_node *np, * device tree nodes. */ +static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); + +int of_reconfig_notifier_register(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&of_reconfig_chain, nb); +} + +int of_reconfig_notifier_unregister(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&of_reconfig_chain, nb); +} + +int of_reconfig_notify(unsigned long action, void *p) +{ + int rc; + + rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); + return notifier_to_errno(rc); +} + #ifdef CONFIG_PROC_DEVICETREE static void of_add_proc_dt_entry(struct device_node *dn) { @@ -1179,9 +1231,14 @@ static void of_add_proc_dt_entry(struct device_node *dn) /** * of_attach_node - Plug a device node into the tree and global list. */ -void of_attach_node(struct device_node *np) +int of_attach_node(struct device_node *np) { unsigned long flags; + int rc; + + rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np); + if (rc) + return rc; write_lock_irqsave(&devtree_lock, flags); np->sibling = np->parent->child; @@ -1191,6 +1248,7 @@ void of_attach_node(struct device_node *np) write_unlock_irqrestore(&devtree_lock, flags); of_add_proc_dt_entry(np); + return 0; } #ifdef CONFIG_PROC_DEVICETREE @@ -1220,23 +1278,28 @@ static void of_remove_proc_dt_entry(struct device_node *dn) * The caller must hold a reference to the node. The memory associated with * the node is not freed until its refcount goes to zero. */ -void of_detach_node(struct device_node *np) +int of_detach_node(struct device_node *np) { struct device_node *parent; unsigned long flags; + int rc = 0; + + rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np); + if (rc) + return rc; write_lock_irqsave(&devtree_lock, flags); if (of_node_check_flag(np, OF_DETACHED)) { /* someone already detached it */ write_unlock_irqrestore(&devtree_lock, flags); - return; + return rc; } parent = np->parent; if (!parent) { write_unlock_irqrestore(&devtree_lock, flags); - return; + return rc; } if (allnodes == np) @@ -1265,6 +1328,7 @@ void of_detach_node(struct device_node *np) write_unlock_irqrestore(&devtree_lock, flags); of_remove_proc_dt_entry(np); + return rc; } #endif /* defined(CONFIG_OF_DYNAMIC) */ -- cgit v1.2.3 From 79d1c712958f94372482ad74578b00f44e744c12 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Tue, 2 Oct 2012 16:58:46 +0000 Subject: powerpc+of: Rename the drivers/of prom_* functions to of_* Rename the prom_*_property routines of the generic OF code to of_*_property. This brings them in line with the naming used by the rest of the OF code. Signed-off-by: Nathan Fontenot Acked-by: Geoff Levand Acked-by: Rob Herring Acked-by: Grant Likely Signed-off-by: Benjamin Herrenschmidt --- drivers/of/base.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/of') diff --git a/drivers/of/base.c b/drivers/of/base.c index 87b63850e8d..02d94c4ea83 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1047,9 +1047,9 @@ static int of_property_notify(int action, struct device_node *np, #endif /** - * prom_add_property - Add a property to a node + * of_add_property - Add a property to a node */ -int prom_add_property(struct device_node *np, struct property *prop) +int of_add_property(struct device_node *np, struct property *prop) { struct property **next; unsigned long flags; @@ -1083,14 +1083,14 @@ int prom_add_property(struct device_node *np, struct property *prop) } /** - * prom_remove_property - Remove a property from a node. + * of_remove_property - Remove a property from a node. * * Note that we don't actually remove it, since we have given out * who-knows-how-many pointers to the data using get-property. * Instead we just move the property to the "dead properties" * list, so it won't be found any more. */ -int prom_remove_property(struct device_node *np, struct property *prop) +int of_remove_property(struct device_node *np, struct property *prop) { struct property **next; unsigned long flags; @@ -1129,7 +1129,7 @@ int prom_remove_property(struct device_node *np, struct property *prop) } /* - * prom_update_property - Update a property in a node, if the property does + * of_update_property - Update a property in a node, if the property does * not exist, add it. * * Note that we don't actually remove it, since we have given out @@ -1137,8 +1137,7 @@ int prom_remove_property(struct device_node *np, struct property *prop) * Instead we just move the property to the "dead properties" list, * and add the new property to the property list */ -int prom_update_property(struct device_node *np, - struct property *newprop) +int of_update_property(struct device_node *np, struct property *newprop) { struct property **next, *oldprop; unsigned long flags; @@ -1153,7 +1152,7 @@ int prom_update_property(struct device_node *np, oldprop = of_find_property(np, newprop->name, NULL); if (!oldprop) - return prom_add_property(np, newprop); + return of_add_property(np, newprop); write_lock_irqsave(&devtree_lock, flags); next = &np->properties; -- cgit v1.2.3 From 1a9bd45412665e73c72612b6f744378d860e02a8 Mon Sep 17 00:00:00 2001 From: Nathan Fontenot Date: Wed, 28 Nov 2012 09:42:26 +0000 Subject: powerpc+of: Export of_reconfig_notifier_[register,unregister] The of reconfiguration notification chains should be exported for use by modules. Signed-off-by:Nathan Fontenot Signed-off-by: Benjamin Herrenschmidt --- drivers/of/base.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/of') diff --git a/drivers/of/base.c b/drivers/of/base.c index 02d94c4ea83..fa40402fe8d 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1197,11 +1197,13 @@ int of_reconfig_notifier_register(struct notifier_block *nb) { return blocking_notifier_chain_register(&of_reconfig_chain, nb); } +EXPORT_SYMBOL_GPL(of_reconfig_notifier_register); int of_reconfig_notifier_unregister(struct notifier_block *nb) { return blocking_notifier_chain_unregister(&of_reconfig_chain, nb); } +EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister); int of_reconfig_notify(unsigned long action, void *p) { -- cgit v1.2.3