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

2000/0604/pc/ether8390.c (diff list | history)

pc/ether8390.c on 1992/1222
1992/1222    
/* 
1997/0327    
 * National Semiconductor DP8390 and clone 
1992/1222    
 * Network Interface Controller. 
 */ 
#include "u.h" 
#include "../port/lib.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
#include "io.h" 
1993/1116    
#include "../port/error.h" 
#include "../port/netif.h" 
1992/1222    
 
1993/1116    
#include "etherif.h" 
1997/0327    
#include "ether8390.h" 
1992/1222    
 
1997/0327    
enum {					/* NIC core registers */ 
1992/1222    
	Cr		= 0x00,		/* command register, all pages */ 
 
1997/0327    
					/* Page 0, read */ 
1992/1222    
	Clda0		= 0x01,		/* current local DMA address 0 */ 
	Clda1		= 0x02,		/* current local DMA address 1 */ 
	Bnry		= 0x03,		/* boundary pointer (R/W) */ 
	Tsr		= 0x04,		/* transmit status register */ 
	Ncr		= 0x05,		/* number of collisions register */ 
	Fifo		= 0x06,		/* FIFO */ 
	Isr		= 0x07,		/* interrupt status register (R/W) */ 
	Crda0		= 0x08,		/* current remote DMA address 0 */ 
1993/0212    
	Crda1		= 0x09,		/* current remote DMA address 1 */ 
1992/1222    
	Rsr		= 0x0C,		/* receive status register */ 
	Cntr0		= 0x0D,		/* frame alignment errors */ 
	Cntr1		= 0x0E,		/* CRC errors */ 
	Cntr2		= 0x0F,		/* missed packet errors */ 
 
1997/0327    
					/* Page 0, write */ 
1992/1222    
	Pstart		= 0x01,		/* page start register */ 
	Pstop		= 0x02,		/* page stop register */ 
	Tpsr		= 0x04,		/* transmit page start address */ 
	Tbcr0		= 0x05,		/* transmit byte count register 0 */ 
	Tbcr1		= 0x06,		/* transmit byte count register 1 */ 
	Rsar0		= 0x08,		/* remote start address register 0 */ 
	Rsar1		= 0x09,		/* remote start address register 1 */ 
	Rbcr0		= 0x0A,		/* remote byte count register 0 */ 
	Rbcr1		= 0x0B,		/* remote byte count register 1 */ 
	Rcr		= 0x0C,		/* receive configuration register */ 
	Tcr		= 0x0D,		/* transmit configuration register */ 
	Dcr		= 0x0E,		/* data configuration register */ 
	Imr		= 0x0F,		/* interrupt mask */ 
 
1997/0327    
					/* Page 1, read/write */ 
1992/1222    
	Par0		= 0x01,		/* physical address register 0 */ 
	Curr		= 0x07,		/* current page register */ 
	Mar0		= 0x08,		/* multicast address register 0 */ 
}; 
 
1997/0327    
enum {					/* Cr */ 
	Stp		= 0x01,		/* stop */ 
	Sta		= 0x02,		/* start */ 
	Txp		= 0x04,		/* transmit packet */ 
	Rd0		= 0x08,		/* remote DMA command */ 
	Rd1		= 0x10,	 
	Rd2		= 0x20, 
	RdREAD		= Rd0,		/* remote read */ 
	RdWRITE		= Rd1,		/* remote write */ 
	RdSEND		= Rd1|Rd0,	/* send packet */ 
	RdABORT		= Rd2,		/* abort/complete remote DMA */ 
	Ps0		= 0x40,		/* page select */ 
	Ps1		= 0x80, 
	Page0		= 0x00, 
	Page1		= Ps0, 
	Page2		= Ps1, 
}; 
 
enum {					/* Isr/Imr */ 
1992/1222    
	Prx		= 0x01,		/* packet received */ 
	Ptx		= 0x02,		/* packet transmitted */ 
	Rxe		= 0x04,		/* receive error */ 
	Txe		= 0x08,		/* transmit error */ 
	Ovw		= 0x10,		/* overwrite warning */ 
	Cnt		= 0x20,		/* counter overflow */ 
	Rdc		= 0x40,		/* remote DMA complete */ 
	Rst		= 0x80,		/* reset status */ 
}; 
 
1997/0327    
enum {					/* Dcr */ 
1992/1222    
	Wts		= 0x01,		/* word transfer select */ 
	Bos		= 0x02,		/* byte order select */ 
	Las		= 0x04,		/* long address select */ 
	Ls		= 0x08,		/* loopback select */ 
	Arm		= 0x10,		/* auto-initialise remote */ 
1997/0327    
	Ft0		= 0x20,		/* FIFO threshold select */ 
	Ft1		= 0x40, 
	Ft1WORD		= 0x00, 
	Ft2WORD		= Ft0, 
	Ft4WORD		= Ft1, 
	Ft6WORD		= Ft1|Ft0, 
1992/1222    
}; 
 
1997/0327    
enum {					/* Tcr */ 
1992/1222    
	Crc		= 0x01,		/* inhibit CRC */ 
1997/0327    
	Lb0		= 0x02,		/* encoded loopback control */ 
	Lb1		= 0x04, 
	LpbkNORMAL	= 0x00,		/* normal operation */ 
	LpbkNIC		= Lb0,		/* internal NIC module loopback */ 
	LpbkENDEC	= Lb1,		/* internal ENDEC module loopback */ 
	LpbkEXTERNAL	= Lb1|Lb0,	/* external loopback */ 
1992/1222    
	Atd		= 0x08,		/* auto transmit disable */ 
	Ofst		= 0x10,		/* collision offset enable */ 
}; 
 
1997/0327    
enum {					/* Tsr */ 
1992/1222    
	Ptxok		= 0x01,		/* packet transmitted */ 
	Col		= 0x04,		/* transmit collided */ 
	Abt		= 0x08,		/* tranmit aborted */ 
	Crs		= 0x10,		/* carrier sense lost */ 
	Fu		= 0x20,		/* FIFO underrun */ 
	Cdh		= 0x40,		/* CD heartbeat */ 
	Owc		= 0x80,		/* out of window collision */ 
}; 
 
1997/0327    
enum {					/* Rcr */ 
1992/1222    
	Sep		= 0x01,		/* save errored packets */ 
	Ar		= 0x02,		/* accept runt packets */ 
	Ab		= 0x04,		/* accept broadcast */ 
	Am		= 0x08,		/* accept multicast */ 
	Pro		= 0x10,		/* promiscuous physical */ 
	Mon		= 0x20,		/* monitor mode */ 
}; 
 
1997/0327    
enum {					/* Rsr */ 
1992/1222    
	Prxok		= 0x01,		/* packet received intact */ 
	Crce		= 0x02,		/* CRC error */ 
	Fae		= 0x04,		/* frame alignment error */ 
	Fo		= 0x08,		/* FIFO overrun */ 
	Mpa		= 0x10,		/* missed packet */ 
	Phy		= 0x20,		/* physical/multicast address */ 
	Dis		= 0x40,		/* receiver disabled */ 
	Dfr		= 0x80,		/* deferring */ 
}; 
 
typedef struct { 
	uchar	status; 
	uchar	next; 
	uchar	len0; 
	uchar	len1; 
} Hdr; 
 
1997/0327    
void 
dp8390getea(Ether* ether, uchar* ea) 
1992/1222    
{ 
1997/0327    
	Dp8390 *ctlr; 
	uchar cr; 
	int i; 
1992/1222    
 
1997/0327    
	ctlr = ether->ctlr; 
 
1992/1222    
	/* 
1997/0327    
	 * Get the ethernet address from the chip. 
	 * Take care to restore the command register 
	 * afterwards. 
1992/1222    
	 */ 
1997/0327    
	ilock(ctlr); 
	cr = regr(ctlr, Cr) & ~Txp; 
	regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr)); 
	for(i = 0; i < Eaddrlen; i++) 
		ea[i] = regr(ctlr, Par0+i); 
	regw(ctlr, Cr, cr); 
	iunlock(ctlr); 
1992/1222    
} 
 
