Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: EHCI: use the new clear_tt_buffer interface

This patch (as1256) changes ehci-hcd and all the other drivers in the
EHCI family to make use of the new clear_tt_buffer callbacks. When a
Clear-TT-Buffer request is in progress for a QH, the QH is not allowed
to be linked into the async schedule until the request is finished.
At that time, if there are any URBs queued for the QH, it is linked
into the async schedule.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
914b7012 cb88a1b8

+86 -23
+2
drivers/usb/host/ehci-au1xxx.c
··· 113 113 .bus_resume = ehci_bus_resume, 114 114 .relinquish_port = ehci_relinquish_port, 115 115 .port_handed_over = ehci_port_handed_over, 116 + 117 + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 116 118 }; 117 119 118 120 static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
+2
drivers/usb/host/ehci-fsl.c
··· 325 325 .bus_resume = ehci_bus_resume, 326 326 .relinquish_port = ehci_relinquish_port, 327 327 .port_handed_over = ehci_port_handed_over, 328 + 329 + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 328 330 }; 329 331 330 332 static int ehci_fsl_drv_probe(struct platform_device *pdev)
+2
drivers/usb/host/ehci-hcd.c
··· 1003 1003 schedule_timeout_uninterruptible(1); 1004 1004 goto rescan; 1005 1005 case QH_STATE_IDLE: /* fully unlinked */ 1006 + if (qh->clearing_tt) 1007 + goto idle_timeout; 1006 1008 if (list_empty (&qh->qtd_list)) { 1007 1009 qh_put (qh); 1008 1010 break;
+2
drivers/usb/host/ehci-ixp4xx.c
··· 61 61 #endif 62 62 .relinquish_port = ehci_relinquish_port, 63 63 .port_handed_over = ehci_port_handed_over, 64 + 65 + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 64 66 }; 65 67 66 68 static int ixp4xx_ehci_probe(struct platform_device *pdev)
+2
drivers/usb/host/ehci-orion.c
··· 165 165 .bus_resume = ehci_bus_resume, 166 166 .relinquish_port = ehci_relinquish_port, 167 167 .port_handed_over = ehci_port_handed_over, 168 + 169 + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 168 170 }; 169 171 170 172 static void __init
+2
drivers/usb/host/ehci-pci.c
··· 404 404 .bus_resume = ehci_bus_resume, 405 405 .relinquish_port = ehci_relinquish_port, 406 406 .port_handed_over = ehci_port_handed_over, 407 + 408 + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 407 409 }; 408 410 409 411 /*-------------------------------------------------------------------------*/
+2
drivers/usb/host/ehci-ppc-of.c
··· 79 79 #endif 80 80 .relinquish_port = ehci_relinquish_port, 81 81 .port_handed_over = ehci_port_handed_over, 82 + 83 + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 82 84 }; 83 85 84 86
+2
drivers/usb/host/ehci-ps3.c
··· 75 75 #endif 76 76 .relinquish_port = ehci_relinquish_port, 77 77 .port_handed_over = ehci_port_handed_over, 78 + 79 + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 78 80 }; 79 81 80 82 static int __devinit ps3_ehci_probe(struct ps3_system_bus_device *dev)
+68 -23
drivers/usb/host/ehci-q.c
··· 139 139 140 140 /*-------------------------------------------------------------------------*/ 141 141 142 + static void qh_link_async(struct ehci_hcd *ehci, struct ehci_qh *qh); 143 + 144 + static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd, 145 + struct usb_host_endpoint *ep) 146 + { 147 + struct ehci_hcd *ehci = hcd_to_ehci(hcd); 148 + struct ehci_qh *qh = ep->hcpriv; 149 + unsigned long flags; 150 + 151 + spin_lock_irqsave(&ehci->lock, flags); 152 + qh->clearing_tt = 0; 153 + if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list) 154 + && HC_IS_RUNNING(hcd->state)) 155 + qh_link_async(ehci, qh); 156 + spin_unlock_irqrestore(&ehci->lock, flags); 157 + } 158 + 159 + static void ehci_clear_tt_buffer(struct ehci_hcd *ehci, struct ehci_qh *qh, 160 + struct urb *urb, u32 token) 161 + { 162 + 163 + /* If an async split transaction gets an error or is unlinked, 164 + * the TT buffer may be left in an indeterminate state. We 165 + * have to clear the TT buffer. 166 + * 167 + * Note: this routine is never called for Isochronous transfers. 168 + */ 169 + if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) { 170 + #ifdef DEBUG 171 + struct usb_device *tt = urb->dev->tt->hub; 172 + dev_dbg(&tt->dev, 173 + "clear tt buffer port %d, a%d ep%d t%08x\n", 174 + urb->dev->ttport, urb->dev->devnum, 175 + usb_pipeendpoint(urb->pipe), token); 176 + #endif /* DEBUG */ 177 + if (!ehci_is_TDI(ehci) 178 + || urb->dev->tt->hub != 179 + ehci_to_hcd(ehci)->self.root_hub) { 180 + if (usb_hub_clear_tt_buffer(urb) == 0) 181 + qh->clearing_tt = 1; 182 + } else { 183 + 184 + /* REVISIT ARC-derived cores don't clear the root 185 + * hub TT buffer in this way... 186 + */ 187 + } 188 + } 189 + } 190 + 142 191 static int qtd_copy_status ( 143 192 struct ehci_hcd *ehci, 144 193 struct urb *urb, ··· 244 195 usb_pipeendpoint (urb->pipe), 245 196 usb_pipein (urb->pipe) ? "in" : "out", 246 197 token, status); 247 - 248 - /* if async CSPLIT failed, try cleaning out the TT buffer */ 249 - if (status != -EPIPE 250 - && urb->dev->tt 251 - && !usb_pipeint(urb->pipe) 252 - && ((token & QTD_STS_MMF) != 0 253 - || QTD_CERR(token) == 0) 254 - && (!ehci_is_TDI(ehci) 255 - || urb->dev->tt->hub != 256 - ehci_to_hcd(ehci)->self.root_hub)) { 257 - #ifdef DEBUG 258 - struct usb_device *tt = urb->dev->tt->hub; 259 - dev_dbg (&tt->dev, 260 - "clear tt buffer port %d, a%d ep%d t%08x\n", 261 - urb->dev->ttport, urb->dev->devnum, 262 - usb_pipeendpoint (urb->pipe), token); 263 - #endif /* DEBUG */ 264 - /* REVISIT ARC-derived cores don't clear the root 265 - * hub TT buffer in this way... 266 - */ 267 - usb_hub_clear_tt_buffer(urb); 268 - } 269 198 } 270 199 271 200 return status; ··· 434 407 /* qh unlinked; token in overlay may be most current */ 435 408 if (state == QH_STATE_IDLE 436 409 && cpu_to_hc32(ehci, qtd->qtd_dma) 437 - == qh->hw_current) 410 + == qh->hw_current) { 438 411 token = hc32_to_cpu(ehci, qh->hw_token); 412 + 413 + /* An unlink may leave an incomplete 414 + * async transaction in the TT buffer. 415 + * We have to clear it. 416 + */ 417 + ehci_clear_tt_buffer(ehci, qh, urb, token); 418 + } 439 419 440 420 /* force halt for unlinked or blocked qh, so we'll 441 421 * patch the qh later and so that completions can't ··· 469 435 && (qtd->hw_alt_next 470 436 & EHCI_LIST_END(ehci))) 471 437 last_status = -EINPROGRESS; 438 + 439 + /* As part of low/full-speed endpoint-halt processing 440 + * we must clear the TT buffer (11.17.5). 441 + */ 442 + if (unlikely(last_status != -EINPROGRESS && 443 + last_status != -EREMOTEIO)) 444 + ehci_clear_tt_buffer(ehci, qh, urb, token); 472 445 } 473 446 474 447 /* if we're removing something not at the queue head, ··· 904 863 { 905 864 __hc32 dma = QH_NEXT(ehci, qh->qh_dma); 906 865 struct ehci_qh *head; 866 + 867 + /* Don't link a QH if there's a Clear-TT-Buffer pending */ 868 + if (unlikely(qh->clearing_tt)) 869 + return; 907 870 908 871 /* (re)start the async schedule? */ 909 872 head = ehci->async;
+2
drivers/usb/host/ehci.h
··· 354 354 unsigned short period; /* polling interval */ 355 355 unsigned short start; /* where polling starts */ 356 356 #define NO_FRAME ((unsigned short)~0) /* pick new start */ 357 + 357 358 struct usb_device *dev; /* access to TT */ 359 + unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ 358 360 } __attribute__ ((aligned (32))); 359 361 360 362 /*-------------------------------------------------------------------------*/