From: Gerd Hoffmann <kraxel@redhat.com>
To: Gerd Hoffmann <kraxel@redhat.com>
Cc: Hans de Goede <hdegoede@redhat.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH 4/4] [wip] ehci: don't flush cache on dorbell rings.
Date: Thu, 21 Jun 2012 11:28:03 +0200 [thread overview]
Message-ID: <4FE2E923.2030606@redhat.com> (raw)
In-Reply-To: <1340196107-6309-5-git-send-email-kraxel@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 377 bytes --]
On 06/20/12 14:41, Gerd Hoffmann wrote:
> Commit 4be23939ab0d7019c7e59a37485b416fbbf0f073 makes ehci instantly
> zap any unlinked queue heads when the guest rings the dorbell.
[ ... ]
> Simply not zapping queue heads on doorbell rings fixes the issue, but of course
> re-introduces the risk of using cached but stale information.
Improved version attached.
cheers,
Gerd
[-- Attachment #2: 0001-wip-ehci-don-t-flush-cache-on-dorbell-rings.patch --]
[-- Type: text/plain, Size: 8315 bytes --]
>From 27c3356deb29f7cd5189aee8fd84058129812e28 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 20 Jun 2012 13:14:08 +0200
Subject: [PATCH v2] ehci: don't flush cache on dorbell rings.
Commit 4be23939ab0d7019c7e59a37485b416fbbf0f073 makes ehci instantly
zap any unlinked queue heads when the guest rings the dorbell.
While hacking up uas support this turned out to be a problem. The linux
kernel can unlink and instantly relink the very same queue head, thereby
killing any async packets in flight. That alone isn't an issue yet, the
packet will canceled and resubmitted and everything is fine. We'll run
into trouble though in case the async packet is completed already, so we
can't cancel it any more. The transaction is simply lost then.
usb_ehci_qh_ptrs q (nil) - QH @ 39c4f000: next 39c4f122 qtds 00000000,00000001,39c50000
usb_ehci_qh_fields QH @ 39c4f000 - rl 0, mplen 0, eps 0, ep 0, dev 0
usb_ehci_qh_ptrs q 0x7f95feba90a0 - QH @ 39c4f000: next 39c4f122 qtds 00000000,00000001,39c50000
usb_ehci_qh_fields QH @ 39c4f000 - rl 0, mplen 0, eps 0, ep 0, dev 0
usb_ehci_qh_ptrs q 0x7f95fe515210 - QH @ 39c4f120: next 39c4f0c2 qtds 29dbce40,29dbc4e0,00000009
usb_ehci_qh_fields QH @ 39c4f120 - rl 4, mplen 512, eps 2, ep 1, dev 2
usb_ehci_packet_action q 0x7f95fe515210 p 0x7f95fdec32a0: alloc
usb_packet_state_change bus 0, port 2, ep 1, packet 0x7f95fdec32e0, state undef -> setup
usb_ehci_packet_action q 0x7f95fe515210 p 0x7f95fdec32a0: process
usb_uas_command dev 2, tag 0x2, lun 0, lun64 00000000-00000000
scsi_req_parsed target 0 lun 0 tag 2 command 42 dir 2 length 16384
scsi_req_parsed_lba target 0 lun 0 tag 2 command 42 lba 5933312
scsi_req_alloc target 0 lun 0 tag 2
scsi_req_continue target 0 lun 0 tag 2
scsi_req_data target 0 lun 0 tag 2 len 16384
usb_uas_scsi_data dev 2, tag 0x2, bytes 16384
usb_uas_write_ready dev 2, tag 0x2
usb_packet_state_change bus 0, port 2, ep 1, packet 0x7f95fdec32e0, state setup -> complete
usb_ehci_packet_action q 0x7f95fe515210 p 0x7f95fdec32a0: free
usb_ehci_qh_ptrs q 0x7f95fdec3210 - QH @ 39c4f0c0: next 39c4f002 qtds 29dbce40,00000001,00000009
usb_ehci_qh_fields QH @ 39c4f0c0 - rl 4, mplen 512, eps 2, ep 2, dev 2
usb_ehci_queue_action q 0x7f95fe5152a0: free
usb_packet_state_change bus 0, port 2, ep 2, packet 0x7f95feba9170, state async -> complete
^^^ async packets completes.
usb_ehci_packet_action q 0x7f95fdec3210 p 0x7f95feba9130: wakeup
usb_ehci_qh_ptrs q (nil) - QH @ 39c4f000: next 39c4f122 qtds 00000000,00000001,39c50000
usb_ehci_qh_fields QH @ 39c4f000 - rl 0, mplen 0, eps 0, ep 0, dev 0
usb_ehci_qh_ptrs q 0x7f95feba90a0 - QH @ 39c4f000: next 39c4f122 qtds 00000000,00000001,39c50000
usb_ehci_qh_fields QH @ 39c4f000 - rl 0, mplen 0, eps 0, ep 0, dev 0
usb_ehci_qh_ptrs q 0x7f95fe515210 - QH @ 39c4f120: next 39c4f002 qtds 29dbc4e0,29dbc8a0,00000009
usb_ehci_qh_fields QH @ 39c4f120 - rl 4, mplen 512, eps 2, ep 1, dev 2
usb_ehci_queue_action q 0x7f95fdec3210: free
usb_ehci_packet_action q 0x7f95fdec3210 p 0x7f95feba9130: free
^^^ endpoint #2 queue head removed from schedule, doorbell makes ehci zap the queue,
the (completed) usb packet is freed too and gets lost.
usb_ehci_qh_ptrs q (nil) - QH @ 39c4f000: next 39c4f0c2 qtds 00000000,00000001,39c50000
usb_ehci_qh_fields QH @ 39c4f000 - rl 0, mplen 0, eps 0, ep 0, dev 0
usb_ehci_qh_ptrs q 0x7f95feba90a0 - QH @ 39c4f000: next 39c4f0c2 qtds 00000000,00000001,39c50000
usb_ehci_qh_fields QH @ 39c4f000 - rl 0, mplen 0, eps 0, ep 0, dev 0
usb_ehci_queue_action q 0x7f9600dff570: alloc
usb_ehci_qh_ptrs q 0x7f9600dff570 - QH @ 39c4f0c0: next 39c4f122 qtds 29dbce40,00000001,00000009
usb_ehci_qh_fields QH @ 39c4f0c0 - rl 4, mplen 512, eps 2, ep 2, dev 2
usb_ehci_packet_action q 0x7f9600dff570 p 0x7f95feba9130: alloc
usb_packet_state_change bus 0, port 2, ep 2, packet 0x7f95feba9170, state undef -> setup
usb_ehci_packet_action q 0x7f9600dff570 p 0x7f95feba9130: process
usb_packet_state_change bus 0, port 2, ep 2, packet 0x7f95feba9170, state setup -> async
usb_ehci_packet_action q 0x7f9600dff570 p 0x7f95feba9130: async
^^^ linux kernel relinked the queue head, ehci creates a new usb packet,
but we should have delivered the completed one instead.
usb_ehci_qh_ptrs q 0x7f95fe515210 - QH @ 39c4f120: next 39c4f002 qtds 29dbc4e0,29dbc8a0,00000009
usb_ehci_qh_fields QH @ 39c4f120 - rl 4, mplen 512, eps 2, ep 1, dev 2
So instead of instantly zapping the queue we'll set a flag that the
queue needs revalidation in case we'll see it again in the schedule.
ehci then checks that the queue head fields addressing / describing the
endpoint and the qtd pointer match the cached content before reusing it.
Cc: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/hcd-ehci.c | 35 +++++++++++++++++++++++++++++------
1 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 9fb6423..890692a 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -365,6 +365,7 @@ 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)
@@ -775,7 +776,18 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
return NULL;
}
-static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush)
+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)
{
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4;
@@ -787,7 +799,7 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush)
q->ts = ehci->last_run_ns;
continue;
}
- if (!flush && ehci->last_run_ns < q->ts + maxage) {
+ if (ehci->last_run_ns < q->ts + maxage) {
continue;
}
ehci_free_queue(q);
@@ -1631,7 +1643,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
ehci_set_usbsts(ehci, USBSTS_REC);
}
- ehci_queues_rip_unused(ehci, async, 0);
+ ehci_queues_rip_unused(ehci, async);
/* Find the head of the list (4.9.1.1) */
for(i = 0; i < MAX_QH; i++) {
@@ -1716,6 +1728,7 @@ 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);
@@ -1733,7 +1746,17 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
}
get_dwords(ehci, NLPTR_GET(q->qhaddr),
- (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
+ (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;
ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh);
devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR);
@@ -2228,7 +2251,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_rip_unused(ehci, async, 1);
+ ehci_queues_tag_unused_async(ehci);
DPRINTF("ASYNC: doorbell request acknowledged\n");
ehci->usbcmd &= ~USBCMD_IAAD;
ehci_set_interrupt(ehci, USBSTS_IAA);
@@ -2281,7 +2304,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, 0);
+ ehci_queues_rip_unused(ehci, async);
break;
default:
--
1.7.1
next prev parent reply other threads:[~2012-06-21 9:28 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-06-20 12:41 [Qemu-devel] [PATCH 0/4] usb attached scsi Gerd Hoffmann
2012-06-20 12:41 ` [Qemu-devel] [PATCH 1/4] ehci: fix ehci_qh_do_overlay Gerd Hoffmann
2012-06-20 12:41 ` [Qemu-devel] [PATCH 2/4] ehci: fix td writeback Gerd Hoffmann
2012-06-20 12:41 ` [Qemu-devel] [PATCH 3/4] usb: add usb attached scsi emulation Gerd Hoffmann
2012-07-01 13:36 ` Paolo Bonzini
2012-07-02 11:20 ` Gerd Hoffmann
2012-06-20 12:41 ` [Qemu-devel] [PATCH 4/4] [wip] ehci: don't flush cache on dorbell rings Gerd Hoffmann
2012-06-21 9:28 ` Gerd Hoffmann [this message]
2012-06-21 10:04 ` Peter Maydell
2012-06-21 10:27 ` Andreas Färber
2012-06-21 11:28 ` Dor Laor
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=4FE2E923.2030606@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).