1b1995d
From 7a3acb928b617b33605c779e7df05c2c896844b1 Mon Sep 17 00:00:00 2001
1b1995d
From: Hans de Goede <hdegoede@redhat.com>
1b1995d
Date: Mon, 20 Feb 2012 16:27:47 +0100
1b1995d
Subject: [PATCH 126/140] usb-ehci: Handle ISO packets failing with an error
1b1995d
 other then NAK
1b1995d
1b1995d
Before this patch the ehci code was not checking for any other errors other
1b1995d
then USB_RET_NAK. This causes 2 problems:
1b1995d
1) Other errors are not reported to the guest.
1b1995d
2) When transactions with the ITD_XACT_IOC bit set completing with another
1b1995d
   error would not result in USBSTS_INT getting set.
1b1995d
1b1995d
I hit this problem when unplugging devices while iso data was streaming from
1b1995d
the device to the guest. When this happens it takes a while for the guest to
1b1995d
process the unplugging and remove ISO transactions from the ehci schedule, in
1b1995d
the mean time these transactions would complete with a result of USB_RET_NODEV,
1b1995d
which was not handled. This lead to the Linux guest's usb subsystem "hanging",
1b1995d
that is it would no longer see new usb devices getting plugged in and running
1b1995d
for example lsusb would lead to a stuck (D state) lsusb process. This patch
1b1995d
fixes this.
1b1995d
1b1995d
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
1b1995d
---
1b1995d
 hw/usb-ehci.c |   22 +++++++++++++++++++---
1b1995d
 1 file changed, 19 insertions(+), 3 deletions(-)
1b1995d
1b1995d
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
1b1995d
index 69bcc4b..a6b6ae5 100644
1b1995d
--- a/hw/usb-ehci.c
1b1995d
+++ b/hw/usb-ehci.c
1b1995d
@@ -1512,11 +1512,27 @@ static int ehci_process_itd(EHCIState *ehci,
1b1995d
                     /* IN */
1b1995d
                     set_field(&itd->transact[i], ret, ITD_XACT_LENGTH);
1b1995d
                 }
1b1995d
-
1b1995d
-                if (itd->transact[i] & ITD_XACT_IOC) {
1b1995d
-                    ehci_record_interrupt(ehci, USBSTS_INT);
1b1995d
+            } else {
1b1995d
+                switch (ret) {
1b1995d
+                default:
1b1995d
+                    fprintf(stderr, "Unexpected iso usb result: %d\n", ret);
1b1995d
+                    /* Fall through */
1b1995d
+                case USB_RET_NODEV:
1b1995d
+                    /* 3.3.2: XACTERR is only allowed on IN transactions */
1b1995d
+                    if (dir) {
1b1995d
+                        itd->transact[i] |= ITD_XACT_XACTERR;
1b1995d
+                        ehci_record_interrupt(ehci, USBSTS_ERRINT);
1b1995d
+                    }
1b1995d
+                    break;
1b1995d
+                case USB_RET_BABBLE:
1b1995d
+                    itd->transact[i] |= ITD_XACT_BABBLE;
1b1995d
+                    ehci_record_interrupt(ehci, USBSTS_ERRINT);
1b1995d
+                    break;
1b1995d
                 }
1b1995d
             }
1b1995d
+            if (itd->transact[i] & ITD_XACT_IOC) {
1b1995d
+                ehci_record_interrupt(ehci, USBSTS_INT);
1b1995d
+            }
1b1995d
             itd->transact[i] &= ~ITD_XACT_ACTIVE;
1b1995d
         }
1b1995d
     }
1b1995d
-- 
1b1995d
1.7.9.3
1b1995d