This patch (as1658) cleans up the usage of qh_completions() in ehci-hcd. Currently the function's return value indicates whether any URBs were given back; the idea was that the caller can scan the QH over again to handle any URBs that were dequeued by a completion handler. This is not necessary; when qh_completions() is ready to give back dequeued URBs, it does its own rescanning. Therefore the new return value will be a flag indicating whether the caller needs to unlink the QH. This is more convenient than forcing the caller to check qh->needs_rescan, and it makes a lot more sense -- why should "needs_rescan" imply that an unlink is needed? The callers are also changed to remove the unneeded rescans. Lastly, the check for whether qh->qtd_list is non-empty is removed from the start of qh_completions(). Two of the callers have to make this test anyway, so the same test can simply be added to the other two callers. Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> --- drivers/usb/host/ehci-q.c | 22 ++++++++-------------- drivers/usb/host/ehci-sched.c | 12 +++++------- 2 files changed, 13 insertions(+), 21 deletions(-) Index: usb-3.9/drivers/usb/host/ehci-q.c =================================================================== --- usb-3.9.orig/drivers/usb/host/ehci-q.c +++ usb-3.9/drivers/usb/host/ehci-q.c @@ -292,8 +292,8 @@ static int qh_schedule (struct ehci_hcd /* * Process and free completed qtds for a qh, returning URBs to drivers. - * Chases up to qh->hw_current. Returns number of completions called, - * indicating how much "real" work we did. + * Chases up to qh->hw_current. Returns nonzero if the caller should + * unlink qh. */ static unsigned qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) @@ -302,13 +302,9 @@ qh_completions (struct ehci_hcd *ehci, s struct list_head *entry, *tmp; int last_status; int stopped; - unsigned count = 0; u8 state; struct ehci_qh_hw *hw = qh->hw; - if (unlikely (list_empty (&qh->qtd_list))) - return count; - /* completions (or tasks on other cpus) must never clobber HALT * till we've gone through and cleaned everything up, even when * they add urbs to this qh's queue or mark them for unlinking. @@ -345,7 +341,6 @@ qh_completions (struct ehci_hcd *ehci, s if (last) { if (likely (last->urb != urb)) { ehci_urb_done(ehci, last->urb, last_status); - count++; last_status = -EINPROGRESS; } ehci_qtd_free (ehci, last); @@ -519,7 +514,6 @@ qh_completions (struct ehci_hcd *ehci, s /* last urb's completion might still need calling */ if (likely (last != NULL)) { ehci_urb_done(ehci, last->urb, last_status); - count++; ehci_qtd_free (ehci, last); } @@ -566,7 +560,7 @@ qh_completions (struct ehci_hcd *ehci, s /* otherwise, unlink already started */ } - return count; + return qh->needs_rescan; } /*-------------------------------------------------------------------------*/ @@ -1254,7 +1248,8 @@ static void end_unlink_async(struct ehci qh->qh_state = QH_STATE_IDLE; qh->qh_next.qh = NULL; - qh_completions(ehci, qh); + if (!list_empty(&qh->qtd_list)) + qh_completions(ehci, qh); if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) qh_link_async(ehci, qh); @@ -1348,7 +1343,7 @@ static void scan_async (struct ehci_hcd while (ehci->qh_scan_next) { qh = ehci->qh_scan_next; ehci->qh_scan_next = qh->qh_next.qh; - rescan: + /* clean any finished work for this qh */ if (!list_empty(&qh->qtd_list)) { int temp; @@ -1361,14 +1356,13 @@ static void scan_async (struct ehci_hcd * in single_unlink_async(). */ temp = qh_completions(ehci, qh); - if (qh->needs_rescan) { + if (unlikely(temp)) { start_unlink_async(ehci, qh); } else if (list_empty(&qh->qtd_list) && qh->qh_state == QH_STATE_LINKED) { qh->unlink_cycle = ehci->async_unlink_cycle; check_unlinks_later = true; - } else if (temp != 0) - goto rescan; + } } } Index: usb-3.9/drivers/usb/host/ehci-sched.c =================================================================== --- usb-3.9.orig/drivers/usb/host/ehci-sched.c +++ usb-3.9/drivers/usb/host/ehci-sched.c @@ -649,7 +649,8 @@ static void end_unlink_intr(struct ehci_ qh->qh_state = QH_STATE_IDLE; hw->hw_next = EHCI_LIST_END(ehci); - qh_completions(ehci, qh); + if (!list_empty(&qh->qtd_list)) + qh_completions(ehci, qh); /* reschedule QH iff another request is queued */ if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) { @@ -914,7 +915,7 @@ static void scan_intr(struct ehci_hcd *e list_for_each_entry_safe(qh, ehci->qh_scan_next, &ehci->intr_qh_list, intr_node) { - rescan: + /* clean any finished work for this qh */ if (!list_empty(&qh->qtd_list)) { int temp; @@ -927,12 +928,9 @@ static void scan_intr(struct ehci_hcd *e * in qh_unlink_periodic(). */ temp = qh_completions(ehci, qh); - if (unlikely(qh->needs_rescan || - (list_empty(&qh->qtd_list) && - qh->qh_state == QH_STATE_LINKED))) + if (unlikely(temp || (list_empty(&qh->qtd_list) && + qh->qh_state == QH_STATE_LINKED))) start_unlink_intr(ehci, qh); - else if (temp != 0) - goto rescan; } } } -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html