# 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.518   -> 1.519  
#	drivers/usb/host/ohci-hcd.c	1.16    -> 1.17   
#	drivers/usb/host/ohci-mem.c	1.6     -> 1.7    
#	drivers/usb/host/ohci-dbg.c	1.5     -> 1.6    
#	drivers/usb/host/ohci-q.c	1.10    -> 1.11   
#	drivers/usb/host/ohci.h	1.7     -> 1.8    
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/06/18	david-b@pacbell.net	1.519
# [PATCH] ohci misc fixes
# 
# This patch applies on top of the other two (for init problems):
# 
# - Uses time to balance interrupt load, not number of transfers.
#    One 8-byte lowspeed transfer costs as much as ten same-size
#    at full speed ... previous code could overcommit branches.
# - Shrinks the code a smidgeon, mostly in the submit path.
# - Updates comments, remove some magic numbers, etc.
# - Adds some debug dump routines for EDs and TDs, which can
#    be rather helpful when debugging!
# - Lays ground work for a "shadow" <linux/list.h> TD queue
#    (but doesn't enlarge the TD or ED on 32bit cpus)
# 
# I'm not sure anyone would have run into that time/balance
# issue, though some folk have talked about hooking up lots
# of lowspeed devices and that would have made trouble.
# --------------------------------------------
#
diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
--- a/drivers/usb/host/ohci-dbg.c	Tue Jun 18 17:01:58 2002
+++ b/drivers/usb/host/ohci-dbg.c	Tue Jun 18 17:01:58 2002
@@ -74,9 +74,9 @@
 static inline struct ed *
 dma_to_ed (struct ohci_hcd *hc, dma_addr_t ed_dma);
 
-#ifdef OHCI_VERBOSE_DEBUG
 /* print non-empty branches of the periodic ed tree */
-void ohci_dump_periodic (struct ohci_hcd *ohci, char *label)
+static void __attribute__ ((unused))
+ohci_dump_periodic (struct ohci_hcd *ohci, char *label)
 {
 	int i, j;
 	u32 *ed_p;
@@ -101,7 +101,6 @@
 		printk (KERN_DEBUG "%s, ohci %s, empty periodic schedule\n",
 				label, ohci->hcd.self.bus_name);
 }
-#endif
 
 static void ohci_dump_intr_mask (char *label, __u32 mask)
 {
@@ -241,6 +240,97 @@
 	ohci_dump_roothub (controller, 1);
 }
 
