1b1995d
From 2d9b6cb9bd00ede47635dc4db413f647143d5a1d Mon Sep 17 00:00:00 2001
1b1995d
From: Hans de Goede <hdegoede@redhat.com>
1b1995d
Date: Thu, 1 Mar 2012 23:55:11 +0100
1b1995d
Subject: [PATCH 135/140] usb-ehci: Fix and simplify nakcnt handling
1b1995d
1b1995d
The nakcnt code in ehci_execute_complete() marked transactions as finished
1b1995d
when a packet completed with a result of USB_RET_NAK, but USB_RET_NAK
1b1995d
means that the device cannot receive / send data at that time and that
1b1995d
the transaction should be retried later, which is also what the usb-uhci
1b1995d
and usb-ohci code does.
1b1995d
1b1995d
Note that there already was some special code in place to handle this
1b1995d
for interrupt endpoints in the form of doing a return from
1b1995d
ehci_execute_complete() when reload == 0, but that for bulk transactions
1b1995d
this was not handled correctly (where as for example the usb-ccid device does
1b1995d
return USB_RET_NAK for bulk packets).
1b1995d
1b1995d
Besides that the code in ehci_execute_complete() decrement nakcnt by 1
1b1995d
on a packet result of USB_RET_NAK, but
1b1995d
-since the transaction got marked as finished,
1b1995d
 nakcnt would never be decremented again
1b1995d
-there is no code checking for nakcnt becoming 0
1b1995d
-there is no use in re-trying the transaction within the same usb frame /
1b1995d
 usb-ehci frame-timer call, since the status of emulated devices won't change
1b1995d
 as long as the usb-ehci frame-timer is running
1b1995d
So we should simply set the nakcnt to 0 when we get a USB_RET_NAK, thus
1b1995d
claiming that we've tried reload times (or as many times as possible if
1b1995d
reload is 0).
1b1995d
1b1995d
Besides the code in ehci_execute_complete() handling USB_RET_NAK there
1b1995d
was also code handling it in ehci_state_executing(), which calls
1b1995d
ehci_execute_complete(), and then does its own handling on top of the handling
1b1995d
in ehci_execute_complete(), this code would decrement nakcnt *again* (if not
1b1995d
already 0), or restore the reload value (which was never changed) on success.
1b1995d
1b1995d
Since the double decrement was wrong to begin with, and is no longer needed
1b1995d
now that we set nakcnt directly to 0 on USB_RET_NAK, and the restore of reload
1b1995d
is not needed either, this patch simply removes all nakcnt handling from
1b1995d
ehci_state_executing().
1b1995d
1b1995d
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
1b1995d
---
1b1995d
 hw/usb-ehci.c |   32 ++++----------------------------
1b1995d
 1 file changed, 4 insertions(+), 28 deletions(-)
1b1995d
1b1995d
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
1b1995d
index 92cdf2a..aa6fae5 100644
1b1995d
--- a/hw/usb-ehci.c
1b1995d
+++ b/hw/usb-ehci.c
1b1995d
@@ -1269,8 +1269,6 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet)
1b1995d
 
1b1995d
 static void ehci_execute_complete(EHCIQueue *q)
1b1995d
 {
1b1995d
-    int reload;
1b1995d
-
1b1995d
     assert(q->async != EHCI_ASYNC_INFLIGHT);
1b1995d
     q->async = EHCI_ASYNC_NONE;
1b1995d
 
1b1995d
@@ -1289,16 +1287,8 @@ static void ehci_execute_complete(EHCIQueue *q)
1b1995d
             ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
1b1995d
             break;
1b1995d
         case USB_RET_NAK:
1b1995d
-            /* 4.10.3 */
1b1995d
-            reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
1b1995d
-            if ((q->pid == USB_TOKEN_IN) && reload) {
1b1995d
-                int nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
1b1995d
-                nakcnt--;
1b1995d
-                set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
1b1995d
-            } else if (!reload) {
1b1995d
-                return;
1b1995d
-            }
1b1995d
-            break;
1b1995d
+            set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT);
1b1995d
+            return; /* We're not done yet with this transaction */
1b1995d
         case USB_RET_BABBLE:
1b1995d
             q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE);
1b1995d
             ehci_record_interrupt(q->ehci, USBSTS_ERRINT);
1b1995d
@@ -1331,7 +1321,7 @@ static void ehci_execute_complete(EHCIQueue *q)
1b1995d
     q->qh.token ^= QTD_TOKEN_DTOGGLE;
1b1995d
     q->qh.token &= ~QTD_TOKEN_ACTIVE;
1b1995d
 
1b1995d
-    if ((q->usb_status != USB_RET_NAK) && (q->qh.token & QTD_TOKEN_IOC)) {
1b1995d
+    if (q->qh.token & QTD_TOKEN_IOC) {
1b1995d
         ehci_record_interrupt(q->ehci, USBSTS_INT);
1b1995d
     }
1b1995d
 }
1b1995d
@@ -1905,7 +1895,6 @@ out:
1b1995d
 static int ehci_state_executing(EHCIQueue *q, int async)
1b1995d
 {
1b1995d
     int again = 0;
1b1995d
-    int reload, nakcnt;
1b1995d
 
1b1995d
     ehci_execute_complete(q);
1b1995d
     if (q->usb_status == USB_RET_ASYNC) {
1b1995d
@@ -1925,21 +1914,8 @@ static int ehci_state_executing(EHCIQueue *q, int async)
1b1995d
         // counter decrements to 0
1b1995d
     }
1b1995d
 
1b1995d
-    reload = get_field(q->qh.epchar, QH_EPCHAR_RL);
1b1995d
-    if (reload) {
1b1995d
-        nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT);
1b1995d
-        if (q->usb_status == USB_RET_NAK) {
1b1995d
-            if (nakcnt) {
1b1995d
-                nakcnt--;
1b1995d
-            }
1b1995d
-        } else {
1b1995d
-            nakcnt = reload;
1b1995d
-        }
1b1995d
-        set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT);
1b1995d
-    }
1b1995d
-
1b1995d
     /* 4.10.5 */
1b1995d
-    if ((q->usb_status == USB_RET_NAK) || (q->qh.token & QTD_TOKEN_ACTIVE)) {
1b1995d
+    if (q->usb_status == USB_RET_NAK) {
1b1995d
         ehci_set_state(q->ehci, async, EST_HORIZONTALQH);
1b1995d
     } else {
1b1995d
         ehci_set_state(q->ehci, async, EST_WRITEBACK);
1b1995d
-- 
1b1995d
1.7.9.3
1b1995d