svn commit: r188704 - head/sys/dev/firewire

Sean Bruno sbruno at FreeBSD.org
Mon Feb 16 20:08:09 PST 2009


Author: sbruno
Date: Tue Feb 17 04:08:08 2009
New Revision: 188704
URL: http://svn.freebsd.org/changeset/base/188704

Log:
  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(0).
  
  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.
  
  I also should note that I am moving "hold_count" to 0 for future
  releases.
  
  This variable determines how many bus resets to "hold" a removed
  firewire device before deletion.  I don't feel this is useful and will
  probably drop support for this sysctl in the future.
  
  Reviewed by:    scottl(mentor)
  MFC after:      2 weeks

Modified:
  head/sys/dev/firewire/firewire.c

Modified: head/sys/dev/firewire/firewire.c
==============================================================================
--- head/sys/dev/firewire/firewire.c	Tue Feb 17 03:58:15 2009	(r188703)
+++ head/sys/dev/firewire/firewire.c	Tue Feb 17 04:08:08 2009	(r188704)
@@ -77,7 +77,7 @@ struct crom_src_buf {
 	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 @@ fw_explore_node(struct fw_device *dfwdev
 	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 @@ fw_explore_node(struct fw_device *dfwdev
 
 	/* 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 @@ fw_explore_node(struct fw_device *dfwdev
 			    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 @@ fw_explore_node(struct fw_device *dfwdev
 		}
 		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 @@ fw_explore_node(struct fw_device *dfwdev
 			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) {


More information about the svn-src-head mailing list