[netdrvr] 3c59x: remove irqs_disabled warning from local_bh_enable
[safe/jmp/linux-2.6] / drivers / ieee1394 / nodemgr.c
index 81b3864..05710c7 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
 #include <linux/freezer.h>
+#include <linux/semaphore.h>
 #include <asm/atomic.h>
 
 #include "csr.h"
@@ -145,8 +146,6 @@ static struct csr1212_bus_ops nodemgr_csr_ops = {
  * but now we are much simpler because of the LDM.
  */
 
-static DEFINE_MUTEX(nodemgr_serialize);
-
 struct host_info {
        struct hpsb_host *host;
        struct list_head list;
@@ -154,8 +153,7 @@ struct host_info {
 };
 
 static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
-static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
-                         char *buffer, int buffer_size);
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env);
 static void nodemgr_resume_ne(struct node_entry *ne);
 static void nodemgr_remove_ne(struct node_entry *ne);
 static struct node_entry *find_entry_by_guid(u64 guid);
@@ -165,37 +163,38 @@ struct bus_type ieee1394_bus_type = {
        .match          = nodemgr_bus_match,
 };
 
-static void host_cls_release(struct class_device *class_dev)
+static void host_cls_release(struct device *dev)
 {
-       put_device(&container_of((class_dev), struct hpsb_host, class_dev)->device);
+       put_device(&container_of((dev), struct hpsb_host, host_dev)->device);
 }
 
 struct class hpsb_host_class = {
        .name           = "ieee1394_host",
-       .release        = host_cls_release,
+       .dev_release    = host_cls_release,
 };
 
-static void ne_cls_release(struct class_device *class_dev)
+static void ne_cls_release(struct device *dev)
 {
-       put_device(&container_of((class_dev), struct node_entry, class_dev)->device);
+       put_device(&container_of((dev), struct node_entry, node_dev)->device);
 }
 
 static struct class nodemgr_ne_class = {
        .name           = "ieee1394_node",
-       .release        = ne_cls_release,
+       .dev_release    = ne_cls_release,
 };
 
-static void ud_cls_release(struct class_device *class_dev)
+static void ud_cls_release(struct device *dev)
 {
-       put_device(&container_of((class_dev), struct unit_directory, class_dev)->device);
+       put_device(&container_of((dev), struct unit_directory, unit_dev)->device);
 }
 
 /* The name here is only so that unit directory hotplug works with old
- * style hotplug, which only ever did unit directories anyway. */
+ * style hotplug, which only ever did unit directories anyway.
+ */
 static struct class nodemgr_ud_class = {
        .name           = "ieee1394",
-       .release        = ud_cls_release,
-       .uevent         = nodemgr_uevent,
+       .dev_release    = ud_cls_release,
+       .dev_uevent     = nodemgr_uevent,
 };
 
 static struct hpsb_highlevel nodemgr_highlevel;
@@ -283,7 +282,7 @@ static ssize_t fw_show_##class##_##td_kv (struct device *dev, struct device_attr
        memcpy(buf,                                                     \
               CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(class->td_kv),      \
               len);                                                    \
-       while ((buf + len - 1) == '\0')                                 \
+       while (buf[len - 1] == '\0')                                    \
                len--;                                                  \
        buf[len++] = '\n';                                              \
        buf[len] = '\0';                                                \
@@ -521,8 +520,11 @@ static ssize_t fw_show_drv_device_ids(struct device_driver *drv, char *buf)
        char *scratch = buf;
 
        driver = container_of(drv, struct hpsb_protocol_driver, driver);
+       id = driver->id_table;
+       if (!id)
+               return 0;
 
