shithub: riscv

Download patch

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;