diff options
author | Inaky Perez-Gonzalez <inaky@linux.intel.com> | 2009-10-20 11:10:59 +0900 |
---|---|---|
committer | Inaky Perez-Gonzalez <inaky@linux.intel.com> | 2009-11-03 12:49:40 -0800 |
commit | faf57162e462eafe87458e21bf641f9d138f8171 (patch) | |
tree | c59c3a457768924a37b2feb80125b35cd15ac056 /drivers/net/wimax/i2400m/usb-tx.c | |
parent | fae92216da87d1c78aa51c4503acb312a47266e9 (diff) | |
download | linux-faf57162e462eafe87458e21bf641f9d138f8171.tar.bz2 |
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-tx.c')
-rw-r--r-- | drivers/net/wimax/i2400m/usb-tx.c | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/drivers/net/wimax/i2400m/usb-tx.c b/drivers/net/wimax/i2400m/usb-tx.c index 6cdf0036a146..c65b9979f87e 100644 --- a/drivers/net/wimax/i2400m/usb-tx.c +++ b/drivers/net/wimax/i2400m/usb-tx.c @@ -115,6 +115,28 @@ retry: result = -EIO; } break; + case -EPIPE: + /* + * Stall -- maybe the device is choking with our + * requests. Clear it and give it some time. If they + * happen to often, it might be another symptom, so we + * reset. + * + * No error handling for usb_clear_halt(0; if it + * works, the retry works; if it fails, this switch + * does the error handling for us. + */ + if (edc_inc(&i2400mu->urb_edc, + 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { + dev_err(dev, "BM-CMD: too many stalls in " + "URB; resetting device\n"); + usb_queue_reset_device(i2400mu->usb_iface); + /* fallthrough */ + } else { + usb_clear_halt(i2400mu->usb_dev, usb_pipe); + msleep(10); /* give the device some time */ + goto retry; + } case -EINVAL: /* while removing driver */ case -ENODEV: /* dev disconnect ... */ case -ENOENT: /* just ignore it */ |