X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fieee1394%2Fnodemgr.c;h=05710c7c12206aa1a9fcca8bad4db2eac3be7697;hb=7a6ad1dd86a45da8f235300349d4abd9ae7d1a21;hp=ba9faeff4793a0a5891493380ff6fb3b5e3278fb;hpb=91efa462054d44ae52b0c6c8325ed5e899f2cd17;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index ba9faef..05710c7 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -16,7 +16,9 @@ #include #include #include +#include #include +#include #include #include "csr.h" @@ -115,7 +117,7 @@ static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length, static int nodemgr_get_max_rom(quadlet_t *bus_info_data, void *__ci) { - return (CSR1212_BE32_TO_CPU(bus_info_data[2]) >> 8) & 0x3; + return (be32_to_cpu(bus_info_data[2]) >> 8) & 0x3; } static struct csr1212_bus_ops nodemgr_csr_ops = { @@ -144,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; @@ -153,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); @@ -164,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; @@ -282,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'; \ @@ -370,9 +370,7 @@ static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute if (state == 1) { ud->ignore_driver = 1; - down_write(&ieee1394_bus_type.subsys.rwsem); device_release_driver(dev); - up_write(&ieee1394_bus_type.subsys.rwsem); } else if (state == 0) ud->ignore_driver = 0; @@ -522,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) { @@ -582,7 +583,7 @@ static void nodemgr_create_drv_files(struct hpsb_protocol_driver *driver) goto fail; return; fail: - HPSB_ERR("Failed to add sysfs attribute for driver %s", driver->name); + HPSB_ERR("Failed to add sysfs attribute"); } @@ -606,8 +607,7 @@ static void nodemgr_create_ne_dev_files(struct node_entry *ne) goto fail; return; fail: - HPSB_ERR("Failed to add sysfs attribute for node %016Lx", - (unsigned long long)ne->guid); + HPSB_ERR("Failed to add sysfs attribute"); } @@ -621,7 +621,7 @@ static void nodemgr_create_host_dev_files(struct hpsb_host *host) goto fail; return; fail: - HPSB_ERR("Failed to add sysfs attribute for host %d", host->id); + HPSB_ERR("Failed to add sysfs attribute"); } @@ -681,8 +681,7 @@ static void nodemgr_create_ud_dev_files(struct unit_directory *ud) } return; fail: - HPSB_ERR("Failed to add sysfs attributes for unit %s", - ud->device.bus_id); + HPSB_ERR("Failed to add sysfs attribute"); } @@ -705,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; @@ -731,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); @@ -775,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); @@ -786,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; } @@ -853,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); @@ -885,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, ¶m, __match_ne_nodeid); + if (!dev) + return NULL; + ne = container_of(dev, struct node_entry, node_dev); + put_device(dev); - return ret_ne; + return ne; } @@ -938,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); @@ -979,7 +1002,8 @@ static struct unit_directory *nodemgr_process_unit_directory ud->ne = ne; ud->ignore_driver = ignore_drivers; - ud->address = ud_kv->offset + CSR1212_CONFIG_ROM_SPACE_BASE; + ud->address = ud_kv->offset + CSR1212_REGISTER_SPACE_BASE; + ud->directory_id = ud->address & 0xffffff; ud->ud_kv = ud_kv; ud->id = (*id)++; @@ -1016,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; } @@ -1088,6 +1112,10 @@ static struct unit_directory *nodemgr_process_unit_directory break; + case CSR1212_KV_ID_DIRECTORY_ID: + ud->directory_id = kv->value.immediate; + break; + default: break; } @@ -1110,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; @@ -1137,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; @@ -1146,44 +1174,40 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent last_key_id = kv->key.id; } - if (ne->vendor_name_kv && - device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv)) - goto fail; - return; -fail: - HPSB_ERR("Failed to add sysfs attribute for node %016Lx", - (unsigned long long)ne->guid); + if (ne->vendor_name_kv) { + 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 { \ - int printed; \ - envp[i++] = buffer; \ - printed = snprintf(buffer, buffer_size - length, \ - fmt, val); \ - if ((buffer_size - (length+printed) <= 0) || (i >= num_envp)) \ - return -ENOMEM; \ - length += printed+1; \ - buffer += printed+1; \ + retval = add_uevent_var(env, fmt, val); \ + if (retval) \ + return retval; \ } while (0) PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id); @@ -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,84 +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; -static void nodemgr_suspend_ne(struct node_entry *ne) + 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); + } + } + + 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; - - down_write(&ieee1394_bus_type.subsys.rwsem); - if (ud->device.driver && - (!ud->device.driver->suspend || - ud->device.driver->suspend(&ud->device, PMSG_SUSPEND))) - device_release_driver(&ud->device); - up_write(&ieee1394_bus_type.subsys.rwsem); - } - 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; - - down_read(&ieee1394_bus_type.subsys.rwsem); - if (ud->device.driver && ud->device.driver->resume) - ud->device.driver->resume(&ud->device); - up_read(&ieee1394_bus_type.subsys.rwsem); - } - 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; - down_write(&ieee1394_bus_type.subsys.rwsem); - 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_write(&ieee1394_bus_type.subsys.rwsem); } - 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); } @@ -1511,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 @@ -1527,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, ¶m, __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 @@ -1675,13 +1727,15 @@ 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); for (;;) { /* Sleep until next bus reset */ set_current_state(TASK_INTERRUPTIBLE); - if (get_hpsb_generation(host) == generation) + if (get_hpsb_generation(host) == generation && + !kthread_should_stop()) schedule(); __set_current_state(TASK_RUNNING); @@ -1691,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 @@ -1712,7 +1761,7 @@ static int nodemgr_host_thread(void *__hi) generation = get_hpsb_generation(host); /* If we get a reset before we are done waiting, then - * start the the waiting over again */ + * start the waiting over again */ if (generation != g) g = generation, i = 0; } @@ -1720,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; @@ -1737,35 +1785,54 @@ 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; } -int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)) +struct host_iter_param { + void *data; + int (*cb)(struct hpsb_host *, void *); +}; + +static int __nodemgr_for_each_host(struct device *dev, void *data) { - struct class_device *cdev; struct hpsb_host *host; + struct host_iter_param *hip = (struct host_iter_param *)data; 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); + host = container_of(dev, struct hpsb_host, host_dev); + error = hip->cb(host, hip->data); - if ((error = cb(host, __data))) - break; - } - up(&hpsb_host_class.sem); + return error; +} +/** + * nodemgr_for_each_host - call a function for each IEEE 1394 host + * @data: an address to supply to the callback + * @cb: function to call for each host + * + * Iterate the hosts, calling a given function with supplied data for each host. + * If the callback fails on a host, i.e. if it returns a non-zero value, the + * iteration is stopped. + * + * Return value: 0 on success, non-zero on failure (same as returned by last run + * of the callback). + */ +int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *)) +{ + struct host_iter_param hip; + int error; + + hip.cb = cb; + hip.data = data; + error = class_for_each_device(&hpsb_host_class, &hip, + __nodemgr_for_each_host); return error; } -/* The following four convenience functions use a struct node_entry +/* The following two convenience functions use a struct node_entry * for addressing a node on the bus. They are intended for use by any * process context, not just the nodemgr thread, so we need to be a * little careful when reading out the node ID and generation. The @@ -1780,12 +1847,20 @@ int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)) * ID's. */ -void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt) +/** + * hpsb_node_fill_packet - fill some destination information into a packet + * @ne: destination node + * @packet: packet to fill in + * + * This will fill in the given, pre-initialised hpsb_packet with the current + * information from the node entry (host, node ID, bus generation number). + */ +void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet) { - pkt->host = ne->host; - pkt->generation = ne->generation; + packet->host = ne->host; + packet->generation = ne->generation; barrier(); - pkt->node_id = ne->nodeid; + packet->node_id = ne->nodeid; } int hpsb_node_write(struct node_entry *ne, u64 addr,