summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Bounine <alexandre.bounine@idt.com>2012-10-04 17:16:08 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-06 03:05:22 +0900
commit005842efd1ac8ef455ebd28a8c713944863edc5a (patch)
tree9aea8b929ab5efc237d699cc36a4bed6adb51ad4
parenta7071efc20567f4b6c454ff93ca80daf51bf93e9 (diff)
rapidio: run discovery as an asynchronous process
Modify mport initialization routine to run the RapidIO discovery process asynchronously. This allows to have an arbitrary order of enumerating and discovering ports in systems with multiple RapidIO controllers without creating a deadlock situation if enumerator port is registered after a discovering one. Making netID matching to mportID ensures consistent net ID assignment in multiport RapidIO systems with asynchronous discovery process (global counter implementation is affected by race between threads). [akpm@linux-foundation.org: tweak code layput] Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com> Cc: Matt Porter <mporter@kernel.crashing.org> Cc: Li Yang <leoli@freescale.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/rapidio/rio-scan.c3
-rw-r--r--drivers/rapidio/rio.c51
2 files changed, 50 insertions, 4 deletions
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 8b7c4bce7a4a..745670f535e8 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -44,7 +44,6 @@ static void rio_init_em(struct rio_dev *rdev);
DEFINE_SPINLOCK(rio_global_list_lock);
static int next_destid = 0;
-static int next_net = 0;
static int next_comptag = 1;
static int rio_mport_phys_table[] = {
@@ -1062,7 +1061,7 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port)
INIT_LIST_HEAD(&net->mports);
list_add_tail(&port->nnode, &net->mports);
net->hport = port;
- net->id = next_net++;
+ net->id = port->id;
}
return net;
}
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index d7b68cc2d843..d4bd69013c50 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -1260,15 +1260,62 @@ static int __devinit rio_init(void)
return 0;
}
+static struct workqueue_struct *rio_wq;
+
+struct rio_disc_work {
+ struct work_struct work;
+ struct rio_mport *mport;
+};
+
+static void __devinit disc_work_handler(struct work_struct *_work)
+{
+ struct rio_disc_work *work;
+
+ work = container_of(_work, struct rio_disc_work, work);
+ pr_debug("RIO: discovery work for mport %d %s\n",
+ work->mport->id, work->mport->name);
+ rio_disc_mport(work->mport);
+
+ kfree(work);
+}
+
int __devinit rio_init_mports(void)
{
struct rio_mport *port;
+ struct rio_disc_work *work;
+ int no_disc = 0;
list_for_each_entry(port, &rio_mports, node) {
if (port->host_deviceid >= 0)
rio_enum_mport(port);
- else
- rio_disc_mport(port);
+ else if (!no_disc) {
+ if (!rio_wq) {
+ rio_wq = alloc_workqueue("riodisc", 0, 0);
+ if (!rio_wq) {
+ pr_err("RIO: unable allocate rio_wq\n");
+ no_disc = 1;
+ continue;
+ }
+ }
+
+ work = kzalloc(sizeof *work, GFP_KERNEL);
+ if (!work) {
+ pr_err("RIO: no memory for work struct\n");
+ no_disc = 1;
+ continue;
+ }
+
+ work->mport = port;
+ INIT_WORK(&work->work, disc_work_handler);
+ queue_work(rio_wq, &work->work);
+ }
+ }
+
+ if (rio_wq) {
+ pr_debug("RIO: flush discovery workqueue\n");
+ flush_workqueue(rio_wq);
+ pr_debug("RIO: flush discovery workqueue finished\n");
+ destroy_workqueue(rio_wq);
}
rio_init();