ref: 40dc39bf7d8d17a84d6a2a427ca7facd8b2cb66b
parent: eee7357c2778a65a3ecf552ac44b9a419e6e92d9
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Jul 17 17:10:25 EDT 2017
usbxhci: better approach to unstalling endpoint and fixup td ring instead of guessing where the controllers dequeue pointer went, stop the endpoint and then explicitely set te dequeue pointer to the next write td position. that way we do not need to fix the cycle bit in the td's and dont need to rely on if the controller advanced the dequeue pointer after a stall or not. add ctx and slot back pointers to ring.
--- a/sys/src/9/pc/usbxhci.c
+++ b/sys/src/9/pc/usbxhci.c
@@ -159,6 +159,10 @@
struct Ring
{
+ int id;
+
+ Slot *slot;
+
u32int *base;
u32int size;
@@ -168,10 +172,8 @@
u32int rp;
u32int wp;
- struct {
- u32int *r;
- u32int v;
- } doorbell;
+ u32int *ctx;
+ u32int *doorbell;
Wait *pending;
Lock;
@@ -264,8 +266,10 @@
static void
initring(Ring *r, int shift)
{
- r->doorbell.v = 0;
- r->doorbell.r = nil;
+ r->id = 0;
+ r->ctx = nil;
+ r->slot = nil;
+ r->doorbell = nil;
r->pending = nil;
r->shift = shift;
r->size = 1<<shift;
@@ -337,8 +341,8 @@
ctlr->setrptr(&ctlr->opr[DCBAAP], PADDR(ctlr->dcba));
initring(ctlr->cr, 8); /* 256 entries */
- ctlr->cr->doorbell.r = &ctlr->dba[0];
- ctlr->cr->doorbell.v = 0;
+ ctlr->cr->doorbell = &ctlr->dba[0];
+ ctlr->cr->id = 0;
coherence();
ctlr->setrptr(&ctlr->opr[CRCR], PADDR(ctlr->cr[0].base) | 1);
@@ -464,7 +468,7 @@
kickring(Ring *r)
{
coherence();
- *r->doorbell.r = r->doorbell.v;
+ *r->doorbell = r->id;
}
static char*
@@ -742,8 +746,10 @@
}
if(ep->mode != OREAD){
initring(io->ring[OWRITE] = &slot->epr[ep->nb*2-1], 8);
- io->ring[OWRITE]->doorbell.r = &ctlr->dba[slot->id];
- io->ring[OWRITE]->doorbell.v = ep->nb*2;
+ 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)
@@ -751,8 +757,10 @@
}
if(ep->mode != OWRITE){
initring(io->ring[OREAD] = &slot->epr[ep->nb*2], 8);
- io->ring[OREAD]->doorbell.r = &ctlr->dba[slot->id];
- io->ring[OREAD]->doorbell.v = ep->nb*2+1;
+ 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)
@@ -849,8 +857,10 @@
/* allocate control ep 0 ring */
initring(io->ring[OWRITE] = &slot->epr[0], 8);
- io->ring[OWRITE]->doorbell.r = &ctlr->dba[slot->id];
- io->ring[OWRITE]->doorbell.v = 1;
+ 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;
slot->nep = 1;
/* (input) control context */
@@ -905,60 +915,21 @@
}
static void
-resetring(Ring *r)
+unstall(Ring *r)
{
- ilock(r);
- r->rp--; /* assume previous td halted */
- while((int)(r->wp - r->rp) > 0){
- u32int *td = &r->base[4*(--r->wp & r->mask)];
- td[0] = td[1] = td[2] = 0;
- td[3] = (r->wp>>r->shift)&1;
- }
- iunlock(r);
-}
+ u64int qp;
-static int
-epunstall(Ep *ep, int mode)
-{
- Ctlr *ctlr;
- Slot *slot;
- Epio *io;
- u32int *w;
- int dci, ret;
+ switch(r->ctx[0]&7){
+ case 2:
+ case 4:
+ ilock(r);
+ r->rp = r->wp;
+ qp = PADDR(&r->base[4*(r->wp & r->mask)]) | ((~r->wp>>r->shift) & 1);
+ iunlock(r);
- ret = 0;
- io = ep->aux;
- slot = ep->dev->aux;
- ctlr = slot->ctlr;
-
- if(ep->nb == 0)
- dci = 1;
- else
- dci = ep->nb*2;
-
- /* (output) ep context */
- w = slot->obase;
- w += dci*8<<ctlr->csz;
- if(mode != OREAD && io->ring[OWRITE] != nil){
- switch(w[0]&7){
- case 2:
- case 4:
- resetring(io->ring[OWRITE]);
- ctlrcmd(ctlr, CR_RESETEP | (dci<<16) | (slot->id<<24), 0, 0, nil);
- ret++;
- }
+ 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);
}
- w += 8<<ctlr->csz, dci++;
- if(mode != OWRITE && io->ring[OREAD] != nil){
- switch(w[0]&7){
- case 2:
- case 4:
- resetring(io->ring[OREAD]);
- ctlrcmd(ctlr, CR_RESETEP | (dci<<16) | (slot->id<<24), 0, 0, nil);
- ret++;
- }
- }
- return ret;
}
static long
@@ -972,6 +943,7 @@
p = va;
io = ep->aux;
+
if(ep->ttype == Tctl){
qlock(io);
if(io->cb == nil || BLEN(io->cb) == 0){
@@ -1001,8 +973,8 @@
return n;
}
- epunstall(ep, OREAD);
ring = io->ring[OREAD];
+ unstall(ring);
ilock(ring);
queuetd(ring, TR_NORMAL | 1<<16 | 1<<5, n, PADDR(p), ws);
iunlock(ring);
@@ -1028,6 +1000,7 @@
p = va;
io = ep->aux;
+
if(ep->ttype == Tctl){
int dir, len;
@@ -1059,8 +1032,8 @@
}
}
- epunstall(ep, OWRITE);
ring = io->ring[OWRITE];
+ unstall(ring);
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 |
@@ -1104,8 +1077,8 @@
return n;
}
- epunstall(ep, OWRITE);
ring = io->ring[OWRITE];
+ unstall(ring);
ilock(ring);
queuetd(ring, TR_NORMAL | 1<<16 | 1<<5, n, PADDR(p), ws);
iunlock(ring);
@@ -1237,8 +1210,6 @@
if(getconf("*nousbxhci"))
return -1;
-
- fmtinstall(L'H', encodefmt);
scanpci();