From 868dd50c5c24f4851cf699c471dcc3c96623e91b Mon Sep 17 00:00:00 2001 From: kettenis Date: Thu, 15 Aug 2024 17:17:05 +0000 Subject: [PATCH] Upon resume, restore the saved state. Newer Intel xHCI controller (e.g. those on Meteor Lake) need this, otherwise the ports are dead after resume. ok mglocker@, deraadt@ --- sys/dev/usb/xhci.c | 30 +++++++++++++++++++++++++----- sys/dev/usb/xhcivar.h | 3 ++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c index e2ca8e8056d..75792693b70 100644 --- a/sys/dev/usb/xhci.c +++ b/sys/dev/usb/xhci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xhci.c,v 1.132 2024/08/06 17:30:04 kettenis Exp $ */ +/* $OpenBSD: xhci.c,v 1.133 2024/08/15 17:17:05 kettenis Exp $ */ /* * Copyright (c) 2014-2015 Martin Pieuchot @@ -415,6 +415,7 @@ xhci_config(struct xhci_softc *sc) { uint64_t paddr; uint32_t hcr; + int i; /* Make sure to program a number of device slots we can handle. */ if (sc->sc_noslot > USB_MAX_DEVICES) @@ -457,6 +458,27 @@ xhci_config(struct xhci_softc *sc) DPRINTF(("%s: ERDP=%#x%#x\n", DEVNAME(sc), XRREAD4(sc, XHCI_ERDP_HI(0)), XRREAD4(sc, XHCI_ERDP_LO(0)))); + /* + * If we successfully saved the state during suspend, restore + * it here. Otherwise some Intel controllers don't function + * correctly after resume. + */ + if (sc->sc_saved_state) { + XOWRITE4(sc, XHCI_USBCMD, XHCI_CMD_CRS); /* Restore state */ + hcr = XOREAD4(sc, XHCI_USBSTS); + for (i = 0; i < 100; i++) { + usb_delay_ms(&sc->sc_bus, 1); + hcr = XOREAD4(sc, XHCI_USBSTS) & XHCI_STS_RSS; + if (!hcr) + break; + } + + if (hcr) + printf("%s: restore state timeout\n", DEVNAME(sc)); + + sc->sc_saved_state = 0; + } + /* Enable interrupts. */ hcr = XRREAD4(sc, XHCI_IMAN(0)); XRWRITE4(sc, XHCI_IMAN(0), hcr | XHCI_IMAN_INTR_ENA); @@ -603,10 +625,6 @@ xhci_suspend(struct xhci_softc *sc) * unless they have seen a save state command. This in turn * will prevent the SoC from reaching its lowest idle state. * So save the state here. - * - * Note that we don't restore this saved state anywhere. - * Instead we reset the controller and reinitialize it from - * scratch when we resume. */ XOWRITE4(sc, XHCI_USBCMD, XHCI_CMD_CSS); /* Save state */ @@ -624,6 +642,8 @@ xhci_suspend(struct xhci_softc *sc) return; } + sc->sc_saved_state = 1; + /* Disable interrupts. */ XRWRITE4(sc, XHCI_IMOD(0), 0); XRWRITE4(sc, XHCI_IMAN(0), 0); diff --git a/sys/dev/usb/xhcivar.h b/sys/dev/usb/xhcivar.h index d1a4a831389..cf1e86feb56 100644 --- a/sys/dev/usb/xhcivar.h +++ b/sys/dev/usb/xhcivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: xhcivar.h,v 1.14 2022/12/12 19:18:25 kettenis Exp $ */ +/* $OpenBSD: xhcivar.h,v 1.15 2024/08/15 17:17:05 kettenis Exp $ */ /* * Copyright (c) 2014 Martin Pieuchot @@ -89,6 +89,7 @@ struct xhci_softc { bus_size_t sc_size; int sc_dead; + int sc_saved_state; bus_size_t sc_oper_off; /* Operational Register space */ bus_size_t sc_runt_off; /* Runtime */ -- 2.20.1