X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fieee1394%2Fnodemgr.c;h=8b12e668b9325878d83ee593f59f24b03cfe2abb;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=cc9c999f9a8bc565d8311620569431248d7dfb1c;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index cc9c999f9..8b12e668b 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -8,8 +8,8 @@ * directory of the kernel sources for details. */ +#include #include -#include #include #include #include @@ -19,18 +19,18 @@ #include #include #include -#include #include #include "ieee1394_types.h" #include "ieee1394.h" +#include "ieee1394_core.h" #include "hosts.h" #include "ieee1394_transactions.h" #include "highlevel.h" #include "csr.h" #include "nodemgr.h" -static int ignore_drivers = 0; +static int ignore_drivers; module_param(ignore_drivers, int, 0444); MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers."); @@ -38,6 +38,7 @@ struct nodemgr_csr_info { struct hpsb_host *host; nodeid_t nodeid; unsigned int generation; + unsigned int speed_unverified:1; }; @@ -57,24 +58,75 @@ static char *nodemgr_find_oui_name(int oui) return NULL; } +/* + * Correct the speed map entry. This is necessary + * - for nodes with link speed < phy speed, + * - for 1394b nodes with negotiated phy port speed < IEEE1394_SPEED_MAX. + * A possible speed is determined by trial and error, using quadlet reads. + */ +static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr, + quadlet_t *buffer) +{ + quadlet_t q; + u8 i, *speed, old_speed, good_speed; + int ret; + + speed = ci->host->speed + NODEID_TO_NODE(ci->nodeid); + old_speed = *speed; + good_speed = IEEE1394_SPEED_MAX + 1; + + /* Try every speed from S100 to old_speed. + * If we did it the other way around, a too low speed could be caught + * if the retry succeeded for some other reason, e.g. because the link + * just finished its initialization. */ + for (i = IEEE1394_SPEED_100; i <= old_speed; i++) { + *speed = i; + ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr, + &q, sizeof(quadlet_t)); + if (ret) + break; + *buffer = q; + good_speed = i; + } + if (good_speed <= IEEE1394_SPEED_MAX) { + HPSB_DEBUG("Speed probe of node " NODE_BUS_FMT " yields %s", + NODE_BUS_ARGS(ci->host, ci->nodeid), + hpsb_speedto_str[good_speed]); + *speed = good_speed; + ci->speed_unverified = 0; + return 0; + } + *speed = old_speed; + return ret; +} static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length, void *buffer, void *__ci) { struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci; - int i, ret = 0; + int i, ret; - for (i = 0; i < 3; i++) { + for (i = 1; ; i++) { ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr, buffer, length); - if (!ret) + if (!ret) { + ci->speed_unverified = 0; + break; + } + /* Give up after 3rd failure. */ + if (i == 3) break; - set_current_state(TASK_INTERRUPTIBLE); - if (schedule_timeout (HZ/3)) + /* The ieee1394_core guessed the node's speed capability from + * the self ID. Check whether a lower speed works. */ + if (ci->speed_unverified && length == sizeof(quadlet_t)) { + ret = nodemgr_check_speed(ci, addr, buffer); + if (!ret) + break; + } + if (msleep_interruptible(334)) return -EINTR; } - return ret; } @@ -122,8 +174,8 @@ struct host_info { }; static int nodemgr_bus_match(struct device * dev, struct device_driver * drv); -static int nodemgr_hotplug(struct class_device *cdev, char **envp, int num_envp, - char *buffer, int buffer_size); +static int nodemgr_uevent(struct class_device *cdev, 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); static struct node_entry *find_entry_by_guid(u64 guid); @@ -148,7 +200,7 @@ static void ne_cls_release(struct class_device *class_dev) put_device(&container_of((class_dev), struct node_entry, class_dev)->device); } -struct class nodemgr_ne_class = { +static struct class nodemgr_ne_class = { .name = "ieee1394_node", .release = ne_cls_release, }; @@ -160,10 +212,10 @@ static void ud_cls_release(struct class_device *class_dev) /* The name here is only so that unit directory hotplug works with old * style hotplug, which only ever did unit directories anyway. */ -struct class nodemgr_ud_class = { +static struct class nodemgr_ud_class = { .name = "ieee1394", .release = ud_cls_release, - .hotplug = nodemgr_hotplug, + .uevent = nodemgr_uevent, }; static struct hpsb_highlevel nodemgr_highlevel; @@ -221,7 +273,7 @@ struct device nodemgr_dev_template_host = { #define fw_attr(class, class_type, field, type, format_string) \ -static ssize_t fw_show_##class##_##field (struct device *dev, char *buf)\ +static ssize_t fw_show_##class##_##field (struct device *dev, struct device_attribute *attr, char *buf)\ { \ class_type *class; \ class = container_of(dev, class_type, device); \ @@ -233,7 +285,7 @@ static struct device_attribute dev_attr_##class##_##field = { \ }; #define fw_attr_td(class, class_type, td_kv) \ -static ssize_t fw_show_##class##_##td_kv (struct device *dev, char *buf)\ +static ssize_t fw_show_##class##_##td_kv (struct device *dev, struct device_attribute *attr, char *buf)\ { \ int len; \ class_type *class = container_of(dev, class_type, device); \ @@ -266,7 +318,7 @@ static struct driver_attribute driver_attr_drv_##field = { \ }; -static ssize_t fw_show_ne_bus_options(struct device *dev, char *buf) +static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribute *attr, char *buf) { struct node_entry *ne = container_of(dev, struct node_entry, device); @@ -282,15 +334,17 @@ static ssize_t fw_show_ne_bus_options(struct device *dev, char *buf) static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL); -static ssize_t fw_show_ne_tlabels_free(struct device *dev, char *buf) +/* tlabels_free, tlabels_allocations, tlabels_mask are read non-atomically + * here, therefore displayed values may be occasionally wrong. */ +static ssize_t fw_show_ne_tlabels_free(struct device *dev, struct device_attribute *attr, char *buf) { struct node_entry *ne = container_of(dev, struct node_entry, device); - return sprintf(buf, "%d\n", atomic_read(&ne->tpool->count.count) + 1); + return sprintf(buf, "%d\n", 64 - bitmap_weight(ne->tpool->pool, 64)); } static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL); -static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, char *buf) +static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, struct device_attribute *attr, char *buf) { struct node_entry *ne = container_of(dev, struct node_entry, device); return sprintf(buf, "%u\n", ne->tpool->allocations); @@ -298,7 +352,7 @@ static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, char *buf) static DEVICE_ATTR(tlabels_allocations,S_IRUGO,fw_show_ne_tlabels_allocations,NULL); -static ssize_t fw_show_ne_tlabels_mask(struct device *dev, char *buf) +static ssize_t fw_show_ne_tlabels_mask(struct device *dev, struct device_attribute *attr, char *buf) { struct node_entry *ne = container_of(dev, struct node_entry, device); #if (BITS_PER_LONG <= 32) @@ -310,7 +364,7 @@ static ssize_t fw_show_ne_tlabels_mask(struct device *dev, char *buf) static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL); -static ssize_t fw_set_ignore_driver(struct device *dev, const char *buf, size_t count) +static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct unit_directory *ud = container_of(dev, struct unit_directory, device); int state = simple_strtoul(buf, NULL, 10); @@ -325,7 +379,7 @@ static ssize_t fw_set_ignore_driver(struct device *dev, const char *buf, size_t return count; } -static ssize_t fw_get_ignore_driver(struct device *dev, char *buf) +static ssize_t fw_get_ignore_driver(struct device *dev, struct device_attribute *attr, char *buf) { struct unit_directory *ud = container_of(dev, struct unit_directory, device); @@ -696,14 +750,15 @@ static void nodemgr_remove_ne(struct node_entry *ne) put_device(dev); } +static int __nodemgr_remove_host_dev(struct device *dev, void *data) +{ + nodemgr_remove_ne(container_of(dev, struct node_entry, device)); + return 0; +} static void nodemgr_remove_host_dev(struct device *dev) { - struct device *ne_dev, *next; - - list_for_each_entry_safe(ne_dev, next, &dev->children, node) - nodemgr_remove_ne(container_of(ne_dev, struct node_entry, device)); - + device_for_each_child(dev, NULL, __nodemgr_remove_host_dev); sysfs_remove_link(&dev->kobj, "irm_id"); sysfs_remove_link(&dev->kobj, "busmgr_id"); sysfs_remove_link(&dev->kobj, "host_id"); @@ -743,21 +798,20 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr unsigned int generation) { struct hpsb_host *host = hi->host; - struct node_entry *ne; - - ne = kmalloc(sizeof(struct node_entry), GFP_KERNEL); - if (!ne) return NULL; + struct node_entry *ne; - memset(ne, 0, sizeof(struct node_entry)); + ne = kzalloc(sizeof(*ne), GFP_KERNEL); + if (!ne) + return NULL; ne->tpool = &host->tpool[nodeid & NODE_MASK]; - ne->host = host; - ne->nodeid = nodeid; + ne->host = host; + ne->nodeid = nodeid; ne->generation = generation; ne->needs_probe = 1; - ne->guid = guid; + ne->guid = guid; ne->guid_vendor_id = (guid >> 40) & 0xffffff; ne->guid_vendor_oui = nodemgr_find_oui_name(ne->guid_vendor_id); ne->csr = csr; @@ -787,7 +841,7 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr (host->node_id == nodeid) ? "Host" : "Node", NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid); - return ne; + return ne; } @@ -833,6 +887,31 @@ static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t } +static void nodemgr_register_device(struct node_entry *ne, + struct unit_directory *ud, struct device *parent) +{ + memcpy(&ud->device, &nodemgr_dev_template_ud, + sizeof(ud->device)); + + ud->device.parent = parent; + + 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", + ne->device.bus_id, ud->id); + + device_register(&ud->device); + class_device_register(&ud->class_dev); + get_device(&ud->device); + + if (ud->vendor_oui) + device_create_file(&ud->device, &dev_attr_ud_vendor_oui); + nodemgr_create_ud_dev_files(ud); +} + /* This implementation currently only scans the config rom and its * immediate unit directories looking for software_id and @@ -842,17 +921,15 @@ static struct unit_directory *nodemgr_process_unit_directory unsigned int *id, struct unit_directory *parent) { struct unit_directory *ud; - struct unit_directory *ud_temp = NULL; + struct unit_directory *ud_child = NULL; struct csr1212_dentry *dentry; struct csr1212_keyval *kv; u8 last_key_id = 0; - ud = kmalloc(sizeof(struct unit_directory), GFP_KERNEL); + ud = kzalloc(sizeof(*ud), GFP_KERNEL); if (!ud) goto unit_directory_error; - memset (ud, 0, sizeof(struct unit_directory)); - ud->ne = ne; ud->ignore_driver = ignore_drivers; ud->address = ud_kv->offset + CSR1212_CONFIG_ROM_SPACE_BASE; @@ -909,42 +986,61 @@ static struct unit_directory *nodemgr_process_unit_directory break; case CSR1212_KV_ID_DEPENDENT_INFO: - if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) { + /* Logical Unit Number */ + if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) { + if (ud->flags & UNIT_DIRECTORY_HAS_LUN) { + ud_child = kmalloc(sizeof(*ud_child), GFP_KERNEL); + if (!ud_child) + goto unit_directory_error; + memcpy(ud_child, ud, sizeof(*ud_child)); + nodemgr_register_device(ne, ud_child, &ne->device); + ud_child = NULL; + + ud->id = (*id)++; + } + ud->lun = kv->value.immediate; + ud->flags |= UNIT_DIRECTORY_HAS_LUN; + + /* Logical Unit Directory */ + } else if (kv->key.type == CSR1212_KV_TYPE_DIRECTORY) { /* This should really be done in SBP2 as this is - * doing SBP2 specific parsing. */ + * doing SBP2 specific parsing. + */ + + /* first register the parent unit */ ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY; - ud_temp = nodemgr_process_unit_directory(hi, ne, kv, id, - parent); + if (ud->device.bus != &ieee1394_bus_type) + nodemgr_register_device(ne, ud, &ne->device); + + /* process the child unit */ + ud_child = nodemgr_process_unit_directory(hi, ne, kv, id, ud); - if (ud_temp == NULL) + if (ud_child == NULL) break; - - /* inherit unspecified values */ - if ((ud->flags & UNIT_DIRECTORY_VENDOR_ID) && - !(ud_temp->flags & UNIT_DIRECTORY_VENDOR_ID)) - { - ud_temp->flags |= UNIT_DIRECTORY_VENDOR_ID; - ud_temp->vendor_id = ud->vendor_id; - ud_temp->vendor_oui = ud->vendor_oui; - } + + /* inherit unspecified values, the driver core picks it up */ if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) && - !(ud_temp->flags & UNIT_DIRECTORY_MODEL_ID)) + !(ud_child->flags & UNIT_DIRECTORY_MODEL_ID)) { - ud_temp->flags |= UNIT_DIRECTORY_MODEL_ID; - ud_temp->model_id = ud->model_id; + ud_child->flags |= UNIT_DIRECTORY_MODEL_ID; + ud_child->model_id = ud->model_id; } if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) && - !(ud_temp->flags & UNIT_DIRECTORY_SPECIFIER_ID)) + !(ud_child->flags & UNIT_DIRECTORY_SPECIFIER_ID)) { - ud_temp->flags |= UNIT_DIRECTORY_SPECIFIER_ID; - ud_temp->specifier_id = ud->specifier_id; + ud_child->flags |= UNIT_DIRECTORY_SPECIFIER_ID; + ud_child->specifier_id = ud->specifier_id; } if ((ud->flags & UNIT_DIRECTORY_VERSION) && - !(ud_temp->flags & UNIT_DIRECTORY_VERSION)) + !(ud_child->flags & UNIT_DIRECTORY_VERSION)) { - ud_temp->flags |= UNIT_DIRECTORY_VERSION; - ud_temp->version = ud->version; + ud_child->flags |= UNIT_DIRECTORY_VERSION; + ud_child->version = ud->version; } + + /* register the child unit */ + ud_child->flags |= UNIT_DIRECTORY_LUN_DIRECTORY; + nodemgr_register_device(ne, ud_child, &ud->device); } break; @@ -954,37 +1050,15 @@ static struct unit_directory *nodemgr_process_unit_directory } last_key_id = kv->key.id; } - - memcpy(&ud->device, &nodemgr_dev_template_ud, - sizeof(ud->device)); - - if (parent) { - ud->flags |= UNIT_DIRECTORY_LUN_DIRECTORY; - ud->device.parent = &parent->device; - } else - ud->device.parent = &ne->device; - - 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", - ne->device.bus_id, ud->id); - - device_register(&ud->device); - class_device_register(&ud->class_dev); - get_device(&ud->device); - - if (ud->vendor_oui) - device_create_file(&ud->device, &dev_attr_ud_vendor_oui); - nodemgr_create_ud_dev_files(ud); + + /* do not process child units here and only if not already registered */ + if (!parent && ud->device.bus != &ieee1394_bus_type) + nodemgr_register_device(ne, ud, &ne->device); return ud; unit_directory_error: - if (ud != NULL) - kfree(ud); + kfree(ud); return NULL; } @@ -1040,12 +1114,14 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent #ifdef CONFIG_HOTPLUG -static int nodemgr_hotplug(struct class_device *cdev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp, + char *buffer, int buffer_size) { struct unit_directory *ud; int i = 0; int length = 0; + /* ieee1394:venNmoNspNverN */ + char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1]; if (!cdev) return -ENODEV; @@ -1072,6 +1148,12 @@ do { \ PUT_ENVP("GUID=%016Lx", (unsigned long long)ud->ne->guid); PUT_ENVP("SPECIFIER_ID=%06x", ud->specifier_id); PUT_ENVP("VERSION=%06x", ud->version); + snprintf(buf, sizeof(buf), "ieee1394:ven%08Xmo%08Xsp%08Xver%08X", + ud->vendor_id, + ud->model_id, + ud->specifier_id, + ud->version); + PUT_ENVP("MODALIAS=%s", buf); #undef PUT_ENVP @@ -1082,8 +1164,8 @@ do { \ #else -static int nodemgr_hotplug(struct class_device *cdev, char **envp, int num_envp, - char *buffer, int buffer_size) +static int nodemgr_uevent(struct class_device *cdev, char **envp, int num_envp, + char *buffer, int buffer_size) { return -ENODEV; } @@ -1143,6 +1225,13 @@ static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr, /* Mark the node as new, so it gets re-probed */ ne->needs_probe = 1; + } else { + /* old cache is valid, so update its generation */ + struct nodemgr_csr_info *ci = ne->csr->private; + ci->generation = generation; + /* free the partially filled now unneeded new cache */ + kfree(csr->private); + csr1212_destroy_csr(csr); } if (ne->in_limbo) @@ -1163,13 +1252,15 @@ static void nodemgr_node_scan_one(struct host_info *hi, struct csr1212_csr *csr; struct nodemgr_csr_info *ci; - ci = kmalloc(sizeof(struct nodemgr_csr_info), GFP_KERNEL); + ci = kmalloc(sizeof(*ci), GFP_KERNEL); if (!ci) return; ci->host = host; ci->nodeid = nodeid; ci->generation = generation; + ci->speed_unverified = + host->speed[NODEID_TO_NODE(nodeid)] > IEEE1394_SPEED_100; /* We need to detect when the ConfigROM's generation has changed, * so we only update the node's info when it needs to be. */ @@ -1235,6 +1326,7 @@ static void nodemgr_node_scan(struct host_info *hi, int generation) } +/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader. */ static void nodemgr_suspend_ne(struct node_entry *ne) { struct class_device *cdev; @@ -1255,7 +1347,7 @@ static void nodemgr_suspend_ne(struct node_entry *ne) if (ud->device.driver && (!ud->device.driver->suspend || - ud->device.driver->suspend(&ud->device, 0, 0))) + ud->device.driver->suspend(&ud->device, PMSG_SUSPEND))) device_release_driver(&ud->device); } up_write(&ne->device.bus->subsys.rwsem); @@ -1278,7 +1370,7 @@ static void nodemgr_resume_ne(struct node_entry *ne) continue; if (ud->device.driver && ud->device.driver->resume) - ud->device.driver->resume(&ud->device, 0); + ud->device.driver->resume(&ud->device); } up_read(&ne->device.bus->subsys.rwsem); @@ -1287,15 +1379,14 @@ static void nodemgr_resume_ne(struct node_entry *ne) } +/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader. */ static void nodemgr_update_pdrv(struct node_entry *ne) { struct unit_directory *ud; struct hpsb_protocol_driver *pdrv; - struct class *class = &nodemgr_ud_class; struct class_device *cdev; - down_read(&class->subsys.rwsem); - list_for_each_entry(cdev, &class->children, node) { + list_for_each_entry(cdev, &nodemgr_ud_class.children, node) { ud = container_of(cdev, struct unit_directory, class_dev); if (ud->ne != ne || !ud->device.driver) continue; @@ -1308,10 +1399,38 @@ static void nodemgr_update_pdrv(struct node_entry *ne) up_write(&ud->device.bus->subsys.rwsem); } } - up_read(&class->subsys.rwsem); } +/* 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. + * + * Note that we cannot do a broadcast write to all nodes at once because some + * pre-1394a devices would hang. */ +static void nodemgr_irm_write_bc(struct node_entry *ne, int generation) +{ + const u64 bc_addr = (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL); + quadlet_t bc_remote, bc_local; + int ret; + + if (!ne->host->is_irm || ne->generation != generation || + ne->nodeid == ne->host->node_id) + return; + + bc_local = cpu_to_be32(ne->host->csr.broadcast_channel); + + /* Check if the register is implemented and 1394a compliant. */ + ret = hpsb_read(ne->host, ne->nodeid, generation, bc_addr, &bc_remote, + sizeof(bc_remote)); + if (!ret && bc_remote & cpu_to_be32(0x80000000) && + bc_remote != bc_local) + hpsb_node_write(ne, bc_addr, &bc_local, sizeof(bc_local)); +} + + +/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader because the + * calls to nodemgr_update_pdrv() and nodemgr_suspend_ne() here require it. */ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int generation) { struct device *dev; @@ -1323,6 +1442,8 @@ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int ge if (!dev) return; + nodemgr_irm_write_bc(ne, generation); + /* If "needs_probe", then this is either a new or changed node we * rescan totally. If the generation matches for an existing node * (one that existed prior to the bus reset) we send update calls @@ -1344,14 +1465,28 @@ static void nodemgr_node_probe(struct host_info *hi, int generation) struct hpsb_host *host = hi->host; struct class *class = &nodemgr_ne_class; struct class_device *cdev; + struct node_entry *ne; /* 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 - * unit-directories. */ + * unit-directories. + * + * Run updates before probes. Usually, updates are time-critical + * while probes are time-consuming. (Well, those probes need some + * improvement...) */ + down_read(&class->subsys.rwsem); - list_for_each_entry(cdev, &class->children, node) - nodemgr_probe_ne(hi, container_of(cdev, struct node_entry, class_dev), generation); + list_for_each_entry(cdev, &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, &class->children, node) { + ne = container_of(cdev, struct node_entry, class_dev); + if (ne->needs_probe) + nodemgr_probe_ne(hi, ne, generation); + } up_read(&class->subsys.rwsem); @@ -1376,9 +1511,26 @@ static void nodemgr_node_probe(struct host_info *hi, int generation) return; } -/* Because we are a 1394a-2000 compliant IRM, we need to inform all the other - * nodes of the broadcast channel. (Really we're only setting the validity - * bit). Other IRM responsibilities go in here as well. */ +static int nodemgr_send_resume_packet(struct hpsb_host *host) +{ + struct hpsb_packet *packet; + int ret = 1; + + packet = hpsb_make_phypacket(host, + EXTPHYPACKET_TYPE_RESUME | + NODEID_TO_NODE(host->node_id) << PHYPACKET_PORT_SHIFT); + if (packet) { + packet->no_waiter = 1; + packet->generation = get_hpsb_generation(host); + ret = hpsb_send_packet(packet); + } + if (ret) + HPSB_WARN("fw-host%d: Failed to broadcast resume packet", + host->id); + return ret; +} + +/* Perform a few high-level IRM responsibilities. */ static int nodemgr_do_irm_duties(struct hpsb_host *host, int cycles) { quadlet_t bc; @@ -1387,13 +1539,8 @@ static int nodemgr_do_irm_duties(struct hpsb_host *host, int cycles) if (!host->is_irm || host->irm_id == (nodeid_t)-1) return 1; - host->csr.broadcast_channel |= 0x40000000; /* set validity bit */ - - bc = cpu_to_be32(host->csr.broadcast_channel); - - hpsb_write(host, LOCAL_BUS | ALL_NODES, get_hpsb_generation(host), - (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL), - &bc, sizeof(quadlet_t)); + /* We are a 1394a-2000 compliant IRM. Set the validity bit. */ + host->csr.broadcast_channel |= 0x40000000; /* If there is no bus manager then we should set the root node's * force_root bit to promote bus stability per the 1394 @@ -1401,9 +1548,13 @@ static int nodemgr_do_irm_duties(struct hpsb_host *host, int cycles) if (host->busmgr_id == 0xffff && host->node_count > 1) { u16 root_node = host->node_count - 1; - struct node_entry *ne = find_entry_by_nodeid(host, root_node | LOCAL_BUS); - if (ne && ne->busopt.cmc) + /* get cycle master capability flag from root node */ + if (host->is_cycmst || + (!hpsb_read(host, LOCAL_BUS | root_node, get_hpsb_generation(host), + (CSR_REGISTER_BASE + CSR_CONFIG_ROM + 2 * sizeof(quadlet_t)), + &bc, sizeof(quadlet_t)) && + be32_to_cpu(bc) & 1 << CSR_CMC_SHIFT)) hpsb_send_phy_config(host, root_node, -1); else { HPSB_DEBUG("The root node is not cycle master capable; " @@ -1422,6 +1573,13 @@ static int nodemgr_do_irm_duties(struct hpsb_host *host, int cycles) } } + /* Some devices suspend their ports while being connected to an inactive + * host adapter, i.e. if connected before the low-level driver is + * loaded. They become visible either when physically unplugged and + * replugged, or when receiving a resume packet. Send one once. */ + if (!host->resume_packet_sent && !nodemgr_send_resume_packet(host)) + host->resume_packet_sent = 1; + return 1; } @@ -1433,7 +1591,7 @@ static int nodemgr_check_irm_capability(struct hpsb_host *host, int cycles) quadlet_t bc; int status; - if (host->is_irm) + if (hpsb_disable_irm || host->is_irm) return 1; status = hpsb_read(host, LOCAL_BUS | (host->irm_id), @@ -1481,22 +1639,22 @@ static int nodemgr_host_thread(void *__hi) if (down_interruptible(&hi->reset_sem) || down_interruptible(&nodemgr_serialize)) { - if (current->flags & PF_FREEZE) { - refrigerator(0); + if (try_to_freeze()) continue; - } printk("NodeMgr: received unexpected signal?!\n" ); break; } - if (hi->kill_me) + if (hi->kill_me) { + up(&nodemgr_serialize); break; + } /* Pause for 1/4 second in 1/16 second intervals, * to make sure things settle down. */ for (i = 0; i < 4 ; i++) { set_current_state(TASK_INTERRUPTIBLE); - if (schedule_timeout(HZ/16)) { + if (msleep_interruptible(63)) { up(&nodemgr_serialize); goto caught_signal; } @@ -1514,28 +1672,25 @@ static int nodemgr_host_thread(void *__hi) i = 0; /* Check the kill_me again */ - if (hi->kill_me) + if (hi->kill_me) { + up(&nodemgr_serialize); goto caught_signal; + } } - if (!nodemgr_check_irm_capability(host, reset_cycles)) { + if (!nodemgr_check_irm_capability(host, reset_cycles) || + !nodemgr_do_irm_duties(host, reset_cycles)) { reset_cycles++; up(&nodemgr_serialize); continue; } + reset_cycles = 0; /* Scan our nodes to get the bus options and create node * entries. This does not do the sysfs stuff, since that - * would trigger hotplug callbacks and such, which is a - * bad idea at this point. */ + * would trigger uevents and such, which is a bad idea at + * this point. */ nodemgr_node_scan(hi, generation); - if (!nodemgr_do_irm_duties(host, reset_cycles)) { - reset_cycles++; - up(&nodemgr_serialize); - continue; - } - - reset_cycles = 0; /* This actually does the full probe, with sysfs * registration. */ @@ -1553,29 +1708,6 @@ caught_signal: complete_and_exit(&hi->exited, 0); } -struct node_entry *hpsb_guid_get_entry(u64 guid) -{ - struct node_entry *ne; - - down(&nodemgr_serialize); - ne = find_entry_by_guid(guid); - up(&nodemgr_serialize); - - return ne; -} - -struct node_entry *hpsb_nodeid_get_entry(struct hpsb_host *host, nodeid_t nodeid) -{ - struct node_entry *ne; - - down(&nodemgr_serialize); - ne = find_entry_by_nodeid(host, nodeid); - up(&nodemgr_serialize); - - return ne; -} - - int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)) { struct class *class = &hpsb_host_class; @@ -1618,16 +1750,6 @@ void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt) pkt->node_id = ne->nodeid; } -int hpsb_node_read(struct node_entry *ne, u64 addr, - quadlet_t *buffer, size_t length) -{ - unsigned int generation = ne->generation; - - barrier(); - return hpsb_read(ne->host, ne->nodeid, generation, - addr, buffer, length); -} - int hpsb_node_write(struct node_entry *ne, u64 addr, quadlet_t *buffer, size_t length) { @@ -1638,16 +1760,6 @@ int hpsb_node_write(struct node_entry *ne, u64 addr, addr, buffer, length); } -int hpsb_node_lock(struct node_entry *ne, u64 addr, - int extcode, quadlet_t *data, quadlet_t arg) -{ - unsigned int generation = ne->generation; - - barrier(); - return hpsb_lock(ne->host, ne->nodeid, generation, - addr, extcode, data, arg); -} - static void nodemgr_add_host(struct hpsb_host *host) { struct host_info *hi;