void 
1997/0327    
dp8390setea(Ether* ether) 
1992/1222    
{ 
	int i; 
1997/0327    
	uchar cr; 
	Dp8390 *ctlr; 
1992/1222    
 
1997/0327    
	ctlr = ether->ctlr; 
 
1992/1222    
	/* 
	 * Set the ethernet address into the chip. 
	 * Take care to restore the command register 
1997/0327    
	 * afterwards. Don't care about multicast 
	 * addresses as multicast is never enabled 
	 * (currently). 
1992/1222    
	 */ 
1997/0327    
	ilock(ctlr); 
	cr = regr(ctlr, Cr) & ~Txp; 
	regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr)); 
	for(i = 0; i < Eaddrlen; i++) 
		regw(ctlr, Par0+i, ether->ea[i]); 
	regw(ctlr, Cr, cr); 
	iunlock(ctlr); 
1992/1222    
} 
 
1997/0327    
static void* 
_dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len) 
1992/1222    
{ 
	uchar cr; 
	int timo; 
 
	/* 
1993/0212    
	 * Read some data at offset 'from' in the card's memory 
1992/1222    
	 * using the DP8390 remote DMA facility, and place it at 
	 * 'to' in main memory, via the I/O data port. 
	 */ 
1997/0327    
	cr = regr(ctlr, Cr) & ~Txp; 
	regw(ctlr, Cr, Page0|RdABORT|Sta); 
	regw(ctlr, Isr, Rdc); 
1992/1222    
 
	/* 
	 * Set up the remote DMA address and count. 
	 */ 
1997/0327    
	len = ROUNDUP(len, ctlr->width); 
	regw(ctlr, Rbcr0, len & 0xFF); 
	regw(ctlr, Rbcr1, (len>>8) & 0xFF); 
	regw(ctlr, Rsar0, from & 0xFF); 
	regw(ctlr, Rsar1, (from>>8) & 0xFF); 
1992/1222    
 
	/* 
	 * Start the remote DMA read and suck the data 
	 * out of the I/O port. 
	 */ 
1997/0327    
	regw(ctlr, Cr, Page0|RdREAD|Sta); 
	rdread(ctlr, to, len); 
1992/1222    
 
	/* 
	 * Wait for the remote DMA to complete. The timeout 
1997/0327    
	 * is necessary because this routine may be called on 
1992/1222    
	 * a non-existent chip during initialisation and, due 
1997/0327    
	 * to the miracles of the bus, it's possible to get this 
	 * far and still be talking to a slot full of nothing. 
1992/1222    
	 */ 
1997/0327    
	for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--) 
1992/1222    
			; 
 
1997/0327    
	regw(ctlr, Isr, Rdc); 
	regw(ctlr, Cr, cr); 
 
1992/1222    
	return to; 
} 
 
1994/0128    
void* 
1997/0327    
dp8390read(Dp8390* ctlr, void* to, ulong from, ulong len) 
1992/1222    
{ 
1997/0327    
	void *v; 
 
	ilock(ctlr); 
1998/0129    
	v = _dp8390read(ctlr, to, from, len); 
1997/0327    
	iunlock(ctlr); 
 
	return v; 
} 
 
