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

1992/0404/pc/devether.c (diff list | history)

1992/0403/sys/src/9/pc/devether.c:1,71992/0404/sys/src/9/pc/devether.c:1,7 (short | long | prev | next)
1992/0403    
/* 
 * Western Digital ethernet adapter 
 * BUGS: 
 *	more than one controller 
1992/0404    
 *	no more than one controller 
1992/0403    
 *	fix for different controller types 
 */ 
#include "u.h" 
1992/0403/sys/src/9/pc/devether.c:15,241992/0404/sys/src/9/pc/devether.c:15,36
1992/0403    
 
typedef struct Ctlr Ctlr; 
typedef struct Pktype Pktype; 
1992/0404    
typedef struct Ring Ring; 
1992/0403    
 
enum { 
	IObase		= 0x360, 
1992/0404    
	RAMbase		= 0xC8000, 
	RAMsize		= 8*1024, 
	BUFsize		= 256, 
1992/0403    
 
1992/0404    
	Nctlr		= 1, 
	NPktype		= 9,		/* types/interface */ 
}; 
 
/* 
 * register offsets from IObase 
 */ 
enum { 
1992/0403    
	EA		= 0x08,		/* Ethernet Address in ROM */ 
	ID		= 0x0E,		/* interface type */ 
 
1992/0403/sys/src/9/pc/devether.c:25,381992/0404/sys/src/9/pc/devether.c:37,49
1992/0403    
	NIC		= 0x10,		/* National DP8390 Chip */ 
	Cr		= NIC+0x00,	/* Page [01] */ 
 
	Clda0		= NIC+0x01,	/* read */ 
	Pstart		= Clda0,	/* write */ 
	Clda1		= NIC+0x02,	/* read */ 
	Pstop		= Clda1,	/* write */ 
	Bnry		= NIC+0x03,	/* Page 0 */ 
1992/0404    
	Pstart		= NIC+0x01,	/* write */ 
	Pstop		= NIC+0x02,	/* write */ 
	Bnry		= NIC+0x03, 
1992/0403    
	Tsr		= NIC+0x04,	/* read */ 
	Tpsr		= Tsr,		/* write */ 
	Ncr		= NIC+0x05, 
1992/0404    
	Tbcr0		= NIC+0x05,	/* write */ 
	Tbcr1		= NIC+0x06,	/* write */ 
1992/0403    
	Isr		= NIC+0x07, 
	Rbcr0		= NIC+0x0A, 
	Rbcr1		= NIC+0x0B, 
1992/0403/sys/src/9/pc/devether.c:47,651992/0404/sys/src/9/pc/devether.c:58,82
1992/0403    
 
	Par0		= NIC+0x01,	/* Page 1 */ 
	Curr		= NIC+0x07, 
	Mar0		= NIC+0x08, 
	Mar1		= NIC+0x09, 
	Mar2		= NIC+0x0A, 
	Mar3		= NIC+0x0B, 
	Mar4		= NIC+0x0C, 
	Mar5		= NIC+0x0D, 
	Mar6		= NIC+0x0E, 
	Mar7		= NIC+0x0F, 
1992/0404    
}; 
1992/0403    
 
	RAMbase		= 0xC8000, 
1992/0404    
/* 
 * some register bits 
 */ 
enum { 
	Prx		= 0x01,		/* Isr:	packet received */ 
	Ptx		= 0x02,		/*	packet transmitted */ 
	Rxe		= 0x04,		/*	receive error */ 
	Txe		= 0x08,		/*	transmit error */ 
	Ovw		= 0x10,		/*	overwrite warning */ 
	Rst		= 0x80,		/*	reset status */ 
}; 
1992/0403    
 
	Nctlr		= 1, 
	NPktype		= 9,		/* types/interface */ 
1992/0404    
struct Ring { 
	uchar	status; 
	uchar	next; 
	ushort	len; 
	uchar	data[BUFsize-4]; 
1992/0403    
}; 
 
/* 
1992/0403/sys/src/9/pc/devether.c:81,891992/0404/sys/src/9/pc/devether.c:98,109
1992/0403    
	QLock; 
 
	Rendez	rr;			/* rendezvous for an input buffer */ 
1992/0404    
	uchar	bnry; 
	uchar	curr; 
	uchar	ovw; 
1992/0403    
	Queue	rq; 
 
	Qlock	xl; 
1992/0404    
	QLock	xl; 
1992/0403    
	Rendez	xr; 
 
	int	iobase;			/* I/O base address */ 
1992/0403/sys/src/9/pc/devether.c:117,1221992/0404/sys/src/9/pc/devether.c:137,144
1992/0403    
	Etherpkt *p; 
	Block *nbp; 
 
1992/0404    
panic("etheroput\n"); 
#ifdef notdef 
1992/0403    
	c = ((Pktype *)q->ptr)->ctlr; 
	if(bp->type == M_CTL){ 
		t = q->ptr; 
1992/0403/sys/src/9/pc/devether.c:126,1331992/0404/sys/src/9/pc/devether.c:148,157
1992/0403    
			t->prom = 1; 
			qlock(c); 
			c->prom++; 
			if(c->prom == 1) 
1992/0404    
			if(c->prom == 1){ 
				outb(t->ctlr->iobase+Cr, 0x22);	/* Page0, RD2|STA */ 
1992/0403    
				outb(c->iobase+Rcr, 0x14);	/* PRO|AB */ 
1992/0404    
			} 
1992/0403    
			qunlock(c); 
		} 
		freeb(bp); 
1992/0403/sys/src/9/pc/devether.c:226,2311992/0404/sys/src/9/pc/devether.c:250,256
1992/0403    
	poperror(); 
 
	enet.outpackets++; 
1992/0404    
#endif 
1992/0403    
} 
 
/* 
1992/0403/sys/src/9/pc/devether.c:237,2531992/0404/sys/src/9/pc/devether.c:262,278
1992/0403    
static void 
etherstopen(Queue *q, Stream *s) 
{ 
	Ctlr *c = &ctlr[0]; 
	Pktype *t; 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
	Pktype *pp; 
1992/0403    
 
	t = &c->pktype[s->id]; 
	qlock(t); 
	RD(q)->ptr = WR(q)->ptr = t; 
	t->type = 0; 
	t->q = RD(q); 
	t->inuse = 1; 
	t->ctlr = c; 
	qunlock(t); 
1992/0404    
	pp = &cp->pktype[s->id]; 
	qlock(pp); 
	RD(q)->ptr = WR(q)->ptr = pp; 
	pp->type = 0; 
	pp->q = RD(q); 
	pp->inuse = 1; 
	pp->ctlr = cp; 
	qunlock(pp); 
1992/0403    
} 
 
/* 
1992/0403/sys/src/9/pc/devether.c:259,2811992/0404/sys/src/9/pc/devether.c:284,308
1992/0403    
static void 
etherstclose(Queue *q) 
{ 
	Pktype *t; 
1992/0404    
	Pktype *pp; 
1992/0403    
 
	t = (Pktype *)(q->ptr); 
	if(t->prom){ 
		qlock(t->ctlr); 
		t->ctlr->prom--; 
		if(t->ctlr->prom == 0) 
			/* turn off promiscuous mode here */; 
		qunlock(t->ctlr); 
1992/0404    
	pp = (Pktype *)(q->ptr); 
	if(pp->prom){ 
		qlock(pp->ctlr); 
		pp->ctlr->prom--; 
		if(pp->ctlr->prom == 0){ 
			outb(pp->ctlr->iobase+Cr, 0x22);/* Page0, RD2|STA */ 
			outb(pp->ctlr->iobase+Rcr, 0x04);/* AB */ 
		} 
		qunlock(pp->ctlr); 
1992/0403    
	} 
	qlock(t); 
	t->type = 0; 
	t->q = 0; 
	t->prom = 0; 
	t->inuse = 0; 
	netdisown(&t->ctlr->net, t - t->ctlr->pktype); 
	qunlock(t); 
1992/0404    
	qlock(pp); 
	pp->type = 0; 
	pp->q = 0; 
	pp->prom = 0; 
	pp->inuse = 0; 
	netdisown(&pp->ctlr->net, pp - pp->ctlr->pktype); 
	qunlock(pp); 
1992/0403    
} 
 
static Qinfo info = { 
1992/0403/sys/src/9/pc/devether.c:287,3211992/0404/sys/src/9/pc/devether.c:314,348
1992/0403    
}; 
 
