plan 9 kernel history: overview | file list | diff list

1991/1121/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; 
1991/1121    
	uchar	bcast[6]; 
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; 
	} 
1991/1121    
	if(memcmp(l.bcast, p->d, sizeof(l.bcast)) == 0){ 
		len = blen(bp); 
		nbp = copyb(bp, len = len >= ETHERMINTU ? len : ETHERMINTU); 
		if(nbp){ 
			nbp->wptr = nbp->rptr+len; 
			putq(&l.self, nbp); 
			wakeup(&l.rr); 
		} 
	} 
1991/1106    
 
	/* 
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; 
1991/1121    
 
		memset(l.bcast, 0xff, sizeof l.bcast); 
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    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)