aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
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
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')
-rw-r--r--drivers/usb/host/ehci-hcd.c7
-rw-r--r--drivers/usb/host/ehci-q.c3
-rw-r--r--drivers/usb/host/ehci-sched.c96
-rw-r--r--drivers/usb/host/ehci-timer.c7
-rw-r--r--drivers/usb/host/ehci.h8
5 files changed, 71 insertions, 50 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index f6cf1d178107..c13dad8a8503 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -410,8 +410,10 @@ static void ehci_work (struct ehci_hcd *ehci)
410 ehci->need_rescan = false; 410 ehci->need_rescan = false;
411 if (ehci->async_count) 411 if (ehci->async_count)
412 scan_async(ehci); 412 scan_async(ehci);
413 if (ehci->next_uframe != -1) 413 if (ehci->intr_count > 0)
414 scan_periodic (ehci); 414 scan_intr(ehci);
415 if (ehci->isoc_count > 0)
416 scan_isoc(ehci);
415 if (ehci->need_rescan) 417 if (ehci->need_rescan)
416 goto rescan; 418 goto rescan;
417 ehci->scanning = false; 419 ehci->scanning = false;
@@ -509,6 +511,7 @@ static int ehci_init(struct usb_hcd *hcd)
509 * periodic_size can shrink by USBCMD update if hcc_params allows. 511 * periodic_size can shrink by USBCMD update if hcc_params allows.
510 */ 512 */
511 ehci->periodic_size = DEFAULT_I_TDPS; 513 ehci->periodic_size = DEFAULT_I_TDPS;
514 INIT_LIST_HEAD(&ehci->intr_qh_list);
512 INIT_LIST_HEAD(&ehci->cached_itd_list); 515 INIT_LIST_HEAD(&ehci->cached_itd_list);
513 INIT_LIST_HEAD(&ehci->cached_sitd_list); 516 INIT_LIST_HEAD(&ehci->cached_sitd_list);
514 517
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index bae931767825..c9c7f7b3b7db 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -322,7 +322,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
322 * 322 *
323 * It's a bug for qh->qh_state to be anything other than 323 * It's a bug for qh->qh_state to be anything other than
324 * QH_STATE_IDLE, unless our caller is scan_async() or 324 * QH_STATE_IDLE, unless our caller is scan_async() or
325 * scan_periodic(). 325 * scan_intr().
326 */ 326 */
327 state = qh->qh_state; 327 state = qh->qh_state;
328 qh->qh_state = QH_STATE_COMPLETING; 328 qh->qh_state = QH_STATE_COMPLETING;
@@ -832,7 +832,6 @@ qh_make (
832 is_input, 0, 832 is_input, 0,
833 hb_mult(maxp) * max_packet(maxp))); 833 hb_mult(maxp) * max_packet(maxp)));
834 qh->start = NO_FRAME; 834 qh->start = NO_FRAME;
835 qh->stamp = ehci->periodic_stamp;
836 835
837 if (urb->dev->speed == USB_SPEED_HIGH) { 836 if (urb->dev->speed == USB_SPEED_HIGH) {
838 qh->c_usecs = 0; 837 qh->c_usecs = 0;
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 11b2f21d7ac1..263b542985c0 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -569,7 +569,10 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
569 ? ((qh->usecs + qh->c_usecs) / qh->period) 569 ? ((qh->usecs + qh->c_usecs) / qh->period)
570 : (qh->usecs * 8); 570 : (qh->usecs * 8);
571 571
572 list_add(&qh->intr_node, &ehci->intr_qh_list);
573
572 /* maybe enable periodic schedule processing */ 574 /* maybe enable periodic schedule processing */
575 ++ehci->intr_count;
573 enable_periodic(ehci); 576 enable_periodic(ehci);
574} 577}
575 578
@@ -614,6 +617,11 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
614 /* qh->qh_next still "live" to HC */ 617 /* qh->qh_next still "live" to HC */
615 qh->qh_state = QH_STATE_UNLINK; 618 qh->qh_state = QH_STATE_UNLINK;
616 qh->qh_next.ptr = NULL; 619 qh->qh_next.ptr = NULL;
620
621 if (ehci->qh_scan_next == qh)
622 ehci->qh_scan_next = list_entry(qh->intr_node.next,
623 struct ehci_qh, intr_node);
624 list_del(&qh->intr_node);
617} 625}
618 626
619static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) 627static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
@@ -683,6 +691,7 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
683 } 691 }
684 692
685 /* maybe turn off periodic schedule */ 693 /* maybe turn off periodic schedule */
694 --ehci->intr_count;
686 disable_periodic(ehci); 695 disable_periodic(ehci);
687} 696}
688 697
@@ -920,6 +929,35 @@ done_not_linked:
920 return status; 929 return status;
921} 930}
922 931
932static void scan_intr(struct ehci_hcd *ehci)
933{
934 struct ehci_qh *qh;
935
936 list_for_each_entry_safe(qh, ehci->qh_scan_next, &ehci->intr_qh_list,
937 intr_node) {
938 rescan:
939 /* clean any finished work for this qh */
940 if (!list_empty(&qh->qtd_list)) {
941 int temp;
942
943 /*
944 * Unlinks could happen here; completion reporting
945 * drops the lock. That's why ehci->qh_scan_next
946 * always holds the next qh to scan; if the next qh
947 * gets unlinked then ehci->qh_scan_next is adjusted
948 * in qh_unlink_periodic().
949 */
950 temp = qh_completions(ehci, qh);
951 if (unlikely(qh->needs_rescan ||
952 (list_empty(&qh->qtd_list) &&
953 qh->qh_state == QH_STATE_LINKED)))
954 start_unlink_intr(ehci, qh);
955 else if (temp != 0)
956 goto rescan;
957 }
958 }
959}
960
923/*-------------------------------------------------------------------------*/ 961/*-------------------------------------------------------------------------*/
924 962
925/* ehci_iso_stream ops work with both ITD and SITD */ 963/* ehci_iso_stream ops work with both ITD and SITD */
@@ -1450,6 +1488,10 @@ iso_stream_schedule (
1450 urb->start_frame = stream->next_uframe; 1488 urb->start_frame = stream->next_uframe;
1451 if (!stream->highspeed) 1489 if (!stream->highspeed)
1452 urb->start_frame >>= 3; 1490 urb->start_frame >>= 3;
1491
1492 /* Make sure scan_isoc() sees these */
1493 if (ehci->isoc_count == 0)
1494 ehci->next_uframe = now;
1453 return 0; 1495 return 0;
1454 1496
1455 fail: 1497 fail:
@@ -1608,6 +1650,7 @@ static void itd_link_urb(
1608 urb->hcpriv = NULL; 1650 urb->hcpriv = NULL;
1609 1651
1610 timer_action (ehci, TIMER_IO_WATCHDOG); 1652 timer_action (ehci, TIMER_IO_WATCHDOG);
1653 ++ehci->isoc_count;
1611 enable_periodic(ehci); 1654 enable_periodic(ehci);
1612} 1655}
1613 1656
@@ -1688,9 +1731,11 @@ itd_complete (
1688 ehci_urb_done(ehci, urb, 0); 1731 ehci_urb_done(ehci, urb, 0);
1689 retval = true; 1732 retval = true;
1690 urb = NULL; 1733 urb = NULL;
1734
1735 --ehci->isoc_count;
1691 disable_periodic(ehci); 1736 disable_periodic(ehci);
1692 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
1693 1737
1738 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
1694 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { 1739 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
1695 if (ehci->amd_pll_fix == 1) 1740 if (ehci->amd_pll_fix == 1)
1696 usb_amd_quirk_pll_enable(); 1741 usb_amd_quirk_pll_enable();
@@ -2008,6 +2053,7 @@ static void sitd_link_urb(
2008 urb->hcpriv = NULL; 2053 urb->hcpriv = NULL;
2009 2054
2010 timer_action (ehci, TIMER_IO_WATCHDOG); 2055 timer_action (ehci, TIMER_IO_WATCHDOG);
2056 ++ehci->isoc_count;
2011 enable_periodic(ehci); 2057 enable_periodic(ehci);
2012} 2058}
2013 2059
@@ -2074,9 +2120,11 @@ sitd_complete (
2074 ehci_urb_done(ehci, urb, 0); 2120 ehci_urb_done(ehci, urb, 0);
2075 retval = true; 2121 retval = true;
2076 urb = NULL; 2122 urb = NULL;
2123
2124 --ehci->isoc_count;
2077 disable_periodic(ehci); 2125 disable_periodic(ehci);
2078 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
2079 2126
2127 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
2080 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) { 2128 if (ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs == 0) {
2081 if (ehci->amd_pll_fix == 1) 2129 if (ehci->amd_pll_fix == 1)
2082 usb_amd_quirk_pll_enable(); 2130 usb_amd_quirk_pll_enable();
@@ -2165,8 +2213,7 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
2165 2213
2166/*-------------------------------------------------------------------------*/ 2214/*-------------------------------------------------------------------------*/
2167 2215
2168static void 2216static void scan_isoc(struct ehci_hcd *ehci)
2169scan_periodic (struct ehci_hcd *ehci)
2170{ 2217{
2171 unsigned now_uframe, frame, clock, clock_frame, mod; 2218 unsigned now_uframe, frame, clock, clock_frame, mod;
2172 unsigned modified; 2219 unsigned modified;
@@ -2189,7 +2236,6 @@ scan_periodic (struct ehci_hcd *ehci)
2189 ehci->clock_frame = clock_frame; 2236 ehci->clock_frame = clock_frame;
2190 clock &= mod - 1; 2237 clock &= mod - 1;
2191 clock_frame = clock >> 3; 2238 clock_frame = clock >> 3;
2192 ++ehci->periodic_stamp;
2193 2239
2194 for (;;) { 2240 for (;;) {
2195 union ehci_shadow q, *q_p; 2241 union ehci_shadow q, *q_p;
@@ -2208,36 +2254,10 @@ restart:
2208 2254
2209 while (q.ptr != NULL) { 2255 while (q.ptr != NULL) {
2210 unsigned uf; 2256 unsigned uf;
2211 union ehci_shadow temp;
2212 int live; 2257 int live;
2213 2258
2214 live = (ehci->rh_state >= EHCI_RH_RUNNING); 2259 live = (ehci->rh_state >= EHCI_RH_RUNNING);
2215 switch (hc32_to_cpu(ehci, type)) { 2260 switch (hc32_to_cpu(ehci, type)) {
2216 case Q_TYPE_QH:
2217 /* handle any completions */
2218 temp.qh = q.qh;
2219 type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
2220 q = q.qh->qh_next;
2221 if (temp.qh->stamp != ehci->periodic_stamp) {
2222 modified = qh_completions(ehci, temp.qh);
2223 if (!modified)
2224 temp.qh->stamp = ehci->periodic_stamp;
2225 if (unlikely(list_empty(&temp.qh->qtd_list) ||
2226 temp.qh->needs_rescan))
2227 start_unlink_intr(ehci, temp.qh);
2228 }
2229 break;
2230 case Q_TYPE_FSTN:
2231 /* for "save place" FSTNs, look at QH entries
2232 * in the previous frame for completions.
2233 */
2234 if (q.fstn->hw_prev != EHCI_LIST_END(ehci)) {
2235 ehci_dbg(ehci,
2236 "ignoring completions from FSTNs\n");
2237 }
2238 type = Q_NEXT_TYPE(ehci, q.fstn->hw_next);
2239 q = q.fstn->fstn_next;
2240 break;
2241 case Q_TYPE_ITD: 2261 case Q_TYPE_ITD:
2242 /* If this ITD is still active, leave it for 2262 /* If this ITD is still active, leave it for
2243 * later processing ... check the next entry. 2263 * later processing ... check the next entry.
@@ -2319,12 +2339,17 @@ restart:
2319 ehci_dbg(ehci, "corrupt type %d frame %d shadow %p\n", 2339 ehci_dbg(ehci, "corrupt type %d frame %d shadow %p\n",
2320 type, frame, q.ptr); 2340 type, frame, q.ptr);
2321 // BUG (); 2341 // BUG ();
2342 /* FALL THROUGH */
2343 case Q_TYPE_QH:
2344 case Q_TYPE_FSTN:
2345 /* End of the iTDs and siTDs */
2322 q.ptr = NULL; 2346 q.ptr = NULL;
2347 break;
2323 } 2348 }
2324 2349
2325 /* assume completion callbacks modify the queue */ 2350 /* assume completion callbacks modify the queue */
2326 if (unlikely (modified)) { 2351 if (unlikely (modified)) {
2327 if (likely(ehci->periodic_count > 0)) 2352 if (likely(ehci->isoc_count > 0))
2328 goto restart; 2353 goto restart;
2329 /* short-circuit this scan */ 2354 /* short-circuit this scan */
2330 now_uframe = clock; 2355 now_uframe = clock;
@@ -2353,7 +2378,7 @@ restart:
2353 unsigned now; 2378 unsigned now;
2354 2379
2355 if (ehci->rh_state < EHCI_RH_RUNNING 2380 if (ehci->rh_state < EHCI_RH_RUNNING
2356 || ehci->periodic_count == 0) 2381 || ehci->isoc_count == 0)
2357 break; 2382 break;
2358 ehci->next_uframe = now_uframe; 2383 ehci->next_uframe = now_uframe;
2359 now = ehci_read_frame_index(ehci) & (mod - 1); 2384 now = ehci_read_frame_index(ehci) & (mod - 1);
@@ -2363,10 +2388,7 @@ restart:
2363 /* rescan the rest of this frame, then ... */ 2388 /* rescan the rest of this frame, then ... */
2364 clock = now; 2389 clock = now;
2365 clock_frame = clock >> 3; 2390 clock_frame = clock >> 3;
2366 if (ehci->clock_frame != clock_frame) { 2391 ehci->clock_frame = clock_frame;
2367 ehci->clock_frame = clock_frame;
2368 ++ehci->periodic_stamp;
2369 }
2370 } else { 2392 } else {
2371 now_uframe++; 2393 now_uframe++;
2372 now_uframe &= mod - 1; 2394 now_uframe &= mod - 1;
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index a823290b5139..0e28bae78d18 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -168,13 +168,8 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci)
168 168
169 /* The status is up-to-date; restart or stop the schedule as needed */ 169 /* The status is up-to-date; restart or stop the schedule as needed */
170 if (want == 0) { /* Stopped */ 170 if (want == 0) { /* Stopped */
171 if (ehci->periodic_count > 0) { 171 if (ehci->periodic_count > 0)
172
173 /* make sure ehci_work scans these */
174 ehci->next_uframe = ehci_read_frame_index(ehci)
175 & ((ehci->periodic_size << 3) - 1);
176 ehci_set_command_bit(ehci, CMD_PSE); 172 ehci_set_command_bit(ehci, CMD_PSE);
177 }
178 173
179 } else { /* Running */ 174 } else { /* Running */
180 if (ehci->periodic_count == 0) { 175 if (ehci->periodic_count == 0) {
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;