diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-03-28 14:11:17 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-03-28 14:11:17 +0100 |
commit | feb92fedb1eb041465a4185a114b3441e70cc132 (patch) | |
tree | 11dea0d89f78822b06fd583939ea4db696d5a597 | |
parent | 177cbace733eeceaef54e2c1a4032c55d4e100dd (diff) | |
download | plan9front-feb92fedb1eb041465a4185a114b3441e70cc132.tar.xz |
sgi: new approach for etherseeq
touching transmit descriptors while dma is running causes the
front to fall off. new approach keeps a counter of free
descriptors in the Ring structure that is incremented
by txintr() when transmit completed.
txintr() will clean descriptors once dma has stopped and
restart dma when there are more descrtors in the chain.
-rw-r--r-- | sys/src/9/sgi/etherseeq.c | 102 |
1 files changed, 55 insertions, 47 deletions
diff --git a/sys/src/9/sgi/etherseeq.c b/sys/src/9/sgi/etherseeq.c index 4f9d930ac..ce2036225 100644 --- a/sys/src/9/sgi/etherseeq.c +++ b/sys/src/9/sgi/etherseeq.c @@ -110,6 +110,7 @@ struct Ring { Rendez; int size; + int free; uchar* base; Desc* head; Desc* tail; @@ -119,9 +120,10 @@ enum { Eor= 1<<31, /* end of ring */ Eop= 1<<30, - Ie= 1<<29, + Ioc= 1<<29, /* interrupt on completion */ Busy= 1<<24, Empty= 1<<14, /* no data here */ + Done= 1<<15, /* transmit done */ }; enum { @@ -141,6 +143,32 @@ struct Ctlr static ulong dummy; static void +txintr(Ctlr *ctlr) +{ + Hio *io; + ulong s; + Desc *p; + + io = ctlr->io; + s = io->xstat; + if((s & Xdma) != 0) + return; + p = IO(Desc, ctlr->tx.head->next); + while((p->count & Busy) != 0){ + if((p->count & Done) == 0){ + io->nxbdp = PADDR(p); + io->xstat = Xdma; + break; + } + ctlr->tx.head = p; + p->count = Eor|Eop; + p = IO(Desc, p->next); + ctlr->tx.free++; + } + wakeup(&ctlr->tx); +} + +static void interrupt(Ureg *, void *arg) { Ether *edev; @@ -156,6 +184,7 @@ interrupt(Ureg *, void *arg) io->ctl = Cnormal | Cover; if(s & Cint) { io->ctl = Cnormal | Cint; + txintr(ctlr); wakeup(&ctlr->rx); } } @@ -164,12 +193,6 @@ static int notempty(void *arg) { Ctlr *ctlr = arg; - Hio *io; - - io = ctlr->io; - dummy = io->piocfg; - if((io->rstat & Rdma) == 0) - return 1; return (IO(Desc, ctlr->rx.head->next)->count & Empty) == 0; } @@ -178,7 +201,6 @@ rxproc(void *arg) { Ether *edev = arg; Ctlr *ctlr; - Hio *io; Block *b; Desc *p; int n; @@ -187,12 +209,9 @@ rxproc(void *arg) ; ctlr = edev->ctlr; - io = ctlr->io; for(p = IO(Desc, ctlr->rx.head->next);; p = IO(Desc, p->next)){ - while((p->count & Empty) != 0){ - io->rstat = Rdma; - tsleep(&ctlr->rx, notempty, ctlr, 500); - } + 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){ @@ -203,50 +222,35 @@ rxproc(void *arg) } } p->addr = PADDR(p->base); - p->count = Ie|Empty|Rbsize; + p->count = Ioc|Empty|Rbsize; ctlr->rx.head = p; } } +static int +notbusy(void *arg) +{ + Ctlr *ctlr = arg; + return ctlr->tx.free > 0; +} + static void txproc(void *arg) { Ether *edev = arg; Ctlr *ctlr; - Hio *io; Block *b; Desc *p; - int clean, n; + int n; while(waserror()) ; ctlr = edev->ctlr; - io = ctlr->io; - clean = ctlr->tx.size / 2; for(p = IO(Desc, ctlr->tx.tail->next); (b = qbread(edev->oq, 1000000)) != nil; p = IO(Desc, p->next)){ - while(!clean){ - splhi(); - p = ctlr->tx.head; - dummy = io->piocfg; - ctlr->tx.head = IO(Desc, io->nxbdp & ~0xf); - spllo(); - while(p != ctlr->tx.head){ - if((p->count & Busy) == 0) - break; - clean++; - p->count = Eor|Eop; - p = IO(Desc, p->next); - } - - p = IO(Desc, ctlr->tx.tail->next); - if(clean) - break; - - io->xstat = Xdma; - tsleep(&ctlr->tx, return0, nil, 10); - } - clean--; + while(ctlr->tx.free == 0) + sleep(&ctlr->tx, notbusy, ctlr); + ctlr->tx.free--; n = BLEN(b); if(n > ETHERMAXTU) @@ -254,12 +258,14 @@ txproc(void *arg) memmove(p->base, b->rp, n); p->addr = PADDR(p->base); - p->count = Eor|Eop|Busy|n; + p->count = Ioc|Eor|Eop|Busy|n; - ctlr->tx.tail->count &= ~Eor; + ctlr->tx.tail->count &= ~(Ioc|Eor); ctlr->tx.tail = p; - io->xstat = Xdma; + splhi(); + txintr(ctlr); + spllo(); freeb(b); } @@ -273,7 +279,8 @@ allocring(Ring *r, int n) int m; r->size = n; - + r->free = n; + m = n*BY2PG/2; b = xspanalloc(m, BY2PG, 0); dcflush(b, m); @@ -324,7 +331,7 @@ init(Ether *edev) p = ctlr->rx.head; do { p->addr = PADDR(p->base); - p->count = Ie|Empty|Rbsize; + p->count = Ioc|Empty|Rbsize; p = IO(Desc, p->next); } while(p != ctlr->rx.head); io->crbdp = PADDR(p); @@ -336,16 +343,17 @@ init(Ether *edev) p->count = Eor|Eop; p = IO(Desc, p->next); } while(p != ctlr->tx.tail); - ctlr->tx.head = IO(Desc, p->next); io->cxbdp = PADDR(p); io->nxbdp = p->next; for(i=0; i<6; i++) io->eaddr[i] = edev->ea[i]; - io->csx = 0; /* XIok | XImaxtry | XIcoll | XIunder; -- no interrupts needed */ + io->csx = XIok | XImaxtry | XIcoll | XIunder; io->csr = Rprom | RIok|RIend|RIshort|RIdrbl|RIcrc; + io->rstat = Rdma; + return 0; } |