X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=sys%2Fsrc%2F9%2Fport%2Fusbehci.c;h=66546675cdd2a499fddb935a06116568c7e95b48;hb=77611280935dfbd7b976fd9340bf8593bf4320f1;hp=22af2e79889ec01b8dbeeff15b6f06e9df91f392;hpb=cfd25faa2857ee9de75910d81530be62d7ba4704;p=plan9front.git diff --git a/sys/src/9/port/usbehci.c b/sys/src/9/port/usbehci.c index 22af2e798..66546675c 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); } @@ -1338,8 +1338,7 @@ isohsinterrupt(Ctlr *ctlr, Isoio *iso) Itd *tdi; tdi = iso->tdi; - assert(tdi != nil); - if(itdactive(tdi)) /* not all tds are done */ + if(tdi == nil || itdactive(tdi)) /* not all tds are done */ return 0; ctlr->nisointr++; ddiprint("isohsintr: iso %#p: tdi %#p tdu %#p\n", iso, tdi, iso->tdu); @@ -1409,8 +1408,7 @@ isofsinterrupt(Ctlr *ctlr, Isoio *iso) Sitd *stdi; stdi = iso->stdi; - assert(stdi != nil); - if((stdi->csw & Stdactive) != 0) /* nothing new done */ + if(stdi == nil || (stdi->csw & Stdactive) != 0) /* nothing new done */ return 0; ctlr->nisointr++; ddiprint("isofsintr: iso %#p: tdi %#p tdu %#p\n", iso, stdi, iso->stdu); @@ -1479,7 +1477,7 @@ qhinterrupt(Ctlr *ctlr, Qh *qh) panic("qhinterrupt: qh state"); td = qh->tds; if(td == nil) - panic("qhinterrupt: no tds"); + return 0; if((td->csw & Tdactive) == 0) ddqprint("qhinterrupt port %#p qh %#p\n", ctlr->capio, qh); for(; td != nil; td = td->next){ @@ -1514,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); @@ -1557,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); } @@ -1583,17 +1575,27 @@ ehciintr(Hci *hp) qh = ctlr->qhs; i = 0; do{ - if (qh == nil) - panic("ehciintr: nil qh"); + if(qh == nil) + break; if(qh->state == Qrun) some += qhinterrupt(ctlr, qh); qh = qh->next; }while(qh != ctlr->qhs && i++ < 100); if(i > 100) - print("echi: interrupt: qh loop?\n"); + iprint("echi: interrupt: qh loop?\n"); } -// if (some == 0) -// panic("ehciintr: no work"); + return some; +} + +static int +ehciintr(Hci *hp) +{ + Ctlr *ctlr; + int some; + + ctlr = hp->aux; + ilock(ctlr); + some = ctlrinterrupt(ctlr); iunlock(ctlr); return some; } @@ -1688,22 +1690,24 @@ portreset(Hci *hp, int port, int on) if (opio->sts & Shalted) iprint("ehci %#p: halted yet trying to reset port\n", ctlr->capio); - *portscp = (*portscp & ~Psenable) | Psreset; /* initiate reset */ - coherence(); + *portscp = (*portscp & ~Psenable) | Psreset; /* initiate reset */ /* * usb 2 spec: reset must finish within 20 ms. * linux says spec says it can take 50 ms. for hubs. */ + delay(50); + *portscp &= ~Psreset; /* terminate reset */ + + delay(10); 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", - ctlr->capio, port, i * 10, *portscp); - *portscp &= ~Psreset; /* force appearance of reset done */ - coherence(); - delay(10); /* ehci spec: enable within 2 ms. */ + iprint("ehci %#p: port %d didn't reset; sts %#lux\n", + ctlr->capio, port, *portscp); + delay(10); /* ehci spec: enable within 2 ms. */ if((*portscp & Psenable) == 0) portlend(ctlr, port, "full"); @@ -1881,6 +1885,8 @@ episohscpy(Ctlr *ctlr, Ep *ep, Isoio* iso, uchar *b, long count) iunlock(ctlr); /* We could page fault here */ memmove(b+tot, tdu->data, nr); ilock(ctlr); + if(iso->tdu != tdu) + continue; if(nr < tdu->ndata) memmove(tdu->data, tdu->data+nr, tdu->ndata - nr); tdu->ndata -= nr; @@ -1917,6 +1923,8 @@ episofscpy(Ctlr *ctlr, Ep *ep, Isoio* iso, uchar *b, long count) iunlock(ctlr); /* We could page fault here */ memmove(b+tot, stdu->data, nr); ilock(ctlr); + if(iso->stdu != stdu) + continue; if(nr < stdu->ndata) memmove(stdu->data, stdu->data+nr, stdu->ndata - nr); @@ -2150,14 +2158,17 @@ epgettd(Qio *io, int flags, void *a, int count, int maxpkt) if(count <= Align - sizeof(Td)){ td->data = td->sbuff; td->buff = nil; - }else - td->data = td->buff = smalloc(Tdmaxpkt); + } else if(count <= 0x4000){ + td->buff = td->data = smalloc(count); + } else { + td->buff = smalloc(count + 0x1000); + td->data = (uchar*)ROUND((uintptr)td->buff, 0x1000); + } pa = PADDR(td->data); for(i = 0; i < nelem(td->buffer); i++){ td->buffer[i] = pa; - if(i > 0) - td->buffer[i] &= ~0xFFF; + pa &= ~0xFFF; pa += 0x1000; } td->ndata = count; @@ -2177,16 +2188,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(); + } } } @@ -2214,6 +2225,8 @@ ehcipoll(void* a) hp = a; ctlr = hp->aux; poll = &ctlr->poll; + while(waserror()) + ; for(;;){ if(ctlr->nreqs == 0){ if(0)ddprint("ehcipoll %#p sleep\n", ctlr->capio); @@ -2285,9 +2298,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; @@ -2301,18 +2312,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--; @@ -2337,7 +2349,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; @@ -2357,7 +2368,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); } @@ -2414,6 +2426,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; @@ -2435,16 +2448,19 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock) io->toggle = td->csw & Tddata1; coherence(); } - tot += td->ndata; - if(c != nil && (td->csw & Tdtok) == Tdtokin && td->ndata > 0){ - memmove(c, td->data, td->ndata); - c += td->ndata; + if(err == nil && (n = td->ndata) > 0 && tot < count){ + if((tot + n) > count) + n = count - tot; + if(c != nil && (td->csw & Tdtok) == Tdtokin){ + memmove(c, td->data, n); + c += n; + } + tot += n; } } ntd = td->next; tdfree(td); } - err = io->err; if(mustlock){ qunlock(io); poperror(); @@ -2455,8 +2471,6 @@ epio(Ep *ep, Qio *io, void *a, long count, int mustlock) return 0; /* that's our convention */ if(err != nil) error(err); - if(tot < 0) - error(Eio); return tot; } @@ -2725,10 +2739,11 @@ isohsinit(Ep *ep, Isoio *iso) td = itdalloc(); td->data = iso->data + i * 8 * iso->maxsize; pa = PADDR(td->data) & ~0xFFF; - for(p = 0; p < 8; p++) - td->buffer[i] = pa + p * 0x1000; - td->buffer[0] = PADDR(iso->data) & ~0xFFF | - ep->nb << Itdepshift | ep->dev->nb << Itddevshift; + for(p = 0; p < nelem(td->buffer); p++){ + td->buffer[p] = pa; + pa += 0x1000; + } + td->buffer[0] |= ep->nb << Itdepshift | ep->dev->nb << Itddevshift; if(ep->mode == OREAD) td->buffer[1] |= Itdin; else @@ -2949,7 +2964,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; } @@ -2958,17 +2973,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 @@ -3238,12 +3254,9 @@ init(Hci *hp) opio->cmd |= Case; coherence(); ehcirun(ctlr, 1); - /* - * route all ports by default to only one ehci (the first). - * it's not obvious how multiple ehcis could work and on some - * machines, setting Callmine on all ehcis makes the machine seize up. - */ - opio->config = (ctlrno == 0 ? Callmine : 0); + + /* route all ports to us */ + opio->config = Callmine; coherence(); for (i = 0; i < hp->nports; i++)