ref: feb92fedb1eb041465a4185a114b3441e70cc132
parent: 177cbace733eeceaef54e2c1a4032c55d4e100dd
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Mar 28 10:11:17 EDT 2015
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.
--- a/sys/src/9/sgi/etherseeq.c
+++ b/sys/src/9/sgi/etherseeq.c
@@ -110,6 +110,7 @@
{
Rendez;
int size;
+ int free;
uchar* base;
Desc* head;
Desc* tail;
@@ -119,9 +120,10 @@
{
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 @@
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 @@
io->ctl = Cnormal | Cover;
if(s & Cint) {
io->ctl = Cnormal | Cint;
+ txintr(ctlr);
wakeup(&ctlr->rx);
}
}
@@ -164,12 +193,6 @@
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 @@
{
Ether *edev = arg;
Ctlr *ctlr;
- Hio *io;
Block *b;
Desc *p;
int n;
@@ -187,12 +209,9 @@
;
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);
- }
+ 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){
@@ -203,51 +222,36 @@
}
}
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);
- }
+ while(ctlr->tx.free == 0)
+ sleep(&ctlr->tx, notbusy, ctlr);
+ ctlr->tx.free--;
- p = IO(Desc, ctlr->tx.tail->next);
- if(clean)
- break;
-
- io->xstat = Xdma;
- tsleep(&ctlr->tx, return0, nil, 10);
- }
- clean--;
-
n = BLEN(b);
if(n > ETHERMAXTU)
n = ETHERMAXTU;
@@ -254,12 +258,14 @@
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 @@
int m;
r->size = n;
-
+ r->free = n;
+
m = n*BY2PG/2;
b = xspanalloc(m, BY2PG, 0);
dcflush(b, m);
@@ -324,7 +331,7 @@
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,7 +343,6 @@
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;
@@ -343,8 +349,10 @@
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;
}