diff options
author | Hans de Goede <hdegoede@redhat.com> | 2012-11-14 17:21:37 +0100 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2012-11-16 11:27:32 +0100 |
commit | ff80ce599e0465cc6109a38bd3a8ca1890e88891 (patch) | |
tree | 536155f69c0af748f9e664104e044b068cad76bf /hw/usb/hcd-ehci.c | |
parent | 30d68cf6e156b97fc462e18f38ce83f44702cd7f (diff) | |
download | hqemu-ff80ce599e0465cc6109a38bd3a8ca1890e88891.zip hqemu-ff80ce599e0465cc6109a38bd3a8ca1890e88891.tar.gz |
ehci: Fixup q->qtdaddr after cancelling an already completed packet
This avoids the q->qtdaddr == p->qtdaddr asserts we have triggering, when
a queue contains multiple completed packages when we cancel the queue.
I triggered this with windows7 + async interrupt endpoint handling (*)
+ not detecting circles in ehci_fill_queue() properly, which makes the qtd
validation in ehci_fill_queue fail, causing cancellation of the queue on every
mouse event ...
*) Which is not going upstream as it will cause loss of interrupt events on
migration.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Diffstat (limited to 'hw/usb/hcd-ehci.c')
-rw-r--r-- | hw/usb/hcd-ehci.c | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index a8b1a40..5e3b4a8 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -189,6 +189,7 @@ static const char *ehci_mmio_names[] = { static int ehci_state_executing(EHCIQueue *q); static int ehci_state_writeback(EHCIQueue *q); +static int ehci_state_advqueue(EHCIQueue *q); static int ehci_fill_queue(EHCIPacket *p); static const char *nr2str(const char **n, size_t len, uint32_t nr) @@ -459,6 +460,9 @@ static void ehci_free_packet(EHCIPacket *p) fprintf(stderr, "EHCI: Warning packet completed but not processed\n"); ehci_state_executing(q); ehci_state_writeback(q); + if (!(q->qh.token & QTD_TOKEN_HALT)) { + ehci_state_advqueue(q); + } ehci_set_state(q->ehci, q->async, state); /* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */ return; |