usb: bugfixes for xhci, usb pass-through and usb redirection.

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJeHGtbAAoJEEy22O7T6HE43vQQANtKv7pd2FsvgXsXc8nK1VOP
 oiGQdL96pUCHHQvPWOE9z+PhmwCoyJ3NSE2p1iDkiIHqyNykZSvlO9FADwPeKnUu
 b5oJpj1Joewrzdb7N8/Fs0TVq6/4KFiTXUGf1mdAi1TIrFDGOCtLllQMOj2nlMuV
 kfCKd8hbv41OSy4buDZb7BA4sKREynfZneKvFwx/0Er1Xv1wjIPIHgnZiDSqEQf4
 /uXGBdYIdMPTaHAK0NJfM1OjIMmjLnd30w4MhjhJRUeRScQhD0+DOZiSmV1mJb6P
 ddLVystut5+wPPH8cadKqCW6xxwkwaxYe8Mz97j0dyHG4dt9n4iwOb+BjNxRRG/S
 kLK5TlStnRk8PyzH0qhHKH2YtTpHVfULEM7FRS2MQ6fSLrC8RaW6i9WzfLF+ye42
 F7G6AYjU5Re5pFO2kqhcvE/UEFV0Al+AWjRzQDDq0bnRflGz4PCZgckOBfE6OjNp
 eUpMbfCAeaWcatIIIZYGbl1HXDAdgig4REpJCoM8HgHZV2Fc2e8p/BeXm60t2XV8
 YNjfg1gyUSfL1gEYZno+L8ixO5tv4Y+RXRTjt8Hx6zQkNEbEW4nJf7A31SiN2/b3
 1l9rPPsn43q3KIOC3Ylg57tSDUQnTBRrCThy1/wYrp9Av8hqb7dNrjFvkoLHRY5x
 R9cU7rsvnPRqwWbZVUOl
 =zECN
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kraxel/tags/usb-20200113-pull-request' into staging

usb: bugfixes for xhci, usb pass-through and usb redirection.

# gpg: Signature made Mon 13 Jan 2020 13:06:35 GMT
# gpg:                using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/usb-20200113-pull-request:
  xhci: recheck slot status
  xhci: Fix memory leak in xhci_kick_epctx when poweroff GuestOS
  usbredir: Prevent recursion in usbredir_write
  usb-redir: remove 'remote wakeup' flag from configuration descriptor
  usb-host: remove 'remote wakeup' flag from configuration descriptor

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-01-13 14:19:56 +00:00
commit 3c8a657598
5 changed files with 65 additions and 3 deletions

View File

@ -32,6 +32,8 @@ GlobalProperty hw_compat_4_2[] = {
{ "virtio-blk-device", "seg-max-adjust", "off"},
{ "virtio-scsi-device", "seg_max_adjust", "off"},
{ "vhost-blk-device", "seg_max_adjust", "off"},
{ "usb-host", "suppress-remote-wake", "off" },
{ "usb-redir", "suppress-remote-wake", "off" },
};
const size_t hw_compat_4_2_len = G_N_ELEMENTS(hw_compat_4_2);

View File

