OK, here's a patch that I suspect will help a lot ... I ran a version
of it on 2.4.21-pre4 (plus ehci24-0201 and the usb-storage patch that
Tom Collins recently forwarded) and it sped up "hdparm -tT" on a VT8235
by a factor of four (!). It worked on a VT6202 too (which I usually see
just on 2.5), but not as fast.
What the patch does is make the driver avoid a qh reactivation path that
seems to be slow and troublesome on those VIA controllers. Easy to avoid:
use the timer, it already handles such delayed scans. The cost is some
wasted memory accesses (DMA reads) from the controller, for up to 5msec
(HZ/200).
The patch is against 2.5.60 but should apply to that latest 2.4 code.
- Dave
--- ./drivers/usb-dist/host/ehci-q.c Tue Feb 11 08:37:47 2003
+++ ./drivers/usb/host/ehci-q.c Sun Feb 16 15:49:55 2003
@@ -800,6 +800,7 @@
&& !usb_pipecontrol (urb->pipe)) {
/* "never happens": drivers do stall cleanup right */
if (qh->qh_state != QH_STATE_IDLE
+ && !list_empty (&qh->qtd_list)
&& qh->qh_state != QH_STATE_COMPLETING)
ehci_warn (ehci, "clear toggle dev%d "
"ep%d%s: not idle\n",
@@ -1014,6 +1015,7 @@
scan_async (struct ehci_hcd *ehci, struct pt_regs *regs)
{
struct ehci_qh *qh;
+ int unlink_delay = 0;
if (!++(ehci->stamp))
ehci->stamp++;
@@ -1040,17 +1042,25 @@
}
}
- /* unlink idle entries, reducing HC PCI usage as
- * well as HCD schedule-scanning costs.
- *
- * FIXME don't unlink idle entries so quickly; it
- * can penalize (common) half duplex protocols.
+ /* unlink idle entries, reducing HC PCI usage as well
+ * as HCD schedule-scanning costs. delay for any qh
+ * we just scanned, there's a not-unusual case that it
+ * doesn't stay idle for long.
+ * (plus, avoids some kind of re-activation race.)
*/
- if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
- start_unlink_async (ehci, qh);
+ if (list_empty (&qh->qtd_list)) {
+ if (qh->stamp == ehci->stamp)
+ unlink_delay = 1;
+ else if (!ehci->reclaim) {
+ start_unlink_async (ehci, qh);
+ unlink_delay = 0;
+ }
}
qh = qh->qh_next.qh;
} while (qh);
}
+
+ if (unlink_delay && !timer_pending (&ehci->watchdog))
+ mod_timer (&ehci->watchdog, jiffies + EHCI_WATCHDOG_JIFFIES/2);
}