aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci.h
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-07-11 11:23:00 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-16 19:56:47 -0400
commit569b394f53f0abd177cc665c9b4ace89e3f4c7fb (patch)
tree030ce9c94e724f713155ffacc7caab7f459e9b96 /drivers/usb/host/ehci.h
parent361aabf395e4a23cf554cf4ec0c0c6963b8beb01 (diff)
USB: EHCI: always scan each interrupt QH
This patch (as1585) fixes a bug in ehci-hcd's scheme for scanning interrupt QHs. Currently a single routine takes care of scanning everything on the periodic schedule. Whenever an interrupt occurs, it scans all isochronous and interrupt URBs scheduled for frames that have elapsed since the last scan. This has two disadvantages. The first is relatively minor: An interrupt QH is likely to end up getting scanned multiple times, particularly if the last scan was not fairly recent. (The current code avoids this by maintaining a periodic_stamp in each interrupt QH.) The second is more serious. The periodic schedule wraps around. If the last scan occurred during frame N, and the next scan occurs when the schedule has gone through an entire cycle and is back at frame N, the scanning code won't look at any frames other than N. Consequently it won't see any QHs that completed during frame N-1 or earlier. The patch replaces the entire frame-based approach for scanning interrupt QHs with a new routine using a list-based approach, the same as for async QHs. This has a slight disadvantage, because it means that all interrupt QHs have to be scanned every time. But it is more robust than the current approach. 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.h8
1 files changed, 5 insertions, 3 deletions
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index c462d52ac575..08637183aad0 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -117,6 +117,7 @@ struct ehci_hcd { /* one per controller */
117 bool need_rescan:1; 117 bool need_rescan:1;
118 bool intr_unlinking:1; 118 bool intr_unlinking:1;
119 bool async_unlinking:1; 119 bool async_unlinking:1;
120 struct ehci_qh *qh_scan_next;
120 121
121 /* async schedule support */ 122 /* async schedule support */
122 struct ehci_qh *async; 123 struct ehci_qh *async;
@@ -124,7 +125,6 @@ struct ehci_hcd { /* one per controller */
124 struct ehci_qh *async_unlink; 125 struct ehci_qh *async_unlink;
125 struct ehci_qh *async_unlink_last; 126 struct ehci_qh *async_unlink_last;
126 struct ehci_qh *async_iaa; 127 struct ehci_qh *async_iaa;
127 struct ehci_qh *qh_scan_next;
128 unsigned async_unlink_cycle; 128 unsigned async_unlink_cycle;
129 unsigned async_count; /* async activity count */ 129 unsigned async_count; /* async activity count */
130 130
@@ -133,6 +133,7 @@ struct ehci_hcd { /* one per controller */
133 unsigned periodic_size; 133 unsigned periodic_size;
134 __hc32 *periodic; /* hw periodic table */ 134 __hc32 *periodic; /* hw periodic table */
135 dma_addr_t periodic_dma; 135 dma_addr_t periodic_dma;
136 struct list_head intr_qh_list;
136 unsigned i_thresh; /* uframes HC might cache */ 137 unsigned i_thresh; /* uframes HC might cache */
137 138
138 union ehci_shadow *pshadow; /* mirror hw periodic table */ 139 union ehci_shadow *pshadow; /* mirror hw periodic table */
@@ -140,6 +141,8 @@ struct ehci_hcd { /* one per controller */
140 struct ehci_qh *intr_unlink_last; 141 struct ehci_qh *intr_unlink_last;
141 unsigned intr_unlink_cycle; 142 unsigned intr_unlink_cycle;
142 int next_uframe; /* scan periodic, start here */ 143 int next_uframe; /* scan periodic, start here */
144 unsigned intr_count; /* intr activity count */
145 unsigned isoc_count; /* isoc activity count */
143 unsigned periodic_count; /* periodic activity count */ 146 unsigned periodic_count; /* periodic activity count */
144 unsigned uframe_periodic_max; /* max periodic time per uframe */ 147 unsigned uframe_periodic_max; /* max periodic time per uframe */
145 148
@@ -176,7 +179,6 @@ struct ehci_hcd { /* one per controller */
176 179
177 struct timer_list watchdog; 180 struct timer_list watchdog;
178 unsigned long actions; 181 unsigned long actions;
179 unsigned periodic_stamp;
180 unsigned random_frame; 182 unsigned random_frame;
181 unsigned long next_statechange; 183 unsigned long next_statechange;
182 ktime_t last_periodic_enable; 184 ktime_t last_periodic_enable;
@@ -381,11 +383,11 @@ struct ehci_qh {
381 dma_addr_t qh_dma; /* address of qh */ 383 dma_addr_t qh_dma; /* address of qh */
382 union ehci_shadow qh_next; /* ptr to qh; or periodic */ 384 union ehci_shadow qh_next; /* ptr to qh; or periodic */
383 struct list_head qtd_list; /* sw qtd list */ 385 struct list_head qtd_list; /* sw qtd list */
386 struct list_head intr_node; /* list of intr QHs */
384 struct ehci_qtd *dummy; 387 struct ehci_qtd *dummy;
385 struct ehci_qh *unlink_next; /* next on unlink list */ 388 struct ehci_qh *unlink_next; /* next on unlink list */
386 389
387 unsigned unlink_cycle; 390 unsigned unlink_cycle;
388 unsigned stamp;
389 391
390 u8 needs_rescan; /* Dequeue during giveback */ 392 u8 needs_rescan; /* Dequeue during giveback */
391 u8 qh_state; 393 u8 qh_state;