@ -1861,6 +1861,13 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
xhci_kick_epctx(epctx, streamid);
}
static bool xhci_slot_ok(XHCIState *xhci, int slotid)
{
return (xhci->slots[slotid - 1].uport &&
xhci->slots[slotid - 1].uport->dev &&
xhci->slots[slotid - 1].uport->dev->attached);
}
static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
{
XHCIState *xhci = epctx->xhci;
@ -1878,9 +1885,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
/* If the device has been detached, but the guest has not noticed this
yet the 2 above checks will succeed, but we must NOT continue */
if (!xhci->slots[epctx->slotid - 1].uport ||
!xhci->slots[epctx->slotid - 1].uport->dev ||
!xhci->slots[epctx->slotid - 1].uport->dev->attached) {
if (!xhci_slot_ok(xhci, epctx->slotid)) {
return;
}
@ -1987,6 +1992,10 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
} else {
xhci_fire_transfer(xhci, xfer, epctx);
}
if (!xhci_slot_ok(xhci, epctx->slotid)) {
/* surprise removal -> stop processing */
break;
}
if (xfer->complete) {
/* update ring dequeue ptr */
xhci_set_ep_state(xhci, epctx, stctx, epctx->state);
@ -2000,6 +2009,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
if (xfer != NULL && xfer->running_retry) {
DPRINTF("xhci: xfer nacked, stopping schedule\n");
epctx->retry = xfer;
xhci_xfer_unmap(xfer);
break;
}
if (count++ > TRANSFER_LIMIT) {

View File

@ -88,6 +88,7 @@ struct USBHostDevice {
bool needs_autoscan;
bool allow_one_guest_reset;
bool allow_all_guest_resets;
bool suppress_remote_wake;
/* state */
QTAILQ_ENTRY(USBHostDevice) next;
@ -386,6 +387,8 @@ static void LIBUSB_CALL usb_host_req_complete_ctrl(struct libusb_transfer *xfer)
r->p->status = status_map[xfer->status];
r->p->actual_length = xfer->actual_length;
if (r->in && xfer->actual_length) {
USBDevice *udev = USB_DEVICE(s);
struct libusb_config_descriptor *conf = (void *)r->cbuf;
memcpy(r->cbuf, r->buffer + 8, xfer->actual_length);
/* Fix up USB-3 ep0 maxpacket size to allow superspeed connected devices
@ -394,6 +397,21 @@ static void LIBUSB_CALL usb_host_req_complete_ctrl(struct libusb_transfer *xfer)
r->cbuf[7] == 9) {
r->cbuf[7] = 64;
}
/*
*If this is GET_DESCRIPTOR request for configuration descriptor,
* remove 'remote wakeup' flag from it to prevent idle power down
* in Windows guest
*/
if (s->suppress_remote_wake &&
udev->setup_buf[0] == USB_DIR_IN &&
udev->setup_buf[1] == USB_REQ_GET_DESCRIPTOR &&
udev->setup_buf[3] == USB_DT_CONFIG && udev->setup_buf[2] == 0 &&
xfer->actual_length >
offsetof(struct libusb_config_descriptor, bmAttributes) &&
(conf->bmAttributes & USB_CFG_ATT_WAKEUP)) {
trace_usb_host_remote_wakeup_removed(s->bus_num, s->addr);
conf->bmAttributes &= ~USB_CFG_ATT_WAKEUP;
}
}
trace_usb_host_req_complete(s->bus_num, s->addr, r->p,
r->p->status, r->p->actual_length);
@ -1596,6 +1614,8 @@ static Property usb_host_dev_properties[] = {
LIBUSB_LOG_LEVEL_WARNING),
DEFINE_PROP_BIT("pipeline", USBHostDevice, options,
USB_HOST_OPT_PIPELINE, true),
DEFINE_PROP_BOOL("suppress-remote-wake", USBHostDevice,
suppress_remote_wake, true),
DEFINE_PROP_END_OF_LIST(),
};

View File

@ -113,6 +113,8 @@ struct USBRedirDevice {
/* Properties */
CharBackend cs;
bool enable_streams;
bool suppress_remote_wake;
bool in_write;
uint8_t debug;
int32_t bootindex;
char *filter_str;
@ -290,6 +292,13 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
return 0;
}
/* Recursion check */
if (dev->in_write) {
DPRINTF("usbredir_write recursion\n");
return 0;
}
dev->in_write = true;
r = qemu_chr_fe_write(&dev->cs, data, count);
if (r < count) {
if (!dev->watch) {
@ -300,6 +309,7 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
r = 0;
}
}
dev->in_write = false;
return r;
}
@ -1994,6 +2004,23 @@ static void usbredir_control_packet(void *priv, uint64_t id,
memcpy(dev->dev.data_buf, data, data_len);
}
p->actual_length = len;
/*
* If this is GET_DESCRIPTOR request for configuration descriptor,
* remove 'remote wakeup' flag from it to prevent idle power down
* in Windows guest
*/
if (dev->suppress_remote_wake &&
control_packet->requesttype == USB_DIR_IN &&
control_packet->request == USB_REQ_GET_DESCRIPTOR &&
control_packet->value == (USB_DT_CONFIG << 8) &&
control_packet->index == 0 &&
/* bmAttributes field of config descriptor */
len > 7 && (dev->dev.data_buf[7] & USB_CFG_ATT_WAKEUP)) {
DPRINTF("Removed remote wake %04X:%04X\n",
dev->device_info.vendor_id,
dev->device_info.product_id);
dev->dev.data_buf[7] &= ~USB_CFG_ATT_WAKEUP;
}
usb_generic_async_ctrl_complete(&dev->dev, p);
}
free(data);
@ -2535,6 +2562,8 @@ static Property usbredir_properties[] = {
DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, usbredirparser_warning),
DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str),
DEFINE_PROP_BOOL("streams", USBRedirDevice, enable_streams, true),
DEFINE_PROP_BOOL("suppress-remote-wake", USBRedirDevice,
suppress_remote_wake, true),
DEFINE_PROP_END_OF_LIST(),
};

View File

@ -266,3 +266,4 @@ usb_host_parse_config(int bus, int addr, int value, int active) "dev %d:%d, valu
usb_host_parse_interface(int bus, int addr, int num, int alt, int active) "dev %d:%d, num %d, alt %d, active %d"
usb_host_parse_endpoint(int bus, int addr, int ep, const char *dir, const char *type, int active) "dev %d:%d, ep %d, %s, %s, active %d"
usb_host_parse_error(int bus, int addr, const char *errmsg) "dev %d:%d, msg %s"
usb_host_remote_wakeup_removed(int bus, int addr) "dev %d:%d"