changelog shortlog tags branches changeset file revisions annotate raw help

Mercurial > hg > plan9front / sys/src/9/bcm/usbdwc.c

revision 7205: 3aeef7e94ea9
parent 6832: f80792d28e0e
child 7312: 4dbf2522f668
     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);