| plan 9 kernel history: overview | file list | diff list |
1991/1115/port/devlance.c (diff list | history)
| port/devlance.c on 1990/0227 | ||
| 1990/0227 | #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "errno.h" #include "devtab.h" | |
| 1990/1231 | ||
| 1990/0227 | enum { | |
| 1991/0621 | Ntypes= 9, /* max number of ethernet packet types */ | |
| 1990/1231 | Maxrb= 128, /* max buffers in a ring */ | |
| 1990/0227 | }; | |
| 1990/1231 | #define RSUCC(x) (((x)+1)%l.nrrb) #define TSUCC(x) (((x)+1)%l.ntrb) | |
| 1990/0227 | ||
| 1990/0707 | #define NOW (MACHP(0)->ticks*MS2HZ) | |
| 1990/03042 | ||
| 1991/1113 | static int netlight; | |
| 1990/0227 | /* * Communication with the lance is via a transmit and receive ring of * message descriptors. The Initblock contains pointers to and sizes of * these rings. The rings must be in RAM addressible by the lance */ typedef struct { ushort laddr; /* low order piece of address */ ushort flags; /* flags and high order piece of address */ short size; /* size of buffer */ ushort cntflags; /* (rcv)count of bytes in buffer; (xmt) more flags */ } Msg; /* * lance memory map */ | |
| 1990/1231 | struct Lancemem | |
| 1990/0227 | { /* * initialization block */ | |
| 1990/0911 | ushort mode; /* chip control (see below) */ ushort etheraddr[3]; /* the ethernet physical address */ ushort multi[4]; /* multicast addresses, 1 bit for each of 64 */ ushort rdralow; /* receive buffer ring */ ushort rdrahigh; /* (top three bits define size of ring) */ ushort tdralow; /* transmit buffer ring */ ushort tdrahigh; /* (top three bits define size of ring) */ | |
| 1990/0227 | /* | |
| 1990/0911 | * ring buffers * first receive, then transmit | |
| 1990/0227 | */ | |
| 1990/1231 | Msg rmr[Maxrb]; /* recieve message ring */ Msg tmr[Maxrb]; /* transmit message ring */ }; | |
| 1990/0227 | /* * Some macros for dealing with lance memory addresses. The lance splits * its 24 bit addresses across two 16 bit registers. */ | |
| 1990/0911 | #define HADDR(a) ((((ulong)(a))>>16)&0xFF) | |
| 1990/0227 | #define LADDR(a) (((ulong)a)&0xFFFF) | |
| 1990/1228 | /* * The following functions exist to sidestep a quirk in the SGI IO3 lance * interface. In all other processors, the lance's initialization block and * descriptor rings look like normal memory. In the SGI IO3, the CPU sees a * 6 byte pad twixt all lance memory shorts. Therefore, we use the following * macros to compute the address whenever accessing the lance memory to make * the code portable. Sic transit gloria. */ #define LANCEMEM ((Lancemem*)0) | |
| 1990/0911 | #define MPs(a) (*(short *)(l.lanceram + l.sep*((ushort*)&a - (ushort*)0))) #define MPus(a) (*(ushort *)(l.lanceram + l.sep*((ushort*)&a - (ushort*)0))) | |
| 1990/0227 | /* * one per ethernet packet type */ typedef struct { QLock; int type; /* ethernet type */ | |
| 1991/0621 | int prom; /* promiscuous mode */ | |
| 1990/0227 | Queue *q; | |
| 1991/1114 | int inuse; | |
| 1990/0227 | } Ethertype; /* * lance state */ typedef struct { QLock; | |
| 1990/1231 | Lance; /* host dependent lance params */ | |
| 1991/0621 | int prom; /* number of promiscuous channels */ | |
| 1991/1114 | Network net; | |
| 1991/1115 | Netprot prot[Ntypes]; | |
| 1990/1231 | ||
| 1990/0227 | int inited; uchar *lmp; /* location of parity test */ Rendez rr; /* rendezvous for an input buffer */ | |
| 1991/0621 | QLock rlock; /* semaphore on tc */ | |
| 1990/0227 | ushort rl; /* first rcv Message belonging to Lance */ ushort rc; /* first rcv Message belonging to CPU */ Rendez tr; /* rendezvous for an output buffer */ QLock tlock; /* semaphore on tc */ ushort tl; /* first xmt Message belonging to Lance */ ushort tc; /* first xmt Message belonging to CPU */ Ethertype e[Ntypes]; int debug; int kstarted; | |
| 1990/0911 | ||
| 1991/1106 | Queue self; /* packets turned around at the interface */ | |
| 1990/0911 | /* sadistics */ int inpackets; int outpackets; int crcs; /* input crc errors */ int oerrs; /* output erros */ int frames; /* framing errors */ int overflows; /* packet overflows */ int buffs; /* buffering errors */ | |
| 1990/1231 | } SoftLance; static SoftLance l; | |
| 1990/0227 | /* * mode bits in the lance initialization block */ #define PROM 0x8000 #define INTL 0x40 #define DRTY 0x20 #define COLL 0x10 #define DTCR 0x8 #define LOOP 0x4 #define DTX 0x2 #define DRX 0x1 /* * LANCE CSR0, this is the register we play with most often. We leave * this register pointed to by l.rap in normal operation. */ #define ERR0 0x8000 #define BABL 0x4000 #define CERR 0x2000 #define MISS 0x1000 #define MERR 0x800 #define RINT 0x400 #define TINT 0x200 #define IDON 0x100 #define INTR 0x80 #define INEA 0x40 #define RXON 0x20 #define TXON 0x10 #define TDMD 0x8 #define STOP 0x4 #define STRT 0x2 #define INIT 0x1 /* * flag bits from a buffer descriptor in the rcv/xmt rings */ #define OWN 0x8000 /* 1 means that the buffer can be used by the chip */ #define ERR 0x4000 /* error summary, the OR of all error bits */ #define FRAM 0x2000 /* CRC error and incoming packet not a multiple of 8 bits */ #define OFLO 0x1000 /* (receive) lost some of the packet */ #define MORE 0x1000 /* (transmit) more than 1 retry to send the packet */ #define CRC 0x800 /* (receive) crc error reading packet */ #define ONE 0x800 /* (transmit) one retry to transmit the packet */ #define BUF 0x400 /* (receive) out of buffers while reading a packet */ #define DEF 0x400 /* (transmit) deffered while transmitting packet */ #define STP 0x200 /* start of packet */ #define ENP 0x100 /* end of packet */ /* * cntflags bits from a buffer descriptor in the rcv/xmt rings */ #define BUFF 0x8000 /* buffer error (host screwed up?) */ #define UFLO 0x4000 /* underflow from memory */ #define LCOL 0x1000 /* late collision (ether too long?) */ #define LCAR 0x800 /* loss of carrier (ether broken?) */ #define RTRY 0x400 /* couldn't transmit (bad station on ether?) */ #define TTDR 0x3FF /* time domain reflectometer */ /* * predeclared */ | |
| 1991/1114 | static void lancekproc(void *); static void lancestart(int, int); static void lanceup(Etherpkt*, int); static int lanceclonecon(Chan*); static void lancestatsfill(Chan*, char*, int); static void lancetypefill(Chan*, char*, int); | |
| 1991/0828 | ||
| 1990/0227 | /* * lance stream module definition */ static void lanceoput(Queue*, Block*); static void lancestopen(Queue*, Stream*); static void lancestclose(Queue*); static void stagerbuf(void); Qinfo lanceinfo = { nullput, lanceoput, lancestopen, lancestclose, "lance" }; /* * open a lance line discipline * * the lock is to synchronize changing the ethertype with * sending packets up the stream on interrupts. */ void lancestopen(Queue *q, Stream *s) { Ethertype *et; et = &l.e[s->id]; qlock(et); RD(q)->ptr = WR(q)->ptr = et; et->type = 0; et->q = RD(q); | |
| 1991/1114 | et->inuse = 1; | |
| 1990/0227 | qunlock(et); } /* * close lance line discipline * * the lock is to synchronize changing the ethertype with * sending packets up the stream on interrupts. */ static void lancestclose(Queue *q) { Ethertype *et; et = (Ethertype *)(q->ptr); | |
| 1991/0621 | if(et->prom){ qlock(&l); l.prom--; if(l.prom == 0) | |
| 1991/0828 | lancestart(0, 1); | |
| 1991/0621 | qunlock(&l); } | |
| 1990/0721 | qlock(et); | |
| 1990/0227 | et->type = 0; et->q = 0; | |
| 1991/0621 | et->prom = 0; | |
| 1991/1114 | et->inuse = 0; | |
| 1991/1115 | netdisown(&l.net, et - l.e); | |
| 1990/0227 | qunlock(et); } /* * the ``connect'' control message specifyies the type */ Proc *lanceout; static int isobuf(void *x) { | |
| 1991/1115 | USED(x); | |
| 1990/0227 | return TSUCC(l.tc) != l.tl; } static void lanceoput(Queue *q, Block *bp ) { int n, len; | |
| 1990/1228 | Etherpkt *p; | |
| 1991/0413 | Ethertype *e; | |
| 1990/0227 | Msg *m; | |
| 1991/0925 | Block *nbp; | |
| 1990/0227 | if(bp->type == M_CTL){ | |
| 1991/0621 | e = q->ptr; | |
| 1990/0227 | if(streamparse("connect", bp)){ | |
| 1991/0621 | e->type = strtol((char *)bp->rptr, 0, 0); } else if(streamparse("promiscuous", bp)) { e->prom = 1; qlock(&l); l.prom++; if(l.prom == 1) | |
| 1991/0828 | lancestart(PROM, 1); | |
| 1991/0621 | qunlock(&l); | |
| 1990/0227 | } freeb(bp); return; } /* | |
| 1991/1106 | * 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, l.ea, sizeof(l.ea)); if(memcmp(l.ea, p->d, sizeof(l.ea)) == 0){ len = blen(bp); | |
| 1991/1107 | bp = expandb(bp, len >= ETHERMINTU ? len : ETHERMINTU); | |
| 1991/1106 | if(bp){ putq(&l.self, bp); wakeup(&l.rr); } return; } /* | |
| 1990/0227 | * only one transmitter at a time */ qlock(&l.tlock); | |
| 1991/0828 | if(waserror()){ | |
| 1991/0925 | freeb(bp); | |
| 1991/0828 | qunlock(&l.tlock); nexterror(); } | |
| 1990/0227 | /* * Wait till we get an output buffer */ | |
| 1991/0828 | sleep(&l.tr, isobuf, (void *)0); | |
| 1990/0911 | p = &l.tp[l.tc]; | |
| 1990/0227 | /* * copy message into lance RAM */ len = 0; | |
| 1991/0925 | for(nbp = bp; nbp; nbp = nbp->next){ if(sizeof(Etherpkt) - len >= (n = BLEN(nbp))){ memmove(((uchar *)p)+len, nbp->rptr, n); | |
| 1990/0227 | len += n; } else print("no room damn it\n"); | |
| 1991/0925 | if(bp->flags & S_DELIM) | |
| 1990/0227 | break; } /* | |
| 1991/0118 | * pad the packet (zero the pad) | |
| 1990/0227 | */ | |
| 1991/1107 | if(len < ETHERMINTU){ memset(((char*)p)+len, 0, ETHERMINTU-len); len = ETHERMINTU; | |
| 1991/0118 | } | |
| 1990/0227 | /* * set up the ring descriptor and hand to lance */ | |
| 1990/0911 | l.outpackets++; | |
| 1990/0227 | m = &(LANCEMEM->tmr[l.tc]); | |
| 1990/0911 | MPs(m->size) = -len; MPus(m->cntflags) = 0; | |
| 1990/1229 | MPus(m->laddr) = LADDR(&l.ltp[l.tc]); MPus(m->flags) = OWN|STP|ENP|HADDR(&l.ltp[l.tc]); | |
| 1990/0227 | l.tc = TSUCC(l.tc); *l.rdp = INEA|TDMD; /**/ | |
| 1990/1229 | wbflush(); | |
| 1991/0925 | freeb(bp); | |
| 1990/0227 | qunlock(&l.tlock); | |
| 1991/0828 | poperror(); | |
| 1990/0227 | } /* | |
| 1990/1229 | * stop the lance and allocate buffers | |
| 1990/1228 | */ void | |
| 1990/0227 | lancereset(void) { | |
| 1990/0911 | static int already; | |
| 1990/0227 | ||
| 1990/1231 | if(already == 0){ already = 1; lancesetup(&l); | |
| 1991/1114 | l.net.name = "ether"; l.net.nconv = Ntypes; l.net.devp = &lanceinfo; l.net.protop = 0; l.net.listen = 0; l.net.clone = lanceclonecon; l.net.ninfo = 2; | |
| 1991/1115 | l.net.prot = l.prot; | |
| 1991/1114 | l.net.info[0].name = "stats"; l.net.info[0].fill = lancestatsfill; l.net.info[1].name = "type"; l.net.info[1].fill = lancetypefill; | |
| 1990/1231 | } | |
| 1990/1229 | ||
| 1990/0227 | /* | |
| 1990/1228 | * stop the lance | |
| 1990/0227 | */ | |
| 1990/1228 | *l.rap = 0; *l.rdp = STOP; | |
| 1990/0227 | } /* * Initialize and start the lance. This routine can be called at any time. * It may be used to restart a dead lance. */ static void | |
| 1991/0828 | lancestart(int mode, int dolock) | |
| 1990/0227 | { int i; | |
| 1990/1228 | Etherpkt *p; | |
| 1990/0911 | Lancemem *lm = LANCEMEM; Msg *m; | |
| 1990/0227 | ||
| 1991/0621 | /* * wait till both receiver and transmitter are * quiescent */ | |
| 1991/0828 | if(dolock){ qlock(&l.tlock); qlock(&l.rlock); } | |
| 1991/0621 | ||
| 1990/0227 | lancereset(); | |
| 1991/0621 | l.rl = 0; l.rc = 0; l.tl = 0; l.tc = 0; | |
| 1990/0227 | /* * create the initialization block */ | |
| 1991/0621 | MPus(lm->mode) = mode; | |
| 1990/0227 | /* * set ether addr from the value in the id prom. * the id prom has them in reverse order, the init * structure wants them in byte swapped order */ | |
| 1990/1228 | MPus(lm->etheraddr[0]) = (l.ea[1]<<8) | l.ea[0]; MPus(lm->etheraddr[1]) = (l.ea[3]<<8) | l.ea[2]; MPus(lm->etheraddr[2]) = (l.ea[5]<<8) | l.ea[4]; | |
| 1990/0227 | /* * ignore multicast addresses */ | |
| 1990/0911 | MPus(lm->multi[0]) = 0; MPus(lm->multi[1]) = 0; MPus(lm->multi[2]) = 0; MPus(lm->multi[3]) = 0; | |
| 1990/0227 | /* * set up rcv message ring */ | |
| 1990/0911 | m = lm->rmr; | |
| 1990/1231 | for(i = 0; i < l.nrrb; i++, m++){ | |
| 1990/1228 | MPs(m->size) = -sizeof(Etherpkt); | |
| 1990/0911 | MPus(m->cntflags) = 0; | |
| 1990/1229 | MPus(m->laddr) = LADDR(&l.lrp[i]); MPus(m->flags) = HADDR(&l.lrp[i]); | |
| 1990/0227 | } | |
| 1990/0911 | MPus(lm->rdralow) = LADDR(l.lm->rmr); | |
| 1990/1231 | MPus(lm->rdrahigh) = (l.lognrrb<<13)|HADDR(l.lm->rmr); | |
| 1990/0227 | ||
| 1990/0911 | ||
| 1990/0227 | /* * give the lance all the rcv buffers except one (as a sentinel) */ | |
| 1990/1231 | l.rc = l.nrrb - 1; | |
| 1990/0911 | m = lm->rmr; for(i = 0; i < l.rc; i++, m++) MPus(m->flags) |= OWN; | |
| 1990/0227 | /* * set up xmit message ring */ | |
| 1990/0911 | m = lm->tmr; | |
| 1990/1231 | for(i = 0; i < l.ntrb; i++, m++){ | |
| 1990/0911 | MPs(m->size) = 0; MPus(m->cntflags) = 0; | |
| 1990/1229 | MPus(m->laddr) = LADDR(&l.ltp[i]); MPus(m->flags) = HADDR(&l.ltp[i]); | |
| 1990/0227 | } | |
| 1990/0911 | MPus(lm->tdralow) = LADDR(l.lm->tmr); | |
| 1990/1231 | MPus(lm->tdrahigh) = (l.logntrb<<13)|HADDR(l.lm->tmr); | |
| 1990/0227 | /* * point lance to the initialization block */ *l.rap = 1; | |
| 1990/0911 | *l.rdp = LADDR(l.lm); | |
| 1990/0227 | wbflush(); *l.rap = 2; | |
| 1990/0911 | *l.rdp = HADDR(l.lm); | |
| 1990/0227 | /* * The lance byte swaps the ethernet packet unless we tell it not to */ wbflush(); *l.rap = 3; | |
| 1991/0109 | *l.rdp = l.busctl; | |
| 1990/0227 | /* * initialize lance, turn on interrupts, turn on transmit and rcv. */ | |
| 1990/1229 | wbflush(); | |
| 1990/0227 | *l.rap = 0; *l.rdp = INEA|INIT|STRT; /**/ } /* | |
| 1991/0621 | * set up lance directory. | |
| 1990/0227 | */ void lanceinit(void) { } Chan* lanceattach(char *spec) { if(l.kstarted == 0){ | |
| 1990/0911 | kproc("lancekproc", lancekproc, 0);/**/ | |
| 1990/0227 | l.kstarted = 1; | |
| 1991/0828 | lancestart(0, 1); | |
| 1990/0227 | } | |
| 1991/0316 | return devattach('l', spec); | |
| 1990/0227 | } Chan* lanceclone(Chan *c, Chan *nc) { return devclone(c, nc); } int lancewalk(Chan *c, char *name) { | |
| 1991/1114 | return netwalk(c, name, &l.net); | |
| 1990/0227 | } void lancestat(Chan *c, char *dp) { | |
| 1991/1114 | netstat(c, dp, &l.net); | |
| 1990/0227 | } /* * Pass open's of anything except the directory to streamopen */ Chan* lanceopen(Chan *c, int omode) { | |
| 1991/1114 | return netopen(c, omode, &l.net); | |
| 1990/0227 | } void lancecreate(Chan *c, char *name, int omode, ulong perm) { | |
| 1991/1115 | USED(c, name, omode, perm); | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | } void lanceclose(Chan *c) { | |
| 1991/0316 | if(c->stream) | |
| 1990/0227 | streamclose(c); } long | |
| 1991/0411 | lanceread(Chan *c, void *a, long n, ulong offset) | |
| 1990/0227 | { | |
| 1991/1114 | return netread(c, a, n, offset, &l.net); | |
| 1990/0227 | } long | |
| 1991/0411 | lancewrite(Chan *c, void *a, long n, ulong offset) | |
| 1990/0227 | { | |
| 1990/0312 | return streamwrite(c, a, n, 0); | |
| 1990/0227 | } void lanceremove(Chan *c) { | |
| 1991/1115 | USED(c); | |
| 1990/11211 | error(Eperm); | |
| 1990/0227 | } void lancewstat(Chan *c, char *dp) { | |
| 1991/1115 | netwstat(c, dp, &l.net); | |
| 1991/1114 | } /* * user level network interface routines */ static void lancestatsfill(Chan *c, char* p, int n) { char buf[256]; | |
| 1991/1115 | USED(c); | |
| 1991/1114 | sprint(buf, "in: %d\nout: %d\ncrc errs %d\noverflows: %d\nframe errs %d\nbuff errs: %d\noerrs %d\naddr: %.02x:%.02x:%.02x:%.02x:%.02x:%.02x\n", l.inpackets, l.outpackets, l.crcs, l.overflows, l.frames, l.buffs, l.oerrs, l.ea[0], l.ea[1], l.ea[2], l.ea[3], l.ea[4], l.ea[5]); strncpy(p, buf, n); } | |
| 1991/1115 | ||
| 1991/1114 | static void lancetypefill(Chan *c, char* p, int n) { char buf[16]; Ethertype *e; e = &l.e[STREAMID(c->qid.path)]; sprint(buf, "%d", e->type); strncpy(p, buf, n); } static int lanceclonecon(Chan *c) { Ethertype *e; | |
| 1991/1115 | USED(c); | |
| 1991/1114 | for(e = l.e; e < &l.e[Ntypes]; e++){ qlock(e); if(e->inuse || e->q){ qunlock(e); continue; } e->inuse = 1; | |
| 1991/1115 | netown(&l.net, e - l.e, u->p->user, 0); | |
| 1991/1114 | qunlock(e); return e - l.e; } errors("no unused lance channels"); | |
| 1990/0227 | } /* * We will: * (1) Clear interrupt cause in the lance * (2) service all current events */ void lanceintr(void) { | |
| 1990/0911 | int i; | |
| 1990/0227 | ushort csr; | |
| 1990/0911 | Lancemem *lm = LANCEMEM; | |
| 1991/0828 | static int misses; | |
| 1990/0227 | csr = *l.rdp; /* * turn off the interrupt and any error indicators */ *l.rdp = IDON|INEA|TINT|RINT|BABL|CERR|MISS|MERR; /* * see if an error occurred */ | |
| 1991/0108 | if(csr & (BABL|MISS|MERR)){ | |
| 1991/1107 | if(misses++ < 4) print("lance err %ux\n", csr); | |
| 1991/0108 | } | |
| 1990/0227 | ||
| 1990/1231 | if(csr & IDON){ | |
| 1990/0227 | l.inited = 1; | |
| 1991/0621 | qunlock(&l.rlock); qunlock(&l.tlock); | |
| 1990/1231 | } | |
| 1990/0227 | /* * look for rcv'd packets, just wakeup the input process */ | |
| 1990/1229 | if(l.rl!=l.rc && (MPus(lm->rmr[l.rl].flags) & OWN)==0){ | |
| 1991/0828 | misses = 0; | |
| 1990/0227 | wakeup(&l.rr); | |
| 1990/1229 | } | |
| 1990/0227 | /* * look for xmitt'd packets, wake any process waiting for a * transmit buffer */ | |
| 1990/0911 | while(l.tl!=l.tc && (MPus(lm->tmr[l.tl].flags) & OWN)==0){ if(MPus(lm->tmr[l.tl].flags) & ERR) l.oerrs++; | |
| 1990/0227 | l.tl = TSUCC(l.tl); wakeup(&l.tr); } } /* | |
| 1991/0621 | * send a packet upstream */ | |
| 1991/1106 | static void lanceup(Etherpkt *p, int len) | |
| 1991/0621 | { Block *bp; | |
| 1991/1106 | Ethertype *e; int t; | |
| 1991/0621 | ||
| 1991/1106 | t = (p->type[0]<<8) | p->type[1]; for(e = &l.e[0]; e < &l.e[Ntypes]; e++){ /* * check before locking just to save a lock */ if(e->q==0 || (t!=e->type && e->type!=-1)) continue; | |
| 1991/1026 | ||
| 1991/1106 | /* * only a trace channel gets packets destined for other machines */ if(e->type!=-1 && p->d[0]!=0xff && memcmp(p->d, l.ea, sizeof(p->d))!=0) continue; /* * check after locking to make sure things didn't * change under foot */ if(!canqlock(e)) continue; if(e->q==0 || e->q->next->len>Streamhi || (t!=e->type && e->type!=-1)){ qunlock(e); continue; } if(!waserror()){ bp = allocb(len); memmove(bp->rptr, (uchar *)p, len); bp->wptr += len; bp->flags |= S_DELIM; PUTNEXT(e->q, bp); } poperror(); qunlock(e); | |
| 1991/0621 | } } /* | |
| 1990/0227 | * input process, awakened on each interrupt with rcv buffers filled */ static int isinput(void *arg) { | |
| 1990/0911 | Lancemem *lm = LANCEMEM; | |
| 1991/1115 | USED(arg); | |
| 1991/1106 | return l.self.first || (l.rl!=l.rc && (MPus(lm->rmr[l.rl].flags) & OWN)==0); | |
| 1990/0227 | } | |
| 1991/1027 | ||
| 1991/0621 | static void | |
| 1990/0227 | lancekproc(void *arg) { | |
| 1990/1228 | Etherpkt *p; | |
| 1990/0227 | Ethertype *e; int len; | |
| 1991/0621 | int t; | |
| 1990/0911 | Lancemem *lm = LANCEMEM; Msg *m; | |
| 1991/1106 | Block *bp; | |
| 1990/0227 | ||
| 1991/1115 | USED(arg); | |
| 1990/0227 | for(;;){ | |
| 1991/0621 | qlock(&l.rlock); | |
| 1991/1106 | while(bp = getq(&l.self)){ lanceup((Etherpkt*)bp->rptr, BLEN(bp)); freeb(bp); } | |
| 1990/0911 | for(; l.rl!=l.rc && (MPus(lm->rmr[l.rl].flags) & OWN)==0 ; l.rl=RSUCC(l.rl)){ | |
| 1990/0227 | l.inpackets++; m = &(lm->rmr[l.rl]); | |
| 1991/1031 | t = MPus(m->flags); if(t & ERR){ | |
| 1990/0911 | if(t & FRAM) l.frames++; if(t & OFLO) l.overflows++; if(t & CRC) l.crcs++; if(t & BUFF) l.buffs++; | |
| 1990/0227 | goto stage; } /* | |
| 1991/0621 | * stuff packet up each queue that wants it | |
| 1990/0227 | */ | |
| 1990/0911 | p = &l.rp[l.rl]; len = MPus(m->cntflags) - 4; | |
| 1991/1106 | lanceup(p, len); | |
| 1991/0621 | ||
| 1990/0227 | stage: /* * stage the next input buffer */ m = &(lm->rmr[l.rc]); | |
| 1990/1228 | MPs(m->size) = -sizeof(Etherpkt); | |
| 1990/0911 | MPus(m->cntflags) = 0; | |
| 1990/1229 | MPus(m->laddr) = LADDR(&l.lrp[l.rc]); MPus(m->flags) = OWN|HADDR(&l.lrp[l.rc]); | |
| 1990/0227 | l.rc = RSUCC(l.rc); | |
| 1990/1229 | wbflush(); | |
| 1990/0227 | } | |
| 1991/0621 | qunlock(&l.rlock); | |
| 1990/0227 | sleep(&l.rr, isinput, 0); } | |
| 1990/0826 | } | |