diff options
Diffstat (limited to 'drivers/usb/host/ehci-q.c')
-rw-r--r-- | drivers/usb/host/ehci-q.c | 99 |
1 files changed, 51 insertions, 48 deletions
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 140bfa423e07..b10f39c047e9 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->status != -EINPROGRESS)) | 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,25 +235,13 @@ __acquires(ehci->lock) | |||
231 | qh_put (qh); | 235 | qh_put (qh); |
232 | } | 236 | } |
233 | 237 | ||
234 | spin_lock (&urb->lock); | 238 | if (unlikely(urb->unlinked)) { |
235 | urb->hcpriv = NULL; | 239 | COUNT(ehci->stats.unlink); |
236 | switch (urb->status) { | 240 | } else { |
237 | case -EINPROGRESS: /* success */ | 241 | if (likely(status == -EINPROGRESS)) |
238 | urb->status = 0; | 242 | status = 0; |
239 | default: /* fault */ | 243 | COUNT(ehci->stats.complete); |
240 | COUNT (ehci->stats.complete); | ||
241 | break; | ||
242 | case -EREMOTEIO: /* fault or normal */ | ||
243 | if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) | ||
244 | urb->status = 0; | ||
245 | COUNT (ehci->stats.complete); | ||
246 | break; | ||
247 | case -ECONNRESET: /* canceled */ | ||
248 | case -ENOENT: | ||
249 | COUNT (ehci->stats.unlink); | ||
250 | break; | ||
251 | } | 244 | } |
252 | spin_unlock (&urb->lock); | ||
253 | 245 | ||
254 | #ifdef EHCI_URB_TRACE | 246 | #ifdef EHCI_URB_TRACE |
255 | ehci_dbg (ehci, | 247 | ehci_dbg (ehci, |
@@ -257,13 +249,14 @@ __acquires(ehci->lock) | |||
257 | __FUNCTION__, urb->dev->devpath, urb, | 249 | __FUNCTION__, urb->dev->devpath, urb, |
258 | usb_pipeendpoint (urb->pipe), | 250 | usb_pipeendpoint (urb->pipe), |
259 | usb_pipein (urb->pipe) ? "in" : "out", | 251 | usb_pipein (urb->pipe) ? "in" : "out", |
260 | urb->status, | 252 | status, |
261 | urb->actual_length, urb->transfer_buffer_length); | 253 | urb->actual_length, urb->transfer_buffer_length); |
262 | #endif | 254 | #endif |
263 | 255 | ||
264 | /* complete() can reenter this HCD */ | 256 | /* complete() can reenter this HCD */ |
257 | usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); | ||
265 | spin_unlock (&ehci->lock); | 258 | spin_unlock (&ehci->lock); |
266 | usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb); | 259 | usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status); |
267 | spin_lock (&ehci->lock); | 260 | spin_lock (&ehci->lock); |
268 | } | 261 | } |
269 | 262 | ||
@@ -283,6 +276,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
283 | { | 276 | { |
284 | struct ehci_qtd *last = NULL, *end = qh->dummy; | 277 | struct ehci_qtd *last = NULL, *end = qh->dummy; |
285 | struct list_head *entry, *tmp; | 278 | struct list_head *entry, *tmp; |
279 | int last_status = -EINPROGRESS; | ||
286 | int stopped; | 280 | int stopped; |
287 | unsigned count = 0; | 281 | unsigned count = 0; |
288 | int do_status = 0; | 282 | int do_status = 0; |
@@ -311,6 +305,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
311 | struct ehci_qtd *qtd; | 305 | struct ehci_qtd *qtd; |
312 | struct urb *urb; | 306 | struct urb *urb; |
313 | u32 token = 0; | 307 | u32 token = 0; |
308 | int qtd_status; | ||
314 | 309 | ||
315 | qtd = list_entry (entry, struct ehci_qtd, qtd_list); | 310 | qtd = list_entry (entry, struct ehci_qtd, qtd_list); |
316 | urb = qtd->urb; | 311 | urb = qtd->urb; |
@@ -318,11 +313,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
318 | /* clean up any state from previous QTD ...*/ | 313 | /* clean up any state from previous QTD ...*/ |
319 | if (last) { | 314 | if (last) { |
320 | if (likely (last->urb != urb)) { | 315 | if (likely (last->urb != urb)) { |
321 | ehci_urb_done (ehci, last->urb); | 316 | ehci_urb_done(ehci, last->urb, last_status); |
322 | count++; | 317 | count++; |
323 | } | 318 | } |
324 | ehci_qtd_free (ehci, last); | 319 | ehci_qtd_free (ehci, last); |
325 | last = NULL; | 320 | last = NULL; |
321 | last_status = -EINPROGRESS; | ||
326 | } | 322 | } |
327 | 323 | ||
328 | /* ignore urbs submitted during completions we reported */ | 324 | /* ignore urbs submitted during completions we reported */ |
@@ -358,13 +354,14 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
358 | stopped = 1; | 354 | stopped = 1; |
359 | 355 | ||
360 | if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) | 356 | if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) |
361 | urb->status = -ESHUTDOWN; | 357 | last_status = -ESHUTDOWN; |
362 | 358 | ||
363 | /* ignore active urbs unless some previous qtd | 359 | /* ignore active urbs unless some previous qtd |
364 | * for the urb faulted (including short read) or | 360 | * for the urb faulted (including short read) or |
365 | * its urb was canceled. we may patch qh or qtds. | 361 | * its urb was canceled. we may patch qh or qtds. |
366 | */ | 362 | */ |
367 | if (likely (urb->status == -EINPROGRESS)) | 363 | if (likely(last_status == -EINPROGRESS && |
364 | !urb->unlinked)) | ||
368 | continue; | 365 | continue; |
369 | 366 | ||
370 | /* issue status after short control reads */ | 367 | /* issue status after short control reads */ |
@@ -392,11 +389,14 @@ halt: | |||
392 | } | 389 | } |
393 | 390 | ||
394 | /* remove it from the queue */ | 391 | /* remove it from the queue */ |
395 | spin_lock (&urb->lock); | 392 | qtd_status = qtd_copy_status(ehci, urb, qtd->length, token); |
396 | qtd_copy_status (ehci, urb, qtd->length, token); | 393 | if (unlikely(qtd_status == -EREMOTEIO)) { |
397 | do_status = (urb->status == -EREMOTEIO) | 394 | do_status = (!urb->unlinked && |
398 | && usb_pipecontrol (urb->pipe); | 395 | usb_pipecontrol(urb->pipe)); |
399 | spin_unlock (&urb->lock); | 396 | qtd_status = 0; |
397 | } | ||
398 | if (likely(last_status == -EINPROGRESS)) | ||
399 | last_status = qtd_status; | ||
400 | 400 | ||
401 | if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { | 401 | if (stopped && qtd->qtd_list.prev != &qh->qtd_list) { |
402 | last = list_entry (qtd->qtd_list.prev, | 402 | last = list_entry (qtd->qtd_list.prev, |
@@ -409,7 +409,7 @@ halt: | |||
409 | 409 | ||
410 | /* last urb's completion might still need calling */ | 410 | /* last urb's completion might still need calling */ |
411 | if (likely (last != NULL)) { | 411 | if (likely (last != NULL)) { |
412 | ehci_urb_done (ehci, last->urb); | 412 | ehci_urb_done(ehci, last->urb, last_status); |
413 | count++; | 413 | count++; |
414 | ehci_qtd_free (ehci, last); | 414 | ehci_qtd_free (ehci, last); |
415 | } | 415 | } |
@@ -913,7 +913,6 @@ static struct ehci_qh *qh_append_tds ( | |||
913 | static int | 913 | static int |
914 | submit_async ( | 914 | submit_async ( |
915 | struct ehci_hcd *ehci, | 915 | struct ehci_hcd *ehci, |
916 | struct usb_host_endpoint *ep, | ||
917 | struct urb *urb, | 916 | struct urb *urb, |
918 | struct list_head *qtd_list, | 917 | struct list_head *qtd_list, |
919 | gfp_t mem_flags | 918 | gfp_t mem_flags |
@@ -922,10 +921,10 @@ submit_async ( | |||
922 | int epnum; | 921 | int epnum; |
923 | unsigned long flags; | 922 | unsigned long flags; |
924 | struct ehci_qh *qh = NULL; | 923 | struct ehci_qh *qh = NULL; |
925 | int rc = 0; | 924 | int rc; |
926 | 925 | ||
927 | qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); | 926 | qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); |
928 | epnum = ep->desc.bEndpointAddress; | 927 | epnum = urb->ep->desc.bEndpointAddress; |
929 | 928 | ||
930 | #ifdef EHCI_URB_TRACE | 929 | #ifdef EHCI_URB_TRACE |
931 | ehci_dbg (ehci, | 930 | ehci_dbg (ehci, |
@@ -933,7 +932,7 @@ submit_async ( | |||
933 | __FUNCTION__, urb->dev->devpath, urb, | 932 | __FUNCTION__, urb->dev->devpath, urb, |
934 | epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", | 933 | epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out", |
935 | urb->transfer_buffer_length, | 934 | urb->transfer_buffer_length, |
936 | qtd, ep->hcpriv); | 935 | qtd, urb->ep->hcpriv); |
937 | #endif | 936 | #endif |
938 | 937 | ||
939 | spin_lock_irqsave (&ehci->lock, flags); | 938 | spin_lock_irqsave (&ehci->lock, flags); |
@@ -942,9 +941,13 @@ submit_async ( | |||
942 | rc = -ESHUTDOWN; | 941 | rc = -ESHUTDOWN; |
943 | goto done; | 942 | goto done; |
944 | } | 943 | } |
944 | rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb); | ||
945 | if (unlikely(rc)) | ||
946 | goto done; | ||
945 | 947 | ||
946 | qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); | 948 | qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv); |
947 | if (unlikely(qh == NULL)) { | 949 | if (unlikely(qh == NULL)) { |
950 | usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); | ||
948 | rc = -ENOMEM; | 951 | rc = -ENOMEM; |
949 | goto done; | 952 | goto done; |
950 | } | 953 | } |