# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.536   -> 1.537  
#	drivers/usb/host/ehci-q.c	1.15    -> 1.16   
#	drivers/usb/host/ehci-hcd.c	1.15    -> 1.16   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/05/11	david-b@pacbell.net	1.537
# [PATCH] -- ehci misc FIXMEs
# 
# This addresses FIXME comments in the EHCI code, notably:
# 
#     - telling the hub driver to clear up TT error state
#       (relies on the hub error recovery patch I just sent)
#     - using 64bit PCI DMA where appropriate
#     - handling BIOS handoff as neeed
# --------------------------------------------
#
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Sat May 11 22:29:32 2002
+++ b/drivers/usb/host/ehci-hcd.c	Sat May 11 22:29:32 2002
@@ -46,8 +46,6 @@
 #include <asm/system.h>
 #include <asm/unaligned.h>
 
-//#undef KERN_DEBUG
-//#define KERN_DEBUG ""
 
 /*-------------------------------------------------------------------------*/
 
@@ -55,21 +53,20 @@
  * EHCI hc_driver implementation ... experimental, incomplete.
  * Based on the final 1.0 register interface specification.
  *
- * There are lots of things to help out with here ... notably
- * everything "periodic", and of course testing with all sorts
- * of usb 2.0 devices and configurations.
- *
  * USB 2.0 shows up in upcoming www.pcmcia.org technology.
  * First was PCMCIA, like ISA; then CardBus, which is PCI.
  * Next comes "CardBay", using USB 2.0 signals.
  *
- * Contains additional contributions by:
- *	Brad Hards
- *	Rory Bolt
- *	...
+ * Contains additional contributions by: Brad Hards, Rory Bolt, ...
+ *
+ * Special thanks to Intel and VIA for providing host controllers to
+ * test this driver on, and Cypress (including In-System Design) for
+ * providing early devices for those host controllers to talk to!
  *
  * HISTORY:
  *
+ * 2002-05-11	Clear TT errors for FS/LS ctrl/bulk.  Fill in some other
+ *	missing pieces:  enabling 64bit dma, handoff from BIOS/SMM.
  * 2002-05-07	Some error path cleanups to report better errors; wmb();
  *	use non-CVS version id; better iso bandwidth claim.
  * 2002-04-19	Control/bulk/interrupt submit no longer uses giveback() on
@@ -85,7 +82,7 @@
  * 2001-June	Works with usb-storage and NEC EHCI on 2.4
  */
 
-#define DRIVER_VERSION "2002-May-07"
+#define DRIVER_VERSION "2002-May-11"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
@@ -165,6 +162,34 @@
 
 static void ehci_tasklet (unsigned long param);
 
+/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
+ * off the controller (maybe it can boot from highspeed USB disks).
+ */
+static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
+{
+	if (cap & (1 << 16)) {
+		int msec = 500;
+
+		/* request handoff to OS */
+		cap &= 1 << 24;
+		pci_write_config_dword (ehci->hcd.pdev, where, cap);
+
+		/* and wait a while for it to happen */
+		do {
+			wait_ms (10);
+			msec -= 10;
+			pci_read_config_dword (ehci->hcd.pdev, where, &cap);
+		} while ((cap & (1 << 16)) && msec);
+		if (cap & (1 << 16)) {
+			info ("BIOS handoff failed (%d, %04x)", where, cap);
+			return 1;
+		} 
+		dbg ("BIOS handoff succeeded");
+	} else
+		dbg ("BIOS handoff not needed");
+	return 0;
+}
+
 /* called by khubd or root hub init threads */
 
 static int ehci_start (struct usb_hcd *hcd)
@@ -176,10 +201,6 @@
 	u32			hcc_params;
 	u8                      tempbyte;
 
-	// FIXME:  given EHCI 0.96 or later, and a controller with
-	// the USBLEGSUP/USBLEGCTLSTS extended capability, make sure
-	// the BIOS doesn't still own this controller.
-
 	spin_lock_init (&ehci->lock);
 
 	ehci->caps = (struct ehci_caps *) hcd->regs;
@@ -187,6 +208,30 @@
 	dbg_hcs_params (ehci, "ehci_start");
 	dbg_hcc_params (ehci, "ehci_start");
 
+	hcc_params = readl (&ehci->caps->hcc_params);
+
+	/* EHCI 0.96 and later may have "extended capabilities" */
+	temp = HCC_EXT_CAPS (hcc_params);
+	while (temp) {
+		u32		cap;
+
+		pci_read_config_dword (ehci->hcd.pdev, temp, &cap);
+		dbg ("capability %04x at %02x", cap, temp);
+		switch (cap & 0xff) {
+		case 1:			/* BIOS/SMM/... handoff */
+			if (bios_handoff (ehci, temp, cap) != 0)
+				return -EOPNOTSUPP;
+			break;
+		case 0:			/* illegal reserved capability */
+			warn ("illegal capability!");
+			cap = 0;
+			/* FALLTHROUGH */
+		default:		/* unknown */
+			break;
+		}
+		temp = (cap >> 8) & 0xff;
+	}
+
 	/* cache this readonly data; minimize PCI reads */
 	ehci->hcs_params = readl (&ehci->caps->hcs_params);
 
