[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 05/13] usb-ehci: Drop cached qhs when the doorbell g
From: |
Hans de Goede |
Subject: |
[Qemu-devel] [PATCH 05/13] usb-ehci: Drop cached qhs when the doorbell gets rung |
Date: |
Fri, 2 Mar 2012 21:27:12 +0100 |
The purpose of the IAAD bit / the doorbell is to make the ehci controller
forget about cached qhs, this is mainly used when cancelling transactions,
the qh is unlinked from the async schedule and then the doorbell gets rung,
once the doorbell is acked by the controller the hcd knows that the qh is
no longer in use and that it can do something else with the memory, such
as re-use it for a new qh! But we keep our struct representing this qh around
for circa 250 ms. This allows for a (mightily large) race window where the
following could happen:
-hcd submits a qh at address 0xdeadbeef
-our ehci code sees the qh, sends a request to a usb-device, gets a result
of USB_RET_ASYNC, sets the async_state of the qh to EHCI_ASYNC_INFLIGHT
-hcd unlinks the qh at address 0xdeadbeef
-hcd rings the doorbell, wait for us to ack it
-hcd re-uses the qh at address 0xdeadbeef
-our ehci code sees the qh, looks in the async_queue, sees there already is
a qh at address 0xdeadbeef there with async_state of EHCI_ASYNC_INFLIGHT,
does nothing
-the *original* (which the hcd thinks it has cancelled) transaction finishes
-our ehci code sees the qh on yet another pass through the async list,
looks in the async_queue, sees there already is a qh at address 0xdeadbeef
there with async_state of EHCI_ASYNC_COMPLETED, and finished the transaction
with the results of the *original* transaction.
Not good (tm), this patch fixes this race by removing all qhs which have not
been seen during the last cycle through the async list immidiately when the
doorbell is rung.
Note this patch does not fix any actually observed problem, but upon
reading of the EHCI spec it became apparent to me that the above race could
happen and the usb-ehci behavior from before this patch is not good.
Signed-off-by: Hans de Goede <address@hidden>
---
hw/usb-ehci.c | 33 +++++++++++++++++----------------
1 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index d384fcc..b349003 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -697,7 +697,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci,
uint32_t addr,
return NULL;
}
-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;
EHCIQueue *q, *tmp;
@@ -708,7 +708,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 + 250000000) {
+ if (!flush && ehci->last_run_ns < q->ts + 250000000) {
/* allow 0.25 sec idle */
continue;
}
@@ -1537,7 +1537,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++) {
@@ -2093,18 +2093,7 @@ static void ehci_advance_async_state(EHCIState *ehci)
break;
}
- /* If the doorbell is set, the guest wants to make a change to the
- * schedule. The host controller needs to release cached data.
- * (section 4.8.2)
- */
- if (ehci->usbcmd & USBCMD_IAAD) {
- DPRINTF("ASYNC: doorbell request acknowledged\n");
- ehci->usbcmd &= ~USBCMD_IAAD;
- ehci_set_interrupt(ehci, USBSTS_IAA);
- break;
- }
-
- /* make sure guest has acknowledged */
+ /* make sure guest has acknowledged the doorbell interrupt */
/* TO-DO: is this really needed? */
if (ehci->usbsts & USBSTS_IAA) {
DPRINTF("IAA status bit still set.\n");
@@ -2118,6 +2107,18 @@ static void ehci_advance_async_state(EHCIState *ehci)
ehci_set_state(ehci, async, EST_WAITLISTHEAD);
ehci_advance_state(ehci, async);
+
+ /* If the doorbell is set, the guest wants to make a change to the
+ * schedule. The host controller needs to release cached data.
+ * (section 4.8.2)
+ */
+ if (ehci->usbcmd & USBCMD_IAAD) {
+ /* Remove all unseen qhs from the async qhs queue */
+ ehci_queues_rip_unused(ehci, async, 1);
+ DPRINTF("ASYNC: doorbell request acknowledged\n");
+ ehci->usbcmd &= ~USBCMD_IAAD;
+ ehci_set_interrupt(ehci, USBSTS_IAA);
+ }
break;
default:
@@ -2167,7 +2168,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:
--
1.7.7.6
- [Qemu-devel] [PATCH 03/13] usb-ehci: split our qh queue into async and periodic queues, (continued)
- [Qemu-devel] [PATCH 03/13] usb-ehci: split our qh queue into async and periodic queues, Hans de Goede, 2012/03/02
- [Qemu-devel] [PATCH 06/13] usb-ehci: Rip the queues when the async or period schedule is halted, Hans de Goede, 2012/03/02
- [Qemu-devel] [PATCH 07/13] usb-ehci: Any packet completion except for NAK should set the interrupt, Hans de Goede, 2012/03/02
- [Qemu-devel] [PATCH 08/13] usb-ehci: Fix cerr tracking, Hans de Goede, 2012/03/02
- [Qemu-devel] [PATCH 10/13] usb-ehci: Fix and simplify nakcnt handling, Hans de Goede, 2012/03/02
- [Qemu-devel] [PATCH 11/13] usb-ehci: Cleanup itd error handling, Hans de Goede, 2012/03/02
- [Qemu-devel] [PATCH 12/13] usb: return BABBLE rather then NAK when we receive too much data, Hans de Goede, 2012/03/02
- [Qemu-devel] [PATCH 13/13] usb: add USB_RET_IOERROR, Hans de Goede, 2012/03/02
- [Qemu-devel] [PATCH 01/13] usb-redir: Set ep type and interface, Hans de Goede, 2012/03/02
- [Qemu-devel] [PATCH 04/13] usb-ehci: always call ehci_queues_rip_unused for period queues, Hans de Goede, 2012/03/02
- [Qemu-devel] [PATCH 05/13] usb-ehci: Drop cached qhs when the doorbell gets rung,
Hans de Goede <=
- [Qemu-devel] [PATCH 09/13] usb-ehci: Remove dead nakcnt code, Hans de Goede, 2012/03/02
- Re: [Qemu-devel] usb patches [v2], Gerd Hoffmann, 2012/03/05