forked from Minki/linux
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:
parent
c1fdb68e3d
commit
79bcf7b02b
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user