USB: EHCI: use hrtimer for interrupt QH unlink
This patch (as1577) adds hrtimer support for unlinking interrupt QHs
in ehci-hcd. The current code relies on a fixed delay of either 2 or
55 us, which is not always adequate and in any case is totally bogus.
Thanks to internal caching, the EHCI hardware may continue to access
an interrupt QH for more than a millisecond after it has been unlinked.
In fact, the EHCI spec doesn't say how long to wait before using an
unlinked interrupt QH. The patch sets the delay to 9 microframes
minimum, which ought to be adequate.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index bf06bbb..f36f1f8 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -81,6 +81,7 @@
enum ehci_hrtimer_event {
EHCI_HRTIMER_POLL_ASS, /* Poll for async schedule off */
EHCI_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */
+ EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */
EHCI_HRTIMER_NUM_EVENTS /* Must come last */
@@ -106,13 +107,16 @@
spinlock_t lock;
enum ehci_rh_state rh_state;
+ /* general schedule support */
+ unsigned scanning:1;
+ bool intr_unlinking:1;
+
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *dummy; /* For AMD quirk use */
struct ehci_qh *async_unlink;
struct ehci_qh *async_unlink_last;
struct ehci_qh *qh_scan_next;
- unsigned scanning : 1;
unsigned async_count; /* async activity count */
/* periodic schedule support */
@@ -123,6 +127,9 @@
unsigned i_thresh; /* uframes HC might cache */
union ehci_shadow *pshadow; /* mirror hw periodic table */
+ struct ehci_qh *intr_unlink;
+ struct ehci_qh *intr_unlink_last;
+ unsigned intr_unlink_cycle;
int next_uframe; /* scan periodic, start here */
unsigned periodic_count; /* periodic activity count */
unsigned uframe_periodic_max; /* max periodic time per uframe */
@@ -385,6 +392,7 @@
struct ehci_qh *unlink_next; /* next on unlink list */
unsigned long unlink_time;
+ unsigned unlink_cycle;
unsigned stamp;
u8 needs_rescan; /* Dequeue during giveback */