-       for (id = driver->id_table; id->match_flags != 0; id++) {
+       for (; id->match_flags != 0; id++) {
                int need_coma = 0;
 
                if (id->match_flags & IEEE1394_MATCH_VENDOR_ID) {
@@ -702,7 +704,11 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
                return 0;
 
        driver = container_of(drv, struct hpsb_protocol_driver, driver);
-       for (id = driver->id_table; id->match_flags != 0; id++) {
+       id = driver->id_table;
+       if (!id)
+               return 0;
+
+       for (; id->match_flags != 0; id++) {
                if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&
                    id->vendor_id != ud->vendor_id)
                        continue;
@@ -728,34 +734,32 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
 
 static DEFINE_MUTEX(nodemgr_serialize_remove_uds);
 
+static int __match_ne(struct device *dev, void *data)
+{
+       struct unit_directory *ud;
+       struct node_entry *ne = (struct node_entry *)data;
+
+       ud = container_of(dev, struct unit_directory, unit_dev);
+       return ud->ne == ne;
+}
+
 static void nodemgr_remove_uds(struct node_entry *ne)
 {
-       struct class_device *cdev;
-       struct unit_directory *tmp, *ud;
+       struct device *dev;
+       struct unit_directory *ud;
 
-       /* Iteration over nodemgr_ud_class.children has to be protected by
-        * nodemgr_ud_class.sem, but class_device_unregister() will eventually
-        * take nodemgr_ud_class.sem too. Therefore pick out one ud at a time,
-        * release the semaphore, and then unregister the ud. Since this code
-        * may be called from other contexts besides the knodemgrds, protect the
-        * gap after release of the semaphore by nodemgr_serialize_remove_uds.
+       /* Use class_find device to iterate the devices. Since this code
+        * may be called from other contexts besides the knodemgrds,
+        * protect it by nodemgr_serialize_remove_uds.
         */
        mutex_lock(&nodemgr_serialize_remove_uds);
        for (;;) {
-               ud = NULL;
-               down(&nodemgr_ud_class.sem);
-               list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
-                       tmp = container_of(cdev, struct unit_directory,
-                                          class_dev);
-                       if (tmp->ne == ne) {
-                               ud = tmp;
-                               break;
-                       }
-               }
-               up(&nodemgr_ud_class.sem);
-               if (ud == NULL)
+               dev = class_find_device(&nodemgr_ud_class, ne, __match_ne);
+               if (!dev)
                        break;
-               class_device_unregister(&ud->class_dev);
+               ud = container_of(dev, struct unit_directory, unit_dev);
+               put_device(dev);
+               device_unregister(&ud->unit_dev);
                device_unregister(&ud->device);
        }
        mutex_unlock(&nodemgr_serialize_remove_uds);
@@ -772,10 +776,9 @@ static void nodemgr_remove_ne(struct node_entry *ne)
 
        HPSB_DEBUG("Node removed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
                   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
-
        nodemgr_remove_uds(ne);
 
-       class_device_unregister(&ne->class_dev);
+       device_unregister(&ne->node_dev);
        device_unregister(dev);
 
        put_device(dev);
@@ -783,7 +786,9 @@ static void nodemgr_remove_ne(struct node_entry *ne)
 
 static int __nodemgr_remove_host_dev(struct device *dev, void *data)
 {
-       nodemgr_remove_ne(container_of(dev, struct node_entry, device));
+       if (dev->bus == &ieee1394_bus_type)
+               nodemgr_remove_ne(container_of(dev, struct node_entry,
+                                 device));
        return 0;
 }
 
@@ -850,14 +855,14 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
        snprintf(ne->device.bus_id, BUS_ID_SIZE, "%016Lx",
                 (unsigned long long)(ne->guid));
 
-       ne->class_dev.dev = &ne->device;
-       ne->class_dev.class = &nodemgr_ne_class;
-       snprintf(ne->class_dev.class_id, BUS_ID_SIZE, "%016Lx",
-                (unsigned long long)(ne->guid));
+       ne->node_dev.parent = &ne->device;
+       ne->node_dev.class = &nodemgr_ne_class;
+       snprintf(ne->node_dev.bus_id, BUS_ID_SIZE, "%016Lx",
+               (unsigned long long)(ne->guid));
 
        if (device_register(&ne->device))
                goto fail_devreg;
-       if (class_device_register(&ne->class_dev))
+       if (device_register(&ne->node_dev))
                goto fail_classdevreg;
        get_device(&ne->device);
 
@@ -882,45 +887,66 @@ fail_alloc:
        return NULL;
 }
 
+static int __match_ne_guid(struct device *dev, void *data)
+{
+       struct node_entry *ne;
+       u64 *guid = (u64 *)data;
+
+       ne = container_of(dev, struct node_entry, node_dev);
+       return ne->guid == *guid;
+}
 
 static struct node_entry *find_entry_by_guid(u64 guid)
 {
-       struct class_device *cdev;
-       struct node_entry *ne, *ret_ne = NULL;
-
-       down(&nodemgr_ne_class.sem);
-       list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {
-               ne = container_of(cdev, struct node_entry, class_dev);
+       struct device *dev;
+       struct node_entry *ne;
 
-               if (ne->guid == guid) {
-                       ret_ne = ne;
-                       break;
-               }
-       }
-       up(&nodemgr_ne_class.sem);
+       dev = class_find_device(&nodemgr_ne_class, &guid, __match_ne_guid);
+       if (!dev)
+               return NULL;
+       ne = container_of(dev, struct node_entry, node_dev);
+       put_device(dev);
 
-       return ret_ne;
+       return ne;
 }
 
+struct match_nodeid_param {
+       struct hpsb_host *host;
+       nodeid_t nodeid;
+};
+
+static int __match_ne_nodeid(struct device *dev, void *data)
+{
+       int found = 0;
+       struct node_entry *ne;
+       struct match_nodeid_param *param = (struct match_nodeid_param *)data;
+
+       if (!dev)
+               goto ret;
+       ne = container_of(dev, struct node_entry, node_dev);
+       if (ne->host == param->host && ne->nodeid == param->nodeid)
+               found = 1;
+ret:
+       return found;
+}
 
 static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host,
                                               nodeid_t nodeid)
 {
-       struct class_device *cdev;
-       struct node_entry *ne, *ret_ne = NULL;
+       struct device *dev;
+       struct node_entry *ne;
+       struct match_nodeid_param param;
 
-       down(&nodemgr_ne_class.sem);
-       list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {
-               ne = container_of(cdev, struct node_entry, class_dev);
+       param.host = host;
+       param.nodeid = nodeid;
 
-               if (ne->host == host && ne->nodeid == nodeid) {
-                       ret_ne = ne;
-                       break;
-               }
-       }
-       up(&nodemgr_ne_class.sem);
+       dev = class_find_device(&nodemgr_ne_class, &param, __match_ne_nodeid);
+       if (!dev)
+               return NULL;
+       ne = container_of(dev, struct node_entry, node_dev);
+       put_device(dev);
 
-       return ret_ne;
+       return ne;
 }
 
 
@@ -935,14 +961,14 @@ static void nodemgr_register_device(struct node_entry *ne,
        snprintf(ud->device.bus_id, BUS_ID_SIZE, "%s-%u",
                 ne->device.bus_id, ud->id);
 
-       ud->class_dev.dev = &ud->device;
-       ud->class_dev.class = &nodemgr_ud_class;
-       snprintf(ud->class_dev.class_id, BUS_ID_SIZE, "%s-%u",
+       ud->unit_dev.parent = &ud->device;
+       ud->unit_dev.class = &nodemgr_ud_class;
+       snprintf(ud->unit_dev.bus_id, BUS_ID_SIZE, "%s-%u",
                 ne->device.bus_id, ud->id);
 
        if (device_register(&ud->device))
                goto fail_devreg;
-       if (class_device_register(&ud->class_dev))
+       if (device_register(&ud->unit_dev))
                goto fail_classdevreg;
        get_device(&ud->device);
 
@@ -1014,13 +1040,13 @@ static struct unit_directory *nodemgr_process_unit_directory
                            CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
                                switch (last_key_id) {
                                case CSR1212_KV_ID_VENDOR:
-                                       ud->vendor_name_kv = kv;
                                        csr1212_keep_keyval(kv);
+                                       ud->vendor_name_kv = kv;
                                        break;
 
                                case CSR1212_KV_ID_MODEL:
-                                       ud->model_name_kv = kv;
                                        csr1212_keep_keyval(kv);
+                                       ud->model_name_kv = kv;
                                        break;
 
                                }
@@ -1112,7 +1138,7 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
 {
        unsigned int ud_id = 0;
        struct csr1212_dentry *dentry;
-       struct csr1212_keyval *kv;
+       struct csr1212_keyval *kv, *vendor_name_kv = NULL;
        u8 last_key_id = 0;
 
        ne->needs_probe = 0;
@@ -1139,8 +1165,8 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
                                    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) == 0 &&
                                    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) == 0 &&
                                    CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) == 0) {
-                                       ne->vendor_name_kv = kv;
                                        csr1212_keep_keyval(kv);
+                                       vendor_name_kv = kv;
                                }
                        }
                        break;
@@ -1149,39 +1175,37 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
        }
 
        if (ne->vendor_name_kv) {
-               int error = device_create_file(&ne->device,
-                                              &dev_attr_ne_vendor_name_kv);
-
-               if (error && error != -EEXIST)
+               kv = ne->vendor_name_kv;
+               ne->vendor_name_kv = vendor_name_kv;
+               csr1212_release_keyval(kv);
+       } else if (vendor_name_kv) {
+               ne->vendor_name_kv = vendor_name_kv;
+               if (device_create_file(&ne->device,
+                                      &dev_attr_ne_vendor_name_kv) != 0)
                        HPSB_ERR("Failed to add sysfs attribute");
        }
 }
 
 #ifdef CONFIG_HOTPLUG
 
