]> err.no Git - linux-2.6/commitdiff
ieee1394: write broadcast_channel only to select nodes (fixes device recognition)
authorStefan Richter <stefanr@s5r6.in-berlin.de>
Mon, 5 Dec 2005 21:28:59 +0000 (16:28 -0500)
committerJody McIntyre <scjody@modernduck.com>
Mon, 5 Dec 2005 21:28:59 +0000 (16:28 -0500)
Some old 1394-1995 SBP-2 bridges would hang if they received a broadcast write
request to BROADCAST_CHANNEL before the config ROM was read.  Affected devices
include Datafab MD2-FW2 2.5" HDD and SmartDisk VST FWCDRW-V8 portable CD writer.
The write request is now directed to specific nodes instead of being broadcast
to all nodes at once, and it is only performed if a previous read request at
this register succeeded.

Fixes an old interoperability problem which was perceived as a 2.6.14-specific
regression: http://marc.theaimsgroup.com/?t=113190586800003

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Signed-off-by: Jody McIntyre <scjody@modernduck.com>
drivers/ieee1394/nodemgr.c

index f4b6025fde61e6aa493a29a84369f702255d28aa..01ab2bfa8d9d3c2c21d8757d766bc9e3fe5f4239 100644 (file)
@@ -1346,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;
@@ -1357,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
@@ -1429,9 +1458,7 @@ static int nodemgr_send_resume_packet(struct hpsb_host *host)
        return ret;
 }
 
-/* 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. */
+/* Perform a few high-level IRM responsibilities. */
 static int nodemgr_do_irm_duties(struct hpsb_host *host, int cycles)
 {
        quadlet_t bc;
@@ -1440,13 +1467,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