Commit b77a2030 authored by Alexandre Bounine's avatar Alexandre Bounine Committed by Linus Torvalds

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: default avatarAlexandre 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent e6b585ca
...@@ -149,6 +149,7 @@ int rio_add_device(struct rio_dev *rdev) ...@@ -149,6 +149,7 @@ int rio_add_device(struct rio_dev *rdev)
{ {
int err; int err;
atomic_set(&rdev->state, RIO_DEVICE_RUNNING);
err = device_register(&rdev->dev); err = device_register(&rdev->dev);
if (err) if (err)
return err; return err;
...@@ -172,13 +173,15 @@ EXPORT_SYMBOL_GPL(rio_add_device); ...@@ -172,13 +173,15 @@ EXPORT_SYMBOL_GPL(rio_add_device);
/* /*
* rio_del_device - removes a RIO device from the device model * rio_del_device - removes a RIO device from the device model
* @rdev: RIO device * @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. * Removes the RIO device to the kernel device list and subsystem's device list.
* Clears sysfs entries for the removed device. * 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)); pr_debug("RIO: %s: removing %s\n", __func__, rio_name(rdev));
atomic_set(&rdev->state, state);
spin_lock(&rio_global_list_lock); spin_lock(&rio_global_list_lock);
list_del(&rdev->global_list); list_del(&rdev->global_list);
if (rdev->net) { if (rdev->net) {
...@@ -2010,32 +2013,28 @@ static int rio_get_hdid(int index) ...@@ -2010,32 +2013,28 @@ static int rio_get_hdid(int index)
return hdid[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) { if (next_portid >= RIO_MAX_MPORTS) {
pr_err("RIO: reached specified max number of mports\n"); pr_err("RIO: reached specified max number of mports\n");
return 1; return -ENODEV;
} }
port->id = next_portid++; atomic_set(&mport->state, RIO_DEVICE_INITIALIZING);
port->host_deviceid = rio_get_hdid(port->id); mport->id = next_portid++;
port->nscan = NULL; mport->host_deviceid = rio_get_hdid(mport->id);
mport->nscan = NULL;
dev_set_name(&port->dev, "rapidio%d", port->id); return 0;
port->dev.class = &rio_mport_class; }
EXPORT_SYMBOL_GPL(rio_mport_initialize);
res = device_register(&port->dev); int rio_register_mport(struct rio_mport *port)
if (res) {
dev_err(&port->dev, "RIO: mport%d registration failed ERR=%d\n", struct rio_scan_node *scan = NULL;
port->id, res); int res = 0;
else
dev_dbg(&port->dev, "RIO: mport%d registered\n", port->id);
mutex_lock(&rio_mport_list_lock); mutex_lock(&rio_mport_list_lock);
list_add_tail(&port->node, &rio_mports);
/* /*
* Check if there are any registered enumeration/discovery operations * Check if there are any registered enumeration/discovery operations
...@@ -2049,12 +2048,73 @@ int rio_register_mport(struct rio_mport *port) ...@@ -2049,12 +2048,73 @@ int rio_register_mport(struct rio_mport *port)
break; break;
} }
} }
list_add_tail(&port->node, &rio_mports);
mutex_unlock(&rio_mport_list_lock); 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); 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; 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_local_get_device_id);
EXPORT_SYMBOL_GPL(rio_get_device); EXPORT_SYMBOL_GPL(rio_get_device);
......
...@@ -43,7 +43,7 @@ extern struct rio_net *rio_alloc_net(struct rio_mport *mport); ...@@ -43,7 +43,7 @@ extern struct rio_net *rio_alloc_net(struct rio_mport *mport);
extern int rio_add_net(struct rio_net *net); extern int rio_add_net(struct rio_net *net);
extern void rio_free_net(struct rio_net *net); extern void rio_free_net(struct rio_net *net);
extern int rio_add_device(struct rio_dev *rdev); extern int rio_add_device(struct rio_dev *rdev);
extern void rio_del_device(struct rio_dev *rdev); extern void rio_del_device(struct rio_dev *rdev, enum rio_device_state state);
extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid, extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid,
u8 hopcount, u8 port_num); u8 hopcount, u8 port_num);
extern int rio_register_scan(int mport_id, struct rio_scan *scan_ops); extern int rio_register_scan(int mport_id, struct rio_scan *scan_ops);
......
...@@ -137,6 +137,13 @@ struct rio_switch_ops { ...@@ -137,6 +137,13 @@ struct rio_switch_ops {
int (*em_handle) (struct rio_dev *dev, u8 swport); int (*em_handle) (struct rio_dev *dev, u8 swport);
}; };
enum rio_device_state {
RIO_DEVICE_INITIALIZING,
RIO_DEVICE_RUNNING,
RIO_DEVICE_GONE,
RIO_DEVICE_SHUTDOWN,
};
/** /**
* struct rio_dev - RIO device info * struct rio_dev - RIO device info
* @global_list: Node in list of all RIO devices * @global_list: Node in list of all RIO devices
...@@ -165,6 +172,7 @@ struct rio_switch_ops { ...@@ -165,6 +172,7 @@ struct rio_switch_ops {
* @destid: Network destination ID (or associated destid for switch) * @destid: Network destination ID (or associated destid for switch)
* @hopcount: Hopcount to this device * @hopcount: Hopcount to this device
* @prev: Previous RIO device connected to the current one * @prev: Previous RIO device connected to the current one
* @state: device state
* @rswitch: struct rio_switch (if valid for this device) * @rswitch: struct rio_switch (if valid for this device)
*/ */
struct rio_dev { struct rio_dev {
...@@ -194,6 +202,7 @@ struct rio_dev { ...@@ -194,6 +202,7 @@ struct rio_dev {
u16 destid; u16 destid;
u8 hopcount; u8 hopcount;
struct rio_dev *prev; struct rio_dev *prev;
atomic_t state;
struct rio_switch rswitch[0]; /* RIO switch info */ struct rio_switch rswitch[0]; /* RIO switch info */
}; };
...@@ -255,6 +264,7 @@ enum rio_phy_type { ...@@ -255,6 +264,7 @@ enum rio_phy_type {
* @priv: Master port private data * @priv: Master port private data
* @dma: DMA device associated with mport * @dma: DMA device associated with mport
* @nscan: RapidIO network enumeration/discovery operations * @nscan: RapidIO network enumeration/discovery operations
* @state: mport device state
*/ */
struct rio_mport { struct rio_mport {
struct list_head dbells; /* list of doorbell events */ struct list_head dbells; /* list of doorbell events */
...@@ -283,8 +293,14 @@ struct rio_mport { ...@@ -283,8 +293,14 @@ struct rio_mport {
struct dma_device dma; struct dma_device dma;
#endif #endif
struct rio_scan *nscan; struct rio_scan *nscan;
atomic_t state;
}; };
static inline int rio_mport_is_running(struct rio_mport *mport)
{
return atomic_read(&mport->state) == RIO_DEVICE_RUNNING;
}
/* /*
* Enumeration/discovery control flags * Enumeration/discovery control flags
*/ */
...@@ -525,7 +541,9 @@ struct rio_scan_node { ...@@ -525,7 +541,9 @@ struct rio_scan_node {
}; };
/* Architecture and hardware-specific functions */ /* Architecture and hardware-specific functions */
extern int rio_mport_initialize(struct rio_mport *);
extern int rio_register_mport(struct rio_mport *); extern int rio_register_mport(struct rio_mport *);
extern int rio_unregister_mport(struct rio_mport *);
extern int rio_open_inb_mbox(struct rio_mport *, void *, int, int); extern int rio_open_inb_mbox(struct rio_mport *, void *, int, int);
extern void rio_close_inb_mbox(struct rio_mport *, int); extern void rio_close_inb_mbox(struct rio_mport *, int);
extern int rio_open_outb_mbox(struct rio_mport *, void *, int, int); extern int rio_open_outb_mbox(struct rio_mport *, void *, int, int);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment