tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: usbdi(9) improvements



> Date: Sat, 29 Jan 2022 22:24:26 +0000
> From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
> 
> New patch to fix abort races and help USB device drivers -- with a
> less intrusive change to aborting pipes for now.  Since this still
> changes the usbdi(9) API and ABI, though, it will require a kernel
> version bump.

Forgot to attach the patches, oops!

usbdi-v2.patch - git format-patch series
usbdi-v2.diff - giant diff that can be applied to a CVS tree
>From 7a48bc91788d714a04368e3ff0c47fe4a7b4f650 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sat, 8 Jan 2022 13:54:12 +0000
Subject: [PATCH 01/14] usb: Factor usb_insert_transfer out of upm_transfer and
 make private.

Almost every upm_transfer function starts with:

	mutex_enter(&sc->sc_lock);
	err = usb_insert_transfer(xfer);
	mutex_exit(&sc->sc_lock);
	if (err)
		return err;

Some of them have debug messages sprinkled in here too, or assert
that err == USBD_NORMAL_COMPLETION (alternative is USBD_IN_PROGRESS,
only for pipes with up_running or up_serialise, presumably not
applicable for these types of pipes).  Some of them also assert
xfer->ux_status == USBD_NOT_STARTED, which is guaranteed on entry and
preserved by usb_insert_transer.

Exceptions:

- arch/mips/adm5120/dev/ahci.c ahci_device_isoc_transfer just returns
  USBD_NORMAL_COMPLETION, but I'm pretty sure this is and always has
  been broken anyway, so won't make anything worse (if anything, might
  make it better...)

- external/bsd/dwc2/dwc2.c dwc2_device_bulk_transfer and
  dwc2_device_isoc_transfer _also_ issue dwc2_device_start(xfer)
  under the lock.  This is probably a better way to do it, but let's
  do it uniformly across all HCIs at once.

- rump/dev/lib/libugenhc/ugenhc.c rumpusb_device_bulk_transfer
  sometimes returns USBD_IN_PROGRESS _without_ queueing the transfer,
  in the !rump_threads case.  Not really sure how this is supposed to
  work...  If it actually breaks anything, we can figure it out.
---
 sys/arch/mips/adm5120/dev/ahci.c    | 38 +----------------
 sys/dev/ic/sl811hs.c                | 17 +-------
 sys/dev/usb/ehci.c                  | 57 +------------------------
 sys/dev/usb/motg.c                  | 46 ++-------------------
 sys/dev/usb/ohci.c                  | 46 ---------------------
 sys/dev/usb/uhci.c                  | 64 ++---------------------------
 sys/dev/usb/usbdi.c                 | 12 +++++-
 sys/dev/usb/usbdivar.h              |  2 -
 sys/dev/usb/usbroothub.c            | 10 -----
 sys/dev/usb/vhci.c                  | 18 --------
 sys/dev/usb/xhci.c                  | 60 +--------------------------
 sys/external/bsd/dwc2/dwc2.c        | 39 +-----------------
 sys/rump/dev/lib/libugenhc/ugenhc.c | 29 -------------
 13 files changed, 24 insertions(+), 414 deletions(-)

diff --git a/sys/arch/mips/adm5120/dev/ahci.c b/sys/arch/mips/adm5120/dev/ahci.c
index 2b98e4ae221e..340650e2a13a 100644
--- a/sys/arch/mips/adm5120/dev/ahci.c
+++ b/sys/arch/mips/adm5120/dev/ahci.c
@@ -729,22 +729,10 @@ ahci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 static usbd_status
 ahci_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct ahci_softc *sc = AHCI_XFER2SC(xfer);
-	usbd_status error;
 
 	DPRINTF(D_TRACE, ("SLRItransfer "));
 
-	/* Insert last in queue */
-	mutex_enter(&sc->sc_lock);
-	error = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (error)
-		return error;
-
-	/*
-	 * Pipe isn't running (otherwise error would be USBD_INPROG),
-	 * start first.
-	 */
+	/* Pipe isn't running, start first.  */
 	return ahci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -827,17 +815,9 @@ ahci_root_intr_done(struct usbd_xfer *xfer)
 static usbd_status
 ahci_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	struct ahci_softc *sc = AHCI_XFER2SC(xfer);
-	usbd_status error;
 
 	DPRINTF(D_TRACE, ("C"));
 
-	mutex_enter(&sc->sc_lock);
-	error = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (error)
-		return error;
-
 	return ahci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -1017,17 +997,9 @@ ahci_device_ctrl_done(struct usbd_xfer *xfer)
 static usbd_status
 ahci_device_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct ahci_softc *sc = AHCI_XFER2SC(xfer);
-	usbd_status error;
 
 	DPRINTF(D_TRACE, ("INTRtrans "));
 
-	mutex_enter(&sc->sc_lock);
-	error = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (error)
-		return error;
-
 	return ahci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -1161,17 +1133,9 @@ ahci_device_isoc_done(struct usbd_xfer *xfer)
 static usbd_status
 ahci_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	struct ahci_softc *sc = AHCI_XFER2SC(xfer);
-	usbd_status error;
 
 	DPRINTF(D_TRACE, ("B"));
 
-	mutex_enter(&sc->sc_lock);
-	error = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (error)
-		return error;
-
 	return ahci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
diff --git a/sys/dev/ic/sl811hs.c b/sys/dev/ic/sl811hs.c
index e5773430ccaf..35fea39878d1 100644
--- a/sys/dev/ic/sl811hs.c
+++ b/sys/dev/ic/sl811hs.c
@@ -839,28 +839,13 @@ usbd_status
 slhci_transfer(struct usbd_xfer *xfer)
 {
 	SLHCIHIST_FUNC(); SLHCIHIST_CALLED();
-	struct slhci_softc *sc = SLHCI_XFER2SC(xfer);
 	usbd_status error;
 
 	DLOG(D_TRACE, "transfer type %jd xfer %#jx spipe %#jx ",
 	    SLHCI_XFER_TYPE(xfer), (uintptr_t)xfer, (uintptr_t)xfer->ux_pipe,
 	    0);
 
-	/* Insert last in queue */
-	mutex_enter(&sc->sc_lock);
-	error = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (error) {
-		if (error != USBD_IN_PROGRESS)
-			DLOG(D_ERR, "usb_insert_transfer returns %jd!", error,
-			    0,0,0);
-		return error;
-	}
-
-	/*
-	 * Pipe isn't running (otherwise error would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 
 	/*
 	 * Start will take the lock.
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
index f6ff864d5155..aaa39e2a29ea 100644
--- a/sys/dev/usb/ehci.c
+++ b/sys/dev/usb/ehci.c
@@ -2748,15 +2748,6 @@ ehci_disown(ehci_softc_t *sc, int index, int lowspeed)
 Static usbd_status
 ehci_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ehci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -3606,15 +3597,6 @@ ehci_device_ctrl_fini(struct usbd_xfer *xfer)
 Static usbd_status
 ehci_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ehci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -3886,15 +3868,6 @@ ehci_device_bulk_fini(struct usbd_xfer *xfer)
 Static usbd_status
 ehci_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ehci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -4099,20 +4072,8 @@ ehci_device_intr_fini(struct usbd_xfer *xfer)
 Static usbd_status
 ehci_device_intr_transfer(struct usbd_xfer *xfer)
 {
-	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	usbd_status err;
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return ehci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -4351,14 +4312,6 @@ Static usbd_status
 ehci_device_fs_isoc_transfer(struct usbd_xfer *xfer)
 {
 	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	usbd_status __diagused err;
-
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	KASSERT(err == USBD_NORMAL_COMPLETION);
-
 	struct ehci_pipe *epipe = EHCI_XFER2EPIPE(xfer);
 	struct usbd_device *dev = xfer->ux_pipe->up_dev;
 	struct ehci_xfer *exfer = EHCI_XFER2EXFER(xfer);
@@ -4724,14 +4677,6 @@ Static usbd_status
 ehci_device_isoc_transfer(struct usbd_xfer *xfer)
 {
 	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	usbd_status __diagused err;
-
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	KASSERT(err == USBD_NORMAL_COMPLETION);
-
 	struct ehci_pipe *epipe = EHCI_XFER2EPIPE(xfer);
 	struct ehci_xfer *exfer = EHCI_XFER2EXFER(xfer);
 	ehci_soft_itd_t *itd, *prev;
diff --git a/sys/dev/usb/motg.c b/sys/dev/usb/motg.c
index 63339b4f0d54..54b6afcffb93 100644
--- a/sys/dev/usb/motg.c
+++ b/sys/dev/usb/motg.c
@@ -1009,20 +1009,8 @@ motg_root_intr_abort(struct usbd_xfer *xfer)
 usbd_status
 motg_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct motg_softc *sc = MOTG_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * start first
-	 */
+	/* Pipe isn't running, start first */
 	return motg_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -1279,21 +1267,8 @@ motg_setup_endpoint_rx(struct usbd_xfer *xfer)
 static usbd_status
 motg_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	struct motg_softc *sc = MOTG_XFER2SC(xfer);
-	usbd_status err;
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	KASSERT(xfer->ux_status == USBD_NOT_STARTED);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return motg_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -1731,24 +1706,9 @@ motg_device_ctrl_done(struct usbd_xfer *xfer)
 static usbd_status
 motg_device_data_transfer(struct usbd_xfer *xfer)
 {
-	struct motg_softc *sc = MOTG_XFER2SC(xfer);
-	usbd_status err;
-
 	MOTGHIST_FUNC(); MOTGHIST_CALLED();
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	DPRINTF("xfer %#jx status %jd", (uintptr_t)xfer, xfer->ux_status, 0, 0);
-	err = usb_insert_transfer(xfer);
-	KASSERT(xfer->ux_status == USBD_NOT_STARTED);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return motg_device_data_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index bd8ab4f33a27..3bbb0a01e239 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -2616,15 +2616,6 @@ ohci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 Static usbd_status
 ohci_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	ohci_softc_t *sc = OHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ohci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -2774,15 +2765,6 @@ ohci_device_ctrl_fini(struct usbd_xfer *xfer)
 Static usbd_status
 ohci_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	ohci_softc_t *sc = OHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ohci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -3062,15 +3044,6 @@ ohci_device_bulk_fini(struct usbd_xfer *xfer)
 Static usbd_status
 ohci_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	ohci_softc_t *sc = OHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ohci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -3270,15 +3243,6 @@ ohci_device_intr_fini(struct usbd_xfer *xfer)
 Static usbd_status
 ohci_device_intr_transfer(struct usbd_xfer *xfer)
 {
-	ohci_softc_t *sc = OHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ohci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -3574,20 +3538,10 @@ ohci_device_isoc_fini(struct usbd_xfer *xfer)
 usbd_status
 ohci_device_isoc_transfer(struct usbd_xfer *xfer)
 {
-	ohci_softc_t *sc = OHCI_XFER2SC(xfer);
-	usbd_status __diagused err;
-
 	OHCIHIST_FUNC(); OHCIHIST_CALLED();
 
 	DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0);
 
-	/* Put it on our queue, */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	KASSERT(err == USBD_NORMAL_COMPLETION);
-
 	/* insert into schedule, */
 	ohci_device_isoc_enter(xfer);
 
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index acf5e2e32c11..99531c10b753 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -2258,20 +2258,8 @@ uhci_device_bulk_fini(struct usbd_xfer *xfer)
 usbd_status
 uhci_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return uhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -2495,20 +2483,8 @@ uhci_device_ctrl_fini(struct usbd_xfer *xfer)
 usbd_status
 uhci_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return uhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -2701,20 +2677,8 @@ uhci_device_intr_fini(struct usbd_xfer *xfer)
 usbd_status
 uhci_device_intr_transfer(struct usbd_xfer *xfer)
 {
-	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
-	usbd_status err;
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return uhci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -2891,18 +2855,10 @@ usbd_status
 uhci_device_isoc_transfer(struct usbd_xfer *xfer)
 {
 	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
-	usbd_status err __diagused;
 
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
 	DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0);
 
-	/* Put it on our queue, */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	KASSERT(err == USBD_NORMAL_COMPLETION);
-
 	/* insert into schedule, */
 
 	struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
@@ -3890,20 +3846,8 @@ uhci_root_intr_abort(struct usbd_xfer *xfer)
 usbd_status
 uhci_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * start first
-	 */
+	/* Pipe isn't running, start first */
 	return uhci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index 02b1a41e9e08..077b2c768842 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -114,6 +114,7 @@ SDT_PROBE_DEFINE2(usb, device, xfer, done,
 SDT_PROBE_DEFINE1(usb, device, xfer, destroy,  "struct usbd_xfer *"/*xfer*/);
 
 Static usbd_status usbd_ar_pipe(struct usbd_pipe *);
+static usbd_status usb_insert_transfer(struct usbd_xfer *);
 Static void usbd_start_next(struct usbd_pipe *);
 Static usbd_status usbd_open_pipe_ival
 	(struct usbd_interface *, uint8_t, uint8_t, struct usbd_pipe **, int);
@@ -406,7 +407,14 @@ usbd_transfer(struct usbd_xfer *xfer)
 
 	/* xfer is not valid after the transfer method unless synchronous */
 	SDT_PROBE2(usb, device, pipe, transfer__start,  pipe, xfer);
-	err = pipe->up_methods->upm_transfer(xfer);
+	do {
+		usbd_lock_pipe(pipe);
+		err = usb_insert_transfer(xfer);
+		usbd_unlock_pipe(pipe);
+		if (err)
+			break;
+		err = pipe->up_methods->upm_transfer(xfer);
+	} while (0);
 	SDT_PROBE3(usb, device, pipe, transfer__done,  pipe, xfer, err);
 
 	if (err != USBD_IN_PROGRESS && err) {
@@ -1136,7 +1144,7 @@ usb_transfer_complete(struct usbd_xfer *xfer)
 }
 
 /* Called with USB lock held. */
-usbd_status
+static usbd_status
 usb_insert_transfer(struct usbd_xfer *xfer)
 {
 	struct usbd_pipe *pipe = xfer->ux_pipe;
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index e993fc25b7a1..68acac665e9e 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -64,7 +64,6 @@
  * USB functions known to expect the lock taken include (this list is
  * probably not exhaustive):
  *    usb_transfer_complete()
- *    usb_insert_transfer()
  *    usb_start_next()
  *
  */
@@ -356,7 +355,6 @@ void		usbd_iface_pipeunref(struct usbd_interface *);
 usbd_status	usbd_fill_iface_data(struct usbd_device *, int, int);
 void		usb_free_device(struct usbd_device *);
 
-usbd_status	usb_insert_transfer(struct usbd_xfer *);
 void		usb_transfer_complete(struct usbd_xfer *);
 int		usb_disconnect_port(struct usbd_port *, device_t, int);
 
diff --git a/sys/dev/usb/usbroothub.c b/sys/dev/usb/usbroothub.c
index c455f89abee4..7e9139434fb7 100644
--- a/sys/dev/usb/usbroothub.c
+++ b/sys/dev/usb/usbroothub.c
@@ -343,16 +343,6 @@ static const usb_hub_descriptor_t usbroothub_hubd = {
 usbd_status
 roothub_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	struct usbd_pipe *pipe = xfer->ux_pipe;
-	struct usbd_bus *bus = pipe->up_dev->ud_bus;
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(bus->ub_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(bus->ub_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return roothub_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
diff --git a/sys/dev/usb/vhci.c b/sys/dev/usb/vhci.c
index f5c46b9a774e..a73b14e1cb5a 100644
--- a/sys/dev/usb/vhci.c
+++ b/sys/dev/usb/vhci.c
@@ -590,18 +590,9 @@ vhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 static usbd_status
 vhci_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
-	usbd_status err;
 
 	DPRINTF("%s: called\n", __func__);
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return vhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -707,18 +698,9 @@ vhci_device_ctrl_done(struct usbd_xfer *xfer)
 static usbd_status
 vhci_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
-	usbd_status err;
 
 	DPRINTF("%s: called\n", __func__);
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return vhci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c
index 6c79c07ac6ec..1a14fb896a94 100644
--- a/sys/dev/usb/xhci.c
+++ b/sys/dev/usb/xhci.c
@@ -4129,18 +4129,8 @@ xhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 static usbd_status
 xhci_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
-	usbd_status err;
-
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return xhci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -4233,18 +4223,8 @@ xhci_root_intr_done(struct usbd_xfer *xfer)
 static usbd_status
 xhci_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
-	usbd_status err;
-
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return xhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -4378,18 +4358,8 @@ xhci_device_ctrl_close(struct usbd_pipe *pipe)
 static usbd_status
 xhci_device_isoc_transfer(struct usbd_xfer *xfer)
 {
-	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
-	usbd_status err;
-
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	return xhci_device_isoc_enter(xfer);
 }
 
@@ -4542,22 +4512,9 @@ xhci_device_isoc_done(struct usbd_xfer *xfer)
 static usbd_status
 xhci_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
-	usbd_status err;
-
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return xhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -4680,22 +4637,9 @@ xhci_device_bulk_close(struct usbd_pipe *pipe)
 static usbd_status
 xhci_device_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
-	usbd_status err;
-
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return xhci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
diff --git a/sys/external/bsd/dwc2/dwc2.c b/sys/external/bsd/dwc2/dwc2.c
index e3e61a072b23..921f5fbed998 100644
--- a/sys/external/bsd/dwc2/dwc2.c
+++ b/sys/external/bsd/dwc2/dwc2.c
@@ -614,18 +614,9 @@ dwc2_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 Static usbd_status
 dwc2_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	usbd_status err;
 
 	DPRINTF("\n");
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return dwc2_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -711,18 +702,9 @@ dwc2_root_intr_done(struct usbd_xfer *xfer)
 Static usbd_status
 dwc2_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	usbd_status err;
 
 	DPRINTF("\n");
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return dwc2_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -788,12 +770,8 @@ dwc2_device_bulk_transfer(struct usbd_xfer *xfer)
 
 	DPRINTF("xfer=%p\n", xfer);
 
-	/* Insert last in queue. */
 	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-
-	KASSERT(err == USBD_NORMAL_COMPLETION);
-
+	KASSERT(xfer->ux_status == USBD_NOT_STARTED);
 	xfer->ux_status = USBD_IN_PROGRESS;
 	err = dwc2_device_start(xfer);
 	mutex_exit(&sc->sc_lock);
@@ -833,18 +811,9 @@ dwc2_device_bulk_done(struct usbd_xfer *xfer)
 Static usbd_status
 dwc2_device_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	usbd_status err;
 
 	DPRINTF("xfer=%p\n", xfer);
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return dwc2_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -909,12 +878,8 @@ dwc2_device_isoc_transfer(struct usbd_xfer *xfer)
 
 	DPRINTF("xfer=%p\n", xfer);
 
-	/* Insert last in queue. */
 	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-
-	KASSERT(err == USBD_NORMAL_COMPLETION);
-
+	KASSERT(xfer->ux_status == USBD_NOT_STARTED);
 	xfer->ux_status = USBD_IN_PROGRESS;
 	err = dwc2_device_start(xfer);
 	mutex_exit(&sc->sc_lock);
diff --git a/sys/rump/dev/lib/libugenhc/ugenhc.c b/sys/rump/dev/lib/libugenhc/ugenhc.c
index 003f1cc54453..f6f80877940e 100644
--- a/sys/rump/dev/lib/libugenhc/ugenhc.c
+++ b/sys/rump/dev/lib/libugenhc/ugenhc.c
@@ -401,14 +401,6 @@ rumpusb_device_ctrl_start(struct usbd_xfer *xfer)
 static usbd_status
 rumpusb_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer);
-	usbd_status err;
-
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	return rumpusb_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -540,14 +532,6 @@ rumpusb_root_intr_start(struct usbd_xfer *xfer)
 static usbd_status
 rumpusb_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer);
-	usbd_status err;
-
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	return rumpusb_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -709,8 +693,6 @@ doxfer_kth(void *arg)
 static usbd_status
 rumpusb_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer);
-	usbd_status err;
 
 	if (!rump_threads) {
 		/* XXX: lie about supporting async transfers */
@@ -720,20 +702,9 @@ rumpusb_device_bulk_transfer(struct usbd_xfer *xfer)
 			return USBD_IN_PROGRESS;
 		}
 
-		mutex_enter(&sc->sc_lock);
-		err = usb_insert_transfer(xfer);
-		mutex_exit(&sc->sc_lock);
-		if (err)
-			return err;
-
 		return rumpusb_device_bulk_start(
 		    SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 	} else {
-		mutex_enter(&sc->sc_lock);
-		err = usb_insert_transfer(xfer);
-		mutex_exit(&sc->sc_lock);
-		if (err)
-			return err;
 		kthread_create(PRI_NONE, 0, NULL, doxfer_kth, xfer->ux_pipe, NULL,
 		    "rusbhcxf");
 

>From 1fe541208e1cfd7de6fe919e998b6baf8163df41 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sat, 8 Jan 2022 17:47:22 +0000
Subject: [PATCH 02/14] usb: usbd_abort_pipe never fails.  Make it return void.

Prune dead branches as a result of this change.
---
 sys/dev/usb/if_atu.c | 12 ++----------
 sys/dev/usb/ualea.c  |  2 +-
 sys/dev/usb/usbdi.c  | 15 ++++++---------
 sys/dev/usb/usbdi.h  |  4 ++--
 sys/dev/usb/usbnet.c | 15 +++------------
 sys/dev/usb/utoppy.c |  7 ++-----
 6 files changed, 16 insertions(+), 39 deletions(-)

diff --git a/sys/dev/usb/if_atu.c b/sys/dev/usb/if_atu.c
index 85222d1dce28..9d37935701b9 100644
--- a/sys/dev/usb/if_atu.c
+++ b/sys/dev/usb/if_atu.c
@@ -2235,19 +2235,11 @@ atu_stop(struct ifnet *ifp, int disable)
 
 	/* Stop transfers. */
 	if (sc->atu_ep[ATU_ENDPT_RX] != NULL) {
-		err = usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_RX]);
-		if (err) {
-			DPRINTF(("%s: abort rx pipe failed: %s\n",
-			    device_xname(sc->atu_dev), usbd_errstr(err)));
-		}
+		usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_RX]);
 	}
 
 	if (sc->atu_ep[ATU_ENDPT_TX] != NULL) {
-		err = usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_TX]);
-		if (err) {
-			DPRINTF(("%s: abort tx pipe failed: %s\n",
-			    device_xname(sc->atu_dev), usbd_errstr(err)));
-		}
+		usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_TX]);
 	}
 
 	/* Free RX/TX/MGMT list resources. */
diff --git a/sys/dev/usb/ualea.c b/sys/dev/usb/ualea.c
index ede886968af4..333a9e63cab3 100644
--- a/sys/dev/usb/ualea.c
+++ b/sys/dev/usb/ualea.c
@@ -161,7 +161,7 @@ ualea_detach(device_t self, int flags)
 
 	/* Cancel pending xfer.  */
 	if (sc->sc_pipe)
-		(void)usbd_abort_pipe(sc->sc_pipe);
+		usbd_abort_pipe(sc->sc_pipe);
 	KASSERT(!sc->sc_inflight);
 
 	/* All users have drained.  Tear it all down.  */
diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index 077b2c768842..e5a3e8916093 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -113,7 +113,7 @@ SDT_PROBE_DEFINE2(usb, device, xfer, done,
     "usbd_status"/*status*/);
 SDT_PROBE_DEFINE1(usb, device, xfer, destroy,  "struct usbd_xfer *"/*xfer*/);
 
-Static usbd_status usbd_ar_pipe(struct usbd_pipe *);
+Static void usbd_ar_pipe(struct usbd_pipe *);
 static usbd_status usb_insert_transfer(struct usbd_xfer *);
 Static void usbd_start_next(struct usbd_pipe *);
 Static usbd_status usbd_open_pipe_ival
@@ -769,23 +769,21 @@ usbd_interface2endpoint_descriptor(struct usbd_interface *iface, uint8_t index)
 
 /* Some drivers may wish to abort requests on the default pipe, *
  * but there is no mechanism for getting a handle on it.        */
-usbd_status
+void
 usbd_abort_default_pipe(struct usbd_device *device)
 {
-	return usbd_abort_pipe(device->ud_pipe0);
+	usbd_abort_pipe(device->ud_pipe0);
 }
 
-usbd_status
+void
 usbd_abort_pipe(struct usbd_pipe *pipe)
 {
-	usbd_status err;
 
 	KASSERT(pipe != NULL);
 
 	usbd_lock_pipe(pipe);
-	err = usbd_ar_pipe(pipe);
+	usbd_ar_pipe(pipe);
 	usbd_unlock_pipe(pipe);
-	return err;
 }
 
 usbd_status
@@ -966,7 +964,7 @@ usbd_get_interface(struct usbd_interface *iface, uint8_t *aiface)
 /*** Internal routines ***/
 
 /* Dequeue all pipe operations, called with bus lock held. */
-Static usbd_status
+Static void
 usbd_ar_pipe(struct usbd_pipe *pipe)
 {
 	struct usbd_xfer *xfer;
@@ -1010,7 +1008,6 @@ usbd_ar_pipe(struct usbd_pipe *pipe)
 	}
 	pipe->up_aborting = 0;
 	SDT_PROBE1(usb, device, pipe, abort__done,  pipe);
-	return USBD_NORMAL_COMPLETION;
 }
 
 /* Called with USB lock held. */
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 71d61eca5394..8052a6487923 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -118,8 +118,8 @@ void usbd_get_xfer_status(struct usbd_xfer *, void **,
 usb_endpoint_descriptor_t *usbd_interface2endpoint_descriptor
     (struct usbd_interface *, uint8_t);
 
-usbd_status usbd_abort_pipe(struct usbd_pipe *);
-usbd_status usbd_abort_default_pipe(struct usbd_device *);
+void usbd_abort_pipe(struct usbd_pipe *);
+void usbd_abort_default_pipe(struct usbd_device *);
 
 usbd_status usbd_clear_endpoint_stall(struct usbd_pipe *);
 void usbd_clear_endpoint_stall_async(struct usbd_pipe *);
diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 1f57e11ea39e..b37290dacc50 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -817,21 +817,16 @@ usbnet_ep_open_pipes(struct usbnet * const un)
 	return USBD_NORMAL_COMPLETION;
 }
 
-static usbd_status
+static void
 usbnet_ep_stop_pipes(struct usbnet * const un)
 {
 	struct usbnet_private * const unp = un->un_pri;
-	usbd_status err = USBD_NORMAL_COMPLETION;
 
 	for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) {
 		if (unp->unp_ep[i] == NULL)
 			continue;
-		usbd_status err2 = usbd_abort_pipe(unp->unp_ep[i]);
-		if (err == USBD_NORMAL_COMPLETION && err2)
-			err = err2;
+		usbd_abort_pipe(unp->unp_ep[i]);
 	}
-
-	return err;
 }
 
 static int
@@ -1208,17 +1203,13 @@ usbnet_watchdog(struct ifnet *ifp)
 	struct usbnet * const un = ifp->if_softc;
 	struct usbnet_private * const unp = un->un_pri;
 	struct usbnet_cdata * const cd = un_cdata(un);
-	usbd_status err;
 
 	if_statinc(ifp, if_oerrors);
 	device_printf(un->un_dev, "watchdog timeout\n");
 
 	if (cd->uncd_tx_cnt > 0) {
 		DPRINTF("uncd_tx_cnt=%ju non zero, aborting pipe", 0, 0, 0, 0);
-		err = usbd_abort_pipe(unp->unp_ep[USBNET_ENDPT_TX]);
-		if (err)
-			device_printf(un->un_dev, "pipe abort failed: %s\n",
-			    usbd_errstr(err));
+		usbd_abort_pipe(unp->unp_ep[USBNET_ENDPT_TX]);
 		if (cd->uncd_tx_cnt != 0)
 			DPRINTF("uncd_tx_cnt now %ju", cd->uncd_tx_cnt, 0, 0, 0);
 	}
diff --git a/sys/dev/usb/utoppy.c b/sys/dev/usb/utoppy.c
index a40352fedf90..b412542d5c3d 100644
--- a/sys/dev/usb/utoppy.c
+++ b/sys/dev/usb/utoppy.c
@@ -1365,7 +1365,6 @@ static int
 utoppyclose(dev_t dev, int flag, int mode, struct lwp *l)
 {
 	struct utoppy_softc *sc;
-	usbd_status err;
 
 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
 
@@ -1384,14 +1383,12 @@ utoppyclose(dev_t dev, int flag, int mode, struct lwp *l)
 		(void) utoppy_cancel(sc);
 
 	if (sc->sc_out_pipe != NULL) {
-		if ((err = usbd_abort_pipe(sc->sc_out_pipe)) != 0)
-			printf("usbd_abort_pipe(OUT) returned %d\n", err);
+		usbd_abort_pipe(sc->sc_out_pipe);
 		sc->sc_out_pipe = NULL;
 	}
 
 	if (sc->sc_in_pipe != NULL) {
-		if ((err = usbd_abort_pipe(sc->sc_in_pipe)) != 0)
-			printf("usbd_abort_pipe(IN) returned %d\n", err);
+		usbd_abort_pipe(sc->sc_in_pipe);
 		sc->sc_in_pipe = NULL;
 	}
 

>From 3f422e67fa0e270ae62dc313e291bd48e7e18fea Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sat, 8 Jan 2022 17:51:11 +0000
Subject: [PATCH 03/14] usb: usbd_close_pipe never fails.  Make it return void.

Prune dead branches as a result of this change.
---
 sys/dev/usb/if_atu.c  | 13 ++-----------
 sys/dev/usb/if_urtw.c | 13 +++----------
 sys/dev/usb/ualea.c   |  2 +-
 sys/dev/usb/usbdi.c   |  4 +---
 sys/dev/usb/usbdi.h   |  2 +-
 sys/dev/usb/usbnet.c  |  5 +----
 6 files changed, 9 insertions(+), 30 deletions(-)

diff --git a/sys/dev/usb/if_atu.c b/sys/dev/usb/if_atu.c
index 9d37935701b9..6b0d464269a5 100644
--- a/sys/dev/usb/if_atu.c
+++ b/sys/dev/usb/if_atu.c
@@ -2223,7 +2223,6 @@ atu_stop(struct ifnet *ifp, int disable)
 	struct atu_softc	*sc = ifp->if_softc;
 	struct ieee80211com	*ic = &sc->sc_ic;
 	struct atu_cdata	*cd;
-	usbd_status		err;
 	int s;
 
 	s = splnet();
@@ -2249,20 +2248,12 @@ atu_stop(struct ifnet *ifp, int disable)
 
 	/* Close pipes */
 	if (sc->atu_ep[ATU_ENDPT_RX] != NULL) {
-		err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_RX]);
-		if (err) {
-			DPRINTF(("%s: close rx pipe failed: %s\n",
-			    device_xname(sc->atu_dev), usbd_errstr(err)));
-		}
+		usbd_close_pipe(sc->atu_ep[ATU_ENDPT_RX]);
 		sc->atu_ep[ATU_ENDPT_RX] = NULL;
 	}
 
 	if (sc->atu_ep[ATU_ENDPT_TX] != NULL) {
-		err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_TX]);
-		if (err) {
-			DPRINTF(("%s: close tx pipe failed: %s\n",
-			    device_xname(sc->atu_dev), usbd_errstr(err)));
-		}
+		usbd_close_pipe(sc->atu_ep[ATU_ENDPT_TX]);
 		sc->atu_ep[ATU_ENDPT_TX] = NULL;
 	}
 
diff --git a/sys/dev/usb/if_urtw.c b/sys/dev/usb/if_urtw.c
index 162141c8072f..f08db3030887 100644
--- a/sys/dev/usb/if_urtw.c
+++ b/sys/dev/usb/if_urtw.c
@@ -829,24 +829,17 @@ urtw_close_pipes(struct urtw_softc *sc)
 	usbd_status error = 0;
 
 	if (sc->sc_rxpipe != NULL) {
-		error = usbd_close_pipe(sc->sc_rxpipe);
-		if (error != 0)
-			goto fail;
+		usbd_close_pipe(sc->sc_rxpipe);
 		sc->sc_rxpipe = NULL;
 	}
 	if (sc->sc_txpipe_low != NULL) {
-		error = usbd_close_pipe(sc->sc_txpipe_low);
-		if (error != 0)
-			goto fail;
+		usbd_close_pipe(sc->sc_txpipe_low);
 		sc->sc_txpipe_low = NULL;
 	}
 	if (sc->sc_txpipe_normal != NULL) {
-		error = usbd_close_pipe(sc->sc_txpipe_normal);
-		if (error != 0)
-			goto fail;
+		usbd_close_pipe(sc->sc_txpipe_normal);
 		sc->sc_txpipe_normal = NULL;
 	}
-fail:
 	return error;
 }
 
diff --git a/sys/dev/usb/ualea.c b/sys/dev/usb/ualea.c
index 333a9e63cab3..d38722351672 100644
--- a/sys/dev/usb/ualea.c
+++ b/sys/dev/usb/ualea.c
@@ -168,7 +168,7 @@ ualea_detach(device_t self, int flags)
 	if (sc->sc_xfer)
 		usbd_destroy_xfer(sc->sc_xfer);
 	if (sc->sc_pipe)
-		(void)usbd_close_pipe(sc->sc_pipe);
+		usbd_close_pipe(sc->sc_pipe);
 	mutex_destroy(&sc->sc_lock);
 
 	return 0;
diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index e5a3e8916093..49035673fdaf 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -321,7 +321,7 @@ usbd_open_pipe_intr(struct usbd_interface *iface, uint8_t address,
 	return err;
 }
 
-usbd_status
+void
 usbd_close_pipe(struct usbd_pipe *pipe)
 {
 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
@@ -348,8 +348,6 @@ usbd_close_pipe(struct usbd_pipe *pipe)
 	if (pipe->up_iface)
 		usbd_iface_pipeunref(pipe->up_iface);
 	kmem_free(pipe, pipe->up_dev->ud_bus->ub_pipesize);
-
-	return USBD_NORMAL_COMPLETION;
 }
 
 usbd_status
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 8052a6487923..c9c4274adb65 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -91,7 +91,7 @@ usbd_status usbd_open_pipe_intr(struct usbd_interface *, uint8_t, uint8_t,
     struct usbd_pipe **, void *, void *, uint32_t, usbd_callback, int);
 usbd_status usbd_open_pipe(struct usbd_interface *, uint8_t, uint8_t,
      struct usbd_pipe **);
-usbd_status usbd_close_pipe(struct usbd_pipe *);
+void usbd_close_pipe(struct usbd_pipe *);
 
 usbd_status usbd_transfer(struct usbd_xfer *);
 
diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index b37290dacc50..50603bed02d8 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -779,10 +779,7 @@ usbnet_ep_close_pipes(struct usbnet * const un)
 	for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) {
 		if (unp->unp_ep[i] == NULL)
 			continue;
-		usbd_status err = usbd_close_pipe(unp->unp_ep[i]);
-		if (err)
-			aprint_error_dev(un->un_dev, "close pipe %zu: %s\n", i,
-			    usbd_errstr(err));
+		usbd_close_pipe(unp->unp_ep[i]);
 		unp->unp_ep[i] = NULL;
 	}
 }

>From 791116c5cf10c5b39e1e325e578e50539f892d5e Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sat, 8 Jan 2022 17:53:01 +0000
Subject: [PATCH 04/14] usb: usbd_free_xfer never fails.  Make it return void.

---
 sys/dev/usb/usbdi.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index 49035673fdaf..85521b4903ef 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -121,7 +121,7 @@ Static usbd_status usbd_open_pipe_ival
 static void *usbd_alloc_buffer(struct usbd_xfer *, uint32_t);
 static void usbd_free_buffer(struct usbd_xfer *);
 static struct usbd_xfer *usbd_alloc_xfer(struct usbd_device *, unsigned int);
-static usbd_status usbd_free_xfer(struct usbd_xfer *);
+static void usbd_free_xfer(struct usbd_xfer *);
 static void usbd_request_async_cb(struct usbd_xfer *, void *, usbd_status);
 static void usbd_xfer_timeout(void *);
 static void usbd_xfer_timeout_task(void *);
@@ -588,7 +588,7 @@ out:
 	return xfer;
 }
 
-static usbd_status
+static void
 usbd_free_xfer(struct usbd_xfer *xfer)
 {
 	USBHIST_FUNC();
@@ -608,7 +608,6 @@ usbd_free_xfer(struct usbd_xfer *xfer)
 
 	cv_destroy(&xfer->ux_cv);
 	xfer->ux_bus->ub_methods->ubm_freex(xfer->ux_bus, xfer);
-	return USBD_NORMAL_COMPLETION;
 }
 
 int

>From d64f15a130475e077e5b77b8ef43d568fae167db Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sat, 8 Jan 2022 19:35:23 +0000
Subject: [PATCH 05/14] usb: Factor usb_transfer_complete out of ubm_abortx
 method.

---
 sys/dev/usb/ehci.c           |  4 ----
 sys/dev/usb/motg.c           |  1 -
 sys/dev/usb/ohci.c           |  5 -----
 sys/dev/usb/uhci.c           |  5 -----
 sys/dev/usb/usbdi.c          | 12 ++++++++----
 sys/dev/usb/xhci.c           |  2 --
 sys/external/bsd/dwc2/dwc2.c |  7 +------
 7 files changed, 9 insertions(+), 27 deletions(-)

diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
index aaa39e2a29ea..f01a15d411ca 100644
--- a/sys/dev/usb/ehci.c
+++ b/sys/dev/usb/ehci.c
@@ -3388,14 +3388,10 @@ ehci_abortx(struct usbd_xfer *xfer)
 		    BUS_DMASYNC_PREREAD);
 	}
 
-	/*
-	 * Final step: Notify completion to waiting xfers.
-	 */
 dying:
 #ifdef DIAGNOSTIC
 	exfer->ex_isdone = true;
 #endif
-	usb_transfer_complete(xfer);
 	DPRINTFN(14, "end", 0, 0, 0, 0);
 
 	KASSERT(mutex_owned(&sc->sc_lock));
diff --git a/sys/dev/usb/motg.c b/sys/dev/usb/motg.c
index 54b6afcffb93..36f5e01c4b64 100644
--- a/sys/dev/usb/motg.c
+++ b/sys/dev/usb/motg.c
@@ -2222,6 +2222,5 @@ motg_abortx(struct usbd_xfer *xfer)
 		}
 	}
 dying:
-	usb_transfer_complete(xfer);
 	KASSERT(mutex_owned(&sc->sc_lock));
 }
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index 3bbb0a01e239..4e0f827c100f 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -2409,12 +2409,7 @@ ohci_abortx(struct usbd_xfer *xfer)
 	usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags),
 	    sizeof(sed->ed.ed_flags),
 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-
-	/*
-	 * Final step: Notify completion to waiting xfers.
-	 */
 dying:
-	usb_transfer_complete(xfer);
 	DPRINTFN(14, "end", 0, 0, 0, 0);
 
 	KASSERT(mutex_owned(&sc->sc_lock));
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index 99531c10b753..1e9718b112c0 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -2402,15 +2402,10 @@ uhci_abortx(struct usbd_xfer *xfer)
 	 */
 	/* Hardware finishes in 1ms */
 	usb_delay_ms_locked(upipe->pipe.up_dev->ud_bus, 2, &sc->sc_lock);
-
-	/*
-	 * HC Step 3: Notify completion to waiting xfers.
-	 */
 dying:
 #ifdef DIAGNOSTIC
 	ux->ux_isdone = true;
 #endif
-	usb_transfer_complete(xfer);
 	DPRINTFN(14, "end", 0, 0, 0, 0);
 
 	KASSERT(mutex_owned(&sc->sc_lock));
diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index 85521b4903ef..6900e3aab206 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -1533,11 +1533,13 @@ usbd_xfer_abort(struct usbd_xfer *xfer)
 	usbd_xfer_cancel_timeout_async(xfer);
 
 	/*
-	 * We beat everyone else.  Claim the status as cancelled and do
-	 * the bus-specific dance to abort the hardware.
+	 * We beat everyone else.  Claim the status as cancelled, do
+	 * the bus-specific dance to abort the hardware, and complete
+	 * the xfer.
 	 */
 	xfer->ux_status = USBD_CANCELLED;
 	bus->ub_methods->ubm_abortx(xfer);
+	usb_transfer_complete(xfer);
 }
 
 /*
@@ -1617,11 +1619,13 @@ usbd_xfer_timeout_task(void *cookie)
 		goto out;
 
 	/*
-	 * We beat everyone else.  Claim the status as timed out and do
-	 * the bus-specific dance to abort the hardware.
+	 * We beat everyone else.  Claim the status as timed out, do
+	 * the bus-specific dance to abort the hardware, and complete
+	 * the xfer.
 	 */
 	xfer->ux_status = USBD_TIMEOUT;
 	bus->ub_methods->ubm_abortx(xfer);
+	usb_transfer_complete(xfer);
 
 out:	/* All done -- release the lock.  */
 	mutex_exit(bus->ub_lock);
diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c
index 1a14fb896a94..9be02a019def 100644
--- a/sys/dev/usb/xhci.c
+++ b/sys/dev/usb/xhci.c
@@ -2154,8 +2154,6 @@ xhci_abortx(struct usbd_xfer *xfer)
 
 	xhci_pipe_restart(xfer->ux_pipe);
 
-	usb_transfer_complete(xfer);
-
 	DPRINTFN(14, "end", 0, 0, 0, 0);
 }
 
diff --git a/sys/external/bsd/dwc2/dwc2.c b/sys/external/bsd/dwc2/dwc2.c
index 921f5fbed998..19ffae0e8ab4 100644
--- a/sys/external/bsd/dwc2/dwc2.c
+++ b/sys/external/bsd/dwc2/dwc2.c
@@ -515,7 +515,7 @@ dwc2_abortx(struct usbd_xfer *xfer)
 	}
 
 	/*
-	 * HC Step 1: Handle the hardware.
+	 * Handle the hardware.
 	 */
 	err = dwc2_hcd_urb_dequeue(hsotg, dxfer->urb);
 	if (err) {
@@ -524,11 +524,6 @@ dwc2_abortx(struct usbd_xfer *xfer)
 
 dying:
 	mutex_spin_exit(&hsotg->lock);
-
-	/*
-	 * Final Step: Notify completion to waiting xfers.
-	 */
-	usb_transfer_complete(xfer);
 	KASSERT(mutex_owned(&sc->sc_lock));
 }
 

>From 846e4269d3e7909ee3cc22fd6acb0420d6c139d5 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sat, 22 Jan 2022 23:59:42 +0000
Subject: [PATCH 06/14] usbdi(9): Add some missing header include guards.

---
 sys/dev/usb/usb_mem.h  | 5 +++++
 sys/dev/usb/usbdivar.h | 5 +++++
 2 files changed, 10 insertions(+)

