diff options
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 70 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 2 |
2 files changed, 33 insertions, 39 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 7cf3da7babf0..7eb242f27c00 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
@@ -1361,7 +1361,7 @@ sitd_slot_ok ( | |||
1361 | * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler! | 1361 | * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler! |
1362 | */ | 1362 | */ |
1363 | 1363 | ||
1364 | #define SCHEDULE_SLOP 80 /* microframes */ | 1364 | #define SCHEDULING_DELAY 40 /* microframes */ |
1365 | 1365 | ||
1366 | static int | 1366 | static int |
1367 | iso_stream_schedule ( | 1367 | iso_stream_schedule ( |
@@ -1370,7 +1370,7 @@ iso_stream_schedule ( | |||
1370 | struct ehci_iso_stream *stream | 1370 | struct ehci_iso_stream *stream |
1371 | ) | 1371 | ) |
1372 | { | 1372 | { |
1373 | u32 now, next, start, period, span; | 1373 | u32 now, base, next, start, period, span; |
1374 | int status; | 1374 | int status; |
1375 | unsigned mod = ehci->periodic_size << 3; | 1375 | unsigned mod = ehci->periodic_size << 3; |
1376 | struct ehci_iso_sched *sched = urb->hcpriv; | 1376 | struct ehci_iso_sched *sched = urb->hcpriv; |
@@ -1382,12 +1382,6 @@ iso_stream_schedule ( | |||
1382 | span <<= 3; | 1382 | span <<= 3; |
1383 | } | 1383 | } |
1384 | 1384 | ||
1385 | if (span > mod - SCHEDULE_SLOP) { | ||
1386 | ehci_dbg (ehci, "iso request %p too long\n", urb); | ||
1387 | status = -EFBIG; | ||
1388 | goto fail; | ||
1389 | } | ||
1390 | |||
1391 | now = ehci_read_frame_index(ehci) & (mod - 1); | 1385 | now = ehci_read_frame_index(ehci) & (mod - 1); |
1392 | 1386 | ||
1393 | /* Typical case: reuse current schedule, stream is still active. | 1387 | /* Typical case: reuse current schedule, stream is still active. |
@@ -1396,7 +1390,6 @@ iso_stream_schedule ( | |||
1396 | * slot in the schedule, implicitly assuming URB_ISO_ASAP. | 1390 | * slot in the schedule, implicitly assuming URB_ISO_ASAP. |
1397 | */ | 1391 | */ |
1398 | if (likely (!list_empty (&stream->td_list))) { | 1392 | if (likely (!list_empty (&stream->td_list))) { |
1399 | u32 excess; | ||
1400 | 1393 | ||
1401 | /* For high speed devices, allow scheduling within the | 1394 | /* For high speed devices, allow scheduling within the |
1402 | * isochronous scheduling threshold. For full speed devices | 1395 | * isochronous scheduling threshold. For full speed devices |
@@ -1408,36 +1401,41 @@ iso_stream_schedule ( | |||
1408 | else | 1401 | else |
1409 | next = now; | 1402 | next = now; |
1410 | 1403 | ||
1411 | /* Fell behind (by up to twice the slop amount)? | 1404 | /* |
1412 | * We decide based on the time of the last currently-scheduled | 1405 | * Use ehci->last_iso_frame as the base. There can't be any |
1413 | * slot, not the time of the next available slot. | 1406 | * TDs scheduled for earlier than that. |
1414 | */ | 1407 | */ |
1415 | excess = (stream->next_uframe - period - next) & (mod - 1); | 1408 | base = ehci->last_iso_frame << 3; |
1416 | if (excess >= mod - 2 * SCHEDULE_SLOP) | 1409 | next = (next - base) & (mod - 1); |
1417 | start = next + excess - mod + period * | 1410 | start = (stream->next_uframe - base) & (mod - 1); |
1418 | DIV_ROUND_UP(mod - excess, period); | 1411 | |
1419 | else | 1412 | /* Is the schedule already full? */ |
1420 | start = next + excess + period; | 1413 | if (unlikely(start < period)) { |
1421 | if (start - now >= mod) { | 1414 | ehci_dbg(ehci, "iso sched full %p (%u-%u < %u mod %u)\n", |
1422 | ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n", | 1415 | urb, stream->next_uframe, base, |
1423 | urb, start - now - period, period, | 1416 | period, mod); |
1424 | mod); | 1417 | status = -ENOSPC; |
1425 | status = -EFBIG; | ||
1426 | goto fail; | 1418 | goto fail; |
1427 | } | 1419 | } |
1420 | |||
1421 | /* Behind the scheduling threshold? Assume URB_ISO_ASAP. */ | ||
1422 | if (unlikely(start < next)) | ||
1423 | start += period * DIV_ROUND_UP(next - start, period); | ||
1424 | |||
1425 | start += base; | ||
1428 | } | 1426 | } |
1429 | 1427 | ||
1430 | /* need to schedule; when's the next (u)frame we could start? | 1428 | /* need to schedule; when's the next (u)frame we could start? |
1431 | * this is bigger than ehci->i_thresh allows; scheduling itself | 1429 | * this is bigger than ehci->i_thresh allows; scheduling itself |
1432 | * isn't free, the slop should handle reasonably slow cpus. it | 1430 | * isn't free, the delay should handle reasonably slow cpus. it |
1433 | * can also help high bandwidth if the dma and irq loads don't | 1431 | * can also help high bandwidth if the dma and irq loads don't |
1434 | * jump until after the queue is primed. | 1432 | * jump until after the queue is primed. |
1435 | */ | 1433 | */ |
1436 | else { | 1434 | else { |
1437 | int done = 0; | 1435 | int done = 0; |
1438 | start = SCHEDULE_SLOP + (now & ~0x07); | ||
1439 | 1436 | ||
1440 | /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ | 1437 | base = now & ~0x07; |
1438 | start = base + SCHEDULING_DELAY; | ||
1441 | 1439 | ||
1442 | /* find a uframe slot with enough bandwidth. | 1440 | /* find a uframe slot with enough bandwidth. |
1443 | * Early uframes are more precious because full-speed | 1441 | * Early uframes are more precious because full-speed |
@@ -1464,19 +1462,16 @@ iso_stream_schedule ( | |||
1464 | 1462 | ||
1465 | /* no room in the schedule */ | 1463 | /* no room in the schedule */ |
1466 | if (!done) { | 1464 | if (!done) { |
1467 | ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n", | 1465 | ehci_dbg(ehci, "iso sched full %p", urb); |
1468 | urb, now, now + mod); | ||
1469 | status = -ENOSPC; | 1466 | status = -ENOSPC; |
1470 | goto fail; | 1467 | goto fail; |
1471 | } | 1468 | } |
1472 | } | 1469 | } |
1473 | 1470 | ||
1474 | /* Tried to schedule too far into the future? */ | 1471 | /* Tried to schedule too far into the future? */ |
1475 | if (unlikely(start - now + span - period | 1472 | if (unlikely(start - base + span - period >= mod)) { |
1476 | >= mod - 2 * SCHEDULE_SLOP)) { | 1473 | ehci_dbg(ehci, "request %p would overflow (%u+%u >= %u)\n", |
1477 | ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n", | 1474 | urb, start - base, span - period, mod); |
1478 | urb, start - now, span - period, | ||
1479 | mod - 2 * SCHEDULE_SLOP); | ||
1480 | status = -EFBIG; | 1475 | status = -EFBIG; |
1481 | goto fail; | 1476 | goto fail; |
1482 | } | 1477 | } |
@@ -1490,7 +1485,7 @@ iso_stream_schedule ( | |||
1490 | 1485 | ||
1491 | /* Make sure scan_isoc() sees these */ | 1486 | /* Make sure scan_isoc() sees these */ |
1492 | if (ehci->isoc_count == 0) | 1487 | if (ehci->isoc_count == 0) |
1493 | ehci->next_frame = now >> 3; | 1488 | ehci->last_iso_frame = now >> 3; |
1494 | return 0; | 1489 | return 0; |
1495 | 1490 | ||
1496 | fail: | 1491 | fail: |
@@ -2220,16 +2215,16 @@ static void scan_isoc(struct ehci_hcd *ehci) | |||
2220 | now_frame = (uf >> 3) & fmask; | 2215 | now_frame = (uf >> 3) & fmask; |
2221 | live = true; | 2216 | live = true; |
2222 | } else { | 2217 | } else { |
2223 | now_frame = (ehci->next_frame - 1) & fmask; | 2218 | now_frame = (ehci->last_iso_frame - 1) & fmask; |
2224 | live = false; | 2219 | live = false; |
2225 | } | 2220 | } |
2226 | ehci->now_frame = now_frame; | 2221 | ehci->now_frame = now_frame; |
2227 | 2222 | ||
2228 | frame = ehci->next_frame; | ||
2229 | for (;;) { | 2223 | for (;;) { |
2230 | union ehci_shadow q, *q_p; | 2224 | union ehci_shadow q, *q_p; |
2231 | __hc32 type, *hw_p; | 2225 | __hc32 type, *hw_p; |
2232 | 2226 | ||
2227 | frame = ehci->last_iso_frame; | ||
2233 | restart: | 2228 | restart: |
2234 | /* scan each element in frame's queue for completions */ | 2229 | /* scan each element in frame's queue for completions */ |
2235 | q_p = &ehci->pshadow [frame]; | 2230 | q_p = &ehci->pshadow [frame]; |
@@ -2334,7 +2329,6 @@ restart: | |||
2334 | /* Stop when we have reached the current frame */ | 2329 | /* Stop when we have reached the current frame */ |
2335 | if (frame == now_frame) | 2330 | if (frame == now_frame) |
2336 | break; | 2331 | break; |
2337 | frame = (frame + 1) & fmask; | 2332 | ehci->last_iso_frame = (frame + 1) & fmask; |
2338 | } | 2333 | } |
2339 | ehci->next_frame = now_frame; | ||
2340 | } | 2334 | } |
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index da07d98f7d1d..0564a63f5eb3 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
@@ -143,7 +143,7 @@ struct ehci_hcd { /* one per controller */ | |||
143 | struct ehci_qh *intr_unlink_last; | 143 | struct ehci_qh *intr_unlink_last; |
144 | unsigned intr_unlink_cycle; | 144 | unsigned intr_unlink_cycle; |
145 | unsigned now_frame; /* frame from HC hardware */ | 145 | unsigned now_frame; /* frame from HC hardware */ |
146 | unsigned next_frame; /* scan periodic, start here */ | 146 | unsigned last_iso_frame; /* last frame scanned for iso */ |
147 | unsigned intr_count; /* intr activity count */ | 147 | unsigned intr_count; /* intr activity count */ |
148 | unsigned isoc_count; /* isoc activity count */ | 148 | unsigned isoc_count; /* isoc activity count */ |
149 | unsigned periodic_count; /* periodic activity count */ | 149 | unsigned periodic_count; /* periodic activity count */ |