Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F175358656
D60432.id189006.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
18 KB
Referenced Files
None
Subscribers
None
D60432.id189006.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D60432: bhyve: xhci: serialise the device callbacks without the controller lock
Attached
Detach File
Event Timeline
Log In to Comment