Module Name:    src
Committed By:   jmcneill
Date:           Sun Dec  4 13:23:17 UTC 2011

Modified Files:
        src/sys/dev/ic [jmcneill-usbmp]: sl811hs.c
        src/sys/dev/pci [jmcneill-usbmp]: ehci_pci.c
        src/sys/dev/usb [jmcneill-usbmp]: ehci.c ehcivar.h ohci.c uhci.c usb.c
            usb_subr.c usbdi.c usbdivar.h

Log Message:
Make ehci mpsafe.


To generate a diff of this commit:
cvs rdiff -u -r1.31 -r1.31.2.1 src/sys/dev/ic/sl811hs.c
cvs rdiff -u -r1.53 -r1.53.6.1 src/sys/dev/pci/ehci_pci.c
cvs rdiff -u -r1.181 -r1.181.6.1 src/sys/dev/usb/ehci.c
cvs rdiff -u -r1.38 -r1.38.10.1 src/sys/dev/usb/ehcivar.h
cvs rdiff -u -r1.218 -r1.218.6.1 src/sys/dev/usb/ohci.c
cvs rdiff -u -r1.240 -r1.240.6.1 src/sys/dev/usb/uhci.c
cvs rdiff -u -r1.125 -r1.125.6.1 src/sys/dev/usb/usb.c
cvs rdiff -u -r1.180 -r1.180.6.1 src/sys/dev/usb/usb_subr.c
cvs rdiff -u -r1.134 -r1.134.2.1 src/sys/dev/usb/usbdi.c
cvs rdiff -u -r1.93 -r1.93.8.1 src/sys/dev/usb/usbdivar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ic/sl811hs.c
diff -u src/sys/dev/ic/sl811hs.c:1.31 src/sys/dev/ic/sl811hs.c:1.31.2.1
--- src/sys/dev/ic/sl811hs.c:1.31	Sun Nov 27 14:36:20 2011
+++ src/sys/dev/ic/sl811hs.c	Sun Dec  4 13:23:16 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: sl811hs.c,v 1.31 2011/11/27 14:36:20 rmind Exp $	*/
+/*	$NetBSD: sl811hs.c,v 1.31.2.1 2011/12/04 13:23:16 jmcneill Exp $	*/
 
 /*
  * Not (c) 2007 Matthew Orgass
@@ -84,7 +84,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sl811hs.c,v 1.31 2011/11/27 14:36:20 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sl811hs.c,v 1.31.2.1 2011/12/04 13:23:16 jmcneill Exp $");
 
 #include "opt_slhci.h"
 
@@ -694,6 +694,7 @@ const struct usbd_bus_methods slhci_bus_
 	slhci_freem,
 	slhci_allocx,
 	slhci_freex,
+	NULL, /* slhci_get_locks */
 };
 
 const struct usbd_pipe_methods slhci_pipe_methods = {

Index: src/sys/dev/pci/ehci_pci.c
diff -u src/sys/dev/pci/ehci_pci.c:1.53 src/sys/dev/pci/ehci_pci.c:1.53.6.1
--- src/sys/dev/pci/ehci_pci.c:1.53	Sat Jul 30 13:19:21 2011
+++ src/sys/dev/pci/ehci_pci.c	Sun Dec  4 13:23:16 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: ehci_pci.c,v 1.53 2011/07/30 13:19:21 jmcneill Exp $	*/
+/*	$NetBSD: ehci_pci.c,v 1.53.6.1 2011/12/04 13:23:16 jmcneill Exp $	*/
 
 /*
  * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.53 2011/07/30 13:19:21 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.53.6.1 2011/12/04 13:23:16 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -304,6 +304,9 @@ ehci_pci_detach(device_t self, int flags
 		sc->sc.sc_size = 0;
 	}
 
+	mutex_destroy(&sc->sc.sc_lock);
+	mutex_destroy(&sc->sc.sc_intr_lock);
+
 	return 0;
 }
 

Index: src/sys/dev/usb/ehci.c
diff -u src/sys/dev/usb/ehci.c:1.181 src/sys/dev/usb/ehci.c:1.181.6.1
--- src/sys/dev/usb/ehci.c:1.181	Fri Jul  1 23:48:20 2011
+++ src/sys/dev/usb/ehci.c	Sun Dec  4 13:23:16 2011
@@ -1,12 +1,13 @@
-/*	$NetBSD: ehci.c,v 1.181 2011/07/01 23:48:20 mrg Exp $ */
+/*	$NetBSD: ehci.c,v 1.181.6.1 2011/12/04 13:23:16 jmcneill Exp $ */
 
 /*
- * Copyright (c) 2004-2008 The NetBSD Foundation, Inc.
+ * Copyright (c) 2004-2011 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
- * by Lennart Augustsson ([email protected]), Charles M. Hannum and
- * Jeremy Morse ([email protected]).
+ * by Lennart Augustsson ([email protected]), Charles M. Hannum,
+ * Jeremy Morse ([email protected]), and Jared D. McNeill
+ * ([email protected]).
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -52,7 +53,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.181 2011/07/01 23:48:20 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.181.6.1 2011/12/04 13:23:16 jmcneill Exp $");
 
 #include "ohci.h"
 #include "uhci.h"
@@ -61,7 +62,7 @@ __KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.1
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
 #include <sys/device.h>
 #include <sys/select.h>
 #include <sys/proc.h>
@@ -82,8 +83,19 @@ __KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.1
 #include <dev/usb/usbroothub_subr.h>
 
 #ifdef EHCI_DEBUG
-#define DPRINTF(x)	do { if (ehcidebug) printf x; } while(0)
-#define DPRINTFN(n,x)	do { if (ehcidebug>(n)) printf x; } while (0)
+#include <sys/kprintf.h>
+static void
+ehciprintf(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	kprintf(fmt, TOLOG|TOCONS, NULL, NULL, ap);
+	va_end(ap);
+}
+
+#define DPRINTF(x)	do { if (ehcidebug) ehciprintf x; } while(0)
+#define DPRINTFN(n,x)	do { if (ehcidebug>(n)) ehciprintf x; } while (0)
 int ehcidebug = 0;
 #else
 #define DPRINTF(x)
@@ -133,12 +145,16 @@ Static void		ehci_idone(struct ehci_xfer
 Static void		ehci_timeout(void *);
 Static void		ehci_timeout_task(void *);
 Static void		ehci_intrlist_timeout(void *);
+Static void		ehci_doorbell(void *);
+Static void		ehci_pcd(void *);
 
 Static usbd_status	ehci_allocm(struct usbd_bus *, usb_dma_t *, u_int32_t);
 Static void		ehci_freem(struct usbd_bus *, usb_dma_t *);
 
 Static usbd_xfer_handle	ehci_allocx(struct usbd_bus *);
 Static void		ehci_freex(struct usbd_bus *, usbd_xfer_handle);
+Static void		ehci_get_locks(struct usbd_bus *, kmutex_t **,
+				       kmutex_t **);
 
 Static usbd_status	ehci_root_ctrl_transfer(usbd_xfer_handle);
 Static usbd_status	ehci_root_ctrl_start(usbd_xfer_handle);
@@ -179,7 +195,6 @@ Static void		ehci_device_isoc_done(usbd_
 Static void		ehci_device_clear_toggle(usbd_pipe_handle pipe);
 Static void		ehci_noop(usbd_pipe_handle pipe);
 
-Static void		ehci_pcd(ehci_softc_t *, usbd_xfer_handle);
 Static void		ehci_disown(ehci_softc_t *, int, int);
 
 Static ehci_soft_qh_t  *ehci_alloc_sqh(ehci_softc_t *);
@@ -253,6 +268,7 @@ Static const struct usbd_bus_methods ehc
 	ehci_freem,
 	ehci_allocx,
 	ehci_freex,
+	ehci_get_locks,
 };
 
 Static const struct usbd_pipe_methods ehci_root_ctrl_methods = {
@@ -334,6 +350,16 @@ ehci_init(ehci_softc_t *sc)
 	theehci = sc;
 #endif
 
+	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB);
+	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_USB);
+	cv_init(&sc->sc_softwake_cv, "ehciab");
+	cv_init(&sc->sc_doorbell, "ehcidi");
+
+	sc->sc_doorbell_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE,
+	    ehci_doorbell, sc);
+	sc->sc_pcd_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE,
+	    ehci_pcd, sc);
+
 	sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH);
 
 	vers = EREAD2(sc, EHCI_HCIVERSION);
@@ -431,13 +457,12 @@ ehci_init(ehci_softc_t *sc)
 
 	EOWRITE4(sc, EHCI_PERIODICLISTBASE, DMAADDR(&sc->sc_fldma, 0));
 
-	sc->sc_softitds = malloc(sc->sc_flsize * sizeof(ehci_soft_itd_t *),
-					M_USB, M_NOWAIT | M_ZERO);
+	sc->sc_softitds = kmem_zalloc(sc->sc_flsize * sizeof(ehci_soft_itd_t *),
+				     KM_SLEEP);
 	if (sc->sc_softitds == NULL)
 		return ENOMEM;
 	LIST_INIT(&sc->sc_freeitds);
 	TAILQ_INIT(&sc->sc_intrhead);
-	mutex_init(&sc->sc_intrhead_lock, MUTEX_DEFAULT, IPL_USB);
 
 	/* Set up the bus struct. */
 	sc->sc_bus.methods = &ehci_bus_methods;
@@ -522,9 +547,7 @@ ehci_init(ehci_softc_t *sc)
 	sc->sc_async_head = sqh;
 	EOWRITE4(sc, EHCI_ASYNCLISTADDR, sqh->physaddr | EHCI_LINK_QH);
 
-	callout_init(&(sc->sc_tmo_intrlist), 0);
-
-	mutex_init(&sc->sc_doorbell_lock, MUTEX_DEFAULT, IPL_NONE);
+	callout_init(&(sc->sc_tmo_intrlist), CALLOUT_MPSAFE);
 
 	/* Turn on controller */
 	EOWRITE4(sc, EHCI_USBCMD,
@@ -567,9 +590,15 @@ int
 ehci_intr(void *v)
 {
 	ehci_softc_t *sc = v;
+	int ret = 0;
 
-	if (sc == NULL || sc->sc_dying || !device_has_power(sc->sc_dev))
-		return (0);
+	if (sc == NULL)
+		return 0;
+
+	mutex_spin_enter(&sc->sc_intr_lock);
+
+	if (sc->sc_dying || !device_has_power(sc->sc_dev))
+		goto done;
 
 	/* If we get an interrupt while polling, then just ignore it. */
 	if (sc->sc_bus.use_polling) {
@@ -580,10 +609,14 @@ ehci_intr(void *v)
 #ifdef DIAGNOSTIC
 		DPRINTFN(16, ("ehci_intr: ignored interrupt while polling\n"));
 #endif
-		return (0);
+		goto done;
 	}
 
-	return (ehci_intr1(sc));
+	ret = ehci_intr1(sc);
+
+done:
+	mutex_spin_exit(&sc->sc_intr_lock);
+	return ret;
 }
 
 Static int
@@ -601,6 +634,8 @@ ehci_intr1(ehci_softc_t *sc)
 		return (0);
 	}
 
+	KASSERT(mutex_owned(&sc->sc_intr_lock));
+
 	intrs = EHCI_STS_INTRS(EOREAD4(sc, EHCI_USBSTS));
 	if (!intrs)
 		return (0);
@@ -617,7 +652,7 @@ ehci_intr1(ehci_softc_t *sc)
 	sc->sc_bus.no_intrs++;
 	if (eintrs & EHCI_STS_IAA) {
 		DPRINTF(("ehci_intr1: door bell\n"));
-		wakeup(&sc->sc_async_head);
+		softint_schedule(sc->sc_doorbell_si);
 		eintrs &= ~EHCI_STS_IAA;
 	}
 	if (eintrs & (EHCI_STS_INT | EHCI_STS_ERRINT)) {
@@ -633,7 +668,7 @@ ehci_intr1(ehci_softc_t *sc)
 		/* XXX what else */
 	}
 	if (eintrs & EHCI_STS_PCD) {
-		ehci_pcd(sc, sc->sc_intrxfer);
+		softint_schedule(sc->sc_pcd_si);
 		eintrs &= ~EHCI_STS_PCD;
 	}
 
@@ -650,17 +685,31 @@ ehci_intr1(ehci_softc_t *sc)
 	return (1);
 }
 
