Tue Dec 6 05:06:50 2011 UTC ()
my compiles-but-un-runtime-tested port of uhci to usbmp branch.
based upon the ohci and ehci changes.


(mrg)
diff -r1.240.6.1 -r1.240.6.2 src/sys/dev/usb/uhci.c
diff -r1.48 -r1.48.12.1 src/sys/dev/usb/uhcivar.h

cvs diff -r1.240.6.1 -r1.240.6.2 src/sys/dev/usb/uhci.c (expand / switch to context diff)
--- src/sys/dev/usb/uhci.c 2011/12/04 13:23:17 1.240.6.1
+++ src/sys/dev/usb/uhci.c 2011/12/06 05:06:50 1.240.6.2
@@ -1,13 +1,14 @@
-/*	$NetBSD: uhci.c,v 1.240.6.1 2011/12/04 13:23:17 jmcneill Exp $	*/
+/*	$NetBSD: uhci.c,v 1.240.6.2 2011/12/06 05:06:50 mrg Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $	*/
 
 /*
- * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2004, 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
  * by Lennart Augustsson (lennart@augustsson.net) at
- * Carlstedt Research & Technology.
+ * Carlstedt Research & Technology, Jared D. McNeill (jmcneill@invisible.ca)
+ * and Matthew R. Green.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -42,14 +43,14 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.240.6.1 2011/12/04 13:23:17 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.240.6.2 2011/12/06 05:06:50 mrg Exp $");
 
 #include "opt_usb.h"
 
 #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/extent.h>
@@ -171,6 +172,8 @@
 
 Static usbd_xfer_handle	uhci_allocx(struct usbd_bus *);
 Static void		uhci_freex(struct usbd_bus *, usbd_xfer_handle);
+Static void		uhci_get_locks(struct usbd_bus *, kmutex_t **,
+				       kmutex_t **);
 
 Static usbd_status	uhci_device_ctrl_transfer(usbd_xfer_handle);
 Static usbd_status	uhci_device_ctrl_start(usbd_xfer_handle);
@@ -288,7 +291,7 @@
 	uhci_freem,
 	uhci_allocx,
 	uhci_freex,
-	NULL, /* uhci_get_locks */
+	uhci_get_locks,
 };
 
 const struct usbd_pipe_methods uhci_root_ctrl_methods = {
@@ -523,8 +526,12 @@
 
 	SIMPLEQ_INIT(&sc->sc_free_xfers);
 
-	callout_init(&sc->sc_poll_handle, 0);
+	callout_init(&sc->sc_poll_handle, CALLOUT_MPSAFE);
 
+	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, "uhciab");
+
 	/* Set up the bus struct. */
 	sc->sc_bus.methods = &uhci_bus_methods;
 	sc->sc_bus.pipe_size = sizeof(struct uhci_pipe);
@@ -580,12 +587,17 @@
 		if (xfer == NULL)
 			break;
 		SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
-		free(xfer, M_USB);
+		kmem_free(xfer, sizeof(struct uhci_xfer));
 	}
 
 	callout_halt(&sc->sc_poll_handle, NULL);
 	callout_destroy(&sc->sc_poll_handle);
 
+	cv_destroy(&sc->sc_softwake_cv);
+
+	mutex_destroy(&sc->sc_lock);
+	mutex_destroy(&sc->sc_intr_lock);
+
 	/* XXX free other data structures XXX */
 
 	return (rv);
@@ -609,18 +621,19 @@
 	if (n > 16) {
 		u_int32_t i;
 		uhci_soft_td_t **stds;
+
 		DPRINTF(("uhci_allocm: get %d TDs\n", n));
-		stds = malloc(sizeof(uhci_soft_td_t *) * n, M_TEMP,
-		    M_WAITOK|M_ZERO);
-		for(i=0; i < n; i++)
+		stds = kmem_alloc(sizeof(uhci_soft_td_t *) * n, KM_SLEEP);
+		if (!stds)
+			return USBD_NOMEM;
+		for(i = 0; i < n; i++)
 			stds[i] = uhci_alloc_std(sc);
-		for(i=0; i < n; i++)
+		for(i = 0; i < n; i++)
 			if (stds[i] != NULL)
 				uhci_free_std(sc, stds[i]);
-		free(stds, M_TEMP);
+		kmem_free(stds, sizeof(uhci_soft_td_t *) * n);
 	}
 
