diff options
| author | cinap_lenrek <cinap_lenrek@felloff.net> | 2017-07-29 01:02:23 +0200 |
|---|---|---|
| committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2017-07-29 01:02:23 +0200 |
| commit | c74538a67e57ab9e37826104210d1c1f64711a04 (patch) | |
| tree | e10d7f6a554eae9c466004014142df441f9d886e | |
| parent | aaf6d7c5586d442c0bc10ed50558b984faeb51aa (diff) | |
| download | plan9front-c74538a67e57ab9e37826104210d1c1f64711a04.tar.xz | |
usbxhci: implement controller handoff, ignore usb3.0 ports, honor pollival for isochronous endpoints
| -rw-r--r-- | sys/src/9/pc/usbxhci.c | 225 |
1 files changed, 149 insertions, 76 deletions
diff --git a/sys/src/9/pc/usbxhci.c b/sys/src/9/pc/usbxhci.c index e1e94770c..4851368c8 100644 --- a/sys/src/9/pc/usbxhci.c +++ b/sys/src/9/pc/usbxhci.c @@ -147,6 +147,7 @@ typedef struct Wait Wait; typedef struct Ring Ring; typedef struct Slot Slot; typedef struct Epio Epio; +typedef struct Port Port; struct Wait { @@ -193,6 +194,14 @@ struct Slot Ring epr[32]; }; +struct Port +{ + char spec[4]; + int proto; + + u32int *reg; +}; + struct Ctlr { Pcidev *pcidev; @@ -200,7 +209,6 @@ struct Ctlr u32int *mmio; u32int *opr; /* operational registers */ - u32int *prt; /* port register set */ u32int *rts; /* runtime registers */ u32int *dba; /* doorbell array */ @@ -213,10 +221,11 @@ struct Ctlr Ring er[1]; /* event ring segment */ Ring cr[1]; /* command ring segment */ - u32int mfwrap; + u32int µframe; QLock slotlock; Slot **slot; /* slots by slot id */ + Port *port; u32int hccparams; @@ -239,10 +248,12 @@ struct Epio Block *b; /* iso */ - int nleft; u32int frame; + u32int period; u32int incr; u32int tdsz; + + int nleft; }; static char Ebadlen[] = "bad usb request length"; @@ -262,15 +273,14 @@ setrptr64(u32int *reg, u64int pa) } static u32int -mfindex(Ctlr *ctlr) +µframe(Ctlr *ctlr) { - u32int lo, hi; - + u32int µ; do { - hi = ctlr->mfwrap; - lo = ctlr->rts[MFINDEX]; - } while(hi != ctlr->mfwrap); - return (lo & (1<<14)-1) | hi<<14; + µ = (ctlr->rts[MFINDEX] & (1<<14)-1) | + (ctlr->µframe & ~((1<<14)-1)); + } while((int)(µ - ctlr->µframe) < 0); + return µ; } static void @@ -302,38 +312,78 @@ initring(Ring *r, int shift) return r; } +static u32int* +xecp(Ctlr *ctlr, uchar id, u32int *p) +{ + u32int x; + + if(p != nil) { + x = *p; + goto Next; + } + x = ctlr->hccparams>>16; + if(x == 0) + return nil; + p = ctlr->mmio + x; + while(((x = *p) & 255) != id){ + Next: + x >>= 8, x &= 255; + if(x == 0) + return nil; + p += x; + } + return p; +} + +static void +handoff(Ctlr *ctlr) +{ + u32int *r; + int i; + + if((r = xecp(ctlr, 1, nil)) == nil) + return; + r[0] |= 1<<24; /* request ownership */ + for(i = 0; (r[0] & (1<<16)) != 0 && i<100; i++) + tsleep(&up->sleep, return0, nil, 10); + r[1] = 0; /* disable SMI interrupts */ + r[0] &= ~(1<<16); /* in case of timeout */ +} + static void init(Hci *hp) { Ctlr *ctlr; + Port *pp; + u32int *x; uchar *p; - int i; + int i, j; ctlr = hp->aux; ctlr->opr = &ctlr->mmio[(ctlr->mmio[CAPLENGTH]&0xFF)/4]; - ctlr->prt = &ctlr->opr[0x400/4]; ctlr->dba = &ctlr->mmio[ctlr->mmio[DBOFF]/4]; ctlr->rts = &ctlr->mmio[ctlr->mmio[RTSOFF]/4]; - while(ctlr->opr[USBSTS] & CNR) + ctlr->hccparams = ctlr->mmio[HCCPARAMS]; + handoff(ctlr); + + for(i=0; (ctlr->opr[USBSTS] & CNR) != 0 && i<100; i++) tsleep(&up->sleep, return0, nil, 10); ctlr->opr[USBCMD] = HCRST; - while((ctlr->opr[USBSTS] & (CNR|HCH)) != HCH) + for(i=0; (ctlr->opr[USBSTS] & (CNR|HCH)) != HCH && i<100; i++) tsleep(&up->sleep, return0, nil, 10); pcisetbme(ctlr->pcidev); pcisetpms(ctlr->pcidev, 0); intrenable(ctlr->pcidev->intl, hp->interrupt, hp, ctlr->pcidev->tbdf, hp->type); - ctlr->hccparams = ctlr->mmio[HCCPARAMS]; ctlr->csz = (ctlr->hccparams & CSZ) != 0; if(ctlr->hccparams & AC64) ctlr->setrptr = setrptr64; else ctlr->setrptr = setrptr32; - ctlr->pagesize = ctlr->opr[PAGESIZE]<<12; ctlr->nscratch = (ctlr->mmio[HCSPARAMS2] >> 27) & 0x1F; @@ -341,6 +391,24 @@ init(Hci *hp) ctlr->nslots = (ctlr->mmio[HCSPARAMS1] >> 0) & 0xFF; hp->nports = (ctlr->mmio[HCSPARAMS1] >> 24) & 0xFF; + ctlr->port = malloc(hp->nports * sizeof(Port)); + for(i=0; i<hp->nports; i++) + ctlr->port[i].reg = &ctlr->opr[0x400/4 + i*4]; + + x = nil; + while((x = xecp(ctlr, 2, x)) != nil){ + i = x[2]&255; + j = (x[2]>>8)&255; + while(j--){ + if(i < 1 || i > hp->nports) + break; + pp = &ctlr->port[i-1]; + pp->proto = x[0]>>16; + memmove(pp->spec, &x[1], 4); + i++; + } + } + ctlr->slot = malloc((1+ctlr->nslots)*sizeof(ctlr->slot[0])); ctlr->dcba = mallocalign((1+ctlr->nslots)*8, 64, 0, ctlr->pagesize); if(ctlr->nscratch != 0){ @@ -391,10 +459,9 @@ init(Hci *hp) irs[IMOD] = 0; } - ctlr->mfwrap = 0; - + ctlr->µframe = 0; ctlr->opr[USBCMD] = RUNSTOP|INTE|HSEE|EWE; - while(ctlr->opr[USBSTS] & (CNR|HCH)) + for(i=0; (ctlr->opr[USBSTS] & (CNR|HCH)) != 0 && i<100; i++) tsleep(&up->sleep, return0, nil, 10); } @@ -580,6 +647,9 @@ interrupt(Ureg*, void *arg) Slot *slot; u32int *irs, *td, x; + if(ring->base == nil) + return; + irs = &ctlr->rts[IR0]; x = irs[IMAN]; if(x & 1) irs[IMAN] = x & 3; @@ -603,7 +673,8 @@ interrupt(Ureg*, void *arg) completering(&slot->epr[(td[3]>>16)-1&31], td); break; case ER_MFINDEXWRAP: - ctlr->mfwrap++; + ctlr->µframe = (ctlr->rts[MFINDEX] & (1<<14)-1) | + (ctlr->µframe+(1<<14) & ~((1<<14)-1)); break; case ER_HCE: iprint("xhci: host controller error: %ux %ux %ux %ux\n", @@ -787,10 +858,9 @@ initisoio(Epio *io, Ep *ep) if(io->ring == nil) return; io->frame = 0; - io->incr = (ep->hz<<8)/1000; + io->period = ep->pollival<<3*(ep->dev->speed == Fullspeed); + io->incr = (ep->hz*io->period<<8)/8000; io->tdsz = (io->incr+255>>8)*ep->samplesz; - if(io->tdsz > ep->maxpkt*ep->ntds) - error(Egreg); io->b = allocb((io->ring->mask+1)*io->tdsz); } @@ -977,36 +1047,6 @@ epopen(Ep *ep) poperror(); } -static char* -unstall(Ring *r) -{ - u64int qp; - char *err; - - switch(r->ctx[0]&7){ - case 0: /* disabled */ - case 1: /* running */ - case 3: /* stopped */ - break; - case 2: /* halted */ - case 4: /* error */ - ilock(r); - r->rp = r->wp; - qp = PADDR(&r->base[4*(r->wp & r->mask)]) | ((~r->wp>>r->shift) & 1); - iunlock(r); - - err = ctlrcmd(r->slot->ctlr, CR_RESETEP | (r->id<<16) | (r->slot->id<<24), 0, 0, nil); - ctlrcmd(r->slot->ctlr, CR_SETTRDQP | (r->id<<16) | (r->slot->id<<24), 0, qp, nil); - if(err != nil) - return err; - } - - if(r->wp - r->rp >= r->mask) - return "Ring Full"; - - return nil; -} - static long isoread(Ep *, uchar *, long) { @@ -1020,7 +1060,7 @@ isowrite(Ep *ep, uchar *p, long n) uchar *s, *d; Ctlr *ctlr; Epio *io; - u32int x; + u32int i, µ; long m; s = p; @@ -1030,21 +1070,20 @@ isowrite(Ep *ep, uchar *p, long n) qunlock(io); nexterror(); } - + µ = io->period; ctlr = ep->hp->aux; - for(x = io->frame;; x++){ + for(i = io->frame;; i++){ for(;;){ m = (int)(io->ring->wp - io->ring->rp); if(m <= 0) - x = 10 + mfindex(ctlr)/8; - if(m < io->ring->mask-1) + i = (80 + µframe(ctlr))/µ; + if(m < io->ring->mask) break; - coherence(); *io->ring->doorbell = io->ring->id; tsleep(&up->sleep, return0, nil, 5); } - m = ((io->incr + (x*io->incr&255))>>8)*ep->samplesz; - d = io->b->rp + (x&io->ring->mask)*io->tdsz; + m = ((io->incr + (i*io->incr&255))>>8)*ep->samplesz; + d = io->b->rp + (i&io->ring->mask)*io->tdsz; m -= io->nleft, d += io->nleft; if(n < m){ memmove(d, p, n); @@ -1056,28 +1095,56 @@ isowrite(Ep *ep, uchar *p, long n) p += m, n -= m; m += io->nleft, d -= io->nleft; io->nleft = 0; - + coherence(); ilock(io->ring); - queuetd(io->ring, TR_ISOCH | (x & 0x7ff)<<20 | 1<<5, m, PADDR(d), nil); + queuetd(io->ring, TR_ISOCH | (i*µ/8 & 0x7ff)<<20 | 1<<5, m, PADDR(d), nil); iunlock(io->ring); } - io->frame = x; - coherence(); - *io->ring->doorbell = io->ring->id; - qunlock(io); - poperror(); - - for(;;){ - int d = (int)(x - mfindex(ctlr)/8); + io->frame = i; + while(io->ring->rp != io->ring->wp){ + int d = (int)(i*µ - µframe(ctlr))/8; d -= ep->sampledelay*1000 / ep->hz; if(d < 5) break; + *io->ring->doorbell = io->ring->id; tsleep(&up->sleep, return0, nil, d); } + qunlock(io); + poperror(); return p - s; } +static char* +unstall(Ring *r) +{ + u64int qp; + char *err; + + switch(r->ctx[0]&7){ + case 0: /* disabled */ + case 1: /* running */ + case 3: /* stopped */ + break; + case 2: /* halted */ + case 4: /* error */ + ilock(r); + r->rp = r->wp; + qp = PADDR(&r->base[4*(r->wp & r->mask)]) | ((~r->wp>>r->shift) & 1); + iunlock(r); + + err = ctlrcmd(r->slot->ctlr, CR_RESETEP | (r->id<<16) | (r->slot->id<<24), 0, 0, nil); + ctlrcmd(r->slot->ctlr, CR_SETTRDQP | (r->id<<16) | (r->slot->id<<24), 0, qp, nil); + if(err != nil) + return err; + } + + if(r->wp - r->rp >= r->mask) + return "Ring Full"; + + return nil; +} + static long epread(Ep *ep, void *va, long n) { @@ -1269,9 +1336,13 @@ static int portstatus(Hci *hp, int port) { Ctlr *ctlr = hp->aux; - u32int psc = ctlr->prt[PORTSC + (port-1)*4]; + Port *pp = &ctlr->port[port-1]; + u32int psc = pp->reg[PORTSC]; int ps = 0; + if(memcmp(pp->spec, "USB", 3) != 0 || pp->proto > 0x0200) + return 0; + if(psc & CCS) ps |= HPpresent; if(psc & PED) ps |= HPenable; if(psc & OCA) ps |= HPovercurrent; @@ -1287,8 +1358,7 @@ portstatus(Hci *hp, int port) case 3: ps |= HPhigh; break; - case 4: - /* super speed */ + case 4: /* super speed */ break; } } @@ -1310,10 +1380,13 @@ static int portreset(Hci *hp, int port, int on) { Ctlr *ctlr = hp->aux; - u32int *r = &ctlr->prt[PORTSC + (port-1)*4]; + Port *pp = &ctlr->port[port-1]; + + if(memcmp(pp->spec, "USB", 3) != 0 || pp->proto > 0x0200) + return 0; if(on){ - *r |= PR; + pp->reg[PORTSC] |= PR; tsleep(&up->sleep, return0, nil, 200); } |
