From a5525457bdde5ac519859b0a8f72eba6144a0230 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sun, 12 Jan 2014 12:08:10 +0100 Subject: 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. --- sys/src/9/pc/etheryuk.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/sys/src/9/pc/etheryuk.c b/sys/src/9/pc/etheryuk.c index 9e8ad140f..d049a3595 100644 --- a/sys/src/9/pc/etheryuk.c +++ b/sys/src/9/pc/etheryuk.c @@ -49,6 +49,7 @@ enum { 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 @@ getnslot(Sring *r, uint *wp, Status **t, uint n) { 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 @@ tproc(void *v) 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 @@ rxscrew(Ether *e, Sring *r, Status *t, uint wp) 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 @@ replenish(Ether *e, Ctlr *c) freeb(b); break; } - assert(c->rbring[t - r->r] == nil); c->rbring[t - r->r] = b; if(is64()){ @@ -1260,9 +1259,9 @@ replenish(Ether *e, Ctlr *c) 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 @@ link(Ether *e) 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 @@ txcleanup(Ctlr *c, uint end) if(b != nil) freeb(b); } - if(r->wp - r->rp > 16) - unstarve(&c->txmit); + unstarve(&c->txmit); } static void @@ -1412,14 +1410,17 @@ rx(Ether *e, uint l, uint x, uint flag) 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; 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 @@ rx(Ether *e, uint l, uint x, uint flag) b->flag |= flag; etheriq(e, b, 1); } - r->rp = rp; + unstarve(&c->rxmit); } static uint @@ -1446,7 +1447,7 @@ cksum(Ctlr *c, uint ck, uint css) 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 @@ sring(Ether *e) 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 @@ sring(Ether *e) 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 @@ sring(Ether *e) s->op = 0; r->rp++; } - if(p != 0) - unstarve(&c->rxmit); c->reg[Statctl] = Statirqclr; } @@ -1674,9 +1671,14 @@ interrupt(Ureg*, void *v) 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 @@ ifstat(Ether *e0, void *a, long n, ulong offset) 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); -- cgit v1.2.3