Switch to the same abort mechanism as in [eo]hci; it should be more

robust.
This commit is contained in:
augustss 2002-02-11 11:40:33 +00:00
parent 9baadd8ee5
commit f8204d29e1
1 changed files with 67 additions and 26 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: uhci.c,v 1.152 2002/02/03 18:15:20 augustss Exp $ */
/* $NetBSD: uhci.c,v 1.153 2002/02/11 11:40:33 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $ */
/*
@ -49,7 +49,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.152 2002/02/03 18:15:20 augustss Exp $");
__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.153 2002/02/11 11:40:33 augustss Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -189,6 +189,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 *);
@ -1192,7 +1193,7 @@ uhci_intr1(uhci_softc_t *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);
@ -1272,6 +1273,11 @@ uhci_softintr(void *v)
for (ii = LIST_FIRST(&sc->sc_intrhead); ii; ii = LIST_NEXT(ii, list))
uhci_check_intr(sc, ii);
if (sc->sc_softwake) {
sc->sc_softwake = 0;
wakeup(&sc->sc_softwake);
}
sc->sc_bus.intr_context--;
}
@ -1459,17 +1465,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);
}
/*
@ -1867,35 +1889,54 @@ 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;
if (xfer->device->bus->intr_context || !curproc)
panic("ohci_abort_xfer: not in process context\n");
/* don't timeout, */
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);
/* make hardware ignore it, */
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));
xfer->hcpriv = ii;
splx(s);
delay(1000);
/*
* 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