Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/usb Be a little more careful when aborting.
details: https://anonhg.NetBSD.org/src/rev/6b7533e567f9
branches: trunk
changeset: 484204:6b7533e567f9
user: augustss <augustss%NetBSD.org@localhost>
date: Mon Mar 27 22:42:57 2000 +0000
description:
Be a little more careful when aborting.
Preallocate some TDs for large buffers.
diffstat:
sys/dev/usb/uhci.c | 92 ++++++++++++++++++++++++++++++++++++++---------------
1 files changed, 66 insertions(+), 26 deletions(-)
diffs (222 lines):
diff -r 3f2a7908fdb5 -r 6b7533e567f9 sys/dev/usb/uhci.c
--- a/sys/dev/usb/uhci.c Mon Mar 27 22:40:48 2000 +0000
+++ b/sys/dev/usb/uhci.c Mon Mar 27 22:42:57 2000 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: uhci.c,v 1.101 2000/03/27 12:33:55 augustss Exp $ */
+/* $NetBSD: uhci.c,v 1.102 2000/03/27 22:42:57 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.33 1999/11/17 22:33:41 n_hibma Exp $ */
/*
@@ -182,7 +182,7 @@
Static void uhci_abort_xfer_end __P((void *v));
Static void uhci_abort_unlink_qh __P((struct uhci_pipe *));
Static void uhci_abort_relink_qh __P((struct uhci_pipe *));
-Static void uhci_cancel_abort __P((usbd_pipe_handle));
+Static void uhci_wait_abort __P((usbd_pipe_handle));
Static void uhci_timeout __P((void *));
Static void uhci_add_ctrl __P((uhci_softc_t *, uhci_soft_qh_t *));
@@ -357,7 +357,7 @@
for (; pqh->hlink != sqh; pqh = pqh->hlink) {
#if defined(DIAGNOSTIC) || defined(UHCI_DEBUG)
if (le32toh(pqh->qh.qh_hlink) & UHCI_PTR_T) {
- printf("uhci_find_qh: QH not found\n");
+ printf("uhci_find_prev_qh: QH not found\n");
return (NULL);
}
#endif
@@ -540,8 +540,32 @@
usb_dma_t *dma;
u_int32_t size;
{
- return (usb_allocmem(&((struct uhci_softc *)bus)->sc_bus, size, 0,
- dma));
+ struct uhci_softc *sc = (struct uhci_softc *)bus;
+ u_int32_t n;
+
+ /*
+ * XXX
+ * Since we are allocating a buffer we can assume that we will
+ * need TDs for it. Since we don't want to alolocate those from
+ * an interrupt context, we allocate them here and free them again.
+ * This is no guarantee that we'll get the TDs next time...
+ */
+ n = size / 8;
+ if (n > 16) {
+ u_int32_t i;
+ uhci_soft_td_t **stds;
+ DPRINTF(("uhci_allocm: get %d TDs\n", n));
+ stds = malloc(sizeof(uhci_soft_td_t *) * n, M_TEMP, M_NOWAIT);
+ memset(stds, 0, sizeof(uhci_soft_td_t *) * n);
+ for(i=0; i < n; i++)
+ stds[i] = uhci_alloc_std(sc);
+ for(i=0; i < n; i++)
+ if (stds[i] != NULL)
+ uhci_free_std(sc, stds[i]);
+ free(stds, M_TEMP);
+ }
+
+ return (usb_allocmem(&sc->sc_bus, size, 0, dma));
}
void
@@ -1618,7 +1642,7 @@
#endif
len = xfer->length;
- endpt = xfer->pipe->endpoint->edesc->bEndpointAddress;
+ endpt = upipe->pipe.endpoint->edesc->bEndpointAddress;
isread = UE_GET_DIR(endpt) == UE_DIR_IN;
sqh = upipe->u.bulk.sqh;
@@ -1736,8 +1760,7 @@
* - Turn off flag about abort in progress.
* Done!
*
- * The timeout is associated with the pipe and it must be cancelled if
- * the pipe is closed.
+ * If the pipe is closed, the abort must be allowed to finish.
*/
void
@@ -1810,9 +1833,12 @@
usb_transfer_complete(xfer);
/* Set up final processing. */
- usb_callout(xfer->pipe->abort_handle, hz / USB_FRAMES_PER_SECOND,
+ usb_callout(upipe->pipe.abort_handle, hz / USB_FRAMES_PER_SECOND,
uhci_abort_xfer_end, upipe);
+ /* Pretend we are running to avoid QH manipulation. */
+ upipe->pipe.running = 1;
+
/* And return. */
splx(s);
}
@@ -1822,13 +1848,14 @@
void *v;
{
struct uhci_pipe *upipe = v;
- usbd_xfer_handle xf;
+ usbd_xfer_handle xfer;
uhci_soft_td_t *std;
uhci_soft_qh_t *sqh, **qhs;
+ usbd_status err;
int s;
int i, nqhs;
- DPRINTFN(5,("uhci_abort_xfer_end: upipe=%p\n", upipe));
+ DPRINTFN(2,("uhci_abort_xfer_end: upipe=%p\n", upipe));
switch (UE_GET_XFERTYPE(upipe->pipe.endpoint->edesc->bmAttributes)) {
case UE_CONTROL:
@@ -1859,14 +1886,14 @@
for (i = 0; i < nqhs; i++) {
sqh = qhs[i];
/* Check if inside remaining TD chain. */
- for (xf = upipe->abortstart; xf != NULL;
- xf = SIMPLEQ_NEXT(xf, next)) {
- for (std = UXFER(xf)->iinfo.stdstart; std != NULL;
+ for (xfer = upipe->abortstart; xfer != NULL;
+ xfer = SIMPLEQ_NEXT(xfer, next)) {
+ for (std = UXFER(xfer)->iinfo.stdstart; std != NULL;
std = std->link.std) {
if (std->physaddr == le32toh(sqh->qh.qh_elink))
goto outside;
}
- if (xf == upipe->abortend)
+ if (xfer == upipe->abortend)
break;
}
if (upipe->abortstart != NULL) {
@@ -1889,6 +1916,22 @@
/* No longer aborting */
upipe->aborting = 0;
+ /* Wake anyone waiting for the abort to finish. */
+ wakeup(&upipe->aborting);
+
+ /* Start next xfer, if there is one. */
+ xfer = SIMPLEQ_FIRST(&upipe->pipe.queue);
+ if (xfer == NULL) {
+ upipe->pipe.running = 0;
+ } else {
+ err = upipe->pipe.methods->start(xfer);
+ if (err != USBD_IN_PROGRESS) {
+ printf("usbd_start_next: error=%d\n", err);
+ upipe->pipe.running = 0;
+ /* XXX do what? */
+ }
+ }
+
splx(s);
}
@@ -1981,17 +2024,15 @@
}
void
-uhci_cancel_abort(pipe)
+uhci_wait_abort(pipe)
usbd_pipe_handle pipe;
{
struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
int s;
s = splusb();
- if (upipe->aborting) {
- usb_uncallout(pipe->abort_handle, uhci_abort_xfer_end, upipe);
- upipe->aborting = 0;
- }
+ while (upipe->aborting)
+ tsleep(&upipe->aborting, PWAIT, "uhciab", 0);
splx(s);
}
@@ -2005,7 +2046,7 @@
usbd_device_handle dev = upipe->pipe.device;
uhci_softc_t *sc = (uhci_softc_t *)dev->bus;
- uhci_cancel_abort(pipe);
+ uhci_wait_abort(pipe);
uhci_free_sqh(sc, upipe->u.bulk.sqh);
}
@@ -2155,7 +2196,7 @@
uhci_device_ctrl_close(pipe)
usbd_pipe_handle pipe;
{
- uhci_cancel_abort(pipe);
+ uhci_wait_abort(pipe);
}
/* Abort a device interrupt request. */
@@ -2181,7 +2222,7 @@
int i, npoll;
int s;
- uhci_cancel_abort(pipe);
+ uhci_wait_abort(pipe);
/* Unlink descriptors from controller data structures. */
npoll = upipe->u.intr.npoll;
@@ -2350,7 +2391,7 @@
/* insert into schedule, */
uhci_device_isoc_enter(xfer);
- /* and put on interrupt list if the pipe wasn't running */
+ /* and start if the pipe wasn't running */
if (!err)
uhci_device_isoc_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
@@ -2468,9 +2509,8 @@
ii->stdstart = end;
ii->stdend = end;
#ifdef DIAGNOSTIC
- if (!ii->isdone) {
+ if (!ii->isdone)
printf("uhci_device_isoc_start: not done, ii=%p\n", ii);
- }
ii->isdone = 0;
#endif
uhci_add_intr_info(sc, ii);
Home |
Main Index |
Thread Index |
Old Index