-
 	status = usb_allocmem(&sc->sc_bus, size, 0, dma);
 	if (status == USBD_NOMEM)
 		status = usb_reserve_allocm(&sc->sc_dma_reserve, dma, size);
@@ -654,7 +667,7 @@
 		}
 #endif
 	} else {
-		xfer = malloc(sizeof(struct uhci_xfer), M_USB, M_NOWAIT);
+		xfer = kmem_alloc(sizeof(struct uhci_xfer), KM_SLEEP);
 	}
 	if (xfer != NULL) {
 		memset(xfer, 0, sizeof (struct uhci_xfer));
@@ -685,6 +698,16 @@
 	SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
 }
 
+Static void
+uhci_get_locks(struct usbd_bus *bus, kmutex_t **intr, kmutex_t **thread)
+{
+	struct uhci_softc *sc = bus->hci_private;
+
+	*intr = &sc->sc_intr_lock;
+	*thread = &sc->sc_lock;
+}
+
+
 /*
  * Handle suspend/resume.
  *
@@ -697,9 +720,8 @@
 {
 	uhci_softc_t *sc = device_private(dv);
 	int cmd;
-	int s;
 
-	s = splhardusb();
+	mutex_spin_enter(&sc->sc_intr_lock);
 
 	cmd = UREAD2(sc, UHCI_CMD);
 	sc->sc_bus.use_polling++;
@@ -732,7 +754,7 @@
 #endif
 
 	sc->sc_suspend = PWR_RESUME;
-	splx(s);
+	mutex_spin_exit(&sc->sc_intr_lock);
 
 	return true;
 }
@@ -742,9 +764,8 @@
 {
 	uhci_softc_t *sc = device_private(dv);
 	int cmd;
-	int s;
 
-	s = splhardusb();
+	mutex_spin_enter(&sc->sc_intr_lock);
 
 	cmd = UREAD2(sc, UHCI_CMD);
 
@@ -770,7 +791,7 @@
 	usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
 	sc->sc_bus.use_polling--;
 
-	splx(s);
+	mutex_spin_exit(&sc->sc_intr_lock);
 
 	return true;
 }
@@ -992,7 +1013,6 @@
 	usbd_xfer_handle xfer = addr;
 	usbd_pipe_handle pipe = xfer->pipe;
 	uhci_softc_t *sc;
-	int s;
 	u_char *p;
 
 	DPRINTFN(20, ("uhci_poll_hub\n"));
@@ -1014,11 +1034,11 @@
 
 	xfer->actlen = 1;
 	xfer->status = USBD_NORMAL_COMPLETION;
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 	xfer->device->bus->intr_context++;
 	usb_transfer_complete(xfer);
 	xfer->device->bus->intr_context--;
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 }
 
 void
@@ -1269,18 +1289,25 @@
 uhci_intr(void *arg)
 {
 	uhci_softc_t *sc = arg;
+	int ret = 0;
 
+	mutex_spin_enter(&sc->sc_intr_lock);
+
 	if (sc->sc_dying || !device_has_power(sc->sc_dev))
-		return (0);
+		goto done;
 
 	if (sc->sc_bus.use_polling || UREAD2(sc, UHCI_INTR) == 0) {
 #ifdef DIAGNOSTIC
 		DPRINTFN(16, ("uhci_intr: ignored interrupt while polling\n"));
 #endif
-		return (0);
+		goto done;
 	}
 
-	return (uhci_intr1(sc));
+	ret = uhci_intr1(sc);
+
+ done:
+	mutex_spin_exit(&sc->sc_intr_lock);
+	return ret;
 }
 
 int
@@ -1296,6 +1323,8 @@
 	}
 #endif
 
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	status = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS;
 	if (status == 0)	/* The interrupt was not for us. */
 		return (0);
@@ -1365,6 +1394,8 @@
 	DPRINTFN(10,("%s: uhci_softintr (%d)\n", device_xname(sc->sc_dev),
 		     sc->sc_bus.intr_context));
 
