Improve xfer abort sequence.

Fix another bug in qTD chain allocation.
This commit is contained in:
augustss 2001-11-23 01:16:27 +00:00
parent 6d8419a6cc
commit cdc819cd8a
2 changed files with 53 additions and 25 deletions

View File

@ -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 */
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 4: Turn on hardware again.
*/
/* XXX */
/*
* 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

View File

@ -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