usbxhci: have to serialize and set read pointer for endpoint stop command
This commit is contained in:
parent
f001ddfdb5
commit
8ed13fe664
1 changed files with 86 additions and 33 deletions
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue