aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax/i2400m/usb.c
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2009-10-19 22:10:59 -0400
committerInaky Perez-Gonzalez <inaky@linux.intel.com>2009-11-03 15:49:40 -0500
commitfaf57162e462eafe87458e21bf641f9d138f8171 (patch)
treec59c3a457768924a37b2feb80125b35cd15ac056 /drivers/net/wimax/i2400m/usb.c
parentfae92216da87d1c78aa51c4503acb312a47266e9 (diff)
wimax/i2400m: handle USB stalls
When the device stalls, clear it and retry; if it keeps failing too often, reset the device. This specially happens when running on virtual machines; the real hardware doesn't seem to trip on stalls too much, except for a few reports in the mailing list (still to be confirmed this is the cause, although it seems likely. NOTE: it is not clear if the URB has to be resubmitted fully or start only at the offset of the first transaction sent. Can't find documentation to clarify one end or the other. Tests that just resubmit the whole URB seemed to work in my environment. Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
Diffstat (limited to 'drivers/net/wimax/i2400m/usb.c')
-rw-r--r--drivers/net/wimax/i2400m/usb.c57
1 files changed, 51 insertions, 6 deletions
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 34df0906caae..47e84ef355c5 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -172,14 +172,59 @@ int __i2400mu_send_barker(struct i2400mu *i2400mu,
172 epd = usb_get_epd(i2400mu->usb_iface, endpoint); 172 epd = usb_get_epd(i2400mu->usb_iface, endpoint);
173 pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress); 173 pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
174 memcpy(buffer, barker, barker_size); 174 memcpy(buffer, barker, barker_size);
175retry:
175 ret = usb_bulk_msg(i2400mu->usb_dev, pipe, buffer, barker_size, 176 ret = usb_bulk_msg(i2400mu->usb_dev, pipe, buffer, barker_size,
176 &actual_len, 200); 177 &actual_len, 200);
177 if (ret < 0) { 178 switch (ret) {
178 if (ret != -EINVAL) 179 case 0:
179 dev_err(dev, "E: barker error: %d\n", ret); 180 if (actual_len != barker_size) { /* Too short? drop it */
180 } else if (actual_len != barker_size) { 181 dev_err(dev, "E: %s: short write (%d B vs %zu "
181 dev_err(dev, "E: only %d bytes transmitted\n", actual_len); 182 "expected)\n",
182 ret = -EIO; 183 __func__, actual_len, barker_size);
184 ret = -EIO;
185 }
186 break;
187 case -EPIPE:
188 /*
189 * Stall -- maybe the device is choking with our
190 * requests. Clear it and give it some time. If they
191 * happen to often, it might be another symptom, so we
192 * reset.
193 *
194 * No error handling for usb_clear_halt(0; if it
195 * works, the retry works; if it fails, this switch
196 * does the error handling for us.
197 */
198 if (edc_inc(&i2400mu->urb_edc,
199 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
200 dev_err(dev, "E: %s: too many stalls in "
201 "URB; resetting device\n", __func__);
202 usb_queue_reset_device(i2400mu->usb_iface);
203 /* fallthrough */
204 } else {
205 usb_clear_halt(i2400mu->usb_dev, pipe);
206 msleep(10); /* give the device some time */
207 goto retry;
208 }
209 case -EINVAL: /* while removing driver */
210 case -ENODEV: /* dev disconnect ... */
211 case -ENOENT: /* just ignore it */
212 case -ESHUTDOWN: /* and exit */
213 case -ECONNRESET:
214 ret = -ESHUTDOWN;
215 break;
216 default: /* Some error? */
217 if (edc_inc(&i2400mu->urb_edc,
218 EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
219 dev_err(dev, "E: %s: maximum errors in URB "
220 "exceeded; resetting device\n",
221 __func__);
222 usb_queue_reset_device(i2400mu->usb_iface);
223 } else {
224 dev_warn(dev, "W: %s: cannot send URB: %d\n",
225 __func__, ret);
226 goto retry;
227 }
183 } 228 }
184 kfree(buffer); 229 kfree(buffer);
185error_kzalloc: 230error_kzalloc: