summaryrefslogtreecommitdiff
path: root/drivers/rapidio/rio.c
diff options
context:
space:
mode:
authorAlexandre Bounine <alexandre.bounine@idt.com>2016-03-23 00:26:20 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-23 01:36:02 +0300
commitb77a2030dface6ea6b0d900bd8496ef41a9f3323 (patch)
treec31dccba4f2f4754f8443087550a3e7be52950f9 /drivers/rapidio/rio.c
parente6b585ca6e81badeb3d42db3cc408174f2826034 (diff)
downloadlinux-b77a2030dface6ea6b0d900bd8496ef41a9f3323.tar.xz
rapidio: add core mport removal support
Add common mport removal support functions into the RapidIO subsystem core. Changes to the existing mport registration process have been made to avoid race conditions with active subsystem interfaces immediately after mport device registration: part of initialization code from rio_register_mport() have been moved into separate function rio_mport_initialize() to allow to perform mport registration as the final step of setup process. Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com> Cc: Matt Porter <mporter@kernel.crashing.org> Cc: Aurelien Jacquiot <a-jacquiot@ti.com> Cc: Andre van Herk <andre.van.herk@prodrive-technologies.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rapidio/rio.c')
-rw-r--r--drivers/rapidio/rio.c98
1 files changed, 79 insertions, 19 deletions
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index 5fd68cb4b610..03b8c5af72bb 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -149,6 +149,7 @@ int rio_add_device(struct rio_dev *rdev)
{
int err;
+ atomic_set(&rdev->state, RIO_DEVICE_RUNNING);
err = device_register(&rdev->dev);
if (err)
return err;
@@ -172,13 +173,15 @@ EXPORT_SYMBOL_GPL(rio_add_device);
/*
* rio_del_device - removes a RIO device from the device model
* @rdev: RIO device
+ * @state: device state to set during removal process
*
* Removes the RIO device to the kernel device list and subsystem's device list.
* Clears sysfs entries for the removed device.
*/
-void rio_del_device(struct rio_dev *rdev)
+void rio_del_device(struct rio_dev *rdev, enum rio_device_state state)
{
pr_debug("RIO: %s: removing %s\n", __func__, rio_name(rdev));
+ atomic_set(&rdev->state, state);
spin_lock(&rio_global_list_lock);
list_del(&rdev->global_list);
if (rdev->net) {
@@ -2010,32 +2013,28 @@ static int rio_get_hdid(int index)
return hdid[index];
}
-int rio_register_mport(struct rio_mport *port)
+int rio_mport_initialize(struct rio_mport *mport)
{
- struct rio_scan_node *scan = NULL;
- int res = 0;
-
if (next_portid >= RIO_MAX_MPORTS) {
pr_err("RIO: reached specified max number of mports\n");
- return 1;
+ return -ENODEV;
}
- port->id = next_portid++;
- port->host_deviceid = rio_get_hdid(port->id);
- port->nscan = NULL;
+ atomic_set(&mport->state, RIO_DEVICE_INITIALIZING);
+ mport->id = next_portid++;
+ mport->host_deviceid = rio_get_hdid(mport->id);
+ mport->nscan = NULL;
- dev_set_name(&port->dev, "rapidio%d", port->id);
- port->dev.class = &rio_mport_class;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rio_mport_initialize);
- res = device_register(&port->dev);
- if (res)
- dev_err(&port->dev, "RIO: mport%d registration failed ERR=%d\n",
- port->id, res);
- else
- dev_dbg(&port->dev, "RIO: mport%d registered\n", port->id);
+int rio_register_mport(struct rio_mport *port)
+{
+ struct rio_scan_node *scan = NULL;
+ int res = 0;
mutex_lock(&rio_mport_list_lock);
- list_add_tail(&port->node, &rio_mports);
/*
* Check if there are any registered enumeration/discovery operations
@@ -2049,12 +2048,73 @@ int rio_register_mport(struct rio_mport *port)
break;
}
}
+
+ list_add_tail(&port->node, &rio_mports);
mutex_unlock(&rio_mport_list_lock);
+ dev_set_name(&port->dev, "rapidio%d", port->id);
+ port->dev.class = &rio_mport_class;
+ atomic_set(&port->state, RIO_DEVICE_RUNNING);
+
+ res = device_register(&port->dev);
+ if (res)
+ dev_err(&port->dev, "RIO: mport%d registration failed ERR=%d\n",
+ port->id, res);
+ else
+ dev_dbg(&port->dev, "RIO: registered mport%d\n", port->id);
+
+ return res;
+}
+EXPORT_SYMBOL_GPL(rio_register_mport);
+
+static int rio_mport_cleanup_callback(struct device *dev, void *data)
+{
+ struct rio_dev *rdev = to_rio_dev(dev);
+
+ if (dev->bus == &rio_bus_type)
+ rio_del_device(rdev, RIO_DEVICE_SHUTDOWN);
+ return 0;
+}
+
+static int rio_net_remove_children(struct rio_net *net)
+{
+ /*
+ * Unregister all RapidIO devices residing on this net (this will
+ * invoke notification of registered subsystem interfaces as well).
+ */
+ device_for_each_child(&net->dev, NULL, rio_mport_cleanup_callback);
+ return 0;
+}
+
+int rio_unregister_mport(struct rio_mport *port)
+{
pr_debug("RIO: %s %s id=%d\n", __func__, port->name, port->id);
+
+ /* Transition mport to the SHUTDOWN state */
+ if (atomic_cmpxchg(&port->state,
+ RIO_DEVICE_RUNNING,
+ RIO_DEVICE_SHUTDOWN) != RIO_DEVICE_RUNNING) {
+ pr_err("RIO: %s unexpected state transition for mport %s\n",
+ __func__, port->name);
+ }
+
+ if (port->net && port->net->hport == port) {
+ rio_net_remove_children(port->net);
+ rio_free_net(port->net);
+ }
+
+ /*
+ * Unregister all RapidIO devices attached to this mport (this will
+ * invoke notification of registered subsystem interfaces as well).
+ */
+ mutex_lock(&rio_mport_list_lock);
+ list_del(&port->node);
+ mutex_unlock(&rio_mport_list_lock);
+ device_unregister(&port->dev);
+
return 0;
}
-EXPORT_SYMBOL_GPL(rio_register_mport);
+EXPORT_SYMBOL_GPL(rio_unregister_mport);
EXPORT_SYMBOL_GPL(rio_local_get_device_id);
EXPORT_SYMBOL_GPL(rio_get_device);