+Static void
+ehci_doorbell(void *addr)
+{
+	ehci_softc_t *sc = addr;
+
+	mutex_enter(&sc->sc_lock);
+	cv_broadcast(&sc->sc_doorbell);
+	mutex_exit(&sc->sc_lock);
+}
 
 Static void
-ehci_pcd(ehci_softc_t *sc, usbd_xfer_handle xfer)
+ehci_pcd(void *addr)
 {
+	ehci_softc_t *sc = addr;
+	usbd_xfer_handle xfer;
 	usbd_pipe_handle pipe;
 	u_char *p;
 	int i, m;
 
+	mutex_enter(&sc->sc_lock);
+	xfer = sc->sc_intrxfer;
+
 	if (xfer == NULL) {
 		/* Just ignore the change. */
-		return;
+		goto done;
 	}
 
 	pipe = xfer->pipe;
@@ -678,6 +727,9 @@ ehci_pcd(ehci_softc_t *sc, usbd_xfer_han
 	xfer->status = USBD_NORMAL_COMPLETION;
 
 	usb_transfer_complete(xfer);
+
+done:
+	mutex_exit(&sc->sc_lock);
 }
 
 Static void
@@ -690,6 +742,8 @@ ehci_softintr(void *v)
 	DPRINTFN(10,("%s: ehci_softintr (%d)\n", device_xname(sc->sc_dev),
 		     sc->sc_bus.intr_context));
 
+	mutex_enter(&sc->sc_lock);
+
 	sc->sc_bus.intr_context++;
 
 	/*
@@ -709,14 +763,14 @@ ehci_softintr(void *v)
 		callout_reset(&(sc->sc_tmo_intrlist),
 		    (hz), (ehci_intrlist_timeout), (sc));
 
-#ifdef USB_USE_SOFTINTR
 	if (sc->sc_softwake) {
 		sc->sc_softwake = 0;
-		wakeup(&sc->sc_softwake);
+		cv_broadcast(&sc->sc_softwake_cv);
 	}
-#endif /* USB_USE_SOFTINTR */
 
 	sc->sc_bus.intr_context--;
+
+	mutex_exit(&sc->sc_lock);
 }
 
 /* Check for an interrupt. */
