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

pc/etherelnk3.c (diff list | history)

1996/0607/sys/src/9/pc/etherelnk3.c:564,5701996/0608/sys/src/9/pc/etherelnk3.c:564,569 (short | long)
1996/0607    
		 */ 
		if(rxstatus & rxError){ 
			if(ctlr->rxstatus9){ 
iprint("R%uX|", rxstatus); 
				switch(rxstatus & rxError9){ 
 
				case rxOverrun9: 
1996/0607/sys/src/9/pc/etherelnk3.c:588,5941996/0608/sys/src/9/pc/etherelnk3.c:587,592
1996/0607    
			} 
			else{ 
				rxerror = inb(port+RxError); 
iprint("R%uX|", rxerror); 
				if(rxerror & rxOverrun) 
					ether->overflows++; 
				if(rxerror & (oversizedFrame|runtFrame)) 
1996/0608/sys/src/9/pc/etherelnk3.c:409,4141996/0612/sys/src/9/pc/etherelnk3.c:409,415 (short | long)
1996/0607    
	x = interruptMask|interruptLatch; 
	if(ctlr->busmaster) 
		x &= ~(rxEarly|rxComplete); 
1996/0612    
x &= ~rxEarly; 
1996/0607    
	COMMAND(port, SetIndicationEnable, x); 
	COMMAND(port, SetInterruptEnable, x); 
 
1996/0612/sys/src/9/pc/etherelnk3.c:2,71996/0613/sys/src/9/pc/etherelnk3.c:2,8 (short | long)
1996/0607    
 * Etherlink III and Fast EtherLink adapters. 
 * To do: 
 *	check robustness in the face of errors; 
1996/0613    
 *	RxEarly and busmaster; 
1996/0607    
 *	autoSelect; 
 *	PCI latency timer and master enable; 
 *	errata list. 
1996/0612/sys/src/9/pc/etherelnk3.c:409,4151996/0613/sys/src/9/pc/etherelnk3.c:410,415
1996/0607    
	x = interruptMask|interruptLatch; 
	if(ctlr->busmaster) 
		x &= ~(rxEarly|rxComplete); 
1996/0612    
x &= ~rxEarly; 
1996/0607    
	COMMAND(port, SetIndicationEnable, x); 
	COMMAND(port, SetInterruptEnable, x); 
 
1996/0612/sys/src/9/pc/etherelnk3.c:745,7501996/0613/sys/src/9/pc/etherelnk3.c:745,758
1996/0607    
		} 
 
		/* 
1996/0613    
		 * Currently, this shouldn't happen. 
		 */ 
		if(status & rxEarly){ 
			COMMAND(port, AcknowledgeInterrupt, rxEarly); 
			status &= ~rxEarly; 
		} 
 
		/* 
1996/0607    
		 * Panic if there are any interrupts not dealt with. 
		 */ 
		if(status & interruptMask) 
1996/0612/sys/src/9/pc/etherelnk3.c:1039,10451996/0613/sys/src/9/pc/etherelnk3.c:1047,1053
1996/0607    
static int 
tcm5XXpcmcia(Ether* ether) 
{ 
	if(cistrcmp(ether->type, "3C589") == 0) 
1996/0613    
	if(cistrcmp(ether->type, "3C589") == 0 || cistrcmp(ether->type, "3C562") == 0) 
1996/0607    
		return ether->port; 
 
	return 0; 
1996/0612/sys/src/9/pc/etherelnk3.c:1048,10541996/0613/sys/src/9/pc/etherelnk3.c:1056,1062
1996/0607    
int 
etherelnk3reset(Ether* ether) 
{ 
	int busmaster, i, port, rxstatus9, x, xcvr; 
1996/0613    
	int busmaster, i, port, rxearly, rxstatus9, x, xcvr; 
1996/0607    
	Adapter *ap, **app; 
	uchar ea[Eaddrlen]; 
	Ctlr *ctlr; 
1996/0612/sys/src/9/pc/etherelnk3.c:1062,10671996/0613/sys/src/9/pc/etherelnk3.c:1070,1076
1996/0607    
	 * If an adapter is found save the IRQ and transceiver type. 
	 */ 
	port = 0; 
1996/0613    
	rxearly = 2044; 
1996/0607    
	rxstatus9 = 0; 
	xcvr = 0; 
	for(app = &adapter, ap = *app; ap; app = &ap->next, ap = ap->next){ 
1996/0612/sys/src/9/pc/etherelnk3.c:1079,10841996/0613/sys/src/9/pc/etherelnk3.c:1088,1094
1996/0607    
	} 
	else if(port == 0 && (port = tcm59Xpci(ether))){ 
		COMMAND(port, SelectRegisterWindow, Wfifo); 
1996/0613    
		rxearly = 8188; 
1996/0607    
		xcvr = inl(port+InternalConfig) & xcvrMask; 
	} 
	else if(port == 0 && (port = tcm5XXeisa(ether))){ 
1996/0612/sys/src/9/pc/etherelnk3.c:1085,10901996/0613/sys/src/9/pc/etherelnk3.c:1095,1101
1996/0607    
		x = ins(port+ProductID); 
		if((x & 0xFF00) == 0x5900){ 
			COMMAND(port, SelectRegisterWindow, Wfifo); 
1996/0613    
			rxearly = 8188; 
1996/0607    
			xcvr = inl(port+InternalConfig) & xcvrMask; 
		} 
		else{ 
1996/0612/sys/src/9/pc/etherelnk3.c:1207,12131996/0613/sys/src/9/pc/etherelnk3.c:1218,1224
1996/0607    
	 */ 
	ctlr->txthreshold = ETHERMINTU; 
	COMMAND(port, SetTxStartThresh, ETHERMINTU); 
	COMMAND(port, SetRxEarlyThresh, ETHERMAXTU); 
1996/0613    
	COMMAND(port, SetRxEarlyThresh, rxearly); 
1996/0607    
 
	iunlock(&ctlr->wlock); 
 
1996/0613/sys/src/9/pc/etherelnk3.c:328,3331996/0925/sys/src/9/pc/etherelnk3.c:328,334 (short | long)
1996/0607    
 
	int	xcvr;				/* transceiver type */ 
	int	rxstatus9;			/* old-style RxStatus register */ 
1996/0925    
	int	ts;				/* threshold shift */ 
1996/0607    
} Ctlr; 
 
static Block* 
1996/0613/sys/src/9/pc/etherelnk3.c:501,5071996/0925/sys/src/9/pc/etherelnk3.c:502,508
1996/0607    
		} 
		else if(ctlr->txbusy == 0){ 
			ctlr->txbusy = 1; 
			COMMAND(port, SetTxAvailableThresh, len); 
1996/0925    
			COMMAND(port, SetTxAvailableThresh, len>>ctlr->ts); 
1996/0607    
			return; 
		} 
	} 
1996/0613/sys/src/9/pc/etherelnk3.c:724,7301996/0925/sys/src/9/pc/etherelnk3.c:725,731
1996/0607    
				COMMAND(port, TxReset, 0); 
				while(STATUS(port) & commandInProgress) 
					; 
				COMMAND(port, SetTxStartThresh, ctlr->txthreshold); 
1996/0925    
				COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts); 
1996/0607    
			} 
			COMMAND(port, TxEnable, 0); 
			ether->oerrs++; 
1996/0613/sys/src/9/pc/etherelnk3.c:1200,12051996/0925/sys/src/9/pc/etherelnk3.c:1201,1208
1996/0607    
	ctlr->busmaster = busmaster; 
	ctlr->xcvr = xcvr; 
	ctlr->rxstatus9 = rxstatus9; 
1996/0925    
	if(rxearly >= 2048) 
		ctlr->ts = 2; 
1996/0607    
 
	COMMAND(port, StatisticsEnable, 0); 
 
1996/0613/sys/src/9/pc/etherelnk3.c:1217,12241996/0925/sys/src/9/pc/etherelnk3.c:1220,1227
1996/0607    
	 * interrupts happen. 
	 */ 
	ctlr->txthreshold = ETHERMINTU; 
	COMMAND(port, SetTxStartThresh, ETHERMINTU); 
1996/0613    
	COMMAND(port, SetRxEarlyThresh, rxearly); 
1996/0925    
	COMMAND(port, SetTxStartThresh, ETHERMINTU>>ctlr->ts); 
	COMMAND(port, SetRxEarlyThresh, rxearly>>ctlr->ts); 
1996/0607    
 
	iunlock(&ctlr->wlock); 
 
1996/0925/sys/src/9/pc/etherelnk3.c:722,7281996/0928/sys/src/9/pc/etherelnk3.c:722,728 (short | long)
1996/0607    
			} 
 
			if(txstatus & (txJabber|txUnderrun)){ 
				COMMAND(port, TxReset, 0); 
1996/0928    
				COMMAND(port, TxReset, dmaReset); 
1996/0607    
				while(STATUS(port) & commandInProgress) 
					; 
1996/0925    
				COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts); 
1996/0925/sys/src/9/pc/etherelnk3.c:1219,12261996/0928/sys/src/9/pc/etherelnk3.c:1219,1226
1996/0607    
	 * if any txUnderrun errors occur and ensure no RxEarly 
	 * interrupts happen. 
	 */ 
	ctlr->txthreshold = ETHERMINTU; 
1996/0925    
	COMMAND(port, SetTxStartThresh, ETHERMINTU>>ctlr->ts); 
1996/0928    
	ctlr->txthreshold = ETHERMINTU*2; 
	COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts); 
1996/0925    
	COMMAND(port, SetRxEarlyThresh, rxearly>>ctlr->ts); 
1996/0607    
 
	iunlock(&ctlr->wlock); 
1996/0928/sys/src/9/pc/etherelnk3.c:136,1411996/0929/sys/src/9/pc/etherelnk3.c:136,142 (short | long)
1996/0607    
	EepromCommand		= 0x000A, 
	EepromData		= 0x000C, 
						/* AddressConfig Bits */ 
1996/0929    
	autoSelect9		= 0x0080, 
1996/0607    
	xcvrMask9		= 0xC000, 
						/* ConfigControl bits */ 
	Ena			= 0x0001, 
1996/0928/sys/src/9/pc/etherelnk3.c:673,6791996/0929/sys/src/9/pc/etherelnk3.c:674,683
1996/0607    
			    ether->ctlrno, status, x); 
 
			if(x & txOverrun){ 
				COMMAND(port, TxReset, 0); 
1996/0929    
				if(ctlr->busmaster == 0) 
					COMMAND(port, TxReset, 0); 
				else 
					COMMAND(port, TxReset, dmaReset); 
1996/0607    
				COMMAND(port, TxEnable, 0); 
				wakeup(ðer->tr); 
			} 
1996/0928/sys/src/9/pc/etherelnk3.c:702,7081996/0929/sys/src/9/pc/etherelnk3.c:706,713
1996/0607    
			 * Pop the TxStatus stack, accumulating errors. 
			 * Adjust the TX start threshold if there was an underrun. 
			 * If there was a Jabber or Underrun error, reset 
			 * the transmitter. 
1996/0929    
			 * the transmitter, taking care not to reset the dma logic 
			 * as a busmaster receive may be in progress. 
1996/0607    
			 * For all conditions enable the transmitter. 
			 */ 
			txstatus = 0; 
1996/0928/sys/src/9/pc/etherelnk3.c:722,7281996/0929/sys/src/9/pc/etherelnk3.c:727,736
1996/0607    
			} 
 
			if(txstatus & (txJabber|txUnderrun)){ 
1996/0928    
				COMMAND(port, TxReset, dmaReset); 
1996/0929    
				if(ctlr->busmaster == 0) 
					COMMAND(port, TxReset, 0); 
				else 
					COMMAND(port, TxReset, dmaReset); 
1996/0607    
				while(STATUS(port) & commandInProgress) 
					; 
1996/0925    
				COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts); 
1996/0928/sys/src/9/pc/etherelnk3.c:846,8531996/0929/sys/src/9/pc/etherelnk3.c:854,861
1996/0607    
	 * One time only: 
	 *	write ID sequence to get the attention of all adapters; 
	 *	untag all adapters. 
	 * If we do a global reset here on all adapters we'll confuse any 
	 * ISA cards configured for EISA mode. 
1996/0929    
	 * If a global reset is done here on all adapters it will confuse 
	 * any ISA cards configured for EISA mode. 
1996/0607    
	 */ 
	if(untag == 0){ 
		outb(IDport, 0xD0); 
1996/0928/sys/src/9/pc/etherelnk3.c:874,8801996/0929/sys/src/9/pc/etherelnk3.c:882,888
1996/0607    
	 *    is the 'read EEPROM' command, 0x07 is the offset of 
	 *    the Manufacturer ID field in the EEPROM). 
	 *    The data comes back 1 bit at a time. 
	 *    We seem to need a delay here between reading the bits. 
1996/0929    
	 *    A delay seems necessary between reading the bits. 
1996/0607    
	 * 
	 * If the ID doesn't match, there are no more adapters. 
	 */ 
1996/0928/sys/src/9/pc/etherelnk3.c:978,9841996/0929/sys/src/9/pc/etherelnk3.c:986,992
1996/0607    
	/* 
	 * Continue through the EISA slots looking for a match on both 
	 * 3COM as the manufacturer and 3C579-* or 3C59[27]-* as the product. 
	 * If we find an adapter, select window 0, enable it and clear 
1996/0929    
	 * If an adapter is found, select window 0, enable it and clear 
1996/0607    
	 * out any lingering status and interrupts. 
	 */ 
	while(slot < MaxEISA){ 
1996/0928/sys/src/9/pc/etherelnk3.c:1054,10591996/0929/sys/src/9/pc/etherelnk3.c:1062,1148
1996/0607    
	return 0; 
} 
 
