Module Name: src
Committed By: jmcneill
Date: Sun Dec 4 21:02:27 UTC 2011
Modified Files:
src/sys/dev/usb [jmcneill-usbmp]: ohci.c ohcivar.h
Log Message:
adapt ohci, from mrg with some changes by me
To generate a diff of this commit:
cvs rdiff -u -r1.218.6.1 -r1.218.6.2 src/sys/dev/usb/ohci.c
cvs rdiff -u -r1.51 -r1.51.8.1 src/sys/dev/usb/ohcivar.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/usb/ohci.c
diff -u src/sys/dev/usb/ohci.c:1.218.6.1 src/sys/dev/usb/ohci.c:1.218.6.2
--- src/sys/dev/usb/ohci.c:1.218.6.1 Sun Dec 4 13:23:16 2011
+++ src/sys/dev/usb/ohci.c Sun Dec 4 21:02:27 2011
@@ -1,13 +1,14 @@
-/* $NetBSD: ohci.c,v 1.218.6.1 2011/12/04 13:23:16 jmcneill Exp $ */
+/* $NetBSD: ohci.c,v 1.218.6.2 2011/12/04 21:02:27 jmcneill Exp $ */
/* $FreeBSD: src/sys/dev/usb/ohci.c,v 1.22 1999/11/17 22:33:40 n_hibma Exp $ */
/*
- * Copyright (c) 1998, 2004, 2005 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2004, 2005, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson ([email protected]) at
- * Carlstedt Research & Technology.
+ * Carlstedt Research & Technology, Jared D. McNeill ([email protected])
+ * and Matthew R. Green.
* This code is derived from software contributed to The NetBSD Foundation
* by Charles M. Hannum.
*
@@ -41,13 +42,13 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.218.6.1 2011/12/04 13:23:16 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.218.6.2 2011/12/04 21:02:27 jmcneill Exp $");
#include "opt_usb.h"
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/select.h>
@@ -113,6 +114,7 @@ Static void ohci_poll(struct usbd_bus *
Static void ohci_softintr(void *);
Static void ohci_waitintr(ohci_softc_t *, usbd_xfer_handle);
Static void ohci_rhsc(ohci_softc_t *, usbd_xfer_handle);
+Static void ohci_rhsc_softint(void *arg);
Static usbd_status ohci_device_request(usbd_xfer_handle xfer);
Static void ohci_add_ed(ohci_softc_t *, ohci_soft_ed_t *,
@@ -134,6 +136,8 @@ Static void ohci_freem(struct usbd_bus
Static usbd_xfer_handle ohci_allocx(struct usbd_bus *);
Static void ohci_freex(struct usbd_bus *, usbd_xfer_handle);
+Static void ohci_get_locks(struct usbd_bus *, kmutex_t **,
+ kmutex_t **);
Static usbd_status ohci_root_ctrl_transfer(usbd_xfer_handle);
Static usbd_status ohci_root_ctrl_start(usbd_xfer_handle);
@@ -274,7 +278,7 @@ Static const struct usbd_bus_methods ohc
ohci_freem,
ohci_allocx,
ohci_freex,
- NULL, /* ohci_get_locks */
+ ohci_get_locks,
};
Static const struct usbd_pipe_methods ohci_root_ctrl_methods = {
@@ -371,11 +375,18 @@ ohci_detach(struct ohci_softc *sc, int f
usb_delay_ms(&sc->sc_bus, 300); /* XXX let stray task complete */
callout_destroy(&sc->sc_tmo_rhsc);
+ softint_disestablish(sc->sc_rhsc_si);
+
+ cv_destroy(&sc->sc_softwake_cv);
+
+ mutex_destroy(&sc->sc_lock);
+ mutex_destroy(&sc->sc_intr_lock);
+
if (sc->sc_hcca != NULL)
usb_freemem(&sc->sc_bus, &sc->sc_hccadma);
while((xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers)) != NULL) {
SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
- free(xfer, M_USB);
+ kmem_free(xfer, sizeof(struct ohci_xfer));
}
return (rv);
@@ -426,7 +437,6 @@ ohci_alloc_std(ohci_softc_t *sc)
usbd_status err;
int i, offs;
usb_dma_t dma;
- int s;
if (sc->sc_freetds == NULL) {
DPRINTFN(2, ("ohci_alloc_std: allocating chunk\n"));
@@ -434,7 +444,6 @@ ohci_alloc_std(ohci_softc_t *sc)
OHCI_TD_ALIGN, &dma);
if (err)
return (NULL);
- s = splusb();
for(i = 0; i < OHCI_STD_CHUNK; i++) {
offs = i * OHCI_STD_SIZE;
std = KERNADDR(&dma, offs);
@@ -444,17 +453,14 @@ ohci_alloc_std(ohci_softc_t *sc)
std->nexttd = sc->sc_freetds;
sc->sc_freetds = std;
}
- splx(s);
}
- s = splusb();
std = sc->sc_freetds;
sc->sc_freetds = std->nexttd;
memset(&std->td, 0, sizeof(ohci_td_t));
std->nexttd = NULL;
std->xfer = NULL;
ohci_hash_add_td(sc, std);
- splx(s);
return (std);
}
@@ -462,13 +468,10 @@ ohci_alloc_std(ohci_softc_t *sc)
void
ohci_free_std(ohci_softc_t *sc, ohci_soft_td_t *std)
{
- int s;
- s = splusb();
ohci_hash_rem_td(sc, std);
std->nexttd = sc->sc_freetds;
sc->sc_freetds = std;
- splx(s);
}
usbd_status
@@ -485,6 +488,8 @@ ohci_alloc_std_chain(struct ohci_pipe *o
DPRINTFN(alen < 4096,("ohci_alloc_std_chain: start len=%d\n", alen));
+ KASSERT(mutex_owned(&sc->sc_lock));
+
len = alen;
cur = sp;
dataphys = DMAADDR(dma, 0);
@@ -590,7 +595,7 @@ ohci_alloc_sitd(ohci_softc_t *sc)
{
ohci_soft_itd_t *sitd;
usbd_status err;
- int i, s, offs;
+ int i, offs;
usb_dma_t dma;
if (sc->sc_freeitds == NULL) {
@@ -599,7 +604,6 @@ ohci_alloc_sitd(ohci_softc_t *sc)
OHCI_ITD_ALIGN, &dma);
if (err)
return (NULL);
- s = splusb();
for(i = 0; i < OHCI_SITD_CHUNK; i++) {
offs = i * OHCI_SITD_SIZE;
sitd = KERNADDR(&dma, offs);
@@ -609,17 +613,14 @@ ohci_alloc_sitd(ohci_softc_t *sc)
sitd->nextitd = sc->sc_freeitds;
sc->sc_freeitds = sitd;
}
- splx(s);
}
- s = splusb();
sitd = sc->sc_freeitds;
sc->sc_freeitds = sitd->nextitd;
memset(&sitd->itd, 0, sizeof(ohci_itd_t));
sitd->nextitd = NULL;
sitd->xfer = NULL;
ohci_hash_add_itd(sc, sitd);
- splx(s);
#ifdef DIAGNOSTIC
sitd->isdone = 0;
@@ -631,7 +632,6 @@ ohci_alloc_sitd(ohci_softc_t *sc)
void
ohci_free_sitd(ohci_softc_t *sc, ohci_soft_itd_t *sitd)
{
- int s;
DPRINTFN(10,("ohci_free_sitd: sitd=%p\n", sitd));
@@ -644,11 +644,9 @@ ohci_free_sitd(ohci_softc_t *sc, ohci_so
sitd->isdone = 0;
#endif
- s = splusb();
ohci_hash_rem_itd(sc, sitd);
sitd->nextitd = sc->sc_freeitds;
sc->sc_freeitds = sitd;
- splx(s);
}
usbd_status
@@ -663,7 +661,14 @@ ohci_init(ohci_softc_t *sc)
aprint_normal_dev(sc->sc_dev, "");
sc->sc_hcca = NULL;
- callout_init(&sc->sc_tmo_rhsc, 0);
+ callout_init(&sc->sc_tmo_rhsc, 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, "ohciab");
+
+ sc->sc_rhsc_si = softint_establish(SOFTINT_NET | SOFTINT_MPSAFE,
+ ohci_rhsc_softint, sc);
for (i = 0; i < OHCI_HASH_SIZE; i++)
LIST_INIT(&sc->sc_hash_tds[i]);
@@ -959,7 +964,7 @@ ohci_allocx(struct usbd_bus *bus)
}
#endif
} else {
- xfer = malloc(sizeof(struct ohci_xfer), M_USB, M_NOWAIT);
+ xfer = kmem_alloc(sizeof(struct ohci_xfer), KM_SLEEP);
}
if (xfer != NULL) {
memset(xfer, 0, sizeof (struct ohci_xfer));
@@ -985,6 +990,15 @@ ohci_freex(struct usbd_bus *bus, usbd_xf
SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
}
+Static void
+ohci_get_locks(struct usbd_bus *bus, kmutex_t **intr, kmutex_t **thread)
+{
+ struct ohci_softc *sc = bus->hci_private;
+
+ *intr = &sc->sc_intr_lock;
+ *thread = &sc->sc_lock;
+}
+
/*
* Shut down the controller when the system is going down.
*/
@@ -1003,10 +1017,11 @@ ohci_resume(device_t dv, const pmf_qual_
{
ohci_softc_t *sc = device_private(dv);
uint32_t ctl;
- int s;
- s = splhardusb();
+ mutex_spin_enter(&sc->sc_intr_lock);
sc->sc_bus.use_polling++;
+ mutex_spin_exit(&sc->sc_intr_lock);
+
/* Some broken BIOSes do not recover these values */
OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0));
OWRITE4(sc, OHCI_CONTROL_HEAD_ED,
@@ -1027,8 +1042,10 @@ ohci_resume(device_t dv, const pmf_qual_
OWRITE4(sc, OHCI_CONTROL, ctl);
usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
sc->sc_control = sc->sc_intre = 0;
+
+ mutex_spin_enter(&sc->sc_intr_lock);
sc->sc_bus.use_polling--;
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
return true;
}
@@ -1038,10 +1055,11 @@ ohci_suspend(device_t dv, const pmf_qual
{
ohci_softc_t *sc = device_private(dv);
uint32_t ctl;
- int s;
- s = splhardusb();
+ mutex_spin_enter(&sc->sc_intr_lock);
sc->sc_bus.use_polling++;
+ mutex_spin_exit(&sc->sc_intr_lock);
+
ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK;
if (sc->sc_control == 0) {
/*
@@ -1055,8 +1073,10 @@ ohci_suspend(device_t dv, const pmf_qual
ctl |= OHCI_HCFS_SUSPEND;
OWRITE4(sc, OHCI_CONTROL, ctl);
usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);
+
+ mutex_spin_enter(&sc->sc_intr_lock);
sc->sc_bus.use_polling--;
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
return true;
}
@@ -1108,10 +1128,16 @@ int
ohci_intr(void *p)
{
ohci_softc_t *sc = p;
+ int ret = 0;
- if (sc == NULL || sc->sc_dying || !device_has_power(sc->sc_dev))
+ 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) {
#ifdef DIAGNOSTIC
@@ -1124,7 +1150,11 @@ ohci_intr(void *p)
return (0);
}
- return (ohci_intr1(sc));
+ ret = ohci_intr1(sc);
+
+done:
+ mutex_spin_exit(&sc->sc_intr_lock);
+ return ret;
}
Static int
@@ -1142,6 +1172,8 @@ ohci_intr1(ohci_softc_t *sc)
return (0);
}
+ KASSERT(mutex_owned(&sc->sc_intr_lock));
+
intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS);
if (!intrs)
return (0);
@@ -1190,9 +1222,7 @@ ohci_intr1(ohci_softc_t *sc)
* We block the interrupt below, and reenable it later from
* a timeout.
*/
- ohci_rhsc(sc, sc->sc_intrxfer);
- /* Do not allow RHSC interrupts > 1 per second */
- callout_reset(&sc->sc_tmo_rhsc, hz, ohci_rhsc_enable, sc);
+ softint_schedule(sc->sc_rhsc_si);
}
sc->sc_bus.intr_context--;
@@ -1212,12 +1242,12 @@ void
ohci_rhsc_enable(void *v_sc)
{
ohci_softc_t *sc = v_sc;
- int s;
- s = splhardusb();
+ DPRINTFN(1, ("%s: %s\n", __func__, device_xname(sc->sc_dev)));
+ mutex_spin_enter(&sc->sc_intr_lock);
sc->sc_eintrs |= OHCI_RHSC;
OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC);
- splx(s);
+ mutex_spin_exit(&sc->sc_intr_lock);
}
#ifdef OHCI_DEBUG
@@ -1250,15 +1280,16 @@ ohci_softintr(void *v)
ohci_soft_td_t *std, *sdone, *stdnext;
usbd_xfer_handle xfer;
struct ohci_pipe *opipe;
- int len, cc, s;
+ int len, cc;
int i, j, actlen, iframes, uedir;
ohci_physaddr_t done;
DPRINTFN(10,("ohci_softintr: enter\n"));
+ mutex_enter(&sc->sc_lock);
+
sc->sc_bus.intr_context++;
- s = splhardusb();
usb_syncmem(&sc->sc_hccadma, offsetof(struct ohci_hcca, hcca_done_head),
sizeof(sc->sc_hcca->hcca_done_head),
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
@@ -1270,7 +1301,6 @@ ohci_softintr(void *v)
OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_WDH);
sc->sc_eintrs |= OHCI_WDH;
OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_WDH);
- splx(s);
/* Reverse the done list. */
for (sdone = NULL, sidone = NULL; done != 0; ) {
@@ -1344,9 +1374,7 @@ ohci_softintr(void *v)
if (cc == OHCI_CC_NO_ERROR) {
if (std->flags & OHCI_CALL_DONE) {
xfer->status = USBD_NORMAL_COMPLETION;
- s = splusb();
usb_transfer_complete(xfer);
- splx(s);
}
ohci_free_std(sc, std);
} else {
@@ -1376,9 +1404,7 @@ ohci_softintr(void *v)
xfer->status = USBD_STALLED;
else
xfer->status = USBD_IOERROR;
- s = splusb();
usb_transfer_complete(xfer);
- splx(s);
}
}
@@ -1452,20 +1478,18 @@ ohci_softintr(void *v)
xfer->actlen = actlen;
xfer->hcpriv = NULL;
- s = splusb();
usb_transfer_complete(xfer);
- splx(s);
}
}
-#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);
+
DPRINTFN(10,("ohci_softintr: done:\n"));
}
@@ -1473,11 +1497,14 @@ void
ohci_device_ctrl_done(usbd_xfer_handle xfer)
{
struct ohci_pipe *opipe = (struct ohci_pipe *)xfer->pipe;
+ ohci_softc_t *sc = xfer->pipe->device->bus->hci_private;
int len = UGETW(xfer->request.wLength);
int isread = (xfer->request.bmRequestType & UT_READ);
DPRINTFN(10,("ohci_device_ctrl_done: xfer=%p\n", xfer));
+ KASSERT(mutex_owned(&sc->sc_lock));
+
#ifdef DIAGNOSTIC
if (!(xfer->rqflags & URQ_REQUEST)) {
panic("ohci_device_ctrl_done: not a request");
@@ -1500,10 +1527,11 @@ ohci_device_intr_done(usbd_xfer_handle x
int isread =
(UE_GET_DIR(xfer->pipe->endpoint->edesc->bEndpointAddress) == UE_DIR_IN);
-
DPRINTFN(10,("ohci_device_intr_done: xfer=%p, actlen=%d\n",
xfer, xfer->actlen));
+ KASSERT(mutex_owned(&sc->sc_lock));
+
usb_syncmem(&xfer->dmabuf, 0, xfer->length,
isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
if (xfer->pipe->repeat) {
@@ -1545,15 +1573,33 @@ ohci_device_intr_done(usbd_xfer_handle x
void
ohci_device_bulk_done(usbd_xfer_handle xfer)
{
+ ohci_softc_t *sc = xfer->pipe->device->bus->hci_private;
int isread =
(UE_GET_DIR(xfer->pipe->endpoint->edesc->bEndpointAddress) == UE_DIR_IN);
+ KASSERT(mutex_owned(&sc->sc_lock));
+
DPRINTFN(10,("ohci_device_bulk_done: xfer=%p, actlen=%d\n",
xfer, xfer->actlen));
usb_syncmem(&xfer->dmabuf, 0, xfer->length,
isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
}
+Static void
+ohci_rhsc_softint(void *arg)
+{
+ ohci_softc_t *sc = arg;
+
+ mutex_enter(&sc->sc_lock);
+
+ ohci_rhsc(sc, sc->sc_intrxfer);
+
+ /* Do not allow RHSC interrupts > 1 per second */
+ callout_reset(&sc->sc_tmo_rhsc, hz, ohci_rhsc_enable, sc);
+
+ mutex_exit(&sc->sc_lock);
+}
+
void
ohci_rhsc(ohci_softc_t *sc, usbd_xfer_handle xfer)
{
@@ -1562,6 +1608,8 @@ ohci_rhsc(ohci_softc_t *sc, usbd_xfer_ha
int i, m;
int hstatus;
+ KASSERT(mutex_owned(&sc->sc_lock));
+
hstatus = OREAD4(sc, OHCI_RH_STATUS);
DPRINTF(("ohci_rhsc: sc=%p xfer=%p hstatus=0x%08x\n",
sc, xfer, hstatus));
@@ -1609,6 +1657,8 @@ ohci_waitintr(ohci_softc_t *sc, usbd_xfe
int timo;
u_int32_t intrs;
+ mutex_enter(&sc->sc_lock);
+
xfer->status = USBD_IN_PROGRESS;
for (timo = xfer->timeout; timo >= 0; timo--) {
usb_delay_ms(&sc->sc_bus, 1);
@@ -1621,7 +1671,9 @@ ohci_waitintr(ohci_softc_t *sc, usbd_xfe
ohci_dumpregs(sc);
#endif
if (intrs) {
+ mutex_spin_enter(&sc->sc_intr_lock);
ohci_intr1(sc);
+ mutex_spin_exit(&sc->sc_intr_lock);
if (xfer->status != USBD_IN_PROGRESS)
return;
}
@@ -1631,7 +1683,10 @@ ohci_waitintr(ohci_softc_t *sc, usbd_xfe
DPRINTF(("ohci_waitintr: timeout\n"));
xfer->status = USBD_TIMEOUT;
usb_transfer_complete(xfer);
+
/* XXX should free TD */
+
+ mutex_exit(&sc->sc_lock);
}
void
@@ -1649,8 +1704,11 @@ ohci_poll(struct usbd_bus *bus)
#endif
sc->sc_eintrs |= OHCI_WDH;
- if (OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs)
+ if (OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs) {
+ mutex_spin_enter(&sc->sc_intr_lock);
ohci_intr1(sc);
+ mutex_spin_exit(&sc->sc_intr_lock);
+ }
}
usbd_status
@@ -1666,7 +1724,8 @@ ohci_device_request(usbd_xfer_handle xfe
int isread;
int len;
usbd_status err;
- int s;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
isread = req->bmRequestType & UT_READ;
len = UGETW(req->wLength);
@@ -1767,7 +1826,6 @@ ohci_device_request(usbd_xfer_handle xfe
#endif
/* Insert ED in schedule */
- s = splusb();
sed->ed.ed_tailp = HTOO32(tail->physaddr);
usb_syncmem(&sed->dma,
sed->offs + offsetof(ohci_ed_t, ed_tailp),
@@ -1779,7 +1837,6 @@ ohci_device_request(usbd_xfer_handle xfe
callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout),
ohci_timeout, xfer);
}
- splx(s);
#ifdef OHCI_DEBUG
if (ohcidebug > 20) {
@@ -1963,13 +2020,14 @@ void
ohci_timeout_task(void *addr)
{
usbd_xfer_handle xfer = addr;
- int s;
+ ohci_softc_t *sc = xfer->pipe->device->bus->hci_private;
DPRINTF(("ohci_timeout_task: xfer=%p\n", xfer));
- s = splusb();
+ KASSERT(mutex_owned(&sc->sc_lock));
+ //mutex_enter(&sc->sc_lock);
ohci_abort_xfer(xfer, USBD_TIMEOUT);
- splx(s);
+ //mutex_exit(&sc->sc_lock);
}
#ifdef OHCI_DEBUG
@@ -2070,15 +2128,16 @@ ohci_open(usbd_pipe_handle pipe)
ohci_soft_itd_t *sitd;
ohci_physaddr_t tdphys;
u_int32_t fmt;
- usbd_status err;
- int s;
+ usbd_status err = USBD_NOMEM;
int ival;
DPRINTFN(1, ("ohci_open: pipe=%p, addr=%d, endpt=%d (%d)\n",
pipe, addr, ed->bEndpointAddress, sc->sc_addr));
- if (sc->sc_dying)
- return (USBD_IOERROR);
+ if (sc->sc_dying) {
+ err = USBD_IOERROR;
+ goto bad0;
+ }
std = NULL;
sed = NULL;
@@ -2092,7 +2151,8 @@ ohci_open(usbd_pipe_handle pipe)
pipe->methods = &ohci_root_intr_methods;
break;
default:
- return (USBD_INVAL);
+ err = USBD_INVAL;
+ goto bad0;
}
} else {
sed = ohci_alloc_sed(sc);
@@ -2138,9 +2198,9 @@ ohci_open(usbd_pipe_handle pipe)
0, &opipe->u.ctl.reqdma);
if (err)
goto bad;
- s = splusb();
+ mutex_enter(&sc->sc_lock);
ohci_add_ed(sc, sed, sc->sc_ctrl_head);
- splx(s);
+ mutex_exit(&sc->sc_lock);
break;
case UE_INTERRUPT:
pipe->methods = &ohci_device_intr_methods;
@@ -2153,13 +2213,14 @@ ohci_open(usbd_pipe_handle pipe)
return (ohci_setup_isoc(pipe));
case UE_BULK:
pipe->methods = &ohci_device_bulk_methods;
- s = splusb();
+ mutex_enter(&sc->sc_lock);
ohci_add_ed(sc, sed, sc->sc_bulk_head);
- splx(s);
+ mutex_exit(&sc->sc_lock);
break;
}
}
- return (USBD_NORMAL_COMPLETION);
+
+ return USBD_NORMAL_COMPLETION;
bad:
if (std != NULL)
@@ -2168,7 +2229,8 @@ ohci_open(usbd_pipe_handle pipe)
if (sed != NULL)
ohci_free_sed(sc, sed);
bad0:
- return (USBD_NOMEM);
+ mutex_exit(&sc->sc_lock);
+ return err;
}
@@ -2182,9 +2244,9 @@ ohci_close_pipe(usbd_pipe_handle pipe, o
struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
ohci_softc_t *sc = pipe->device->bus->hci_private;
ohci_soft_ed_t *sed = opipe->sed;
- int s;
- s = splusb();
+ KASSERT(mutex_owned(&sc->sc_lock));
+
#ifdef DIAGNOSTIC
sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP);
if ((O32TOH(sed->ed.ed_tailp) & OHCI_HEADMASK) !=
@@ -2215,7 +2277,6 @@ ohci_close_pipe(usbd_pipe_handle pipe, o
usb_delay_ms(&sc->sc_bus, 1);
pipe->endpoint->datatoggle =
(O32TOH(sed->ed.ed_headp) & OHCI_TOGGLECARRY) ? 1 : 0;
- splx(s);
ohci_free_sed(sc, opipe->sed);
}
@@ -2237,24 +2298,26 @@ ohci_abort_xfer(usbd_xfer_handle xfer, u
ohci_soft_ed_t *sed = opipe->sed;
ohci_soft_td_t *p, *n;
ohci_physaddr_t headp;
- int s, hit;
+ int hit;
int wake;
DPRINTF(("ohci_abort_xfer: xfer=%p pipe=%p sed=%p\n", xfer, opipe,sed));
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);
+ callout_halt(&xfer->timeout_handle, &sc->sc_lock);
usb_transfer_complete(xfer);
- splx(s);
+ mutex_exit(&sc->sc_lock);
return;
}
if (xfer->device->bus->intr_context || !curproc)
panic("ohci_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.
@@ -2270,7 +2333,8 @@ ohci_abort_xfer(usbd_xfer_handle xfer, u
DPRINTFN(2, ("ohci_abort_xfer: waiting for abort to finish\n"));
xfer->hcflags |= UXFER_ABORTWAIT;
while (xfer->hcflags & UXFER_ABORTING)
- tsleep(&xfer->hcflags, PZERO, "ohciaw", 0);
+ cv_wait(&xfer->hccv, &sc->sc_lock);
+ goto done;
return;
}
xfer->hcflags |= UXFER_ABORTING;
@@ -2278,10 +2342,8 @@ ohci_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);
- splx(s);
DPRINTFN(1,("ohci_abort_xfer: stop ed=%p\n", sed));
usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags),
sizeof(sed->ed.ed_flags),
@@ -2297,15 +2359,9 @@ ohci_abort_xfer(usbd_xfer_handle xfer, u
* has run.
*/
usb_delay_ms(opipe->pipe.device->bus, 20); /* 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
- tsleep(&sc->sc_softwake, PZERO, "ohciab", 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.
@@ -2314,14 +2370,12 @@ ohci_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? */
p = xfer->hcpriv;
#ifdef DIAGNOSTIC
if (p == NULL) {
xfer->hcflags &= ~UXFER_ABORTING; /* XXX */
- splx(s);
printf("ohci_abort_xfer: hcpriv is NULL\n");
- return;
+ goto done;
}
#endif
#ifdef OHCI_DEBUG
@@ -2369,9 +2423,10 @@ ohci_abort_xfer(usbd_xfer_handle xfer, u
xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
usb_transfer_complete(xfer);
if (wake)
- wakeup(&xfer->hcflags);
+ cv_broadcast(&xfer->hccv);
- splx(s);
+done:
+ mutex_exit(&sc->sc_lock);
}
/*
@@ -2435,10 +2490,13 @@ Static const usb_hub_descriptor_t ohci_h
Static usbd_status
ohci_root_ctrl_transfer(usbd_xfer_handle xfer)
{
+ ohci_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);
@@ -2453,7 +2511,7 @@ ohci_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;
@@ -2754,9 +2812,9 @@ ohci_root_ctrl_start(usbd_xfer_handle xf
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);
}
@@ -2778,10 +2836,13 @@ ohci_root_ctrl_close(usbd_pipe_handle pi
Static usbd_status
ohci_root_intr_transfer(usbd_xfer_handle xfer)
{
+ ohci_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);
@@ -2798,7 +2859,10 @@ ohci_root_intr_start(usbd_xfer_handle xf
if (sc->sc_dying)
return (USBD_IOERROR);
+ mutex_enter(&sc->sc_lock);
+ KASSERT(sc->sc_intrxfer == NULL);
sc->sc_intrxfer = xfer;
+ mutex_exit(&sc->sc_lock);
return (USBD_IN_PROGRESS);
}
@@ -2807,16 +2871,16 @@ ohci_root_intr_start(usbd_xfer_handle xf
Static void
ohci_root_intr_abort(usbd_xfer_handle xfer)
{
- int s;
+ ohci_softc_t *sc = xfer->pipe->device->bus->hci_private;
if (xfer->pipe->intrxfer == xfer) {
DPRINTF(("ohci_root_intr_abort: remove\n"));
xfer->pipe->intrxfer = NULL;
}
xfer->status = USBD_CANCELLED;
- s = splusb();
+ mutex_enter(&sc->sc_lock);
usb_transfer_complete(xfer);
- splx(s);
+ mutex_exit(&sc->sc_lock);
}
/* Close the root pipe. */
@@ -2835,10 +2899,13 @@ ohci_root_intr_close(usbd_pipe_handle pi
Static usbd_status
ohci_device_ctrl_transfer(usbd_xfer_handle xfer)
{
+ ohci_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);
@@ -2863,7 +2930,9 @@ ohci_device_ctrl_start(usbd_xfer_handle
}
#endif
+ mutex_enter(&sc->sc_lock);
err = ohci_device_request(xfer);
+ mutex_exit(&sc->sc_lock);
if (err)
return (err);
@@ -2888,7 +2957,9 @@ ohci_device_ctrl_close(usbd_pipe_handle
ohci_softc_t *sc = pipe->device->bus->hci_private;
DPRINTF(("ohci_device_ctrl_close: pipe=%p\n", pipe));
+ mutex_enter(&sc->sc_lock);
ohci_close_pipe(pipe, sc->sc_ctrl_head);
+ mutex_exit(&sc->sc_lock);
ohci_free_std(sc, opipe->tail.td);
}
@@ -2911,10 +2982,13 @@ ohci_noop(usbd_pipe_handle pipe)
Static usbd_status
ohci_device_bulk_transfer(usbd_xfer_handle xfer)
{
+ ohci_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);
@@ -2931,7 +3005,7 @@ ohci_device_bulk_start(usbd_xfer_handle
int addr = dev->address;
ohci_soft_td_t *data, *tail, *tdp;
ohci_soft_ed_t *sed;
- int s, len, isread, endpt;
+ int len, isread, endpt;
usbd_status err;
if (sc->sc_dying)
@@ -2945,6 +3019,8 @@ ohci_device_bulk_start(usbd_xfer_handle
}
#endif
+ mutex_enter(&sc->sc_lock);
+
len = xfer->length;
endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
isread = UE_GET_DIR(endpt) == UE_DIR_IN;
@@ -2976,8 +3052,10 @@ ohci_device_bulk_start(usbd_xfer_handle
usb_syncmem(&tail->dma, tail->offs + offsetof(ohci_td_t, td_flags),
sizeof(tail->td.td_flags),
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
- if (err)
+ if (err) {
+ mutex_exit(&sc->sc_lock);
return (err);
+ }
tail->xfer = NULL;
xfer->hcpriv = data;
@@ -2997,7 +3075,6 @@ ohci_device_bulk_start(usbd_xfer_handle
#endif
/* Insert ED in schedule */
- s = splusb();
for (tdp = data; tdp != tail; tdp = tdp->nexttd) {
tdp->xfer = xfer;
}
@@ -3011,6 +3088,7 @@ ohci_device_bulk_start(usbd_xfer_handle
callout_reset(&xfer->timeout_handle, mstohz(xfer->timeout),
ohci_timeout, xfer);
}
+ mutex_exit(&sc->sc_lock);
#if 0
/* This goes wrong if we are too slow. */
@@ -3023,8 +3101,6 @@ ohci_device_bulk_start(usbd_xfer_handle
}
#endif
- splx(s);
-
return (USBD_IN_PROGRESS);
}
@@ -3045,7 +3121,9 @@ ohci_device_bulk_close(usbd_pipe_handle
ohci_softc_t *sc = pipe->device->bus->hci_private;
DPRINTF(("ohci_device_bulk_close: pipe=%p\n", pipe));
+ mutex_enter(&sc->sc_lock);
ohci_close_pipe(pipe, sc->sc_bulk_head);
+ mutex_exit(&sc->sc_lock);
ohci_free_std(sc, opipe->tail.td);
}
@@ -3054,10 +3132,13 @@ ohci_device_bulk_close(usbd_pipe_handle
Static usbd_status
ohci_device_intr_transfer(usbd_xfer_handle xfer)
{
+ ohci_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);
@@ -3073,7 +3154,7 @@ ohci_device_intr_start(usbd_xfer_handle
ohci_softc_t *sc = dev->bus->hci_private;
ohci_soft_ed_t *sed = opipe->sed;
ohci_soft_td_t *data, *tail;
- int s, len, isread, endpt;
+ int len, isread, endpt;
if (sc->sc_dying)
return (USBD_IOERROR);
@@ -3123,7 +3204,7 @@ ohci_device_intr_start(usbd_xfer_handle
#endif
/* Insert ED in schedule */
- s = splusb();
+ mutex_enter(&sc->sc_lock);
usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed),
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
sed->ed.ed_tailp = HTOO32(tail->physaddr);
@@ -3146,7 +3227,7 @@ ohci_device_intr_start(usbd_xfer_handle
ohci_dump_tds(sc, data);
}
#endif
- splx(s);
+ mutex_exit(&sc->sc_lock);
return (USBD_IN_PROGRESS);
}
@@ -3172,11 +3253,10 @@ ohci_device_intr_close(usbd_pipe_handle
int pos = opipe->u.intr.pos;
int j;
ohci_soft_ed_t *p, *sed = opipe->sed;
- int s;
DPRINTFN(1,("ohci_device_intr_close: pipe=%p nslots=%d pos=%d\n",
pipe, nslots, pos));
- s = splusb();
+ mutex_enter(&sc->sc_lock);
usb_syncmem(&sed->dma, sed->offs,
sizeof(sed->ed), BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
sed->ed.ed_flags |= HTOO32(OHCI_ED_SKIP);
@@ -3198,7 +3278,7 @@ ohci_device_intr_close(usbd_pipe_handle
usb_syncmem(&p->dma, p->offs + offsetof(ohci_ed_t, ed_nexted),
sizeof(p->ed.ed_nexted),
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
- splx(s);
+ mutex_exit(&sc->sc_lock);
for (j = 0; j < nslots; j++)
--sc->sc_bws[(pos * nslots + j) % OHCI_NO_INTRS];
@@ -3210,7 +3290,7 @@ ohci_device_intr_close(usbd_pipe_handle
Static usbd_status
ohci_device_setintr(ohci_softc_t *sc, struct ohci_pipe *opipe, int ival)
{
- int i, j, s, best;
+ int i, j, best;
u_int npoll, slow, shigh, nslots;
u_int bestbw, bw;
ohci_soft_ed_t *hsed, *sed = opipe->sed;
@@ -3252,7 +3332,7 @@ ohci_device_setintr(ohci_softc_t *sc, st
DPRINTFN(2, ("ohci_setintr: best=%d(%d..%d) bestbw=%d\n",
best, slow, shigh, bestbw));
- s = splusb();
+ mutex_enter(&sc->sc_lock);
hsed = sc->sc_eds[best];
sed->next = hsed->next;
usb_syncmem(&hsed->dma, hsed->offs + offsetof(ohci_ed_t, ed_flags),
@@ -3267,7 +3347,7 @@ ohci_device_setintr(ohci_softc_t *sc, st
usb_syncmem(&hsed->dma, hsed->offs + offsetof(ohci_ed_t, ed_flags),
sizeof(hsed->ed.ed_flags),
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
- splx(s);
+ mutex_exit(&sc->sc_lock);
for (j = 0; j < nslots; j++)
++sc->sc_bws[(best * nslots + j) % OHCI_NO_INTRS];
@@ -3283,12 +3363,15 @@ ohci_device_setintr(ohci_softc_t *sc, st
usbd_status
ohci_device_isoc_transfer(usbd_xfer_handle xfer)
{
+ ohci_softc_t *sc = xfer->pipe->device->bus->hci_private;
usbd_status err;
DPRINTFN(5,("ohci_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)
@@ -3317,7 +3400,6 @@ ohci_device_isoc_enter(usbd_xfer_handle
ohci_soft_itd_t *sitd, *nsitd;
ohci_physaddr_t buf, offs, noffs, bp0;
int i, ncur, nframes;
- int s;
DPRINTFN(1,("ohci_device_isoc_enter: used=%d next=%d xfer=%p "
"nframes=%d\n",
@@ -3414,7 +3496,7 @@ ohci_device_isoc_enter(usbd_xfer_handle
}
#endif
- s = splusb();
+ mutex_enter(&sc->sc_lock);
usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed),
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
sed->ed.ed_tailp = HTOO32(nsitd->physaddr);
@@ -3423,7 +3505,7 @@ ohci_device_isoc_enter(usbd_xfer_handle
usb_syncmem(&sed->dma, sed->offs + offsetof(ohci_ed_t, ed_flags),
sizeof(sed->ed.ed_flags),
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
- splx(s);
+ mutex_exit(&sc->sc_lock);
#ifdef OHCI_DEBUG
if (ohcidebug > 5) {
@@ -3444,8 +3526,12 @@ ohci_device_isoc_start(usbd_xfer_handle
DPRINTFN(5,("ohci_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)
@@ -3464,18 +3550,16 @@ ohci_device_isoc_abort(usbd_xfer_handle
ohci_softc_t *sc = opipe->pipe.device->bus->hci_private;
ohci_soft_ed_t *sed;
ohci_soft_itd_t *sitd;
- int s;
-
- s = splusb();
DPRINTFN(1,("ohci_device_isoc_abort: xfer=%p\n", xfer));
+ KASSERT(mutex_owned(&sc->sc_lock));
+
/* Transfer is already done. */
if (xfer->status != USBD_NOT_STARTED &&
xfer->status != USBD_IN_PROGRESS) {
- splx(s);
printf("ohci_device_isoc_abort: early return\n");
- return;
+ goto done;
}
/* Give xfer the requested abort code. */
@@ -3492,9 +3576,8 @@ ohci_device_isoc_abort(usbd_xfer_handle
sitd = xfer->hcpriv;
#ifdef DIAGNOSTIC
if (sitd == NULL) {
- splx(s);
printf("ohci_device_isoc_abort: hcpriv==0\n");
- return;
+ goto done;
}
#endif
for (; sitd->xfer == xfer; sitd = sitd->nextitd) {
@@ -3504,11 +3587,11 @@ ohci_device_isoc_abort(usbd_xfer_handle
#endif
}
- splx(s);
+ mutex_exit(&sc->sc_lock);
usb_delay_ms(&sc->sc_bus, OHCI_ITD_NOFFSET);
- s = splusb();
+ mutex_enter(&sc->sc_lock);
/* Run callback. */
usb_transfer_complete(xfer);
@@ -3518,7 +3601,8 @@ ohci_device_isoc_abort(usbd_xfer_handle
usb_syncmem(&sed->dma, sed->offs, sizeof(sed->ed),
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
- splx(s);
+ done:
+ mutex_exit(&sc->sc_lock);
}
void
@@ -3533,14 +3617,13 @@ ohci_setup_isoc(usbd_pipe_handle pipe)
struct ohci_pipe *opipe = (struct ohci_pipe *)pipe;
ohci_softc_t *sc = pipe->device->bus->hci_private;
struct iso *iso = &opipe->u.iso;
- int s;
iso->next = -1;
iso->inuse = 0;
- s = splusb();
+ mutex_enter(&sc->sc_lock);
ohci_add_ed(sc, opipe->sed, sc->sc_isoc_head);
- splx(s);
+ mutex_exit(&sc->sc_lock);
return (USBD_NORMAL_COMPLETION);
}
Index: src/sys/dev/usb/ohcivar.h
diff -u src/sys/dev/usb/ohcivar.h:1.51 src/sys/dev/usb/ohcivar.h:1.51.8.1
--- src/sys/dev/usb/ohcivar.h:1.51 Sat May 28 15:47:17 2011
+++ src/sys/dev/usb/ohcivar.h Sun Dec 4 21:02:27 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: ohcivar.h,v 1.51 2011/05/28 15:47:17 tsutsui Exp $ */
+/* $NetBSD: ohcivar.h,v 1.51.8.1 2011/12/04 21:02:27 jmcneill Exp $ */
/* $FreeBSD: src/sys/dev/usb/ohcivar.h,v 1.13 1999/11/17 22:33:41 n_hibma Exp $ */
/*
@@ -87,6 +87,10 @@ typedef struct ohci_softc {
bus_space_handle_t ioh;
bus_size_t sc_size;
+ kmutex_t sc_lock;
+ kmutex_t sc_intr_lock;
+ void *sc_rhsc_si;
+
usb_dma_t sc_hccadma;
struct ohci_hcca *sc_hcca;
ohci_soft_ed_t *sc_eds[OHCI_NO_EDS];
@@ -109,9 +113,8 @@ typedef struct ohci_softc {
#define OHCI_BIG_ENDIAN 1 /* big endian OHCI? never seen it */
#define OHCI_HOST_ENDIAN 2 /* if OHCI always matches CPU */
-#ifdef USB_USE_SOFTINTR
char sc_softwake;
-#endif /* USB_USE_SOFTINTR */
+ kcondvar_t sc_softwake_cv;
ohci_soft_ed_t *sc_freeeds;
ohci_soft_td_t *sc_freetds;