From: Kevin O'Connor Date: Tue, 10 Nov 2015 13:50:52 +0000 (-0500) Subject: xhci: Check for device disconnects during USB2 reset polling X-Git-Tag: rel-1.9.1~8 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=fe4154e31cda747827c051cbd2ba1a537469ab9f;p=seabios.git xhci: Check for device disconnects during USB2 reset polling Some XHCI controllers register super-speed devices on high-speed ports and then disconnect them when the super-speed detection completes. Make sure to recognize these disconnect events during the reset process. Signed-off-by: Kevin O'Connor (cherry picked from commit aa34e4e52fb65abb4ef8539660f05b4d52fb1f6f) --- diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index 173dff1..945b462 100644 --- a/src/hw/usb-xhci.c +++ b/src/hw/usb-xhci.c @@ -351,6 +351,9 @@ xhci_hub_reset(struct usbhub_s *hub, u32 port) struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb); u32 portsc = readl(&xhci->pr[port].portsc); int rc; + if (!(portsc & XHCI_PORTSC_CCS)) + // Device no longer connected?! + return -1; switch (xhci_get_field(portsc, XHCI_PORTSC_PLS)) { case PLS_U0: @@ -360,11 +363,22 @@ xhci_hub_reset(struct usbhub_s *hub, u32 port) case PLS_POLLING: // A USB2 port - perform device reset and wait for completion xhci_print_port_state(3, __func__, port, portsc); - portsc |= XHCI_PORTSC_PR; - writel(&xhci->pr[port].portsc, portsc); - if (wait_bit(&xhci->pr[port].portsc, XHCI_PORTSC_PED, XHCI_PORTSC_PED, 100) != 0) - return -1; - portsc = readl(&xhci->pr[port].portsc); + writel(&xhci->pr[port].portsc, portsc | XHCI_PORTSC_PR); + u32 end = timer_calc(100); + for (;;) { + portsc = readl(&xhci->pr[port].portsc); + if (!(portsc & XHCI_PORTSC_CCS)) + // Device disconnected during reset + return -1; + if (portsc & XHCI_PORTSC_PED) + // Reset complete + break; + if (timer_check(end)) { + warn_timeout(); + return -1; + } + yield(); + } rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)]; break; default: