ref: 2c9b1c6b53c2a6573e286ce7cbd76ef316068a3a
parent: eff2a40c163933b65f016c1a154aa77dacaaef09
author: cinap_lenrek <[email protected]>
date: Mon Mar 30 19:45:09 EDT 2015
etherseeq: reset the card when it gets stuck (dma timeouts)
--- a/sys/src/9/sgi/etherseeq.c
+++ b/sys/src/9/sgi/etherseeq.c
@@ -133,14 +133,16 @@
struct Ctlr
{
int attach;
+ char* txerr;
+ ulong txwdog;
- Hio *io;
+ Hio* io;
Ring rx;
Ring tx;
};
-static ulong dummy;
+static int reset(Ether*);
static void
txintr(Ctlr *ctlr)
@@ -153,17 +155,21 @@
s = io->xstat;
if((s & Xdma) != 0)
return;
- p = IO(Desc, ctlr->tx.head->next);
- while((p->count & Busy) != 0){
+ if((s & Xmaxtry) != 0)
+ ctlr->txerr = "transmission failed";
+ if((s & Xunder) != 0)
+ ctlr->txerr = "transmitter underflowed";
+ for(p = IO(Desc, ctlr->tx.head->next); (p->count & Busy) != 0; p = IO(Desc, p->next)){
if((p->count & Done) == 0){
io->nxbdp = PADDR(p);
io->xstat = Xdma;
+ ctlr->txwdog = MACHP(0)->ticks;
break;
}
- ctlr->tx.head = p;
p->count = Eor|Eop;
- p = IO(Desc, p->next);
+ ctlr->tx.head = p;
ctlr->tx.free++;
+ ctlr->txwdog = 0;
}
wakeup(&ctlr->tx);
}
@@ -180,8 +186,10 @@
ctlr = edev->ctlr;
io = ctlr->io;
s = io->ctl;
- if(s & Cover)
+ if(s & Cover){
io->ctl = Cnormal | Cover;
+ edev->overflows++;
+ }
if(s & Cint) {
io->ctl = Cnormal | Cint;
txintr(ctlr);
@@ -193,14 +201,31 @@
notempty(void *arg)
{
Ctlr *ctlr = arg;
+
return (IO(Desc, ctlr->rx.head->next)->count & Empty) == 0;
}
+static char*
+checkerr(Ctlr *ctlr)
+{
+ ulong t;
+
+ if(ctlr->txerr != nil)
+ return ctlr->txerr;
+ t = ctlr->txwdog;
+ if(t != 0 && TK2MS(MACHP(0)->ticks - t) > 1000)
+ return "transmitter dma timeout";
+ if((ctlr->io->rstat & Rdma) == 0)
+ return "recevier dma stopped";
+ return nil;
+}
+
static void
rxproc(void *arg)
{
Ether *edev = arg;
Ctlr *ctlr;
+ char *err;
Block *b;
Desc *p;
int n;
@@ -210,17 +235,23 @@
ctlr = edev->ctlr;
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){
- b = allocb(n);
- b->wp += n;
- memmove(b->rp, p->base+2, n);
- etheriq(edev, b, 1);
+ while((p->count & Empty) != 0){
+ err = checkerr(ctlr);
+ if(err != nil){
+ print("%s: %s; reseting\n", up->text, err);
+ splhi();
+ reset(edev);
+ spllo();
}
+ tsleep(&ctlr->rx, notempty, ctlr, 500);
}
+ n = Rbsize - (p->count & 0x3fff)-3;
+ if(n >= ETHERMINTU && (p->base[n+2] & Rok) != 0){
+ b = allocb(n);
+ b->wp += n;
+ memmove(b->rp, p->base+2, n);
+ etheriq(edev, b, 1);
+ }
p->addr = PADDR(p->base);
p->count = Ioc|Empty|Rbsize;
ctlr->rx.head = p;
@@ -250,7 +281,6 @@
for(p = IO(Desc, ctlr->tx.tail->next); (b = qbread(edev->oq, 1000000)) != nil; p = IO(Desc, p->next)){
while(ctlr->tx.free == 0)
sleep(&ctlr->tx, notbusy, ctlr);
- ctlr->tx.free--;
n = BLEN(b);
if(n > ETHERMAXTU)
@@ -264,6 +294,7 @@
ctlr->tx.tail = p;
splhi();
+ ctlr->tx.free--;
txintr(ctlr);
spllo();
@@ -303,7 +334,7 @@
}
static int
-init(Ether *edev)
+reset(Ether *edev)
{
Ctlr *ctlr;
Desc *p;
@@ -310,14 +341,13 @@
Hio *io;
int i;
- io = IO(Hio, edev->port);
ctlr = edev->ctlr;
- ctlr->io = io;
+ io = ctlr->io;
- io->csx = Xreg0;
- allocring(&ctlr->rx, 256);
- allocring(&ctlr->tx, 64);
+ ctlr->txerr = nil;
+ ctlr->txwdog = 0;
+ io->csx = Xreg0;
io->rstat = 0;
io->xstat = 0;
io->ctl = Cnormal | Creset | Cint;
@@ -336,15 +366,19 @@
} while(p != ctlr->rx.head);
io->crbdp = PADDR(p);
io->nrbdp = p->next;
+ ctlr->rx.tail = p;
+ ctlr->rx.free = ctlr->rx.size;
p = ctlr->tx.tail;
do {
- p->addr = 0;
+ p->addr = PADDR(p->base);
p->count = Eor|Eop;
p = IO(Desc, p->next);
} while(p != ctlr->tx.tail);
io->cxbdp = PADDR(p);
io->nxbdp = p->next;
+ ctlr->tx.head = p;
+ ctlr->tx.free = ctlr->tx.size;
for(i=0; i<6; i++)
io->eaddr[i] = edev->ea[i];
@@ -354,9 +388,26 @@
io->rstat = Rdma;
+ wakeup(&ctlr->rx);
+ wakeup(&ctlr->tx);
+
return 0;
+
}
+static int
+init(Ether *edev)
+{
+ Ctlr *ctlr;
+
+ ctlr = edev->ctlr;
+ ctlr->io = IO(Hio, edev->port);
+ allocring(&ctlr->rx, 256);
+ allocring(&ctlr->tx, 64);
+
+ return reset(edev);
+}
+
/*
* do nothing for promiscuous() and multicast() as we
* are always in promisc mode.
@@ -379,8 +430,8 @@
if(ctlr->attach)
return;
ctlr->attach = 1;
- kproc("#0rx", rxproc, edev);
- kproc("#0tx", txproc, edev);
+ kproc("#l0rx", rxproc, edev);
+ kproc("#l0tx", txproc, edev);
}
static int