summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authoraugustss <augustss@NetBSD.org>2001-11-23 01:16:27 +0000
committeraugustss <augustss@NetBSD.org>2001-11-23 01:16:27 +0000
commitcdc819cd8abf03fd122b88ba528818ebbebfd8f6 (patch)
tree7df9871aee16e6be632c4fb1e6ad740172b4484a /sys/dev
parent6d8419a6cc8da98d13cfb4e82fea6ea66550b718 (diff)
Improve xfer abort sequence.
Fix another bug in qTD chain allocation.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/ehci.c74
-rw-r--r--sys/dev/usb/ehcireg.h4
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