# 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.588 -> 1.588.1.1
# drivers/usb/host/ehci-dbg.c 1.3 -> 1.4
# drivers/usb/host/ehci.h 1.3 -> 1.4
# drivers/usb/host/ehci-sched.c 1.12 -> 1.13
# drivers/usb/core/hcd.h 1.7 -> 1.8
# drivers/usb/core/hcd.c 1.20 -> 1.21
# drivers/usb/host/ehci-hcd.c 1.17 -> 1.18
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/05/26 [EMAIL PROTECTED] 1.588.1.1
# [PATCH] ehci split interrupt transactions
#
# This patch lets more devices hook up to USB 2.0 hubs, stuff
# like keyboards, mice, hubs that hasn't worked yet:
#
# - schedules full/low speed interrupt transactions
# - tracks CSPLIT bandwidth for full/low speed interrupt
# transactions
# - moves some bus bandwidth calculation out of the EHCI code
# - makes the bandwidth calculation primitive public, and
# adds kerneldoc for it
#
# It still takes a scheduling shortcut, placing at most one
# interrupt transaction in a frame (vs potentially over 100),
# but it should do for now.
# --------------------------------------------
#
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c Tue May 28 23:49:09 2002
+++ b/drivers/usb/core/hcd.c Tue May 28 23:49:09 2002
@@ -745,12 +745,18 @@
/*-------------------------------------------------------------------------*/
-/*
- * usb_calc_bus_time:
+/**
+ * usb_calc_bus_time: approximate periodic transaction time in nanoseconds
+ * @speed: from dev->speed; USB_SPEED_{LOW,FULL,HIGH}
+ * @is_input: true iff the transaction sends data to the host
+ * @is_isoc: true for isochronous transactions, false for interrupt ones
+ * @bytecount: how many bytes in the transaction.
+ *
* Returns approximate bus time in nanoseconds for a periodic transaction.
- * See USB 2.0 spec section 5.11.3
+ * See USB 2.0 spec section 5.11.3; only periodic transfers need to be
+ * scheduled in software, this function is only used for such scheduling.
*/
-static long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
+long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
{
unsigned long tmp;
@@ -772,14 +778,18 @@
return (9107L + BW_HOST_DELAY + tmp);
}
case USB_SPEED_HIGH: /* ISOC or INTR */
- // FIXME merge from EHCI code; caller will need to handle
- // each part of a split separately.
- return 0;
+ // FIXME adjust for input vs output
+ if (isoc)
+ tmp = HS_USECS (bytecount);
+ else
+ tmp = HS_USECS_ISO (bytecount);
+ return tmp;
default:
dbg ("bogus device speed!");
return -1;
}
}
+EXPORT_SYMBOL (usb_calc_bus_time);
/*
* usb_check_bandwidth():
diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
--- a/drivers/usb/core/hcd.h Tue May 28 23:49:09 2002
+++ b/drivers/usb/core/hcd.h Tue May 28 23:49:09 2002
@@ -263,6 +263,22 @@
extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
+/*
+ * Ceiling microseconds (typical) for that many bytes at high speed
+ * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
+ * to preallocate bandwidth)
+ */
+#define USB2_HOST_DELAY 5 /* nsec, guess */
+#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \
+ + ((2083UL * (3167 + BitTime (bytes)))/1000) \
+ + USB2_HOST_DELAY)
+#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \
+ + ((2083UL * (3167 + BitTime (bytes)))/1000) \
+ + USB2_HOST_DELAY)
+
+extern long usb_calc_bus_time (int speed, int is_input,
+ int isoc, int bytecount);
+
/*-------------------------------------------------------------------------*/
extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
diff -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
--- a/drivers/usb/host/ehci-dbg.c Tue May 28 23:49:09 2002
+++ b/drivers/usb/host/ehci-dbg.c Tue May 28 23:49:09 2002
@@ -102,8 +102,8 @@
#ifdef DEBUG
-#if 0
-static void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+static void __attribute__((__unused__))
+dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
{
dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label,
qh, qh->hw_info1, qh->hw_info2,
@@ -117,15 +117,13 @@
qh->hw_buf [4]);
}
}
-#endif
static const char *const fls_strings [] =
{ "1024", "512", "256", "??" };
#else
-#if 0
-static inline void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {}
-#endif
+static inline void __attribute__((__unused__))
+dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {}
#endif /* DEBUG */
/* functions have the "wrong" filename when they're output... */
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c Tue May 28 23:49:09 2002
+++ b/drivers/usb/host/ehci-hcd.c Tue May 28 23:49:09 2002
@@ -65,6 +65,7 @@
*
* HISTORY:
*
+ * 2002-05-24 Preliminary FS/LS interrupts, using scheduling shortcuts
* 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();
@@ -82,7 +83,7 @@
* 2001-June Works with usb-storage and NEC EHCI on 2.4
*/
-#define DRIVER_VERSION "2002-May-11"
+#define DRIVER_VERSION "2002-May-24"
#define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
@@ -622,7 +623,10 @@
return 0;
case PIPE_INTERRUPT:
- intr_deschedule (ehci, urb->start_frame, qh, urb->interval);
+ intr_deschedule (ehci, urb->start_frame, qh,
+ (urb->dev->speed == USB_SPEED_HIGH)
+ ? urb->interval
+ : (urb->interval << 3));
if (ehci->hcd.state == USB_STATE_HALT)
urb->status = -ESHUTDOWN;
qh_completions (ehci, qh, 1);
diff -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
--- a/drivers/usb/host/ehci-sched.c Tue May 28 23:49:09 2002
+++ b/drivers/usb/host/ehci-sched.c Tue May 28 23:49:09 2002
@@ -33,19 +33,6 @@
* or with "USB On The Go" additions to USB 2.0 ...)
*/
-/*
- * Ceiling microseconds (typical) for that many bytes at high speed
- * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
- * to preallocate bandwidth)
- */
-#define EHCI_HOST_DELAY 5 /* nsec, guess */
-#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \
- + ((2083UL * (3167 + BitTime (bytes)))/1000) \
- + EHCI_HOST_DELAY)
-#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \
- + ((2083UL * (3167 + BitTime (bytes)))/1000) \
- + EHCI_HOST_DELAY)
-
static int ehci_get_frame (struct usb_hcd *hcd);
/*-------------------------------------------------------------------------*/
@@ -124,6 +111,9 @@
/* is it in the S-mask? */
if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe))
usecs += q->qh->usecs;
+ /* ... or C-mask? */
+ if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe)))
+ usecs += q->qh->c_usecs;
q = &q->qh->qh_next;
break;
case Q_TYPE_FSTN:
@@ -273,6 +263,12 @@
unsigned period,
unsigned usecs
) {
+ /* complete split running into next frame?
+ * given FSTN support, we could sometimes check...
+ */
+ if (uframe >= 8)
+ return 0;
+
/*
* 80% periodic == 100 usec/uframe available
* convert "usecs we need" to "max already claimed"
@@ -284,6 +280,8 @@
// FIXME delete when intr_submit handles non-empty queues
// this gives us a one intr/frame limit (vs N/uframe)
+// ... and also lets us avoid tracking split transactions
+// that might collide at a given TT/hub.
if (ehci->pshadow [frame].ptr)
return 0;
@@ -305,20 +303,54 @@
int mem_flags
) {
unsigned epnum, period;
- unsigned short usecs;
+ unsigned short usecs, c_usecs, gap_uf;
unsigned long flags;
struct ehci_qh *qh;
struct hcd_dev *dev;
+ int is_input;
int status = 0;
- /* get endpoint and transfer data */
+ /* get endpoint and transfer/schedule data */
epnum = usb_pipeendpoint (urb->pipe);
- if (usb_pipein (urb->pipe))
+ is_input = usb_pipein (urb->pipe);
+ if (is_input)
epnum |= 0x10;
- if (urb->dev->speed != USB_SPEED_HIGH) {
- dbg ("no intr/tt scheduling yet");
- status = -ENOSYS;
- goto done;
+
+ /*
+ * HS interrupt transfers are simple -- only one microframe. FS/LS
+ * interrupt transfers involve a SPLIT in one microframe and CSPLIT
+ * sometime later. We need to know how much time each will be
+ * needed in each microframe and, for FS/LS, how many microframes
+ * separate the two in the best case.
+ */
+ usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
+ urb->transfer_buffer_length);
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+ gap_uf = 0;
+ c_usecs = 0;
+
+ /* FIXME handle HS periods of less than 1 frame. */
+ period = urb->interval >> 3;
+ if (period < 1) {
+ dbg ("intr period %d uframes, NYET!", urb->interval);
+ status = -EINVAL;
+ goto done;
+ }
+ } else {
+ /* gap is a function of full/low speed transfer times */
+ gap_uf = 1 + usb_calc_bus_time (urb->dev->speed, is_input, 0,
+ urb->transfer_buffer_length) / (125 * 1000);
+
+ /* FIXME this just approximates SPLIT/CSPLIT times */
+ if (is_input) { // SPLIT, gap, CSPLIT+DATA
+ c_usecs = usecs + HS_USECS (0);
+ usecs = HS_USECS (1);
+ } else { // SPLIT+DATA, gap, CSPLIT
+ usecs = usecs + HS_USECS (1);
+ c_usecs = HS_USECS (0);
+ }
+
+ period = urb->interval;
}
/*
@@ -339,16 +371,6 @@
goto done;
}
- usecs = HS_USECS (urb->transfer_buffer_length);
-
- /* FIXME handle HS periods of less than 1 frame. */
- period = urb->interval >> 3;
- if (period < 1) {
- dbg ("intr period %d uframes, NYET!", urb->interval);
- status = -EINVAL;
- goto done;
- }
-
spin_lock_irqsave (&ehci->lock, flags);
/* get the qh (must be empty and idle) */
@@ -392,6 +414,7 @@
qh->hw_next = EHCI_LIST_END;
qh->usecs = usecs;
+ qh->c_usecs = c_usecs;
urb->hcpriv = qh_get (qh);
status = -ENOSPC;
@@ -399,18 +422,47 @@
/* pick a set of schedule slots, link the QH into them */
do {
int uframe;
+ u32 c_mask = 0;
/* pick a set of slots such that all uframes have
* enough periodic bandwidth available.
- *
- * FIXME for TT splits, need uframes for start and end.
- * FSTNs can put end into next frame (uframes 0 or 1).
*/
frame--;
for (uframe = 0; uframe < 8; uframe++) {
if (check_period (ehci, frame, uframe,
- period, usecs) != 0)
- break;
+ period, usecs) == 0)
+ continue;
+
+ /* If this is a split transaction, check the
+ * bandwidth available for the completion
+ * too. check both best and worst case gaps:
+ * worst case is SPLIT near uframe end, and
+ * CSPLIT near start ... best is vice versa.
+ * Difference can be almost two uframe times.
+ *
+ * FIXME don't even bother unless we know
+ * this TT is idle in that uframe ... right
+ * now we know only one interrupt transfer
+ * will be scheduled per frame, so we don't
+ * need to update/check TT state when we
+ * schedule a split (QH, SITD, or FSTN).
+ *
+ * FIXME ehci 0.96 and above can use FSTNs
+ */
+ if (!c_usecs)
+ break;
+ if (check_period (ehci, frame,
+ uframe + gap_uf,
+ period, c_usecs) == 0)
+ continue;
+ if (check_period (ehci, frame,
+ uframe + gap_uf + 1,
+ period, c_usecs) == 0)
+ continue;
+
+ c_mask = 0x03 << (8 + uframe + gap_uf);
+ c_mask = cpu_to_le32 (c_mask);
+ break;
}
if (uframe == 8)
continue;
@@ -419,13 +471,14 @@
urb->start_frame = frame;
status = 0;
- /* set S-frame mask */
- qh->hw_info2 |= cpu_to_le32 (1 << uframe);
+ /* reset S-frame and (maybe) C-frame masks */
+ qh->hw_info2 &= ~0xffff;
+ qh->hw_info2 |= cpu_to_le32 (1 << uframe) | c_mask;
// dbg_qh ("Schedule INTR qh", ehci, qh);
/* stuff into the periodic schedule */
qh->qh_state = QH_STATE_LINKED;
- vdbg ("qh %p usecs %d period %d starting %d.%d",
+ vdbg ("qh %p usecs %d period %d.0 starting %d.%d",
qh, qh->usecs, period, frame, uframe);
do {
if (unlikely (ehci->pshadow [frame].ptr != 0)) {
@@ -443,7 +496,8 @@
} while (frame < ehci->periodic_size);
/* update bandwidth utilization records (for usbfs) */
- usb_claim_bandwidth (urb->dev, urb, usecs/period, 0);
+ usb_claim_bandwidth (urb->dev, urb,
+ (usecs + c_usecs) / period, 0);
/* maybe enable periodic schedule processing */
if (!ehci->periodic_urbs++)
@@ -557,6 +611,7 @@
u32 buf1;
unsigned i, epnum, maxp, multi;
unsigned length;
+ int is_input;
itd->hw_next = EHCI_LIST_END;
itd->urb = urb;
@@ -578,7 +633,8 @@
* as encoded in the ep descriptor's maxpacket field
*/
epnum = usb_pipeendpoint (urb->pipe);
- if (usb_pipein (urb->pipe)) {
+ is_input = usb_pipein (urb->pipe);
+ if (is_input) {
maxp = urb->dev->epmaxpacketin [epnum];
buf1 = (1 << 11);
} else {
@@ -598,7 +654,7 @@
urb->iso_frame_desc [index].length);
return -ENOSPC;
}
- itd->usecs = HS_USECS_ISO (length);
+ itd->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 1, length);
/* "plus" info in low order bits of buffer pointers */
itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum);
@@ -919,17 +975,9 @@
return flags;
/*
- * For now, always give the urb back to the driver ... expect it
- * to submit a new urb (or resubmit this), and to have another
- * already queued when un-interrupted transfers are needed.
- * No, that's not what OHCI or UHCI are now doing.
- *
- * FIXME Revisit the ISO URB model. It's cleaner not to have all
- * the special case magic, but it'd be faster to reuse existing
- * ITD/DMA setup and schedule state. Easy to dma_sync/complete(),
- * then either reschedule or, if unlinking, free and giveback().
- * But we can't overcommit like the full and low speed HCs do, and
- * there's no clean way to report an error when rescheduling...
+ * Always give the urb back to the driver ... expect it to submit
+ * a new urb (or resubmit this), and to have another already queued
+ * when un-interrupted transfers are needed.
*
* NOTE that for now we don't accelerate ISO unlinks; they just
* happen according to the current schedule. Means a delay of
diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h Tue May 28 23:49:09 2002
+++ b/drivers/usb/host/ehci.h Tue May 28 23:49:09 2002
@@ -288,14 +288,11 @@
atomic_t refcount;
unsigned short usecs; /* intr bandwidth */
+ unsigned short c_usecs; /* ... split completion bw */
short qh_state;
#define QH_STATE_LINKED 1 /* HC sees this */
#define QH_STATE_UNLINK 2 /* HC may still see this */
#define QH_STATE_IDLE 3 /* HC doesn't see this */
-
-#ifdef EHCI_SOFT_RETRIES
- int retries;
-#endif
} __attribute__ ((aligned (32)));
/*-------------------------------------------------------------------------*/
@@ -360,6 +357,9 @@
union ehci_shadow sitd_next; /* ptr to periodic q entry */
struct urb *urb;
dma_addr_t buf_dma; /* buffer address */
+
+ unsigned short usecs; /* start bandwidth */
+ unsigned short c_usecs; /* completion bandwidth */
} __attribute__ ((aligned (32)));
/*-------------------------------------------------------------------------*/
_______________________________________________________________
Don't miss the 2002 Sprint PCS Application Developer's Conference
August 25-28 in Las Vegas -- http://devcon.sprintpcs.com/adp/index.cfm
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel