ref: 8ed13fe6643eab17ef3f5cff75830d3a7c1bc715
parent: f001ddfdb598f9a588b22c029a5ade9030324c4b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Aug 1 21:45:30 EDT 2017
usbxhci: have to serialize and set read pointer for endpoint stop command
--- a/sys/src/9/pc/usbxhci.c
+++ b/sys/src/9/pc/usbxhci.c
@@ -175,6 +175,8 @@
u32int *ctx;
u32int *doorbell;
+ int stopped;
+
Wait *pending;
Lock;
};
@@ -302,6 +304,7 @@
r->slot = nil;
r->doorbell = nil;
r->pending = nil;
+ r->stopped = 0;
r->shift = shift;
r->mask = (1<<shift)-1;
r->rp = r->wp = 0;
@@ -474,30 +477,30 @@
}
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;
- x = ring->wp++;
- if((x & ring->mask) == ring->mask){
- td = ring->base + 4*(x & ring->mask);
- *(u64int*)td = PADDR(ring->base);
+ x = r->wp++;
+ if((x & r->mask) == r->mask){
+ td = r->base + 4*(x & r->mask);
+ *(u64int*)td = PADDR(r->base);
td[2] = 0;
- td[3] = ((~x>>ring->shift)&1) | (1<<1) | TR_LINK;
- x = ring->wp++;
+ td[3] = ((~x>>r->shift)&1) | (1<<1) | TR_LINK;
+ x = r->wp++;
}
- td = ring->base + 4*(x & ring->mask);
+ td = r->base + 4*(x & r->mask);
if(w != nil){
- memset(w->er, 0, 4*4);
- w->ring = ring;
+ w->er[0] = w->er[1] = w->er[2] = w->er[3] = 0;
+ w->ring = r;
w->td = td;
w->z = &up->sleep;
- w->next = ring->pending;
- ring->pending = w;
+ w->next = r->pending;
+ r->pending = w;
}
*(u64int*)td = p;
td[2] = s;
- td[3] = ((~x>>ring->shift)&1) | c;
+ td[3] = ((~x>>r->shift)&1) | c;
}
static char *ccerrtab[] = {
@@ -556,22 +559,45 @@
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*
ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er);
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();
- *ring->doorbell = ring->id;
+ *r->doorbell = r->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);
+ if(q != nil)
+ qlock(q);
+ if(!r->stopped) {
+ 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;
}
if(tmout > 0){
@@ -584,8 +610,12 @@
}
poperror();
- if(er != nil)
- memmove(er, w->er, 4*4);
+ if(r->stopped) {
+ ilock(r);
+ flushring(r);
+ iunlock(r);
+ }
+
return ccerrstr(w->er[2]>>24);
}
@@ -593,12 +623,21 @@
ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er)
{
Wait ws[1];
+ char *err;
ilock(ctlr->cr);
+ if(ctlr->cr->stopped){
+ flushring(ctlr->cr);
+ ctlr->cr->stopped = 0;
+ }
queuetd(ctlr->cr, c, s, p, ws);
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
@@ -682,6 +721,10 @@
case ER_HCE:
iprint("xhci: host controller error: %ux %ux %ux %ux\n",
td[0], td[1], td[2], td[3]);
+ ilock(ctlr->cr);
+ ctlr->cr->stopped = 1;
+ flushring(ctlr->cr);
+ iunlock(ctlr->cr);
break;
case ER_PORTSC:
break;
@@ -1133,21 +1176,27 @@
char *err;
switch(r->ctx[0]&7){
- case 0: /* disabled */
- case 1: /* running */
- case 3: /* stopped */
- break;
case 2: /* halted */
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);
+ flushring(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);
+ err = ctlrcmd(r->slot->ctlr, CR_SETTRDQP | (r->id<<16) | (r->slot->id<<24), 0, qp, nil);
if(err != nil)
return err;
+
+ r->stopped = 0;
}
if(r->wp - r->rp >= r->mask)
@@ -1210,7 +1259,7 @@
iunlock(io->ring);
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);
n -= (ws->er[2] & 0xFFFFFF);
@@ -1243,8 +1292,13 @@
return n;
io = (Epio*)ep->aux + OREAD;
+ ring = io[OWRITE-OREAD].ring;
qlock(io);
if(waserror()){
+ ilock(ring);
+ ring->pending = nil;
+ iunlock(ring);
+
qunlock(io);
nexterror();
}
@@ -1264,8 +1318,6 @@
io->b->wp += len;
}
}
-
- ring = io[OWRITE-OREAD].ring;
if((err = unstall(ring)) != nil)
error(err);
@@ -1304,6 +1356,7 @@
}
if((err = waittd((Ctlr*)ep->hp->aux, &ws[2], ep->tmout, nil)) != nil)
error(err);
+
qunlock(io);
poperror();
@@ -1337,7 +1390,7 @@
iunlock(io->ring);
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);
return n;