diff options
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 7 | ||||
-rw-r--r-- | drivers/usb/host/ehci-q.c | 3 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 96 | ||||
-rw-r--r-- | drivers/usb/host/ehci-timer.c | 7 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 8 |
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 | ||
619 | static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) | 627 | static 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 | ||
932 | static 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 | ||
2168 | static void | 2216 | static void scan_isoc(struct ehci_hcd *ehci) |
2169 | scan_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; |