diff options
author | Ben Collins <bcollins@ubuntu.com> | 2006-06-12 18:12:37 -0400 |
---|---|---|
committer | Ben Collins <bcollins@ubuntu.com> | 2006-06-12 18:12:37 -0400 |
commit | 647dcb5fae0ebb5da1272ed2773df0d3f152c303 (patch) | |
tree | 31d6a6ab3fd8acb2dc9335dfa181972f4433158a | |
parent | 57fdb58fa5a140bdd52cf4c4ffc30df73676f0a5 (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>
-rw-r--r-- | drivers/ieee1394/eth1394.c | 6 | ||||
-rw-r--r-- | drivers/ieee1394/hosts.h | 11 | ||||
-rw-r--r-- | drivers/ieee1394/ieee1394_core.c | 14 | ||||
-rw-r--r-- | drivers/ieee1394/nodemgr.c | 61 | ||||
-rw-r--r-- | drivers/ieee1394/sbp2.c | 4 |
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 | ||
286 | static void build_speed_map(struct hpsb_host *host, int nodecount) | 286 | static 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 | */ | ||
67 | static 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 | ||
61 | static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length, | 103 | static 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) { |