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

📄 ether8169.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Realtek RTL8110S/8169S. * Mostly there. There are some magic register values used * which are not described in any datasheet or driver but seem * to be necessary. * No tuning has been done. Only tested on an RTL8110S, there * are slight differences between the chips in the series so some * tweaks may be needed. */#include "etherdat.h"#include "etherif.h"#include "ethermii.h"#include "compat.h"#define dprint(...)	print("ether 8169: " __VA_ARGS__);enum {					/* registers */	Idr0		= 0x00,		/* MAC address */	Mar0		= 0x08,		/* Multicast address */	Dtccr		= 0x10,		/* Dump Tally Counter Command */	Tnpds		= 0x20,		/* Transmit Normal Priority Descriptors */	Thpds		= 0x28,		/* Transmit High Priority Descriptors */	Flash		= 0x30,		/* Flash Memory Read/Write */	Erbcr		= 0x34,		/* Early Receive Byte Count */	Ersr		= 0x36,		/* Early Receive Status */	Cr		= 0x37,		/* Command Register */	Tppoll		= 0x38,		/* Transmit Priority Polling */	Imr		= 0x3C,		/* Interrupt Mask */	Isr		= 0x3E,		/* Interrupt Status */	Tcr		= 0x40,		/* Transmit Configuration */	Rcr		= 0x44,		/* Receive Configuration */	Tctr		= 0x48,		/* Timer Count */	Mpc		= 0x4C,		/* Missed Packet Counter */	Cr9346		= 0x50,		/* 9346 Command Register */	Config0		= 0x51,		/* Configuration Register 0 */	Config1		= 0x52,		/* Configuration Register 1 */	Config2		= 0x53,		/* Configuration Register 2 */	Config3		= 0x54,		/* Configuration Register 3 */	Config4		= 0x55,		/* Configuration Register 4 */	Config5		= 0x56,		/* Configuration Register 5 */	Timerint		= 0x58,		/* Timer Interrupt */	Mulint		= 0x5C,		/* Multiple Interrupt Select */	Phyar		= 0x60,		/* PHY Access */	Tbicsr0		= 0x64,		/* TBI Control and Status */	Tbianar		= 0x68,		/* TBI Auto-Negotiation Advertisment */	Tbilpar		= 0x6A,		/* TBI Auto-Negotiation Link Partner */	Phystatus	= 0x6C,		/* PHY Status */	Rms		= 0xDA,		/* Receive Packet Maximum Size */	Cplusc		= 0xE0,		/* C+ Command */	Rdsar		= 0xE4,		/* Receive Descriptor Start Address */	Mtps		= 0xEC,		/* Max. Transmit Packet Size */};enum {					/* Dtccr */	Cmd		= 0x00000008,	/* Command */};enum {					/* Cr */	Te		= 0x04,		/* Transmitter Enable */	Re		= 0x08,		/* Receiver Enable */	Rst		= 0x10,		/* Software Reset */};enum {					/* Tppoll */	Fswint		= 0x01,		/* Forced Software Interrupt */	Npq		= 0x40,		/* Normal Priority Queue polling */	Hpq		= 0x80,		/* High Priority Queue polling */};enum {					/* Imr/Isr */	Rok		= 0x0001,	/* Receive OK */	Rer		= 0x0002,	/* Receive Error */	Tok		= 0x0004,	/* Transmit OK */	Ter		= 0x0008,	/* Transmit Error */	Rdu		= 0x0010,	/* Receive Descriptor Unavailable */	Punlc		= 0x0020,	/* Packet Underrun or Link Change */	Fovw		= 0x0040,	/* Receive FIFO Overflow */	Tdu		= 0x0080,	/* Transmit Descriptor Unavailable */	Swint		= 0x0100,	/* Software Interrupt */	Timeout		= 0x4000,	/* Timer */	Serr		= 0x8000,	/* System Error */};enum {					/* Tcr */	MtxdmaSHIFT	= 8,		/* Max. DMA Burst Size */	MtxdmaMASK	= 0x00000700,	Mtxdmaunlimited	= 0x00000700,	Acrc		= 0x00010000,	/* Append CRC (not) */	Lbk0		= 0x00020000,	/* Loopback Test 0 */	Lbk1		= 0x00040000,	/* Loopback Test 1 */	Ifg2		= 0x00080000,	/* Interframe Gap 2 */	HwveridSHIFT	= 23,		/* Hardware Version ID */	HwveridMASK	= 0x7C800000,	Macv01		= 0x00000000,	/* RTL8169 */	Macv02		= 0x00800000,	/* RTL8169S/8110S */	Macv03		= 0x04000000,	/* RTL8169S/8110S */	Macv04		= 0x10000000,	/* RTL8169SB/8110SB */	Macv05		= 0x18000000,	/* RTL8169SC/8110SC */	Macv11		= 0x30000000,	/* RTL8168B/8111B */	Macv12		= 0x38000000,	/* RTL8169B/8111B */	Macv13		= 0x34000000,	/* RTL8101E */	Macv14		= 0x30800000,	/* RTL8100E */	Macv15		= 0x38800000,	/* RTL8100E */	Ifg0		= 0x01000000,	/* Interframe Gap 0 */	Ifg1		= 0x02000000,	/* Interframe Gap 1 */};enum {					/* Rcr */	Aap		= 0x00000001,	/* Accept All Packets */	Apm		= 0x00000002,	/* Accept Physical Match */	Am		= 0x00000004,	/* Accept Multicast */	Ab		= 0x00000008,	/* Accept Broadcast */	Ar		= 0x00000010,	/* Accept Runt */	Aer		= 0x00000020,	/* Accept Error */	Sel9356		= 0x00000040,	/* 9356 EEPROM used */	MrxdmaSHIFT	= 8,		/* Max. DMA Burst Size */	MrxdmaMASK	= 0x00000700,	Mrxdmaunlimited	= 0x00000700,	RxfthSHIFT	= 13,		/* Receive Buffer Length */	RxfthMASK	= 0x0000E000,	Rxfth256	= 0x00008000,	Rxfthnone	= 0x0000E000,	Rer8		= 0x00010000,	/* Accept Error Packets > 8 bytes */	MulERINT	= 0x01000000,	/* Multiple Early Interrupt Select */};enum {					/* Cr9346 */	Eedo		= 0x01,		/* */	Eedi		= 0x02,		/* */	Eesk		= 0x04,		/* */	Eecs		= 0x08,		/* */	Eem0		= 0x40,		/* Operating Mode */	Eem1		= 0x80,};enum {					/* Phyar */	DataMASK	= 0x0000FFFF,	/* 16-bit GMII/MII Register Data */	DataSHIFT	= 0,	RegaddrMASK	= 0x001F0000,	/* 5-bit GMII/MII Register Address */	RegaddrSHIFT	= 16,	PhyFlag		= 0x80000000,	/* */};enum {					/* Phystatus */	Fd		= 0x01,		/* Full Duplex */	Linksts		= 0x02,		/* Link Status */	Speed10		= 0x04,		/* */	Speed100	= 0x08,		/* */	Speed1000	= 0x10,		/* */	Rxflow		= 0x20,		/* */	Txflow		= 0x40,		/* */	Entbi		= 0x80,		/* */};enum {					/* Cplusc */	Mulrw		= 0x0008,	/* PCI Multiple R/W Enable */	Dac		= 0x0010,	/* PCI Dual Address Cycle Enable */	Rxchksum	= 0x0020,	/* Receive Checksum Offload Enable */	Rxvlan		= 0x0040,	/* Receive VLAN De-tagging Enable */	Endian		= 0x0200,	/* Endian Mode */};typedef struct D D;			/* Transmit/Receive Descriptor */struct D {	u32int	control;	u32int	vlan;	u32int	addrlo;	u32int	addrhi;};enum {					/* Transmit Descriptor control */	TxflMASK	= 0x0000FFFF,	/* Transmit Frame Length */	TxflSHIFT	= 0,	Tcps		= 0x00010000,	/* TCP Checksum Offload */	Udpcs		= 0x00020000,	/* UDP Checksum Offload */	Ipcs		= 0x00040000,	/* IP Checksum Offload */	Lgsen		= 0x08000000,	/* Large Send */};enum {					/* Receive Descriptor control */	RxflMASK	= 0x00003FFF,	/* Receive Frame Length */	RxflSHIFT	= 0,	Tcpf		= 0x00004000,	/* TCP Checksum Failure */	Udpf		= 0x00008000,	/* UDP Checksum Failure */	Ipf		= 0x00010000,	/* IP Checksum Failure */	Pid0		= 0x00020000,	/* Protocol ID0 */	Pid1		= 0x00040000,	/* Protocol ID1 */	Crce		= 0x00080000,	/* CRC Error */	Runt		= 0x00100000,	/* Runt Packet */	Res		= 0x00200000,	/* Receive Error Summary */	Rwt		= 0x00400000,	/* Receive Watchdog Timer Expired */	Fovf		= 0x00800000,	/* FIFO Overflow */	Bovf		= 0x01000000,	/* Buffer Overflow */	Bar		= 0x02000000,	/* Broadcast Address Received */	Pam		= 0x04000000,	/* Physical Address Matched */	Mar		= 0x08000000,	/* Multicast Address Received */};enum {					/* General Descriptor control */	Ls		= 0x10000000,	/* Last Segment Descriptor */	Fs		= 0x20000000,	/* First Segment Descriptor */	Eor		= 0x40000000,	/* End of Descriptor Ring */	Own		= 0x80000000,	/* Ownership */};/* */enum {					/* Ring sizes  (<= 1024) */	Ntd		= 32,		/* Transmit Ring */	Nrd		= 128,		/* Receive Ring */	Mps		= ROUNDUP(ETHERMAXTU+4, 128),};typedef struct Dtcc Dtcc;struct Dtcc {	u64int	txok;	u64int	rxok;	u64int	txer;	u32int	rxer;	u16int	misspkt;	u16int	fae;	u32int	tx1col;	u32int	txmcol;	u64int	rxokph;	u64int	rxokbrd;	u32int	rxokmu;	u16int	txabt;	u16int	txundrn;};enum {						/* Variants */	Rtl8100e 	= (0x8136<<16)|0x10EC,	/* RTL810[01]E ? */	Rtl8169c		= (0x0116<<16)|0x16EC,	/* RTL8169C+ (USR997902) */	Rtl8169sc	= (0x8167<<16)|0x10EC,	/* RTL8169SC */	Rtl8168b 	= (0x8168<<16)|0x10EC,	/* RTL8168B */	Rtl8169		= (0x8169<<16)|0x10EC,	/* RTL8169 */};typedef struct Ctlr Ctlr;typedef struct Ctlr {	int	port;	Pcidev*	pcidev;	Ctlr*	next;	int	active;	QLock	alock;			/* attach */	Lock	ilock;			/* init */	int	init;			/*  */	int	pciv;			/*  */	int	macv;			/* MAC version */	int	phyv;			/* PHY version */	Mii*	mii;	Lock	tlock;			/* transmit */	D*	td;			/* descriptor ring */	Block**	tb;			/* transmit buffers */	int	ntd;	int	tdh;			/* head - producer index (host) */	int	tdt;			/* tail - consumer index (NIC) */	int	ntdfree;	int	ntq;	int	mtps;			/* Max. Transmit Packet Size */	Lock	rlock;			/* receive */	D*	rd;			/* descriptor ring */	Block**	rb;			/* receive buffers */	int	nrd;	int	rdh;			/* head - producer index (NIC) */	int	rdt;			/* tail - consumer index (host) */	int	nrdfree;	int	tcr;			/* transmit configuration register */	int	rcr;			/* receive configuration register */	int	imr;	QLock	slock;			/* statistics */	Dtcc*	dtcc;	uint	txdu;	uint	tcpf;	uint	udpf;	uint	ipf;	uint	fovf;	uint	ierrs;	uint	rer;	uint	rdu;	uint	punlc;	uint	fovw;} Ctlr;static Ctlr* rtl8169ctlrhead;static Ctlr* rtl8169ctlrtail;#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), (u8int)(b)))#define csr16w(c, r, w)	(outs((c)->port+(r), (u16int)(w)))#define csr32w(c, r, l)	(outl((c)->port+(r), (u32int)(l)))static intrtl8169miimir(Mii* mii, int pa, int ra){	uint r;	int timeo;	Ctlr *ctlr;	if(pa != 1)		return -1;	ctlr = mii->ctlr;	r = (ra<<16) & RegaddrMASK;	csr32w(ctlr, Phyar, r);	delay(1);	for(timeo = 0; timeo < 2000; timeo++){		if((r = csr32r(ctlr, Phyar)) & PhyFlag)			break;		microdelay(100);	}	if(!(r & PhyFlag))		return -1;	return (r & DataMASK)>>DataSHIFT;}static intrtl8169miimiw(Mii* mii, int pa, int ra, int data){	uint r;	int timeo;	Ctlr *ctlr;	if(pa != 1)		return -1;	ctlr = mii->ctlr;	r = PhyFlag|((ra<<16) & RegaddrMASK)|((data<<DataSHIFT) & DataMASK);	csr32w(ctlr, Phyar, r);	delay(1);	for(timeo = 0; timeo < 2000; timeo++){		if(!((r = csr32r(ctlr, Phyar)) & PhyFlag))			break;		microdelay(100);	}	if(r & PhyFlag)		return -1;	return 0;}static intrtl8169mii(Ctlr* ctlr){	MiiPhy *phy;	/*	 * Link management.	 */	if((ctlr->mii = malloc(sizeof(Mii))) == nil)		return -1;	ctlr->mii->mir = rtl8169miimir;	ctlr->mii->miw = rtl8169miimiw;	ctlr->mii->ctlr = ctlr;	/*	 * Get rev number out of Phyidr2 so can config properly.	 * There's probably more special stuff for Macv0[234] needed here.	 */	ctlr->phyv = rtl8169miimir(ctlr->mii, 1, Phyidr2) & 0x0F;	if(ctlr->macv == Macv02){		csr8w(ctlr, 0x82, 1);				/* magic */		rtl8169miimiw(ctlr->mii, 1, 0x0B, 0x0000);	/* magic */	}	if(mii(ctlr->mii, (1<<1)) == 0 || (phy = ctlr->mii->curphy) == nil){		free(ctlr->mii);		ctlr->mii = nil;		return -1;	}	print("oui %#ux phyno %d, macv = %#8.8ux phyv = %#4.4ux\n",		phy->oui, phy->phyno, ctlr->macv, ctlr->phyv);	miiane(ctlr->mii, ~0, ~0, ~0);	return 0;}voidrtl8169promiscuous(void* arg, int on){	Ether *edev;	Ctlr * ctlr;	edev = arg;	ctlr = edev->ctlr;	ilock(&ctlr->ilock);	if(on)		ctlr->rcr |= Aap;	else		ctlr->rcr &= ~Aap;	csr32w(ctlr, Rcr, ctlr->rcr);	iunlock(&ctlr->ilock);}#ifndef FSstatic longrtl8169ifstat(Ether* edev, void* a, long n, ulong offset){	char *p;	Ctlr *ctlr;	Dtcc *dtcc;	int i, l, r, timeo;	ctlr = edev->ctlr;	qlock(&ctlr->slock);	p = nil;	if(waserror()){		qunlock(&ctlr->slock);		free(p);		nexterror();	}	csr32w(ctlr, Dtccr+4, 0);	csr32w(ctlr, Dtccr, PCIWADDR(ctlr->dtcc)|Cmd);	for(timeo = 0; timeo < 1000; timeo++){		if(!(csr32r(ctlr, Dtccr) & Cmd))			break;		delay(1);	}	if(csr32r(ctlr, Dtccr) & Cmd)		error(Eio);	dtcc = ctlr->dtcc;	edev->oerrs = dtcc->txer;	edev->crcs = dtcc->rxer;	edev->frames = dtcc->fae;	edev->buffs = dtcc->misspkt;	edev->overflows = ctlr->txdu+ctlr->rdu;	if(n == 0){		qunlock(&ctlr->slock);		poperror();		return 0;	}	if((p = malloc(READSTR)) == nil)		error(Enomem);	l = snprint(p, READSTR, "TxOk: %llud\n", dtcc->txok);	l += snprint(p+l, READSTR-l, "RxOk: %llud\n", dtcc->rxok);	l += snprint(p+l, READSTR-l, "TxEr: %llud\n", dtcc->txer);	l += snprint(p+l, READSTR-l, "RxEr: %ud\n", dtcc->rxer);	l += snprint(p+l, READSTR-l, "MissPkt: %ud\n", dtcc->misspkt);	l += snprint(p+l, READSTR-l, "FAE: %ud\n", dtcc->fae);	l += snprint(p+l, READSTR-l, "Tx1Col: %ud\n", dtcc->tx1col);	l += snprint(p+l, READSTR-l, "TxMCol: %ud\n", dtcc->txmcol);	l += snprint(p+l, READSTR-l, "RxOkPh: %llud\n", dtcc->rxokph);	l += snprint(p+l, READSTR-l, "RxOkBrd: %llud\n", dtcc->rxokbrd);	l += snprint(p+l, READSTR-l, "RxOkMu: %ud\n", dtcc->rxokmu);	l += snprint(p+l, READSTR-l, "TxAbt: %ud\n", dtcc->txabt);	l += snprint(p+l, READSTR-l, "TxUndrn: %ud\n", dtcc->txundrn);	l += snprint(p+l, READSTR-l, "txdu: %ud\n", ctlr->txdu);	l += snprint(p+l, READSTR-l, "tcpf: %ud\n", ctlr->tcpf);	l += snprint(p+l, READSTR-l, "udpf: %ud\n", ctlr->udpf);	l += snprint(p+l, READSTR-l, "ipf: %ud\n", ctlr->ipf);	l += snprint(p+l, READSTR-l, "fovf: %ud\n", ctlr->fovf);	l += snprint(p+l, READSTR-l, "ierrs: %ud\n", ctlr->ierrs);	l += snprint(p+l, READSTR-l, "rer: %ud\n", ctlr->rer);	l += snprint(p+l, READSTR-l, "rdu: %ud\n", ctlr->rdu);	l += snprint(p+l, READSTR-l, "punlc: %ud\n", ctlr->punlc);	l += snprint(p+l, READSTR-l, "fovw: %ud\n", ctlr->fovw);	l += snprint(p+l, READSTR-l, "tcr: %#8.8ux\n", ctlr->tcr);	l += snprint(p+l, READSTR-l, "rcr: %#8.8ux\n", ctlr->rcr);	if(ctlr->mii != nil && ctlr->mii->curphy != nil){		l += snprint(p+l, READSTR, "phy:   ");		for(i = 0; i < NMiiPhyr; i++){			if(i && ((i & 0x07) == 0))				l += snprint(p+l, READSTR-l, "\n       ");			r = miimir(ctlr->mii, i);			l += snprint(p+l, READSTR-l, " %4.4ux", r);		}		snprint(p+l, READSTR-l, "\n");	}	n = readstr(offset, a, n, p);	qunlock(&ctlr->slock);	poperror();	free(p);	return n;}#endifstatic voidrtl8169halt(Ctlr* ctlr){	csr8w(ctlr, Cr, 0);	csr16w(ctlr, Imr, 0);	csr16w(ctlr, Isr, ~0);}static intrtl8169reset(Ctlr* ctlr){	u32int r;	int timeo;	/*	 * Soft reset the controller.	 */	csr8w(ctlr, Cr, Rst);	for(r = timeo = 0; timeo < 1000; timeo++){		r = csr8r(ctlr, Cr);		if(!(r & Rst))			break;		delay(1);	}	rtl8169halt(ctlr);	if(r & Rst)		return -1;	return 0;}static voidrtl8169replenish(Ctlr* ctlr){	D *d;	int rdt;	Block *bp;	rdt = ctlr->rdt;	while(NEXT(rdt, ctlr->nrd) != ctlr->rdh){		d = &ctlr->rd[rdt];		if(ctlr->rb[rdt] == nil){			/*			 * Simple allocation for now.			 * This better be aligned on 8.			 */			bp = iallocb(Mps);			if(bp == nil){				iprint("no available buffers\n");				break;			}			ctlr->rb[rdt] = bp;			d->addrlo = PCIWADDR(bp->rp);			d->addrhi = 0;		}		coherence();		d->control |= Own|Mps;		rdt = NEXT(rdt, ctlr->nrd);		ctlr->nrdfree++;	}	ctlr->rdt = rdt;}

⌨️ 快捷键说明

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