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

📄 rtl8139.c

📁 44b0uclinux下的8319网卡芯片驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. *//*	Written 1997-2001 by Donald Becker.	This software may be used and distributed according to the terms of	the GNU General Public License (GPL), incorporated herein by reference.	Drivers based on or derived from this code fall under the GPL and must	retain the authorship, copyright and license notice.  This file is not	a complete program and may only be used when the entire operating	system is licensed under the GPL.	This driver is for boards based on the RTL8129 and RTL8139 PCI ethernet	chips.	The author may be reached as becker@scyld.com, or C/O	Scyld Computing Corporation	410 Severn Ave., Suite 210	Annapolis MD 21403	Support and updates available at	http://www.scyld.com/network/rtl8139.html	Twister-tuning table provided by Kinston <shangh@realtek.com.tw>.*//* These identify the driver base version and may not be removed. */static const char versionA[] ="rtl8139.c:v1.16a 11/13/2001 Donald Becker, becker@scyld.com.\n";static const char versionB[] =" http://www.scyld.com/network/rtl8139.html\n";#ifndef USE_MEM_OPS/* Note: Register access width and timing restrictions apply in MMIO mode.   This updated driver should nominally work, but I/O mode is better tested. */#define USE_IO_OPS#endif/* The user-configurable values.   These may be modified when a driver module is loaded.*/static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. *//* Maximum events (Rx packets, etc.) to handle at each interrupt. */static int max_interrupt_work = 20;/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).   The RTL chips use a 64 element hash table based on the Ethernet CRC.  It   is efficient to update the hardware filter, but recalculating the table   for a long filter list is painful.  */static int multicast_filter_limit = 32;/* Used to pass the full-duplex flag, etc. */#define MAX_UNITS 8		/* More are supported, limit only on options */static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};/* Operational parameters that are set at compile time. *//* Maximum size of the in-memory receive ring (smaller if no memory). */#define RX_BUF_LEN_IDX	2			/* 0==8K, 1==16K, 2==32K, 3==64K *//* 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		/* Calculate as 16<<val. *//* Operational parameters that usually are not changed. *//* Time in jiffies before concluding the transmitter is hung. */#define TX_TIMEOUT  (6*HZ)#ifndef __KERNEL__#define __KERNEL__#endif#if !defined(__OPTIMIZE__)#warning  You must compile this file with the correct options!#warning  See the last lines of the source file.#error You must compile this driver with "-O".#endif#include <linux/config.h>#if defined(CONFIG_SMP) && ! defined(__SMP__)#define __SMP__#endif#if defined(MODULE) && defined(CONFIG_MODVERSIONS) && ! defined(MODVERSIONS)#define MODVERSIONS#endif#include <linux/version.h>#include <linux/module.h>#if LINUX_VERSION_CODE < 0x20300  &&  defined(MODVERSIONS)#include <linux/modversions.h>#endif#include <linux/kernel.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/malloc.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <asm/processor.h>		/* Processor type for cache alignment. */#include <asm/bitops.h>#include <asm/io.h>#if LINUX_VERSION_CODE >= 0x20300#include <linux/spinlock.h>#elif LINUX_VERSION_CODE >= 0x20200#include <asm/spinlock.h>#endif#ifdef INLINE_PCISCAN#include "k_compat.h"#else#include "pci-scan.h"#include "kern_compat.h"#endif#ifdef CONFIG_LEDMAN#include <linux/ledman.h>#endif#if (LINUX_VERSION_CODE >= 0x20100)  &&  defined(MODULE)char kernel_version[] = UTS_RELEASE;#endif/*				Theory of OperationI. Board CompatibilityThis device driver is designed for the RealTek RTL8129 series, the RealTekFast Ethernet controllers for PCI and CardBus.  This chip is used on manylow-end boards, sometimes with custom chip labels.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 block the Rx ring and cause us to dropframes.  It would be difficult to design a protocol stack where the databuffer could be recalled by the device driver.IIIb. Tx operationThe RTL8129 uses a fixed set of four Tx descriptors in register space.  Txframes must be 32 bit aligned.  Linux aligns the IP header on wordboundaries, and 14 byte ethernet header means that almost all frames willneed to be copied to an alignment buffer.  The driver statically allocatesalignment the four alignment buffers at open() time.IVb. Referenceshttp://www.realtek.com.tw/cn/cn.htmlhttp://cesdis.gsfc.nasa.gov/linux/misc/NWay.htmlIVc. Errata*/static void *rtl8139_probe1(struct pci_dev *pdev, void *init_dev,							long ioaddr, int irq, int chip_idx, int find_cnt);static int rtl_pwr_event(void *dev_instance, int event);enum chip_capability_flags {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02,							HAS_LNK_CHNG=0x04, HAS_DESC=0x08};#ifdef USE_IO_OPS#define RTL8139_IOTYPE  PCI_USES_MASTER|PCI_USES_IO |PCI_ADDR0#else#define RTL8139_IOTYPE  PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR1#endif#define RTL8129_CAPS  HAS_MII_XCVR#define RTL8139_CAPS  HAS_CHIP_XCVR|HAS_LNK_CHNG#define RTL8139D_CAPS  HAS_CHIP_XCVR|HAS_LNK_CHNG|HAS_DESC/* Note: Update the marked constant in _attach() if the RTL8139B entry moves.*/static struct pci_id_info pci_tbl[] = {	{"RealTek RTL8139C+, 64 bit high performance",	 { 0x813910ec, 0xffffffff, 0,0, 0x10, 0xff},	 RTL8139_IOTYPE, 0x80, RTL8139D_CAPS, },#if 1	/* Raw 8139 with no serial EEPRON will produce ID of 8129! */	{"RealTek RTL8139 Fast Ethernet", { 0x812910ec, 0xffffffff,},	 RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },#else	{"RealTek RTL8129 Fast Ethernet", { 0x812910ec, 0xffffffff,},	 RTL8139_IOTYPE, 0x80, RTL8129_CAPS, },#endif	{"RealTek RTL8139 Fast Ethernet", { 0x813910ec, 0xffffffff,},	 RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },	{"RealTek RTL8139B PCI/CardBus",  { 0x813810ec, 0xffffffff,},	 RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },	{"SMC1211TX EZCard 10/100 (RealTek RTL8139)", { 0x12111113, 0xffffffff,},	 RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },	{"Accton MPX5030 (RealTek RTL8139)", { 0x12111113, 0xffffffff,},	 RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },	{"D-Link DFE-538TX (RealTek RTL8139)", { 0x13001186, 0xffffffff,},	 RTL8139_IOTYPE, 0x80, RTL8139_CAPS, },	{0,},						/* 0 terminated list. */};struct drv_id_info rtl8139_drv_id = {	"realtek", PCI_HOTSWAP, PCI_CLASS_NETWORK_ETHERNET<<8, pci_tbl,	rtl8139_probe1, rtl_pwr_event };#ifndef USE_IO_OPS#undef inb#undef inw#undef inl#undef outb#undef outw#undef outl#define inb readb#define inw readw#define inl readl#define outb writeb#define outw writew#define outl writel#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. */	TxStatus0=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,	MII_BMCR=0x62, MII_BMSR=0x64, NWayAdvert=0x66, NWayLPAR=0x68,	NWayExpansion=0x6A,	/* Undocumented registers, but required for proper operation. */	FIFOTMS=0x70,	/* FIFO Control and test. */	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,};/* Twister tuning parameters from RealTek.   Completely undocumented, but required to tune bad links. */enum CSCRBits {	CSCR_LinkOKBit=0x0400, CSCR_LinkChangeBit=0x0800,	CSCR_LinkStatusBits=0x0f000, CSCR_LinkDownOffCmd=0x003c0,	CSCR_LinkDownCmd=0x0f3c0,};#define PARA78_default	0x78fa8388#define PARA7c_default	0xcb38de43 			/* param[0][3] */#define PARA7c_xxx		0xcb38de43unsigned long param[4][4]={	{0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},	{0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},	{0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},	{0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}};#define PRIV_ALIGN	15 	/* Desired alignment mask */struct rtl8129_private {	struct net_device *next_module;	void *priv_addr;					/* Unaligned address for kfree */	int chip_id;	int drv_flags;	struct pci_dev *pci_dev;	struct net_device_stats stats;	struct timer_list timer;	/* Media selection timer. */	unsigned char *rx_ring;	unsigned int cur_rx;		/* Index into the Rx buffer of next Rx pkt. */	unsigned int rx_buf_len;	/* Size (8K 16K 32K or 64KB) of the Rx ring */	unsigned int rx_config;	unsigned int cur_tx, dirty_tx, tx_flag;	unsigned long tx_full;				/* The Tx queue is full. */	/* 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 *tx_bufs;				/* Tx bounce buffer region. */	char phys[4];						/* MII device addresses. */	u16 advertising;					/* NWay media advertisement */	char twistie, twist_row, twist_col;	/* Twister tune state. */	unsigned int full_duplex:1;			/* Full-duplex operation requested. */	unsigned int duplex_lock:1;	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. */};MODULE_AUTHOR("Donald Becker <becker@scyld.com>");MODULE_DESCRIPTION("RealTek RTL8129/8139 Fast Ethernet driver");MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(multicast_filter_limit, "i");MODULE_PARM(max_interrupt_work, "i");MODULE_PARM(debug, "i");static int rtl8129_open(struct net_device *dev);static void rtl_hw_start(struct net_device *dev);static int read_eeprom(long ioaddr, int location, int addr_len);static int mdio_read(struct net_device *dev, int phy_id, int location);static void mdio_write(struct net_device *dev, int phy_id, int location, int val);static void rtl8129_timer(unsigned long data);static void rtl8129_tx_timeout(struct net_device *dev);static void rtl8129_init_ring(struct net_device *dev);static int rtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev);static int rtl8129_rx(struct net_device *dev);static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs);static int rtl8129_close(struct net_device *dev);static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static struct net_device_stats *rtl8129_get_stats(struct net_device *dev);static inline u32 ether_crc(int length, unsigned char *data);static void set_rx_mode(struct net_device *dev);/* A list of all installed RTL8129 devices, for removing the driver module. */static struct net_device *root_rtl8129_dev = NULL;#ifndef MODULEint rtl8139_probe(struct net_device *dev){	static int did_version = 0;			/* Already printed version info. */	if (debug > 0  &&  did_version++ == 0)		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);	return pci_drv_register(&rtl8139_drv_id, dev);}#endifstatic void *rtl8139_probe1(struct pci_dev *pdev, void *init_dev,							long ioaddr, int irq, int chip_idx, int found_cnt){	struct net_device *dev;	struct rtl8129_private *np;	void *priv_mem;	int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0;	dev = init_etherdev(init_dev, 0);	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",		   dev->name, pci_tbl[chip_idx].name, ioaddr, irq);	/* Bring the chip out of low-power mode. */	outb(0x00, ioaddr + Config1);#if 1	for (i = 0; i < 6; i++)		dev->dev_addr[i] = inb(ioaddr + MAC0 + i);#else	{		int addr_len = read_eeprom(ioaddr, 0, 8) == 0x8129 ? 8 : 6;		for (i = 0; i < 3; i++)			((u16 *)(dev->dev_addr))[i] =				le16_to_cpu(read_eeprom(ioaddr, i+7, addr_len));	}#endif	for (i = 0; i < 5; i++)		printk("%2.2x:", dev->dev_addr[i]);	printk("%2.2x.\n", dev->dev_addr[i]);	/* Make certain elements e.g. descriptor lists are aligned. */	priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);	/* Check for the very unlikely case of no memory. */	if (priv_mem == NULL)

⌨️ 快捷键说明

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