From 944817ec342094827161ef3272e349a42a0f4010 Mon Sep 17 00:00:00 2001 From: joe Date: Sun, 7 Apr 2002 18:03:45 +0000 Subject: [PATCH] MFNetBSD: revision 1.153 date: 2002/02/11 11:40:33; author: augustss; state: Exp; lines: +67 -26 Switch to the same abort mechanism as in [eo]hci; it should be more robust. --- sys/dev/usb/uhci.c | 100 ++++++++++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 28 deletions(-) diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c index bb9ea17eb663..1dcd8691c544 100644 --- a/sys/dev/usb/uhci.c +++ b/sys/dev/usb/uhci.c @@ -1,4 +1,4 @@ -/* $NetBSD: uhci.c,v 1.151 2002/01/27 23:00:34 augustss Exp $ */ +/* $NetBSD: uhci.c,v 1.153 2002/02/11 11:40:33 augustss Exp $ */ /* $FreeBSD$ */ /* @@ -181,6 +181,7 @@ Static void uhci_idone(uhci_intr_info_t *); Static void uhci_abort_xfer(usbd_xfer_handle, usbd_status status); Static void uhci_timeout(void *); +Static void uhci_timeout_task(void *); Static void uhci_add_ls_ctrl(uhci_softc_t *, uhci_soft_qh_t *); Static void uhci_add_hs_ctrl(uhci_softc_t *, uhci_soft_qh_t *); Static void uhci_add_bulk(uhci_softc_t *, uhci_soft_qh_t *); @@ -1193,7 +1194,7 @@ uhci_intr1(uhci_softc_t *sc) uhci_dumpregs(sc); } #endif - status = UREAD2(sc, UHCI_STS); + status = UREAD2(sc, UHCI_STS) & UHCI_STS_ALLINTRS; if (status == 0) /* The interrupt was not for us. */ return (0); @@ -1278,6 +1279,11 @@ uhci_softintr(void *v) LIST_FOREACH(ii, &sc->sc_intrhead, list) uhci_check_intr(sc, ii); + if (sc->sc_softwake) { + sc->sc_softwake = 0; + wakeup(&sc->sc_softwake); + } + sc->sc_bus.intr_context--; } @@ -1465,17 +1471,33 @@ void uhci_timeout(void *addr) { uhci_intr_info_t *ii = addr; + struct uhci_xfer *uxfer = UXFER(ii->xfer); + struct uhci_pipe *upipe = (struct uhci_pipe *)uxfer->xfer.pipe; + uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus; - DPRINTF(("uhci_timeout: ii=%p\n", ii)); + DPRINTF(("uhci_timeout: uxfer=%p\n", uxfer)); -#ifdef UHCI_DEBUG - if (uhcidebug > 10) - uhci_dump_tds(ii->stdstart); -#endif + if (sc->sc_dying) { + uhci_abort_xfer(&uxfer->xfer, USBD_TIMEOUT); + return; + } - ii->xfer->device->bus->intr_context++; - uhci_abort_xfer(ii->xfer, USBD_TIMEOUT); - ii->xfer->device->bus->intr_context--; + /* Execute the abort in a process context. */ + usb_init_task(&uxfer->abort_task, uhci_timeout_task, addr); + usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task); +} + +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); } /* @@ -1872,39 +1894,61 @@ void uhci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) { uhci_intr_info_t *ii = &UXFER(xfer)->iinfo; + struct uhci_pipe *upipe = (struct uhci_pipe *)xfer->pipe; + uhci_softc_t *sc = (uhci_softc_t *)upipe->pipe.device->bus; uhci_soft_td_t *std; int s; DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status)); - s = splusb(); - - /* Transfer is already done. */ - if (xfer->status != USBD_NOT_STARTED && - xfer->status != USBD_IN_PROGRESS) { + if (sc->sc_dying) { + /* If we're dying, just do the software part. */ + s = splusb(); + xfer->status = status; /* make software ignore it */ + usb_uncallout(xfer->timeout_handle, ehci_timeout, xfer); + usb_transfer_complete(xfer); splx(s); return; } - /* Make interrupt routine ignore it, */ - xfer->status = status; - - /* don't timeout, */ - usb_uncallout(xfer->timeout_handle, uhci_timeout, ii); - - /* make hardware ignore it, */ - for (std = ii->stdstart; std != NULL; std = std->link.std) - std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC)); - - xfer->hcpriv = ii; - - splx(s); + if (xfer->device->bus->intr_context || !curproc) + panic("ohci_abort_xfer: not in process context\n"); s = splusb(); + /* + * Step 1: Make interrupt routine and hardware ignore xfer. + */ + s = splusb(); + xfer->status = status; /* make software ignore it */ + usb_uncallout(xfer->timeout_handle, uhci_timeout, ii); + DPRINTFN(1,("uhci_abort_xfer: stop ii=%p\n", ii)); + for (std = ii->stdstart; std != NULL; std = std->link.std) + std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC)); + splx(s); + + /* + * Step 2: Wait until we know hardware has finished any possible + * use of the xfer. Also make sure the soft interrupt routine + * has run. + */ + usb_delay_ms(upipe->pipe.device->bus, 20); /* Hardware finishes in 1ms */ + s = splusb(); + sc->sc_softwake = 1; + usb_schedsoftintr(&sc->sc_bus); + tsleep(&sc->sc_softwake, PZERO, "uhciab", 0); + splx(s); + + /* + * Step 3: Execute callback. + */ + xfer->hcpriv = ii; + + s = splusb(); #ifdef DIAGNOSTIC ii->isdone = 1; #endif + usb_transfer_complete(xfer); splx(s); }