+	mutex_enter(&sc->sc_lock);
+
 	sc->sc_bus.intr_context++;
 
 	/*
@@ -1383,14 +1414,14 @@
 		uhci_check_intr(sc, ii);
 	}
 
-#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. */
@@ -1485,6 +1516,7 @@
 	DPRINTFN(12, ("uhci_idone: ii=%p\n", ii));
 #ifdef DIAGNOSTIC
 	{
+		/* XXX SMP? */
 		int s = splhigh();
 		if (ii->isdone) {
 			splx(s);
@@ -1631,13 +1663,10 @@
 uhci_timeout_task(void *addr)
 {
 	usbd_xfer_handle xfer = addr;
-	int s;
 
 	DPRINTF(("uhci_timeout_task: xfer=%p\n", xfer));
 
-	s = splusb();
 	uhci_abort_xfer(xfer, USBD_TIMEOUT);
-	splx(s);
 }
 
 /*
@@ -1652,6 +1681,8 @@
 	int timo = xfer->timeout;
 	uhci_intr_info_t *ii;
 
+	mutex_enter(&sc->sc_lock);
+
 	DPRINTFN(10,("uhci_waitintr: timeout = %dms\n", timo));
 
 	xfer->status = USBD_IN_PROGRESS;
@@ -1659,9 +1690,11 @@
 		usb_delay_ms(&sc->sc_bus, 1);
 		DPRINTFN(20,("uhci_waitintr: 0x%04x\n", UREAD2(sc, UHCI_STS)));
 		if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT) {
+			mutex_spin_enter(&sc->sc_intr_lock);
 			uhci_intr1(sc);
+			mutex_spin_exit(&sc->sc_intr_lock);
 			if (xfer->status != USBD_IN_PROGRESS)
-				return;
+				goto done;
 		}
 	}
 
@@ -1676,6 +1709,9 @@
 		panic("uhci_waitintr: lost intr_info");
 #endif
 	uhci_idone(ii);
+
+done:
+	mutex_exit(&sc->sc_lock);
 }
 
 void
@@ -1683,8 +1719,11 @@
 {
 	uhci_softc_t *sc = bus->hci_private;
 
-	if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT)
+	if (UREAD2(sc, UHCI_STS) & UHCI_STS_USBINT) {
+		mutex_spin_enter(&sc->sc_intr_lock);
 		uhci_intr1(sc);
+		mutex_spin_exit(&sc->sc_intr_lock);
+	}
 }
 
 void
@@ -1705,11 +1744,11 @@
 usbd_status
 uhci_run(uhci_softc_t *sc, int run)
 {
-	int s, n, running;
+	int n, running;
 	u_int16_t cmd;
 
 	run = run != 0;
-	s = splhardusb();
+	mutex_spin_enter(&sc->sc_intr_lock);
 	DPRINTF(("uhci_run: setting run=%d\n", run));
 	cmd = UREAD2(sc, UHCI_CMD);
 	if (run)
@@ -1721,14 +1760,14 @@
 		running = !(UREAD2(sc, UHCI_STS) & UHCI_STS_HCH);
 		/* return when we've entered the state we want */
 		if (run == running) {
-			splx(s);
+			mutex_spin_exit(&sc->sc_intr_lock);
 			DPRINTF(("uhci_run: done cmd=0x%x sts=0x%x\n",
 				 UREAD2(sc, UHCI_CMD), UREAD2(sc, UHCI_STS)));
 			return (USBD_NORMAL_COMPLETION);
 		}
 		usb_delay_ms(&sc->sc_bus, 1);
 	}
-	splx(s);
+	mutex_spin_exit(&sc->sc_intr_lock);
 	printf("%s: cannot %s\n", device_xname(sc->sc_dev),
 	       run ? "start" : "stop");
 	return (USBD_IOERROR);
@@ -1758,7 +1797,7 @@
 			  UHCI_TD_ALIGN, &dma);
 		if (err)
 			return (0);
-		for(i = 0; i < UHCI_STD_CHUNK; i++) {
+		for (i = 0; i < UHCI_STD_CHUNK; i++) {
 			offs = i * UHCI_STD_SIZE;
 			std = KERNADDR(&dma, offs);
 			std->physaddr = DMAADDR(&dma, offs);
@@ -1873,6 +1912,9 @@
 	DPRINTFN(8, ("uhci_alloc_std_chain: addr=%d endpt=%d len=%d speed=%d "
 		      "flags=0x%x\n", addr, UE_GET_ADDR(endpt), len,
 		      upipe->pipe.device->speed, flags));
+
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	maxp = UGETW(upipe->pipe.endpoint->edesc->wMaxPacketSize);
 	if (maxp == 0) {
 		printf("uhci_alloc_std_chain: maxp=0\n");
@@ -1950,10 +1992,13 @@
 usbd_status
 uhci_device_bulk_transfer(usbd_xfer_handle xfer)
 {
+	uhci_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);
 
@@ -1975,7 +2020,6 @@
 	uhci_soft_qh_t *sqh;
 	usbd_status err;
 	int len, isread, endpt;
-	int s;
 
 	DPRINTFN(3, ("uhci_device_bulk_start: xfer=%p len=%d flags=%d ii=%p\n",
 		     xfer, xfer->length, xfer->flags, ii));
@@ -1988,6 +2032,8 @@
 		panic("uhci_device_bulk_transfer: a request");
 #endif
 
+	mutex_enter(&sc->sc_lock);
+
 	len = xfer->length;
 	endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
 	isread = UE_GET_DIR(endpt) == UE_DIR_IN;
@@ -1998,8 +2044,10 @@
 
 	err = uhci_alloc_std_chain(upipe, sc, len, isread, xfer->flags,
 				   &xfer->dmabuf, &data, &dataend);
-	if (err)
+	if (err) {
+		mutex_exit(&sc->sc_lock);
 		return (err);
+	}
 	dataend->td.td_status |= htole32(UHCI_TD_IOC);
 	usb_syncmem(&dataend->dma,
 	    dataend->offs + offsetof(uhci_td_t, td_status),
@@ -2029,7 +2077,6 @@
 	sqh->qh.qh_elink = htole32(data->physaddr | UHCI_PTR_TD);
 	/* uhci_add_bulk() will do usb_syncmem(sqh) */
 
-	s = splusb();
 	uhci_add_bulk(sc, sqh);
 	uhci_add_intr_info(sc, ii);
 
@@ -2038,7 +2085,6 @@
 			    uhci_timeout, ii);
 	}
 	xfer->status = USBD_IN_PROGRESS;
-	splx(s);
 
 #ifdef UHCI_DEBUG
 	if (uhcidebug > 10) {
@@ -2050,6 +2096,7 @@
 	if (sc->sc_bus.use_polling)
 		uhci_waitintr(sc, xfer);
 
+	mutex_exit(&sc->sc_lock);
 	return (USBD_IN_PROGRESS);
 }
 
@@ -2078,24 +2125,25 @@
 	struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
 	uhci_softc_t *sc = upipe->pipe.device->bus->hci_private;
 	uhci_soft_td_t *std;
-	int s;
 	int wake;
 
 	DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status));
 
 	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 || !curproc)
 		panic("uhci_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.
@@ -2111,15 +2159,14 @@
 		DPRINTFN(2, ("uhci_abort_xfer: waiting for abort to finish\n"));
 		xfer->hcflags |= UXFER_ABORTWAIT;
 		while (xfer->hcflags & UXFER_ABORTING)
-			tsleep(&xfer->hcflags, PZERO, "uhciaw", 0);
-		return;
+			cv_wait(&xfer->hccv, &sc->sc_lock);
+		goto done;
 	}
 	xfer->hcflags |= UXFER_ABORTING;
 
 	/*
 	 * Step 1: Make interrupt routine and hardware ignore xfer.
 	 */
-	s = splusb();
 	xfer->status = status;	/* make software ignore it */
 	callout_stop(&xfer->timeout_handle);
 	DPRINTFN(1,("uhci_abort_xfer: stop ii=%p\n", ii));
@@ -2134,7 +2181,6 @@
 		    sizeof(std->td.td_status),
 		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 	}
-	splx(s);
 
 	/*
 	 * Step 2: Wait until we know hardware has finished any possible
@@ -2142,22 +2188,15 @@
 	 * has run.
 	 */
 	usb_delay_ms(upipe->pipe.device->bus, 2); /* Hardware finishes in 1ms */
-	s = splusb();
-#ifdef USB_USE_SOFTINTR
 	sc->sc_softwake = 1;
-#endif /* USB_USE_SOFTINTR */
 	usb_schedsoftintr(&sc->sc_bus);
