usbxhci: have to serialize and set read pointer for endpoint stop command

This commit is contained in:
cinap_lenrek 2017-08-02 01:45:30 +02:00
parent f001ddfdb5
commit 8ed13fe664

View file

@ -175,6 +175,8 @@ struct Ring
u32int *ctx; u32int *ctx;
u32int *doorbell; u32int *doorbell;
int stopped;
Wait *pending; Wait *pending;
Lock; Lock;
}; };
@ -302,6 +304,7 @@ initring(Ring *r, int shift)
r->slot = nil; r->slot = nil;
r->doorbell = nil; r->doorbell = nil;
r->pending = nil; r->pending = nil;
r->stopped = 0;
r->shift = shift; r->shift = shift;
r->mask = (1<<shift)-1; r->mask = (1<<shift)-1;
r->rp = r->wp = 0; r->rp = r->wp = 0;
@ -474,30 +477,30 @@ dump(Hci *)
} }
static void static void
queuetd(Ring *ring, u32int c, u32int s, u64int p, Wait *w) queuetd(Ring *r, u32int c, u32int s, u64int p, Wait *w)
{ {
u32int *td, x; u32int *td, x;
x = ring->wp++; x = r->wp++;
if((x & ring->mask) == ring->mask){ if((x & r->mask) == r->mask){
td = ring->base + 4*(x & ring->mask); td = r->base + 4*(x & r->mask);
*(u64int*)td = PADDR(ring->base); *(u64int*)td = PADDR(r->base);
td[2] = 0; td[2] = 0;
td[3] = ((~x>>ring->shift)&1) | (1<<1) | TR_LINK; td[3] = ((~x>>r->shift)&1) | (1<<1) | TR_LINK;
x = ring->wp++; x = r->wp++;
} }
td = ring->base + 4*(x & ring->mask); td = r->base + 4*(x & r->mask);
if(w != nil){ if(w != nil){
memset(w->er, 0, 4*4); w->er[0] = w->er[1] = w->er[2] = w->er[3] = 0;
w->ring = ring; w->ring = r;
w->td = td; w->td = td;
w->z = &up->sleep; w->z = &up->sleep;
w->next = ring->pending; w->next = r->pending;
ring->pending = w; r->pending = w;
} }
*(u64int*)td = p; *(u64int*)td = p;
td[2] = s; td[2] = s;
td[3] = ((~x>>ring->shift)&1) | c; td[3] = ((~x>>r->shift)&1) | c;
} }
static char *ccerrtab[] = { static char *ccerrtab[] = {
@ -556,22 +559,45 @@ waitdone(void *a)
return ((Wait*)a)->z == nil; return ((Wait*)a)->z == nil;
} }
static void
flushring(Ring *r)
{
Rendez *z;
Wait *w;
while((w = r->pending) != nil){
r->pending = w->next;
w->next = nil;
if((z = w->z) != nil){
w->z = nil;
wakeup(z);
}
}
}
static char* static char*
ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er); ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er);
static char* static char*
waittd(Ctlr *ctlr, Wait *w, int tmout, u32int *er) waittd(Ctlr *ctlr, Wait *w, int tmout, QLock *q)
{ {
Ring *ring = w->ring; Ring *r = w->ring;
coherence(); coherence();
*ring->doorbell = ring->id; *r->doorbell = r->id;
while(waserror()){ while(waserror()){
if(ring == ctlr->cr) if(q != nil)
ctlr->opr[CRCR] |= CA; qlock(q);
else if(!r->stopped) {
ctlrcmd(ctlr, CR_STOPEP | (ring->id<<16) | (ring->slot->id<<24), 0, 0, nil); if(r == ctlr->cr)
ctlr->opr[CRCR] |= CA;
else
ctlrcmd(ctlr, CR_STOPEP | (r->id<<16) | (r->slot->id<<24), 0, 0, nil);
r->stopped = 1;
}
if(q != nil)
qunlock(q);
tmout = 0; tmout = 0;
} }
if(tmout > 0){ if(tmout > 0){
@ -584,8 +610,12 @@ waittd(Ctlr *ctlr, Wait *w, int tmout, u32int *er)
} }
poperror(); poperror();
if(er != nil) if(r->stopped) {
memmove(er, w->er, 4*4); ilock(r);
flushring(r);
iunlock(r);
}
return ccerrstr(w->er[2]>>24); return ccerrstr(w->er[2]>>24);
} }
@ -593,12 +623,21 @@ static char*
ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er) ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er)
{ {
Wait ws[1]; Wait ws[1];
char *err;
ilock(ctlr->cr); ilock(ctlr->cr);
if(ctlr->cr->stopped){
flushring(ctlr->cr);
ctlr->cr->stopped = 0;
}
queuetd(ctlr->cr, c, s, p, ws); queuetd(ctlr->cr, c, s, p, ws);
iunlock(ctlr->cr); iunlock(ctlr->cr);
return waittd(ctlr, ws, 5000, er); err = waittd(ctlr, ws, 5000, nil);
if(er != nil)
memmove(er, ws->er, 4*4);
return err;
} }
static void static void
@ -682,6 +721,10 @@ interrupt(Ureg*, void *arg)
case ER_HCE: case ER_HCE:
iprint("xhci: host controller error: %ux %ux %ux %ux\n", iprint("xhci: host controller error: %ux %ux %ux %ux\n",
td[0], td[1], td[2], td[3]); td[0], td[1], td[2], td[3]);
ilock(ctlr->cr);
ctlr->cr->stopped = 1;
flushring(ctlr->cr);
iunlock(ctlr->cr);
break; break;
case ER_PORTSC: case ER_PORTSC:
break; break;
@ -1133,21 +1176,27 @@ unstall(Ring *r)
char *err; char *err;
switch(r->ctx[0]&7){ switch(r->ctx[0]&7){
case 0: /* disabled */
case 1: /* running */
case 3: /* stopped */
break;
case 2: /* halted */ case 2: /* halted */
case 4: /* error */ case 4: /* error */
r->stopped = 1;
err = ctlrcmd(r->slot->ctlr, CR_RESETEP | (r->id<<16) | (r->slot->id<<24), 0, 0, nil);
if(err != nil)
return err;
}
if(r->stopped){
ilock(r); ilock(r);
flushring(r);
r->rp = r->wp; r->rp = r->wp;
qp = PADDR(&r->base[4*(r->wp & r->mask)]) | ((~r->wp>>r->shift) & 1); qp = PADDR(&r->base[4*(r->wp & r->mask)]) | ((~r->wp>>r->shift) & 1);
iunlock(r); iunlock(r);
err = ctlrcmd(r->slot->ctlr, CR_RESETEP | (r->id<<16) | (r->slot->id<<24), 0, 0, nil); err = ctlrcmd(r->slot->ctlr, CR_SETTRDQP | (r->id<<16) | (r->slot->id<<24), 0, qp, nil);
ctlrcmd(r->slot->ctlr, CR_SETTRDQP | (r->id<<16) | (r->slot->id<<24), 0, qp, nil);
if(err != nil) if(err != nil)
return err; return err;
r->stopped = 0;
} }
if(r->wp - r->rp >= r->mask) if(r->wp - r->rp >= r->mask)
@ -1210,7 +1259,7 @@ epread(Ep *ep, void *va, long n)
iunlock(io->ring); iunlock(io->ring);
qunlock(io); qunlock(io);
if((err = waittd((Ctlr*)ep->hp->aux, ws, ep->tmout, nil)) != nil) if((err = waittd((Ctlr*)ep->hp->aux, ws, ep->tmout, io)) != nil)
error(err); error(err);
n -= (ws->er[2] & 0xFFFFFF); n -= (ws->er[2] & 0xFFFFFF);
@ -1243,8 +1292,13 @@ epwrite(Ep *ep, void *va, long n)
return n; return n;
io = (Epio*)ep->aux + OREAD; io = (Epio*)ep->aux + OREAD;
ring = io[OWRITE-OREAD].ring;
qlock(io); qlock(io);
if(waserror()){ if(waserror()){
ilock(ring);
ring->pending = nil;
iunlock(ring);
qunlock(io); qunlock(io);
nexterror(); nexterror();
} }
@ -1264,8 +1318,6 @@ epwrite(Ep *ep, void *va, long n)
io->b->wp += len; io->b->wp += len;
} }
} }
ring = io[OWRITE-OREAD].ring;
if((err = unstall(ring)) != nil) if((err = unstall(ring)) != nil)
error(err); error(err);
@ -1304,6 +1356,7 @@ epwrite(Ep *ep, void *va, long n)
} }
if((err = waittd((Ctlr*)ep->hp->aux, &ws[2], ep->tmout, nil)) != nil) if((err = waittd((Ctlr*)ep->hp->aux, &ws[2], ep->tmout, nil)) != nil)
error(err); error(err);
qunlock(io); qunlock(io);
poperror(); poperror();
@ -1337,7 +1390,7 @@ epwrite(Ep *ep, void *va, long n)
iunlock(io->ring); iunlock(io->ring);
qunlock(io); qunlock(io);
if((err = waittd((Ctlr*)ep->hp->aux, ws, ep->tmout, nil)) != nil) if((err = waittd((Ctlr*)ep->hp->aux, ws, ep->tmout, io)) != nil)
error(err); error(err);
return n; return n;