Module Name: src
Committed By: skrll
Date: Sun Jun 5 09:16:02 UTC 2016
Modified Files:
src/sys/dev/usb: xhci.c
Log Message:
PR/51202: XHCI driver sends stale TRBs from a pipe previously opened
A similar patch was sent to me by t-hash and the xhci_setup_ctx is taken
from that.
To generate a diff of this commit:
cvs rdiff -u -r1.54 -r1.55 src/sys/dev/usb/xhci.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/usb/xhci.c
diff -u src/sys/dev/usb/xhci.c:1.54 src/sys/dev/usb/xhci.c:1.55
--- src/sys/dev/usb/xhci.c:1.54 Sun Jun 5 08:25:05 2016
+++ src/sys/dev/usb/xhci.c Sun Jun 5 09:16:02 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: xhci.c,v 1.54 2016/06/05 08:25:05 skrll Exp $ */
+/* $NetBSD: xhci.c,v 1.55 2016/06/05 09:16:02 skrll Exp $ */
/*
* Copyright (c) 2013 Jonathan A. Kollasch
@@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.54 2016/06/05 08:25:05 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.55 2016/06/05 09:16:02 skrll Exp $");
#ifdef _KERNEL_OPT
#include "opt_usb.h"
@@ -142,6 +142,7 @@ static usbd_status xhci_configure_endpoi
static usbd_status xhci_reset_endpoint(struct usbd_pipe *);
static usbd_status xhci_stop_endpoint(struct usbd_pipe *);
+static void xhci_host_dequeue(struct xhci_ring * const);
static usbd_status xhci_set_dequeue(struct usbd_pipe *);
static usbd_status xhci_do_command(struct xhci_softc * const,
@@ -1500,6 +1501,9 @@ xhci_close_pipe(struct usbd_pipe *pipe)
cp = xhci_slot_get_icv(sc, xs, xhci_dci_to_ici(XHCI_DCI_SLOT));
cp[0] = htole32(XHCI_SCTX_0_CTX_NUM_SET(dci));
+ /* configure ep context performs an implicit dequeue */
+ xhci_host_dequeue(&xs->xs_ep[dci].xe_tr);
+
/* sync input contexts before they are read from memory */
usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE);
@@ -1545,6 +1549,19 @@ xhci_abort_xfer(struct usbd_xfer *xfer,
KASSERT(mutex_owned(&sc->sc_lock));
}
+static void
+xhci_host_dequeue(struct xhci_ring * const xr)
+{
+ /* When dequeueing the controller, update our struct copy too */
+ memset(xr->xr_trb, 0, xr->xr_ntrb * XHCI_TRB_SIZE);
+ usb_syncmem(&xr->xr_dma, 0, xr->xr_ntrb * XHCI_TRB_SIZE,
+ BUS_DMASYNC_PREWRITE);
+ memset(xr->xr_cookies, 0, xr->xr_ntrb * sizeof(*xr->xr_cookies));
+
+ xr->xr_ep = 0;
+ xr->xr_cs = 1;
+}
+
/*
* Recover STALLed endpoint.
* xHCI 1.1 sect 4.10.2.1
@@ -2173,11 +2190,8 @@ xhci_ring_init(struct xhci_softc * const
xr->xr_cookies = kmem_zalloc(sizeof(*xr->xr_cookies) * ntrb, KM_SLEEP);
xr->xr_trb = xhci_ring_trbv(xr, 0);
xr->xr_ntrb = ntrb;
- xr->xr_ep = 0;
- xr->xr_cs = 1;
- memset(xr->xr_trb, 0, size);
- usb_syncmem(&xr->xr_dma, 0, size, BUS_DMASYNC_PREWRITE);
xr->is_halted = false;
+ xhci_host_dequeue(xr);
return USBD_NORMAL_COMPLETION;
}
@@ -2751,6 +2765,7 @@ xhci_setup_ctx(struct usbd_pipe *pipe)
DPRINTFN(4, "setting ival %u MaxBurst %#x",
XHCI_EPCTX_0_IVAL_GET(cp[0]), XHCI_EPCTX_1_MAXB_GET(cp[1]), 0, 0);
+ /* rewind TR dequeue pointer in xHC */
/* can't use xhci_ep_get_dci() yet? */
*(uint64_t *)(&cp[2]) = htole64(
xhci_ring_trbp(&xs->xs_ep[dci].xe_tr, 0) |
@@ -2760,6 +2775,12 @@ xhci_setup_ctx(struct usbd_pipe *pipe)
cp[1] = htole32(cp[1]);
cp[4] = htole32(cp[4]);
+ /* rewind TR dequeue pointer in driver */
+ struct xhci_ring *xr = &xs->xs_ep[dci].xe_tr;
+ mutex_enter(&xr->xr_lock);
+ xhci_host_dequeue(xr);
+ mutex_exit(&xr->xr_lock);
+
/* sync input contexts before they are read from memory */
usb_syncmem(&xs->xs_ic_dma, 0, sc->sc_pgsz, BUS_DMASYNC_PREWRITE);
}