-#ifdef USB_USE_SOFTINTR
-	DPRINTFN(1,("uhci_abort_xfer: tsleep\n"));
-	tsleep(&sc->sc_softwake, PZERO, "uhciab", 0);
-#endif /* USB_USE_SOFTINTR */
-	splx(s);
+	DPRINTFN(1,("uhci_abort_xfer: cv_wait\n"));
+	cv_wait(&sc->sc_softwake_cv, &sc->sc_lock);
 
 	/*
 	 * Step 3: Execute callback.
 	 */
 	DPRINTFN(1,("uhci_abort_xfer: callback\n"));
-	s = splusb();
 #ifdef DIAGNOSTIC
 	ii->isdone = 1;
 #endif
@@ -2165,8 +2204,9 @@
 	xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
 	usb_transfer_complete(xfer);
 	if (wake)
-		wakeup(&xfer->hcflags);
-	splx(s);
+		cv_broadcast(&xfer->hccv);
+done:
+	mutex_exit(&sc->sc_lock);
 }
 
 /* Close a device bulk pipe. */
@@ -2185,10 +2225,13 @@
 usbd_status
 uhci_device_ctrl_transfer(usbd_xfer_handle xfer)
 {
+	uhci_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);
 
@@ -2213,7 +2256,9 @@
 		panic("uhci_device_ctrl_transfer: not a request");
 #endif
 
+	mutex_enter(&sc->sc_lock);
 	err = uhci_device_request(xfer);
+	mutex_exit(&sc->sc_lock);
 	if (err)
 		return (err);
 
@@ -2225,10 +2270,13 @@
 usbd_status
 uhci_device_intr_transfer(usbd_xfer_handle xfer)
 {
+	uhci_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);
 
@@ -2250,7 +2298,7 @@
 	uhci_soft_qh_t *sqh;
 	usbd_status err;
 	int isread, endpt;
-	int i, s;
+	int i;
 
 	if (sc->sc_dying)
 		return (USBD_IOERROR);
@@ -2287,7 +2335,7 @@
 	}
 #endif
 
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 	/* Set up interrupt info. */
 	ii->xfer = xfer;
 	ii->stdstart = data;
@@ -2312,7 +2360,7 @@
 	}
 	uhci_add_intr_info(sc, ii);
 	xfer->status = USBD_IN_PROGRESS;
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 
 #ifdef UHCI_DEBUG
 	if (uhcidebug > 10) {
@@ -2358,14 +2406,13 @@
 	struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
 	uhci_softc_t *sc = pipe->device->bus->hci_private;
 	int i, npoll;
-	int s;
 
 	/* Unlink descriptors from controller data structures. */
 	npoll = upipe->u.intr.npoll;
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 	for (i = 0; i < npoll; i++)
 		uhci_remove_intr(sc, upipe->u.intr.qhs[i]);
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 
 	/*
 	 * We now have to wait for any activity on the physical
@@ -2375,7 +2422,7 @@
 
 	for(i = 0; i < npoll; i++)
 		uhci_free_sqh(sc, upipe->u.intr.qhs[i]);
-	free(upipe->u.intr.qhs, M_USBHC);
+	kmem_free(upipe->u.intr.qhs, npoll * sizeof(uhci_soft_qh_t *));
 
 	/* XXX free other resources */
 }
@@ -2396,8 +2443,9 @@
 	u_int32_t ls;
 	usbd_status err;
 	int isread;
-	int s;
 
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	DPRINTFN(3,("uhci_device_control type=0x%02x, request=0x%02x, "
 		    "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n",
 		    req->bmRequestType, req->bRequest, UGETW(req->wValue),
@@ -2476,7 +2524,7 @@
 	sqh->qh.qh_elink = htole32(setup->physaddr | UHCI_PTR_TD);
 	/* uhci_add_?s_ctrl() will do usb_syncmem(sqh) */
 
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 	if (dev->speed == USB_SPEED_LOW)
 		uhci_add_ls_ctrl(sc, sqh);
 	else
@@ -2514,7 +2562,7 @@
 			    uhci_timeout, ii);
 	}
 	xfer->status = USBD_IN_PROGRESS;
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 
 	return (USBD_NORMAL_COMPLETION);
 }
