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

📄 rtl8139.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
/* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. *//*	Written 1997-1998 by Donald Becker.	This software may be used and distributed according to the terms	of the GNU Public License, incorporated herein by reference.    All other rights reserved.	This driver is for boards based on the RTL8129 and RTL8139 PCI ethernet	chips.	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O	Center of Excellence in Space Data and Information Sciences	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771	Support and updates available at	http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html	Twister-tuning code contributed by Kinston <shangh@realtek.com.tw>.*/static const char *version ="rtl8139.c:v0.99B 4/7/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";/* A few user-configurable values. *//* Maximum events (Rx packets, etc.) to handle at each interrupt. */static int max_interrupt_work = 10;/* Size of the in-memory receive ring. */#define RX_BUF_LEN_IDX	2			/* 0==8K, 1==16K, 2==32K, 3==64K */#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */#define TX_BUF_SIZE	1536/* PCI Tuning Parameters   Threshold is bytes transferred to chip before transmission starts. */#define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. *//* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024. */#define RX_FIFO_THRESH	4		/* Rx buffer level before first PCI xfer.  */#define RX_DMA_BURST	4		/* Maximum PCI burst, '4' is 256 bytes */#define TX_DMA_BURST	4/* Operational parameters that usually are not changed. *//* Time in jiffies before concluding the transmitter is hung. */#define TX_TIMEOUT  ((4000*HZ)/1000)#ifdef MODULE#ifdef MODVERSIONS#include <linux/modversions.h>#endif#include <linux/module.h>#include <linux/version.h>#else#define MOD_INC_USE_COUNT#define MOD_DEC_USE_COUNT#endif#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/ptrace.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/malloc.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/bios32.h>#include <asm/processor.h>		/* Processor type for cache alignment. */#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#define RUN_AT(x) (jiffies + (x))#include <linux/delay.h>#if (LINUX_VERSION_CODE < 0x20123)#define test_and_set_bit(val, addr) set_bit(val, addr)#endif/* The I/O extent. */#define RTL8129_TOTAL_SIZE 0x80#ifdef HAVE_DEVLISTstruct netdev_entry rtl8139_drv ={"RTL8139", rtl8139_probe, RTL8129_TOTAL_SIZE, NULL};#endifstatic int rtl8129_debug = 1;/*				Theory of OperationI. Board CompatibilityThis device driver is designed for the RealTek RTL8129, the RealTek FastEthernet controllers for PCI.  This chip is used on a few clone boards.II. Board-specific settingsPCI bus devices are configured by the system at boot time, so no jumpersneed to be set on the board.  The system BIOS will assign thePCI INTA signal to a (preferably otherwise unused) system IRQ line.Note: Kernel versions earlier than 1.3.73 do not support shared PCIinterrupt lines.III. Driver operationIIIa. Rx Ring buffersThe receive unit uses a single linear ring buffer rather than the morecommon (and more efficient) descriptor-based architecture.  Incoming framesare sequentially stored into the Rx region, and the host copies them intoskbuffs.Comment: While it is theoretically possible to process many frames in place,any delay in Rx processing would cause us to drop frames.  More importantly,the Linux protocol stack is not designed to operate in this manner.IIIb. Tx operationThe RTL8129 uses a fixed set of four Tx descriptors in register space.In a stunningly bad design choice, Tx frames must be 32 bit aligned.  Linuxaligns the IP header on word boundaries, and 14 byte ethernet header meansthat almost all frames will need to be copied to an alignment buffer.IVb. Referenceshttp://www.realtek.com.tw/cn/cn.htmlhttp://cesdis.gsfc.nasa.gov/linux/misc/NWay.htmlIVc. Errata*/#ifndef PCI_VENDOR_ID_REALTEK#define PCI_VENDOR_ID_REALTEK		0x10ec#endif#ifndef PCI_DEVICE_ID_REALTEK_8129#define PCI_DEVICE_ID_REALTEK_8129	0x8129#endif#ifndef PCI_DEVICE_ID_REALTEK_8139#define PCI_DEVICE_ID_REALTEK_8139	0x8139#endif/* The rest of these values should never change. */#define NUM_TX_DESC	4			/* Number of Tx descriptor registers. *//* Symbolic offsets to registers. */enum RTL8129_registers {	MAC0=0,						/* Ethernet hardware address. */	MAR0=8,						/* Multicast filter. */	TxStat0=0x10,				/* Transmit status (Four 32bit registers). */	TxAddr0=0x20,				/* Tx descriptors (also four 32bit). */	RxBuf=0x30, RxEarlyCnt=0x34, RxEarlyStatus=0x36,	ChipCmd=0x37, RxBufPtr=0x38, RxBufAddr=0x3A,	IntrMask=0x3C, IntrStatus=0x3E,	TxConfig=0x40, RxConfig=0x44,	Timer=0x48,					/* A general-purpose counter. */	RxMissed=0x4C,				/* 24 bits valid, write clears. */	Cfg9346=0x50, Config0=0x51, Config1=0x52,	FlashReg=0x54, GPPinData=0x58, GPPinDir=0x59, MII_SMI=0x5A, HltClk=0x5B,	MultiIntr=0x5C, TxSummary=0x60,	BMCR=0x62, BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68, NWayExpansion=0x6A,	/* Undocumented registers, but required for proper operation. */	FIFOTMS=0x70,	/* FIFO Test Mode Select */	CSCR=0x74,	/* Chip Status and Configuration Register. */	PARA78=0x78, PARA7c=0x7c,	/* Magic transceiver parameter register. */};enum ChipCmdBits {	CmdReset=0x10, CmdRxEnb=0x08, CmdTxEnb=0x04, RxBufEmpty=0x01, };/* Interrupt register bits, using my own meaningful names. */enum IntrStatusBits {	PCIErr=0x8000, PCSTimeout=0x4000,	RxFIFOOver=0x40, RxUnderrun=0x20, RxOverflow=0x10,	TxErr=0x08, TxOK=0x04, RxErr=0x02, RxOK=0x01,};enum TxStatusBits {	TxHostOwns=0x2000, TxUnderrun=0x4000, TxStatOK=0x8000,	TxOutOfWindow=0x20000000, TxAborted=0x40000000, TxCarrierLost=0x80000000,};enum RxStatusBits {	RxMulticast=0x8000, RxPhysical=0x4000, RxBroadcast=0x2000,	RxBadSymbol=0x0020, RxRunt=0x0010, RxTooLong=0x0008, RxCRCErr=0x0004,	RxBadAlign=0x0002, RxStatusOK=0x0001,};enum CSCRBits {	CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,	CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,	CSCR_LinkDownCmd=0x0f3c0,};	/* Twister tuning parameters from RealTek.  Completely undocumented. */unsigned long param[4][4]={	{0x0cb39de43,0x0cb39ce43,0x0fb38de03,0x0cb38de43},	{0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},	{0x0cb39de43,0x0cb39ce43,0x0cb39ce83,0x0cb39ce83},	{0x0bb39de43,0x0bb39ce43,0x0bb39ce83,0x0bb39ce83}};struct rtl8129_private {	char devname[8];			/* Used only for kernel debugging. */	const char *product_name;	struct device *next_module;	int chip_id;	int chip_revision;#if LINUX_VERSION_CODE > 0x20139	struct net_device_stats stats;#else	struct enet_statistics stats;#endif	struct timer_list timer;	/* Media selection timer. */	unsigned int cur_rx, cur_tx;		/* The next free and used entries */	unsigned int dirty_rx, dirty_tx;	/* The saved address of a sent-in-place packet/buffer, for skfree(). */	struct sk_buff* tx_skbuff[NUM_TX_DESC];	unsigned char *tx_buf[NUM_TX_DESC];	/* Tx bounce buffers */	unsigned char *rx_ring;	unsigned char *tx_bufs;				/* Tx bounce buffer region. */	unsigned char mc_filter[8];			/* Current multicast filter. */	char phys[4];						/* MII device addresses. */	int in_interrupt;					/* Alpha needs word-wide lock. */	unsigned int tx_full:1;				/* The Tx queue is full. */	unsigned int full_duplex:1;			/* Full-duplex operation requested. */	unsigned int default_port:4;		/* Last dev->if_port value. */	unsigned int media2:4;				/* Secondary monitored media port. */	unsigned int medialock:1;			/* Don't sense media type. */	unsigned int mediasense:1;			/* Media sensing in progress. */};#ifdef MODULE/* Used to pass the full-duplex flag, etc. */static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};#if LINUX_VERSION_CODE > 0x20118MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");MODULE_DESCRIPTION("RealTek RTL8129/8139 Fast Ethernet driver");MODULE_PARM(debug, "i");MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");MODULE_PARM(max_interrupt_work, "i");#endif#endifstatic struct device *rtl8129_probe1(struct device *dev, int ioaddr, int irq,									 int chip_id, int options, int card_idx);static int rtl8129_open(struct device *dev);static int read_eeprom(int ioaddr, int location);static int mdio_read(int ioaddr, int phy_id, int location);static void rtl8129_timer(unsigned long data);static void rtl8129_tx_timeout(struct device *dev);static void rtl8129_init_ring(struct device *dev);static int rtl8129_start_xmit(struct sk_buff *skb, struct device *dev);static int rtl8129_rx(struct device *dev);static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs);static int rtl8129_close(struct device *dev);static struct enet_statistics *rtl8129_get_stats(struct device *dev);static void set_rx_mode(struct device *dev);#ifdef MODULE/* A list of all installed RTL8129 devices, for removing the driver module. */static struct device *root_rtl8129_dev = NULL;#endifint rtl8139_probe(struct device *dev){	int cards_found = 0;	static int pci_index = 0;	/* Static, for multiple probe calls. */	/* Ideally we would detect all network cards in slot order.  That would	   be best done a central PCI probe dispatch, which wouldn't work	   well with the current structure.  So instead we detect just the	   Rtl81*9 cards in slot order. */	if (pcibios_present()) {		unsigned char pci_bus, pci_device_fn;		for (;pci_index < 0xff; pci_index++) {			u8 pci_irq_line, pci_latency;			u16 pci_command, new_command, vendor, device;			u32 pci_ioaddr;			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,#ifdef REVERSE_PROBE_ORDER									0xff - pci_index,#else									pci_index,#endif									&pci_bus, &pci_device_fn)				!= PCIBIOS_SUCCESSFUL)				break;			pcibios_read_config_word(pci_bus, pci_device_fn,									 PCI_VENDOR_ID, &vendor);			if (vendor != PCI_VENDOR_ID_REALTEK)				continue;			pcibios_read_config_word(pci_bus, pci_device_fn,									 PCI_DEVICE_ID, &device);			pcibios_read_config_byte(pci_bus, pci_device_fn,									 PCI_INTERRUPT_LINE, &pci_irq_line);			pcibios_read_config_dword(pci_bus, pci_device_fn,									  PCI_BASE_ADDRESS_0, &pci_ioaddr);			/* Remove I/O space marker in bit 0. */			pci_ioaddr &= ~3;			if (device != PCI_DEVICE_ID_REALTEK_8129				&&  device != PCI_DEVICE_ID_REALTEK_8139) {				printk(KERN_NOTICE "Unknown RealTek PCI ethernet chip type "					   "%4.4x detected: not configured.\n", device);				continue;			}			if (check_region(pci_ioaddr, RTL8129_TOTAL_SIZE))				continue;			/* Activate the card: fix for brain-damaged Win98 BIOSes. */			pcibios_read_config_word(pci_bus, pci_device_fn,									 PCI_COMMAND, &pci_command);			new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;			if (pci_command != new_command) {				printk(KERN_INFO "  The PCI BIOS has not enabled this"					   " device!  Updating PCI config %4.4x->%4.4x.\n",					   pci_command, new_command);				pcibios_write_config_word(pci_bus, pci_device_fn,										  PCI_COMMAND, new_command);			}#ifdef MODULE			dev = rtl8129_probe1(dev, pci_ioaddr, pci_irq_line, device,								 options[cards_found], cards_found);#else			dev = rtl8129_probe1(dev, pci_ioaddr, pci_irq_line, device,								 dev ? dev->mem_start : 0, -1);#endif			if (dev) {				pcibios_read_config_byte(pci_bus, pci_device_fn,										 PCI_LATENCY_TIMER, &pci_latency);				if (pci_latency < 32) {					printk(KERN_NOTICE"  PCI latency timer (CFLT) is "						   "unreasonably low at %d.  Setting to 64 clocks.\n",						   pci_latency);					pcibios_write_config_byte(pci_bus, pci_device_fn,											  PCI_LATENCY_TIMER, 64);				} else if (rtl8129_debug > 1)					printk(KERN_INFO"  PCI latency timer (CFLT) is %#x.\n",						   pci_latency);				dev = 0;				cards_found++;			}		}	}#if defined (MODULE)	return cards_found;#else	return cards_found ? 0 : -ENODEV;#endif}static struct device *rtl8129_probe1(struct device *dev, int ioaddr, int irq,								   int chip_id, int options, int card_idx){	static int did_version = 0;			/* Already printed version info. */	struct rtl8129_private *tp;	int i;	if (rtl8129_debug > 0  &&  did_version++ == 0)		printk(KERN_INFO "%s", version);	dev = init_etherdev(dev, 0);	printk(KERN_INFO "%s: RealTek RTL%x at %#3x, IRQ %d, ",		   dev->name, chip_id, ioaddr, irq);	/* Bring the chip out of low-power mode. */	outb(0x00, ioaddr + Config1);	/* Perhaps this should be read from the EEPROM? */	for (i = 0; i < 6; i++)		dev->dev_addr[i] = inb(ioaddr + MAC0 + i);	for (i = 0; i < 5; i++)		printk("%2.2x:", dev->dev_addr[i]);	printk("%2.2x.\n", dev->dev_addr[i]);	if (rtl8129_debug > 1) {		printk(KERN_INFO "%s: EEPROM contents\n", dev->name);		for (i = 0; i < 64; i++)			printk(" %4.4x%s", read_eeprom(ioaddr, i),				   i%16 == 15 ? "\n"KERN_INFO : "");	}	/* We do a request_region() to register /proc/ioports info. */	request_region(ioaddr, RTL8129_TOTAL_SIZE, "RealTek RTL8129/39 Fast Ethernet");	dev->base_addr = ioaddr;	dev->irq = irq;	/* Some data structures must be quadword aligned. */	tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA);	memset(tp, 0, sizeof(*tp));	dev->priv = tp;#ifdef MODULE	tp->next_module = root_rtl8129_dev;	root_rtl8129_dev = dev;#endif	tp->chip_id = chip_id;	/* Find the connected MII xcvrs.	   Doing this in open() would allow detecting external xcvrs later, but	   takes too much time. */	if (chip_id == 0x8129) {		int phy, phy_idx;		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);			 phy++) {			int mii_status = mdio_read(ioaddr, phy, 1);			if (mii_status != 0xffff  && mii_status != 0x0000) {				tp->phys[phy_idx++] = phy;				printk(KERN_INFO "%s: MII transceiver found at address %d.\n",					   dev->name, phy);

⌨️ 快捷键说明

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