+static void ohci_dump_td (char *label, struct td *td)
+{
+	u32	tmp = le32_to_cpup (&td->hwINFO);
+
+	dbg ("%s td %p; urb %p index %d; hw next td %08x",
+		label, td,
+		td->urb, td->index,
+		le32_to_cpup (&td->hwNextTD));
+	if ((tmp & TD_ISO) == 0) {
+		char	*toggle, *pid;
+		u32	cbp, be;
+
+		switch (tmp & TD_T) {
+		case TD_T_DATA0: toggle = "DATA0"; break;
+		case TD_T_DATA1: toggle = "DATA1"; break;
+		case TD_T_TOGGLE: toggle = "(CARRY)"; break;
+		default: toggle = "(?)"; break;
+		}
+		switch (tmp & TD_DP) {
+		case TD_DP_SETUP: pid = "SETUP"; break;
+		case TD_DP_IN: pid = "IN"; break;
+		case TD_DP_OUT: pid = "OUT"; break;
+		default: pid = "(bad pid)"; break;
+		}
+		dbg ("     info %08x CC=%x %s DI=%d %s %s", tmp,
+			TD_CC_GET(tmp), /* EC, */ toggle,
+			(tmp & TD_DI) >> 21, pid,
+			(tmp & TD_R) ? "R" : "");
+		cbp = le32_to_cpup (&td->hwCBP);
+		be = le32_to_cpup (&td->hwBE);
+		dbg ("     cbp %08x be %08x (len %d)", cbp, be,
+			cbp ? (be + 1 - cbp) : 0);
+	} else {
+		unsigned	i;
+		dbg ("     info %08x CC=%x DI=%d START=%04x", tmp,
+			TD_CC_GET(tmp), /* FC, */
+			(tmp & TD_DI) >> 21,
+			tmp & 0x0000ffff);
+		dbg ("     bp0 %08x be %08x",
+			le32_to_cpup (&td->hwCBP) & ~0x0fff,
+			le32_to_cpup (&td->hwBE));
+		for (i = 0; i < MAXPSW; i++) {
+			dbg ("       psw [%d] = %2x", i,
+				le16_to_cpu (td->hwPSW [i]));
+		}
+	}
+}
+
+/* caller MUST own hcd spinlock if verbose is set! */
+static void __attribute__((unused))
+ohci_dump_ed (struct ohci_hcd *ohci, char *label, struct ed *ed, int verbose)
+{
+	u32	tmp = ed->hwINFO;
+	char	*type = "";
+
+	dbg ("%s: %s, ed %p state 0x%x type %d; next ed %08x",
+		ohci->hcd.self.bus_name, label,
+		ed, ed->state, ed->type,
+		le32_to_cpup (&ed->hwNextED));
+	switch (tmp & (ED_IN|ED_OUT)) {
+	case ED_OUT: type = "-OUT"; break;
+	case ED_IN: type = "-IN"; break;
+	/* else from TDs ... control */
+	}
+	dbg ("  info %08x MAX=%d%s%s%s EP=%d%s DEV=%d", le32_to_cpu (tmp),
+		0x0fff & (le32_to_cpu (tmp) >> 16),
+		(tmp & ED_ISO) ? " ISO" : "",
+		(tmp & ED_SKIP) ? " SKIP" : "",
+		(tmp & ED_LOWSPEED) ? " LOW" : "",
+		0x000f & (le32_to_cpu (tmp) >> 7),
+		type,
+		0x007f & le32_to_cpu (tmp));
+	dbg ("  tds: head %08x%s%s tail %08x%s",
+		tmp = le32_to_cpup (&ed->hwHeadP),
+		(ed->hwHeadP & ED_H) ? " HALT" : "",
+		(ed->hwHeadP & ED_C) ? " CARRY" : "",
+		le32_to_cpup (&ed->hwTailP),
+		verbose ? "" : " (not listing)");
+	if (verbose) {
+		struct list_head	*tmp;
+
+		/* use ed->td_list because HC concurrently modifies
+		 * hwNextTD as it accumulates ed_donelist.
+		 */
+		list_for_each (tmp, &ed->td_list) {
+			struct td		*td;
+			td = list_entry (tmp, struct td, td_list);
+			ohci_dump_td ("  ->", td);
+		}
+	}
+}
 
 #endif
 
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 18 17:01:58 2002
+++ b/drivers/usb/host/ohci-hcd.c	Tue Jun 18 17:01:58 2002
@@ -100,7 +100,7 @@
  *	- lots more testing!!
  */
 
-#define DRIVER_VERSION "2002-Jun-10"
+#define DRIVER_VERSION "2002-Jun-15"
 #define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
 #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
 
@@ -145,8 +145,8 @@
 	urb_print (urb, "SUB", usb_pipein (pipe));
 #endif
 	
-	/* every endpoint has a ed, locate and fill it */
-	if (! (ed = ep_add_ed (urb->dev, pipe, urb->interval, 1, mem_flags)))
+	/* every endpoint has a ed, locate and maybe (re)initialize it */
+	if (! (ed = ed_get (ohci, urb->dev, pipe, urb->interval)))
 		return -ENOMEM;
 
 	/* for the private part of the URB we need the number of TDs (size) */
@@ -498,6 +498,7 @@
 	struct ohci_regs	*regs = ohci->regs;
  	int			ints; 
 