@@ -197,7 +242,6 @@
 	ehci->periodic_size = DEFAULT_I_TDPS;
 	if ((retval = ehci_mem_init (ehci, SLAB_KERNEL)) < 0)
 		return retval;
-	hcc_params = readl (&ehci->caps->hcc_params);
 
 	/* controllers may cache some of the periodic schedule ... */
 	if (HCC_ISOC_CACHE (hcc_params)) 	// full frame cache
@@ -221,23 +265,24 @@
 	 * hcc_params controls whether ehci->regs->segment must (!!!)
 	 * be used; it constrains QH/ITD/SITD and QTD locations.
 	 * pci_pool consistent memory always uses segment zero.
+	 * streaming mappings for I/O buffers, like pci_map_single(),
+	 * can return segments above 4GB, if the device allows.
+	 *
+	 * NOTE:  layered drivers can't yet tell when we enable that,
+	 * so they can't pass this info along (like NETIF_F_HIGHDMA)
 	 */
 	if (HCC_64BIT_ADDR (hcc_params)) {
 		writel (0, &ehci->regs->segment);
-		/*
-		 * FIXME Enlarge pci_set_dma_mask() when possible.  The DMA
-		 * mapping API spec now says that'll affect only single shot
-		 * mappings, and the pci_pool data will stay safe in seg 0.
-		 * That's what we want:  no extra copies for USB transfers.
-		 */
-		info ("restricting 64bit DMA mappings to segment 0 ...");
+		if (!pci_set_dma_mask (ehci->hcd.pdev, 0xffffffffffffffffULL))
+			info ("enabled 64bit PCI DMA (DAC)");
 	}
 
 	/* clear interrupt enables, set irq latency */
 	temp = readl (&ehci->regs->command) & 0xff;
 	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
-	    log2_irq_thresh = 0;
+		log2_irq_thresh = 0;
 	temp |= 1 << (16 + log2_irq_thresh);
+	// if hc can park (ehci >= 0.96), default is 3 packets per async QH 
 	// keeping default periodic framelist size
 	temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE),
 	// Philips, Intel, and maybe others need CMD_RUN before the
@@ -433,10 +478,6 @@
 	scan_async (ehci);
 	if (ehci->next_uframe != -1)
 		scan_periodic (ehci);
-
-	// FIXME:  when nothing is connected to the root hub,
-	// turn off the RUN bit so the host can enter C3 "sleep" power
-	// saving mode; make root hub code scan memory less often.
 }
 
 /*-------------------------------------------------------------------------*/
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c	Sat May 11 22:29:32 2002
+++ b/drivers/usb/host/ehci-q.c	Sat May 11 22:29:32 2002
@@ -144,13 +144,12 @@
 					usb_pipeendpoint (pipe),
 					usb_pipeout (pipe));
 			if (urb->dev->tt && !usb_pipeint (pipe)) {
-err ("must CLEAR_TT_BUFFER, hub port %d%s addr %d ep %d",
-    urb->dev->ttport, /* devpath */
-    urb->dev->tt->multi ? "" : " (all-ports TT)",
-    urb->dev->devnum, usb_pipeendpoint (urb->pipe));
-				// FIXME something (khubd?) should make the hub
-				// CLEAR_TT_BUFFER ASAP, it's blocking other
-				// fs/ls requests... hub_tt_clear_buffer() ?
+				struct usb_device *tt = urb->dev->tt->hub;
+				dbg ("clear tt %s-%s p%d buffer, a%d ep%d",
+					tt->bus->bus_name, tt->devpath,
+    					urb->dev->ttport, urb->dev->devnum,
+    					usb_pipeendpoint (pipe));
+				usb_hub_tt_clear_buffer (urb->dev, pipe);
 			}
 		}
 	}
@@ -817,9 +816,9 @@
 		} else {
 			// dbg_qh ("empty qh", ehci, qh);
 
-// FIXME:  how handle usb_clear_halt() for an EP with queued URBs?
-// usbcore may not let us handle that cleanly...
-// likely must cancel them all first!
+			/* NOTE: we already canceled any queued URBs
+			 * when the endpoint halted.
+			 */
 
 			/* usb_clear_halt() means qh data toggle gets reset */
 			if (usb_pipebulk (urb->pipe)
