From b18ffd49e86102a9ed0a1cc83fdafe3891e844e5 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 27 May 2009 18:21:56 -0400 Subject: USB: EHCI: update toggle state for linked QHs This patch (as1245) fixes a bug in ehci-hcd. When an URB is queued for an endpoint whose QH is already in the LINKED state, the QH doesn't get refreshed. As a result, if usb_clear_halt() was called during the time that the QH was linked but idle, the data toggle value in the QH doesn't get reset. The symptom is that after a clear_halt, data gets lost and transfers time out. This problem is starting to show up now because the "ehci-hcd unlink speedups" patch causes QHs with no queued URBs to remain linked for a suitable time. The patch utilizes the new endpoint_reset mechanism to fix the problem. When an endpoint is reset, the new method forcibly unlinks the QH (if necessary) and safely updates the toggle value. This allows qh_update() to be simplified and avoids using usb_device's toggle bits in a rather unintuitive way. Signed-off-by: Alan Stern CC: David Brownell Tested-by: David Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-q.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'drivers/usb/host/ehci-q.c') diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 1976b1b3778..3192f683f80 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -93,22 +93,6 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma); qh->hw_alt_next = EHCI_LIST_END(ehci); - /* Except for control endpoints, we make hardware maintain data - * toggle (like OHCI) ... here (re)initialize the toggle in the QH, - * and set the pseudo-toggle in udev. Only usb_clear_halt() will - * ever clear it. - */ - if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) { - unsigned is_out, epnum; - - is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8)); - epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f; - if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { - qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); - usb_settoggle (qh->dev, epnum, is_out, 1); - } - } - /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ wmb (); qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING); @@ -850,7 +834,6 @@ done: qh->qh_state = QH_STATE_IDLE; qh->hw_info1 = cpu_to_hc32(ehci, info1); qh->hw_info2 = cpu_to_hc32(ehci, info2); - usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); qh_refresh (ehci, qh); return qh; } @@ -881,7 +864,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) } } - /* clear halt and/or toggle; and maybe recover from silicon quirk */ + /* clear halt and maybe recover from silicon quirk */ if (qh->qh_state == QH_STATE_IDLE) qh_refresh (ehci, qh); -- cgit v1.2.3