static void* 
dp8390write(Dp8390* ctlr, ulong to, void* from, ulong len) 
{ 
1993/1118    
	ulong crda; 
1992/1222    
	uchar cr; 
1997/0327    
	int timo, width; 
1992/1222    
 
1994/0202    
	/* 
1993/0212    
	 * Write some data to offset 'to' in the card's memory 
1992/1222    
	 * using the DP8390 remote DMA facility, reading it at 
	 * 'from' in main memory, via the I/O data port. 
	 */ 
1997/0327    
	cr = regr(ctlr, Cr) & ~Txp; 
	regw(ctlr, Cr, Page0|RdABORT|Sta); 
	regw(ctlr, Isr, Rdc); 
1992/1222    
 
1997/0327    
	len = ROUNDUP(len, ctlr->width); 
1993/0212    
 
1992/1222    
	/* 
	 * Set up the remote DMA address and count. 
1997/0327    
	 * This is straight from the DP8390[12D] datasheet, 
	 * hence the initial set up for read. 
	 * Assumption here that the A7000 EtherV card will 
	 * never need a dummyrr. 
1992/1222    
	 */ 
1997/0327    
	if(ctlr->dummyrr && (ctlr->width == 1 || ctlr->width == 2)){ 
		if(ctlr->width == 2) 
			width = 1; 
		else 
			width = 0; 
		crda = to-1-width; 
		regw(ctlr, Rbcr0, (len+1+width) & 0xFF); 
		regw(ctlr, Rbcr1, ((len+1+width)>>8) & 0xFF); 
		regw(ctlr, Rsar0, crda & 0xFF); 
		regw(ctlr, Rsar1, (crda>>8) & 0xFF); 
		regw(ctlr, Cr, Page0|RdREAD|Sta); 
	 
		for(;;){ 
			crda = regr(ctlr, Crda0); 
			crda |= regr(ctlr, Crda1)<<8; 
			if(crda == to){ 
				/* 
				 * Start the remote DMA write and make sure 
				 * the registers are correct. 
				 */ 
				regw(ctlr, Cr, Page0|RdWRITE|Sta); 
	 
				crda = regr(ctlr, Crda0); 
				crda |= regr(ctlr, Crda1)<<8; 
				if(crda != to) 
					panic("crda write %d to %d\n", crda, to); 
	 
				break; 
			} 
1993/0212    
		} 
	} 
1997/0327    
	else{ 
		regw(ctlr, Rsar0, to & 0xFF); 
		regw(ctlr, Rsar1, (to>>8) & 0xFF); 
		regw(ctlr, Rbcr0, len & 0xFF); 
		regw(ctlr, Rbcr1, (len>>8) & 0xFF); 
		regw(ctlr, Cr, Page0|RdWRITE|Sta); 
	} 
1993/0212    
 
1992/1222    
	/* 
1997/0327    
	 * Pump the data into the I/O port 
	 * then wait for the remote DMA to finish. 
1992/1222    
	 */ 
1997/0327    
	rdwrite(ctlr, from, len); 
	for(timo = 10000; (regr(ctlr, Isr) & Rdc) == 0 && timo; timo--) 
			; 
1992/1222    
 
1997/0327    
	regw(ctlr, Isr, Rdc); 
	regw(ctlr, Cr, cr); 
1992/1222    
 
	return (void*)to; 
} 
 
1997/0327    
static void 
ringinit(Dp8390* ctlr) 
{ 
	regw(ctlr, Pstart, ctlr->pstart); 
	regw(ctlr, Pstop, ctlr->pstop); 
	regw(ctlr, Bnry, ctlr->pstop-1); 
 
	regw(ctlr, Cr, Page1|RdABORT|Stp); 
	regw(ctlr, Curr, ctlr->pstart); 
	regw(ctlr, Cr, Page0|RdABORT|Stp); 
 
	ctlr->nxtpkt = ctlr->pstart; 
} 
 
1993/0212    
static uchar 
1997/0327    
getcurr(Dp8390* ctlr) 
1993/0212    
{ 
	uchar cr, curr; 
 
1997/0327    
	cr = regr(ctlr, Cr) & ~Txp; 
	regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr)); 
	curr = regr(ctlr, Curr); 
	regw(ctlr, Cr, cr); 
 
1993/0212    
	return curr; 
} 
 
1993/0213    
static void 
1997/0327    
receive(Ether* ether) 
1993/0213    
{ 
1997/0327    
	Dp8390 *ctlr; 
	uchar curr, *p; 
1992/1222    
	Hdr hdr; 
1997/0327    
	ulong count, data, len; 
	Block *bp; 
1992/1222    
 
1997/0327    
	ctlr = ether->ctlr; 
	for(curr = getcurr(ctlr); ctlr->nxtpkt != curr; curr = getcurr(ctlr)){ 
		data = ctlr->nxtpkt*Dp8390BufSz; 
		if(ctlr->ram) 
1993/1118    
			memmove(&hdr, (void*)(ether->mem+data), sizeof(Hdr)); 
		else 
1997/0327    
			_dp8390read(ctlr, &hdr, data, sizeof(Hdr)); 
1992/1222    
 
		/* 
1993/0212    
		 * Don't believe the upper byte count, work it 
		 * out from the software next-page pointer and 
		 * the current next-page pointer. 
1992/1222    
		 */ 
1997/0327    
		if(hdr.next > ctlr->nxtpkt) 
			len = hdr.next - ctlr->nxtpkt - 1; 
1993/0212    
		else 
1997/0327    
			len = (ctlr->pstop-ctlr->nxtpkt) + (hdr.next-ctlr->pstart) - 1; 
1993/0212    
		if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr))) 
