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

📄 ether82557.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Intel 82557 Fast Ethernet PCI Bus LAN Controller * as found on the Intel EtherExpress PRO/100B. This chip is full * of smarts, unfortunately they're not all in the right place. * To do: *	the PCI scanning code could be made common to other adapters; *	auto-negotiation, full-duplex; *	optionally use memory-mapped registers; *	detach for PCI reset problems (also towards loadable drivers). */#ifdef FS#include "all.h"#include "io.h"#include "mem.h"#include "../ip/ip.h"#else#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h"#include "../port/netif.h"#endif			/* FS */#include "etherif.h"#include "ethermii.h"#include "compat.h"enum {	Nrfd		= 64,		/* receive frame area */	Ncb		= 64,		/* maximum control blocks queued */	NullPointer	= 0xFFFFFFFF,	/* 82557 NULL pointer */};enum {					/* CSR */	Status		= 0x00,		/* byte or word (word includes Ack) */	Ack		= 0x01,		/* byte */	CommandR	= 0x02,		/* byte or word (word includes Interrupt) */	Interrupt	= 0x03,		/* byte */	General		= 0x04,		/* dword */	Port		= 0x08,		/* dword */	Fcr		= 0x0C,		/* Flash control register */	Ecr		= 0x0E,		/* EEPROM control register */	Mcr		= 0x10,		/* MDI control register */	Gstatus		= 0x1D,		/* General status register */};enum {					/* Status */	RUidle		= 0x0000,	RUsuspended	= 0x0004,	RUnoresources	= 0x0008,	RUready		= 0x0010,	RUrbd		= 0x0020,	/* bit */	RUstatus	= 0x003F,	/* mask */	CUidle		= 0x0000,	CUsuspended	= 0x0040,	CUactive	= 0x0080,	CUstatus	= 0x00C0,	/* mask */	StatSWI		= 0x0400,	/* SoftWare generated Interrupt */	StatMDI		= 0x0800,	/* MDI r/w done */	StatRNR		= 0x1000,	/* Receive unit Not Ready */	StatCNA		= 0x2000,	/* Command unit Not Active (Active->Idle) */	StatFR		= 0x4000,	/* Finished Receiving */	StatCX		= 0x8000,	/* Command eXecuted */	StatTNO		= 0x8000,	/* Transmit NOT OK */};enum {					/* Command (byte) */	CUnop		= 0x00,	CUstart		= 0x10,	CUresume	= 0x20,	LoadDCA		= 0x40,		/* Load Dump Counters Address */	DumpSC		= 0x50,		/* Dump Statistical Counters */	LoadCUB		= 0x60,		/* Load CU Base */	ResetSA		= 0x70,		/* Dump and Reset Statistical Counters */	RUstart		= 0x01,	RUresume	= 0x02,	RUabort		= 0x04,	LoadHDS		= 0x05,		/* Load Header Data Size */	LoadRUB		= 0x06,		/* Load RU Base */	RBDresume	= 0x07,		/* Resume frame reception */};enum {					/* Interrupt (byte) */	InterruptM	= 0x01,		/* interrupt Mask */	InterruptSI	= 0x02,		/* Software generated Interrupt */};enum {					/* Ecr */	EEsk		= 0x01,		/* serial clock */	EEcs		= 0x02,		/* chip select */	EEdi		= 0x04,		/* serial data in */	EEdo		= 0x08,		/* serial data out */	EEstart		= 0x04,		/* start bit */	EEread		= 0x02,		/* read opcode */};enum {					/* Mcr */	MDIread		= 0x08000000,	/* read opcode */	MDIwrite	= 0x04000000,	/* write opcode */	MDIready	= 0x10000000,	/* ready bit */	MDIie		= 0x20000000,	/* interrupt enable */};typedef struct Rfd {	int	field;	ulong	link;	ulong	rbd;	ushort	count;	ushort	size;	uchar	data[1700];} Rfd;enum {					/* field */	RfdCollision	= 0x00000001,	RfdIA		= 0x00000002,	/* IA match */	RfdRxerr	= 0x00000010,	/* PHY character error */	RfdType		= 0x00000020,	/* Type frame */	RfdRunt		= 0x00000080,	RfdOverrun	= 0x00000100,	RfdBuffer	= 0x00000200,	RfdAlignment	= 0x00000400,	RfdCRC		= 0x00000800,	RfdOK		= 0x00002000,	/* frame received OK */	RfdC		= 0x00008000,	/* reception Complete */	RfdSF		= 0x00080000,	/* Simplified or Flexible (1) Rfd */	RfdH		= 0x00100000,	/* Header RFD */	RfdI		= 0x20000000,	/* Interrupt after completion */	RfdS		= 0x40000000,	/* Suspend after completion */	RfdEL		= 0x80000000,	/* End of List */};enum {					/* count */	RfdF		= 0x4000,	RfdEOF		= 0x8000,};typedef struct Cb Cb;typedef struct Cb {	ushort	status;	ushort	command;	ulong	link;	union {		uchar	data[24];	/* CbIAS + CbConfigure */		struct {			ulong	tbd;			ushort	count;			uchar	threshold;			uchar	number;			ulong	tba;			ushort	tbasz;			ushort	pad;		};	};	Block*	bp;	Cb*	next;} Cb;enum {					/* action command */	CbU		= 0x1000,	/* transmit underrun */	CbOK		= 0x2000,	/* DMA completed OK */	CbC		= 0x8000,	/* execution Complete */	CbNOP		= 0x0000,	CbIAS		= 0x0001,	/* Individual Address Setup */	CbConfigure	= 0x0002,	CbMAS		= 0x0003,	/* Multicast Address Setup */	CbTransmit	= 0x0004,	CbDump		= 0x0006,	CbDiagnose	= 0x0007,	CbCommand	= 0x0007,	/* mask */	CbSF		= 0x0008,	/* Flexible-mode CbTransmit */	CbI		= 0x2000,	/* Interrupt after completion */	CbS		= 0x4000,	/* Suspend after completion */	CbEL		= 0x8000,	/* End of List */};enum {					/* CbTransmit count */	CbEOF		= 0x8000,};typedef struct Ctlr Ctlr;typedef struct Ctlr {	Lock	slock;			/* attach */	int	state;	int	port;	Pcidev*	pcidev;	Ctlr*	next;	int	active;	int	eepromsz;		/* address size in bits */	ushort*	eeprom;	Lock	miilock;	int	tick;	Lock	rlock;			/* registers */	int	command;		/* last command issued */	Block*	rfdhead;		/* receive side */	Block*	rfdtail;	int	nrfd;	Lock	cblock;			/* transmit side */	int	action;	int	nop;	uchar	configdata[24];	int	threshold;	int	ncb;	Cb*	cbr;	Cb*	cbhead;	Cb*	cbtail;	int	cbq;	int	cbqmax;	int	cbqmaxhw;	Rendez	timer;			/* for watchdog */	Lock	dlock;			/* dump statistical counters */	ulong	dump[17];} Ctlr;static Ctlr* ctlrhead;static Ctlr* ctlrtail;static uchar configdata[24] = {	0x16,				/* byte count */	0x08,				/* Rx/Tx FIFO limit */	0x00,				/* adaptive IFS */	0x00,		0x00,				/* Rx DMA maximum byte count *///	0x80,				/* Tx DMA maximum byte count */	0x00,				/* Tx DMA maximum byte count */	0x32,				/* !late SCB, CNA interrupts */	0x03,				/* discard short Rx frames */	0x00,				/* 503/MII */	0x00,		0x2E,				/* normal operation, NSAI */	0x00,				/* linear priority */	0x60,				/* inter-frame spacing */	0x00,		0xF2,		0xC8,				/* 503, promiscuous mode off */	0x00,		0x40,		0xF3,				/* transmit padding enable */	0x80,				/* full duplex pin enable */	0x3F,				/* no Multi IA */	0x05,				/* no Multi Cast ALL */};#define csr8r(c, r)	(inb((c)->port+(r)))#define csr16r(c, r)	(ins((c)->port+(r)))#define csr32r(c, r)	(inl((c)->port+(r)))#define csr8w(c, r, b)	(outb((c)->port+(r), (int)(b)))#define csr16w(c, r, w)	(outs((c)->port+(r), (ushort)(w)))#define csr32w(c, r, l)	(outl((c)->port+(r), (ulong)(l)))static voidcommand(Ctlr* ctlr, int c, int v){	int timeo;	ilock(&ctlr->rlock);	/*	 * Only back-to-back CUresume can be done	 * without waiting for any previous command to complete.	 * This should be the common case.	 * Unfortunately there's a chip errata where back-to-back	 * CUresumes can be lost, the fix is to always wait.	if(c == CUresume && ctlr->command == CUresume){		csr8w(ctlr, CommandR, c);		iunlock(&ctlr->rlock);		return;	}	 */	for(timeo = 0; timeo < 100; timeo++){		if(!csr8r(ctlr, CommandR))			break;		microdelay(1);	}	if(timeo >= 100){		ctlr->command = -1;		iunlock(&ctlr->rlock);		iprint("i82557: command %#ux %#ux timeout\n", c, v);		return;	}	switch(c){	case CUstart:	case LoadDCA:	case LoadCUB:	case RUstart:	case LoadHDS:	case LoadRUB:		csr32w(ctlr, General, v);		break;	/*	case CUnop:	case CUresume:	case DumpSC:	case ResetSA:	case RUresume:	case RUabort:	 */	default:		break;	}	csr8w(ctlr, CommandR, c);	ctlr->command = c;	iunlock(&ctlr->rlock);}static Block*rfdalloc(ulong link){	Block *bp;	Rfd *rfd;	if(bp = iallocb(sizeof(Rfd))){		rfd = (Rfd*)bp->rp;		rfd->field = 0;		rfd->link = link;		rfd->rbd = NullPointer;		rfd->count = 0;		rfd->size = sizeof(Etherpkt);	}	return bp;}#ifdef FSstatic intreturn0(void*){	return 0;}#endifstatic voidwatchdog(PROCARG(void* arg)){	Ether *ether;	Ctlr *ctlr;	static void txstart(Ether*);	static Rendez timer;		/* for FS */	ether = GETARG(arg);	for(;;){		tsleep(&timer, return0, 0, 4000);		/*		 * Hmmm. This doesn't seem right. Currently		 * the device can't be disabled but it may be in		 * the future.		 */		ctlr = ether->ctlr;		if(ctlr == nil || ctlr->state == 0){#ifdef FS			print("i82557: watchdog: exiting\n");			for (;;)				tsleep(&timer, return0, 0, 10000);#else			print("%s: exiting\n", up->text);			pexit("disabled", 0);#endif		}		ilock(&ctlr->cblock);		if(ctlr->tick++){			ctlr->action = CbMAS;			txstart(ether);		}		iunlock(&ctlr->cblock);	}}static voidattach(Ether* ether){	Ctlr *ctlr;	char name[KNAMELEN];	ctlr = ether->ctlr;	lock(&ctlr->slock);	if(ctlr->state == 0){		ilock(&ctlr->rlock);		csr8w(ctlr, Interrupt, 0);		iunlock(&ctlr->rlock);		command(ctlr, RUstart, PADDR(ctlr->rfdhead->rp));		ctlr->state = 1;		/*		 * Start the watchdog timer for the receive lockup errata		 * unless the EEPROM compatibility word indicates it may be		 * omitted.		 */		if((ctlr->eeprom[0x03] & 0x0003) != 0x0003){			snprint(name, KNAMELEN, "#l%dwatchdog", ether->ctlrno);			kproc(name, watchdog, ether);		}	}	unlock(&ctlr->slock);}#ifndef FSstatic longifstat(Ether* ether, void* a, long n, ulong offset){	char *p;	int i, len, phyaddr;	Ctlr *ctlr;	ulong dump[17];	ctlr = ether->ctlr;	lock(&ctlr->dlock);	/*	 * Start the command then	 * wait for completion status,	 * should be 0xA005.	 */	ctlr->dump[16] = 0;	command(ctlr, DumpSC, 0);	while(ctlr->dump[16] == 0)		;	ether->oerrs = ctlr->dump[1]+ctlr->dump[2]+ctlr->dump[3];	ether->crcs = ctlr->dump[10];	ether->frames = ctlr->dump[11];	ether->buffs = ctlr->dump[12]+ctlr->dump[15];	ether->overflows = ctlr->dump[13];	if(n == 0){		unlock(&ctlr->dlock);		return 0;	}	memmove(dump, ctlr->dump, sizeof(dump));	unlock(&ctlr->dlock);	p = malloc(READSTR);	len = snprint(p, READSTR, "transmit good frames: %lud\n", dump[0]);	len += snprint(p+len, READSTR-len, "transmit maximum collisions errors: %lud\n", dump[1]);	len += snprint(p+len, READSTR-len, "transmit late collisions errors: %lud\n", dump[2]);	len += snprint(p+len, READSTR-len, "transmit underrun errors: %lud\n", dump[3]);	len += snprint(p+len, READSTR-len, "transmit lost carrier sense: %lud\n", dump[4]);	len += snprint(p+len, READSTR-len, "transmit deferred: %lud\n", dump[5]);	len += snprint(p+len, READSTR-len, "transmit single collisions: %lud\n", dump[6]);	len += snprint(p+len, READSTR-len, "transmit multiple collisions: %lud\n", dump[7]);	len += snprint(p+len, READSTR-len, "transmit total collisions: %lud\n", dump[8]);	len += snprint(p+len, READSTR-len, "receive good frames: %lud\n", dump[9]);	len += snprint(p+len, READSTR-len, "receive CRC errors: %lud\n", dump[10]);	len += snprint(p+len, READSTR-len, "receive alignment errors: %lud\n", dump[11]);	len += snprint(p+len, READSTR-len, "receive resource errors: %lud\n", dump[12]);	len += snprint(p+len, READSTR-len, "receive overrun errors: %lud\n", dump[13]);	len += snprint(p+len, READSTR-len, "receive collision detect errors: %lud\n", dump[14]);	len += snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]);	len += snprint(p+len, READSTR-len, "nop: %d\n", ctlr->nop);	if(ctlr->cbqmax > ctlr->cbqmaxhw)		ctlr->cbqmaxhw = ctlr->cbqmax;	len += snprint(p+len, READSTR-len, "cbqmax: %d\n", ctlr->cbqmax);	ctlr->cbqmax = 0;	len += snprint(p+len, READSTR-len, "threshold: %d\n", ctlr->threshold);	len += snprint(p+len, READSTR-len, "eeprom:");	for(i = 0; i < (1<<ctlr->eepromsz); i++){		if(i && ((i & 0x07) == 0))			len += snprint(p+len, READSTR-len, "\n       ");		len += snprint(p+len, READSTR-len, " %4.4ux", ctlr->eeprom[i]);	}	if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)){		phyaddr = ctlr->eeprom[6] & 0x00FF;		len += snprint(p+len, READSTR-len, "\nphy %2d:", phyaddr);		for(i = 0; i < 6; i++){			static int miir(Ctlr*, int, int);			len += snprint(p+len, READSTR-len, " %4.4ux",				miir(ctlr, phyaddr, i));		}	}	snprint(p+len, READSTR-len, "\n");	n = readstr(offset, a, n, p);	free(p);	return n;}#endifstatic voidtxstart(Ether* ether){	Ctlr *ctlr;	Block *bp;	Cb *cb;	ctlr = ether->ctlr;	while(ctlr->cbq < (ctlr->ncb-1)){		cb = ctlr->cbhead->next;		if(ctlr->action == 0){			bp = etheroq(ether);			if(bp == nil)				break;			cb->command = CbS|CbSF|CbTransmit;			cb->tbd = PADDR(&cb->tba);			cb->count = 0;			cb->threshold = ctlr->threshold;			cb->number = 1;			cb->tba = PADDR(bp->rp);			cb->bp = bp;			cb->tbasz = BLEN(bp);		}		else if(ctlr->action == CbConfigure){			cb->command = CbS|CbConfigure;			memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata));			ctlr->action = 0;		}		else if(ctlr->action == CbIAS){			cb->command = CbS|CbIAS;			memmove(cb->data, ether->ea, Eaddrlen);			ctlr->action = 0;		}		else if(ctlr->action == CbMAS){			cb->command = CbS|CbMAS;			memset(cb->data, 0, sizeof(cb->data));			ctlr->action = 0;		}		else{			print("#l%d: action %#ux\n", ether->ctlrno, ctlr->action);			ctlr->action = 0;			break;		}		cb->status = 0;		coherence();		ctlr->cbhead->command &= ~CbS;		ctlr->cbhead = cb;		ctlr->cbq++;	}	/*	 * Workaround for some broken HUB chips	 * when connected at 10Mb/s half-duplex.	 */	if(ctlr->nop){		command(ctlr, CUnop, 0);		microdelay(1);	}	command(ctlr, CUresume, 0);	if(ctlr->cbq > ctlr->cbqmax)		ctlr->cbqmax = ctlr->cbq;}static voidconfigure(Ether* ether, int promiscuous){	Ctlr *ctlr;	ctlr = ether->ctlr;	ilock(&ctlr->cblock);	if(promiscuous){		ctlr->configdata[6] |= 0x80;		/* Save Bad Frames */		//ctlr->configdata[6] &= ~0x40;		/* !Discard Overrun Rx Frames */		ctlr->configdata[7] &= ~0x01;		/* !Discard Short Rx Frames */		ctlr->configdata[15] |= 0x01;		/* Promiscuous mode */		ctlr->configdata[18] &= ~0x01;		/* (!Padding enable?), !stripping enable */		ctlr->configdata[21] |= 0x08;		/* Multi Cast ALL */	}	else{		ctlr->configdata[6] &= ~0x80;		//ctlr->configdata[6] |= 0x40;		ctlr->configdata[7] |= 0x01;		ctlr->configdata[15] &= ~0x01;		ctlr->configdata[18] |= 0x01;		/* 0x03? */		ctlr->configdata[21] &= ~0x08;	}	ctlr->action = CbConfigure;	txstart(ether);	iunlock(&ctlr->cblock);}static voidpromiscuous(void* arg, int on){	configure(arg, on);}static voidmulticast(void* arg, uchar *addr, int on){	USED(addr, on);	configure(arg, 1);}static voidtransmit(Ether* ether){	Ctlr *ctlr;	ctlr = ether->ctlr;	ilock(&ctlr->cblock);	txstart(ether);	iunlock(&ctlr->cblock);}static voidreceive(Ether* ether){	Rfd *rfd;	Ctlr *ctlr;	int count;	Block *bp, *pbp, *xbp;	ctlr = ether->ctlr;	bp = ctlr->rfdhead;	for(rfd = (Rfd*)bp->rp; rfd->field & RfdC; rfd = (Rfd*)bp->rp){		/*		 * If it's an OK receive frame		 * 1) save the count 		 * 2) if it's small, try to allocate a block and copy		 *    the data, then adjust the necessary fields for reuse;		 * 3) if it's big, try to allocate a new Rfd and if		 *    successful		 *	adjust the received buffer pointers for the		 *	  actual data received;		 *	initialise the replacement buffer to point to		 *	  the next in the ring;		 *	initialise bp to point to the replacement;		 * 4) if there's a good packet, pass it on for disposal.		 */		if(rfd->field & RfdOK){			pbp = nil;			count = rfd->count & 0x3FFF;			if((count < ETHERMAXTU/4) && (pbp = iallocb(count))){				memmove(pbp->rp, bp->rp+offsetof(Rfd, data[0]), count);				SETWPCNT(pbp, count);				rfd->count = 0;				rfd->field = 0;			}			else if(xbp = rfdalloc(rfd->link)){				bp->rp += offsetof(Rfd, data[0]);				SETWPCNT(bp, count);				xbp->next = bp->next;				bp->next = 0;				pbp = bp;				bp = xbp;			}			if(pbp != nil)				ETHERIQ(ether, pbp, 1);		}		else{			rfd->count = 0;

⌨️ 快捷键说明

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