aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Collins <bcollins@ubuntu.com>2006-06-12 18:12:37 -0400
committerBen Collins <bcollins@ubuntu.com>2006-06-12 18:12:37 -0400
commit647dcb5fae0ebb5da1272ed2773df0d3f152c303 (patch)
tree31d6a6ab3fd8acb2dc9335dfa181972f4433158a /drivers
parent57fdb58fa5a140bdd52cf4c4ffc30df73676f0a5 (diff)
ieee1394: support for slow links or slow 1394b phy ports
Add support for the following types of hardware: + nodes that have a link speed < PHY speed + 1394b PHYs that are less than S800 capable + 1394b/1394a adapter cable between two 1394b PHYs Also, S1600 and S3200 are now supported if IEEE1394_SPEED_MAX is raised. A probing function is added to nodemgr's config ROM fetching routine which adjusts the allowable speed if an access problem was encountered. Pros and Cons of the approach: + minimum code footprint to support this less widely used hardware + nearly no overhead for unaffected hardware - ineffective before nodemgr began to read the ROM of affected nodes - ineffective if ieee1394 is loaded with disable_nodemgr=1 The speed map CSRs which are published to the bus are not touched by the patch. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Cc: Hakan Ardo <hakan@debian.org> Cc: Calculex <linux@calculex.com> Cc: Robert J. Kosinski <robk@cmcherald.com> Signed-off-by: Ben Collins <bcollins@ubuntu.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ieee1394/eth1394.c6
-rw-r--r--drivers/ieee1394/hosts.h11
-rw-r--r--drivers/ieee1394/ieee1394_core.c14
-rw-r--r--drivers/ieee1394/nodemgr.c61
-rw-r--r--drivers/ieee1394/sbp2.c4
5 files changed, 76 insertions, 20 deletions
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 30fa0d43a43a..b2d2c4dd075b 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -502,10 +502,8 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu)
502 502
503 /* Determine speed limit */ 503 /* Determine speed limit */
504 for (i = 0; i < host->node_count; i++) 504 for (i = 0; i < host->node_count; i++)
505 if (max_speed > host->speed_map[NODEID_TO_NODE(host->node_id) * 505 if (max_speed > host->speed[i])
506 64 + i]) 506 max_speed = host->speed[i];
507 max_speed = host->speed_map[NODEID_TO_NODE(host->node_id) *
508 64 + i];
509 priv->bc_sspd = max_speed; 507 priv->bc_sspd = max_speed;
510 508
511 /* We'll use our maxpayload as the default mtu */ 509 /* We'll use our maxpayload as the default mtu */
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
index 07d188ca8495..d1a47607cb89 100644
--- a/drivers/ieee1394/hosts.h
+++ b/drivers/ieee1394/hosts.h
@@ -30,12 +30,13 @@ struct hpsb_host {
30 30
31 unsigned char iso_listen_count[64]; 31 unsigned char iso_listen_count[64];
32 32
33 int node_count; /* number of identified nodes on this bus */ 33 int node_count; /* number of identified nodes on this bus */
34 int selfid_count; /* total number of SelfIDs received */ 34 int selfid_count; /* total number of SelfIDs received */
35 int nodes_active; /* number of nodes that are actually active */ 35 int nodes_active; /* number of nodes with active link layer */
36 u8 speed[63]; /* speed between each node and local node */
36 37
37 nodeid_t node_id; /* node ID of this host */ 38 nodeid_t node_id; /* node ID of this host */
38 nodeid_t irm_id; /* ID of this bus' isochronous resource manager */ 39 nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
39 nodeid_t busmgr_id; /* ID of this bus' bus manager */ 40 nodeid_t busmgr_id; /* ID of this bus' bus manager */
40 41
41 /* this nodes state */ 42 /* this nodes state */
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index be6854e25ad4..c83e2b8295e3 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -285,9 +285,9 @@ static int check_selfids(struct hpsb_host *host)
285 285
286static void build_speed_map(struct hpsb_host *host, int nodecount) 286static void build_speed_map(struct hpsb_host *host, int nodecount)
287{ 287{
288 u8 speedcap[nodecount];
289 u8 cldcnt[nodecount]; 288 u8 cldcnt[nodecount];
290 u8 *map = host->speed_map; 289 u8 *map = host->speed_map;
290 u8 *speedcap = host->speed;
291 struct selfid *sid; 291 struct selfid *sid;
292 struct ext_selfid *esid; 292 struct ext_selfid *esid;
293 int i, j, n; 293 int i, j, n;
@@ -354,6 +354,11 @@ static void build_speed_map(struct hpsb_host *host, int nodecount)
354 } 354 }
355 } 355 }
356 } 356 }
357
358 /* assume maximum speed for 1394b PHYs, nodemgr will correct it */
359 for (n = 0; n < nodecount; n++)
360 if (speedcap[n] == 3)
361 speedcap[n] = IEEE1394_SPEED_MAX;
357} 362}
358 363
359 364
@@ -554,11 +559,10 @@ int hpsb_send_packet(struct hpsb_packet *packet)
554 return 0; 559 return 0;
555 } 560 }
556 561
557 if (packet->type == hpsb_async && packet->node_id != ALL_NODES) { 562 if (packet->type == hpsb_async &&
563 NODEID_TO_NODE(packet->node_id) != ALL_NODES)
558 packet->speed_code = 564 packet->speed_code =
559 host->speed_map[NODEID_TO_NODE(host->node_id) * 64 565 host->speed[NODEID_TO_NODE(packet->node_id)];
560 + NODEID_TO_NODE(packet->node_id)];
561 }
562 566
563 dump_packet("send packet", packet->header, packet->header_size, packet->speed_code); 567 dump_packet("send packet", packet->header, packet->header_size, packet->speed_code);
564 568
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 082c7fd239f5..948f1b8c4238 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -38,6 +38,7 @@ struct nodemgr_csr_info {
38 struct hpsb_host *host; 38 struct hpsb_host *host;
39 nodeid_t nodeid; 39 nodeid_t nodeid;
40 unsigned int generation; 40 unsigned int generation;
41 unsigned int speed_unverified:1;
41}; 42};
42 43
43 44
@@ -57,23 +58,75 @@ static char *nodemgr_find_oui_name(int oui)
57 return NULL; 58 return NULL;
58} 59}
59 60
61/*
62 * Correct the speed map entry. This is necessary
63 * - for nodes with link speed < phy speed,
64 * - for 1394b nodes with negotiated phy port speed < IEEE1394_SPEED_MAX.
65 * A possible speed is determined by trial and error, using quadlet reads.
66 */
67static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
68 quadlet_t *buffer)
69{
70 quadlet_t q;
71 u8 i, *speed, old_speed, good_speed;
72 int ret;
73
74 speed = ci->host->speed + NODEID_TO_NODE(ci->nodeid);
75 old_speed = *speed;
76 good_speed = IEEE1394_SPEED_MAX + 1;
77
78 /* Try every speed from S100 to old_speed.
79 * If we did it the other way around, a too low speed could be caught
80 * if the retry succeeded for some other reason, e.g. because the link
81 * just finished its initialization. */
82 for (i = IEEE1394_SPEED_100; i <= old_speed; i++) {
83 *speed = i;
84 ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
85 &q, sizeof(quadlet_t));
86 if (ret)
87 break;
88 *buffer = q;
89 good_speed = i;
90 }
91 if (good_speed <= IEEE1394_SPEED_MAX) {
92 HPSB_DEBUG("Speed probe of node " NODE_BUS_FMT " yields %s",
93 NODE_BUS_ARGS(ci->host, ci->nodeid),
94 hpsb_speedto_str[good_speed]);
95 *speed = good_speed;
96 ci->speed_unverified = 0;
97 return 0;
98 }
99 *speed = old_speed;
100 return ret;
101}
60 102
61static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length, 103static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
62 void *buffer, void *__ci) 104 void *buffer, void *__ci)
63{ 105{
64 struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci; 106 struct nodemgr_csr_info *ci = (struct nodemgr_csr_info*)__ci;
65 int i, ret = 0; 107 int i, ret;
66 108
67 for (i = 1; ; i++) { 109 for (i = 1; ; i++) {
68 ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr, 110 ret = hpsb_read(ci->host, ci->nodeid, ci->generation, addr,
69 buffer, length); 111 buffer, length);
70 if (!ret || i == 3) 112 if (!ret) {
113 ci->speed_unverified = 0;
114 break;
115 }
116 /* Give up after 3rd failure. */
117 if (i == 3)
71 break; 118 break;
72 119
120 /* The ieee1394_core guessed the node's speed capability from
121 * the self ID. Check whether a lower speed works. */
122 if (ci->speed_unverified && length == sizeof(quadlet_t)) {
123 ret = nodemgr_check_speed(ci, addr, buffer);
124 if (!ret)
125 break;
126 }
73 if (msleep_interruptible(334)) 127 if (msleep_interruptible(334))
74 return -EINTR; 128 return -EINTR;
75 } 129 }
76
77 return ret; 130 return ret;
78} 131}
79 132
@@ -1204,6 +1257,8 @@ static void nodemgr_node_scan_one(struct host_info *hi,
1204 ci->host = host; 1257 ci->host = host;
1205 ci->nodeid = nodeid; 1258 ci->nodeid = nodeid;
1206 ci->generation = generation; 1259 ci->generation = generation;
1260 ci->speed_unverified =
1261 host->speed[NODEID_TO_NODE(nodeid)] > IEEE1394_SPEED_100;
1207 1262
1208 /* We need to detect when the ConfigROM's generation has changed, 1263 /* We need to detect when the ConfigROM's generation has changed,
1209 * so we only update the node's info when it needs to be. */ 1264 * so we only update the node's info when it needs to be. */
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 24cd1e250d84..c30e03a0e63b 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -1664,10 +1664,8 @@ static int sbp2_max_speed_and_size(struct scsi_id_instance_data *scsi_id)
1664 1664
1665 SBP2_DEBUG_ENTER(); 1665 SBP2_DEBUG_ENTER();
1666 1666
1667 /* Initial setting comes from the hosts speed map */
1668 scsi_id->speed_code = 1667 scsi_id->speed_code =
1669 hi->host->speed_map[NODEID_TO_NODE(hi->host->node_id) * 64 + 1668 hi->host->speed[NODEID_TO_NODE(scsi_id->ne->nodeid)];
1670 NODEID_TO_NODE(scsi_id->ne->nodeid)];
1671 1669
1672 /* Bump down our speed if the user requested it */ 1670 /* Bump down our speed if the user requested it */
1673 if (scsi_id->speed_code > max_speed) { 1671 if (scsi_id->speed_code > max_speed) {