diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2014-11-07 14:06:44 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2014-11-07 14:06:44 +0000 |
commit | 388f55252f2d5d103ea95d789b2402857ffb9999 (patch) | |
tree | e559f73fdff0581e2410526bf83f9f2f80c810d6 /sys/dev/usb | |
parent | e887c8718d124be600c83add78e0d76c9ef0afa9 (diff) |
Prevent a race when submitting a command by using the appropriate spl
protection.
Fix a panic reported by Patrick Wildt.
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/xhci.c | 22 |
1 files changed, 13 insertions, 9 deletions
diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c index 204bc3e190a..c774bfc8331 100644 --- a/sys/dev/usb/xhci.c +++ b/sys/dev/usb/xhci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xhci.c,v 1.34 2014/11/01 18:21:07 mpi Exp $ */ +/* $OpenBSD: xhci.c,v 1.35 2014/11/07 14:06:43 mpi Exp $ */ /* * Copyright (c) 2014 Martin Pieuchot @@ -1381,39 +1381,43 @@ int xhci_command_submit(struct xhci_softc *sc, struct xhci_trb *trb0, int timeout) { struct xhci_trb *trb; - int error = 0; + int s, error = 0; KASSERT(timeout == 0 || sc->sc_cmd_trb == NULL); trb0->trb_flags |= htole32(sc->sc_cmd_ring.toggle); trb = xhci_ring_dequeue(sc, &sc->sc_cmd_ring, 0); + if (trb == NULL) + return (EAGAIN); memcpy(trb, trb0, sizeof(struct xhci_trb)); usb_syncmem(&sc->sc_cmd_ring.dma, TRBOFF(sc->sc_cmd_ring, trb), sizeof(struct xhci_trb), BUS_DMASYNC_PREWRITE); - if (timeout) - sc->sc_cmd_trb = trb; - - XDWRITE4(sc, XHCI_DOORBELL(0), 0); - - if (timeout == 0) + if (timeout == 0) { + XDWRITE4(sc, XHCI_DOORBELL(0), 0); return (0); + } assertwaitok(); + s = splusb(); + sc->sc_cmd_trb = trb; + XDWRITE4(sc, XHCI_DOORBELL(0), 0); error = tsleep(&sc->sc_cmd_trb, PZERO, "xhcicmd", (timeout*hz+999)/ 1000 + 1); if (error) { #ifdef XHCI_DEBUG printf("%s: tsleep() = %d\n", __func__, error); - printf("cmd = %d " ,XHCI_TRB_TYPE(letoh32(trb->trb_flags))); + printf("cmd = %d ", XHCI_TRB_TYPE(letoh32(trb->trb_flags))); xhci_dump_trb(trb); #endif KASSERT(sc->sc_cmd_trb == trb); sc->sc_cmd_trb = NULL; + splx(s); return (error); } + splx(s); memcpy(trb0, &sc->sc_result_trb, sizeof(struct xhci_trb)); |