-static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
-                         char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct unit_directory *ud;
-       int i = 0;
-       int length = 0;
        int retval = 0;
        /* ieee1394:venNmoNspNverN */
        char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
 
-       if (!cdev)
+       if (!dev)
                return -ENODEV;
 
-       ud = container_of(cdev, struct unit_directory, class_dev);
+       ud = container_of(dev, struct unit_directory, unit_dev);
 
        if (ud->ne->in_limbo || ud->ignore_driver)
                return -ENODEV;
 
 #define PUT_ENVP(fmt,val)                                      \
 do {                                                           \
-       retval = add_uevent_var(envp, num_envp, &i,             \
-                               buffer, buffer_size, &length,   \
-                               fmt, val);                      \
+       retval = add_uevent_var(env, fmt, val);         \
        if (retval)                                             \
                return retval;                                  \
 } while (0)
@@ -1200,15 +1224,12 @@ do {                                                            \
 
 #undef PUT_ENVP
 
-       envp[i] = NULL;
-
        return 0;
 }
 
 #else
 
-static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp,
-                         char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        return -ENODEV;
 }
@@ -1375,78 +1396,109 @@ static void nodemgr_node_scan(struct host_info *hi, int generation)
        }
 }
 
+static int __nodemgr_driver_suspend(struct device *dev, void *data)
+{
+       struct unit_directory *ud;
+       struct device_driver *drv;
+       struct node_entry *ne = (struct node_entry *)data;
+       int error;
+
+       ud = container_of(dev, struct unit_directory, unit_dev);
+       if (ud->ne == ne) {
+               drv = get_driver(ud->device.driver);
+               if (drv) {
+                       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);
+                       put_driver(drv);
+               }
+       }
 
