aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/ehci-sched.c70
-rw-r--r--drivers/usb/host/ehci.h2
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
1366static int 1366static int
1367iso_stream_schedule ( 1367iso_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;
2233restart: 2228restart:
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 */