1997/0327    
			len--; 
1993/0212    
 
1997/0327    
		len = ((len<<8)|hdr.len0)-4; 
1993/0212    
 
		/* 
		 * Chip is badly scrogged, reinitialise the ring. 
		 */ 
1997/0327    
		if(hdr.next < ctlr->pstart || hdr.next >= ctlr->pstop 
1993/0212    
		  || len < 60 || len > sizeof(Etherpkt)){ 
1998/0825    
			print("dp8390: H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%lud\n", 
1993/0212    
				hdr.status, hdr.next, hdr.len0, hdr.len1, len); 
1997/0327    
			regw(ctlr, Cr, Page0|RdABORT|Stp); 
			ringinit(ctlr); 
			regw(ctlr, Cr, Page0|RdABORT|Sta); 
 
1992/1222    
			return; 
		} 
 
1993/0212    
		/* 
1993/1116    
		 * If it's a good packet read it in to the software buffer. 
1997/0327    
		 * If the packet wraps round the hardware ring, read it in 
		 * two pieces. 
1993/0212    
		 */ 
1997/0327    
		if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && (bp = iallocb(len))){ 
			p = bp->rp; 
			bp->wp = p+len; 
1992/1222    
			data += sizeof(Hdr); 
1993/0212    
 
1997/0327    
			if((data+len) >= ctlr->pstop*Dp8390BufSz){ 
				count = ctlr->pstop*Dp8390BufSz - data; 
				if(ctlr->ram) 
					memmove(p, (void*)(ether->mem+data), count); 
1993/1118    
				else 
1997/0327    
					_dp8390read(ctlr, p, data, count); 
				p += count; 
				data = ctlr->pstart*Dp8390BufSz; 
				len -= count; 
1992/1222    
			} 
1997/0327    
			if(len){ 
				if(ctlr->ram) 
					memmove(p, (void*)(ether->mem+data), len); 
1993/1118    
				else 
1997/0327    
					_dp8390read(ctlr, p, data, len); 
1993/1118    
			} 
1993/0212    
 
1993/1116    
			/* 
			 * Copy the packet to whoever wants it. 
			 */ 
1997/0327    
			etheriq(ether, bp, 1); 
1992/1222    
		} 
 
1993/0212    
		/* 
1993/1118    
		 * Finished with this packet, update the 
1993/0212    
		 * hardware and software ring pointers. 
		 */ 
1997/0327    
		ctlr->nxtpkt = hdr.next; 
1993/0212    
 
		hdr.next--; 
1997/0327    
		if(hdr.next < ctlr->pstart) 
			hdr.next = ctlr->pstop-1; 
		regw(ctlr, Bnry, hdr.next); 
1992/1222    
	} 
} 
 
1997/0327    
static void 
txstart(Ether* ether) 
1992/1222    
{ 
1997/0327    
	int len; 
	Dp8390 *ctlr; 
	Block *bp; 
	uchar minpkt[ETHERMINTU], *rp; 
1993/0212    
 
1997/0327    
	ctlr = ether->ctlr; 
1993/0213    
 
1993/1120    
	/* 
1997/0327    
	 * This routine is called both from the top level and from interrupt 
	 * level and expects to be called with ctlr already locked. 
1993/1120    
	 */ 
1997/0327    
	if(ctlr->txbusy) 
		return; 
	bp = qget(ether->oq); 
	if(bp == nil) 
		return; 
1993/1118    
 
1993/1120    
	/* 
1997/0327    
	 * Make sure the packet is of minimum length; 
	 * copy it to the card's memory by the appropriate means; 
	 * start the transmission. 
1993/1120    
	 */ 
1997/0327    
	len = BLEN(bp); 
	rp = bp->rp; 
1993/1120    
	if(len < ETHERMINTU){ 
1997/0327    
		rp = minpkt; 
		memmove(rp, bp->rp, len); 
		memset(rp+len, 0, ETHERMINTU-len); 
1993/1120    
		len = ETHERMINTU; 
	} 
 
1997/0327    
	if(ctlr->ram) 
		memmove((void*)(ether->mem+ctlr->tstart*Dp8390BufSz), rp, len); 
	else 
		dp8390write(ctlr, ctlr->tstart*Dp8390BufSz, rp, len); 
	freeb(bp); 
1993/1120    
 
1997/0327    
	regw(ctlr, Tbcr0, len & 0xFF); 
	regw(ctlr, Tbcr1, (len>>8) & 0xFF); 
	regw(ctlr, Cr, Page0|RdABORT|Txp|Sta); 
1993/1118    
 
1997/0327    
	ether->outpackets++; 
	ctlr->txbusy = 1; 
1993/0212    
} 
 
