* [Qemu-devel] [PATCH] ehci: Fix interrupt packet MULT handling
@ 2012-09-20 15:38 Hans de Goede
2012-09-21 7:02 ` Gerd Hoffmann
2012-09-22 13:16 ` Blue Swirl
0 siblings, 2 replies; 5+ messages in thread
From: Hans de Goede @ 2012-09-20 15:38 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: Hans de Goede, shawn.starr, qemu-devel
There are several issues with our handling of the MULT epcap field
of interrupt qhs, which this patch fixes.
1) When we don't execute a transaction because of the transaction counter
being 0, p->async stays EHCI_ASYNC_NONE, and the next time we process the
same qtd we hit an assert in ehci_state_fetchqtd because of this. Even though
I believe that this is caused by 3 below, this patch still removes the assert,
as that can still happen without 3, when multiple packets are queued for the
same interrupt ep.
2) We only *check* the transaction counter from ehci_state_execute, any
packets queued up by fill_queue bypass this check. This is fixed by not calling
fill_queue for interrupt packets.
3) Some versions of Windows set the MULT field of the qh to 0, which is a
clear violation of the EHCI spec, but still they do it. This means that we
will never execute a qtd for these, making interrupt ep-s on USB-2 devices
not work, and after recent changes, triggering 1).
So far we've stored the transaction counter in our copy of the mult field,
but with this beginnig at 0 already when dealing with these version of windows
this won't work. So this patch adds a transact_ctr field to our qh struct,
and sets this to the MULT field value on fetchqh. When the MULT field value
is 0, we set it to 4. Assuming that windows gets way with setting it to 0,
by the actual hardware going horizontal on a 1 -> 0 transition, which will
give it 4 transactions (MULT goes from 0 - 3).
Note that we cannot stop on detecting the 1 -> 0 transition, as our decrement
of the transaction counter, and checking for it are done in 2 different places.
Reported-by: Shawn Starr <shawn.starr@rogers.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
hw/usb/hcd-ehci.c | 39 +++++++++++++++++++--------------------
1 file changed, 19 insertions(+), 20 deletions(-)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 48a1b09..3acd881a 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -373,6 +373,7 @@ struct EHCIQueue {
uint32_t seen;
uint64_t ts;
int async;
+ int transact_ctr;
/* cached data from guest - needs to be flushed
* when guest removes an entry (doorbell, handshake sequence)
@@ -1837,6 +1838,10 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
}
q->qh = qh;
+ q->transact_ctr = get_field(q->qh.epcap, QH_EPCAP_MULT);
+ if (q->transact_ctr == 0) /* Guest bug in some versions of windows */
+ q->transact_ctr = 4;
+
if (q->dev == NULL) {
q->dev = ehci_find_device(q->ehci, devaddr);
}
@@ -2014,11 +2019,8 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
} else if (p != NULL) {
switch (p->async) {
case EHCI_ASYNC_NONE:
- /* Should never happen packet should at least be initialized */
- assert(0);
- break;
case EHCI_ASYNC_INITIALIZED:
- /* Previously nacked packet (likely interrupt ep) */
+ /* Not yet executed (MULT), or previously nacked (int) packet */
ehci_set_state(q->ehci, q->async, EST_EXECUTE);
break;
case EHCI_ASYNC_INFLIGHT:
@@ -2107,15 +2109,12 @@ static int ehci_state_execute(EHCIQueue *q)
// TODO verify enough time remains in the uframe as in 4.4.1.1
// TODO write back ptr to async list when done or out of time
- // TODO Windows does not seem to ever set the MULT field
- if (!q->async) {
- int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
- if (!transactCtr) {
- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- again = 1;
- goto out;
- }
+ /* 4.10.3, bottom of page 82, go horizontal on transaction counter == 0 */
+ if (!q->async && q->transact_ctr == 0) {
+ ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
+ again = 1;
+ goto out;
}
if (q->async) {
@@ -2132,7 +2131,11 @@ static int ehci_state_execute(EHCIQueue *q)
trace_usb_ehci_packet_action(p->queue, p, "async");
p->async = EHCI_ASYNC_INFLIGHT;
ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
- again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1;
+ if (q->async) {
+ again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1;
+ } else {
+ again = 1;
+ }
goto out;
}
@@ -2152,13 +2155,9 @@ static int ehci_state_executing(EHCIQueue *q)
ehci_execute_complete(q);
- // 4.10.3
- if (!q->async) {
- int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
- transactCtr--;
- set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT);
- // 4.10.3, bottom of page 82, should exit this state when transaction
- // counter decrements to 0
+ /* 4.10.3 */
+ if (!q->async && q->transact_ctr > 0) {
+ q->transact_ctr--;
}
/* 4.10.5 */
--
1.7.12
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] ehci: Fix interrupt packet MULT handling
2012-09-20 15:38 [Qemu-devel] [PATCH] ehci: Fix interrupt packet MULT handling Hans de Goede
@ 2012-09-21 7:02 ` Gerd Hoffmann
2012-09-22 13:16 ` Blue Swirl
1 sibling, 0 replies; 5+ messages in thread
From: Gerd Hoffmann @ 2012-09-21 7:02 UTC (permalink / raw)
To: Hans de Goede; +Cc: shawn.starr, qemu-devel
On 09/20/12 17:38, Hans de Goede wrote:
> There are several issues with our handling of the MULT epcap field
> of interrupt qhs, which this patch fixes.
Patch added to usb patch queue.
thanks,
Gerd
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] ehci: Fix interrupt packet MULT handling
2012-09-20 15:38 [Qemu-devel] [PATCH] ehci: Fix interrupt packet MULT handling Hans de Goede
2012-09-21 7:02 ` Gerd Hoffmann
@ 2012-09-22 13:16 ` Blue Swirl
2012-09-23 10:06 ` Hans de Goede
1 sibling, 1 reply; 5+ messages in thread
From: Blue Swirl @ 2012-09-22 13:16 UTC (permalink / raw)
To: Hans de Goede; +Cc: shawn.starr, Gerd Hoffmann, qemu-devel
On Thu, Sep 20, 2012 at 3:38 PM, Hans de Goede <hdegoede@redhat.com> wrote:
> There are several issues with our handling of the MULT epcap field
> of interrupt qhs, which this patch fixes.
>
> 1) When we don't execute a transaction because of the transaction counter
> being 0, p->async stays EHCI_ASYNC_NONE, and the next time we process the
> same qtd we hit an assert in ehci_state_fetchqtd because of this. Even though
> I believe that this is caused by 3 below, this patch still removes the assert,
> as that can still happen without 3, when multiple packets are queued for the
> same interrupt ep.
>
> 2) We only *check* the transaction counter from ehci_state_execute, any
> packets queued up by fill_queue bypass this check. This is fixed by not calling
> fill_queue for interrupt packets.
>
> 3) Some versions of Windows set the MULT field of the qh to 0, which is a
> clear violation of the EHCI spec, but still they do it. This means that we
> will never execute a qtd for these, making interrupt ep-s on USB-2 devices
> not work, and after recent changes, triggering 1).
>
> So far we've stored the transaction counter in our copy of the mult field,
> but with this beginnig at 0 already when dealing with these version of windows
> this won't work. So this patch adds a transact_ctr field to our qh struct,
> and sets this to the MULT field value on fetchqh. When the MULT field value
> is 0, we set it to 4. Assuming that windows gets way with setting it to 0,
> by the actual hardware going horizontal on a 1 -> 0 transition, which will
> give it 4 transactions (MULT goes from 0 - 3).
>
> Note that we cannot stop on detecting the 1 -> 0 transition, as our decrement
> of the transaction counter, and checking for it are done in 2 different places.
>
> Reported-by: Shawn Starr <shawn.starr@rogers.com>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> hw/usb/hcd-ehci.c | 39 +++++++++++++++++++--------------------
> 1 file changed, 19 insertions(+), 20 deletions(-)
>
> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
> index 48a1b09..3acd881a 100644
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -373,6 +373,7 @@ struct EHCIQueue {
> uint32_t seen;
> uint64_t ts;
> int async;
> + int transact_ctr;
>
> /* cached data from guest - needs to be flushed
> * when guest removes an entry (doorbell, handshake sequence)
> @@ -1837,6 +1838,10 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
> }
> q->qh = qh;
>
> + q->transact_ctr = get_field(q->qh.epcap, QH_EPCAP_MULT);
> + if (q->transact_ctr == 0) /* Guest bug in some versions of windows */
> + q->transact_ctr = 4;
Missing braces, please use checkpatch.pl.
> +
> if (q->dev == NULL) {
> q->dev = ehci_find_device(q->ehci, devaddr);
> }
> @@ -2014,11 +2019,8 @@ static int ehci_state_fetchqtd(EHCIQueue *q)
> } else if (p != NULL) {
> switch (p->async) {
> case EHCI_ASYNC_NONE:
> - /* Should never happen packet should at least be initialized */
> - assert(0);
> - break;
> case EHCI_ASYNC_INITIALIZED:
> - /* Previously nacked packet (likely interrupt ep) */
> + /* Not yet executed (MULT), or previously nacked (int) packet */
> ehci_set_state(q->ehci, q->async, EST_EXECUTE);
> break;
> case EHCI_ASYNC_INFLIGHT:
> @@ -2107,15 +2109,12 @@ static int ehci_state_execute(EHCIQueue *q)
>
> // TODO verify enough time remains in the uframe as in 4.4.1.1
> // TODO write back ptr to async list when done or out of time
> - // TODO Windows does not seem to ever set the MULT field
>
> - if (!q->async) {
> - int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
> - if (!transactCtr) {
> - ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
> - again = 1;
> - goto out;
> - }
> + /* 4.10.3, bottom of page 82, go horizontal on transaction counter == 0 */
> + if (!q->async && q->transact_ctr == 0) {
> + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
> + again = 1;
> + goto out;
> }
>
> if (q->async) {
> @@ -2132,7 +2131,11 @@ static int ehci_state_execute(EHCIQueue *q)
> trace_usb_ehci_packet_action(p->queue, p, "async");
> p->async = EHCI_ASYNC_INFLIGHT;
> ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH);
> - again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1;
> + if (q->async) {
> + again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1;
> + } else {
> + again = 1;
> + }
> goto out;
> }
>
> @@ -2152,13 +2155,9 @@ static int ehci_state_executing(EHCIQueue *q)
>
> ehci_execute_complete(q);
>
> - // 4.10.3
> - if (!q->async) {
> - int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT);
> - transactCtr--;
> - set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT);
> - // 4.10.3, bottom of page 82, should exit this state when transaction
> - // counter decrements to 0
> + /* 4.10.3 */
> + if (!q->async && q->transact_ctr > 0) {
> + q->transact_ctr--;
> }
>
> /* 4.10.5 */
> --
> 1.7.12
>
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] ehci: Fix interrupt packet MULT handling
2012-09-22 13:16 ` Blue Swirl
@ 2012-09-23 10:06 ` Hans de Goede
2012-09-24 6:10 ` Gerd Hoffmann
0 siblings, 1 reply; 5+ messages in thread
From: Hans de Goede @ 2012-09-23 10:06 UTC (permalink / raw)
To: Blue Swirl; +Cc: shawn.starr, Gerd Hoffmann, qemu-devel
Hi,
Sorry.
On 09/22/2012 03:16 PM, Blue Swirl wrote:
> On Thu, Sep 20, 2012 at 3:38 PM, Hans de Goede <hdegoede@redhat.com> wrote:
<snip>
>> @@ -1837,6 +1838,10 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
>> }
>> q->qh = qh;
>>
>> + q->transact_ctr = get_field(q->qh.epcap, QH_EPCAP_MULT);
>> + if (q->transact_ctr == 0) /* Guest bug in some versions of windows */
>> + q->transact_ctr = 4;
>
> Missing braces, please use checkpatch.pl.
>
Oops, Gerd since this is already in your tree, can you fix this, or do you
want a new fixed version ?
Regards,
Hans
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] ehci: Fix interrupt packet MULT handling
2012-09-23 10:06 ` Hans de Goede
@ 2012-09-24 6:10 ` Gerd Hoffmann
0 siblings, 0 replies; 5+ messages in thread
From: Gerd Hoffmann @ 2012-09-24 6:10 UTC (permalink / raw)
To: Hans de Goede; +Cc: Blue Swirl, shawn.starr, qemu-devel
Hi,
>>
>> Missing braces, please use checkpatch.pl.
>>
>
> Oops, Gerd since this is already in your tree, can you fix this, or do you
> want a new fixed version ?
I've already fixed it.
You can wire checkpatch.pl into the git commit hook to avoid those slip
through unnoticed.
cheers,
Gerd
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-09-24 6:10 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-20 15:38 [Qemu-devel] [PATCH] ehci: Fix interrupt packet MULT handling Hans de Goede
2012-09-21 7:02 ` Gerd Hoffmann
2012-09-22 13:16 ` Blue Swirl
2012-09-23 10:06 ` Hans de Goede
2012-09-24 6:10 ` Gerd Hoffmann
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).