From c5f05895d34cd248b09969c250676edadd646d3d Mon Sep 17 00:00:00 2001 From: hselasky Date: Sat, 29 Oct 2011 12:39:05 +0000 Subject: [PATCH] MFC r226803: Fix suspend and resume of non-super-speed USB devices in the generic XHCI driver. There appears to be some minor logic missing for this feature to work. Approved by: re (kib) git-svn-id: svn://svn.freebsd.org/base/stable/9@226904 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/usb/controller/xhci.c | 15 ++++++++++++++- sys/dev/usb/controller/xhcireg.h | 2 +- sys/dev/usb/usb.h | 1 + sys/dev/usb/usb_hub.c | 1 + 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c index f6c8c0e24..0df4c4d17 100644 --- a/sys/dev/usb/controller/xhci.c +++ b/sys/dev/usb/controller/xhci.c @@ -3048,7 +3048,9 @@ xhci_roothub_exec(struct usb_device *udev, } port = XHCI_PORTSC(index); - v = XREAD4(sc, oper, port) & ~XHCI_PS_CLEAR; + v = XREAD4(sc, oper, port); + i = XHCI_PS_PLS_GET(v); + v &= ~XHCI_PS_CLEAR; switch (value) { case UHF_C_BH_PORT_RESET: @@ -3082,6 +3084,17 @@ xhci_roothub_exec(struct usb_device *udev, XWRITE4(sc, oper, port, v & ~XHCI_PS_PIC_SET(3)); break; case UHF_PORT_SUSPEND: + + /* U3 -> U15 */ + if (i == 3) { + XWRITE4(sc, oper, port, v | + XHCI_PS_PLS_SET(0xF) | XHCI_PS_LWS); + } + + /* wait 20ms for resume sequence to complete */ + usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 50); + + /* U0 */ XWRITE4(sc, oper, port, v | XHCI_PS_PLS_SET(0) | XHCI_PS_LWS); break; diff --git a/sys/dev/usb/controller/xhcireg.h b/sys/dev/usb/controller/xhcireg.h index 71c5c284a..8be502ef3 100644 --- a/sys/dev/usb/controller/xhcireg.h +++ b/sys/dev/usb/controller/xhcireg.h @@ -133,7 +133,7 @@ #define XHCI_PS_WOE 0x08000000 /* RW - wake on over-current enable */ #define XHCI_PS_DR 0x40000000 /* RO - device removable */ #define XHCI_PS_WPR 0x80000000U /* RW - warm port reset */ -#define XHCI_PS_CLEAR 0x80FF00F7U /* command bits */ +#define XHCI_PS_CLEAR 0x80FF01FFU /* command bits */ #define XHCI_PORTPMSC(n) (0x3F4 + (0x10 * (n))) /* XHCI status and control */ #define XHCI_PM3_U1TO_GET(x) (((x) >> 0) & 0xFF) /* RW - U1 timeout */ diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h index 89bc2c44a..6a9b12663 100644 --- a/sys/dev/usb/usb.h +++ b/sys/dev/usb/usb.h @@ -686,6 +686,7 @@ struct usb_port_status { #define UPS_PORT_LS_HOT_RST 0x09 #define UPS_PORT_LS_COMP_MODE 0x0A #define UPS_PORT_LS_LOOPBACK 0x0B +#define UPS_PORT_LS_RESUME 0x0F #define UPS_PORT_POWER 0x0100 #define UPS_LOW_SPEED 0x0200 #define UPS_HIGH_SPEED 0x0400 diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c index 12898ec26..5795d56bf 100644 --- a/sys/dev/usb/usb_hub.c +++ b/sys/dev/usb/usb_hub.c @@ -611,6 +611,7 @@ uhub_suspend_resume_port(struct uhub_softc *sc, uint8_t portno) switch (UPS_PORT_LINK_STATE_GET(sc->sc_st.port_status)) { case UPS_PORT_LS_U0: case UPS_PORT_LS_U1: + case UPS_PORT_LS_RESUME: is_suspend = 0; break; default: -- 2.45.0