Page MenuHomeFreeBSD

D60432.id189006.diff
No OneTemporary

D60432.id189006.diff

diff --git a/usr.sbin/bhyve/pci_xhci.c b/usr.sbin/bhyve/pci_xhci.c
--- a/usr.sbin/bhyve/pci_xhci.c
+++ b/usr.sbin/bhyve/pci_xhci.c
@@ -38,6 +38,7 @@
#include <sys/types.h>
#include <sys/queue.h>
+#include <stdatomic.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -210,7 +211,16 @@
/* xHC operational registers */
struct pci_xhci_opregs {
uint32_t usbcmd; /* usb command */
- uint32_t usbsts; /* usb status */
+ _Atomic uint32_t usbsts; /* usb status: mutated from both the
+ * MMIO/vCPU thread and a backend's
+ * event thread (usb_mouse/usb_passthru
+ * hci_intr(), usb_passthru hci_event()).
+ * Every update here is an unconditional
+ * set/clear of independent bits, so
+ * this is atomic rather than mutex
+ * protected -- see port_mtx for why a
+ * mutex is unsafe to take from those
+ * callbacks. */
uint32_t pgsz; /* page size */
uint32_t dnctrl; /* device notification control */
uint64_t crcr; /* command ring control */
@@ -280,6 +290,38 @@
* which also needs this lock (under sc->mtx).
* Lock order: sc->mtx -> [xfer_lock ->]
* event_mtx */
+ pthread_mutex_t port_mtx; /* serialises portsc mutations across
+ * threads: portregs_write/reset_port/
+ * usbcmd_write (vCPU, under sc->mtx)
+ * vs. dev_event/dev_intr, called from
+ * a backend's own thread (usb_mouse's
+ * console thread, usb_passthru's libusb
+ * and hotplug threads). Leaf lock:
+ * never held across insert_event,
+ * assert_interrupt or a backend call. */
+ pthread_mutex_t intr_mtx; /* serialises the interrupter state
+ * (IMAN.IP, ERDP.EHB, USBSTS.EINT and
+ * the INTx line / MSI) between the
+ * vCPU's register writes and
+ * assert_interrupt() from a backend
+ * thread. Leaf lock. */
+ /*
+ * Locking. The vCPU holds sc->mtx for every MMIO access. A backend
+ * delivers its completions and hotplug events through hci_intr /
+ * hci_event from its own thread; usb_passthru does so holding the
+ * endpoint's xfer lock, so those callbacks must never take sc->mtx
+ * (the vCPU takes the xfer lock under sc->mtx: ABBA). Instead each
+ * piece of shared state has its own lock, none of which is held
+ * across a call into a backend:
+ *
+ * sc->mtx -> xfer lock -> { port_mtx | event_mtx | intr_mtx }
+ *
+ * The endpoint's transfer ring state (ep_ringaddr/ep_ccs, the stream
+ * rings, the queued blocks) is protected by that endpoint's xfer lock,
+ * which device_doorbell() takes before reading it; handle_transfer()
+ * and try_usb_xfer() are called with it held. opregs.usbsts is
+ * atomic (see above). opregs.usbcmd is written by the vCPU only.
+ */
uint32_t caplength; /* caplen & hciversion */
uint32_t hcsparams1; /* structural parameters 1 */
@@ -309,7 +351,9 @@
#define XHCI_DEVINST_PTR(x,n) ((x)->devices[(n) - 1])
#define XHCI_SLOTDEV_PTR(x,n) ((x)->slots[(n) - 1])
-#define XHCI_HALTED(sc) ((sc)->opregs.usbsts & XHCI_STS_HCH)
+#define XHCI_HALTED(sc) \
+ (atomic_load_explicit(&(sc)->opregs.usbsts, memory_order_seq_cst) & \
+ XHCI_STS_HCH)
#define XHCI_GADDR_SIZE(a) (XHCI_PADDR_SZ - \
(((uint64_t) (a)) & (XHCI_PADDR_SZ - 1)))
@@ -393,6 +437,25 @@
}
}
+/*
+ * Atomically clear one set of usbsts bits and set another as a single
+ * transaction, so a concurrent reader (guest MMIO read, or another
+ * backend's hci_intr()/hci_event()) never observes a state where only one
+ * side of the pair has taken effect.
+ */
+static void
+pci_xhci_usbsts_swap(struct pci_xhci_softc *sc, uint32_t clear_bits,
+ uint32_t set_bits)
+{
+ uint32_t old, new;
+
+ old = atomic_load_explicit(&sc->opregs.usbsts, memory_order_relaxed);
+ do {
+ new = (old & ~clear_bits) | set_bits;
+ } while (!atomic_compare_exchange_weak_explicit(&sc->opregs.usbsts,
+ &old, new, memory_order_seq_cst, memory_order_relaxed));
+}
+
static uint32_t
pci_xhci_usbcmd_write(struct pci_xhci_softc *sc, uint32_t cmd)
{
@@ -403,8 +466,7 @@
do_intr = (sc->opregs.usbcmd & XHCI_CMD_RS) == 0;
sc->opregs.usbcmd |= XHCI_CMD_RS;
- sc->opregs.usbsts &= ~XHCI_STS_HCH;
- sc->opregs.usbsts |= XHCI_STS_PCD;
+ pci_xhci_usbsts_swap(sc, XHCI_STS_HCH, XHCI_STS_PCD);
/* Queue port change event on controller run from stop */
if (do_intr)
@@ -412,24 +474,25 @@
struct pci_xhci_dev_emu *dev;
struct pci_xhci_portregs *port;
struct xhci_trb evtrb;
+ uint32_t pls;
if ((dev = XHCI_DEVINST_PTR(sc, i)) == NULL)
continue;
port = XHCI_PORTREG_PTR(sc, i);
- port->portsc |= XHCI_PS_CSC | XHCI_PS_CCS;
- port->portsc &= ~XHCI_PS_PLS_MASK;
/*
* XHCI 4.19.3 USB2 RxDetect->Polling,
* USB3 Polling->U0
*/
- if (dev->hci.hci_usbver <= 2)
- port->portsc |=
- XHCI_PS_PLS_SET(UPS_PORT_LS_POLL);
- else
- port->portsc |=
- XHCI_PS_PLS_SET(UPS_PORT_LS_U0);
+ pls = (dev->hci.hci_usbver <= 2) ?
+ UPS_PORT_LS_POLL : UPS_PORT_LS_U0;
+
+ pthread_mutex_lock(&sc->port_mtx);
+ port->portsc |= XHCI_PS_CSC | XHCI_PS_CCS;
+ port->portsc &= ~XHCI_PS_PLS_MASK;
+ port->portsc |= XHCI_PS_PLS_SET(pls);
+ pthread_mutex_unlock(&sc->port_mtx);
pci_xhci_set_evtrb(&evtrb, i,
XHCI_TRB_ERROR_SUCCESS,
@@ -441,8 +504,7 @@
}
} else {
sc->opregs.usbcmd &= ~XHCI_CMD_RS;
- sc->opregs.usbsts |= XHCI_STS_HCH;
- sc->opregs.usbsts &= ~XHCI_STS_PCD;
+ pci_xhci_usbsts_swap(sc, XHCI_STS_PCD, XHCI_STS_HCH);
}
/* start execution of schedule; stop when set to 0 */
@@ -495,25 +557,32 @@
p = XHCI_PORTREG_PTR(sc, port);
switch (offset) {
- case 0:
+ case 0: {
+ bool need_event = false;
+
/* port reset or warm reset */
if (value & (XHCI_PS_PR | XHCI_PS_WPR)) {
pci_xhci_reset_port(sc, port, value & XHCI_PS_WPR);
break;
}
+ pthread_mutex_lock(&sc->port_mtx);
+
if ((p->portsc & XHCI_PS_PP) == 0) {
if (value & XHCI_PS_PP) {
pci_xhci_init_port(sc, port);
p->portsc |= XHCI_PS_CSC;
+ need_event = true;
+ } else {
+ WPRINTF(("pci_xhci: portregs_write to unpowered "
+ "port %d", port));
+ }
+ pthread_mutex_unlock(&sc->port_mtx);
+ if (need_event) {
pci_xhci_set_evtrb(&evtrb, port,
XHCI_TRB_ERROR_SUCCESS,
XHCI_TRB_EVENT_PORT_STS_CHANGE);
-
pci_xhci_insert_event(sc, &evtrb, 1);
- } else {
- WPRINTF(("pci_xhci: portregs_write to unpowered "
- "port %d", port));
}
break;
}
@@ -552,34 +621,37 @@
if (value & XHCI_PS_PED)
DPRINTF(("Disable port %d request", port));
- if (!(value & XHCI_PS_LWS))
- break;
-
- DPRINTF(("Port new PLS: %d", newpls));
- switch (newpls) {
- case 0: /* U0 */
- case 3: /* U3 */
- if (oldpls != newpls) {
- p->portsc &= ~XHCI_PS_PLS_MASK;
- p->portsc |= XHCI_PS_PLS_SET(newpls) |
- XHCI_PS_PLC;
-
- if (oldpls != 0 && newpls == 0) {
- pci_xhci_set_evtrb(&evtrb, port,
- XHCI_TRB_ERROR_SUCCESS,
- XHCI_TRB_EVENT_PORT_STS_CHANGE);
-
- pci_xhci_insert_event(sc, &evtrb, 1);
+ if (value & XHCI_PS_LWS) {
+ DPRINTF(("Port new PLS: %d", newpls));
+ switch (newpls) {
+ case 0: /* U0 */
+ case 3: /* U3 */
+ if (oldpls != newpls) {
+ p->portsc &= ~XHCI_PS_PLS_MASK;
+ p->portsc |= XHCI_PS_PLS_SET(newpls) |
+ XHCI_PS_PLC;
+ need_event = (oldpls != 0 &&
+ newpls == 0);
}
+ break;
+
+ default:
+ DPRINTF(("Unhandled change port %d PLS %u",
+ port, newpls));
+ break;
}
- break;
+ }
- default:
- DPRINTF(("Unhandled change port %d PLS %u",
- port, newpls));
- break;
+ pthread_mutex_unlock(&sc->port_mtx);
+
+ if (need_event) {
+ pci_xhci_set_evtrb(&evtrb, port,
+ XHCI_TRB_ERROR_SUCCESS,
+ XHCI_TRB_EVENT_PORT_STS_CHANGE);
+ pci_xhci_insert_event(sc, &evtrb, 1);
}
break;
+ }
case 4:
/* Port power management status and control register */
p->portpmsc = value;
@@ -655,9 +727,11 @@
{
DPRINTF(("%s", __func__));
+ pthread_mutex_lock(&sc->intr_mtx);
sc->rtsregs.intrreg.erdp |= XHCI_ERDP_LO_BUSY;
sc->rtsregs.intrreg.iman |= XHCI_IMAN_INTR_PEND;
- sc->opregs.usbsts |= XHCI_STS_EINT;
+ atomic_fetch_or_explicit(&sc->opregs.usbsts, XHCI_STS_EINT,
+ memory_order_seq_cst);
/* only trigger interrupt if permitted */
if ((sc->opregs.usbcmd & XHCI_CMD_INTE) &&
@@ -667,14 +741,17 @@
else
pci_lintr_assert(sc->xsc_pi);
}
+ pthread_mutex_unlock(&sc->intr_mtx);
}
static void
pci_xhci_deassert_interrupt(struct pci_xhci_softc *sc)
{
+ pthread_mutex_lock(&sc->intr_mtx);
if (!pci_msi_enabled(sc->xsc_pi))
pci_lintr_assert(sc->xsc_pi);
+ pthread_mutex_unlock(&sc->intr_mtx);
}
static void
@@ -1239,8 +1316,10 @@
}
devep = &dev->eps[epid];
- if (devep->ep_xfer != NULL)
+ if (devep->ep_xfer != NULL) {
+ USB_DATA_XFER_LOCK(devep->ep_xfer);
USB_DATA_XFER_RESET(devep->ep_xfer);
+ }
dev_ctx = dev->dev_ctx;
assert(dev_ctx != NULL);
@@ -1270,12 +1349,10 @@
break;
case XHCI_TRB_TYPE_STOP_EP:
if (devep->ep_xfer != NULL) {
- USB_DATA_XFER_LOCK(devep->ep_xfer);
if (dev->dev_ue->ue_cancel == NULL ||
dev->dev_ue->ue_cancel(devep->ep_xfer) !=
USB_ERR_NORMAL_COMPLETION)
cmderr = XHCI_TRB_ERROR_ENDP_NOT_ON;
- USB_DATA_XFER_UNLOCK(devep->ep_xfer);
}
break;
@@ -1283,6 +1360,9 @@
break;
}
+ if (devep->ep_xfer != NULL)
+ USB_DATA_XFER_UNLOCK(devep->ep_xfer);
+
done:
return (cmderr);
}
@@ -1369,6 +1449,8 @@
}
streamid = XHCI_TRB_2_STREAM_GET(trb->dwTrb2);
+ if (devep->ep_xfer != NULL)
+ USB_DATA_XFER_LOCK(devep->ep_xfer);
if (devep->ep_MaxPStreams > 0) {
cmderr = pci_xhci_find_stream(sc, ep_ctx, devep, streamid);
if (cmderr == XHCI_TRB_ERROR_SUCCESS) {
@@ -1394,6 +1476,8 @@
pci_xhci_dump_trb(devep->ep_tr);
}
ep_ctx->dwEpCtx0 = (ep_ctx->dwEpCtx0 & ~0x7) | XHCI_ST_EPCTX_STOPPED;
+ if (devep->ep_xfer != NULL)
+ USB_DATA_XFER_UNLOCK(devep->ep_xfer);
done:
return (cmderr);
@@ -1793,6 +1877,7 @@
int err;
int do_intr;
+ /* Called with the endpoint's xfer lock held. */
ep_ctx->dwEpCtx0 = FIELD_REPLACE(
ep_ctx->dwEpCtx0, XHCI_ST_EPCTX_RUNNING, 0x7, 0);
@@ -1800,7 +1885,6 @@
do_intr = 0;
xfer = devep->ep_xfer;
- USB_DATA_XFER_LOCK(xfer);
/* outstanding requests queued up */
if (dev->dev_ue->ue_data != NULL) {
@@ -1823,9 +1907,6 @@
}
}
- USB_DATA_XFER_UNLOCK(xfer);
-
-
return (err);
}
@@ -1844,11 +1925,11 @@
int do_intr, err;
int do_retry;
+ /* Called with the endpoint's xfer lock held. */
ep_ctx->dwEpCtx0 = FIELD_REPLACE(ep_ctx->dwEpCtx0,
XHCI_ST_EPCTX_RUNNING, 0x7, 0);
xfer = devep->ep_xfer;
- USB_DATA_XFER_LOCK(xfer);
DPRINTF(("pci_xhci handle_transfer slot %u", slot));
@@ -2003,9 +2084,6 @@
if (err == XHCI_TRB_ERROR_EV_RING_FULL)
DPRINTF(("pci_xhci[%d]: event ring full", __LINE__));
- if (!do_retry)
- USB_DATA_XFER_UNLOCK(xfer);
-
if (do_intr)
pci_xhci_assert_interrupt(sc);
@@ -2063,12 +2141,20 @@
epid, ep_ctx->dwEpCtx0, ep_ctx->dwEpCtx1, ep_ctx->qwEpCtx2,
ep_ctx->dwEpCtx4));
- if (ep_ctx->qwEpCtx2 == 0)
+ if (ep_ctx->qwEpCtx2 == 0 || devep->ep_xfer == NULL)
return;
+ /*
+ * The endpoint's ring state and queued blocks are shared with the
+ * backend's completion path (hci_intr), which may run on another
+ * thread; the xfer lock serialises the two.
+ */
+ USB_DATA_XFER_LOCK(devep->ep_xfer);
+
/* handle pending transfers */
if (devep->ep_xfer->ndata > 0) {
pci_xhci_try_usb_xfer(sc, dev, devep, ep_ctx, slot, epid);
+ USB_DATA_XFER_UNLOCK(devep->ep_xfer);
return;
}
@@ -2080,14 +2166,14 @@
*/
if (streamid == 0 || streamid == 65534 || streamid == 65535) {
DPRINTF(("pci_xhci: invalid stream %u", streamid));
- return;
+ goto out;
}
error = pci_xhci_find_stream(sc, ep_ctx, devep, streamid);
if (error != XHCI_TRB_ERROR_SUCCESS) {
DPRINTF(("pci_xhci: invalid stream %u: %d",
streamid, error));
- return;
+ goto out;
}
sctx_tr = &devep->ep_sctx_trbs[streamid];
ringaddr = sctx_tr->ringaddr;
@@ -2099,7 +2185,7 @@
} else {
if (streamid != 0) {
DPRINTF(("pci_xhci: invalid stream %u", streamid));
- return;
+ goto out;
}
ringaddr = devep->ep_ringaddr;
ccs = devep->ep_ccs;
@@ -2112,11 +2198,13 @@
if (XHCI_TRB_3_TYPE_GET(trb->dwTrb3) == 0) {
DPRINTF(("pci_xhci: ring %lx trb[%lx] EP %u is RESERVED?",
ep_ctx->qwEpCtx2, devep->ep_ringaddr, epid));
- return;
+ goto out;
}
pci_xhci_handle_transfer(sc, dev, devep, ep_ctx, trb, slot, epid,
ringaddr, ccs, streamid);
+out:
+ USB_DATA_XFER_UNLOCK(devep->ep_xfer);
}
static void
@@ -2163,10 +2251,12 @@
switch (offset) {
case 0x00:
+ pthread_mutex_lock(&sc->intr_mtx);
if (value & XHCI_IMAN_INTR_PEND)
rts->intrreg.iman &= ~XHCI_IMAN_INTR_PEND;
rts->intrreg.iman = (value & XHCI_IMAN_INTR_ENA) |
(rts->intrreg.iman & XHCI_IMAN_INTR_PEND);
+ pthread_mutex_unlock(&sc->intr_mtx);
if (!(value & XHCI_IMAN_INTR_ENA))
pci_xhci_deassert_interrupt(sc);
@@ -2211,6 +2301,7 @@
case 0x18:
/* ERDP low bits -- does not touch er_events_cnt/er_enq_idx */
+ pthread_mutex_lock(&sc->intr_mtx);
rts->intrreg.erdp =
MASK_64_HI(sc->rtsregs.intrreg.erdp) |
(rts->intrreg.erdp & XHCI_ERDP_LO_BUSY) |
@@ -2219,6 +2310,7 @@
rts->intrreg.erdp &= ~XHCI_ERDP_LO_BUSY;
rts->intrreg.iman &= ~XHCI_IMAN_INTR_PEND;
}
+ pthread_mutex_unlock(&sc->intr_mtx);
rts->er_deq_seg = XHCI_ERDP_LO_SINDEX(value);
@@ -2324,9 +2416,11 @@
case XHCI_USBSTS:
/* clear bits on write */
- sc->opregs.usbsts &= ~(value &
+ atomic_fetch_and_explicit(&sc->opregs.usbsts,
+ (uint32_t)~(value &
(XHCI_STS_HSE|XHCI_STS_EINT|XHCI_STS_PCD|XHCI_STS_SSS|
- XHCI_STS_RSS|XHCI_STS_SRE|XHCI_STS_CNR));
+ XHCI_STS_RSS|XHCI_STS_SRE|XHCI_STS_CNR)),
+ memory_order_seq_cst);
break;
case XHCI_PAGESIZE:
@@ -2481,7 +2575,8 @@
break;
case XHCI_USBSTS: /* 0x04 */
- value = sc->opregs.usbsts;
+ value = atomic_load_explicit(&sc->opregs.usbsts,
+ memory_order_seq_cst);
break;
case XHCI_PAGESIZE: /* 0x08 */
@@ -2665,6 +2760,7 @@
struct pci_xhci_dev_emu *dev;
struct xhci_trb evtrb;
int error;
+ bool need_event = false;
assert(portn <= XHCI_MAX_DEVS);
@@ -2672,6 +2768,7 @@
port = XHCI_PORTREG_PTR(sc, portn);
dev = XHCI_DEVINST_PTR(sc, portn);
+ pthread_mutex_lock(&sc->port_mtx);
if (dev) {
port->portsc &= ~(XHCI_PS_PLS_MASK | XHCI_PS_PR | XHCI_PS_PRC);
port->portsc |= XHCI_PS_PED |
@@ -2683,16 +2780,19 @@
if ((port->portsc & XHCI_PS_PRC) == 0) {
port->portsc |= XHCI_PS_PRC;
-
- pci_xhci_set_evtrb(&evtrb, portn,
- XHCI_TRB_ERROR_SUCCESS,
- XHCI_TRB_EVENT_PORT_STS_CHANGE);
- error = pci_xhci_insert_event(sc, &evtrb, 1);
- if (error != XHCI_TRB_ERROR_SUCCESS)
- DPRINTF(("xhci reset port insert event "
- "failed"));
+ need_event = true;
}
}
+ pthread_mutex_unlock(&sc->port_mtx);
+
+ if (need_event) {
+ pci_xhci_set_evtrb(&evtrb, portn,
+ XHCI_TRB_ERROR_SUCCESS,
+ XHCI_TRB_EVENT_PORT_STS_CHANGE);
+ error = pci_xhci_insert_event(sc, &evtrb, 1);
+ if (error != XHCI_TRB_ERROR_SUCCESS)
+ DPRINTF(("xhci reset port insert event failed"));
+ }
}
static void
@@ -2780,19 +2880,25 @@
p = XHCI_PORTREG_PTR(sc, hci->hci_port);
/* raise event if link U3 (suspended) state */
+ pthread_mutex_lock(&sc->port_mtx);
if (XHCI_PS_PLS_GET(p->portsc) == 3) {
p->portsc &= ~XHCI_PS_PLS_MASK;
p->portsc |= XHCI_PS_PLS_SET(UPS_PORT_LS_RESUME);
- if ((p->portsc & XHCI_PS_PLC) != 0)
+ if ((p->portsc & XHCI_PS_PLC) != 0) {
+ pthread_mutex_unlock(&sc->port_mtx);
return (0);
+ }
p->portsc |= XHCI_PS_PLC;
+ pthread_mutex_unlock(&sc->port_mtx);
pci_xhci_set_evtrb(&evtrb, hci->hci_port,
XHCI_TRB_ERROR_SUCCESS, XHCI_TRB_EVENT_PORT_STS_CHANGE);
error = pci_xhci_insert_event(sc, &evtrb, 0);
if (error != XHCI_TRB_ERROR_SUCCESS)
goto done;
+ } else {
+ pthread_mutex_unlock(&sc->port_mtx);
}
dev_ctx = dev->dev_ctx;
@@ -2826,25 +2932,31 @@
switch (evid) {
case USBDEV_ATTACH:
+ pthread_mutex_lock(&xsc->port_mtx);
pci_xhci_init_port(xsc, hci->hci_port);
port->portsc |= XHCI_PS_CSC;
+ pthread_mutex_unlock(&xsc->port_mtx);
pci_xhci_set_evtrb(&evtrb, hci->hci_port,
XHCI_TRB_ERROR_SUCCESS, XHCI_TRB_EVENT_PORT_STS_CHANGE);
if ((err = pci_xhci_insert_event(xsc, &evtrb, 1)) !=
XHCI_TRB_ERROR_SUCCESS)
return (err);
- xsc->opregs.usbsts |= XHCI_STS_PCD;
+ atomic_fetch_or_explicit(&xsc->opregs.usbsts, XHCI_STS_PCD,
+ memory_order_seq_cst);
pci_xhci_assert_interrupt(xsc);
return (0);
case USBDEV_REMOVE:
+ pthread_mutex_lock(&xsc->port_mtx);
pci_xhci_deinit_port(xsc, hci->hci_port);
port->portsc |= XHCI_PS_CSC;
+ pthread_mutex_unlock(&xsc->port_mtx);
pci_xhci_set_evtrb(&evtrb, hci->hci_port,
XHCI_TRB_ERROR_SUCCESS, XHCI_TRB_EVENT_PORT_STS_CHANGE);
if ((err = pci_xhci_insert_event(xsc, &evtrb, 1)) !=
XHCI_TRB_ERROR_SUCCESS)
return (err);
- xsc->opregs.usbsts |= XHCI_STS_PCD;
+ atomic_fetch_or_explicit(&xsc->opregs.usbsts, XHCI_STS_PCD,
+ memory_order_seq_cst);
pci_xhci_assert_interrupt(xsc);
return (0);
default:
@@ -3033,7 +3145,9 @@
if (ndevices > 0) {
for (i = 1; i <= XHCI_MAX_DEVS; i++) {
+ pthread_mutex_lock(&sc->port_mtx);
pci_xhci_init_port(sc, i);
+ pthread_mutex_unlock(&sc->port_mtx);
}
} else {
WPRINTF(("pci_xhci no USB devices configured"));
@@ -3075,10 +3189,21 @@
pthread_mutex_init(&sc->mtx, NULL);
pthread_mutex_init(&sc->event_mtx, NULL);
+ pthread_mutex_init(&sc->port_mtx, NULL);
+ pthread_mutex_init(&sc->intr_mtx, NULL);
sc->usb2_port_start = (XHCI_MAX_DEVS/2) + 1;
sc->usb3_port_start = 1;
+ /*
+ * Must be set before pci_xhci_parse_devices(), which runs each
+ * backend's ue_init() -- for a dynamic backend (e.g. usb_passthru)
+ * that starts its hotplug/event thread, which can call back into
+ * pci_xhci_dev_event()/pci_xhci_dev_intr() and touch opregs.usbsts
+ * before this function otherwise would have initialized it.
+ */
+ sc->opregs.usbsts = XHCI_STS_HCH;
+
/* discover devices */
error = pci_xhci_parse_devices(sc, nvl);
if (error < 0)
@@ -3115,7 +3240,6 @@
DPRINTF(("pci_xhci dboff: 0x%x, rtsoff: 0x%x", sc->dboff,
sc->rtsoff));
- sc->opregs.usbsts = XHCI_STS_HCH;
sc->opregs.pgsz = XHCI_PAGESIZE_4K;
pci_xhci_reset(sc);
@@ -3146,6 +3270,8 @@
done:
if (error) {
+ pthread_mutex_destroy(&sc->intr_mtx);
+ pthread_mutex_destroy(&sc->port_mtx);
pthread_mutex_destroy(&sc->event_mtx);
pthread_mutex_destroy(&sc->mtx);
free(sc);

File Metadata

Mime Type
text/plain
Expires
Sun, Oct 11, 6:44 AM (9 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40454159
Default Alt Text
D60432.id189006.diff (18 KB)

Event Timeline