shithub: riscv

Download patch

ref: 1ea109345b8654110239d9c2695ae15486aa6810
parent: 8ed13fe6643eab17ef3f5cff75830d3a7c1bc715
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Aug 2 16:25:19 EDT 2017

usbxhci: abandon multiple requests per endpoint, cleanup

more conservative approach: only one transaction in flight
per endpoint (except iso). also serialize controller commands.
no driver currently uses this and i doubt it is usefull.

create constants for common TRB flags and remove bogus 1<<16
flag on TR_NORMAL.

--- a/sys/src/9/pc/usbxhci.c
+++ b/sys/src/9/pc/usbxhci.c
@@ -105,6 +105,15 @@
 	ERSTBA		= 0x10/4,	/* Event Ring Segment Table Base Address */
 	ERDP		= 0x18/4,	/* Event Ring Dequeue Pointer */
 
+	/* TRB flags */
+	TR_ENT		= 1<<1,
+	TR_ISP		= 1<<2,
+	TR_NS		= 1<<3,
+	TR_CH		= 1<<4,
+	TR_IOC		= 1<<5,
+	TR_IDT		= 1<<6,
+	TR_BEI		= 1<<9,
+	
 	/* TRB types */
 	TR_RESERVED	= 0<<10,
 	TR_NORMAL	= 1<<10,
@@ -222,6 +231,7 @@
 	u32int	*erst[1];	/* event ring segment table */
 	Ring	er[1];		/* event ring segment */
 	Ring	cr[1];		/* command ring segment */
+	QLock	cmdlock;
 
 	u32int	µframe;
 
@@ -265,6 +275,7 @@
 static void
 setrptr32(u32int *reg, u64int pa)
 {
+	coherence();
 	reg[0] = pa;
 	reg[1] = pa>>32;
 }
@@ -272,6 +283,7 @@
 static void
 setrptr64(u32int *reg, u64int pa)
 {
+	coherence();
 	*((u64int*)reg) = pa;
 }
 
@@ -316,6 +328,36 @@
 	return r;
 }
 
+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 u64int
+resetring(Ring *r)
+{
+	u64int pa;
+
+	ilock(r);
+	flushring(r);
+	r->rp = r->wp;
+	pa = PADDR(&r->base[4*(r->wp & r->mask)]) | ((~r->wp>>r->shift) & 1);
+	iunlock(r);
+
+	return pa;
+}
+
 static u32int*
 xecp(Ctlr *ctlr, uchar id, u32int *p)
 {
@@ -431,14 +473,12 @@
 	for(i=1; i<=ctlr->nslots; i++)
 		ctlr->dcba[i] = 0;
 	ctlr->opr[CONFIG] = ctlr->nslots;	/* MaxSlotsEn */
-	coherence();
 	ctlr->setrptr(&ctlr->opr[DCBAAP], PADDR(ctlr->dcba));
 
 	initring(ctlr->cr, 8);		/* 256 entries */
 	ctlr->cr->id = 0;
 	ctlr->cr->doorbell = &ctlr->dba[0];
-	coherence();
-	ctlr->setrptr(&ctlr->opr[CRCR], PADDR(ctlr->cr[0].base) | 1);
+	ctlr->setrptr(&ctlr->opr[CRCR], resetring(ctlr->cr));
 
 	for(i=0; i<ctlr->nintrs; i++){
 		u32int *irs = &ctlr->rts[IR0 + i*8];
@@ -456,9 +496,7 @@
 		ctlr->erst[i][3] = 0;
 
 		irs[ERSTSZ] = 1;	/* just one segment */
-		coherence();
 		ctlr->setrptr(&irs[ERDP], PADDR(ctlr->er[i].base));
-		coherence();
 		ctlr->setrptr(&irs[ERSTBA], PADDR(ctlr->erst[i]));
 
 		irs[IMAN] = 3;
@@ -495,9 +533,13 @@
 		w->ring = r;
 		w->td = td;
 		w->z = &up->sleep;
+
+		ilock(r);
 		w->next = r->pending;
 		r->pending = w;
+		iunlock(r);
 	}
+	coherence();
 	*(u64int*)td = p;
 	td[2] = s;
 	td[3] = ((~x>>r->shift)&1) | c;
@@ -559,27 +601,11 @@
 	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, QLock *q)
+waittd(Ctlr *ctlr, Wait *w, int tmout)
 {
 	Ring *r = w->ring;
 
@@ -587,8 +613,6 @@
 	*r->doorbell = r->id;
 
 	while(waserror()){
-		if(q != nil)
-			qlock(q);
 		if(!r->stopped) {
 			if(r == ctlr->cr)
 				ctlr->opr[CRCR] |= CA;
@@ -596,8 +620,6 @@
 				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){
@@ -610,12 +632,6 @@
 	}
 	poperror();
 
-	if(r->stopped) {
-		ilock(r);
-		flushring(r);
-		iunlock(r);
-	}
-
 	return ccerrstr(w->er[2]>>24);
 }
 
@@ -622,20 +638,25 @@
 static char*
 ctlrcmd(Ctlr *ctlr, u32int c, u32int s, u64int p, u32int *er)
 {
-	Wait ws[1];
+	Wait w[1];
 	char *err;
 
-	ilock(ctlr->cr);
-	if(ctlr->cr->stopped){
-		flushring(ctlr->cr);
-		ctlr->cr->stopped = 0;
+	qlock(&ctlr->cmdlock);
+
+	if((ctlr->opr[USBSTS] & (HCH|HCE|HSE)) != 0){
+		qunlock(&ctlr->cmdlock);
+		return "xhci busted";
 	}
-	queuetd(ctlr->cr, c, s, p, ws);
-	iunlock(ctlr->cr);
 
-	err = waittd(ctlr, ws, 5000, nil);
+	ctlr->cr->stopped = 0;
+
+	queuetd(ctlr->cr, c, s, p, w);
+	err = waittd(ctlr, w, 5000);
+
+	qunlock(&ctlr->cmdlock);
+
 	if(er != nil)
-		memmove(er, ws->er, 4*4);
+		memmove(er, w->er, 4*4);
 
 	return err;
 }
@@ -1149,10 +1170,7 @@
 		p += m, n -= m;
 		m += io->nleft, d -= io->nleft;
 		io->nleft = 0;
-		coherence();
-		ilock(io->ring);
-		queuetd(io->ring, TR_ISOCH | (i*µ/8 & 0x7ff)<<20 | 1<<5, m, PADDR(d), nil);
-		iunlock(io->ring);
+		queuetd(io->ring, TR_ISOCH | (i*µ/8 & 0x7ff)<<20 | TR_IOC, m, PADDR(d), nil);
 	}
 	io->frame = i;
 	while(io->ring->rp != io->ring->wp){
@@ -1172,7 +1190,6 @@
 static char*
 unstall(Ring *r)
 {
-	u64int qp;
 	char *err;
 
 	switch(r->ctx[0]&7){
@@ -1179,29 +1196,18 @@
 	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_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, resetring(r), nil);
 		if(err != nil)
 			return err;
-
 		r->stopped = 0;
 	}
-
 	if(r->wp - r->rp >= r->mask)
 		return "Ring Full";
-
 	return nil;
 }
 
@@ -1211,7 +1217,7 @@
 	Epio *io;
 	uchar *p;
 	char *err;
-	Wait ws[1];
+	Wait w[1];
 
 	if(ep->dev->isroot)
 		error(Egreg);
@@ -1250,19 +1256,22 @@
 
 	io = (Epio*)ep->aux + OREAD;
 	qlock(io);
-	if((err = unstall(io->ring)) != nil){
+	if(waserror()){
 		qunlock(io);
-		error(err);
+		nexterror();
 	}
-	ilock(io->ring);
-	queuetd(io->ring, TR_NORMAL | 1<<16 | 1<<5, n, PADDR(p), ws);
-	iunlock(io->ring);
-	qunlock(io);
 
-	if((err = waittd((Ctlr*)ep->hp->aux, ws, ep->tmout, io)) != nil)
+	if((err = unstall(io->ring)) != nil)
 		error(err);
 
-	n -= (ws->er[2] & 0xFFFFFF);
+	queuetd(io->ring, TR_NORMAL | TR_IOC, n, PADDR(p), w);
+	if((err = waittd((Ctlr*)ep->hp->aux, w, ep->tmout)) != nil)
+		error(err);
+
+	qunlock(io);
+	poperror();
+
+	n -= (w->er[2] & 0xFFFFFF);
 	if(n < 0)
 		n = 0;
 
@@ -1272,7 +1281,7 @@
 static long
 epwrite(Ep *ep, void *va, long n)
 {
-	Wait ws[3];
+	Wait w[3];
 	Epio *io;
 	uchar *p;
 	char *err;
@@ -1298,7 +1307,6 @@
 			ilock(ring);
 			ring->pending = nil;
 			iunlock(ring);
-
 			qunlock(io);
 			nexterror();
 		}
@@ -1333,28 +1341,26 @@
 				error(err);
 		}
 
-		ilock(ring);
-		queuetd(ring, TR_SETUPSTAGE | (len > 0 ? 2+dir : 0)<<16 | 1<<6 | 1<<5, 8,
+		queuetd(ring, TR_SETUPSTAGE | (len > 0 ? 2+dir : 0)<<16 | TR_IDT | TR_IOC, 8,
 			p[0] | p[1]<<8 | GET2(&p[2])<<16 |
-			(u64int)(GET2(&p[4]) | len<<16)<<32, &ws[0]);
+			(u64int)(GET2(&p[4]) | len<<16)<<32, &w[0]);
 		if(len > 0)
-			queuetd(ring, TR_DATASTAGE | dir<<16 | 1<<5, len,
-				PADDR(io->b->rp), &ws[1]);
-		queuetd(ring, TR_STATUSSTAGE | (len == 0 || !dir)<<16 | 1<<5, 0, 0, &ws[2]);
-		iunlock(ring);
+			queuetd(ring, TR_DATASTAGE | dir<<16 | TR_IOC, len,
+				PADDR(io->b->rp), &w[1]);
+		queuetd(ring, TR_STATUSSTAGE | (len == 0 || !dir)<<16 | TR_IOC, 0, 0, &w[2]);
 
-		if((err = waittd((Ctlr*)ep->hp->aux, &ws[0], ep->tmout, nil)) != nil)
+		if((err = waittd((Ctlr*)ep->hp->aux, &w[0], ep->tmout)) != nil)
 			error(err);
 		if(len > 0){
-			if((err = waittd((Ctlr*)ep->hp->aux, &ws[1], ep->tmout, nil)) != nil)
+			if((err = waittd((Ctlr*)ep->hp->aux, &w[1], ep->tmout)) != nil)
 				error(err);
 			if(dir != 0){
-				io->b->wp -= (ws[1].er[2] & 0xFFFFFF);
+				io->b->wp -= (w[1].er[2] & 0xFFFFFF);
 				if(io->b->wp < io->b->rp)
 					io->b->wp = io->b->rp;
 			}
 		}
-		if((err = waittd((Ctlr*)ep->hp->aux, &ws[2], ep->tmout, nil)) != nil)
+		if((err = waittd((Ctlr*)ep->hp->aux, &w[2], ep->tmout)) != nil)
 			error(err);
 
 		qunlock(io);
@@ -1381,17 +1387,20 @@
 
 	io = (Epio*)ep->aux + OWRITE;
 	qlock(io);
-	if((err = unstall(io->ring)) != nil){
+	if(waserror()){
 		qunlock(io);
-		error(err);
+		nexterror();
 	}
-	ilock(io->ring);
-	queuetd(io->ring, TR_NORMAL | 1<<16 | 1<<5, n, PADDR(p), ws);
-	iunlock(io->ring);
-	qunlock(io);
 
-	if((err = waittd((Ctlr*)ep->hp->aux, ws, ep->tmout, io)) != nil)
+	if((err = unstall(io->ring)) != nil)
 		error(err);
+
+	queuetd(io->ring, TR_NORMAL | TR_IOC, n, PADDR(p), w);
+	if((err = waittd((Ctlr*)ep->hp->aux, w, ep->tmout)) != nil)
+		error(err);
+
+	qunlock(io);
+	poperror();
 
 	return n;
 }