ref: a1afc14ea308bfc4e8f62164938cf6b8589159be
parent: 0d230bd39d7a243c7c8468d9abeddda732246cd3
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;
}
--
⑨