aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-sched.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
-rw-r--r--drivers/usb/host/ehci-sched.c67
1 files changed, 44 insertions, 23 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index be575e46eac3..b7853c8bac0f 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1349,18 +1349,27 @@ iso_stream_schedule (
1349 /* when's the last uframe this urb could start? */ 1349 /* when's the last uframe this urb could start? */
1350 max = now + mod; 1350 max = now + mod;
1351 1351
1352 /* typical case: reuse current schedule. stream is still active, 1352 /* Typical case: reuse current schedule, stream is still active.
1353 * and no gaps from host falling behind (irq delays etc) 1353 * Hopefully there are no gaps from the host falling behind
1354 * (irq delays etc), but if there are we'll take the next
1355 * slot in the schedule, implicitly assuming URB_ISO_ASAP.
1354 */ 1356 */
1355 if (likely (!list_empty (&stream->td_list))) { 1357 if (likely (!list_empty (&stream->td_list))) {
1356 start = stream->next_uframe; 1358 start = stream->next_uframe;
1357 if (start < now) 1359 if (start < now)
1358 start += mod; 1360 start += mod;
1359 if (likely ((start + sched->span) < max)) 1361
1360 goto ready; 1362 /* Fell behind (by up to twice the slop amount)? */
1361 /* else fell behind; someday, try to reschedule */ 1363 if (start >= max - 2 * 8 * SCHEDULE_SLOP)
1362 status = -EL2NSYNC; 1364 start += stream->interval * DIV_ROUND_UP(
1363 goto fail; 1365 max - start, stream->interval) - mod;
1366
1367 /* Tried to schedule too far into the future? */
1368 if (unlikely((start + sched->span) >= max)) {
1369 status = -EFBIG;
1370 goto fail;
1371 }
1372 goto ready;
1364 } 1373 }
1365 1374
1366 /* need to schedule; when's the next (u)frame we could start? 1375 /* need to schedule; when's the next (u)frame we could start?
@@ -1613,6 +1622,9 @@ itd_complete (
1613 } else if (likely ((t & EHCI_ISOC_ACTIVE) == 0)) { 1622 } else if (likely ((t & EHCI_ISOC_ACTIVE) == 0)) {
1614 desc->status = 0; 1623 desc->status = 0;
1615 desc->actual_length = EHCI_ITD_LENGTH (t); 1624 desc->actual_length = EHCI_ITD_LENGTH (t);
1625 } else {
1626 /* URB was too late */
1627 desc->status = -EXDEV;
1616 } 1628 }
1617 } 1629 }
1618 1630
@@ -2095,7 +2107,7 @@ done:
2095static void 2107static void
2096scan_periodic (struct ehci_hcd *ehci) 2108scan_periodic (struct ehci_hcd *ehci)
2097{ 2109{
2098 unsigned frame, clock, now_uframe, mod; 2110 unsigned now_uframe, frame, clock, clock_frame, mod;
2099 unsigned modified; 2111 unsigned modified;
2100 2112
2101 mod = ehci->periodic_size << 3; 2113 mod = ehci->periodic_size << 3;
@@ -2111,6 +2123,7 @@ scan_periodic (struct ehci_hcd *ehci)
2111 else 2123 else
2112 clock = now_uframe + mod - 1; 2124 clock = now_uframe + mod - 1;
2113 clock %= mod; 2125 clock %= mod;
2126 clock_frame = clock >> 3;
2114 2127
2115 for (;;) { 2128 for (;;) {
2116 union ehci_shadow q, *q_p; 2129 union ehci_shadow q, *q_p;
@@ -2157,22 +2170,26 @@ restart:
2157 case Q_TYPE_ITD: 2170 case Q_TYPE_ITD:
2158 /* If this ITD is still active, leave it for 2171 /* If this ITD is still active, leave it for
2159 * later processing ... check the next entry. 2172 * later processing ... check the next entry.
2173 * No need to check for activity unless the
2174 * frame is current.
2160 */ 2175 */
2161 rmb (); 2176 if (frame == clock_frame && live) {
2162 for (uf = 0; uf < 8 && live; uf++) { 2177 rmb();
2163 if (0 == (q.itd->hw_transaction [uf] 2178 for (uf = 0; uf < 8; uf++) {
2164 & ITD_ACTIVE(ehci))) 2179 if (q.itd->hw_transaction[uf] &
2165 continue; 2180 ITD_ACTIVE(ehci))
2166 incomplete = true; 2181 break;
2167 q_p = &q.itd->itd_next; 2182 }
2168 hw_p = &q.itd->hw_next; 2183 if (uf < 8) {
2169 type = Q_NEXT_TYPE(ehci, 2184 incomplete = true;
2185 q_p = &q.itd->itd_next;
2186 hw_p = &q.itd->hw_next;
2187 type = Q_NEXT_TYPE(ehci,
2170 q.itd->hw_next); 2188 q.itd->hw_next);
2171 q = *q_p; 2189 q = *q_p;
2172 break; 2190 break;
2191 }
2173 } 2192 }
2174 if (uf < 8 && live)
2175 break;
2176 2193
2177 /* Take finished ITDs out of the schedule 2194 /* Take finished ITDs out of the schedule
2178 * and process them: recycle, maybe report 2195 * and process them: recycle, maybe report
@@ -2189,9 +2206,12 @@ restart:
2189 case Q_TYPE_SITD: 2206 case Q_TYPE_SITD:
2190 /* If this SITD is still active, leave it for 2207 /* If this SITD is still active, leave it for
2191 * later processing ... check the next entry. 2208 * later processing ... check the next entry.
2209 * No need to check for activity unless the
2210 * frame is current.
2192 */ 2211 */
2193 if ((q.sitd->hw_results & SITD_ACTIVE(ehci)) 2212 if (frame == clock_frame && live &&
2194 && live) { 2213 (q.sitd->hw_results &
2214 SITD_ACTIVE(ehci))) {
2195 incomplete = true; 2215 incomplete = true;
2196 q_p = &q.sitd->sitd_next; 2216 q_p = &q.sitd->sitd_next;
2197 hw_p = &q.sitd->hw_next; 2217 hw_p = &q.sitd->hw_next;
@@ -2260,6 +2280,7 @@ restart:
2260 2280
2261 /* rescan the rest of this frame, then ... */ 2281 /* rescan the rest of this frame, then ... */
2262 clock = now; 2282 clock = now;
2283 clock_frame = clock >> 3;
2263 } else { 2284 } else {
2264 now_uframe++; 2285 now_uframe++;
2265 now_uframe %= mod; 2286 now_uframe %= mod;