# 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.447.16.5 -> 1.447.16.6
#	drivers/usb/host/ohci-hcd.c	1.13    -> 1.14   
#	drivers/usb/host/ohci-q.c	1.9     -> 1.10   
#	drivers/usb/host/ohci.h	1.6     -> 1.7    
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/06/10	david-b@pacbell.net	1.447.16.6
# [PATCH] ohci-hcd, speedups+misc
# 
# - Delays or eliminates some IRQs  It'll mostly affect control
#    or iso transfers, which typically have multiple TDs per URB,
#    by making only the last TD generate an IRQ.
# 
# - Shortens some of the submit path that needs to run with
#    IRQs disabled ... no need to use the dma_to_td hashtable.
#    (Of course that path is still pretty long...)
# 
# - Gets rid of case where the ED state was confused ... now
#    there's only one such state, not two.
# --------------------------------------------
#
diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c	Tue Jun 11 14:58:55 2002
+++ b/drivers/usb/host/ohci-hcd.c	Tue Jun 11 14:58:55 2002
@@ -100,7 +100,7 @@
  *	- lots more testing!!
  */
 
-#define DRIVER_VERSION "2002-Jun-01"
+#define DRIVER_VERSION "2002-Jun-10"
 #define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
 #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
 
@@ -307,7 +307,6 @@
 	spin_lock_irqsave (&ohci->lock, flags);
 	for (i = 0; i < 32; i++) {
 		struct ed	*ed = dev->ep [i];
-		struct td	*tdTailP;
 
 		if (!ed)
 			continue;
@@ -319,10 +318,7 @@
 		case ED_NEW:
 			break;
 		case ED_UNLINK:
-			tdTailP = dma_to_td (ohci,
-				le32_to_cpup (&ed->hwTailP) & 0xfffffff0);
-			td_free (ohci, tdTailP); /* free dummy td */
-			hash_free_ed (ohci, ed);
+			td_free (ohci, ed->dummy);
 			break;
 
 		case ED_OPER:
diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c	Tue Jun 11 14:58:55 2002
+++ b/drivers/usb/host/ohci-q.c	Tue Jun 11 14:58:55 2002
@@ -440,14 +440,16 @@
 			spin_unlock_irqrestore (&ohci->lock, flags);
 			return NULL;
 		}
+		ed->dummy = td;
 		ed->hwTailP = cpu_to_le32 (td->td_dma);
-		ed->hwHeadP = ed->hwTailP;	
+		ed->hwHeadP = ed->hwTailP;	/* ED_C, ED_H zeroed */
 		ed->state = ED_UNLINK;
 		ed->type = usb_pipetype (pipe);
 	}
 