@@ -727,6 +781,8 @@ ehci_check_intr(ehci_softc_t *sc, struct
 
 	DPRINTFN(/*15*/2, ("ehci_check_intr: ex=%p\n", ex));
 
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	attr = ex->xfer.pipe->endpoint->edesc->bmAttributes;
 	if (UE_GET_XFERTYPE(attr) == UE_ISOCHRONOUS)
 		ehci_check_itd_intr(sc, ex);
@@ -742,6 +798,8 @@ ehci_check_qh_intr(ehci_softc_t *sc, str
 	ehci_soft_qtd_t *sqtd, *lsqtd;
 	__uint32_t status;
 
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	if (ex->sqtdstart == NULL) {
 		printf("ehci_check_qh_intr: not valid sqtd\n");
 		return;
@@ -802,6 +860,8 @@ ehci_check_itd_intr(ehci_softc_t *sc, st
 	ehci_soft_itd_t *itd;
 	int i;
 
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	if (&ex->xfer != SIMPLEQ_FIRST(&ex->xfer.pipe->queue))
 		return;
 
@@ -849,16 +909,18 @@ ehci_idone(struct ehci_xfer *ex)
 {
 	usbd_xfer_handle xfer = &ex->xfer;
 	struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
+	struct ehci_softc *sc = xfer->pipe->device->bus->hci_private;
 	ehci_soft_qtd_t *sqtd, *lsqtd;
 	u_int32_t status = 0, nstatus = 0;
 	int actlen;
 
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex));
+
 #ifdef DIAGNOSTIC
 	{
-		int s = splhigh();
 		if (ex->isdone) {
-			splx(s);
 #ifdef EHCI_DEBUG
 			printf("ehci_idone: ex is done!\n   ");
 			ehci_dump_exfer(ex);
@@ -868,7 +930,6 @@ ehci_idone(struct ehci_xfer *ex)
 			return;
 		}
 		ex->isdone = 1;
-		splx(s);
 	}
 #endif
 	if (xfer->status == USBD_CANCELLED ||
@@ -999,9 +1060,6 @@ ehci_idone(struct ehci_xfer *ex)
 		}
 		/* XXX need to reset TT on missed microframe */
 		if (status & EHCI_QTD_MISSEDMICRO) {
-			ehci_softc_t *sc =
-			    xfer->pipe->device->bus->hci_private;
-
 			printf("%s: missed microframe, TT reset not "
 			    "implemented, hub might be inoperational\n",
 			    device_xname(sc->sc_dev));
@@ -1042,7 +1100,9 @@ ehci_waitintr(ehci_softc_t *sc, usbd_xfe
 			ehci_dump_regs(sc);
 #endif
 		if (intrs) {
+			mutex_spin_enter(&sc->sc_intr_lock);
 			ehci_intr1(sc);
+			mutex_spin_exit(&sc->sc_intr_lock);
 			if (xfer->status != USBD_IN_PROGRESS)
 				return;
 		}
@@ -1069,8 +1129,11 @@ ehci_poll(struct usbd_bus *bus)
 	}
 #endif
 
-	if (EOREAD4(sc, EHCI_USBSTS) & sc->sc_eintrs)
+	if (EOREAD4(sc, EHCI_USBSTS) & sc->sc_eintrs) {
+		mutex_spin_enter(&sc->sc_intr_lock);
 		ehci_intr1(sc);
+		mutex_spin_exit(&sc->sc_intr_lock);
+	}
 }
 
 void
@@ -1085,6 +1148,7 @@ ehci_childdet(device_t self, device_t ch
 int
 ehci_detach(struct ehci_softc *sc, int flags)
 {
+	usbd_xfer_handle xfer;
 	int rv = 0;
 
 	if (sc->sc_child != NULL)
@@ -1098,8 +1162,19 @@ ehci_detach(struct ehci_softc *sc, int f
 	usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */
 
 	/* XXX free other data structures XXX */
-	mutex_destroy(&sc->sc_doorbell_lock);
-	mutex_destroy(&sc->sc_intrhead_lock);
+	if (sc->sc_softitds)
+		kmem_free(sc->sc_softitds,
+		    sc->sc_flsize * sizeof(ehci_soft_itd_t *));
+	cv_destroy(&sc->sc_doorbell);
+	cv_destroy(&sc->sc_softwake_cv);
+
+	softint_disestablish(sc->sc_doorbell_si);
+	softint_disestablish(sc->sc_pcd_si);
+
+	while ((xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers)) != NULL) {
+		SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
+		kmem_free(xfer, sizeof(struct ehci_xfer));
+	}
 
 	EOWRITE4(sc, EHCI_CONFIGFLAG, 0);
 
@@ -1135,12 +1210,12 @@ bool
 ehci_suspend(device_t dv, const pmf_qual_t *qual)
 {
 	ehci_softc_t *sc = device_private(dv);
-	int i, s;
+	int i;
 	uint32_t cmd, hcr;
 
-	s = splhardusb();
-
+	mutex_spin_enter(&sc->sc_intr_lock);
 	sc->sc_bus.use_polling++;
+	mutex_spin_exit(&sc->sc_intr_lock);
 
 	for (i = 1; i <= sc->sc_noport; i++) {
 		cmd = EOREAD4(sc, EHCI_PORTSC(i)) & ~EHCI_PS_CLEAR;
@@ -1176,8 +1251,9 @@ ehci_suspend(device_t dv, const pmf_qual
 	if (hcr != EHCI_STS_HCH)
 		printf("%s: config timeout\n", device_xname(dv));
 
+	mutex_spin_enter(&sc->sc_intr_lock);
 	sc->sc_bus.use_polling--;
-	splx(s);
+	mutex_spin_exit(&sc->sc_intr_lock);
 
 	return true;
 }
@@ -1296,7 +1372,7 @@ ehci_allocx(struct usbd_bus *bus)
 		}
 #endif
 	} else {
-		xfer = malloc(sizeof(struct ehci_xfer), M_USB, M_NOWAIT);
+		xfer = kmem_alloc(sizeof(struct ehci_xfer), KM_SLEEP);
 	}
 	if (xfer != NULL) {
 		memset(xfer, 0, sizeof(struct ehci_xfer));
@@ -1327,6 +1403,15 @@ ehci_freex(struct usbd_bus *bus, usbd_xf
 }
 
 Static void
+ehci_get_locks(struct usbd_bus *bus, kmutex_t **intr, kmutex_t **thread)
+{
+	struct ehci_softc *sc = bus->hci_private;
+
+	*intr = &sc->sc_intr_lock;
+	*thread = &sc->sc_lock;
+}
+
+Static void
 ehci_device_clear_toggle(usbd_pipe_handle pipe)
 {
 	struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
@@ -1540,7 +1625,6 @@ ehci_open(usbd_pipe_handle pipe)
 	struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
 	ehci_soft_qh_t *sqh;
 	usbd_status err;
-	int s;
 	int ival, speed, naks;
 	int hshubaddr, hshubport;
 
@@ -1665,15 +1749,15 @@ ehci_open(usbd_pipe_handle pipe)
 		if (err)
 			goto bad;
 		pipe->methods = &ehci_device_ctrl_methods;
-		s = splusb();
+		mutex_enter(&sc->sc_lock);
 		ehci_add_qh(sqh, sc->sc_async_head);
-		splx(s);
+		mutex_exit(&sc->sc_lock);
 		break;
 	case UE_BULK:
 		pipe->methods = &ehci_device_bulk_methods;
-		s = splusb();
+		mutex_enter(&sc->sc_lock);
 		ehci_add_qh(sqh, sc->sc_async_head);
-		splx(s);
+		mutex_exit(&sc->sc_lock);
 		break;
 	case UE_INTERRUPT:
 		pipe->methods = &ehci_device_intr_methods;
@@ -1819,27 +1903,25 @@ ehci_set_qh_qtd(ehci_soft_qh_t *sqh, ehc
 Static void
 ehci_sync_hc(ehci_softc_t *sc)
 {
-	int s, error;
+	int error;
+
+	KASSERT(mutex_owned(&sc->sc_lock));
 
 	if (sc->sc_dying) {
 		DPRINTFN(2,("ehci_sync_hc: dying\n"));
 		return;
 	}
 	DPRINTFN(2,("ehci_sync_hc: enter\n"));
-	mutex_enter(&sc->sc_doorbell_lock);	/* get doorbell */
-	s = splhardusb();
 	/* ask for doorbell */
 	EOWRITE4(sc, EHCI_USBCMD, EOREAD4(sc, EHCI_USBCMD) | EHCI_CMD_IAAD);
 	DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n",
 		    EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS)));
-	error = tsleep(&sc->sc_async_head, PZERO, "ehcidi", hz); /* bell wait */
+	error = cv_timedwait(&sc->sc_doorbell, &sc->sc_lock, hz); /* bell wait */
 	DPRINTFN(1,("ehci_sync_hc: cmd=0x%08x sts=0x%08x\n",
 		    EOREAD4(sc, EHCI_USBCMD), EOREAD4(sc, EHCI_USBSTS)));
-	splx(s);
-	mutex_exit(&sc->sc_doorbell_lock);	/* release doorbell */
 #ifdef DIAGNOSTIC
 	if (error)
-		printf("ehci_sync_hc: tsleep() = %d\n", error);
+		printf("ehci_sync_hc: cv_timedwait() = %d\n", error);
 #endif
 	DPRINTFN(2,("ehci_sync_hc: exit\n"));
 }
@@ -1974,10 +2056,13 @@ Static const usb_hub_descriptor_t ehci_h
 Static usbd_status
 ehci_root_ctrl_transfer(usbd_xfer_handle xfer)
 {
+	ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
 	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);
 
@@ -1992,7 +2077,7 @@ ehci_root_ctrl_start(usbd_xfer_handle xf
 	usb_device_request_t *req;
 	void *buf = NULL;
 	int port, i;
-	int s, len, value, index, l, totlen = 0;
+	int len, value, index, l, totlen = 0;
 	usb_port_status_t ps;
 	usb_hub_descriptor_t hubd;
 	usbd_status err;
@@ -2414,10 +2499,10 @@ ehci_root_ctrl_start(usbd_xfer_handle xf
 	xfer->actlen = totlen;
 	err = USBD_NORMAL_COMPLETION;
  ret:
+	mutex_enter(&sc->sc_lock);
 	xfer->status = err;
-	s = splusb();
 	usb_transfer_complete(xfer);
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 	return (USBD_IN_PROGRESS);
 }
 
@@ -2473,10 +2558,13 @@ ehci_root_intr_done(usbd_xfer_handle xfe
 Static usbd_status
 ehci_root_intr_transfer(usbd_xfer_handle xfer)
 {
+	ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
 	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);
 
@@ -2493,7 +2581,9 @@ ehci_root_intr_start(usbd_xfer_handle xf
 	if (sc->sc_dying)
 		return (USBD_IOERROR);
 
+	mutex_enter(&sc->sc_lock);
 	sc->sc_intrxfer = xfer;
+	mutex_exit(&sc->sc_lock);
 
 	return (USBD_IN_PROGRESS);
 }
@@ -2502,16 +2592,16 @@ ehci_root_intr_start(usbd_xfer_handle xf
 Static void
 ehci_root_intr_abort(usbd_xfer_handle xfer)
 {
-	int s;
+	ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
 
+	mutex_enter(&sc->sc_lock);
 	if (xfer->pipe->intrxfer == xfer) {
 		DPRINTF(("ehci_root_intr_abort: remove\n"));
 		xfer->pipe->intrxfer = NULL;
 	}
 	xfer->status = USBD_CANCELLED;
-	s = splusb();
 	usb_transfer_complete(xfer);
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 }
 
 /* Close the root pipe. */
@@ -2522,7 +2612,9 @@ ehci_root_intr_close(usbd_pipe_handle pi
 
 	DPRINTF(("ehci_root_intr_close\n"));
 
+	mutex_enter(&sc->sc_lock);
 	sc->sc_intrxfer = NULL;
+	mutex_exit(&sc->sc_lock);
 }
 
 Static void
@@ -2578,14 +2670,14 @@ ehci_free_sqh(ehci_softc_t *sc, ehci_sof
 Static ehci_soft_qtd_t *
 ehci_alloc_sqtd(ehci_softc_t *sc)
 {
-	ehci_soft_qtd_t *sqtd;
+	ehci_soft_qtd_t *sqtd = NULL;
 	usbd_status err;
 	int i, offs;
 	usb_dma_t dma;
-	int s;
 
 	if (sc->sc_freeqtds == NULL) {
 		DPRINTFN(2, ("ehci_alloc_sqtd: allocating chunk\n"));
+
 		err = usb_allocmem(&sc->sc_bus, EHCI_SQTD_SIZE*EHCI_SQTD_CHUNK,
 			  EHCI_PAGE_SIZE, &dma);
 #ifdef EHCI_DEBUG
@@ -2593,40 +2685,38 @@ ehci_alloc_sqtd(ehci_softc_t *sc)
 			printf("ehci_alloc_sqtd: usb_allocmem()=%d\n", err);
 #endif
 		if (err)
-			return (NULL);
-		s = splusb();
+			goto done;
+
 		for(i = 0; i < EHCI_SQTD_CHUNK; i++) {
 			offs = i * EHCI_SQTD_SIZE;
 			sqtd = KERNADDR(&dma, offs);
 			sqtd->physaddr = DMAADDR(&dma, offs);
 			sqtd->dma = dma;
 			sqtd->offs = offs;
+
 			sqtd->nextqtd = sc->sc_freeqtds;
 			sc->sc_freeqtds = sqtd;
 		}
-		splx(s);
 	}
 
-	s = splusb();
 	sqtd = sc->sc_freeqtds;
 	sc->sc_freeqtds = sqtd->nextqtd;
 	memset(&sqtd->qtd, 0, sizeof(ehci_qtd_t));
 	sqtd->nextqtd = NULL;
 	sqtd->xfer = NULL;
-	splx(s);
 
+done:
 	return (sqtd);
 }
 
 Static void
 ehci_free_sqtd(ehci_softc_t *sc, ehci_soft_qtd_t *sqtd)
 {
-	int s;
 
-	s = splusb();
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	sqtd->nextqtd = sc->sc_freeqtds;
 	sc->sc_freeqtds = sqtd;
-	splx(s);
 }
 
 Static usbd_status
@@ -2797,7 +2887,7 @@ ehci_alloc_itd(ehci_softc_t *sc)
 	int i, s, offs, frindex, previndex;
 	usb_dma_t dma;
 
-	s = splusb();
+	KASSERT(mutex_owned(&sc->sc_lock));
 
 	/* Find an itd that wasn't freed this frame or last frame. This can
 	 * discard itds that were freed before frindex wrapped around
@@ -2856,11 +2946,10 @@ ehci_alloc_itd(ehci_softc_t *sc)
 Static void
 ehci_free_itd(ehci_softc_t *sc, ehci_soft_itd_t *itd)
 {
-	int s;
 
-	s = splusb();
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	LIST_INSERT_HEAD(&sc->sc_freeitds, itd, u.free_list);
-	splx(s);
 }
 
 /****************/
@@ -2875,11 +2964,10 @@ ehci_close_pipe(usbd_pipe_handle pipe, e
 	struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
 	ehci_softc_t *sc = pipe->device->bus->hci_private;
 	ehci_soft_qh_t *sqh = epipe->sqh;
-	int s;
 
-	s = splusb();
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	ehci_rem_qh(sc, sqh, head);
-	splx(s);
 	ehci_free_sqh(sc, epipe->sqh);
 }
 
@@ -2904,7 +2992,6 @@ ehci_abort_xfer(usbd_xfer_handle xfer, u
 	ehci_soft_qtd_t *sqtd;
 	ehci_physaddr_t cur;
 	u_int32_t qhstatus;
-	int s;
 	int hit;
 	int wake;
 
@@ -2912,17 +2999,19 @@ ehci_abort_xfer(usbd_xfer_handle xfer, u
 
 	if (sc->sc_dying) {
 		/* If we're dying, just do the software part. */
-		s = splusb();
+		mutex_enter(&sc->sc_lock);
 		xfer->status = status;	/* make software ignore it */
 		callout_stop(&xfer->timeout_handle);
 		usb_transfer_complete(xfer);
-		splx(s);
+		mutex_exit(&sc->sc_lock);
 		return;
 	}
 
 	if (xfer->device->bus->intr_context)
 		panic("ehci_abort_xfer: not in process context");
 
+	mutex_enter(&sc->sc_lock);
+
 	/*
 	 * If an abort is already in progress then just wait for it to
 	 * complete and return.
@@ -2938,7 +3027,8 @@ ehci_abort_xfer(usbd_xfer_handle xfer, u
 		DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n"));
 		xfer->hcflags |= UXFER_ABORTWAIT;
 		while (xfer->hcflags & UXFER_ABORTING)
-			tsleep(&xfer->hcflags, PZERO, "ehciaw", 0);
+			cv_wait(&xfer->hccv, &sc->sc_lock);
+		mutex_exit(&sc->sc_lock);
 		return;
 	}
 	xfer->hcflags |= UXFER_ABORTING;
@@ -2946,7 +3036,6 @@ ehci_abort_xfer(usbd_xfer_handle xfer, u
 	/*
 	 * Step 1: Make interrupt routine and hardware ignore xfer.
 	 */
-	s = splusb();
 	xfer->status = status;	/* make software ignore it */
 	callout_stop(&xfer->timeout_handle);
 
@@ -2973,7 +3062,6 @@ ehci_abort_xfer(usbd_xfer_handle xfer, u
 		if (sqtd == exfer->sqtdend)
 			break;
 	}
-	splx(s);
 
 	/*
 	 * Step 2: Wait until we know hardware has finished any possible
@@ -2981,15 +3069,9 @@ ehci_abort_xfer(usbd_xfer_handle xfer, u
 	 * has run.
 	 */
 	ehci_sync_hc(sc);
-	s = splusb();
-#ifdef USB_USE_SOFTINTR
 	sc->sc_softwake = 1;
-#endif /* USB_USE_SOFTINTR */
 	usb_schedsoftintr(&sc->sc_bus);
-#ifdef USB_USE_SOFTINTR
-	tsleep(&sc->sc_softwake, PZERO, "ehciab", 0);
-#endif /* USB_USE_SOFTINTR */
-	splx(s);
+	cv_wait(&sc->sc_softwake_cv, &sc->sc_lock);
 
 	/*
 	 * Step 3: Remove any vestiges of the xfer from the hardware.
@@ -2998,7 +3080,6 @@ ehci_abort_xfer(usbd_xfer_handle xfer, u
 	 * the TDs of this xfer we check if the hardware points to
 	 * any of them.
 	 */
-	s = splusb();		/* XXX why? */
 
 	usb_syncmem(&sqh->dma,
 	    sqh->offs + offsetof(ehci_qh_t, qh_curqtd),
@@ -3038,10 +3119,11 @@ ehci_abort_xfer(usbd_xfer_handle xfer, u
 	wake = xfer->hcflags & UXFER_ABORTWAIT;
 	xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
 	usb_transfer_complete(xfer);
-	if (wake)
-		wakeup(&xfer->hcflags);
+	if (wake) {
+		cv_broadcast(&xfer->hccv);
+	}
 
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 #undef exfer
 }
 
@@ -3053,7 +3135,7 @@ ehci_abort_isoc_xfer(usbd_xfer_handle xf
 	struct ehci_xfer *exfer;
 	ehci_softc_t *sc;
 	struct ehci_soft_itd *itd;
-	int s, i, wake;
+	int i, wake;
 
 	epipe = (struct ehci_pipe *) xfer->pipe;
 	exfer = EXFER(xfer);
@@ -3062,14 +3144,16 @@ ehci_abort_isoc_xfer(usbd_xfer_handle xf
 	DPRINTF(("ehci_abort_isoc_xfer: xfer %p pipe %p\n", xfer, epipe));
 
 	if (sc->sc_dying) {
-		s = splusb();
+		mutex_enter(&sc->sc_lock);
 		xfer->status = status;
 		callout_stop(&xfer->timeout_handle);
 		usb_transfer_complete(xfer);
-		splx(s);
+		mutex_exit(&sc->sc_lock);
 		return;
 	}
 
+	mutex_enter(&sc->sc_lock);
+
 	if (xfer->hcflags & UXFER_ABORTING) {
 		DPRINTFN(2, ("ehci_abort_isoc_xfer: already aborting\n"));
 
@@ -3082,15 +3166,14 @@ ehci_abort_isoc_xfer(usbd_xfer_handle xf
 		DPRINTFN(2, ("ehci_abort_xfer: waiting for abort to finish\n"));
 		xfer->hcflags |= UXFER_ABORTWAIT;
 		while (xfer->hcflags & UXFER_ABORTING)
-			tsleep(&xfer->hcflags, PZERO, "ehciiaw", 0);
-		return;
+			cv_wait(&xfer->hccv, &sc->sc_intr_lock);
+		goto done;
 	}
 	xfer->hcflags |= UXFER_ABORTING;
 
 	xfer->status = status;
 	callout_stop(&xfer->timeout_handle);
 
-	s = splusb();
 	for (itd = exfer->itdstart; itd != NULL; itd = itd->xfer_next) {
 		usb_syncmem(&itd->dma,
 		    itd->offs + offsetof(ehci_itd_t, itd_ctl),
@@ -3108,17 +3191,10 @@ ehci_abort_isoc_xfer(usbd_xfer_handle xf
 		    sizeof(itd->itd.itd_ctl),
 		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 	}
-	splx(s);
 
-        s = splusb();
-#ifdef USB_USE_SOFTINTR
         sc->sc_softwake = 1;
-#endif /* USB_USE_SOFTINTR */
         usb_schedsoftintr(&sc->sc_bus);
-#ifdef USB_USE_SOFTINTR
-        tsleep(&sc->sc_softwake, PZERO, "ehciab", 0);
-#endif /* USB_USE_SOFTINTR */
-        splx(s);
+	cv_wait(&sc->sc_softwake_cv, &sc->sc_intr_lock);
 
 #ifdef DIAGNOSTIC
 	exfer->isdone = 1;
@@ -3126,9 +3202,12 @@ ehci_abort_isoc_xfer(usbd_xfer_handle xf
 	wake = xfer->hcflags & UXFER_ABORTWAIT;
 	xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
 	usb_transfer_complete(xfer);
-	if (wake)
-		wakeup(&xfer->hcflags);
+	if (wake) {
+		cv_broadcast(&xfer->hccv);
+	}
 
+done:
+	mutex_exit(&sc->sc_lock);
 	return;
 }
 
@@ -3160,13 +3239,10 @@ Static void
 ehci_timeout_task(void *addr)
 {
 	usbd_xfer_handle xfer = addr;
-	int s;
 
 	DPRINTF(("ehci_timeout_task: xfer=%p\n", xfer));
 
-	s = splusb();
 	ehci_abort_xfer(xfer, USBD_TIMEOUT);
-	splx(s);
 }
 
 /************************/
@@ -3174,10 +3250,13 @@ ehci_timeout_task(void *addr)
 Static usbd_status
 ehci_device_ctrl_transfer(usbd_xfer_handle xfer)
 {
+	ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
 	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);
 
@@ -3203,11 +3282,13 @@ ehci_device_ctrl_start(usbd_xfer_handle 
 #endif
 
 	err = ehci_device_request(xfer);
-	if (err)
+	if (err) {
 		return (err);
+	}
 
 	if (sc->sc_bus.use_polling)
 		ehci_waitintr(sc, xfer);
+
 	return (USBD_IN_PROGRESS);
 }
 
@@ -3223,13 +3304,14 @@ ehci_device_ctrl_done(usbd_xfer_handle x
 
 	DPRINTFN(10,("ehci_ctrl_done: xfer=%p\n", xfer));
 
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 #ifdef DIAGNOSTIC
 	if (!(xfer->rqflags & URQ_REQUEST)) {
 		panic("ehci_ctrl_done: not a request");
 	}
 #endif
 
-	mutex_enter(&sc->sc_intrhead_lock);
 	if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
 		ehci_del_intr_list(sc, ex);	/* remove from active list */
 		ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
@@ -3239,7 +3321,6 @@ ehci_device_ctrl_done(usbd_xfer_handle x
 			usb_syncmem(&xfer->dmabuf, 0, len,
 			    rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
 	}
-	mutex_exit(&sc->sc_intrhead_lock);
 
 	DPRINTFN(5, ("ehci_ctrl_done: length=%d\n", xfer->actlen));
 }
@@ -3260,7 +3341,10 @@ ehci_device_ctrl_close(usbd_pipe_handle 
 	/*struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;*/
 
 	DPRINTF(("ehci_device_ctrl_close: pipe=%p\n", pipe));
+
+	mutex_enter(&sc->sc_lock);
 	ehci_close_pipe(pipe, sc->sc_async_head);
+	mutex_exit(&sc->sc_lock);
 }
 
 Static usbd_status
@@ -3277,7 +3361,6 @@ ehci_device_request(usbd_xfer_handle xfe
 	int isread;
 	int len;
 	usbd_status err;
-	int s;
 
 	isread = req->bmRequestType & UT_READ;
 	len = UGETW(req->wLength);
@@ -3299,6 +3382,8 @@ ehci_device_request(usbd_xfer_handle xfe
 		goto bad2;
 	}
 
+	mutex_enter(&sc->sc_lock);
+
 	sqh = epipe->sqh;
 	epipe->u.ctl.length = len;
 
@@ -3387,17 +3472,14 @@ ehci_device_request(usbd_xfer_handle xfe
 #endif
 
 	/* Insert qTD in QH list. */
-	s = splusb();
 	ehci_set_qh_qtd(sqh, setup); /* also does usb_syncmem(sqh) */
 	if (xfer->timeout && !sc->sc_bus.use_polling) {
 		callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)),
 		    (ehci_timeout), (xfer));
 	}
-	mutex_enter(&sc->sc_intrhead_lock);
 	ehci_add_intr_list(sc, exfer);
-	mutex_exit(&sc->sc_intrhead_lock);
 	xfer->status = USBD_IN_PROGRESS;
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 
 #ifdef EHCI_DEBUG
 	if (ehcidebug > 10) {
@@ -3414,13 +3496,16 @@ ehci_device_request(usbd_xfer_handle xfe
 	return (USBD_NORMAL_COMPLETION);
 
  bad3:
+	mutex_exit(&sc->sc_lock);
 	ehci_free_sqtd(sc, stat);
  bad2:
 	ehci_free_sqtd(sc, setup);
  bad1:
 	DPRINTFN(-1,("ehci_device_request: no memory\n"));
+	mutex_enter(&sc->sc_lock);
 	xfer->status = err;
 	usb_transfer_complete(xfer);
+	mutex_exit(&sc->sc_lock);
 	return (err);
 #undef exfer
 }
@@ -3440,12 +3525,11 @@ Static void
 ehci_intrlist_timeout(void *arg)
 {
 	ehci_softc_t *sc = arg;
-	int s = splusb();
 
 	DPRINTF(("ehci_intrlist_timeout\n"));
+	mutex_spin_enter(&sc->sc_intr_lock);
 	usb_schedsoftintr(&sc->sc_bus);
-
-	splx(s);
+	mutex_spin_exit(&sc->sc_intr_lock);
 }
 
 /************************/
@@ -3453,10 +3537,13 @@ ehci_intrlist_timeout(void *arg)
 Static usbd_status
 ehci_device_bulk_transfer(usbd_xfer_handle xfer)
 {
+	ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
 	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);
 
@@ -3475,7 +3562,6 @@ ehci_device_bulk_start(usbd_xfer_handle 
 	ehci_soft_qh_t *sqh;
 	usbd_status err;
 	int len, isread, endpt;
-	int s;
 
 	DPRINTFN(2, ("ehci_device_bulk_start: xfer=%p len=%d flags=%d\n",
 		     xfer, xfer->length, xfer->flags));
@@ -3522,17 +3608,15 @@ ehci_device_bulk_start(usbd_xfer_handle 
 	exfer->isdone = 0;
 #endif
 
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 	ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */
 	if (xfer->timeout && !sc->sc_bus.use_polling) {
 		callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)),
 		    (ehci_timeout), (xfer));
 	}
-	mutex_enter(&sc->sc_intrhead_lock);
 	ehci_add_intr_list(sc, exfer);
-	mutex_exit(&sc->sc_intrhead_lock);
 	xfer->status = USBD_IN_PROGRESS;
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 
 #ifdef EHCI_DEBUG
 	if (ehcidebug > 10) {
@@ -3574,8 +3658,10 @@ ehci_device_bulk_close(usbd_pipe_handle 
 	struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
 
 	DPRINTF(("ehci_device_bulk_close: pipe=%p\n", pipe));
+	mutex_enter(&sc->sc_lock);
 	pipe->endpoint->datatoggle = epipe->nexttoggle;
 	ehci_close_pipe(pipe, sc->sc_async_head);
+	mutex_exit(&sc->sc_lock);
 }
 
 Static void
@@ -3590,14 +3676,14 @@ ehci_device_bulk_done(usbd_xfer_handle x
 	DPRINTFN(10,("ehci_bulk_done: xfer=%p, actlen=%d\n",
 		     xfer, xfer->actlen));
 
-	mutex_enter(&sc->sc_intrhead_lock);
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
 		ehci_del_intr_list(sc, ex);	/* remove from active list */
 		ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
 		usb_syncmem(&xfer->dmabuf, 0, xfer->length,
 		    rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
 	}
-	mutex_exit(&sc->sc_intrhead_lock);
 
 	DPRINTFN(5, ("ehci_bulk_done: length=%d\n", xfer->actlen));
 }
@@ -3630,10 +3716,13 @@ ehci_device_setintr(ehci_softc_t *sc, eh
 Static usbd_status
 ehci_device_intr_transfer(usbd_xfer_handle xfer)
 {
+	ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
 	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);
 
@@ -3655,7 +3744,6 @@ ehci_device_intr_start(usbd_xfer_handle 
 	ehci_soft_qh_t *sqh;
 	usbd_status err;
 	int len, isread, endpt;
-	int s;
 
 	DPRINTFN(2, ("ehci_device_intr_start: xfer=%p len=%d flags=%d\n",
 	    xfer, xfer->length, xfer->flags));
@@ -3702,17 +3790,15 @@ ehci_device_intr_start(usbd_xfer_handle 
 	exfer->isdone = 0;
 #endif
 
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 	ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */
 	if (xfer->timeout && !sc->sc_bus.use_polling) {
 		callout_reset(&(xfer->timeout_handle), (mstohz(xfer->timeout)),
 		    (ehci_timeout), (xfer));
 	}
-	mutex_enter(&sc->sc_intrhead_lock);
 	ehci_add_intr_list(sc, exfer);
-	mutex_exit(&sc->sc_intrhead_lock);
 	xfer->status = USBD_IN_PROGRESS;
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 
 #ifdef EHCI_DEBUG
 	if (ehcidebug > 10) {
@@ -3770,12 +3856,13 @@ ehci_device_intr_done(usbd_xfer_handle x
 	ehci_soft_qtd_t *data, *dataend;
 	ehci_soft_qh_t *sqh;
 	usbd_status err;
-	int len, isread, endpt, s;
+	int len, isread, endpt;
 
 	DPRINTFN(10, ("ehci_device_intr_done: xfer=%p, actlen=%d\n",
 	    xfer, xfer->actlen));
 
-	mutex_enter(&sc->sc_intrhead_lock);
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	if (xfer->pipe->repeat) {
 		ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
 
@@ -3792,7 +3879,6 @@ ehci_device_intr_done(usbd_xfer_handle x
 		if (err) {
 			DPRINTFN(-1, ("ehci_device_intr_done: no memory\n"));
 			xfer->status = err;
-			mutex_exit(&sc->sc_intrhead_lock);
 			return;
 		}
 
@@ -3807,13 +3893,11 @@ ehci_device_intr_done(usbd_xfer_handle x
 		exfer->isdone = 0;
 #endif
 
-		s = splusb();
 		ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */
 		if (xfer->timeout && !sc->sc_bus.use_polling) {
 			callout_reset(&(xfer->timeout_handle),
 			    (mstohz(xfer->timeout)), (ehci_timeout), (xfer));
 		}
-		splx(s);
 
 		xfer->status = USBD_IN_PROGRESS;
 	} else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
@@ -3824,7 +3908,6 @@ ehci_device_intr_done(usbd_xfer_handle x
 		usb_syncmem(&xfer->dmabuf, 0, xfer->length,
 		    isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
 	}
-	mutex_exit(&sc->sc_intrhead_lock);
 #undef exfer
 }
 
@@ -3833,9 +3916,12 @@ ehci_device_intr_done(usbd_xfer_handle x
 Static usbd_status
 ehci_device_isoc_transfer(usbd_xfer_handle xfer)
 {
+	ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
 	usbd_status err;
 
+	mutex_enter(&sc->sc_lock);
 	err = usb_insert_transfer(xfer);
+	mutex_exit(&sc->sc_lock);
 	if (err && err != USBD_IN_PROGRESS)
 		return err;
 
@@ -3852,7 +3938,7 @@ ehci_device_isoc_start(usbd_xfer_handle 
 	ehci_soft_itd_t *itd, *prev, *start, *stop;
 	usb_dma_t *dma_buf;
 	int i, j, k, frames, uframes, ufrperframe;
-	int s, trans_count, offs, total_length;
+	int trans_count, offs, total_length;
 	int frindex;
 
 	start = NULL;
@@ -4036,7 +4122,7 @@ ehci_device_isoc_start(usbd_xfer_handle 
 	 * more than the period frame list.
 	 */
 
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 
 	/* Start inserting frames */
 	if (epipe->u.isoc.cur_xfers > 0) {
@@ -4102,12 +4188,10 @@ ehci_device_isoc_start(usbd_xfer_handle 
 	exfer->sqtdstart = NULL;
 	exfer->sqtdstart = NULL;
 
-	mutex_enter(&sc->sc_intrhead_lock);
 	ehci_add_intr_list(sc, exfer);
-	mutex_exit(&sc->sc_intrhead_lock);
 	xfer->status = USBD_IN_PROGRESS;
 	xfer->done = 0;
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 
 	if (sc->sc_bus.use_polling) {
 		printf("Starting ehci isoc xfer with polling. Bad idea?\n");
@@ -4136,21 +4220,18 @@ ehci_device_isoc_done(usbd_xfer_handle x
 	struct ehci_xfer *exfer;
 	ehci_softc_t *sc;
 	struct ehci_pipe *epipe;
-	int s;
 
 	exfer = EXFER(xfer);
 	sc = xfer->pipe->device->bus->hci_private;
 	epipe = (struct ehci_pipe *) xfer->pipe;
 
-	s = splusb();
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	epipe->u.isoc.cur_xfers--;
-	mutex_enter(&sc->sc_intrhead_lock);
 	if (xfer->status != USBD_NOMEM && ehci_active_intr_list(exfer)) {
 		ehci_del_intr_list(sc, exfer);
 		ehci_rem_free_itd_chain(sc, exfer);
 	}
-	mutex_exit(&sc->sc_intrhead_lock);
-	splx(s);
 
 	usb_syncmem(&xfer->dmabuf, 0, xfer->length, BUS_DMASYNC_POSTWRITE |
                     BUS_DMASYNC_POSTREAD);

Index: src/sys/dev/usb/ehcivar.h
diff -u src/sys/dev/usb/ehcivar.h:1.38 src/sys/dev/usb/ehcivar.h:1.38.10.1
--- src/sys/dev/usb/ehcivar.h:1.38	Tue Jan 18 08:29:24 2011
+++ src/sys/dev/usb/ehcivar.h	Sun Dec  4 13:23:16 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: ehcivar.h,v 1.38 2011/01/18 08:29:24 matt Exp $ */
+/*	$NetBSD: ehcivar.h,v 1.38.10.1 2011/12/04 13:23:16 jmcneill Exp $ */
 
 /*
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -109,6 +109,11 @@ struct ehci_soft_islot {
 
 typedef struct ehci_softc {
 	device_t sc_dev;
+	kmutex_t sc_lock;
+	kmutex_t sc_intr_lock;
+	kcondvar_t sc_doorbell;
+	void *sc_doorbell_si;
+	void *sc_pcd_si;
 	struct usbd_bus sc_bus;
 	bus_space_tag_t iot;
 	bus_space_handle_t ioh;
@@ -140,7 +145,6 @@ typedef struct ehci_softc {
 	struct ehci_soft_itd **sc_softitds;
 
 	TAILQ_HEAD(, ehci_xfer) sc_intrhead;
-	kmutex_t sc_intrhead_lock;
 
 	ehci_soft_qh_t *sc_freeqhs;
 	ehci_soft_qtd_t *sc_freeqtds;
@@ -152,17 +156,14 @@ typedef struct ehci_softc {
 	u_int8_t sc_conf;		/* device configuration */
 	usbd_xfer_handle sc_intrxfer;
 	char sc_isreset[EHCI_MAX_PORTS];
-#ifdef USB_USE_SOFTINTR
 	char sc_softwake;
-#endif /* USB_USE_SOFTINTR */
+	kcondvar_t sc_softwake_cv;
 
 	u_int32_t sc_eintrs;
 	ehci_soft_qh_t *sc_async_head;
 
 	SIMPLEQ_HEAD(, usbd_xfer) sc_free_xfers; /* free xfers */
 
-	kmutex_t sc_doorbell_lock;
-
 	struct callout sc_tmo_intrlist;
 
 	device_t sc_child; /* /dev/usb# device */

Index: src/sys/dev/usb/ohci.c
diff -u src/sys/dev/usb/ohci.c:1.218 src/sys/dev/usb/ohci.c:1.218.6.1
--- src/sys/dev/usb/ohci.c:1.218	Sun Aug  7 13:45:46 2011
+++ src/sys/dev/usb/ohci.c	Sun Dec  4 13:23:16 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: ohci.c,v 1.218 2011/08/07 13:45:46 jmcneill Exp $	*/
+/*	$NetBSD: ohci.c,v 1.218.6.1 2011/12/04 13:23:16 jmcneill Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/ohci.c,v 1.22 1999/11/17 22:33:40 n_hibma Exp $	*/
 
 /*
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.218 2011/08/07 13:45:46 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.218.6.1 2011/12/04 13:23:16 jmcneill Exp $");
 
 #include "opt_usb.h"
 
@@ -274,6 +274,7 @@ Static const struct usbd_bus_methods ohc
 	ohci_freem,
 	ohci_allocx,
 	ohci_freex,
+	NULL, /* ohci_get_locks */
 };
 
 Static const struct usbd_pipe_methods ohci_root_ctrl_methods = {

Index: src/sys/dev/usb/uhci.c
diff -u src/sys/dev/usb/uhci.c:1.240 src/sys/dev/usb/uhci.c:1.240.6.1
--- src/sys/dev/usb/uhci.c:1.240	Sun Aug  7 18:58:52 2011
+++ src/sys/dev/usb/uhci.c	Sun Dec  4 13:23:17 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: uhci.c,v 1.240 2011/08/07 18:58:52 jakllsch Exp $	*/
+/*	$NetBSD: uhci.c,v 1.240.6.1 2011/12/04 13:23:17 jmcneill Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $	*/
 
 /*
@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.240 2011/08/07 18:58:52 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.240.6.1 2011/12/04 13:23:17 jmcneill Exp $");
 
 #include "opt_usb.h"
 
@@ -288,6 +288,7 @@ const struct usbd_bus_methods uhci_bus_m
 	uhci_freem,
 	uhci_allocx,
 	uhci_freex,
+	NULL, /* uhci_get_locks */
 };
 
 const struct usbd_pipe_methods uhci_root_ctrl_methods = {

Index: src/sys/dev/usb/usb.c
diff -u src/sys/dev/usb/usb.c:1.125 src/sys/dev/usb/usb.c:1.125.6.1
--- src/sys/dev/usb/usb.c:1.125	Thu Jun  9 19:08:32 2011
+++ src/sys/dev/usb/usb.c	Sun Dec  4 13:23:17 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: usb.c,v 1.125 2011/06/09 19:08:32 matt Exp $	*/
+/*	$NetBSD: usb.c,v 1.125.6.1 2011/12/04 13:23:17 jmcneill Exp $	*/
 
 /*
  * Copyright (c) 1998, 2002, 2008 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.125 2011/06/09 19:08:32 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.125.6.1 2011/12/04 13:23:17 jmcneill Exp $");
 
 #include "opt_compat_netbsd.h"
 #include "opt_usb.h"
@@ -202,6 +202,7 @@ usb_doattach(device_t self)
 	usbd_status err;
 	int speed;
 	struct usb_event *ue;
+	bool mpsafe = sc->sc_bus->methods->get_locks ? true : false;
 
 	if (!usb_selevent_init) {
 		selinit(&usb_selevent);
@@ -228,9 +229,9 @@ usb_doattach(device_t self)
 	ue->u.ue_ctrlr.ue_bus = device_unit(self);
 	usb_add_event(USB_EVENT_CTRLR_ATTACH, ue);
 
-#ifdef USB_USE_SOFTINTR
 	/* XXX we should have our own level */
-	sc->sc_bus->soft = softint_establish(SOFTINT_NET,
+	sc->sc_bus->soft = softint_establish(
+	    SOFTINT_NET | (mpsafe ? SOFTINT_MPSAFE : 0),
 	    sc->sc_bus->methods->soft_intr, sc->sc_bus);
 	if (sc->sc_bus->soft == NULL) {
 		aprint_error("%s: can't register softintr\n",
@@ -238,7 +239,6 @@ usb_doattach(device_t self)
 		sc->sc_dying = 1;
 		return;
 	}
-#endif
 
 	err = usbd_new_device(self, sc->sc_bus, 0, speed, 0,
 		  &sc->sc_port);
@@ -910,15 +910,11 @@ void
 usb_schedsoftintr(usbd_bus_handle bus)
 {
 	DPRINTFN(10,("usb_schedsoftintr: polling=%d\n", bus->use_polling));
-#ifdef USB_USE_SOFTINTR
 	if (bus->use_polling) {
 		bus->methods->soft_intr(bus);
 	} else {
 		softint_schedule(bus->soft);
 	}
-#else
-	bus->methods->soft_intr(bus);
-#endif /* USB_USE_SOFTINTR */
 }
 
 int
@@ -973,12 +969,10 @@ usb_detach(device_t self, int flags)
 	}
 	DPRINTF(("usb_detach: event thread dead\n"));
 
-#ifdef USB_USE_SOFTINTR
 	if (sc->sc_bus->soft != NULL) {
 		softint_disestablish(sc->sc_bus->soft);
 		sc->sc_bus->soft = NULL;
 	}
-#endif
 
 	ue = usb_alloc_event();
 	ue->u.ue_ctrlr.ue_bus = device_unit(self);

Index: src/sys/dev/usb/usb_subr.c
diff -u src/sys/dev/usb/usb_subr.c:1.180 src/sys/dev/usb/usb_subr.c:1.180.6.1
--- src/sys/dev/usb/usb_subr.c:1.180	Thu Jun  9 19:08:33 2011
+++ src/sys/dev/usb/usb_subr.c	Sun Dec  4 13:23:17 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: usb_subr.c,v 1.180 2011/06/09 19:08:33 matt Exp $	*/
+/*	$NetBSD: usb_subr.c,v 1.180.6.1 2011/12/04 13:23:17 jmcneill Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $	*/
 
 /*
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.180 2011/06/09 19:08:33 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.180.6.1 2011/12/04 13:23:17 jmcneill Exp $");
 
 #include "opt_compat_netbsd.h"
 #include "opt_usbverbose.h"
@@ -751,6 +751,11 @@ usbd_setup_pipe(usbd_device_handle dev, 
 		free(p, M_USB);
 		return (err);
 	}
+	if (dev->bus->methods->get_locks) {
+		dev->bus->methods->get_locks(dev->bus, &p->intr_lock, &p->lock);
+	} else {
+		p->intr_lock = p->lock = NULL;
+	}
 	*pipe = p;
 	return (USBD_NORMAL_COMPLETION);
 }

Index: src/sys/dev/usb/usbdi.c
diff -u src/sys/dev/usb/usbdi.c:1.134 src/sys/dev/usb/usbdi.c:1.134.2.1
--- src/sys/dev/usb/usbdi.c:1.134	Sun Nov 27 03:25:00 2011
+++ src/sys/dev/usb/usbdi.c	Sun Dec  4 13:23:17 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: usbdi.c,v 1.134 2011/11/27 03:25:00 jmcneill Exp $	*/
+/*	$NetBSD: usbdi.c,v 1.134.2.1 2011/12/04 13:23:17 jmcneill Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/usbdi.c,v 1.28 1999/11/17 22:33:49 n_hibma Exp $	*/
 
 /*
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.134 2011/11/27 03:25:00 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.134.2.1 2011/12/04 13:23:17 jmcneill Exp $");
 
 #include "opt_compat_netbsd.h"
 #include "opt_usb.h"
@@ -261,8 +261,6 @@ usbd_transfer(usbd_xfer_handle xfer)
 	DPRINTFN(5,("usbd_transfer: xfer=%p, flags=%#x, pipe=%p, running=%d\n",
 		    xfer, xfer->flags, pipe, pipe->running));
 
-	KASSERT(KERNEL_LOCKED_P());
-
 #ifdef USB_DEBUG
 	if (usbdebug > 5)
 		usbd_dump_queue(pipe);
@@ -312,13 +310,17 @@ usbd_transfer(usbd_xfer_handle xfer)
 	/* Sync transfer, wait for completion. */
 	if (err != USBD_IN_PROGRESS)
 		return (err);
-	s = splusb();
+	usbd_lock(pipe->lock);
 	if (!xfer->done) {
 		if (pipe->device->bus->use_polling)
 			panic("usbd_transfer: not done");
-		tsleep(xfer, PRIBIO, "usbsyn", 0);
+		if (pipe->lock) {
+			cv_wait(&xfer->cv, pipe->lock);
+		} else {
+			tsleep(xfer, PRIBIO, "usbsyn", 0);
+		}
 	}
-	splx(s);
+	usbd_unlock(pipe->lock);
 	return (xfer->status);
 }
 
@@ -378,6 +380,8 @@ usbd_alloc_xfer(usbd_device_handle dev)
 		return (NULL);
 	xfer->device = dev;
 	callout_init(&xfer->timeout_handle, 0);
+	cv_init(&xfer->cv, "usbxfer");
+	cv_init(&xfer->hccv, "usbhcxfer");
 	DPRINTFN(5,("usbd_alloc_xfer() = %p\n", xfer));
 	return (xfer);
 }
@@ -394,6 +398,8 @@ usbd_free_xfer(usbd_xfer_handle xfer)
 		printf("usbd_free_xfer: timout_handle pending");
 	}
 #endif
+	cv_destroy(&xfer->cv);
+	cv_destroy(&xfer->hccv);
 	xfer->device->bus->methods->freex(xfer->device->bus, xfer);
 	return (USBD_NORMAL_COMPLETION);
 }
@@ -531,9 +537,9 @@ usbd_abort_pipe(usbd_pipe_handle pipe)
 		return (USBD_NORMAL_COMPLETION);
 	}
 #endif
-	s = splusb();
+	usbd_lock(pipe->lock);
 	err = usbd_ar_pipe(pipe);
-	splx(s);
+	usbd_unlock(pipe->lock);
 	if (pipe->intrxfer != intrxfer)
 		usbd_free_xfer(intrxfer);
 	return (err);
@@ -722,6 +728,7 @@ usbd_ar_pipe(usbd_pipe_handle pipe)
 	usbd_xfer_handle xfer;
 
 	SPLUSBCHECK;
+	KASSERT(pipe->lock == NULL || mutex_owned(pipe->lock));
 
 	DPRINTFN(2,("usbd_ar_pipe: pipe=%p\n", pipe));
 #ifdef USB_DEBUG
@@ -734,7 +741,11 @@ usbd_ar_pipe(usbd_pipe_handle pipe)
 		DPRINTFN(2,("usbd_ar_pipe: pipe=%p xfer=%p (methods=%p)\n",
 			    pipe, xfer, pipe->methods));
 		/* Make the HC abort it (and invoke the callback). */
+		if (pipe->lock)
+			mutex_exit(pipe->lock);
 		pipe->methods->abort(xfer);
+		if (pipe->lock)
+			mutex_enter(pipe->lock);
 		/* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */
 	}
 	pipe->aborting = 0;
@@ -757,7 +768,7 @@ usb_transfer_complete(usbd_xfer_handle x
 	DPRINTFN(5, ("usb_transfer_complete: pipe=%p xfer=%p status=%d "
 		     "actlen=%d\n", pipe, xfer, xfer->status, xfer->actlen));
 
-	KASSERT(KERNEL_LOCKED_P());
+	KASSERT(pipe->lock == NULL || mutex_owned(pipe->lock));
 
 #ifdef DIAGNOSTIC
 	if (xfer->busy_free != XFER_ONQU) {
@@ -825,17 +836,28 @@ usb_transfer_complete(usbd_xfer_handle x
 	}
 
 	if (repeat) {
-		if (xfer->callback)
+		if (xfer->callback) {
+			if (pipe->lock) mutex_exit(pipe->lock);
 			xfer->callback(xfer, xfer->priv, xfer->status);
+			if (pipe->lock) mutex_enter(pipe->lock);
+		}
 		pipe->methods->done(xfer);
 	} else {
 		pipe->methods->done(xfer);
-		if (xfer->callback)
+		if (xfer->callback) {
+			if (pipe->lock) mutex_exit(pipe->lock);
 			xfer->callback(xfer, xfer->priv, xfer->status);
+			if (pipe->lock) mutex_enter(pipe->lock);
+		}
 	}
 
-	if (sync && !polling)
-		wakeup(xfer);
+	if (sync && !polling) {
+		if (pipe->lock) {
+			cv_broadcast(&xfer->cv);
+		} else {
+			wakeup(xfer);
+		}
+	}
 
 	if (!repeat) {
 		/* XXX should we stop the queue on all errors? */
@@ -856,7 +878,7 @@ usb_insert_transfer(usbd_xfer_handle xfe
 	DPRINTFN(5,("usb_insert_transfer: pipe=%p running=%d timeout=%d\n",
 		    pipe, pipe->running, xfer->timeout));
 
-	KASSERT(KERNEL_LOCKED_P());
+	KASSERT(pipe->lock == NULL || mutex_owned(pipe->lock));
 
 #ifdef DIAGNOSTIC
 	if (xfer->busy_free != XFER_BUSY) {
@@ -898,13 +920,19 @@ usbd_start_next(usbd_pipe_handle pipe)
 	}
 #endif
 
+	KASSERT(pipe->lock == NULL || mutex_owned(pipe->lock));
+
 	/* Get next request in queue. */
 	xfer = SIMPLEQ_FIRST(&pipe->queue);
 	DPRINTFN(5, ("usbd_start_next: pipe=%p, xfer=%p\n", pipe, xfer));
 	if (xfer == NULL) {
 		pipe->running = 0;
 	} else {
+		if (pipe->lock)
+			mutex_exit(pipe->lock);
 		err = pipe->methods->start(xfer);
+		if (pipe->lock)
+			mutex_enter(pipe->lock);
 		if (err != USBD_IN_PROGRESS) {
 			printf("usbd_start_next: error=%d\n", err);
 			pipe->running = 0;

Index: src/sys/dev/usb/usbdivar.h
diff -u src/sys/dev/usb/usbdivar.h:1.93 src/sys/dev/usb/usbdivar.h:1.93.8.1
--- src/sys/dev/usb/usbdivar.h:1.93	Fri May 27 17:19:18 2011
+++ src/sys/dev/usb/usbdivar.h	Sun Dec  4 13:23:17 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: usbdivar.h,v 1.93 2011/05/27 17:19:18 drochner Exp $	*/
+/*	$NetBSD: usbdivar.h,v 1.93.8.1 2011/12/04 13:23:17 jmcneill Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $	*/
 
 /*
@@ -32,6 +32,7 @@
  */
 
 #include <sys/callout.h>
+#include <sys/mutex.h>
 
 /* From usb_mem.h */
 struct usb_dma_block;
@@ -58,6 +59,8 @@ struct usbd_bus_methods {
 	void		      (*freem)(struct usbd_bus *, usb_dma_t *);
 	struct usbd_xfer *    (*allocx)(struct usbd_bus *);
 	void		      (*freex)(struct usbd_bus *, struct usbd_xfer *);
+	void		      (*get_locks)(struct usbd_bus *,
+					kmutex_t **, kmutex_t **);
 };
 
 struct usbd_pipe_methods {
@@ -175,6 +178,9 @@ struct usbd_pipe {
 	char			repeat;
 	int			interval;
 
+	kmutex_t		*intr_lock;
+	kmutex_t		*lock;
+
 	/* Filled by HC driver. */
 	const struct usbd_pipe_methods *methods;
 };
@@ -183,6 +189,7 @@ struct usbd_xfer {
 	struct usbd_pipe       *pipe;
 	void		       *priv;
 	void		       *buffer;
+	kcondvar_t		cv;
 	u_int32_t		length;
 	u_int32_t		actlen;
 	u_int16_t		flags;
@@ -217,6 +224,7 @@ struct usbd_xfer {
 	u_int8_t		hcflags; /* private use by the HC driver */
 #define UXFER_ABORTING	0x01	/* xfer is aborting. */
 #define UXFER_ABORTWAIT	0x02	/* abort completion is being awaited. */
+	kcondvar_t		hccv; /* private use by the HC driver */
 
         struct callout timeout_handle;
 };
@@ -259,6 +267,9 @@ void		usb_needs_explore(usbd_device_hand
 void		usb_needs_reattach(usbd_device_handle);
 void		usb_schedsoftintr(struct usbd_bus *);
 
+#define usbd_lock(m)	if (m) { s = -1; mutex_enter(m); } else s = splusb()
+#define usbd_unlock(m)	if (m) { s = -1; mutex_exit(m); } else splx(s)
+
 /*
  * XXX This check is extremely bogus. Bad Bad Bad.
  */

Reply via email to