Here's a patch that resolves a regression I've been chasing for a while ... it may address other issues too, which is why there's a CC list.
The significant change is some updates to how completed qTDs get processed.
Less significant changes include updates to the debug output, a version change, removing a now-fixed FIXME comment, and getting rid of some runtime byteswaps on big-endian hardware.
Please test this. Unless it makes something worse, it should get into 2.5.next, and at least the qTD change should get into the 2.4.22-pre series.
- Dave
--- 1.47/drivers/usb/host/ehci-q.c Mon May 19 02:10:48 2003 +++ edited/drivers/usb/host/ehci-q.c Mon Jun 9 23:44:02 2003 @@ -99,8 +99,6 @@ /*-------------------------------------------------------------------------*/ -#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1) - static void qtd_copy_status ( struct ehci_hcd *ehci, struct urb *urb, @@ -279,16 +277,15 @@ /* hardware copies qtd out of qh overlay */ rmb (); token = le32_to_cpu (qtd->hw_token); - stopped = stopped - || (HALT_BIT & qh->hw_token) != 0 - || (ehci->hcd.state == USB_STATE_HALT); /* always clean up qtds the hc de-activated */ if ((token & QTD_STS_ACTIVE) == 0) { - /* magic dummy for short reads; won't advance */ - if (IS_SHORT_READ (token) - && !(token & QTD_STS_HALT) + if ((token & QTD_STS_HALT) != 0) { + stopped = 1; + + /* magic dummy for some short reads; qh won't advance */ + } else if (IS_SHORT_READ (token) && (qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next) { stopped = 1; @@ -296,10 +293,13 @@ } /* stop scanning when we reach qtds the hc is using */ - } else if (likely (!stopped)) { + } else if (likely (!stopped + || HCD_IS_RUNNING (ehci->hcd.state))) { break; } else { + stopped = 1; + /* ignore active urbs unless some previous qtd * for the urb faulted (including short read) or * its urb was canceled. we may patch qh or qtds. @@ -358,7 +358,7 @@ qh->qh_state = state; /* update qh after fault cleanup */ - if (unlikely ((HALT_BIT & qh->hw_token) != 0)) { + if (unlikely (stopped != 0)) { qh_update (ehci, qh, list_empty (&qh->qtd_list) ? qh->dummy @@ -787,11 +787,6 @@ } } } - - /* FIXME: changing config or interface setting is not - * supported yet. preferred fix is for usbcore to tell - * us to clear out each endpoint's state, but... - */ /* usb_clear_halt() means qh data toggle gets reset */ if (unlikely (!usb_gettoggle (urb->dev, --- 1.20/drivers/usb/host/ehci.h Thu Apr 24 06:29:02 2003 +++ edited/drivers/usb/host/ehci.h Mon Jun 9 21:32:15 2003 @@ -290,7 +290,10 @@ size_t length; /* length of buffer */ } __attribute__ ((aligned (32))); -#define QTD_MASK cpu_to_le32 (~0x1f) /* mask NakCnt+T in qh->hw_alt_next */ +/* mask NakCnt+T in qh->hw_alt_next */ +#define QTD_MASK __constant_cpu_to_le32 (~0x1f) + +#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1) /*-------------------------------------------------------------------------*/ --- 1.19/drivers/usb/host/ehci-dbg.c Wed Mar 19 02:25:01 2003 +++ edited/drivers/usb/host/ehci-dbg.c Mon Jun 9 21:52:55 2003 @@ -114,20 +114,22 @@ #ifdef DEBUG +static inline void __attribute__((__unused__)) +dbg_qtd (char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd) +{ + ehci_dbg (ehci, "%s td %p n%08x %08x t%08x p0=%08x p1=%08x\n", label, + qtd, qtd->hw_next, qtd->hw_alt_next, qtd->hw_token, + qtd->hw_buf [0], qtd->hw_buf [1]); + // not dumping qtd->hw_buf[2..4] +} + static void __attribute__((__unused__)) dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) { - dbg ("%s %p n%08x info1 %x info2 %x hw_curr %x qtd_next %x", label, + ehci_dbg (ehci, "%s %p n%08x info1 %x info2 %x hw_curr %x\n", label, qh, qh->hw_next, qh->hw_info1, qh->hw_info2, - qh->hw_current, qh->hw_qtd_next); - dbg (" alt+nak+t= %x, token= %x, page0= %x, page1= %x", - qh->hw_alt_next, qh->hw_token, - qh->hw_buf [0], qh->hw_buf [1]); - if (qh->hw_buf [2]) { - dbg (" page2= %x, page3= %x, page4= %x", - qh->hw_buf [2], qh->hw_buf [3], - qh->hw_buf [4]); - } + qh->hw_current); + dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next); } static int __attribute__((__unused__)) @@ -284,8 +286,7 @@ return '*'; if (token & QTD_STS_HALT) return '-'; - if (QTD_PID (token) != 1 /* not IN: OUT or SETUP */ - || QTD_LENGTH (token) == 0) + if (!IS_SHORT_READ (token)) return ' '; /* tries to advance through hw_alt_next */ return '/'; @@ -311,7 +312,7 @@ if (mark == '/') { /* qh_alt_next controls qh advance? */ if ((qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next) mark = '#'; /* blocked */ - else if (qh->hw_alt_next & cpu_to_le32 (0x01)) + else if (qh->hw_alt_next == EHCI_LIST_END) mark = '.'; /* use hw_qtd_next */ /* else alt_next points to some other qtd */ } @@ -324,7 +325,7 @@ (scratch >> 8) & 0x000f, scratch, cpu_to_le32p (&qh->hw_info2), cpu_to_le32p (&qh->hw_token), mark, - (cpu_to_le32 (0x8000000) & qh->hw_token) + (__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token) ? "data0" : "data1", (cpu_to_le32p (&qh->hw_alt_next) >> 1) & 0x0f); size -= temp; @@ -390,6 +391,8 @@ char *next; struct ehci_qh *qh; + *buf = 0; + pdev = container_of (dev, struct pci_dev, dev); ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd); next = buf; @@ -412,7 +415,7 @@ } spin_unlock_irqrestore (&ehci->lock, flags); - return PAGE_SIZE - size; + return strlen (buf); } static DEVICE_ATTR (async, S_IRUGO, show_async, NULL); --- 1.49/drivers/usb/host/ehci-hcd.c Sun May 11 11:20:45 2003 +++ edited/drivers/usb/host/ehci-hcd.c Mon Jun 9 23:07:35 2003 @@ -94,7 +94,7 @@ * 2001-June Works with usb-storage and NEC EHCI on 2.4 */ -#define DRIVER_VERSION "2003-Jan-22" +#define DRIVER_VERSION "2003-Jun-09" #define DRIVER_AUTHOR "David Brownell" #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" @@ -1020,7 +1020,8 @@ if (usb_disabled()) return -ENODEV; - dbg ("block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd", + pr_debug ("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", + hcd_name, sizeof (struct ehci_qh), sizeof (struct ehci_qtd), sizeof (struct ehci_itd), sizeof (struct ehci_sitd));