ChangeSet 1.1148.6.11, 2003/10/14 16:48:33-07:00, david-b@pacbell.net

[PATCH] USB: ehci-hcd, misc bugfixes

This fixes some bugs observed in the EHCI code:

 - Byte-order confusion caused the wrong address to be set
   on big-endian hardware (reported last week on PPC and
   SPARC).   That bug's been there for about a year, with
   no problem reports ... hmm.  (a while less on 2.4)

 - Used the wrong bitmask to determine max packet size
   for interrupt transfers, so they were limited to 1023
   bytes (not 1024 bytes) at high speed.

 - Because those two problems related to the masking,
   I sanity checked it and moved more of byteswapping
   to compile time.

 - Removes some oopsing in the (debug) periodic schedule
   dump, seen with patches that add more interesting
   behaviors (which folk are finally trying...).


 drivers/usb/host/ehci-dbg.c |   10 ++++++----
 drivers/usb/host/ehci-q.c   |   30 ++++++++++++++++--------------
 drivers/usb/host/ehci.h     |    1 +
 3 files changed, 23 insertions(+), 18 deletions(-)


diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
--- a/drivers/usb/host/ehci-dbg.c	Fri Oct 24 17:01:01 2003
+++ b/drivers/usb/host/ehci-dbg.c	Fri Oct 24 17:01:01 2003
@@ -471,7 +471,7 @@
 	spin_lock_irqsave (&ehci->lock, flags);
 	for (i = 0; i < ehci->periodic_size; i++) {
 		p = ehci->pshadow [i];
-		if (!p.ptr)
+		if (likely (!p.ptr))
 			continue;
 		tag = Q_NEXT_TYPE (ehci->periodic [i]);
 
@@ -491,7 +491,7 @@
 						break;
 				}
 				/* show more info the first time around */
-				if (temp == seen_count) {
+				if (temp == seen_count && p.ptr) {
 					u32	scratch = cpu_to_le32p (
 							&p.qh->hw_info1);
 
@@ -509,8 +509,10 @@
 						seen [seen_count++].qh = p.qh;
 				} else
 					temp = 0;
-				tag = Q_NEXT_TYPE (p.qh->hw_next);
-				p = p.qh->qh_next;
+				if (p.qh) {
+					tag = Q_NEXT_TYPE (p.qh->hw_next);
+					p = p.qh->qh_next;
+				}
 				break;
 			case Q_TYPE_FSTN:
 				temp = snprintf (next, size,
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c	Fri Oct 24 17:01:01 2003
+++ b/drivers/usb/host/ehci-q.c	Fri Oct 24 17:01:01 2003
@@ -189,7 +189,7 @@
 		struct ehci_qh	*qh = (struct ehci_qh *) urb->hcpriv;
 
 		/* S-mask in a QH means it's an interrupt urb */
-		if ((qh->hw_info2 & cpu_to_le32 (0x00ff)) != 0) {
+		if ((qh->hw_info2 & __constant_cpu_to_le32 (0x00ff)) != 0) {
 
 			/* ... update hc-wide periodic stats (for usbfs) */
 			hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--;
@@ -257,7 +257,7 @@
  * Chases up to qh->hw_current.  Returns number of completions called,
  * indicating how much "real" work we did.
  */
-#define HALT_BIT cpu_to_le32(QTD_STS_HALT)
+#define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
 static unsigned
 qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
 {
@@ -410,10 +410,14 @@
 
 	return count;
 }
-#undef HALT_BIT
 
 /*-------------------------------------------------------------------------*/
 
+// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+// ... and packet size, for any kind of endpoint descriptor
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+
 /*
  * reverse of qh_urb_transaction:  free a list of TDs.
  * used for cleanup after errors, before HC sees an URB's TDs.
@@ -494,7 +498,7 @@
 		token |= (1 /* "in" */ << 8);
 	/* else it's already initted to "out" pid (0 << 8) */
 
-	maxpacket = usb_maxpacket (urb->dev, urb->pipe, !is_input) & 0x03ff;
+	maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
 
 	/*
 	 * buffer gets wrapped in one or more qtds;
@@ -597,11 +601,6 @@
 // That'd mean updating how usbcore talks to HCDs. (2.5?)
 
 
-// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
-#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
-// ... and packet size, for any kind of endpoint descriptor
-#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x03ff)
-
 /*
  * Each QH holds a qtd list; a QH is used for everything except iso.
  *
@@ -766,7 +765,7 @@
 		}
 	}
 
-	qh->hw_token &= ~__constant_cpu_to_le32 (QTD_STS_HALT);
+	qh->hw_token &= ~HALT_BIT;
 
 	/* splice right after start */
 	qh->qh_next = head->qh_next;
@@ -782,6 +781,8 @@
 
 /*-------------------------------------------------------------------------*/
 
+#define	QH_ADDR_MASK	__constant_le32_to_cpu(0x7f)
+
 /*
  * For control/bulk/interrupt, return QH with these TDs appended.
  * Allocates and initializes the QH if necessary.
@@ -816,12 +817,13 @@
 		/* control qh may need patching after enumeration */
 		if (unlikely (epnum == 0)) {
 			/* set_address changes the address */
-			if (le32_to_cpu (qh->hw_info1 & 0x7f) == 0)
+			if ((qh->hw_info1 & QH_ADDR_MASK) == 0)
 				qh->hw_info1 |= cpu_to_le32 (
 						usb_pipedevice (urb->pipe));
 
 			/* for full speed, ep0 maxpacket can grow */
-			else if (!(qh->hw_info1 & cpu_to_le32 (0x3 << 12))) {
+			else if (!(qh->hw_info1
+					& __constant_cpu_to_le32 (0x3 << 12))) {
 				u32	info, max;
 
 				info = le32_to_cpu (qh->hw_info1);
@@ -835,7 +837,7 @@
 
                         /* usb_reset_device() briefly reverts to address 0 */
                         if (usb_pipedevice (urb->pipe) == 0)
-                                qh->hw_info1 &= cpu_to_le32(~0x7f);
+                                qh->hw_info1 &= ~QH_ADDR_MASK;
 		}
 
 		/* NOTE:  changing config or interface setting is not
@@ -875,7 +877,7 @@
 			 * HC is allowed to fetch the old dummy (4.10.2).
 			 */
 			token = qtd->hw_token;
-			qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
+			qtd->hw_token = HALT_BIT;
 			wmb ();
 			dummy = qh->dummy;
 
diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h	Fri Oct 24 17:01:01 2003
+++ b/drivers/usb/host/ehci.h	Fri Oct 24 17:01:01 2003
@@ -325,6 +325,7 @@
 	struct ehci_itd		*itd;		/* Q_TYPE_ITD */
 	struct ehci_sitd	*sitd;		/* Q_TYPE_SITD */
 	struct ehci_fstn	*fstn;		/* Q_TYPE_FSTN */
+	u32			*hw_next;	/* (all types) */
 	void			*ptr;
 };
 
