changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: usbdwc: enable Slowbuilkin workarround, improve split transaction timing, handle erroring sleep(), debugging

changeset 7205: 3aeef7e94ea9
parent 7204: d41b5fcde5ce
child 7206: 53f5476f9ffd
author: cinap_lenrek@felloff.net
date: Sun, 05 May 2019 13:34:02 +0200
files: sys/src/9/bcm/usbdwc.c
description: usbdwc: enable Slowbuilkin workarround, improve split transaction timing, handle erroring sleep(), debugging

i'v been seeing the error condition described above in the
Slowbulkin comment. so i'm enabling the work arround which
seems to fix the lockup.

in the split transaction case where we want to start the
transaction at frame start, acquire the ctlr lock *before*
checking if we are in the right frame number. so the start
will happen atomically. checking the software ctlr->sofchan
instead of checking the interrupt mask register seems to
be quicker.

setting the haint mask bit for the chan under ctlr lock
in chanio() instead of chanwait() avoids needing to acquire
the ctlr lock twice.

mask wakechan bits with busychan bitmap in interrupt handlers
so we will not try to wake up released chans by accident.

sleep() and tsleep() might get interrupted so we have to
release the split qlock in the split transaction case and
in all cases, make sure to halt the channel before release.

add some common debug functions to dump channel and controller
registers.
     1.1--- a/sys/src/9/bcm/usbdwc.c
     1.2+++ b/sys/src/9/bcm/usbdwc.c
     1.3@@ -41,10 +41,9 @@ enum
     1.4 	 * when the controller is reading a sequence of bulk input
     1.5 	 * packets in DMA mode.  Setting Slowbulkin=1 will avoid the
     1.6 	 * lockup by reading packets individually with an interrupt
     1.7-	 * after each.  More recent chips don't seem to exhibit the
     1.8-	 * problem, so it's probably safe to leave this off now.
     1.9+	 * after each.
    1.10 	 */
    1.11-	Slowbulkin	= 0,
    1.12+	Slowbulkin	= 1,
    1.13 };
    1.14 
    1.15 typedef struct Ctlr Ctlr;
    1.16@@ -54,13 +53,13 @@ struct Ctlr {
    1.17 	Lock;
    1.18 	Dwcregs	*regs;		/* controller registers */
    1.19 	int	nchan;		/* number of host channels */
    1.20-	ulong	chanbusy;	/* bitmap of in-use channels */
    1.21+	uint	chanbusy;	/* bitmap of in-use channels */
    1.22 	Lock	chanlock;	/* serialise access to chanbusy */
    1.23 	QLock	split;		/* serialise split transactions */
    1.24 	int	splitretry;	/* count retries of Nyet */
    1.25-	int	sofchan;	/* bitmap of channels waiting for sof */
    1.26-	int	wakechan;	/* bitmap of channels to wakeup after fiq */
    1.27-	int	debugchan;	/* bitmap of channels for interrupt debug */
    1.28+	uint	sofchan;	/* bitmap of channels waiting for sof */
    1.29+	uint	wakechan;	/* bitmap of channels to wakeup after fiq */
    1.30+	uint	debugchan;	/* bitmap of channels for interrupt debug */
    1.31 	Rendez	*chanintr;	/* sleep till interrupt on channel N */
    1.32 };
    1.33 
    1.34@@ -75,13 +74,17 @@ struct Epio {
    1.35 };
    1.36 
    1.37 static Ctlr dwc;
    1.38-static int debug;
    1.39+static int debug = 0;
    1.40 
    1.41 static char Ebadlen[] = "bad usb request length";
    1.42 
    1.43 static void clog(Ep *ep, Hostchan *hc);
    1.44 static void logdump(Ep *ep);
    1.45 
    1.46+static void dumpctlr(Ctlr *ctlr);
    1.47+static void dumphchan(Ctlr *ctlr, Hostchan *hc);
    1.48+static void dump(Hci *hp);
    1.49+
    1.50 static void
    1.51 filock(Lock *l)
    1.52 {
    1.53@@ -102,7 +105,8 @@ static Hostchan*
    1.54 chanalloc(Ep *ep)
    1.55 {
    1.56 	Ctlr *ctlr;
    1.57-	int bitmap, i;
    1.58+	int i;
    1.59+	uint bitmap;
    1.60 	static int first;
    1.61 
    1.62 	ctlr = ep->hp->aux;
    1.63@@ -123,13 +127,13 @@ retry:
    1.64 }
    1.65 
    1.66 static void
    1.67-chanrelease(Ep *ep, Hostchan *chan)
    1.68+chanrelease(Ep *ep, Hostchan *hc)
    1.69 {
    1.70 	Ctlr *ctlr;
    1.71 	int i;
    1.72 
    1.73 	ctlr = ep->hp->aux;
    1.74-	i = chan - ctlr->regs->hchan;
    1.75+	i = hc - ctlr->regs->hchan;
    1.76 	lock(&ctlr->chanlock);
    1.77 	ctlr->chanbusy &= ~(1<<i);
    1.78 	unlock(&ctlr->chanlock);
    1.79@@ -188,74 +192,68 @@ chansetup(Hostchan *hc, Ep *ep)
    1.80 	hc->hcint = ~0;
    1.81 }
    1.82 
    1.83+static void
    1.84+chanhalt(Ep *ep, Hostchan *hc)
    1.85+{
    1.86+	ulong start;
    1.87+
    1.88+	hc->hcintmsk = 0;
    1.89+	hc->hcchar |= Chdis;
    1.90+	start = m->ticks;
    1.91+	while(hc->hcchar & Chen){
    1.92+		if(m->ticks - start >= 100){
    1.93+			print("ep%d.%d channel won't halt hcchar %8.8ux\n",
    1.94+				ep->dev->nb, ep->nb, hc->hcchar);
    1.95+			dump(ep->hp);
    1.96+			break;
    1.97+		}
    1.98+	}
    1.99+}
   1.100+
   1.101 static int
   1.102 sofdone(void *a)
   1.103 {
   1.104-	Dwcregs *r;
   1.105-
   1.106-	r = a;
   1.107-	return (r->gintmsk & Sofintr) == 0;
   1.108-}
   1.109-
   1.110-static void
   1.111-sofwait(Ctlr *ctlr, int n)
   1.112-{
   1.113-	Dwcregs *r;
   1.114-
   1.115-	r = ctlr->regs;
   1.116-	do{
   1.117-		filock(ctlr);
   1.118-		r->gintsts = Sofintr;
   1.119-		ctlr->sofchan |= 1<<n;
   1.120-		r->gintmsk |= Sofintr;
   1.121-		fiunlock(ctlr);
   1.122-		sleep(&ctlr->chanintr[n], sofdone, r);
   1.123-	}while((r->hfnum & 7) == 6);
   1.124+	Ctlr *ctlr = a;
   1.125+	return ctlr->sofchan == 0;
   1.126 }
   1.127 
   1.128 static int
   1.129 chandone(void *a)
   1.130 {
   1.131 	Hostchan *hc;
   1.132+	int i;
   1.133 
   1.134 	hc = a;
   1.135-	if(hc->hcint == (Chhltd|Ack))
   1.136+	i = hc->hcint;
   1.137+	if(i == (Chhltd|Ack))
   1.138 		return 0;
   1.139-	return (hc->hcint & hc->hcintmsk) != 0;
   1.140+	return (i & hc->hcintmsk) != 0;
   1.141 }
   1.142 
   1.143 static int
   1.144 chanwait(Ep *ep, Ctlr *ctlr, Hostchan *hc, int mask)
   1.145 {
   1.146-	int intr, n, ointr;
   1.147+	int intr, ointr, chan;
   1.148 	ulong start, now;
   1.149-	Dwcregs *r;
   1.150 
   1.151-	r = ctlr->regs;
   1.152-	n = hc - r->hchan;
   1.153+	chan = hc - ctlr->regs->hchan;
   1.154 	for(;;){
   1.155 restart:
   1.156-		filock(ctlr);
   1.157-		r->haintmsk |= 1<<n;
   1.158-		hc->hcintmsk = mask;
   1.159-		fiunlock(ctlr);
   1.160-		tsleep(&ctlr->chanintr[n], chandone, hc, 1000);
   1.161+		tsleep(&ctlr->chanintr[chan], chandone, hc, 1000);
   1.162 		if((intr = hc->hcint) == 0)
   1.163 			goto restart;
   1.164-		hc->hcintmsk = 0;
   1.165 		if(intr & Chhltd)
   1.166 			return intr;
   1.167-		start = fastticks(0);
   1.168 		ointr = intr;
   1.169-		now = start;
   1.170+		now = start = fastticks(0);
   1.171 		do{
   1.172 			intr = hc->hcint;
   1.173 			if(intr & Chhltd){
   1.174 				if((ointr != Ack && ointr != (Ack|Xfercomp)) ||
   1.175 				   intr != (Ack|Chhltd|Xfercomp) ||
   1.176 				   (now - start) > 60)
   1.177-					dprint("await %x after %ldµs %x -> %x\n",
   1.178-						mask, now - start, ointr, intr);
   1.179+					dprint("ep%d.%d await %x after %ldµs %x -> %x\n",
   1.180+						ep->dev->nb, ep->nb, mask, now - start, ointr, intr);
   1.181 				return intr;
   1.182 			}
   1.183 			if((intr & mask) == 0){
   1.184@@ -266,21 +264,15 @@ restart:
   1.185 			}
   1.186 			now = fastticks(0);
   1.187 		}while(now - start < 100);
   1.188-		dprint("ep%d.%d halting channel %8.8ux hcchar %8.8ux "
   1.189-			"grxstsr %8.8ux gnptxsts %8.8ux hptxsts %8.8ux\n",
   1.190-			ep->dev->nb, ep->nb, intr, hc->hcchar, r->grxstsr,
   1.191-			r->gnptxsts, r->hptxsts);
   1.192-		mask = Chhltd;
   1.193-		hc->hcchar |= Chdis;
   1.194-		start = m->ticks;
   1.195-		while(hc->hcchar & Chen){
   1.196-			if(m->ticks - start >= 100){
   1.197-				print("ep%d.%d channel won't halt hcchar %8.8ux\n",
   1.198-					ep->dev->nb, ep->nb, hc->hcchar);
   1.199-				break;
   1.200-			}
   1.201+		if(debug){
   1.202+			print("ep%d.%d halting chan %d intr %x\n",
   1.203+				ep->dev->nb, ep->nb, chan, intr);
   1.204+			dumphchan(ctlr, hc);
   1.205+			dumpctlr(ctlr);
   1.206 		}
   1.207+		chanhalt(ep, hc);
   1.208 		logdump(ep);
   1.209+		hc->hcintmsk = mask = Chhltd;
   1.210 	}
   1.211 }
   1.212 
   1.213@@ -371,7 +363,7 @@ static int
   1.214 chanio(Ep *ep, Hostchan *hc, int dir, int pid, void *a, int len)
   1.215 {
   1.216 	Ctlr *ctlr;
   1.217-	int nleft, n, nt, i, maxpkt, npkt;
   1.218+	int nleft, n, nt, i, imask, maxpkt, npkt, chan, split;
   1.219 	uint hcdma, hctsiz;
   1.220 
   1.221 	ctlr = ep->hp->aux;
   1.222@@ -388,9 +380,17 @@ chanio(Ep *ep, Hostchan *hc, int dir, in
   1.223 	hc->hctsiz = n | npkt<<OPktcnt | pid;
   1.224 	hc->hcdma  = dmaaddr(a);
   1.225 
   1.226+	split = hc->hcsplt & Spltena;
   1.227+	if(ep->ttype == Tbulk && dir == Epin || ep->ttype == Tintr && split)
   1.228+		imask = Chhltd;
   1.229+	else
   1.230+		imask = Chhltd|Nak;
   1.231+
   1.232 	nleft = len;
   1.233 	logstart(ep);
   1.234 	for(;;){
   1.235+		Dwcregs *r;
   1.236+
   1.237 		hcdma = hc->hcdma;
   1.238 		hctsiz = hc->hctsiz;
   1.239 		hc->hctsiz = hctsiz & ~Dopng;
   1.240@@ -407,34 +407,46 @@ chanio(Ep *ep, Hostchan *hc, int dir, in
   1.241 				ep->dev->nb, ep->nb, i);
   1.242 			hc->hcint = i;
   1.243 		}
   1.244-		if(hc->hcsplt & Spltena){
   1.245+
   1.246+		r = ctlr->regs;
   1.247+		chan = hc - r->hchan;
   1.248+		if(split){
   1.249 			qlock(&ctlr->split);
   1.250-			sofwait(ctlr, hc - ctlr->regs->hchan);
   1.251-			if((dwc.regs->hfnum & 1) == 0)
   1.252+			if(waserror()){
   1.253+				qunlock(&ctlr->split);
   1.254+				nexterror();
   1.255+			}
   1.256+			filock(ctlr);
   1.257+			do {
   1.258+				ctlr->sofchan = 1<<chan;
   1.259+				r->gintmsk |= Sofintr;
   1.260+				fiunlock(ctlr);
   1.261+				sleep(&ctlr->chanintr[chan], sofdone, ctlr);
   1.262+				filock(ctlr);
   1.263+				i = r->hfnum;
   1.264+			} while((i & 7) == 6);
   1.265+			if((i & 1) == 0)
   1.266 				hc->hcchar &= ~Oddfrm;
   1.267 			else
   1.268 				hc->hcchar |= Oddfrm;
   1.269+		} else {
   1.270+			filock(ctlr);
   1.271 		}
   1.272+		hc->hcintmsk = imask;
   1.273 		hc->hcchar = (hc->hcchar &~ Chdis) | Chen;
   1.274 		clog(ep, hc);
   1.275-wait:
   1.276-		if(ep->ttype == Tbulk && dir == Epin)
   1.277-			i = chanwait(ep, ctlr, hc, Chhltd);
   1.278-		else if(ep->ttype == Tintr && (hc->hcsplt & Spltena))
   1.279-			i = chanwait(ep, ctlr, hc, Chhltd);
   1.280-		else
   1.281-			i = chanwait(ep, ctlr, hc, Chhltd|Nak);
   1.282+		r->haintmsk |= 1<<chan;
   1.283+		fiunlock(ctlr);
   1.284+
   1.285+		i = chanwait(ep, ctlr, hc, imask);
   1.286 		clog(ep, hc);
   1.287-		if(hc->hcint != i){
   1.288-			dprint("chanwait intr %ux->%ux\n", i, hc->hcint);
   1.289-			if((i = hc->hcint) == 0)
   1.290-				goto wait;
   1.291-		}
   1.292+		hc->hcintmsk = 0;
   1.293 		hc->hcint = i;
   1.294 
   1.295-		if(hc->hcsplt & Spltena){
   1.296+		if(split){
   1.297 			hc->hcsplt &= ~Compsplt;
   1.298 			qunlock(&ctlr->split);
   1.299+			poperror();
   1.300 		}
   1.301 
   1.302 		if((i & Xfercomp) == 0 && i != (Chhltd|Ack) && i != Chhltd){
   1.303@@ -530,6 +542,7 @@ eptrans(Ep *ep, int rw, void *a, long n)
   1.304 	hc = chanalloc(ep);
   1.305 	if(waserror()){
   1.306 		ep->toggle[rw] = hc->hctsiz & Pid;
   1.307+		chanhalt(ep, hc);
   1.308 		chanrelease(ep, hc);
   1.309 		if(strcmp(up->errstr, Estalled) == 0)
   1.310 			return 0;
   1.311@@ -581,6 +594,7 @@ ctltrans(Ep *ep, uchar *req, long n)
   1.312 	}
   1.313 	hc = chanalloc(ep);
   1.314 	if(waserror()){
   1.315+		chanhalt(ep, hc);
   1.316 		chanrelease(ep, hc);
   1.317 		if(strcmp(up->errstr, Estalled) == 0)
   1.318 			return 0;
   1.319@@ -683,8 +697,34 @@ init(Hci *hp)
   1.320 }
   1.321 
   1.322 static void
   1.323-dump(Hci*)
   1.324+dumphchan(Ctlr *ctlr, Hostchan *hc)
   1.325+{
   1.326+	int chan = hc - ctlr->regs->hchan;
   1.327+
   1.328+	print("hchan[%d] hcchar %ux hcsplt %ux hcint %ux hcintmsk %ux hctsiz %ux hcdma %ux\n",
   1.329+		chan, hc->hcchar, hc->hcsplt, hc->hcint, hc->hcintmsk, hc->hctsiz, hc->hcdma);
   1.330+}
   1.331+
   1.332+static void
   1.333+dumpctlr(Ctlr *ctlr)
   1.334 {
   1.335+	Dwcregs *r = ctlr->regs;
   1.336+
   1.337+	print("grxstsr %ux gnptxsts %ux hptxsts %ux\n",
   1.338+		r->grxstsr, r->gnptxsts, r->hptxsts);
   1.339+	print("gintsts %ux gintmsk %ux, haint %ux haintmsk %ux\n",
   1.340+		r->gintsts, r->gintmsk, r->haint, r->haintmsk);
   1.341+}
   1.342+
   1.343+static void
   1.344+dump(Hci *hp)
   1.345+{
   1.346+	Ctlr *ctlr = hp->aux;
   1.347+	int i;
   1.348+
   1.349+	dumpctlr(ctlr);
   1.350+	for(i = 0; i < ctlr->nchan; i++)
   1.351+		dumphchan(ctlr, &ctlr->regs->hchan[i]);
   1.352 }
   1.353 
   1.354 static void
   1.355@@ -703,6 +743,7 @@ fiqintr(Ureg*, void *a)
   1.356 	filock(ctlr);
   1.357 	intr = r->gintsts;
   1.358 	if(intr & Hcintr){
   1.359+		r->haintmsk &= ctlr->chanbusy;
   1.360 		haint = r->haint & r->haintmsk;
   1.361 		for(i = 0; haint; i++){
   1.362 			if(haint & 1){
   1.363@@ -722,6 +763,7 @@ fiqintr(Ureg*, void *a)
   1.364 			ctlr->sofchan = 0;
   1.365 		}
   1.366 	}
   1.367+	wakechan &= ctlr->chanbusy;
   1.368 	if(wakechan){
   1.369 		ctlr->wakechan |= wakechan;
   1.370 		armtimerset(1);
   1.371@@ -742,6 +784,7 @@ irqintr(Ureg*, void *a)
   1.372 	wakechan = ctlr->wakechan;
   1.373 	ctlr->wakechan = 0;
   1.374 	fiunlock(ctlr);
   1.375+	wakechan &= ctlr->chanbusy;
   1.376 	for(i = 0; wakechan; i++){
   1.377 		if(wakechan & 1)
   1.378 			wakeup(&ctlr->chanintr[i]);
   1.379@@ -831,8 +874,8 @@ epread(Ep *ep, void *a, long n)
   1.380 		assert(((uintptr)p & (BLOCKALIGN-1)) == 0);
   1.381 		cachedinvse(p, n);
   1.382 		nr = eptrans(ep, Read, p, n);
   1.383+		epio->lastpoll = TK2MS(m->ticks);
   1.384 		cachedinvse(p, nr);
   1.385-		epio->lastpoll = TK2MS(m->ticks);
   1.386 		memmove(a, p, nr);
   1.387 		qunlock(q);
   1.388 		freeb(b);