static int 
clonecon(Chan *chan) 
1992/0404    
clonecon(Chan *c) 
1992/0403    
{ 
	Ctlr *c = &ctlr[0]; 
	Pktype *t; 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
	Pktype *pp; 
1992/0403    
 
	for(t = c->pktype; t < &c->pktype[NPktype]; t++){ 
		qlock(t); 
		if(t->inuse || t->q){ 
			qunlock(t); 
1992/0404    
	for(pp = cp->pktype; pp < &cp->pktype[NPktype]; pp++){ 
		qlock(pp); 
		if(pp->inuse || pp->q){ 
			qunlock(pp); 
1992/0403    
			continue; 
		} 
		t->inuse = 1; 
		netown(&c->net, t - c->pktype, u->p->user, 0); 
		qunlock(t); 
		return t - c->pktype; 
1992/0404    
		pp->inuse = 1; 
		netown(&cp->net, pp - cp->pktype, u->p->user, 0); 
		qunlock(pp); 
		return pp - cp->pktype; 
1992/0403    
	} 
	exhausted("ether channels"); 
} 
 
static void 
statsfill(Chan *chan, char *p, int n) 
1992/0404    
statsfill(Chan *c, char *p, int n) 
1992/0403    
{ 
	Ctlr *c = &ctlr[0]; 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0403    
	char buf[256]; 
 
	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", 
		c->inpackets, c->outpackets, c->crcs, 
		c->overflows, c->frames, c->buffs, c->oerrs, 
		c->ea[0], c->ea[1], c->ea[2], c->ea[3], c->ea[4], c->ea[5]); 
1992/0404    
		cp->inpackets, cp->outpackets, cp->crcs, 
		cp->overflows, cp->frames, cp->buffs, cp->oerrs, 
		cp->ea[0], cp->ea[1], cp->ea[2], cp->ea[3], cp->ea[4], cp->ea[5]); 
1992/0403    
	strncpy(p, buf, n); 
} 
 
1992/0403/sys/src/9/pc/devether.c:323,3321992/0404/sys/src/9/pc/devether.c:350,359
1992/0403    
typefill(Chan *c, char *p, int n) 
{ 
	char buf[16]; 
	Pktype *t; 
1992/0404    
	Pktype *pp; 
1992/0403    
 
	t = &ctlr[0].pktype[STREAMID(c->qid.path)]; 
	sprint(buf, "%d", t->type); 
1992/0404    
	pp = &ctlr[0].pktype[STREAMID(c->qid.path)]; 
	sprint(buf, "%d", pp->type); 
1992/0403    
	strncpy(p, buf, n); 
} 
 
1992/0403/sys/src/9/pc/devether.c:333,4181992/0404/sys/src/9/pc/devether.c:360,554
1992/0403    
static void 
intr(Ureg *ur) 
{ 
	panic("ether intr\n"); 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
	uchar isr, curr; 
 
	outb(cp->iobase+Cr, 0x22);			/* Page0, RD2|STA */ 
	while(isr = inb(cp->iobase+Isr)){ 
		outb(cp->iobase+Isr, isr); 
		if(isr & Txe) 
			cp->oerrs++; 
		if(isr & Rxe){ 
			cp->frames += inb(cp->iobase+Cntr0); 
			cp->crcs += inb(cp->iobase+Cntr1); 
			cp->buffs += inb(cp->iobase+Cntr2); 
		} 
		if(isr & Ptx) 
			cp->outpackets++; 
		if(isr & (Txe|Ptx)){ 
			panic("tx intr\n"); 
		} 
		/* 
		 * the receive ring is full. 
		 * put the NIC into loopback mode to give 
		 * kproc a chance to process some packets. 
		 */ 
		if(isr & Ovw){ 
			outb(cp->iobase+Cr, 0x21);	/* Page0, RD2|STP */ 
			outb(cp->iobase+Rbcr0, 0); 
			outb(cp->iobase+Rbcr1, 0); 
			while((inb(cp->iobase+Isr) & Rst) == 0) 
				delay(1); 
			outb(cp->iobase+Tcr, 0x20);	/* LB0 */ 
			outb(cp->iobase+Cr, 0x22);	/* Page0, RD2|STA */ 
			cp->ovw = 1; 
		} 
		/* 
		 * we have received packets. 
		 * this is the only place, other than the init code, 
		 * where we set the controller to Page1. 
		 * we must be careful to reset it back to Page0 in case 
		 * we interrupted some other part of this driver. 
		 */ 
		if(isr & (Ovw|Prx)){ 
			outb(cp->iobase+Cr, 0x62);	/* Page1, RD2|STA */ 
			cp->curr = inb(cp->iobase+Curr); 
			outb(cp->iobase+Cr, 0x22);	/* Page0, RD2|STA */ 
			wakeup(&cp->rr); 
		} 
	} 
1992/0403    
} 
 
