aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-q.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-06-29 17:36:14 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-07-12 18:16:39 -0400
commitba516de332c0e574457e58fb5aa0293e628b7b10 (patch)
treea3b36a84db2c0ae0da8762061d3566fe94138125 /drivers/usb/host/ehci-q.c
parent914b701280a76f96890ad63eb0fa99bf204b961c (diff)
USB: EHCI: check for STALL before other errors
This patch (as1257) revises the way ehci-hcd detects STALLs. The logic is a little peculiar because there's no hardware status bit specifically meant to indicate a STALL. You just have to guess that a STALL was received if the BABBLE bit (which is fatal) isn't set and the transfer stopped before all its retries were used up. The existing code doesn't do this properly, because it tests for MMF (Missed MicroFrame) and DBE (Data Buffer Error) before testing the retry counter. Thus, if a transaction gets either MMF or DBE the corresponding flag is set and the transaction is retried. If the second attempt receives a STALL then -EPIPE is the correct return value. But the existing code would see the MMF or DBE flag instead and return -EPROTO, -ENOSR, or -ECOMM. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ehci-q.c')
-rw-r--r--drivers/usb/host/ehci-q.c30
1 files changed, 16 insertions, 14 deletions
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index e3d2b627bfb3..9a1384747f3b 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -214,6 +214,14 @@ static int qtd_copy_status (
214 if (token & QTD_STS_BABBLE) { 214 if (token & QTD_STS_BABBLE) {
215 /* FIXME "must" disable babbling device's port too */ 215 /* FIXME "must" disable babbling device's port too */
216 status = -EOVERFLOW; 216 status = -EOVERFLOW;
217 /* CERR nonzero + halt --> stall */
218 } else if (QTD_CERR(token)) {
219 status = -EPIPE;
220
221 /* In theory, more than one of the following bits can be set
222 * since they are sticky and the transaction is retried.
223 * Which to test first is rather arbitrary.
224 */
217 } else if (token & QTD_STS_MMF) { 225 } else if (token & QTD_STS_MMF) {
218 /* fs/ls interrupt xfer missed the complete-split */ 226 /* fs/ls interrupt xfer missed the complete-split */
219 status = -EPROTO; 227 status = -EPROTO;
@@ -222,21 +230,15 @@ static int qtd_copy_status (
222 ? -ENOSR /* hc couldn't read data */ 230 ? -ENOSR /* hc couldn't read data */
223 : -ECOMM; /* hc couldn't write data */ 231 : -ECOMM; /* hc couldn't write data */
224 } else if (token & QTD_STS_XACT) { 232 } else if (token & QTD_STS_XACT) {
225 /* timeout, bad crc, wrong PID, etc; retried */ 233 /* timeout, bad CRC, wrong PID, etc */
226 if (QTD_CERR (token)) 234 ehci_dbg(ehci, "devpath %s ep%d%s 3strikes\n",
227 status = -EPIPE; 235 urb->dev->devpath,
228 else { 236 usb_pipeendpoint(urb->pipe),
229 ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n", 237 usb_pipein(urb->pipe) ? "in" : "out");
230 urb->dev->devpath, 238 status = -EPROTO;
231 usb_pipeendpoint (urb->pipe), 239 } else { /* unknown */
232 usb_pipein (urb->pipe) ? "in" : "out");
233 status = -EPROTO;
234 }
235 /* CERR nonzero + no errors + halt --> stall */
236 } else if (QTD_CERR (token))
237 status = -EPIPE;
238 else /* unknown */
239 status = -EPROTO; 240 status = -EPROTO;
241 }
240 242
241 ehci_vdbg (ehci, 243 ehci_vdbg (ehci,
242 "dev%d ep%d%s qtd token %08x --> status %d\n", 244 "dev%d ep%d%s qtd token %08x --> status %d\n",