code: plan9front

Download patch

ref: 9672be80e84cb3253dc999fbaa5dbc7913a17e0e
parent: 30dcf55ee221b986aee6d428b4da431f6174c66b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jul 31 09:12:17 EDT 2022

usb: fix ehci isochronous "in" split transactions

For "in" transactions, the "Total Bytes to Transfer" field in
the siTD is decremented by the controller by the actual transfer
size, so what remains in the field is the residue number of bytes.

Also, handle restart when we get a zero byte read on a isochronous
"in" endpoint in devusb itself (removing the restart code for
xhci drivers).

This fixes audio recording with a usb1.1 audio device connected
to ehci controller.

--- a/sys/src/9/imx8/usbxhciimx.c
+++ b/sys/src/9/imx8/usbxhciimx.c
@@ -1326,7 +1326,6 @@
 	}
 	µ = io->period;
 	ctlr = ep->hp->aux;
-Again:
 	if(needrecover(ctlr))
 		error(Erecover);
 
@@ -1374,10 +1373,6 @@
 	io->frame = i;
 
 	*io->ring->doorbell = io->ring->id;
-	if(p == s){
-		tsleep(&up->sleep, return0, nil, 5);
-		goto Again;
-	}
 	qunlock(io);
 	poperror();
 
--- a/sys/src/9/port/devusb.c
+++ b/sys/src/9/port/devusb.c
@@ -1199,19 +1199,22 @@
 		error(Enotconf);
 	case Tctl:
 		nr = rhubread(ep, a, n);
-		if(nr >= 0){
-			n = nr;
+		if(nr >= 0)
 			break;
-		}
 		/* else fall */
 	default:
 		ddeprint("\nusbread q %#x fid %d cnt %ld off %lld\n",q,c->fid,n,offset);
-		n = ep->hp->epread(ep, a, n);
+	Again:
+		nr = ep->hp->epread(ep, a, n);
+		if(nr == 0 && ep->ttype == Tiso){
+			tsleep(&up->sleep, return0, nil, 2*ep->pollival);
+			goto Again;
+		}
 		break;
 	}
 	poperror();
 	putep(ep);
-	return n;
+	return nr;
 }
 
 /*
--- a/sys/src/9/port/usbehci.c
+++ b/sys/src/9/port/usbehci.c
@@ -1365,7 +1365,7 @@
 	ctlr->nisointr++;
 	ddiprint("isohsintr: iso %#p: tdi %#p tdu %#p\n", iso, tdi, iso->tdu);
 	if(iso->state != Qrun && iso->state != Qdone)
-		panic("isofsintr: iso state");
+		panic("isohsintr: iso state");
 	if(ehcidebug > 1 || iso->debug > 1)
 		isodump(iso, 0);
 
@@ -1394,6 +1394,8 @@
 			tdi->ndata = 0;
 
 		if(tdi->next == iso->tdu || tdi->next->next == iso->tdu){
+			diprint("overrun iso %#p tdi %#p tdu %#p\n", iso, tdi, iso->tdu);
+
 			memset(iso->tdu->data, 0, iso->tdu->mdata);
 			itdinit(ctlr, iso, iso->tdu);
 			iso->tdu = iso->tdu->next;
@@ -1402,13 +1404,13 @@
 		tdi = tdi->next;
 		coherence();
 	}
-	ddiprint("isohsintr: %d frames processed\n", nframes);
+	ddiprint("isohsintr: %d frames processed\n", i);
 	if(i == nframes){
 		tdi->csw[0] |= Itdioc;
 		coherence();
 	}
-	iso->tdi = tdi;
 	coherence();
+	iso->tdi = tdi;
 	if(isocanwrite(iso) || isocanread(iso)){
 		diprint("wakeup iso %#p tdi %#p tdu %#p\n", iso,
 			iso->tdi, iso->tdu);
@@ -1444,20 +1446,24 @@
 		err = stdi->csw & Stderrors;
 		if(err == 0){
 			iso->nerrs = 0;
-			if(iso->tok == Tdtokin)
-				stdi->ndata = (stdi->csw>>Stdlenshift)&Stdlenmask;
-		}else if(iso->nerrs++ > iso->nframes/2){
-			if(iso->err == nil){
-				iso->err = serrmsg(err);
-				diprint("isofsintr: tdi %#p error %#ux %s\n",
-					stdi, err, iso->err);
-				diprint("ctlr load %uld\n", ctlr->load);
+			if(iso->tok == Tdtokin){
+				ulong residue = (stdi->csw>>Stdlenshift)&Stdlenmask;
+				stdi->ndata = residue < stdi->ndata ? stdi->ndata - residue : 0;
+				diprint("isofsintr: tdi %#p ndata %lud, mdata %lud\n", stdi, stdi->ndata, stdi->mdata);
 			}
+		}else {
+			diprint("isofsintr: tdi %#p error %#ux %s\n", stdi, err, serrmsg(err));
+			if(iso->nerrs++ > iso->nframes/2){
+				if(iso->err == nil){
+					iso->err = serrmsg(err);
+					diprint("ctlr load %uld\n", ctlr->load);
+				}
+			}
 			stdi->ndata = 0;
-		}else
-			stdi->ndata = 0;
-
+		}
 		if(stdi->next == iso->stdu || stdi->next->next == iso->stdu){
+			diprint("overrun iso %#p tdi %#p tdu %#p\n", iso, stdi, iso->stdu);
+
 			memset(iso->stdu->data, 0, iso->stdu->mdata);
 			sitdinit(ctlr, iso, iso->stdu);
 			iso->stdu = iso->stdu->next;
@@ -1466,13 +1472,13 @@
 		coherence();
 		stdi = stdi->next;
 	}
-	ddiprint("isofsintr: %d frames processed\n", nframes);
+	ddiprint("isofsintr: %d frames processed\n", i);
 	if(i == nframes){
 		stdi->csw |= Stdioc;
 		coherence();
 	}
-	iso->stdi = stdi;
 	coherence();
+	iso->stdi = stdi;
 	if(isocanwrite(iso) || isocanread(iso)){
 		diprint("wakeup iso %#p tdi %#p tdu %#p\n", iso,
 			iso->stdi, iso->stdu);
--- a/sys/src/9/port/usbxhci.c
+++ b/sys/src/9/port/usbxhci.c
@@ -1338,7 +1338,6 @@
 	}
 	µ = io->period;
 	ctlr = ep->hp->aux;
-Again:
 	if(needrecover(ctlr))
 		error(Erecover);
 
@@ -1386,10 +1385,6 @@
 	io->frame = i;
 
 	*io->ring->doorbell = io->ring->id;
-	if(p == s){
-		tsleep(&up->sleep, return0, nil, 5);
-		goto Again;
-	}
 	qunlock(io);
 	poperror();