From owner-p4-projects@FreeBSD.ORG Sat Dec 15 17:08:13 2007 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 0C36516A420; Sat, 15 Dec 2007 17:08:13 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A689816A419 for ; Sat, 15 Dec 2007 17:08:12 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 8C61E13C458 for ; Sat, 15 Dec 2007 17:08:12 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id lBFH8CQT079117 for ; Sat, 15 Dec 2007 17:08:12 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id lBFH8C72079114 for perforce@freebsd.org; Sat, 15 Dec 2007 17:08:12 GMT (envelope-from hselasky@FreeBSD.org) Date: Sat, 15 Dec 2007 17:08:12 GMT Message-Id: <200712151708.lBFH8C72079114@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Cc: Subject: PERFORCE change 130957 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 15 Dec 2007 17:08:13 -0000 http://perforce.freebsd.org/chv.cgi?CH=130957 Change 130957 by hselasky@hselasky_laptop001 on 2007/12/15 17:07:50 This commit is required for USB device side support. o This commit adds automatic context detection to "usb_callback_wrapper()", so that you can call the "usb_callback_wrapper()" from almost everywhere. This leads to a lot of cleanup related to calling callbacks in the EHCI, OHCI and UHCI drivers. o Optimized "uhci_interrupt()" a little bit. o The interrupt list where USB transfers are queued has been moved to "struct usbd_bus" so that we can factor out some code. o Allow all "usbd_bus_mem_xxx" functions to be passed a NULL callback pointer. Affected files ... .. //depot/projects/usb/src/sys/dev/usb/ehci.c#62 edit .. //depot/projects/usb/src/sys/dev/usb/ehci.h#25 edit .. //depot/projects/usb/src/sys/dev/usb/ohci.c#51 edit .. //depot/projects/usb/src/sys/dev/usb/ohci.h#21 edit .. //depot/projects/usb/src/sys/dev/usb/uhci.c#52 edit .. //depot/projects/usb/src/sys/dev/usb/uhci.h#21 edit .. //depot/projects/usb/src/sys/dev/usb/usb_subr.c#70 edit .. //depot/projects/usb/src/sys/dev/usb/usb_subr.h#75 edit .. //depot/projects/usb/src/sys/dev/usb/usb_transfer.c#70 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/ehci.c#62 (text+ko) ==== @@ -79,7 +79,7 @@ printf x ; } } while (0) #define DPRINTFN(n,x) do { if (ehcidebug > (n)) { printf("%s: ", __FUNCTION__); \ printf x ; } } while (0) -int ehcidebug = 0; +static int ehcidebug = 0; SYSCTL_NODE(_hw_usb, OID_AUTO, ehci, CTLFLAG_RW, 0, "USB ehci"); SYSCTL_INT(_hw_usb_ehci, OID_AUTO, debug, CTLFLAG_RW, @@ -105,11 +105,11 @@ extern struct usbd_pipe_methods ehci_root_intr_methods; static usbd_config_td_command_t ehci_root_ctrl_task; -static void ehci_root_ctrl_task_td(struct ehci_softc *sc, struct thread *ctd); static void ehci_do_poll(struct usbd_bus *bus); +static void ehci_root_ctrl_poll(struct ehci_softc *sc); static usbd_std_root_transfer_func_t ehci_root_intr_done; -static usbd_std_root_transfer_func_t ehci_root_ctrl_task_td_sub; +static usbd_std_root_transfer_func_t ehci_root_ctrl_done; struct ehci_std_temp { struct usbd_page_cache *pc; @@ -213,8 +213,6 @@ DPRINTF(("start\n")); - LIST_INIT(&sc->sc_interrupt_list_head); - usb_callout_init_mtx(&sc->sc_tmo_pcd, &sc->sc_bus.mtx, CALLOUT_RETURNUNLOCKED); @@ -1280,18 +1278,12 @@ * Else: USB transfer is finished *------------------------------------------------------------------------*/ static uint8_t -ehci_check_transfer(struct usbd_xfer *xfer, struct thread *ctd) +ehci_check_transfer(struct usbd_xfer *xfer) { struct usbd_pipe_methods *methods = xfer->pipe->methods; uint32_t status; - if (xfer->usb_thread != ctd) { - /* - * cannot call this transfer back due to locking ! - */ - goto done; - } DPRINTFN(12, ("xfer=%p checking transfer\n", xfer)); if (methods == &ehci_device_isoc_fs_methods) { @@ -1402,57 +1394,48 @@ /* acknowledge any PCD interrupt */ EOWRITE4(sc, EHCI_USBSTS, EHCI_STS_PCD); - if (usbd_std_root_transfer(&(sc->sc_root_intr), NULL, - &ehci_root_intr_done)) { - mtx_unlock(&(sc->sc_bus.mtx)); - } + usbd_std_root_transfer(&(sc->sc_root_intr), + &ehci_root_intr_done); + + mtx_unlock(&(sc->sc_bus.mtx)); return; } static void -ehci_interrupt_td(ehci_softc_t *sc, struct thread *ctd) +ehci_interrupt_poll(ehci_softc_t *sc) { - enum { - FINISH_LIST_MAX = 16}; - - struct usbd_xfer *xlist[FINISH_LIST_MAX + 1]; - struct usbd_xfer **xptr = xlist; struct usbd_xfer *xfer; - struct thread *td; - uint32_t status; - uint8_t need_repeat = 0; - td = ctd; /* default value */ - - mtx_lock(&sc->sc_bus.mtx); - - /* - * It can happen that an interrupt will be delivered to - * us before the device has been fully attached and the - * softc struct has been configured. Usually this happens - * when kldloading the USB support as a module after the - * system has been booted. If we detect this condition, - * we need to squelch the unwanted interrupts until we're - * ready for them. - */ - if (sc->sc_bus.bdev == NULL) { - goto done; - } - if (ctd) { + LIST_FOREACH(xfer, &sc->sc_bus.intr_list_head, interrupt_list) { /* - * the poll thread should not read any status registers that - * will clear interrupts! + * check if transfer is transferred */ - goto repeat; + if (ehci_check_transfer(xfer)) { + /* queue callback for execution */ + usbd_callback_wrapper(xfer, NULL, USBD_CONTEXT_CALLBACK); + } } - td = curthread; /* NULL is not a valid thread */ + return; +} + +/*------------------------------------------------------------------------* + * ehci_interrupt - EHCI interrupt handler + * + * NOTE: Do not access "sc->sc_bus.bdev" inside the interrupt handler, + * hence the interrupt handler will be setup before "sc->sc_bus.bdev" + * is present ! + *------------------------------------------------------------------------*/ +void +ehci_interrupt(ehci_softc_t *sc) +{ + uint32_t status; + + mtx_lock(&sc->sc_bus.mtx); - DPRINTFN(15, ("%s: real interrupt\n", - device_get_nameunit(sc->sc_bus.bdev))); + DPRINTFN(15, ("real interrupt\n")); #ifdef USB_DEBUG if (ehcidebug > 15) { - DPRINTF(("%s\n", device_get_nameunit(sc->sc_bus.bdev))); ehci_dump_regs(sc); } #endif @@ -1474,8 +1457,8 @@ wakeup(&sc->sc_async_p_last); } if (status & EHCI_STS_HSE) { - device_printf(sc->sc_bus.bdev, "unrecoverable error, " - "controller halted\n"); + printf("%s: unrecoverable error, " + "controller halted\n", __FUNCTION__); #ifdef USB_DEBUG ehci_dump_regs(sc); ehci_dump_isoc(sc); @@ -1489,13 +1472,12 @@ sc->sc_eintrs &= ~EHCI_STS_PCD; EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); - if (!usbd_std_root_transfer(&(sc->sc_root_intr), ctd, - &ehci_root_intr_done)) { - mtx_lock(&(sc->sc_bus.mtx)); - } + usbd_std_root_transfer(&(sc->sc_root_intr), + &ehci_root_intr_done); + /* do not allow RHSC interrupts > 1 per second */ usb_callout_reset(&sc->sc_tmo_pcd, hz, - (void *)(void *)ehci_pcd_enable, sc); + (void *)&ehci_pcd_enable, sc); } status &= ~(EHCI_STS_INT | EHCI_STS_ERRINT | EHCI_STS_PCD | EHCI_STS_IAA); @@ -1503,69 +1485,24 @@ /* block unprocessed interrupts */ sc->sc_eintrs &= ~status; EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs); - device_printf(sc->sc_bus.bdev, "blocking intrs 0x%x\n", - status); + printf("%s: blocking interrupts 0x%x\n", __FUNCTION__, status); } -repeat: - LIST_FOREACH(xfer, &sc->sc_interrupt_list_head, interrupt_list) { - /* - * check if transfer is transferred - */ - if (ehci_check_transfer(xfer, ctd)) { - /* queue callback */ - - *(xptr++) = xfer; + /* poll all the USB transfers */ + ehci_interrupt_poll(sc); - xfer->usb_thread = td; - xfer->usb_root->memory_refcount++; - - /* check queue length */ - if (xptr >= &xlist[FINISH_LIST_MAX]) { - need_repeat = 1; - break; - } - } - } - done: mtx_unlock(&sc->sc_bus.mtx); - - /* zero terminate the callback list */ - *(xptr) = NULL; - - usbd_do_callback(xlist, td); - - if (need_repeat) { - xptr = xlist; - - need_repeat = 0; - - mtx_lock(&sc->sc_bus.mtx); - - goto repeat; - } return; } -void -ehci_interrupt(ehci_softc_t *sc) -{ - ehci_interrupt_td(sc, NULL); - return; -} - /* * called when a request does not complete */ static void ehci_timeout(struct usbd_xfer *xfer) { - struct thread *td; - struct usbd_xfer *xlist[2]; ehci_softc_t *sc = xfer->usb_sc; - td = curthread; - DPRINTF(("xfer=%p\n", xfer)); mtx_assert(&sc->sc_bus.mtx, MA_OWNED); @@ -1573,17 +1510,11 @@ /* transfer is transferred */ ehci_device_done(xfer, USBD_TIMEOUT); - /* queue callback */ - xlist[0] = xfer; - xlist[1] = NULL; - - xfer->usb_thread = td; - xfer->usb_root->memory_refcount++; + /* queue callback for execution */ + usbd_callback_wrapper(xfer, NULL, USBD_CONTEXT_CALLBACK); mtx_unlock(&sc->sc_bus.mtx); - usbd_do_callback(xlist, td); - return; } @@ -1591,29 +1522,15 @@ ehci_do_poll(struct usbd_bus *bus) { struct ehci_softc *sc = EHCI_BUS2SC(bus); - struct thread *ctd = curthread; - ehci_interrupt_td(sc, ctd); mtx_lock(&(sc->sc_bus.mtx)); - ehci_root_ctrl_task_td(sc, ctd); + ehci_interrupt_poll(sc); + ehci_root_ctrl_poll(sc); mtx_unlock(&(sc->sc_bus.mtx)); return; } -#define ehci_add_interrupt_info(sc, xfer) \ - LIST_INSERT_HEAD(&(sc)->sc_interrupt_list_head, (xfer), interrupt_list) - static void -ehci_remove_interrupt_info(struct usbd_xfer *xfer) -{ - if ((xfer)->interrupt_list.le_prev) { - LIST_REMOVE((xfer), interrupt_list); - (xfer)->interrupt_list.le_prev = NULL; - } - return; -} - -static void ehci_setup_standard_chain_sub(struct ehci_std_temp *temp) { struct usbd_page_search buf_res; @@ -2227,12 +2144,6 @@ xfer->td_transfer_first = NULL; xfer->td_transfer_last = NULL; } - /* stop timeout */ - usb_callout_stop(&xfer->timeout_handle); - - /* remove interrupt info (if any) */ - ehci_remove_interrupt_info(xfer); - if ((methods != &ehci_root_ctrl_methods) && (methods != &ehci_root_intr_methods)) { @@ -2329,7 +2240,7 @@ ehci_setup_standard_chain(xfer, &sc->sc_async_p_last); /**/ - ehci_add_interrupt_info(sc, xfer); + usbd_transfer_intr_enqueue(xfer); if (xfer->timeout && (!xfer->flags.use_polling)) { usb_callout_reset(&xfer->timeout_handle, USBD_MS_TO_TICKS(xfer->timeout), @@ -2379,7 +2290,7 @@ ehci_setup_standard_chain(xfer, &sc->sc_async_p_last); /**/ - ehci_add_interrupt_info(sc, xfer); + usbd_transfer_intr_enqueue(xfer); if (xfer->timeout && (!xfer->flags.use_polling)) { usb_callout_reset(&xfer->timeout_handle, USBD_MS_TO_TICKS(xfer->timeout), @@ -2485,7 +2396,7 @@ ehci_setup_standard_chain(xfer, &sc->sc_intr_p_last[xfer->qh_pos]); /**/ - ehci_add_interrupt_info(sc, xfer); + usbd_transfer_intr_enqueue(xfer); if (xfer->timeout && (!xfer->flags.use_polling)) { usb_callout_reset(&xfer->timeout_handle, USBD_MS_TO_TICKS(xfer->timeout), @@ -2741,7 +2652,7 @@ (EHCI_VIRTUAL_FRAMELIST_COUNT - 1); /**/ - ehci_add_interrupt_info(sc, xfer); + usbd_transfer_intr_enqueue(xfer); /* * enqueue transfer (so that it can be aborted through pipe abort) @@ -3020,7 +2931,7 @@ (EHCI_VIRTUAL_FRAMELIST_COUNT - 1); /**/ - ehci_add_interrupt_info(sc, xfer); + usbd_transfer_intr_enqueue(xfer); /* * enqueue transfer (so that it can be aborted through pipe abort) @@ -3192,12 +3103,12 @@ ehci_root_ctrl_task(struct ehci_softc *sc, struct ehci_config_copy *cc, uint16_t refcount) { - ehci_root_ctrl_task_td(sc, NULL); + ehci_root_ctrl_poll(sc); return; } static void -ehci_root_ctrl_task_td_sub(struct usbd_xfer *xfer, +ehci_root_ctrl_done(struct usbd_xfer *xfer, struct usbd_std_root_transfer *std) { struct ehci_softc *sc = xfer->usb_sc; @@ -3592,12 +3503,10 @@ } static void -ehci_root_ctrl_task_td(struct ehci_softc *sc, struct thread *ctd) +ehci_root_ctrl_poll(struct ehci_softc *sc) { - if (!usbd_std_root_transfer(&(sc->sc_root_ctrl), ctd, - &ehci_root_ctrl_task_td_sub)) { - mtx_lock(&sc->sc_bus.mtx); - } + usbd_std_root_transfer(&(sc->sc_root_ctrl), + &ehci_root_ctrl_done); return; } ==== //depot/projects/usb/src/sys/dev/usb/ehci.h#25 (text+ko) ==== @@ -443,7 +443,6 @@ struct usbd_bus sc_bus; /* base device */ struct usbd_config_td sc_config_td; struct usb_callout sc_tmo_pcd; - LIST_HEAD(, usbd_xfer) sc_interrupt_list_head; union ehci_hub_desc sc_hub_desc; struct usbd_std_root_transfer sc_root_ctrl; struct usbd_std_root_transfer sc_root_intr; ==== //depot/projects/usb/src/sys/dev/usb/ohci.c#51 (text+ko) ==== @@ -84,7 +84,7 @@ #undef DPRINTFN #define DPRINTF(x) do { if (ohcidebug) { printf("%s: ", __FUNCTION__); printf x ; } } while (0) #define DPRINTFN(n,x) do { if (ohcidebug > (n)) { printf("%s: ", __FUNCTION__); printf x ; } } while (0) -int ohcidebug = 0; +static int ohcidebug = 0; SYSCTL_NODE(_hw_usb, OID_AUTO, ohci, CTLFLAG_RW, 0, "USB ohci"); SYSCTL_INT(_hw_usb_ohci, OID_AUTO, debug, CTLFLAG_RW, @@ -121,12 +121,12 @@ extern struct usbd_pipe_methods ohci_root_intr_methods; static usbd_config_td_command_t ohci_root_ctrl_task; -static void ohci_root_ctrl_task_td(struct ohci_softc *sc, struct thread *ctd); +static void ohci_root_ctrl_poll(struct ohci_softc *sc); static void ohci_do_poll(struct usbd_bus *bus); static void ohci_device_done(struct usbd_xfer *xfer, usbd_status_t error); static usbd_std_root_transfer_func_t ohci_root_intr_done; -static usbd_std_root_transfer_func_t ohci_root_ctrl_task_td_sub; +static usbd_std_root_transfer_func_t ohci_root_ctrl_done; struct ohci_std_temp { struct usbd_page_cache *pc; @@ -412,8 +412,6 @@ usbd_bus_mem_flush_all(&(sc->sc_bus), &ohci_iterate_hw_softc); - LIST_INIT(&sc->sc_interrupt_list_head); - /* set up the bus struct */ sc->sc_bus.methods = &ohci_bus_methods; @@ -1055,19 +1053,13 @@ * Else: USB transfer is finished *------------------------------------------------------------------------*/ static uint8_t -ohci_check_transfer(struct usbd_xfer *xfer, struct thread *ctd) +ohci_check_transfer(struct usbd_xfer *xfer) { ohci_ed_t *ed = xfer->qh_start; uint32_t ed_flags; uint32_t ed_headp; uint32_t ed_tailp; - if (xfer->usb_thread != ctd) { - /* - * cannot call this transfer back due to locking ! - */ - return (0); - } DPRINTFN(12, ("xfer=%p checking transfer\n", xfer)); usbd_pc_cpu_invalidate(ed->page_cache); @@ -1118,54 +1110,52 @@ /* acknowledge any RHSC interrupt */ OWRITE4(sc, OHCI_INTERRUPT_STATUS, OHCI_RHSC); - if (usbd_std_root_transfer(&(sc->sc_root_intr), NULL, - &ohci_root_intr_done)) { - mtx_unlock(&(sc->sc_bus.mtx)); - } + usbd_std_root_transfer(&(sc->sc_root_intr), + &ohci_root_intr_done); + + mtx_unlock(&(sc->sc_bus.mtx)); return; } static void -ohci_interrupt_td(ohci_softc_t *sc, struct thread *ctd) +ohci_interrupt_poll(ohci_softc_t *sc) { - enum { - FINISH_LIST_MAX = 16, - }; + struct usbd_xfer *xfer; + + LIST_FOREACH(xfer, &(sc->sc_bus.intr_list_head), interrupt_list) { + /* + * check if transfer is transferred + */ + if (ohci_check_transfer(xfer)) { + /* queue callback for execution */ + usbd_callback_wrapper(xfer, NULL, USBD_CONTEXT_CALLBACK); + } + } + return; +} - struct usbd_xfer *xlist[FINISH_LIST_MAX + 1]; - struct usbd_xfer **xptr = xlist; +/*------------------------------------------------------------------------* + * ohci_interrupt - OHCI interrupt handler + * + * NOTE: Do not access "sc->sc_bus.bdev" inside the interrupt handler, + * hence the interrupt handler will be setup before "sc->sc_bus.bdev" + * is present ! + *------------------------------------------------------------------------*/ +void +ohci_interrupt(ohci_softc_t *sc) +{ struct ohci_hcca *hcca; - struct usbd_xfer *xfer; - struct thread *td; uint32_t status; uint32_t done; - uint8_t need_repeat = 0; - td = ctd; /* default value */ - mtx_lock(&sc->sc_bus.mtx); - if (sc->sc_bus.bdev == NULL) { - /* too early interrupt */ - goto done; - } - if (ctd) { - /* - * the poll thread should not read any status registers that - * will clear interrupts! - */ - goto repeat; - } - td = curthread; /* NULL is not a valid thread */ - hcca = ohci_get_hcca(sc); - DPRINTFN(15, ("%s: real interrupt\n", - device_get_nameunit(sc->sc_bus.bdev))); + DPRINTFN(15, ("real interrupt\n")); #ifdef USB_DEBUG if (ohcidebug > 15) { - DPRINTF(("%s:\n", device_get_nameunit(sc->sc_bus.bdev))); ohci_dumpregs(sc); } #endif @@ -1221,12 +1211,12 @@ } #endif if (status & OHCI_RD) { - device_printf(sc->sc_bus.bdev, "resume detect\n"); + printf("%s: resume detect\n", __FUNCTION__); /* XXX process resume detect */ } if (status & OHCI_UE) { - device_printf(sc->sc_bus.bdev, "unrecoverable error, " - "controller halted\n"); + printf("%s: unrecoverable error, " + "controller halted\n", __FUNCTION__); OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); /* XXX what else */ } @@ -1238,13 +1228,12 @@ sc->sc_eintrs &= ~OHCI_RHSC; OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_RHSC); - if (!usbd_std_root_transfer(&(sc->sc_root_intr), ctd, - &ohci_root_intr_done)) { - mtx_lock(&(sc->sc_bus.mtx)); - } + usbd_std_root_transfer(&(sc->sc_root_intr), + &ohci_root_intr_done); + /* do not allow RHSC interrupts > 1 per second */ usb_callout_reset(&sc->sc_tmo_rhsc, hz, - (void *)(void *)ohci_rhsc_enable, sc); + (void *)&ohci_rhsc_enable, sc); } } status &= ~(OHCI_RHSC | OHCI_WDH | OHCI_SO); @@ -1252,73 +1241,25 @@ /* Block unprocessed interrupts. XXX */ OWRITE4(sc, OHCI_INTERRUPT_DISABLE, status); sc->sc_eintrs &= ~status; - device_printf(sc->sc_bus.bdev, - "blocking intrs 0x%x\n", status); + printf("%s: blocking intrs 0x%x\n", + __FUNCTION__, status); } - /* - * when the host controller interrupts because a transfer - * is completed, all active transfers are checked! - */ + /* poll all the USB transfers */ + ohci_interrupt_poll(sc); -repeat: - LIST_FOREACH(xfer, &sc->sc_interrupt_list_head, interrupt_list) { - /* - * check if transfer is transferred - */ - if (ohci_check_transfer(xfer, ctd)) { - /* queue callback */ - - *(xptr++) = xfer; - - xfer->usb_thread = td; - xfer->usb_root->memory_refcount++; - - /* check queue length */ - if (xptr >= &xlist[FINISH_LIST_MAX]) { - need_repeat = 1; - break; - } - } - } - done: mtx_unlock(&sc->sc_bus.mtx); - - /* zero terminate the callback list */ - *(xptr) = NULL; - - usbd_do_callback(xlist, td); - - if (need_repeat) { - xptr = xlist; - - need_repeat = 0; - mtx_lock(&sc->sc_bus.mtx); - - goto repeat; - } return; } -void -ohci_interrupt(ohci_softc_t *sc) -{ - ohci_interrupt_td(sc, NULL); - return; -} - /* * called when a request does not complete */ static void ohci_timeout(struct usbd_xfer *xfer) { - struct thread *td; - struct usbd_xfer *xlist[2]; ohci_softc_t *sc = xfer->usb_sc; - td = curthread; - DPRINTF(("xfer=%p\n", xfer)); mtx_assert(&sc->sc_bus.mtx, MA_OWNED); @@ -1326,17 +1267,11 @@ /* transfer is transferred */ ohci_device_done(xfer, USBD_TIMEOUT); - /* queue callback */ - xlist[0] = xfer; - xlist[1] = NULL; - - xfer->usb_thread = td; - xfer->usb_root->memory_refcount++; + /* queue callback for execution */ + usbd_callback_wrapper(xfer, NULL, USBD_CONTEXT_CALLBACK); mtx_unlock(&sc->sc_bus.mtx); - usbd_do_callback(xlist, td); - return; } @@ -1344,28 +1279,14 @@ ohci_do_poll(struct usbd_bus *bus) { struct ohci_softc *sc = OHCI_BUS2SC(bus); - struct thread *ctd = curthread; - ohci_interrupt_td(sc, ctd); mtx_lock(&(sc->sc_bus.mtx)); - ohci_root_ctrl_task_td(sc, ctd); + ohci_interrupt_poll(sc); + ohci_root_ctrl_poll(sc); mtx_unlock(&(sc->sc_bus.mtx)); return; } -#define ohci_add_interrupt_info(sc, xfer) \ - LIST_INSERT_HEAD(&(sc)->sc_interrupt_list_head, (xfer), interrupt_list) - -static void -ohci_remove_interrupt_info(struct usbd_xfer *xfer) -{ - if ((xfer)->interrupt_list.le_prev) { - LIST_REMOVE((xfer), interrupt_list); - (xfer)->interrupt_list.le_prev = NULL; - } - return; -} - static void ohci_setup_standard_chain_sub(struct ohci_std_temp *temp) { @@ -1765,12 +1686,6 @@ xfer->td_transfer_first = NULL; xfer->td_transfer_last = NULL; - /* stop timeout */ - usb_callout_stop(&xfer->timeout_handle); - - /* remove interrupt info */ - ohci_remove_interrupt_info(xfer); - if ((methods != &ohci_root_ctrl_methods) && (methods != &ohci_root_intr_methods)) { @@ -1820,7 +1735,7 @@ ohci_setup_standard_chain(xfer, &sc->sc_bulk_p_last); /**/ - ohci_add_interrupt_info(sc, xfer); + usbd_transfer_intr_enqueue(xfer); if (xfer->timeout && (!(xfer->flags.use_polling))) { usb_callout_reset(&xfer->timeout_handle, USBD_MS_TO_TICKS(xfer->timeout), @@ -1870,7 +1785,7 @@ ohci_setup_standard_chain(xfer, &sc->sc_ctrl_p_last); /**/ - ohci_add_interrupt_info(sc, xfer); + usbd_transfer_intr_enqueue(xfer); if (xfer->timeout && (!(xfer->flags.use_polling))) { usb_callout_reset(&xfer->timeout_handle, USBD_MS_TO_TICKS(xfer->timeout), @@ -1952,7 +1867,7 @@ ohci_setup_standard_chain(xfer, &sc->sc_intr_p_last[xfer->qh_pos]); /**/ - ohci_add_interrupt_info(sc, xfer); + usbd_transfer_intr_enqueue(xfer); if (xfer->timeout && (!(xfer->flags.use_polling))) { usb_callout_reset(&xfer->timeout_handle, USBD_MS_TO_TICKS(xfer->timeout), @@ -2151,7 +2066,7 @@ OHCI_APPEND_QH(ed, td->itd_self, sc->sc_isoc_p_last); /**/ - ohci_add_interrupt_info(sc, xfer); + usbd_transfer_intr_enqueue(xfer); /* * enqueue transfer (so that it can be aborted through pipe abort) @@ -2296,12 +2211,12 @@ ohci_root_ctrl_task(struct ohci_softc *sc, struct ohci_config_copy *cc, uint16_t refcount) { - ohci_root_ctrl_task_td(sc, NULL); + ohci_root_ctrl_poll(sc); return; } static void -ohci_root_ctrl_task_td_sub(struct usbd_xfer *xfer, +ohci_root_ctrl_done(struct usbd_xfer *xfer, struct usbd_std_root_transfer *std) { ohci_softc_t *sc = xfer->usb_sc; @@ -2604,12 +2519,10 @@ } static void -ohci_root_ctrl_task_td(struct ohci_softc *sc, struct thread *ctd) +ohci_root_ctrl_poll(struct ohci_softc *sc) { - if (!usbd_std_root_transfer(&(sc->sc_root_ctrl), ctd, - &ohci_root_ctrl_task_td_sub)) { - mtx_lock(&sc->sc_bus.mtx); - } + usbd_std_root_transfer(&(sc->sc_root_ctrl), + &ohci_root_ctrl_done); return; } ==== //depot/projects/usb/src/sys/dev/usb/ohci.h#21 (text+ko) ==== @@ -320,7 +320,6 @@ struct usbd_bus sc_bus; /* base device */ struct usbd_config_td sc_config_td; struct usb_callout sc_tmo_rhsc; - LIST_HEAD(, usbd_xfer) sc_interrupt_list_head; union ohci_hub_desc sc_hub_desc; struct usbd_std_root_transfer sc_root_ctrl; struct usbd_std_root_transfer sc_root_intr; ==== //depot/projects/usb/src/sys/dev/usb/uhci.c#52 (text+ko) ==== @@ -87,8 +87,8 @@ #undef DPRINTFN #define DPRINTF(x) do { if (uhcidebug) { printf("%s: ", __FUNCTION__); printf x ; } } while (0) #define DPRINTFN(n,x) do { if (uhcidebug > (n)) { printf("%s: ", __FUNCTION__); printf x ; } } while (0) -int uhcidebug = 0; -int uhcinoloop = 0; +static int uhcidebug = 0; +static int uhcinoloop = 0; SYSCTL_NODE(_hw_usb, OID_AUTO, uhci, CTLFLAG_RW, 0, "USB uhci"); SYSCTL_INT(_hw_usb_uhci, OID_AUTO, debug, CTLFLAG_RW, @@ -158,7 +158,7 @@ extern struct usbd_pipe_methods uhci_root_intr_methods; static usbd_config_td_command_t uhci_root_ctrl_task; -static void uhci_root_ctrl_task_td(struct uhci_softc *sc, struct thread *ctd); +static void uhci_root_ctrl_poll(struct uhci_softc *sc); static void uhci_do_poll(struct usbd_bus *bus); static void uhci_device_done(struct usbd_xfer *xfer, usbd_status_t error); @@ -618,8 +618,6 @@ usbd_bus_mem_flush_all(&(sc->sc_bus), &uhci_iterate_hw_softc); - LIST_INIT(&sc->sc_interrupt_list_head); - /* set up the bus struct */ sc->sc_bus.methods = &uhci_bus_methods; @@ -852,20 +850,6 @@ return; } -#if 0 -static void -uhci_dump_iis(struct uhci_softc *sc) -{ - struct usbd_xfer *xfer; - - printf("interrupt list:\n"); - LIST_FOREACH(xfer, &sc->sc_interrupt_list_head, interrupt_list) { - usbd_dump_xfer(xfer); - } - return; -} - -#endif #endif /* @@ -1341,18 +1325,12 @@ * Else: USB transfer is finished *------------------------------------------------------------------------*/ static uint8_t -uhci_check_transfer(struct usbd_xfer *xfer, struct thread *ctd) +uhci_check_transfer(struct usbd_xfer *xfer) { uint32_t status; uint32_t token; uhci_td_t *td; - if (xfer->usb_thread != ctd) { - /* - * cannot call this transfer back due to locking ! - */ - goto done; - } DPRINTFN(15, ("xfer=%p checking transfer\n", xfer)); if (xfer->pipe->methods == &uhci_device_isoc_methods) { @@ -1436,54 +1414,40 @@ } static void -uhci_interrupt_td(uhci_softc_t *sc, struct thread *ctd) +uhci_interrupt_poll(uhci_softc_t *sc) { - enum { - FINISH_LIST_MAX = 16}; - - struct usbd_xfer *xlist[FINISH_LIST_MAX + 1]; - struct usbd_xfer **xptr = xlist; struct usbd_xfer *xfer; - struct thread *td; - uint32_t status; - uint8_t need_repeat = 0; - td = ctd; /* default value */ - - mtx_lock(&sc->sc_bus.mtx); - - /* - * It can happen that an interrupt will be delivered to - * us before the device has been fully attached and the - * softc struct has been configured. Usually this happens - * when kldloading the USB support as a module after the - * system has been booted. If we detect this condition, - * we need to squelch the unwanted interrupts until we're - * ready for them. - */ - if (sc->sc_bus.bdev == NULL) { /* XXX */ -#if 0 - UWRITE2(sc, UHCI_STS, 0xFFFF); /* ack pending interrupts */ - uhci_reset(sc); /* stop the controller */ - UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */ -#endif - goto done; - } - if (ctd) { + LIST_FOREACH(xfer, &(sc->sc_bus.intr_list_head), interrupt_list) { /* - * the poll thread should not read any status registers that - * will clear interrupts! + * check if transfer is transferred */ - goto repeat; + if (uhci_check_transfer(xfer)) { + /* queue callback for execution */ + usbd_callback_wrapper(xfer, NULL, USBD_CONTEXT_CALLBACK); + } } - td = curthread; /* NULL is not a valid thread */ + return; +} + +/*------------------------------------------------------------------------* + * uhci_interrupt - UHCI interrupt handler + * + * NOTE: Do not access "sc->sc_bus.bdev" inside the interrupt handler, + * hence the interrupt handler will be setup before "sc->sc_bus.bdev" + * is present ! + *------------------------------------------------------------------------*/ +void +uhci_interrupt(uhci_softc_t *sc) +{ + uint32_t status; + + mtx_lock(&sc->sc_bus.mtx); - DPRINTFN(15, ("%s: real interrupt\n", - device_get_nameunit(sc->sc_bus.bdev))); + DPRINTFN(15, ("real interrupt\n")); #ifdef USB_DEBUG if (uhcidebug > 15) { - DPRINTF(("%s\n", device_get_nameunit(sc->sc_bus.bdev))); uhci_dumpregs(sc); } #endif @@ -1492,27 +1456,31 @@ /* the interrupt was not for us */ goto done; } - if (status & UHCI_STS_RD) { + if (status & (UHCI_STS_RD | UHCI_STS_HSE | + UHCI_STS_HCPE | UHCI_STS_HCH)) { + + if (status & UHCI_STS_RD) { #ifdef USB_DEBUG - device_printf(sc->sc_bus.bdev, - "resume detect\n"); + printf("%s: resume detect\n", + __FUNCTION__); #endif - } - if (status & UHCI_STS_HSE) { - device_printf(sc->sc_bus.bdev, - "host system error\n"); - } - if (status & UHCI_STS_HCPE) { - device_printf(sc->sc_bus.bdev, - "host controller process error\n"); - } - if (status & UHCI_STS_HCH) { >>> TRUNCATED FOR MAIL (1000 lines) <<<