summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2006-05-12 11:41:59 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2006-06-21 15:04:11 -0700
commitb761d9d867bcc29e8de3e62d1d72b27e75078ca6 (patch)
tree40b8f2e530bd9bbece14007a3d887bbe12e8afde /drivers/usb
parent84afddd7ac58adad00cb0e50d0af25fcf825668b (diff)
[PATCH] UHCI: Work around old Intel bug
Some old Intel UHCI controllers have a bug that has shown up in a few systems (the PIIX3 "Neptune" chip set). Until now there has not been any simple way to work around the bug, but the lastest changes in uhci-hcd have made it easy. This patch (as684) adds the work-around. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/uhci-q.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 2be84b3b40f..76b0a9e95a7 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -13,7 +13,7 @@
* (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
* support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
* (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu
*/
@@ -1287,6 +1287,11 @@ restart:
* Check for queues that have made some forward progress.
* Returns 0 if the queue is not Isochronous, is ACTIVE, and
* has not advanced since last examined; 1 otherwise.
+ *
+ * Early Intel controllers have a bug which causes qh->element sometimes
+ * not to advance when a TD completes successfully. The queue remains
+ * stuck on the inactive completed TD. We detect such cases and advance
+ * the element pointer by hand.
*/
static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
@@ -1327,6 +1332,15 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
/* The queue hasn't advanced; check for timeout */
if (!qh->wait_expired && time_after(jiffies,
qh->advance_jiffies + QH_WAIT_TIMEOUT)) {
+
+ /* Detect the Intel bug and work around it */
+ if (qh->post_td && qh_element(qh) ==
+ cpu_to_le32(qh->post_td->dma_handle)) {
+ qh->element = qh->post_td->link;
+ qh->advance_jiffies = jiffies;
+ return 1;
+ }
+
qh->wait_expired = 1;
/* If the current URB wants FSBR, unlink it temporarily