@@ -2522,12 +2570,15 @@
 usbd_status
 uhci_device_isoc_transfer(usbd_xfer_handle xfer)
 {
+	uhci_softc_t *sc = xfer->pipe->device->bus->hci_private;
 	usbd_status err;
 
 	DPRINTFN(5,("uhci_device_isoc_transfer: xfer=%p\n", xfer));
 
 	/* Put it on our queue, */
+	mutex_enter(&sc->sc_lock);
 	err = usb_insert_transfer(xfer);
+	mutex_exit(&sc->sc_lock);
 
 	/* bail out on error, */
 	if (err && err != USBD_IN_PROGRESS)
@@ -2554,7 +2605,7 @@
 	struct iso *iso = &upipe->u.iso;
 	uhci_soft_td_t *std;
 	u_int32_t buf, len, status, offs;
-	int s, i, next, nframes;
+	int i, next, nframes;
 	int rd = UE_GET_DIR(upipe->pipe.endpoint->edesc->bEndpointAddress) == UE_DIR_IN;
 
 	DPRINTFN(5,("uhci_device_isoc_enter: used=%d next=%d xfer=%p "
@@ -2591,7 +2642,7 @@
 				     UHCI_TD_ACTIVE |
 				     UHCI_TD_IOS);
 	nframes = xfer->nframes;
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 	for (i = 0; i < nframes; i++) {
 		std = iso->stds[next];
 		if (++next >= UHCI_VFRAMELIST_COUNT)
@@ -2619,7 +2670,7 @@
 	iso->next = next;
 	iso->inuse += xfer->nframes;
 
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 }
 
 usbd_status
@@ -2629,12 +2680,16 @@
 	uhci_softc_t *sc = upipe->pipe.device->bus->hci_private;
 	uhci_intr_info_t *ii = &UXFER(xfer)->iinfo;
 	uhci_soft_td_t *end;
-	int s, i;
+	int i;
 
 	DPRINTFN(5,("uhci_device_isoc_start: xfer=%p\n", xfer));
 
-	if (sc->sc_dying)
+	mutex_enter(&sc->sc_lock);
+
+	if (sc->sc_dying) {
+		mutex_exit(&sc->sc_lock);
 		return (USBD_IOERROR);
+	}
 
 #ifdef DIAGNOSTIC
 	if (xfer->status != USBD_IN_PROGRESS)
@@ -2654,8 +2709,6 @@
 	}
 #endif
 
-	s = splusb();
-
 	/* Set up interrupt info. */
 	ii->xfer = xfer;
 	ii->stdstart = end;
@@ -2667,7 +2720,7 @@
 #endif
 	uhci_add_intr_info(sc, ii);
 
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 
 	return (USBD_IN_PROGRESS);
 }
@@ -2675,17 +2728,18 @@
 void
 uhci_device_isoc_abort(usbd_xfer_handle xfer)
 {
+	uhci_softc_t *sc = xfer->pipe->device->bus->hci_private;
 	struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe;
 	uhci_soft_td_t **stds = upipe->u.iso.stds;
 	uhci_soft_td_t *std;
-	int i, n, s, nframes, maxlen, len;
+	int i, n, nframes, maxlen, len;
 
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 
 	/* Transfer is already done. */
 	if (xfer->status != USBD_NOT_STARTED &&
 	    xfer->status != USBD_IN_PROGRESS) {
-		splx(s);
+		mutex_exit(&sc->sc_lock);
 		return;
 	}
 
@@ -2727,7 +2781,7 @@
 	/* Run callback and remove from interrupt list. */
 	usb_transfer_complete(xfer);
 
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 }
 
 void
@@ -2738,7 +2792,7 @@
 	uhci_softc_t *sc = dev->bus->hci_private;
 	uhci_soft_td_t *std, *vstd;
 	struct iso *iso;
-	int i, s;
+	int i;
 
 	/*
 	 * Make sure all TDs are marked as inactive.
@@ -2748,6 +2802,7 @@
 	 */
 	iso = &upipe->u.iso;
 
+	mutex_enter(&sc->sc_lock);
 	for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
 		std = iso->stds[i];
 		usb_syncmem(&std->dma,
@@ -2762,7 +2817,6 @@
 	}
 	usb_delay_ms(&sc->sc_bus, 2); /* wait for completion */
 
-	s = splusb();
 	for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
 		std = iso->stds[i];
 		for (vstd = sc->sc_vframes[i].htd;
@@ -2772,7 +2826,7 @@
 		if (vstd == NULL) {
 			/*panic*/
 			printf("uhci_device_isoc_close: %p not found\n", std);
-			splx(s);
+			mutex_exit(&sc->sc_lock);
 			return;
 		}
 		vstd->link = std->link;
@@ -2787,9 +2841,9 @@
 		    BUS_DMASYNC_PREWRITE);
 		uhci_free_std(sc, std);
 	}
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 
-	free(iso->stds, M_USBHC);
+	kmem_free(iso->stds, UHCI_VFRAMELIST_COUNT * sizeof (uhci_soft_td_t *));
 }
 
 usbd_status
@@ -2804,15 +2858,20 @@
 	uhci_soft_td_t *std, *vstd;
 	u_int32_t token;
 	struct iso *iso;
-	int i, s;
+	int i;
 
 	iso = &upipe->u.iso;
-	iso->stds = malloc(UHCI_VFRAMELIST_COUNT * sizeof (uhci_soft_td_t *),
-			   M_USBHC, M_WAITOK);
+	iso->stds = kmem_alloc(UHCI_VFRAMELIST_COUNT *
+				 sizeof (uhci_soft_td_t *),
+			       KM_SLEEP);
+	if (iso->stds == NULL)
+		return USBD_NOMEM;
 
 	token = rd ? UHCI_TD_IN (0, endpt, addr, 0) :
 		     UHCI_TD_OUT(0, endpt, addr, 0);
 
+	mutex_enter(&sc->sc_lock);
+
 	/* Allocate the TDs and mark as inactive; */
 	for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
 		std = uhci_alloc_std(sc);
@@ -2826,7 +2885,6 @@
 	}
 
 	/* Insert TDs into schedule. */
-	s = splusb();
 	for (i = 0; i < UHCI_VFRAMELIST_COUNT; i++) {
 		std = iso->stds[i];
 		vstd = sc->sc_vframes[i].htd;
@@ -2847,7 +2905,7 @@
 		    sizeof(vstd->td.td_link),
 		    BUS_DMASYNC_PREWRITE);
 	}
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 
 	iso->next = -1;
 	iso->inuse = 0;
@@ -2857,7 +2915,8 @@
  bad:
 	while (--i >= 0)
 		uhci_free_std(sc, iso->stds[i]);
-	free(iso->stds, M_USBHC);
+	mutex_exit(&sc->sc_lock);
+	kmem_free(iso->stds, UHCI_VFRAMELIST_COUNT * sizeof (uhci_soft_td_t *));
 	return (USBD_NOMEM);
 }
 
