diff options
| author | Alan Stern <stern@rowland.harvard.edu> | 2007-08-24 15:40:19 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-10-12 17:55:21 -0400 |
| commit | 14c04c0f88f228fee1f412be91d6edcb935c78aa (patch) | |
| tree | af635fda5cab3d0559326976dc818cd34c7f53bd /drivers/usb/host | |
| parent | 4d2f110c51eec853c50f68cf068888a77551c8d3 (diff) | |
USB: reorganize urb->status use in ehci-hcd
This patch (as974) reorganizes the way ehci-hcd sets urb->status. It
now keeps the information in a local variable until the last moment.
The patch also simplifies the handling of -EREMOTEIO, since the only
use of that code is to set the do_status flag.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: David Brownell <david-b@pacbell.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host')
| -rw-r--r-- | drivers/usb/host/ehci-q.c | 62 | ||||
| -rw-r--r-- | drivers/usb/host/ehci-sched.c | 4 |
2 files changed, 35 insertions, 31 deletions
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index a8f5408c16..794d27e078 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c | |||
| @@ -139,63 +139,65 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
| 139 | 139 | ||
| 140 | /*-------------------------------------------------------------------------*/ | 140 | /*-------------------------------------------------------------------------*/ |
| 141 | 141 | ||
| 142 | static void qtd_copy_status ( | 142 | static int qtd_copy_status ( |
| 143 | struct ehci_hcd *ehci, | 143 | struct ehci_hcd *ehci, |
| 144 | struct urb *urb, | 144 | struct urb *urb, |
| 145 | size_t length, | 145 | size_t length, |
| 146 | u32 token | 146 | u32 token |
| 147 | ) | 147 | ) |
| 148 | { | 148 | { |
| 149 | int status = -EINPROGRESS; | ||
| 150 | |||
| 149 | /* count IN/OUT bytes, not SETUP (even short packets) */ | 151 | /* count IN/OUT bytes, not SETUP (even short packets) */ |
| 150 | if (likely (QTD_PID (token) != 2)) | 152 | if (likely (QTD_PID (token) != 2)) |
| 151 | urb->actual_length += length - QTD_LENGTH (token); | 153 | urb->actual_length += length - QTD_LENGTH (token); |
| 152 | 154 | ||
| 153 | /* don't modify error codes */ | 155 | /* don't modify error codes */ |
| 154 | if (unlikely(urb->unlinked)) | 156 | if (unlikely(urb->unlinked)) |
| 155 | return; | 157 | return status; |
| 156 | 158 | ||
| 157 | /* force cleanup after short read; not always an error */ | 159 | /* force cleanup after short read; not always an error */ |
| 158 | if (unlikely (IS_SHORT_READ (token))) | 160 | if (unlikely (IS_SHORT_READ (token))) |
| 159 | urb->status = -EREMOTEIO; | 161 | status = -EREMOTEIO; |
| 160 | 162 | ||
| 161 | /* serious "can't proceed" faults reported by the hardware */ | 163 | /* serious "can't proceed" faults reported by the hardware */ |
| 162 | if (token & QTD_STS_HALT) { | 164 | if (token & QTD_STS_HALT) { |
| 163 | if (token & QTD_STS_BABBLE) { | 165 | if (token & QTD_STS_BABBLE) { |
| 164 | /* FIXME "must" disable babbling device's port too */ | 166 | /* FIXME "must" disable babbling device's port too */ |
| 165 | urb->status = -EOVERFLOW; | 167 | status = -EOVERFLOW; |
| 166 | } else if (token & QTD_STS_MMF) { | 168 | } else if (token & QTD_STS_MMF) { |
| 167 | /* fs/ls interrupt xfer missed the complete-split */ | 169 | /* fs/ls interrupt xfer missed the complete-split */ |
| 168 | urb->status = -EPROTO; | 170 | status = -EPROTO; |
| 169 | } else if (token & QTD_STS_DBE) { | 171 | } else if (token & QTD_STS_DBE) { |
| 170 | urb->status = (QTD_PID (token) == 1) /* IN ? */ | 172 | status = (QTD_PID (token) == 1) /* IN ? */ |
| 171 | ? -ENOSR /* hc couldn't read data */ | 173 | ? -ENOSR /* hc couldn't read data */ |
| 172 | : -ECOMM; /* hc couldn't write data */ | 174 | : -ECOMM; /* hc couldn't write data */ |
| 173 | } else if (token & QTD_STS_XACT) { | 175 | } else if (token & QTD_STS_XACT) { |
| 174 | /* timeout, bad crc, wrong PID, etc; retried */ | 176 | /* timeout, bad crc, wrong PID, etc; retried */ |
| 175 | if (QTD_CERR (token)) | 177 | if (QTD_CERR (token)) |
| 176 | urb->status = -EPIPE; | 178 | status = -EPIPE; |
| 177 | else { | 179 | else { |
| 178 | ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n", | 180 | ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n", |
| 179 | urb->dev->devpath, | 181 | urb->dev->devpath, |
| 180 | usb_pipeendpoint (urb->pipe), | 182 | usb_pipeendpoint (urb->pipe), |
| 181 | usb_pipein (urb->pipe) ? "in" : "out"); | 183 | usb_pipein (urb->pipe) ? "in" : "out"); |
| 182 | urb->status = -EPROTO; | 184 | status = -EPROTO; |
| 183 | } | 185 | } |
| 184 | /* CERR nonzero + no errors + halt --> stall */ | 186 | /* CERR nonzero + no errors + halt --> stall */ |
| 185 | } else if (QTD_CERR (token)) | 187 | } else if (QTD_CERR (token)) |
| 186 | urb->status = -EPIPE; | 188 | status = -EPIPE; |
| 187 | else /* unknown */ | 189 | else /* unknown */ |
| 188 | urb->status = -EPROTO; | 190 | status = -EPROTO; |
| 189 | 191 | ||
| 190 | ehci_vdbg (ehci, | 192 | ehci_vdbg (ehci, |
| 191 | "dev%d ep%d%s qtd token %08x --> status %d\n", | 193 | "dev%d ep%d%s qtd token %08x --> status %d\n", |
| 192 | usb_pipedevice (urb->pipe), | 194 | usb_pipedevice (urb->pipe), |
| 193 | usb_pipeendpoint (urb->pipe), | 195 | usb_pipeendpoint (urb->pipe), |
| 194 | usb_pipein (urb->pipe) ? "in" : "out", | 196 | usb_pipein (urb->pipe) ? "in" : "out", |
| 195 | token, urb->status); | 197 | token, status); |
| 196 | 198 | ||
| 197 | /* if async CSPLIT failed, try cleaning out the TT buffer */ | 199 | /* if async CSPLIT failed, try cleaning out the TT buffer */ |
| 198 | if (urb->status != -EPIPE | 200 | if (status != -EPIPE |
| 199 | && urb->dev->tt && !usb_pipeint (urb->pipe) | 201 | && urb->dev->tt && !usb_pipeint (urb->pipe) |
| 200 | && ((token & QTD_STS_MMF) != 0 | 202 | && ((token & QTD_STS_MMF) != 0 |
| 201 | || QTD_CERR(token) == 0) | 203 | || QTD_CERR(token) == 0) |
| @@ -212,10 +214,12 @@ static void qtd_copy_status ( | |||
| 212 | usb_hub_tt_clear_buffer (urb->dev, urb->pipe); | 214 | usb_hub_tt_clear_buffer (urb->dev, urb->pipe); |
| 213 | } | 215 | } |
| 214 | } | 216 | } |
| 217 | |||
| 218 | return status; | ||
| 215 | } | 219 | } |
| 216 | 220 | ||
| 217 | static void | 221 | static void |
| 218 | ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb) | 222 | ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status) |
| 219 | __releases(ehci->lock) | 223 | __releases(ehci->lock) |
| 220 | __acquires(ehci->lock) | 224 | __acquires(ehci->lock) |
| 221 | { | 225 | { |
| @@ -231,17 +235,13 @@ __acquires(ehci->lock) | |||
| 231 | qh_put (qh); | 235 | qh_put (qh); |
| 232 | } | 236 | } |
| 233 | 237 | ||
| 234 | spin_lock (&urb->lock); | ||
| 235 | if (unlikely(urb->unlinked)) { | 238 | if (unlikely(urb->unlinked)) { |
| 236 | COUNT(ehci->stats.unlink); | 239 | COUNT(ehci->stats.unlink); |
| 237 | } else { | 240 | } else { |
| 238 | if (likely(urb->status == -EINPROGRESS || | 241 | if (likely(status == -EINPROGRESS)) |
| 239 | (urb->status == -EREMOTEIO && | 242 | status = 0; |
| 240 | !(urb->transfer_flags & URB_SHORT_NOT_OK)))) | ||
| 241 | urb->status = 0; | ||
| 242 | COUNT(ehci->stats.complete); | 243 | COUNT(ehci->stats.complete); |
| 243 | } | 244 | } |
| 244 | spin_unlock (&urb->lock); | ||
| 245 | 245 | ||
| 246 | #ifdef EHCI_URB_TRACE | 246 | #ifdef EHCI_URB_TRACE |
| 247 | ehci_dbg (ehci, | 247 | ehci_dbg (ehci, |
| @@ -249,13 +249,14 @@ __acquires(ehci->lock) | |||
| 249 | __FUNCTION__, urb->dev->devpath, urb, | 249 | __FUNCTION__, urb->dev->devpath, urb, |
| 250 | usb_pipeendpoint (urb->pipe), | 250 | usb_pipeendpoint (urb->pipe), |
| 251 | usb_pipein (urb->pipe) ? "in" : "out", | 251 | usb_pipein (urb->pipe) ? "in" : "out", |
| 252 | urb->status, | 252 | status, |
| 253 | urb->actual_length, urb->transfer_buffer_length); | 253 | urb->actual_length, urb->transfer_buffer_length); |
| 254 | #endif | 254 | #endif |
| 255 | 255 | ||
| 256 | /* complete() can reenter this HCD */ | 256 | /* complete() can reenter this HCD */ |
| 257 | usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); | 257 | usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); |
| 258 | spin_unlock (&ehci->lock); | 258 | spin_unlock (&ehci->lock); |
| 259 | urb->status = status; | ||
| 259 | usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); | 260 | usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); |
| 260 | spin_lock (&ehci->lock); | 261 | spin_lock (&ehci->lock); |
| 261 | } | 262 | } |
| @@ -276,6 +277,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
| 276 | { | 277 | { |
| 277 | struct ehci_qtd *last = NULL, *end = qh->dummy; | 278 | struct ehci_qtd *last = NULL, *end = qh->dummy; |
| 278 | struct list_head *entry, *tmp; | 279 | struct list_head *entry, *tmp; |
| 280 | int last_status = -EINPROGRESS; | ||
| 279 | int stopped; | 281 | int stopped; |
| 280 | unsigned count = 0; | 282 | unsigned count = 0; |
| 281 | int do_status = 0; | 283 | int do_status = 0; |
| @@ -304,6 +306,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
| 304 | struct ehci_qtd *qtd; | 306 | struct ehci_qtd *qtd; |
| 305 | struct urb *urb; | 307 | struct urb *urb; |
| 306 | u32 token = 0; | 308 | u32 token = 0; |
| 309 | int qtd_status; | ||
| 307 | 310 | ||
| 308 | qtd = list_entry (entry, struct ehci_qtd, qtd_list); | 311 | qtd = list_entry (entry, struct ehci_qtd, qtd_list); |
| 309 | urb = qtd->urb; | 312 | urb = qtd->urb; |
| @@ -311,11 +314,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
| 311 | /* clean up any state from previous QTD ...*/ | 314 | /* clean up any state from previous QTD ...*/ |
| 312 | if (last) { | 315 | if (last) { |
| 313 | if (likely (last->urb != urb)) { | 316 | if (likely (last->urb != urb)) { |
| 314 | ehci_urb_done (ehci, last->urb); | 317 | ehci_urb_done(ehci, last->urb, last_status); |
| 315 | count++; | 318 | count++; |
| 316 | } | 319 | } |
| 317 | ehci_qtd_free (ehci, last); | 320 | ehci_qtd_free (ehci, last); |
| 318 | last = NULL; | 321 | last = NULL; |
| 322 | last_status = -EINPROGRESS; | ||
| 319 | } | 323 | } |
| 320 | 324 | ||
| 321 | /* ignore urbs submitted during completions we reported */ | 325 | /* ignore urbs submitted during completions we reported */ |
| @@ -351,13 +355,13 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
| 351 | stopped = 1; | 355 | stopped = 1; |
| 352 | 356 | ||
| 353 | if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) | 357 | if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) |
| 354 | urb->status = -ESHUTDOWN; | 358 | last_status = -ESHUTDOWN; |
| 355 | 359 | ||
| 356 | /* ignore active urbs unless some previous qtd | 360 | /* ignore active urbs unless some previous qtd |
| 357 | * for the urb faulted (including short read) or | 361 | * for the urb faulted (including short read) or |
| 358 | * its urb was canceled. we may patch qh or qtds. | 362 | * its urb was canceled. we may patch qh or qtds. |
| 359 | */ | 363 | */ |
| 360 | if (likely(urb->status == -EINPROGRESS && | 364 | if (likely(last_status == -EINPROGRESS && |
| 361 | !urb->unlinked)) | 365 | !urb->unlinked)) |
| 362 | continue; | 366 | continue; |
| 363 | 367 | ||
| @@ -386,14 +390,14 @@ halt: | |||
| 386 | } | 390 | } |
| 387 | 391 | ||
| 388 | /* remove it from the queue */ | 392 | /* remove it from the queue */ |
| 389 | spin_lock (&urb->lock); | 393 | qtd_status = qtd_copy_status(ehci, urb, qtd->length, token); |
| 390 | qtd_copy_status (ehci, urb, qtd->length, token); | 394 | if (unlikely(qtd_status == -EREMOTEIO)) { |
| 391 | if (unlikely(urb->status == -EREMOTEIO)) { | ||
| 392 | do_status = (!urb->unlinked && | 395 | do_status = (!urb->unlinked && |
| 393 | usb_pipecontrol(urb->pipe)); | 396 | usb_pipecontrol(urb->pipe)); |
| 394 | urb->status = 0; | 397 | qtd_status = 0; |
| 395 | } | 398 | } |
| 396 | spin_unlock (&urb->lock); | 399 | if (likely(last_status == -EINPROGRESS)) |
| 400 | last_status = qtd_status; | ||
| 397 | 401 | ||
| 398 | if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { | 402 | if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { |
| 399 | last = list_entry (qtd->qtd_list.prev, | 403 | last = list_entry (qtd->qtd_list.prev, |
| @@ -406,7 +410,7 @@ halt: | |||
| 406 | 410 | ||
| 407 | /* last urb's completion might still need calling */ | 411 | /* last urb's completion might still need calling */ |
| 408 | if (likely (last != NULL)) { | 412 | if (likely (last != NULL)) { |
| 409 | ehci_urb_done (ehci, last->urb); | 413 | ehci_urb_done(ehci, last->urb, last_status); |
| 410 | count++; | 414 | count++; |
| 411 | ehci_qtd_free (ehci, last); | 415 | ehci_qtd_free (ehci, last); |
| 412 | } | 416 | } |
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 8b267b3fd2..80d99bce2b 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
| @@ -1627,7 +1627,7 @@ itd_complete ( | |||
| 1627 | 1627 | ||
| 1628 | /* give urb back to the driver ... can be out-of-order */ | 1628 | /* give urb back to the driver ... can be out-of-order */ |
| 1629 | dev = urb->dev; | 1629 | dev = urb->dev; |
| 1630 | ehci_urb_done (ehci, urb); | 1630 | ehci_urb_done(ehci, urb, 0); |
| 1631 | urb = NULL; | 1631 | urb = NULL; |
| 1632 | 1632 | ||
| 1633 | /* defer stopping schedule; completion can submit */ | 1633 | /* defer stopping schedule; completion can submit */ |
| @@ -2000,7 +2000,7 @@ sitd_complete ( | |||
| 2000 | 2000 | ||
| 2001 | /* give urb back to the driver */ | 2001 | /* give urb back to the driver */ |
| 2002 | dev = urb->dev; | 2002 | dev = urb->dev; |
| 2003 | ehci_urb_done (ehci, urb); | 2003 | ehci_urb_done(ehci, urb, 0); |
| 2004 | urb = NULL; | 2004 | urb = NULL; |
| 2005 | 2005 | ||
| 2006 | /* defer stopping schedule; completion can submit */ | 2006 | /* defer stopping schedule; completion can submit */ |
