Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / ieee1394 / nodemgr.c
index 83e66ed..082c7fd 100644 (file)
@@ -30,7 +30,7 @@
 #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.");
 
@@ -64,10 +64,10 @@ static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
        struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
        int i, ret = 0;
 
-       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 || i == 3)
                        break;
 
                if (msleep_interruptible(334))
@@ -121,8 +121,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);
@@ -162,7 +162,7 @@ static void ud_cls_release(struct class_device *class_dev)
 static struct class nodemgr_ud_class = {
        .name           = "ieee1394",
        .release        = ud_cls_release,
-       .hotplug        = nodemgr_hotplug,
+       .uevent         = nodemgr_uevent,
 };
 
 static struct hpsb_highlevel nodemgr_highlevel;
@@ -220,7 +220,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);                  \
@@ -232,7 +232,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);      \
@@ -265,7 +265,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);
 
@@ -281,7 +281,7 @@ 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)
+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);
@@ -289,7 +289,7 @@ static ssize_t fw_show_ne_tlabels_free(struct device *dev, char *buf)
 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);
@@ -297,7 +297,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)
@@ -309,7 +309,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);
@@ -324,7 +324,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);
 
@@ -695,14 +695,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");
@@ -742,21 +743,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;
@@ -786,7 +786,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;
 }
 
 
@@ -871,12 +871,10 @@ static struct unit_directory *nodemgr_process_unit_directory
        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;
@@ -936,10 +934,10 @@ static struct unit_directory *nodemgr_process_unit_directory
                        /* Logical Unit Number */
                        if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
                                if (ud->flags & UNIT_DIRECTORY_HAS_LUN) {
-                                       ud_child = kmalloc(sizeof(struct unit_directory), GFP_KERNEL);
+                                       ud_child = kmalloc(sizeof(*ud_child), GFP_KERNEL);
                                        if (!ud_child)
                                                goto unit_directory_error;
-                                       memcpy(ud_child, ud, sizeof(struct unit_directory));
+                                       memcpy(ud_child, ud, sizeof(*ud_child));
                                        nodemgr_register_device(ne, ud_child, &ne->device);
                                        ud_child = NULL;
                                        
@@ -965,7 +963,7 @@ static struct unit_directory *nodemgr_process_unit_directory
                                if (ud_child == NULL)
                                        break;
                                
-                               /* inherit unspecified values so hotplug picks it up */
+                               /* inherit unspecified values, the driver core picks it up */
                                if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) &&
                                    !(ud_child->flags & UNIT_DIRECTORY_MODEL_ID))
                                {
@@ -1061,12 +1059,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;
@@ -1093,6 +1093,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
 
@@ -1103,8 +1109,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;
 }
@@ -1191,7 +1197,7 @@ 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;
 
@@ -1283,7 +1289,7 @@ static void nodemgr_suspend_ne(struct node_entry *ne)
 
                if (ud->device.driver &&
                    (!ud->device.driver->suspend ||
-                     ud->device.driver->suspend(&ud->device, PMSG_SUSPEND, 0)))
+                     ud->device.driver->suspend(&ud->device, PMSG_SUSPEND)))
                        device_release_driver(&ud->device);
        }
        up_write(&ne->device.bus->subsys.rwsem);
@@ -1306,7 +1312,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);
 
@@ -1340,6 +1346,33 @@ static void nodemgr_update_pdrv(struct node_entry *ne)
 }
 
 
+/* 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));
+}
+
+
 static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int generation)
 {
        struct device *dev;
@@ -1351,6 +1384,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
@@ -1372,14 +1407,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);
 
 
@@ -1404,9 +1453,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;
@@ -1415,13 +1481,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
@@ -1429,9 +1490,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; "
@@ -1450,6 +1515,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;
 }
 
@@ -1509,7 +1581,7 @@ static int nodemgr_host_thread(void *__hi)
 
                if (down_interruptible(&hi->reset_sem) ||
                    down_interruptible(&nodemgr_serialize)) {
-                       if (try_to_freeze(PF_FREEZE))
+                       if (try_to_freeze())
                                continue;
                        printk("NodeMgr: received unexpected signal?!\n" );
                        break;
@@ -1548,24 +1620,19 @@ static int nodemgr_host_thread(void *__hi)
                        }
                }
 
-               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. */