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

pc/ether82557.c (diff list | history)

1996/0418/sys/src/9/pc/ether82557.c:108,1151996/0419/sys/src/9/pc/ether82557.c:108,113 (short | long)
1996/0418    
	ushort	size; 
 
	Etherpkt; 
                 
	Block*	bp; 
} Rfd; 
 
enum {					/* field */ 
1996/0418/sys/src/9/pc/ether82557.c:437,4441996/0419/sys/src/9/pc/ether82557.c:435,440
1996/0418    
		rfd->rbd = NullPointer; 
		rfd->count = 0; 
		rfd->size = sizeof(Etherpkt); 
                 
		rfd->bp = bp; 
	} 
	((Rfd*)ctlr->rfd[Nrfd-1]->rp)->link = PADDR(ctlr->rfd[0]->rp); 
 
1996/0419/sys/src/9/pc/ether82557.c:6,111996/0423/sys/src/9/pc/ether82557.c:6,13 (short | long)
1996/0418    
 *	the PCI scanning code could be made common to other adapters; 
 *	PCI code needs rewritten to handle byte, word, dword accesses 
 *	  and using the devno as a bus+dev+function triplet; 
1996/0423    
 *	tidy/fix locking; 
 *	optionally use memory-mapped registers; 
1996/0418    
 *	stats. 
 */ 
#include "u.h" 
1996/0419/sys/src/9/pc/ether82557.c:30,361996/0423/sys/src/9/pc/ether82557.c:32,38
1996/0418    
	Ack		= 0x01,		/* byte */ 
	Command		= 0x02,		/* byte or word (word includes Interrupt) */ 
	Interrupt	= 0x03,		/* byte */ 
	Pointer		= 0x04,		/* dword */ 
1996/0423    
	General		= 0x04,		/* dword */ 
1996/0418    
	Port		= 0x08,		/* dword */ 
	Fcr		= 0x0C,		/* Flash control register */ 
	Ecr		= 0x0E,		/* EEPROM control register */ 
1996/0419/sys/src/9/pc/ether82557.c:156,1621996/0423/sys/src/9/pc/ether82557.c:158,164
1996/0418    
	CbC		= 0x00008000,	/* execution Complete */ 
 
	CbNOP		= 0x00000000, 
	CbIAS		= 0x00010000,	/* Indvidual Address Setup */ 
1996/0423    
	CbIAS		= 0x00010000,	/* Individual Address Setup */ 
1996/0418    
	CbConfigure	= 0x00020000, 
	CbMAS		= 0x00030000,	/* Multicast Address Setup */ 
	CbTransmit	= 0x00040000, 
1996/0419/sys/src/9/pc/ether82557.c:237,2431996/0423/sys/src/9/pc/ether82557.c:239,245
1996/0418    
	} 
	ctlr->cbqbusy = 1; 
 
	csr32w(ctlr, Pointer, PADDR(ctlr->cbqhead->rp)); 
1996/0423    
	csr32w(ctlr, General, PADDR(ctlr->cbqhead->rp)); 
1996/0418    
	while(csr8r(ctlr, Command)) 
		; 
	csr8w(ctlr, Command, CUstart); 
1996/0419/sys/src/9/pc/ether82557.c:278,2841996/0423/sys/src/9/pc/ether82557.c:280,286
1996/0418    
	ilock(&ctlr->rlock); 
	status = csr16r(ctlr, Status); 
	if((status & RUstatus) == RUidle){ 
		csr32w(ctlr, Pointer, PADDR(ctlr->rfd[ctlr->rfdx]->rp)); 
1996/0423    
		csr32w(ctlr, General, PADDR(ctlr->rfd[ctlr->rfdx]->rp)); 
1996/0418    
		while(csr8r(ctlr, Command)) 
			; 
		csr8w(ctlr, Command, RUstart); 
1996/0419/sys/src/9/pc/ether82557.c:617,6321996/0423/sys/src/9/pc/ether82557.c:619,634
1996/0418    
	if((x & 0x05) != 0x05) 
		print("PCI command = %uX\n", x); 
 
	csr32w(ctlr, Pointer, 0); 
	csr8w(ctlr, Command, LoadRUB); 
1996/0423    
	csr32w(ctlr, General, 0); 
1996/0418    
	while(csr8r(ctlr, Command)) 
		; 
	csr8w(ctlr, Command, LoadCUB); 
1996/0423    
	csr8w(ctlr, Command, LoadRUB); 
1996/0418    
	while(csr8r(ctlr, Command)) 
		; 
1996/0423    
	csr8w(ctlr, Command, LoadCUB); 
1996/0418    
 
	/* 
	 * Initialise the action and receive frame areas. 
1996/0423    
	 * Initialise the receive frame and configuration areas. 
1996/0418    
	 */ 
	ctlrinit(ctlr); 
 
1996/0423/sys/src/9/pc/ether82557.c:214,2201996/0601/sys/src/9/pc/ether82557.c:214,220 (short | long)
1996/0418    
	0x60,				/* inter-frame spacing */ 
	0x00,	 
	0xF2,	 
	0x48,				/* promiscuous mode off */ 
1996/0601    
	0xC8,				/* promiscuous mode off */ 
1996/0418    
	0x00,	 
	0x40,	 
	0xF2,				/* transmit padding enable */ 
1996/0423/sys/src/9/pc/ether82557.c:652,6581996/0601/sys/src/9/pc/ether82557.c:652,659
1996/0418    
		x = dp83840r(ctlr, i, 0x1B); 
		if((x & 0x0200) == 0){ 
			ctlr->configdata[8] = 1; 
			ctlr->configdata[15] |= 0x80; 
1996/0601    
			ctlr->configdata[15] &= ~0x80; 
			ether->mbps = 100; 
1996/0418    
		} 
		break; 
	} 
1996/0601/sys/src/9/pc/ether82557.c:6,141996/0607/sys/src/9/pc/ether82557.c:6,12 (short | long)
1996/0418    
 *	the PCI scanning code could be made common to other adapters; 
 *	PCI code needs rewritten to handle byte, word, dword accesses 
 *	  and using the devno as a bus+dev+function triplet; 
1996/0423    
 *	tidy/fix locking; 
 *	optionally use memory-mapped registers; 
1996/0418    
 *	stats. 
1996/0607    
 *	optionally use memory-mapped registers. 
1996/0418    
 */ 
#include "u.h" 
#include "../port/lib.h" 
1996/0601/sys/src/9/pc/ether82557.c:141,1471996/0607/sys/src/9/pc/ether82557.c:139,145
1996/0418    
typedef struct Cb { 
	int	command; 
	ulong	link; 
	uchar	data[24];	/* CbIAS + CbConfigure */ 
1996/0607    
	uchar	data[24];		/* CbIAS + CbConfigure */ 
1996/0418    
} Cb; 
 
typedef struct TxCB { 
1996/0601/sys/src/9/pc/ether82557.c:185,2001996/0607/sys/src/9/pc/ether82557.c:183,200
1996/0418    
 
	uchar	configdata[24]; 
 
	Lock	rlock; 
1996/0607    
	Lock	rlock;			/* registers */ 
1996/0418    
 
	Block*	rfd[Nrfd]; 
1996/0607    
	Block*	rfd[Nrfd];		/* receive side */ 
1996/0418    
	int	rfdl; 
	int	rfdx; 
 
	Lock	cbqlock; 
	Block*	cbqhead; 
1996/0607    
	Block*	cbqhead;		/* transmit side */ 
1996/0418    
	Block*	cbqtail; 
	int	cbqbusy; 
1996/0607    
 
	Lock	dlock;		/* dump statistical counters */ 
	ulong	dump[17]; 
1996/0418    
} Ctlr; 
 
static uchar configdata[24] = { 
1996/0601/sys/src/9/pc/ether82557.c:239,2471996/0607/sys/src/9/pc/ether82557.c:239,247
1996/0418    
	} 
	ctlr->cbqbusy = 1; 
 
1996/0423    
	csr32w(ctlr, General, PADDR(ctlr->cbqhead->rp)); 
1996/0418    
	while(csr8r(ctlr, Command)) 
		; 
1996/0607    
	csr32w(ctlr, General, PADDR(ctlr->cbqhead->rp)); 
1996/0418    
	csr8w(ctlr, Command, CUstart); 
} 
 
1996/0601/sys/src/9/pc/ether82557.c:250,2561996/0607/sys/src/9/pc/ether82557.c:250,255
1996/0418    
{ 
	Cb *cb; 
 
	ilock(&ctlr->cbqlock); 
	cb = (Cb*)bp->rp; 
	cb->command |= CbEL; 
 
1996/0601/sys/src/9/pc/ether82557.c:266,2731996/0607/sys/src/9/pc/ether82557.c:265,270
1996/0418    
 
	if(ctlr->cbqbusy == 0) 
		custart(ctlr); 
                 
	iunlock(&ctlr->cbqlock); 
} 
 
static void 
1996/0601/sys/src/9/pc/ether82557.c:280,3021996/0607/sys/src/9/pc/ether82557.c:277,296
1996/0418    
	ilock(&ctlr->rlock); 
	status = csr16r(ctlr, Status); 
	if((status & RUstatus) == RUidle){ 
1996/0423    
		csr32w(ctlr, General, PADDR(ctlr->rfd[ctlr->rfdx]->rp)); 
1996/0418    
		while(csr8r(ctlr, Command)) 
			; 
1996/0607    
		csr32w(ctlr, General, PADDR(ctlr->rfd[ctlr->rfdx]->rp)); 
1996/0418    
		csr8w(ctlr, Command, RUstart); 
	} 
	iunlock(&ctlr->rlock); 
} 
 
static void 
configure(void* arg, int promiscuous) 
1996/0607    
static Block* 
configure(Ctlr* ctlr, int promiscuous) 
1996/0418    
{ 
	Ctlr *ctlr; 
	Block *bp; 
	Cb *cb; 
 
	ctlr = ((Ether*)arg)->ctlr; 
                 
	bp = allocb(sizeof(Cb)); 
	cb = (Cb*)bp->rp; 
	bp->wp += sizeof(Cb); 
1996/0601/sys/src/9/pc/ether82557.c:306,3171996/0607/sys/src/9/pc/ether82557.c:300,383
1996/0418    
	memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata)); 
	if(promiscuous) 
		cb->data[15] |= 0x01; 
1996/0607    
 
	return bp; 
} 
 
static void 
promiscuous(void* arg, int on) 
{ 
	Ctlr *ctlr; 
	Block *bp; 
 
	ctlr = ((Ether*)arg)->ctlr; 
	bp = configure(ctlr, on); 
 
	ilock(&ctlr->rlock); 
1996/0418    
	action(ctlr, bp); 
1996/0607    
	iunlock(&ctlr->rlock); 
1996/0418    
} 
 
static long 
1996/0607    
ifstat(Ether* ether, void* a, long n, ulong offset) 
{ 
	Ctlr *ctlr; 
	char buf[512]; 
	int len; 
 
	ctlr = ether->ctlr; 
	lock(&ctlr->dlock); 
	ctlr->dump[16] = 0; 
 
	ilock(&ctlr->rlock); 
	while(csr8r(ctlr, Command)) 
		; 
	csr8w(ctlr, Command, DumpSC); 
	iunlock(&ctlr->rlock); 
 
	/* 
	 * Wait for completion status, should be 0xA005. 
	 */ 
	while(ctlr->dump[16] == 0) 
		; 
 
	ether->oerrs = ctlr->dump[1]+ctlr->dump[2]+ctlr->dump[3]; 
	ether->crcs = ctlr->dump[10]; 
	ether->frames = ctlr->dump[11]; 
	ether->buffs = ctlr->dump[12]+ctlr->dump[15]; 
	ether->overflows = ctlr->dump[13]; 
 
	if(n == 0){ 
		unlock(&ctlr->dlock); 
		return 0; 
	} 
 
	len = sprint(buf, "transmit good frames: %ld\n", ctlr->dump[0]); 
	len += sprint(buf+len, "transmit maximum collisions errors: %ld\n", ctlr->dump[1]); 
	len += sprint(buf+len, "transmit late collisions errors: %ld\n", ctlr->dump[2]); 
	len += sprint(buf+len, "transmit underrun errors: %ld\n", ctlr->dump[3]); 
	len += sprint(buf+len, "transmit lost carrier sense: %ld\n", ctlr->dump[4]); 
	len += sprint(buf+len, "transmit deferred: %ld\n", ctlr->dump[5]); 
	len += sprint(buf+len, "transmit single collisions: %ld\n", ctlr->dump[6]); 
	len += sprint(buf+len, "transmit multiple collisions: %ld\n", ctlr->dump[7]); 
	len += sprint(buf+len, "transmit total collisions: %ld\n", ctlr->dump[8]); 
	len += sprint(buf+len, "receive good frames: %ld\n", ctlr->dump[9]); 
	len += sprint(buf+len, "receive CRC errors: %ld\n", ctlr->dump[10]); 
	len += sprint(buf+len, "receive alignment errors: %ld\n", ctlr->dump[11]); 
	len += sprint(buf+len, "receive resource errors: %ld\n", ctlr->dump[12]); 
	len += sprint(buf+len, "receive overrun errors: %ld\n", ctlr->dump[13]); 
	len += sprint(buf+len, "receive collision detect errors: %ld\n", ctlr->dump[14]); 
	sprint(buf+len, "receive short frame errors: %ld\n", ctlr->dump[15]); 
 
	unlock(&ctlr->dlock); 
 
	return readstr(offset, a, n, buf); 
} 
 
static long 
1996/0418    
write(Ether* ether, void* buf, long n) 
{ 
1996/0607    
	Ctlr *ctlr; 
1996/0418    
	Block *bp; 
	TxCB *txcb; 
 
1996/0601/sys/src/9/pc/ether82557.c:330,3361996/0607/sys/src/9/pc/ether82557.c:396,405
1996/0418    
	memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); 
	bp->wp += n; 
 
	action(ether->ctlr, bp); 
1996/0607    
	ctlr = ether->ctlr; 
	ilock(&ctlr->rlock); 
	action(ctlr, bp); 
	iunlock(&ctlr->rlock); 
1996/0418    
 
	ether->outpackets++; 
 
1996/0601/sys/src/9/pc/ether82557.c:349,3671996/0607/sys/src/9/pc/ether82557.c:418,440
1996/0418    
	ether = arg; 
	ctlr = ether->ctlr; 
 
1996/0607    
	ilock(&ctlr->rlock); 
1996/0418    
	for(;;){ 
		status = csr16r(ctlr, Status); 
		csr8w(ctlr, Ack, (status>>8) & 0xFF); 
 
		if((status & (StatCX|StatFR|StatCNA|StatRNR)) == 0) 
			return; 
1996/0607    
		if((status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) == 0) 
			break; 
1996/0418    
 
		if(status & StatFR){ 
			bp = ctlr->rfd[ctlr->rfdx]; 
			rfd = (Rfd*)bp->rp; 
			while(rfd->field & RfdC){ 
				etherrloop(ether, rfd, rfd->count & 0x3FFF); 
				ether->inpackets++; 
1996/0607    
				if(rfd->field & RfdOK){ 
					etherrloop(ether, rfd, rfd->count & 0x3FFF); 
					ether->inpackets++; 
				} 
else print("%s#%d: rfd->field %uX\n", ctlr->type,  ctlr->ctlrno, rfd->field); 
1996/0418    
 
				/* 
				 * Reinitialise the frame for reception and bump 
1996/0601/sys/src/9/pc/ether82557.c:390,4011996/0607/sys/src/9/pc/ether82557.c:463,474
1996/0418    
			while(csr8r(ctlr, Command)) 
				; 
			csr8w(ctlr, Command, RUresume); 
1996/0607    
print("%s#%d: status %uX\n", ctlr->type,  ctlr->ctlrno, status); 
1996/0418    
 
			status &= ~StatRNR; 
		} 
 
		if(status & StatCNA){ 
			lock(&ctlr->cbqlock); 
			while(bp = ctlr->cbqhead){ 
				if((((Cb*)bp->rp)->command & CbC) == 0) 
					break; 
1996/0601/sys/src/9/pc/ether82557.c:403,4091996/0607/sys/src/9/pc/ether82557.c:476,481
1996/0418    
				freeb(bp); 
			} 
			custart(ctlr); 
			unlock(&ctlr->cbqlock); 
 
			status &= ~StatCNA; 
		} 
1996/0601/sys/src/9/pc/ether82557.c:411,4161996/0607/sys/src/9/pc/ether82557.c:483,489
1996/0418    
		if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) 
			panic("%s#%d: status %uX\n", ctlr->type,  ctlr->ctlrno, status); 
	} 
1996/0607    
	iunlock(&ctlr->rlock); 
1996/0418    
} 
 
static void 
1996/0601/sys/src/9/pc/ether82557.c:612,6321996/0607/sys/src/9/pc/ether82557.c:685,710
1996/0418    
	ctlr->type = ether->type; 
	ctlr->port = port; 
 
1996/0607    
	ilock(&ctlr->rlock); 
 
1996/0418    
	csr32w(ctlr, Port, 0); 
	delay(1); 
 
	pcicfgr(0, pcidevno, 0, 0x04, &x, 4); 
	if((x & 0x05) != 0x05) 
		print("PCI command = %uX\n", x); 
                 
1996/0423    
	csr32w(ctlr, General, 0); 
1996/0418    
	while(csr8r(ctlr, Command)) 
		; 
1996/0607    
	csr32w(ctlr, General, 0); 
1996/0423    
	csr8w(ctlr, Command, LoadRUB); 
1996/0607    
 
1996/0418    
	while(csr8r(ctlr, Command)) 
		; 
1996/0423    
	csr8w(ctlr, Command, LoadCUB); 
1996/0418    
 
1996/0607    
	while(csr8r(ctlr, Command)) 
		; 
	csr32w(ctlr, General, PADDR(ctlr->dump)); 
	csr8w(ctlr, Command, LoadDCA); 
 
 
1996/0418    
	/* 
1996/0423    
	 * Initialise the receive frame and configuration areas. 
1996/0418    
	 */ 
1996/0601/sys/src/9/pc/ether82557.c:638,6451996/0607/sys/src/9/pc/ether82557.c:716,723
1996/0418    
	 * configuration. However, should check for the existence of the PHY 
	 * and, if found, check whether to use 82503 (serial) or MII (nibble) 
	 * mode. Verify the PHY is a National Semiconductor DP83840 by looking 
	 * at the Organizationally Unique Identifier (OUI) in registers 2 and 3 
	 * which should be 0x80017. 
1996/0607    
	 * at the Organizationally Unique Identifier (OUI) in registers 2 and 
	 * 3 which should be 0x80017. 
1996/0418    
	 */ 
	for(i = 1; i < 32; i++){ 
		if((x = dp83840r(ctlr, i, 2)) == 0xFFFF) 
1996/0601/sys/src/9/pc/ether82557.c:661,6671996/0607/sys/src/9/pc/ether82557.c:739,746
1996/0418    
	/* 
	 * Load the chip configuration 
	 */ 
	configure(ether, 0); 
1996/0607    
	bp = configure(ctlr, 0); 
	action(ctlr, bp); 
1996/0418    
 
	/* 
	 * Check if the adapter's station address is to be overridden. 
1996/0601/sys/src/9/pc/ether82557.c:686,6911996/0607/sys/src/9/pc/ether82557.c:765,772
1996/0418    
	memmove(cb->data, ether->ea, Eaddrlen); 
	action(ctlr, bp); 
 
1996/0607    
	iunlock(&ctlr->rlock); 
 
1996/0418    
	/* 
	 * Linkage to the generic ethernet driver. 
	 */ 
1996/0601/sys/src/9/pc/ether82557.c:693,7001996/0607/sys/src/9/pc/ether82557.c:774,782
1996/0418    
	ether->attach = attach; 
	ether->write = write; 
	ether->interrupt = interrupt; 
1996/0607    
	ether->ifstat = ifstat; 
1996/0418    
 
	ether->promiscuous = configure; 
1996/0607    
	ether->promiscuous = promiscuous; 
1996/0418    
	ether->arg = ether; 
 
	return 0; 
1996/0607/sys/src/9/pc/ether82557.c:434,4401996/0608/sys/src/9/pc/ether82557.c:434,439 (short | long)
1996/0607    
					etherrloop(ether, rfd, rfd->count & 0x3FFF); 
					ether->inpackets++; 
				} 
else print("%s#%d: rfd->field %uX\n", ctlr->type,  ctlr->ctlrno, rfd->field); 
1996/0418    
 
				/* 
				 * Reinitialise the frame for reception and bump 
1996/0607/sys/src/9/pc/ether82557.c:463,4691996/0608/sys/src/9/pc/ether82557.c:462,467
1996/0418    
			while(csr8r(ctlr, Command)) 
				; 
			csr8w(ctlr, Command, RUresume); 
1996/0607    
print("%s#%d: status %uX\n", ctlr->type,  ctlr->ctlrno, status); 
1996/0418    
 
			status &= ~StatRNR; 
		} 
1996/0608/sys/src/9/pc/ether82557.c:183,1891996/0622/sys/src/9/pc/ether82557.c:183,189 (short | long)
1996/0418    
 
	uchar	configdata[24]; 
 
1996/0607    
	Lock	rlock;			/* registers */ 
1996/0622    
	Lock	lock; 
1996/0418    
 
1996/0607    
	Block*	rfd[Nrfd];		/* receive side */ 
1996/0418    
	int	rfdl; 
1996/0608/sys/src/9/pc/ether82557.c:193,1991996/0622/sys/src/9/pc/ether82557.c:193,199
1996/0418    
	Block*	cbqtail; 
	int	cbqbusy; 
1996/0607    
 
	Lock	dlock;		/* dump statistical counters */ 
1996/0622    
	Lock	dlock;			/* dump statistical counters */ 
1996/0607    
	ulong	dump[17]; 
1996/0418    
} Ctlr; 
 
1996/0608/sys/src/9/pc/ether82557.c:274,2801996/0622/sys/src/9/pc/ether82557.c:274,280
1996/0418    
	Ctlr *ctlr; 
 
	ctlr = ether->ctlr; 
	ilock(&ctlr->rlock); 
1996/0622    
	ilock(&ctlr->lock); 
1996/0418    
	status = csr16r(ctlr, Status); 
	if((status & RUstatus) == RUidle){ 
		while(csr8r(ctlr, Command)) 
1996/0608/sys/src/9/pc/ether82557.c:282,2881996/0622/sys/src/9/pc/ether82557.c:282,288
1996/0607    
		csr32w(ctlr, General, PADDR(ctlr->rfd[ctlr->rfdx]->rp)); 
1996/0418    
		csr8w(ctlr, Command, RUstart); 
	} 
	iunlock(&ctlr->rlock); 
1996/0622    
	iunlock(&ctlr->lock); 
1996/0418    
} 
 
1996/0607    
static Block* 
1996/0608/sys/src/9/pc/ether82557.c:313,3211996/0622/sys/src/9/pc/ether82557.c:313,321
1996/0607    
	ctlr = ((Ether*)arg)->ctlr; 
	bp = configure(ctlr, on); 
 
	ilock(&ctlr->rlock); 
1996/0622    
	ilock(&ctlr->lock); 
1996/0418    
	action(ctlr, bp); 
1996/0607    
	iunlock(&ctlr->rlock); 
1996/0622    
	iunlock(&ctlr->lock); 
1996/0418    
} 
 
