Commit a0e857ee authored by Stefan Richter's avatar Stefan Richter

ieee1394: nodemgr: parallelize between several hosts

Remove the global nodemgr_serialize mutex which enclosed most of the
host thread event loop.  This allows for parallelism between several
host adapter cards.

Properly serialize the driver hooks .update(), .suspend(), .resume(),
and .remove() by means of device->sem.  These hooks can be called from
outside the host threads' contexts.

Get() and put() the device.driver when calling its hooks.
Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent dd7f2928
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/semaphore.h>
#include "csr.h" #include "csr.h"
#include "highlevel.h" #include "highlevel.h"
...@@ -145,8 +146,6 @@ static struct csr1212_bus_ops nodemgr_csr_ops = { ...@@ -145,8 +146,6 @@ static struct csr1212_bus_ops nodemgr_csr_ops = {
* but now we are much simpler because of the LDM. * but now we are much simpler because of the LDM.
*/ */
static DEFINE_MUTEX(nodemgr_serialize);
struct host_info { struct host_info {
struct hpsb_host *host; struct hpsb_host *host;
struct list_head list; struct list_head list;
...@@ -1382,6 +1381,8 @@ static void nodemgr_suspend_ne(struct node_entry *ne) ...@@ -1382,6 +1381,8 @@ static void nodemgr_suspend_ne(struct node_entry *ne)
{ {
struct device *dev; struct device *dev;
struct unit_directory *ud; struct unit_directory *ud;
struct device_driver *drv;
int error;
HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
...@@ -1395,10 +1396,19 @@ static void nodemgr_suspend_ne(struct node_entry *ne) ...@@ -1395,10 +1396,19 @@ static void nodemgr_suspend_ne(struct node_entry *ne)
if (ud->ne != ne) if (ud->ne != ne)
continue; continue;
if (ud->device.driver && drv = get_driver(ud->device.driver);
(!ud->device.driver->suspend || if (!drv)
ud->device.driver->suspend(&ud->device, PMSG_SUSPEND))) continue;
error = 1; /* release if suspend is not implemented */
if (drv->suspend) {
down(&ud->device.sem);
error = drv->suspend(&ud->device, PMSG_SUSPEND);
up(&ud->device.sem);
}
if (error)
device_release_driver(&ud->device); device_release_driver(&ud->device);
put_driver(drv);
} }
up(&nodemgr_ud_class.sem); up(&nodemgr_ud_class.sem);
} }
...@@ -1408,6 +1418,7 @@ static void nodemgr_resume_ne(struct node_entry *ne) ...@@ -1408,6 +1418,7 @@ static void nodemgr_resume_ne(struct node_entry *ne)
{ {
struct device *dev; struct device *dev;
struct unit_directory *ud; struct unit_directory *ud;
struct device_driver *drv;
ne->in_limbo = 0; ne->in_limbo = 0;
device_remove_file(&ne->device, &dev_attr_ne_in_limbo); device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
...@@ -1418,8 +1429,16 @@ static void nodemgr_resume_ne(struct node_entry *ne) ...@@ -1418,8 +1429,16 @@ static void nodemgr_resume_ne(struct node_entry *ne)
if (ud->ne != ne) if (ud->ne != ne)
continue; continue;
if (ud->device.driver && ud->device.driver->resume) drv = get_driver(ud->device.driver);
ud->device.driver->resume(&ud->device); if (!drv)
continue;
if (drv->resume) {
down(&ud->device.sem);
drv->resume(&ud->device);
up(&ud->device.sem);
}
put_driver(drv);
} }
up(&nodemgr_ud_class.sem); up(&nodemgr_ud_class.sem);
...@@ -1430,9 +1449,11 @@ static void nodemgr_resume_ne(struct node_entry *ne) ...@@ -1430,9 +1449,11 @@ static void nodemgr_resume_ne(struct node_entry *ne)
static void nodemgr_update_pdrv(struct node_entry *ne) static void nodemgr_update_pdrv(struct node_entry *ne)
{ {
struct device *dev;
struct unit_directory *ud; struct unit_directory *ud;
struct device_driver *drv;
struct hpsb_protocol_driver *pdrv; struct hpsb_protocol_driver *pdrv;
struct device *dev; int error;
down(&nodemgr_ud_class.sem); down(&nodemgr_ud_class.sem);
list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { list_for_each_entry(dev, &nodemgr_ud_class.devices, node) {
...@@ -1440,13 +1461,20 @@ static void nodemgr_update_pdrv(struct node_entry *ne) ...@@ -1440,13 +1461,20 @@ static void nodemgr_update_pdrv(struct node_entry *ne)
if (ud->ne != ne) if (ud->ne != ne)
continue; continue;
if (ud->device.driver) { drv = get_driver(ud->device.driver);
pdrv = container_of(ud->device.driver, if (!drv)
struct hpsb_protocol_driver, continue;
driver);
if (pdrv->update && pdrv->update(ud)) error = 0;
device_release_driver(&ud->device); pdrv = container_of(drv, struct hpsb_protocol_driver, driver);
if (pdrv->update) {
down(&ud->device.sem);
error = pdrv->update(ud);
up(&ud->device.sem);
} }
if (error)
device_release_driver(&ud->device);
put_driver(drv);
} }
up(&nodemgr_ud_class.sem); up(&nodemgr_ud_class.sem);
} }
...@@ -1688,18 +1716,12 @@ static int nodemgr_host_thread(void *__hi) ...@@ -1688,18 +1716,12 @@ static int nodemgr_host_thread(void *__hi)
if (kthread_should_stop()) if (kthread_should_stop())
goto exit; goto exit;
if (mutex_lock_interruptible(&nodemgr_serialize)) {
if (try_to_freeze())
continue;
goto exit;
}
/* Pause for 1/4 second in 1/16 second intervals, /* Pause for 1/4 second in 1/16 second intervals,
* to make sure things settle down. */ * to make sure things settle down. */
g = get_hpsb_generation(host); g = get_hpsb_generation(host);
for (i = 0; i < 4 ; i++) { for (i = 0; i < 4 ; i++) {
if (msleep_interruptible(63) || kthread_should_stop()) if (msleep_interruptible(63) || kthread_should_stop())
goto unlock_exit; goto exit;
/* Now get the generation in which the node ID's we collect /* Now get the generation in which the node ID's we collect
* are valid. During the bus scan we will use this generation * are valid. During the bus scan we will use this generation
...@@ -1717,7 +1739,6 @@ static int nodemgr_host_thread(void *__hi) ...@@ -1717,7 +1739,6 @@ static int nodemgr_host_thread(void *__hi)
if (!nodemgr_check_irm_capability(host, reset_cycles) || if (!nodemgr_check_irm_capability(host, reset_cycles) ||
!nodemgr_do_irm_duties(host, reset_cycles)) { !nodemgr_do_irm_duties(host, reset_cycles)) {
reset_cycles++; reset_cycles++;
mutex_unlock(&nodemgr_serialize);
continue; continue;
} }
reset_cycles = 0; reset_cycles = 0;
...@@ -1734,11 +1755,7 @@ static int nodemgr_host_thread(void *__hi) ...@@ -1734,11 +1755,7 @@ static int nodemgr_host_thread(void *__hi)
/* Update some of our sysfs symlinks */ /* Update some of our sysfs symlinks */
nodemgr_update_host_dev_links(host); nodemgr_update_host_dev_links(host);
mutex_unlock(&nodemgr_serialize);
} }
unlock_exit:
mutex_unlock(&nodemgr_serialize);
exit: exit:
HPSB_VERBOSE("NodeMgr: Exiting thread"); HPSB_VERBOSE("NodeMgr: Exiting thread");
return 0; return 0;
......
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