diff options
Diffstat (limited to 'drivers/ieee1394/nodemgr.c')
-rw-r--r-- | drivers/ieee1394/nodemgr.c | 188 |
1 files changed, 104 insertions, 84 deletions
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 81b3864d2ba..2ffd53461db 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -19,6 +19,7 @@ #include <linux/mutex.h> #include <linux/freezer.h> #include <asm/atomic.h> +#include <asm/semaphore.h> #include "csr.h" #include "highlevel.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,7 +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, +static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); static void nodemgr_resume_ne(struct node_entry *ne); static void nodemgr_remove_ne(struct node_entry *ne); @@ -165,37 +164,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 +283,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'; \ @@ -730,11 +730,11 @@ static DEFINE_MUTEX(nodemgr_serialize_remove_uds); static void nodemgr_remove_uds(struct node_entry *ne) { - struct class_device *cdev; + struct device *dev; struct unit_directory *tmp, *ud; - /* Iteration over nodemgr_ud_class.children has to be protected by - * nodemgr_ud_class.sem, but class_device_unregister() will eventually + /* Iteration over nodemgr_ud_class.devices has to be protected by + * nodemgr_ud_class.sem, but 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 @@ -744,9 +744,9 @@ static void nodemgr_remove_uds(struct node_entry *ne) 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); + list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { + tmp = container_of(dev, struct unit_directory, + unit_dev); if (tmp->ne == ne) { ud = tmp; break; @@ -755,7 +755,7 @@ static void nodemgr_remove_uds(struct node_entry *ne) up(&nodemgr_ud_class.sem); if (ud == NULL) break; - class_device_unregister(&ud->class_dev); + device_unregister(&ud->unit_dev); device_unregister(&ud->device); } mutex_unlock(&nodemgr_serialize_remove_uds); @@ -772,10 +772,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 +782,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 +851,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,12 +886,12 @@ fail_alloc: static struct node_entry *find_entry_by_guid(u64 guid) { - struct class_device *cdev; + struct device *dev; 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); + list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { + ne = container_of(dev, struct node_entry, node_dev); if (ne->guid == guid) { ret_ne = ne; @@ -906,12 +907,12 @@ static struct node_entry *find_entry_by_guid(u64 guid) static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t nodeid) { - struct class_device *cdev; + struct device *dev; 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); + list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { + ne = container_of(dev, struct node_entry, node_dev); if (ne->host == host && ne->nodeid == nodeid) { ret_ne = ne; @@ -935,14 +936,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); @@ -1159,7 +1160,7 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent #ifdef CONFIG_HOTPLUG -static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp, +static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { struct unit_directory *ud; @@ -1169,10 +1170,10 @@ static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp, /* 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; @@ -1207,7 +1208,7 @@ do { \ #else -static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp, +static int nodemgr_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { return -ENODEV; @@ -1378,8 +1379,10 @@ static void nodemgr_node_scan(struct host_info *hi, int generation) static void nodemgr_suspend_ne(struct node_entry *ne) { - struct class_device *cdev; + struct device *dev; struct unit_directory *ud; + struct device_driver *drv; + int error; HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); @@ -1388,15 +1391,24 @@ static void nodemgr_suspend_ne(struct node_entry *ne) 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); + list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { + ud = container_of(dev, struct unit_directory, unit_dev); if (ud->ne != ne) continue; - if (ud->device.driver && - (!ud->device.driver->suspend || - ud->device.driver->suspend(&ud->device, PMSG_SUSPEND))) + drv = get_driver(ud->device.driver); + if (!drv) + 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); + put_driver(drv); } up(&nodemgr_ud_class.sem); } @@ -1404,20 +1416,29 @@ static void nodemgr_suspend_ne(struct node_entry *ne) static void nodemgr_resume_ne(struct node_entry *ne) { - struct class_device *cdev; + struct device *dev; struct unit_directory *ud; + struct device_driver *drv; 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); + list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { + ud = container_of(dev, struct unit_directory, unit_dev); if (ud->ne != ne) continue; - if (ud->device.driver && ud->device.driver->resume) - ud->device.driver->resume(&ud->device); + drv = get_driver(ud->device.driver); + 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); @@ -1428,23 +1449,32 @@ static void nodemgr_resume_ne(struct node_entry *ne) static void nodemgr_update_pdrv(struct node_entry *ne) { + struct device *dev; struct unit_directory *ud; + struct device_driver *drv; struct hpsb_protocol_driver *pdrv; - struct class_device *cdev; + int error; down(&nodemgr_ud_class.sem); - list_for_each_entry(cdev, &nodemgr_ud_class.children, node) { - ud = container_of(cdev, struct unit_directory, class_dev); + list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { + ud = container_of(dev, struct unit_directory, unit_dev); if (ud->ne != ne) continue; - if (ud->device.driver) { - pdrv = container_of(ud->device.driver, - struct hpsb_protocol_driver, - driver); - if (pdrv->update && pdrv->update(ud)) - device_release_driver(&ud->device); + drv = get_driver(ud->device.driver); + if (!drv) + continue; + + error = 0; + 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); } @@ -1509,7 +1539,7 @@ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int ge static void nodemgr_node_probe(struct host_info *hi, int generation) { struct hpsb_host *host = hi->host; - struct class_device *cdev; + struct device *dev; struct node_entry *ne; /* Do some processing of the nodes we've probed. This pulls them @@ -1522,13 +1552,13 @@ static void nodemgr_node_probe(struct host_info *hi, int generation) * 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); + list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { + ne = container_of(dev, struct node_entry, node_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); + list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { + ne = container_of(dev, struct node_entry, node_dev); if (ne->needs_probe) nodemgr_probe_ne(hi, ne, generation); } @@ -1669,6 +1699,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 +1717,12 @@ 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; + 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 +1740,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,11 +1756,7 @@ 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; @@ -1756,13 +1776,13 @@ exit: */ int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *)) { - struct class_device *cdev; + struct device *dev; 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); + list_for_each_entry(dev, &hpsb_host_class.devices, node) { + host = container_of(dev, struct hpsb_host, host_dev); if ((error = cb(host, data))) break; |