1996/0929    
static int 
autoselect(int port, int rxstatus9) 
{ 
	int media, x; 
 
	/* 
	 * Pathetic attempt at automatic media selection. 
	 * Really just to get the Fast Etherlink 10BASE-T/100BASE-TX 
	 * cards operational. 
	 */ 
	media = auiAvailable|coaxAvailable|base10TAvailable; 
	if(rxstatus9 == 0){ 
		COMMAND(port, SelectRegisterWindow, Wfifo); 
		media = ins(port+ResetOptions); 
	} 
 
	COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
	x = ins(port+MediaStatus) & ~(dcConverterEnabled|linkBeatEnable|jabberGuardEnable); 
	outs(port+MediaStatus, x); 
 
	if(media & baseTXAvailable){ 
		/* 
		 * Must have InternalConfig register. 
		 */ 
		COMMAND(port, SelectRegisterWindow, Wfifo); 
		x = inl(port+InternalConfig) & ~xcvrMask; 
		x |= xcvr100BaseTX; 
		outl(port+InternalConfig, x); 
		COMMAND(port, TxReset, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
		COMMAND(port, RxReset, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
 
		COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
		x = ins(port+MediaStatus); 
		outs(port+MediaStatus, linkBeatEnable|jabberGuardEnable|x); 
		delay(1); 
 
		if(ins(port+MediaStatus) & linkBeatDetect) 
			return xcvr100BaseTX; 
		outs(port+MediaStatus, x); 
	} 
 
	if(media & base10TAvailable){ 
		if(rxstatus9 == 0){ 
			COMMAND(port, SelectRegisterWindow, Wfifo); 
			x = inl(port+InternalConfig) & ~xcvrMask; 
			x |= xcvr10BaseT; 
			outl(port+InternalConfig, x); 
		} 
		else{ 
			COMMAND(port, SelectRegisterWindow, Wsetup); 
			x = ins(port+AddressConfig) & ~xcvrMask9; 
			x |= (xcvr10BaseT>>20)<<14; 
			outs(port+AddressConfig, x); 
		} 
		COMMAND(port, TxReset, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
		COMMAND(port, RxReset, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
 
		COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
		x = ins(port+MediaStatus); 
		outs(port+MediaStatus, linkBeatEnable|jabberGuardEnable|x); 
		delay(1); 
 
		if(ins(port+MediaStatus) & linkBeatDetect) 
			return xcvr10BaseT; 
		outs(port+MediaStatus, x); 
	} 
 
	/* 
	 * Botch. 
	 */ 
	return autoSelect; 
} 
 
1996/0607    
int 
etherelnk3reset(Ether* ether) 
{ 
1996/0928/sys/src/9/pc/etherelnk3.c:1090,10961996/0929/sys/src/9/pc/etherelnk3.c:1179,1185
1996/0607    
	else if(port == 0 && (port = tcm59Xpci(ether))){ 
		COMMAND(port, SelectRegisterWindow, Wfifo); 
1996/0613    
		rxearly = 8188; 
1996/0607    
		xcvr = inl(port+InternalConfig) & xcvrMask; 
1996/0929    
		xcvr = inl(port+InternalConfig) & (autoSelect|xcvrMask); 
1996/0607    
	} 
	else if(port == 0 && (port = tcm5XXeisa(ether))){ 
		x = ins(port+ProductID); 
1996/0928/sys/src/9/pc/etherelnk3.c:1097,11111996/0929/sys/src/9/pc/etherelnk3.c:1186,1206
1996/0607    
		if((x & 0xFF00) == 0x5900){ 
			COMMAND(port, SelectRegisterWindow, Wfifo); 
1996/0613    
			rxearly = 8188; 
1996/0607    
			xcvr = inl(port+InternalConfig) & xcvrMask; 
1996/0929    
			xcvr = inl(port+InternalConfig) & (autoSelect|xcvrMask); 
1996/0607    
		} 
		else{ 
			xcvr = ((ins(port+AddressConfig) & xcvrMask9)>>14)<<20; 
1996/0929    
			x = ins(port+AddressConfig); 
			xcvr = ((x & xcvrMask9)>>14)<<20; 
			if(x & autoSelect9) 
				xcvr |= autoSelect; 
1996/0607    
			rxstatus9 = 1; 
		} 
	} 
	else if(port == 0 && (port = tcm509isa(ether))){ 
		xcvr = ((ins(port+AddressConfig) & xcvrMask9)>>14)<<20; 
1996/0929    
		x = ins(port+AddressConfig); 
		xcvr = ((x & xcvrMask9)>>14)<<20; 
		if(x & autoSelect9) 
			xcvr |= autoSelect; 
1996/0607    
		rxstatus9 = 1; 
	} 
 
1996/0928/sys/src/9/pc/etherelnk3.c:1127,11341996/0929/sys/src/9/pc/etherelnk3.c:1222,1229
1996/0607    
			while(EEPROMBUSY(port)) 
				; 
			x = EEPROMDATA(port); 
			ether->ea[2*i] = (x>>8) & 0xFF; 
			ether->ea[2*i+1] = x & 0xFF; 
1996/0929    
			ether->ea[2*i] = x>>8; 
			ether->ea[2*i+1] = x; 
1996/0607    
		} 
	} 
 
1996/0928/sys/src/9/pc/etherelnk3.c:1141,11461996/0929/sys/src/9/pc/etherelnk3.c:1236,1243
1996/0607    
	 * busmastering can be used. Due to bugs in the first revision 
	 * of the 3C59[05], don't use busmastering at 10Mbps. 
	 */ 
1996/0929    
	if(xcvr & autoSelect) 
		xcvr = autoselect(port, rxstatus9); 
1996/0607    
	COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
	x = ins(port+MediaStatus) & ~(linkBeatEnable|jabberGuardEnable); 
	outs(port+MediaStatus, x); 
1996/0929/sys/src/9/pc/etherelnk3.c:1056,10621996/1025/sys/src/9/pc/etherelnk3.c:1056,1062 (short | long)
1996/0607    
static int 
tcm5XXpcmcia(Ether* ether) 
{ 
1996/0613    
	if(cistrcmp(ether->type, "3C589") == 0 || cistrcmp(ether->type, "3C562") == 0) 
1996/1025    
	if(!cistrcmp(ether->type, "3C589") || !cistrcmp(ether->type, "3C562")) 
1996/0607    
		return ether->port; 
 
	return 0; 
1996/1025/sys/src/9/pc/etherelnk3.c:1,111997/0327/sys/src/9/pc/etherelnk3.c:1,12 (short | long)
1996/0607    
/* 
 * Etherlink III and Fast EtherLink adapters. 
 * To do: 
 *	check robustness in the face of errors; 
1997/0327    
 *	check robustness in the face of errors (e.g. busmaster & rxUnderrun); 
1996/0613    
 *	RxEarly and busmaster; 
1996/0607    
 *	autoSelect; 
 *	PCI latency timer and master enable; 
 *	errata list. 
1997/0327    
 *	errata list; 
 *	3C90x. 
1996/0607    
 * 
 * Product ID: 
 *	9150 ISA	3C509[B] 
1996/1025/sys/src/9/pc/etherelnk3.c:47,541997/0327/sys/src/9/pc/etherelnk3.c:48,55
1996/0607    
}; 
 
enum {						/* all windows */ 
	Command			= 0x000E, 
	IntStatus		= 0x000E, 
1997/0327    
	CommandR		= 0x000E, 
	IntStatusR		= 0x000E, 
1996/0607    
}; 
 
enum {						/* Commands */ 
1996/1025/sys/src/9/pc/etherelnk3.c:122,1291997/0327/sys/src/9/pc/etherelnk3.c:123,130
1996/0607    
	interruptMask		= 0x01FE, 
}; 
 
#define COMMAND(port, cmd, a)	outs((port)+Command, ((cmd)<<11)|(a)) 
#define STATUS(port)		ins((port)+IntStatus) 
1997/0327    
#define COMMAND(port, cmd, a)	outs((port)+CommandR, ((cmd)<<11)|(a)) 
#define STATUS(port)		ins((port)+IntStatusR) 
1996/0607    
 
enum {						/* Window 0 - setup */ 
	Wsetup			= 0x0000, 
1996/1025/sys/src/9/pc/etherelnk3.c:200,2051997/0327/sys/src/9/pc/etherelnk3.c:201,210
1996/0607    
	ResetOptions		= 0x0008,	/* 3C59[0257] */ 
	RxFree			= 0x000A, 
						/* InternalConfig bits */ 
1997/0327    
	ramPartition5to3	= 0x00000000, 
	ramPartition3to1	= 0x00010000, 
	ramPartition1to1	= 0x00020000, 
	ramPartitionMask	= 0x00030000, 
1996/0607    
	xcvr10BaseT		= 0x00000000, 
	xcvrAui			= 0x00100000,	/* 10BASE5 */ 
	xcvr10Base2		= 0x00300000, 
1996/1025/sys/src/9/pc/etherelnk3.c:256,2621997/0327/sys/src/9/pc/etherelnk3.c:261,267
1996/0607    
	Wstate			= 0x0005, 
						/* registers */ 
	TxStartThresh		= 0x0000, 
	TxAvalableThresh	= 0x0002, 
1997/0327    
	TxAvailableThresh	= 0x0002, 
1996/0607    
	RxEarlyThresh		= 0x0006, 
	RxFilter		= 0x0008, 
	InterruptEnable		= 0x000A, 
1996/1025/sys/src/9/pc/etherelnk3.c:303,3131997/0327/sys/src/9/pc/etherelnk3.c:308,316
1996/0607    
 
	int	attached; 
	int	busmaster; 
	Block*	rbp[2];				/* receive buffers */ 
	int	rbpix; 
1997/0327    
	Block*	rbp;				/* receive buffer */ 
1996/0607    
 
	Block*	txqhead;			/* transmit queue */ 
	Block*	txqtail; 
1997/0327    
	Block*	txbp;				/* */ 
1996/0607    
	int	txthreshold; 
	int	txbusy; 
 
1996/1025/sys/src/9/pc/etherelnk3.c:329,3391997/0327/sys/src/9/pc/etherelnk3.c:332,343
1996/0607    
 
	int	xcvr;				/* transceiver type */ 
	int	rxstatus9;			/* old-style RxStatus register */ 
1997/0327    
	int	rxearly;			/* RxEarlyThreshold */ 
1996/0925    
	int	ts;				/* threshold shift */ 
1996/0607    
} Ctlr; 
 
static Block* 
allocrbp(void) 
1997/0327    
allocrbp(Block* (*f)(int)) 
1996/0607    
{ 
	Block *bp; 
	ulong addr; 
1996/1025/sys/src/9/pc/etherelnk3.c:342,3511997/0327/sys/src/9/pc/etherelnk3.c:346,356
1996/0607    
	 * The receive buffers must be on a 32-byte 
	 * boundary for EISA busmastering. 
	 */ 
	bp = allocb(ROUNDUP(sizeof(Etherpkt), 4) + 31); 
	addr = (ulong)bp->base; 
	addr = ROUNDUP(addr, 32); 
	bp->rp = (uchar*)addr; 
1997/0327    
	if(bp = f(ROUNDUP(sizeof(Etherpkt), 4) + 31)){ 
		addr = (ulong)bp->base; 
		addr = ROUNDUP(addr, 32); 
		bp->rp = (uchar*)addr; 
	} 
1996/0607    
 
	return bp; 
} 
1996/1025/sys/src/9/pc/etherelnk3.c:364,3701997/0327/sys/src/9/pc/etherelnk3.c:369,375
1996/0607    
	wp = KADDR(inl(port+MasterAddress)); 
	status = ins(port+MasterStatus); 
	if(status & (masterInProgress|targetAbort|masterAbort)) 
		print("elnk3#%d: BM status 0x%uX\n", ether->ctlrno, status); 
1997/0327    
		print("#l%d: BM status 0x%uX\n", ether->ctlrno, status); 
1996/0607    
	outs(port+MasterStatus, masterMask); 
	outl(port+MasterAddress, address); 
	outs(port+MasterLen, sizeof(Etherpkt)); 
1996/1025/sys/src/9/pc/etherelnk3.c:409,4151997/0327/sys/src/9/pc/etherelnk3.c:414,420
1996/0607    
	 */ 
	promiscuous(ether, ether->prom); 
 
	x = interruptMask|interruptLatch; 
1997/0327    
	x = interruptMask; 
1996/0607    
	if(ctlr->busmaster) 
		x &= ~(rxEarly|rxComplete); 
	COMMAND(port, SetIndicationEnable, x); 
1996/1025/sys/src/9/pc/etherelnk3.c:422,4301997/0327/sys/src/9/pc/etherelnk3.c:427,434
1996/0607    
	 * Prime the busmaster channel for receiving directly into a 
	 * receive packet buffer if necessary. 
	 */ 
	ctlr->rbpix = 0; 
	if(ctlr->busmaster) 
		startdma(ether, PADDR(ctlr->rbp[ctlr->rbpix]->rp)); 
1997/0327    
		startdma(ether, PADDR(ctlr->rbp->rp)); 
1996/0607    
 
	ctlr->attached = 1; 
	iunlock(&ctlr->wlock); 
1996/1025/sys/src/9/pc/etherelnk3.c:472,4781997/0327/sys/src/9/pc/etherelnk3.c:476,482
1996/0607    
} 
 
static void 
transmit(Ether* ether) 
1997/0327    
txstart(Ether* ether) 
1996/0607    
{ 
	int port, len; 
	Ctlr *ctlr; 
1996/1025/sys/src/9/pc/etherelnk3.c:490,5491997/0327/sys/src/9/pc/etherelnk3.c:494,545
1996/0607    
	 * level and expects to be called with ctlr->wlock already locked 
	 * and the correct register window (Wop) in place. 
	 */ 
	while(bp = ctlr->txqhead){ 
1997/0327    
	for(;;){ 
		if(ctlr->txbp){ 
			bp = ctlr->txbp; 
			ctlr->txbp = 0; 
		} 
		else{ 
			bp = qget(ether->oq); 
			if(bp == nil) 
				break; 
		} 
 
1996/0607    
		len = ROUNDUP(BLEN(bp), 4); 
		if(len+4 <= ins(port+TxFree)){ 
			outl(port+Fifo, BLEN(bp)); 
			outsl(port+Fifo, bp->rp, len/4); 
 
			ctlr->txqhead = bp->next; 
			freeb(bp); 
 
			ether->outpackets++; 
		} 
		else if(ctlr->txbusy == 0){ 
			ctlr->txbusy = 1; 
1996/0925    
			COMMAND(port, SetTxAvailableThresh, len>>ctlr->ts); 
1996/0607    
			return; 
1997/0327    
		else{ 
			ctlr->txbp = bp; 
			if(ctlr->txbusy == 0){ 
				ctlr->txbusy = 1; 
				COMMAND(port, SetTxAvailableThresh, len>>ctlr->ts); 
			} 
			break; 
1996/0607    
		} 
	} 
} 
 
static long 
write(Ether* ether, void* buf, long n) 
1997/0327    
static void 
transmit(Ether* ether) 
1996/0607    
{ 
	Ctlr *ctlr; 
	Block *bp; 
	int port, w; 
 
	port = ether->port; 
	ctlr = ether->ctlr; 
 
	/* 
	 * Pack the write request up in a buffer, give it a source address 
	 * and place it on the end of the transmit queue. The data written to the 
	 * FIFO must be padded to a dword boundary, hence the ROUNDUP allocation. 
	 * Call transmit() to stuff it into the TxFIFO if possible.  
	 */ 
	bp = allocb(ROUNDUP(n, 4)); 
	memmove(bp->wp, buf, n); 
	memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); 
	bp->wp += n; 
                 
	ilock(&ctlr->wlock); 
	w = (STATUS(port)>>13) & 0x07; 
	COMMAND(port, SelectRegisterWindow, Wop); 
	if(ctlr->txqhead == 0) 
		ctlr->txqhead = bp; 
	else 
		ctlr->txqtail->next = bp; 
	ctlr->txqtail = bp; 
	if(ctlr->txbusy == 0) 
		transmit(ether); 
1997/0327    
	txstart(ether); 
1996/0607    
	COMMAND(port, SelectRegisterWindow, w); 
	iunlock(&ctlr->wlock); 
                 
	return n; 
} 
 
static void 
1996/1025/sys/src/9/pc/etherelnk3.c:599,6331997/0327/sys/src/9/pc/etherelnk3.c:595,641
1996/0607    
				if(rxerror & crcError) 
					ether->crcs++; 
			} 
1997/0327    
		} 
1996/0607    
 
1997/0327    
		/* 
		 * If there was an error or a new receive buffer can't be 
		 * allocated, discard the packet and go on to the next. 
		 */ 
		if((rxstatus & rxError) || (bp = allocrbp(iallocb)) == 0){ 
1996/0607    
			COMMAND(port, RxDiscard, 0); 
			while(STATUS(port) & commandInProgress) 
				; 
 
			if(ctlr->busmaster) 
				startdma(ether, PADDR(ctlr->rbp[ctlr->rbpix]->rp)); 
1997/0327    
				startdma(ether, PADDR(ctlr->rbp->rp)); 
 
			continue; 
1996/0607    
		} 
		else{ 
			ether->inpackets++; 
			bp = ctlr->rbp[ctlr->rbpix]; 
 
			if(ctlr->busmaster == 0){ 
				len = (rxstatus & rxBytes9); 
				bp->wp = bp->rp + len; 
				insl(port+Fifo, bp->rp, HOWMANY(len, 4)); 
			} 
1997/0327    
		/* 
		 * A valid receive packet awaits: 
		 *	if using PIO, read it into the buffer; 
		 *	discard the packet from the FIFO; 
		 *	if using busmastering, start a new transfer for 
		 *	  the next packet and as a side-effect get the 
		 *	  end-pointer of the one just received; 
		 *	pass the packet on to whoever wants it. 
		 */ 
		if(ctlr->busmaster == 0){ 
			len = (rxstatus & rxBytes9); 
			ctlr->rbp->wp = ctlr->rbp->rp + len; 
			insl(port+Fifo, ctlr->rbp->rp, HOWMANY(len, 4)); 
		} 
1996/0607    
 
			COMMAND(port, RxDiscard, 0); 
			while(STATUS(port) & commandInProgress) 
				; 
1997/0327    
		COMMAND(port, RxDiscard, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
1996/0607    
 
			if(ctlr->busmaster){ 
				ctlr->rbpix ^= 1; 
				bp->wp = startdma(ether, PADDR(ctlr->rbp[ctlr->rbpix]->rp)); 
			} 
1997/0327    
		if(ctlr->busmaster) 
			ctlr->rbp->wp = startdma(ether, PADDR(bp->rp)); 
1996/0607    
 
			etherrloop(ether, (Etherpkt*)bp->rp, BLEN(bp)); 
		} 
1997/0327    
		etheriq(ether, ctlr->rbp, 1); 
		ctlr->rbp = bp; 
1996/0607    
	} 
} 
 