static long 
1996/0608/sys/src/9/pc/ether82557.c:329,3391996/0622/sys/src/9/pc/ether82557.c:329,339
1996/0607    
	lock(&ctlr->dlock); 
	ctlr->dump[16] = 0; 
 
	ilock(&ctlr->rlock); 
1996/0622    
	ilock(&ctlr->lock); 
1996/0607    
	while(csr8r(ctlr, Command)) 
		; 
	csr8w(ctlr, Command, DumpSC); 
	iunlock(&ctlr->rlock); 
1996/0622    
	iunlock(&ctlr->lock); 
1996/0607    
 
	/* 
	 * Wait for completion status, should be 0xA005. 
1996/0608/sys/src/9/pc/ether82557.c:397,4051996/0622/sys/src/9/pc/ether82557.c:397,405
1996/0418    
	bp->wp += n; 
 
1996/0607    
	ctlr = ether->ctlr; 
	ilock(&ctlr->rlock); 
1996/0622    
	ilock(&ctlr->lock); 
1996/0607    
	action(ctlr, bp); 
	iunlock(&ctlr->rlock); 
1996/0622    
	iunlock(&ctlr->lock); 
1996/0418    
 
	ether->outpackets++; 
 
1996/0608/sys/src/9/pc/ether82557.c:418,4241996/0622/sys/src/9/pc/ether82557.c:418,424
1996/0418    
	ether = arg; 
	ctlr = ether->ctlr; 
 
1996/0607    
	ilock(&ctlr->rlock); 
1996/0622    
	ilock(&ctlr->lock); 
1996/0418    
	for(;;){ 
		status = csr16r(ctlr, Status); 
		csr8w(ctlr, Ack, (status>>8) & 0xFF); 
1996/0608/sys/src/9/pc/ether82557.c:481,4871996/0622/sys/src/9/pc/ether82557.c:481,487
1996/0418    
		if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) 
			panic("%s#%d: status %uX\n", ctlr->type,  ctlr->ctlrno, status); 
	} 
1996/0607    
	iunlock(&ctlr->rlock); 
1996/0622    
	iunlock(&ctlr->lock); 
1996/0418    
} 
 
static void 
1996/0608/sys/src/9/pc/ether82557.c:600,6061996/0622/sys/src/9/pc/ether82557.c:600,606
1996/0418    
static Adapter *adapter; 
 
static int 
i82557(Ether* ether, int* pcidevno) 
1996/0622    
i82557pci(Ether* ether, int* pcidevno) 
1996/0418    
{ 
	PCIcfg pcicfg; 
	static int devno = 0; 
1996/0608/sys/src/9/pc/ether82557.c:666,6721996/0622/sys/src/9/pc/ether82557.c:666,672
1996/0418    
			break; 
		} 
	} 
	if(port == 0 && (port = i82557(ether, &pcidevno)) == 0) 
1996/0622    
	if(port == 0 && (port = i82557pci(ether, &pcidevno)) == 0) 
1996/0418    
		return -1; 
 
	/* 
1996/0608/sys/src/9/pc/ether82557.c:683,6891996/0622/sys/src/9/pc/ether82557.c:683,689
1996/0418    
	ctlr->type = ether->type; 
	ctlr->port = port; 
 
1996/0607    
	ilock(&ctlr->rlock); 
1996/0622    
	ilock(&ctlr->lock); 
1996/0607    
 
1996/0418    
	csr32w(ctlr, Port, 0); 
	delay(1); 
1996/0608/sys/src/9/pc/ether82557.c:763,7691996/0622/sys/src/9/pc/ether82557.c:763,769
1996/0418    
	memmove(cb->data, ether->ea, Eaddrlen); 
	action(ctlr, bp); 
 
1996/0607    
	iunlock(&ctlr->rlock); 
1996/0622    
	iunlock(&ctlr->lock); 
1996/0607    
 
1996/0418    
	/* 
	 * Linkage to the generic ethernet driver. 
1996/0622/sys/src/9/pc/ether82557.c:6,111996/0625/sys/src/9/pc/ether82557.c:6,12 (short | long)
1996/0418    
 *	the PCI scanning code could be made common to other adapters; 
 *	PCI code needs rewritten to handle byte, word, dword accesses 
 *	  and using the devno as a bus+dev+function triplet; 
1996/0625    
 *	auto-negotiation; 
1996/0607    
 *	optionally use memory-mapped registers. 
1996/0418    
 */ 
#include "u.h" 
1996/0622/sys/src/9/pc/ether82557.c:725,7351996/0625/sys/src/9/pc/ether82557.c:726,743
1996/0418    
		if(x != 0x80017) 
			continue; 
 
		x = dp83840r(ctlr, i, 0x1B); 
		if((x & 0x0200) == 0){ 
1996/0625    
		x = dp83840r(ctlr, i, 0x19); 
		if((x & 0x0040) == 0){ 
			ether->mbps = 100; 
1996/0418    
			ctlr->configdata[8] = 1; 
1996/0601    
			ctlr->configdata[15] &= ~0x80; 
			ether->mbps = 100; 
1996/0625    
		} 
		else{ 
			x = dp83840r(ctlr, i, 0x1B); 
			if((x & 0x0200) == 0){ 
				ctlr->configdata[8] = 1; 
				ctlr->configdata[15] &= ~0x80; 
			} 
1996/0418    
		} 
		break; 
	} 
1996/0625/sys/src/9/pc/ether82557.c:4,111997/0327/sys/src/9/pc/ether82557.c:4,9 (short | long)
1996/0418    
 * of smarts, unfortunately none of them are in the right place. 
 * To do: 
 *	the PCI scanning code could be made common to other adapters; 
 *	PCI code needs rewritten to handle byte, word, dword accesses 
 *	  and using the devno as a bus+dev+function triplet; 
1996/0625    
 *	auto-negotiation; 
1996/0607    
 *	optionally use memory-mapped registers. 
1996/0418    
 */ 
1996/0625/sys/src/9/pc/ether82557.c:108,1141997/0327/sys/src/9/pc/ether82557.c:106,112
1996/0418    
	ushort	count; 
	ushort	size; 
 
	Etherpkt; 
1997/0327    
	uchar	data[sizeof(Etherpkt)]; 
1996/0418    
} Rfd; 
 
enum {					/* field */ 
1996/0625/sys/src/9/pc/ether82557.c:137,1571997/0327/sys/src/9/pc/ether82557.c:135,162
1996/0418    
	RfdEOF		= 0x00008000, 
}; 
 
1997/0327    
typedef struct Cb Cb; 
1996/0418    
typedef struct Cb { 
	int	command; 
	ulong	link; 
1996/0607    
	uchar	data[24];		/* CbIAS + CbConfigure */ 
1996/0418    
} Cb; 
1997/0327    
	Cb*	next; 
	Block*	bp; 
1996/0418    
 
typedef struct TxCB { 
	int	command; 
	ulong	link; 
	ulong	tbd; 
	ushort	count; 
	uchar	threshold; 
	uchar	number; 
} TxCB; 
1997/0327    
	union { 
		uchar	data[24];	/* CbIAS + CbConfigure */ 
		struct { 
			ulong	tbd; 
			ushort	count; 
			uchar	threshold; 
			uchar	number; 
1996/0418    
 
1997/0327    
			ulong	tba; 
			ushort	tbasz; 
			ushort	pad; 
		}; 
	}; 
} Cb; 
 
1996/0418    
enum {					/* action command */ 
	CbOK		= 0x00002000,	/* DMA completed OK */ 
	CbC		= 0x00008000,	/* execution Complete */ 
1996/0625/sys/src/9/pc/ether82557.c:165,1711997/0327/sys/src/9/pc/ether82557.c:170,176
1996/0418    
	CbDiagnose	= 0x00070000, 
	CbCommand	= 0x00070000,	/* mask */ 
 
	CbSF		= 0x00080000,	/* CbTransmit */ 
1997/0327    
	CbSF		= 0x00080000,	/* Flexible-mode CbTransmit */ 
1996/0418    
 
	CbI		= 0x20000000,	/* Interrupt after completion */ 
	CbS		= 0x40000000,	/* Suspend after completion */ 
1996/0625/sys/src/9/pc/ether82557.c:178,1991997/0327/sys/src/9/pc/ether82557.c:183,206
1996/0418    
 
typedef struct Ctlr { 
	int	port; 
                 
	int	ctlrno; 
	char*	type; 
                 
	uchar	configdata[24]; 
 
1996/0622    
	Lock	lock; 
1997/0327    
	Lock	rlock;			/* registers */ 
1996/0418    
 
1996/0607    
	Block*	rfd[Nrfd];		/* receive side */ 
1996/0418    
	int	rfdl; 
	int	rfdx; 
1997/0327    
	Lock	rfdlock;		/* receive side */ 
	Block*	rfdhead; 
	Block*	rfdtail; 
	int	nrfd; 
1996/0418    
 
1996/0607    
	Block*	cbqhead;		/* transmit side */ 
1996/0418    
	Block*	cbqtail; 
1997/0327    
	Lock	cbqlock;		/* transmit side */ 
	Cb*	cbqhead; 
	Cb*	cbqtail; 
1996/0418    
	int	cbqbusy; 
1996/0607    
 
1997/0327    
	Lock	cbplock;		/* pool of free Cb's */ 
	Cb*	cbpool; 
 
 
1996/0622    
	Lock	dlock;			/* dump statistical counters */ 
1996/0607    
	ulong	dump[17]; 
1996/0418    
} Ctlr; 
1996/0625/sys/src/9/pc/ether82557.c:200,2121997/0327/sys/src/9/pc/ether82557.c:207,219
1996/0418    
 
static uchar configdata[24] = { 
	0x16,				/* byte count */ 
	0x44,				/* Rx/Tx FIFO limit */ 
1997/0327    
	0x08,				/* Rx/Tx FIFO limit */ 
1996/0418    
	0x00,				/* adaptive IFS */ 
	0x00,	 
	0x04,				/* Rx DMA maximum byte count */ 
	0x84,				/* Tx DMA maximum byte count */ 
	0x33,				/* late SCB, CNA interrupts */ 
	0x01,				/* discard short Rx frames */ 
1997/0327    
	0x00,				/* Rx DMA maximum byte count */ 
	0x80,				/* Tx DMA maximum byte count */ 
	0x32,				/* !late SCB, CNA interrupts */ 
	0x03,				/* discard short Rx frames */ 
1996/0418    
	0x00,				/* 503/MII */ 
 
	0x00,	 
1996/0625/sys/src/9/pc/ether82557.c:218,2241997/0327/sys/src/9/pc/ether82557.c:225,231
1996/0601    
	0xC8,				/* promiscuous mode off */ 
1996/0418    
	0x00,	 
	0x40,	 
	0xF2,				/* transmit padding enable */ 
1997/0327    
	0xF3,				/* transmit padding enable */ 
1996/0418    
	0x80,				/* full duplex pin enable */ 
	0x3F,				/* no Multi IA */ 
	0x05,				/* no Multi Cast ALL */ 
1996/0625/sys/src/9/pc/ether82557.c:231,2371997/0327/sys/src/9/pc/ether82557.c:238,294
1996/0418    
#define csr16w(c, r, w)	(outs((c)->port+(r), (ushort)(w))) 
#define csr32w(c, r, l)	(outl((c)->port+(r), (ulong)(l))) 
 
1997/0327    
static Block* 
rfdalloc(ulong link) 
{ 
	Block *bp; 
	Rfd *rfd; 
 
	if(bp = iallocb(sizeof(Rfd))){ 
		rfd = (Rfd*)bp->rp; 
		rfd->field = 0; 
		rfd->link = link; 
		rfd->rbd = NullPointer; 
		rfd->count = 0; 
		rfd->size = sizeof(Etherpkt); 
	} 
 
	return bp; 
} 
 
static Cb* 
cballoc(Ctlr* ctlr, int command) 
{ 
	Cb *cb; 
 
	ilock(&ctlr->cbplock); 
	if(cb = ctlr->cbpool){ 
		ctlr->cbpool = cb->next; 
		iunlock(&ctlr->cbplock); 
		cb->next = 0; 
		cb->bp = 0; 
	} 
	else{ 
		iunlock(&ctlr->cbplock); 
		cb = smalloc(sizeof(Cb)); 
	} 
 
	cb->command = command; 
	cb->link = NullPointer; 
 
	return cb; 
} 
 
1996/0418    
static void 
1997/0327    
cbfree(Ctlr* ctlr, Cb* cb) 
{ 
	ilock(&ctlr->cbplock); 
	cb->next = ctlr->cbpool; 
	ctlr->cbpool = cb; 
	iunlock(&ctlr->cbplock); 
} 
 
static void 
1996/0418    
custart(Ctlr* ctlr) 
{ 
	if(ctlr->cbqhead == 0){ 
1996/0625/sys/src/9/pc/ether82557.c:240,2711997/0327/sys/src/9/pc/ether82557.c:297,331
1996/0418    
	} 
	ctlr->cbqbusy = 1; 
 
1997/0327    
	ilock(&ctlr->rlock); 
1996/0418    
	while(csr8r(ctlr, Command)) 
		; 
1996/0607    
	csr32w(ctlr, General, PADDR(ctlr->cbqhead->rp)); 
1997/0327    
	csr32w(ctlr, General, PADDR(&ctlr->cbqhead->command)); 
1996/0418    
	csr8w(ctlr, Command, CUstart); 
1997/0327    
	iunlock(&ctlr->rlock); 
1996/0418    
} 
 
static void 
action(Ctlr* ctlr, Block* bp) 
1997/0327    
action(Ctlr* ctlr, Cb* cb) 
1996/0418    
{ 
	Cb *cb; 
1997/0327    
	Cb* tail; 
1996/0418    
 
	cb = (Cb*)bp->rp; 
	cb->command |= CbEL; 
 
1997/0327    
	ilock(&ctlr->cbqlock); 
1996/0418    
	if(ctlr->cbqhead){ 
		ctlr->cbqtail->next = bp; 
		cb = (Cb*)ctlr->cbqtail->rp; 
		cb->link = PADDR(bp->rp); 
		cb->command &= ~CbEL; 
1997/0327    
		tail = ctlr->cbqtail; 
		tail->next = cb; 
		tail->link = PADDR(&cb->command); 
		tail->command &= ~CbEL; 
1996/0418    
	} 
	else 
		ctlr->cbqhead = bp; 
	ctlr->cbqtail = bp; 
1997/0327    
		ctlr->cbqhead = cb; 
	ctlr->cbqtail = cb; 
1996/0418    
 
	if(ctlr->cbqbusy == 0) 
1997/0327    
	if(!ctlr->cbqbusy) 
1996/0418    
		custart(ctlr); 
1997/0327    
	iunlock(&ctlr->cbqlock); 
1996/0418    
} 
 
static void 
1996/0625/sys/src/9/pc/ether82557.c:275,3221997/0327/sys/src/9/pc/ether82557.c:335,367
1996/0418    
	Ctlr *ctlr; 
 
	ctlr = ether->ctlr; 
1996/0622    
	ilock(&ctlr->lock); 
1997/0327    
	ilock(&ctlr->rlock); 
1996/0418    
	status = csr16r(ctlr, Status); 
	if((status & RUstatus) == RUidle){ 
		while(csr8r(ctlr, Command)) 
			; 
1996/0607    
		csr32w(ctlr, General, PADDR(ctlr->rfd[ctlr->rfdx]->rp)); 
1997/0327    
		csr32w(ctlr, General, PADDR(ctlr->rfdhead->rp)); 
1996/0418    
		csr8w(ctlr, Command, RUstart); 
	} 
1996/0622    
	iunlock(&ctlr->lock); 
1997/0327    
	iunlock(&ctlr->rlock); 
1996/0418    
} 
 
1996/0607    
static Block* 
1997/0327    
static void 
1996/0607    
configure(Ctlr* ctlr, int promiscuous) 
1996/0418    
{ 
	Block *bp; 
	Cb *cb; 
 
	bp = allocb(sizeof(Cb)); 
	cb = (Cb*)bp->rp; 
	bp->wp += sizeof(Cb); 
                 
	cb->command = CbConfigure; 
	cb->link = NullPointer; 
1997/0327    
	cb = cballoc(ctlr, CbConfigure); 
1996/0418    
	memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata)); 
	if(promiscuous) 
		cb->data[15] |= 0x01; 
