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.
This commit is contained in:
joe 2002-04-07 18:03:45 +00:00
parent 2baf91fe25
commit f9e691f784

View File

@ -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);
}