Commit c5375618 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] ehci-hcd, urb queuing

In doing some more extensive testing of the urb queueing behavior,
I noticed that (a) IOC wasn't always being set for each urb, while
for now it needs to be set; (b) a qh patchup wasn't done quite
where it should be.  This resolves those two issues, as well
as making it a bit less noisy to unlink lots of urbs at the once.
parent ef3249f3
...@@ -749,7 +749,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) ...@@ -749,7 +749,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
default: default:
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
if (ehci->reclaim) { if (ehci->reclaim) {
dbg ("dq %p: reclaim = %p, %s", vdbg ("dq %p: reclaim = %p, %s",
qh, ehci->reclaim, RUN_CONTEXT); qh, ehci->reclaim, RUN_CONTEXT);
if (qh == ehci->reclaim) { if (qh == ehci->reclaim) {
/* unlinking qh for another queued urb? */ /* unlinking qh for another queued urb? */
......
...@@ -255,23 +255,23 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -255,23 +255,23 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
struct urb *urb = qtd->urb; struct urb *urb = qtd->urb;
u32 token = 0; u32 token = 0;
/* hc's on-chip qh overlay cache can overwrite our idea of
* next qtd ptrs, if we appended a qtd while the queue was
* advancing. (because we don't use dummy qtds.)
*/
if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current
&& qtd->hw_next != qh->hw_qtd_next) {
qh->hw_alt_next = qtd->hw_alt_next;
qh->hw_qtd_next = qtd->hw_next;
COUNT (ehci->stats.qpatch);
}
/* clean up any state from previous QTD ...*/ /* clean up any state from previous QTD ...*/
if (last) { if (last) {
if (likely (last->urb != urb)) { if (likely (last->urb != urb)) {
ehci_urb_done (ehci, last->urb); ehci_urb_done (ehci, last->urb);
count++; count++;
} }
/* qh overlays can have HC's old cached copies of
* next qtd ptrs, if an URB was queued afterwards.
*/
if (cpu_to_le32 (last->qtd_dma) == qh->hw_current
&& last->hw_next != qh->hw_qtd_next) {
qh->hw_alt_next = last->hw_alt_next;
qh->hw_qtd_next = last->hw_next;
COUNT (ehci->stats.qpatch);
}
ehci_qtd_free (ehci, last); ehci_qtd_free (ehci, last);
last = 0; last = 0;
} }
...@@ -529,7 +529,8 @@ qh_urb_transaction ( ...@@ -529,7 +529,8 @@ qh_urb_transaction (
} }
/* by default, enable interrupt on urb completion */ /* by default, enable interrupt on urb completion */
if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT))) // ... do it always, unless we switch over to dummy qtds
// if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC); qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
return head; return head;
...@@ -785,7 +786,6 @@ static struct ehci_qh *qh_append_tds ( ...@@ -785,7 +786,6 @@ static struct ehci_qh *qh_append_tds (
/* append to tds already queued to this qh? */ /* append to tds already queued to this qh? */
if (unlikely (!list_empty (&qh->qtd_list) && qtd)) { if (unlikely (!list_empty (&qh->qtd_list) && qtd)) {
struct ehci_qtd *last_qtd; struct ehci_qtd *last_qtd;
int short_rx = 0;
u32 hw_next; u32 hw_next;
/* update the last qtd's "next" pointer */ /* update the last qtd's "next" pointer */
...@@ -800,23 +800,16 @@ static struct ehci_qh *qh_append_tds ( ...@@ -800,23 +800,16 @@ static struct ehci_qh *qh_append_tds (
&& (epnum & 0x10)) { && (epnum & 0x10)) {
// only the last QTD for now // only the last QTD for now
last_qtd->hw_alt_next = hw_next; last_qtd->hw_alt_next = hw_next;
short_rx = 1;
} }
/* Adjust any old copies in qh overlay too. /* qh_completions() may need to patch the qh overlay if
* Interrupt code must cope with case of HC having it * the hc was advancing this queue while we appended.
* cached, and clobbering these updates. * we know it can: last_qtd->hw_token has IOC set.
* ... complicates getting rid of extra interrupts! *
* (Or: use dummy td, so cache always stays valid.) * or: use a dummy td (so the overlay gets the next td
* only when we set its active bit); fewer irqs.
*/ */
if (qh->hw_current == cpu_to_le32 (last_qtd->qtd_dma)) {
wmb (); wmb ();
qh->hw_qtd_next = hw_next;
if (short_rx)
qh->hw_alt_next = hw_next
| (qh->hw_alt_next & 0x1e);
vdbg ("queue to qh %p, patch", qh);
}
/* no URB queued */ /* no URB queued */
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment