Upon resume, restore the saved state. Newer Intel xHCI controller (e.g.
authorkettenis <kettenis@openbsd.org>
Thu, 15 Aug 2024 17:17:05 +0000 (17:17 +0000)
committerkettenis <kettenis@openbsd.org>
Thu, 15 Aug 2024 17:17:05 +0000 (17:17 +0000)
those on Meteor Lake) need this, otherwise the ports are dead after
resume.

ok mglocker@, deraadt@

sys/dev/usb/xhci.c
sys/dev/usb/xhcivar.h

index e2ca8e8..7579269 100644 (file)
@@ -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);
index d1a4a83..cf1e86f 100644 (file)
@@ -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 */