git: 9front

Download patch

ref: d80cdf26e535edc0ceaa6ee8b0d5df8e1f98b5a7
parent: 5d58d1f595274389d81ab4ef7f1e5840d372db19
author: cinap_lenrek <cinap_lenrek@centraldogma>
date: Tue Aug 30 13:19:22 EDT 2011

ether8169: reset on fifo overflow error

--- a/sys/src/9/pc/ether8169.c
+++ b/sys/src/9/pc/ether8169.c
@@ -260,6 +260,7 @@
 	QLock	alock;			/* attach */
 	Lock	ilock;			/* init */
 	int	init;			/*  */
+	Rendez	reset;
 
 	int	pciv;			/*  */
 	int	macv;			/* MAC version */
@@ -306,7 +307,6 @@
 	uint	rer;
 	uint	rdu;
 	uint	punlc;
-	uint	fovw;
 	uint	mcast;
 	uint	frag;			/* partial packets; rb was too small */
 } Ctlr;
@@ -556,7 +556,6 @@
 	l += snprint(p+l, READSTR-l, "rer: %ud\n", ctlr->rer);
 	l += snprint(p+l, READSTR-l, "rdu: %ud\n", ctlr->rdu);
 	l += snprint(p+l, READSTR-l, "punlc: %ud\n", ctlr->punlc);
-	l += snprint(p+l, READSTR-l, "fovw: %ud\n", ctlr->fovw);
 
 	l += snprint(p+l, READSTR-l, "tcr: %#8.8ux\n", ctlr->tcr);
 	l += snprint(p+l, READSTR-l, "rcr: %#8.8ux\n", ctlr->rcr);
@@ -810,12 +809,33 @@
 
 	iunlock(&ctlr->ilock);
 
-//	rtl8169mii(ctlr);
-
 	return 0;
 }
 
 static void
+rtl8169reseter(void *arg)
+{
+	Ether *edev;
+	Ctlr *ctlr;
+
+	edev = arg;
+	ctlr = edev->ctlr;
+
+	for(;;){
+		print("rtl8169: reset\n");
+		rtl8169init(edev);
+		qunlock(&ctlr->alock);
+
+		while(waserror())
+			;
+		sleep(&ctlr->reset, return0, nil);
+		poperror();
+
+		qlock(&ctlr->alock);
+	}
+}
+
+static void
 rtl8169attach(Ether* edev)
 {
 	int timeo;
@@ -834,8 +854,10 @@
 		ctlr->rb = malloc(Nrd*sizeof(Block*));
 		ctlr->nrd = Nrd;
 		ctlr->dtcc = mallocalign(sizeof(Dtcc), 64, 0, 0);
-		rtl8169init(edev);
 		ctlr->init = 1;
+
+		kproc("rtl8169", rtl8169reseter, edev);
+		qlock(&ctlr->alock);	/* reset proc unlocks when finished */
 	}
 	qunlock(&ctlr->alock);
 
@@ -1010,6 +1032,25 @@
 }
 
 static void
+rtl8169restart(Ctlr *ctlr)
+{
+	ilock(&ctlr->ilock);
+
+	/* disable interrupts */
+	ctlr->imr = 0;
+	csr16w(ctlr, Imr, ctlr->imr);
+	csr16w(ctlr, Isr, 0xFFFF);
+
+	/* software reset */
+	csr8w(ctlr, Cr, Rst);
+	csr8r(ctlr, Cr);
+
+	wakeup(&ctlr->reset);
+
+	iunlock(&ctlr->ilock);
+}
+
+static void
 rtl8169interrupt(Ureg*, void* arg)
 {
 	Ctlr *ctlr;
@@ -1024,7 +1065,12 @@
 		if((isr & ctlr->imr) == 0)
 			break;
 
-		if(isr & (Fovw|Punlc|Rdu|Rer|Rok)){
+		if(isr & Fovw){
+			rtl8169restart(ctlr);
+			break;
+		}
+
+		if(isr & (Punlc|Rdu|Rer|Rok)){
 			rtl8169receive(edev);
 			if(!(isr & (Punlc|Rok)))
 				ctlr->ierrs++;
@@ -1034,9 +1080,7 @@
 				ctlr->rdu++;
 			if(isr & Punlc)
 				ctlr->punlc++;
-			if(isr & Fovw)
-				ctlr->fovw++;
-			isr &= ~(Fovw|Rdu|Rer|Rok);
+			isr &= ~(Rdu|Rer|Rok);
 		}
 
 		if(isr & (Tdu|Ter|Tok)){
--