Here's another one -- the EHCI driver fixes that are now in Linus' tree, and are mostly in 2.4.21-ac1 (but that's missing an important one-liner). It goes on top of the patches Greg just sent.
The "meat" of this patch is fixing a handful of logic bugs in the qh_completions() code which usually did a good job of covering for each other.
Please merge into 2.4.22-pre with the other USB changes.
- Dave
--- 1.14/drivers/usb/host/ehci-dbg.c Mon May 12 22:25:05 2003
+++ edited/drivers/usb/host/ehci-dbg.c Thu Jun 12 10:30:21 2003
@@ -125,19 +125,28 @@
#ifdef DEBUG
static 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\n", label, qtd,
+ cpu_to_le32p (&qtd->hw_next),
+ cpu_to_le32p (&qtd->hw_alt_next),
+ cpu_to_le32p (&qtd->hw_token),
+ cpu_to_le32p (&qtd->hw_buf [0]));
+ if (qtd->hw_buf [1])
+ ehci_dbg (ehci, " p1=%08x p2=%08x p3=%08x p4=%08x\n",
+ cpu_to_le32p (&qtd->hw_buf [1]),
+ cpu_to_le32p (&qtd->hw_buf [2]),
+ cpu_to_le32p (&qtd->hw_buf [3]),
+ cpu_to_le32p (&qtd->hw_buf [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 qh %p n%08x info %x %x qtd %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__))
@@ -294,8 +303,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 '/';
@@ -317,11 +325,14 @@
char *next = *nextp;
char mark;
- mark = token_mark (qh->hw_token);
+ if (qh->hw_qtd_next == EHCI_LIST_END) /* NEC does this */
+ mark = '@';
+ else
+ mark = token_mark (qh->hw_token);
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 */
}
@@ -334,7 +345,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;
@@ -400,6 +411,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;
@@ -422,7 +435,7 @@
}
spin_unlock_irqrestore (&ehci->lock, flags);
- return PAGE_SIZE - size;
+ return strlen (buf);
}
static DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
@@ -558,7 +571,8 @@
/* Capability Registers */
i = readw (&ehci->caps->hci_version);
temp = snprintf (next, size,
- "EHCI %x.%02x, hcd state %d (version " DRIVER_VERSION ")\n",
+ "%s\nEHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n",
+ pdev->dev.name,
i >> 8, i & 0x0ff, ehci->hcd.state);
size -= temp;
next += temp;
--- 1.22/drivers/usb/host/ehci-hcd.c Mon May 19 08:27:49 2003
+++ edited/drivers/usb/host/ehci-hcd.c Thu Jun 19 13:54:16 2003
@@ -42,11 +42,7 @@
#include <linux/usb.h>
#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
#include "../hcd.h"
-#else
-#include "../core/hcd.h"
-#endif
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -95,11 +91,11 @@
* 2001-June Works with usb-storage and NEC EHCI on 2.4
*/
-#define DRIVER_VERSION "2003-Jan-22"
+#define DRIVER_VERSION "2003-Jun-19/2.4"
#define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
-static const char hcd_name [] = "ehci-hcd";
+static const char hcd_name [] = "ehci_hcd";
// #define EHCI_VERBOSE_DEBUG
@@ -437,7 +433,7 @@
pci_set_mwi (ehci->hcd.pdev);
/* clear interrupt enables, set irq latency */
- temp = readl (&ehci->regs->command) & 0xff;
+ temp = readl (&ehci->regs->command) & 0x0fff;
if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
log2_irq_thresh = 0;
temp |= 1 << (16 + log2_irq_thresh);
@@ -1046,8 +1042,8 @@
static int __init init (void)
{
- dbg (DRIVER_INFO);
- 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));
--- 1.22/drivers/usb/host/ehci-q.c Wed Jun 11 19:03:02 2003
+++ edited/drivers/usb/host/ehci-q.c Thu Jun 19 13:51:52 2003
@@ -88,7 +88,6 @@
static inline void
qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
{
- qh->hw_current = 0;
qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
qh->hw_alt_next = EHCI_LIST_END;
@@ -99,8 +98,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,
@@ -314,16 +311,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;
@@ -331,10 +327,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.
@@ -393,12 +392,20 @@
qh->qh_state = state;
/* update qh after fault cleanup */
- if (unlikely ((HALT_BIT & qh->hw_token) != 0)) {
- qh_update (ehci, qh,
- list_empty (&qh->qtd_list)
- ? qh->dummy
- : list_entry (qh->qtd_list.next,
- struct ehci_qtd, qtd_list));
+ if (unlikely (stopped != 0)
+ /* some EHCI 0.95 impls will overlay dummy qtds */
+ || qh->hw_qtd_next == EHCI_LIST_END) {
+ if (list_empty (&qh->qtd_list))
+ end = qh->dummy;
+ else {
+ end = list_entry (qh->qtd_list.next,
+ struct ehci_qtd, qtd_list);
+ /* first qtd may already be partially processed */
+ if (cpu_to_le32 (end->qtd_dma) == qh->hw_current)
+ end = 0;
+ }
+ if (end)
+ qh_update (ehci, qh, end);
}
return count;
@@ -718,12 +725,11 @@
/* NOTE: if (PIPE_INTERRUPT) { scheduler sets s-mask } */
- /* init as halted, toggle clear, advance to dummy */
+ /* init as live, toggle clear, advance to dummy */
qh->qh_state = QH_STATE_IDLE;
qh->hw_info1 = cpu_to_le32 (info1);
qh->hw_info2 = cpu_to_le32 (info2);
qh_update (ehci, qh, qh->dummy);
- qh->hw_token = cpu_to_le32 (QTD_STS_HALT);
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
return qh;
}
@@ -828,9 +834,8 @@
}
}
- /* 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...
+ /* NOTE: changing config or interface setting is not
+ * supported without the 2.5 endpoint disable logic.
*/
/* usb_clear_halt() means qh data toggle gets reset */
--- 1.14/drivers/usb/host/ehci.h Mon May 12 22:25:05 2003
+++ edited/drivers/usb/host/ehci.h Sat Jun 14 17:29:11 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)
/*-------------------------------------------------------------------------*/
