summaryrefslogtreecommitdiffstats
path: root/drivers/ieee1394/nodemgr.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-06-20 20:01:16 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-20 20:01:16 -0700
commit34641a58a227e498adf471ab016bd054cc399d7e (patch)
treeda1e0af965d06d0c6e13c546ac01f6a54a904d86 /drivers/ieee1394/nodemgr.c
parent2eec0e0842ef747027eb9181d5f50d7157184d57 (diff)
parent7136b8073f0123918e3e50269ae021bbb09e1a81 (diff)
downloadop-kernel-dev-34641a58a227e498adf471ab016bd054cc399d7e.zip
op-kernel-dev-34641a58a227e498adf471ab016bd054cc399d7e.tar.gz
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bcollins/linux1394-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/bcollins/linux1394-2.6: (28 commits) eth1394: replace __constant_htons by htons ieee1394: adjust code formatting in highlevel.c ieee1394: hl_irqs_lock is taken in hardware interrupt context ieee1394_core: switch to kthread API ieee1394: sbp2: Kconfig fix ieee1394: add preprocessor constant for invalid csr address sbp2: fix deregistration of status fifo address space [PATCH] eth1394: endian fixes Fix broken suspend/resume in ohci1394 sbp2: use __attribute__((packed)) for on-the-wire structures sbp2: provide helptext for CONFIG_IEEE1394_SBP2_PHYS_DMA and mark it experimental Update feature removal of obsolete raw1394 ISO requests. sbp2: fix S800 transfers if phys_dma is off sbp2: remove ohci1394 specific constant ohci1394: make phys_dma parameter read-only ohci1394: set address range properties ieee1394: extend lowlevel API for address range properties sbp2: log number of supported concurrent logins sbp2: remove manipulation of inquiry response ieee1394: save RAM by using a single tlabel for broadcast transactions ...
Diffstat (limited to 'drivers/ieee1394/nodemgr.c')
-rw-r--r--drivers/ieee1394/nodemgr.c61
1 files changed, 58 insertions, 3 deletions
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 082c7fd..948f1b8 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -38,6 +38,7 @@ struct nodemgr_csr_info {
struct hpsb_host *host;
nodeid_t nodeid;
unsigned int generation;
+ unsigned int speed_unverified:1;
};
@@ -57,23 +58,75 @@ static char *nodemgr_find_oui_name(int oui)
return NULL;
}
+/*
+ * Correct the speed map entry. This is necessary
+ * - for nodes with link speed < phy speed,
+ * - for 1394b nodes with negotiated phy port speed < IEEE1394_SPEED_MAX.
+ * A possible speed is determined by trial and error, using quadlet reads.
+ */
+static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
+ quadlet_t *buffer)
+{
+ quadlet_t q;
+ u8 i, *speed, old_speed, good_speed;
+ int ret;
+
+ speed = ci->host->speed + NODEID_TO_NODE(ci->nodeid);
+ old_speed = *speed;
+ good_speed = IEEE1394_SPEED_MAX + 1;
+
+ /* Try every speed from S100 to old_speed.
+ * If we did it the other way around, a too low speed could be caught
+ * if the retry succeeded for some other reason, e.g. because the link
+ * just finished its initialization. */
+ for (i = IEEE1394_SPEED_100; i <= old_speed; i++) {
+ *speed = i;
+ ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
+ &q, sizeof(quadlet_t));
+ if (ret)
+ break;
+ *buffer = q;
+ good_speed = i;
+ }
+ if (good_speed <= IEEE1394_SPEED_MAX) {
+ HPSB_DEBUG("Speed probe of node " NODE_BUS_FMT " yields %s",
+ NODE_BUS_ARGS(ci->host, ci->nodeid),
+ hpsb_speedto_str[good_speed]);
+ *speed = good_speed;
+ ci->speed_unverified = 0;
+ return 0;
+ }
+ *speed = old_speed;
+ return ret;
+}
static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
void *buffer, void *__ci)
{
struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
- int i, ret = 0;
+ int i, ret;
for (i = 1; ; i++) {
ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
buffer, length);
- if (!ret || i == 3)
+ if (!ret) {
+ ci->speed_unverified = 0;
+ break;
+ }
+ /* Give up after 3rd failure. */
+ if (i == 3)
break;
+ /* The ieee1394_core guessed the node's speed capability from
+ * the self ID. Check whether a lower speed works. */
+ if (ci->speed_unverified && length == sizeof(quadlet_t)) {
+ ret = nodemgr_check_speed(ci, addr, buffer);
+ if (!ret)
+ break;
+ }
if (msleep_interruptible(334))
return -EINTR;
}
-
return ret;
}
@@ -1204,6 +1257,8 @@ static void nodemgr_node_scan_one(struct host_info *hi,
ci->host = host;
ci->nodeid = nodeid;
ci->generation = generation;
+ ci->speed_unverified =
+ host->speed[NODEID_TO_NODE(nodeid)] > IEEE1394_SPEED_100;
/* We need to detect when the ConfigROM's generation has changed,
* so we only update the node's info when it needs to be. */
OpenPOWER on IntegriCloud