diff --git a/sys/src/9/pc/usbuhci.c b/sys/src/9/pc/usbuhci.c index 3bf01ced1..043b52dd8 100644 --- a/sys/src/9/pc/usbuhci.c +++ b/sys/src/9/pc/usbuhci.c @@ -30,7 +30,7 @@ enum { Resetdelay = 100, /* delay after a controller reset (ms) */ Enabledelay = 100, /* waiting for a port to enable */ - Abortdelay = 5, /* delay after cancelling Tds (ms) */ + Abortdelay = 10, /* delay after cancelling Tds (ms) */ Incr = 64, /* for Td and Qh pools */ Tdatomic = 8, /* max nb. of Tds per bulk I/O op. */ @@ -704,12 +704,8 @@ static void qhfree(Ctlr *ctlr, Qh *qh) { Td *td; - Td *ltd; Qh *q; - if(qh == nil) - return; - ilock(ctlr); for(q = ctlr->qhs; q != nil; q = q->next) if(q->next == qh) @@ -718,14 +714,15 @@ qhfree(Ctlr *ctlr, Qh *qh) panic("qhfree: nil q"); q->next = qh->next; q->link = qh->link; + qh->state = Qfree; /* paranoia */ iunlock(ctlr); - for(td = qh->tds; td != nil; td = ltd){ - ltd = td->next; + while((td = qh->tds) != nil){ + qh->tds = td->next; tdfree(td); } + lock(&qhpool); - qh->state = Qfree; /* paranoia */ qh->next = qhpool.free; qh->tag = nil; qh->io = nil; @@ -961,14 +958,14 @@ interrupt(Ureg*, void *a) OUTS(Status, sts & Sall); cmd = INS(Cmd); if(cmd & Crun == 0){ - print("uhci %#ux: not running: uhci bug?\n", ctlr->port); + iprint("uhci %#ux: not running: uhci bug?\n", ctlr->port); /* BUG: should abort everything in this case */ } if(debug > 1){ frptr = INL(Flbaseadd); frno = INL(Frnum); frno = TRUNC(frno, Nframes); - print("cmd %#ux sts %#ux frptr %#ux frno %d\n", + iprint("cmd %#ux sts %#ux frptr %#ux frno %d\n", cmd, sts, frptr, frno); } ctlr->ntdintr++; @@ -1220,12 +1217,14 @@ aborttds(Qh *qh) { Td *td; - qh->state = Qdone; qh->elink = QHterm; + coherence(); for(td = qh->tds; td != nil; td = td->next){ - if(td->csw & Tdactive) + if(td->csw & Tdactive){ td->ndata = 0; - td->csw &= ~(Tdactive|Tdioc); + td->csw &= ~(Tdactive|Tdioc); + coherence(); + } } } @@ -1263,13 +1262,15 @@ epiowait(Ctlr *ctlr, Qio *io, int tmout, ulong load) else if(qh->state != Qdone && qh->state != Qclose) panic("epio: queue not done and not closed"); if(timedout){ - aborttds(io->qh); - io->err = "request timed out"; + aborttds(qh); + qh->state = Qdone; + if(io->err == nil) + io->err = "request timed out"; iunlock(ctlr); - if(!waserror()){ - tsleep(&up->sleep, return0, 0, Abortdelay); - poperror(); - } + while(waserror()) + ; + tsleep(&up->sleep, return0, 0, Abortdelay); + poperror(); ilock(ctlr); } if(qh->state != Qclose) @@ -1297,7 +1298,6 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock) ulong load; char *err; - qh = io->qh; ctlr = ep->hp->aux; io->debug = ep->debug; tmout = ep->tmout; @@ -1317,7 +1317,8 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock) } io->err = nil; ilock(ctlr); - if(qh->state == Qclose){ /* Tds released by cancelio */ + qh = io->qh; + if(qh == nil || qh->state == Qclose){ /* Tds released by cancelio */ iunlock(ctlr); error(io->err ? io->err : Eio); } @@ -1365,6 +1366,8 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock) if(debug > 1 || ep->debug > 1) dumptd(td0, "epio: got tds: "); + err = io->err; + tot = 0; c = a; saved = 0; @@ -1380,16 +1383,22 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock) if(saved++ == 0) io->toggle = td->token & Tddata1; }else{ - tot += td->ndata; - if(c != nil && tdtok(td) == Tdtokin && td->ndata > 0){ - memmove(c, td->data, td->ndata); - c += td->ndata; + n = td->ndata; + if(err == nil && n < 0) + err = Eio; + if(err == nil && n > 0 && tot < count){ + if((tot + n) > count) + n = count - tot; + if(c != nil && tdtok(td) == Tdtokin){ + memmove(c, td->data, n); + c += n; + } + tot += n; } } ntd = td->next; tdfree(td); } - err = io->err; if(mustlock){ qunlock(io); poperror(); @@ -1398,8 +1407,6 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock) io, ntds, tot, err); if(err != nil) error(err); - if(tot < 0) - error(Eio); return tot; } @@ -1817,7 +1824,7 @@ cancelio(Ctlr *ctlr, Qio *io) ilock(ctlr); qh = io->qh; - if(io == nil || io->qh == nil || io->qh->state == Qclose){ + if(qh == nil || qh->state == Qclose){ iunlock(ctlr); return; } @@ -1826,18 +1833,20 @@ cancelio(Ctlr *ctlr, Qio *io) aborttds(qh); qh->state = Qclose; iunlock(ctlr); - if(!waserror()){ - tsleep(&up->sleep, return0, 0, Abortdelay); - poperror(); - } + + while(waserror()) + ; + tsleep(&up->sleep, return0, 0, Abortdelay); + poperror(); wakeup(io); qlock(io); /* wait for epio if running */ + if(io->qh == qh) + io->qh = nil; qunlock(io); qhfree(ctlr, qh); - io->qh = nil; } static void diff --git a/sys/src/9/port/usbehci.c b/sys/src/9/port/usbehci.c index 207b93d44..dd6ac8820 100644 --- a/sys/src/9/port/usbehci.c +++ b/sys/src/9/port/usbehci.c @@ -53,7 +53,7 @@ enum Qfree, Enabledelay = 100, /* waiting for a port to enable */ - Abortdelay = 5, /* delay after cancelling Tds (ms) */ + Abortdelay = 10, /* delay after cancelling Tds (ms) */ Incr = 64, /* for pools of Tds, Qhs, etc. */ Align = 128, /* in bytes for all those descriptors */ @@ -739,11 +739,12 @@ qhcoherency(Ctlr *ctlr) qlock(&ctlr->portlck); ctlr->opio->cmd |= Ciasync; /* ask for intr. on async advance */ coherence(); - for(i = 0; i < 3 && qhadvanced(ctlr) == 0; i++) - if(!waserror()){ - tsleep(ctlr, qhadvanced, ctlr, Abortdelay); - poperror(); - } + for(i = 0; i < 3 && qhadvanced(ctlr) == 0; i++){ + while(waserror()) + ; + tsleep(ctlr, qhadvanced, ctlr, Abortdelay); + poperror(); + } dprint("ehci: qhcoherency: doorbell %d\n", qhadvanced(ctlr)); if(i == 3) print("ehci: async advance doorbell did not ring\n"); @@ -754,11 +755,9 @@ qhcoherency(Ctlr *ctlr) static void qhfree(Ctlr *ctlr, Qh *qh) { - Td *td, *ltd; + Td *td; Qh *q; - if(qh == nil) - return; ilock(ctlr); if(qh->sched < 0){ for(q = ctlr->qhs; q != nil; q = q->next) @@ -771,12 +770,13 @@ qhfree(Ctlr *ctlr, Qh *qh) coherence(); }else unschedq(ctlr, qh); + qh->state = Qfree; /* paranoia */ iunlock(ctlr); qhcoherency(ctlr); - for(td = qh->tds; td != nil; td = ltd){ - ltd = td->next; + while((td = qh->tds) != nil){ + qh->tds = td->next; tdfree(td); } @@ -1512,36 +1512,30 @@ qhinterrupt(Ctlr *ctlr, Qh *qh) } static int -ehciintr(Hci *hp) +ctlrinterrupt(Ctlr *ctlr) { - Ctlr *ctlr; Eopio *opio; Isoio *iso; ulong sts; Qh *qh; int i, some; - ctlr = hp->aux; opio = ctlr->opio; - /* * Will we know in USB 3.0 who the interrupt was for?. * Do they still teach indexing in CS? * This is Intel's doing. */ - ilock(ctlr); - ctlr->nintr++; sts = opio->sts & Sintrs; - if(sts == 0){ /* not ours; shared intr. */ - iunlock(ctlr); + if(sts == 0) /* not ours; shared intr. */ return 0; - } opio->sts = sts; coherence(); + ctlr->nintr++; if((sts & Sherr) != 0) - print("ehci: port %#p fatal host system error\n", ctlr->capio); + iprint("ehci: port %#p fatal host system error\n", ctlr->capio); if((sts & Shalted) != 0) - print("ehci: port %#p: halted\n", ctlr->capio); + iprint("ehci: port %#p: halted\n", ctlr->capio); if((sts & Sasync) != 0){ dprint("ehci: doorbell\n"); wakeup(ctlr); @@ -1555,12 +1549,12 @@ ehciintr(Hci *hp) if((sts & (Serrintr|Sintr)) != 0){ ctlr->ntdintr++; if(ehcidebug > 1){ - print("ehci port %#p frames %#p nintr %d ntdintr %d", + iprint("ehci port %#p frames %#p nintr %d ntdintr %d", ctlr->capio, ctlr->frames, ctlr->nintr, ctlr->ntdintr); - print(" nqhintr %d nisointr %d\n", + iprint(" nqhintr %d nisointr %d\n", ctlr->nqhintr, ctlr->nisointr); - print("\tcmd %#lux sts %#lux intr %#lux frno %uld", + iprint("\tcmd %#lux sts %#lux intr %#lux frno %uld", opio->cmd, opio->sts, opio->intr, opio->frno); } @@ -1588,8 +1582,20 @@ ehciintr(Hci *hp) qh = qh->next; }while(qh != ctlr->qhs && i++ < 100); if(i > 100) - print("echi: interrupt: qh loop?\n"); + iprint("echi: interrupt: qh loop?\n"); } + return some; +} + +static int +ehciintr(Hci *hp) +{ + Ctlr *ctlr; + int some; + + ctlr = hp->aux; + ilock(ctlr); + some = ctlrinterrupt(ctlr); iunlock(ctlr); return some; } @@ -1694,7 +1700,7 @@ portreset(Hci *hp, int port, int on) for(i = 0; *portscp & Psreset && i < 10; i++) delay(10); if (*portscp & Psreset) - iprint("ehci %#p: port %d didn't reset within %d ms; sts %#lux\n", + if(0) iprint("ehci %#p: port %d didn't reset within %d ms; sts %#lux\n", ctlr->capio, port, i * 10, *portscp); *portscp &= ~Psreset; /* force appearance of reset done */ coherence(); @@ -2180,16 +2186,16 @@ aborttds(Qh *qh) { Td *td; - qh->state = Qdone; - coherence(); if(qh->sched >= 0 && (qh->eps0 & Qhspeedmask) != Qhhigh) qh->eps0 |= Qhint; /* inactivate on next pass */ + qh->csw = (qh->csw & ~Tdactive) | Tdhalt; coherence(); for(td = qh->tds; td != nil; td = td->next){ - if(td->csw & Tdactive) + if(td->csw & Tdactive){ td->ndata = 0; - td->csw |= Tdhalt; - coherence(); + td->csw |= Tdhalt; + coherence(); + } } } @@ -2288,9 +2294,7 @@ epiowait(Hci *hp, Qio *io, int tmout, ulong load) ilock(ctlr); /* Are we missing interrupts? */ if(qh->state == Qrun){ - iunlock(ctlr); - ehciintr(hp); - ilock(ctlr); + ctlrinterrupt(ctlr); if(qh->state == Qdone){ dqprint("ehci %#p: polling required\n", ctlr->capio); ctlr->poll.must = 1; @@ -2304,18 +2308,19 @@ epiowait(Hci *hp, Qio *io, int tmout, ulong load) }else if(qh->state != Qdone && qh->state != Qclose) panic("ehci: epio: queue state %d", qh->state); if(timedout){ - aborttds(io->qh); - io->err = "request timed out"; + aborttds(qh); + qh->state = Qdone; + if(io->err == nil) + io->err = "request timed out"; iunlock(ctlr); - if(!waserror()){ - tsleep(&up->sleep, return0, 0, Abortdelay); - poperror(); - } + while(waserror()) + ; + tsleep(&up->sleep, return0, 0, Abortdelay); + poperror(); ilock(ctlr); } if(qh->state != Qclose) qh->state = Qidle; - coherence(); qhlinktd(qh, nil); ctlr->load -= load; ctlr->nreqs--; @@ -2340,7 +2345,6 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock) Qh* qh; Td *td, *ltd, *td0, *ntd; - qh = io->qh; ctlr = ep->hp->aux; io->debug = ep->debug; tmout = ep->tmout; @@ -2360,7 +2364,8 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock) } io->err = nil; ilock(ctlr); - if(qh->state == Qclose){ /* Tds released by cancelio */ + qh = io->qh; + if(qh == nil || qh->state == Qclose){ /* Tds released by cancelio */ iunlock(ctlr); error(io->err ? io->err : Eio); } @@ -2417,6 +2422,7 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock) dumptd(td0, "epio: got: "); qhdump(qh); } + err = io->err; tot = 0; c = a; @@ -2438,7 +2444,7 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock) io->toggle = td->csw & Tddata1; coherence(); } - if((n = td->ndata) > 0 && tot < count){ + if(err == nil && (n = td->ndata) > 0 && tot < count){ if((tot + n) > count) n = count - tot; if(c != nil && (td->csw & Tdtok) == Tdtokin){ @@ -2451,7 +2457,6 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock) ntd = td->next; tdfree(td); } - err = io->err; if(mustlock){ qunlock(io); poperror(); @@ -2955,7 +2960,7 @@ cancelio(Ctlr *ctlr, Qio *io) ilock(ctlr); qh = io->qh; - if(io == nil || io->qh == nil || io->qh->state == Qclose){ + if(qh == nil || qh->state == Qclose){ iunlock(ctlr); return; } @@ -2964,17 +2969,18 @@ cancelio(Ctlr *ctlr, Qio *io) aborttds(qh); qh->state = Qclose; iunlock(ctlr); - if(!waserror()){ - tsleep(&up->sleep, return0, 0, Abortdelay); - poperror(); - } + while(waserror()) + ; + tsleep(&up->sleep, return0, 0, Abortdelay); + poperror(); wakeup(io); qlock(io); /* wait for epio if running */ + if(io->qh == qh) + io->qh = nil; qunlock(io); qhfree(ctlr, qh); - io->qh = nil; } static void