@@ -2922,6 +2981,8 @@
 
 	DPRINTFN(5, ("uhci_device_intr_done: length=%d\n", xfer->actlen));
 
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	npoll = upipe->u.intr.npoll;
 	for(i = 0; i < npoll; i++) {
 		sqh = upipe->u.intr.qhs[i];
@@ -2998,6 +3059,8 @@
 	int len = UGETW(xfer->request.wLength);
 	int isread = (xfer->request.bmRequestType & UT_READ);
 
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 #ifdef DIAGNOSTIC
 	if (!(xfer->rqflags & URQ_REQUEST))
 		panic("uhci_device_ctrl_done: not a request");
@@ -3037,6 +3100,8 @@
 	DPRINTFN(5,("uhci_device_bulk_done: xfer=%p ii=%p sc=%p upipe=%p\n",
 		    xfer, ii, sc, upipe));
 
+	KASSERT(mutex_owned(&sc->sc_lock));
+
 	if (!uhci_active_intr_info(ii))
 		return;
 
@@ -3118,7 +3183,7 @@
 uhci_device_setintr(uhci_softc_t *sc, struct uhci_pipe *upipe, int ival)
 {
 	uhci_soft_qh_t *sqh;
-	int i, npoll, s;
+	int i, npoll;
 	u_int bestbw, bw, bestoffs, offs;
 
 	DPRINTFN(2, ("uhci_device_setintr: pipe=%p\n", upipe));
@@ -3134,7 +3199,9 @@
 
 	upipe->u.intr.npoll = npoll;
 	upipe->u.intr.qhs =
-		malloc(npoll * sizeof(uhci_soft_qh_t *), M_USBHC, M_WAITOK);
+		kmem_alloc(npoll * sizeof(uhci_soft_qh_t *), KM_SLEEP);
+	if (upipe->u.intr.qhs == NULL)
+		return USBD_NOMEM;
 
 	/*
 	 * Figure out which offset in the schedule that has most
@@ -3151,6 +3218,7 @@
 	}
 	DPRINTFN(1, ("uhci_device_setintr: bw=%d offs=%d\n", bestbw, bestoffs));
 
+	mutex_enter(&sc->sc_lock);
 	for(i = 0; i < npoll; i++) {
 		upipe->u.intr.qhs[i] = sqh = uhci_alloc_sqh(sc);
 		sqh->elink = NULL;
@@ -3163,11 +3231,10 @@
 	}
 #undef MOD
 
-	s = splusb();
 	/* Enter QHs into the controller data structures. */
 	for(i = 0; i < npoll; i++)
 		uhci_add_intr(sc, upipe->u.intr.qhs[i]);
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 
 	DPRINTFN(5, ("uhci_device_setintr: returns %p\n", upipe));
 	return (USBD_NORMAL_COMPLETION);
@@ -3180,13 +3247,16 @@
 	uhci_softc_t *sc = pipe->device->bus->hci_private;
 	struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
 	usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
-	usbd_status err;
+	usbd_status err = USBD_NOMEM;
 	int ival;
 
 	DPRINTFN(1, ("uhci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
 		     pipe, pipe->device->address,
 		     ed->bEndpointAddress, sc->sc_addr));
 
+	if (sc->sc_dying)
+		return USBD_IOERROR;
+
 	upipe->aborting = 0;
 	/* toggle state needed for bulk endpoints */
 	upipe->nexttoggle = pipe->endpoint->datatoggle;
@@ -3250,7 +3320,7 @@
 	return (USBD_NORMAL_COMPLETION);
 
  bad:
-	return (USBD_NOMEM);
+	return USBD_NOMEM;
 }
 
 /*
@@ -3415,10 +3485,13 @@
 usbd_status
 uhci_root_ctrl_transfer(usbd_xfer_handle xfer)
 {
+	uhci_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);
 
@@ -3436,7 +3509,7 @@
 	usb_device_request_t *req;
 	void *buf = NULL;
 	int port, x;
-	int s, len, value, index, status, change, l, totlen = 0;
+	int len, value, index, status, change, l, totlen = 0;
 	usb_port_status_t ps;
 	usbd_status err;
 
@@ -3759,9 +3832,9 @@
 	err = USBD_NORMAL_COMPLETION;
  ret:
 	xfer->status = err;
-	s = splusb();
+	mutex_enter(&sc->sc_lock);
 	usb_transfer_complete(xfer);
-	splx(s);
+	mutex_exit(&sc->sc_lock);
 	return (USBD_IN_PROGRESS);
 }
 
@@ -3802,10 +3875,13 @@
 usbd_status
 uhci_root_intr_transfer(usbd_xfer_handle xfer)
 {
+	uhci_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);
 

cvs diff -r1.48 -r1.48.12.1 src/sys/dev/usb/uhcivar.h (expand / switch to context diff)
--- src/sys/dev/usb/uhcivar.h 2010/11/03 22:34:23 1.48
+++ src/sys/dev/usb/uhcivar.h 2011/12/06 05:06:50 1.48.12.1
@@ -1,4 +1,4 @@
-/*	$NetBSD: uhcivar.h,v 1.48 2010/11/03 22:34:23 dyoung Exp $	*/
+/*	$NetBSD: uhcivar.h,v 1.48.12.1 2011/12/06 05:06:50 mrg Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/uhcivar.h,v 1.14 1999/11/17 22:33:42 n_hibma Exp $	*/
 
 /*
@@ -132,6 +132,10 @@
 	bus_space_tag_t iot;
 	bus_space_handle_t ioh;
 	bus_size_t sc_size;
+
+	kmutex_t sc_lock;
+	kmutex_t sc_intr_lock;
+	kcondvar_t sc_softwake_cv;
 
 	uhci_physaddr_t *sc_pframes;
 	usb_dma_t sc_dma;