@@ -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);