diff options
Diffstat (limited to 'drivers/ieee1394/nodemgr.c')
-rw-r--r-- | drivers/ieee1394/nodemgr.c | 279 |
1 files changed, 108 insertions, 171 deletions
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 16240a789650..2376b729e876 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -154,9 +154,6 @@ struct host_info { static int nodemgr_bus_match(struct device * dev, struct device_driver * drv); 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); struct bus_type ieee1394_bus_type = { .name = "ieee1394", @@ -385,27 +382,6 @@ static ssize_t fw_get_ignore_driver(struct device *dev, struct device_attribute static DEVICE_ATTR(ignore_driver, S_IWUSR | S_IRUGO, fw_get_ignore_driver, fw_set_ignore_driver); -static ssize_t fw_set_destroy_node(struct bus_type *bus, const char *buf, size_t count) -{ - struct node_entry *ne; - u64 guid = (u64)simple_strtoull(buf, NULL, 16); - - ne = find_entry_by_guid(guid); - - if (ne == NULL || !ne->in_limbo) - return -EINVAL; - - nodemgr_remove_ne(ne); - - return count; -} -static ssize_t fw_get_destroy_node(struct bus_type *bus, char *buf) -{ - return sprintf(buf, "You can destroy in_limbo nodes by writing their GUID to this file\n"); -} -static BUS_ATTR(destroy_node, S_IWUSR | S_IRUGO, fw_get_destroy_node, fw_set_destroy_node); - - static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf, size_t count) { @@ -442,7 +418,6 @@ static BUS_ATTR(ignore_drivers, S_IWUSR | S_IRUGO, fw_get_ignore_drivers, fw_set struct bus_attribute *const fw_bus_attrs[] = { - &bus_attr_destroy_node, &bus_attr_rescan, &bus_attr_ignore_drivers, NULL @@ -734,10 +709,10 @@ 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) +static int match_ne(struct device *dev, void *data) { struct unit_directory *ud; - struct node_entry *ne = (struct node_entry *)data; + struct node_entry *ne = data; ud = container_of(dev, struct unit_directory, unit_dev); return ud->ne == ne; @@ -754,8 +729,7 @@ static void nodemgr_remove_uds(struct node_entry *ne) */ mutex_lock(&nodemgr_serialize_remove_uds); for (;;) { - dev = class_find_device(&nodemgr_ud_class, NULL, ne, - __match_ne); + dev = class_find_device(&nodemgr_ud_class, NULL, ne, match_ne); if (!dev) break; ud = container_of(dev, struct unit_directory, unit_dev); @@ -785,7 +759,7 @@ static void nodemgr_remove_ne(struct node_entry *ne) put_device(dev); } -static int __nodemgr_remove_host_dev(struct device *dev, void *data) +static int remove_host_dev(struct device *dev, void *data) { if (dev->bus == &ieee1394_bus_type) nodemgr_remove_ne(container_of(dev, struct node_entry, @@ -795,7 +769,7 @@ static int __nodemgr_remove_host_dev(struct device *dev, void *data) static void nodemgr_remove_host_dev(struct device *dev) { - WARN_ON(device_for_each_child(dev, NULL, __nodemgr_remove_host_dev)); + device_for_each_child(dev, NULL, remove_host_dev); sysfs_remove_link(&dev->kobj, "irm_id"); sysfs_remove_link(&dev->kobj, "busmgr_id"); sysfs_remove_link(&dev->kobj, "host_id"); @@ -830,11 +804,10 @@ static void nodemgr_update_bus_options(struct node_entry *ne) } -static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr *csr, - struct host_info *hi, nodeid_t nodeid, - unsigned int generation) +static struct node_entry *nodemgr_create_node(octlet_t guid, + struct csr1212_csr *csr, struct hpsb_host *host, + nodeid_t nodeid, unsigned int generation) { - struct hpsb_host *host = hi->host; struct node_entry *ne; ne = kzalloc(sizeof(*ne), GFP_KERNEL); @@ -888,10 +861,10 @@ fail_alloc: return NULL; } -static int __match_ne_guid(struct device *dev, void *data) +static int match_ne_guid(struct device *dev, void *data) { struct node_entry *ne; - u64 *guid = (u64 *)data; + u64 *guid = data; ne = container_of(dev, struct node_entry, node_dev); return ne->guid == *guid; @@ -902,8 +875,7 @@ static struct node_entry *find_entry_by_guid(u64 guid) struct device *dev; struct node_entry *ne; - dev = class_find_device(&nodemgr_ne_class, NULL, &guid, - __match_ne_guid); + dev = class_find_device(&nodemgr_ne_class, NULL, &guid, match_ne_guid); if (!dev) return NULL; ne = container_of(dev, struct node_entry, node_dev); @@ -912,21 +884,21 @@ static struct node_entry *find_entry_by_guid(u64 guid) return ne; } -struct match_nodeid_param { +struct match_nodeid_parameter { struct hpsb_host *host; nodeid_t nodeid; }; -static int __match_ne_nodeid(struct device *dev, void *data) +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; + struct match_nodeid_parameter *p = data; if (!dev) goto ret; ne = container_of(dev, struct node_entry, node_dev); - if (ne->host == param->host && ne->nodeid == param->nodeid) + if (ne->host == p->host && ne->nodeid == p->nodeid) found = 1; ret: return found; @@ -937,13 +909,12 @@ static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, { struct device *dev; struct node_entry *ne; - struct match_nodeid_param param; + struct match_nodeid_parameter p; - param.host = host; - param.nodeid = nodeid; + p.host = host; + p.nodeid = nodeid; - dev = class_find_device(&nodemgr_ne_class, NULL, ¶m, - __match_ne_nodeid); + dev = class_find_device(&nodemgr_ne_class, NULL, &p, match_ne_nodeid); if (!dev) return NULL; ne = container_of(dev, struct node_entry, node_dev); @@ -990,7 +961,7 @@ fail_devreg: * immediate unit directories looking for software_id and * software_version entries, in order to get driver autoloading working. */ static struct unit_directory *nodemgr_process_unit_directory - (struct host_info *hi, struct node_entry *ne, struct csr1212_keyval *ud_kv, + (struct node_entry *ne, struct csr1212_keyval *ud_kv, unsigned int *id, struct unit_directory *parent) { struct unit_directory *ud; @@ -1083,7 +1054,7 @@ static struct unit_directory *nodemgr_process_unit_directory nodemgr_register_device(ne, ud, &ne->device); /* process the child unit */ - ud_child = nodemgr_process_unit_directory(hi, ne, kv, id, ud); + ud_child = nodemgr_process_unit_directory(ne, kv, id, ud); if (ud_child == NULL) break; @@ -1137,7 +1108,7 @@ unit_directory_error: } -static void nodemgr_process_root_directory(struct host_info *hi, struct node_entry *ne) +static void nodemgr_process_root_directory(struct node_entry *ne) { unsigned int ud_id = 0; struct csr1212_dentry *dentry; @@ -1157,7 +1128,7 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent break; case CSR1212_KV_ID_UNIT: - nodemgr_process_unit_directory(hi, ne, kv, &ud_id, NULL); + nodemgr_process_unit_directory(ne, kv, &ud_id, NULL); break; case CSR1212_KV_ID_DESCRIPTOR: @@ -1273,8 +1244,7 @@ void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver) * the to take whatever actions required. */ static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr, - struct host_info *hi, nodeid_t nodeid, - unsigned int generation) + nodeid_t nodeid, unsigned int generation) { if (ne->nodeid != nodeid) { HPSB_DEBUG("Node changed: " NODE_BUS_FMT " -> " NODE_BUS_FMT, @@ -1305,19 +1275,23 @@ static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr, csr1212_destroy_csr(csr); } - if (ne->in_limbo) - nodemgr_resume_ne(ne); - /* Mark the node current */ ne->generation = generation; -} + if (ne->in_limbo) { + device_remove_file(&ne->device, &dev_attr_ne_in_limbo); + ne->in_limbo = false; + HPSB_DEBUG("Node reactivated: " + "ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", + NODE_BUS_ARGS(ne->host, ne->nodeid), + (unsigned long long)ne->guid); + } +} -static void nodemgr_node_scan_one(struct host_info *hi, +static void nodemgr_node_scan_one(struct hpsb_host *host, nodeid_t nodeid, int generation) { - struct hpsb_host *host = hi->host; struct node_entry *ne; octlet_t guid; struct csr1212_csr *csr; @@ -1373,16 +1347,15 @@ static void nodemgr_node_scan_one(struct host_info *hi, } if (!ne) - nodemgr_create_node(guid, csr, hi, nodeid, generation); + nodemgr_create_node(guid, csr, host, nodeid, generation); else - nodemgr_update_node(ne, csr, hi, nodeid, generation); + nodemgr_update_node(ne, csr, nodeid, generation); } -static void nodemgr_node_scan(struct host_info *hi, int generation) +static void nodemgr_node_scan(struct hpsb_host *host, int generation) { int count; - struct hpsb_host *host = hi->host; struct selfid *sid = (struct selfid *)host->topology_map; nodeid_t nodeid = LOCAL_BUS; @@ -1395,89 +1368,26 @@ static void nodemgr_node_scan(struct host_info *hi, int generation) nodeid++; continue; } - nodemgr_node_scan_one(hi, nodeid++, 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); - } - } - - return 0; -} - -static int __nodemgr_driver_resume(struct device *dev, void *data) -{ - 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); - } + nodemgr_node_scan_one(host, nodeid++, generation); } - - return 0; } -static void nodemgr_suspend_ne(struct node_entry *ne) +static void nodemgr_pause_ne(struct node_entry *ne) { - HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", + HPSB_DEBUG("Node paused: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); - ne->in_limbo = 1; + ne->in_limbo = true; WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo)); - - class_for_each_device(&nodemgr_ud_class, NULL, ne, - __nodemgr_driver_suspend); -} - - -static void nodemgr_resume_ne(struct node_entry *ne) -{ - ne->in_limbo = 0; - device_remove_file(&ne->device, &dev_attr_ne_in_limbo); - - class_for_each_device(&nodemgr_ud_class, NULL, 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 int __nodemgr_update_pdrv(struct device *dev, void *data) +static int update_pdrv(struct device *dev, void *data) { struct unit_directory *ud; struct device_driver *drv; struct hpsb_protocol_driver *pdrv; - struct node_entry *ne = (struct node_entry *)data; + struct node_entry *ne = data; int error; ud = container_of(dev, struct unit_directory, unit_dev); @@ -1503,11 +1413,9 @@ static int __nodemgr_update_pdrv(struct device *dev, void *data) static void nodemgr_update_pdrv(struct node_entry *ne) { - class_for_each_device(&nodemgr_ud_class, NULL, ne, - __nodemgr_update_pdrv); + class_for_each_device(&nodemgr_ud_class, NULL, ne, update_pdrv); } - /* Write the BROADCAST_CHANNEL as per IEEE1394a 8.3.2.3.11 and 8.4.2.3. This * seems like an optional service but in the end it is practically mandatory * as a consequence of these clauses. @@ -1535,11 +1443,12 @@ static void nodemgr_irm_write_bc(struct node_entry *ne, int generation) } -static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int generation) +static void nodemgr_probe_ne(struct hpsb_host *host, struct node_entry *ne, + int generation) { struct device *dev; - if (ne->host != hi->host || ne->in_limbo) + if (ne->host != host || ne->in_limbo) return; dev = get_device(&ne->device); @@ -1554,40 +1463,40 @@ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int ge * down to the drivers. Otherwise, this is a dead node and we * suspend it. */ if (ne->needs_probe) - nodemgr_process_root_directory(hi, ne); + nodemgr_process_root_directory(ne); else if (ne->generation == generation) nodemgr_update_pdrv(ne); else - nodemgr_suspend_ne(ne); + nodemgr_pause_ne(ne); put_device(dev); } -struct probe_param { - struct host_info *hi; +struct node_probe_parameter { + struct hpsb_host *host; int generation; bool probe_now; }; static int node_probe(struct device *dev, void *data) { - struct probe_param *p = data; + struct node_probe_parameter *p = data; struct node_entry *ne; - if (p->generation != get_hpsb_generation(p->hi->host)) + if (p->generation != get_hpsb_generation(p->host)) return -EAGAIN; ne = container_of(dev, struct node_entry, node_dev); if (ne->needs_probe == p->probe_now) - nodemgr_probe_ne(p->hi, ne, p->generation); + nodemgr_probe_ne(p->host, ne, p->generation); return 0; } -static void nodemgr_node_probe(struct host_info *hi, int generation) +static int nodemgr_node_probe(struct hpsb_host *host, int generation) { - struct probe_param p; + struct node_probe_parameter p; - p.hi = hi; + p.host = host; p.generation = generation; /* * Do some processing of the nodes we've probed. This pulls them @@ -1604,11 +1513,11 @@ static void nodemgr_node_probe(struct host_info *hi, int generation) */ p.probe_now = false; if (class_for_each_device(&nodemgr_ne_class, NULL, &p, node_probe) != 0) - return; + return 0; p.probe_now = true; if (class_for_each_device(&nodemgr_ne_class, NULL, &p, node_probe) != 0) - return; + return 0; /* * Now let's tell the bus to rescan our devices. This may seem * like overhead, but the driver-model core will only scan a @@ -1620,6 +1529,27 @@ static void nodemgr_node_probe(struct host_info *hi, int generation) */ if (bus_rescan_devices(&ieee1394_bus_type) != 0) HPSB_DEBUG("bus_rescan_devices had an error"); + + return 1; +} + +static int remove_nodes_in_limbo(struct device *dev, void *data) +{ + struct node_entry *ne; + + if (dev->bus != &ieee1394_bus_type) + return 0; + + ne = container_of(dev, struct node_entry, device); + if (ne->in_limbo) + nodemgr_remove_ne(ne); + + return 0; +} + +static void nodemgr_remove_nodes_in_limbo(struct hpsb_host *host) +{ + device_for_each_child(&host->device, NULL, remove_nodes_in_limbo); } static int nodemgr_send_resume_packet(struct hpsb_host *host) @@ -1730,10 +1660,9 @@ static int nodemgr_check_irm_capability(struct hpsb_host *host, int cycles) return 1; } -static int nodemgr_host_thread(void *__hi) +static int nodemgr_host_thread(void *data) { - struct host_info *hi = (struct host_info *)__hi; - struct hpsb_host *host = hi->host; + struct hpsb_host *host = data; unsigned int g, generation = 0; int i, reset_cycles = 0; @@ -1787,36 +1716,48 @@ static int nodemgr_host_thread(void *__hi) * entries. This does not do the sysfs stuff, since that * would trigger uevents and such, which is a bad idea at * this point. */ - nodemgr_node_scan(hi, generation); + nodemgr_node_scan(host, generation); /* This actually does the full probe, with sysfs * registration. */ - nodemgr_node_probe(hi, generation); + if (!nodemgr_node_probe(host, generation)) + continue; /* Update some of our sysfs symlinks */ nodemgr_update_host_dev_links(host); + + /* Sleep 3 seconds */ + for (i = 3000/200; i; i--) { + msleep_interruptible(200); + if (kthread_should_stop()) + goto exit; + + if (generation != get_hpsb_generation(host)) + break; + } + /* Remove nodes which are gone, unless a bus reset happened */ + if (!i) + nodemgr_remove_nodes_in_limbo(host); } exit: HPSB_VERBOSE("NodeMgr: Exiting thread"); return 0; } -struct host_iter_param { +struct per_host_parameter { void *data; int (*cb)(struct hpsb_host *, void *); }; -static int __nodemgr_for_each_host(struct device *dev, void *data) +static int per_host(struct device *dev, void *data) { struct hpsb_host *host; - struct host_iter_param *hip = (struct host_iter_param *)data; - int error = 0; + struct per_host_parameter *p = data; host = container_of(dev, struct hpsb_host, host_dev); - error = hip->cb(host, hip->data); - - return error; + return p->cb(host, p->data); } + /** * nodemgr_for_each_host - call a function for each IEEE 1394 host * @data: an address to supply to the callback @@ -1831,15 +1772,11 @@ static int __nodemgr_for_each_host(struct device *dev, void *data) */ 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, NULL, &hip, - __nodemgr_for_each_host); + struct per_host_parameter p; - return error; + p.cb = cb; + p.data = data; + return class_for_each_device(&hpsb_host_class, NULL, &p, per_host); } /* The following two convenience functions use a struct node_entry @@ -1893,7 +1830,7 @@ static void nodemgr_add_host(struct hpsb_host *host) return; } hi->host = host; - hi->thread = kthread_run(nodemgr_host_thread, hi, "knodemgrd_%d", + hi->thread = kthread_run(nodemgr_host_thread, host, "knodemgrd_%d", host->id); if (IS_ERR(hi->thread)) { HPSB_ERR("NodeMgr: cannot start thread for host %d", host->id); |