1996/0607    
                 
	return bp; 
1997/0327    
	action(ctlr, cb); 
1996/0607    
} 
 
static void 
promiscuous(void* arg, int on) 
{ 
	Ctlr *ctlr; 
	Block *bp; 
                 
	ctlr = ((Ether*)arg)->ctlr; 
	bp = configure(ctlr, on); 
                 
1996/0622    
	ilock(&ctlr->lock); 
1996/0418    
	action(ctlr, bp); 
1996/0622    
	iunlock(&ctlr->lock); 
1997/0327    
	configure(((Ether*)arg)->ctlr, on); 
1996/0418    
} 
 
static long 
1996/0625/sys/src/9/pc/ether82557.c:330,3401997/0327/sys/src/9/pc/ether82557.c:375,385
1996/0607    
	lock(&ctlr->dlock); 
	ctlr->dump[16] = 0; 
 
1996/0622    
	ilock(&ctlr->lock); 
1997/0327    
	ilock(&ctlr->rlock); 
1996/0607    
	while(csr8r(ctlr, Command)) 
		; 
	csr8w(ctlr, Command, DumpSC); 
1996/0622    
	iunlock(&ctlr->lock); 
1997/0327    
	iunlock(&ctlr->rlock); 
1996/0607    
 
	/* 
	 * Wait for completion status, should be 0xA005. 
1996/0625/sys/src/9/pc/ether82557.c:375,4101997/0327/sys/src/9/pc/ether82557.c:420,448
1996/0607    
	return readstr(offset, a, n, buf); 
} 
 
static long 
1996/0418    
write(Ether* ether, void* buf, long n) 
1997/0327    
static void 
transmit(Ether* ether) 
1996/0418    
{ 
1996/0607    
	Ctlr *ctlr; 
1996/0418    
	Block *bp; 
	TxCB *txcb; 
1997/0327    
	Cb *cb; 
1996/0418    
 
	bp = allocb(n+sizeof(TxCB)); 
	txcb = (TxCB*)bp->wp; 
	bp->wp += sizeof(TxCB); 
1997/0327    
	bp = qget(ether->oq); 
	if(bp == nil) 
		return; 
1996/0418    
 
	txcb->command = CbTransmit; 
	txcb->link = NullPointer; 
	txcb->tbd = NullPointer; 
	txcb->count = CbEOF|n; 
	txcb->threshold = 2; 
	txcb->number = 0; 
                 
	memmove(bp->wp, buf, n); 
	memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); 
	bp->wp += n; 
                 
1996/0607    
	ctlr = ether->ctlr; 
1996/0622    
	ilock(&ctlr->lock); 
1996/0607    
	action(ctlr, bp); 
1996/0622    
	iunlock(&ctlr->lock); 
1996/0418    
 
	ether->outpackets++; 
1997/0327    
	cb = cballoc(ctlr, CbSF|CbTransmit); 
	cb->bp = bp; 
	cb->tbd = PADDR(&cb->tba); 
	cb->count = 0; 
	cb->threshold = 2; 
	cb->number = 1; 
	cb->tba = PADDR(bp->rp); 
	cb->tbasz = BLEN(bp); 
1996/0418    
 
	return n; 
1997/0327    
	action(ctlr, cb); 
1996/0418    
} 
 
static void 
1996/0625/sys/src/9/pc/ether82557.c:411,4171997/0327/sys/src/9/pc/ether82557.c:449,456
1996/0418    
interrupt(Ureg*, void* arg) 
{ 
	Rfd *rfd; 
	Block *bp; 
1997/0327    
	Cb* cb; 
	Block *bp, *xbp; 
1996/0418    
	Ctlr *ctlr; 
	Ether *ether; 
	int status; 
1996/0625/sys/src/9/pc/ether82557.c:419,4591997/0327/sys/src/9/pc/ether82557.c:458,526
1996/0418    
	ether = arg; 
	ctlr = ether->ctlr; 
 
1996/0622    
	ilock(&ctlr->lock); 
1996/0418    
	for(;;){ 
1997/0327    
		lock(&ctlr->rlock); 
1996/0418    
		status = csr16r(ctlr, Status); 
		csr8w(ctlr, Ack, (status>>8) & 0xFF); 
1997/0327    
		unlock(&ctlr->rlock); 
1996/0418    
 
1996/0607    
		if((status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) == 0) 
1997/0327    
		if(!(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI))) 
1996/0607    
			break; 
1996/0418    
 
		if(status & StatFR){ 
			bp = ctlr->rfd[ctlr->rfdx]; 
1997/0327    
			bp = ctlr->rfdhead; 
1996/0418    
			rfd = (Rfd*)bp->rp; 
			while(rfd->field & RfdC){ 
1996/0607    
				if(rfd->field & RfdOK){ 
					etherrloop(ether, rfd, rfd->count & 0x3FFF); 
					ether->inpackets++; 
1997/0327    
				/* 
				 * If it's an OK receive frame and a replacement buffer 
				 * can be allocated then 
				 *	adjust the received buffer pointers for the 
				 *	  actual data received; 
				 *	initialise the replacement buffer to point to 
				 *	  the next in the ring; 
				 *	pass the received buffer on for disposal; 
				 *	initialise bp to point to the replacement. 
				 * If not, just adjust the necessary fields for reuse. 
				 */ 
				if((rfd->field & RfdOK) && (xbp = rfdalloc(rfd->link))){ 
					bp->rp += sizeof(Rfd)-sizeof(Etherpkt); 
					bp->wp = bp->rp + (rfd->count & 0x3FFF); 
 
					xbp->next = bp->next; 
					bp->next = 0; 
 
					etheriq(ether, bp, 1); 
					bp = xbp; 
1996/0607    
				} 
1997/0327    
				else{ 
					rfd->field = 0; 
					rfd->count = 0; 
				} 
1996/0418    
 
				/* 
				 * Reinitialise the frame for reception and bump 
				 * the receive frame processing index; 
				 * bump the sentinel index, mark the new sentinel 
				 * and clear the old sentinel suspend bit; 
				 * set bp and rfd for the next receive frame to 
				 * process. 
1997/0327    
				 * The ring tail pointer follows the head with with one 
				 * unused buffer in between to defeat hardware prefetch; 
				 * once the tail pointer has been bumped on to the next 
				 * and the new tail has the Suspend bit set, it can be 
				 * removed from the old tail buffer. 
				 * As a replacement for the current head buffer may have 
				 * been allocated above, ensure that the new tail points 
				 * to it (next and link). 
1996/0418    
				 */ 
				rfd->field = 0; 
				rfd->count = 0; 
				ctlr->rfdx = NEXT(ctlr->rfdx, Nrfd); 
                 
				rfd = (Rfd*)ctlr->rfd[ctlr->rfdl]->rp; 
				ctlr->rfdl = NEXT(ctlr->rfdl, Nrfd); 
				((Rfd*)ctlr->rfd[ctlr->rfdl]->rp)->field |= RfdS; 
1997/0327    
				rfd = (Rfd*)ctlr->rfdtail->rp; 
				ctlr->rfdtail = ctlr->rfdtail->next; 
				ctlr->rfdtail->next = bp; 
				((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp); 
				((Rfd*)ctlr->rfdtail->rp)->field |= RfdS; 
1996/0418    
				rfd->field &= ~RfdS; 
 
				bp = ctlr->rfd[ctlr->rfdx]; 
1997/0327    
				/* 
				 * Finally done with the current (possibly replaced) 
				 * head, move on to the next and maintain the sentinel 
				 * between tail and head. 
				 */ 
				ctlr->rfdhead = bp->next; 
				bp = ctlr->rfdhead; 
1996/0418    
				rfd = (Rfd*)bp->rp; 
			} 
			status &= ~StatFR; 
1996/0625/sys/src/9/pc/ether82557.c:460,4881997/0327/sys/src/9/pc/ether82557.c:527,560
1996/0418    
		} 
 
		if(status & StatRNR){ 
1997/0327    
			lock(&ctlr->rlock); 
1996/0418    
			while(csr8r(ctlr, Command)) 
				; 
			csr8w(ctlr, Command, RUresume); 
1997/0327    
			unlock(&ctlr->rlock); 
1996/0418    
 
			status &= ~StatRNR; 
		} 
 
		if(status & StatCNA){ 
			while(bp = ctlr->cbqhead){ 
				if((((Cb*)bp->rp)->command & CbC) == 0) 
1997/0327    
			lock(&ctlr->cbqlock); 
			while(cb = ctlr->cbqhead){ 
				if(!(cb->command & CbC)) 
1996/0418    
					break; 
				ctlr->cbqhead = bp->next; 
				freeb(bp); 
1997/0327    
				ctlr->cbqhead = cb->next; 
				if(cb->bp) 
					freeb(cb->bp); 
				cbfree(ctlr, cb); 
1996/0418    
			} 
			custart(ctlr); 
1997/0327    
			unlock(&ctlr->cbqlock); 
1996/0418    
 
			status &= ~StatCNA; 
		} 
 
		if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) 
			panic("%s#%d: status %uX\n", ctlr->type,  ctlr->ctlrno, status); 
1997/0327    
			panic("#l%d: status %uX\n", ether->ctlrno, status); 
1996/0418    
	} 
1996/0622    
	iunlock(&ctlr->lock); 
1996/0418    
} 
 
static void 
1996/0625/sys/src/9/pc/ether82557.c:493,5211997/0327/sys/src/9/pc/ether82557.c:565,593
1996/0418    
	Rfd *rfd; 
	ulong link; 
 
1997/0327    
	/* 
	 * Create the Receive Frame Area (RFA) as a ring of allocated 
	 * buffers. 
	 * A sentinel buffer is maintained between the last buffer in 
	 * the ring (marked with RfdS) and the head buffer to defeat the 
	 * hardware prefetch of the next RFD and allow dynamic buffer 
	 * allocation. 
	 */ 
1996/0418    
	link = NullPointer; 
	for(i = Nrfd-1; i >= 0; i--){ 
		if(ctlr->rfd[i] == 0){ 
			bp = allocb(sizeof(Rfd)); 
			ctlr->rfd[i] = bp; 
		} 
		else 
			bp = ctlr->rfd[i]; 
		rfd = (Rfd*)bp->rp; 
                 
		rfd->field = 0; 
		rfd->link = link; 
		link = PADDR(rfd); 
		rfd->rbd = NullPointer; 
		rfd->count = 0; 
		rfd->size = sizeof(Etherpkt); 
1997/0327    
	for(i = 0; i < Nrfd; i++){ 
		bp = rfdalloc(link); 
		if(ctlr->rfdhead == nil) 
			ctlr->rfdtail = bp; 
		bp->next = ctlr->rfdhead; 
		ctlr->rfdhead = bp; 
		link = PADDR(bp->rp); 
1996/0418    
	} 
	((Rfd*)ctlr->rfd[Nrfd-1]->rp)->link = PADDR(ctlr->rfd[0]->rp); 
1997/0327    
	ctlr->rfdtail->next = ctlr->rfdhead; 
	rfd = (Rfd*)ctlr->rfdtail->rp; 
	rfd->link = PADDR(ctlr->rfdhead->rp); 
	rfd->field |= RfdS; 
	ctlr->rfdhead = ctlr->rfdhead->next; 
1996/0418    
 
	ctlr->rfdl = 0; 
	((Rfd*)ctlr->rfd[0]->rp)->field |= RfdS; 
	ctlr->rfdx = 2; 
                 
	memmove(ctlr->configdata, configdata, sizeof(configdata)); 
} 
 
1996/0625/sys/src/9/pc/ether82557.c:572,5781997/0327/sys/src/9/pc/ether82557.c:644,650
1996/0418    
		delay(1); 
		csr16w(ctlr, Ecr, data); 
		delay(1); 
		if((csr16r(ctlr, Ecr) & EEdo) == 0) 
1997/0327    
		if(!(csr16r(ctlr, Ecr) & EEdo)) 
1996/0418    
			break; 
	} 
 
1996/0625/sys/src/9/pc/ether82557.c:591,6411997/0327/sys/src/9/pc/ether82557.c:663,712
1996/0418    
	return data; 
} 
 
typedef struct Adapter Adapter; 
struct Adapter { 
	Adapter*	next; 
	int		port; 
	int		irq; 
	int		pcidevno; 
}; 
static Adapter *adapter; 
1997/0327    
typedef struct Adapter { 
	int	port; 
	int	irq; 
	int	tbdf; 
} Adapter; 
static Block* adapter; 
1996/0418    
 
static int 
1996/0622    
i82557pci(Ether* ether, int* pcidevno) 
1997/0327    
static void 
i82557adapter(Block** bpp, int port, int irq, int tbdf) 
1996/0418    
{ 
	PCIcfg pcicfg; 
	static int devno = 0; 
	int i, irq, port; 
1997/0327    
	Block *bp; 
1996/0418    
	Adapter *ap; 
 
	for(;;){ 
		pcicfg.vid = 0x8086; 
		pcicfg.did = 0x1229; 
		if((devno = pcimatch(0, devno, &pcicfg)) == -1) 
			break; 
1997/0327    
	bp = allocb(sizeof(Adapter)); 
	ap = (Adapter*)bp->rp; 
	ap->port = port; 
	ap->irq = irq; 
	ap->tbdf = tbdf; 
1996/0418    
 
		port = 0; 
		irq = 0; 
		for(i = 0; i < 6; i++){ 
			if((pcicfg.baseaddr[i] & 0x03) != 0x01) 
				continue; 
			port = pcicfg.baseaddr[i] & ~0x01; 
			irq = pcicfg.irq; 
			if(ether->port == 0 || ether->port == port){ 
				ether->irq = irq; 
				*pcidevno = devno-1; 
				return port; 
			} 
1997/0327    
	bp->next = *bpp; 
	*bpp = bp; 
} 
 
static int 
i82557pci(Ether* ether) 
{ 
	static Pcidev *p; 
	int irq, port; 
 
	while(p = pcimatch(p, 0x8086, 0x1229)){ 
		/* 
		 * bar[0] is the memory-mapped register address (4KB), 
		 * bar[1] is the I/O port register address (32 bytes) and 
		 * bar[2] is for the flash ROM (1MB). 
		 */ 
		port = p->bar[1] & ~0x01; 
		irq = p->intl; 
		if(ether->port == 0 || ether->port == port){ 
			ether->irq = irq; 
			ether->tbdf = p->tbdf; 
			return port; 
1996/0418    
		} 
		if(port == 0) 
			continue; 
 
		ap = malloc(sizeof(Adapter)); 
		ap->port = port; 
		ap->irq = irq; 
		ap->pcidevno = devno-1; 
		ap->next = adapter; 
		adapter = ap; 
1997/0327    
		i82557adapter(&adapter, port, irq, p->tbdf); 
1996/0418    
	} 
 
	return 0; 
1996/0625/sys/src/9/pc/ether82557.c:644,6541997/0327/sys/src/9/pc/ether82557.c:715,725
1996/0418    
static int 
reset(Ether* ether) 
{ 
	int i, pcidevno, port, x; 
	Adapter *ap, **app; 
1997/0327    
	int i, port, x; 
	Block *bp, **bpp; 
	Adapter *ap; 
1996/0418    
	uchar ea[Eaddrlen]; 
	Ctlr *ctlr; 
	Block *bp; 
	Cb *cb; 
 
	/* 
1996/0625/sys/src/9/pc/ether82557.c:657,6731997/0327/sys/src/9/pc/ether82557.c:728,746
1996/0418    
	 * already been found. If not, scan for another. 
	 */ 
	port = 0; 
	pcidevno = -1; 
	for(app = &adapter, ap = *app; ap; app = &ap->next, ap = ap->next){ 
1997/0327    
	bpp = &adapter; 
	for(bp = *bpp; bp; bp = bp->next){ 
		ap = (Adapter*)bp->rp; 
1996/0418    
		if(ether->port == 0 || ether->port == ap->port){ 
1997/0327    
			port = ap->port; 
1996/0418    
			ether->irq = ap->irq; 
			pcidevno = ap->pcidevno; 
			*app = ap->next; 
			free(ap); 
1997/0327    
			ether->tbdf = ap->tbdf; 
			*bpp = bp->next; 
			freeb(bp); 
1996/0418    
			break; 
		} 
	} 
1996/0622    
	if(port == 0 && (port = i82557pci(ether, &pcidevno)) == 0) 
1997/0327    
	if(port == 0 && (port = i82557pci(ether)) == 0) 
1996/0418    
		return -1; 
 
	/* 
1996/0625/sys/src/9/pc/ether82557.c:680,6911997/0327/sys/src/9/pc/ether82557.c:753,761
1996/0418    
	 */ 
	ether->ctlr = malloc(sizeof(Ctlr)); 
	ctlr = ether->ctlr; 
	ctlr->ctlrno = ether->ctlrno; 
	ctlr->type = ether->type; 
	ctlr->port = port; 
 
1996/0622    
	ilock(&ctlr->lock); 
1996/0607    
                 
1997/0327    
	ilock(&ctlr->rlock); 
1996/0418    
	csr32w(ctlr, Port, 0); 
	delay(1); 
 
1996/0625/sys/src/9/pc/ether82557.c:702,7091997/0327/sys/src/9/pc/ether82557.c:772,779
1996/0607    
		; 
	csr32w(ctlr, General, PADDR(ctlr->dump)); 
	csr8w(ctlr, Command, LoadDCA); 
1997/0327    
	iunlock(&ctlr->rlock); 
1996/0607    
 
                 
1996/0418    
	/* 
1996/0423    
	 * Initialise the receive frame and configuration areas. 
1996/0418    
	 */ 
1996/0625/sys/src/9/pc/ether82557.c:727,7331997/0327/sys/src/9/pc/ether82557.c:797,803
1996/0418    
			continue; 
 
1996/0625    
		x = dp83840r(ctlr, i, 0x19); 
		if((x & 0x0040) == 0){ 
1997/0327    
		if(!(x & 0x0040)){ 
1996/0625    
			ether->mbps = 100; 
1996/0418    
			ctlr->configdata[8] = 1; 
1996/0601    
			ctlr->configdata[15] &= ~0x80; 
1996/0625/sys/src/9/pc/ether82557.c:734,7401997/0327/sys/src/9/pc/ether82557.c:804,810
1996/0625    
		} 
		else{ 
			x = dp83840r(ctlr, i, 0x1B); 
			if((x & 0x0200) == 0){ 
1997/0327    
			if(!(x & 0x0200)){ 
1996/0625    
				ctlr->configdata[8] = 1; 
				ctlr->configdata[15] &= ~0x80; 
			} 
1996/0625/sys/src/9/pc/ether82557.c:745,7521997/0327/sys/src/9/pc/ether82557.c:815,821
1996/0418    
	/* 
	 * Load the chip configuration 
	 */ 
1996/0607    
	bp = configure(ctlr, 0); 
	action(ctlr, bp); 
1997/0327    
	configure(ctlr, 0); 
1996/0418    
 
	/* 
	 * Check if the adapter's station address is to be overridden. 
1996/0625/sys/src/9/pc/ether82557.c:754,7771997/0327/sys/src/9/pc/ether82557.c:823,840
1996/0418    
	 * the station address with the Individual Address Setup command. 
	 */ 
	memset(ea, 0, Eaddrlen); 
	if(memcmp(ea, ether->ea, Eaddrlen) == 0){ 
1997/0327    
	if(!memcmp(ea, ether->ea, Eaddrlen)){ 
1996/0418    
		for(i = 0; i < Eaddrlen/2; i++){ 
			x = hy93c46r(ctlr, i); 
			ether->ea[2*i] = x & 0xFF; 
			ether->ea[2*i+1] = (x>>8) & 0xFF; 
1997/0327    
			ether->ea[2*i] = x; 
			ether->ea[2*i+1] = x>>8; 
1996/0418    
		} 
	} 
 
	bp = allocb(sizeof(Cb)); 
	cb = (Cb*)bp->rp; 
	bp->wp += sizeof(Cb); 
                 
	cb->command = CbIAS; 
	cb->link = NullPointer; 
1997/0327    
	cb = cballoc(ctlr, CbIAS); 
1996/0418    
	memmove(cb->data, ether->ea, Eaddrlen); 
	action(ctlr, bp); 
1997/0327    
	action(ctlr, cb); 
1996/0418    
 
1996/0622    
	iunlock(&ctlr->lock); 
1996/0607    
 
1996/0418    
	/* 
	 * Linkage to the generic ethernet driver. 
1996/0625/sys/src/9/pc/ether82557.c:778,7841997/0327/sys/src/9/pc/ether82557.c:841,847
1996/0418    
	 */ 
	ether->port = port; 
	ether->attach = attach; 
	ether->write = write; 
1997/0327    
	ether->transmit = transmit; 
1996/0418    
	ether->interrupt = interrupt; 
1996/0607    
	ether->ifstat = ifstat; 
1996/0418    
 
1997/0327/sys/src/9/pc/ether82557.c:367,3781997/0417/sys/src/9/pc/ether82557.c:367,380 (short | long)
1996/0418    
static long 
1996/0607    
ifstat(Ether* ether, void* a, long n, ulong offset) 
{ 
	Ctlr *ctlr; 
	char buf[512]; 
1997/0417    
	char *p; 
1996/0607    
	int len; 
1997/0417    
	Ctlr *ctlr; 
	ulong dump[17]; 
1996/0607    
 
	ctlr = ether->ctlr; 
	lock(&ctlr->dlock); 
1997/0417    
 
1996/0607    
	ctlr->dump[16] = 0; 
 
1997/0327    
	ilock(&ctlr->rlock); 
1997/0327/sys/src/9/pc/ether82557.c:398,4231997/0417/sys/src/9/pc/ether82557.c:400,430
1996/0607    
		return 0; 
	} 
 
	len = sprint(buf, "transmit good frames: %ld\n", ctlr->dump[0]); 
	len += sprint(buf+len, "transmit maximum collisions errors: %ld\n", ctlr->dump[1]); 
	len += sprint(buf+len, "transmit late collisions errors: %ld\n", ctlr->dump[2]); 
	len += sprint(buf+len, "transmit underrun errors: %ld\n", ctlr->dump[3]); 
	len += sprint(buf+len, "transmit lost carrier sense: %ld\n", ctlr->dump[4]); 
	len += sprint(buf+len, "transmit deferred: %ld\n", ctlr->dump[5]); 
	len += sprint(buf+len, "transmit single collisions: %ld\n", ctlr->dump[6]); 
	len += sprint(buf+len, "transmit multiple collisions: %ld\n", ctlr->dump[7]); 
	len += sprint(buf+len, "transmit total collisions: %ld\n", ctlr->dump[8]); 
	len += sprint(buf+len, "receive good frames: %ld\n", ctlr->dump[9]); 
	len += sprint(buf+len, "receive CRC errors: %ld\n", ctlr->dump[10]); 
	len += sprint(buf+len, "receive alignment errors: %ld\n", ctlr->dump[11]); 
	len += sprint(buf+len, "receive resource errors: %ld\n", ctlr->dump[12]); 
	len += sprint(buf+len, "receive overrun errors: %ld\n", ctlr->dump[13]); 
	len += sprint(buf+len, "receive collision detect errors: %ld\n", ctlr->dump[14]); 
	sprint(buf+len, "receive short frame errors: %ld\n", ctlr->dump[15]); 
                 
1997/0417    
	memmove(dump, ctlr->dump, sizeof(dump)); 
1996/0607    
	unlock(&ctlr->dlock); 
 
	return readstr(offset, a, n, buf); 
1997/0417    
	p = malloc(READSTR); 
	len = snprint(p, READSTR, "transmit good frames: %ld\n", dump[0]); 
	len += snprint(p+len, READSTR-len, "transmit maximum collisions errors: %ld\n", dump[1]); 
	len += snprint(p+len, READSTR-len, "transmit late collisions errors: %ld\n", dump[2]); 
	len += snprint(p+len, READSTR-len, "transmit underrun errors: %ld\n", dump[3]); 
	len += snprint(p+len, READSTR-len, "transmit lost carrier sense: %ld\n", dump[4]); 
	len += snprint(p+len, READSTR-len, "transmit deferred: %ld\n", dump[5]); 
	len += snprint(p+len, READSTR-len, "transmit single collisions: %ld\n", dump[6]); 
	len += snprint(p+len, READSTR-len, "transmit multiple collisions: %ld\n", dump[7]); 
	len += snprint(p+len, READSTR-len, "transmit total collisions: %ld\n", dump[8]); 
	len += snprint(p+len, READSTR-len, "receive good frames: %ld\n", dump[9]); 
	len += snprint(p+len, READSTR-len, "receive CRC errors: %ld\n", dump[10]); 
	len += snprint(p+len, READSTR-len, "receive alignment errors: %ld\n", dump[11]); 
	len += snprint(p+len, READSTR-len, "receive resource errors: %ld\n", dump[12]); 
	len += snprint(p+len, READSTR-len, "receive overrun errors: %ld\n", dump[13]); 
	len += snprint(p+len, READSTR-len, "receive collision detect errors: %ld\n", dump[14]); 
	snprint(p+len, READSTR-len, "receive short frame errors: %ld\n", dump[15]); 
 
	n = readstr(offset, a, n, p); 
	free(p); 
 
	return n; 
1996/0607    
} 
 
1997/0327    
static void 
1997/0417/sys/src/9/pc/ether82557.c:1,101997/0628/sys/src/9/pc/ether82557.c:1,11 (short | long)
1996/0418    
/* 
 * Intel 82557 Fast Ethernet PCI Bus LAN Controller 
 * as found on the Intel EtherExpress PRO/100B. This chip is full 
 * of smarts, unfortunately none of them are in the right place. 
1997/0628    
 * of smarts, unfortunately they're not all in the right place. 
1996/0418    
 * To do: 
 *	the PCI scanning code could be made common to other adapters; 
1996/0625    
 *	auto-negotiation; 
1997/0628    
 *	full-duplex; 
1996/0607    
 *	optionally use memory-mapped registers. 
1996/0418    
 */ 
#include "u.h" 
1997/0628/sys/src/9/pc/ether82557.c:1,111997/0723/sys/src/9/pc/ether82557.c:1,10 (short | long)
1996/0418    
/* 
 * Intel 82557 Fast Ethernet PCI Bus LAN Controller 
 * as found on the Intel EtherExpress PRO/100B. This chip is full 
1997/0628    
 * of smarts, unfortunately they're not all in the right place. 
1997/0723    
 * of smarts, unfortunately none of them are in the right place. 
1996/0418    
 * To do: 
 *	the PCI scanning code could be made common to other adapters; 
1996/0625    
 *	auto-negotiation; 
1997/0628    
 *	full-duplex; 
1996/0607    
 *	optionally use memory-mapped registers. 
1996/0418    
 */ 
#include "u.h" 
1997/0628/sys/src/9/pc/ether82557.c:694,7051997/0723/sys/src/9/pc/ether82557.c:693,704
1997/0327    
	*bpp = bp; 
} 
 
static int 
i82557pci(Ether* ether) 
1997/0723    
static void 
i82557pci(void) 
1997/0327    
{ 
	static Pcidev *p; 
	int irq, port; 
1997/0723    
	Pcidev *p; 
1997/0327    
 
1997/0723    
	p = nil; 
1997/0327    
	while(p = pcimatch(p, 0x8086, 0x1229)){ 
		/* 
		 * bar[0] is the memory-mapped register address (4KB), 
1997/0628/sys/src/9/pc/ether82557.c:706,7231997/0723/sys/src/9/pc/ether82557.c:705,712
1997/0327    
		 * bar[1] is the I/O port register address (32 bytes) and 
		 * bar[2] is for the flash ROM (1MB). 
		 */ 
		port = p->bar[1] & ~0x01; 
		irq = p->intl; 
		if(ether->port == 0 || ether->port == port){ 
			ether->irq = irq; 
			ether->tbdf = p->tbdf; 
			return port; 
1996/0418    
		} 
                 
1997/0327    
		i82557adapter(&adapter, port, irq, p->tbdf); 
1997/0723    
		i82557adapter(&adapter, p->bar[1] & ~0x01, p->intl, p->tbdf); 
1996/0418    
	} 
                 
	return 0; 
} 
 
static int 
1997/0628/sys/src/9/pc/ether82557.c:729,7351997/0723/sys/src/9/pc/ether82557.c:718,730
1996/0418    
	uchar ea[Eaddrlen]; 
	Ctlr *ctlr; 
	Cb *cb; 
1997/0723    
	static int scandone; 
1996/0418    
 
1997/0723    
	if(scandone == 0){ 
		i82557pci(); 
		scandone = 1; 
	} 
 
1996/0418    
	/* 
	 * Any adapter matches if no ether->port is supplied, otherwise the 
	 * ports must match. First see if an adapter that fits the bill has 
1997/0628/sys/src/9/pc/ether82557.c:747,7541997/0723/sys/src/9/pc/ether82557.c:742,750
1997/0327    
			freeb(bp); 
1996/0418    
			break; 
		} 
1997/0723    
		bpp = &bp->next; 
1996/0418    
	} 
1997/0327    
	if(port == 0 && (port = i82557pci(ether)) == 0) 
1997/0723    
	if(port == 0) 
1996/0418    
		return -1; 
 
	/* 
1997/0628/sys/src/9/pc/ether82557.c:792,8001997/0723/sys/src/9/pc/ether82557.c:788,796
1996/0418    
	 * EtherExpress PRO/100B appears to bring it up with a sensible default 
	 * configuration. However, should check for the existence of the PHY 
	 * and, if found, check whether to use 82503 (serial) or MII (nibble) 
	 * mode. Verify the PHY is a National Semiconductor DP83840 by looking 
1996/0607    
	 * at the Organizationally Unique Identifier (OUI) in registers 2 and 
	 * 3 which should be 0x80017. 
1997/0723    
	 * mode. Verify the PHY is a National Semiconductor DP83840 (OUI 0x80017) 
	 * or an Intel 82555 (OUI 0xAA00) by looking at the Organizationally Unique 
	 * Identifier (OUI) in registers 2 and 3. 
1996/0418    
	 */ 
	for(i = 1; i < 32; i++){ 
		if((x = dp83840r(ctlr, i, 2)) == 0xFFFF) 
1997/0628/sys/src/9/pc/ether82557.c:801,8081997/0723/sys/src/9/pc/ether82557.c:797,804
1996/0418    
			continue; 
		x <<= 6; 
		x |= dp83840r(ctlr, i, 3)>>10; 
		if(x != 0x80017) 
			continue; 
1997/0723    
		if(x != 0x80017 && x != 0xAA00) 
			print("#l%d: unrecognised PHY - OUI 0x%4.4uX\n", ether->ctlrno, x); 
1996/0418    
 
1996/0625    
		x = dp83840r(ctlr, i, 0x19); 
1997/0327    
		if(!(x & 0x0040)){ 
1997/0723/sys/src/9/pc/ether82557.c:1,101997/0806/sys/src/9/pc/ether82557.c:1,11 (short | long)
1996/0418    
/* 
 * Intel 82557 Fast Ethernet PCI Bus LAN Controller 
 * as found on the Intel EtherExpress PRO/100B. This chip is full 
1997/0723    
 * of smarts, unfortunately none of them are in the right place. 
1997/0806    
 * of smarts, unfortunately they're not all in the right place. 
1996/0418    
 * To do: 
 *	the PCI scanning code could be made common to other adapters; 
1996/0625    
 *	auto-negotiation; 
1997/0806    
 *	full-duplex; 
1996/0607    
 *	optionally use memory-mapped registers. 
1996/0418    
 */ 
#include "u.h" 
1997/0723/sys/src/9/pc/ether82557.c:27,331997/0806/sys/src/9/pc/ether82557.c:28,34
1996/0418    
enum {					/* CSR */ 
	Status		= 0x00,		/* byte or word (word includes Ack) */ 
	Ack		= 0x01,		/* byte */ 
	Command		= 0x02,		/* byte or word (word includes Interrupt) */ 
1997/0806    
	CommandR	= 0x02,		/* byte or word (word includes Interrupt) */ 
1996/0418    
	Interrupt	= 0x03,		/* byte */ 
1996/0423    
	General		= 0x04,		/* dword */ 
1996/0418    
	Port		= 0x08,		/* dword */ 
1997/0723/sys/src/9/pc/ether82557.c:298,3071997/0806/sys/src/9/pc/ether82557.c:299,308
1996/0418    
	ctlr->cbqbusy = 1; 
 
1997/0327    
	ilock(&ctlr->rlock); 
1996/0418    
	while(csr8r(ctlr, Command)) 
1997/0806    
	while(csr8r(ctlr, CommandR)) 
1996/0418    
		; 
1997/0327    
	csr32w(ctlr, General, PADDR(&ctlr->cbqhead->command)); 
1996/0418    
	csr8w(ctlr, Command, CUstart); 
1997/0806    
	csr8w(ctlr, CommandR, CUstart); 
1997/0327    
	iunlock(&ctlr->rlock); 
1996/0418    
} 
 
1997/0723/sys/src/9/pc/ether82557.c:338,3471997/0806/sys/src/9/pc/ether82557.c:339,348
1997/0327    
	ilock(&ctlr->rlock); 
1996/0418    
	status = csr16r(ctlr, Status); 
	if((status & RUstatus) == RUidle){ 
		while(csr8r(ctlr, Command)) 
1997/0806    
		while(csr8r(ctlr, CommandR)) 
1996/0418    
			; 
1997/0327    
		csr32w(ctlr, General, PADDR(ctlr->rfdhead->rp)); 
1996/0418    
		csr8w(ctlr, Command, RUstart); 
1997/0806    
		csr8w(ctlr, CommandR, RUstart); 
1996/0418    
	} 
1997/0327    
	iunlock(&ctlr->rlock); 
1996/0418    
} 
1997/0723/sys/src/9/pc/ether82557.c:378,3861997/0806/sys/src/9/pc/ether82557.c:379,387
1996/0607    
	ctlr->dump[16] = 0; 
 
1997/0327    
	ilock(&ctlr->rlock); 
1996/0607    
	while(csr8r(ctlr, Command)) 
1997/0806    
	while(csr8r(ctlr, CommandR)) 
1996/0607    
		; 
	csr8w(ctlr, Command, DumpSC); 
1997/0806    
	csr8w(ctlr, CommandR, DumpSC); 
1997/0327    
	iunlock(&ctlr->rlock); 
1996/0607    
 
	/* 
1997/0723/sys/src/9/pc/ether82557.c:535,5431997/0806/sys/src/9/pc/ether82557.c:536,544
1996/0418    
 
		if(status & StatRNR){ 
1997/0327    
			lock(&ctlr->rlock); 
1996/0418    
			while(csr8r(ctlr, Command)) 
1997/0806    
			while(csr8r(ctlr, CommandR)) 
1996/0418    
				; 
			csr8w(ctlr, Command, RUresume); 
1997/0806    
			csr8w(ctlr, CommandR, RUresume); 
1997/0327    
			unlock(&ctlr->rlock); 
1996/0418    
 
			status &= ~StatRNR; 
1997/0723/sys/src/9/pc/ether82557.c:726,7341997/0806/sys/src/9/pc/ether82557.c:727,734
1997/0723    
	} 
 
1996/0418    
	/* 
	 * Any adapter matches if no ether->port is supplied, otherwise the 
	 * ports must match. First see if an adapter that fits the bill has 
	 * already been found. If not, scan for another. 
1997/0806    
	 * Any adapter matches if no port is supplied, 
	 * otherwise the ports must match. 
1996/0418    
	 */ 
	port = 0; 
1997/0327    
	bpp = &adapter; 
1997/0723/sys/src/9/pc/ether82557.c:763,7811997/0806/sys/src/9/pc/ether82557.c:763,781
1996/0418    
	csr32w(ctlr, Port, 0); 
	delay(1); 
 
	while(csr8r(ctlr, Command)) 
1997/0806    
	while(csr8r(ctlr, CommandR)) 
1996/0418    
		; 
1996/0607    
	csr32w(ctlr, General, 0); 
1996/0423    
	csr8w(ctlr, Command, LoadRUB); 
1997/0806    
	csr8w(ctlr, CommandR, LoadRUB); 
1996/0607    
 
1996/0418    
	while(csr8r(ctlr, Command)) 
1997/0806    
	while(csr8r(ctlr, CommandR)) 
1996/0418    
		; 
1996/0423    
	csr8w(ctlr, Command, LoadCUB); 
1997/0806    
	csr8w(ctlr, CommandR, LoadCUB); 
1996/0418    
 
1996/0607    
	while(csr8r(ctlr, Command)) 
1997/0806    
	while(csr8r(ctlr, CommandR)) 
1996/0607    
		; 
	csr32w(ctlr, General, PADDR(ctlr->dump)); 
	csr8w(ctlr, Command, LoadDCA); 
1997/0806    
	csr8w(ctlr, CommandR, LoadDCA); 
1997/0327    
	iunlock(&ctlr->rlock); 
1996/0607    
 
1996/0418    
	/* 
1997/0723/sys/src/9/pc/ether82557.c:827,8331997/0806/sys/src/9/pc/ether82557.c:827,833
1996/0418    
	 * the station address with the Individual Address Setup command. 
	 */ 
	memset(ea, 0, Eaddrlen); 
1997/0327    
	if(!memcmp(ea, ether->ea, Eaddrlen)){ 
1997/0806    
	if(memcmp(ea, ether->ea, Eaddrlen) == 0){ 
1996/0418    
		for(i = 0; i < Eaddrlen/2; i++){ 
			x = hy93c46r(ctlr, i); 
1997/0327    
			ether->ea[2*i] = x; 
1997/0806/sys/src/9/pc/ether82557.c:405,4261997/0807/sys/src/9/pc/ether82557.c:405,426 (short | long)
1996/0607    
	unlock(&ctlr->dlock); 
 
1997/0417    
	p = malloc(READSTR); 
	len = snprint(p, READSTR, "transmit good frames: %ld\n", dump[0]); 
	len += snprint(p+len, READSTR-len, "transmit maximum collisions errors: %ld\n", dump[1]); 
	len += snprint(p+len, READSTR-len, "transmit late collisions errors: %ld\n", dump[2]); 
	len += snprint(p+len, READSTR-len, "transmit underrun errors: %ld\n", dump[3]); 
	len += snprint(p+len, READSTR-len, "transmit lost carrier sense: %ld\n", dump[4]); 
	len += snprint(p+len, READSTR-len, "transmit deferred: %ld\n", dump[5]); 
	len += snprint(p+len, READSTR-len, "transmit single collisions: %ld\n", dump[6]); 
	len += snprint(p+len, READSTR-len, "transmit multiple collisions: %ld\n", dump[7]); 
	len += snprint(p+len, READSTR-len, "transmit total collisions: %ld\n", dump[8]); 
	len += snprint(p+len, READSTR-len, "receive good frames: %ld\n", dump[9]); 
	len += snprint(p+len, READSTR-len, "receive CRC errors: %ld\n", dump[10]); 
	len += snprint(p+len, READSTR-len, "receive alignment errors: %ld\n", dump[11]); 
	len += snprint(p+len, READSTR-len, "receive resource errors: %ld\n", dump[12]); 
	len += snprint(p+len, READSTR-len, "receive overrun errors: %ld\n", dump[13]); 
	len += snprint(p+len, READSTR-len, "receive collision detect errors: %ld\n", dump[14]); 
	snprint(p+len, READSTR-len, "receive short frame errors: %ld\n", dump[15]); 
1997/0807    
	len = snprint(p, READSTR, "transmit good frames: %lud\n", dump[0]); 
	len += snprint(p+len, READSTR-len, "transmit maximum collisions errors: %lud\n", dump[1]); 
	len += snprint(p+len, READSTR-len, "transmit late collisions errors: %lud\n", dump[2]); 
	len += snprint(p+len, READSTR-len, "transmit underrun errors: %lud\n", dump[3]); 
	len += snprint(p+len, READSTR-len, "transmit lost carrier sense: %lud\n", dump[4]); 
	len += snprint(p+len, READSTR-len, "transmit deferred: %lud\n", dump[5]); 
	len += snprint(p+len, READSTR-len, "transmit single collisions: %lud\n", dump[6]); 
	len += snprint(p+len, READSTR-len, "transmit multiple collisions: %lud\n", dump[7]); 
	len += snprint(p+len, READSTR-len, "transmit total collisions: %lud\n", dump[8]); 
	len += snprint(p+len, READSTR-len, "receive good frames: %lud\n", dump[9]); 
	len += snprint(p+len, READSTR-len, "receive CRC errors: %lud\n", dump[10]); 
	len += snprint(p+len, READSTR-len, "receive alignment errors: %lud\n", dump[11]); 
	len += snprint(p+len, READSTR-len, "receive resource errors: %lud\n", dump[12]); 
	len += snprint(p+len, READSTR-len, "receive overrun errors: %lud\n", dump[13]); 
	len += snprint(p+len, READSTR-len, "receive collision detect errors: %lud\n", dump[14]); 
	snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]); 
1997/0417    
 
	n = readstr(offset, a, n, p); 
	free(p); 
1997/0807/sys/src/9/pc/ether82557.c:4,121997/0823/sys/src/9/pc/ether82557.c:4,12 (short | long)
1997/0806    
 * of smarts, unfortunately they're not all in the right place. 
1996/0418    
 * To do: 
 *	the PCI scanning code could be made common to other adapters; 
1996/0625    
 *	auto-negotiation; 
1997/0806    
 *	full-duplex; 
1996/0607    
 *	optionally use memory-mapped registers. 
1997/0823    
 *	auto-negotiation, full-duplex; 
 *	optionally use memory-mapped registers; 
 *	detach for PCI reset problems (also towards loadable drivers). 
1996/0418    
 */ 
#include "u.h" 
#include "../port/lib.h" 
1997/0807/sys/src/9/pc/ether82557.c:21,261997/0823/sys/src/9/pc/ether82557.c:21,27
1996/0418    
 
enum { 
	Nrfd		= 64,		/* receive frame area */ 
1997/0823    
	Ncb		= 64,		/* maximum control blocks queued */ 
1996/0418    
 
	NullPointer	= 0xFFFFFFFF,	/* 82557 NULL pointer */ 
}; 
1997/0807/sys/src/9/pc/ether82557.c:132,1471997/0823/sys/src/9/pc/ether82557.c:133,146
1996/0418    
}; 
 
enum {					/* count */ 
	RfdF		= 0x00004000, 
	RfdEOF		= 0x00008000, 
1997/0823    
	RfdF		= 0x4000, 
	RfdEOF		= 0x8000, 
1996/0418    
}; 
 
1997/0327    
typedef struct Cb Cb; 
1996/0418    
typedef struct Cb { 
1997/0327    
	Cb*	next; 
	Block*	bp; 
1996/0418    
                 
	int	command; 
1997/0823    
	ushort	status; 
	ushort	command; 
1996/0418    
	ulong	link; 
1997/0327    
	union { 
		uchar	data[24];	/* CbIAS + CbConfigure */ 
1997/0807/sys/src/9/pc/ether82557.c:156,2071997/0823/sys/src/9/pc/ether82557.c:155,214
1997/0327    
			ushort	pad; 
		}; 
	}; 
1997/0823    
 
	Block*	bp; 
	Cb*	next; 
1997/0327    
} Cb; 
 
1996/0418    
enum {					/* action command */ 
	CbOK		= 0x00002000,	/* DMA completed OK */ 
	CbC		= 0x00008000,	/* execution Complete */ 
1997/0823    
	CbU		= 0x1000,	/* transmit underrun */ 
	CbOK		= 0x2000,	/* DMA completed OK */ 
	CbC		= 0x8000,	/* execution Complete */ 
1996/0418    
 
	CbNOP		= 0x00000000, 
1996/0423    
	CbIAS		= 0x00010000,	/* Individual Address Setup */ 
1996/0418    
	CbConfigure	= 0x00020000, 
	CbMAS		= 0x00030000,	/* Multicast Address Setup */ 
	CbTransmit	= 0x00040000, 
	CbDump		= 0x00060000, 
	CbDiagnose	= 0x00070000, 
	CbCommand	= 0x00070000,	/* mask */ 
1997/0823    
	CbNOP		= 0x0000, 
	CbIAS		= 0x0001,	/* Individual Address Setup */ 
	CbConfigure	= 0x0002, 
	CbMAS		= 0x0003,	/* Multicast Address Setup */ 
	CbTransmit	= 0x0004, 
	CbDump		= 0x0006, 
	CbDiagnose	= 0x0007, 
	CbCommand	= 0x0007,	/* mask */ 
1996/0418    
 
1997/0327    
	CbSF		= 0x00080000,	/* Flexible-mode CbTransmit */ 
1997/0823    
	CbSF		= 0x0008,	/* Flexible-mode CbTransmit */ 
1996/0418    
 
	CbI		= 0x20000000,	/* Interrupt after completion */ 
	CbS		= 0x40000000,	/* Suspend after completion */ 
	CbEL		= 0x80000000,	/* End of List */ 
1997/0823    
	CbI		= 0x2000,	/* Interrupt after completion */ 
	CbS		= 0x4000,	/* Suspend after completion */ 
	CbEL		= 0x8000,	/* End of List */ 
1996/0418    
}; 
 
enum {					/* CbTransmit count */ 
	CbEOF		= 0x00008000, 
1997/0823    
	CbEOF		= 0x8000, 
1996/0418    
}; 
 
typedef struct Ctlr { 
1997/0823    
	Lock	slock;			/* attach */ 
	int	state; 
 
1996/0418    
	int	port; 
	uchar	configdata[24]; 
 
1997/0327    
	Lock	rlock;			/* registers */ 
1997/0823    
	int	command;		/* last command issued */ 
1996/0418    
 
1997/0327    
	Lock	rfdlock;		/* receive side */ 
	Block*	rfdhead; 
1997/0823    
	Block*	rfdhead;		/* receive side */ 
1997/0327    
	Block*	rfdtail; 
	int	nrfd; 
1996/0418    
 
1997/0327    
	Lock	cbqlock;		/* transmit side */ 
	Cb*	cbqhead; 
	Cb*	cbqtail; 
1996/0418    
	int	cbqbusy; 
1997/0823    
	Lock	cblock;			/* transmit side */ 
	int	action; 
	uchar	configdata[24]; 
	int	threshold; 
	int	ncb; 
	Cb*	cbr; 
	Cb*	cbhead; 
	Cb*	cbtail; 
	int	cbq; 
	int	cbqmax; 
1996/0607    
 
1997/0327    
	Lock	cbplock;		/* pool of free Cb's */ 
	Cb*	cbpool; 
                 
                 
1996/0622    
	Lock	dlock;			/* dump statistical counters */ 
1996/0607    
	ulong	dump[17]; 
1996/0418    
} Ctlr; 
1997/0807/sys/src/9/pc/ether82557.c:239,2441997/0823/sys/src/9/pc/ether82557.c:246,298
1996/0418    
#define csr16w(c, r, w)	(outs((c)->port+(r), (ushort)(w))) 
#define csr32w(c, r, l)	(outl((c)->port+(r), (ulong)(l))) 
 
1997/0823    
static void 
command(Ctlr* ctlr, int c, int v) 
{ 
	ilock(&ctlr->rlock); 
 
	/* 
	 * Only back-to-back CUresume can be done 
	 * without waiting for any previous command to complete. 
	 * This should be the common case. 
	 */ 
	if(c == CUresume && ctlr->command == CUresume){ 
		csr8w(ctlr, CommandR, c); 
		iunlock(&ctlr->rlock); 
		return; 
	} 
 
	while(csr8r(ctlr, CommandR)) 
		; 
 
	switch(c){ 
 
	case CUstart: 
	case LoadDCA: 
	case LoadCUB: 
	case RUstart: 
	case LoadHDS: 
	case LoadRUB: 
		csr32w(ctlr, General, v); 
		break; 
 
	/* 
	case CUnop: 
	case CUresume: 
	case DumpSC: 
	case ResetSA: 
	case RUresume: 
	case RUabort: 
	 */ 
	default: 
		break; 
	} 
	csr8w(ctlr, CommandR, c); 
	ctlr->command = c; 
 
	iunlock(&ctlr->rlock); 
} 
 
1997/0327    
static Block* 
rfdalloc(ulong link) 
{ 
1997/0807/sys/src/9/pc/ether82557.c:257,3701997/0823/sys/src/9/pc/ether82557.c:311,330
1997/0327    
	return bp; 
} 
 
static Cb* 
cballoc(Ctlr* ctlr, int command) 
{ 
	Cb *cb; 
                 
	ilock(&ctlr->cbplock); 
	if(cb = ctlr->cbpool){ 
		ctlr->cbpool = cb->next; 
		iunlock(&ctlr->cbplock); 
		cb->next = 0; 
		cb->bp = 0; 
	} 
	else{ 
		iunlock(&ctlr->cbplock); 
		cb = smalloc(sizeof(Cb)); 
	} 
                 
	cb->command = command; 
	cb->link = NullPointer; 
                 
	return cb; 
} 
                 
1996/0418    
static void 
1997/0327    
cbfree(Ctlr* ctlr, Cb* cb) 
{ 
	ilock(&ctlr->cbplock); 
	cb->next = ctlr->cbpool; 
	ctlr->cbpool = cb; 
	iunlock(&ctlr->cbplock); 
} 
                 
static void 
1996/0418    
custart(Ctlr* ctlr) 
{ 
	if(ctlr->cbqhead == 0){ 
		ctlr->cbqbusy = 0; 
		return; 
	} 
	ctlr->cbqbusy = 1; 
                 
1997/0327    
	ilock(&ctlr->rlock); 
1997/0806    
	while(csr8r(ctlr, CommandR)) 
1996/0418    
		; 
1997/0327    
	csr32w(ctlr, General, PADDR(&ctlr->cbqhead->command)); 
1997/0806    
	csr8w(ctlr, CommandR, CUstart); 
1997/0327    
	iunlock(&ctlr->rlock); 
1996/0418    
} 
                 
static void 
1997/0327    
action(Ctlr* ctlr, Cb* cb) 
1996/0418    
{ 
1997/0327    
	Cb* tail; 
1996/0418    
                 
	cb->command |= CbEL; 
                 
1997/0327    
	ilock(&ctlr->cbqlock); 
1996/0418    
	if(ctlr->cbqhead){ 
1997/0327    
		tail = ctlr->cbqtail; 
		tail->next = cb; 
		tail->link = PADDR(&cb->command); 
		tail->command &= ~CbEL; 
1996/0418    
	} 
	else 
1997/0327    
		ctlr->cbqhead = cb; 
	ctlr->cbqtail = cb; 
1996/0418    
                 
1997/0327    
	if(!ctlr->cbqbusy) 
1996/0418    
		custart(ctlr); 
1997/0327    
	iunlock(&ctlr->cbqlock); 
1996/0418    
} 
                 
static void 
attach(Ether* ether) 
{ 
	int status; 
	Ctlr *ctlr; 
 
	ctlr = ether->ctlr; 
1997/0327    
	ilock(&ctlr->rlock); 
1996/0418    
	status = csr16r(ctlr, Status); 
	if((status & RUstatus) == RUidle){ 
1997/0806    
		while(csr8r(ctlr, CommandR)) 
1996/0418    
			; 
1997/0327    
		csr32w(ctlr, General, PADDR(ctlr->rfdhead->rp)); 
1997/0806    
		csr8w(ctlr, CommandR, RUstart); 
1997/0823    
	lock(&ctlr->slock); 
	if(ctlr->state == 0){ 
		command(ctlr, RUstart, PADDR(ctlr->rfdhead->rp)); 
		ctlr->state = 1; 
1996/0418    
	} 
1997/0327    
	iunlock(&ctlr->rlock); 
1997/0823    
	unlock(&ctlr->slock); 
1996/0418    
} 
 
1997/0327    
static void 
1996/0607    
configure(Ctlr* ctlr, int promiscuous) 
1996/0418    
{ 
	Cb *cb; 
                 
1997/0327    
	cb = cballoc(ctlr, CbConfigure); 
1996/0418    
	memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata)); 
	if(promiscuous) 
		cb->data[15] |= 0x01; 
1997/0327    
	action(ctlr, cb); 
1996/0607    
} 
                 
static void 
promiscuous(void* arg, int on) 
{ 
1997/0327    
	configure(((Ether*)arg)->ctlr, on); 
1996/0418    
} 
                 
static long 
1996/0607    
ifstat(Ether* ether, void* a, long n, ulong offset) 
{ 
1997/0807/sys/src/9/pc/ether82557.c:376,3921997/0823/sys/src/9/pc/ether82557.c:336,348
1996/0607    
	ctlr = ether->ctlr; 
	lock(&ctlr->dlock); 
1997/0417    
 
1996/0607    
	ctlr->dump[16] = 0; 
                 
1997/0327    
	ilock(&ctlr->rlock); 
1997/0806    
	while(csr8r(ctlr, CommandR)) 
1996/0607    
		; 
1997/0806    
	csr8w(ctlr, CommandR, DumpSC); 
1997/0327    
	iunlock(&ctlr->rlock); 
1996/0607    
                 
	/* 
	 * Wait for completion status, should be 0xA005. 
1997/0823    
	 * Start the command then 
	 * wait for completion status, 
	 * should be 0xA005. 
1996/0607    
	 */ 
1997/0823    
	ctlr->dump[16] = 0; 
	command(ctlr, DumpSC, 0); 
1996/0607    
	while(ctlr->dump[16] == 0) 
		; 
 
1997/0807/sys/src/9/pc/ether82557.c:420,4261997/0823/sys/src/9/pc/ether82557.c:376,384
1997/0807    
	len += snprint(p+len, READSTR-len, "receive resource errors: %lud\n", dump[12]); 
	len += snprint(p+len, READSTR-len, "receive overrun errors: %lud\n", dump[13]); 
	len += snprint(p+len, READSTR-len, "receive collision detect errors: %lud\n", dump[14]); 
	snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]); 
1997/0823    
	len += snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]); 
	snprint(p+len, READSTR-len, "cbqmax: %lud\n", ctlr->cbqmax); 
ctlr->cbqmax = 0; 
1997/0417    
 
	n = readstr(offset, a, n, p); 
	free(p); 
1997/0807/sys/src/9/pc/ether82557.c:429,4561997/0823/sys/src/9/pc/ether82557.c:387,484
1996/0607    
} 
 
1997/0327    
static void 
transmit(Ether* ether) 
1997/0823    
txstart(Ether* ether) 
1996/0418    
{ 
1996/0607    
	Ctlr *ctlr; 
1996/0418    
	Block *bp; 
1997/0327    
	Cb *cb; 
1996/0418    
 
1997/0327    
	bp = qget(ether->oq); 
	if(bp == nil) 
		return; 
1997/0823    
	ctlr = ether->ctlr; 
	while(ctlr->cbq < (ctlr->ncb-1)){ 
		cb = ctlr->cbhead->next; 
		if(ctlr->action == 0){ 
			bp = qget(ether->oq); 
			if(bp == nil) 
				break; 
1996/0418    
 
1997/0823    
			cb->command = CbS|CbSF|CbTransmit; 
			cb->tbd = PADDR(&cb->tba); 
			cb->count = 0; 
			cb->threshold = ctlr->threshold; 
			cb->number = 1; 
			cb->tba = PADDR(bp->rp); 
			cb->bp = bp; 
			cb->tbasz = BLEN(bp); 
		} 
		else if(ctlr->action == CbConfigure){ 
			cb->command = CbS|CbConfigure; 
			memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata)); 
			ctlr->action = 0; 
		} 
		else if(ctlr->action == CbIAS){ 
			cb->command = CbS|CbIAS; 
			memmove(cb->data, ether->ea, Eaddrlen); 
			ctlr->action = 0; 
		} 
		else{ 
			print("#l%d: action 0x%uX\n", ether->ctlrno, ctlr->action); 
			ctlr->action = 0; 
			break; 
		} 
		cb->status = 0; 
 
		ctlr->cbhead->command &= ~CbS; 
		ctlr->cbhead = cb; 
		ctlr->cbq++; 
	} 
	command(ctlr, CUresume, 0); 
 
	if(ctlr->cbq > ctlr->cbqmax) 
		ctlr->cbqmax = ctlr->cbq; 
} 
 
