summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2024-08-15 17:17:06 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2024-08-15 17:17:06 +0000
commitdb78bb79e46f57c5dbb0351a3fd2a9f486ee5320 (patch)
treef037897a98007cdc1ace7aeff497f3a5116d49c0 /sys/dev/usb
parentf8527be07957483b0ff103642f9f58938e9936a2 (diff)
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@
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/xhci.c30
-rw-r--r--sys/dev/usb/xhcivar.h3
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 */