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:
parent
2baf91fe25
commit
f9e691f784
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user