diff options
author | 2020-06-30 10:21:59 +0000 | |
---|---|---|
committer | 2020-06-30 10:21:59 +0000 | |
commit | f748d23196a96dc6b23c160715086da88a58ad97 (patch) | |
tree | dbc288caf471a08f017ac9a2d4d50821ad0a5888 /sys/dev/usb/xhci.c | |
parent | Add size to free(9) call (diff) | |
download | wireguard-openbsd-f748d23196a96dc6b23c160715086da88a58ad97.tar.xz wireguard-openbsd-f748d23196a96dc6b23c160715086da88a58ad97.zip |
When a transfer times out, the TRB should be aborted, too. But still
the completion interrupt may already be pending while aborting.
Hence, in xhci_event_command() ignore events from a TRB that is not
the expected one. And don't let xhci_abort_command() yield the CPU.
ok mpi@
Diffstat (limited to 'sys/dev/usb/xhci.c')
-rw-r--r-- | sys/dev/usb/xhci.c | 29 |
1 files changed, 21 insertions, 8 deletions
diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c index 903e57039a0..9f138b4d0e3 100644 --- a/sys/dev/usb/xhci.c +++ b/sys/dev/usb/xhci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xhci.c,v 1.115 2020/06/24 09:43:20 patrick Exp $ */ +/* $OpenBSD: xhci.c,v 1.116 2020/06/30 10:21:59 gerhard Exp $ */ /* * Copyright (c) 2014-2015 Martin Pieuchot @@ -1048,10 +1048,16 @@ xhci_event_command(struct xhci_softc *sc, uint64_t paddr) case XHCI_CMD_ADDRESS_DEVICE: case XHCI_CMD_EVAL_CTX: case XHCI_CMD_NOOP: - /* All these commands are synchronous. */ - KASSERT(sc->sc_cmd_trb == trb); - sc->sc_cmd_trb = NULL; - wakeup(&sc->sc_cmd_trb); + /* + * All these commands are synchronous. + * + * If TRBs differ, this could be a delayed result after we + * gave up waiting for the expected TRB due to timeout. + */ + if (sc->sc_cmd_trb == trb) { + sc->sc_cmd_trb = NULL; + wakeup(&sc->sc_cmd_trb); + } break; default: DPRINTF(("%s: unexpected command %x\n", DEVNAME(sc), flags)); @@ -1874,7 +1880,14 @@ xhci_command_submit(struct xhci_softc *sc, struct xhci_trb *trb0, int timeout) printf("cmd = %d ", XHCI_TRB_TYPE(letoh32(trb->trb_flags))); xhci_dump_trb(trb); #endif - KASSERT(sc->sc_cmd_trb == trb); + KASSERT(sc->sc_cmd_trb == trb || sc->sc_cmd_trb == NULL); + /* + * Just because the timeout expired this does not mean that the + * TRB isn't active anymore! We could get an interrupt from + * this TRB later on and then wonder what to do with it. + * We'd rather abort it. + */ + xhci_command_abort(sc); sc->sc_cmd_trb = NULL; splx(s); return (error); @@ -1908,8 +1921,8 @@ xhci_command_abort(struct xhci_softc *sc) XOWRITE4(sc, XHCI_CRCR_LO, reg | XHCI_CRCR_LO_CA); XOWRITE4(sc, XHCI_CRCR_HI, 0); - for (i = 0; i < 250; i++) { - usb_delay_ms(&sc->sc_bus, 1); + for (i = 0; i < 2500; i++) { + DELAY(100); reg = XOREAD4(sc, XHCI_CRCR_LO) & XHCI_CRCR_LO_CRR; if (!reg) break; |