diff options
| author | augustss <augustss@NetBSD.org> | 2001-11-23 01:16:27 +0000 |
|---|---|---|
| committer | augustss <augustss@NetBSD.org> | 2001-11-23 01:16:27 +0000 |
| commit | cdc819cd8abf03fd122b88ba528818ebbebfd8f6 (patch) | |
| tree | 7df9871aee16e6be632c4fb1e6ad740172b4484a /sys/dev | |
| parent | 6d8419a6cc8da98d13cfb4e82fea6ea66550b718 (diff) | |
Improve xfer abort sequence.
Fix another bug in qTD chain allocation.
Diffstat (limited to 'sys/dev')
| -rw-r--r-- | sys/dev/usb/ehci.c | 74 | ||||
| -rw-r--r-- | sys/dev/usb/ehcireg.h | 4 |
2 files changed, 53 insertions, 25 deletions
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c index 18962bd8e27..dd514d21028 100644 --- a/sys/dev/usb/ehci.c +++ b/sys/dev/usb/ehci.c @@ -1,4 +1,4 @@ -/* $NetBSD: ehci.c,v 1.25 2001/11/22 04:20:49 augustss Exp $ */ +/* $NetBSD: ehci.c,v 1.26 2001/11/23 01:16:27 augustss Exp $ */ /* * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -47,7 +47,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.25 2001/11/22 04:20:49 augustss Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.26 2001/11/23 01:16:27 augustss Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -377,8 +377,7 @@ ehci_init(ehci_softc_t *sc) /* Fill the overlay qTD */ sqh->qh.qh_qtd.qtd_next = EHCI_NULL; sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL; - sqh->qh.qh_qtd.qtd_status = - htole32(EHCI_QTD_SET_STATUS(EHCI_QTD_HALTED)); + sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED); sqh->sqtd = NULL; #ifdef EHCI_DEBUG if (ehcidebug) { @@ -699,7 +698,8 @@ ehci_idone(struct ehci_xfer *ex) /* If there are left over TDs we need to update the toggle. */ if (sqtd != NULL) { - printf("ehci_idone: need toggle update\n"); + if (!(xfer->rqflags & URQ_REQUEST)) + printf("ehci_idone: need toggle update\n"); #if 0 epipe->nexttoggle = EHCI_TD_GET_DT(le32toh(std->td.td_token)); #endif @@ -2042,7 +2042,7 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, dataphys = DMAADDR(dma); dataphyslastpage = EHCI_PAGE(dataphys + len - 1); qtdstatus = htole32( - EHCI_QTD_SET_STATUS(EHCI_QTD_ACTIVE) | + EHCI_QTD_ACTIVE | EHCI_QTD_SET_PID(rd ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) | EHCI_QTD_SET_CERR(3) /* IOC set below */ @@ -2056,9 +2056,9 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, goto nomem; for (;;) { dataphyspage = EHCI_PAGE(dataphys); - /* The EHCI hardware can handle at most 4 page crossings. */ + /* The EHCI hardware can handle at most 5 pages. */ if (dataphyslastpage - dataphyspage < - (EHCI_QTD_NBUFFERS-1) * EHCI_PAGE_SIZE) { + EHCI_QTD_NBUFFERS * EHCI_PAGE_SIZE) { /* we can handle it in this QTD */ curlen = len; } else { @@ -2067,8 +2067,12 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, EHCI_PAGE_OFFSET(dataphys); #ifdef DIAGNOSTIC if (curlen > len) { - printf("ehci_alloc_sqtd_chain: curlen=%d " - "len=%d\n", curlen, len); + printf("ehci_alloc_sqtd_chain: curlen=0x%x " + "len=0x%x offs=0x%x\n", curlen, len, + EHCI_PAGE_OFFSET(dataphys)); + printf("lastpage=0x%x page=0x%x phys=0x%x\n", + dataphyslastpage, dataphyspage, + dataphys); curlen = len; } #endif @@ -2178,13 +2182,20 @@ ehci_close_pipe(usbd_pipe_handle pipe, ehci_soft_qh_t *head) * have happened since the hardware runs concurrently. * If the transaction has already happened we rely on the ordinary * interrupt processing to process it. + * XXX This is most probably wrong. */ void ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) { +#define exfer EXFER(xfer) struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe; ehci_softc_t *sc = (ehci_softc_t *)epipe->pipe.device->bus; + ehci_soft_qh_t *sqh = epipe->sqh; + ehci_soft_qtd_t *sqtd; + ehci_physaddr_t cur; + u_int32_t qhstatus; int s; + int hit; DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe)); @@ -2207,15 +2218,21 @@ ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) s = splusb(); xfer->status = status; /* make software ignore it */ usb_uncallout(xfer->timeout_handle, ehci_timeout, xfer); + qhstatus = sqh->qh.qh_qtd.qtd_status; + sqh->qh.qh_qtd.qtd_status = qhstatus | htole32(EHCI_QTD_HALTED); + for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) { + sqtd->qtd.qtd_status |= htole32(EHCI_QTD_HALTED); + if (sqtd == exfer->sqtdend) + break; + } splx(s); - /* XXX */ /* * 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(epipe->pipe.device->bus, 1); /* Hardware finishes in 1ms */ + ehci_sync_hc(sc); /* XXX should have some communication with softintr() to know when it's done */ usb_delay_ms(epipe->pipe.device->bus, 250); @@ -2228,22 +2245,33 @@ ehci_abort_xfer(usbd_xfer_handle xfer, usbd_status status) * any of them. */ s = splusb(); /* XXX why? */ - /* XXX */ - - /* - * Step 4: Turn on hardware again. - */ - /* XXX */ + cur = EHCI_LINK_ADDR(le32toh(sqh->qh.qh_curqtd)); + hit = 0; + for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) { + hit |= cur == sqtd->physaddr; + if (sqtd == exfer->sqtdend) + break; + } + sqtd = sqtd->nextqtd; + /* Zap curqtd register if hardware pointed inside the xfer. */ + if (hit && sqtd != NULL) { + DPRINTFN(1,("ehci_abort_xfer: cur=0x%08x\n", sqtd->physaddr)); + sqh->qh.qh_curqtd = htole32(sqtd->physaddr); /* unlink qTDs */ + sqh->qh.qh_qtd.qtd_status = qhstatus; + } else { + DPRINTFN(1,("ehci_abort_xfer: no hit\n")); + } /* - * Step 5: Execute callback. + * Step 4: Execute callback. */ #ifdef DIAGNOSTIC - EXFER(xfer)->isdone = 1; + exfer->isdone = 1; #endif usb_transfer_complete(xfer); splx(s); +#undef exfer } void @@ -2255,7 +2283,7 @@ ehci_timeout(void *addr) DPRINTF(("ehci_timeout: exfer=%p\n", exfer)); #ifdef USB_DEBUG - if (ehcidebug) + if (ehcidebug > 1) usbd_dump_pipe(exfer->xfer.pipe); #endif @@ -2446,7 +2474,7 @@ ehci_device_request(usbd_xfer_handle xfer) memcpy(KERNADDR(&epipe->u.ctl.reqdma), req, sizeof *req); setup->qtd.qtd_status = htole32( - EHCI_QTD_SET_STATUS(EHCI_QTD_ACTIVE) | + EHCI_QTD_ACTIVE | EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) | EHCI_QTD_SET_CERR(3) | EHCI_QTD_SET_BYTES(sizeof *req) @@ -2458,7 +2486,7 @@ ehci_device_request(usbd_xfer_handle xfer) setup->len = sizeof *req; stat->qtd.qtd_status = htole32( - EHCI_QTD_SET_STATUS(EHCI_QTD_ACTIVE) | + EHCI_QTD_ACTIVE | EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN) | EHCI_QTD_SET_CERR(3) | EHCI_QTD_IOC diff --git a/sys/dev/usb/ehcireg.h b/sys/dev/usb/ehcireg.h index fccda9b8cc3..88667a4c938 100644 --- a/sys/dev/usb/ehcireg.h +++ b/sys/dev/usb/ehcireg.h @@ -1,4 +1,4 @@ -/* $NetBSD: ehcireg.h,v 1.12 2001/11/21 12:28:23 augustss Exp $ */ +/* $NetBSD: ehcireg.h,v 1.13 2001/11/23 01:16:27 augustss Exp $ */ /* * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -181,6 +181,7 @@ typedef u_int32_t ehci_link_t; #define EHCI_LINK_QH 0x2 #define EHCI_LINK_SITD 0x4 #define EHCI_LINK_FSTN 0x6 +#define EHCI_LINK_ADDR(x) ((x) &~ 0x1f) typedef u_int32_t ehci_physaddr_t; @@ -205,7 +206,6 @@ typedef struct { ehci_link_t qtd_altnext; u_int32_t qtd_status; #define EHCI_QTD_GET_STATUS(x) (((x) >> 0) & 0xff) -#define EHCI_QTD_SET_STATUS(x) ((x) << 0) #define EHCI_QTD_ACTIVE 0x80 #define EHCI_QTD_HALTED 0x40 #define EHCI_QTD_BUFERR 0x20 |
