From: Gerd Hoffmann <kraxel@redhat.com>
To: qemu-devel@nongnu.org
Cc: Hans de Goede <hdegoede@redhat.com>, Gerd Hoffmann <kraxel@redhat.com>
Subject: [Qemu-devel] [PATCH 05/20] usb-ehci: Drop cached qhs when the doorbell gets rung
Date: Wed, 7 Mar 2012 14:05:05 +0100 [thread overview]
Message-ID: <1331125520-13467-6-git-send-email-kraxel@redhat.com> (raw)
In-Reply-To: <1331125520-13467-1-git-send-email-kraxel@redhat.com>
From: Hans de Goede <hdegoede@redhat.com>
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 <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
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.1
next prev parent reply other threads:[~2012-03-07 13:05 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-03-07 13:05 [Qemu-devel] [PULL 00/20] usb patch queue Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 01/20] usb-redir: Set ep type and interface Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 02/20] usb-ehci: Never follow table entries with the T-bit set Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 03/20] usb-ehci: split our qh queue into async and periodic queues Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 04/20] usb-ehci: always call ehci_queues_rip_unused for period queues Gerd Hoffmann
2012-03-07 13:05 ` Gerd Hoffmann [this message]
2012-03-07 13:05 ` [Qemu-devel] [PATCH 06/20] usb-ehci: Rip the queues when the async or period schedule is halted Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 07/20] usb-ehci: Any packet completion except for NAK should set the interrupt Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 08/20] usb-ehci: Fix cerr tracking Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 09/20] usb-ehci: Remove dead nakcnt code Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 10/20] usb-ehci: Fix and simplify nakcnt handling Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 11/20] usb-ehci: Cleanup itd error handling Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 12/20] usb: return BABBLE rather then NAK when we receive too much data Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 13/20] usb: add USB_RET_IOERROR Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 14/20] uhci_fill_queue: zap debug printf Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 15/20] usb: queue can have async packets Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 16/20] usb: add pipelining option to usb endpoints Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 17/20] usb-host: enable pipelineing for bulk endpoints Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 18/20] usb: add shortcut for control transfers Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 19/20] xhci: fix control xfers Gerd Hoffmann
2012-03-07 13:05 ` [Qemu-devel] [PATCH 20/20] xhci: fix port status Gerd Hoffmann
2012-03-09 19:17 ` [Qemu-devel] [PULL 00/20] usb patch queue Anthony Liguori
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1331125520-13467-6-git-send-email-kraxel@redhat.com \
--to=kraxel@redhat.com \
--cc=hdegoede@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).