1993/1116    
static void 
1997/0327    
transmit(Ether* ether) 
{ 
	Dp8390 *ctlr; 
 
	ctlr = ether->ctlr; 
 
	ilock(ctlr); 
	txstart(ether); 
	iunlock(ctlr); 
} 
 
static void 
1993/1116    
overflow(Ether *ether) 
1993/0212    
{ 
1997/0327    
	Dp8390 *ctlr; 
1993/0212    
	uchar txp; 
	int resend; 
 
1997/0327    
	ctlr = ether->ctlr; 
1993/1118    
 
1993/0212    
	/* 
	 * The following procedure is taken from the DP8390[12D] datasheet, 
	 * it seems pretty adamant that this is what has to be done. 
	 */ 
1997/0327    
	txp = regr(ctlr, Cr) & Txp; 
	regw(ctlr, Cr, Page0|RdABORT|Stp); 
1993/0212    
	delay(2); 
1997/0327    
	regw(ctlr, Rbcr0, 0); 
	regw(ctlr, Rbcr1, 0); 
1993/0212    
 
	resend = 0; 
1997/0327    
	if(txp && (regr(ctlr, Isr) & (Txe|Ptx)) == 0) 
1993/0212    
		resend = 1; 
 
1997/0327    
	regw(ctlr, Tcr, LpbkNIC); 
	regw(ctlr, Cr, Page0|RdABORT|Sta); 
1993/1118    
	receive(ether); 
1997/0327    
	regw(ctlr, Isr, Ovw); 
2000/0604    
	regw(ctlr, Tcr, LpbkNORMAL); 
1993/0212    
 
	if(resend) 
1997/0327    
		regw(ctlr, Cr, Page0|RdABORT|Txp|Sta); 
1993/0212    
} 
 
1993/1116    
static void 
1997/0327    
interrupt(Ureg*, void* arg) 
1993/0212    
{ 
1993/1124    
	Ether *ether; 
1997/0327    
	Dp8390 *ctlr; 
1993/0212    
	uchar isr, r; 
1992/1222    
 
1993/1124    
	ether = arg; 
1997/0327    
	ctlr = ether->ctlr; 
1993/1118    
 
1992/1222    
	/* 
	 * While there is something of interest, 
	 * clear all the interrupts and process. 
	 */ 
2000/0604    
	ilock(ctlr); 
1997/0327    
	regw(ctlr, Imr, 0x00); 
	while(isr = (regr(ctlr, Isr) & (Cnt|Ovw|Txe|Rxe|Ptx|Prx))){ 
1992/1222    
		if(isr & Ovw){ 
1993/1116    
			overflow(ether); 
1997/0327    
			regw(ctlr, Isr, Ovw); 
1993/1116    
			ether->overflows++; 
1992/1222    
		} 
 
		/* 
1997/0327    
		 * Packets have been received. 
		 * Take a spin round the ring. 
1992/1222    
		 */ 
		if(isr & (Rxe|Prx)){ 
1993/1116    
			receive(ether); 
1997/0327    
			regw(ctlr, Isr, Rxe|Prx); 
1992/1222    
		} 
 
		/* 
		 * A packet completed transmission, successfully or 
		 * not. Start transmission on the next buffered packet, 
		 * and wake the output routine. 
		 */ 
		if(isr & (Txe|Ptx)){ 
1997/0327    
			r = regr(ctlr, Tsr); 
			if((isr & Txe) && (r & (Cdh|Fu|Crs|Abt))){ 
				print("dp8390: Tsr#%2.2ux|", r); 
1993/1116    
				ether->oerrs++; 
1993/0212    
			} 
 
1997/0327    
			regw(ctlr, Isr, Txe|Ptx); 
1993/0212    
 
			if(isr & Ptx) 
1993/1116    
				ether->outpackets++; 
1997/0327    
			ctlr->txbusy = 0; 
			txstart(ether); 
1992/1222    
		} 
1993/0212    
 
		if(isr & Cnt){ 
1997/0327    
			ether->frames += regr(ctlr, Cntr0); 
			ether->crcs += regr(ctlr, Cntr1); 
			ether->buffs += regr(ctlr, Cntr2); 
			regw(ctlr, Isr, Cnt); 
1993/0212    
		} 
1992/1222    
	} 
1997/0327    
	regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx); 
