Skip to content

Commit

Permalink
usb/hcd-ehci: Fix error handling on missing device for iTD
Browse files Browse the repository at this point in the history
The EHCI Host Controller emulation attempt to locate the device
associated with a periodic isochronous transfer description (iTD) and
when this fail the host controller is reset.

But according the EHCI spec 1.0 section 5.15.2.4 Host System
Error, the host controller is supposed to reset itself only when it
failed to communicate with the Host (Operating System), like when
there's an error on the PCI bus. If a transaction fails, there's
nothing in the spec that say to reset the host controller.

This patch rework the error path so that the host controller can keep
working when the OS setup a bogus transaction, it also revert to the
behavior of the EHCI emulation to before commits:
e94682f ("ehci: check device is not NULL before calling usb_ep_get()")
7011bae ("usb: remove unnecessary NULL device check from usb_ep_get()")

The issue has been found while trying to passthrough a USB device to a
Windows Server 2012 Xen guest via "usb-ehci", which prevent the USB
device from working in Windows. ("usb-ehci" alone works, windows only
setup this weird periodic iTD to device 127 endpoint 15 when the USB
device is passthrough.)

Signed-off-by: Anthony PERARD <[email protected]>
Message-id: [email protected]
Signed-off-by: Gerd Hoffmann <[email protected]>
  • Loading branch information
anthonyper-ctx authored and kraxel committed Oct 19, 2020
1 parent 69958d8 commit ccee80c
Showing 1 changed file with 18 additions and 17 deletions.
35 changes: 18 additions & 17 deletions hw/usb/hcd-ehci.c
Original file line number Diff line number Diff line change
Expand Up @@ -1447,24 +1447,25 @@ static int ehci_process_itd(EHCIState *ehci,
dev = ehci_find_device(ehci, devaddr);
if (dev == NULL) {
ehci_trace_guest_bug(ehci, "no device found");
qemu_sglist_destroy(&ehci->isgl);
return -1;
}
pid = dir ? USB_TOKEN_IN : USB_TOKEN_OUT;
ep = usb_ep_get(dev, pid, endp);
if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) {
usb_packet_setup(&ehci->ipacket, pid, ep, 0, addr, false,
(itd->transact[i] & ITD_XACT_IOC) != 0);
if (usb_packet_map(&ehci->ipacket, &ehci->isgl)) {
qemu_sglist_destroy(&ehci->isgl);
return -1;
}
usb_handle_packet(dev, &ehci->ipacket);
usb_packet_unmap(&ehci->ipacket, &ehci->isgl);
} else {
DPRINTF("ISOCH: attempt to addess non-iso endpoint\n");
ehci->ipacket.status = USB_RET_NAK;
ehci->ipacket.status = USB_RET_NODEV;
ehci->ipacket.actual_length = 0;
} else {
pid = dir ? USB_TOKEN_IN : USB_TOKEN_OUT;
ep = usb_ep_get(dev, pid, endp);
if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) {
usb_packet_setup(&ehci->ipacket, pid, ep, 0, addr, false,
(itd->transact[i] & ITD_XACT_IOC) != 0);
if (usb_packet_map(&ehci->ipacket, &ehci->isgl)) {
qemu_sglist_destroy(&ehci->isgl);
return -1;
}
usb_handle_packet(dev, &ehci->ipacket);
usb_packet_unmap(&ehci->ipacket, &ehci->isgl);
} else {
DPRINTF("ISOCH: attempt to addess non-iso endpoint\n");
ehci->ipacket.status = USB_RET_NAK;
ehci->ipacket.actual_length = 0;
}
}
qemu_sglist_destroy(&ehci->isgl);

Expand Down

0 comments on commit ccee80c

Please sign in to comment.