1996/1025/sys/src/9/pc/etherelnk3.c:635,6411997/0327/sys/src/9/pc/etherelnk3.c:643,649
1996/0607    
interrupt(Ureg*, void* arg) 
{ 
	Ether *ether; 
	int port, status, txstatus, w, x; 
1997/0327    
	int port, status, s, w, x; 
1996/0607    
	Ctlr *ctlr; 
 
	ether = arg; 
1996/1025/sys/src/9/pc/etherelnk3.c:648,6661997/0327/sys/src/9/pc/etherelnk3.c:656,662
1996/0607    
 
	ctlr->interrupts++; 
	ctlr->timer += inb(port+Timer) & 0xFF; 
	for(;;){ 
		/* 
		 * Clear the interrupt latch. 
		 * It's possible to receive a packet and for another 
		 * to become complete before exiting the interrupt 
		 * handler so this must be done first to ensure another 
		 * interrupt will occur. 
		 */ 
		COMMAND(port, AcknowledgeInterrupt, interruptLatch); 
		status = STATUS(port); 
		if((status & interruptMask) == 0) 
			break; 
                 
1997/0327    
	for(status = STATUS(port); status & interruptMask; status = STATUS(port)){ 
1996/0607    
		if(status & hostError){ 
			/* 
			 * Adapter failure, try to find out why, reset if 
1996/1025/sys/src/9/pc/etherelnk3.c:670,6761997/0327/sys/src/9/pc/etherelnk3.c:666,672
1996/0607    
			COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
			x = ins(port+FifoDiagnostic); 
			COMMAND(port, SelectRegisterWindow, Wop); 
			print("elnk3#%d: status 0x%uX, diag 0x%uX\n", 
1997/0327    
			print("#l%d: status 0x%uX, diag 0x%uX\n", 
1996/0607    
			    ether->ctlrno, status, x); 
 
			if(x & txOverrun){ 
1996/1025/sys/src/9/pc/etherelnk3.c:679,6951997/0327/sys/src/9/pc/etherelnk3.c:675,697
1996/0929    
				else 
					COMMAND(port, TxReset, dmaReset); 
1996/0607    
				COMMAND(port, TxEnable, 0); 
				wakeup(ðer->tr); 
			} 
 
			if(x & rxUnderrun){ 
				/* 
				 * This shouldn't happen... 
1997/0327    
				 * Reset the receiver and restore the filter and RxEarly 
				 * threshold before re-enabling. 
1996/0607    
				 * Need to restart any busmastering? 
				 */ 
1997/0327    
				COMMAND(port, SelectRegisterWindow, Wstate); 
				s = (port+RxFilter) & 0x000F; 
				COMMAND(port, SelectRegisterWindow, Wop); 
1996/0607    
				COMMAND(port, RxReset, 0); 
				while(STATUS(port) & commandInProgress) 
					; 
1997/0327    
				COMMAND(port, SetRxFilter, s); 
				COMMAND(port, SetRxEarlyThresh, ctlr->rxearly>>ctlr->ts); 
1996/0607    
				COMMAND(port, RxEnable, 0); 
			} 
 
1996/1025/sys/src/9/pc/etherelnk3.c:710,7231997/0327/sys/src/9/pc/etherelnk3.c:712,725
1996/0929    
			 * as a busmaster receive may be in progress. 
1996/0607    
			 * For all conditions enable the transmitter. 
			 */ 
			txstatus = 0; 
1997/0327    
			s = 0; 
1996/0607    
			do{ 
				if(x = inb(port+TxStatus)) 
					outb(port+TxStatus, 0); 
				txstatus |= x; 
1997/0327    
				s |= x; 
1996/0607    
			}while(STATUS(port) & txComplete); 
 
			if(txstatus & txUnderrun){ 
1997/0327    
			if(s & txUnderrun){ 
1996/0607    
				COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
				while(ins(port+MediaStatus) & txInProg) 
					; 
1996/1025/sys/src/9/pc/etherelnk3.c:726,7321997/0327/sys/src/9/pc/etherelnk3.c:728,734
1996/0607    
					ctlr->txthreshold += ETHERMINTU; 
			} 
 
			if(txstatus & (txJabber|txUnderrun)){ 
1997/0327    
			if(s & (txJabber|txUnderrun)){ 
1996/0929    
				if(ctlr->busmaster == 0) 
					COMMAND(port, TxReset, 0); 
				else 
1996/1025/sys/src/9/pc/etherelnk3.c:744,7501997/0327/sys/src/9/pc/etherelnk3.c:746,752
1996/0607    
		if(status & txAvailable){ 
			COMMAND(port, AcknowledgeInterrupt, txAvailable); 
			ctlr->txbusy = 0; 
			transmit(ether); 
1997/0327    
			txstart(ether); 
1996/0607    
			status &= ~txAvailable; 
		} 
 
1996/1025/sys/src/9/pc/etherelnk3.c:765,7721997/0327/sys/src/9/pc/etherelnk3.c:767,775
1996/0607    
		 * Panic if there are any interrupts not dealt with. 
		 */ 
		if(status & interruptMask) 
			panic("elnk3#%d: interrupt mask 0x%uX\n", ether->ctlrno, status); 
1997/0327    
			panic("#l%d: interrupt mask 0x%uX\n", ether->ctlrno, status); 
1996/0607    
	} 
1997/0327    
	COMMAND(port, AcknowledgeInterrupt, interruptLatch); 
1996/0607    
 
	COMMAND(port, SelectRegisterWindow, w); 
	unlock(&ctlr->wlock); 
1996/1025/sys/src/9/pc/etherelnk3.c:806,8191997/0327/sys/src/9/pc/etherelnk3.c:809,837
1996/0607    
	return readstr(offset, a, n, buf); 
} 
 
typedef struct Adapter Adapter; 
struct Adapter { 
	Adapter*	next; 
	int		port; 
	int		irq; 
}; 
static Adapter *adapter; 
1997/0327    
typedef struct Adapter { 
	int	port; 
	int	irq; 
	int	tbdf; 
} Adapter; 
static Block* adapter; 
1996/0607    
 
1997/0327    
static void 
tcmadapter(int port, int irq, int tbdf) 
{ 
	Block *bp; 
	Adapter *ap; 
 
	bp = allocb(sizeof(Adapter)); 
	ap = (Adapter*)bp->rp; 
	ap->port = port; 
	ap->irq = irq; 
	ap->tbdf = tbdf; 
 
	bp->next = adapter; 
	adapter = bp; 
} 
 
1996/0607    
/* 
 * Write two 0 bytes to identify the IDport and then reset the 
 * ID sequence. Then send the ID sequence to the card to get 
1996/1025/sys/src/9/pc/etherelnk3.c:914,9201997/0327/sys/src/9/pc/etherelnk3.c:932,937
1996/0607    
tcm509isa(Ether* ether) 
{ 
	int irq, port; 
	Adapter *ap; 
 
	/* 
	 * Attempt to activate adapters until one matches the 
1996/1025/sys/src/9/pc/etherelnk3.c:958,9681997/0327/sys/src/9/pc/etherelnk3.c:975,981
1996/0607    
			return port; 
		} 
 
		ap = malloc(sizeof(Adapter)); 
		ap->port = port; 
		ap->irq = irq; 
		ap->next = adapter; 
		adapter = ap; 
1997/0327    
		tcmadapter(port, irq, BUSUNKNOWN); 
1996/0607    
	} 
 
	return 0; 
1996/1025/sys/src/9/pc/etherelnk3.c:974,9801997/0327/sys/src/9/pc/etherelnk3.c:987,992
1996/0607    
	static int slot = 1; 
	ushort x; 
	int irq, port; 
	Adapter *ap; 
 
	/* 
	 * First time through, check if this is an EISA machine. 
1996/1025/sys/src/9/pc/etherelnk3.c:1010,10201997/0327/sys/src/9/pc/etherelnk3.c:1022,1028
1996/0607    
			return port; 
		} 
 
		ap = malloc(sizeof(Adapter)); 
		ap->port = port; 
		ap->irq = irq; 
		ap->next = adapter; 
		adapter = ap; 
1997/0327    
		tcmadapter(port, irq, BUSUNKNOWN); 
1996/0607    
	} 
 
	return 0; 
1996/1025/sys/src/9/pc/etherelnk3.c:1023,10531997/0327/sys/src/9/pc/etherelnk3.c:1031,1049
1996/0607    
static int 
tcm59Xpci(Ether* ether) 
{ 
	PCIcfg pcicfg; 
	static int devno = 0; 
1997/0327    
	static Pcidev *p; 
1996/0607    
	int irq, port; 
	Adapter *ap; 
 
	for(;;){ 
		pcicfg.vid = 0x10B7; 
		pcicfg.did = 0; 
		if((devno = pcimatch(0, devno, &pcicfg)) == -1) 
			break; 
		port = pcicfg.baseaddr[0] & ~0x01; 
		COMMAND(port, GlobalReset, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
		irq = pcicfg.irq; 
1997/0327    
	while(p = pcimatch(p, 0x10B7, 0)){ 
		port = p->bar[0] & ~0x01; 
		irq = p->intl; 
1996/0607    
		if(ether->port == 0 || ether->port == port){ 
			ether->irq = irq; 
1997/0327    
			ether->tbdf = p->tbdf; 
1996/0607    
			return port; 
		} 
 
		ap = malloc(sizeof(Adapter)); 
		ap->port = port; 
		ap->irq = irq; 
		ap->next = adapter; 
		adapter = ap; 
1997/0327    
		tcmadapter(port, irq, p->tbdf); 
1996/0607    
	} 
 
	return 0; 
1996/1025/sys/src/9/pc/etherelnk3.c:1147,11531997/0327/sys/src/9/pc/etherelnk3.c:1143,1150
1996/0607    
etherelnk3reset(Ether* ether) 
{ 
1996/0613    
	int busmaster, i, port, rxearly, rxstatus9, x, xcvr; 
1996/0607    
	Adapter *ap, **app; 
1997/0327    
	Block *bp, **bpp; 
	Adapter *ap; 
1996/0607    
	uchar ea[Eaddrlen]; 
	Ctlr *ctlr; 
 
1996/1025/sys/src/9/pc/etherelnk3.c:1163,11761997/0327/sys/src/9/pc/etherelnk3.c:1160,1177
1996/0613    
	rxearly = 2044; 
1996/0607    
	rxstatus9 = 0; 
	xcvr = 0; 
	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/0607    
		if(ether->port == 0 || ether->port == ap->port){ 
			port = ap->port; 
			ether->irq = ap->irq; 
			*app = ap->next; 
			free(ap); 
1997/0327    
			ether->tbdf = ap->tbdf; 
			*bpp = bp->next; 
			freeb(bp); 
1996/0607    
			break; 
		} 
1997/0327    
		bpp = &bp->next; 
1996/0607    
	} 
	if(port == 0 && (port = tcm5XXpcmcia(ether))){ 
		xcvr = ((ins(port+AddressConfig) & xcvrMask9)>>14)<<20; 
1996/1025/sys/src/9/pc/etherelnk3.c:1177,11821997/0327/sys/src/9/pc/etherelnk3.c:1178,1186
1996/0607    
		rxstatus9 = 1; 
	} 
	else if(port == 0 && (port = tcm59Xpci(ether))){ 
1997/0327    
		COMMAND(port, GlobalReset, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
1996/0607    
		COMMAND(port, SelectRegisterWindow, Wfifo); 
1996/0613    
		rxearly = 8188; 
1996/0929    
		xcvr = inl(port+InternalConfig) & (autoSelect|xcvrMask); 
1996/1025/sys/src/9/pc/etherelnk3.c:1241,12481997/0327/sys/src/9/pc/etherelnk3.c:1245,1255
1996/0607    
	COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
	x = ins(port+MediaStatus) & ~(linkBeatEnable|jabberGuardEnable); 
	outs(port+MediaStatus, x); 
	if(x & dataRate100) 
1997/0327    
	if(x & dataRate100){ 
1996/0607    
		busmaster = 1; 
1997/0327    
		x = inl(port+InternalConfig) & ~ramPartitionMask; 
		outl(port+InternalConfig, x|ramPartition1to1); 
	} 
1996/0607    
	else 
		busmaster = 0; 
	switch(xcvr){ 
1996/1025/sys/src/9/pc/etherelnk3.c:1298,13031997/0327/sys/src/9/pc/etherelnk3.c:1305,1311
1996/0607    
	ctlr->busmaster = busmaster; 
	ctlr->xcvr = xcvr; 
	ctlr->rxstatus9 = rxstatus9; 
1997/0327    
	ctlr->rxearly = rxearly; 
1996/0925    
	if(rxearly >= 2048) 
		ctlr->ts = 2; 
1996/0607    
 
1996/1025/sys/src/9/pc/etherelnk3.c:1304,13151997/0327/sys/src/9/pc/etherelnk3.c:1312,1320
1996/0607    
	COMMAND(port, StatisticsEnable, 0); 
 
	/* 
	 * Allocate the receive buffers. 
1997/0327    
	 * Allocate the receive buffer. 
1996/0607    
	 */ 
	ctlr->rbpix = 0; 
	ctlr->rbp[0] = allocrbp(); 
	if(ctlr->busmaster) 
		ctlr->rbp[1] = allocrbp(); 
1997/0327    
	ctlr->rbp = allocrbp(allocb); 
1996/0607    
 
	/* 
	 * Set a base TxStartThresh which will be incremented 
1996/1025/sys/src/9/pc/etherelnk3.c:1316,13221997/0327/sys/src/9/pc/etherelnk3.c:1321,1327
1996/0607    
	 * if any txUnderrun errors occur and ensure no RxEarly 
	 * interrupts happen. 
	 */ 
1996/0928    
	ctlr->txthreshold = ETHERMINTU*2; 
1997/0327    
	ctlr->txthreshold = ETHERMAXTU/2; 
1996/0928    
	COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts); 
1996/0925    
	COMMAND(port, SetRxEarlyThresh, rxearly>>ctlr->ts); 
1996/0607    
 
1996/1025/sys/src/9/pc/etherelnk3.c:1327,13331997/0327/sys/src/9/pc/etherelnk3.c:1332,1338
1996/0607    
	 */ 
	ether->port = port; 
	ether->attach = attach; 
	ether->write = write; 
1997/0327    
	ether->transmit = transmit; 
1996/0607    
	ether->interrupt = interrupt; 
	ether->ifstat = ifstat; 
 
1997/0327/sys/src/9/pc/etherelnk3.c:6,121997/0328/sys/src/9/pc/etherelnk3.c:6,13 (short | long)
1996/0607    
 *	autoSelect; 
 *	PCI latency timer and master enable; 
1997/0327    
 *	errata list; 
 *	3C90x. 
1997/0328    
 *	3C90x full busmastering; 
 *	rewrite all initialisation. 
1996/0607    
 * 
 * Product ID: 
 *	9150 ISA	3C509[B] 
1997/0327/sys/src/9/pc/etherelnk3.c:27,321997/0328/sys/src/9/pc/etherelnk3.c:28,38
1996/0607    
 *	5951 PCI	3C595-T4	Fast Etherlink Shared 10BASE-T/100BASE-T4 
 *	5952 PCI	3C595-MII	Fast Etherlink 10BASE-T/MII 
 * 
1997/0328    
 *	9000 PCI	3C900-TPO	Etherlink III XL PCI 10BASE-T 
 *	9001 PCI	3C900-COMBO	Etherlink III XL PCI 10BASE-T/10BASE-2/AUI 
 *	9050 PCI	3C905-TX	Fast Etherlink XL Shared 10BASE-T/100BASE-TX 
 *	9051 PCI	3C905-T4	Fast Etherlink Shared 10BASE-T/100BASE-T4 
 * 
1996/0607    
 *	9058 PCMCIA	3C589[B]-[TP|COMBO] 
 * 
 *	627C MCA	3C529 
1997/0327/sys/src/9/pc/etherelnk3.c:54,651997/0328/sys/src/9/pc/etherelnk3.c:60,72
1996/0607    
 
enum {						/* Commands */ 
	GlobalReset		= 0x0000, 
	SelectRegisterWindow	= 0x0001,	 
1997/0328    
	SelectRegisterWindow	= 0x0001, 
1996/0607    
	EnableDcConverter	= 0x0002, 
	RxDisable		= 0x0003, 
	RxEnable		= 0x0004, 
	RxReset			= 0x0005, 
	TxDone			= 0x0007,	 
1997/0328    
	Stall			= 0x0006,	/* 3C90x */ 
	TxDone			= 0x0007, 
1996/0607    
	RxDiscard		= 0x0008, 
	TxEnable		= 0x0009, 
	TxDisable		= 0x000A, 
1997/0327/sys/src/9/pc/etherelnk3.c:91,1001997/0328/sys/src/9/pc/etherelnk3.c:98,115
1996/0607    
	hostReset		= 0x0020,	/* bus interface logic */ 
	dmaReset		= 0x0040,	/* bus master logic */ 
	vcoReset		= 0x0080,	/* on-board 10Mbps VCO */ 
1997/0328    
	updnReset		= 0x0100,	/* upload/download (Rx/TX) logic */ 
1996/0607    
 
	resetMask		= 0x00FF, 
1997/0328    
	resetMask		= 0x01FF, 
1996/0607    
}; 
 
1997/0328    
enum {						/* Stall command bits */ 
	UpStall			= 0x0000, 
	UpUnStall		= 0x0001, 
	DnStall			= 0x0002, 
	DnUnStall		= 0x0003, 
}; 
 
1996/0607    
enum {						/* SetRxFilter command bits */ 
	receiveIndividual	= 0x0001,	/* match station address */ 
	receiveMulticast	= 0x0002, 
1997/0327/sys/src/9/pc/etherelnk3.c:117,1261997/0328/sys/src/9/pc/etherelnk3.c:132,143
1996/0607    
	intRequested		= 0x0040, 
	updateStats		= 0x0080, 
	transferInt		= 0x0100,	/* Bus Master Transfer Complete */ 
1997/0328    
	dnComplete		= 0x0200, 
	upComplete		= 0x0400, 
1996/0607    
	busMasterInProgress	= 0x0800, 
	commandInProgress	= 0x1000, 
 
	interruptMask		= 0x01FE, 
1997/0328    
	interruptMask		= 0x07FE, 
1996/0607    
}; 
 
1997/0327    
#define COMMAND(port, cmd, a)	outs((port)+CommandR, ((cmd)<<11)|(a)) 
1997/0327/sys/src/9/pc/etherelnk3.c:201,2091997/0328/sys/src/9/pc/etherelnk3.c:218,229
1996/0607    
	ResetOptions		= 0x0008,	/* 3C59[0257] */ 
	RxFree			= 0x000A, 
						/* InternalConfig bits */ 
1997/0328    
	disableBadSsdDetect	= 0x00000100, 
	ramLocation		= 0x00000200,	/* 0 external, 1 internal */ 
1997/0327    
	ramPartition5to3	= 0x00000000, 
	ramPartition3to1	= 0x00010000, 
	ramPartition1to1	= 0x00020000, 
1997/0328    
	ramPartition3to5	= 0x00030000, 
1997/0327    
	ramPartitionMask	= 0x00030000, 
1996/0607    
	xcvr10BaseT		= 0x00000000, 
	xcvrAui			= 0x00100000,	/* 10BASE5 */ 
1997/0327/sys/src/9/pc/etherelnk3.c:225,2311997/0328/sys/src/9/pc/etherelnk3.c:245,251
1996/0607    
	base10TAvailable	= 0x0008, 
	coaxAvailable		= 0x0010, 
	auiAvailable		= 0x0020, 
	miiAvailable		= 0x0040, 
1997/0328    
	miiConnector		= 0x0040, 
1996/0607    
}; 
 
enum {						/* Window 4 - diagnostic */ 
1997/0327/sys/src/9/pc/etherelnk3.c:237,2421997/0328/sys/src/9/pc/etherelnk3.c:257,263
1996/0607    
	PhysicalMgmt		= 0x0008, 
	MediaStatus		= 0x000A, 
	BadSSD			= 0x000C, 
1997/0328    
	UpperBytesOk		= 0x000D, 
1996/0607    
						/* FifoDiagnostic bits */ 
	txOverrun		= 0x0400, 
	rxUnderrun		= 0x2000, 
1997/0327/sys/src/9/pc/etherelnk3.c:254,2601997/0328/sys/src/9/pc/etherelnk3.c:275,281
1996/0607    
	linkBeatDetect		= 0x0800, 
	txInProg		= 0x1000, 
	dcConverterEnabled	= 0x4000, 
	auiDisable		= 0x8000, 
1997/0328    
	auiDisable		= 0x8000,	/* 10BaseT transceiver selected */ 
1996/0607    
}; 
 
enum {						/* Window 5 - internal state */ 
1997/0327/sys/src/9/pc/etherelnk3.c:301,3081997/0328/sys/src/9/pc/etherelnk3.c:322,380
1996/0607    
	masterInProgress	= 0x8000, 
 
	masterMask		= 0xD00F, 
};	 
1997/0328    
}; 
1996/0607    
 
1997/0328    
enum {						/* 3C90x extended register set */ 
	PktStatus		= 0x0020,	/* 32-bits */ 
	DnListPtr		= 0x0024,	/* 32-bits, 8-byte aligned */ 
	FragAddr		= 0x0028,	/* 32-bits */ 
	FragLen			= 0x002C,	/* 16-bits */ 
	ListOffset		= 0x002E,	/* 8-bits */ 
	TxFreeThresh		= 0x002F,	/* 8-bits */ 
	UpPktStatus		= 0x0030,	/* 32-bits */ 
	FreeTimer		= 0x0034,	/* 16-bits */ 
	UpListPtr		= 0x0038,	/* 32-bits, 8-byte aligned */ 
 
						/* PktStatus bits */ 
	fragLast		= 0x00000001, 
	dnCmplReq		= 0x00000002, 
	dnStalled		= 0x00000004, 
	upCompleteX		= 0x00000008, 
	dnCompleteX		= 0x00000010, 
	upRxEarlyEnable		= 0x00000020, 
	armCountdown		= 0x00000040, 
	dnInProg		= 0x00000080, 
	counterSpeed		= 0x00000010,	/* 0 3.2uS, 1 320nS */ 
	countdownMode		= 0x00000020, 
						/* UpPktStatus bits */ 
	upPktLenMask		= 0x00001FFF, 
	upStalled		= 0x00002000, 
	upError			= 0x00004000, 
	upPktComplete		= 0x00008000, 
	upOverrrun		= 0x00010000,	/* RxError<<16 */ 
	upRuntFrame		= 0x00020000, 
	upAlignmentError	= 0x00040000, 
	upCRCError		= 0x00080000, 
	upOversizedFrame	= 0x00100000, 
	upDribbleBits		= 0x00800000, 
	upOverflow		= 0x01000000, 
}; 
 
/* 
 * Up/Dn Packet Descriptor. 
 * The hardware info (np, control, addr, len) must be 8-byte aligned. 
 */ 
typedef struct Pd Pd; 
typedef struct Pd { 
	Pd*	next; 
	Block*	bp; 
 
	ulong	np;				/* next pointer */ 
	ulong	control;			/* FSH or UpPktStatus */ 
	ulong	addr; 
	ulong	len; 
}; 
 
1996/0607    
typedef struct { 
	Lock	wlock;				/* window access */ 
 
1997/0327/sys/src/9/pc/etherelnk3.c:316,3341997/0328/sys/src/9/pc/etherelnk3.c:388,394
1996/0607    
 
	long	interrupts;			/* statistics */ 
	long	timer; 
	                 
	long	carrierlost; 
	long	sqeerrors; 
	long	multiplecolls; 
	long	singlecollframes; 
	long	latecollisions; 
	long	rxoverruns; 
	long	framesxmittedok; 
	long	framesrcvdok; 
	long	framesdeferred; 
	long	bytesrcvdok; 
	long	bytesxmittedok; 
	long	badssd; 
1997/0328    
	long	stats[BytesRcvdOk+2]; 
1996/0607    
 
	int	xcvr;				/* transceiver type */ 
	int	rxstatus9;			/* old-style RxStatus register */ 
1997/0327/sys/src/9/pc/etherelnk3.c:385,3911997/0328/sys/src/9/pc/etherelnk3.c:445,451
1996/0607    
	int filter, port; 
 
	port = ((Ether*)arg)->port; 
	                 
1997/0328    
 
1996/0607    
	filter = receiveBroadcast|receiveIndividual; 
	if(on) 
		filter |= receiveAllFrames; 
1997/0327/sys/src/9/pc/etherelnk3.c:437,4431997/0328/sys/src/9/pc/etherelnk3.c:497,503
1996/0607    
static void 
statistics(Ether* ether) 
{ 
	int port, u, w; 
1997/0328    
	int port, i, u, w; 
1996/0607    
	Ctlr *ctlr; 
 
	port = ether->port; 
1997/0327/sys/src/9/pc/etherelnk3.c:451,4751997/0328/sys/src/9/pc/etherelnk3.c:511,528
1996/0607    
	COMMAND(port, SelectRegisterWindow, Wstatistics); 
	STATUS(port); 
 
	ctlr->carrierlost += inb(port+CarrierLost) & 0xFF; 
	ctlr->sqeerrors += inb(port+SqeErrors) & 0xFF; 
	ctlr->multiplecolls += inb(port+MultipleColls) & 0xFF; 
	ctlr->singlecollframes += inb(port+SingleCollFrames) & 0xFF; 
	ctlr->latecollisions += inb(port+LateCollisions) & 0xFF; 
	ctlr->rxoverruns += inb(port+RxOverruns) & 0xFF; 
	ctlr->framesxmittedok += inb(port+FramesXmittedOk) & 0xFF; 
	ctlr->framesrcvdok += inb(port+FramesRcvdOk) & 0xFF; 
1997/0328    
	for(i = 0; i < UpperFramesOk; i++) 
		ctlr->stats[i] += inb(port+i) & 0xFF; 
1996/0607    
	u = inb(port+UpperFramesOk) & 0xFF; 
	ctlr->framesxmittedok += (u & 0x30)<<4; 
	ctlr->framesrcvdok += (u & 0x03)<<8; 
	ctlr->framesdeferred += inb(port+FramesDeferred) & 0xFF; 
	ctlr->bytesrcvdok += ins(port+BytesRcvdOk) & 0xFFFF; 
	ctlr->bytesxmittedok += ins(port+BytesXmittedOk) & 0xFFFF; 
1997/0328    
	ctlr->stats[FramesXmittedOk] += (u & 0x30)<<4; 
	ctlr->stats[FramesRcvdOk] += (u & 0x03)<<8; 
	ctlr->stats[BytesRcvdOk] += ins(port+BytesRcvdOk) & 0xFFFF; 
	ctlr->stats[BytesRcvdOk+1] += ins(port+BytesXmittedOk) & 0xFFFF; 
1996/0607    
 
	if(ctlr->xcvr == xcvr100BaseTX || ctlr->xcvr == xcvr100BaseFX){ 
		COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
		STATUS(port); 
		ctlr->badssd += inb(port+BadSSD); 
1997/0328    
		ctlr->stats[BytesRcvdOk+2] += inb(port+BadSSD); 
1996/0607    
	} 
 
	COMMAND(port, SelectRegisterWindow, w); 
1997/0327/sys/src/9/pc/etherelnk3.c:656,6621997/0328/sys/src/9/pc/etherelnk3.c:709,715
1996/0607    
 
	ctlr->interrupts++; 
	ctlr->timer += inb(port+Timer) & 0xFF; 
1997/0327    
	for(status = STATUS(port); status & interruptMask; status = STATUS(port)){ 
1997/0328    
	while((status = STATUS(port)) & (interruptMask|interruptLatch)){ 
1996/0607    
		if(status & hostError){ 
			/* 
			 * Adapter failure, try to find out why, reset if 
1997/0327/sys/src/9/pc/etherelnk3.c:732,7381997/0328/sys/src/9/pc/etherelnk3.c:785,791
1996/0929    
				if(ctlr->busmaster == 0) 
					COMMAND(port, TxReset, 0); 
				else 
					COMMAND(port, TxReset, dmaReset); 
1997/0328    
					COMMAND(port, TxReset, (updnReset|dmaReset)); 
1996/0607    
				while(STATUS(port) & commandInProgress) 
					; 
1996/0925    
				COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts); 
1997/0327/sys/src/9/pc/etherelnk3.c:768,7751997/0328/sys/src/9/pc/etherelnk3.c:821,829
1996/0607    
		 */ 
		if(status & interruptMask) 
1997/0327    
			panic("#l%d: interrupt mask 0x%uX\n", ether->ctlrno, status); 
1997/0328    
 
		COMMAND(port, AcknowledgeInterrupt, interruptLatch); 
1996/0607    
	} 
1997/0327    
	COMMAND(port, AcknowledgeInterrupt, interruptLatch); 
1996/0607    
 
	COMMAND(port, SelectRegisterWindow, w); 
	unlock(&ctlr->wlock); 
1997/0327/sys/src/9/pc/etherelnk3.c:793,8101997/0328/sys/src/9/pc/etherelnk3.c:847,864
1996/0607    
 
	len = sprint(buf, "interrupts: %ld\n", ctlr->interrupts); 
	len += sprint(buf+len, "timer: %ld\n", ctlr->timer); 
	len += sprint(buf+len, "carrierlost: %ld\n", ctlr->carrierlost); 
	len += sprint(buf+len, "sqeerrors: %ld\n", ctlr->sqeerrors); 
	len += sprint(buf+len, "multiplecolls: %ld\n", ctlr->multiplecolls); 
	len += sprint(buf+len, "singlecollframes: %ld\n", ctlr->singlecollframes); 
	len += sprint(buf+len, "latecollisions: %ld\n", ctlr->latecollisions); 
	len += sprint(buf+len, "rxoverruns: %ld\n", ctlr->rxoverruns); 
	len += sprint(buf+len, "framesxmittedok: %ld\n", ctlr->framesxmittedok); 
	len += sprint(buf+len, "framesrcvdok: %ld\n", ctlr->framesrcvdok); 
	len += sprint(buf+len, "framesdeferred: %ld\n", ctlr->framesdeferred); 
	len += sprint(buf+len, "bytesrcvdok: %ld\n", ctlr->bytesrcvdok); 
	len += sprint(buf+len, "bytesxmittedok: %ld\n", ctlr->bytesxmittedok); 
	sprint(buf+len, "badssd: %ld\n", ctlr->badssd); 
1997/0328    
	len += sprint(buf+len, "carrierlost: %ld\n", ctlr->stats[CarrierLost]); 
	len += sprint(buf+len, "sqeerrors: %ld\n", ctlr->stats[SqeErrors]); 
	len += sprint(buf+len, "multiplecolls: %ld\n", ctlr->stats[MultipleColls]); 
	len += sprint(buf+len, "singlecollframes: %ld\n", ctlr->stats[SingleCollFrames]); 
	len += sprint(buf+len, "latecollisions: %ld\n", ctlr->stats[LateCollisions]); 
	len += sprint(buf+len, "rxoverruns: %ld\n", ctlr->stats[RxOverruns]); 
	len += sprint(buf+len, "framesxmittedok: %ld\n", ctlr->stats[FramesXmittedOk]); 
	len += sprint(buf+len, "framesrcvdok: %ld\n", ctlr->stats[FramesRcvdOk]); 
	len += sprint(buf+len, "framesdeferred: %ld\n", ctlr->stats[FramesDeferred]); 
	len += sprint(buf+len, "bytesrcvdok: %ld\n", ctlr->stats[BytesRcvdOk]); 
	len += sprint(buf+len, "bytesxmittedok: %ld\n", ctlr->stats[BytesRcvdOk+1]); 
	sprint(buf+len, "badssd: %ld\n", ctlr->stats[BytesRcvdOk+2]); 
1996/0607    
 
	return readstr(offset, a, n, buf); 
} 
1997/0327/sys/src/9/pc/etherelnk3.c:1037,10421997/0328/sys/src/9/pc/etherelnk3.c:1091,1099
1997/0327    
	while(p = pcimatch(p, 0x10B7, 0)){ 
		port = p->bar[0] & ~0x01; 
		irq = p->intl; 
1997/0328    
		COMMAND(port, GlobalReset, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
1996/0607    
		if(ether->port == 0 || ether->port == port){ 
			ether->irq = irq; 
1997/0327    
			ether->tbdf = p->tbdf; 
1997/0327/sys/src/9/pc/etherelnk3.c:1074,10791997/0328/sys/src/9/pc/etherelnk3.c:1131,1139
1996/0929    
		media = ins(port+ResetOptions); 
	} 
 
1997/0328    
	if(media & miiConnector) 
		return xcvrMii; 
 
1996/0929    
	COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
	x = ins(port+MediaStatus) & ~(dcConverterEnabled|linkBeatEnable|jabberGuardEnable); 
	outs(port+MediaStatus, x); 
1997/0327/sys/src/9/pc/etherelnk3.c:1139,11481997/0328/sys/src/9/pc/etherelnk3.c:1199,1220
1996/0929    
	return autoSelect; 
} 
 
1997/0328    
static int 
eepromdata(int port, int offset) 
{ 
	COMMAND(port, SelectRegisterWindow, Wsetup); 
	while(EEPROMBUSY(port)) 
		; 
	EEPROMCMD(port, EepromReadRegister, offset); 
	while(EEPROMBUSY(port)) 
		; 
	return EEPROMDATA(port); 
} 
 
1996/0607    
int 
etherelnk3reset(Ether* ether) 
{ 
1996/0613    
	int busmaster, i, port, rxearly, rxstatus9, x, xcvr; 
1997/0328    
	int busmaster, did, i, port, rxearly, rxstatus9, x, xcvr; 
1997/0327    
	Block *bp, **bpp; 
	Adapter *ap; 
1996/0607    
	uchar ea[Eaddrlen]; 
1997/0327/sys/src/9/pc/etherelnk3.c:1157,11651997/0328/sys/src/9/pc/etherelnk3.c:1229,1234
1996/0607    
	 * If an adapter is found save the IRQ and transceiver type. 
	 */ 
	port = 0; 
1996/0613    
	rxearly = 2044; 
1996/0607    
	rxstatus9 = 0; 
	xcvr = 0; 
1997/0327    
	bpp = &adapter; 
	for(bp = *bpp; bp; bp = bp->next){ 
		ap = (Adapter*)bp->rp; 
1997/0327/sys/src/9/pc/etherelnk3.c:1173,12161997/0328/sys/src/9/pc/etherelnk3.c:1242,1301
1996/0607    
		} 
1997/0327    
		bpp = &bp->next; 
1996/0607    
	} 
	if(port == 0 && (port = tcm5XXpcmcia(ether))){ 
		xcvr = ((ins(port+AddressConfig) & xcvrMask9)>>14)<<20; 
		rxstatus9 = 1; 
	} 
	else if(port == 0 && (port = tcm59Xpci(ether))){ 
1997/0327    
		COMMAND(port, GlobalReset, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
1997/0328    
	if(port == 0) 
		port = tcm5XXpcmcia(ether); 
	if(port == 0) 
		port = tcm59Xpci(ether); 
	if(port == 0) 
		port = tcm5XXeisa(ether); 
	if(port == 0) 
		port = tcm509isa(ether); 
	if(port == 0) 
		return -1; 
	/* 
	 * Read the DeviceID from the EEPROM, it's at offset 0x03, 
	 * and do something depending on capabilities. 
	 */ 
	switch(did = eepromdata(port, 0x03)){ 
 
	case 0x9000: 
	case 0x9001: 
	case 0x9050: 
	case 0x9051: 
		if(BUSTYPE(ether->tbdf) != BusPCI) 
			goto buggery; 
		busmaster = 2; 
		goto vortex; 
 
	case 0x5900: 
	case 0x5920: 
	case 0x5950: 
	case 0x5951: 
	case 0x5952: 
	case 0x5970: 
	case 0x5971: 
	case 0x5972: 
		busmaster = 1; 
	vortex: 
1996/0607    
		COMMAND(port, SelectRegisterWindow, Wfifo); 
1996/0613    
		rxearly = 8188; 
1996/0929    
		xcvr = inl(port+InternalConfig) & (autoSelect|xcvrMask); 
1996/0607    
	} 
	else if(port == 0 && (port = tcm5XXeisa(ether))){ 
		x = ins(port+ProductID); 
		if((x & 0xFF00) == 0x5900){ 
			COMMAND(port, SelectRegisterWindow, Wfifo); 
1996/0613    
			rxearly = 8188; 
1996/0929    
			xcvr = inl(port+InternalConfig) & (autoSelect|xcvrMask); 
1996/0607    
		} 
		else{ 
1996/0929    
			x = ins(port+AddressConfig); 
			xcvr = ((x & xcvrMask9)>>14)<<20; 
			if(x & autoSelect9) 
				xcvr |= autoSelect; 
1996/0607    
			rxstatus9 = 1; 
		} 
	} 
	else if(port == 0 && (port = tcm509isa(ether))){ 
1997/0328    
		rxearly = 8188; 
		rxstatus9 = 0; 
		break; 
 
	buggery: 
	default: 
		busmaster = 0; 
		COMMAND(port, SelectRegisterWindow, Wsetup); 
1996/0929    
		x = ins(port+AddressConfig); 
		xcvr = ((x & xcvrMask9)>>14)<<20; 
		if(x & autoSelect9) 
			xcvr |= autoSelect; 
1997/0328    
		rxearly = 2044; 
1996/0607    
		rxstatus9 = 1; 
1997/0328    
		break; 
1996/0607    
	} 
 
	if(port == 0) 
		return -1; 
                 
	/* 
	 * Check if the adapter's station address is to be overridden. 
	 * If not, read it from the EEPROM and set in ether->ea prior to loading the 
1997/0327/sys/src/9/pc/etherelnk3.c:1218,12311997/0328/sys/src/9/pc/etherelnk3.c:1303,1310
1996/0607    
	 */ 
	memset(ea, 0, Eaddrlen); 
	if(memcmp(ea, ether->ea, Eaddrlen) == 0){ 
		COMMAND(port, SelectRegisterWindow, Wsetup); 
		while(EEPROMBUSY(port)) 
			; 
		for(i = 0; i < Eaddrlen/2; i++){ 
			EEPROMCMD(port, EepromReadRegister, i); 
			while(EEPROMBUSY(port)) 
				; 
			x = EEPROMDATA(port); 
1997/0328    
			x = eepromdata(port, i); 
1996/0929    
			ether->ea[2*i] = x>>8; 
			ether->ea[2*i+1] = x; 
1996/0607    
		} 
1997/0327/sys/src/9/pc/etherelnk3.c:1246,12521997/0328/sys/src/9/pc/etherelnk3.c:1325,1331
1996/0607    
	x = ins(port+MediaStatus) & ~(linkBeatEnable|jabberGuardEnable); 
	outs(port+MediaStatus, x); 
1997/0327    
	if(x & dataRate100){ 
1996/0607    
		busmaster = 1; 
1997/0328    
		ether->mbps = 100; 
1997/0327    
		x = inl(port+InternalConfig) & ~ramPartitionMask; 
		outl(port+InternalConfig, x|ramPartition1to1); 
	} 
1997/0327/sys/src/9/pc/etherelnk3.c:1254,12631997/0328/sys/src/9/pc/etherelnk3.c:1333,1343
1996/0607    
		busmaster = 0; 
	switch(xcvr){ 
 
1997/0328    
	case xcvrMii: 
		break; 
 
1996/0607    
	case xcvr100BaseTX: 
	case xcvr100BaseFX: 
		ether->mbps = 100; 
		/*FALLTHROUGH*/ 
	case xcvr10BaseT: 
		/* 
		 * Enable Link Beat and Jabber to start the 
1997/0328/sys/src/9/pc/etherelnk3.c:443,4541997/0403/sys/src/9/pc/etherelnk3.c:443,473 (short | long)
1996/0607    
promiscuous(void* arg, int on) 
{ 
	int filter, port; 
1997/0403    
	Ether *ether; 
1996/0607    
 
	port = ((Ether*)arg)->port; 
1997/0403    
	ether = (Ether*)arg; 
	port = ether->port; 
1997/0328    
 
1996/0607    
	filter = receiveBroadcast|receiveIndividual; 
1997/0403    
	if(ether->nmaddr) 
		filter |= receiveMulticast; 
1996/0607    
	if(on) 
		filter |= receiveAllFrames; 
1997/0403    
	COMMAND(port, SetRxFilter, filter); 
} 
 
static void 
multicast(void* arg, char *addr, int on) 
{ 
	int filter, port; 
	Ether *ether; 
 
	ether = (Ether*)arg; 
	port = ether->port; 
 
	filter = receiveBroadcast|receiveIndividual; 
	if(ether->nmaddr) 
		filter |= receiveMulticast; 
1996/0607    
	COMMAND(port, SetRxFilter, filter); 
} 
 
1997/0403/sys/src/9/pc/etherelnk3.c:457,4701997/0404/sys/src/9/pc/etherelnk3.c:457,473 (short | long)
1997/0403    
} 
 
static void 
multicast(void* arg, char *addr, int on) 
1997/0404    
multicast(void* arg, uchar *addr, int on) 
1997/0403    
{ 
	int filter, port; 
	Ether *ether; 
 
1997/0404    
	USED(addr, on); 
 
1997/0403    
	ether = (Ether*)arg; 
	port = ether->port; 
 
1997/0404    
print("mutlicast nmaddr == %d\n", ether->nmaddr); 
1997/0403    
	filter = receiveBroadcast|receiveIndividual; 
	if(ether->nmaddr) 
		filter |= receiveMulticast; 
1997/0403/sys/src/9/pc/etherelnk3.c:1314,13191997/0404/sys/src/9/pc/etherelnk3.c:1317,1323
1996/0607    
		rxstatus9 = 1; 
1997/0328    
		break; 
1996/0607    
	} 
1997/0404    
	USED(did); 
1996/0607    
 
	/* 
	 * Check if the adapter's station address is to be overridden. 
1997/0403/sys/src/9/pc/etherelnk3.c:1436,14411997/0404/sys/src/9/pc/etherelnk3.c:1440,1446
1996/0607    
	ether->ifstat = ifstat; 
 
	ether->promiscuous = promiscuous; 
1997/0404    
	ether->multicast = multicast; 
1996/0607    
	ether->arg = ether; 
 
	return 0; 
1997/0404/sys/src/9/pc/etherelnk3.c:467,4761997/0415/sys/src/9/pc/etherelnk3.c:467,478 (short | long)
1997/0403    
	ether = (Ether*)arg; 
	port = ether->port; 
 
1997/0404    
print("mutlicast nmaddr == %d\n", ether->nmaddr); 
1997/0415    
print("multicast nmaddr == %d\n", ether->nmaddr); 
1997/0403    
	filter = receiveBroadcast|receiveIndividual; 
	if(ether->nmaddr) 
		filter |= receiveMulticast; 
1997/0415    
	if(ether->prom) 
		filter |= receiveAllFrames; 
1996/0607    
	COMMAND(port, SetRxFilter, filter); 
} 
 
1997/0415/sys/src/9/pc/etherelnk3.c:856,8641997/0417/sys/src/9/pc/etherelnk3.c:856,864 (short | long)
1996/0607    
static long 
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; 
1996/0607    
 
	if(n == 0) 
		return 0; 
1997/0415/sys/src/9/pc/etherelnk3.c:869,8901997/0417/sys/src/9/pc/etherelnk3.c:869,894
1996/0607    
	statistics(ether); 
	iunlock(&ctlr->wlock); 
 
	len = sprint(buf, "interrupts: %ld\n", ctlr->interrupts); 
	len += sprint(buf+len, "timer: %ld\n", ctlr->timer); 
1997/0328    
	len += sprint(buf+len, "carrierlost: %ld\n", ctlr->stats[CarrierLost]); 
	len += sprint(buf+len, "sqeerrors: %ld\n", ctlr->stats[SqeErrors]); 
	len += sprint(buf+len, "multiplecolls: %ld\n", ctlr->stats[MultipleColls]); 
	len += sprint(buf+len, "singlecollframes: %ld\n", ctlr->stats[SingleCollFrames]); 
	len += sprint(buf+len, "latecollisions: %ld\n", ctlr->stats[LateCollisions]); 
	len += sprint(buf+len, "rxoverruns: %ld\n", ctlr->stats[RxOverruns]); 
	len += sprint(buf+len, "framesxmittedok: %ld\n", ctlr->stats[FramesXmittedOk]); 
	len += sprint(buf+len, "framesrcvdok: %ld\n", ctlr->stats[FramesRcvdOk]); 
	len += sprint(buf+len, "framesdeferred: %ld\n", ctlr->stats[FramesDeferred]); 
	len += sprint(buf+len, "bytesrcvdok: %ld\n", ctlr->stats[BytesRcvdOk]); 
	len += sprint(buf+len, "bytesxmittedok: %ld\n", ctlr->stats[BytesRcvdOk+1]); 
	sprint(buf+len, "badssd: %ld\n", ctlr->stats[BytesRcvdOk+2]); 
1997/0417    
	p = malloc(READSTR); 
	len = snprint(p, READSTR, "interrupts: %ld\n", ctlr->interrupts); 
	len += snprint(p+len, READSTR-len, "timer: %ld\n", ctlr->timer); 
	len += snprint(p+len, READSTR-len, "carrierlost: %ld\n", ctlr->stats[CarrierLost]); 
	len += snprint(p+len, READSTR-len, "sqeerrors: %ld\n", ctlr->stats[SqeErrors]); 
	len += snprint(p+len, READSTR-len, "multiplecolls: %ld\n", ctlr->stats[MultipleColls]); 
	len += snprint(p+len, READSTR-len, "singlecollframes: %ld\n", ctlr->stats[SingleCollFrames]); 
	len += snprint(p+len, READSTR-len, "latecollisions: %ld\n", ctlr->stats[LateCollisions]); 
	len += snprint(p+len, READSTR-len, "rxoverruns: %ld\n", ctlr->stats[RxOverruns]); 
	len += snprint(p+len, READSTR-len, "framesxmittedok: %ld\n", ctlr->stats[FramesXmittedOk]); 
	len += snprint(p+len, READSTR-len, "framesrcvdok: %ld\n", ctlr->stats[FramesRcvdOk]); 
	len += snprint(p+len, READSTR-len, "framesdeferred: %ld\n", ctlr->stats[FramesDeferred]); 
	len += snprint(p+len, READSTR-len, "bytesrcvdok: %ld\n", ctlr->stats[BytesRcvdOk]); 
	len += snprint(p+len, READSTR-len, "bytesxmittedok: %ld\n", ctlr->stats[BytesRcvdOk+1]); 
	snprint(p+len, READSTR-len, "badssd: %ld\n", ctlr->stats[BytesRcvdOk+2]); 
1996/0607    
 
	return readstr(offset, a, n, buf); 
1997/0417    
	n = readstr(offset, a, n, p); 
	free(p); 
 
	return n; 
1996/0607    
} 
 
1997/0327    
typedef struct Adapter { 
1997/0417/sys/src/9/pc/etherelnk3.c:467,4731997/0418/sys/src/9/pc/etherelnk3.c:467,472 (short | long)
1997/0403    
	ether = (Ether*)arg; 
	port = ether->port; 
 
1997/0415    
print("multicast nmaddr == %d\n", ether->nmaddr); 
1997/0403    
	filter = receiveBroadcast|receiveIndividual; 
	if(ether->nmaddr) 
		filter |= receiveMulticast; 
1997/0418/sys/src/9/pc/etherelnk3.c:1408,14141997/0614/sys/src/9/pc/etherelnk3.c:1408,1414 (short | long)
1996/0607    
	ilock(&ctlr->wlock); 
	ctlr->xcvr = xcvr; 
	statistics(ether); 
	memset(ctlr, 0, sizeof(Ctlr)); 
1997/0614    
	memset(ctlr->stats, 0, sizeof(ctlr->stats)); 
1996/0607    
 
	ctlr->busmaster = busmaster; 
	ctlr->xcvr = xcvr; 
1997/0614/sys/src/9/pc/etherelnk3.c:104,1131997/0712/sys/src/9/pc/etherelnk3.c:104,113 (short | long)
1996/0607    
}; 
 
1997/0328    
enum {						/* Stall command bits */ 
	UpStall			= 0x0000, 
	UpUnStall		= 0x0001, 
	DnStall			= 0x0002, 
	DnUnStall		= 0x0003, 
1997/0712    
	upStall			= 0x0000, 
	upUnStall		= 0x0001, 
	dnStall			= 0x0002, 
	dnUnStall		= 0x0003, 
1997/0328    
}; 
 
1996/0607    
enum {						/* SetRxFilter command bits */ 
1997/0614/sys/src/9/pc/etherelnk3.c:158,1631997/0712/sys/src/9/pc/etherelnk3.c:158,166
1996/0607    
	xcvrMask9		= 0xC000, 
						/* ConfigControl bits */ 
	Ena			= 0x0001, 
1997/0712    
	base10TAvailable9	= 0x0200, 
	coaxAvailable9		= 0x1000, 
	auiAvailable9		= 0x2000, 
1996/0607    
						/* EepromCommand bits */ 
	EepromReadRegister	= 0x0080, 
	EepromBusy		= 0x8000, 
1997/0614/sys/src/9/pc/etherelnk3.c:346,3571997/0712/sys/src/9/pc/etherelnk3.c:349,360
1997/0328    
	dnInProg		= 0x00000080, 
	counterSpeed		= 0x00000010,	/* 0 3.2uS, 1 320nS */ 
	countdownMode		= 0x00000020, 
						/* UpPktStatus bits */ 
1997/0712    
						/* UpPktStatus bits (dpd->control) */ 
1997/0328    
	upPktLenMask		= 0x00001FFF, 
	upStalled		= 0x00002000, 
	upError			= 0x00004000, 
	upPktComplete		= 0x00008000, 
	upOverrrun		= 0x00010000,	/* RxError<<16 */ 
1997/0712    
	upOverrun		= 0x00010000,	/* RxError<<16 */ 
1997/0328    
	upRuntFrame		= 0x00020000, 
	upAlignmentError	= 0x00040000, 
	upCRCError		= 0x00080000, 
1997/0614/sys/src/9/pc/etherelnk3.c:358,3631997/0712/sys/src/9/pc/etherelnk3.c:361,370
1997/0328    
	upOversizedFrame	= 0x00100000, 
	upDribbleBits		= 0x00800000, 
	upOverflow		= 0x01000000, 
1997/0712    
 
	dnIndicate		= 0x80000000,	/* FrameStartHeader (dpd->control) */ 
 
	updnLastFrag		= 0x80000000,	/* (dpd->len) */ 
1997/0328    
}; 
 
/* 
1997/0614/sys/src/9/pc/etherelnk3.c:364,3801997/0712/sys/src/9/pc/etherelnk3.c:371,397
1997/0328    
 * Up/Dn Packet Descriptor. 
 * The hardware info (np, control, addr, len) must be 8-byte aligned. 
 */ 
typedef struct Pd Pd; 
typedef struct Pd { 
	Pd*	next; 
1997/0712    
typedef struct Dpd Dpd; 
typedef struct Dpd { 
	ulong	np;				/* next pointer */ 
	ulong	control;			/* FSH or UpPktStatus */ 
	ulong	addr; 
	ulong	len; 
 
	Dpd*	next; 
1997/0328    
	Block*	bp; 
1997/0712    
	void*	base;				/* base of this allocation */ 
} Dpd; 
1997/0328    
 
1997/0712    
typedef struct Upd { 
1997/0328    
	ulong	np;				/* next pointer */ 
	ulong	control;			/* FSH or UpPktStatus */ 
	ulong	addr; 
	ulong	len; 
}; 
 
1997/0712    
	uchar	data[sizeof(Etherpkt)]; 
} Upd; 
 
1996/0607    
typedef struct { 
	Lock	wlock;				/* window access */ 
 
1997/0614/sys/src/9/pc/etherelnk3.c:382,4051997/0712/sys/src/9/pc/etherelnk3.c:399,514
1996/0607    
	int	busmaster; 
1997/0327    
	Block*	rbp;				/* receive buffer */ 
1996/0607    
 
1997/0327    
	Block*	txbp;				/* */ 
1997/0712    
	Block*	txbp;				/* FIFO -based transmission */ 
1996/0607    
	int	txthreshold; 
	int	txbusy; 
 
1997/0712    
	//Lock	upqlock;			/* full-busmaster -based reception */ 
	Block*	upqhead; 
	Block*	upqtail; 
	int	upalloc; 
	int	nupd; 
 
	Lock	dpdlock;			/* pool of free Dpd's */ 
	Dpd*	dpdpool; 
 
	Lock	dnqlock;			/* full-busmaster -based transmission */ 
	Dpd*	dnqhead; 
	Dpd*	dnqtail; 
 
1996/0607    
	long	interrupts;			/* statistics */ 
	long	timer; 
1997/0328    
	long	stats[BytesRcvdOk+2]; 
1997/0712    
	long	stats[BytesRcvdOk+3]; 
1996/0607    
 
	int	xcvr;				/* transceiver type */ 
	int	rxstatus9;			/* old-style RxStatus register */ 
1997/0327    
	int	rxearly;			/* RxEarlyThreshold */ 
1996/0925    
	int	ts;				/* threshold shift */ 
1997/0712    
	int	upenabled; 
	int	dnenabled; 
1996/0607    
} Ctlr; 
 
static Block* 
1997/0327    
allocrbp(Block* (*f)(int)) 
1997/0712    
updalloc(ulong np) 
1996/0607    
{ 
	Block *bp; 
1997/0712    
	Upd *upd; 
 
	/* 
	 * The hardware info (np, control, addr, len) 
	 * must be 8-byte aligned. 
	 */ 
	if(bp = iallocb(sizeof(Upd)+8)){ 
		bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 8); 
		bp->wp = bp->rp; 
		upd = (Upd*)bp->rp; 
		upd->np = np; 
		upd->control = 0; 
		upd->addr = PADDR(upd->data); 
		upd->len = updnLastFrag|sizeof(Etherpkt); 
	} 
 
	return bp; 
} 
 
static void 
init905(Ctlr* ctlr) 
{ 
	int i; 
	ulong np; 
	Block *bp; 
	Upd *upd; 
 
	np = 0; 
	for(i = 0; i < 16; i++){ 
		bp = updalloc(np); 
		if(ctlr->upqhead == 0) 
			ctlr->upqtail = bp; 
		bp->next = ctlr->upqhead; 
		ctlr->upqhead = bp; 
		np = PADDR(bp->rp); 
	} 
	ctlr->upqtail->next = ctlr->upqhead; 
	upd = (Upd*)ctlr->upqtail->rp; 
	upd->np = PADDR(ctlr->upqhead->rp); 
} 
 
static Dpd* 
dpdalloc(Ctlr* ctlr) 
{ 
	Dpd *dpd; 
	void *base; 
 
	ilock(&ctlr->dpdlock); 
	if(dpd = ctlr->dpdpool){ 
		ctlr->dpdpool = dpd->next; 
		iunlock(&ctlr->dpdlock); 
		dpd->next = 0; 
		dpd->bp = 0; 
	} 
	else{ 
		iunlock(&ctlr->dpdlock); 
		base = smalloc(sizeof(Dpd)+8); 
		dpd = (Dpd*)ROUNDUP((ulong)base, 8); 
		dpd->base = base; 
	} 
 
	return dpd; 
} 
 
static void 
dpdfree(Ctlr* ctlr, Dpd* dpd) 
{ 
	ilock(&ctlr->dpdlock); 
	dpd->next = ctlr->dpdpool; 
	ctlr->dpdpool = dpd; 
	iunlock(&ctlr->dpdlock); 
} 
 
static Block* 
rbpalloc(Block* (*f)(int)) 
{ 
	Block *bp; 
1996/0607    
	ulong addr; 
 
	/* 
1997/0614/sys/src/9/pc/etherelnk3.c:498,5051997/0712/sys/src/9/pc/etherelnk3.c:607,620
1996/0607    
	promiscuous(ether, ether->prom); 
 
1997/0327    
	x = interruptMask; 
1996/0607    
	if(ctlr->busmaster) 
1997/0712    
	if(ctlr->busmaster == 1) 
1996/0607    
		x &= ~(rxEarly|rxComplete); 
1997/0712    
	else{ 
		if(ctlr->dnenabled) 
			x &= ~transferInt; 
		if(ctlr->upenabled) 
			x &= ~(rxEarly|rxComplete); 
	} 
1996/0607    
	COMMAND(port, SetIndicationEnable, x); 
	COMMAND(port, SetInterruptEnable, x); 
 
1997/0614/sys/src/9/pc/etherelnk3.c:510,5171997/0712/sys/src/9/pc/etherelnk3.c:625,636
1996/0607    
	 * Prime the busmaster channel for receiving directly into a 
	 * receive packet buffer if necessary. 
	 */ 
	if(ctlr->busmaster) 
1997/0712    
	if(ctlr->busmaster == 1) 
1997/0327    
		startdma(ether, PADDR(ctlr->rbp->rp)); 
1997/0712    
	else{ 
		if(ctlr->upenabled) 
			outl(port+UpListPtr, PADDR(ctlr->upqhead->rp)); 
	} 
1996/0607    
 
	ctlr->attached = 1; 
	iunlock(&ctlr->wlock); 
1997/0614/sys/src/9/pc/etherelnk3.c:542,5511997/0712/sys/src/9/pc/etherelnk3.c:661,675
1997/0328    
	ctlr->stats[BytesRcvdOk] += ins(port+BytesRcvdOk) & 0xFFFF; 
	ctlr->stats[BytesRcvdOk+1] += ins(port+BytesXmittedOk) & 0xFFFF; 
1996/0607    
 
	if(ctlr->xcvr == xcvr100BaseTX || ctlr->xcvr == xcvr100BaseFX){ 
1997/0712    
	switch(ctlr->xcvr){ 
 
	case xcvrMii: 
	case xcvr100BaseTX: 
	case xcvr100BaseFX: 
1996/0607    
		COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
		STATUS(port); 
1997/0328    
		ctlr->stats[BytesRcvdOk+2] += inb(port+BadSSD); 
1997/0712    
		break; 
1996/0607    
	} 
 
	COMMAND(port, SelectRegisterWindow, w); 
1997/0614/sys/src/9/pc/etherelnk3.c:602,6071997/0712/sys/src/9/pc/etherelnk3.c:726,810
1996/0607    
} 
 
1997/0327    
static void 
1997/0712    
start905(Ether* ether, Dpd* add) 
{ 
	Ctlr *ctlr; 
	int dnlistptr, port; 
	Dpd *dpd; 
 
	ctlr = ether->ctlr; 
	port = ether->port; 
 
	ilock(&ctlr->dnqlock); 
	COMMAND(port, Stall, dnStall); 
	while(STATUS(port) & commandInProgress) 
		; 
 
	/* 
	 * Free any completed packets. 
	 */ 
	dnlistptr = inl(port+DnListPtr); 
	while(dpd = ctlr->dnqhead){ 
		if(PADDR(dpd) == dnlistptr) 
			break; 
		ctlr->dnqhead = dpd->next; 
		if(dpd->bp) 
			freeb(dpd->bp); 
		dpdfree(ctlr, dpd); 
	} 
 
	/* 
	 * Add any new packets to the queue. 
	 */ 
	if(add){ 
		if(ctlr->dnqhead){ 
			dpd = ctlr->dnqtail; 
			dpd->next = add; 
			dpd->np = PADDR(&add->np); 
			dpd->control &= ~dnIndicate; 
		} 
		else 
			ctlr->dnqhead = add; 
		ctlr->dnqtail = add; 
	} 
 
	/* 
	 * If the adapter is not currently processing anything 
	 * and there is something on the queue, start it processing. 
	 */ 
	if(dnlistptr == 0 && ctlr->dnqhead) 
		outl(port+DnListPtr, PADDR(ctlr->dnqhead)); 
 
	COMMAND(port, Stall, dnUnStall); 
	iunlock(&ctlr->dnqlock); 
} 
 
static void 
transmit905(Ether* ether) 
{ 
	Ctlr *ctlr; 
	Block *bp; 
	Dpd* dpd; 
 
	bp = qget(ether->oq); 
	if(bp == nil) 
		return; 
 
	ctlr = ether->ctlr; 
 
	dpd = dpdalloc(ctlr); 
	dpd->next = 0; 
	dpd->bp = bp; 
 
	dpd->np = 0; 
	dpd->control = dnIndicate|BLEN(bp); 
	dpd->addr = PADDR(bp->rp); 
	dpd->len = updnLastFrag|BLEN(bp); 
 
	start905(ether, dpd); 
} 
 
static void 
1997/0327    
transmit(Ether* ether) 
1996/0607    
{ 
	Ctlr *ctlr; 
1997/0614/sys/src/9/pc/etherelnk3.c:610,6151997/0712/sys/src/9/pc/etherelnk3.c:813,823
1996/0607    
	port = ether->port; 
	ctlr = ether->ctlr; 
 
1997/0712    
	if(ctlr->dnenabled){ 
		transmit905(ether); 
		return; 
	} 
 
1996/0607    
	ilock(&ctlr->wlock); 
	w = (STATUS(port)>>13) & 0x07; 
	COMMAND(port, SelectRegisterWindow, Wop); 
1997/0614/sys/src/9/pc/etherelnk3.c:619,6241997/0712/sys/src/9/pc/etherelnk3.c:827,888
1996/0607    
} 
 
static void 
1997/0712    
receive905(Ether* ether) 
{ 
	Ctlr *ctlr; 
	int port; 
	Block *bp, *xbp; 
	Upd *upd; 
 
	ctlr = ether->ctlr; 
	port = ether->port; 
 
	//ilock(&ctlr->upqlock); 
	COMMAND(port, Stall, upStall); 
	while(STATUS(port) & commandInProgress) 
		; 
 
	bp = ctlr->upqhead; 
	upd = (Upd*)bp->rp; 
	while(upd->control & upPktComplete){ 
		if(upd->control & upError){ 
			if(upd->control & upOverrun) 
				ether->overflows++; 
			if(upd->control & (upOversizedFrame|upRuntFrame)) 
				ether->buffs++; 
			if(upd->control & upAlignmentError) 
				ether->frames++; 
			if(upd->control & upCRCError) 
				ether->crcs++; 
 
			upd->control = 0; 
		} 
		else if(xbp = updalloc(upd->np)){ 
			bp->rp += sizeof(Upd)-sizeof(Etherpkt); 
			bp->wp = bp->rp + (upd->control & rxBytes); 
 
			xbp->next = bp->next; 
			bp->next = 0; 
 
			etheriq(ether, bp, 1); 
			bp = xbp; 
		} 
 
		upd = (Upd*)ctlr->upqtail->rp; 
		upd->np = PADDR(bp->rp); 
		ctlr->upqtail->next = bp; 
		ctlr->upqtail = bp; 
		ctlr->upqhead = bp->next; 
 
		bp = ctlr->upqhead; 
		upd = (Upd*)bp->rp; 
	} 
 
	COMMAND(port, Stall, upUnStall); 
	//iunlock(&ctlr->upqlock); 
} 
 
static void 
1996/0607    
receive(Ether* ether) 
{ 
	int len, port, rxerror, rxstatus; 
1997/0614/sys/src/9/pc/etherelnk3.c:629,6351997/0712/sys/src/9/pc/etherelnk3.c:893,899
1996/0607    
	ctlr = ether->ctlr; 
 
	while(((rxstatus = ins(port+RxStatus)) & rxIncomplete) == 0){ 
		if(ctlr->busmaster && (STATUS(port) & busMasterInProgress)) 
1997/0712    
		if(ctlr->busmaster == 1 && (STATUS(port) & busMasterInProgress)) 
1996/0607    
			break; 
 
		/* 
1997/0614/sys/src/9/pc/etherelnk3.c:677,6881997/0712/sys/src/9/pc/etherelnk3.c:941,952
1997/0327    
		 * If there was an error or a new receive buffer can't be 
		 * allocated, discard the packet and go on to the next. 
		 */ 
		if((rxstatus & rxError) || (bp = allocrbp(iallocb)) == 0){ 
1997/0712    
		if((rxstatus & rxError) || (bp = rbpalloc(iallocb)) == 0){ 
1996/0607    
			COMMAND(port, RxDiscard, 0); 
			while(STATUS(port) & commandInProgress) 
				; 
 
			if(ctlr->busmaster) 
1997/0712    
			if(ctlr->busmaster == 1) 
1997/0327    
				startdma(ether, PADDR(ctlr->rbp->rp)); 
 
			continue; 
1997/0614/sys/src/9/pc/etherelnk3.c:697,7031997/0712/sys/src/9/pc/etherelnk3.c:961,967
1997/0327    
		 *	  end-pointer of the one just received; 
		 *	pass the packet on to whoever wants it. 
		 */ 
		if(ctlr->busmaster == 0){ 
1997/0712    
		if(ctlr->busmaster == 0 || ctlr->busmaster == 2){ 
1997/0327    
			len = (rxstatus & rxBytes9); 
			ctlr->rbp->wp = ctlr->rbp->rp + len; 
			insl(port+Fifo, ctlr->rbp->rp, HOWMANY(len, 4)); 
1997/0614/sys/src/9/pc/etherelnk3.c:707,7131997/0712/sys/src/9/pc/etherelnk3.c:971,977
1997/0327    
		while(STATUS(port) & commandInProgress) 
			; 
1996/0607    
 
1997/0327    
		if(ctlr->busmaster) 
1997/0712    
		if(ctlr->busmaster == 1) 
1997/0327    
			ctlr->rbp->wp = startdma(ether, PADDR(bp->rp)); 
1996/0607    
 
1997/0327    
		etheriq(ether, ctlr->rbp, 1); 
1997/0614/sys/src/9/pc/etherelnk3.c:779,7841997/0712/sys/src/9/pc/etherelnk3.c:1043,1054
1996/0607    
			status &= ~(transferInt|rxComplete); 
		} 
 
1997/0712    
		if(status & (upComplete)){ 
			COMMAND(port, AcknowledgeInterrupt, upComplete); 
			receive905(ether); 
			status &= ~upComplete; 
		} 
 
1996/0607    
		if(status & txComplete){ 
			/* 
			 * Pop the TxStatus stack, accumulating errors. 
1997/0614/sys/src/9/pc/etherelnk3.c:796,8011997/0712/sys/src/9/pc/etherelnk3.c:1066,1075
1996/0607    
			}while(STATUS(port) & txComplete); 
 
1997/0327    
			if(s & txUnderrun){ 
1997/0712    
				if(ctlr->dnenabled){ 
					while(inl(port+PktStatus) & dnInProg) 
						; 
				} 
1996/0607    
				COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
				while(ins(port+MediaStatus) & txInProg) 
					; 
1997/0614/sys/src/9/pc/etherelnk3.c:812,8171997/0712/sys/src/9/pc/etherelnk3.c:1086,1093
1996/0607    
				while(STATUS(port) & commandInProgress) 
					; 
1996/0925    
				COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts); 
1997/0712    
				if(ctlr->busmaster == 2) 
					outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256)); 
1996/0607    
			} 
			COMMAND(port, TxEnable, 0); 
			ether->oerrs++; 
1997/0614/sys/src/9/pc/etherelnk3.c:826,8311997/0712/sys/src/9/pc/etherelnk3.c:1102,1113
1996/0607    
			status &= ~txAvailable; 
		} 
 
1997/0712    
		if(status & dnComplete){ 
			COMMAND(port, AcknowledgeInterrupt, dnComplete); 
			start905(ether, 0); 
			status &= ~dnComplete; 
		} 
 
1996/0607    
		if(status & updateStats){ 
			statistics(ether); 
			status &= ~updateStats; 
1997/0614/sys/src/9/pc/etherelnk3.c:869,8881997/0712/sys/src/9/pc/etherelnk3.c:1151,1170
1996/0607    
	iunlock(&ctlr->wlock); 
 
1997/0417    
	p = malloc(READSTR); 
	len = snprint(p, READSTR, "interrupts: %ld\n", ctlr->interrupts); 
	len += snprint(p+len, READSTR-len, "timer: %ld\n", ctlr->timer); 
	len += snprint(p+len, READSTR-len, "carrierlost: %ld\n", ctlr->stats[CarrierLost]); 
	len += snprint(p+len, READSTR-len, "sqeerrors: %ld\n", ctlr->stats[SqeErrors]); 
	len += snprint(p+len, READSTR-len, "multiplecolls: %ld\n", ctlr->stats[MultipleColls]); 
	len += snprint(p+len, READSTR-len, "singlecollframes: %ld\n", ctlr->stats[SingleCollFrames]); 
	len += snprint(p+len, READSTR-len, "latecollisions: %ld\n", ctlr->stats[LateCollisions]); 
	len += snprint(p+len, READSTR-len, "rxoverruns: %ld\n", ctlr->stats[RxOverruns]); 
	len += snprint(p+len, READSTR-len, "framesxmittedok: %ld\n", ctlr->stats[FramesXmittedOk]); 
	len += snprint(p+len, READSTR-len, "framesrcvdok: %ld\n", ctlr->stats[FramesRcvdOk]); 
	len += snprint(p+len, READSTR-len, "framesdeferred: %ld\n", ctlr->stats[FramesDeferred]); 
	len += snprint(p+len, READSTR-len, "bytesrcvdok: %ld\n", ctlr->stats[BytesRcvdOk]); 
	len += snprint(p+len, READSTR-len, "bytesxmittedok: %ld\n", ctlr->stats[BytesRcvdOk+1]); 
	snprint(p+len, READSTR-len, "badssd: %ld\n", ctlr->stats[BytesRcvdOk+2]); 
1997/0712    
	len = snprint(p, READSTR, "interrupts: %lud\n", ctlr->interrupts); 
	len += snprint(p+len, READSTR-len, "timer: %lud\n", ctlr->timer); 
	len += snprint(p+len, READSTR-len, "carrierlost: %lud\n", ctlr->stats[CarrierLost]); 
	len += snprint(p+len, READSTR-len, "sqeerrors: %lud\n", ctlr->stats[SqeErrors]); 
	len += snprint(p+len, READSTR-len, "multiplecolls: %lud\n", ctlr->stats[MultipleColls]); 
	len += snprint(p+len, READSTR-len, "singlecollframes: %lud\n", ctlr->stats[SingleCollFrames]); 
	len += snprint(p+len, READSTR-len, "latecollisions: %lud\n", ctlr->stats[LateCollisions]); 
	len += snprint(p+len, READSTR-len, "rxoverruns: %lud\n", ctlr->stats[RxOverruns]); 
	len += snprint(p+len, READSTR-len, "framesxmittedok: %lud\n", ctlr->stats[FramesXmittedOk]); 
	len += snprint(p+len, READSTR-len, "framesrcvdok: %lud\n", ctlr->stats[FramesRcvdOk]); 
	len += snprint(p+len, READSTR-len, "framesdeferred: %lud\n", ctlr->stats[FramesDeferred]); 
	len += snprint(p+len, READSTR-len, "bytesrcvdok: %lud\n", ctlr->stats[BytesRcvdOk]); 
	len += snprint(p+len, READSTR-len, "bytesxmittedok: %lud\n", ctlr->stats[BytesRcvdOk+1]); 
	snprint(p+len, READSTR-len, "badssd: %lud\n", ctlr->stats[BytesRcvdOk+2]); 
1996/0607    
 
1997/0417    
	n = readstr(offset, a, n, p); 
	free(p); 
1997/0614/sys/src/9/pc/etherelnk3.c:1009,10231997/0712/sys/src/9/pc/etherelnk3.c:1291,1305
1996/0607    
	return (acr & 0x1F)*0x10 + 0x200; 
} 
 
static ulong 
tcm509isa(Ether* ether) 
1997/0712    
static void 
tcm509isa(void) 
1996/0607    
{ 
	int irq, port; 
 
	/* 
	 * Attempt to activate adapters until one matches the 
	 * address criteria. If adapter is set for EISA mode (0x3F0), 
	 * tag it and ignore. Otherwise, activate it fully. 
1997/0712    
	 * Attempt to activate all adapters. If adapter is set for 
	 * EISA mode (0x3F0), tag it and ignore. Otherwise, activate 
	 * it fully. 
1996/0607    
	 */ 
	while(port = activate()){ 
		/* 
1997/0614/sys/src/9/pc/etherelnk3.c:1051,10801997/0712/sys/src/9/pc/etherelnk3.c:1333,1354
1996/0607    
		COMMAND(port, AcknowledgeInterrupt, 0xFF); 
 
		irq = (ins(port+ResourceConfig)>>12) & 0x0F; 
		if(ether->port == 0 || ether->port == port){ 
			ether->irq = irq; 
			return port; 
		} 
                 
1997/0327    
		tcmadapter(port, irq, BUSUNKNOWN); 
1996/0607    
	} 
                 
	return 0; 
} 
 
static int 
tcm5XXeisa(Ether* ether) 
1997/0712    
static void 
tcm5XXeisa(void) 
1996/0607    
{ 
	static int slot = 1; 
	ushort x; 
	int irq, port; 
1997/0712    
	int irq, port, slot; 
1996/0607    
 
	/* 
	 * First time through, check if this is an EISA machine. 
1997/0712    
	 * Check if this is an EISA machine. 
1996/0607    
	 * If not, nothing to do. 
	 */ 
	if(slot == 1 && strncmp((char*)(KZERO|0xFFFD9), "EISA", 4)) 
		return 0; 
1997/0712    
	if(strncmp((char*)(KZERO|0xFFFD9), "EISA", 4)) 
		return; 
1996/0607    
 
	/* 
	 * Continue through the EISA slots looking for a match on both 
1997/0614/sys/src/9/pc/etherelnk3.c:1082,10891997/0712/sys/src/9/pc/etherelnk3.c:1356,1363
1996/0929    
	 * If an adapter is found, select window 0, enable it and clear 
1996/0607    
	 * out any lingering status and interrupts. 
	 */ 
	while(slot < MaxEISA){ 
		port = slot++*0x1000; 
1997/0712    
	for(slot = 1; slot < MaxEISA; slot++){ 
		port = slot*0x1000; 
1996/0607    
		if(ins(port+0xC80+ManufacturerID) != 0x6D50) 
			continue; 
		x = ins(port+0xC80+ProductID); 
1997/0614/sys/src/9/pc/etherelnk3.c:1098,11201997/0712/sys/src/9/pc/etherelnk3.c:1372,1388
1996/0607    
		COMMAND(port, AcknowledgeInterrupt, 0xFF); 
 
		irq = (ins(port+ResourceConfig)>>12) & 0x0F; 
		if(ether->port == 0 || ether->port == port){ 
			ether->irq = irq; 
			return port; 
		} 
                 
1997/0327    
		tcmadapter(port, irq, BUSUNKNOWN); 
1996/0607    
	} 
                 
	return 0; 
} 
 
static int 
tcm59Xpci(Ether* ether) 
1997/0712    
static void 
tcm59Xpci(void) 
1996/0607    
{ 
1997/0327    
	static Pcidev *p; 
1997/0712    
	Pcidev *p; 
1996/0607    
	int irq, port; 
 
1997/0712    
	p = nil; 
1997/0327    
	while(p = pcimatch(p, 0x10B7, 0)){ 
		port = p->bar[0] & ~0x01; 
		irq = p->intl; 
1997/0614/sys/src/9/pc/etherelnk3.c:1121,11361997/0712/sys/src/9/pc/etherelnk3.c:1389,1397
1997/0328    
		COMMAND(port, GlobalReset, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
1996/0607    
		if(ether->port == 0 || ether->port == port){ 
			ether->irq = irq; 
1997/0327    
			ether->tbdf = p->tbdf; 
1996/0607    
			return port; 
		} 
 
1997/0327    
		tcmadapter(port, irq, p->tbdf); 
1996/0607    
	} 
                 
	return 0; 
} 
 
static int 
1997/0614/sys/src/9/pc/etherelnk3.c:1142,11491997/0712/sys/src/9/pc/etherelnk3.c:1403,1452
1996/0607    
	return 0; 
} 
 
1997/0712    
static void 
setxcvr(int port, int xcvr, int is9) 
{ 
	int x; 
 
	if(is9){ 
		COMMAND(port, SelectRegisterWindow, Wsetup); 
		x = ins(port+AddressConfig) & ~xcvrMask9; 
		x |= (xcvr>>20)<<14; 
		outs(port+AddressConfig, x); 
	} 
	else{ 
		COMMAND(port, SelectRegisterWindow, Wfifo); 
		x = inl(port+InternalConfig) & ~xcvrMask; 
		x |= xcvr; 
		outl(port+InternalConfig, x); 
	} 
 
	COMMAND(port, TxReset, 0); 
	while(STATUS(port) & commandInProgress) 
		; 
	COMMAND(port, RxReset, 0); 
	while(STATUS(port) & commandInProgress) 
		; 
} 
 
#ifdef notdef 
static struct xxx { 
	int	available; 
	int	next; 
} xxx[8] = { 
	{ base10TAvailable,	1, },		/* xcvr10BaseT	-> xcvrAui */ 
	{ auiAvailable,		3, },		/* xcvrAui	-> xcvr10Base2 */ 
	{ 0, -1, }, 
	{ coaxAvailable,	-1, },		/* xcvr10Base2	-> nowhere */ 
	{ baseTXAvailable,	5, },		/* xcvr100BaseTX-> xcvr100BaseFX */ 
	{ baseFXAvailable,	-1, },		/* xcvr100BaseFX-> nowhere */ 
	{ miiConnector,		-1, },		/* xcvrMii	-> nowhere */ 
	{ 0, -1, }, 
}; 
#endif /* notdef */ 
 
1996/0929    
static int 
autoselect(int port, int rxstatus9) 
1997/0712    
autoselect(int port, int xcvr, int is9) 
1996/0929    
{ 
	int media, x; 
 
1997/0614/sys/src/9/pc/etherelnk3.c:1151,11901997/0712/sys/src/9/pc/etherelnk3.c:1454,1507
1996/0929    
	 * Pathetic attempt at automatic media selection. 
	 * Really just to get the Fast Etherlink 10BASE-T/100BASE-TX 
	 * cards operational. 
1997/0712    
	 * It's a bonus if it works for anything else. 
1996/0929    
	 */ 
	media = auiAvailable|coaxAvailable|base10TAvailable; 
	if(rxstatus9 == 0){ 
1997/0712    
	if(is9){ 
		COMMAND(port, SelectRegisterWindow, Wsetup); 
		x = ins(port+ConfigControl); 
		media = 0; 
		if(x & base10TAvailable9) 
			media |= base10TAvailable; 
		if(x & coaxAvailable9) 
			media |= coaxAvailable; 
		if(x & auiAvailable9) 
			media |= auiAvailable; 
	} 
	else{ 
1996/0929    
		COMMAND(port, SelectRegisterWindow, Wfifo); 
		media = ins(port+ResetOptions); 
	} 
1997/0712    
//print("autoselect: media %uX\n", media); 
1996/0929    
 
1997/0328    
	if(media & miiConnector) 
		return xcvrMii; 
 
1996/0929    
	COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
	x = ins(port+MediaStatus) & ~(dcConverterEnabled|linkBeatEnable|jabberGuardEnable); 
	outs(port+MediaStatus, x); 
1997/0712    
//COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
//print("autoselect: media status %uX\n", ins(port+MediaStatus)); 
1996/0929    
 
	if(media & baseTXAvailable){ 
		/* 
		 * Must have InternalConfig register. 
		 */ 
		COMMAND(port, SelectRegisterWindow, Wfifo); 
		x = inl(port+InternalConfig) & ~xcvrMask; 
		x |= xcvr100BaseTX; 
		outl(port+InternalConfig, x); 
		COMMAND(port, TxReset, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
		COMMAND(port, RxReset, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
1997/0712    
		setxcvr(port, xcvr100BaseTX, is9); 
1996/0929    
 
		COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
		x = ins(port+MediaStatus); 
		outs(port+MediaStatus, linkBeatEnable|jabberGuardEnable|x); 
		delay(1); 
1997/0712    
		x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable); 
		outs(port+MediaStatus, linkBeatEnable|x); 
		delay(10); 
1996/0929    
 
1997/0712    
{ int i, v; 
  for(i = 0; i < 2000; i++){ 
	v = ins(port+MediaStatus); 
	if(v & linkBeatDetect){ 
		print("count %d v %uX\n", i, v); 
		return xcvr100BaseTX; 
	} 
	delay(1); 
  } 
//print("count %d v %uX\n", i, ins(port+MediaStatus)); 
} 
 
1996/0929    
		if(ins(port+MediaStatus) & linkBeatDetect) 
			return xcvr100BaseTX; 
		outs(port+MediaStatus, x); 
1997/0614/sys/src/9/pc/etherelnk3.c:1191,12191997/0712/sys/src/9/pc/etherelnk3.c:1508,1519
1996/0929    
	} 
 
	if(media & base10TAvailable){ 
		if(rxstatus9 == 0){ 
			COMMAND(port, SelectRegisterWindow, Wfifo); 
			x = inl(port+InternalConfig) & ~xcvrMask; 
			x |= xcvr10BaseT; 
			outl(port+InternalConfig, x); 
		} 
		else{ 
			COMMAND(port, SelectRegisterWindow, Wsetup); 
			x = ins(port+AddressConfig) & ~xcvrMask9; 
			x |= (xcvr10BaseT>>20)<<14; 
			outs(port+AddressConfig, x); 
		} 
		COMMAND(port, TxReset, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
		COMMAND(port, RxReset, 0); 
		while(STATUS(port) & commandInProgress) 
			; 
1997/0712    
		setxcvr(port, xcvr10BaseT, is9); 
1996/0929    
 
		COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
		x = ins(port+MediaStatus); 
1997/0712    
		x = ins(port+MediaStatus) & ~dcConverterEnabled; 
1996/0929    
		outs(port+MediaStatus, linkBeatEnable|jabberGuardEnable|x); 
		delay(1); 
1997/0712    
		delay(100); 
1996/0929    
 
		if(ins(port+MediaStatus) & linkBeatDetect) 
			return xcvr10BaseT; 
1997/0614/sys/src/9/pc/etherelnk3.c:1246,12601997/0712/sys/src/9/pc/etherelnk3.c:1546,1568
1997/0327    
	Adapter *ap; 
1996/0607    
	uchar ea[Eaddrlen]; 
	Ctlr *ctlr; 
1997/0712    
	static int scandone; 
1996/0607    
 
	/* 
	 * 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 adapter on PCI, EISA and finally 
	 * using the little ISA configuration dance. The EISA and ISA scan 
	 * routines leave Wsetup mapped. 
	 * If an adapter is found save the IRQ and transceiver type. 
1997/0712    
	 * Scan for adapter on PCI, EISA and finally 
	 * using the little ISA configuration dance. 
1996/0607    
	 */ 
1997/0712    
	if(scandone == 0){ 
		tcm59Xpci(); 
		tcm5XXeisa(); 
		tcm509isa(); 
		scandone = 1; 
	} 
 
	/* 
	 * Any adapter matches if no ether->port is supplied, 
	 * otherwise the ports must match. 
	 */ 
1996/0607    
	port = 0; 
1997/0327    
	bpp = &adapter; 
	for(bp = *bpp; bp; bp = bp->next){ 
1997/0614/sys/src/9/pc/etherelnk3.c:1269,12841997/0712/sys/src/9/pc/etherelnk3.c:1577,1585
1996/0607    
		} 
1997/0327    
		bpp = &bp->next; 
1996/0607    
	} 
1997/0328    
	if(port == 0) 
		port = tcm5XXpcmcia(ether); 
	if(port == 0) 
		port = tcm59Xpci(ether); 
	if(port == 0) 
		port = tcm5XXeisa(ether); 
	if(port == 0) 
		port = tcm509isa(ether); 
	if(port == 0) 
1997/0712    
	if(port == 0 && (port = tcm5XXpcmcia(ether)) == 0) 
1997/0328    
		return -1; 
1997/0712    
 
1997/0328    
	/* 
	 * Read the DeviceID from the EEPROM, it's at offset 0x03, 
	 * and do something depending on capabilities. 
1997/0614/sys/src/9/pc/etherelnk3.c:1322,13281997/0712/sys/src/9/pc/etherelnk3.c:1623,1628
1996/0607    
		rxstatus9 = 1; 
1997/0328    
		break; 
1996/0607    
	} 
1997/0404    
	USED(did); 
1996/0607    
 
	/* 
	 * Check if the adapter's station address is to be overridden. 
1997/0614/sys/src/9/pc/etherelnk3.c:1347,13811997/0712/sys/src/9/pc/etherelnk3.c:1647,1700
1996/0607    
	 * busmastering can be used. Due to bugs in the first revision 
	 * of the 3C59[05], don't use busmastering at 10Mbps. 
	 */ 
1997/0712    
//print("reset: xcvr %uX\n", xcvr); 
1996/0929    
	if(xcvr & autoSelect) 
		xcvr = autoselect(port, rxstatus9); 
1996/0607    
	COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
	x = ins(port+MediaStatus) & ~(linkBeatEnable|jabberGuardEnable); 
	outs(port+MediaStatus, x); 
1997/0327    
	if(x & dataRate100){ 
1997/0328    
		ether->mbps = 100; 
1997/0327    
		x = inl(port+InternalConfig) & ~ramPartitionMask; 
		outl(port+InternalConfig, x|ramPartition1to1); 
	} 
1996/0607    
	else 
		busmaster = 0; 
1997/0712    
		xcvr = autoselect(port, xcvr, rxstatus9); 
1996/0607    
	switch(xcvr){ 
 
1997/0328    
	case xcvrMii: 
1997/0712    
		/* 
		 * Bug? the 3c905 always seems to have dataRate100 set. 
		 */ 
		COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
		if(ins(port+MediaStatus) & dataRate100) 
			ether->mbps = 100; 
1997/0328    
		break; 
 
1996/0607    
	case xcvr100BaseTX: 
	case xcvr100BaseFX: 
1997/0712    
		COMMAND(port, SelectRegisterWindow, Wfifo); 
		x = inl(port+InternalConfig) & ~ramPartitionMask; 
		outl(port+InternalConfig, x|ramPartition1to1); 
 
		COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
		x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable); 
		x |= linkBeatEnable; 
		outs(port+MediaStatus, x); 
 
		if(x & dataRate100) 
			ether->mbps = 100; 
		break; 
 
1996/0607    
	case xcvr10BaseT: 
		/* 
		 * Enable Link Beat and Jabber to start the 
		 * transceiver. 
		 */ 
1997/0712    
		COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
		x = ins(port+MediaStatus) & ~dcConverterEnabled; 
1996/0607    
		x |= linkBeatEnable|jabberGuardEnable; 
		outs(port+MediaStatus, x); 
1997/0712    
 
		if((did & 0xFF00) == 0x5900) 
			busmaster = 0; 
1996/0607    
		break; 
 
	case xcvr10Base2: 
1997/0712    
		COMMAND(port, SelectRegisterWindow, Wdiagnostic); 
		x = ins(port+MediaStatus) & ~(linkBeatEnable|jabberGuardEnable); 
		outs(port+MediaStatus, x); 
 
1996/0607    
		/* 
		 * Start the DC-DC converter. 
		 * Wait > 800 microseconds. 
1997/0614/sys/src/9/pc/etherelnk3.c:1420,14281997/0712/sys/src/9/pc/etherelnk3.c:1739,1772
1996/0607    
	COMMAND(port, StatisticsEnable, 0); 
 
	/* 
1997/0327    
	 * Allocate the receive buffer. 
1997/0712    
	 * Allocate any receive buffers. 
1996/0607    
	 */ 
1997/0327    
	ctlr->rbp = allocrbp(allocb); 
1997/0712    
	switch(ctlr->busmaster){ 
 
	case 2: 
		ctlr->dnenabled = 1; 
 
		/* 
		 * Too severe, can use receive busmastering at 100Mbps OK, 
		 * but how to tell which rate is actually being used - the 
		 * 3c905 always seems to have dataRate100 set? 
		 */ 
		x = eepromdata(port, 0x0F); 
		print("software info 2: %uX\n", x); 
		if(x & 0x01) 
			ctlr->upenabled = 1; 
 
		if(ctlr->upenabled) 
			init905(ctlr); 
		else 
			ctlr->rbp = rbpalloc(allocb); 
		outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256)); 
		break; 
 
	default: 
		ctlr->rbp = rbpalloc(allocb); 
		break; 
	} 
1996/0607    
 
	/* 
	 * Set a base TxStartThresh which will be incremented 
1997/0712/sys/src/9/pc/etherelnk3.c:460,4661997/0715/sys/src/9/pc/etherelnk3.c:460,466 (short | long)
1997/0712    
	Upd *upd; 
 
	np = 0; 
	for(i = 0; i < 16; i++){ 
1997/0715    
	for(i = 0; i < 64; i++){ 
1997/0712    
		bp = updalloc(np); 
		if(ctlr->upqhead == 0) 
			ctlr->upqtail = bp; 
1997/0712/sys/src/9/pc/etherelnk3.c:1747,17601997/0715/sys/src/9/pc/etherelnk3.c:1747,1765
1997/0712    
		ctlr->dnenabled = 1; 
 
		/* 
		 * Too severe, can use receive busmastering at 100Mbps OK, 
		 * but how to tell which rate is actually being used - the 
		 * 3c905 always seems to have dataRate100 set? 
1997/0715    
		 * 10MUpldBug. 
		 * Disabling is too severe, can use receive busmastering at 
		 * 100Mbps OK, but how to tell which rate is actually being used - 
		 * the 3c905 always seems to have dataRate100 set? 
		 * Believe the bug doesn't apply if upRxEarlyEnable is set 
		 * and the threshold is set such that uploads won't start 
		 * until the whole packet has been received. 
1997/0712    
		 */ 
1997/0715    
		ctlr->upenabled = 1; 
1997/0712    
		x = eepromdata(port, 0x0F); 
		print("software info 2: %uX\n", x); 
		if(x & 0x01) 
			ctlr->upenabled = 1; 
1997/0715    
		//print("software info 2: %uX\n", x); 
		if(!(x & 0x01)) 
			outl(port+PktStatus, upRxEarlyEnable); 
1997/0712    
 
		if(ctlr->upenabled) 
			init905(ctlr); 
1997/0715/sys/src/9/pc/etherelnk3.c:6,121997/0806/sys/src/9/pc/etherelnk3.c:6,12 (short | long)
1996/0607    
 *	autoSelect; 
 *	PCI latency timer and master enable; 
1997/0327    
 *	errata list; 
1997/0328    
 *	3C90x full busmastering; 
1997/0806    
 *	limit 3C90x transmit queue; 
1997/0328    
 *	rewrite all initialisation. 
1996/0607    
 * 
 * Product ID: 
1997/0806/sys/src/9/pc/etherelnk3.c:6,121997/0919/sys/src/9/pc/etherelnk3.c:6,11 (short | long)
1996/0607    
 *	autoSelect; 
 *	PCI latency timer and master enable; 
1997/0327    
 *	errata list; 
1997/0806    
 *	limit 3C90x transmit queue; 
1997/0328    
 *	rewrite all initialisation. 
1996/0607    
 * 
 * Product ID: 
1997/0806/sys/src/9/pc/etherelnk3.c:365,3971997/0919/sys/src/9/pc/etherelnk3.c:364,390
1997/0712    
	dnIndicate		= 0x80000000,	/* FrameStartHeader (dpd->control) */ 
 
	updnLastFrag		= 0x80000000,	/* (dpd->len) */ 
1997/0919    
 
	Nup			= 32, 
	Ndn			= 16, 
1997/0328    
}; 
 
/* 
 * Up/Dn Packet Descriptor. 
 * The hardware info (np, control, addr, len) must be 8-byte aligned. 
1997/0919    
 * Up/Dn Packet Descriptors. 
 * The hardware info (np, control, addr, len) must be 8-byte aligned 
 * and this structure size must be a multiple of 8. 
1997/0328    
 */ 
1997/0712    
typedef struct Dpd Dpd; 
typedef struct Dpd { 
1997/0919    
typedef struct Pd Pd; 
typedef struct Pd { 
1997/0712    
	ulong	np;				/* next pointer */ 
	ulong	control;			/* FSH or UpPktStatus */ 
	ulong	addr; 
	ulong	len; 
 
	Dpd*	next; 
1997/0919    
	Pd*	next; 
1997/0328    
	Block*	bp; 
1997/0712    
	void*	base;				/* base of this allocation */ 
} Dpd; 
1997/0919    
} Pd; 
1997/0328    
 
1997/0712    
typedef struct Upd { 
1997/0328    
	ulong	np;				/* next pointer */ 
	ulong	control;			/* FSH or UpPktStatus */ 
	ulong	addr; 
	ulong	len; 
                 
1997/0712    
	uchar	data[sizeof(Etherpkt)]; 
} Upd; 
                 
1996/0607    
typedef struct { 
	Lock	wlock;				/* window access */ 
 
1997/0806/sys/src/9/pc/etherelnk3.c:403,4251997/0919/sys/src/9/pc/etherelnk3.c:396,424
1996/0607    
	int	txthreshold; 
	int	txbusy; 
 
1997/0712    
	//Lock	upqlock;			/* full-busmaster -based reception */ 
	Block*	upqhead; 
	Block*	upqtail; 
	int	upalloc; 
	int	nupd; 
1997/0919    
	int	nup;				/* full-busmaster -based reception */ 
	void*	upbase; 
	Pd*	upr; 
	Pd*	uphead; 
1997/0712    
 
	Lock	dpdlock;			/* pool of free Dpd's */ 
	Dpd*	dpdpool; 
1997/0919    
	Lock	dnlock;				/* full-busmaster -based transmission */ 
	int	ndn; 
	void*	dnbase; 
	Pd*	dnr; 
	Pd*	dnhead; 
	Pd*	dntail; 
	int	dnq; 
1997/0712    
 
	Lock	dnqlock;			/* full-busmaster -based transmission */ 
	Dpd*	dnqhead; 
	Dpd*	dnqtail; 
                 
1996/0607    
	long	interrupts;			/* statistics */ 
	long	timer; 
1997/0712    
	long	stats[BytesRcvdOk+3]; 
1996/0607    
 
1997/0919    
	int	upqmax; 
	int	upstalls; 
	int	dnqmax; 
	long	dninterrupts; 
	long	dnqueued; 
 
1996/0607    
	int	xcvr;				/* transceiver type */ 
	int	rxstatus9;			/* old-style RxStatus register */ 
1997/0327    
	int	rxearly;			/* RxEarlyThreshold */ 
1997/0806/sys/src/9/pc/etherelnk3.c:428,5101997/0919/sys/src/9/pc/etherelnk3.c:427,476
1997/0712    
	int	dnenabled; 
1996/0607    
} Ctlr; 
 
static Block* 
1997/0712    
updalloc(ulong np) 
1997/0919    
static void 
init905(Ctlr* ctlr) 
1996/0607    
{ 
	Block *bp; 
1997/0712    
	Upd *upd; 
1997/0919    
	Pd *pd, *prev; 
1997/0712    
 
	/* 
	 * The hardware info (np, control, addr, len) 
	 * must be 8-byte aligned. 
1997/0919    
	 * Create rings for the receive and transmit sides. 
	 * Take care with alignment: 
	 *	make sure ring base is 8-byte aligned; 
	 *	make sure each entry is 8-byte aligned. 
1997/0712    
	 */ 
	if(bp = iallocb(sizeof(Upd)+8)){ 
		bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 8); 
		bp->wp = bp->rp; 
		upd = (Upd*)bp->rp; 
		upd->np = np; 
		upd->control = 0; 
		upd->addr = PADDR(upd->data); 
		upd->len = updnLastFrag|sizeof(Etherpkt); 
	} 
1997/0919    
	ctlr->upbase = malloc((ctlr->nup+1)*sizeof(Pd)); 
	ctlr->upr = (Pd*)ROUNDUP((ulong)ctlr->upbase, 8); 
1997/0712    
 
	return bp; 
} 
1997/0919    
	prev = ctlr->upr; 
	for(pd = &ctlr->upr[ctlr->nup-1]; pd >= ctlr->upr; pd--){ 
		pd->np = PADDR(&prev->np); 
		pd->control = 0; 
		bp = allocb(sizeof(Etherpkt)); 
		pd->addr = PADDR(bp->rp); 
		pd->len = updnLastFrag|sizeof(Etherpkt); 
1997/0712    
 
static void 
init905(Ctlr* ctlr) 
{ 
	int i; 
	ulong np; 
	Block *bp; 
	Upd *upd; 
                 
	np = 0; 
1997/0715    
	for(i = 0; i < 64; i++){ 
1997/0712    
		bp = updalloc(np); 
		if(ctlr->upqhead == 0) 
			ctlr->upqtail = bp; 
		bp->next = ctlr->upqhead; 
		ctlr->upqhead = bp; 
		np = PADDR(bp->rp); 
1997/0919    
		pd->next = prev; 
		prev = pd; 
		pd->bp = bp; 
1997/0712    
	} 
	ctlr->upqtail->next = ctlr->upqhead; 
	upd = (Upd*)ctlr->upqtail->rp; 
	upd->np = PADDR(ctlr->upqhead->rp); 
} 
1997/0919    
	ctlr->uphead = ctlr->upr; 
1997/0712    
 
static Dpd* 
dpdalloc(Ctlr* ctlr) 
{ 
	Dpd *dpd; 
	void *base; 
1997/0919    
	ilock(&ctlr->dnlock); 
	ctlr->dnbase = malloc((ctlr->ndn+1)*sizeof(Pd)); 
	ctlr->dnr = (Pd*)ROUNDUP((ulong)ctlr->dnbase, 8); 
1997/0712    
 
	ilock(&ctlr->dpdlock); 
	if(dpd = ctlr->dpdpool){ 
		ctlr->dpdpool = dpd->next; 
		iunlock(&ctlr->dpdlock); 
		dpd->next = 0; 
		dpd->bp = 0; 
1997/0919    
	prev = ctlr->dnr; 
	for(pd = &ctlr->dnr[ctlr->ndn-1]; pd >= ctlr->dnr; pd--){ 
		pd->next = prev; 
		prev = pd; 
1997/0712    
	} 
	else{ 
		iunlock(&ctlr->dpdlock); 
		base = smalloc(sizeof(Dpd)+8); 
		dpd = (Dpd*)ROUNDUP((ulong)base, 8); 
		dpd->base = base; 
	} 
                 
	return dpd; 
1997/0919    
	ctlr->dnhead = ctlr->dnr; 
	ctlr->dntail = ctlr->dnr; 
	ctlr->dnq = 0; 
	iunlock(&ctlr->dnlock); 
1997/0712    
} 
 
static void 
dpdfree(Ctlr* ctlr, Dpd* dpd) 
{ 
	ilock(&ctlr->dpdlock); 
	dpd->next = ctlr->dpdpool; 
	ctlr->dpdpool = dpd; 
	iunlock(&ctlr->dpdlock); 
} 
                 
static Block* 
rbpalloc(Block* (*f)(int)) 
{ 
1997/0806/sys/src/9/pc/etherelnk3.c:629,6351997/0919/sys/src/9/pc/etherelnk3.c:595,601
1997/0327    
		startdma(ether, PADDR(ctlr->rbp->rp)); 
1997/0712    
	else{ 
		if(ctlr->upenabled) 
			outl(port+UpListPtr, PADDR(ctlr->upqhead->rp)); 
1997/0919    
			outl(port+UpListPtr, PADDR(&ctlr->uphead->np)); 
1997/0712    
	} 
1996/0607    
 
	ctlr->attached = 1; 
1997/0806/sys/src/9/pc/etherelnk3.c:726,7411997/0919/sys/src/9/pc/etherelnk3.c:692,708
1996/0607    
} 
 
1997/0327    
static void 
1997/0712    
start905(Ether* ether, Dpd* add) 
1997/0919    
txstart905(Ether* ether) 
1997/0712    
{ 
	Ctlr *ctlr; 
	int dnlistptr, port; 
	Dpd *dpd; 
1997/0919    
	Block *bp; 
	Pd *pd; 
1997/0712    
 
	ctlr = ether->ctlr; 
	port = ether->port; 
 
	ilock(&ctlr->dnqlock); 
1997/0919    
	ilock(&ctlr->dnlock); 
1997/0712    
	COMMAND(port, Stall, dnStall); 
	while(STATUS(port) & commandInProgress) 
		; 
1997/0806/sys/src/9/pc/etherelnk3.c:744,8101997/0919/sys/src/9/pc/etherelnk3.c:711,766
1997/0712    
	 * Free any completed packets. 
	 */ 
	dnlistptr = inl(port+DnListPtr); 
	while(dpd = ctlr->dnqhead){ 
		if(PADDR(dpd) == dnlistptr) 
1997/0919    
	pd = ctlr->dntail; 
	while(ctlr->dnq){ 
		if(PADDR(&pd->np) == dnlistptr) 
1997/0712    
			break; 
		ctlr->dnqhead = dpd->next; 
		if(dpd->bp) 
			freeb(dpd->bp); 
		dpdfree(ctlr, dpd); 
1997/0919    
		if(pd->bp){ 
			freeb(pd->bp); 
			pd->bp = nil; 
		} 
		ctlr->dnq--; 
		pd = pd->next; 
1997/0712    
	} 
1997/0919    
	ctlr->dntail = pd; 
1997/0712    
 
	/* 
	 * Add any new packets to the queue. 
	 */ 
	if(add){ 
		if(ctlr->dnqhead){ 
			dpd = ctlr->dnqtail; 
			dpd->next = add; 
			dpd->np = PADDR(&add->np); 
			dpd->control &= ~dnIndicate; 
		} 
		else 
			ctlr->dnqhead = add; 
		ctlr->dnqtail = add; 
1997/0919    
	while(ctlr->dnq < (ctlr->ndn-1)){ 
		bp = qget(ether->oq); 
		if(bp == nil) 
			break; 
 
		pd = ctlr->dnhead->next; 
		pd->np = 0; 
		pd->control = dnIndicate|BLEN(bp); 
		pd->addr = PADDR(bp->rp); 
		pd->len = updnLastFrag|BLEN(bp); 
		pd->bp = bp; 
 
		if(ctlr->dnq == 0) 
			ctlr->dntail = pd; 
		ctlr->dnhead->np = PADDR(&pd->np); 
		ctlr->dnhead->control &= ~dnIndicate; 
		ctlr->dnhead = pd; 
		ctlr->dnq++; 
 
		ctlr->dnqueued++; 
1997/0712    
	} 
 
1997/0919    
	if(ctlr->dnq > ctlr->dnqmax) 
		ctlr->dnqmax = ctlr->dnq; 
 
1997/0712    
	/* 
	 * If the adapter is not currently processing anything 
	 * and there is something on the queue, start it processing. 
	 */ 
	if(dnlistptr == 0 && ctlr->dnqhead) 
		outl(port+DnListPtr, PADDR(ctlr->dnqhead)); 
1997/0919    
	if(dnlistptr == 0 && ctlr->dnq) 
		outl(port+DnListPtr, PADDR(&ctlr->dnhead->np)); 
1997/0712    
 
	COMMAND(port, Stall, dnUnStall); 
	iunlock(&ctlr->dnqlock); 
1997/0919    
	iunlock(&ctlr->dnlock); 
1997/0712    
} 
 
static void 
transmit905(Ether* ether) 
{ 
	Ctlr *ctlr; 
	Block *bp; 
	Dpd* dpd; 
                 
	bp = qget(ether->oq); 
	if(bp == nil) 
		return; 
                 
	ctlr = ether->ctlr; 
                 
	dpd = dpdalloc(ctlr); 
	dpd->next = 0; 
	dpd->bp = bp; 
                 
	dpd->np = 0; 
	dpd->control = dnIndicate|BLEN(bp); 
	dpd->addr = PADDR(bp->rp); 
	dpd->len = updnLastFrag|BLEN(bp); 
                 
	start905(ether, dpd); 
} 
                 
static void 
1997/0327    
transmit(Ether* ether) 
1996/0607    
{ 
	Ctlr *ctlr; 
1997/0806/sys/src/9/pc/etherelnk3.c:814,8201997/0919/sys/src/9/pc/etherelnk3.c:770,776
1996/0607    
	ctlr = ether->ctlr; 
 
1997/0712    
	if(ctlr->dnenabled){ 
		transmit905(ether); 
1997/0919    
		txstart905(ether); 
1997/0712    
		return; 
	} 
 
1997/0806/sys/src/9/pc/etherelnk3.c:830,8851997/0919/sys/src/9/pc/etherelnk3.c:786,829
1997/0712    
receive905(Ether* ether) 
{ 
	Ctlr *ctlr; 
	int port; 
	Block *bp, *xbp; 
	Upd *upd; 
1997/0919    
	int len, port, q; 
	Pd *pd; 
	Block *bp; 
1997/0712    
 
	ctlr = ether->ctlr; 
	port = ether->port; 
 
	//ilock(&ctlr->upqlock); 
	COMMAND(port, Stall, upStall); 
	while(STATUS(port) & commandInProgress) 
		; 
                 
	bp = ctlr->upqhead; 
	upd = (Upd*)bp->rp; 
	while(upd->control & upPktComplete){ 
		if(upd->control & upError){ 
			if(upd->control & upOverrun) 
1997/0919    
	if(inl(port+UpPktStatus) & upStalled) 
		ctlr->upstalls++; 
	q = 0; 
	for(pd = ctlr->uphead; pd->control & upPktComplete; pd = pd->next){ 
		if(pd->control & upError){ 
			if(pd->control & upOverrun) 
1997/0712    
				ether->overflows++; 
			if(upd->control & (upOversizedFrame|upRuntFrame)) 
1997/0919    
			if(pd->control & (upOversizedFrame|upRuntFrame)) 
1997/0712    
				ether->buffs++; 
			if(upd->control & upAlignmentError) 
1997/0919    
			if(pd->control & upAlignmentError) 
1997/0712    
				ether->frames++; 
			if(upd->control & upCRCError) 
1997/0919    
			if(pd->control & upCRCError) 
1997/0712    
				ether->crcs++; 
                 
			upd->control = 0; 
		} 
		else if(xbp = updalloc(upd->np)){ 
			bp->rp += sizeof(Upd)-sizeof(Etherpkt); 
			bp->wp = bp->rp + (upd->control & rxBytes); 
                 
			xbp->next = bp->next; 
			bp->next = 0; 
                 
			etheriq(ether, bp, 1); 
			bp = xbp; 
1997/0919    
		else if(bp = iallocb(sizeof(Etherpkt)+4)){ 
			len = pd->control & rxBytes; 
			pd->bp->wp = pd->bp->rp+len; 
			etheriq(ether, pd->bp, 1); 
			pd->bp = bp; 
			pd->addr = PADDR(bp->rp); 
1997/0712    
		} 
 
		upd = (Upd*)ctlr->upqtail->rp; 
		upd->np = PADDR(bp->rp); 
		ctlr->upqtail->next = bp; 
		ctlr->upqtail = bp; 
		ctlr->upqhead = bp->next; 
1997/0919    
		pd->control = 0; 
		COMMAND(port, Stall, upUnStall); 
1997/0712    
 
		bp = ctlr->upqhead; 
		upd = (Upd*)bp->rp; 
1997/0919    
		q++; 
1997/0712    
	} 
1997/0919    
	ctlr->uphead = pd; 
1997/0712    
 
	COMMAND(port, Stall, upUnStall); 
	//iunlock(&ctlr->upqlock); 
1997/0919    
	if(q > ctlr->upqmax) 
		ctlr->upqmax = q; 
1997/0712    
} 
 
static void 
1997/0806/sys/src/9/pc/etherelnk3.c:1044,10511997/0919/sys/src/9/pc/etherelnk3.c:988,995
1996/0607    
		} 
 
1997/0712    
		if(status & (upComplete)){ 
			COMMAND(port, AcknowledgeInterrupt, upComplete); 
			receive905(ether); 
1997/0919    
			COMMAND(port, AcknowledgeInterrupt, upComplete); 
1997/0712    
			status &= ~upComplete; 
		} 
 
1997/0806/sys/src/9/pc/etherelnk3.c:1103,11111997/0919/sys/src/9/pc/etherelnk3.c:1047,1056
1996/0607    
		} 
 
1997/0712    
		if(status & dnComplete){ 
1997/0919    
			txstart905(ether); 
1997/0712    
			COMMAND(port, AcknowledgeInterrupt, dnComplete); 
			start905(ether, 0); 
			status &= ~dnComplete; 
1997/0919    
			ctlr->dninterrupts++; 
1997/0712    
		} 
 
1996/0607    
		if(status & updateStats){ 
1997/0806/sys/src/9/pc/etherelnk3.c:1164,11691997/0919/sys/src/9/pc/etherelnk3.c:1109,1120
1997/0712    
	len += snprint(p+len, READSTR-len, "framesdeferred: %lud\n", ctlr->stats[FramesDeferred]); 
	len += snprint(p+len, READSTR-len, "bytesrcvdok: %lud\n", ctlr->stats[BytesRcvdOk]); 
	len += snprint(p+len, READSTR-len, "bytesxmittedok: %lud\n", ctlr->stats[BytesRcvdOk+1]); 
1997/0919    
len += snprint(p+len, READSTR-len, "up: q %lud s %lud\n", 
    ctlr->upqmax, ctlr->upstalls); 
ctlr->upqmax = 0; 
len += snprint(p+len, READSTR-len, "dn: q %lud i %lud m %d\n", 
    ctlr->dnqueued, ctlr->dninterrupts, ctlr->dnqmax); 
ctlr->dnqmax = 0; 
1997/0712    
	snprint(p+len, READSTR-len, "badssd: %lud\n", ctlr->stats[BytesRcvdOk+2]); 
1996/0607    
 
1997/0417    
	n = readstr(offset, a, n, p); 
1997/0806/sys/src/9/pc/etherelnk3.c:1761,17681997/0919/sys/src/9/pc/etherelnk3.c:1712,1722
1997/0715    
		if(!(x & 0x01)) 
			outl(port+PktStatus, upRxEarlyEnable); 
1997/0712    
 
		if(ctlr->upenabled) 
1997/0919    
		if(ctlr->upenabled || ctlr->dnenabled){ 
			ctlr->nup = Nup; 
			ctlr->ndn = Ndn; 
1997/0712    
			init905(ctlr); 
1997/0919    
		} 
1997/0712    
		else 
			ctlr->rbp = rbpalloc(allocb); 
		outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256)); 
1997/0919/sys/src/9/pc/etherelnk3.c:1335,13411997/1011/sys/src/9/pc/etherelnk3.c:1335,1341 (short | long)
1996/0607    
 
1997/0712    
	p = nil; 
1997/0327    
	while(p = pcimatch(p, 0x10B7, 0)){ 
		port = p->bar[0] & ~0x01; 
1997/1011    
		port = p->mem[0].bar & ~0x01; 
1997/0327    
		irq = p->intl; 
1997/0328    
		COMMAND(port, GlobalReset, 0); 
		while(STATUS(port) & commandInProgress) 
1997/1011/sys/src/9/pc/etherelnk3.c:401,4081997/1025/sys/src/9/pc/etherelnk3.c:401,407 (short | long)
1997/0919    
	Pd*	upr; 
	Pd*	uphead; 
1997/0712    
 
1997/0919    
	Lock	dnlock;				/* full-busmaster -based transmission */ 
	int	ndn; 
1997/1025    
	int	ndn;				/* full-busmaster -based transmission */ 
1997/0919    
	void*	dnbase; 
	Pd*	dnr; 
	Pd*	dnhead; 
1997/1011/sys/src/9/pc/etherelnk3.c:456,4621997/1025/sys/src/9/pc/etherelnk3.c:455,460
1997/0712    
	} 
1997/0919    
	ctlr->uphead = ctlr->upr; 
1997/0712    
 
1997/0919    
	ilock(&ctlr->dnlock); 
	ctlr->dnbase = malloc((ctlr->ndn+1)*sizeof(Pd)); 
	ctlr->dnr = (Pd*)ROUNDUP((ulong)ctlr->dnbase, 8); 
1997/0712    
 
1997/1011/sys/src/9/pc/etherelnk3.c:468,4741997/1025/sys/src/9/pc/etherelnk3.c:466,471
1997/0919    
	ctlr->dnhead = ctlr->dnr; 
	ctlr->dntail = ctlr->dnr; 
	ctlr->dnq = 0; 
	iunlock(&ctlr->dnlock); 
1997/0712    
} 
 
static Block* 
1997/1011/sys/src/9/pc/etherelnk3.c:702,7081997/1025/sys/src/9/pc/etherelnk3.c:699,704
1997/0712    
	ctlr = ether->ctlr; 
	port = ether->port; 
 
1997/0919    
	ilock(&ctlr->dnlock); 
1997/0712    
	COMMAND(port, Stall, dnStall); 
	while(STATUS(port) & commandInProgress) 
		; 
1997/1011/sys/src/9/pc/etherelnk3.c:757,7631997/1025/sys/src/9/pc/etherelnk3.c:753,758
1997/0919    
		outl(port+DnListPtr, PADDR(&ctlr->dnhead->np)); 
1997/0712    
 
	COMMAND(port, Stall, dnUnStall); 
1997/0919    
	iunlock(&ctlr->dnlock); 
1997/0712    
} 
 
static void 
1997/1011/sys/src/9/pc/etherelnk3.c:769,7841997/1025/sys/src/9/pc/etherelnk3.c:764,778
1996/0607    
	port = ether->port; 
	ctlr = ether->ctlr; 
 
1997/0712    
	if(ctlr->dnenabled){ 
1997/1025    
	ilock(&ctlr->wlock); 
	if(ctlr->dnenabled) 
1997/0919    
		txstart905(ether); 
1997/0712    
		return; 
1997/1025    
	else{ 
		w = (STATUS(port)>>13) & 0x07; 
		COMMAND(port, SelectRegisterWindow, Wop); 
		txstart(ether); 
		COMMAND(port, SelectRegisterWindow, w); 
1997/0712    
	} 
                 
1996/0607    
	ilock(&ctlr->wlock); 
	w = (STATUS(port)>>13) & 0x07; 
	COMMAND(port, SelectRegisterWindow, Wop); 
1997/0327    
	txstart(ether); 
1996/0607    
	COMMAND(port, SelectRegisterWindow, w); 
	iunlock(&ctlr->wlock); 
} 
 
1997/1011/sys/src/9/pc/etherelnk3.c:1298,13041997/1025/sys/src/9/pc/etherelnk3.c:1292,1298
1997/0712    
	 * Check if this is an EISA machine. 
1996/0607    
	 * If not, nothing to do. 
	 */ 
1997/0712    
	if(strncmp((char*)(KZERO|0xFFFD9), "EISA", 4)) 
1997/1025    
	if(strncmp((char*)KADDR(0xFFFD9), "EISA", 4)) 
1997/0712    
		return; 
1996/0607    
 
	/* 
1997/1025/sys/src/9/pc/etherelnk3.c:413,4181997/1203/sys/src/9/pc/etherelnk3.c:413,420 (short | long)
1997/0712    
	long	stats[BytesRcvdOk+3]; 
1996/0607    
 
1997/0919    
	int	upqmax; 
1997/1203    
	long	upinterrupts; 
	long	upqueued; 
1997/0919    
	int	upstalls; 
	int	dnqmax; 
	long	dninterrupts; 
1997/1025/sys/src/9/pc/etherelnk3.c:816,8211997/1203/sys/src/9/pc/etherelnk3.c:818,824
1997/0712    
	} 
1997/0919    
	ctlr->uphead = pd; 
1997/0712    
 
1997/1203    
	ctlr->upqueued += q; 
1997/0919    
	if(q > ctlr->upqmax) 
		ctlr->upqmax = q; 
1997/0712    
} 
1997/1025/sys/src/9/pc/etherelnk3.c:982,9901997/1203/sys/src/9/pc/etherelnk3.c:985,994
1996/0607    
		} 
 
1997/0712    
		if(status & (upComplete)){ 
			receive905(ether); 
1997/0919    
			COMMAND(port, AcknowledgeInterrupt, upComplete); 
1997/1203    
			receive905(ether); 
1997/0712    
			status &= ~upComplete; 
1997/1203    
			ctlr->upinterrupts++; 
1997/0712    
		} 
 
1996/0607    
		if(status & txComplete){ 
1997/1025/sys/src/9/pc/etherelnk3.c:1041,10481997/1203/sys/src/9/pc/etherelnk3.c:1045,1052
1996/0607    
		} 
 
1997/0712    
		if(status & dnComplete){ 
1997/0919    
			txstart905(ether); 
1997/0712    
			COMMAND(port, AcknowledgeInterrupt, dnComplete); 
1997/1203    
			txstart905(ether); 
1997/0712    
			status &= ~dnComplete; 
1997/0919    
			ctlr->dninterrupts++; 
1997/0712    
		} 
1997/1025/sys/src/9/pc/etherelnk3.c:1103,11141997/1203/sys/src/9/pc/etherelnk3.c:1107,1124
1997/0712    
	len += snprint(p+len, READSTR-len, "framesdeferred: %lud\n", ctlr->stats[FramesDeferred]); 
	len += snprint(p+len, READSTR-len, "bytesrcvdok: %lud\n", ctlr->stats[BytesRcvdOk]); 
	len += snprint(p+len, READSTR-len, "bytesxmittedok: %lud\n", ctlr->stats[BytesRcvdOk+1]); 
1997/0919    
len += snprint(p+len, READSTR-len, "up: q %lud s %lud\n", 
    ctlr->upqmax, ctlr->upstalls); 
ctlr->upqmax = 0; 
len += snprint(p+len, READSTR-len, "dn: q %lud i %lud m %d\n", 
    ctlr->dnqueued, ctlr->dninterrupts, ctlr->dnqmax); 
ctlr->dnqmax = 0; 
1997/1203    
 
	if(ctlr->upenabled){ 
		len += snprint(p+len, READSTR-len, "up: q %lud i %lud m %d s %lud\n", 
			ctlr->upqueued, ctlr->upinterrupts, ctlr->dnqmax, ctlr->upstalls); 
		ctlr->upqmax = 0; 
	} 
	if(ctlr->dnenabled){ 
		len += snprint(p+len, READSTR-len, "dn: q %lud i %lud m %d\n", 
			ctlr->dnqueued, ctlr->dninterrupts, ctlr->dnqmax); 
		ctlr->dnqmax = 0; 
	} 
 
1997/0712    
	snprint(p+len, READSTR-len, "badssd: %lud\n", ctlr->stats[BytesRcvdOk+2]); 
1996/0607    
 
1997/0417    
	n = readstr(offset, a, n, p); 
1997/1025/sys/src/9/pc/etherelnk3.c:1729,17341997/1203/sys/src/9/pc/etherelnk3.c:1739,1746
1997/0327    
	ctlr->txthreshold = ETHERMAXTU/2; 
1996/0928    
	COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts); 
1996/0925    
	COMMAND(port, SetRxEarlyThresh, rxearly>>ctlr->ts); 
1997/1203    
 
COMMAND(port, AcknowledgeInterrupt, interruptLatch); 
1996/0607    
 
	iunlock(&ctlr->wlock); 
 
1997/1203/sys/src/9/pc/etherelnk3.c:366,3721997/1207/sys/src/9/pc/etherelnk3.c:366,372 (short | long)
1997/0712    
	updnLastFrag		= 0x80000000,	/* (dpd->len) */ 
1997/0919    
 
	Nup			= 32, 
	Ndn			= 16, 
1997/1207    
	Ndn			= 32, 
1997/0328    
}; 
 
/* 
1997/1203/sys/src/9/pc/etherelnk3.c:1110,11161997/1207/sys/src/9/pc/etherelnk3.c:1110,1116
1997/1203    
 
	if(ctlr->upenabled){ 
		len += snprint(p+len, READSTR-len, "up: q %lud i %lud m %d s %lud\n", 
			ctlr->upqueued, ctlr->upinterrupts, ctlr->dnqmax, ctlr->upstalls); 
1997/1207    
			ctlr->upqueued, ctlr->upinterrupts, ctlr->upqmax, ctlr->upstalls); 
1997/1203    
		ctlr->upqmax = 0; 
	} 
	if(ctlr->dnenabled){ 
1997/1207/sys/src/9/pc/etherelnk3.c:366,3721997/1212/sys/src/9/pc/etherelnk3.c:366,372 (short | long)
1997/0712    
	updnLastFrag		= 0x80000000,	/* (dpd->len) */ 
1997/0919    
 
	Nup			= 32, 
1997/1207    
	Ndn			= 32, 
1997/1212    
	Ndn			= 64, 
1997/0328    
}; 
 
/* 
1997/1207/sys/src/9/pc/etherelnk3.c:694,7001997/1212/sys/src/9/pc/etherelnk3.c:694,700
1997/0919    
txstart905(Ether* ether) 
1997/0712    
{ 
	Ctlr *ctlr; 
	int dnlistptr, port; 
1997/1212    
	int port, stalled, timeo; 
1997/0919    
	Block *bp; 
	Pd *pd; 
1997/0712    
 
1997/1207/sys/src/9/pc/etherelnk3.c:701,7171997/1212/sys/src/9/pc/etherelnk3.c:701,712
1997/0712    
	ctlr = ether->ctlr; 
	port = ether->port; 
 
	COMMAND(port, Stall, dnStall); 
	while(STATUS(port) & commandInProgress) 
		; 
                 
	/* 
	 * Free any completed packets. 
	 */ 
	dnlistptr = inl(port+DnListPtr); 
1997/0919    
	pd = ctlr->dntail; 
	while(ctlr->dnq){ 
		if(PADDR(&pd->np) == dnlistptr) 
1997/1212    
		if(PADDR(&pd->np) == inl(port+DnListPtr)) 
1997/0712    
			break; 
1997/0919    
		if(pd->bp){ 
			freeb(pd->bp); 
1997/1207/sys/src/9/pc/etherelnk3.c:722,7271997/1212/sys/src/9/pc/etherelnk3.c:717,723
1997/0712    
	} 
1997/0919    
	ctlr->dntail = pd; 
1997/0712    
 
1997/1212    
	stalled = 0; 
1997/0919    
	while(ctlr->dnq < (ctlr->ndn-1)){ 
		bp = qget(ether->oq); 
		if(bp == nil) 
1997/1207/sys/src/9/pc/etherelnk3.c:734,7441997/1212/sys/src/9/pc/etherelnk3.c:730,749
1997/0919    
		pd->len = updnLastFrag|BLEN(bp); 
		pd->bp = bp; 
 
		if(ctlr->dnq == 0) 
			ctlr->dntail = pd; 
1997/1212    
		if(stalled == 0 && ctlr->dnq && inl(port+DnListPtr)){ 
			COMMAND(port, Stall, dnStall); 
			for(timeo = 100; (STATUS(port) & commandInProgress) && timeo; timeo--) 
				; 
			if(timeo == 0) 
				print("#l%d: dnstall %d\n", ether->ctlrno, timeo); 
			stalled = 1; 
		} 
 
1997/0919    
		ctlr->dnhead->np = PADDR(&pd->np); 
		ctlr->dnhead->control &= ~dnIndicate; 
		ctlr->dnhead = pd; 
1997/1212    
		if(ctlr->dnq == 0) 
			ctlr->dntail = pd; 
1997/0919    
		ctlr->dnq++; 
 
		ctlr->dnqueued++; 
1997/1207/sys/src/9/pc/etherelnk3.c:751,7601997/1212/sys/src/9/pc/etherelnk3.c:756,765
1997/0712    
	 * If the adapter is not currently processing anything 
	 * and there is something on the queue, start it processing. 
	 */ 
1997/0919    
	if(dnlistptr == 0 && ctlr->dnq) 
1997/1212    
	if(inl(port+DnListPtr) == 0 && ctlr->dnq) 
1997/0919    
		outl(port+DnListPtr, PADDR(&ctlr->dnhead->np)); 
1997/0712    
                 
	COMMAND(port, Stall, dnUnStall); 
1997/1212    
	if(stalled) 
		COMMAND(port, Stall, dnUnStall); 
1997/0712    
} 
 
static void 
1997/1207/sys/src/9/pc/etherelnk3.c:1030,10361997/1212/sys/src/9/pc/etherelnk3.c:1035,1046
1996/0925    
				COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts); 
1997/0712    
				if(ctlr->busmaster == 2) 
					outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256)); 
1997/1212    
				if(ctlr->dnenabled) 
					status |= dnComplete; 
1996/0607    
			} 
1997/1212    
 
			print("#l%d: txstatus 0x%uX, threshold %d\n", 
			    	ether->ctlrno, s, ctlr->txthreshold); 
1996/0607    
			COMMAND(port, TxEnable, 0); 
			ether->oerrs++; 
			status &= ~txComplete; 
1997/1207/sys/src/9/pc/etherelnk3.c:1739,17461997/1212/sys/src/9/pc/etherelnk3.c:1749,1754
1997/0327    
	ctlr->txthreshold = ETHERMAXTU/2; 
1996/0928    
	COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts); 
1996/0925    
	COMMAND(port, SetRxEarlyThresh, rxearly>>ctlr->ts); 
1997/1203    
                 
COMMAND(port, AcknowledgeInterrupt, interruptLatch); 
1996/0607    
 
	iunlock(&ctlr->wlock); 
 
1997/1212/sys/src/9/pc/etherelnk3.c:1411,14171998/0319/sys/src/9/pc/etherelnk3.c:1411,1417 (short | long)
Anonymize autoselect.
rsc Fri Mar 4 12:44:25 2005
1997/0712    
#endif /* notdef */ 
 
1996/0929    
static int 
1997/0712    
autoselect(int port, int xcvr, int is9) 
1998/0319    
autoselect(int port, int , int is9) 
1996/0929    
{ 
	int media, x; 
 
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)