aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-sched.c
diff options
context:
space:
mode:
authorMing Lei <ming.lei@canonical.com>2013-07-03 10:53:10 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-12 14:43:48 -0400
commit9118f9eb4f1e97a135de3f78853c411befcf9775 (patch)
tree1db640132f3a1dfbffbbe74ca2382c3239de8d90 /drivers/usb/host/ehci-sched.c
parent35371e4fbc3e1863a6e7a79b8c17c25cc96a1380 (diff)
USB: EHCI: improve interrupt qh unlink
ehci-hcd currently unlinks an interrupt QH when it becomes empty, that is, after its last URB completes. This works well because in almost all cases, the completion handler for an interrupt URB resubmits the URB; therefore the QH doesn't become empty and doesn't get unlinked. When we start using tasklets for URB completion, this scheme won't work as well. The resubmission won't occur until the tasklet runs, which will be some time after the completion is queued with the tasklet. During that delay, the QH will be empty and so will be unlinked unnecessarily. To prevent this problem, this patch adds a 5-ms time delay before empty interrupt QHs are unlinked. Most often, during that time the interrupt URB will be resubmitted and thus we can avoid unlinking the QH. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Ming Lei <ming.lei@canonical.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
-rw-r--r--drivers/usb/host/ehci-sched.c47
1 files changed, 45 insertions, 2 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index f80d0330d548..94388738a6f7 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -601,12 +601,29 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
601 list_del(&qh->intr_node); 601 list_del(&qh->intr_node);
602} 602}
603 603
604static void cancel_unlink_wait_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
605{
606 if (qh->qh_state != QH_STATE_LINKED ||
607 list_empty(&qh->unlink_node))
608 return;
609
610 list_del_init(&qh->unlink_node);
611
612 /*
613 * TODO: disable the event of EHCI_HRTIMER_START_UNLINK_INTR for
614 * avoiding unnecessary CPU wakeup
615 */
616}
617
604static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) 618static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
605{ 619{
606 /* If the QH isn't linked then there's nothing we can do. */ 620 /* If the QH isn't linked then there's nothing we can do. */
607 if (qh->qh_state != QH_STATE_LINKED) 621 if (qh->qh_state != QH_STATE_LINKED)
608 return; 622 return;
609 623
624 /* if the qh is waiting for unlink, cancel it now */
625 cancel_unlink_wait_intr(ehci, qh);
626
610 qh_unlink_periodic (ehci, qh); 627 qh_unlink_periodic (ehci, qh);
611 628
612 /* Make sure the unlinks are visible before starting the timer */ 629 /* Make sure the unlinks are visible before starting the timer */
@@ -632,6 +649,27 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
632 } 649 }
633} 650}
634 651
652/*
653 * It is common only one intr URB is scheduled on one qh, and
654 * given complete() is run in tasklet context, introduce a bit
655 * delay to avoid unlink qh too early.
656 */
657static void start_unlink_intr_wait(struct ehci_hcd *ehci,
658 struct ehci_qh *qh)
659{
660 qh->unlink_cycle = ehci->intr_unlink_wait_cycle;
661
662 /* New entries go at the end of the intr_unlink_wait list */
663 list_add_tail(&qh->unlink_node, &ehci->intr_unlink_wait);
664
665 if (ehci->rh_state < EHCI_RH_RUNNING)
666 ehci_handle_start_intr_unlinks(ehci);
667 else if (ehci->intr_unlink_wait.next == &qh->unlink_node) {
668 ehci_enable_event(ehci, EHCI_HRTIMER_START_UNLINK_INTR, true);
669 ++ehci->intr_unlink_wait_cycle;
670 }
671}
672
635static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh) 673static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
636{ 674{
637 struct ehci_qh_hw *hw = qh->hw; 675 struct ehci_qh_hw *hw = qh->hw;
@@ -889,6 +927,9 @@ static int intr_submit (
889 if (qh->qh_state == QH_STATE_IDLE) { 927 if (qh->qh_state == QH_STATE_IDLE) {
890 qh_refresh(ehci, qh); 928 qh_refresh(ehci, qh);
891 qh_link_periodic(ehci, qh); 929 qh_link_periodic(ehci, qh);
930 } else {
931 /* cancel unlink wait for the qh */
932 cancel_unlink_wait_intr(ehci, qh);
892 } 933 }
893 934
894 /* ... update usbfs periodic stats */ 935 /* ... update usbfs periodic stats */
@@ -924,9 +965,11 @@ static void scan_intr(struct ehci_hcd *ehci)
924 * in qh_unlink_periodic(). 965 * in qh_unlink_periodic().
925 */ 966 */
926 temp = qh_completions(ehci, qh); 967 temp = qh_completions(ehci, qh);
927 if (unlikely(temp || (list_empty(&qh->qtd_list) && 968 if (unlikely(temp))
928 qh->qh_state == QH_STATE_LINKED)))
929 start_unlink_intr(ehci, qh); 969 start_unlink_intr(ehci, qh);
970 else if (unlikely(list_empty(&qh->qtd_list) &&
971 qh->qh_state == QH_STATE_LINKED))
972 start_unlink_intr_wait(ehci, qh);
930 } 973 }
931 } 974 }
932} 975}