#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h"#include "devtab.h" #define DEBUG if(0)kprint typedef struct Hio Hio;typedef struct Hstate Hstate;typedef struct Rdesc Rdesc;typedef struct Xdesc Xdesc;typedef struct Ethertype Ethertype; enum{ Eor= 1<<31, /* end of ring */ Eorp= 1<<30, Rxie= 1<<29, Empty= 1<<14, /* no data here */}; struct Rdesc{ ulong addr; /* addr */ ulong count; /* eor / empty / count:13 */ Rdesc* next; uchar* base;}; enum{ Eox= 1<<31, /* end of transmission */ Eoxp= 1<<30, /* end of transmitted packet */ Busy= 1<<24, Xie= 1<<29, /* interrupt enable */}; struct Xdesc{ ulong addr; /* addr */ ulong count; /* eox / eop / busy / xie / count:13 */ Xdesc* next; uchar* base;}; /* * SEEQ 8003 interfaced to HPC3 (very different from IP20) */struct Hio{ ulong unused[20480]; ulong crbp; /* current receive buf desc ptr */ ulong nrbdp; /* next receive buf desc ptr */ ulong unused[1022]; ulong rbc; /* receive byte count */ ulong rstat; /* receiver status */ ulong rgio; /* receive gio fifo ptr */ ulong rdev; /* receive device fifo ptr */ ulong unused; ulong ctl; /* interrupt, channel reset, buf oflow */ ulong dmacfg; /* dma configuration */ ulong piocfg; /* pio configuration */ ulong unused[1016]; ulong cxbdp; /* current xmit buf desc ptr */ ulong nxbdp; /* next xmit buffer desc. pointer */ ulong unused[1022]; ulong xbc; /* xmit byte count */ ulong xstat; ulong xgio; /* xmit gio fifo ptr */ ulong xdev; /* xmit device fifo ptr */ ulong unused[1020]; ulong crbdp; /* current receive descriptor ptr */ ulong unused[2047]; ulong cpfxbdp; /* current/previous packet 1st xmit */ ulong ppfxbdp; /* desc ptr */ ulong unused[59390]; ulong eaddr[6]; /* seeq station address wo */ ulong csr; /* seeq receiver cmd/status reg */ ulong csx; /* seeq transmitter cmd/status reg */}; enum{ /* ctl */ Cover= 0x08, /* receive buffer overflow */ Cnormal=0x00, /* 1=normal, 0=loopback */ Cint= 0x02, /* interrupt (write 1 to clear) */ Creset= 0x01, /* ethernet channel reset */ /* xstat */ Xdma= 0x200, /* dma active */ Xold= 0x080, /* register has been read */ Xok= 0x008, /* transmission was successful */ Xmaxtry=0x004, /* transmission failed after 16 attempts */ Xcoll= 0x002, /* transmission collided */ Xunder= 0x001, /* transmitter underflowed */ /* csx */ Xreg0= 0x00, /* access reg bank 0 incl station addr */ XIok= 0x08, XImaxtry=0x04, XIcoll= 0x02, XIunder=0x01, /* rstat */ Rlshort=0x800, /* [small len in received frame] */ Rdma= 0x200, /* dma active */ Rold= 0x80, /* register has been read */ Rok= 0x20, /* received good frame */ Rend= 0x10, /* received end of frame */ Rshort= 0x08, /* received short frame */ Rdrbl= 0x04, /* dribble error */ Rcrc= 0x02, /* CRC error */ Rover= 0x01, /* overflow error */ /* csr */ Rsmb= 0xc0, /* receive station/broadcast/multicast frames */ Rsb= 0x80, /* receive station/broadcast frames */ Rprom= 0x40, /* receive all frames */ RIok= 0x20, /* interrupt on good frame */ RIend= 0x10, /* interrupt on end of frame */ RIshort=0x08, /* interrupt on short frame */ RIdrbl= 0x04, /* interrupt on dribble error */ RIcrc= 0x02, /* interrupt on CRC error */ RIover= 0x01, /* interrupt on overflow error */ HPC_MODNORM= 0x0, /* mode: 0=normal, 1=loopback */ HPC_FIX_INTR= 0x8000, /* start timeout counter after */ HPC_FIX_EOP= 0x4000, /* rcv_eop_intr/eop_in_chip is set */ HPC_FIX_RXDC= 0x2000, /* clear eop status upon rxdc */}; /* * one per ethernet packet type */struct Ethertype{ QLock; Netprot; /* stat info */ int type; /* ethernet type */ int prom; /* promiscuous mode */ Queue* q; int inuse; Rendez rc; /* rendzvous for close */ Ethertype* closeline; /* close list */}; enum{ Ntypes= 9 /* max number of ethernet packet types */}; struct Hstate{ QLock; int inited; uchar ea[6]; /* ethernet address */ int prom; /* # of promiscuous channels */ int all; /* # of chans listening to all packets */ int wedged; /* the device is wedged */ Network net; uchar* rbase; Rdesc* rring; Rdesc* rhead; Rendez tr; /* rendezvous for an output buffer */ QLock trlock; /* semaphore on tr */ Rendez rr; /* rendezvous for an input buffer */ QLock rlock; /* semaphore on rr */ QLock tlock; /* semaphore on Xdesc chain */ int tfree; /* count of available Xdesc's */ uchar* tbase; Xdesc* tring; Xdesc* thead; /* scavenge transmitted blocks from here */ Xdesc* ttail; /* append blocks to be transmitted here */ Ethertype*closeline; /* channels waiting to close */ Lock closepin; /* lock for closeline */ Ethertype e[Ntypes]; int debug; int kstarted; uchar bcast[6]; Queue self; /* packets turned around at the interface */ /* sadistics */ int inpackets; int inchars; int outpackets; int outchars; int over; /* input overflow */ int shrt; /* short packet (status) */ int lshrt; /* short packet (len) */ int drbl; /* dribble error */ int crc; /* crc error */ int maxtry; /* transmission failure (16 tries) */ int under; /* transmitter underflow */}; #define NXRING 64#define NRRING 128#define RBSIZE (sizeof(Etherpkt)+3) #define DEV IO(Hio, HPC3_ETHER) static void etherstart(int);static void etherhardreset(void); static Hstate ether; /* * predeclared */static int seqclonecon(Chan*);static void seqkproc(void *);static void seqstart(int);static void seqstatsfill(Chan*, char*, int);static void seqtypefill(Chan*, char*, int);static void sequp(void*, int);static void xintr(int); void seqintr(Ureg*, void*); /* * seq stream module definition */static void seqoput(Queue*, Block*);static void seqstopen(Queue*, Stream*);static void seqstclose(Queue*);Qinfo seqinfo = { nullput, seqoput, seqstopen, seqstclose, "seq" }; ulongrdreg(ulong *p){ ulong s, v; s = splhi(); v = DEV->piocfg; USED(v); v = *p; splx(s); return v;} /* * open a seq line discipline */static voidseqstopen(Queue *q, Stream *s){ Ethertype *e; e = ðer.e[s->id]; RD(q)->ptr = WR(q)->ptr = e; e->type = 0; e->q = RD(q); e->inuse = 1;} /* * close seq line discipline * * the lock is to synchronize changing the ethertype with * sending packets up the stream on interrupts. */static intisclosed(void *x){ return ((Ethertype *)x)->q == 0;} static voidseqstclose(Queue *q){ Ethertype *e; e = q->ptr; if(e->prom){ qlock(ðer); ether.prom--; if(ether.prom == 0) seqstart(0); qunlock(ðer); } if(e->type == -1){ qlock(ðer); ether.all--; qunlock(ðer); } /* * mark as closing and wait for kproc to close us */ lock(ðer.closepin); e->closeline = ether.closeline; ether.closeline = e; unlock(ðer.closepin); wakeup(ðer.rr); sleep(&e->rc, isclosed, e); e->type = 0; e->q = 0; e->prom = 0; e->inuse = 0; netdisown(e);} static intisobuf(void *arg){ return ether.tfree > (long)arg;} static voidseqoput(Queue *q, Block *bp){ Hio *dev; Xdesc *xp; uchar *dp; Block *nbp; Etherpkt *p; Ethertype *e; int len, k, n, s; dev = DEV; if(bp->type == M_CTL){ e = q->ptr; qlock(ðer); if(streamparse("connect", bp)){ if(e->type == -1) ether.all--; e->type = strtol((char *)bp->rptr, 0, 0); if(e->type == -1) ether.all++; } else if(streamparse("promiscuous", bp)){ e->prom = 1; if(++ether.prom == 1) seqstart(1); } qunlock(ðer); freeb(bp); return; } /* * give packet a local address, return upstream if destined for * this machine. */ if(BLEN(bp) < ETHERHDRSIZE){ bp = pullup(bp, ETHERHDRSIZE); if(bp == 0) return; } p = (Etherpkt *)bp->rptr; memmove(p->s, ether.ea, sizeof(ether.ea)); len = blen(bp); if(len < ETHERMINTU){ bp = expandb(bp, ETHERMINTU); len = ETHERMINTU; }else if(len > ETHERMAXTU){ print("seqoput len=%d\n", len); freeb(bp); } if(*p->d == 0xff || ether.prom || ether.all){ nbp = copyb(bp, len); if(nbp->next) nbp = expandb(nbp, len); if(nbp){ nbp->wptr = nbp->rptr+len; putq(ðer.self, nbp); wakeup(ðer.rr); } } else if(*p->d == *ether.ea && memcmp(ether.ea, p->d, sizeof(ether.ea)) == 0){ if(bp->next) bp = expandb(bp, len); if(bp){ putq(ðer.self, bp); wakeup(ðer.rr); } return; } if(ether.wedged){ freeb(bp); return; } /* * only one transmitter at a time */ qlock(ðer.trlock); qlock(ðer.tlock); while(!isobuf(ðer)){ qunlock(ðer.tlock); sleep(ðer.tr, isobuf, 0); qlock(ðer.tlock); } if(ether.wedged){ qunlock(ðer.tlock); qlock(ðer.trlock); freeb(bp); return; } ++ether.outpackets; --ether.tfree; ether.outchars += len; xp = IO(Xdesc, ether.ttail->next); dp = xp->base; for(nbp=bp; nbp; nbp=nbp->next){ n = BLEN(nbp); if(n == 0) continue; memmove(dp, nbp->rptr, n); dp += n; } n = dp - xp->base; xp->addr = PADDR(xp->base); /* end of transmission */ xp->count = Eox|Eoxp|Busy|Xie|n; /* end of packet */ s = splhi(); ether.tfree--; k = rdreg(&dev->xstat); if(k & Xdma){ DEBUG("\tappend\n"); ether.ttail->count &= ~(Eox|Xie); } else xintr(k); splx(s); ether.ttail = xp; qunlock(ðer.tlock); qunlock(ðer.trlock); freeb(bp);} staticvoidinitmem(void){ int i; Hio *dev; Xdesc *xp; Rdesc *rp; dev = DEV; dev->csx = Xreg0; /* allocate receiver ring */ rp = xspanalloc(NRRING*sizeof(Rdesc), BY2PG, 0); dcflush(rp, NRRING*sizeof(Rdesc)); rp = IO(Rdesc, rp); memset(rp, 0, NRRING*sizeof(Rdesc)); ether.rring = rp; ether.rhead = rp; ether.rbase = xspanalloc(NRRING*BY2PG/2, BY2PG, 0); dcflush(ether.rbase, NRRING*BY2PG/2); ether.rbase = IO(uchar, ether.rbase); memset(ether.rbase, 0, NRRING*BY2PG/2); for(i=0; i<NRRING; i++, rp++){ rp->base = ether.rbase + i*(BY2PG/2); rp->next = (Rdesc*)PADDR(rp+1); } --rp; rp->next = (Rdesc*)PADDR(ether.rring); /* allocate transmitter ring */ xp = xspanalloc(NXRING*sizeof(Xdesc), BY2PG, 0); dcflush(xp, NXRING*sizeof(Xdesc)); xp = IO(Xdesc, xp); memset(xp, 0, NXRING*sizeof(Xdesc)); ether.tring = xp; ether.ttail = xp; ether.tbase = xspanalloc(NXRING*BY2PG/2, BY2PG, 0); dcflush(ether.tbase, NXRING*BY2PG/2); ether.tbase = IO(uchar, ether.tbase); for(i=0; i<NXRING; i++, xp++){ xp->base = ether.tbase + i*(BY2PG/2); xp->next = (Rdesc*)PADDR(xp+1); } --xp; xp->next = (Rdesc*)PADDR(ether.tring);} voidseqreset(void){ Hio *dev = DEV; int i; Xdesc *xp; Rdesc *rp; Lines 1–500 of 947. Load more
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #include "devtab.h" #define DEBUG if(0)kprint typedef struct Hio Hio; typedef struct Hstate Hstate; typedef struct Rdesc Rdesc; typedef struct Xdesc Xdesc; typedef struct Ethertype Ethertype; enum { Eor= 1<<31, /* end of ring */ Eorp= 1<<30, Rxie= 1<<29, Empty= 1<<14, /* no data here */ }; struct Rdesc { ulong addr; /* addr */ ulong count; /* eor / empty / count:13 */ Rdesc* next; uchar* base; }; enum { Eox= 1<<31, /* end of transmission */ Eoxp= 1<<30, /* end of transmitted packet */ Busy= 1<<24, Xie= 1<<29, /* interrupt enable */ }; struct Xdesc { ulong addr; /* addr */ ulong count; /* eox / eop / busy / xie / count:13 */ Xdesc* next; uchar* base; }; /* * SEEQ 8003 interfaced to HPC3 (very different from IP20) */ struct Hio { ulong unused[20480]; ulong crbp; /* current receive buf desc ptr */ ulong nrbdp; /* next receive buf desc ptr */ ulong unused[1022]; ulong rbc; /* receive byte count */ ulong rstat; /* receiver status */ ulong rgio; /* receive gio fifo ptr */ ulong rdev; /* receive device fifo ptr */ ulong unused; ulong ctl; /* interrupt, channel reset, buf oflow */ ulong dmacfg; /* dma configuration */ ulong piocfg; /* pio configuration */ ulong unused[1016]; ulong cxbdp; /* current xmit buf desc ptr */ ulong nxbdp; /* next xmit buffer desc. pointer */ ulong unused[1022]; ulong xbc; /* xmit byte count */ ulong xstat; ulong xgio; /* xmit gio fifo ptr */ ulong xdev; /* xmit device fifo ptr */ ulong unused[1020]; ulong crbdp; /* current receive descriptor ptr */ ulong unused[2047]; ulong cpfxbdp; /* current/previous packet 1st xmit */ ulong ppfxbdp; /* desc ptr */ ulong unused[59390]; ulong eaddr[6]; /* seeq station address wo */ ulong csr; /* seeq receiver cmd/status reg */ ulong csx; /* seeq transmitter cmd/status reg */ }; enum { /* ctl */ Cover= 0x08, /* receive buffer overflow */ Cnormal=0x00, /* 1=normal, 0=loopback */ Cint= 0x02, /* interrupt (write 1 to clear) */ Creset= 0x01, /* ethernet channel reset */ /* xstat */ Xdma= 0x200, /* dma active */ Xold= 0x080, /* register has been read */ Xok= 0x008, /* transmission was successful */ Xmaxtry=0x004, /* transmission failed after 16 attempts */ Xcoll= 0x002, /* transmission collided */ Xunder= 0x001, /* transmitter underflowed */ /* csx */ Xreg0= 0x00, /* access reg bank 0 incl station addr */ XIok= 0x08, XImaxtry=0x04, XIcoll= 0x02, XIunder=0x01, /* rstat */ Rlshort=0x800, /* [small len in received frame] */ Rdma= 0x200, /* dma active */ Rold= 0x80, /* register has been read */ Rok= 0x20, /* received good frame */ Rend= 0x10, /* received end of frame */ Rshort= 0x08, /* received short frame */ Rdrbl= 0x04, /* dribble error */ Rcrc= 0x02, /* CRC error */ Rover= 0x01, /* overflow error */ /* csr */ Rsmb= 0xc0, /* receive station/broadcast/multicast frames */ Rsb= 0x80, /* receive station/broadcast frames */ Rprom= 0x40, /* receive all frames */ RIok= 0x20, /* interrupt on good frame */ RIend= 0x10, /* interrupt on end of frame */ RIshort=0x08, /* interrupt on short frame */ RIdrbl= 0x04, /* interrupt on dribble error */ RIcrc= 0x02, /* interrupt on CRC error */ RIover= 0x01, /* interrupt on overflow error */ HPC_MODNORM= 0x0, /* mode: 0=normal, 1=loopback */ HPC_FIX_INTR= 0x8000, /* start timeout counter after */ HPC_FIX_EOP= 0x4000, /* rcv_eop_intr/eop_in_chip is set */ HPC_FIX_RXDC= 0x2000, /* clear eop status upon rxdc */ }; /* * one per ethernet packet type */ struct Ethertype { QLock; Netprot; /* stat info */ int type; /* ethernet type */ int prom; /* promiscuous mode */ Queue* q; int inuse; Rendez rc; /* rendzvous for close */ Ethertype* closeline; /* close list */ }; enum { Ntypes= 9 /* max number of ethernet packet types */ }; struct Hstate { QLock; int inited; uchar ea[6]; /* ethernet address */ int prom; /* # of promiscuous channels */ int all; /* # of chans listening to all packets */ int wedged; /* the device is wedged */ Network net; uchar* rbase; Rdesc* rring; Rdesc* rhead; Rendez tr; /* rendezvous for an output buffer */ QLock trlock; /* semaphore on tr */ Rendez rr; /* rendezvous for an input buffer */ QLock rlock; /* semaphore on rr */ QLock tlock; /* semaphore on Xdesc chain */ int tfree; /* count of available Xdesc's */ uchar* tbase; Xdesc* tring; Xdesc* thead; /* scavenge transmitted blocks from here */ Xdesc* ttail; /* append blocks to be transmitted here */ Ethertype*closeline; /* channels waiting to close */ Lock closepin; /* lock for closeline */ Ethertype e[Ntypes]; int debug; int kstarted; uchar bcast[6]; Queue self; /* packets turned around at the interface */ /* sadistics */ int inpackets; int inchars; int outpackets; int outchars; int over; /* input overflow */ int shrt; /* short packet (status) */ int lshrt; /* short packet (len) */ int drbl; /* dribble error */ int crc; /* crc error */ int maxtry; /* transmission failure (16 tries) */ int under; /* transmitter underflow */ }; #define NXRING 64 #define NRRING 128 #define RBSIZE (sizeof(Etherpkt)+3) #define DEV IO(Hio, HPC3_ETHER) static void etherstart(int); static void etherhardreset(void); static Hstate ether; /* * predeclared */ static int seqclonecon(Chan*); static void seqkproc(void *); static void seqstart(int); static void seqstatsfill(Chan*, char*, int); static void seqtypefill(Chan*, char*, int); static void sequp(void*, int); static void xintr(int); void seqintr(Ureg*, void*); /* * seq stream module definition */ static void seqoput(Queue*, Block*); static void seqstopen(Queue*, Stream*); static void seqstclose(Queue*); Qinfo seqinfo = { nullput, seqoput, seqstopen, seqstclose, "seq" }; ulong rdreg(ulong *p) { ulong s, v; s = splhi(); v = DEV->piocfg; USED(v); v = *p; splx(s); return v; } /* * open a seq line discipline */ static void seqstopen(Queue *q, Stream *s) { Ethertype *e; e = ðer.e[s->id]; RD(q)->ptr = WR(q)->ptr = e; e->type = 0; e->q = RD(q); e->inuse = 1; } /* * close seq line discipline * * the lock is to synchronize changing the ethertype with * sending packets up the stream on interrupts. */ static int isclosed(void *x) { return ((Ethertype *)x)->q == 0; } static void seqstclose(Queue *q) { Ethertype *e; e = q->ptr; if(e->prom){ qlock(ðer); ether.prom--; if(ether.prom == 0) seqstart(0); qunlock(ðer); } if(e->type == -1){ qlock(ðer); ether.all--; qunlock(ðer); } /* * mark as closing and wait for kproc to close us */ lock(ðer.closepin); e->closeline = ether.closeline; ether.closeline = e; unlock(ðer.closepin); wakeup(ðer.rr); sleep(&e->rc, isclosed, e); e->type = 0; e->q = 0; e->prom = 0; e->inuse = 0; netdisown(e); } static int isobuf(void *arg) { return ether.tfree > (long)arg; } static void seqoput(Queue *q, Block *bp) { Hio *dev; Xdesc *xp; uchar *dp; Block *nbp; Etherpkt *p; Ethertype *e; int len, k, n, s; dev = DEV; if(bp->type == M_CTL){ e = q->ptr; qlock(ðer); if(streamparse("connect", bp)){ if(e->type == -1) ether.all--; e->type = strtol((char *)bp->rptr, 0, 0); if(e->type == -1) ether.all++; } else if(streamparse("promiscuous", bp)){ e->prom = 1; if(++ether.prom == 1) seqstart(1); } qunlock(ðer); freeb(bp); return; } /* * give packet a local address, return upstream if destined for * this machine. */ if(BLEN(bp) < ETHERHDRSIZE){ bp = pullup(bp, ETHERHDRSIZE); if(bp == 0) return; } p = (Etherpkt *)bp->rptr; memmove(p->s, ether.ea, sizeof(ether.ea)); len = blen(bp); if(len < ETHERMINTU){ bp = expandb(bp, ETHERMINTU); len = ETHERMINTU; }else if(len > ETHERMAXTU){ print("seqoput len=%d\n", len); freeb(bp); } if(*p->d == 0xff || ether.prom || ether.all){ nbp = copyb(bp, len); if(nbp->next) nbp = expandb(nbp, len); if(nbp){ nbp->wptr = nbp->rptr+len; putq(ðer.self, nbp); wakeup(ðer.rr); } } else if(*p->d == *ether.ea && memcmp(ether.ea, p->d, sizeof(ether.ea)) == 0){ if(bp->next) bp = expandb(bp, len); if(bp){ putq(ðer.self, bp); wakeup(ðer.rr); } return; } if(ether.wedged){ freeb(bp); return; } /* * only one transmitter at a time */ qlock(ðer.trlock); qlock(ðer.tlock); while(!isobuf(ðer)){ qunlock(ðer.tlock); sleep(ðer.tr, isobuf, 0); qlock(ðer.tlock); } if(ether.wedged){ qunlock(ðer.tlock); qlock(ðer.trlock); freeb(bp); return; } ++ether.outpackets; --ether.tfree; ether.outchars += len; xp = IO(Xdesc, ether.ttail->next); dp = xp->base; for(nbp=bp; nbp; nbp=nbp->next){ n = BLEN(nbp); if(n == 0) continue; memmove(dp, nbp->rptr, n); dp += n; } n = dp - xp->base; xp->addr = PADDR(xp->base); /* end of transmission */ xp->count = Eox|Eoxp|Busy|Xie|n; /* end of packet */ s = splhi(); ether.tfree--; k = rdreg(&dev->xstat); if(k & Xdma){ DEBUG("\tappend\n"); ether.ttail->count &= ~(Eox|Xie); } else xintr(k); splx(s); ether.ttail = xp; qunlock(ðer.tlock); qunlock(ðer.trlock); freeb(bp); } static void initmem(void) { int i; Hio *dev; Xdesc *xp; Rdesc *rp; dev = DEV; dev->csx = Xreg0; /* allocate receiver ring */ rp = xspanalloc(NRRING*sizeof(Rdesc), BY2PG, 0); dcflush(rp, NRRING*sizeof(Rdesc)); rp = IO(Rdesc, rp); memset(rp, 0, NRRING*sizeof(Rdesc)); ether.rring = rp; ether.rhead = rp; ether.rbase = xspanalloc(NRRING*BY2PG/2, BY2PG, 0); dcflush(ether.rbase, NRRING*BY2PG/2); ether.rbase = IO(uchar, ether.rbase); memset(ether.rbase, 0, NRRING*BY2PG/2); for(i=0; i<NRRING; i++, rp++){ rp->base = ether.rbase + i*(BY2PG/2); rp->next = (Rdesc*)PADDR(rp+1); } --rp; rp->next = (Rdesc*)PADDR(ether.rring); /* allocate transmitter ring */ xp = xspanalloc(NXRING*sizeof(Xdesc), BY2PG, 0); dcflush(xp, NXRING*sizeof(Xdesc)); xp = IO(Xdesc, xp); memset(xp, 0, NXRING*sizeof(Xdesc)); ether.tring = xp; ether.ttail = xp; ether.tbase = xspanalloc(NXRING*BY2PG/2, BY2PG, 0); dcflush(ether.tbase, NXRING*BY2PG/2); ether.tbase = IO(uchar, ether.tbase); for(i=0; i<NXRING; i++, xp++){ xp->base = ether.tbase + i*(BY2PG/2); xp->next = (Rdesc*)PADDR(xp+1); } --xp; xp->next = (Rdesc*)PADDR(ether.tring); } void seqreset(void) { Hio *dev = DEV; int i; Xdesc *xp; Rdesc *rp;