diff options
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 136 |
1 files changed, 61 insertions, 75 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 7cf3da7babf0..69ebee73c0c1 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
@@ -36,29 +36,6 @@ | |||
36 | 36 | ||
37 | static int ehci_get_frame (struct usb_hcd *hcd); | 37 | static int ehci_get_frame (struct usb_hcd *hcd); |
38 | 38 | ||
39 | #ifdef CONFIG_PCI | ||
40 | |||
41 | static unsigned ehci_read_frame_index(struct ehci_hcd *ehci) | ||
42 | { | ||
43 | unsigned uf; | ||
44 | |||
45 | /* | ||
46 | * The MosChip MCS9990 controller updates its microframe counter | ||
47 | * a little before the frame counter, and occasionally we will read | ||
48 | * the invalid intermediate value. Avoid problems by checking the | ||
49 | * microframe number (the low-order 3 bits); if they are 0 then | ||
50 | * re-read the register to get the correct value. | ||
51 | */ | ||
52 | uf = ehci_readl(ehci, &ehci->regs->frame_index); | ||
53 | if (unlikely(ehci->frame_index_bug && ((uf & 7) == 0))) | ||
54 | uf = ehci_readl(ehci, &ehci->regs->frame_index); | ||
55 | return uf; | ||
56 | } | ||
57 | |||
58 | #endif | ||
59 | |||
60 | /*-------------------------------------------------------------------------*/ | ||
61 | |||
62 | /* | 39 | /* |
63 | * periodic_next_shadow - return "next" pointer on shadow list | 40 | * periodic_next_shadow - return "next" pointer on shadow list |
64 | * @periodic: host pointer to qh/itd/sitd | 41 | * @periodic: host pointer to qh/itd/sitd |
@@ -1361,7 +1338,7 @@ sitd_slot_ok ( | |||
1361 | * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler! | 1338 | * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler! |
1362 | */ | 1339 | */ |
1363 | 1340 | ||
1364 | #define SCHEDULE_SLOP 80 /* microframes */ | 1341 | #define SCHEDULING_DELAY 40 /* microframes */ |
1365 | 1342 | ||
1366 | static int | 1343 | static int |
1367 | iso_stream_schedule ( | 1344 | iso_stream_schedule ( |
@@ -1370,7 +1347,7 @@ iso_stream_schedule ( | |||
1370 | struct ehci_iso_stream *stream | 1347 | struct ehci_iso_stream *stream |
1371 | ) | 1348 | ) |
1372 | { | 1349 | { |
1373 | u32 now, next, start, period, span; | 1350 | u32 now, base, next, start, period, span; |
1374 | int status; | 1351 | int status; |
1375 | unsigned mod = ehci->periodic_size << 3; | 1352 | unsigned mod = ehci->periodic_size << 3; |
1376 | struct ehci_iso_sched *sched = urb->hcpriv; | 1353 | struct ehci_iso_sched *sched = urb->hcpriv; |
@@ -1382,62 +1359,72 @@ iso_stream_schedule ( | |||
1382 | span <<= 3; | 1359 | span <<= 3; |
1383 | } | 1360 | } |
1384 | 1361 | ||
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); | 1362 | now = ehci_read_frame_index(ehci) & (mod - 1); |
1392 | 1363 | ||
1393 | /* Typical case: reuse current schedule, stream is still active. | 1364 | /* Typical case: reuse current schedule, stream is still active. |
1394 | * Hopefully there are no gaps from the host falling behind | 1365 | * Hopefully there are no gaps from the host falling behind |
1395 | * (irq delays etc), but if there are we'll take the next | 1366 | * (irq delays etc). If there are, the behavior depends on |
1396 | * slot in the schedule, implicitly assuming URB_ISO_ASAP. | 1367 | * whether URB_ISO_ASAP is set. |
1397 | */ | 1368 | */ |
1398 | if (likely (!list_empty (&stream->td_list))) { | 1369 | if (likely (!list_empty (&stream->td_list))) { |
1399 | u32 excess; | ||
1400 | 1370 | ||
1401 | /* For high speed devices, allow scheduling within the | 1371 | /* Take the isochronous scheduling threshold into account */ |
1402 | * isochronous scheduling threshold. For full speed devices | 1372 | if (ehci->i_thresh) |
1403 | * and Intel PCI-based controllers, don't (work around for | 1373 | next = now + ehci->i_thresh; /* uframe cache */ |
1404 | * Intel ICH9 bug). | ||
1405 | */ | ||
1406 | if (!stream->highspeed && ehci->fs_i_thresh) | ||
1407 | next = now + ehci->i_thresh; | ||
1408 | else | 1374 | else |
1409 | next = now; | 1375 | next = (now + 2 + 7) & ~0x07; /* full frame cache */ |
1410 | 1376 | ||
1411 | /* Fell behind (by up to twice the slop amount)? | 1377 | /* |
1412 | * We decide based on the time of the last currently-scheduled | 1378 | * Use ehci->last_iso_frame as the base. There can't be any |
1413 | * slot, not the time of the next available slot. | 1379 | * TDs scheduled for earlier than that. |
1414 | */ | 1380 | */ |
1415 | excess = (stream->next_uframe - period - next) & (mod - 1); | 1381 | base = ehci->last_iso_frame << 3; |
1416 | if (excess >= mod - 2 * SCHEDULE_SLOP) | 1382 | next = (next - base) & (mod - 1); |
1417 | start = next + excess - mod + period * | 1383 | start = (stream->next_uframe - base) & (mod - 1); |
1418 | DIV_ROUND_UP(mod - excess, period); | 1384 | |
1419 | else | 1385 | /* Is the schedule already full? */ |
1420 | start = next + excess + period; | 1386 | if (unlikely(start < period)) { |
1421 | if (start - now >= mod) { | 1387 | 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", | 1388 | urb, stream->next_uframe, base, |
1423 | urb, start - now - period, period, | 1389 | period, mod); |
1424 | mod); | 1390 | status = -ENOSPC; |
1425 | status = -EFBIG; | ||
1426 | goto fail; | 1391 | goto fail; |
1427 | } | 1392 | } |
1393 | |||
1394 | /* Behind the scheduling threshold? */ | ||
1395 | if (unlikely(start < next)) { | ||
1396 | |||
1397 | /* USB_ISO_ASAP: Round up to the first available slot */ | ||
1398 | if (urb->transfer_flags & URB_ISO_ASAP) | ||
1399 | start += (next - start + period - 1) & -period; | ||
1400 | |||
1401 | /* | ||
1402 | * Not ASAP: Use the next slot in the stream. If | ||
1403 | * the entire URB falls before the threshold, fail. | ||
1404 | */ | ||
1405 | else if (start + span - period < next) { | ||
1406 | ehci_dbg(ehci, "iso urb late %p (%u+%u < %u)\n", | ||
1407 | urb, start + base, | ||
1408 | span - period, next + base); | ||
1409 | status = -EXDEV; | ||
1410 | goto fail; | ||
1411 | } | ||
1412 | } | ||
1413 | |||
1414 | start += base; | ||
1428 | } | 1415 | } |
1429 | 1416 | ||
1430 | /* need to schedule; when's the next (u)frame we could start? | 1417 | /* need to schedule; when's the next (u)frame we could start? |
1431 | * this is bigger than ehci->i_thresh allows; scheduling itself | 1418 | * this is bigger than ehci->i_thresh allows; scheduling itself |
1432 | * isn't free, the slop should handle reasonably slow cpus. it | 1419 | * 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 | 1420 | * can also help high bandwidth if the dma and irq loads don't |
1434 | * jump until after the queue is primed. | 1421 | * jump until after the queue is primed. |
1435 | */ | 1422 | */ |
1436 | else { | 1423 | else { |
1437 | int done = 0; | 1424 | int done = 0; |
1438 | start = SCHEDULE_SLOP + (now & ~0x07); | ||
1439 | 1425 | ||
1440 | /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ | 1426 | base = now & ~0x07; |
1427 | start = base + SCHEDULING_DELAY; | ||
1441 | 1428 | ||
1442 | /* find a uframe slot with enough bandwidth. | 1429 | /* find a uframe slot with enough bandwidth. |
1443 | * Early uframes are more precious because full-speed | 1430 | * Early uframes are more precious because full-speed |
@@ -1464,19 +1451,16 @@ iso_stream_schedule ( | |||
1464 | 1451 | ||
1465 | /* no room in the schedule */ | 1452 | /* no room in the schedule */ |
1466 | if (!done) { | 1453 | if (!done) { |
1467 | ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n", | 1454 | ehci_dbg(ehci, "iso sched full %p", urb); |
1468 | urb, now, now + mod); | ||
1469 | status = -ENOSPC; | 1455 | status = -ENOSPC; |
1470 | goto fail; | 1456 | goto fail; |
1471 | } | 1457 | } |
1472 | } | 1458 | } |
1473 | 1459 | ||
1474 | /* Tried to schedule too far into the future? */ | 1460 | /* Tried to schedule too far into the future? */ |
1475 | if (unlikely(start - now + span - period | 1461 | if (unlikely(start - base + span - period >= mod)) { |
1476 | >= mod - 2 * SCHEDULE_SLOP)) { | 1462 | ehci_dbg(ehci, "request %p would overflow (%u+%u >= %u)\n", |
1477 | ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n", | 1463 | urb, start - base, span - period, mod); |
1478 | urb, start - now, span - period, | ||
1479 | mod - 2 * SCHEDULE_SLOP); | ||
1480 | status = -EFBIG; | 1464 | status = -EFBIG; |
1481 | goto fail; | 1465 | goto fail; |
1482 | } | 1466 | } |
@@ -1490,7 +1474,7 @@ iso_stream_schedule ( | |||
1490 | 1474 | ||
1491 | /* Make sure scan_isoc() sees these */ | 1475 | /* Make sure scan_isoc() sees these */ |
1492 | if (ehci->isoc_count == 0) | 1476 | if (ehci->isoc_count == 0) |
1493 | ehci->next_frame = now >> 3; | 1477 | ehci->last_iso_frame = now >> 3; |
1494 | return 0; | 1478 | return 0; |
1495 | 1479 | ||
1496 | fail: | 1480 | fail: |
@@ -1646,7 +1630,7 @@ static void itd_link_urb( | |||
1646 | 1630 | ||
1647 | /* don't need that schedule data any more */ | 1631 | /* don't need that schedule data any more */ |
1648 | iso_sched_free (stream, iso_sched); | 1632 | iso_sched_free (stream, iso_sched); |
1649 | urb->hcpriv = NULL; | 1633 | urb->hcpriv = stream; |
1650 | 1634 | ||
1651 | ++ehci->isoc_count; | 1635 | ++ehci->isoc_count; |
1652 | enable_periodic(ehci); | 1636 | enable_periodic(ehci); |
@@ -1708,7 +1692,7 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd) | |||
1708 | urb->actual_length += desc->actual_length; | 1692 | urb->actual_length += desc->actual_length; |
1709 | } else { | 1693 | } else { |
1710 | /* URB was too late */ | 1694 | /* URB was too late */ |
1711 | desc->status = -EXDEV; | 1695 | urb->error_count++; |
1712 | } | 1696 | } |
1713 | } | 1697 | } |
1714 | 1698 | ||
@@ -2045,7 +2029,7 @@ static void sitd_link_urb( | |||
2045 | 2029 | ||
2046 | /* don't need that schedule data any more */ | 2030 | /* don't need that schedule data any more */ |
2047 | iso_sched_free (stream, sched); | 2031 | iso_sched_free (stream, sched); |
2048 | urb->hcpriv = NULL; | 2032 | urb->hcpriv = stream; |
2049 | 2033 | ||
2050 | ++ehci->isoc_count; | 2034 | ++ehci->isoc_count; |
2051 | enable_periodic(ehci); | 2035 | enable_periodic(ehci); |
@@ -2081,7 +2065,7 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd) | |||
2081 | t = hc32_to_cpup(ehci, &sitd->hw_results); | 2065 | t = hc32_to_cpup(ehci, &sitd->hw_results); |
2082 | 2066 | ||
2083 | /* report transfer status */ | 2067 | /* report transfer status */ |
2084 | if (t & SITD_ERRS) { | 2068 | if (unlikely(t & SITD_ERRS)) { |
2085 | urb->error_count++; | 2069 | urb->error_count++; |
2086 | if (t & SITD_STS_DBE) | 2070 | if (t & SITD_STS_DBE) |
2087 | desc->status = usb_pipein (urb->pipe) | 2071 | desc->status = usb_pipein (urb->pipe) |
@@ -2091,6 +2075,9 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd) | |||
2091 | desc->status = -EOVERFLOW; | 2075 | desc->status = -EOVERFLOW; |
2092 | else /* XACT, MMF, etc */ | 2076 | else /* XACT, MMF, etc */ |
2093 | desc->status = -EPROTO; | 2077 | desc->status = -EPROTO; |
2078 | } else if (unlikely(t & SITD_STS_ACTIVE)) { | ||
2079 | /* URB was too late */ | ||
2080 | urb->error_count++; | ||
2094 | } else { | 2081 | } else { |
2095 | desc->status = 0; | 2082 | desc->status = 0; |
2096 | desc->actual_length = desc->length - SITD_LENGTH(t); | 2083 | desc->actual_length = desc->length - SITD_LENGTH(t); |
@@ -2220,16 +2207,16 @@ static void scan_isoc(struct ehci_hcd *ehci) | |||
2220 | now_frame = (uf >> 3) & fmask; | 2207 | now_frame = (uf >> 3) & fmask; |
2221 | live = true; | 2208 | live = true; |
2222 | } else { | 2209 | } else { |
2223 | now_frame = (ehci->next_frame - 1) & fmask; | 2210 | now_frame = (ehci->last_iso_frame - 1) & fmask; |
2224 | live = false; | 2211 | live = false; |
2225 | } | 2212 | } |
2226 | ehci->now_frame = now_frame; | 2213 | ehci->now_frame = now_frame; |
2227 | 2214 | ||
2228 | frame = ehci->next_frame; | ||
2229 | for (;;) { | 2215 | for (;;) { |
2230 | union ehci_shadow q, *q_p; | 2216 | union ehci_shadow q, *q_p; |
2231 | __hc32 type, *hw_p; | 2217 | __hc32 type, *hw_p; |
2232 | 2218 | ||
2219 | frame = ehci->last_iso_frame; | ||
2233 | restart: | 2220 | restart: |
2234 | /* scan each element in frame's queue for completions */ | 2221 | /* scan each element in frame's queue for completions */ |
2235 | q_p = &ehci->pshadow [frame]; | 2222 | q_p = &ehci->pshadow [frame]; |
@@ -2334,7 +2321,6 @@ restart: | |||
2334 | /* Stop when we have reached the current frame */ | 2321 | /* Stop when we have reached the current frame */ |
2335 | if (frame == now_frame) | 2322 | if (frame == now_frame) |
2336 | break; | 2323 | break; |
2337 | frame = (frame + 1) & fmask; | 2324 | ehci->last_iso_frame = (frame + 1) & fmask; |
2338 | } | 2325 | } |
2339 | ehci->next_frame = now_frame; | ||
2340 | } | 2326 | } |