+	/* we can eliminate a (slow) readl() if _only_ WDH caused this irq */
 	if ((ohci->hcca->done_head != 0)
 			&& ! (le32_to_cpup (&ohci->hcca->done_head) & 0x01)) {
 		ints =  OHCI_INTR_WDH;
diff -Nru a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
--- a/drivers/usb/host/ohci-mem.c	Tue Jun 18 17:01:58 2002
+++ b/drivers/usb/host/ohci-mem.c	Tue Jun 18 17:01:58 2002
@@ -221,6 +221,7 @@
 	ed = pci_pool_alloc (hc->ed_cache, mem_flags, &dma);
 	if (ed) {
 		memset (ed, 0, sizeof (*ed));
+		INIT_LIST_HEAD (&ed->td_list);
 		ed->dma = dma;
 		/* hash it for later reverse mapping */
 		if (!hash_add_ed (hc, ed, mem_flags)) {
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 18 17:01:58 2002
+++ b/drivers/usb/host/ohci-q.c	Tue Jun 18 17:01:58 2002
@@ -131,8 +131,9 @@
 
 /* search for the right branch to insert an interrupt ed into the int tree 
  * do some load balancing;
- * returns the branch and 
- * sets the interval to interval = 2^integer (ld (interval))
+ * returns the branch
+ * FIXME allow for failure, when there's no bandwidth left;
+ * and consider iso loads too
  */
 static int ep_int_balance (struct ohci_hcd *ohci, int interval, int load)
 {
@@ -152,19 +153,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-/*  2^int ( ld (inter)) */
-
-static int ep_2_n_interval (int inter)
-{	
-	int	i;
-
-	for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++)
-		continue;
-	return 1 << i;
-}
-
-/*-------------------------------------------------------------------------*/
-
 /* the int tree is a binary tree 
  * in order to process it sequentially the indexes of the branches have
  * to be mapped the mapping reverses the bits of a word of num_bits length
@@ -230,8 +218,7 @@
 
 	case PIPE_INTERRUPT:
 		load = ed->intriso.intr_info.int_load;
-		interval = ep_2_n_interval (ed->intriso.intr_info.int_period);
-		ed->interval = interval;
+		interval = ed->interval;
 		int_branch = ep_int_balance (ohci, interval, load);
 		ed->intriso.intr_info.int_branch = int_branch;
 
@@ -301,6 +288,7 @@
  * just the link to the ed is unlinked.
  * the link from the ed still points to another operational ed or 0
  * so the HC can eventually finish the processing of the unlinked ed
+ * caller guarantees the ED has no active TDs.
  */
 static int start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed) 
 {
@@ -387,84 +375,99 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* (re)init an endpoint; this _should_ be done once at the
- * usb_set_configuration command, but the USB stack is a bit stateless
- * so we do it at every transaction.
- * if the state of the ed is ED_NEW then a dummy td is added and the
- * state is changed to ED_UNLINK
- * in all other cases the state is left unchanged
- * the ed info fields are set even though most of them should
- * not change
+/* get and maybe (re)init an endpoint. init _should_ be done only as part
+ * of usb_set_configuration() or usb_set_interface() ... but the USB stack
+ * isn't very stateful, so we re-init whenever the HC isn't looking.
  */
-static struct ed *ep_add_ed (
+static struct ed *ed_get (
+	struct ohci_hcd		*ohci,
 	struct usb_device	*udev,
 	unsigned int		pipe,
-	int			interval,
-	int			load,
-	int			mem_flags
+	int			interval
 ) {
-   	struct ohci_hcd		*ohci = hcd_to_ohci (udev->bus->hcpriv);
+	int			is_out = !usb_pipein (pipe);
+	int			type = usb_pipetype (pipe);
+	int			bus_msecs = 0;
 	struct hcd_dev		*dev = (struct hcd_dev *) udev->hcpriv;
-	struct td		*td;
 	struct ed		*ed; 
 	unsigned		ep;
 	unsigned long		flags;
 
-	spin_lock_irqsave (&ohci->lock, flags);
-
 	ep = usb_pipeendpoint (pipe) << 1;
-	if (!usb_pipecontrol (pipe) && usb_pipeout (pipe))
+	if (type != PIPE_CONTROL && is_out)
 		ep |= 1;
+	if (type == PIPE_INTERRUPT)
+		bus_msecs = usb_calc_bus_time (udev->speed, !is_out, 0,
+			usb_maxpacket (udev, pipe, is_out)) / 1000;
+
+	spin_lock_irqsave (&ohci->lock, flags);
+
 	if (!(ed = dev->ep [ep])) {
 		ed = ed_alloc (ohci, SLAB_ATOMIC);
 		if (!ed) {
 			/* out of memory */
-			spin_unlock_irqrestore (&ohci->lock, flags);
-			return NULL;
+			goto done;
 		}
 		dev->ep [ep] = ed;
 	}
 
 	if (ed->state & ED_URB_DEL) {
 		/* pending unlink request */
-		spin_unlock_irqrestore (&ohci->lock, flags);
-		return NULL;
+		ed = 0;
+		goto done;
 	}
 
 	if (ed->state == ED_NEW) {
+		struct td		*td;
+
 		ed->hwINFO = ED_SKIP;
   		/* dummy td; end of td list for ed */
 		td = td_alloc (ohci, SLAB_ATOMIC);
  		if (!td) {
 			/* out of memory */
-			spin_unlock_irqrestore (&ohci->lock, flags);
-			return NULL;
+			ed = 0;
+			goto done;
 		}
 		ed->dummy = td;
 		ed->hwTailP = cpu_to_le32 (td->td_dma);
 		ed->hwHeadP = ed->hwTailP;	/* ED_C, ED_H zeroed */
 		ed->state = ED_UNLINK;
-		ed->type = usb_pipetype (pipe);
+		ed->type = type;
 	}
 
-// 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
-			| (usb_pipeisoc (pipe)? 0x8000: 0)
-			| (usb_pipecontrol (pipe)
-				? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) 
-			| (udev->speed == USB_SPEED_LOW) << 13
-			| usb_maxpacket (udev, pipe, usb_pipeout (pipe))
-				<< 16);
-
-  	if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
-  		ed->intriso.intr_info.int_period = interval;
-  		ed->intriso.intr_info.int_load = load;
-  	}
+	/* FIXME:  Don't do this without knowing it's safe to clobber this
+	 * state/mode info.  Currently the upper layers don't support such
+	 * guarantees; we're lucky changing config/altsetting is rare.
+	 */
+  	if (ed->state == ED_UNLINK) {
+		u32	info;
 
+		info = usb_pipedevice (pipe);
+		info |= (ep >> 1) << 7;
+		info |= usb_maxpacket (udev, pipe, is_out) << 16;
+		info = cpu_to_le32 (info);
+		if (udev->speed == USB_SPEED_LOW)
+			info |= ED_LOWSPEED;
+		/* control transfers store pids in tds */
+		if (type != PIPE_CONTROL) {
+			info |= is_out ? ED_OUT : ED_IN;
+			if (type == PIPE_ISOCHRONOUS)
+				info |= ED_ISO;
+			if (type == PIPE_INTERRUPT) {
+				ed->intriso.intr_info.int_load = bus_msecs;
+				if (interval > 32)
+					interval = 32;
+			}
+		}
+		ed->hwINFO = info;
+
+		/* value ignored except on periodic EDs, where
+		 * we know it's already a power of 2
+		 */
+		ed->interval = interval;
+	}
+
+done:
 	spin_unlock_irqrestore (&ohci->lock, flags);
 	return ed; 
 }
@@ -736,8 +739,8 @@
 		urb->iso_frame_desc [td->index].status = cc_to_error [cc];
 
 		if (cc != 0)
-			dbg ("  urb %p iso TD %d len %d CC %d",
-				urb, td->index, dlen, cc);
+			dbg ("  urb %p iso TD %p (%d) len %d CC %d",
+				urb, td, 1 + td->index, dlen, cc);
 
 	/* BULK, INT, CONTROL ... drivers see aggregate length/status,
 	 * except that "setup" bytes aren't counted and "short" transfers
@@ -776,9 +779,13 @@
 					- td->data_dma;
 		}
 
+#ifdef VERBOSE_DEBUG
 		if (cc != 0)
-			dbg ("  urb %p TD %d CC %d, len=%d",
-				urb, td->index, cc, urb->actual_length);
+			dbg ("  urb %p TD %p (%d) CC %d, len=%d/%d",
+				urb, td, 1 + td->index, cc,
+				urb->actual_length,
+				urb->transfer_buffer_length);
+#endif
   	}
 }
 
@@ -812,8 +819,8 @@
 				if (urb_priv && ((td_list->index + 1)
 						< urb_priv->length)) {
 #ifdef OHCI_VERBOSE_DEBUG
-					dbg ("urb %p TD %d of %d, patch ED",
-						td_list->urb,
+					dbg ("urb %p TD %p (%d/%d), patch ED",
+						td_list->urb, td_list,
 						1 + td_list->index,
 						urb_priv->length);
 #endif
diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
--- a/drivers/usb/host/ohci.h	Tue Jun 18 17:01:58 2002
+++ b/drivers/usb/host/ohci.h	Tue Jun 18 17:01:58 2002
@@ -19,7 +19,7 @@
 #define ED_SKIP		__constant_cpu_to_le32(1 << 14)
 #define ED_LOWSPEED	__constant_cpu_to_le32(1 << 13)
 #define ED_OUT		__constant_cpu_to_le32(0x01 << 11)
-#define ED_IN		__constant_cpu_to_le32(0x10 << 11)
+#define ED_IN		__constant_cpu_to_le32(0x02 << 11)
 	__u32			hwTailP;	/* tail of TD list */
 	__u32			hwHeadP;	/* head of TD list */
 #define ED_C		__constant_cpu_to_le32(0x02)	/* toggle carry */
@@ -30,24 +30,24 @@
 	dma_addr_t		dma;		/* addr of ED */
 	struct ed		*ed_prev;	/* for non-interrupt EDs */
 	struct td		*dummy;
+	struct list_head	td_list;	/* "shadow list" of our TDs */
+
+	u8			state;		/* ED_{NEW,UNLINK,OPER} */
+#define ED_NEW 		0x00		/* unused, no dummy td */
+#define ED_UNLINK 	0x01		/* dummy td, maybe linked to hc */
+#define ED_OPER		0x02		/* dummy td, _is_ linked to hc */
+#define ED_URB_DEL  	0x08		/* for unlinking; masked in */
 
 	u8			type; 		/* PIPE_{BULK,...} */
-	u8			interval;	/* interrupt, isochronous */
+	u16			interval;	/* interrupt, isochronous */
 	union {
 		struct intr_info {		/* interrupt */
-			u8	int_period;
 			u8	int_branch;
 			u8	int_load; 
 		} intr_info;
 		u16		last_iso;	/* isochronous */
 	} intriso;
 
-	u8			state;		/* ED_{NEW,UNLINK,OPER} */
-#define ED_NEW 		0x00		/* unused, no dummy td */
-#define ED_UNLINK 	0x01		/* dummy td, maybe linked to hc */
-#define ED_OPER		0x02		/* dummy td, _is_ linked to hc */
-#define ED_URB_DEL  	0x08		/* for unlinking; masked in */
-
 	/* HC may see EDs on rm_list until next frame (frame_no == tick) */
 	u16			tick;
 	struct ed		*ed_rm_list;
@@ -108,6 +108,8 @@
 
 	dma_addr_t	td_dma;		/* addr of this TD */
 	dma_addr_t	data_dma;	/* addr of data it points to */
+
+	struct list_head td_list;	/* "shadow list", TDs on same ED */
 } __attribute__ ((aligned(32)));	/* c/b/i need 16; only iso needs 32 */
 
 #define TD_MASK	((u32)~0x1f)		/* strip hw status in low addr bits */