2000/0604    
	iunlock(ctlr); 
1993/1116    
} 
 
1997/0418    
static uchar allmar[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 
 
1993/1116    
static void 
1997/0418    
setfilter(Ether *ether, Dp8390 *ctlr) 
{ 
	uchar r, cr; 
	int i; 
	uchar *mar; 
 
	r = Ab; 
	mar = 0; 
	if(ether->prom){ 
		r |= Pro|Am; 
		mar = allmar; 
	} else if(ether->nmaddr){ 
		r |= Am; 
		mar = ctlr->mar; 
	} 
	if(mar){ 
		cr = regr(ctlr, Cr) & ~Txp; 
		regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr)); 
		for(i = 0; i < 8; i++) 
			regw(ctlr, Mar0+i, *(mar++)); 
		regw(ctlr, Cr, cr); 
	} 
	regw(ctlr, Rcr, r); 
} 
 
static void 
1998/0319    
promiscuous(void *arg, int ) 
1993/1116    
{ 
1997/0327    
	Ether *ether; 
	Dp8390 *ctlr; 
1993/1117    
 
1997/0327    
	ether = arg; 
	ctlr = ether->ctlr; 
 
	ilock(ctlr); 
1997/0418    
	setfilter(ether, ctlr); 
1997/0327    
	iunlock(ctlr); 
1993/1116    
} 
 
1993/1118    
static void 
1997/0418    
setbit(Dp8390 *ctlr, int bit, int on) 
{ 
	int i, h; 
 
	i = bit/8; 
	h = bit%8; 
	if(on){ 
		if(++(ctlr->mref[bit]) == 1) 
			ctlr->mar[i] |= 1<<h; 
	} else { 
		if(--(ctlr->mref[bit]) <= 0){ 
			ctlr->mref[bit] = 0; 
			ctlr->mar[i] &= ~(1<<h); 
		} 
	} 
} 
 
static uchar reverse[64]; 
 
static void 
1997/0415    
multicast(void* arg, uchar *addr, int on) 
{ 
	Ether *ether; 
	Dp8390 *ctlr; 
	int i; 
	ulong h; 
 
	ether = arg; 
	ctlr = ether->ctlr; 
1997/0418    
	if(reverse[1] == 0){ 
		for(i = 0; i < 64; i++) 
			reverse[i] = ((i&1)<<5) | ((i&2)<<3) | ((i&4)<<1) 
					| ((i&8)>>1) | ((i&16)>>3) | ((i&32)>>5); 
	} 
1997/0415    
 
	/* 
	 *  change filter bits 
	 */ 
	h = ethercrc(addr, 6); 
	ilock(ctlr); 
1997/0418    
	setbit(ctlr, reverse[h&0x3f], on); 
	setfilter(ether, ctlr); 
1997/0415    
	iunlock(ctlr); 
} 
 
