Move the 100ms (USB_TIME_SIGATT) device detect polling from the ohci/uhci/usb-hub code to the generic usb_hub_port_setup() code. This extends the 100ms polling to ehci and xhci controllers. The code in usb_hub_port_setup() now compares USB_TIME_SIGATT to the start of usb_enumerate(), which may make boots faster when threads are disabled.
This patch also changes the meaning of the return code for hub->op->detect() calls. Now 1 indicates device found, 0 indicates device not found, and -1 indicates permanent failure.
Also, the xhci controller generic delay of 100ms is replaced with a 20ms root hub power stabilize time. This in combination with the 100ms for USB_TIME_SIGATT should be closer to the USB2 spec (the USB3 spec does not seem to declare an equivalent of USB_TIME_SIGATT).
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-ehci.c | 4 ++-- src/hw/usb-hub.c | 26 +++++--------------------- src/hw/usb-ohci.c | 17 ++--------------- src/hw/usb-uhci.c | 18 +++++------------- src/hw/usb-xhci.c | 8 +++++--- src/hw/usb.c | 21 +++++++++++++++------ src/hw/usb.h | 1 + 7 files changed, 35 insertions(+), 60 deletions(-)
diff --git a/src/hw/usb-ehci.c b/src/hw/usb-ehci.c index 86496ce..20e387b 100644 --- a/src/hw/usb-ehci.c +++ b/src/hw/usb-ehci.c @@ -52,7 +52,7 @@ ehci_hub_detect(struct usbhub_s *hub, u32 port)
if (!(portsc & PORT_CONNECT)) // No device present - return -1; + return 0;
if ((portsc & PORT_LINESTATUS_MASK) == PORT_LINESTATUS_KSTATE) { // low speed device @@ -66,7 +66,7 @@ ehci_hub_detect(struct usbhub_s *hub, u32 port) portsc = (portsc & ~PORT_PE) | PORT_RESET; writel(portreg, portsc); msleep(USB_TIME_DRSTR); - return 0; + return 1; }
// Reset device on port diff --git a/src/hw/usb-hub.c b/src/hw/usb-hub.c index 2a34e57..4731a91 100644 --- a/src/hw/usb-hub.c +++ b/src/hw/usb-hub.c @@ -72,29 +72,13 @@ get_port_status(struct usbhub_s *hub, int port, struct usb_port_status *sts) static int usb_hub_detect(struct usbhub_s *hub, u32 port) { - // Check periodically for a device connect. struct usb_port_status sts; - u32 end = timer_calc(USB_TIME_SIGATT); - for (;;) { - int ret = get_port_status(hub, port, &sts); - if (ret) - goto fail; - if (sts.wPortStatus & USB_PORT_STAT_CONNECTION) - // Device connected. - break; - if (timer_check(end)) - // No device found. - return -1; - msleep(5); + int ret = get_port_status(hub, port, &sts); + if (ret) { + dprintf(1, "Failure on hub port %d detect\n", port); + return -1; } - - // XXX - wait USB_TIME_ATTDB time? - - return 0; - -fail: - dprintf(1, "Failure on hub port %d detect\n", port); - return -1; + return (sts.wPortStatus & USB_PORT_STAT_CONNECTION) ? 1 : 0; }
// Disable port diff --git a/src/hw/usb-ohci.c b/src/hw/usb-ohci.c index 8089e13..7a22057 100644 --- a/src/hw/usb-ohci.c +++ b/src/hw/usb-ohci.c @@ -42,21 +42,8 @@ static int ohci_hub_detect(struct usbhub_s *hub, u32 port) { struct usb_ohci_s *cntl = container_of(hub->cntl, struct usb_ohci_s, usb); - u32 end = timer_calc(USB_TIME_SIGATT); - for (;;) { - u32 sts = readl(&cntl->regs->roothub_portstatus[port]); - if (sts & RH_PS_CCS) - // Device connected. - break; - if (timer_check(end)) - // No device found. - return -1; - msleep(5); - } - - // XXX - need to wait for USB_TIME_ATTDB if just powered up? - - return 0; + u32 sts = readl(&cntl->regs->roothub_portstatus[port]); + return (sts & RH_PS_CCS) ? 1 : 0; }
// Disable port diff --git a/src/hw/usb-uhci.c b/src/hw/usb-uhci.c index 406af90..a34f6db 100644 --- a/src/hw/usb-uhci.c +++ b/src/hw/usb-uhci.c @@ -43,25 +43,17 @@ uhci_hub_detect(struct usbhub_s *hub, u32 port) { struct usb_uhci_s *cntl = container_of(hub->cntl, struct usb_uhci_s, usb); u16 ioport = cntl->iobase + USBPORTSC1 + port * 2; - - u32 end = timer_calc(USB_TIME_SIGATT); - for (;;) { - u16 status = inw(ioport); - if (status & USBPORTSC_CCS) - // Device connected. - break; - if (timer_check(end)) - // No device found. - return -1; - msleep(5); - } + u16 status = inw(ioport); + if (!(status & USBPORTSC_CCS)) + // No device found. + return 0;
// XXX - if just powered up, need to wait for USB_TIME_ATTDB?
// Begin reset on port outw(USBPORTSC_PR, ioport); msleep(USB_TIME_DRSTR); - return 0; + return 1; }
// Reset device on port diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index 5f91d89..eafa4cb 100644 --- a/src/hw/usb-xhci.c +++ b/src/hw/usb-xhci.c @@ -320,6 +320,8 @@ static int wait_bit(u32 *reg, u32 mask, int value, u32 timeout) * Root hub ****************************************************************/
+#define XHCI_TIME_POSTPOWER 20 + // Check if device attached to port static void xhci_print_port_state(int loglevel, const char *prefix, u32 port, u32 portsc) @@ -339,7 +341,7 @@ xhci_hub_detect(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); - return (portsc & XHCI_PORTSC_CCS) ? 0 : -1; + return (portsc & XHCI_PORTSC_CCS) ? 1 : 0; }
// Reset device on port @@ -388,8 +390,8 @@ static struct usbhub_op_s xhci_hub_ops = { static int xhci_check_ports(struct usb_xhci_s *xhci) { - // FIXME: try find a more elegant way than a fixed delay - msleep(100); + // Wait for port power to stabilize. + msleep(XHCI_TIME_POSTPOWER);
struct usbhub_s hub; memset(&hub, 0, sizeof(hub)); diff --git a/src/hw/usb.c b/src/hw/usb.c index 930b5d9..153e153 100644 --- a/src/hw/usb.c +++ b/src/hw/usb.c @@ -404,15 +404,23 @@ usb_hub_port_setup(void *data) struct usbhub_s *hub = usbdev->hub; u32 port = usbdev->port;
- // Detect if device present (and possibly start reset) - int ret = hub->op->detect(hub, port); - if (ret) - // No device present - goto done; + for (;;) { + // Detect if device present (and possibly start reset) + int ret = hub->op->detect(hub, port); + if (ret > 0) + // Device connected. + break; + if (ret < 0 || timer_check(hub->detectend)) + // No device found. + goto done; + msleep(5); + } + + // XXX - wait USB_TIME_ATTDB time?
// Reset port and determine device speed mutex_lock(&hub->cntl->resetlock); - ret = hub->op->reset(hub, port); + int ret = hub->op->reset(hub, port); if (ret < 0) // Reset failed goto resetfail; @@ -447,6 +455,7 @@ usb_enumerate(struct usbhub_s *hub) { u32 portcount = hub->portcount; hub->threads = portcount; + hub->detectend = timer_calc(USB_TIME_SIGATT);
// Launch a thread for every port. int i; diff --git a/src/hw/usb.h b/src/hw/usb.h index 223e4d6..fe80ea6 100644 --- a/src/hw/usb.h +++ b/src/hw/usb.h @@ -46,6 +46,7 @@ struct usbhub_s { struct usbdevice_s *usbdev; struct usb_s *cntl; struct mutex_s lock; + u32 detectend; u32 port; u32 threads; u32 portcount;