From b7480ee071b510fb22b3c1d4f8281d213abfcfba Mon Sep 17 00:00:00 2001 From: hselasky Date: Tue, 14 Mar 2017 15:28:59 +0000 Subject: [PATCH] MFC r312424: Fix problem with suspend and resume when using Skylake chipsets. Make sure the XHCI controller is reset after halting it. The problem is clearly a BIOS bug as the suspend and resume is failing without loading the XHCI driver. The same happens when using Linux and the XHCI driver is not loaded. Submitted by: Yanko Yankulov PR: 216261 git-svn-id: svn://svn.freebsd.org/base/stable/10@315252 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/usb/controller/xhci.c | 49 +++++++++++++++++++++---------- sys/dev/usb/controller/xhci.h | 1 + sys/dev/usb/controller/xhci_pci.c | 1 + 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c index 2376cee2a..14db80538 100644 --- a/sys/dev/usb/controller/xhci.c +++ b/sys/dev/usb/controller/xhci.c @@ -352,6 +352,7 @@ xhci_start_controller(struct xhci_softc *sc) struct usb_page_search buf_res; struct xhci_hw_root *phwr; struct xhci_dev_ctx_addr *pdctxa; + usb_error_t err; uint64_t addr; uint32_t temp; uint16_t i; @@ -363,22 +364,9 @@ xhci_start_controller(struct xhci_softc *sc) sc->sc_command_ccs = 1; sc->sc_command_idx = 0; - /* Reset controller */ - XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_HCRST); - - for (i = 0; i != 100; i++) { - usb_pause_mtx(NULL, hz / 100); - temp = (XREAD4(sc, oper, XHCI_USBCMD) & XHCI_CMD_HCRST) | - (XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_CNR); - if (!temp) - break; - } - - if (temp) { - device_printf(sc->sc_bus.parent, "Controller " - "reset timeout.\n"); - return (USB_ERR_IOERROR); - } + err = xhci_reset_controller(sc); + if (err) + return (err); /* set up number of device slots */ DPRINTF("CONFIG=0x%08x -> 0x%08x\n", @@ -525,6 +513,33 @@ xhci_halt_controller(struct xhci_softc *sc) return (0); } +usb_error_t +xhci_reset_controller(struct xhci_softc *sc) +{ + uint32_t temp = 0; + uint16_t i; + + DPRINTF("\n"); + + /* Reset controller */ + XWRITE4(sc, oper, XHCI_USBCMD, XHCI_CMD_HCRST); + + for (i = 0; i != 100; i++) { + usb_pause_mtx(NULL, hz / 100); + temp = (XREAD4(sc, oper, XHCI_USBCMD) & XHCI_CMD_HCRST) | + (XREAD4(sc, oper, XHCI_USBSTS) & XHCI_STS_CNR); + if (!temp) + break; + } + + if (temp) { + device_printf(sc->sc_bus.parent, "Controller " + "reset timeout.\n"); + return (USB_ERR_IOERROR); + } + return (0); +} + usb_error_t xhci_init(struct xhci_softc *sc, device_t self, uint8_t dma32) { @@ -676,10 +691,12 @@ xhci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) case USB_HW_POWER_SUSPEND: DPRINTF("Stopping the XHCI\n"); xhci_halt_controller(sc); + xhci_reset_controller(sc); break; case USB_HW_POWER_SHUTDOWN: DPRINTF("Stopping the XHCI\n"); xhci_halt_controller(sc); + xhci_reset_controller(sc); break; case USB_HW_POWER_RESUME: DPRINTF("Starting the XHCI\n"); diff --git a/sys/dev/usb/controller/xhci.h b/sys/dev/usb/controller/xhci.h index c50e8520f..f08c24763 100644 --- a/sys/dev/usb/controller/xhci.h +++ b/sys/dev/usb/controller/xhci.h @@ -524,6 +524,7 @@ struct xhci_softc { uint8_t xhci_use_polling(void); usb_error_t xhci_halt_controller(struct xhci_softc *); +usb_error_t xhci_reset_controller(struct xhci_softc *); usb_error_t xhci_init(struct xhci_softc *, device_t, uint8_t); usb_error_t xhci_start_controller(struct xhci_softc *); void xhci_interrupt(struct xhci_softc *); diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c index 967ba862f..43bfb5daf 100644 --- a/sys/dev/usb/controller/xhci_pci.c +++ b/sys/dev/usb/controller/xhci_pci.c @@ -326,6 +326,7 @@ xhci_pci_detach(device_t self) usb_callout_drain(&sc->sc_callout); xhci_halt_controller(sc); + xhci_reset_controller(sc); pci_disable_busmaster(self); -- 2.45.0