Enhance speed detection

Sean Bruno <[email protected]>
Newsgroups gmane.os.freebsd.devel.firewire
Message-ID <[email protected]>
Synopsis:
If speed of link between two devices is slower than the reported max
speed of both endpoints, the current driver will fail and be unable to
negotiate.

Summary:
Test negotiated speed by reading the CSRROM into a dummy variable.
If that read fails, decrement our speed and retry.  If all else fails,
go to lowest speed possible.

Report speed to the user.
Add display of the Bus Info Block when debug.firewire_debug > 1
Support the Bus Info Block(1394a-2000) method of speed detection.

_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-firewire
To unsubscribe, send any mail to "[email protected]"
firewire.c.diff (text/x-patch, 3.2 KB)
Index: firewire.c
===================================================================
--- firewire.c	(revision 188697)
+++ firewire.c	(working copy)
@@ -77,7 +77,7 @@
 	struct crom_chunk hw;
 };
 
-int firewire_debug=0, try_bmr=1, hold_count=3;
+int firewire_debug=0, try_bmr=1, hold_count=0;
 SYSCTL_INT(_debug, OID_AUTO, firewire_debug, CTLFLAG_RW, &firewire_debug, 0,
 	"FireWire driver debug flag");
 SYSCTL_NODE(_hw, OID_AUTO, firewire, CTLFLAG_RD, 0, "FireWire Subsystem");
@@ -1503,7 +1503,8 @@
 	uint32_t *csr;
 	struct csrhdr *hdr;
 	struct bus_info *binfo;
-	int err, node, spd;
+	int err, node;
+	uint32_t speed_test = 0;
 
 	fc = dfwdev->fc;
 	csr = dfwdev->csrrom;
@@ -1511,8 +1512,12 @@
 
 	/* First quad */
 	err = fw_explore_read_quads(dfwdev, CSRROMOFF, &csr[0], 1);
-	if (err)
+	if (err) {
+		device_printf(fc->bdev, "%s: node%d: explore_read_quads failure\n",
+		    __func__, node);
+		dfwdev->status = FWDEVINVAL;
 		return (-1);
+	}
 	hdr = (struct csrhdr *)&csr[0];
 	if (hdr->info_len != 4) {
 		if (firewire_debug)
@@ -1532,7 +1537,18 @@
 			    node, binfo->bus_name);
 		return (-1);
 	}
-	spd = fc->speed_map->speed[fc->nodeid][node];
+
+	if (firewire_debug)
+		device_printf(fc->bdev, "%s: node(%d) BUS INFO BLOCK:\n"
+					"irmc(%d) cmc(%d) isc(%d) bmc(%d) pmc(%d) "
+					"cyc_clk_acc(%d) max_rec(%d) max_rom(%d) "
+					"generation(%d) link_spd(%d)\n",
+					__func__, node,
+					binfo->irmc, binfo->cmc, binfo->isc,
+					binfo->bmc, binfo->pmc, binfo->cyc_clk_acc,
+					binfo->max_rec, binfo->max_rom,
+					binfo->generation, binfo->link_spd);
+
 	STAILQ_FOREACH(fwdev, &fc->devices, link)
 		if (FW_EUI64_EQUAL(fwdev->eui, binfo->eui64))
 			break;
@@ -1547,6 +1563,40 @@
 		}
 		fwdev->fc = fc;
 		fwdev->eui = binfo->eui64;
+		/*
+		 * Pre-1394a-2000 didn't have link_spd in
+		 * the Bus Info block, so try and use the 
+		 * speed map value.
+		 * 1394a-2000 compliant devices only use
+		 * the Bus Info Block link spd value, so
+		 * ignore the speed map alltogether. SWB
+		 */
+		if ( binfo->link_spd == FWSPD_S100 /* 0 */) {
+			device_printf(fc->bdev, "%s"
+				"Pre 1394a-2000 detected\n",
+				__func__);
+			fwdev->speed = fc->speed_map->speed[fc->nodeid][node];
+		} else
+			fwdev->speed = binfo->link_spd;
+		/*
+		 * Test this speed with a read to the CSRROM.
+		 * If it fails, slow down the speed and retry.
+		 */
+		while (fwdev->speed > 0) {
+			err = fw_explore_read_quads(fwdev, CSRROMOFF,
+            				&speed_test, 1);
+			if (err)
+				fwdev->speed--;
+			else
+				break;
+				
+		}
+		if (fwdev->speed != binfo->link_spd)
+			device_printf(fc->bdev, "%s: fwdev->speed(%s)"
+						" set lower than binfo->link_spd(%s)\n",
+						__func__,
+						linkspeed[fwdev->speed],
+						linkspeed[binfo->link_spd]);
 		/* inesrt into sorted fwdev list */
 		pfwdev = NULL;
 		STAILQ_FOREACH(tfwdev, &fc->devices, link) {
@@ -1562,12 +1612,11 @@
 			STAILQ_INSERT_AFTER(&fc->devices, pfwdev, fwdev, link);
 
 		device_printf(fc->bdev, "New %s device ID:%08x%08x\n",
-		    linkspeed[spd],
+		    linkspeed[fwdev->speed],
 		    fwdev->eui.hi, fwdev->eui.lo);
 	}
 	fwdev->dst = node;
 	fwdev->status = FWDEVINIT;
-	fwdev->speed = spd;
 
 	/* unchanged ? */
 	if (bcmp(&csr[0], &fwdev->csrrom[0], sizeof(uint32_t) * 5) == 0) {
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.