diff options
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 7b5ae7111f23..500aebbaa741 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
@@ -473,6 +473,111 @@ static int disable_periodic (struct ehci_hcd *ehci) | |||
473 | } | 473 | } |
474 | 474 | ||
475 | /*-------------------------------------------------------------------------*/ | 475 | /*-------------------------------------------------------------------------*/ |
476 | #ifdef CONFIG_CPU_FREQ | ||
477 | |||
478 | /* ignore/inactivate bit in QH hw_info1 */ | ||
479 | #define INACTIVATE_BIT __constant_cpu_to_le32(QH_INACTIVATE) | ||
480 | |||
481 | #define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT) | ||
482 | #define ACTIVE_BIT __constant_cpu_to_le32(QTD_STS_ACTIVE) | ||
483 | #define STATUS_BIT __constant_cpu_to_le32(QTD_STS_STS) | ||
484 | |||
485 | static int safe_to_modify_i (struct ehci_hcd *ehci, struct ehci_qh *qh) | ||
486 | { | ||
487 | int now; /* current (frame * 8) + uframe */ | ||
488 | int prev_start, next_start; /* uframes from/to split start */ | ||
489 | int start_uframe = ffs(le32_to_cpup (&qh->hw_info2) & QH_SMASK); | ||
490 | int end_uframe = fls((le32_to_cpup (&qh->hw_info2) & QH_CMASK) >> 8); | ||
491 | int split_duration = end_uframe - start_uframe; | ||
492 | |||
493 | now = readl(&ehci->regs->frame_index) % (ehci->periodic_size << 3); | ||
494 | |||
495 | next_start = ((1024 << 3) + (qh->start << 3) + start_uframe - now) % | ||
496 | (qh->period << 3); | ||
497 | prev_start = (qh->period << 3) - next_start; | ||
498 | |||
499 | /* | ||
500 | * Make sure there will be at least one uframe when qh is safe. | ||
501 | */ | ||
502 | if ((qh->period << 3) <= (ehci->i_thresh + 2 + split_duration)) | ||
503 | /* never safe */ | ||
504 | return -EINVAL; | ||
505 | |||
506 | /* | ||
507 | * Wait 1 uframe after transaction should have started, to make | ||
508 | * sure controller has time to write back overlay, so we can | ||
509 | * check QTD_STS_STS to see if transaction is in progress. | ||
510 | */ | ||
511 | if ((next_start > ehci->i_thresh) && (prev_start > 1)) | ||
512 | /* safe to set "i" bit if split isn't in progress */ | ||
513 | return (qh->hw_token & STATUS_BIT) ? 0 : 1; | ||
514 | else | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | /* Set inactivate bit for all the split interrupt QHs. */ | ||
519 | static void qh_inactivate_split_intr_qhs (struct ehci_hcd *ehci) | ||
520 | { | ||
521 | struct ehci_qh *qh; | ||
522 | int not_done, safe; | ||
523 | |||
524 | do { | ||
525 | not_done = 0; | ||
526 | list_for_each_entry(qh, &ehci->split_intr_qhs, | ||
527 | split_intr_qhs) { | ||
528 | if (qh->hw_info1 & INACTIVATE_BIT) | ||
529 | /* already off */ | ||
530 | continue; | ||
531 | /* | ||
532 | * To avoid setting "I" after the start split happens, | ||
533 | * don't set it if the QH might be cached in the | ||
534 | * controller. Some HCs (Broadcom/ServerWorks HT1000) | ||
535 | * will stop in the middle of a split transaction when | ||
536 | * the "I" bit is set. | ||
537 | */ | ||
538 | safe = safe_to_modify_i(ehci, qh); | ||
539 | if (safe == 0) { | ||
540 | not_done = 1; | ||
541 | } else if (safe > 0) { | ||
542 | qh->was_active = qh->hw_token & ACTIVE_BIT; | ||
543 | qh->hw_info1 |= INACTIVATE_BIT; | ||
544 | } | ||
545 | } | ||
546 | } while (not_done); | ||
547 | wmb(); | ||
548 | } | ||
549 | |||
550 | static void qh_reactivate_split_intr_qhs (struct ehci_hcd *ehci) | ||
551 | { | ||
552 | struct ehci_qh *qh; | ||
553 | u32 token; | ||
554 | int not_done, safe; | ||
555 | |||
556 | do { | ||
557 | not_done = 0; | ||
558 | list_for_each_entry(qh, &ehci->split_intr_qhs, split_intr_qhs) { | ||
559 | if (!(qh->hw_info1 & INACTIVATE_BIT)) /* already on */ | ||
560 | continue; | ||
561 | /* | ||
562 | * Don't reactivate if cached, or controller might | ||
563 | * overwrite overlay after we modify it! | ||
564 | */ | ||
565 | safe = safe_to_modify_i(ehci, qh); | ||
566 | if (safe == 0) { | ||
567 | not_done = 1; | ||
568 | } else if (safe > 0) { | ||
569 | /* See EHCI 1.0 section 4.15.2.4. */ | ||
570 | token = qh->hw_token; | ||
571 | qh->hw_token = (token | HALT_BIT) & ~ACTIVE_BIT; | ||
572 | wmb(); | ||
573 | qh->hw_info1 &= ~INACTIVATE_BIT; | ||
574 | wmb(); | ||
575 | qh->hw_token = (token & ~HALT_BIT) | qh->was_active; | ||
576 | } | ||
577 | } | ||
578 | } while (not_done); | ||
579 | } | ||
580 | #endif | ||
476 | 581 | ||
477 | /* periodic schedule slots have iso tds (normal or split) first, then a | 582 | /* periodic schedule slots have iso tds (normal or split) first, then a |
478 | * sparse tree for active interrupt transfers. | 583 | * sparse tree for active interrupt transfers. |
@@ -490,6 +595,17 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
490 | period, le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK), | 595 | period, le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK), |
491 | qh, qh->start, qh->usecs, qh->c_usecs); | 596 | qh, qh->start, qh->usecs, qh->c_usecs); |
492 | 597 | ||
598 | #ifdef CONFIG_CPU_FREQ | ||
599 | /* | ||
600 | * If low/full speed interrupt QHs are inactive (because of | ||
601 | * cpufreq changing processor speeds), start QH with I flag set-- | ||
602 | * it will automatically be cleared when cpufreq is done. | ||
603 | */ | ||
604 | if (ehci->cpufreq_changing) | ||
605 | if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) | ||
606 | qh->hw_info1 |= INACTIVATE_BIT; | ||
607 | #endif | ||
608 | |||
493 | /* high bandwidth, or otherwise every microframe */ | 609 | /* high bandwidth, or otherwise every microframe */ |
494 | if (period == 0) | 610 | if (period == 0) |
495 | period = 1; | 611 | period = 1; |
@@ -538,6 +654,12 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
538 | ? ((qh->usecs + qh->c_usecs) / qh->period) | 654 | ? ((qh->usecs + qh->c_usecs) / qh->period) |
539 | : (qh->usecs * 8); | 655 | : (qh->usecs * 8); |
540 | 656 | ||
657 | #ifdef CONFIG_CPU_FREQ | ||
658 | /* add qh to list of low/full speed interrupt QHs, if applicable */ | ||
659 | if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) { | ||
660 | list_add(&qh->split_intr_qhs, &ehci->split_intr_qhs); | ||
661 | } | ||
662 | #endif | ||
541 | /* maybe enable periodic schedule processing */ | 663 | /* maybe enable periodic schedule processing */ |
542 | if (!ehci->periodic_sched++) | 664 | if (!ehci->periodic_sched++) |
543 | return enable_periodic (ehci); | 665 | return enable_periodic (ehci); |
@@ -557,6 +679,13 @@ static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) | |||
557 | // THEN | 679 | // THEN |
558 | // qh->hw_info1 |= __constant_cpu_to_le32 (1 << 7 /* "ignore" */); | 680 | // qh->hw_info1 |= __constant_cpu_to_le32 (1 << 7 /* "ignore" */); |
559 | 681 | ||
682 | #ifdef CONFIG_CPU_FREQ | ||
683 | /* remove qh from list of low/full speed interrupt QHs */ | ||
684 | if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) { | ||
685 | list_del_init(&qh->split_intr_qhs); | ||
686 | } | ||
687 | #endif | ||
688 | |||
560 | /* high bandwidth, or otherwise part of every microframe */ | 689 | /* high bandwidth, or otherwise part of every microframe */ |
561 | if ((period = qh->period) == 0) | 690 | if ((period = qh->period) == 0) |
562 | period = 1; | 691 | period = 1; |