Module Name: src Committed By: mrg Date: Tue Dec 6 05:06:50 UTC 2011
Modified Files: src/sys/dev/usb [jmcneill-usbmp]: uhci.c uhcivar.h Log Message: my compiles-but-un-runtime-tested port of uhci to usbmp branch. based upon the ohci and ehci changes. To generate a diff of this commit: cvs rdiff -u -r1.240.6.1 -r1.240.6.2 src/sys/dev/usb/uhci.c cvs rdiff -u -r1.48 -r1.48.12.1 src/sys/dev/usb/uhcivar.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/uhci.c diff -u src/sys/dev/usb/uhci.c:1.240.6.1 src/sys/dev/usb/uhci.c:1.240.6.2 --- src/sys/dev/usb/uhci.c:1.240.6.1 Sun Dec 4 13:23:17 2011 +++ src/sys/dev/usb/uhci.c Tue Dec 6 05:06:50 2011 @@ -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 (lenn...@augustsson.net) at - * Carlstedt Research & Technology. + * Carlstedt Research & Technology, Jared D. McNeill (jmcne...@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 void uhci_freem(struct usbd_bus 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 @@ const struct usbd_bus_methods uhci_bus_m uhci_freem, uhci_allocx, uhci_freex, - NULL, /* uhci_get_locks */ + uhci_get_locks, }; const struct usbd_pipe_methods uhci_root_ctrl_methods = { @@ -523,7 +526,11 @@ uhci_init(uhci_softc_t *sc) 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; @@ -580,12 +587,17 @@ uhci_detach(struct uhci_softc *sc, int f 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 @@ uhci_allocm(struct usbd_bus *bus, usb_dm 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 @@ uhci_allocx(struct usbd_bus *bus) } #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 @@ uhci_freex(struct usbd_bus *bus, usbd_xf 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_resume(device_t dv, const pmf_qual_ { 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 @@ uhci_resume(device_t dv, const pmf_qual_ #endif sc->sc_suspend = PWR_RESUME; - splx(s); + mutex_spin_exit(&sc->sc_intr_lock); return true; } @@ -742,9 +764,8 @@ uhci_suspend(device_t dv, const pmf_qual { 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 @@ uhci_suspend(device_t dv, const pmf_qual 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 @@ uhci_poll_hub(void *addr) 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 @@ uhci_poll_hub(void *addr) 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 @@ int 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 @@ uhci_intr1(uhci_softc_t *sc) } #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 @@ uhci_softintr(void *v) 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_softintr(void *v) 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 @@ uhci_idone(uhci_intr_info_t *ii) DPRINTFN(12, ("uhci_idone: ii=%p\n", ii)); #ifdef DIAGNOSTIC { + /* XXX SMP? */ int s = splhigh(); if (ii->isdone) { splx(s); @@ -1631,13 +1663,10 @@ void 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 @@ uhci_waitintr(uhci_softc_t *sc, usbd_xfe 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 @@ uhci_waitintr(uhci_softc_t *sc, usbd_xfe 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 @@ uhci_waitintr(uhci_softc_t *sc, usbd_xfe panic("uhci_waitintr: lost intr_info"); #endif uhci_idone(ii); + +done: + mutex_exit(&sc->sc_lock); } void @@ -1683,8 +1719,11 @@ uhci_poll(struct usbd_bus *bus) { 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 @@ uhci_reset(uhci_softc_t *sc) 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 @@ uhci_run(uhci_softc_t *sc, int run) 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_alloc_std(uhci_softc_t *sc) 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 @@ uhci_alloc_std_chain(struct uhci_pipe *u 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 @@ uhci_noop(usbd_pipe_handle pipe) 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_device_bulk_start(usbd_xfer_handle 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 @@ uhci_device_bulk_start(usbd_xfer_handle 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 @@ uhci_device_bulk_start(usbd_xfer_handle 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 @@ uhci_device_bulk_start(usbd_xfer_handle 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_device_bulk_start(usbd_xfer_handle uhci_timeout, ii); } xfer->status = USBD_IN_PROGRESS; - splx(s); #ifdef UHCI_DEBUG if (uhcidebug > 10) { @@ -2050,6 +2096,7 @@ uhci_device_bulk_start(usbd_xfer_handle if (sc->sc_bus.use_polling) uhci_waitintr(sc, xfer); + mutex_exit(&sc->sc_lock); return (USBD_IN_PROGRESS); } @@ -2078,24 +2125,25 @@ uhci_abort_xfer(usbd_xfer_handle xfer, u 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 @@ uhci_abort_xfer(usbd_xfer_handle xfer, u 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 @@ uhci_abort_xfer(usbd_xfer_handle xfer, u 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 @@ uhci_abort_xfer(usbd_xfer_handle xfer, u * 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 @@ uhci_abort_xfer(usbd_xfer_handle xfer, u 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 @@ uhci_device_bulk_close(usbd_pipe_handle 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 @@ uhci_device_ctrl_start(usbd_xfer_handle 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 @@ uhci_device_ctrl_start(usbd_xfer_handle 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_device_intr_start(usbd_xfer_handle 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 @@ uhci_device_intr_start(usbd_xfer_handle } #endif - s = splusb(); + mutex_enter(&sc->sc_lock); /* Set up interrupt info. */ ii->xfer = xfer; ii->stdstart = data; @@ -2312,7 +2360,7 @@ uhci_device_intr_start(usbd_xfer_handle } 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 @@ uhci_device_intr_close(usbd_pipe_handle 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 @@ uhci_device_intr_close(usbd_pipe_handle 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,7 +2443,8 @@ uhci_device_request(usbd_xfer_handle xfe 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", @@ -2476,7 +2524,7 @@ uhci_device_request(usbd_xfer_handle xfe 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_device_request(usbd_xfer_handle xfe uhci_timeout, ii); } xfer->status = USBD_IN_PROGRESS; - splx(s); + mutex_exit(&sc->sc_lock); return (USBD_NORMAL_COMPLETION); } @@ -2522,12 +2570,15 @@ uhci_device_request(usbd_xfer_handle xfe 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 @@ uhci_device_isoc_enter(usbd_xfer_handle 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_device_isoc_enter(usbd_xfer_handle 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 @@ uhci_device_isoc_enter(usbd_xfer_handle iso->next = next; iso->inuse += xfer->nframes; - splx(s); + mutex_exit(&sc->sc_lock); } usbd_status @@ -2629,12 +2680,16 @@ uhci_device_isoc_start(usbd_xfer_handle 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 @@ uhci_device_isoc_start(usbd_xfer_handle } #endif - s = splusb(); - /* Set up interrupt info. */ ii->xfer = xfer; ii->stdstart = end; @@ -2667,7 +2720,7 @@ uhci_device_isoc_start(usbd_xfer_handle #endif uhci_add_intr_info(sc, ii); - splx(s); + mutex_exit(&sc->sc_lock); return (USBD_IN_PROGRESS); } @@ -2675,17 +2728,18 @@ uhci_device_isoc_start(usbd_xfer_handle 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 @@ uhci_device_isoc_abort(usbd_xfer_handle /* Run callback and remove from interrupt list. */ usb_transfer_complete(xfer); - splx(s); + mutex_exit(&sc->sc_lock); } void @@ -2738,7 +2792,7 @@ uhci_device_isoc_close(usbd_pipe_handle 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 @@ uhci_device_isoc_close(usbd_pipe_handle */ 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 @@ uhci_device_isoc_close(usbd_pipe_handle } 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 @@ uhci_device_isoc_close(usbd_pipe_handle 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 @@ uhci_device_isoc_close(usbd_pipe_handle 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_setup_isoc(usbd_pipe_handle pipe) 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 @@ uhci_setup_isoc(usbd_pipe_handle pipe) } /* 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 @@ uhci_setup_isoc(usbd_pipe_handle pipe) 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 @@ uhci_setup_isoc(usbd_pipe_handle pipe) 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 @@ uhci_device_intr_done(usbd_xfer_handle x 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 @@ uhci_device_ctrl_done(usbd_xfer_handle x 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 @@ uhci_device_bulk_done(usbd_xfer_handle x 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 @@ usbd_status 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 @@ uhci_device_setintr(uhci_softc_t *sc, st 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 @@ uhci_device_setintr(uhci_softc_t *sc, st } 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 @@ uhci_device_setintr(uhci_softc_t *sc, st } #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_open(usbd_pipe_handle pipe) 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 @@ uhci_open(usbd_pipe_handle pipe) return (USBD_NORMAL_COMPLETION); bad: - return (USBD_NOMEM); + return USBD_NOMEM; } /* @@ -3415,10 +3485,13 @@ uhci_portreset(uhci_softc_t *sc, int ind 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 @@ uhci_root_ctrl_start(usbd_xfer_handle xf 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 @@ uhci_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); } @@ -3802,10 +3875,13 @@ uhci_root_intr_abort(usbd_xfer_handle xf 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); Index: src/sys/dev/usb/uhcivar.h diff -u src/sys/dev/usb/uhcivar.h:1.48 src/sys/dev/usb/uhcivar.h:1.48.12.1 --- src/sys/dev/usb/uhcivar.h:1.48 Wed Nov 3 22:34:23 2010 +++ src/sys/dev/usb/uhcivar.h Tue Dec 6 05:06:50 2011 @@ -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 $ */ /* @@ -133,6 +133,10 @@ typedef struct uhci_softc { 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; struct uhci_vframe sc_vframes[UHCI_VFRAMELIST_COUNT];