Various folk have been having problems with certain full speed ISO transfers
through USB 2.0 transaction translating hubs ... where "certain transfers"
starts at about 192 data bytes per transfer, and goes up. (And thus it
involves more than one microframe to transfer the data ... and some messy
microframe scheduling needs to be done.)
If you have a USB audio device, like speakers, you might be able to hear
this problem. Or maybe not; not all systems show the issue. And even
those which do show it won't necessarily show it consistently; this has
all the symptoms of a load-dependant race (or a scheduling bug).
This email attaches two separate patches that affect code in this area, and
I'd like folk who have this problem to try them (singly, and if neither
affects things then combinging them) and report the results:
- tdi-periodic.patch ... updated version of a patch from Craig Nadler
that helped on some of his hardware, but doesn't seem to have helped
some of the other folk experiencing it.
- ehci-0307.patch ... just adds a read barrier, matching the high speed
ISO code.
If either make a difference I suspect I'll want to change the periodic
schedule scanning to handle corresponding issues that could crop up with
periodic interrupt transfers.
- Dave
This is a revised version of a patch to address an issue seen with some
full speed isochronous TDs. It makes the EHCI driver's scanning of the
periodic schedule handle the current microframe a bit differently, by
rescanning it in cases where the controller might not yet have been able
to write back the results before the host tries to read them.
The revisions are to address minor changes to the HCD glue layer; to avoid
rescanning in several cases where it's not needed; and to simplify the
"don't advance the scan" exit case (still needs work).
From: Craig Nadler <[EMAIL PROTECTED]>
--- 1.59/drivers/usb/host/ehci-sched.c 2005-02-07 16:28:43 -08:00
+++ edited/drivers/usb/host/ehci-sched.c 2005-03-07 10:22:57 -08:00
@@ -1848,6 +1848,13 @@
#endif /* USB_EHCI_SPLIT_ISO */
+/* true iff this a completion in this uframe may be pending */
+static inline int sitd_chk(struct ehci_sitd *sitd, unsigned uframe)
+{
+ return uframe < 8
+ && (le32_to_cpu(sitd->hw_results) & (1 << (uframe + 8)));
+}
+
/*-------------------------------------------------------------------------*/
static void
@@ -1874,8 +1881,11 @@
union ehci_shadow q, *q_p;
__le32 type, *hw_p;
unsigned uframes;
+ unsigned uncompleted_itd = 0;
- /* don't scan past the live uframe */
+ /* don't scan past the current/live uframe; we
+ * must sometimes rescan that one for iso tds.
+ */
frame = now_uframe >> 3;
if (frame == (clock >> 3))
uframes = now_uframe & 0x07;
@@ -1931,6 +1941,9 @@
hw_p = &q.itd->hw_next;
type = Q_NEXT_TYPE (q.itd->hw_next);
q = *q_p;
+ /* maybe rescan this uframe */
+ uncompleted_itd = uncompleted_itd
+ || (uf == uframes);
break;
}
if (uf != 8)
@@ -1949,6 +1962,9 @@
case Q_TYPE_SITD:
if ((q.sitd->hw_results & SITD_ACTIVE)
&& live) {
+ /* maybe rescan this uframe */
+ uncompleted_itd = uncompleted_itd
+ || sitd_chk(q.sitd, uframes);
q_p = &q.sitd->sitd_next;
hw_p = &q.sitd->hw_next;
type = Q_NEXT_TYPE (q.sitd->hw_next);
@@ -1973,6 +1989,13 @@
if (unlikely (modified))
goto restart;
}
+
+ /* stop if some ITD or SITD in this current/live uframe needs
+ * to be rescanned later
+ */
+ if (uncompleted_itd
+ && HCD_IS_RUNNING (ehci_to_hcd(ehci)->state))
+ break;
/* stop when we catch up to the HC */
This adds a read barrier to scanning of the full speed (split) ISO TDs,
matching the barrier for the high speed ones.
From: David Brownell <[EMAIL PROTECTED]>
--- 1.59/drivers/usb/host/ehci-sched.c 2005-02-07 16:28:43 -08:00
+++ edited/drivers/usb/host/ehci-sched.c 2005-03-07 10:33:51 -08:00
@@ -1947,6 +1947,7 @@
q = *q_p;
break;
case Q_TYPE_SITD:
+ rmb ();
if ((q.sitd->hw_results & SITD_ACTIVE)
&& live) {
q_p = &q.sitd->sitd_next;