-// FIXME:  don't do this if it's linked to the HC,
-// we might clobber data toggle or other state ...
+// FIXME:  don't do this if it's linked to the HC, or without knowing it's
+// safe to clobber state/mode info tied to (previous) config/altsetting.
+// (but dev0/ep0, used by set_address, must get clobbered)
 
 	ed->hwINFO = cpu_to_le32 (usb_pipedevice (pipe)
 			| usb_pipeendpoint (pipe) << 7
@@ -523,27 +525,31 @@
 	dma_addr_t data, int len,
 	struct urb *urb, int index)
 {
-	volatile struct td	*td, *td_pt;
+	struct td		*td, *td_pt;
 	urb_priv_t		*urb_priv = urb->hcpriv;
+	int			is_iso = info & TD_ISO;
 
 	if (index >= urb_priv->length) {
 		err ("internal OHCI error: TD index > length");
 		return;
 	}
 
-#if 0
-	/* no interrupt needed except for URB's last TD */
+	/* aim for only one interrupt per urb.  mostly applies to control
+	 * and iso; other urbs rarely need more than one TD per urb.
+	 *
+	 * NOTE: could delay interrupts even for the last TD, and get fewer
+	 * interrupts ... increasing per-urb latency by sharing interrupts.
+	 */
 	if (index != (urb_priv->length - 1))
-		info |= TD_DI;
-#endif
+		info |= is_iso ? TD_DI_SET (7) : TD_DI_SET (1);
 
 	/* use this td as the next dummy */
 	td_pt = urb_priv->td [index];
 	td_pt->hwNextTD = 0;
 
 	/* fill the old dummy TD */
-	td = urb_priv->td [index] = dma_to_td (ohci,
-			le32_to_cpup (&urb_priv->ed->hwTailP));
+	td = urb_priv->td [index] = urb_priv->ed->dummy;
+	urb_priv->ed->dummy = td_pt;
 
 	td->ed = urb_priv->ed;
 	td->next_dl_td = NULL;
@@ -554,7 +560,7 @@
 		data = 0;
 
 	td->hwINFO = cpu_to_le32 (info);
-	if ((td->ed->type) == PIPE_ISOCHRONOUS) {
+	if (is_iso) {
 		td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);
 		td->ed->intriso.last_iso = info & 0xffff;
 	} else {
@@ -901,6 +907,7 @@
 		 *     [a2] some (earlier) URBs still linked, re-enable
 		 * (b) finishing ED unlink
 		 *     [b1] no URBs queued, ED is truly idle now
+		 *          ... we could set state ED_NEW and free dummy
 		 *     [b2] URBs now queued, link ED back into schedule
 		 * right now we only have (a)
 		 */
@@ -910,9 +917,6 @@
 		if (tdHeadP == tdTailP) {
 			if (ed->state == ED_OPER)
 				start_ed_unlink (ohci, ed);
-			td_free (ohci, tdTailP);
-			ed->hwINFO = ED_SKIP;
-			ed->state = ED_NEW;
 		} else
 			ed->hwINFO &= ~ED_SKIP;
 
diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
--- a/drivers/usb/host/ohci.h	Tue Jun 11 14:58:55 2002
+++ b/drivers/usb/host/ohci.h	Tue Jun 11 14:58:55 2002
@@ -29,6 +29,7 @@
 	/* rest are purely for the driver's use */
 	dma_addr_t		dma;		/* addr of ED */
 	struct ed		*ed_prev;	/* for non-interrupt EDs */
+	struct td		*dummy;
 
 	u8			type; 		/* PIPE_{BULK,...} */
 	u8			interval;	/* interrupt, isochronous */
@@ -63,24 +64,33 @@
 struct td {
 	/* first fields are hardware-specified, le32 */
 	__u32		hwINFO;		/* transfer info bitmask */
+
+	/* hwINFO bits for both general and iso tds: */
 #define TD_CC       0xf0000000			/* condition code */
 #define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
 //#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
+#define TD_DI       0x00E00000			/* frames before interrupt */
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+	/* these two bits are available for definition/use by HCDs in both
+	 * general and iso tds ... others are available for only one type
+	 */
+//#define TD____	    0x00020000
+#define TD_ISO	    0x00010000			/* copy of ED_ISO */
+
+	/* hwINFO bits for general tds: */
 #define TD_EC       0x0C000000			/* error count */
 #define TD_T        0x03000000			/* data toggle state */
 #define TD_T_DATA0  0x02000000				/* DATA0 */
 #define TD_T_DATA1  0x03000000				/* DATA1 */
 #define TD_T_TOGGLE 0x00000000				/* uses ED_C */
-#define TD_DI       0x00E00000			/* frames before interrupt */
-//#define TD_DI_SET(X) (((X) & 0x07)<< 21)
 #define TD_DP       0x00180000			/* direction/pid */
 #define TD_DP_SETUP 0x00000000			/* SETUP pid */
 #define TD_DP_IN    0x00100000				/* IN pid */
 #define TD_DP_OUT   0x00080000				/* OUT pid */
 							/* 0x00180000 rsvd */
 #define TD_R        0x00040000			/* round: short packets OK? */
-					/* bits 0x1ffff are defined by HCD */
-#define TD_ISO	    0x00010000			/* copy of ED_ISO */
+
+	/* (no hwINFO #defines yet for iso tds) */
 
   	__u32		hwCBP;		/* Current Buffer Pointer (or 0) */
   	__u32		hwNextTD;	/* Next TD Pointer */
