git: 9front

Download patch

ref: a1afc14ea308bfc4e8f62164938cf6b8589159be
parent: 0d230bd39d7a243c7c8468d9abeddda732246cd3
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Mar 28 10:11:17 EDT 2015

sgi: new approach for etherseeq

touching transmit descriptors while dma is running causes the
front to fall off. new approach keeps a counter of free
descriptors in the Ring structure that is incremented
by txintr() when transmit completed.

txintr() will clean descriptors once dma has stopped and
restart dma when there are more descrtors in the chain.

--- a/sys/src/9/sgi/etherseeq.c
+++ b/sys/src/9/sgi/etherseeq.c
@@ -110,6 +110,7 @@
 {
 	Rendez;
 	int	size;
+	int	free;
 	uchar*	base;
 	Desc*	head;
 	Desc*	tail;
@@ -119,9 +120,10 @@
 {
 	Eor=	1<<31,		/* end of ring */
 	Eop=	1<<30,
-	Ie=	1<<29,
+	Ioc=	1<<29,		/* interrupt on completion */
 	Busy=	1<<24,
 	Empty=	1<<14,		/* no data here */
+	Done=	1<<15,		/* transmit done */
 };
 
 enum {
@@ -141,6 +143,32 @@
 static ulong dummy;
 
 static void
+txintr(Ctlr *ctlr)
+{
+	Hio *io;
+	ulong s;
+	Desc *p;
+
+	io = ctlr->io;
+	s = io->xstat;
+	if((s & Xdma) != 0)
+		return;
+	p = IO(Desc, ctlr->tx.head->next);
+	while((p->count & Busy) != 0){
+		if((p->count & Done) == 0){
+			io->nxbdp = PADDR(p);
+			io->xstat = Xdma;
+			break;
+		}
+		ctlr->tx.head = p;
+		p->count = Eor|Eop;
+		p = IO(Desc, p->next);
+		ctlr->tx.free++;
+	}
+	wakeup(&ctlr->tx);
+}
+
+static void
 interrupt(Ureg *, void *arg)
 {
 	Ether *edev;
@@ -156,6 +184,7 @@
 		io->ctl = Cnormal | Cover;
 	if(s & Cint) {
 		io->ctl = Cnormal | Cint;
+		txintr(ctlr);
 		wakeup(&ctlr->rx);
 	}
 }
@@ -164,12 +193,6 @@
 notempty(void *arg)
 {
 	Ctlr *ctlr = arg;
-	Hio *io;
-
-	io = ctlr->io;
-	dummy = io->piocfg;
-	if((io->rstat & Rdma) == 0)
-		return 1;
 	return (IO(Desc, ctlr->rx.head->next)->count & Empty) == 0;
 }
 
@@ -178,7 +201,6 @@
 {
 	Ether *edev = arg;
 	Ctlr *ctlr;
-	Hio *io;
 	Block *b;
 	Desc *p;
 	int n;
@@ -187,12 +209,9 @@
 		;
 
 	ctlr = edev->ctlr;
-	io = ctlr->io;
-	for(p = IO(Desc, ctlr->rx.head->next);; p = IO(Desc, p->next)){
-		while((p->count & Empty) != 0){
-			io->rstat = Rdma;
-			tsleep(&ctlr->rx, notempty, ctlr, 500);
-		}
+	for(p = IO(Desc, ctlr->rx.head->next);; p = IO(Desc, p->next)){
+		while((p->count & Empty) != 0)
+			sleep(&ctlr->rx, notempty, ctlr);
 		n = Rbsize - (p->count & 0x3fff)-3;
 		if(n >= ETHERMINTU){
 			if((p->base[n+2] & Rok) != 0){
@@ -203,51 +222,36 @@
 			}
 		}
 		p->addr = PADDR(p->base);
-		p->count = Ie|Empty|Rbsize;
+		p->count = Ioc|Empty|Rbsize;
 		ctlr->rx.head = p;
 	}
 }
 
+static int
+notbusy(void *arg)
+{
+	Ctlr *ctlr = arg;
+	return ctlr->tx.free > 0;
+}
+
 static void
 txproc(void *arg)
 {
 	Ether *edev = arg;
 	Ctlr *ctlr;
-	Hio *io;
 	Block *b;
 	Desc *p;
-	int clean, n;
+	int n;
 
 	while(waserror())
 		;
 
 	ctlr = edev->ctlr;
-	io = ctlr->io;
-	clean = ctlr->tx.size / 2;
 	for(p = IO(Desc, ctlr->tx.tail->next); (b = qbread(edev->oq, 1000000)) != nil; p = IO(Desc, p->next)){
-		while(!clean){
-			splhi();
-			p = ctlr->tx.head;
-			dummy = io->piocfg;
-			ctlr->tx.head = IO(Desc, io->nxbdp & ~0xf);
-			spllo();
-			while(p != ctlr->tx.head){
-				if((p->count & Busy) == 0)
-					break;
-				clean++;
-				p->count = Eor|Eop;
-				p = IO(Desc, p->next);
-			}
+		while(ctlr->tx.free == 0)
+			sleep(&ctlr->tx, notbusy, ctlr);
+		ctlr->tx.free--;
 
-			p = IO(Desc, ctlr->tx.tail->next);
-			if(clean)
-				break;
-
-			io->xstat = Xdma;
-			tsleep(&ctlr->tx, return0, nil, 10);
-		}
-		clean--;
-
 		n = BLEN(b);
 		if(n > ETHERMAXTU)
 			n = ETHERMAXTU;
@@ -254,12 +258,14 @@
 		memmove(p->base, b->rp, n);
 
 		p->addr = PADDR(p->base);
-		p->count = Eor|Eop|Busy|n;
+		p->count = Ioc|Eor|Eop|Busy|n;
 
-		ctlr->tx.tail->count &= ~Eor;
+		ctlr->tx.tail->count &= ~(Ioc|Eor);
 		ctlr->tx.tail = p;
 
-		io->xstat = Xdma;
+		splhi();
+		txintr(ctlr);
+		spllo();
 
 		freeb(b);
 	}
@@ -273,7 +279,8 @@
 	int m;
 
 	r->size = n;
-	
+	r->free = n;
+
 	m = n*BY2PG/2;
 	b = xspanalloc(m, BY2PG, 0);
 	dcflush(b, m);
@@ -324,7 +331,7 @@
 	p = ctlr->rx.head;
 	do {
 		p->addr = PADDR(p->base);
-		p->count = Ie|Empty|Rbsize;
+		p->count = Ioc|Empty|Rbsize;
 		p = IO(Desc, p->next);
 	} while(p != ctlr->rx.head);
 	io->crbdp = PADDR(p);
@@ -336,7 +343,6 @@
 		p->count = Eor|Eop;
 		p = IO(Desc, p->next);
 	} while(p != ctlr->tx.tail);
-	ctlr->tx.head = IO(Desc, p->next);
 	io->cxbdp = PADDR(p);
 	io->nxbdp = p->next;
 
@@ -343,8 +349,10 @@
 	for(i=0; i<6; i++)
 		io->eaddr[i] = edev->ea[i];
 
-	io->csx = 0; /* XIok | XImaxtry | XIcoll | XIunder; -- no interrupts needed */
+	io->csx = XIok | XImaxtry | XIcoll | XIunder;
 	io->csr = Rprom | RIok|RIend|RIshort|RIdrbl|RIcrc;
+
+	io->rstat = Rdma;
 
 	return 0;
 }
--