summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjoe <joe@FreeBSD.org>2002-04-07 18:03:45 +0000
committerjoe <joe@FreeBSD.org>2002-04-07 18:03:45 +0000
commit944817ec342094827161ef3272e349a42a0f4010 (patch)
treefdcf1d4ec54007540bc554b8a66d241c16ff4c82
parenta1fa7bc7e96e0002834d84fd145690eb1789630e (diff)
downloadFreeBSD-src-944817ec342094827161ef3272e349a42a0f4010.zip
FreeBSD-src-944817ec342094827161ef3272e349a42a0f4010.tar.gz
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.
-rw-r--r--sys/dev/usb/uhci.c90
1 files changed, 67 insertions, 23 deletions
diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c
index bb9ea17..1dcd869 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;
+ if (xfer->device->bus->intr_context || !curproc)
+ panic("ohci_abort_xfer: not in process context\n");
- /* don't timeout, */
- usb_uncallout(xfer->timeout_handle, uhci_timeout, ii);
+ s = splusb();
- /* make hardware ignore it, */
+ /*
+ * 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));
-
- xfer->hcpriv = ii;
-
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);
}
OpenPOWER on IntegriCloud