summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/xhci.c
diff options
context:
space:
mode:
authorgerhard <gerhard@openbsd.org>2020-06-30 10:21:59 +0000
committergerhard <gerhard@openbsd.org>2020-06-30 10:21:59 +0000
commitf748d23196a96dc6b23c160715086da88a58ad97 (patch)
treedbc288caf471a08f017ac9a2d4d50821ad0a5888 /sys/dev/usb/xhci.c
parentAdd size to free(9) call (diff)
downloadwireguard-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.c29
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;