static void 
1997/0327    
attach(Ether* ether) 
1993/1116    
{ 
1997/0327    
	Dp8390 *ctlr; 
	uchar r; 
1993/1117    
 
1997/0327    
	ctlr = ether->ctlr; 
 
1993/1116    
	/* 
	 * Enable the chip for transmit/receive. 
	 * The init routine leaves the chip in monitor 
	 * mode. Clear the missed-packet counter, it 
	 * increments while in monitor mode. 
2000/0604    
	 * Sometimes there's an interrupt pending at this 
	 * point but there's nothing in the Isr, so 
	 * any pending interrupts are cleared and the 
	 * mask of acceptable interrupts is enabled here. 
1993/1116    
	 */ 
1997/0327    
	r = Ab; 
1995/0801    
	if(ether->prom) 
1997/0327    
		r |= Pro; 
1997/0415    
	if(ether->nmaddr) 
		r |= Am; 
1997/0327    
	ilock(ctlr); 
2000/0604    
	regw(ctlr, Isr, 0xFF); 
	regw(ctlr, Imr, Cnt|Ovw|Txe|Rxe|Ptx|Prx); 
1997/0327    
	regw(ctlr, Rcr, r); 
	r = regr(ctlr, Cntr2); 
2000/0604    
	regw(ctlr, Tcr, LpbkNORMAL); 
1997/0327    
	iunlock(ctlr); 
	USED(r); 
1993/1116    
} 
 
1997/0327    
static void 
disable(Dp8390* ctlr) 
{ 
	int timo; 
 
	/* 
	 * Stop the chip. Set the Stp bit and wait for the chip 
	 * to finish whatever was on its tiny mind before it sets 
	 * the Rst bit. 
	 * The timeout is needed because there may not be a real 
	 * chip there if this is called when probing for a device 
	 * at boot. 
	 */ 
	regw(ctlr, Cr, Page0|RdABORT|Stp); 
	regw(ctlr, Rbcr0, 0); 
	regw(ctlr, Rbcr1, 0); 
	for(timo = 10000; (regr(ctlr, Isr) & Rst) == 0 && timo; timo--) 
			; 
} 
 
1993/1118    
int 
1997/0327    
dp8390reset(Ether* ether) 
1993/1116    
{ 
1997/0327    
	Dp8390 *ctlr; 
1993/1116    
 
1997/0327    
	ctlr = ether->ctlr; 
1993/1118    
 
1993/1116    
	/* 
	 * This is the initialisation procedure described 
	 * as 'mandatory' in the datasheet, with references 
1997/0327    
	 * to the 3C503 technical reference manual. 
1993/1116    
	 */  
1997/0327    
	disable(ctlr); 
	if(ctlr->width != 1) 
		regw(ctlr, Dcr, Ft4WORD|Ls|Wts); 
1993/1116    
	else 
1997/0327    
		regw(ctlr, Dcr, Ft4WORD|Ls); 
1993/1116    
 
1997/0327    
	regw(ctlr, Rbcr0, 0); 
	regw(ctlr, Rbcr1, 0); 
1993/1116    
 
2000/0604    
	regw(ctlr, Tcr, LpbkNIC); 
1997/0327    
	regw(ctlr, Rcr, Mon); 
1993/1116    
 
	/* 
	 * Init the ring hardware and software ring pointers. 
1997/0327    
	 * Can't initialise ethernet address as it may not be 
	 * known yet. 
1993/1116    
	 */ 
1997/0327    
	ringinit(ctlr); 
	regw(ctlr, Tpsr, ctlr->tstart); 
1993/1116    
 
2000/0604    
	/* 
	 * Clear any pending interrupts and mask then all off. 
	 */ 
1997/0327    
	regw(ctlr, Isr, 0xFF); 
2000/0604    
	regw(ctlr, Imr, 0); 
1993/1116    
 
	/* 
	 * Leave the chip initialised, 
	 * but in monitor mode. 
	 */ 
1997/0327    
	regw(ctlr, Cr, Page0|RdABORT|Sta); 
1993/1116    
 
	/* 
	 * Set up the software configuration. 
	 */ 
	ether->attach = attach; 
1997/0327    
	ether->transmit = transmit; 
1993/1116    
	ether->interrupt = interrupt; 
1997/0327    
	ether->ifstat = 0; 
1993/1116    
 
	ether->promiscuous = promiscuous; 
1997/0415    
	ether->multicast = multicast; 
1993/1116    
	ether->arg = ether; 
 
	return 0; 
1992/1222    
} 


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