-static void nodemgr_suspend_ne(struct node_entry *ne)
+       return 0;
+}
+
+static int __nodemgr_driver_resume(struct device *dev, void *data)
 {
-       struct class_device *cdev;
        struct unit_directory *ud;
+       struct device_driver *drv;
+       struct node_entry *ne = (struct node_entry *)data;
+
+       ud = container_of(dev, struct unit_directory, unit_dev);
+       if (ud->ne == ne) {
+               drv = get_driver(ud->device.driver);
+               if (drv) {
+                       if (drv->resume) {
+                               down(&ud->device.sem);
+                               drv->resume(&ud->device);
+                               up(&ud->device.sem);
+                       }
+                       put_driver(drv);
+               }
+       }
+
+       return 0;
+}
 
+static void nodemgr_suspend_ne(struct node_entry *ne)
+{
        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);
 
        ne->in_limbo = 1;
        WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo));
 
-       down(&nodemgr_ud_class.sem);
-       list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
-               ud = container_of(cdev, struct unit_directory, class_dev);
-               if (ud->ne != ne)
-                       continue;
-
-               if (ud->device.driver &&
-                   (!ud->device.driver->suspend ||
-                     ud->device.driver->suspend(&ud->device, PMSG_SUSPEND)))
-                       device_release_driver(&ud->device);
-       }
-       up(&nodemgr_ud_class.sem);
+       class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_suspend);
 }
 
 
 static void nodemgr_resume_ne(struct node_entry *ne)
 {
-       struct class_device *cdev;
-       struct unit_directory *ud;
-
        ne->in_limbo = 0;
        device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
 
-       down(&nodemgr_ud_class.sem);
-       list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
-               ud = container_of(cdev, struct unit_directory, class_dev);
-               if (ud->ne != ne)
-                       continue;
-
-               if (ud->device.driver && ud->device.driver->resume)
-                       ud->device.driver->resume(&ud->device);
-       }
-       up(&nodemgr_ud_class.sem);
-
+       class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_resume);
        HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
                   NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
 }
 
