⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 etherelnk3x.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Etherlink III and Fast EtherLink adapters. * To do: *	autoSelect; *	busmaster channel; *	PCMCIA; *	PCI latency timer and master enable; *	errata list. * * Product ID: *	9150 ISA	3C509[B] *	9050 ISA	3C509[B]-TP *	9450 ISA	3C509[B]-COMBO *	9550 ISA	3C509[B]-TPO * *	9350 EISA	3C579 *	9250 EISA	3C579-TP * *	5920 EISA	3C592-[TP|COMBO|TPO] *	5970 EISA	3C597-TX	Fast Etherlink 10BASE-T/100BASE-TX *	5971 EISA	3C597-T4	Fast Etherlink 10BASE-T/100BASE-T4 *	5972 EISA	3C597-MII	Fast Etherlink 10BASE-T/MII * *	5900 PCI	3C590-[TP|COMBO|TPO] *	5950 PCI	3C595-TX	Fast Etherlink Shared 10BASE-T/100BASE-TX *	5951 PCI	3C595-T4	Fast Etherlink Shared 10BASE-T/100BASE-T4 *	5952 PCI	3C595-MII	Fast Etherlink 10BASE-T/MII * *	9058 PCMCIA	3C589[B]-[TP|COMBO] * *	627C MCA	3C529 *	627D MCA	3C529-TP */#include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "etherif.h"enum {	IDport			= 0x0110,	/* anywhere between 0x0100 and 0x01F0 */};enum {						/* all windows */	Command			= 0x000E,	IntStatus		= 0x000E,};enum {						/* Commands */	GlobalReset		= 0x0000,	SelectRegisterWindow	= 0x0001,		EnableDcConverter	= 0x0002,	RxDisable		= 0x0003,	RxEnable		= 0x0004,	RxReset			= 0x0005,	TxDone			= 0x0007,		RxDiscard		= 0x0008,	TxEnable		= 0x0009,	TxDisable		= 0x000A,	TxReset			= 0x000B,	RequestInterrupt	= 0x000C,	AcknowledgeInterrupt	= 0x000D,	SetInterruptEnable	= 0x000E,	SetIndicationEnable	= 0x000F,	/* SetReadZeroMask */	SetRxFilter		= 0x0010,	SetRxEarlyThresh	= 0x0011,	SetTxAvailableThresh	= 0x0012,	SetTxStartThresh	= 0x0013,	StartDma		= 0x0014,	/* initiate busmaster operation */	StatisticsEnable	= 0x0015,	StatisticsDisable	= 0x0016,	DisableDcConverter	= 0x0017,	SetTxReclaimThresh	= 0x0018,	/* PIO-only adapters */	PowerUp			= 0x001B,	/* not all adapters */	PowerDownFull		= 0x001C,	/* not all adapters */	PowerAuto		= 0x001D,	/* not all adapters */};enum {						/* (Global|Rx|Tx)Reset command bits */	tpAuiReset		= 0x0001,	/* 10BaseT and AUI transceivers */	endecReset		= 0x0002,	/* internal Ethernet encoder/decoder */	networkReset		= 0x0004,	/* network interface logic */	fifoReset		= 0x0008,	/* FIFO control logic */	aismReset		= 0x0010,	/* autoinitialise state-machine logic */	hostReset		= 0x0020,	/* bus interface logic */	dmaReset		= 0x0040,	/* bus master logic */	vcoReset		= 0x0080,	/* on-board 10Mbps VCO */	resetMask		= 0x00FF,};enum {						/* SetRxFilter command bits */	receiveIndividual	= 0x0001,	/* match station address */	receiveMulticast	= 0x0002,	receiveBroadcast	= 0x0004,	receiveAllFrames	= 0x0008,	/* promiscuous */};enum {						/* StartDma command bits */	Upload			= 0x0000,	/* transfer data from adapter to memory */	Download		= 0x0001,	/* transfer data from memory to adapter */};enum {						/* IntStatus bits */	interruptLatch		= 0x0001,	hostError		= 0x0002,	/* Adapter Failure */	txComplete		= 0x0004,	txAvailable		= 0x0008,	rxComplete		= 0x0010,	rxEarly			= 0x0020,	intRequested		= 0x0040,	updateStats		= 0x0080,	transferInt		= 0x0100,	/* Bus Master Transfer Complete */	busMasterInProgress	= 0x0800,	commandInProgress	= 0x1000,	interruptMask		= 0x01FE,};#define COMMAND(port, cmd, a)	outs((port)+Command, ((cmd)<<11)|(a))#define STATUS(port)		ins((port)+IntStatus)enum {						/* Window 0 - setup */	Wsetup			= 0x0000,						/* registers */	ManufacturerID		= 0x0000,	/* 3C5[08]*, 3C59[27] */	ProductID		= 0x0002,	/* 3C5[08]*, 3C59[27] */	ConfigControl		= 0x0004,	/* 3C5[08]*, 3C59[27] */	AddressConfig		= 0x0006,	/* 3C5[08]*, 3C59[27] */	ResourceConfig		= 0x0008,	/* 3C5[08]*, 3C59[27] */	EepromCommand		= 0x000A,	EepromData		= 0x000C,						/* AddressConfig Bits */	autoSelect9		= 0x0080,	xcvrMask9		= 0xC000,						/* ConfigControl bits */	Ena			= 0x0001,						/* EepromCommand bits */	EepromReadRegister	= 0x0080,	EepromBusy		= 0x8000,};#define EEPROMCMD(port, cmd, a)	outs((port)+EepromCommand, (cmd)|(a))#define EEPROMBUSY(port)	(ins((port)+EepromCommand) & EepromBusy)#define EEPROMDATA(port)	ins((port)+EepromData)enum {						/* Window 1 - operating set */	Wop			= 0x0001,						/* registers */	Fifo			= 0x0000,	RxError			= 0x0004,	/* 3C59[0257] only */	RxStatus		= 0x0008,	Timer			= 0x000A,	TxStatus		= 0x000B,	TxFree			= 0x000C,						/* RxError bits */	rxOverrun		= 0x0001,	runtFrame		= 0x0002,	alignmentError		= 0x0004,	/* Framing */	crcError		= 0x0008,	oversizedFrame		= 0x0010,	dribbleBits		= 0x0080,						/* RxStatus bits */	rxBytes			= 0x1FFF,	/* 3C59[0257] mask */	rxBytes9		= 0x07FF,	/* 3C5[078]9 mask */	rxError9		= 0x3800,	/* 3C5[078]9 error mask */	rxOverrun9		= 0x0000,	oversizedFrame9		= 0x0800,	dribbleBits9		= 0x1000,	runtFrame9		= 0x1800,	alignmentError9		= 0x2000,	/* Framing */	crcError9		= 0x2800,	rxError			= 0x4000,	rxIncomplete		= 0x8000,						/* TxStatus Bits */	txStatusOverflow	= 0x0004,	maxCollisions		= 0x0008,	txUnderrun		= 0x0010,	txJabber		= 0x0020,	interruptRequested	= 0x0040,	txStatusComplete	= 0x0080,};enum {						/* Window 2 - station address */	Wstation		= 0x0002,};enum {						/* Window 3 - FIFO management */	Wfifo			= 0x0003,						/* registers */	InternalConfig		= 0x0000,	/* 3C509B, 3C589, 3C59[0257] */	OtherInt		= 0x0004,	/* 3C59[0257] */	RomControl		= 0x0006,	/* 3C509B, 3C59[27] */	MacControl		= 0x0006,	/* 3C59[0257] */	ResetOptions		= 0x0008,	/* 3C59[0257] */	RxFree			= 0x000A,						/* InternalConfig bits */	disableBadSsdDetect	= 0x00000100,	ramLocation		= 0x00000200,	/* 0 external, 1 internal */	ramPartition5to3	= 0x00000000,	ramPartition3to1	= 0x00010000,	ramPartition1to1	= 0x00020000,	ramPartition3to5	= 0x00030000,	ramPartitionMask	= 0x00030000,	xcvr10BaseT		= 0x00000000,	xcvrAui			= 0x00100000,	/* 10BASE5 */	xcvr10Base2		= 0x00300000,	xcvr100BaseTX		= 0x00400000,	xcvr100BaseFX		= 0x00500000,	xcvrMii			= 0x00600000,	xcvrMask		= 0x00700000,	autoSelect		= 0x01000000,						/* MacControl bits */	deferExtendEnable	= 0x0001,	deferTimerSelect	= 0x001E,	/* mask */	fullDuplexEnable	= 0x0020,	allowLargePackets	= 0x0040,						/* ResetOptions bits */	baseT4Available		= 0x0001,	baseTXAvailable		= 0x0002,	baseFXAvailable		= 0x0004,	base10TAvailable	= 0x0008,	coaxAvailable		= 0x0010,	auiAvailable		= 0x0020,	miiConnector		= 0x0040,};enum {						/* Window 4 - diagnostic */	Wdiagnostic		= 0x0004,						/* registers */	VcoDiagnostic		= 0x0002,	FifoDiagnostic		= 0x0004,	NetworkDiagnostic	= 0x0006,	PhysicalMgmt		= 0x0008,	MediaStatus		= 0x000A,	BadSSD			= 0x000C,						/* FifoDiagnostic bits */	txOverrun		= 0x0400,	rxUnderrun		= 0x2000,	receiving		= 0x8000,						/* MediaStatus bits */	dataRate100		= 0x0002,	crcStripDisable		= 0x0004,	enableSqeStats		= 0x0008,	collisionDetect		= 0x0010,	carrierSense		= 0x0020,	jabberGuardEnable	= 0x0040,	linkBeatEnable		= 0x0080,	jabberDetect		= 0x0200,	polarityReversed	= 0x0400,	linkBeatDetect		= 0x0800,	txInProg		= 0x1000,	dcConverterEnabled	= 0x4000,	auiDisable		= 0x8000,};enum {						/* Window 5 - internal state */	Wstate			= 0x0005,						/* registers */	TxStartThresh		= 0x0000,	TxAvalableThresh	= 0x0002,	RxEarlyThresh		= 0x0006,	RxFilter		= 0x0008,	InterruptEnable		= 0x000A,	IndicationEnable	= 0x000C,};enum {						/* Window 6 - statistics */	Wstatistics		= 0x0006,						/* registers */	CarrierLost		= 0x0000,	SqeErrors		= 0x0001,	MultipleColls		= 0x0002,	SingleCollFrames	= 0x0003,	LateCollisions		= 0x0004,	RxOverruns		= 0x0005,	FramesXmittedOk		= 0x0006,	FramesRcvdOk		= 0x0007,	FramesDeferred		= 0x0008,	UpperFramesOk		= 0x0009,	BytesRcvdOk		= 0x000A,	BytesXmittedOk		= 0x000C,};enum {						/* Window 7 - bus master operations */	Wmaster			= 0x0007,						/* registers */	MasterAddress		= 0x0000,	MasterLen		= 0x0006,	MasterStatus		= 0x000C,						/* MasterStatus bits */	masterAbort		= 0x0001,	targetAbort		= 0x0002,	targetRetry		= 0x0004,	targetDisc		= 0x0008,	masterDownload		= 0x1000,	masterUpload		= 0x4000,	masterInProgress	= 0x8000,	masterMask		= 0xD00F,};	typedef struct {	int	txthreshold;} Ctlr;static voidattach(Ether* ether){	int port, x;	port = ether->port;	/*	 * Set the receiver packet filter for this and broadcast addresses,	 * set the interrupt masks for all interrupts, enable the receiver	 * and transmitter.	 */	x = receiveBroadcast|receiveIndividual;	COMMAND(port, SetRxFilter, x);	x = interruptMask|interruptLatch;	COMMAND(port, SetIndicationEnable, x);	COMMAND(port, SetInterruptEnable, x);	COMMAND(port, RxEnable, 0);	COMMAND(port, TxEnable, 0);}static voidtransmit(Ether* ether){	int port, len;	RingBuf *tb;	/*	 * Attempt to top-up the transmit FIFO. If there's room simply	 * stuff in the packet length (unpadded to a dword boundary), the	 * packet data (padded) and remove the packet from the queue.	 * If there's no room post an interrupt for when there is.	 * This routine is called both from the top level and from interrupt	 * level.	 */	port = ether->port;	for(tb = &ether->tb[ether->ti]; tb->owner == Interface; tb = &ether->tb[ether->ti]){		len = ROUNDUP(tb->len, 4);		if(len+4 <= ins(port+TxFree)){			outl(port+Fifo, tb->len);			outsl(port+Fifo, tb->pkt, len/4);			tb->owner = Host;			ether->ti = NEXT(ether->ti, ether->ntb);		}		else{			COMMAND(port, SetTxAvailableThresh, len);			break;		}	}}static voidreceive(Ether* ether){	int len, port, rxstatus;	RingBuf *rb;	port = ether->port;	while(((rxstatus = ins(port+RxStatus)) & rxIncomplete) == 0){		/*		 * If there was an error, throw it away and continue.		 * The 3C5[078]9 has the error info in the status register		 * and the 3C59[0257] implement a separate RxError register.		 */		if((rxstatus & rxError) == 0){			/*			 * Packet received. Read it into the next free			 * ring buffer, if any. Must read len bytes padded			 * to a doubleword, can be picked out 32-bits at			 * a time. The CRC is already stripped off.			 */			rb = &ether->rb[ether->ri];			if(rb->owner == Interface){				len = (rxstatus & rxBytes9);				rb->len = len;				insl(port+Fifo, rb->pkt, HOWMANY(len, 4));				rb->owner = Host;				ether->ri = NEXT(ether->ri, ether->nrb);			}		}		/*		 * All done, discard the packet.		 */		COMMAND(port, RxDiscard, 0);		while(STATUS(port) & commandInProgress)			;	}}static voidstatistics(Ether* ether){	int i, port, w;	port = ether->port;	w = (STATUS(port)>>13) & 0x07;	COMMAND(port, SelectRegisterWindow, Wop);	COMMAND(port, SelectRegisterWindow, Wstatistics);	for(i = 0; i < 0x0A; i++)		inb(port+i);	ins(port+BytesRcvdOk);	ins(port+BytesXmittedOk);	COMMAND(port, SelectRegisterWindow, w);}static voidinterrupt(Ureg*, void* arg){	Ether *ether;	int port, status, txstatus, w, x;	Ctlr *ctlr;	ether = arg;	port = ether->port;	ctlr = ether->ctlr;	w = (STATUS(port)>>13) & 0x07;	COMMAND(port, SelectRegisterWindow, Wop);	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;		if(status & hostError){			/*			 * Adapter failure, try to find out why, reset if			 * necessary. What happens if Tx is active and a reset			 * occurs, need to retransmit? This probably isn't right.			 */			COMMAND(port, SelectRegisterWindow, Wdiagnostic);			x = ins(port+FifoDiagnostic);			COMMAND(port, SelectRegisterWindow, Wop);			print("elnk3#%d: status 0x%uX, diag 0x%uX\n",			    ether->ctlrno, status, x);			if(x & txOverrun){				COMMAND(port, TxReset, 0);				COMMAND(port, TxEnable, 0);			}			if(x & rxUnderrun){				/*				 * This shouldn't happen...				 * Need to restart any busmastering?				 */				COMMAND(port, RxReset, 0);				while(STATUS(port) & commandInProgress)					;				COMMAND(port, RxEnable, 0);			}			status &= ~hostError;		}		if(status & (transferInt|rxComplete)){			receive(ether);			status &= ~(transferInt|rxComplete);		}		if(status & txComplete){			/*			 * 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.			 * For all conditions enable the transmitter.			 */			txstatus = 0;			do{				if(x = inb(port+TxStatus))					outb(port+TxStatus, 0);				txstatus |= x;			}while(STATUS(port) & txComplete);			if(txstatus & txUnderrun){				COMMAND(port, SelectRegisterWindow, Wdiagnostic);				while(ins(port+MediaStatus) & txInProg)					;				COMMAND(port, SelectRegisterWindow, Wop);				if(ctlr->txthreshold < ETHERMAXTU)					ctlr->txthreshold += ETHERMINTU;			}			if(txstatus & (txJabber|txUnderrun)){				COMMAND(port, TxReset, 0);				while(STATUS(port) & commandInProgress)					;				COMMAND(port, SetTxStartThresh, ctlr->txthreshold);			}			COMMAND(port, TxEnable, 0);			status &= ~txComplete;			status |= txAvailable;		}		if(status & txAvailable){			COMMAND(port, AcknowledgeInterrupt, txAvailable);			transmit(ether);			status &= ~txAvailable;		}		if(status & updateStats){			statistics(ether);			status &= ~updateStats;		}		/*		 * Panic if there are any interrupts not dealt with.		 */		if(status & interruptMask)			panic("elnk3#%d: interrupt mask 0x%uX\n", ether->ctlrno, status);	}	COMMAND(port, SelectRegisterWindow, w);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -