summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@centraldogma>2011-08-30 17:19:22 +0200
committercinap_lenrek <cinap_lenrek@centraldogma>2011-08-30 17:19:22 +0200
commite113f037a3f79396dfd4bc17e69061d84ee3b8e9 (patch)
tree11cf03f053f73e7c6066dbf011522e787e70b573
parentb2f5e18032d1373ffaf0b3ac9d4c683f58b6a93b (diff)
downloadplan9front-e113f037a3f79396dfd4bc17e69061d84ee3b8e9.tar.xz
ether8169: reset on fifo overflow error
-rw-r--r--sys/src/9/pc/ether8169.c62
1 files changed, 53 insertions, 9 deletions
diff --git a/sys/src/9/pc/ether8169.c b/sys/src/9/pc/ether8169.c
index 8309b786d..b0a2847b0 100644
--- a/sys/src/9/pc/ether8169.c
+++ b/sys/src/9/pc/ether8169.c
@@ -260,6 +260,7 @@ typedef struct Ctlr {
QLock alock; /* attach */
Lock ilock; /* init */
int init; /* */
+ Rendez reset;
int pciv; /* */
int macv; /* MAC version */
@@ -306,7 +307,6 @@ typedef struct Ctlr {
uint rer;
uint rdu;
uint punlc;
- uint fovw;
uint mcast;
uint frag; /* partial packets; rb was too small */
} Ctlr;
@@ -556,7 +556,6 @@ rtl8169ifstat(Ether* edev, void* a, long n, ulong offset)
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 @@ rtl8169init(Ether* edev)
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 @@ rtl8169attach(Ether* edev)
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 @@ rtl8169receive(Ether* edev)
}
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 @@ rtl8169interrupt(Ureg*, void* arg)
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 @@ rtl8169interrupt(Ureg*, void* arg)
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)){