diff --git a/sys/dev/usb/usb_mem.h b/sys/dev/usb/usb_mem.h
index 5473c1b3b810..d806e58760b2 100644
--- a/sys/dev/usb/usb_mem.h
+++ b/sys/dev/usb/usb_mem.h
@@ -31,6 +31,9 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifndef	_DEV_USB_USB_MEM_H_
+#define	_DEV_USB_USB_MEM_H_
+
 typedef struct usb_dma_block {
 	bus_dma_tag_t tag;
 	bus_dmamap_t map;
@@ -60,3 +63,5 @@ bus_addr_t	usb_dmaaddr(usb_dma_t *, unsigned int);
 #define DMAADDR(dma, o)	usb_dmaaddr((dma), (o))
 #define KERNADDR(dma, o) \
 	((void *)((char *)(dma)->udma_block->kaddr + (dma)->udma_offs + (o)))
+
+#endif	/* _DEV_USB_USB_MEM_H_ */
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index 68acac665e9e..3e2c6ce0b59d 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -30,6 +30,9 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifndef	_DEV_USB_USBDIVAR_H_
+#define	_DEV_USB_USBDIVAR_H_
+
 /*
  * Discussion about locking in the USB code:
  *
@@ -395,3 +398,5 @@ usb_addr2dindex(int addr)
 
 #define usbd_lock_pipe(p)	mutex_enter((p)->up_dev->ud_bus->ub_lock)
 #define usbd_unlock_pipe(p)	mutex_exit((p)->up_dev->ud_bus->ub_lock)
+
+#endif	/* _DEV_USB_USBDIVAR_H_ */

>From 9ff66f0a05caf9f7d690dd9351f97d57dd73c33c Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 23 Jan 2022 11:04:15 +0000
Subject: [PATCH 07/14] xhci(4): Add missing includes to xhcivar.h.

---
 sys/dev/usb/xhcivar.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/sys/dev/usb/xhcivar.h b/sys/dev/usb/xhcivar.h
index 9893037be2e1..b253da58557f 100644
--- a/sys/dev/usb/xhcivar.h
+++ b/sys/dev/usb/xhcivar.h
@@ -29,8 +29,17 @@
 #ifndef _DEV_USB_XHCIVAR_H_
 #define _DEV_USB_XHCIVAR_H_
 
+#include <sys/types.h>
+
+#include <sys/condvar.h>
+#include <sys/device.h>
+#include <sys/mutex.h>
+#include <sys/pmf.h>
 #include <sys/pool.h>
 
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+
 #define XHCI_MAX_DCI	31
 
 struct xhci_soft_trb {

>From 15c61f3a5b691f905abdf282d3328b05768233a2 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 23 Jan 2022 11:05:39 +0000
Subject: [PATCH 08/14] usb: Add missing includes in usb_mem.h.

---
 sys/dev/usb/usb_mem.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/sys/dev/usb/usb_mem.h b/sys/dev/usb/usb_mem.h
index d806e58760b2..b93d694cfc3c 100644
--- a/sys/dev/usb/usb_mem.h
+++ b/sys/dev/usb/usb_mem.h
@@ -34,6 +34,13 @@
 #ifndef	_DEV_USB_USB_MEM_H_
 #define	_DEV_USB_USB_MEM_H_
 
+#include <sys/types.h>
+
+#include <sys/bus.h>
+#include <sys/queue.h>
+
+#include <dev/usb/usbdivar.h>
+
 typedef struct usb_dma_block {
 	bus_dma_tag_t tag;
 	bus_dmamap_t map;

>From 44d78efd5af5d00b3acbc2da8b8d7bc8dbcbdf94 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 23 Jan 2022 15:05:41 +0000
Subject: [PATCH 09/14] usb: Update tables of bus/pipe method locking rules.

No functional change.
---
 sys/dev/usb/usbdivar.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index 3e2c6ce0b59d..3f92e323afb2 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -44,16 +44,19 @@
  *	BUS METHOD		LOCK	NOTES
  *	----------------------- -------	-------------------------
  *	ubm_open		-	might want to take lock?
- *	ubm_softint		x
+ *	ubm_softint		x	may release/reacquire lock
  *	ubm_dopoll		-	might want to take lock?
  *	ubm_allocx		-
  *	ubm_freex		-
+ *	ubm_abortx		x	must not release/reacquire lock
  *	ubm_getlock 		-	Called at attach time
  *	ubm_newdev		-	Will take lock
-	ubm_rhctrl
+ *	ubm_rhctrl
  *
  *	PIPE METHOD		LOCK	NOTES
  *	----------------------- -------	-------------------------
+ *	upm_init		-
+ *	upm_fini		-
  *	upm_transfer		-
  *	upm_start		-	might want to take lock?
  *	upm_abort		x

>From 4055f0c91bb554891f024d8fcc1f78c4251ac7ca Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 23 Jan 2022 16:30:13 +0000
Subject: [PATCH 10/14] usbdi(9): New usbd_suspend_pipe, usbd_resume_pipe.

- New usbd_suspend_pipe to persistently stop transfers on a pipe and
  cancel pending ones or wait for their callbacks to finish.
  Idempotent.

- New usbd_resume_pipe to allow transfers again.  Not idempotent --
  as an aid to structuring drivers, you are required to make sure
  every path to usbd_resume_pipe goes through usbd_suspend_pipe.

- Existing usbd_abort_pipe now does suspend then resume.  No change
  in semantics so drivers that relied on being able to submit
  transfers again won't be broken any worse than the already are
  broken.

This allows drivers to avoid races such as:

	/* read */
	if (sc->sc_dying)
		return ENXIO;
	/* (*) */
	err = usbd_bulk_transfer(...);

	/* detach or or close */
	sc->sc_dying = true;
	usbd_abort_pipe(...);
	wait_for_io_to_drain(...);

The detach or close logic might happen at the same time as (*), with
no way to stop the bulk transfer before it starts, leading to
deadlock when detach/close waits for I/O operations like read to
drain.  Instead, the close routine can use usbd_suspend_pipe, and the
usbd_bulk_transfer is guaranteed to fail.

But some drivers such as ucom(4) don't close and reopen pipes after
aborting them -- they open on attach and close on detach, and just
abort when the /dev node is closed, expecting that xfers will
continue to work when next opened.  These drivers can instead use
usbd_suspend_pipe on close and usbd_resume_pipe on open.  Perhaps it
would be better to make them open pipes on open and close pipes on
close, but these functions make for a less intrusive transition.
---
 sys/dev/usb/usbdi.c | 20 +++++++++++++++++++-
 sys/dev/usb/usbdi.h |  3 +++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index 6900e3aab206..4239b1c36eb4 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -774,6 +774,14 @@ usbd_abort_default_pipe(struct usbd_device *device)
 
 void
 usbd_abort_pipe(struct usbd_pipe *pipe)
+{
+
+	usbd_suspend_pipe(pipe);
+	usbd_resume_pipe(pipe);
+}
+
+void
+usbd_suspend_pipe(struct usbd_pipe *pipe)
 {
 
 	KASSERT(pipe != NULL);
@@ -783,6 +791,17 @@ usbd_abort_pipe(struct usbd_pipe *pipe)
 	usbd_unlock_pipe(pipe);
 }
 
+void
+usbd_resume_pipe(struct usbd_pipe *pipe)
+{
+
+	usbd_lock_pipe(pipe);
+	KASSERT(pipe->up_aborting);
+	KASSERT(SIMPLEQ_EMPTY(&pipe->up_queue));
+	pipe->up_aborting = 0;
+	usbd_unlock_pipe(pipe);
+}
+
 usbd_status
 usbd_clear_endpoint_stall(struct usbd_pipe *pipe)
 {
@@ -1003,7 +1022,6 @@ usbd_ar_pipe(struct usbd_pipe *pipe)
 			/* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */
 		}
 	}
-	pipe->up_aborting = 0;
 	SDT_PROBE1(usb, device, pipe, abort__done,  pipe);
 }
 
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index c9c4274adb65..ef81dc466f9a 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -121,6 +121,9 @@ usb_endpoint_descriptor_t *usbd_interface2endpoint_descriptor
 void usbd_abort_pipe(struct usbd_pipe *);
 void usbd_abort_default_pipe(struct usbd_device *);
 
+void usbd_suspend_pipe(struct usbd_pipe *);
+void usbd_resume_pipe(struct usbd_pipe *);
+
 usbd_status usbd_clear_endpoint_stall(struct usbd_pipe *);
 void usbd_clear_endpoint_stall_async(struct usbd_pipe *);
 

>From 284a95cc7c49af55d46dfe82e7a42536266965ee Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 23 Jan 2022 16:40:16 +0000
Subject: [PATCH 11/14] usb: Inline usb_insert_transfer.

This makes it clearer which part happens irrespective of error
(putting it on the queue -- unconditional, not rolled back by
usb_insert_transfer) and what the possible `errors' mean (neither of
which is an error, per se).
---
 sys/dev/usb/usbdi.c | 43 ++++++++++---------------------------------
 1 file changed, 10 insertions(+), 33 deletions(-)

diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index 4239b1c36eb4..a1cb2dfdea29 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -114,7 +114,6 @@ SDT_PROBE_DEFINE2(usb, device, xfer, done,
 SDT_PROBE_DEFINE1(usb, device, xfer, destroy,  "struct usbd_xfer *"/*xfer*/);
 
 Static void usbd_ar_pipe(struct usbd_pipe *);
-static usbd_status usb_insert_transfer(struct usbd_xfer *);
 Static void usbd_start_next(struct usbd_pipe *);
 Static usbd_status usbd_open_pipe_ival
 	(struct usbd_interface *, uint8_t, uint8_t, struct usbd_pipe **, int);
@@ -407,7 +406,16 @@ usbd_transfer(struct usbd_xfer *xfer)
 	SDT_PROBE2(usb, device, pipe, transfer__start,  pipe, xfer);
 	do {
 		usbd_lock_pipe(pipe);
-		err = usb_insert_transfer(xfer);
+#ifdef DIAGNOSTIC
+		xfer->ux_state = XFER_ONQU;
+#endif
+		SIMPLEQ_INSERT_TAIL(&pipe->up_queue, xfer, ux_next);
+		if (pipe->up_running && pipe->up_serialise) {
+			err = USBD_IN_PROGRESS;
+		} else {
+			pipe->up_running = 1;
+			err = USBD_NORMAL_COMPLETION;
+		}
 		usbd_unlock_pipe(pipe);
 		if (err)
 			break;
@@ -1155,37 +1163,6 @@ usb_transfer_complete(struct usbd_xfer *xfer)
 		usbd_start_next(pipe);
 }
 
-/* Called with USB lock held. */
-static usbd_status
-usb_insert_transfer(struct usbd_xfer *xfer)
-{
-	struct usbd_pipe *pipe = xfer->ux_pipe;
-	usbd_status err;
-
-	USBHIST_FUNC(); USBHIST_CALLARGS(usbdebug,
-	    "xfer = %#jx pipe = %#jx running = %jd timeout = %jd",
-	    (uintptr_t)xfer, (uintptr_t)pipe,
-	    pipe->up_running, xfer->ux_timeout);
-
-	KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock));
-	KASSERTMSG(xfer->ux_state == XFER_BUSY, "xfer %p state is %x", xfer,
-	    xfer->ux_state);
-
-#ifdef DIAGNOSTIC
-	xfer->ux_state = XFER_ONQU;
-#endif
-	SIMPLEQ_INSERT_TAIL(&pipe->up_queue, xfer, ux_next);
-	if (pipe->up_running && pipe->up_serialise)
-		err = USBD_IN_PROGRESS;
-	else {
-		pipe->up_running = 1;
-		err = USBD_NORMAL_COMPLETION;
-	}
-	USBHIST_LOG(usbdebug, "<- done xfer %#jx, err %jd", (uintptr_t)xfer,
-	    err, 0, 0);
-	return err;
-}
-
 /* Called with USB lock held. */
 void
 usbd_start_next(struct usbd_pipe *pipe)

>From bd3b7d4c95de67bf2751e3f1c0628bbde430e56a Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sun, 23 Jan 2022 18:50:12 +0000
Subject: [PATCH 12/14] usb: In usbd_transfer, test whether aborting under the
 lock.

Otherwise this test is racy and can cause the bad state of a pipe
with a transfer that will never be completed in a pipe that's about
to close under the expectation that the pipe is empty.
---
 sys/dev/usb/usbdi.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index a1cb2dfdea29..c31f4142ceb9 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -368,13 +368,6 @@ usbd_transfer(struct usbd_xfer *xfer)
 #endif
 	xfer->ux_done = 0;
 
-	if (pipe->up_aborting) {
-		USBHIST_LOG(usbdebug, "<- done xfer %#jx, aborting",
-		    (uintptr_t)xfer, 0, 0, 0);
-		SDT_PROBE2(usb, device, xfer, done,  xfer, USBD_CANCELLED);
-		return USBD_CANCELLED;
-	}
-
 	KASSERT(xfer->ux_length == 0 || xfer->ux_buf != NULL);
 
 	size = xfer->ux_length;
@@ -402,10 +395,23 @@ usbd_transfer(struct usbd_xfer *xfer)
 		}
 	}
 
+	usbd_lock_pipe(pipe);
+	if (pipe->up_aborting) {
+		/*
+		 * XXX For synchronous transfers this is fine.  What to
+		 * do for asynchronous transfers?  The callback is
+		 * never run, not even with status USBD_CANCELLED.
+		 */
+		usbd_unlock_pipe(pipe);
+		USBHIST_LOG(usbdebug, "<- done xfer %#jx, aborting",
+		    (uintptr_t)xfer, 0, 0, 0);
+		SDT_PROBE2(usb, device, xfer, done,  xfer, USBD_CANCELLED);
+		return USBD_CANCELLED;
+	}
+
 	/* xfer is not valid after the transfer method unless synchronous */
 	SDT_PROBE2(usb, device, pipe, transfer__start,  pipe, xfer);
 	do {
-		usbd_lock_pipe(pipe);
 #ifdef DIAGNOSTIC
 		xfer->ux_state = XFER_ONQU;
 #endif

>From 206d3cfc03bc089b52e0aa5ffa3663952bf2da85 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sat, 29 Jan 2022 14:57:27 +0000
Subject: [PATCH 13/14] usb: Hold pipe lock across upm_transfer and upm_start.

This simplifies the code and fixes races with abort.  Access to the
pipe's queue is now done exclusively while the pipe is locked.
---
 sys/arch/mips/adm5120/dev/ahci.c    | 16 +++++---
 sys/dev/ic/sl811hs.c                | 14 +++----
 sys/dev/usb/ehci.c                  | 44 +++++++---------------
 sys/dev/usb/motg.c                  | 27 ++++++--------
 sys/dev/usb/ohci.c                  | 41 ++++++---------------
 sys/dev/usb/uhci.c                  | 46 ++++++++---------------
 sys/dev/usb/usbdi.c                 |  7 +---
 sys/dev/usb/usbdivar.h              |  6 +--
 sys/dev/usb/usbroothub.c            |  9 ++++-
 sys/dev/usb/vhci.c                  | 16 ++------
 sys/dev/usb/xhci.c                  | 57 +++++++++--------------------
 sys/external/bsd/dwc2/dwc2.c        | 43 +++++-----------------
 sys/rump/dev/lib/libugenhc/ugenhc.c | 14 +++----
 13 files changed, 116 insertions(+), 224 deletions(-)

diff --git a/sys/arch/mips/adm5120/dev/ahci.c b/sys/arch/mips/adm5120/dev/ahci.c
index 340650e2a13a..fed8d302a549 100644
--- a/sys/arch/mips/adm5120/dev/ahci.c
+++ b/sys/arch/mips/adm5120/dev/ahci.c
@@ -569,6 +569,8 @@ ahci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 
 	DPRINTF(D_TRACE, ("SLRCstart "));
 
+	KASSERT(bus->ub_polling || mutex_owned(bus->ub_lock));
+
 	len = UGETW(req->wLength);
 	value = UGETW(req->wValue);
 	index = UGETW(req->wIndex);
@@ -743,13 +745,13 @@ ahci_root_intr_start(struct usbd_xfer *xfer)
 
 	DPRINTF(D_TRACE, ("SLRIstart "));
 
-	mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock);
+
 	KASSERT(sc->sc_intr_xfer == NULL);
 	sc->sc_interval = MS_TO_TICKS(xfer->ux_pipe->up_endpoint->ue_edesc->bInterval);
 	callout_schedule(&sc->sc_poll_handle, sc->sc_interval);
 	sc->sc_intr_xfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -834,11 +836,11 @@ ahci_device_ctrl_start(struct usbd_xfer *xfer)
 	struct ahci_softc *sc = AHCI_XFER2SC(xfer);
 	int len, isread;
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock);
 
 #if 0
 	struct ahci_pipe *apipe = (struct ahci_pipe *)xfer->ux_pipe;
 #endif
-	mutex_enter(&sc->sc_lock);
 /*	printf("ctrl_start>>>\n"); */
 
 #ifdef DIAGNOSTIC
@@ -968,7 +970,6 @@ ahci_device_ctrl_start(struct usbd_xfer *xfer)
 /* 	printf("ctrl_start<<<\n"); */
 
 	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
 
 	usb_freemem(&reqdma);
 
@@ -1006,11 +1007,14 @@ ahci_device_intr_transfer(struct usbd_xfer *xfer)
 static usbd_status
 ahci_device_intr_start(struct usbd_xfer *xfer)
 {
+	struct ahci_softc *sc = AHCI_XFER2SC(xfer);
 	struct usbd_pipe *pipe = xfer->ux_pipe;
 	struct ahci_xfer *sx;
 
 	DPRINTF(D_TRACE, ("INTRstart "));
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock);
+
 	sx = kmem_intr_alloc(sizeof(*sx), KM_NOSLEEP);
 	if (sx == NULL)
 		goto reterr;
@@ -1156,6 +1160,8 @@ ahci_device_bulk_start(struct usbd_xfer *xfer)
 #define KSEG1ADDR(x) (0xa0000000 | (((uint32_t)x) & 0x1fffffff))
 	DPRINTF(D_TRACE, ("st "));
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock);
+
 #ifdef DIAGNOSTIC
 	if (xfer->ux_rqflags & URQ_REQUEST) {
 		/* XXX panic */
@@ -1164,7 +1170,6 @@ ahci_device_bulk_start(struct usbd_xfer *xfer)
 	}
 #endif
 
-	mutex_enter(&sc->sc_lock);
 	level++;
 /* 	printf("bulk_start>>>\n"); */
 
@@ -1291,7 +1296,6 @@ ahci_device_bulk_start(struct usbd_xfer *xfer)
 		    isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
 
 	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
 
 	return USBD_NORMAL_COMPLETION;
 }
diff --git a/sys/dev/ic/sl811hs.c b/sys/dev/ic/sl811hs.c
index 35fea39878d1..04a9de937d6c 100644
--- a/sys/dev/ic/sl811hs.c
+++ b/sys/dev/ic/sl811hs.c
@@ -846,10 +846,6 @@ slhci_transfer(struct usbd_xfer *xfer)
 	    0);
 
 	/* Pipe isn't running, so start it first.  */
-
-	/*
-	 * Start will take the lock.
-	 */
 	error = xfer->ux_pipe->up_methods->upm_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 
 	return error;
@@ -867,7 +863,7 @@ slhci_start(struct usbd_xfer *xfer)
 	usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc;
 	unsigned int max_packet;
 
-	mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
 
 	max_packet = UGETW(ed->wMaxPacketSize);
 
@@ -989,8 +985,6 @@ slhci_start(struct usbd_xfer *xfer)
 
 	slhci_start_entry(sc, spipe);
 
-	mutex_exit(&sc->sc_lock);
-
 	return USBD_IN_PROGRESS;
 }
 
@@ -1012,13 +1006,13 @@ slhci_root_start(struct usbd_xfer *xfer)
 	DLOG(D_TRACE, "transfer type %jd start",
 	    SLHCI_XFER_TYPE(xfer), 0, 0, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	KASSERT(spipe->ptype == PT_ROOT_INTR);
 
-	mutex_enter(&sc->sc_intr_lock);
 	KASSERT(t->rootintr == NULL);
 	t->rootintr = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	mutex_exit(&sc->sc_intr_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -3201,6 +3195,8 @@ slhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 	uint8_t type;
 	int actlen = 0;
 
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	len = UGETW(req->wLength);
 	value = UGETW(req->wValue);
 	index = UGETW(req->wIndex);
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
index f01a15d411ca..a3737cbc106c 100644
--- a/sys/dev/usb/ehci.c
+++ b/sys/dev/usb/ehci.c
@@ -2369,6 +2369,8 @@ ehci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 
 	EHCIHIST_FUNC(); EHCIHIST_CALLED();
 
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	if (sc->sc_dying)
 		return -1;
 
@@ -2757,18 +2759,15 @@ Static usbd_status
 ehci_root_intr_start(struct usbd_xfer *xfer)
 {
 	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	const bool polling = sc->sc_bus.ub_usepolling;
+
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
 
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	KASSERT(sc->sc_intrxfer == NULL);
 	sc->sc_intrxfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -3607,10 +3606,10 @@ ehci_device_ctrl_start(struct usbd_xfer *xfer)
 	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
 	ehci_soft_qtd_t *setup, *status, *next;
 	ehci_soft_qh_t *sqh;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	EHCIHIST_FUNC(); EHCIHIST_CALLED();
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
 	KASSERT(xfer->ux_rqflags & URQ_REQUEST);
 
 	if (sc->sc_dying)
@@ -3729,16 +3728,11 @@ ehci_device_ctrl_start(struct usbd_xfer *xfer)
 	DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0);
 #endif
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	/* Insert qTD in QH list - also does usb_syncmem(sqh) */
 	ehci_set_qh_qtd(sqh, setup);
 	usbd_xfer_schedule_timeout(xfer);
 	ehci_add_intr_list(sc, exfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 #if 0
 #ifdef EHCI_DEBUG
@@ -3878,13 +3872,14 @@ ehci_device_bulk_start(struct usbd_xfer *xfer)
 	ehci_soft_qh_t *sqh;
 	ehci_soft_qtd_t *end;
 	int len, isread, endpt;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	EHCIHIST_FUNC(); EHCIHIST_CALLED();
 
 	DPRINTF("xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer, xfer->ux_length,
 	    xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -3901,10 +3896,6 @@ ehci_device_bulk_start(struct usbd_xfer *xfer)
 	exfer->ex_isdone = false;
 #endif
 
-	/* Take lock here to protect nexttoggle */
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	ehci_reset_sqtd_chain(sc, xfer, len, isread, &epipe->nexttoggle, &end);
 
 	exfer->ex_sqtdend = end;
@@ -3928,8 +3919,6 @@ ehci_device_bulk_start(struct usbd_xfer *xfer)
 	usbd_xfer_schedule_timeout(xfer);
 	ehci_add_intr_list(sc, exfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 #if 0
 #ifdef EHCI_DEBUG
@@ -4082,13 +4071,14 @@ ehci_device_intr_start(struct usbd_xfer *xfer)
 	ehci_soft_qtd_t *end;
 	ehci_soft_qh_t *sqh;
 	int len, isread, endpt;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	EHCIHIST_FUNC(); EHCIHIST_CALLED();
 
 	DPRINTF("xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer, xfer->ux_length,
 	    xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -4105,10 +4095,6 @@ ehci_device_intr_start(struct usbd_xfer *xfer)
 	exfer->ex_isdone = false;
 #endif
 
-	/* Take lock to protect nexttoggle */
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	ehci_reset_sqtd_chain(sc, xfer, len, isread, &epipe->nexttoggle, &end);
 
 	end->qtd.qtd_status |= htole32(EHCI_QTD_IOC);
@@ -4132,8 +4118,6 @@ ehci_device_intr_start(struct usbd_xfer *xfer)
 	usbd_xfer_schedule_timeout(xfer);
 	ehci_add_intr_list(sc, exfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 #if 0
 #ifdef EHCI_DEBUG
@@ -4325,6 +4309,8 @@ ehci_device_fs_isoc_transfer(struct usbd_xfer *xfer)
 	DPRINTF("xfer %#jx len %jd flags %jd", (uintptr_t)xfer, xfer->ux_length,
 	    xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -4458,8 +4444,6 @@ ehci_device_fs_isoc_transfer(struct usbd_xfer *xfer)
 	 * more than the period frame list.
 	 */
 
-	mutex_enter(&sc->sc_lock);
-
 	/* Start inserting frames */
 	if (epipe->isoc.cur_xfers > 0) {
 		frindex = epipe->isoc.next_frame;
@@ -4522,7 +4506,6 @@ ehci_device_fs_isoc_transfer(struct usbd_xfer *xfer)
 
 	ehci_add_intr_list(sc, exfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -4690,6 +4673,8 @@ ehci_device_isoc_transfer(struct usbd_xfer *xfer)
 
 	DPRINTF("xfer %#jx flags %jd", (uintptr_t)xfer, xfer->ux_flags, 0, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -4836,8 +4821,6 @@ ehci_device_isoc_transfer(struct usbd_xfer *xfer)
 	 * more than the period frame list.
 	 */
 
-	mutex_enter(&sc->sc_lock);
-
 	/* Start inserting frames */
 	if (epipe->isoc.cur_xfers > 0) {
 		frindex = epipe->isoc.next_frame;
@@ -4905,7 +4888,6 @@ ehci_device_isoc_transfer(struct usbd_xfer *xfer)
 
 	ehci_add_intr_list(sc, exfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
diff --git a/sys/dev/usb/motg.c b/sys/dev/usb/motg.c
index 36f5e01c4b64..2faca383246c 100644
--- a/sys/dev/usb/motg.c
+++ b/sys/dev/usb/motg.c
@@ -806,6 +806,8 @@ motg_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 
 	MOTGHIST_FUNC(); MOTGHIST_CALLED();
 
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	if (sc->sc_dying)
 		return -1;
 
@@ -1020,23 +1022,20 @@ motg_root_intr_start(struct usbd_xfer *xfer)
 {
 	struct usbd_pipe *pipe = xfer->ux_pipe;
 	struct motg_softc *sc = MOTG_PIPE2SC(pipe);
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	MOTGHIST_FUNC(); MOTGHIST_CALLED();
 
 	DPRINTFN(MD_ROOT, "xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer,
 	    xfer->ux_length, xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	KASSERT(sc->sc_intr_xfer == NULL);
 	sc->sc_intr_xfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -1276,11 +1275,10 @@ static usbd_status
 motg_device_ctrl_start(struct usbd_xfer *xfer)
 {
 	struct motg_softc *sc = MOTG_XFER2SC(xfer);
-	usbd_status err;
-	mutex_enter(&sc->sc_lock);
-	err = motg_device_ctrl_start1(sc);
-	mutex_exit(&sc->sc_lock);
-	return err;
+
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
+	return motg_device_ctrl_start1(sc);
 }
 
 static usbd_status
@@ -1717,15 +1715,14 @@ motg_device_data_start(struct usbd_xfer *xfer)
 {
 	struct motg_softc *sc = MOTG_XFER2SC(xfer);
 	struct motg_pipe *otgpipe = MOTG_PIPE2MPIPE(xfer->ux_pipe);
-	usbd_status err;
 
 	MOTGHIST_FUNC(); MOTGHIST_CALLED();
 
-	mutex_enter(&sc->sc_lock);
 	DPRINTF("xfer %#jx status %jd", (uintptr_t)xfer, xfer->ux_status, 0, 0);
-	err = motg_device_data_start1(sc, otgpipe->hw_ep);
-	mutex_exit(&sc->sc_lock);
-	return err;
+
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
+	return motg_device_data_start1(sc, otgpipe->hw_ep);
 }
 
 static usbd_status
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index 4e0f827c100f..938d5e085c9a 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -2431,6 +2431,8 @@ ohci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 
 	OHCIHIST_FUNC(); OHCIHIST_CALLED();
 
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	if (sc->sc_dying)
 		return -1;
 
@@ -2620,18 +2622,15 @@ Static usbd_status
 ohci_root_intr_start(struct usbd_xfer *xfer)
 {
 	ohci_softc_t *sc = OHCI_XFER2SC(xfer);
-	const bool polling = sc->sc_bus.ub_usepolling;
+
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
 
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	KASSERT(sc->sc_intrxfer == NULL);
 	sc->sc_intrxfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -2777,10 +2776,11 @@ ohci_device_ctrl_start(struct usbd_xfer *xfer)
 	ohci_soft_ed_t *sed;
 	int isread;
 	int len;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	OHCIHIST_FUNC(); OHCIHIST_CALLED();
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -2795,10 +2795,6 @@ ohci_device_ctrl_start(struct usbd_xfer *xfer)
 	    req->bmRequestType, req->bRequest, UGETW(req->wValue),
 	    UGETW(req->wIndex));
 
-	/* Need to take lock here for pipe->tail.td */
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	/*
 	 * Use the pipe "tail" TD as our first and loan our first TD to the
 	 * next transfer
@@ -2933,8 +2929,6 @@ ohci_device_ctrl_start(struct usbd_xfer *xfer)
 	DPRINTF("done", 0, 0, 0, 0);
 
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -3054,10 +3048,11 @@ ohci_device_bulk_start(struct usbd_xfer *xfer)
 	ohci_soft_td_t *data, *tail, *tdp;
 	ohci_soft_ed_t *sed;
 	int len, isread, endpt;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	OHCIHIST_FUNC(); OHCIHIST_CALLED();
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -3072,9 +3067,6 @@ ohci_device_bulk_start(struct usbd_xfer *xfer)
 	    len, isread, xfer->ux_flags);
 	DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0);
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	/*
 	 * Use the pipe "tail" TD as our first and loan our first TD to the
 	 * next transfer
@@ -3141,8 +3133,6 @@ ohci_device_bulk_start(struct usbd_xfer *xfer)
 	OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
 	usbd_xfer_schedule_timeout(xfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -3252,10 +3242,11 @@ ohci_device_intr_start(struct usbd_xfer *xfer)
 	ohci_soft_ed_t *sed = opipe->sed;
 	ohci_soft_td_t *data, *last, *tail;
 	int len, isread, endpt;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	OHCIHIST_FUNC(); OHCIHIST_CALLED();
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -3268,9 +3259,6 @@ ohci_device_intr_start(struct usbd_xfer *xfer)
 	endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress;
 	isread = UE_GET_DIR(endpt) == UE_DIR_IN;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	/*
 	 * Use the pipe "tail" TD as our first and loan our first TD to the
 	 * next transfer.
@@ -3327,8 +3315,6 @@ ohci_device_intr_start(struct usbd_xfer *xfer)
 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -3559,12 +3545,10 @@ ohci_device_isoc_enter(struct usbd_xfer *xfer)
 	OHCIHIST_FUNC(); OHCIHIST_CALLED();
 	DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0);
 
-	mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
 
-	if (sc->sc_dying) {
-		mutex_exit(&sc->sc_lock);
+	if (sc->sc_dying)
 		return;
-	}
 
 	struct isoc *isoc = &opipe->isoc;
 
@@ -3723,7 +3707,6 @@ ohci_device_isoc_enter(struct usbd_xfer *xfer)
 	usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags),
 	    sizeof(sed->ed.ed_flags),
 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-	mutex_exit(&sc->sc_lock);
 }
 
 void
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index 1e9718b112c0..692a1ad92dd0 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -2271,7 +2271,6 @@ uhci_device_bulk_start(struct usbd_xfer *xfer)
 	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
 	uhci_soft_td_t *data, *dataend;
 	uhci_soft_qh_t *sqh;
-	const bool polling = sc->sc_bus.ub_usepolling;
 	int len;
 	int endpt;
 	int isread;
@@ -2280,6 +2279,8 @@ uhci_device_bulk_start(struct usbd_xfer *xfer)
 	DPRINTFN(3, "xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer,
 	    xfer->ux_length, xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -2291,10 +2292,6 @@ uhci_device_bulk_start(struct usbd_xfer *xfer)
 	isread = UE_GET_DIR(endpt) == UE_DIR_IN;
 	sqh = upipe->bulk.sqh;
 
-	/* Take lock here to protect nexttoggle */
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	uhci_reset_std_chain(sc, xfer, len, isread, &upipe->nexttoggle,
 	    &dataend);
 
@@ -2328,8 +2325,6 @@ uhci_device_bulk_start(struct usbd_xfer *xfer)
 	uhci_add_intr_list(sc, ux);
 	usbd_xfer_schedule_timeout(xfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -2495,12 +2490,13 @@ uhci_device_ctrl_start(struct usbd_xfer *xfer)
 	int endpt = upipe->pipe.up_endpoint->ue_edesc->bEndpointAddress;
 	uhci_soft_td_t *setup, *stat, *next, *dataend;
 	uhci_soft_qh_t *sqh;
-	const bool polling = sc->sc_bus.ub_usepolling;
 	int len;
 	int isread;
 
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -2523,9 +2519,6 @@ uhci_device_ctrl_start(struct usbd_xfer *xfer)
 	memcpy(KERNADDR(&upipe->ctrl.reqdma, 0), req, sizeof(*req));
 	usb_syncmem(&upipe->ctrl.reqdma, 0, sizeof(*req), BUS_DMASYNC_PREWRITE);
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	/* Set up data transaction */
 	if (len != 0) {
 		upipe->nexttoggle = 1;
@@ -2623,8 +2616,6 @@ uhci_device_ctrl_start(struct usbd_xfer *xfer)
 #endif
 	usbd_xfer_schedule_timeout(xfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -2685,18 +2676,19 @@ uhci_device_intr_start(struct usbd_xfer *xfer)
 	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
 	uhci_soft_td_t *data, *dataend;
 	uhci_soft_qh_t *sqh;
-	const bool polling = sc->sc_bus.ub_usepolling;
 	int isread, endpt;
 	int i;
 
-	if (sc->sc_dying)
-		return USBD_IOERROR;
-
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
 
 	DPRINTFN(3, "xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer,
 	    xfer->ux_length, xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
+	if (sc->sc_dying)
+		return USBD_IOERROR;
+
 	KASSERT(!(xfer->ux_rqflags & URQ_REQUEST));
 	KASSERT(xfer->ux_length <= xfer->ux_bufsize);
 
@@ -2711,8 +2703,6 @@ uhci_device_intr_start(struct usbd_xfer *xfer)
 #endif
 
 	/* Take lock to protect nexttoggle */
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	uhci_reset_std_chain(sc, xfer, xfer->ux_length, isread,
 	    &upipe->nexttoggle, &dataend);
 
@@ -2744,8 +2734,6 @@ uhci_device_intr_start(struct usbd_xfer *xfer)
 	}
 	uhci_add_intr_list(sc, ux);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 #ifdef UHCI_DEBUG
 	if (uhcidebug >= 10) {
@@ -2854,6 +2842,8 @@ uhci_device_isoc_transfer(struct usbd_xfer *xfer)
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
 	DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	/* insert into schedule, */
 
 	struct uhci_pipe *upipe = UHCI_PIPE2UPIPE(xfer->ux_pipe);
@@ -2887,7 +2877,6 @@ uhci_device_isoc_transfer(struct usbd_xfer *xfer)
 		usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length,
 		    rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
 
-	mutex_enter(&sc->sc_lock);
 	next = isoc->next;
 	if (next == -1) {
 		/* Not in use yet, schedule it a few frames ahead. */
@@ -2949,8 +2938,6 @@ uhci_device_isoc_transfer(struct usbd_xfer *xfer)
 #endif
 	uhci_add_intr_list(sc, ux);
 
-	mutex_exit(&sc->sc_lock);
-
 	return USBD_IN_PROGRESS;
 }
 
@@ -3602,6 +3589,8 @@ uhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
 
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	if (sc->sc_dying)
 		return -1;
 
@@ -3853,18 +3842,16 @@ uhci_root_intr_start(struct usbd_xfer *xfer)
 	struct usbd_pipe *pipe = xfer->ux_pipe;
 	uhci_softc_t *sc = UHCI_PIPE2SC(pipe);
 	unsigned int ival;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
 	DPRINTF("xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer, xfer->ux_length,
 	    xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	KASSERT(sc->sc_intr_xfer == NULL);
 
 	/* XXX temporary variable needed to avoid gcc3 warning */
@@ -3874,9 +3861,6 @@ uhci_root_intr_start(struct usbd_xfer *xfer)
 	sc->sc_intr_xfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
 
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
-
 	return USBD_IN_PROGRESS;
 }
 
diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index c31f4142ceb9..32e2afcfd8ea 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -422,13 +422,14 @@ usbd_transfer(struct usbd_xfer *xfer)
 			pipe->up_running = 1;
 			err = USBD_NORMAL_COMPLETION;
 		}
-		usbd_unlock_pipe(pipe);
 		if (err)
 			break;
 		err = pipe->up_methods->upm_transfer(xfer);
 	} while (0);
 	SDT_PROBE3(usb, device, pipe, transfer__done,  pipe, xfer, err);
 
+	usbd_unlock_pipe(pipe);
+
 	if (err != USBD_IN_PROGRESS && err) {
 		/*
 		 * The transfer made it onto the pipe queue, but didn't get
@@ -1193,12 +1194,8 @@ usbd_start_next(struct usbd_pipe *pipe)
 	if (xfer == NULL) {
 		pipe->up_running = 0;
 	} else {
-		if (!polling)
-			mutex_exit(pipe->up_dev->ud_bus->ub_lock);
 		SDT_PROBE2(usb, device, pipe, start,  pipe, xfer);
 		err = pipe->up_methods->upm_start(xfer);
-		if (!polling)
-			mutex_enter(pipe->up_dev->ud_bus->ub_lock);
 
 		if (err != USBD_IN_PROGRESS) {
 			USBHIST_LOG(usbdebug, "error = %jd", err, 0, 0, 0);
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index 3f92e323afb2..81e79ee77bbf 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -51,14 +51,14 @@
  *	ubm_abortx		x	must not release/reacquire lock
  *	ubm_getlock 		-	Called at attach time
  *	ubm_newdev		-	Will take lock
- *	ubm_rhctrl
+ *	ubm_rhctrl              x
  *
  *	PIPE METHOD		LOCK	NOTES
  *	----------------------- -------	-------------------------
  *	upm_init		-
  *	upm_fini		-
- *	upm_transfer		-
- *	upm_start		-	might want to take lock?
+ *	upm_transfer		x
+ *	upm_start		x
  *	upm_abort		x
  *	upm_close		x
  *	upm_cleartoggle		-
diff --git a/sys/dev/usb/usbroothub.c b/sys/dev/usb/usbroothub.c
index 7e9139434fb7..8e2ceacdac5a 100644
--- a/sys/dev/usb/usbroothub.c
+++ b/sys/dev/usb/usbroothub.c
@@ -361,6 +361,13 @@ roothub_ctrl_start(struct usbd_xfer *xfer)
 
 	USBHIST_FUNC();
 
+	/*
+	 * XXX Should really assert pipe lock, in case ever have
+	 * per-pipe locking instead of using the bus lock for all
+	 * pipes.
+	 */
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	KASSERT(xfer->ux_rqflags & URQ_REQUEST);
 	req = &xfer->ux_request;
 
@@ -554,9 +561,7 @@ roothub_ctrl_start(struct usbd_xfer *xfer)
 	    (uintptr_t)xfer, buflen, actlen, err);
 
 	xfer->ux_status = err;
-	mutex_enter(bus->ub_lock);
 	usb_transfer_complete(xfer);
-	mutex_exit(bus->ub_lock);
 
 	return USBD_NORMAL_COMPLETION;
 }
diff --git a/sys/dev/usb/vhci.c b/sys/dev/usb/vhci.c
index a73b14e1cb5a..7d4254cc70b5 100644
--- a/sys/dev/usb/vhci.c
+++ b/sys/dev/usb/vhci.c
@@ -605,7 +605,6 @@ vhci_device_ctrl_start(struct usbd_xfer *xfer)
 	struct usbd_device *dev = xfer->ux_pipe->up_dev;
 	vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
 	vhci_port_t *port;
-	bool polling = sc->sc_bus.ub_usepolling;
 	bool isread = (req->bmRequestType & UT_READ) != 0;
 	uint8_t addr = UE_GET_ADDR(ed->bEndpointAddress);
 	int portno, ret;
@@ -618,14 +617,13 @@ vhci_device_ctrl_start(struct usbd_xfer *xfer)
 	DPRINTF("%s: type=0x%02x, len=%d, isread=%d, portno=%d\n",
 	    __func__, req->bmRequestType, UGETW(req->wLength), isread, portno);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
 	port = &sc->sc_port[portno];
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	mutex_enter(&port->lock);
 	if (port->status & UPS_PORT_ENABLED) {
 		xfer->ux_status = USBD_IN_PROGRESS;
@@ -636,9 +634,6 @@ vhci_device_ctrl_start(struct usbd_xfer *xfer)
 	}
 	mutex_exit(&port->lock);
 
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
-
 	return ret;
 }
 
@@ -709,20 +704,17 @@ static usbd_status
 vhci_root_intr_start(struct usbd_xfer *xfer)
 {
 	vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	DPRINTF("%s: called, len=%zu\n", __func__, (size_t)xfer->ux_length);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	KASSERT(sc->sc_intrxfer == NULL);
 	sc->sc_intrxfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c
index 9be02a019def..efc6f7459eb2 100644
--- a/sys/dev/usb/xhci.c
+++ b/sys/dev/usb/xhci.c
@@ -2186,7 +2186,6 @@ xhci_pipe_async_task(void *cookie)
 	struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
 	const u_int dci = xhci_ep_get_dci(pipe->up_endpoint->ue_edesc);
 	struct xhci_ring * const tr = xs->xs_xr[dci];
-	bool restart = false;
 
 	XHCIHIST_FUNC();
 	XHCIHIST_CALLARGS("pipe %#jx slot %ju dci %ju",
@@ -2227,31 +2226,18 @@ xhci_pipe_async_task(void *cookie)
 
 	/*
 	 * If we halted our own queue because it stalled, mark it no
-	 * longer halted and arrange to start it up again.
+	 * longer halted and start issuing queued transfers again.
 	 */
 	if (tr->is_halted) {
+		struct usbd_xfer *xfer = SIMPLEQ_FIRST(&pipe->up_queue);
+
 		tr->is_halted = false;
-		if (!SIMPLEQ_EMPTY(&pipe->up_queue))
-			restart = true;
+		if (xfer)
+			(*pipe->up_methods->upm_start)(xfer);
 	}
 
 	mutex_exit(&sc->sc_lock);
 
-	/*
-	 * If the endpoint was stalled, start issuing queued transfers
-	 * again.
-	 */
-	if (restart) {
-		/*
-		 * XXX Shouldn't touch the queue unlocked -- upm_start
-		 * should be called with the lock held instead.  The
-		 * pipe could be aborted at this point, and the xfer
-		 * freed.
-		 */
-		struct usbd_xfer *xfer = SIMPLEQ_FIRST(&pipe->up_queue);
-		(*pipe->up_methods->upm_start)(xfer);
-	}
-
 	DPRINTFN(4, "ends", 0, 0, 0, 0);
 }
 
@@ -3870,6 +3856,8 @@ xhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 
 	XHCIHIST_FUNC();
 
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	if (sc->sc_dying)
 		return -1;
 
@@ -4139,20 +4127,17 @@ xhci_root_intr_start(struct usbd_xfer *xfer)
 {
 	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
 	const size_t bn = XHCI_XFER2BUS(xfer) == &sc->sc_bus ? 0 : 1;
-	const bool polling = xhci_polling_p(sc);
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
+	KASSERT(xhci_polling_p(sc) || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	KASSERT(sc->sc_intrxfer[bn] == NULL);
 	sc->sc_intrxfer[bn] = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -4250,14 +4235,14 @@ xhci_device_ctrl_start(struct usbd_xfer *xfer)
 	    req->bmRequestType | (req->bRequest << 8), UGETW(req->wValue),
 	    UGETW(req->wIndex), UGETW(req->wLength));
 
+	KASSERT(polling || mutex_owned(&sc->sc_lock));
+
 	/* we rely on the bottom bits for extra info */
 	KASSERTMSG(((uintptr_t)xfer & 0x3) == 0x0, "xfer %zx",
 	    (uintptr_t) xfer);
 
 	KASSERT((xfer->ux_rqflags & URQ_REQUEST) != 0);
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	if (tr->is_halted)
 		goto out;
 
@@ -4315,8 +4300,6 @@ out:	if (xfer->ux_status == USBD_NOT_STARTED) {
 		 */
 	}
 	KASSERT(xfer->ux_status == USBD_IN_PROGRESS);
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -4388,6 +4371,8 @@ xhci_device_isoc_enter(struct usbd_xfer *xfer)
 	XHCIHIST_CALLARGS("%#jx slot %ju dci %ju",
 	    (uintptr_t)xfer, xs->xs_idx, dci, 0);
 
+	KASSERT(polling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -4460,13 +4445,9 @@ xhci_device_isoc_enter(struct usbd_xfer *xfer)
 	if (!polling)
 		mutex_exit(&tr->xr_lock);
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	xfer->ux_status = USBD_IN_PROGRESS;
 	xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci);
 	usbd_xfer_schedule_timeout(xfer);
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -4536,13 +4517,13 @@ xhci_device_bulk_start(struct usbd_xfer *xfer)
 	XHCIHIST_CALLARGS("%#jx slot %ju dci %ju",
 	    (uintptr_t)xfer, xs->xs_idx, dci, 0);
 
+	KASSERT(polling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
 	KASSERT((xfer->ux_rqflags & URQ_REQUEST) == 0);
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	if (tr->is_halted)
 		goto out;
 
@@ -4590,8 +4571,6 @@ out:	if (xfer->ux_status == USBD_NOT_STARTED) {
 		 */
 	}
 	KASSERT(xfer->ux_status == USBD_IN_PROGRESS);
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -4661,11 +4640,11 @@ xhci_device_intr_start(struct usbd_xfer *xfer)
 	XHCIHIST_CALLARGS("%#jx slot %ju dci %ju",
 	    (uintptr_t)xfer, xs->xs_idx, dci, 0);
 
+	KASSERT(polling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	if (tr->is_halted)
 		goto out;
 
@@ -4703,8 +4682,6 @@ out:	if (xfer->ux_status == USBD_NOT_STARTED) {
 		 */
 	}
 	KASSERT(xfer->ux_status == USBD_IN_PROGRESS);
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
diff --git a/sys/external/bsd/dwc2/dwc2.c b/sys/external/bsd/dwc2/dwc2.c
index 19ffae0e8ab4..7bc817f0448e 100644
--- a/sys/external/bsd/dwc2/dwc2.c
+++ b/sys/external/bsd/dwc2/dwc2.c
@@ -620,20 +620,17 @@ Static usbd_status
 dwc2_root_intr_start(struct usbd_xfer *xfer)
 {
 	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	DPRINTF("\n");
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	KASSERT(sc->sc_intrxfer == NULL);
 	sc->sc_intrxfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -709,17 +706,13 @@ dwc2_device_ctrl_start(struct usbd_xfer *xfer)
 {
 	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
 	usbd_status err;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	DPRINTF("\n");
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	xfer->ux_status = USBD_IN_PROGRESS;
 	err = dwc2_device_start(xfer);
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
-
 	if (err)
 		return err;
 
@@ -760,18 +753,12 @@ dwc2_device_ctrl_done(struct usbd_xfer *xfer)
 Static usbd_status
 dwc2_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	usbd_status err;
 
 	DPRINTF("xfer=%p\n", xfer);
 
-	mutex_enter(&sc->sc_lock);
 	KASSERT(xfer->ux_status == USBD_NOT_STARTED);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	err = dwc2_device_start(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	return err;
+	return dwc2_device_start(xfer);
 }
 
 Static void
@@ -820,15 +807,11 @@ dwc2_device_intr_start(struct usbd_xfer *xfer)
 	struct usbd_device *dev = dpipe->pipe.up_dev;
 	struct dwc2_softc *sc = dev->ud_bus->ub_hcpriv;
 	usbd_status err;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	xfer->ux_status = USBD_IN_PROGRESS;
 	err = dwc2_device_start(xfer);
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
-
 	if (err)
 		return err;
 
@@ -868,18 +851,12 @@ dwc2_device_intr_done(struct usbd_xfer *xfer)
 usbd_status
 dwc2_device_isoc_transfer(struct usbd_xfer *xfer)
 {
-	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	usbd_status err;
 
 	DPRINTF("xfer=%p\n", xfer);
 
-	mutex_enter(&sc->sc_lock);
 	KASSERT(xfer->ux_status == USBD_NOT_STARTED);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	err = dwc2_device_start(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	return err;
+	return dwc2_device_start(xfer);
 }
 
 void
@@ -933,6 +910,8 @@ dwc2_device_start(struct usbd_xfer *xfer)
 
 	DPRINTFN(1, "xfer=%p pipe=%p\n", xfer, xfer->ux_pipe);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (xfertype == UE_ISOCHRONOUS ||
 	    xfertype == UE_INTERRUPT) {
 		mutex_spin_enter(&hsotg->lock);
@@ -1121,9 +1100,7 @@ dwc2_device_start(struct usbd_xfer *xfer)
 				dwc2_hcd_get_ep_bandwidth(hsotg, dpipe),
 				xfer);
 	}
-
 	mutex_spin_exit(&hsotg->lock);
-// 	mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 
diff --git a/sys/rump/dev/lib/libugenhc/ugenhc.c b/sys/rump/dev/lib/libugenhc/ugenhc.c
index f6f80877940e..a1fb16f3e02c 100644
--- a/sys/rump/dev/lib/libugenhc/ugenhc.c
+++ b/sys/rump/dev/lib/libugenhc/ugenhc.c
@@ -227,6 +227,8 @@ rumpusb_device_ctrl_start(struct usbd_xfer *xfer)
 	int err = 0;
 	int ru_error, mightfail = 0;
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	len = totlen = UGETW(req->wLength);
 	if (len)
 		buf = xfer->ux_buf;
@@ -391,9 +393,7 @@ rumpusb_device_ctrl_start(struct usbd_xfer *xfer)
 
  ret:
 	xfer->ux_status = err;
-	mutex_enter(&sc->sc_lock);
 	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -516,7 +516,8 @@ rumpusb_root_intr_start(struct usbd_xfer *xfer)
 	struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer);
 	int error;
 
-	mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	sc->sc_intrxfer = xfer;
 	if (!sc->sc_rhintr) {
 		error = kthread_create(PRI_NONE, 0, NULL,
@@ -524,7 +525,6 @@ rumpusb_root_intr_start(struct usbd_xfer *xfer)
 		if (error)
 			xfer->ux_status = USBD_IOERROR;
 	}
-	mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -581,6 +581,8 @@ rumpusb_device_bulk_start(struct usbd_xfer *xfer)
 	int xfererr = USBD_NORMAL_COMPLETION;
 	int shortval, i;
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	ed = xfer->ux_pipe->up_endpoint->ue_edesc;
 	endpt = ed->bEndpointAddress;
 	isread = UE_GET_DIR(endpt) == UE_DIR_IN;
@@ -667,9 +669,7 @@ rumpusb_device_bulk_start(struct usbd_xfer *xfer)
 		if (done != len)
 			panic("lazy bum");
 	xfer->ux_status = xfererr;
-	mutex_enter(&sc->sc_lock);
 	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
 	return USBD_IN_PROGRESS;
 }
 
@@ -682,9 +682,7 @@ doxfer_kth(void *arg)
 	mutex_enter(&sc->sc_lock);
 	do {
 		struct usbd_xfer *xfer = SIMPLEQ_FIRST(&pipe->up_queue);
-		mutex_exit(&sc->sc_lock);
 		rumpusb_device_bulk_start(xfer);
-		mutex_enter(&sc->sc_lock);
 	} while (!SIMPLEQ_EMPTY(&pipe->up_queue));
 	mutex_exit(&sc->sc_lock);
 	kthread_exit(0);

>From b9d30e8da45841330ff123a527e9d90497aff9f4 Mon Sep 17 00:00:00 2001
From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
Date: Sat, 29 Jan 2022 17:38:23 +0000
Subject: [PATCH 14/14] usb: Assert hci doesn't synchronously complete async
 xfers.

The xfer callback must not be invoked synchronously, because it might
need to take a lock that the caller holds.

However, the hci might return failure to the caller, meaning the xfer
callback will not be invoked at all.
---
 sys/dev/usb/usbdi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index 32e2afcfd8ea..93adb1d5752d 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -452,8 +452,8 @@ usbd_transfer(struct usbd_xfer *xfer)
 	if (!(flags & USBD_SYNCHRONOUS)) {
 		USBHIST_LOG(usbdebug, "<- done xfer %#jx, not sync (err %jd)",
 		    (uintptr_t)xfer, err, 0, 0);
-		if (err != USBD_IN_PROGRESS) /* XXX Possible?  */
-			SDT_PROBE2(usb, device, xfer, done,  xfer, err);
+		KASSERTMSG(err != USBD_NORMAL_COMPLETION,
+		    "asynchronous xfer %p completed synchronously", xfer);
 		return err;
 	}
 
diff --git a/sys/arch/mips/adm5120/dev/ahci.c b/sys/arch/mips/adm5120/dev/ahci.c
index 2b98e4ae221e..fed8d302a549 100644
--- a/sys/arch/mips/adm5120/dev/ahci.c
+++ b/sys/arch/mips/adm5120/dev/ahci.c
@@ -569,6 +569,8 @@ ahci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 
 	DPRINTF(D_TRACE, ("SLRCstart "));
 
+	KASSERT(bus->ub_polling || mutex_owned(bus->ub_lock));
+
 	len = UGETW(req->wLength);
 	value = UGETW(req->wValue);
 	index = UGETW(req->wIndex);
@@ -729,22 +731,10 @@ ahci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 static usbd_status
 ahci_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct ahci_softc *sc = AHCI_XFER2SC(xfer);
-	usbd_status error;
 
 	DPRINTF(D_TRACE, ("SLRItransfer "));
 
-	/* Insert last in queue */
-	mutex_enter(&sc->sc_lock);
-	error = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (error)
-		return error;
-
-	/*
-	 * Pipe isn't running (otherwise error would be USBD_INPROG),
-	 * start first.
-	 */
+	/* Pipe isn't running, start first.  */
 	return ahci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -755,13 +745,13 @@ ahci_root_intr_start(struct usbd_xfer *xfer)
 
 	DPRINTF(D_TRACE, ("SLRIstart "));
 
-	mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock);
+
 	KASSERT(sc->sc_intr_xfer == NULL);
 	sc->sc_interval = MS_TO_TICKS(xfer->ux_pipe->up_endpoint->ue_edesc->bInterval);
 	callout_schedule(&sc->sc_poll_handle, sc->sc_interval);
 	sc->sc_intr_xfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -827,17 +817,9 @@ ahci_root_intr_done(struct usbd_xfer *xfer)
 static usbd_status
 ahci_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	struct ahci_softc *sc = AHCI_XFER2SC(xfer);
-	usbd_status error;
 
 	DPRINTF(D_TRACE, ("C"));
 
-	mutex_enter(&sc->sc_lock);
-	error = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (error)
-		return error;
-
 	return ahci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -854,11 +836,11 @@ ahci_device_ctrl_start(struct usbd_xfer *xfer)
 	struct ahci_softc *sc = AHCI_XFER2SC(xfer);
 	int len, isread;
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock);
 
 #if 0
 	struct ahci_pipe *apipe = (struct ahci_pipe *)xfer->ux_pipe;
 #endif
-	mutex_enter(&sc->sc_lock);
 /*	printf("ctrl_start>>>\n"); */
 
 #ifdef DIAGNOSTIC
@@ -988,7 +970,6 @@ ahci_device_ctrl_start(struct usbd_xfer *xfer)
 /* 	printf("ctrl_start<<<\n"); */
 
 	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
 
 	usb_freemem(&reqdma);
 
@@ -1017,28 +998,23 @@ ahci_device_ctrl_done(struct usbd_xfer *xfer)
 static usbd_status
 ahci_device_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct ahci_softc *sc = AHCI_XFER2SC(xfer);
-	usbd_status error;
 
 	DPRINTF(D_TRACE, ("INTRtrans "));
 
-	mutex_enter(&sc->sc_lock);
-	error = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (error)
-		return error;
-
 	return ahci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
 static usbd_status
 ahci_device_intr_start(struct usbd_xfer *xfer)
 {
+	struct ahci_softc *sc = AHCI_XFER2SC(xfer);
 	struct usbd_pipe *pipe = xfer->ux_pipe;
 	struct ahci_xfer *sx;
 
 	DPRINTF(D_TRACE, ("INTRstart "));
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock);
+
 	sx = kmem_intr_alloc(sizeof(*sx), KM_NOSLEEP);
 	if (sx == NULL)
 		goto reterr;
@@ -1161,17 +1137,9 @@ ahci_device_isoc_done(struct usbd_xfer *xfer)
 static usbd_status
 ahci_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	struct ahci_softc *sc = AHCI_XFER2SC(xfer);
-	usbd_status error;
 
 	DPRINTF(D_TRACE, ("B"));
 
-	mutex_enter(&sc->sc_lock);
-	error = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (error)
-		return error;
-
 	return ahci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -1192,6 +1160,8 @@ ahci_device_bulk_start(struct usbd_xfer *xfer)
 #define KSEG1ADDR(x) (0xa0000000 | (((uint32_t)x) & 0x1fffffff))
 	DPRINTF(D_TRACE, ("st "));
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock);
+
 #ifdef DIAGNOSTIC
 	if (xfer->ux_rqflags & URQ_REQUEST) {
 		/* XXX panic */
@@ -1200,7 +1170,6 @@ ahci_device_bulk_start(struct usbd_xfer *xfer)
 	}
 #endif
 
-	mutex_enter(&sc->sc_lock);
 	level++;
 /* 	printf("bulk_start>>>\n"); */
 
@@ -1327,7 +1296,6 @@ ahci_device_bulk_start(struct usbd_xfer *xfer)
 		    isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
 
 	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
 
 	return USBD_NORMAL_COMPLETION;
 }
diff --git a/sys/dev/ic/sl811hs.c b/sys/dev/ic/sl811hs.c
index e5773430ccaf..04a9de937d6c 100644
--- a/sys/dev/ic/sl811hs.c
+++ b/sys/dev/ic/sl811hs.c
@@ -839,32 +839,13 @@ usbd_status
 slhci_transfer(struct usbd_xfer *xfer)
 {
 	SLHCIHIST_FUNC(); SLHCIHIST_CALLED();
-	struct slhci_softc *sc = SLHCI_XFER2SC(xfer);
 	usbd_status error;
 
 	DLOG(D_TRACE, "transfer type %jd xfer %#jx spipe %#jx ",
 	    SLHCI_XFER_TYPE(xfer), (uintptr_t)xfer, (uintptr_t)xfer->ux_pipe,
 	    0);
 
-	/* Insert last in queue */
-	mutex_enter(&sc->sc_lock);
-	error = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (error) {
-		if (error != USBD_IN_PROGRESS)
-			DLOG(D_ERR, "usb_insert_transfer returns %jd!", error,
-			    0,0,0);
-		return error;
-	}
-
-	/*
-	 * Pipe isn't running (otherwise error would be USBD_INPROG),
-	 * so start it first.
-	 */
-
-	/*
-	 * Start will take the lock.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	error = xfer->ux_pipe->up_methods->upm_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 
 	return error;
@@ -882,7 +863,7 @@ slhci_start(struct usbd_xfer *xfer)
 	usb_endpoint_descriptor_t *ed = pipe->up_endpoint->ue_edesc;
 	unsigned int max_packet;
 
-	mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
 
 	max_packet = UGETW(ed->wMaxPacketSize);
 
@@ -1004,8 +985,6 @@ slhci_start(struct usbd_xfer *xfer)
 
 	slhci_start_entry(sc, spipe);
 
-	mutex_exit(&sc->sc_lock);
-
 	return USBD_IN_PROGRESS;
 }
 
@@ -1027,13 +1006,13 @@ slhci_root_start(struct usbd_xfer *xfer)
 	DLOG(D_TRACE, "transfer type %jd start",
 	    SLHCI_XFER_TYPE(xfer), 0, 0, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	KASSERT(spipe->ptype == PT_ROOT_INTR);
 
-	mutex_enter(&sc->sc_intr_lock);
 	KASSERT(t->rootintr == NULL);
 	t->rootintr = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	mutex_exit(&sc->sc_intr_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -3216,6 +3195,8 @@ slhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 	uint8_t type;
 	int actlen = 0;
 
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	len = UGETW(req->wLength);
 	value = UGETW(req->wValue);
 	index = UGETW(req->wIndex);
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
index f6ff864d5155..a3737cbc106c 100644
--- a/sys/dev/usb/ehci.c
+++ b/sys/dev/usb/ehci.c
@@ -2369,6 +2369,8 @@ ehci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 
 	EHCIHIST_FUNC(); EHCIHIST_CALLED();
 
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	if (sc->sc_dying)
 		return -1;
 
@@ -2748,15 +2750,6 @@ ehci_disown(ehci_softc_t *sc, int index, int lowspeed)
 Static usbd_status
 ehci_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ehci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -2766,18 +2759,15 @@ Static usbd_status
 ehci_root_intr_start(struct usbd_xfer *xfer)
 {
 	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	const bool polling = sc->sc_bus.ub_usepolling;
+
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
 
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	KASSERT(sc->sc_intrxfer == NULL);
 	sc->sc_intrxfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -3397,14 +3387,10 @@ ehci_abortx(struct usbd_xfer *xfer)
 		    BUS_DMASYNC_PREREAD);
 	}
 
-	/*
-	 * Final step: Notify completion to waiting xfers.
-	 */
 dying:
 #ifdef DIAGNOSTIC
 	exfer->ex_isdone = true;
 #endif
-	usb_transfer_complete(xfer);
 	DPRINTFN(14, "end", 0, 0, 0, 0);
 
 	KASSERT(mutex_owned(&sc->sc_lock));
@@ -3606,15 +3592,6 @@ ehci_device_ctrl_fini(struct usbd_xfer *xfer)
 Static usbd_status
 ehci_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ehci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -3629,10 +3606,10 @@ ehci_device_ctrl_start(struct usbd_xfer *xfer)
 	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
 	ehci_soft_qtd_t *setup, *status, *next;
 	ehci_soft_qh_t *sqh;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	EHCIHIST_FUNC(); EHCIHIST_CALLED();
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
 	KASSERT(xfer->ux_rqflags & URQ_REQUEST);
 
 	if (sc->sc_dying)
@@ -3751,16 +3728,11 @@ ehci_device_ctrl_start(struct usbd_xfer *xfer)
 	DPRINTFN(5, "--- dump end ---", 0, 0, 0, 0);
 #endif
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	/* Insert qTD in QH list - also does usb_syncmem(sqh) */
 	ehci_set_qh_qtd(sqh, setup);
 	usbd_xfer_schedule_timeout(xfer);
 	ehci_add_intr_list(sc, exfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 #if 0
 #ifdef EHCI_DEBUG
@@ -3886,15 +3858,6 @@ ehci_device_bulk_fini(struct usbd_xfer *xfer)
 Static usbd_status
 ehci_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ehci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -3909,13 +3872,14 @@ ehci_device_bulk_start(struct usbd_xfer *xfer)
 	ehci_soft_qh_t *sqh;
 	ehci_soft_qtd_t *end;
 	int len, isread, endpt;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	EHCIHIST_FUNC(); EHCIHIST_CALLED();
 
 	DPRINTF("xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer, xfer->ux_length,
 	    xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -3932,10 +3896,6 @@ ehci_device_bulk_start(struct usbd_xfer *xfer)
 	exfer->ex_isdone = false;
 #endif
 
-	/* Take lock here to protect nexttoggle */
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	ehci_reset_sqtd_chain(sc, xfer, len, isread, &epipe->nexttoggle, &end);
 
 	exfer->ex_sqtdend = end;
@@ -3959,8 +3919,6 @@ ehci_device_bulk_start(struct usbd_xfer *xfer)
 	usbd_xfer_schedule_timeout(xfer);
 	ehci_add_intr_list(sc, exfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 #if 0
 #ifdef EHCI_DEBUG
@@ -4099,20 +4057,8 @@ ehci_device_intr_fini(struct usbd_xfer *xfer)
 Static usbd_status
 ehci_device_intr_transfer(struct usbd_xfer *xfer)
 {
-	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	usbd_status err;
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return ehci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -4125,13 +4071,14 @@ ehci_device_intr_start(struct usbd_xfer *xfer)
 	ehci_soft_qtd_t *end;
 	ehci_soft_qh_t *sqh;
 	int len, isread, endpt;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	EHCIHIST_FUNC(); EHCIHIST_CALLED();
 
 	DPRINTF("xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer, xfer->ux_length,
 	    xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -4148,10 +4095,6 @@ ehci_device_intr_start(struct usbd_xfer *xfer)
 	exfer->ex_isdone = false;
 #endif
 
-	/* Take lock to protect nexttoggle */
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	ehci_reset_sqtd_chain(sc, xfer, len, isread, &epipe->nexttoggle, &end);
 
 	end->qtd.qtd_status |= htole32(EHCI_QTD_IOC);
@@ -4175,8 +4118,6 @@ ehci_device_intr_start(struct usbd_xfer *xfer)
 	usbd_xfer_schedule_timeout(xfer);
 	ehci_add_intr_list(sc, exfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 #if 0
 #ifdef EHCI_DEBUG
@@ -4351,14 +4292,6 @@ Static usbd_status
 ehci_device_fs_isoc_transfer(struct usbd_xfer *xfer)
 {
 	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	usbd_status __diagused err;
-
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	KASSERT(err == USBD_NORMAL_COMPLETION);
-
 	struct ehci_pipe *epipe = EHCI_XFER2EPIPE(xfer);
 	struct usbd_device *dev = xfer->ux_pipe->up_dev;
 	struct ehci_xfer *exfer = EHCI_XFER2EXFER(xfer);
@@ -4376,6 +4309,8 @@ ehci_device_fs_isoc_transfer(struct usbd_xfer *xfer)
 	DPRINTF("xfer %#jx len %jd flags %jd", (uintptr_t)xfer, xfer->ux_length,
 	    xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -4509,8 +4444,6 @@ ehci_device_fs_isoc_transfer(struct usbd_xfer *xfer)
 	 * more than the period frame list.
 	 */
 
-	mutex_enter(&sc->sc_lock);
-
 	/* Start inserting frames */
 	if (epipe->isoc.cur_xfers > 0) {
 		frindex = epipe->isoc.next_frame;
@@ -4573,7 +4506,6 @@ ehci_device_fs_isoc_transfer(struct usbd_xfer *xfer)
 
 	ehci_add_intr_list(sc, exfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -4724,14 +4656,6 @@ Static usbd_status
 ehci_device_isoc_transfer(struct usbd_xfer *xfer)
 {
 	ehci_softc_t *sc = EHCI_XFER2SC(xfer);
-	usbd_status __diagused err;
-
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	KASSERT(err == USBD_NORMAL_COMPLETION);
-
 	struct ehci_pipe *epipe = EHCI_XFER2EPIPE(xfer);
 	struct ehci_xfer *exfer = EHCI_XFER2EXFER(xfer);
 	ehci_soft_itd_t *itd, *prev;
@@ -4749,6 +4673,8 @@ ehci_device_isoc_transfer(struct usbd_xfer *xfer)
 
 	DPRINTF("xfer %#jx flags %jd", (uintptr_t)xfer, xfer->ux_flags, 0, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -4895,8 +4821,6 @@ ehci_device_isoc_transfer(struct usbd_xfer *xfer)
 	 * more than the period frame list.
 	 */
 
-	mutex_enter(&sc->sc_lock);
-
 	/* Start inserting frames */
 	if (epipe->isoc.cur_xfers > 0) {
 		frindex = epipe->isoc.next_frame;
@@ -4964,7 +4888,6 @@ ehci_device_isoc_transfer(struct usbd_xfer *xfer)
 
 	ehci_add_intr_list(sc, exfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
diff --git a/sys/dev/usb/if_atu.c b/sys/dev/usb/if_atu.c
index 85222d1dce28..6b0d464269a5 100644
--- a/sys/dev/usb/if_atu.c
+++ b/sys/dev/usb/if_atu.c
@@ -2223,7 +2223,6 @@ atu_stop(struct ifnet *ifp, int disable)
 	struct atu_softc	*sc = ifp->if_softc;
 	struct ieee80211com	*ic = &sc->sc_ic;
 	struct atu_cdata	*cd;
-	usbd_status		err;
 	int s;
 
 	s = splnet();
@@ -2235,19 +2234,11 @@ atu_stop(struct ifnet *ifp, int disable)
 
 	/* Stop transfers. */
 	if (sc->atu_ep[ATU_ENDPT_RX] != NULL) {
-		err = usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_RX]);
-		if (err) {
-			DPRINTF(("%s: abort rx pipe failed: %s\n",
-			    device_xname(sc->atu_dev), usbd_errstr(err)));
-		}
+		usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_RX]);
 	}
 
 	if (sc->atu_ep[ATU_ENDPT_TX] != NULL) {
-		err = usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_TX]);
-		if (err) {
-			DPRINTF(("%s: abort tx pipe failed: %s\n",
-			    device_xname(sc->atu_dev), usbd_errstr(err)));
-		}
+		usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_TX]);
 	}
 
 	/* Free RX/TX/MGMT list resources. */
@@ -2257,20 +2248,12 @@ atu_stop(struct ifnet *ifp, int disable)
 
 	/* Close pipes */
 	if (sc->atu_ep[ATU_ENDPT_RX] != NULL) {
-		err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_RX]);
-		if (err) {
-			DPRINTF(("%s: close rx pipe failed: %s\n",
-			    device_xname(sc->atu_dev), usbd_errstr(err)));
-		}
+		usbd_close_pipe(sc->atu_ep[ATU_ENDPT_RX]);
 		sc->atu_ep[ATU_ENDPT_RX] = NULL;
 	}
 
 	if (sc->atu_ep[ATU_ENDPT_TX] != NULL) {
-		err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_TX]);
-		if (err) {
-			DPRINTF(("%s: close tx pipe failed: %s\n",
-			    device_xname(sc->atu_dev), usbd_errstr(err)));
-		}
+		usbd_close_pipe(sc->atu_ep[ATU_ENDPT_TX]);
 		sc->atu_ep[ATU_ENDPT_TX] = NULL;
 	}
 
diff --git a/sys/dev/usb/if_urtw.c b/sys/dev/usb/if_urtw.c
index 162141c8072f..f08db3030887 100644
--- a/sys/dev/usb/if_urtw.c
+++ b/sys/dev/usb/if_urtw.c
@@ -829,24 +829,17 @@ urtw_close_pipes(struct urtw_softc *sc)
 	usbd_status error = 0;
 
 	if (sc->sc_rxpipe != NULL) {
-		error = usbd_close_pipe(sc->sc_rxpipe);
-		if (error != 0)
-			goto fail;
+		usbd_close_pipe(sc->sc_rxpipe);
 		sc->sc_rxpipe = NULL;
 	}
 	if (sc->sc_txpipe_low != NULL) {
-		error = usbd_close_pipe(sc->sc_txpipe_low);
-		if (error != 0)
-			goto fail;
+		usbd_close_pipe(sc->sc_txpipe_low);
 		sc->sc_txpipe_low = NULL;
 	}
 	if (sc->sc_txpipe_normal != NULL) {
-		error = usbd_close_pipe(sc->sc_txpipe_normal);
-		if (error != 0)
-			goto fail;
+		usbd_close_pipe(sc->sc_txpipe_normal);
 		sc->sc_txpipe_normal = NULL;
 	}
-fail:
 	return error;
 }
 
diff --git a/sys/dev/usb/motg.c b/sys/dev/usb/motg.c
index 63339b4f0d54..2faca383246c 100644
--- a/sys/dev/usb/motg.c
+++ b/sys/dev/usb/motg.c
@@ -806,6 +806,8 @@ motg_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 
 	MOTGHIST_FUNC(); MOTGHIST_CALLED();
 
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	if (sc->sc_dying)
 		return -1;
 
@@ -1009,20 +1011,8 @@ motg_root_intr_abort(struct usbd_xfer *xfer)
 usbd_status
 motg_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct motg_softc *sc = MOTG_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * start first
-	 */
+	/* Pipe isn't running, start first */
 	return motg_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -1032,23 +1022,20 @@ motg_root_intr_start(struct usbd_xfer *xfer)
 {
 	struct usbd_pipe *pipe = xfer->ux_pipe;
 	struct motg_softc *sc = MOTG_PIPE2SC(pipe);
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	MOTGHIST_FUNC(); MOTGHIST_CALLED();
 
 	DPRINTFN(MD_ROOT, "xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer,
 	    xfer->ux_length, xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	KASSERT(sc->sc_intr_xfer == NULL);
 	sc->sc_intr_xfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -1279,21 +1266,8 @@ motg_setup_endpoint_rx(struct usbd_xfer *xfer)
 static usbd_status
 motg_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	struct motg_softc *sc = MOTG_XFER2SC(xfer);
-	usbd_status err;
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	KASSERT(xfer->ux_status == USBD_NOT_STARTED);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return motg_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -1301,11 +1275,10 @@ static usbd_status
 motg_device_ctrl_start(struct usbd_xfer *xfer)
 {
 	struct motg_softc *sc = MOTG_XFER2SC(xfer);
-	usbd_status err;
-	mutex_enter(&sc->sc_lock);
-	err = motg_device_ctrl_start1(sc);
-	mutex_exit(&sc->sc_lock);
-	return err;
+
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
+	return motg_device_ctrl_start1(sc);
 }
 
 static usbd_status
@@ -1731,24 +1704,9 @@ motg_device_ctrl_done(struct usbd_xfer *xfer)
 static usbd_status
 motg_device_data_transfer(struct usbd_xfer *xfer)
 {
-	struct motg_softc *sc = MOTG_XFER2SC(xfer);
-	usbd_status err;
-
 	MOTGHIST_FUNC(); MOTGHIST_CALLED();
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	DPRINTF("xfer %#jx status %jd", (uintptr_t)xfer, xfer->ux_status, 0, 0);
-	err = usb_insert_transfer(xfer);
-	KASSERT(xfer->ux_status == USBD_NOT_STARTED);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return motg_device_data_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -1757,15 +1715,14 @@ motg_device_data_start(struct usbd_xfer *xfer)
 {
 	struct motg_softc *sc = MOTG_XFER2SC(xfer);
 	struct motg_pipe *otgpipe = MOTG_PIPE2MPIPE(xfer->ux_pipe);
-	usbd_status err;
 
 	MOTGHIST_FUNC(); MOTGHIST_CALLED();
 
-	mutex_enter(&sc->sc_lock);
 	DPRINTF("xfer %#jx status %jd", (uintptr_t)xfer, xfer->ux_status, 0, 0);
-	err = motg_device_data_start1(sc, otgpipe->hw_ep);
-	mutex_exit(&sc->sc_lock);
-	return err;
+
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
+	return motg_device_data_start1(sc, otgpipe->hw_ep);
 }
 
 static usbd_status
@@ -2262,6 +2219,5 @@ motg_abortx(struct usbd_xfer *xfer)
 		}
 	}
 dying:
-	usb_transfer_complete(xfer);
 	KASSERT(mutex_owned(&sc->sc_lock));
 }
diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c
index bd8ab4f33a27..938d5e085c9a 100644
--- a/sys/dev/usb/ohci.c
+++ b/sys/dev/usb/ohci.c
@@ -2409,12 +2409,7 @@ ohci_abortx(struct usbd_xfer *xfer)
 	usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags),
 	    sizeof(sed->ed.ed_flags),
 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-
-	/*
-	 * Final step: Notify completion to waiting xfers.
-	 */
 dying:
-	usb_transfer_complete(xfer);
 	DPRINTFN(14, "end", 0, 0, 0, 0);
 
 	KASSERT(mutex_owned(&sc->sc_lock));
@@ -2436,6 +2431,8 @@ ohci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 
 	OHCIHIST_FUNC(); OHCIHIST_CALLED();
 
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	if (sc->sc_dying)
 		return -1;
 
@@ -2616,15 +2613,6 @@ ohci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 Static usbd_status
 ohci_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	ohci_softc_t *sc = OHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ohci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -2634,18 +2622,15 @@ Static usbd_status
 ohci_root_intr_start(struct usbd_xfer *xfer)
 {
 	ohci_softc_t *sc = OHCI_XFER2SC(xfer);
-	const bool polling = sc->sc_bus.ub_usepolling;
+
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
 
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	KASSERT(sc->sc_intrxfer == NULL);
 	sc->sc_intrxfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -2774,15 +2759,6 @@ ohci_device_ctrl_fini(struct usbd_xfer *xfer)
 Static usbd_status
 ohci_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	ohci_softc_t *sc = OHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ohci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -2800,10 +2776,11 @@ ohci_device_ctrl_start(struct usbd_xfer *xfer)
 	ohci_soft_ed_t *sed;
 	int isread;
 	int len;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	OHCIHIST_FUNC(); OHCIHIST_CALLED();
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -2818,10 +2795,6 @@ ohci_device_ctrl_start(struct usbd_xfer *xfer)
 	    req->bmRequestType, req->bRequest, UGETW(req->wValue),
 	    UGETW(req->wIndex));
 
-	/* Need to take lock here for pipe->tail.td */
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	/*
 	 * Use the pipe "tail" TD as our first and loan our first TD to the
 	 * next transfer
@@ -2956,8 +2929,6 @@ ohci_device_ctrl_start(struct usbd_xfer *xfer)
 	DPRINTF("done", 0, 0, 0, 0);
 
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -3062,15 +3033,6 @@ ohci_device_bulk_fini(struct usbd_xfer *xfer)
 Static usbd_status
 ohci_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	ohci_softc_t *sc = OHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ohci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -3086,10 +3048,11 @@ ohci_device_bulk_start(struct usbd_xfer *xfer)
 	ohci_soft_td_t *data, *tail, *tdp;
 	ohci_soft_ed_t *sed;
 	int len, isread, endpt;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	OHCIHIST_FUNC(); OHCIHIST_CALLED();
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -3104,9 +3067,6 @@ ohci_device_bulk_start(struct usbd_xfer *xfer)
 	    len, isread, xfer->ux_flags);
 	DPRINTFN(4, "endpt=%jd", endpt, 0, 0, 0);
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	/*
 	 * Use the pipe "tail" TD as our first and loan our first TD to the
 	 * next transfer
@@ -3173,8 +3133,6 @@ ohci_device_bulk_start(struct usbd_xfer *xfer)
 	OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF);
 	usbd_xfer_schedule_timeout(xfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -3270,15 +3228,6 @@ ohci_device_intr_fini(struct usbd_xfer *xfer)
 Static usbd_status
 ohci_device_intr_transfer(struct usbd_xfer *xfer)
 {
-	ohci_softc_t *sc = OHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return ohci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -3293,10 +3242,11 @@ ohci_device_intr_start(struct usbd_xfer *xfer)
 	ohci_soft_ed_t *sed = opipe->sed;
 	ohci_soft_td_t *data, *last, *tail;
 	int len, isread, endpt;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	OHCIHIST_FUNC(); OHCIHIST_CALLED();
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -3309,9 +3259,6 @@ ohci_device_intr_start(struct usbd_xfer *xfer)
 	endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress;
 	isread = UE_GET_DIR(endpt) == UE_DIR_IN;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	/*
 	 * Use the pipe "tail" TD as our first and loan our first TD to the
 	 * next transfer.
@@ -3368,8 +3315,6 @@ ohci_device_intr_start(struct usbd_xfer *xfer)
 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -3574,20 +3519,10 @@ ohci_device_isoc_fini(struct usbd_xfer *xfer)
 usbd_status
 ohci_device_isoc_transfer(struct usbd_xfer *xfer)
 {
-	ohci_softc_t *sc = OHCI_XFER2SC(xfer);
-	usbd_status __diagused err;
-
 	OHCIHIST_FUNC(); OHCIHIST_CALLED();
 
 	DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0);
 
-	/* Put it on our queue, */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	KASSERT(err == USBD_NORMAL_COMPLETION);
-
 	/* insert into schedule, */
 	ohci_device_isoc_enter(xfer);
 
@@ -3610,12 +3545,10 @@ ohci_device_isoc_enter(struct usbd_xfer *xfer)
 	OHCIHIST_FUNC(); OHCIHIST_CALLED();
 	DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0);
 
-	mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
 
-	if (sc->sc_dying) {
-		mutex_exit(&sc->sc_lock);
+	if (sc->sc_dying)
 		return;
-	}
 
 	struct isoc *isoc = &opipe->isoc;
 
@@ -3774,7 +3707,6 @@ ohci_device_isoc_enter(struct usbd_xfer *xfer)
 	usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags),
 	    sizeof(sed->ed.ed_flags),
 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-	mutex_exit(&sc->sc_lock);
 }
 
 void
diff --git a/sys/dev/usb/ualea.c b/sys/dev/usb/ualea.c
index ede886968af4..d38722351672 100644
--- a/sys/dev/usb/ualea.c
+++ b/sys/dev/usb/ualea.c
@@ -161,14 +161,14 @@ ualea_detach(device_t self, int flags)
 
 	/* Cancel pending xfer.  */
 	if (sc->sc_pipe)
-		(void)usbd_abort_pipe(sc->sc_pipe);
+		usbd_abort_pipe(sc->sc_pipe);
 	KASSERT(!sc->sc_inflight);
 
 	/* All users have drained.  Tear it all down.  */
 	if (sc->sc_xfer)
 		usbd_destroy_xfer(sc->sc_xfer);
 	if (sc->sc_pipe)
-		(void)usbd_close_pipe(sc->sc_pipe);
+		usbd_close_pipe(sc->sc_pipe);
 	mutex_destroy(&sc->sc_lock);
 
 	return 0;
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index acf5e2e32c11..692a1ad92dd0 100644
--- a/sys/dev/usb/uhci.c
+++ b/sys/dev/usb/uhci.c
@@ -2258,20 +2258,8 @@ uhci_device_bulk_fini(struct usbd_xfer *xfer)
 usbd_status
 uhci_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return uhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -2283,7 +2271,6 @@ uhci_device_bulk_start(struct usbd_xfer *xfer)
 	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
 	uhci_soft_td_t *data, *dataend;
 	uhci_soft_qh_t *sqh;
-	const bool polling = sc->sc_bus.ub_usepolling;
 	int len;
 	int endpt;
 	int isread;
@@ -2292,6 +2279,8 @@ uhci_device_bulk_start(struct usbd_xfer *xfer)
 	DPRINTFN(3, "xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer,
 	    xfer->ux_length, xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -2303,10 +2292,6 @@ uhci_device_bulk_start(struct usbd_xfer *xfer)
 	isread = UE_GET_DIR(endpt) == UE_DIR_IN;
 	sqh = upipe->bulk.sqh;
 
-	/* Take lock here to protect nexttoggle */
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	uhci_reset_std_chain(sc, xfer, len, isread, &upipe->nexttoggle,
 	    &dataend);
 
@@ -2340,8 +2325,6 @@ uhci_device_bulk_start(struct usbd_xfer *xfer)
 	uhci_add_intr_list(sc, ux);
 	usbd_xfer_schedule_timeout(xfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -2414,15 +2397,10 @@ uhci_abortx(struct usbd_xfer *xfer)
 	 */
 	/* Hardware finishes in 1ms */
 	usb_delay_ms_locked(upipe->pipe.up_dev->ud_bus, 2, &sc->sc_lock);
-
-	/*
-	 * HC Step 3: Notify completion to waiting xfers.
-	 */
 dying:
 #ifdef DIAGNOSTIC
 	ux->ux_isdone = true;
 #endif
-	usb_transfer_complete(xfer);
 	DPRINTFN(14, "end", 0, 0, 0, 0);
 
 	KASSERT(mutex_owned(&sc->sc_lock));
@@ -2495,20 +2473,8 @@ uhci_device_ctrl_fini(struct usbd_xfer *xfer)
 usbd_status
 uhci_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
-	usbd_status err;
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return uhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -2524,12 +2490,13 @@ uhci_device_ctrl_start(struct usbd_xfer *xfer)
 	int endpt = upipe->pipe.up_endpoint->ue_edesc->bEndpointAddress;
 	uhci_soft_td_t *setup, *stat, *next, *dataend;
 	uhci_soft_qh_t *sqh;
-	const bool polling = sc->sc_bus.ub_usepolling;
 	int len;
 	int isread;
 
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -2552,9 +2519,6 @@ uhci_device_ctrl_start(struct usbd_xfer *xfer)
 	memcpy(KERNADDR(&upipe->ctrl.reqdma, 0), req, sizeof(*req));
 	usb_syncmem(&upipe->ctrl.reqdma, 0, sizeof(*req), BUS_DMASYNC_PREWRITE);
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	/* Set up data transaction */
 	if (len != 0) {
 		upipe->nexttoggle = 1;
@@ -2652,8 +2616,6 @@ uhci_device_ctrl_start(struct usbd_xfer *xfer)
 #endif
 	usbd_xfer_schedule_timeout(xfer);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -2701,20 +2663,8 @@ uhci_device_intr_fini(struct usbd_xfer *xfer)
 usbd_status
 uhci_device_intr_transfer(struct usbd_xfer *xfer)
 {
-	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return uhci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -2726,18 +2676,19 @@ uhci_device_intr_start(struct usbd_xfer *xfer)
 	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
 	uhci_soft_td_t *data, *dataend;
 	uhci_soft_qh_t *sqh;
-	const bool polling = sc->sc_bus.ub_usepolling;
 	int isread, endpt;
 	int i;
 
-	if (sc->sc_dying)
-		return USBD_IOERROR;
-
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
 
 	DPRINTFN(3, "xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer,
 	    xfer->ux_length, xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
+	if (sc->sc_dying)
+		return USBD_IOERROR;
+
 	KASSERT(!(xfer->ux_rqflags & URQ_REQUEST));
 	KASSERT(xfer->ux_length <= xfer->ux_bufsize);
 
@@ -2752,8 +2703,6 @@ uhci_device_intr_start(struct usbd_xfer *xfer)
 #endif
 
 	/* Take lock to protect nexttoggle */
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	uhci_reset_std_chain(sc, xfer, xfer->ux_length, isread,
 	    &upipe->nexttoggle, &dataend);
 
@@ -2785,8 +2734,6 @@ uhci_device_intr_start(struct usbd_xfer *xfer)
 	}
 	uhci_add_intr_list(sc, ux);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 #ifdef UHCI_DEBUG
 	if (uhcidebug >= 10) {
@@ -2891,17 +2838,11 @@ usbd_status
 uhci_device_isoc_transfer(struct usbd_xfer *xfer)
 {
 	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
-	usbd_status err __diagused;
 
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
 	DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0);
 
-	/* Put it on our queue, */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	KASSERT(err == USBD_NORMAL_COMPLETION);
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
 
 	/* insert into schedule, */
 
@@ -2936,7 +2877,6 @@ uhci_device_isoc_transfer(struct usbd_xfer *xfer)
 		usb_syncmem(&xfer->ux_dmabuf, 0, xfer->ux_length,
 		    rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
 
-	mutex_enter(&sc->sc_lock);
 	next = isoc->next;
 	if (next == -1) {
 		/* Not in use yet, schedule it a few frames ahead. */
@@ -2998,8 +2938,6 @@ uhci_device_isoc_transfer(struct usbd_xfer *xfer)
 #endif
 	uhci_add_intr_list(sc, ux);
 
-	mutex_exit(&sc->sc_lock);
-
 	return USBD_IN_PROGRESS;
 }
 
@@ -3651,6 +3589,8 @@ uhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
 
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	if (sc->sc_dying)
 		return -1;
 
@@ -3890,20 +3830,8 @@ uhci_root_intr_abort(struct usbd_xfer *xfer)
 usbd_status
 uhci_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	uhci_softc_t *sc = UHCI_XFER2SC(xfer);
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * start first
-	 */
+	/* Pipe isn't running, start first */
 	return uhci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -3914,18 +3842,16 @@ uhci_root_intr_start(struct usbd_xfer *xfer)
 	struct usbd_pipe *pipe = xfer->ux_pipe;
 	uhci_softc_t *sc = UHCI_PIPE2SC(pipe);
 	unsigned int ival;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
 	DPRINTF("xfer=%#jx len=%jd flags=%jd", (uintptr_t)xfer, xfer->ux_length,
 	    xfer->ux_flags, 0);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	KASSERT(sc->sc_intr_xfer == NULL);
 
 	/* XXX temporary variable needed to avoid gcc3 warning */
@@ -3935,9 +3861,6 @@ uhci_root_intr_start(struct usbd_xfer *xfer)
 	sc->sc_intr_xfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
 
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
-
 	return USBD_IN_PROGRESS;
 }
 
diff --git a/sys/dev/usb/usb_mem.h b/sys/dev/usb/usb_mem.h
index 5473c1b3b810..b93d694cfc3c 100644
--- a/sys/dev/usb/usb_mem.h
+++ b/sys/dev/usb/usb_mem.h
@@ -31,6 +31,16 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifndef	_DEV_USB_USB_MEM_H_
+#define	_DEV_USB_USB_MEM_H_
+
+#include <sys/types.h>
+
+#include <sys/bus.h>
+#include <sys/queue.h>
+
+#include <dev/usb/usbdivar.h>
+
 typedef struct usb_dma_block {
 	bus_dma_tag_t tag;
 	bus_dmamap_t map;
@@ -60,3 +70,5 @@ bus_addr_t	usb_dmaaddr(usb_dma_t *, unsigned int);
 #define DMAADDR(dma, o)	usb_dmaaddr((dma), (o))
 #define KERNADDR(dma, o) \
 	((void *)((char *)(dma)->udma_block->kaddr + (dma)->udma_offs + (o)))
+
+#endif	/* _DEV_USB_USB_MEM_H_ */
diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index 02b1a41e9e08..93adb1d5752d 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -113,14 +113,14 @@ SDT_PROBE_DEFINE2(usb, device, xfer, done,
     "usbd_status"/*status*/);
 SDT_PROBE_DEFINE1(usb, device, xfer, destroy,  "struct usbd_xfer *"/*xfer*/);
 
-Static usbd_status usbd_ar_pipe(struct usbd_pipe *);
+Static void usbd_ar_pipe(struct usbd_pipe *);
 Static void usbd_start_next(struct usbd_pipe *);
 Static usbd_status usbd_open_pipe_ival
 	(struct usbd_interface *, uint8_t, uint8_t, struct usbd_pipe **, int);
 static void *usbd_alloc_buffer(struct usbd_xfer *, uint32_t);
 static void usbd_free_buffer(struct usbd_xfer *);
 static struct usbd_xfer *usbd_alloc_xfer(struct usbd_device *, unsigned int);
-static usbd_status usbd_free_xfer(struct usbd_xfer *);
+static void usbd_free_xfer(struct usbd_xfer *);
 static void usbd_request_async_cb(struct usbd_xfer *, void *, usbd_status);
 static void usbd_xfer_timeout(void *);
 static void usbd_xfer_timeout_task(void *);
@@ -320,7 +320,7 @@ usbd_open_pipe_intr(struct usbd_interface *iface, uint8_t address,
 	return err;
 }
 
-usbd_status
+void
 usbd_close_pipe(struct usbd_pipe *pipe)
 {
 	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
@@ -347,8 +347,6 @@ usbd_close_pipe(struct usbd_pipe *pipe)
 	if (pipe->up_iface)
 		usbd_iface_pipeunref(pipe->up_iface);
 	kmem_free(pipe, pipe->up_dev->ud_bus->ub_pipesize);
-
-	return USBD_NORMAL_COMPLETION;
 }
 
 usbd_status
@@ -370,13 +368,6 @@ usbd_transfer(struct usbd_xfer *xfer)
 #endif
 	xfer->ux_done = 0;
 
-	if (pipe->up_aborting) {
-		USBHIST_LOG(usbdebug, "<- done xfer %#jx, aborting",
-		    (uintptr_t)xfer, 0, 0, 0);
-		SDT_PROBE2(usb, device, xfer, done,  xfer, USBD_CANCELLED);
-		return USBD_CANCELLED;
-	}
-
 	KASSERT(xfer->ux_length == 0 || xfer->ux_buf != NULL);
 
 	size = xfer->ux_length;
@@ -404,11 +395,41 @@ usbd_transfer(struct usbd_xfer *xfer)
 		}
 	}
 
+	usbd_lock_pipe(pipe);
+	if (pipe->up_aborting) {
+		/*
+		 * XXX For synchronous transfers this is fine.  What to
+		 * do for asynchronous transfers?  The callback is
+		 * never run, not even with status USBD_CANCELLED.
+		 */
+		usbd_unlock_pipe(pipe);
+		USBHIST_LOG(usbdebug, "<- done xfer %#jx, aborting",
+		    (uintptr_t)xfer, 0, 0, 0);
+		SDT_PROBE2(usb, device, xfer, done,  xfer, USBD_CANCELLED);
+		return USBD_CANCELLED;
+	}
+
 	/* xfer is not valid after the transfer method unless synchronous */
 	SDT_PROBE2(usb, device, pipe, transfer__start,  pipe, xfer);
-	err = pipe->up_methods->upm_transfer(xfer);
+	do {
+#ifdef DIAGNOSTIC
+		xfer->ux_state = XFER_ONQU;
+#endif
+		SIMPLEQ_INSERT_TAIL(&pipe->up_queue, xfer, ux_next);
+		if (pipe->up_running && pipe->up_serialise) {
+			err = USBD_IN_PROGRESS;
+		} else {
+			pipe->up_running = 1;
+			err = USBD_NORMAL_COMPLETION;
+		}
+		if (err)
+			break;
+		err = pipe->up_methods->upm_transfer(xfer);
+	} while (0);
 	SDT_PROBE3(usb, device, pipe, transfer__done,  pipe, xfer, err);
 
+	usbd_unlock_pipe(pipe);
+
 	if (err != USBD_IN_PROGRESS && err) {
 		/*
 		 * The transfer made it onto the pipe queue, but didn't get
@@ -431,8 +452,8 @@ usbd_transfer(struct usbd_xfer *xfer)
 	if (!(flags & USBD_SYNCHRONOUS)) {
 		USBHIST_LOG(usbdebug, "<- done xfer %#jx, not sync (err %jd)",
 		    (uintptr_t)xfer, err, 0, 0);
-		if (err != USBD_IN_PROGRESS) /* XXX Possible?  */
-			SDT_PROBE2(usb, device, xfer, done,  xfer, err);
+		KASSERTMSG(err != USBD_NORMAL_COMPLETION,
+		    "asynchronous xfer %p completed synchronously", xfer);
 		return err;
 	}
 
@@ -582,7 +603,7 @@ out:
 	return xfer;
 }
 
-static usbd_status
+static void
 usbd_free_xfer(struct usbd_xfer *xfer)
 {
 	USBHIST_FUNC();
@@ -602,7 +623,6 @@ usbd_free_xfer(struct usbd_xfer *xfer)
 
 	cv_destroy(&xfer->ux_cv);
 	xfer->ux_bus->ub_methods->ubm_freex(xfer->ux_bus, xfer);
-	return USBD_NORMAL_COMPLETION;
 }
 
 int
@@ -761,23 +781,40 @@ usbd_interface2endpoint_descriptor(struct usbd_interface *iface, uint8_t index)
 
 /* Some drivers may wish to abort requests on the default pipe, *
  * but there is no mechanism for getting a handle on it.        */
-usbd_status
+void
 usbd_abort_default_pipe(struct usbd_device *device)
 {
-	return usbd_abort_pipe(device->ud_pipe0);
+	usbd_abort_pipe(device->ud_pipe0);
 }
 
-usbd_status
+void
 usbd_abort_pipe(struct usbd_pipe *pipe)
 {
-	usbd_status err;
+
+	usbd_suspend_pipe(pipe);
+	usbd_resume_pipe(pipe);
+}
+
+void
+usbd_suspend_pipe(struct usbd_pipe *pipe)
+{
 
 	KASSERT(pipe != NULL);
 
 	usbd_lock_pipe(pipe);
-	err = usbd_ar_pipe(pipe);
+	usbd_ar_pipe(pipe);
+	usbd_unlock_pipe(pipe);
+}
+
+void
+usbd_resume_pipe(struct usbd_pipe *pipe)
+{
+
+	usbd_lock_pipe(pipe);
+	KASSERT(pipe->up_aborting);
+	KASSERT(SIMPLEQ_EMPTY(&pipe->up_queue));
+	pipe->up_aborting = 0;
 	usbd_unlock_pipe(pipe);
-	return err;
 }
 
 usbd_status
@@ -958,7 +995,7 @@ usbd_get_interface(struct usbd_interface *iface, uint8_t *aiface)
 /*** Internal routines ***/
 
 /* Dequeue all pipe operations, called with bus lock held. */
-Static usbd_status
+Static void
 usbd_ar_pipe(struct usbd_pipe *pipe)
 {
 	struct usbd_xfer *xfer;
@@ -1000,9 +1037,7 @@ usbd_ar_pipe(struct usbd_pipe *pipe)
 			/* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */
 		}
 	}
-	pipe->up_aborting = 0;
 	SDT_PROBE1(usb, device, pipe, abort__done,  pipe);
-	return USBD_NORMAL_COMPLETION;
 }
 
 /* Called with USB lock held. */
@@ -1135,37 +1170,6 @@ usb_transfer_complete(struct usbd_xfer *xfer)
 		usbd_start_next(pipe);
 }
 
-/* Called with USB lock held. */
-usbd_status
-usb_insert_transfer(struct usbd_xfer *xfer)
-{
-	struct usbd_pipe *pipe = xfer->ux_pipe;
-	usbd_status err;
-
-	USBHIST_FUNC(); USBHIST_CALLARGS(usbdebug,
-	    "xfer = %#jx pipe = %#jx running = %jd timeout = %jd",
-	    (uintptr_t)xfer, (uintptr_t)pipe,
-	    pipe->up_running, xfer->ux_timeout);
-
-	KASSERT(mutex_owned(pipe->up_dev->ud_bus->ub_lock));
-	KASSERTMSG(xfer->ux_state == XFER_BUSY, "xfer %p state is %x", xfer,
-	    xfer->ux_state);
-
-#ifdef DIAGNOSTIC
-	xfer->ux_state = XFER_ONQU;
-#endif
-	SIMPLEQ_INSERT_TAIL(&pipe->up_queue, xfer, ux_next);
-	if (pipe->up_running && pipe->up_serialise)
-		err = USBD_IN_PROGRESS;
-	else {
-		pipe->up_running = 1;
-		err = USBD_NORMAL_COMPLETION;
-	}
-	USBHIST_LOG(usbdebug, "<- done xfer %#jx, err %jd", (uintptr_t)xfer,
-	    err, 0, 0);
-	return err;
-}
-
 /* Called with USB lock held. */
 void
 usbd_start_next(struct usbd_pipe *pipe)
@@ -1190,12 +1194,8 @@ usbd_start_next(struct usbd_pipe *pipe)
 	if (xfer == NULL) {
 		pipe->up_running = 0;
 	} else {
-		if (!polling)
-			mutex_exit(pipe->up_dev->ud_bus->ub_lock);
 		SDT_PROBE2(usb, device, pipe, start,  pipe, xfer);
 		err = pipe->up_methods->upm_start(xfer);
-		if (!polling)
-			mutex_enter(pipe->up_dev->ud_bus->ub_lock);
 
 		if (err != USBD_IN_PROGRESS) {
 			USBHIST_LOG(usbdebug, "error = %jd", err, 0, 0, 0);
@@ -1531,11 +1531,13 @@ usbd_xfer_abort(struct usbd_xfer *xfer)
 	usbd_xfer_cancel_timeout_async(xfer);
 
 	/*
-	 * We beat everyone else.  Claim the status as cancelled and do
-	 * the bus-specific dance to abort the hardware.
+	 * We beat everyone else.  Claim the status as cancelled, do
+	 * the bus-specific dance to abort the hardware, and complete
+	 * the xfer.
 	 */
 	xfer->ux_status = USBD_CANCELLED;
 	bus->ub_methods->ubm_abortx(xfer);
+	usb_transfer_complete(xfer);
 }
 
 /*
@@ -1615,11 +1617,13 @@ usbd_xfer_timeout_task(void *cookie)
 		goto out;
 
 	/*
-	 * We beat everyone else.  Claim the status as timed out and do
-	 * the bus-specific dance to abort the hardware.
+	 * We beat everyone else.  Claim the status as timed out, do
+	 * the bus-specific dance to abort the hardware, and complete
+	 * the xfer.
 	 */
 	xfer->ux_status = USBD_TIMEOUT;
 	bus->ub_methods->ubm_abortx(xfer);
+	usb_transfer_complete(xfer);
 
 out:	/* All done -- release the lock.  */
 	mutex_exit(bus->ub_lock);
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index 71d61eca5394..ef81dc466f9a 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -91,7 +91,7 @@ usbd_status usbd_open_pipe_intr(struct usbd_interface *, uint8_t, uint8_t,
     struct usbd_pipe **, void *, void *, uint32_t, usbd_callback, int);
 usbd_status usbd_open_pipe(struct usbd_interface *, uint8_t, uint8_t,
      struct usbd_pipe **);
-usbd_status usbd_close_pipe(struct usbd_pipe *);
+void usbd_close_pipe(struct usbd_pipe *);
 
 usbd_status usbd_transfer(struct usbd_xfer *);
 
@@ -118,8 +118,11 @@ void usbd_get_xfer_status(struct usbd_xfer *, void **,
 usb_endpoint_descriptor_t *usbd_interface2endpoint_descriptor
     (struct usbd_interface *, uint8_t);
 
-usbd_status usbd_abort_pipe(struct usbd_pipe *);
-usbd_status usbd_abort_default_pipe(struct usbd_device *);
+void usbd_abort_pipe(struct usbd_pipe *);
+void usbd_abort_default_pipe(struct usbd_device *);
+
+void usbd_suspend_pipe(struct usbd_pipe *);
+void usbd_resume_pipe(struct usbd_pipe *);
 
 usbd_status usbd_clear_endpoint_stall(struct usbd_pipe *);
 void usbd_clear_endpoint_stall_async(struct usbd_pipe *);
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index e993fc25b7a1..81e79ee77bbf 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -30,6 +30,9 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifndef	_DEV_USB_USBDIVAR_H_
+#define	_DEV_USB_USBDIVAR_H_
+
 /*
  * Discussion about locking in the USB code:
  *
@@ -41,18 +44,21 @@
  *	BUS METHOD		LOCK	NOTES
  *	----------------------- -------	-------------------------
  *	ubm_open		-	might want to take lock?
- *	ubm_softint		x
+ *	ubm_softint		x	may release/reacquire lock
  *	ubm_dopoll		-	might want to take lock?
  *	ubm_allocx		-
  *	ubm_freex		-
+ *	ubm_abortx		x	must not release/reacquire lock
  *	ubm_getlock 		-	Called at attach time
  *	ubm_newdev		-	Will take lock
-	ubm_rhctrl
+ *	ubm_rhctrl              x
  *
  *	PIPE METHOD		LOCK	NOTES
  *	----------------------- -------	-------------------------
- *	upm_transfer		-
- *	upm_start		-	might want to take lock?
+ *	upm_init		-
+ *	upm_fini		-
+ *	upm_transfer		x
+ *	upm_start		x
  *	upm_abort		x
  *	upm_close		x
  *	upm_cleartoggle		-
@@ -64,7 +70,6 @@
  * USB functions known to expect the lock taken include (this list is
  * probably not exhaustive):
  *    usb_transfer_complete()
- *    usb_insert_transfer()
  *    usb_start_next()
  *
  */
@@ -356,7 +361,6 @@ void		usbd_iface_pipeunref(struct usbd_interface *);
 usbd_status	usbd_fill_iface_data(struct usbd_device *, int, int);
 void		usb_free_device(struct usbd_device *);
 
-usbd_status	usb_insert_transfer(struct usbd_xfer *);
 void		usb_transfer_complete(struct usbd_xfer *);
 int		usb_disconnect_port(struct usbd_port *, device_t, int);
 
@@ -397,3 +401,5 @@ usb_addr2dindex(int addr)
 
 #define usbd_lock_pipe(p)	mutex_enter((p)->up_dev->ud_bus->ub_lock)
 #define usbd_unlock_pipe(p)	mutex_exit((p)->up_dev->ud_bus->ub_lock)
+
+#endif	/* _DEV_USB_USBDIVAR_H_ */
diff --git a/sys/dev/usb/usbnet.c b/sys/dev/usb/usbnet.c
index 1f57e11ea39e..50603bed02d8 100644
--- a/sys/dev/usb/usbnet.c
+++ b/sys/dev/usb/usbnet.c
@@ -779,10 +779,7 @@ usbnet_ep_close_pipes(struct usbnet * const un)
 	for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) {
 		if (unp->unp_ep[i] == NULL)
 			continue;
-		usbd_status err = usbd_close_pipe(unp->unp_ep[i]);
-		if (err)
-			aprint_error_dev(un->un_dev, "close pipe %zu: %s\n", i,
-			    usbd_errstr(err));
+		usbd_close_pipe(unp->unp_ep[i]);
 		unp->unp_ep[i] = NULL;
 	}
 }
@@ -817,21 +814,16 @@ usbnet_ep_open_pipes(struct usbnet * const un)
 	return USBD_NORMAL_COMPLETION;
 }
 
-static usbd_status
+static void
 usbnet_ep_stop_pipes(struct usbnet * const un)
 {
 	struct usbnet_private * const unp = un->un_pri;
-	usbd_status err = USBD_NORMAL_COMPLETION;
 
 	for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) {
 		if (unp->unp_ep[i] == NULL)
 			continue;
-		usbd_status err2 = usbd_abort_pipe(unp->unp_ep[i]);
-		if (err == USBD_NORMAL_COMPLETION && err2)
-			err = err2;
+		usbd_abort_pipe(unp->unp_ep[i]);
 	}
-
-	return err;
 }
 
 static int
@@ -1208,17 +1200,13 @@ usbnet_watchdog(struct ifnet *ifp)
 	struct usbnet * const un = ifp->if_softc;
 	struct usbnet_private * const unp = un->un_pri;
 	struct usbnet_cdata * const cd = un_cdata(un);
-	usbd_status err;
 
 	if_statinc(ifp, if_oerrors);
 	device_printf(un->un_dev, "watchdog timeout\n");
 
 	if (cd->uncd_tx_cnt > 0) {
 		DPRINTF("uncd_tx_cnt=%ju non zero, aborting pipe", 0, 0, 0, 0);
-		err = usbd_abort_pipe(unp->unp_ep[USBNET_ENDPT_TX]);
-		if (err)
-			device_printf(un->un_dev, "pipe abort failed: %s\n",
-			    usbd_errstr(err));
+		usbd_abort_pipe(unp->unp_ep[USBNET_ENDPT_TX]);
 		if (cd->uncd_tx_cnt != 0)
 			DPRINTF("uncd_tx_cnt now %ju", cd->uncd_tx_cnt, 0, 0, 0);
 	}
diff --git a/sys/dev/usb/usbroothub.c b/sys/dev/usb/usbroothub.c
index c455f89abee4..8e2ceacdac5a 100644
--- a/sys/dev/usb/usbroothub.c
+++ b/sys/dev/usb/usbroothub.c
@@ -343,16 +343,6 @@ static const usb_hub_descriptor_t usbroothub_hubd = {
 usbd_status
 roothub_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	struct usbd_pipe *pipe = xfer->ux_pipe;
-	struct usbd_bus *bus = pipe->up_dev->ud_bus;
-	usbd_status err;
-
-	/* Insert last in queue. */
-	mutex_enter(bus->ub_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(bus->ub_lock);
-	if (err)
-		return err;
 
 	/* Pipe isn't running, start first */
 	return roothub_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
@@ -371,6 +361,13 @@ roothub_ctrl_start(struct usbd_xfer *xfer)
 
 	USBHIST_FUNC();
 
+	/*
+	 * XXX Should really assert pipe lock, in case ever have
+	 * per-pipe locking instead of using the bus lock for all
+	 * pipes.
+	 */
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	KASSERT(xfer->ux_rqflags & URQ_REQUEST);
 	req = &xfer->ux_request;
 
@@ -564,9 +561,7 @@ roothub_ctrl_start(struct usbd_xfer *xfer)
 	    (uintptr_t)xfer, buflen, actlen, err);
 
 	xfer->ux_status = err;
-	mutex_enter(bus->ub_lock);
 	usb_transfer_complete(xfer);
-	mutex_exit(bus->ub_lock);
 
 	return USBD_NORMAL_COMPLETION;
 }
diff --git a/sys/dev/usb/utoppy.c b/sys/dev/usb/utoppy.c
index a40352fedf90..b412542d5c3d 100644
--- a/sys/dev/usb/utoppy.c
+++ b/sys/dev/usb/utoppy.c
@@ -1365,7 +1365,6 @@ static int
 utoppyclose(dev_t dev, int flag, int mode, struct lwp *l)
 {
 	struct utoppy_softc *sc;
-	usbd_status err;
 
 	sc = device_lookup_private(&utoppy_cd, UTOPPYUNIT(dev));
 
@@ -1384,14 +1383,12 @@ utoppyclose(dev_t dev, int flag, int mode, struct lwp *l)
 		(void) utoppy_cancel(sc);
 
 	if (sc->sc_out_pipe != NULL) {
-		if ((err = usbd_abort_pipe(sc->sc_out_pipe)) != 0)
-			printf("usbd_abort_pipe(OUT) returned %d\n", err);
+		usbd_abort_pipe(sc->sc_out_pipe);
 		sc->sc_out_pipe = NULL;
 	}
 
 	if (sc->sc_in_pipe != NULL) {
-		if ((err = usbd_abort_pipe(sc->sc_in_pipe)) != 0)
-			printf("usbd_abort_pipe(IN) returned %d\n", err);
+		usbd_abort_pipe(sc->sc_in_pipe);
 		sc->sc_in_pipe = NULL;
 	}
 
diff --git a/sys/dev/usb/vhci.c b/sys/dev/usb/vhci.c
index f5c46b9a774e..7d4254cc70b5 100644
--- a/sys/dev/usb/vhci.c
+++ b/sys/dev/usb/vhci.c
@@ -590,18 +590,9 @@ vhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 static usbd_status
 vhci_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
-	usbd_status err;
 
 	DPRINTF("%s: called\n", __func__);
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return vhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -614,7 +605,6 @@ vhci_device_ctrl_start(struct usbd_xfer *xfer)
 	struct usbd_device *dev = xfer->ux_pipe->up_dev;
 	vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
 	vhci_port_t *port;
-	bool polling = sc->sc_bus.ub_usepolling;
 	bool isread = (req->bmRequestType & UT_READ) != 0;
 	uint8_t addr = UE_GET_ADDR(ed->bEndpointAddress);
 	int portno, ret;
@@ -627,14 +617,13 @@ vhci_device_ctrl_start(struct usbd_xfer *xfer)
 	DPRINTF("%s: type=0x%02x, len=%d, isread=%d, portno=%d\n",
 	    __func__, req->bmRequestType, UGETW(req->wLength), isread, portno);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
 	port = &sc->sc_port[portno];
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
-
 	mutex_enter(&port->lock);
 	if (port->status & UPS_PORT_ENABLED) {
 		xfer->ux_status = USBD_IN_PROGRESS;
@@ -645,9 +634,6 @@ vhci_device_ctrl_start(struct usbd_xfer *xfer)
 	}
 	mutex_exit(&port->lock);
 
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
-
 	return ret;
 }
 
@@ -707,18 +693,9 @@ vhci_device_ctrl_done(struct usbd_xfer *xfer)
 static usbd_status
 vhci_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
-	usbd_status err;
 
 	DPRINTF("%s: called\n", __func__);
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return vhci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -727,20 +704,17 @@ static usbd_status
 vhci_root_intr_start(struct usbd_xfer *xfer)
 {
 	vhci_softc_t *sc = xfer->ux_bus->ub_hcpriv;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	DPRINTF("%s: called, len=%zu\n", __func__, (size_t)xfer->ux_length);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	KASSERT(sc->sc_intrxfer == NULL);
 	sc->sc_intrxfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c
index 6c79c07ac6ec..efc6f7459eb2 100644
--- a/sys/dev/usb/xhci.c
+++ b/sys/dev/usb/xhci.c
@@ -2154,8 +2154,6 @@ xhci_abortx(struct usbd_xfer *xfer)
 
 	xhci_pipe_restart(xfer->ux_pipe);
 
-	usb_transfer_complete(xfer);
-
 	DPRINTFN(14, "end", 0, 0, 0, 0);
 }
 
@@ -2188,7 +2186,6 @@ xhci_pipe_async_task(void *cookie)
 	struct xhci_slot * const xs = pipe->up_dev->ud_hcpriv;
 	const u_int dci = xhci_ep_get_dci(pipe->up_endpoint->ue_edesc);
 	struct xhci_ring * const tr = xs->xs_xr[dci];
-	bool restart = false;
 
 	XHCIHIST_FUNC();
 	XHCIHIST_CALLARGS("pipe %#jx slot %ju dci %ju",
@@ -2229,31 +2226,18 @@ xhci_pipe_async_task(void *cookie)
 
 	/*
 	 * If we halted our own queue because it stalled, mark it no
-	 * longer halted and arrange to start it up again.
+	 * longer halted and start issuing queued transfers again.
 	 */
 	if (tr->is_halted) {
+		struct usbd_xfer *xfer = SIMPLEQ_FIRST(&pipe->up_queue);
+
 		tr->is_halted = false;
-		if (!SIMPLEQ_EMPTY(&pipe->up_queue))
-			restart = true;
+		if (xfer)
+			(*pipe->up_methods->upm_start)(xfer);
 	}
 
 	mutex_exit(&sc->sc_lock);
 
-	/*
-	 * If the endpoint was stalled, start issuing queued transfers
-	 * again.
-	 */
-	if (restart) {
-		/*
-		 * XXX Shouldn't touch the queue unlocked -- upm_start
-		 * should be called with the lock held instead.  The
-		 * pipe could be aborted at this point, and the xfer
-		 * freed.
-		 */
-		struct usbd_xfer *xfer = SIMPLEQ_FIRST(&pipe->up_queue);
-		(*pipe->up_methods->upm_start)(xfer);
-	}
-
 	DPRINTFN(4, "ends", 0, 0, 0, 0);
 }
 
@@ -3872,6 +3856,8 @@ xhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 
 	XHCIHIST_FUNC();
 
+	KASSERT(bus->ub_usepolling || mutex_owned(bus->ub_lock));
+
 	if (sc->sc_dying)
 		return -1;
 
@@ -4129,18 +4115,8 @@ xhci_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 static usbd_status
 xhci_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
-	usbd_status err;
-
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return xhci_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -4151,20 +4127,17 @@ xhci_root_intr_start(struct usbd_xfer *xfer)
 {
 	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
 	const size_t bn = XHCI_XFER2BUS(xfer) == &sc->sc_bus ? 0 : 1;
-	const bool polling = xhci_polling_p(sc);
 
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
+	KASSERT(xhci_polling_p(sc) || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	KASSERT(sc->sc_intrxfer[bn] == NULL);
 	sc->sc_intrxfer[bn] = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -4233,18 +4206,8 @@ xhci_root_intr_done(struct usbd_xfer *xfer)
 static usbd_status
 xhci_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
-	usbd_status err;
-
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return xhci_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -4272,14 +4235,14 @@ xhci_device_ctrl_start(struct usbd_xfer *xfer)
 	    req->bmRequestType | (req->bRequest << 8), UGETW(req->wValue),
 	    UGETW(req->wIndex), UGETW(req->wLength));
 
+	KASSERT(polling || mutex_owned(&sc->sc_lock));
+
 	/* we rely on the bottom bits for extra info */
 	KASSERTMSG(((uintptr_t)xfer & 0x3) == 0x0, "xfer %zx",
 	    (uintptr_t) xfer);
 
 	KASSERT((xfer->ux_rqflags & URQ_REQUEST) != 0);
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	if (tr->is_halted)
 		goto out;
 
@@ -4337,8 +4300,6 @@ out:	if (xfer->ux_status == USBD_NOT_STARTED) {
 		 */
 	}
 	KASSERT(xfer->ux_status == USBD_IN_PROGRESS);
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -4378,18 +4339,8 @@ xhci_device_ctrl_close(struct usbd_pipe *pipe)
 static usbd_status
 xhci_device_isoc_transfer(struct usbd_xfer *xfer)
 {
-	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
-	usbd_status err;
-
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	return xhci_device_isoc_enter(xfer);
 }
 
@@ -4420,6 +4371,8 @@ xhci_device_isoc_enter(struct usbd_xfer *xfer)
 	XHCIHIST_CALLARGS("%#jx slot %ju dci %ju",
 	    (uintptr_t)xfer, xs->xs_idx, dci, 0);
 
+	KASSERT(polling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
@@ -4492,13 +4445,9 @@ xhci_device_isoc_enter(struct usbd_xfer *xfer)
 	if (!polling)
 		mutex_exit(&tr->xr_lock);
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	xfer->ux_status = USBD_IN_PROGRESS;
 	xhci_db_write_4(sc, XHCI_DOORBELL(xs->xs_idx), dci);
 	usbd_xfer_schedule_timeout(xfer);
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -4542,22 +4491,9 @@ xhci_device_isoc_done(struct usbd_xfer *xfer)
 static usbd_status
 xhci_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
-	usbd_status err;
-
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return xhci_device_bulk_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -4581,13 +4517,13 @@ xhci_device_bulk_start(struct usbd_xfer *xfer)
 	XHCIHIST_CALLARGS("%#jx slot %ju dci %ju",
 	    (uintptr_t)xfer, xs->xs_idx, dci, 0);
 
+	KASSERT(polling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
 	KASSERT((xfer->ux_rqflags & URQ_REQUEST) == 0);
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	if (tr->is_halted)
 		goto out;
 
@@ -4635,8 +4571,6 @@ out:	if (xfer->ux_status == USBD_NOT_STARTED) {
 		 */
 	}
 	KASSERT(xfer->ux_status == USBD_IN_PROGRESS);
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -4680,22 +4614,9 @@ xhci_device_bulk_close(struct usbd_pipe *pipe)
 static usbd_status
 xhci_device_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct xhci_softc * const sc = XHCI_XFER2SC(xfer);
-	usbd_status err;
-
 	XHCIHIST_FUNC(); XHCIHIST_CALLED();
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
-	/*
-	 * Pipe isn't running (otherwise err would be USBD_INPROG),
-	 * so start it first.
-	 */
+	/* Pipe isn't running, so start it first.  */
 	return xhci_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
 
@@ -4719,11 +4640,11 @@ xhci_device_intr_start(struct usbd_xfer *xfer)
 	XHCIHIST_CALLARGS("%#jx slot %ju dci %ju",
 	    (uintptr_t)xfer, xs->xs_idx, dci, 0);
 
+	KASSERT(polling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	if (tr->is_halted)
 		goto out;
 
@@ -4761,8 +4682,6 @@ out:	if (xfer->ux_status == USBD_NOT_STARTED) {
 		 */
 	}
 	KASSERT(xfer->ux_status == USBD_IN_PROGRESS);
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
diff --git a/sys/dev/usb/xhcivar.h b/sys/dev/usb/xhcivar.h
index 9893037be2e1..b253da58557f 100644
--- a/sys/dev/usb/xhcivar.h
+++ b/sys/dev/usb/xhcivar.h
@@ -29,8 +29,17 @@
 #ifndef _DEV_USB_XHCIVAR_H_
 #define _DEV_USB_XHCIVAR_H_
 
+#include <sys/types.h>
+
+#include <sys/condvar.h>
+#include <sys/device.h>
+#include <sys/mutex.h>
+#include <sys/pmf.h>
 #include <sys/pool.h>
 
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+
 #define XHCI_MAX_DCI	31
 
 struct xhci_soft_trb {
diff --git a/sys/external/bsd/dwc2/dwc2.c b/sys/external/bsd/dwc2/dwc2.c
index e3e61a072b23..7bc817f0448e 100644
--- a/sys/external/bsd/dwc2/dwc2.c
+++ b/sys/external/bsd/dwc2/dwc2.c
@@ -515,7 +515,7 @@ dwc2_abortx(struct usbd_xfer *xfer)
 	}
 
 	/*
-	 * HC Step 1: Handle the hardware.
+	 * Handle the hardware.
 	 */
 	err = dwc2_hcd_urb_dequeue(hsotg, dxfer->urb);
 	if (err) {
@@ -524,11 +524,6 @@ dwc2_abortx(struct usbd_xfer *xfer)
 
 dying:
 	mutex_spin_exit(&hsotg->lock);
-
-	/*
-	 * Final Step: Notify completion to waiting xfers.
-	 */
-	usb_transfer_complete(xfer);
 	KASSERT(mutex_owned(&sc->sc_lock));
 }
 
@@ -614,18 +609,9 @@ dwc2_roothub_ctrl(struct usbd_bus *bus, usb_device_request_t *req,
 Static usbd_status
 dwc2_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	usbd_status err;
 
 	DPRINTF("\n");
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return dwc2_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -634,20 +620,17 @@ Static usbd_status
 dwc2_root_intr_start(struct usbd_xfer *xfer)
 {
 	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	DPRINTF("\n");
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (sc->sc_dying)
 		return USBD_IOERROR;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
 	KASSERT(sc->sc_intrxfer == NULL);
 	sc->sc_intrxfer = xfer;
 	xfer->ux_status = USBD_IN_PROGRESS;
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -711,18 +694,9 @@ dwc2_root_intr_done(struct usbd_xfer *xfer)
 Static usbd_status
 dwc2_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	usbd_status err;
 
 	DPRINTF("\n");
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return dwc2_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -732,17 +706,13 @@ dwc2_device_ctrl_start(struct usbd_xfer *xfer)
 {
 	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
 	usbd_status err;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
 	DPRINTF("\n");
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	xfer->ux_status = USBD_IN_PROGRESS;
 	err = dwc2_device_start(xfer);
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
-
 	if (err)
 		return err;
 
@@ -783,22 +753,12 @@ dwc2_device_ctrl_done(struct usbd_xfer *xfer)
 Static usbd_status
 dwc2_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	usbd_status err;
 
 	DPRINTF("xfer=%p\n", xfer);
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-
-	KASSERT(err == USBD_NORMAL_COMPLETION);
-
+	KASSERT(xfer->ux_status == USBD_NOT_STARTED);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	err = dwc2_device_start(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	return err;
+	return dwc2_device_start(xfer);
 }
 
 Static void
@@ -833,18 +793,9 @@ dwc2_device_bulk_done(struct usbd_xfer *xfer)
 Static usbd_status
 dwc2_device_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	usbd_status err;
 
 	DPRINTF("xfer=%p\n", xfer);
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
-
 	/* Pipe isn't running, start first */
 	return dwc2_device_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -856,15 +807,11 @@ dwc2_device_intr_start(struct usbd_xfer *xfer)
 	struct usbd_device *dev = dpipe->pipe.up_dev;
 	struct dwc2_softc *sc = dev->ud_bus->ub_hcpriv;
 	usbd_status err;
-	const bool polling = sc->sc_bus.ub_usepolling;
 
-	if (!polling)
-		mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	xfer->ux_status = USBD_IN_PROGRESS;
 	err = dwc2_device_start(xfer);
-	if (!polling)
-		mutex_exit(&sc->sc_lock);
-
 	if (err)
 		return err;
 
@@ -904,22 +851,12 @@ dwc2_device_intr_done(struct usbd_xfer *xfer)
 usbd_status
 dwc2_device_isoc_transfer(struct usbd_xfer *xfer)
 {
-	struct dwc2_softc *sc = DWC2_XFER2SC(xfer);
-	usbd_status err;
 
 	DPRINTF("xfer=%p\n", xfer);
 
-	/* Insert last in queue. */
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-
-	KASSERT(err == USBD_NORMAL_COMPLETION);
-
+	KASSERT(xfer->ux_status == USBD_NOT_STARTED);
 	xfer->ux_status = USBD_IN_PROGRESS;
-	err = dwc2_device_start(xfer);
-	mutex_exit(&sc->sc_lock);
-
-	return err;
+	return dwc2_device_start(xfer);
 }
 
 void
@@ -973,6 +910,8 @@ dwc2_device_start(struct usbd_xfer *xfer)
 
 	DPRINTFN(1, "xfer=%p pipe=%p\n", xfer, xfer->ux_pipe);
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	if (xfertype == UE_ISOCHRONOUS ||
 	    xfertype == UE_INTERRUPT) {
 		mutex_spin_enter(&hsotg->lock);
@@ -1161,9 +1100,7 @@ dwc2_device_start(struct usbd_xfer *xfer)
 				dwc2_hcd_get_ep_bandwidth(hsotg, dpipe),
 				xfer);
 	}
-
 	mutex_spin_exit(&hsotg->lock);
-// 	mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 
diff --git a/sys/rump/dev/lib/libugenhc/ugenhc.c b/sys/rump/dev/lib/libugenhc/ugenhc.c
index 003f1cc54453..a1fb16f3e02c 100644
--- a/sys/rump/dev/lib/libugenhc/ugenhc.c
+++ b/sys/rump/dev/lib/libugenhc/ugenhc.c
@@ -227,6 +227,8 @@ rumpusb_device_ctrl_start(struct usbd_xfer *xfer)
 	int err = 0;
 	int ru_error, mightfail = 0;
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	len = totlen = UGETW(req->wLength);
 	if (len)
 		buf = xfer->ux_buf;
@@ -391,9 +393,7 @@ rumpusb_device_ctrl_start(struct usbd_xfer *xfer)
 
  ret:
 	xfer->ux_status = err;
-	mutex_enter(&sc->sc_lock);
 	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -401,14 +401,6 @@ rumpusb_device_ctrl_start(struct usbd_xfer *xfer)
 static usbd_status
 rumpusb_device_ctrl_transfer(struct usbd_xfer *xfer)
 {
-	struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer);
-	usbd_status err;
-
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	return rumpusb_device_ctrl_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -524,7 +516,8 @@ rumpusb_root_intr_start(struct usbd_xfer *xfer)
 	struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer);
 	int error;
 
-	mutex_enter(&sc->sc_lock);
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	sc->sc_intrxfer = xfer;
 	if (!sc->sc_rhintr) {
 		error = kthread_create(PRI_NONE, 0, NULL,
@@ -532,7 +525,6 @@ rumpusb_root_intr_start(struct usbd_xfer *xfer)
 		if (error)
 			xfer->ux_status = USBD_IOERROR;
 	}
-	mutex_exit(&sc->sc_lock);
 
 	return USBD_IN_PROGRESS;
 }
@@ -540,14 +532,6 @@ rumpusb_root_intr_start(struct usbd_xfer *xfer)
 static usbd_status
 rumpusb_root_intr_transfer(struct usbd_xfer *xfer)
 {
-	struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer);
-	usbd_status err;
-
-	mutex_enter(&sc->sc_lock);
-	err = usb_insert_transfer(xfer);
-	mutex_exit(&sc->sc_lock);
-	if (err)
-		return err;
 
 	return rumpusb_root_intr_start(SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 }
@@ -597,6 +581,8 @@ rumpusb_device_bulk_start(struct usbd_xfer *xfer)
 	int xfererr = USBD_NORMAL_COMPLETION;
 	int shortval, i;
 
+	KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
 	ed = xfer->ux_pipe->up_endpoint->ue_edesc;
 	endpt = ed->bEndpointAddress;
 	isread = UE_GET_DIR(endpt) == UE_DIR_IN;
@@ -683,9 +669,7 @@ rumpusb_device_bulk_start(struct usbd_xfer *xfer)
 		if (done != len)
 			panic("lazy bum");
 	xfer->ux_status = xfererr;
-	mutex_enter(&sc->sc_lock);
 	usb_transfer_complete(xfer);
-	mutex_exit(&sc->sc_lock);
 	return USBD_IN_PROGRESS;
 }
 
@@ -698,9 +682,7 @@ doxfer_kth(void *arg)
 	mutex_enter(&sc->sc_lock);
 	do {
 		struct usbd_xfer *xfer = SIMPLEQ_FIRST(&pipe->up_queue);
-		mutex_exit(&sc->sc_lock);
 		rumpusb_device_bulk_start(xfer);
-		mutex_enter(&sc->sc_lock);
 	} while (!SIMPLEQ_EMPTY(&pipe->up_queue));
 	mutex_exit(&sc->sc_lock);
 	kthread_exit(0);
@@ -709,8 +691,6 @@ doxfer_kth(void *arg)
 static usbd_status
 rumpusb_device_bulk_transfer(struct usbd_xfer *xfer)
 {
-	struct ugenhc_softc *sc = UGENHC_XFER2SC(xfer);
-	usbd_status err;
 
 	if (!rump_threads) {
 		/* XXX: lie about supporting async transfers */
@@ -720,20 +700,9 @@ rumpusb_device_bulk_transfer(struct usbd_xfer *xfer)
 			return USBD_IN_PROGRESS;
 		}
 
-		mutex_enter(&sc->sc_lock);
-		err = usb_insert_transfer(xfer);
-		mutex_exit(&sc->sc_lock);
-		if (err)
-			return err;
-
 		return rumpusb_device_bulk_start(
 		    SIMPLEQ_FIRST(&xfer->ux_pipe->up_queue));
 	} else {
-		mutex_enter(&sc->sc_lock);
-		err = usb_insert_transfer(xfer);
-		mutex_exit(&sc->sc_lock);
-		if (err)
-			return err;
 		kthread_create(PRI_NONE, 0, NULL, doxfer_kth, xfer->ux_pipe, NULL,
 		    "rusbhcxf");
 


Home | Main Index | Thread Index | Old Index