diff options
Diffstat (limited to 'drivers/ieee1394/nodemgr.c')
-rw-r--r-- | drivers/ieee1394/nodemgr.c | 61 |
1 files changed, 58 insertions, 3 deletions
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. */ |