Blame SOURCES/kvm-Introduce-new-no_guest_reset-parameter-for-usb-host-.patch

b38b0f
From 7efd1d899d2478ad9fffcf0584907f38cd6d20ff Mon Sep 17 00:00:00 2001
69f3e1
From: Gerd Hoffmann <kraxel@redhat.com>
69f3e1
Date: Tue, 4 Jun 2019 05:12:43 +0100
b38b0f
Subject: [PATCH 1/8] Introduce new "no_guest_reset" parameter for usb-host
69f3e1
 device
69f3e1
69f3e1
RH-Author: Gerd Hoffmann <kraxel@redhat.com>
69f3e1
Message-id: <20190604051246.11374-2-kraxel@redhat.com>
69f3e1
Patchwork-id: 88470
69f3e1
O-Subject: [RHEL-8.1.0 qemu-kvm PATCH 1/4] Introduce new "no_guest_reset" parameter for usb-host device
b38b0f
Bugzilla: 1713677
69f3e1
RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
69f3e1
RH-Acked-by: Max Reitz <mreitz@redhat.com>
69f3e1
RH-Acked-by: Danilo de Paula <ddepaula@redhat.com>
69f3e1
69f3e1
From: Alexander Kappner <agk@godking.net>
69f3e1
69f3e1
With certain USB devices passed through via usb-host, a guest attempting to
69f3e1
reset a usb-host device can trigger a reset loop that renders the USB device
69f3e1
unusable. In my use case, the device was an iPhone XR that was passed through to
69f3e1
a Mac OS X Mojave guest. Upon connecting the device, the following happens:
69f3e1
69f3e1
1) Guest recognizes new device, sends reset to emulated USB host
69f3e1
2) QEMU's USB host sends reset to host kernel
69f3e1
3) Host kernel resets device
69f3e1
4) After reset, host kernel determines that some part of the device descriptor
69f3e1
has changed ("device firmware changed" in dmesg), so host kernel decides to
69f3e1
re-enumerate the device.
69f3e1
5) Re-enumeration causes QEMU to disconnect and reconnect the device in the
69f3e1
guest.
69f3e1
6) goto 1)
69f3e1
69f3e1
Here's from the host kernel (note the "device firmware changed" lines")
69f3e1
69f3e1
[3677704.473050] usb 1-1.3: new high-speed USB device number 53 using ehci-pci
69f3e1
[3677704.555594] usb 1-1.3: New USB device found, idVendor=05ac, idProduct=12a8, bcdDevice=11.08
69f3e1
[3677704.555599] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
69f3e1
[3677704.555602] usb 1-1.3: Product: iPhone
69f3e1
[3677704.555605] usb 1-1.3: Manufacturer: Apple Inc.
69f3e1
[3677704.555607] usb 1-1.3: SerialNumber: [[removed]]
69f3e1
[3677709.401040] usb 1-1.3: reset high-speed USB device number 53 using ehci-pci
69f3e1
[3677709.479486] usb 1-1.3: device firmware changed
69f3e1
[3677709.479842] usb 1-1.3: USB disconnect, device number 53
69f3e1
[3677709.546039] usb 1-1.3: new high-speed USB device number 54 using ehci-pci
69f3e1
[3677709.627471] usb 1-1.3: New USB device found, idVendor=05ac, idProduct=12a8, bcdDevice=11.08
69f3e1
[3677709.627476] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
69f3e1
[3677709.627479] usb 1-1.3: Product: iPhone
69f3e1
[3677709.627481] usb 1-1.3: Manufacturer: Apple Inc.
69f3e1
[3677709.627483] usb 1-1.3: SerialNumber: [[removed]]
69f3e1
[3677762.320044] usb 1-1.3: reset high-speed USB device number 54 using ehci-pci
69f3e1
[3677762.615630] usb 1-1.3: USB disconnect, device number 54
69f3e1
[3677762.787043] usb 1-1.3: new high-speed USB device number 55 using ehci-pci
69f3e1
[3677762.869016] usb 1-1.3: New USB device found, idVendor=05ac, idProduct=12a8, bcdDevice=11.08
69f3e1
[3677762.869024] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
69f3e1
[3677762.869028] usb 1-1.3: Product: iPhone
69f3e1
[3677762.869032] usb 1-1.3: Manufacturer: Apple Inc.
69f3e1
[3677762.869035] usb 1-1.3: SerialNumber: [[removed]]
69f3e1
[3677815.662036] usb 1-1.3: reset high-speed USB device number 55 using ehci-pci
69f3e1
69f3e1
Here's from QEMU:
69f3e1
69f3e1
libusb: error [_get_usbfs_fd] libusb couldn't open USB device /dev/bus/usb/005/022: No such file or directory
69f3e1
libusb: error [udev_hotplug_event] ignoring udev action bind
69f3e1
libusb: error [udev_hotplug_event] ignoring udev action bind
69f3e1
libusb: error [_open_sysfs_attr] open /sys/bus/usb/devices/5-1/bConfigurationValue failed ret=-1 errno=2
69f3e1
libusb: error [_get_usbfs_fd] File doesn't exist, wait 10 ms and try again
69f3e1
69f3e1
libusb: error [_get_usbfs_fd] libusb couldn't open USB device /dev/bus/usb/005/024: No such file or directory
69f3e1
libusb: error [udev_hotplug_event] ignoring udev action bind
69f3e1
libusb: error [udev_hotplug_event] ignoring udev action bind
69f3e1
libusb: error [_open_sysfs_attr] open /sys/bus/usb/devices/5-1/bConfigurationValue failed ret=-1 errno=2
69f3e1
libusb: error [_get_usbfs_fd] File doesn't exist, wait 10 ms and try again
69f3e1
69f3e1
libusb: error [_get_usbfs_fd] libusb couldn't open USB device /dev/bus/usb/005/026: No such file or directory
69f3e1
69f3e1
The result of this is that the device remains permanently unusable in the guest.
69f3e1
The same problem has been previously reported for an iPad:
69f3e1
https://stackoverflow.com/questions/52617634/how-do-i-get-qemu-usb-passthrough-to-work-for-ipad-iphone
69f3e1
69f3e1
This problem can be elegantly solved by interrupting step 2) above. Instead of
69f3e1
passing through the reset, QEMU simply ignores it. To allow this to be
69f3e1
configured on a per-device level,  a new parameter "no_guest_reset" is
69f3e1
introduced for the usb-host device. I can confirm that the configuration
69f3e1
described above (iPhone XS + Mojave guest) works flawlessly with
69f3e1
no_guest_reset=True specified.
69f3e1
69f3e1
Working command line for my scenario:
69f3e1
device_add usb-host,vendorid=0x05ac,productid=0x12a8,no_guest_reset=True,id=iphone
69f3e1
69f3e1
Best regards
69f3e1
Alexander
69f3e1
69f3e1
Signed-off-by: Alexander Kappner <agk@godking.net>
69f3e1
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
69f3e1
Message-id: 20190128140027.9448-1-kraxel@redhat.com
69f3e1
69f3e1
[ kraxel: rename parameter to "guest-reset" ]
69f3e1
69f3e1
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
69f3e1
(cherry picked from commit ba4c735b4fc74e309ce4b2551d258e442ef513a5)
69f3e1
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
69f3e1
---
69f3e1
 hw/usb/host-libusb.c | 7 ++++++-