-
-static void nodemgr_update_pdrv(struct node_entry *ne)
+static int __nodemgr_update_pdrv(struct device *dev, void *data)
 {
        struct unit_directory *ud;
+       struct device_driver *drv;
        struct hpsb_protocol_driver *pdrv;
-       struct class_device *cdev;
-
-       down(&nodemgr_ud_class.sem);
-       list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
-               ud = container_of(cdev, struct unit_directory, class_dev);
-               if (ud->ne != ne)
-                       continue;
+       struct node_entry *ne = (struct node_entry *)data;
+       int error;
 
-               if (ud->device.driver) {
-                       pdrv = container_of(ud->device.driver,
-                                           struct hpsb_protocol_driver,
+       ud = container_of(dev, struct unit_directory, unit_dev);
+       if (ud->ne == ne) {
+               drv = get_driver(ud->device.driver);
+               if (drv) {
+                       error = 0;
+                       pdrv = container_of(drv, struct hpsb_protocol_driver,
                                            driver);
-                       if (pdrv->update && pdrv->update(ud))
+                       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);
+
+       return 0;
+}
+
+static void nodemgr_update_pdrv(struct node_entry *ne)
+{
+       class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_update_pdrv);
 }
 
 
@@ -1505,13 +1557,31 @@ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int ge
        put_device(dev);
 }
 
+struct probe_param {
+       struct host_info *hi;
+       int generation;
+};
+
+static int __nodemgr_node_probe(struct device *dev, void *data)
+{
+       struct probe_param *param = (struct probe_param *)data;
+       struct node_entry *ne;
+
+       ne = container_of(dev, struct node_entry, node_dev);
+       if (!ne->needs_probe)
+               nodemgr_probe_ne(param->hi, ne, param->generation);
+       if (ne->needs_probe)
+               nodemgr_probe_ne(param->hi, ne, param->generation);
+       return 0;
+}
 
 static void nodemgr_node_probe(struct host_info *hi, int generation)
 {
        struct hpsb_host *host = hi->host;
-       struct class_device *cdev;
-       struct node_entry *ne;
+       struct probe_param param;
 
+       param.hi = hi;
+       param.generation = generation;
        /* Do some processing of the nodes we've probed. This pulls them
         * into the sysfs layer if needed, and can result in processing of
         * unit-directories, or just updating the node and it's
@@ -1521,19 +1591,7 @@ static void nodemgr_node_probe(struct host_info *hi, int generation)
         * while probes are time-consuming. (Well, those probes need some
         * improvement...) */
 
-       down(&nodemgr_ne_class.sem);
-       list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {
-               ne = container_of(cdev, struct node_entry, class_dev);
-               if (!ne->needs_probe)
-                       nodemgr_probe_ne(hi, ne, generation);
-       }
-       list_for_each_entry(cdev, &nodemgr_ne_class.children, node) {
-               ne = container_of(cdev, struct node_entry, class_dev);
-               if (ne->needs_probe)
-                       nodemgr_probe_ne(hi, ne, generation);
-       }
-       up(&nodemgr_ne_class.sem);
-
+       class_for_each_device(&nodemgr_ne_class, &param, __nodemgr_node_probe);
 
        /* If we had a bus reset while we were scanning the bus, it is
         * possible that we did not probe all nodes.  In that case, we
@@ -1669,6 +1727,7 @@ static int nodemgr_host_thread(void *__hi)
        unsigned int g, generation = 0;
        int i, reset_cycles = 0;
 
+       set_freezable();
        /* Setup our device-model entries */
        nodemgr_create_host_dev_files(host);
 
@@ -1686,18 +1745,13 @@ static int nodemgr_host_thread(void *__hi)
                if (kthread_should_stop())
                        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,
                 * to make sure things settle down. */
                g = get_hpsb_generation(host);
                for (i = 0; i < 4 ; i++) {
-                       if (msleep_interruptible(63) || kthread_should_stop())
-                               goto unlock_exit;
+                       msleep_interruptible(63);
+                       if (kthread_should_stop())
+                               goto exit;
 
                        /* Now get the generation in which the node ID's we collect
                         * are valid.  During the bus scan we will use this generation
@@ -1715,7 +1769,6 @@ static int nodemgr_host_thread(void *__hi)
                if (!nodemgr_check_irm_capability(host, reset_cycles) ||
                    !nodemgr_do_irm_duties(host, reset_cycles)) {
                        reset_cycles++;
-                       mutex_unlock(&nodemgr_serialize);
                        continue;
                }
                reset_cycles = 0;
@@ -1732,16 +1785,28 @@ static int nodemgr_host_thread(void *__hi)
 
                /* Update some of our sysfs symlinks */
                nodemgr_update_host_dev_links(host);
-
-               mutex_unlock(&nodemgr_serialize);
        }
-unlock_exit:
-       mutex_unlock(&nodemgr_serialize);
 exit:
        HPSB_VERBOSE("NodeMgr: Exiting thread");
        return 0;
 }
 
+struct host_iter_param {
+       void *data;
+       int (*cb)(struct hpsb_host *, void *);
+};
+
+static int __nodemgr_for_each_host(struct device *dev, void *data)
+{
+       struct hpsb_host *host;
+       struct host_iter_param *hip = (struct host_iter_param *)data;
+       int error = 0;
+
+       host = container_of(dev, struct hpsb_host, host_dev);
+       error = hip->cb(host, hip->data);
+
+       return error;
+}
 /**
  * nodemgr_for_each_host - call a function for each IEEE 1394 host
  * @data: an address to supply to the callback
@@ -1756,18 +1821,13 @@ exit:
  */
 int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
 {
-       struct class_device *cdev;
-       struct hpsb_host *host;
-       int error = 0;
-
-       down(&hpsb_host_class.sem);
-       list_for_each_entry(cdev, &hpsb_host_class.children, node) {
-               host = container_of(cdev, struct hpsb_host, class_dev);
+       struct host_iter_param hip;
+       int error;
 
-               if ((error = cb(host, data)))
-                       break;
-       }
-       up(&hpsb_host_class.sem);
+       hip.cb = cb;
+       hip.data = data;
+       error = class_for_each_device(&hpsb_host_class, &hip,
+                                     __nodemgr_for_each_host);
 
        return error;
 }