/* 
 * the following initialisation procedure 
 * is mandatory 
 * after this, the chip is still offline 
1992/0404    
 * we leave the chip idling on internal loopback 
1992/0403    
 */ 
static void 
init(Ctlr *c) 
1992/0404    
init(Ctlr *cp) 
1992/0403    
{ 
	int i; 
 
	outb(c->iobase+Cr, 0x21);	/* Page0, RD2|STP */ 
	outb(c->iobase+Dcr, 0x48);	/* FT1|LS */ 
	outb(c->iobase+Rbcr0, 0); 
	outb(c->iobase+Rbcr1, 0); 
	outb(c->iobase+Rcr, 0x04);	/* AB */ 
	outb(c->iobase+Tcr, 0); 
	outb(c->iobase+Bnry, 6); 
	outb(c->iobase+Pstart, 6);	/* 6*256 */ 
	outb(c->iobase+Pstop, 32);	/* 8*1024/256 */ 
	outb(c->iobase+Isr, 0xFF); 
	outb(c->iobase+Imr, 0x0F);	/* TXEE|RXEE|PTXE|PRXE */ 
1992/0404    
	outb(cp->iobase+Cr, 0x21);		/* Page0, RD2|STP */ 
	outb(cp->iobase+Dcr, 0x48);		/* FT1|LS */ 
	outb(cp->iobase+Rbcr0, 0); 
	outb(cp->iobase+Rbcr1, 0); 
	outb(cp->iobase+Rcr, 0x04);		/* AB */ 
	outb(cp->iobase+Tcr, 0x20);		/* LB0 */ 
	outb(cp->iobase+Bnry, 6); 
	cp->bnry = 6; 
	outb(cp->iobase+Pstart, 6);		/* 6*256 */ 
	outb(cp->iobase+Pstop, 32);		/* 8*1024/256 */ 
	outb(cp->iobase+Isr, 0xFF); 
	outb(cp->iobase+Imr, 0x1F);		/* OVWE|TXEE|RXEE|PTXE|PRXE */ 
1992/0403    
 
	outb(c->iobase+Cr, 0x61);	/* Page1, RD2|STP */ 
	for(i = 0; i < sizeof(c->ea); i++) 
		outb(c->iobase+Par0+i, c->ea[i]); 
	outb(c->iobase+Curr, 6);	/* 6*256 */ 
1992/0404    
	outb(cp->iobase+Cr, 0x61);		/* Page1, RD2|STP */ 
	for(i = 0; i < sizeof(cp->ea); i++) 
		outb(cp->iobase+Par0+i, cp->ea[i]); 
	outb(cp->iobase+Curr, 6);		/* 6*256 */ 
	cp->curr = 6; 
 
	outb(cp->iobase+Cr, 0x22);		/* Page0, RD2|STA */ 
	outb(cp->iobase+Tpsr, 0); 
1992/0403    
} 
 
void 
etherreset(void) 
{ 
	Ctlr *c = &ctlr[0]; 
1992/0404    
	Ctlr *cp = &ctlr[0]; 
1992/0403    
	int i; 
 
	c->iobase = IObase; 
	init(c); 
1992/0404    
	cp->iobase = IObase; 
	init(cp); 
1992/0403    
	setvec(Ethervec, intr); 
 
	for(i = 0; i < sizeof(c->ea); i++) 
		c->ea[i] = inb(c->iobase+EA+i); 
	memset(c->ba, 0xFF, sizeof(c->ba)); 
1992/0404    
	for(i = 0; i < sizeof(cp->ea); i++) 
		cp->ea[i] = inb(cp->iobase+EA+i); 
	memset(cp->ba, 0xFF, sizeof(cp->ba)); 
1992/0403    
 
	c->net.name = "ether"; 
	c->net.nconv = NPktype; 
	c->net.devp = &info; 
	c->net.protop = 0; 
	c->net.listen = 0; 
	c->net.clone = clonecon; 
	c->net.ninfo = 2; 
	c->net.prot = c->prot; 
	c->net.info[0].name = "stats"; 
	c->net.info[0].fill = statsfill; 
	c->net.info[1].name = "type"; 
	c->net.info[1].fill = typefill; 
1992/0404    
	cp->net.name = "ether"; 
	cp->net.nconv = NPktype; 
	cp->net.devp = &info; 
	cp->net.protop = 0; 
	cp->net.listen = 0; 
	cp->net.clone = clonecon; 
	cp->net.ninfo = 2; 
	cp->net.prot = cp->prot; 
	cp->net.info[0].name = "stats"; 
	cp->net.info[0].fill = statsfill; 
	cp->net.info[1].name = "type"; 
	cp->net.info[1].fill = typefill; 
1992/0403    
} 
 
