2012-10-28 18:05:07 +00:00
|
|
|
From 4547897358a12c0f31d688da9922236984742242 Mon Sep 17 00:00:00 2001
|
2012-09-07 15:20:05 +00:00
|
|
|
From: Hans de Goede <hdegoede@redhat.com>
|
|
|
|
Date: Wed, 29 Aug 2012 10:12:52 +0200
|
2012-10-28 18:05:07 +00:00
|
|
|
Subject: [PATCH] Revert "ehci: don't flush cache on doorbell rings."
|
2012-09-07 15:20:05 +00:00
|
|
|
|
|
|
|
This reverts commit 9bc3a3a216e2689bfcdd36c3e079333bbdbf3ba0, which got
|
|
|
|
added to fix an issue where the real, underlying cause was not stopping
|
|
|
|
the ep queue on an error.
|
|
|
|
|
|
|
|
Now that the underlying cause is fixed by the "usb: Halt ep queue and
|
|
|
|
cancel pending packets on a packet error" patch, the "don't flush" fix
|
|
|
|
is no longer needed.
|
|
|
|
|
|
|
|
Not only is it not needed, it causes us to see cancellations (unlinks)
|
|
|
|
done by the Linux EHCI driver too late, which in combination with the new
|
|
|
|
usb-core packet-id generation where qtd addresses are used as ids, causes
|
|
|
|
duplicate ids for in flight packets.
|
|
|
|
|
|
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
2012-10-28 18:05:07 +00:00
|
|
|
(cherry picked from commit 66f092d25697e11847b61d761c38ddebedaed8d1)
|
|
|
|
|
|
|
|
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
|
2012-09-07 15:20:05 +00:00
|
|
|
---
|
|
|
|
hw/usb/hcd-ehci.c | 35 ++++++-----------------------------
|
|
|
|
1 file changed, 6 insertions(+), 29 deletions(-)
|
|
|
|
|
|
|
|
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
|
|
|
|
index 9523247..e7c36f4 100644
|
|
|
|
--- a/hw/usb/hcd-ehci.c
|
|
|
|
+++ b/hw/usb/hcd-ehci.c
|
|
|
|
@@ -365,7 +365,6 @@ struct EHCIQueue {
|
|
|
|
uint32_t seen;
|
|
|
|
uint64_t ts;
|
|
|
|
int async;
|
|
|
|
- int revalidate;
|
|
|
|
|
|
|
|
/* cached data from guest - needs to be flushed
|
|
|
|
* when guest removes an entry (doorbell, handshake sequence)
|
|
|
|
@@ -805,18 +804,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
-static void ehci_queues_tag_unused_async(EHCIState *ehci)
|
|
|
|
-{
|
|
|
|
- EHCIQueue *q;
|
|
|
|
-
|
|
|
|
- QTAILQ_FOREACH(q, &ehci->aqueues, next) {
|
|
|
|
- if (!q->seen) {
|
|
|
|
- q->revalidate = 1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static void ehci_queues_rip_unused(EHCIState *ehci, int async)
|
|
|
|
+static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush)
|
|
|
|
{
|
|
|
|
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
|
|
|
|
uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4;
|
|
|
|
@@ -828,7 +816,7 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async)
|
|
|
|
q->ts = ehci->last_run_ns;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
- if (ehci->last_run_ns < q->ts + maxage) {
|
|
|
|
+ if (!flush && ehci->last_run_ns < q->ts + maxage) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ehci_free_queue(q);
|
|
|
|
@@ -1684,7 +1672,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
|
|
|
|
ehci_set_usbsts(ehci, USBSTS_REC);
|
|
|
|
}
|
|
|
|
|
|
|
|
- ehci_queues_rip_unused(ehci, async);
|
|
|
|
+ ehci_queues_rip_unused(ehci, async, 0);
|
|
|
|
|
|
|
|
/* Find the head of the list (4.9.1.1) */
|
|
|
|
for(i = 0; i < MAX_QH; i++) {
|
|
|
|
@@ -1769,7 +1757,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
|
|
|
EHCIPacket *p;
|
|
|
|
uint32_t entry, devaddr;
|
|
|
|
EHCIQueue *q;
|
|
|
|
- EHCIqh qh;
|
|
|
|
|
|
|
|
entry = ehci_get_fetch_addr(ehci, async);
|
|
|
|
q = ehci_find_queue_by_qh(ehci, entry, async);
|
|
|
|
@@ -1787,17 +1774,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
|
|
|
}
|
|
|
|
|
|
|
|
get_dwords(ehci, NLPTR_GET(q->qhaddr),
|
|
|
|
- (uint32_t *) &qh, sizeof(EHCIqh) >> 2);
|
|
|
|
- if (q->revalidate && (q->qh.epchar != qh.epchar ||
|
|
|
|
- q->qh.epcap != qh.epcap ||
|
|
|
|
- q->qh.current_qtd != qh.current_qtd)) {
|
|
|
|
- ehci_free_queue(q);
|
|
|
|
- q = ehci_alloc_queue(ehci, entry, async);
|
|
|
|
- q->seen++;
|
|
|
|
- p = NULL;
|
|
|
|
- }
|
|
|
|
- q->qh = qh;
|
|
|
|
- q->revalidate = 0;
|
|
|
|
+ (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
|
|
|
|
ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh);
|
|
|
|
|
|
|
|
devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
|
|
|
|
@@ -2306,7 +2283,7 @@ static void ehci_advance_async_state(EHCIState *ehci)
|
|
|
|
*/
|
|
|
|
if (ehci->usbcmd & USBCMD_IAAD) {
|
|
|
|
/* Remove all unseen qhs from the async qhs queue */
|
|
|
|
- ehci_queues_tag_unused_async(ehci);
|
|
|
|
+ ehci_queues_rip_unused(ehci, async, 1);
|
|
|
|
DPRINTF("ASYNC: doorbell request acknowledged\n");
|
|
|
|
ehci->usbcmd &= ~USBCMD_IAAD;
|
|
|
|
ehci_raise_irq(ehci, USBSTS_IAA);
|
|
|
|
@@ -2359,7 +2336,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
|
|
|
|
ehci_set_fetch_addr(ehci, async,entry);
|
|
|
|
ehci_set_state(ehci, async, EST_FETCHENTRY);
|
|
|
|
ehci_advance_state(ehci, async);
|
|
|
|
- ehci_queues_rip_unused(ehci, async);
|
|
|
|
+ ehci_queues_rip_unused(ehci, async, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|