static void 
configure(Ether* ether, int promiscuous) 
{ 
	Ctlr *ctlr; 
 
1996/0607    
	ctlr = ether->ctlr; 
1997/0823    
	ilock(&ctlr->cblock); 
	if(promiscuous){ 
		ctlr->configdata[6] |= 0x80;		/* Save Bad Frames */ 
		ctlr->configdata[6] &= ~0x40;		/* !Discard Overrun Rx Frames */ 
		ctlr->configdata[7] &= ~0x01;		/* !Discard Short Rx Frames */ 
		ctlr->configdata[15] |= 0x01;		/* Promiscuous mode */ 
		ctlr->configdata[18] &= ~0x01;		/* (!Padding enable?), !stripping enable */ 
		ctlr->configdata[21] |= 0x08;		/* Multi Cast ALL */ 
	} 
	else{ 
		ctlr->configdata[6] &= ~0x80; 
		ctlr->configdata[7] |= 0x01; 
		ctlr->configdata[15] &= ~0x01; 
		ctlr->configdata[18] |= 0x01;		/* 0x03? */ 
		ctlr->configdata[21] &= ~0x08; 
	} 
	ctlr->action = CbConfigure; 
	txstart(ether); 
	iunlock(&ctlr->cblock); 
} 
1996/0418    
 
