USB: EHCI: change return value of qh_completions()

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@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Alan Stern 2013-03-22 13:30:56 -04:00 committed by Greg Kroah-Hartman
parent c1fdb68e3d
commit 79bcf7b02b
2 changed files with 13 additions and 21 deletions

View File

@ -292,8 +292,8 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
/* /*
* Process and free completed qtds for a qh, returning URBs to drivers. * Process and free completed qtds for a qh, returning URBs to drivers.
* Chases up to qh->hw_current. Returns number of completions called, * Chases up to qh->hw_current. Returns nonzero if the caller should
* indicating how much "real" work we did. * unlink qh.
*/ */
static unsigned static unsigned
qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
@ -302,13 +302,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
struct list_head *entry, *tmp; struct list_head *entry, *tmp;
int last_status; int last_status;
int stopped; int stopped;
unsigned count = 0;
u8 state; u8 state;
struct ehci_qh_hw *hw = qh->hw; 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 /* completions (or tasks on other cpus) must never clobber HALT
* till we've gone through and cleaned everything up, even when * till we've gone through and cleaned everything up, even when
* they add urbs to this qh's queue or mark them for unlinking. * they add urbs to this qh's queue or mark them for unlinking.
@ -345,7 +341,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (last) { if (last) {
if (likely (last->urb != urb)) { if (likely (last->urb != urb)) {
ehci_urb_done(ehci, last->urb, last_status); ehci_urb_done(ehci, last->urb, last_status);
count++;
last_status = -EINPROGRESS; last_status = -EINPROGRESS;
} }
ehci_qtd_free (ehci, last); ehci_qtd_free (ehci, last);
@ -519,7 +514,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* last urb's completion might still need calling */ /* last urb's completion might still need calling */
if (likely (last != NULL)) { if (likely (last != NULL)) {
ehci_urb_done(ehci, last->urb, last_status); ehci_urb_done(ehci, last->urb, last_status);
count++;
ehci_qtd_free (ehci, last); ehci_qtd_free (ehci, last);
} }
@ -566,7 +560,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* otherwise, unlink already started */ /* otherwise, unlink already started */
} }
return count; return qh->needs_rescan;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@ -1254,7 +1248,8 @@ static void end_unlink_async(struct ehci_hcd *ehci)
qh->qh_state = QH_STATE_IDLE; qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = NULL; 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) && if (!list_empty(&qh->qtd_list) &&
ehci->rh_state == EHCI_RH_RUNNING) ehci->rh_state == EHCI_RH_RUNNING)
qh_link_async(ehci, qh); qh_link_async(ehci, qh);
@ -1348,7 +1343,7 @@ static void scan_async (struct ehci_hcd *ehci)
while (ehci->qh_scan_next) { while (ehci->qh_scan_next) {
qh = ehci->qh_scan_next; qh = ehci->qh_scan_next;
ehci->qh_scan_next = qh->qh_next.qh; ehci->qh_scan_next = qh->qh_next.qh;
rescan:
/* clean any finished work for this qh */ /* clean any finished work for this qh */
if (!list_empty(&qh->qtd_list)) { if (!list_empty(&qh->qtd_list)) {
int temp; int temp;
@ -1361,14 +1356,13 @@ static void scan_async (struct ehci_hcd *ehci)
* in single_unlink_async(). * in single_unlink_async().
*/ */
temp = qh_completions(ehci, qh); temp = qh_completions(ehci, qh);
if (qh->needs_rescan) { if (unlikely(temp)) {
start_unlink_async(ehci, qh); start_unlink_async(ehci, qh);
} else if (list_empty(&qh->qtd_list) } else if (list_empty(&qh->qtd_list)
&& qh->qh_state == QH_STATE_LINKED) { && qh->qh_state == QH_STATE_LINKED) {
qh->unlink_cycle = ehci->async_unlink_cycle; qh->unlink_cycle = ehci->async_unlink_cycle;
check_unlinks_later = true; check_unlinks_later = true;
} else if (temp != 0) }
goto rescan;
} }
} }

View File

@ -649,7 +649,8 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->qh_state = QH_STATE_IDLE; qh->qh_state = QH_STATE_IDLE;
hw->hw_next = EHCI_LIST_END(ehci); 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 */ /* reschedule QH iff another request is queued */
if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) { if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
@ -914,7 +915,7 @@ static void scan_intr(struct ehci_hcd *ehci)
list_for_each_entry_safe(qh, ehci->qh_scan_next, &ehci->intr_qh_list, list_for_each_entry_safe(qh, ehci->qh_scan_next, &ehci->intr_qh_list,
intr_node) { intr_node) {
rescan:
/* clean any finished work for this qh */ /* clean any finished work for this qh */
if (!list_empty(&qh->qtd_list)) { if (!list_empty(&qh->qtd_list)) {
int temp; int temp;
@ -927,12 +928,9 @@ static void scan_intr(struct ehci_hcd *ehci)
* in qh_unlink_periodic(). * in qh_unlink_periodic().
*/ */
temp = qh_completions(ehci, qh); temp = qh_completions(ehci, qh);
if (unlikely(qh->needs_rescan || if (unlikely(temp || (list_empty(&qh->qtd_list) &&
(list_empty(&qh->qtd_list) && qh->qh_state == QH_STATE_LINKED)))
qh->qh_state == QH_STATE_LINKED)))
start_unlink_intr(ehci, qh); start_unlink_intr(ehci, qh);
else if (temp != 0)
goto rescan;
} }
} }
} }