diff options
author | Nathan Fontenot <nfont@linux.vnet.ibm.com> | 2012-10-02 16:57:57 +0000 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-11-15 12:56:41 +1100 |
commit | 1cf3d8b3d24cd383ddfd5442c83ec5c355ffc2f7 (patch) | |
tree | 0f4790e95f917c6b76d95c88b7b3d67445261893 /drivers | |
parent | f59497208363f3dd9d62b79b7f7eafc95432de79 (diff) |
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 <nfont@linux.vnet.ibm.com>
Acked-by: Rob Herring <rob.herring@calxeda.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/crypto/nx/nx-842.c | 20 | ||||
-rw-r--r-- | drivers/crypto/nx/nx.c | 1 | ||||
-rw-r--r-- | drivers/of/base.c | 74 |
3 files changed, 77 insertions, 18 deletions
diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c index 0ce625738677..6c4c000671c5 100644 --- a/drivers/crypto/nx/nx-842.c +++ b/drivers/crypto/nx/nx-842.c @@ -28,7 +28,6 @@ #include <linux/slab.h> #include <asm/page.h> -#include <asm/pSeries_reconfig.h> #include <asm/vio.h> #include "nx_csbcpb.h" /* struct nx_csbcpb */ @@ -1014,26 +1013,23 @@ error_out: * NOTIFY_BAD encoded with error number on failure, use * notifier_to_errno() to decode this value */ -static int nx842_OF_notifier(struct notifier_block *np, - unsigned long action, - void *update) +static int nx842_OF_notifier(struct notifier_block *np, unsigned long action, + void *update) { - struct pSeries_reconfig_prop_update *upd; + struct of_prop_reconfig *upd = update; struct nx842_devdata *local_devdata; struct device_node *node = NULL; - upd = (struct pSeries_reconfig_prop_update *)update; - rcu_read_lock(); local_devdata = rcu_dereference(devdata); if (local_devdata) node = local_devdata->dev->of_node; if (local_devdata && - action == PSERIES_UPDATE_PROPERTY && - !strcmp(upd->node->name, node->name)) { + action == OF_RECONFIG_UPDATE_PROPERTY && + !strcmp(upd->dn->name, node->name)) { rcu_read_unlock(); - nx842_OF_upd(upd->property); + nx842_OF_upd(upd->prop); } else rcu_read_unlock(); @@ -1182,7 +1178,7 @@ static int __init nx842_probe(struct vio_dev *viodev, synchronize_rcu(); kfree(old_devdata); - pSeries_reconfig_notifier_register(&nx842_of_nb); + of_reconfig_notifier_register(&nx842_of_nb); ret = nx842_OF_upd(NULL); if (ret && ret != -ENODEV) { @@ -1228,7 +1224,7 @@ static int __exit nx842_remove(struct vio_dev *viodev) spin_lock_irqsave(&devdata_mutex, flags); old_devdata = rcu_dereference_check(devdata, lockdep_is_held(&devdata_mutex)); - pSeries_reconfig_notifier_unregister(&nx842_of_nb); + of_reconfig_notifier_unregister(&nx842_of_nb); rcu_assign_pointer(devdata, NULL); spin_unlock_irqrestore(&devdata_mutex, flags); synchronize_rcu(); diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c index 638110efae9b..f7a8a16aa7d3 100644 --- a/drivers/crypto/nx/nx.c +++ b/drivers/crypto/nx/nx.c @@ -33,7 +33,6 @@ #include <linux/scatterlist.h> #include <linux/device.h> #include <linux/of.h> -#include <asm/pSeries_reconfig.h> #include <asm/hvcall.h> #include <asm/vio.h> diff --git a/drivers/of/base.c b/drivers/of/base.c index bbd073f53c9f..87b63850e8dc 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) */ |