git: 9front

Download patch

ref: d9f5e134ec90e14bb395214023ef08c79897ef6b
parent: c7fd2271fc751c1cdcc53ca5b822837c261a04e2
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jan 12 07:08:10 EST 2014

etheryuk: fix lockups (thanks burnzez for testing)

according to a comment in linux driver, reading Isrc2
register caused interrupts to be disabled. we used
to read Isrc2 in ifstat() and it was confirmed that
reading ifstat locks up ethernet. removing the Isrc2
read in ifstats, and also reenable interrupts after
reading Isrc2 when the interrupt was not for us.
(this is from the linux driver)

in replenish(), set ring software write pointer (Sring.wp)
*before* the hardware write index register. otherwise
rx() could get status notification for completed
receive but wont find the rx descriptor in the ring.

handle uint wrap arround when calculating ring fill
count and remaining count.

--- a/sys/src/9/pc/etheryuk.c
+++ b/sys/src/9/pc/etheryuk.c
@@ -49,6 +49,7 @@
 	Isrc2	= 0x001c/4,
 	Eisr	= 0x0024/4,
 	Lisr	= 0x0028/4,		/* leave isr */
+	Icr	= 0x002c/4,
 	Macadr	= 0x0100,		/* mac address 2ports*3 */
 	Pmd	= 0x0119,
 	Maccfg	= 0x011a,
@@ -831,7 +832,7 @@
 {
 	int i;
 
-	if(r->rp + r->m - (n - 1) - wp[0] & ~r->m)
+	if(r->m - (int)(wp[0] - r->rp) < n)
 		return -1;
 	for(i = 0; i < n; i++)
 		t[i] = r->r + (wp[0]++ & r->m);
@@ -1150,7 +1151,6 @@
 		while(getnslot(r, &r->wp, tab, 1 + is64()) == -1)
 			starve(&c->txmit);
 		t = tab[is64()];
-		assert(c->tbring[t - r->r] == nil);
 		c->tbring[t - r->r] = b;
 		if(is64()){
 			Status *t = tab[0];
@@ -1205,7 +1205,7 @@
 	Ctlr *c;
 
 	c = e->ctlr;
-	if(wp - r->rp > r->cnt){
+	if((int)(wp - r->rp) >= r->cnt){
 		print("rxscrew1 wp %ud(%ud) rp %ud %lud\n", wp, r->wp, r->rp, t-r->r);
 		return -1;
 	}
@@ -1245,7 +1245,6 @@
 			freeb(b);
 			break;
 		}
-		assert(c->rbring[t - r->r] == nil);
 		c->rbring[t - r->r] = b;
 
 		if(is64()){
@@ -1260,9 +1259,9 @@
 		t->op = Opkt | Hw;
 	}
 	if(n>0){
+		r->wp = wp;
 		sfence();
 		prwrite16(c, Qr + Pputidx, wp & r->m);
-		r->wp = wp;
 		dprint("yuk: replenish %d %ud-%ud [%d-%d]\n", n, r->rp, wp, r->rp&r->m, wp&r->m);
 	}
 	return n == lim;
@@ -1380,14 +1379,14 @@
 static void
 txcleanup(Ctlr *c, uint end)
 {
-	uint rp0, rp;
+	uint rp;
 	Block *b;
 	Sring *r;
 	Status *t;
 
 	r = &c->tx;
-	rp0 = r->rp & r->m;
-	for(rp = rp0; rp != end; rp = r->rp & r->m){
+	end &= r->m;
+	for(rp = r->rp & r->m; rp != end; rp = r->rp & r->m){
 		t = r->r + rp;
 		r->rp++;
 		if((t->ctl & Eop) == 0)
@@ -1397,8 +1396,7 @@
 		if(b != nil)
 			freeb(b);
 	}
-	if(r->wp - r->rp > 16)
-		unstarve(&c->txmit);
+	unstarve(&c->txmit);
 }
 
 static void
@@ -1412,8 +1410,10 @@
 	c = e->ctlr;
 	r = &c->rx;
 	for(rp = r->rp;;){
-		if(rp == r->wp)
+		if(rp == r->wp){
+			print("#l%d: yuk rx empty\n", e->ctlrno);
 			return;
+		}
 		i = rp++&r->m;
 		b = c->rbring[i];
 		c->rbring[i] = nil;
@@ -1420,6 +1420,7 @@
 		if(b != nil)
 			break;
 	}
+	r->rp = rp;
 	cnt = x>>16 & 0x7fff;
 	if((cnt != l || x&Rxerror) &&
 	!(c->type == Yukfep && c->rev == 0)){
@@ -1430,7 +1431,7 @@
 		b->flag |= flag;
 		etheriq(e, b, 1);
 	}
-	r->rp = rp;
+	unstarve(&c->rxmit);
 }
 
 static uint
@@ -1446,7 +1447,7 @@
 static void
 sring(Ether *e)
 {
-	uint i, p, lim, op, l, x;
+	uint i, lim, op, l, x;
 	Ctlr *c;
 	Sring *r;
 	Status *s;
@@ -1455,7 +1456,6 @@
 	c = e->ctlr;
 	r = &c->status;
 	lim = c->reg16[Stathd] & r->m;
-	p = 0;
 	for(;;){
 		i = r->rp & r->m;
 		if(i == lim){
@@ -1477,7 +1477,6 @@
 			x = getle(s->status, 4);
 			rx(e, l, x, cksum(c, ck, s->ctl));
 			ck = Badck;
-			p++;
 			break;
 		case Otxidx:
 			l = getle(s->l, 2);
@@ -1496,8 +1495,6 @@
 		s->op = 0;
 		r->rp++;
 	}
-	if(p != 0)
-		unstarve(&c->rxmit);
 	c->reg[Statctl] = Statirqclr;
 }
 
@@ -1674,9 +1671,14 @@
 	e = v;
 	c = e->ctlr;
 
+	/* reading Isrc2 masks interrupts */
 	cause = c->reg[Isrc2];
-	if(cause != 0 && cause != ~0)
-		unstarve(&c->iproc);
+	if(cause == 0 || cause == ~0){
+		/* reenable interrupts */
+		c->reg[Icr] = 2;
+		return;
+	}
+	unstarve(&c->iproc);
 }
 
 static void
@@ -1755,7 +1757,6 @@
 			p = seprint(p, e, "%s\t%ud\n", stattab[i].name, u);
 	}
 	p = seprint(p, e, "stat %.4ux ctl %.3ux\n", gmacread(c, Stat), gmacread(c, Ctl));
-	p = seprint(p, e, "irq %.8ux\n", c->reg[Isrc2]);
 	p = seprint(p, e, "pref %.8ux %.4ux\n", prread32(c, Qr + Pctl), prread16(c, Qr + Pgetidx));
 	if(debug){
 		p = dumppci(c, p, e);
--