ref: 4fd68773e2c5935b1b5bce0376ced783f87c7934
parent: 40dc39bf7d8d17a84d6a2a427ca7facd8b2cb66b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Jul 20 15:57:14 EDT 2017
usbxhci: implement command timeouts and aborts, serialize unstall
--- a/sys/src/9/pc/usbxhci.c
+++ b/sys/src/9/pc/usbxhci.c
@@ -165,7 +165,6 @@
u32int *base;
- u32int size;
u32int mask;
u32int shift;
@@ -234,7 +233,7 @@
{
QLock;
Block *cb;
- Ring *ring[2]; /* OREAD, OWRITE */
+ Ring *ring;
};
static char Ebadlen[] = "bad usb request length";
@@ -263,7 +262,7 @@
memset(r, 0, sizeof(*r));
}
-static void
+static Ring*
initring(Ring *r, int shift)
{
r->id = 0;
@@ -272,14 +271,14 @@
r->doorbell = nil;
r->pending = nil;
r->shift = shift;
- r->size = 1<<shift;
- r->mask = r->size-1;
+ r->mask = (1<<shift)-1;
r->rp = r->wp = 0;
- r->base = mallocalign(r->size*16, 64, 0, 64*1024);
+ r->base = mallocalign(4*4<<shift, 64, 0, 64*1024);
if(r->base == nil){
freering(r);
error(Enomem);
}
+ return r;
}
static void
@@ -341,8 +340,8 @@
ctlr->setrptr(&ctlr->opr[DCBAAP], PADDR(ctlr->dcba));
initring(ctlr->cr, 8); /* 256 entries */
- ctlr->cr->doorbell = &ctlr->dba[0];
ctlr->cr->id = 0;
+ ctlr->cr->doorbell = &ctlr->dba[0];
coherence();
ctlr->setrptr(&ctlr->opr[CRCR], PADDR(ctlr->cr[0].base) | 1);
@@ -358,7 +357,7 @@
initring(&ctlr->er[i], 8); /* 256 entries */
ctlr->erst[i] = mallocalign(16, 64, 0, 0);
*((u64int*)ctlr->erst[i]) = PADDR(ctlr->er[i].base);
- ctlr->erst[i][2] = ctlr->er[i].size;
+ ctlr->erst[i][2] = ctlr->er[i].mask+1;
ctlr->erst[i][3] = 0;
irs[ERSTSZ] = 1; /* just one segment */
@@ -464,23 +463,34 @@
return ((Wait*)a)->z == nil;
}
-static void
-kickring(Ring *r)
-{
- coherence();
- *r->doorbell = r->id;
-}
+static char*
+ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er);
static char*
-waittd(Wait *w, u32int *er)
+waittd(Ctlr *ctlr, Wait *w, int tmout, u32int *er)
{
- while(!waitdone(w)){
- while(waserror())
- ;
- kickring(w->ring);
- sleep(&up->sleep, waitdone, w);
- poperror();
+ Ring *ring = w->ring;
+
+ coherence();
+ *ring->doorbell = ring->id;
+
+ while(waserror()){
+ if(ring == ctlr->cr)
+ ctlr->opr[CRCR] |= CA;
+ else
+ ctlrcmd(ctlr, CR_STOPEP | (ring->id<<16) | (ring->slot->id<<24), 0, 0, nil);
+ tmout = 0;
}
+ if(tmout > 0){
+ tsleep(&up->sleep, waitdone, w, tmout);
+ if(!waitdone(w))
+ error("timed out");
+ } else {
+ while(!waitdone(w))
+ sleep(&up->sleep, waitdone, w);
+ }
+ poperror();
+
if(er != nil)
memmove(er, w->er, 4*4);
return ccerrstr(w->er[2]>>24);
@@ -489,12 +499,13 @@
static char*
ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er)
{
- Wait w[1];
+ Wait ws[1];
ilock(ctlr->cr);
- queuetd(ctlr->cr, c, s, p, w);
+ queuetd(ctlr->cr, c, s, p, ws);
iunlock(ctlr->cr);
- return waittd(w, er);
+
+ return waittd(ctlr, ws, 5000, er);
}
static void
@@ -569,10 +580,12 @@
break;
completering(&slot->epr[(td[3]>>16)-1&31], td);
break;
+ case ER_HCE:
+ iprint("xhci: host controller error: %ux %ux %ux %ux\n", td[0], td[1], td[2], td[3]);
+ break;
case ER_PORTSC:
case ER_BWREQ:
case ER_DOORBELL:
- case ER_HCE:
case ER_DEVNOTE:
case ER_MFINDEXWRAP:
default:
@@ -679,7 +692,7 @@
ctlr = ep->hp->aux;
slot = ep->dev->aux;
- if(ep->nb > 0 && (io->ring[OREAD] != nil || io->ring[OWRITE] != nil)){
+ if(ep->nb > 0 && (io[OREAD].ring != nil || io[OWRITE].ring != nil)){
u32int *w;
/* input control context */
@@ -686,14 +699,14 @@
w = slot->ibase;
memset(w, 0, 32<<ctlr->csz);
w[1] = 1;
- if(io->ring[OREAD] != nil){
- w[0] |= 2 << ep->nb*2;
- if(ep->nb*2+1 == slot->nep)
+ if(io[OREAD].ring != nil){
+ w[0] |= 1 << io[OREAD].ring->id;
+ if(io[OREAD].ring->id == slot->nep)
slot->nep--;
}
- if(io->ring[OWRITE] != nil){
- w[0] |= 1 << ep->nb*2;
- if(ep->nb*2 == slot->nep)
+ if(io[OWRITE].ring != nil){
+ w[0] |= 1 << io[OWRITE].ring->id;
+ if(io[OWRITE].ring->id == slot->nep)
slot->nep--;
}
@@ -707,10 +720,10 @@
ctlrcmd(ctlr, CR_CONFIGEP | (slot->id<<24), 0, PADDR(slot->ibase), nil);
- freering(io->ring[OREAD]);
- freering(io->ring[OWRITE]);
+ freering(io[OREAD].ring);
+ freering(io[OWRITE].ring);
}
- freeb(io->cb);
+ freeb(io[OREAD].cb);
free(io);
}
@@ -720,6 +733,7 @@
Epio *io;
Ctlr *ctlr;
Slot *slot;
+ Ring *ring;
u32int *w;
int ival;
char *err;
@@ -728,9 +742,9 @@
slot = ep->dev->aux;
ctlr = ep->hp->aux;
- io->ring[OREAD] = io->ring[OWRITE] = nil;
+ io[OREAD].ring = io[OWRITE].ring = nil;
if(ep->nb == 0){
- io->ring[OWRITE] = &slot->epr[0];
+ io[OWRITE].ring = &slot->epr[0];
return;
}
@@ -740,31 +754,29 @@
w[1] = 1;
if(waserror()){
- freering(io->ring[OWRITE]), io->ring[OWRITE] = nil;
- freering(io->ring[OREAD]), io->ring[OREAD] = nil;
+ freering(io[OWRITE].ring), io[OWRITE].ring = nil;
+ freering(io[OREAD].ring), io[OREAD].ring = nil;
nexterror();
}
if(ep->mode != OREAD){
- initring(io->ring[OWRITE] = &slot->epr[ep->nb*2-1], 8);
- io->ring[OWRITE]->doorbell = &ctlr->dba[slot->id];
- io->ring[OWRITE]->slot = slot;
- io->ring[OWRITE]->ctx = &slot->obase[(ep->nb*2+0)*8<<ctlr->csz];
- io->ring[OWRITE]->id = ep->nb*2;
-
- w[1] |= 1 << ep->nb*2;
- if(ep->nb*2 > slot->nep)
- slot->nep = ep->nb*2;
+ ring = initring(io[OWRITE].ring = &slot->epr[ep->nb*2-1], 8);
+ ring->id = ep->nb*2;
+ if(ring->id > slot->nep)
+ slot->nep = ring->id;
+ ring->slot = slot;
+ ring->doorbell = &ctlr->dba[slot->id];
+ ring->ctx = &slot->obase[ring->id*8<<ctlr->csz];
+ w[1] |= 1 << ring->id;
}
if(ep->mode != OWRITE){
- initring(io->ring[OREAD] = &slot->epr[ep->nb*2], 8);
- io->ring[OREAD]->doorbell = &ctlr->dba[slot->id];
- io->ring[OREAD]->slot = slot;
- io->ring[OREAD]->ctx = &slot->obase[(ep->nb*2+1)*8<<ctlr->csz];
- io->ring[OREAD]->id = ep->nb*2+1;
-
- w[1] |= 2 << ep->nb*2;
- if(ep->nb*2+1 > slot->nep)
- slot->nep = ep->nb*2+1;
+ ring = initring(io[OREAD].ring = &slot->epr[ep->nb*2], 8);
+ ring->id = ep->nb*2+1;
+ if(ring->id > slot->nep)
+ slot->nep = ring->id;
+ ring->slot = slot;
+ ring->doorbell = &ctlr->dba[slot->id];
+ ring->ctx = &slot->obase[ring->id*8<<ctlr->csz];
+ w[1] |= 1 << ring->id;
}
/* (input) slot context */
@@ -784,19 +796,19 @@
}
/* out */
- if(io->ring[OWRITE] != nil){
+ if(io[OWRITE].ring != nil){
w[0] = ival<<16;
w[1] = 3<<1 | ((ep->ttype - Tctl)|0)<<3 | ep->maxpkt<<16;
- *((u64int*)&w[2]) = PADDR(io->ring[OWRITE]->base) | 1;
+ *((u64int*)&w[2]) = PADDR(io[OWRITE].ring->base) | 1;
w[4] = 1;
}
/* in */
w += 8<<ctlr->csz;
- if(io->ring[OREAD] != nil){
+ if(io[OREAD].ring != nil){
w[0] = ival<<16;
w[1] = 3<<1 | ((ep->ttype - Tctl)|4)<<3 | ep->maxpkt<<16;
- *((u64int*)&w[2]) = PADDR(io->ring[OREAD]->base) | 1;
+ *((u64int*)&w[2]) = PADDR(io[OREAD].ring->base) | 1;
w[4] = 1;
}
@@ -824,6 +836,7 @@
{
Ctlr *ctlr = ep->hp->aux;
Slot *slot, *hub;
+ Ring *ring;
Epio *io;
Udev *dev;
char *err;
@@ -833,7 +846,7 @@
if(ep->dev->isroot)
return;
- io = malloc(sizeof(Epio));
+ io = malloc(sizeof(Epio)*2);
if(io == nil)
error(Enomem);
ep->aux = io;
@@ -856,12 +869,12 @@
slot = allocslot(ctlr, dev);
/* allocate control ep 0 ring */
- initring(io->ring[OWRITE] = &slot->epr[0], 8);
- io->ring[OWRITE]->doorbell = &ctlr->dba[slot->id];
- io->ring[OWRITE]->slot = slot;
- io->ring[OWRITE]->ctx = &slot->obase[8];
- io->ring[OWRITE]->id = 1;
+ ring = initring(io[OWRITE].ring = &slot->epr[0], 4);
+ ring->id = 1;
slot->nep = 1;
+ ring->slot = slot;
+ ring->doorbell = &ctlr->dba[slot->id];
+ ring->ctx = &slot->obase[8];
/* (input) control context */
w = slot->ibase;
@@ -901,7 +914,7 @@
/* (input) ep context 0 */
w += 8<<ctlr->csz;
w[1] = 3<<1 | 4<<3 | ep->maxpkt<<16;
- *((u64int*)&w[2]) = PADDR(io->ring[OWRITE]->base) | 1;
+ *((u64int*)&w[2]) = PADDR(io[OWRITE].ring->base) | 1;
if((err = ctlrcmd(ctlr, CR_ADDRESSDEV | (slot->id<<24), 0,
PADDR(slot->ibase), nil)) != nil){
@@ -914,22 +927,34 @@
poperror();
}
-static void
+static char*
unstall(Ring *r)
{
u64int qp;
+ char *err;
switch(r->ctx[0]&7){
- case 2:
- case 4:
+ 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);
- ctlrcmd(r->slot->ctlr, CR_RESETEP | (r->id<<16) | (r->slot->id<<24), 0, 0, nil);
+ 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
@@ -937,12 +962,11 @@
{
Epio *io;
uchar *p;
- Ring *ring;
char *err;
Wait ws[1];
p = va;
- io = ep->aux;
+ io = (Epio*)ep->aux + OREAD;
if(ep->ttype == Tctl){
qlock(io);
@@ -973,13 +997,17 @@
return n;
}
- ring = io->ring[OREAD];
- unstall(ring);
- ilock(ring);
- queuetd(ring, TR_NORMAL | 1<<16 | 1<<5, n, PADDR(p), ws);
- iunlock(ring);
+ qlock(io);
+ if((err = unstall(io->ring)) != nil){
+ qunlock(io);
+ error(err);
+ }
+ ilock(io->ring);
+ queuetd(io->ring, TR_NORMAL | 1<<16 | 1<<5, n, PADDR(p), ws);
+ iunlock(io->ring);
+ qunlock(io);
- if((err = waittd(ws, nil)) != nil)
+ if((err = waittd((Ctlr*)ep->hp->aux, ws, ep->tmout, nil)) != nil)
error(err);
n -= (ws->er[2] & 0xFFFFFF);
@@ -993,16 +1021,14 @@
epwrite(Ep *ep, void *va, long n)
{
Wait ws[3];
- Ring *ring;
Epio *io;
uchar *p;
char *err;
p = va;
- io = ep->aux;
-
if(ep->ttype == Tctl){
int dir, len;
+ Ring *ring;
if(n < 8)
error(Eshort);
@@ -1010,6 +1036,7 @@
if(p[0] == 0x00 && p[1] == 0x05)
return n;
+ io = (Epio*)ep->aux + OREAD;
qlock(io);
if(waserror()){
qunlock(io);
@@ -1032,8 +1059,10 @@
}
}
- ring = io->ring[OWRITE];
- unstall(ring);
+ ring = io[OWRITE-OREAD].ring;
+ if((err = unstall(ring)) != nil)
+ error(err);
+
ilock(ring);
queuetd(ring, TR_SETUPSTAGE | (len > 0 ? 2+dir : 0)<<16 | 1<<6 | 1<<5, 8,
p[0] | p[1]<<8 | GET2(&p[2])<<16 |
@@ -1044,10 +1073,10 @@
queuetd(ring, TR_STATUSSTAGE | (len == 0 || !dir)<<16 | 1<<5, 0, 0, &ws[2]);
iunlock(ring);
- if((err = waittd(&ws[0], nil)) != nil)
+ if((err = waittd((Ctlr*)ep->hp->aux, &ws[0], ep->tmout, nil)) != nil)
error(err);
if(len > 0){
- if((err = waittd(&ws[1], nil)) != nil)
+ if((err = waittd((Ctlr*)ep->hp->aux, &ws[1], ep->tmout, nil)) != nil)
error(err);
if(dir != 0){
io->cb->wp -= (ws[1].er[2] & 0xFFFFFF);
@@ -1055,10 +1084,12 @@
io->cb->wp = io->cb->rp;
}
}
- if((err = waittd(&ws[2], nil)) != nil)
+ if((err = waittd((Ctlr*)ep->hp->aux, &ws[2], ep->tmout, nil)) != nil)
error(err);
+
qunlock(io);
poperror();
+
return n;
}
@@ -1077,13 +1108,18 @@
return n;
}
- ring = io->ring[OWRITE];
- unstall(ring);
- ilock(ring);
- queuetd(ring, TR_NORMAL | 1<<16 | 1<<5, n, PADDR(p), ws);
- iunlock(ring);
+ io = (Epio*)ep->aux + OWRITE;
+ qlock(io);
+ if((err = unstall(io->ring)) != nil){
+ qunlock(io);
+ error(err);
+ }
+ ilock(io->ring);
+ queuetd(io->ring, TR_NORMAL | 1<<16 | 1<<5, n, PADDR(p), ws);
+ iunlock(io->ring);
+ qunlock(io);
- if((err = waittd(ws, nil)) != nil)
+ if((err = waittd((Ctlr*)ep->hp->aux, ws, ep->tmout, nil)) != nil)
error(err);
return n;