diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2024-08-15 17:17:06 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2024-08-15 17:17:06 +0000 |
commit | db78bb79e46f57c5dbb0351a3fd2a9f486ee5320 (patch) | |
tree | f037897a98007cdc1ace7aeff497f3a5116d49c0 /sys/dev/usb | |
parent | f8527be07957483b0ff103642f9f58938e9936a2 (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.c | 30 | ||||
-rw-r--r-- | 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 */ |