diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2012-07-11 11:22:26 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-07-16 19:54:25 -0400 |
commit | df2022553dd8d34d49e16c19d851ea619438f0ef (patch) | |
tree | 9850c967e0fbee1cb99e900c2e60a0ad50b528da /drivers/usb/host/ehci.h | |
parent | 314466101c6ae14f6f5db8a86eda1509ba2c02a8 (diff) |
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>
Diffstat (limited to 'drivers/usb/host/ehci.h')
-rw-r--r-- | drivers/usb/host/ehci.h | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index bf06bbb77ba4..f36f1f85d7fd 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
@@ -81,6 +81,7 @@ enum ehci_rh_state { | |||
81 | enum ehci_hrtimer_event { | 81 | enum ehci_hrtimer_event { |
82 | EHCI_HRTIMER_POLL_ASS, /* Poll for async schedule off */ | 82 | EHCI_HRTIMER_POLL_ASS, /* Poll for async schedule off */ |
83 | EHCI_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */ | 83 | EHCI_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */ |
84 | EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */ | ||
84 | EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ | 85 | EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ |
85 | EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */ | 86 | EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */ |
86 | EHCI_HRTIMER_NUM_EVENTS /* Must come last */ | 87 | EHCI_HRTIMER_NUM_EVENTS /* Must come last */ |
@@ -106,13 +107,16 @@ struct ehci_hcd { /* one per controller */ | |||
106 | spinlock_t lock; | 107 | spinlock_t lock; |
107 | enum ehci_rh_state rh_state; | 108 | enum ehci_rh_state rh_state; |
108 | 109 | ||
110 | /* general schedule support */ | ||
111 | unsigned scanning:1; | ||
112 | bool intr_unlinking:1; | ||
113 | |||
109 | /* async schedule support */ | 114 | /* async schedule support */ |
110 | struct ehci_qh *async; | 115 | struct ehci_qh *async; |
111 | struct ehci_qh *dummy; /* For AMD quirk use */ | 116 | struct ehci_qh *dummy; /* For AMD quirk use */ |
112 | struct ehci_qh *async_unlink; | 117 | struct ehci_qh *async_unlink; |
113 | struct ehci_qh *async_unlink_last; | 118 | struct ehci_qh *async_unlink_last; |
114 | struct ehci_qh *qh_scan_next; | 119 | struct ehci_qh *qh_scan_next; |
115 | unsigned scanning : 1; | ||
116 | unsigned async_count; /* async activity count */ | 120 | unsigned async_count; /* async activity count */ |
117 | 121 | ||
118 | /* periodic schedule support */ | 122 | /* periodic schedule support */ |
@@ -123,6 +127,9 @@ struct ehci_hcd { /* one per controller */ | |||
123 | unsigned i_thresh; /* uframes HC might cache */ | 127 | unsigned i_thresh; /* uframes HC might cache */ |
124 | 128 | ||
125 | union ehci_shadow *pshadow; /* mirror hw periodic table */ | 129 | union ehci_shadow *pshadow; /* mirror hw periodic table */ |
130 | struct ehci_qh *intr_unlink; | ||
131 | struct ehci_qh *intr_unlink_last; | ||
132 | unsigned intr_unlink_cycle; | ||
126 | int next_uframe; /* scan periodic, start here */ | 133 | int next_uframe; /* scan periodic, start here */ |
127 | unsigned periodic_count; /* periodic activity count */ | 134 | unsigned periodic_count; /* periodic activity count */ |
128 | unsigned uframe_periodic_max; /* max periodic time per uframe */ | 135 | unsigned uframe_periodic_max; /* max periodic time per uframe */ |
@@ -385,6 +392,7 @@ struct ehci_qh { | |||
385 | struct ehci_qh *unlink_next; /* next on unlink list */ | 392 | struct ehci_qh *unlink_next; /* next on unlink list */ |
386 | 393 | ||
387 | unsigned long unlink_time; | 394 | unsigned long unlink_time; |
395 | unsigned unlink_cycle; | ||
388 | unsigned stamp; | 396 | unsigned stamp; |
389 | 397 | ||
390 | u8 needs_rescan; /* Dequeue during giveback */ | 398 | u8 needs_rescan; /* Dequeue during giveback */ |