1997/0327    
	cb = cballoc(ctlr, CbSF|CbTransmit); 
	cb->bp = bp; 
	cb->tbd = PADDR(&cb->tba); 
	cb->count = 0; 
	cb->threshold = 2; 
	cb->number = 1; 
	cb->tba = PADDR(bp->rp); 
	cb->tbasz = BLEN(bp); 
1997/0823    
static void 
promiscuous(void* arg, int on) 
{ 
	configure(arg, on); 
} 
1996/0418    
 
1997/0327    
	action(ctlr, cb); 
1997/0823    
static void 
transmit(Ether* ether) 
{ 
	Ctlr *ctlr; 
 
	ctlr = ether->ctlr; 
	ilock(&ctlr->cblock); 
	txstart(ether); 
	iunlock(&ctlr->cblock); 
1996/0418    
} 
 
static void 
1997/0807/sys/src/9/pc/ether82557.c:535,5621997/0823/sys/src/9/pc/ether82557.c:563,594
1996/0418    
		} 
 
		if(status & StatRNR){ 
1997/0327    
			lock(&ctlr->rlock); 
1997/0806    
			while(csr8r(ctlr, CommandR)) 
1996/0418    
				; 
1997/0806    
			csr8w(ctlr, CommandR, RUresume); 
1997/0327    
			unlock(&ctlr->rlock); 
1996/0418    
                 
1997/0823    
			command(ctlr, RUresume, 0); 
1996/0418    
			status &= ~StatRNR; 
		} 
 
		if(status & StatCNA){ 
1997/0327    
			lock(&ctlr->cbqlock); 
			while(cb = ctlr->cbqhead){ 
				if(!(cb->command & CbC)) 
1997/0823    
			lock(&ctlr->cblock); 
 
			cb = ctlr->cbtail; 
			while(ctlr->cbq){ 
				if(!(cb->status & CbC)) 
1996/0418    
					break; 
1997/0327    
				ctlr->cbqhead = cb->next; 
				if(cb->bp) 
1997/0823    
				if(cb->bp){ 
1997/0327    
					freeb(cb->bp); 
				cbfree(ctlr, cb); 
1997/0823    
					cb->bp = nil; 
				} 
				if((cb->status & CbU) && ctlr->threshold < 0xE0) 
					ctlr->threshold++; 
 
				ctlr->cbq--; 
				cb = cb->next; 
1996/0418    
			} 
			custart(ctlr); 
1997/0327    
			unlock(&ctlr->cbqlock); 
1997/0823    
			ctlr->cbtail = cb; 
1996/0418    
 
1997/0823    
			txstart(ether); 
			unlock(&ctlr->cblock); 
 
1996/0418    
			status &= ~StatCNA; 
		} 
 
1997/0807/sys/src/9/pc/ether82557.c:596,6021997/0823/sys/src/9/pc/ether82557.c:628,653
1997/0327    
	rfd->field |= RfdS; 
	ctlr->rfdhead = ctlr->rfdhead->next; 
1996/0418    
 
1997/0823    
	/* 
	 * Create a ring of control blocks for the 
	 * transmit side. 
	 */ 
	ilock(&ctlr->cblock); 
	ctlr->cbr = malloc(ctlr->ncb*sizeof(Cb)); 
	for(i = 0; i < ctlr->ncb; i++){ 
		ctlr->cbr[i].status = CbC|CbOK; 
		ctlr->cbr[i].command = CbS|CbNOP; 
		ctlr->cbr[i].link = PADDR(&ctlr->cbr[NEXT(i, ctlr->ncb)].status); 
		ctlr->cbr[i].next = &ctlr->cbr[NEXT(i, ctlr->ncb)]; 
	} 
	ctlr->cbhead = ctlr->cbr; 
	ctlr->cbtail = ctlr->cbr; 
	ctlr->cbq = 0; 
 
1996/0418    
	memmove(ctlr->configdata, configdata, sizeof(configdata)); 
1997/0823    
	ctlr->threshold = 8; 
 
	iunlock(&ctlr->cblock); 
1996/0418    
} 
 
static int 
1997/0807/sys/src/9/pc/ether82557.c:718,7241997/0823/sys/src/9/pc/ether82557.c:769,774
1997/0327    
	Adapter *ap; 
1996/0418    
	uchar ea[Eaddrlen]; 
	Ctlr *ctlr; 
	Cb *cb; 
1997/0723    
	static int scandone; 
1996/0418    
 
1997/0723    
	if(scandone == 0){ 
1997/0807/sys/src/9/pc/ether82557.c:749,7551997/0823/sys/src/9/pc/ether82557.c:799,805
1996/0418    
 
	/* 
	 * Allocate a controller structure and start to initialise it. 
	 * Perform a software reset after which need to ensure busmastering 
1997/0823    
	 * Perform a software reset after which should ensure busmastering 
1996/0418    
	 * is still enabled. The EtherExpress PRO/100B appears to leave 
	 * the PCI configuration alone (see the 'To do' list above) so punt 
	 * for now. 
1997/0807/sys/src/9/pc/ether82557.c:762,7861997/0823/sys/src/9/pc/ether82557.c:812,827
1997/0327    
	ilock(&ctlr->rlock); 
1996/0418    
	csr32w(ctlr, Port, 0); 
	delay(1); 
                 
1997/0806    
	while(csr8r(ctlr, CommandR)) 
1996/0418    
		; 
1996/0607    
	csr32w(ctlr, General, 0); 
1997/0806    
	csr8w(ctlr, CommandR, LoadRUB); 
1996/0607    
                 
1997/0806    
	while(csr8r(ctlr, CommandR)) 
1996/0418    
		; 
1997/0806    
	csr8w(ctlr, CommandR, LoadCUB); 
1996/0418    
                 
1997/0806    
	while(csr8r(ctlr, CommandR)) 
1996/0607    
		; 
	csr32w(ctlr, General, PADDR(ctlr->dump)); 
1997/0806    
	csr8w(ctlr, CommandR, LoadDCA); 
1997/0327    
	iunlock(&ctlr->rlock); 
1996/0607    
 
1997/0823    
	command(ctlr, LoadRUB, 0); 
	command(ctlr, LoadCUB, 0); 
	command(ctlr, LoadDCA, PADDR(ctlr->dump)); 
 
1996/0418    
	/* 
1996/0423    
	 * Initialise the receive frame and configuration areas. 
1997/0823    
	 * Initialise the receive frame, transmit ring and configuration areas. 
1996/0418    
	 */ 
1997/0823    
	ctlr->ncb = Ncb; 
1996/0418    
	ctlrinit(ctlr); 
 
	/* 
1997/0807/sys/src/9/pc/ether82557.c:817,8251997/0823/sys/src/9/pc/ether82557.c:858,869
1996/0418    
	} 
 
	/* 
	 * Load the chip configuration 
1997/0823    
	 * Load the chip configuration and start it off. 
1996/0418    
	 */ 
1997/0327    
	configure(ctlr, 0); 
1997/0823    
	if(ether->oq == 0) 
		ether->oq = qopen(256*1024, 1, 0, 0); 
	configure(ether, 0); 
	command(ctlr, CUstart, PADDR(&ctlr->cbr->status)); 
1996/0418    
 
	/* 
	 * Check if the adapter's station address is to be overridden. 
1997/0807/sys/src/9/pc/ether82557.c:835,8441997/0823/sys/src/9/pc/ether82557.c:879,888
1996/0418    
		} 
	} 
 
1997/0327    
	cb = cballoc(ctlr, CbIAS); 
1996/0418    
	memmove(cb->data, ether->ea, Eaddrlen); 
1997/0327    
	action(ctlr, cb); 
1996/0418    
                 
1997/0823    
	ilock(&ctlr->cblock); 
	ctlr->action = CbIAS; 
	txstart(ether); 
	iunlock(&ctlr->cblock); 
1996/0607    
 
1996/0418    
	/* 
	 * Linkage to the generic ethernet driver. 
1997/0823/sys/src/9/pc/ether82557.c:255,2661997/1011/sys/src/9/pc/ether82557.c:255,268 (short | long)
1997/0823    
	 * Only back-to-back CUresume can be done 
	 * without waiting for any previous command to complete. 
	 * This should be the common case. 
	 */ 
1997/1011    
	 * Unfortunately there's a chip errata where back-to-back 
	 * CUresumes can be lost, the fix is to always wait. 
1997/0823    
	if(c == CUresume && ctlr->command == CUresume){ 
		csr8w(ctlr, CommandR, c); 
		iunlock(&ctlr->rlock); 
		return; 
	} 
1997/1011    
	 */ 
1997/0823    
 
	while(csr8r(ctlr, CommandR)) 
		; 
1997/0823/sys/src/9/pc/ether82557.c:757,7631997/1011/sys/src/9/pc/ether82557.c:759,765
1997/0327    
		 * bar[1] is the I/O port register address (32 bytes) and 
		 * bar[2] is for the flash ROM (1MB). 
		 */ 
1997/0723    
		i82557adapter(&adapter, p->bar[1] & ~0x01, p->intl, p->tbdf); 
1997/1011    
		i82557adapter(&adapter, p->mem[1].bar & ~0x01, p->intl, p->tbdf); 
1996/0418    
	} 
} 
 
1997/1011/sys/src/9/pc/ether82557.c:190,1961998/0304/sys/src/9/pc/ether82557.c:190,200 (short | long)
1997/0823    
	int	state; 
 
1996/0418    
	int	port; 
1998/0304    
	ushort	eeprom[0x40]; 
1996/0418    
 
1998/0304    
	Rendez	timer;			/* watchdog timer for receive lockup errata */ 
	int	tick; 
 
1997/0327    
	Lock	rlock;			/* registers */ 
1997/0823    
	int	command;		/* last command issued */ 
1996/0418    
 
1997/1011/sys/src/9/pc/ether82557.c:208,2131998/0304/sys/src/9/pc/ether82557.c:212,218
1997/0823    
	Cb*	cbtail; 
	int	cbq; 
	int	cbqmax; 
1998/0304    
	int	cbqmaxhw; 
1996/0607    
 
1996/0622    
	Lock	dlock;			/* dump statistical counters */ 
1996/0607    
	ulong	dump[17]; 
1997/1011/sys/src/9/pc/ether82557.c:230,2361998/0304/sys/src/9/pc/ether82557.c:235,241
1996/0418    
	0x60,				/* inter-frame spacing */ 
	0x00,	 
	0xF2,	 
1996/0601    
	0xC8,				/* promiscuous mode off */ 
1998/0304    
	0xC8,				/* 503, promiscuous mode off */ 
1996/0418    
	0x00,	 
	0x40,	 
1997/0327    
	0xF3,				/* transmit padding enable */ 
1997/1011/sys/src/9/pc/ether82557.c:314,3221998/0304/sys/src/9/pc/ether82557.c:319,360
1997/0327    
} 
 
1996/0418    
static void 
1998/0304    
watchdog(void* arg) 
{ 
	Ether *ether; 
	Ctlr *ctlr; 
	static void txstart(Ether*); 
 
	ether = arg; 
	for(;;){ 
		ctlr = ether->ctlr; 
		tsleep(&ctlr->timer, return0, 0, 4000); 
 
		/* 
		 * Hmmm. This doesn't seem right. Currently 
		 * the device can't be disabled but it may be in 
		 * the future. 
		 */ 
		ctlr = ether->ctlr; 
		if(ctlr == nil || ctlr->state == 0){ 
			print("%s: exiting\n", up->text); 
			pexit("disabled", 0); 
		} 
 
		if(ctlr->tick++){ 
			ilock(&ctlr->cblock); 
			ctlr->action = CbMAS; 
			txstart(ether); 
			iunlock(&ctlr->cblock); 
		} 
	} 
} 
 
static void 
1996/0418    
attach(Ether* ether) 
{ 
	Ctlr *ctlr; 
1998/0304    
	char name[NAMELEN]; 
1996/0418    
 
	ctlr = ether->ctlr; 
1997/0823    
	lock(&ctlr->slock); 
1997/1011/sys/src/9/pc/ether82557.c:323,3281998/0304/sys/src/9/pc/ether82557.c:361,376
1997/0823    
	if(ctlr->state == 0){ 
		command(ctlr, RUstart, PADDR(ctlr->rfdhead->rp)); 
		ctlr->state = 1; 
1998/0304    
 
		/* 
		 * Start the watchdog timer for the receive lockup errata 
		 * unless the EEPROM compatibility word indicates it may be 
		 * omitted. 
		 */ 
		if((ctlr->eeprom[0x03] & 0x0003) != 0x0003){ 
			snprint(name, NAMELEN, "#l%dwatchdog", ether->ctlrno); 
			kproc(name, watchdog, ether); 
		} 
1996/0418    
	} 
1997/0823    
	unlock(&ctlr->slock); 
1996/0418    
} 
1997/1011/sys/src/9/pc/ether82557.c:379,3861998/0304/sys/src/9/pc/ether82557.c:427,437
1997/0807    
	len += snprint(p+len, READSTR-len, "receive overrun errors: %lud\n", dump[13]); 
	len += snprint(p+len, READSTR-len, "receive collision detect errors: %lud\n", dump[14]); 
1997/0823    
	len += snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]); 
	snprint(p+len, READSTR-len, "cbqmax: %lud\n", ctlr->cbqmax); 
ctlr->cbqmax = 0; 
1998/0304    
	if(ctlr->cbqmax > ctlr->cbqmaxhw) 
		ctlr->cbqmaxhw = ctlr->cbqmax; 
	len += snprint(p+len, READSTR-len, "cbqmax: %lud\n", ctlr->cbqmax); 
	ctlr->cbqmax = 0; 
	snprint(p+len, READSTR-len, "threshold: %lud\n", ctlr->threshold); 
1997/0417    
 
	n = readstr(offset, a, n, p); 
	free(p); 
1997/1011/sys/src/9/pc/ether82557.c:422,4271998/0304/sys/src/9/pc/ether82557.c:473,483
1997/0823    
			memmove(cb->data, ether->ea, Eaddrlen); 
			ctlr->action = 0; 
		} 
1998/0304    
		else if(ctlr->action == CbMAS){ 
			cb->command = CbS|CbMAS; 
			memset(cb->data, 0, sizeof(cb->data)); 
			ctlr->action = 0; 
		} 
1997/0823    
		else{ 
			print("#l%d: action 0x%uX\n", ether->ctlrno, ctlr->action); 
			ctlr->action = 0; 
1997/1011/sys/src/9/pc/ether82557.c:456,4611998/0304/sys/src/9/pc/ether82557.c:512,518
1997/0823    
	} 
	else{ 
		ctlr->configdata[6] &= ~0x80; 
1998/0304    
		ctlr->configdata[6] |= 0x40; 
1997/0823    
		ctlr->configdata[7] |= 0x01; 
		ctlr->configdata[15] &= ~0x01; 
		ctlr->configdata[18] |= 0x01;		/* 0x03? */ 
1997/1011/sys/src/9/pc/ether82557.c:505,5101998/0304/sys/src/9/pc/ether82557.c:562,574
1997/0327    
		if(!(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI))) 
1996/0607    
			break; 
1996/0418    
 
1998/0304    
		/* 
		 * If the watchdog timer for the receiver lockup errata is running, 
		 * let it know the receiver is active. 
		 */ 
		if(status & (StatFR|StatRNR)) 
			ctlr->tick = 0; 
 
1996/0418    
		if(status & StatFR){ 
1997/0327    
			bp = ctlr->rfdhead; 
1996/0418    
			rfd = (Rfd*)bp->rp; 
1997/1011/sys/src/9/pc/ether82557.c:648,6731998/0304/sys/src/9/pc/ether82557.c:712,734
1997/0823    
 
1996/0418    
	memmove(ctlr->configdata, configdata, sizeof(configdata)); 
1997/0823    
	ctlr->threshold = 8; 
1998/0304    
	ctlr->tick = 0; 
1997/0823    
 
	iunlock(&ctlr->cblock); 
1996/0418    
} 
 