1992/0404    
static void 
etherup(Ctlr *cp, Etherpkt *p, int len) 
{ 
	Block *bp; 
	Pktype *pp; 
	int t; 
 
	t = (p->type[0]<<8) | p->type[1]; 
	for(pp = &cp->pktype[0]; pp < &cp->pktype[NPktype]; pp++){ 
		/* 
		 *  check before locking just to save a lock 
		 */ 
		if(pp->q == 0 || (t != pp->type && pp->type != -1)) 
			continue; 
 
		/* 
		 *  only a trace channel gets packets destined for other machines 
		 */ 
		if(pp->type != -1 && p->d[0] != 0xFF && memcmp(p->d, cp->ea, sizeof(p->d))) 
			continue; 
 
		/* 
		 *  check after locking to make sure things didn't 
		 *  change under foot 
		 */ 
		if(canqlock(pp) == 0) 
			continue; 
		if(pp->q == 0 || pp->q->next->len > Streamhi || (t != pp->type && pp->type != -1)){ 
			qunlock(pp); 
			continue; 
		} 
		if(waserror() == 0){ 
			bp = allocb(len); 
			memmove(bp->rptr, (uchar *)p, len); 
			bp->wptr += len; 
			bp->flags |= S_DELIM; 
			PUTNEXT(pp->q, bp); 
		} 
		poperror(); 
		qunlock(pp); 
	} 
} 
 
1992/0403    
static int 
isinput(void *arg) 
{ 
	Ctlr *c = arg; 
1992/0404    
	Ctlr *cp = arg; 
1992/0403    
 
	return 0; 
1992/0404    
	return cp->bnry != cp->curr; 
1992/0403    
} 
 
static void 
etherkproc(void *arg) 
{ 
	Ctlr *c = arg; 
1992/0404    
	Ctlr *cp = arg; 
	Block *bp; 
	uchar bnry, curr; 
	Ring *rp; 
1992/0403    
 
	if(waserror()){ 
		print("someone noted %s\n", c->name); 
		c->kproc = 0; 
1992/0404    
		print("%s noted\n", cp->name); 
		init(cp); 
		cp->kproc = 0; 
1992/0403    
		nexterror(); 
	} 
	c->kproc = 1; 
1992/0404    
	cp->kproc = 1; 
1992/0403    
	for(;;){ 
		sleep(&c->rr, isinput, c); 
1992/0404    
		sleep(&cp->rr, isinput, cp); 
		while(bp = getq(&cp->rq)){ 
			cp->inpackets++; 
			etherup(cp, (Etherpkt*)bp->rptr, BLEN(bp)); 
			freeb(bp); 
		} 
#ifdef foo 
			bnry = inb(cp->iobase+Bnry); 
			while(bnry != cp->curr){ 
				rp = &((Ring *)RAMbase)[bnry]; 
			} 
#endif 
1992/0403    
	} 
} 
 
1992/0403/sys/src/9/pc/devether.c:425,4321992/0404/sys/src/9/pc/devether.c:561,567
1992/0403    
	 * put the receiver online 
	 * and start the kproc 
	 */ 
	outb(c->iobase+Cr, 0x22);	/* Page0, RD2|STA */ 
	outb(c->iobase+Tpsr, 0); 
1992/0404    
	outb(ctlr[ctlrno].iobase+Tcr, 0); 
1992/0403    
	if(ctlr[ctlrno].kproc == 0){ 
		sprint(ctlr[ctlrno].name, "ether%dkproc", ctlrno); 
		kproc(ctlr[ctlrno].name, etherkproc, &ctlr[ctlrno]); 


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