aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/firewire
diff options
context:
space:
mode:
authorSean Bruno <sbruno@FreeBSD.org>2009-02-17 04:08:08 +0000
committerSean Bruno <sbruno@FreeBSD.org>2009-02-17 04:08:08 +0000
commitebe234793b542fcb0ab0f82dc944fed2ce0ed891 (patch)
tree2c628be32a966918bc76909e418e25c5aac47f83 /sys/dev/firewire
parent993b1ae273ed98b91bb463e7a00f9a67aae6e16f (diff)
downloadsrc-ebe234793b542fcb0ab0f82dc944fed2ce0ed891.tar.gz
src-ebe234793b542fcb0ab0f82dc944fed2ce0ed891.zip
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
Notes
Notes: svn path=/head/; revision=188704
Diffstat (limited to 'sys/dev/firewire')
-rw-r--r--sys/dev/firewire/firewire.c61
1 files changed, 55 insertions, 6 deletions
diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c
index 8137df686c8c..7734b3001501 100644
--- a/sys/dev/firewire/firewire.c
+++ b/sys/dev/firewire/firewire.c
@@ -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) {