69f3e1
 1 file changed, 6 insertions(+), 1 deletion(-)
69f3e1
69f3e1
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
69f3e1
index f31e9cb..d82a10a 100644
69f3e1
--- a/hw/usb/host-libusb.c
69f3e1
+++ b/hw/usb/host-libusb.c
69f3e1
@@ -82,7 +82,7 @@ struct USBHostDevice {
69f3e1
     uint32_t                         options;
69f3e1
     uint32_t                         loglevel;
69f3e1
     bool                             needs_autoscan;
69f3e1
-
69f3e1
+    bool                             allow_guest_reset;
69f3e1
     /* state */
69f3e1
     QTAILQ_ENTRY(USBHostDevice)      next;
69f3e1
     int                              seen, errcount;
69f3e1
@@ -1451,6 +1451,10 @@ static void usb_host_handle_reset(USBDevice *udev)
69f3e1
     USBHostDevice *s = USB_HOST_DEVICE(udev);
69f3e1
     int rc;
69f3e1
 
69f3e1
+    if (!s->allow_guest_reset) {
69f3e1
+        return;
69f3e1
+    }
69f3e1
+
69f3e1
     trace_usb_host_reset(s->bus_num, s->addr);
69f3e1
 
69f3e1
     rc = libusb_reset_device(s->dh);
69f3e1
@@ -1568,6 +1572,7 @@ static Property usb_host_dev_properties[] = {
69f3e1
     DEFINE_PROP_UINT32("productid", USBHostDevice, match.product_id, 0),
69f3e1
     DEFINE_PROP_UINT32("isobufs",  USBHostDevice, iso_urb_count,    4),
69f3e1
     DEFINE_PROP_UINT32("isobsize", USBHostDevice, iso_urb_frames,   32),
69f3e1
+    DEFINE_PROP_BOOL("guest-reset", USBHostDevice, allow_guest_reset, true),
69f3e1
     DEFINE_PROP_UINT32("loglevel",  USBHostDevice, loglevel,
69f3e1
                        LIBUSB_LOG_LEVEL_WARNING),
69f3e1
     DEFINE_PROP_BIT("pipeline",    USBHostDevice, options,
69f3e1
-- 
69f3e1
1.8.3.1
69f3e1