static int 
dp83840r(Ctlr* ctlr, int phyadd, int regadd) 
1998/0304    
miir(Ctlr* ctlr, int phyadd, int regadd) 
1996/0418    
{ 
	int mcr, timo; 
 
	/* 
	 * DP83840 
	 * 10/100Mb/s Ethernet Physical Layer. 
	 */ 
	csr32w(ctlr, Mcr, MDIread|(phyadd<<21)|(regadd<<16)); 
	mcr = 0; 
	for(timo = 10; timo; timo--){ 
1998/0304    
	for(timo = 64; timo; timo--){ 
1996/0418    
		mcr = csr32r(ctlr, Mcr); 
		if(mcr & MDIready) 
			break; 
		delay(1); 
1998/0304    
		microdelay(1); 
1996/0418    
	} 
 
	if(mcr & MDIready) 
1997/1011/sys/src/9/pc/ether82557.c:677,6821998/0304/sys/src/9/pc/ether82557.c:738,763
1996/0418    
} 
 
static int 
1998/0304    
miiw(Ctlr* ctlr, int phyadd, int regadd, int data) 
{ 
	int mcr, timo; 
 
	csr32w(ctlr, Mcr, MDIwrite|(phyadd<<21)|(regadd<<16)|(data & 0xFFFF)); 
	mcr = 0; 
	for(timo = 64; timo; timo--){ 
		mcr = csr32r(ctlr, Mcr); 
		if(mcr & MDIready) 
			break; 
		microdelay(1); 
	} 
 
	if(mcr & MDIready) 
		return 0; 
 
	return -1; 
} 
 
static int 
1996/0418    
hy93c46r(Ctlr* ctlr, int r) 
{ 
	int i, op, data; 
1997/1011/sys/src/9/pc/ether82557.c:685,6911998/0304/sys/src/9/pc/ether82557.c:766,772
1996/0418    
	 * Hyundai HY93C46 or equivalent serial EEPROM. 
	 * This sequence for reading a 16-bit register 'r' 
	 * in the EEPROM is taken straight from Section 
	 * 2.3.4.2 of the Intel 82557 User's Guide. 
1998/0304    
	 * 3.3.4.2 of the Intel 82557 User's Guide. 
1996/0418    
	 */ 
	csr16w(ctlr, Ecr, EEcs); 
	op = EEstart|EEread; 
1997/1011/sys/src/9/pc/ether82557.c:693,7011998/0304/sys/src/9/pc/ether82557.c:774,782
1996/0418    
		data = (((op>>i) & 0x01)<<2)|EEcs; 
		csr16w(ctlr, Ecr, data); 
		csr16w(ctlr, Ecr, data|EEsk); 
		delay(1); 
1998/0304    
		microdelay(1); 
1996/0418    
		csr16w(ctlr, Ecr, data); 
		delay(1); 
1998/0304    
		microdelay(1); 
1996/0418    
	} 
 
	for(i = EEaddrsz-1; i >= 0; i--){ 
1997/1011/sys/src/9/pc/ether82557.c:704,7101998/0304/sys/src/9/pc/ether82557.c:785,791
1996/0418    
		csr16w(ctlr, Ecr, data|EEsk); 
		delay(1); 
		csr16w(ctlr, Ecr, data); 
		delay(1); 
1998/0304    
		microdelay(1); 
1997/0327    
		if(!(csr16r(ctlr, Ecr) & EEdo)) 
1996/0418    
			break; 
	} 
1997/1011/sys/src/9/pc/ether82557.c:712,7221998/0304/sys/src/9/pc/ether82557.c:793,803
1996/0418    
	data = 0; 
	for(i = 15; i >= 0; i--){ 
		csr16w(ctlr, Ecr, EEcs|EEsk); 
		delay(1); 
1998/0304    
		microdelay(1); 
1996/0418    
		if(csr16r(ctlr, Ecr) & EEdo) 
			data |= (1<<i); 
		csr16w(ctlr, Ecr, EEcs); 
		delay(1); 
1998/0304    
		microdelay(1); 
1996/0418    
	} 
 
	csr16w(ctlr, Ecr, 0); 
1997/1011/sys/src/9/pc/ether82557.c:766,7721998/0304/sys/src/9/pc/ether82557.c:847,854
1996/0418    
static int 
reset(Ether* ether) 
{ 
1997/0327    
	int i, port, x; 
1998/0304    
	int an, i, phyaddr, port, x; 
	unsigned short sum; 
1997/0327    
	Block *bp, **bpp; 
	Adapter *ap; 
1996/0418    
	uchar ea[Eaddrlen]; 
1997/1011/sys/src/9/pc/ether82557.c:827,8631998/0304/sys/src/9/pc/ether82557.c:909,977
1996/0418    
	ctlrinit(ctlr); 
 
	/* 
	 * Possibly need to configure the physical-layer chip here, but the 
	 * EtherExpress PRO/100B appears to bring it up with a sensible default 
	 * configuration. However, should check for the existence of the PHY 
	 * and, if found, check whether to use 82503 (serial) or MII (nibble) 
1997/0723    
	 * mode. Verify the PHY is a National Semiconductor DP83840 (OUI 0x80017) 
	 * or an Intel 82555 (OUI 0xAA00) by looking at the Organizationally Unique 
	 * Identifier (OUI) in registers 2 and 3. 
1998/0304    
	 * Read the EEPROM. 
1996/0418    
	 */ 
	for(i = 1; i < 32; i++){ 
		if((x = dp83840r(ctlr, i, 2)) == 0xFFFF) 
			continue; 
		x <<= 6; 
		x |= dp83840r(ctlr, i, 3)>>10; 
1997/0723    
		if(x != 0x80017 && x != 0xAA00) 
			print("#l%d: unrecognised PHY - OUI 0x%4.4uX\n", ether->ctlrno, x); 
1998/0304    
	sum = 0; 
	for(i = 0; i < 0x40; i++){ 
		x = hy93c46r(ctlr, i); 
		ctlr->eeprom[i] = x; 
		sum += x; 
	} 
	if(sum != 0xBABA) 
		print("#l%d: EEPROM checksum - 0x%4.4uX\n", ether->ctlrno, sum); 
1996/0418    
 
1996/0625    
		x = dp83840r(ctlr, i, 0x19); 
1997/0327    
		if(!(x & 0x0040)){ 
1998/0304    
	/* 
	 * Eeprom[6] indicates whether there is a PHY and whether 
	 * it's not 10Mb-only, in which case use the given PHY address 
	 * to set any PHY specific options and determine the speed. 
	 * If no PHY, assume 82503 (serial) operation. 
	 */ 
	if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)){ 
		phyaddr = ctlr->eeprom[6] & 0x00FF; 
 
		/* 
		 * Resolve the highest common ability of the two 
		 * link partners. In descending order: 
		 *	0x0100		100BASE-TX Full Duplex 
		 *	0x0200		100BASE-T4 
		 *	0x0080		100BASE-TX 
		 *	0x0040		10BASE-T Full Duplex 
		 *	0x0020		10BASE-T 
		 */ 
		an = miir(ctlr, phyaddr, 0x04); 
		an &= miir(ctlr, phyaddr, 0x05) & 0x03E0; 
		if(an & 0x380) 
1996/0625    
			ether->mbps = 100; 
1996/0418    
			ctlr->configdata[8] = 1; 
1996/0601    
			ctlr->configdata[15] &= ~0x80; 
1996/0625    
		} 
		else{ 
			x = dp83840r(ctlr, i, 0x1B); 
1997/0327    
			if(!(x & 0x0200)){ 
1996/0625    
				ctlr->configdata[8] = 1; 
				ctlr->configdata[15] &= ~0x80; 
1998/0304    
 
		switch((ctlr->eeprom[6]>>8) & 0x001F){ 
 
		case 0x04:				/* DP83840 */ 
		case 0x0A:				/* DP83840A */ 
			/* 
			 * The DP83840[A] requires some tweaking for 
			 * reliable operation. 
			 */ 
			x = miir(ctlr, phyaddr, 0x17) & ~0x0520; 
			x |= 0x0020; 
			for(i = 0; i < ether->nopt; i++){ 
				if(cistrcmp(ether->opt[i], "congestioncontrol")) 
					continue; 
				x |= 0x0100; 
				break; 
1996/0625    
			} 
1998/0304    
			if(an & 0x0140) 
				x |= 0x0400; 
			miiw(ctlr, phyaddr, 0x17, x); 
			break; 
1996/0418    
		} 
		break; 
1998/0304    
 
		ctlr->configdata[8] = 1; 
		ctlr->configdata[15] &= ~0x80; 
1996/0418    
	} 
1998/0304    
	else{ 
		ctlr->configdata[8] = 0; 
		ctlr->configdata[15] |= 0x80; 
	} 
1996/0418    
 
	/* 
1997/0823    
	 * Load the chip configuration and start it off. 
1997/1011/sys/src/9/pc/ether82557.c:875,8811998/0304/sys/src/9/pc/ether82557.c:989,995
1996/0418    
	memset(ea, 0, Eaddrlen); 
1997/0806    
	if(memcmp(ea, ether->ea, Eaddrlen) == 0){ 
1996/0418    
		for(i = 0; i < Eaddrlen/2; i++){ 
			x = hy93c46r(ctlr, i); 
1998/0304    
			x = ctlr->eeprom[i]; 
1997/0327    
			ether->ea[2*i] = x; 
			ether->ea[2*i+1] = x>>8; 
1996/0418    
		} 
1998/0304/sys/src/9/pc/ether82557.c:554,5631998/0331/sys/src/9/pc/ether82557.c:554,563 (short | long)
Use ilock instead of lock in interrupt handler.
XXX - Is this necessary?
rsc Fri Mar 4 12:44:25 2005
1996/0418    
	ctlr = ether->ctlr; 
 
	for(;;){ 
1997/0327    
		lock(&ctlr->rlock); 
1998/0331    
		ilock(&ctlr->rlock); 
1996/0418    
		status = csr16r(ctlr, Status); 
		csr8w(ctlr, Ack, (status>>8) & 0xFF); 
1997/0327    
		unlock(&ctlr->rlock); 
1998/0331    
		iunlock(&ctlr->rlock); 
1996/0418    
 
1997/0327    
		if(!(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI))) 
1996/0607    
			break; 
1998/0304/sys/src/9/pc/ether82557.c:634,6401998/0331/sys/src/9/pc/ether82557.c:634,640
1996/0418    
		} 
 
		if(status & StatCNA){ 
1997/0823    
			lock(&ctlr->cblock); 
1998/0331    
			ilock(&ctlr->cblock); 
1997/0823    
 
			cb = ctlr->cbtail; 
			while(ctlr->cbq){ 
1998/0304/sys/src/9/pc/ether82557.c:653,6591998/0331/sys/src/9/pc/ether82557.c:653,659
1997/0823    
			ctlr->cbtail = cb; 
1996/0418    
 
1997/0823    
			txstart(ether); 
			unlock(&ctlr->cblock); 
1998/0331    
			iunlock(&ctlr->cblock); 
1997/0823    
 
1996/0418    
			status &= ~StatCNA; 
		} 
1998/0331/sys/src/9/pc/ether82557.c:530,5351998/0507/sys/src/9/pc/ether82557.c:530,542 (short | long)
Add multicast function.
rsc Fri Mar 4 12:44:25 2005
1997/0823    
} 
1996/0418    
 
1997/0823    
static void 
1998/0507    
multicast(void* arg, uchar *addr, int on) 
{ 
	USED(addr, on); 
	configure(arg, 1); 
} 
 
static void 
1997/0823    
transmit(Ether* ether) 
{ 
	Ctlr *ctlr; 
1998/0331/sys/src/9/pc/ether82557.c:1010,10151998/0507/sys/src/9/pc/ether82557.c:1017,1023
1996/0607    
	ether->ifstat = ifstat; 
1996/0418    
 
1996/0607    
	ether->promiscuous = promiscuous; 
1998/0507    
	ether->multicast = multicast; 
1996/0418    
	ether->arg = ether; 
 
	return 0; 
1998/0507/sys/src/9/pc/ether82557.c:854,8601998/0511/sys/src/9/pc/ether82557.c:854,860 (short | long)
Add auto-negotiation for 82555.
Add fullduplex and speed options for cards that cannot auto-negotiate.
rsc Fri Mar 4 12:44:25 2005
1996/0418    
static int 
reset(Ether* ether) 
{ 
1998/0304    
	int an, i, phyaddr, port, x; 
1998/0511    
	int anar, anlpar, bmcr, bmsr, force, i, phyaddr, port, x; 
1998/0304    
	unsigned short sum; 
1997/0327    
	Block *bp, **bpp; 
	Adapter *ap; 
1998/0507/sys/src/9/pc/ether82557.c:945,9541998/0511/sys/src/9/pc/ether82557.c:945,958
1998/0304    
		 *	0x0040		10BASE-T Full Duplex 
		 *	0x0020		10BASE-T 
		 */ 
		an = miir(ctlr, phyaddr, 0x04); 
		an &= miir(ctlr, phyaddr, 0x05) & 0x03E0; 
		if(an & 0x380) 
1996/0625    
			ether->mbps = 100; 
1998/0511    
		anar = miir(ctlr, phyaddr, 0x04); 
		anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0; 
		anar &= anlpar; 
		bmcr = 0; 
		if(anar & 0x380) 
			bmcr = 0x2000; 
		if(anar & 0x0140) 
			bmcr |= 0x0100; 
1998/0304    
 
		switch((ctlr->eeprom[6]>>8) & 0x001F){ 
 
1998/0507/sys/src/9/pc/ether82557.c:957,9651998/0511/sys/src/9/pc/ether82557.c:961,972
1998/0304    
			/* 
			 * The DP83840[A] requires some tweaking for 
			 * reliable operation. 
1998/0511    
			 * The manual says bit 10 should be unconditionally 
			 * set although it supposedly only affects full-duplex 
			 * operation (an & 0x0140). 
1998/0304    
			 */ 
			x = miir(ctlr, phyaddr, 0x17) & ~0x0520; 
			x |= 0x0020; 
1998/0511    
			x |= 0x0420; 
1998/0304    
			for(i = 0; i < ether->nopt; i++){ 
				if(cistrcmp(ether->opt[i], "congestioncontrol")) 
					continue; 
1998/0507/sys/src/9/pc/ether82557.c:966,9751998/0511/sys/src/9/pc/ether82557.c:973,1047
1998/0304    
				x |= 0x0100; 
				break; 
1996/0625    
			} 
1998/0304    
			if(an & 0x0140) 
				x |= 0x0400; 
			miiw(ctlr, phyaddr, 0x17, x); 
1998/0511    
 
			/* 
			 * If the link partner can't autonegotiate, determine 
			 * the speed from elsewhere. 
			 */ 
			if(anlpar == 0){ 
				miir(ctlr, phyaddr, 0x01); 
				bmsr = miir(ctlr, phyaddr, 0x01); 
				x = miir(ctlr, phyaddr, 0x19); 
				if((bmsr & 0x0004) && !(x & 0x0040)) 
					bmcr = 0x2000; 
			} 
1998/0304    
			break; 
1998/0511    
 
		case 0x07:				/* Intel 82555 */ 
			/* 
			 * Auto-negotiation may fail if the other end is 
			 * a DP83840A and the cable is short. 
			 */ 
			miir(ctlr, phyaddr, 0x01); 
			bmsr = miir(ctlr, phyaddr, 0x01); 
			if((miir(ctlr, phyaddr, 0) & 0x1000) && !(bmsr & 0x0020)){ 
				miiw(ctlr, phyaddr, 0x1A, 0x2010); 
				x = miir(ctlr, phyaddr, 0); 
				miiw(ctlr, phyaddr, 0, 0x0200|x); 
				for(i = 0; i < 3000; i++){ 
					delay(1); 
					if(miir(ctlr, phyaddr, 0x01) & 0x0020) 
						break; 
				} 
				miiw(ctlr, phyaddr, 0x1A, 0x2000); 
					 
				anar = miir(ctlr, phyaddr, 0x04); 
				anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0; 
				anar &= anlpar; 
				bmcr = 0; 
				if(anar & 0x380) 
					bmcr = 0x2000; 
				if(anar & 0x0140) 
					bmcr |= 0x0100; 
			} 
			break; 
		} 
 
		/* 
		 * Force speed and duplex if no auto-negotiation. 
		 */ 
		if(anlpar == 0){ 
			force = 0; 
			for(i = 0; i < ether->nopt; i++){ 
				if(cistrcmp(ether->opt[i], "fullduplex") == 0){ 
					force = 1; 
					bmcr |= 0x0100; 
					ctlr->configdata[19] |= 0x40; 
				} 
				else if(cistrcmp(ether->opt[i], "speed") == 0){ 
					force = 1; 
					x = strtol(ðer->opt[i][6], 0, 0); 
					if(x == 10) 
						bmcr &= ~0x2000; 
					else if(x == 100) 
						bmcr |= 0x2000; 
					else 
						force = 0; 
				} 
			} 
			if(force) 
				miiw(ctlr, phyaddr, 0x00, bmcr); 
1996/0418    
		} 
1998/0304    
 
		ctlr->configdata[8] = 1; 
1998/0511/sys/src/9/pc/ether82557.c:108,1141998/0522/sys/src/9/pc/ether82557.c:108,114 (short | long)
Bug fix?: call coherence after changing card data.
Buf fix? or paranoia: use 1700 instead of sizeof(Etherpkt) and don't discard overruns.
rsc Fri Mar 4 12:44:25 2005
1996/0418    
	ushort	count; 
	ushort	size; 
 
1997/0327    
	uchar	data[sizeof(Etherpkt)]; 
1998/0522    
	uchar	data[1700]; 
1996/0418    
} Rfd; 
 
enum {					/* field */ 
1998/0511/sys/src/9/pc/ether82557.c:485,4901998/0522/sys/src/9/pc/ether82557.c:485,491
1997/0823    
		} 
		cb->status = 0; 
 
1998/0522    
		coherence(); 
1997/0823    
		ctlr->cbhead->command &= ~CbS; 
		ctlr->cbhead = cb; 
		ctlr->cbq++; 
1998/0511/sys/src/9/pc/ether82557.c:504,5101998/0522/sys/src/9/pc/ether82557.c:505,511
1997/0823    
	ilock(&ctlr->cblock); 
	if(promiscuous){ 
		ctlr->configdata[6] |= 0x80;		/* Save Bad Frames */ 
		ctlr->configdata[6] &= ~0x40;		/* !Discard Overrun Rx Frames */ 
1998/0522    
		//ctlr->configdata[6] &= ~0x40;		/* !Discard Overrun Rx Frames */ 
1997/0823    
		ctlr->configdata[7] &= ~0x01;		/* !Discard Short Rx Frames */ 
		ctlr->configdata[15] |= 0x01;		/* Promiscuous mode */ 
		ctlr->configdata[18] &= ~0x01;		/* (!Padding enable?), !stripping enable */ 
1998/0511/sys/src/9/pc/ether82557.c:512,5181998/0522/sys/src/9/pc/ether82557.c:513,519
1997/0823    
	} 
	else{ 
		ctlr->configdata[6] &= ~0x80; 
1998/0304    
		ctlr->configdata[6] |= 0x40; 
1998/0522    
		//ctlr->configdata[6] |= 0x40; 
1997/0823    
		ctlr->configdata[7] |= 0x01; 
		ctlr->configdata[15] &= ~0x01; 
		ctlr->configdata[18] |= 0x01;		/* 0x03? */ 
1998/0511/sys/src/9/pc/ether82557.c:592,5981998/0522/sys/src/9/pc/ether82557.c:593,599
1997/0327    
				 * If not, just adjust the necessary fields for reuse. 
				 */ 
				if((rfd->field & RfdOK) && (xbp = rfdalloc(rfd->link))){ 
					bp->rp += sizeof(Rfd)-sizeof(Etherpkt); 
1998/0522    
					bp->rp += sizeof(Rfd)-sizeof(rfd->data); 
1997/0327    
					bp->wp = bp->rp + (rfd->count & 0x3FFF); 
 
					xbp->next = bp->next; 
1998/0511/sys/src/9/pc/ether82557.c:621,6261998/0522/sys/src/9/pc/ether82557.c:622,628
1997/0327    
				ctlr->rfdtail->next = bp; 
				((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp); 
				((Rfd*)ctlr->rfdtail->rp)->field |= RfdS; 
1998/0522    
				coherence(); 
1996/0418    
				rfd->field &= ~RfdS; 
 
1997/0327    
				/* 
1998/0522/sys/src/9/pc/ether82557.c:429,4371998/0825/sys/src/9/pc/ether82557.c:429,437 (short | long)
Bug fix: print format.
rsc Fri Mar 4 12:44:25 2005
1997/0823    
	len += snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]); 
1998/0304    
	if(ctlr->cbqmax > ctlr->cbqmaxhw) 
		ctlr->cbqmaxhw = ctlr->cbqmax; 
	len += snprint(p+len, READSTR-len, "cbqmax: %lud\n", ctlr->cbqmax); 
1998/0825    
	len += snprint(p+len, READSTR-len, "cbqmax: %d\n", ctlr->cbqmax); 
1998/0304    
	ctlr->cbqmax = 0; 
	snprint(p+len, READSTR-len, "threshold: %lud\n", ctlr->threshold); 
1998/0825    
	snprint(p+len, READSTR-len, "threshold: %d\n", ctlr->threshold); 
1997/0417    
 
	n = readstr(offset, a, n, p); 
	free(p); 
1998/0825/sys/src/9/pc/ether82557.c:192,1971998/0929/sys/src/9/pc/ether82557.c:192,199 (short | long)
1996/0418    
	int	port; 
1998/0304    
	ushort	eeprom[0x40]; 
1996/0418    
 
1998/0929    
	Lock	miilock; 
 
1998/0304    
	Rendez	timer;			/* watchdog timer for receive lockup errata */ 
	int	tick; 
 
1998/0825/sys/src/9/pc/ether82557.c:379,3851998/0929/sys/src/9/pc/ether82557.c:381,387
1996/0607    
ifstat(Ether* ether, void* a, long n, ulong offset) 
{ 
1997/0417    
	char *p; 
1996/0607    
	int len; 
1998/0929    
	int i, len, phyaddr; 
1997/0417    
	Ctlr *ctlr; 
	ulong dump[17]; 
1996/0607    
 
1998/0825/sys/src/9/pc/ether82557.c:431,4381998/0929/sys/src/9/pc/ether82557.c:433,459
1998/0304    
		ctlr->cbqmaxhw = ctlr->cbqmax; 
1998/0825    
	len += snprint(p+len, READSTR-len, "cbqmax: %d\n", ctlr->cbqmax); 
1998/0304    
	ctlr->cbqmax = 0; 
1998/0825    
	snprint(p+len, READSTR-len, "threshold: %d\n", ctlr->threshold); 
1998/0929    
	len += snprint(p+len, READSTR-len, "threshold: %d\n", ctlr->threshold); 
1997/0417    
 
1998/0929    
	len += snprint(p+len, READSTR-len, "eeprom:"); 
	for(i = 0; i < 0x40; i++){ 
		if(i && ((i & 0x07) == 0)) 
			len += snprint(p+len, READSTR-len, "\n       "); 
		len += snprint(p+len, READSTR-len, " %4.4uX", ctlr->eeprom[i]); 
	} 
 
	if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)){ 
		phyaddr = ctlr->eeprom[6] & 0x00FF; 
		len += snprint(p+len, READSTR-len, "\nphy %2d:", phyaddr); 
		for(i = 0; i < 6; i++){ 
			static int miir(Ctlr*, int, int); 
 
			len += snprint(p+len, READSTR-len, " %4.4uX", 
				miir(ctlr, phyaddr, i)); 
		} 
	} 
 
	snprint(p+len, READSTR-len, "\n"); 
1997/0417    
	n = readstr(offset, a, n, p); 
	free(p); 
 
1998/0825/sys/src/9/pc/ether82557.c:731,7361998/0929/sys/src/9/pc/ether82557.c:752,758
1996/0418    
{ 
	int mcr, timo; 
 
1998/0929    
	lock(&ctlr->miilock); 
1996/0418    
	csr32w(ctlr, Mcr, MDIread|(phyadd<<21)|(regadd<<16)); 
	mcr = 0; 
1998/0304    
	for(timo = 64; timo; timo--){ 
1998/0825/sys/src/9/pc/ether82557.c:739,7441998/0929/sys/src/9/pc/ether82557.c:761,767
1996/0418    
			break; 
1998/0304    
		microdelay(1); 
1996/0418    
	} 
1998/0929    
	unlock(&ctlr->miilock); 
1996/0418    
 
	if(mcr & MDIready) 
		return mcr & 0xFFFF; 
1998/0825/sys/src/9/pc/ether82557.c:751,7561998/0929/sys/src/9/pc/ether82557.c:774,780
1998/0304    
{ 
	int mcr, timo; 
 
1998/0929    
	lock(&ctlr->miilock); 
1998/0304    
	csr32w(ctlr, Mcr, MDIwrite|(phyadd<<21)|(regadd<<16)|(data & 0xFFFF)); 
	mcr = 0; 
	for(timo = 64; timo; timo--){ 
1998/0825/sys/src/9/pc/ether82557.c:759,7641998/0929/sys/src/9/pc/ether82557.c:783,789
1998/0304    
			break; 
		microdelay(1); 
	} 
1998/0929    
	unlock(&ctlr->miilock); 
1998/0304    
 
	if(mcr & MDIready) 
		return 0; 
1998/0825/sys/src/9/pc/ether82557.c:853,8621998/0929/sys/src/9/pc/ether82557.c:878,899
1996/0418    
	} 
} 
 
1998/0929    
static char* mediatable[9] = { 
	"10BASE-T",				/* TP */ 
	"10BASE-2",				/* BNC */ 
	"10BASE-5",				/* AUI */ 
	"100BASE-TX", 
	"10BASE-TFD", 
	"100BASE-TXFD", 
	"100BASE-T4", 
	"100BASE-FX", 
	"100BASE-FXFD", 
}; 
 
1996/0418    
static int 
reset(Ether* ether) 
{ 
1998/0511    
	int anar, anlpar, bmcr, bmsr, force, i, phyaddr, port, x; 
1998/0929    
	int anar, anlpar, bmcr, bmsr, i, k, medium, phyaddr, port, x; 
1998/0304    
	unsigned short sum; 
1997/0327    
	Block *bp, **bpp; 
	Adapter *ap; 
1998/0825/sys/src/9/pc/ether82557.c:1024,10481998/0929/sys/src/9/pc/ether82557.c:1061,1106
1998/0511    
		 * Force speed and duplex if no auto-negotiation. 
		 */ 
		if(anlpar == 0){ 
			force = 0; 
1998/0929    
			medium = -1; 
1998/0511    
			for(i = 0; i < ether->nopt; i++){ 
				if(cistrcmp(ether->opt[i], "fullduplex") == 0){ 
					force = 1; 
					bmcr |= 0x0100; 
1998/0929    
				for(k = 0; k < nelem(mediatable); k++){ 
					if(cistrcmp(mediatable[k], ether->opt[i])) 
						continue; 
					medium = k; 
					break; 
				} 
		 
				switch(medium){ 
				default: 
					break; 
 
				case 0x00:			/* 10BASE-T */ 
				case 0x01:			/* 10BASE-2 */ 
				case 0x02:			/* 10BASE-5 */ 
					bmcr &= ~(0x2000|0x0100); 
					ctlr->configdata[19] &= ~0x40; 
					break; 
 
				case 0x03:			/* 100BASE-TX */ 
				case 0x06:			/* 100BASE-T4 */ 
				case 0x07:			/* 100BASE-FX */ 
					ctlr->configdata[19] &= ~0x40; 
					bmcr |= 0x2000; 
					break; 
 
				case 0x04:			/* 10BASE-TFD */ 
					bmcr = (bmcr & ~0x2000)|0x0100; 
1998/0511    
					ctlr->configdata[19] |= 0x40; 
1998/0929    
					break; 
 
				case 0x05:			/* 100BASE-TXFD */ 
				case 0x08:			/* 100BASE-FXFD */ 
					bmcr |= 0x2000|0x0100; 
					ctlr->configdata[19] |= 0x40; 
					break; 
1998/0511    
				} 
				else if(cistrcmp(ether->opt[i], "speed") == 0){ 
					force = 1; 
					x = strtol(ðer->opt[i][6], 0, 0); 
					if(x == 10) 
						bmcr &= ~0x2000; 
					else if(x == 100) 
						bmcr |= 0x2000; 
					else 
						force = 0; 
				} 
			} 
			if(force) 
1998/0929    
			if(medium != -1) 
1998/0511    
				miiw(ctlr, phyaddr, 0x00, bmcr); 
1996/0418    
		} 
1998/0304    
 
1998/0929/sys/src/9/pc/ether82557.c:570,5801998/0930/sys/src/9/pc/ether82557.c:570,659 (short | long)
1996/0418    
} 
 
static void 
interrupt(Ureg*, void* arg) 
1998/0930    
receive(Ether* ether) 
1996/0418    
{ 
	Rfd *rfd; 
1998/0930    
	Ctlr *ctlr; 
	int count; 
	Block *bp, *pbp, *xbp; 
 
	ctlr = ether->ctlr; 
	bp = ctlr->rfdhead; 
	for(rfd = (Rfd*)bp->rp; rfd->field & RfdC; rfd = (Rfd*)bp->rp){ 
		/* 
		 * If it's an OK receive frame 
		 * 1) save the count  
		 * 2) if it's small, try to allocate a block and copy 
		 *    the data, then adjust the necessary fields for reuse; 
		 * 3) if it's big, try to allocate a new Rfd and if 
		 *    successful 
		 *	adjust the received buffer pointers for the 
		 *	  actual data received; 
		 *	initialise the replacement buffer to point to 
		 *	  the next in the ring; 
		 *	initialise bp to point to the replacement; 
		 * 4) if there's a good packet, pass it on for disposal. 
		 */ 
		if(rfd->field & RfdOK){ 
			pbp = nil; 
			count = rfd->count & 0x3FFF; 
			if((count < ETHERMAXTU/4) && (pbp = iallocb(count))){ 
				memmove(pbp->rp, bp->rp+sizeof(Rfd)-sizeof(rfd->data), count); 
				pbp->wp = pbp->rp + count; 
 
				rfd->count = 0; 
				rfd->field = 0; 
			} 
			else if(xbp = rfdalloc(rfd->link)){ 
				bp->rp += sizeof(Rfd)-sizeof(rfd->data); 
				bp->wp = bp->rp + count; 
 
				xbp->next = bp->next; 
				bp->next = 0; 
 
				pbp = bp; 
				bp = xbp; 
			} 
			if(pbp != nil) 
				etheriq(ether, pbp, 1); 
		} 
		else{ 
			rfd->count = 0; 
			rfd->field = 0; 
		} 
 
		/* 
		 * The ring tail pointer follows the head with with one 
		 * unused buffer in between to defeat hardware prefetch; 
		 * once the tail pointer has been bumped on to the next 
		 * and the new tail has the Suspend bit set, it can be 
		 * removed from the old tail buffer. 
		 * As a replacement for the current head buffer may have 
		 * been allocated above, ensure that the new tail points 
		 * to it (next and link). 
		 */ 
		rfd = (Rfd*)ctlr->rfdtail->rp; 
		ctlr->rfdtail = ctlr->rfdtail->next; 
		ctlr->rfdtail->next = bp; 
		((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp); 
		((Rfd*)ctlr->rfdtail->rp)->field |= RfdS; 
		coherence(); 
		rfd->field &= ~RfdS; 
 
		/* 
		 * Finally done with the current (possibly replaced) 
		 * head, move on to the next and maintain the sentinel 
		 * between tail and head. 
		 */ 
		ctlr->rfdhead = bp->next; 
		bp = ctlr->rfdhead; 
	} 
} 
 
static void 
interrupt(Ureg*, void* arg) 
{ 
1997/0327    
	Cb* cb; 
	Block *bp, *xbp; 
1996/0418    
	Ctlr *ctlr; 
	Ether *ether; 
	int status; 
1998/0929/sys/src/9/pc/ether82557.c:599,6601998/0930/sys/src/9/pc/ether82557.c:678,684
1998/0304    
			ctlr->tick = 0; 
 
1996/0418    
		if(status & StatFR){ 
1997/0327    
			bp = ctlr->rfdhead; 
1996/0418    
			rfd = (Rfd*)bp->rp; 
			while(rfd->field & RfdC){ 
1997/0327    
				/* 
				 * If it's an OK receive frame and a replacement buffer 
				 * can be allocated then 
				 *	adjust the received buffer pointers for the 
				 *	  actual data received; 
				 *	initialise the replacement buffer to point to 
				 *	  the next in the ring; 
				 *	pass the received buffer on for disposal; 
				 *	initialise bp to point to the replacement. 
				 * If not, just adjust the necessary fields for reuse. 
				 */ 
				if((rfd->field & RfdOK) && (xbp = rfdalloc(rfd->link))){ 
1998/0522    
					bp->rp += sizeof(Rfd)-sizeof(rfd->data); 
1997/0327    
					bp->wp = bp->rp + (rfd->count & 0x3FFF); 
                 
					xbp->next = bp->next; 
					bp->next = 0; 
                 
					etheriq(ether, bp, 1); 
					bp = xbp; 
1996/0607    
				} 
1997/0327    
				else{ 
					rfd->field = 0; 
					rfd->count = 0; 
				} 
1996/0418    
                 
				/* 
1997/0327    
				 * The ring tail pointer follows the head with with one 
				 * unused buffer in between to defeat hardware prefetch; 
				 * once the tail pointer has been bumped on to the next 
				 * and the new tail has the Suspend bit set, it can be 
				 * removed from the old tail buffer. 
				 * As a replacement for the current head buffer may have 
				 * been allocated above, ensure that the new tail points 
				 * to it (next and link). 
1996/0418    
				 */ 
1997/0327    
				rfd = (Rfd*)ctlr->rfdtail->rp; 
				ctlr->rfdtail = ctlr->rfdtail->next; 
				ctlr->rfdtail->next = bp; 
				((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp); 
				((Rfd*)ctlr->rfdtail->rp)->field |= RfdS; 
1998/0522    
				coherence(); 
1996/0418    
				rfd->field &= ~RfdS; 
                 
1997/0327    
				/* 
				 * Finally done with the current (possibly replaced) 
				 * head, move on to the next and maintain the sentinel 
				 * between tail and head. 
				 */ 
				ctlr->rfdhead = bp->next; 
				bp = ctlr->rfdhead; 
1996/0418    
				rfd = (Rfd*)bp->rp; 
			} 
1998/0930    
			receive(ether); 
1996/0418    
			status &= ~StatFR; 
		} 
 
1998/0930/sys/src/9/pc/ether82557.c:226,2321998/1024/sys/src/9/pc/ether82557.c:226,233 (short | long)
1996/0418    
	0x00,				/* adaptive IFS */ 
	0x00,	 
1997/0327    
	0x00,				/* Rx DMA maximum byte count */ 
	0x80,				/* Tx DMA maximum byte count */ 
1998/1024    
//	0x80,				/* Tx DMA maximum byte count */ 
	0x00,				/* Tx DMA maximum byte count */ 
1997/0327    
	0x32,				/* !late SCB, CNA interrupts */ 
	0x03,				/* discard short Rx frames */ 
1996/0418    
	0x00,				/* 503/MII */ 
1998/0930/sys/src/9/pc/ether82557.c:343,3541998/1024/sys/src/9/pc/ether82557.c:344,355
1998/0304    
			pexit("disabled", 0); 
		} 
 
1998/1024    
		ilock(&ctlr->cblock); 
1998/0304    
		if(ctlr->tick++){ 
			ilock(&ctlr->cblock); 
			ctlr->action = CbMAS; 
			txstart(ether); 
			iunlock(&ctlr->cblock); 
		} 
1998/1024    
		iunlock(&ctlr->cblock); 
1998/0304    
	} 
} 
 
1998/0930/sys/src/9/pc/ether82557.c:674,6811998/1024/sys/src/9/pc/ether82557.c:675,685
1998/0304    
		 * If the watchdog timer for the receiver lockup errata is running, 
		 * let it know the receiver is active. 
		 */ 
		if(status & (StatFR|StatRNR)) 
1998/1024    
		if(status & (StatFR|StatRNR)){ 
			ilock(&ctlr->cblock); 
1998/0304    
			ctlr->tick = 0; 
1998/1024    
			iunlock(&ctlr->cblock); 
		} 
1998/0304    
 
1996/0418    
		if(status & StatFR){ 
1998/0930    
			receive(ether); 
1998/0930/sys/src/9/pc/ether82557.c:765,7711998/1024/sys/src/9/pc/ether82557.c:769,775
1997/0823    
	ctlr->cbq = 0; 
 
1996/0418    
	memmove(ctlr->configdata, configdata, sizeof(configdata)); 
1997/0823    
	ctlr->threshold = 8; 
1998/1024    
	ctlr->threshold = 80; 
1998/0304    
	ctlr->tick = 0; 
1997/0823    
 
	iunlock(&ctlr->cblock); 
1998/0930/sys/src/9/pc/ether82557.c:1127,11321998/1024/sys/src/9/pc/ether82557.c:1131,1139
1998/0929    
			if(medium != -1) 
1998/0511    
				miiw(ctlr, phyaddr, 0x00, bmcr); 
1996/0418    
		} 
1998/1024    
 
		if(bmcr & 0x2000) 
			ether->mbps = 100; 
1998/0304    
 
		ctlr->configdata[8] = 1; 
		ctlr->configdata[15] &= ~0x80; 
1998/1024/sys/src/9/pc/ether82557.c:362,3671998/1126/sys/src/9/pc/ether82557.c:362,370 (short | long)
1996/0418    
	ctlr = ether->ctlr; 
1997/0823    
	lock(&ctlr->slock); 
	if(ctlr->state == 0){ 
1998/1126    
		ilock(&ctlr->rlock); 
		csr8w(ctlr, Interrupt, 0); 
		iunlock(&ctlr->rlock); 
1997/0823    
		command(ctlr, RUstart, PADDR(ctlr->rfdhead->rp)); 
		ctlr->state = 1; 
1998/0304    
 
1998/1024/sys/src/9/pc/ether82557.c:970,9751998/1126/sys/src/9/pc/ether82557.c:973,979
1997/0327    
	ilock(&ctlr->rlock); 
1996/0418    
	csr32w(ctlr, Port, 0); 
	delay(1); 
1998/1126    
	csr8w(ctlr, Interrupt, InterruptM); 
1997/0327    
	iunlock(&ctlr->rlock); 
1996/0607    
 
1997/0823    
	command(ctlr, LoadRUB, 0); 
Too many diffs (26 > 25). Stopping.


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