📄 r8169.c
字号:
/*========================================================================= r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver for Linux kernel 2.4.x. -------------------------------------------------------------------- History: Feb 4 2002 - created initially by ShuChen <shuchen@realtek.com.tw>. May 20 2002 - Add link status force-mode and TBI mode support.========================================================================= 1. [DEPRECATED: use ethtool instead] The media can be forced in 5 modes. Command: 'insmod r8169 media = SET_MEDIA' Ex: 'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex. SET_MEDIA can be: _10_Half = 0x01 _10_Full = 0x02 _100_Half = 0x04 _100_Full = 0x08 _1000_Full = 0x10 2. Support TBI mode.=========================================================================VERSION 1.1 <2002/10/4> The bit4:0 of MII register 4 is called "selector field", and have to be 00001b to indicate support of IEEE std 802.3 during NWay process of exchanging Link Code Word (FLP). VERSION 1.2 <2002/11/30> - Large style cleanup - Use ether_crc in stock kernel (linux/crc32.h) - Copy mc_filter setup code from 8139cp (includes an optimization, and avoids set_bit use)*/#include <linux/module.h>#include <linux/pci.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/delay.h>#include <linux/ethtool.h>#include <linux/mii.h>#include <linux/crc32.h>#include <linux/init.h>#include <linux/dma-mapping.h>#include <asm/io.h>#define RTL8169_VERSION "1.2"#define MODULENAME "r8169"#define RTL8169_DRIVER_NAME MODULENAME " Gigabit Ethernet driver " RTL8169_VERSION#define PFX MODULENAME ": "#ifdef RTL8169_DEBUG#define assert(expr) \ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n", \ #expr,__FILE__,__FUNCTION__,__LINE__); \ }#define dprintk(fmt, args...) do { printk(PFX fmt, ## args) } while (0)#else#define assert(expr) do {} while (0)#define dprintk(fmt, args...) do {} while (0)#endif /* RTL8169_DEBUG */#ifdef CONFIG_R8169_NAPI#define rtl8169_rx_skb netif_receive_skb#define rtl8169_rx_quota(count, quota) min(count, quota)#else#define rtl8169_rx_skb netif_rx#define rtl8169_rx_quota(count, quota) count#endif/* media options */#define MAX_UNITS 8static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };/* 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. */static int multicast_filter_limit = 32;/* MAC address length*/#define MAC_ADDR_LEN 6/* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/#define MAX_ETH_FRAME_SIZE 1536#define TX_FIFO_THRESH 256 /* In bytes */#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */#define RxPacketMaxSize 0x0800 /* Maximum size supported is 16K-1 */#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */#define R8169_NAPI_WEIGHT 64#define NUM_TX_DESC 64 /* Number of Tx descriptor registers */#define NUM_RX_DESC 256 /* Number of Rx descriptor registers */#define RX_BUF_SIZE 1536 /* Rx Buffer size */#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))#define RTL_MIN_IO_SIZE 0x80#define RTL8169_TX_TIMEOUT (6*HZ)#define RTL8169_PHY_TIMEOUT (10*HZ)/* write/read MMIO register */#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))#define RTL_R8(reg) readb (ioaddr + (reg))#define RTL_R16(reg) readw (ioaddr + (reg))#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))enum mac_version { RTL_GIGA_MAC_VER_B = 0x00, /* RTL_GIGA_MAC_VER_C = 0x03, */ RTL_GIGA_MAC_VER_D = 0x01, RTL_GIGA_MAC_VER_E = 0x02};enum phy_version { RTL_GIGA_PHY_VER_C = 0x03, /* PHY Reg 0x03 bit0-3 == 0x0000 */ RTL_GIGA_PHY_VER_D = 0x04, /* PHY Reg 0x03 bit0-3 == 0x0000 */ RTL_GIGA_PHY_VER_E = 0x05, /* PHY Reg 0x03 bit0-3 == 0x0000 */ RTL_GIGA_PHY_VER_F = 0x06, /* PHY Reg 0x03 bit0-3 == 0x0001 */ RTL_GIGA_PHY_VER_G = 0x07, /* PHY Reg 0x03 bit0-3 == 0x0002 */};#define _R(NAME,MAC,MASK) \ { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK }const static struct { const char *name; u8 mac_version; u32 RxConfigMask; /* Clears the bits supported by this chip */} rtl_chip_info[] = { _R("RTL8169", RTL_GIGA_MAC_VER_B, 0xff7e1880), _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_D, 0xff7e1880), _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_E, 0xff7e1880)};#undef _Rstatic struct pci_device_id rtl8169_pci_tbl[] = { {0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0,},};MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);static int rx_copybreak = 200;static int use_dac;enum RTL8169_registers { MAC0 = 0, /* Ethernet hardware address. */ MAR0 = 8, /* Multicast filter. */ TxDescStartAddrLow = 0x20, TxDescStartAddrHigh = 0x24, TxHDescStartAddrLow = 0x28, TxHDescStartAddrHigh = 0x2c, FLASH = 0x30, ERSR = 0x36, ChipCmd = 0x37, TxPoll = 0x38, IntrMask = 0x3C, IntrStatus = 0x3E, TxConfig = 0x40, RxConfig = 0x44, RxMissed = 0x4C, Cfg9346 = 0x50, Config0 = 0x51, Config1 = 0x52, Config2 = 0x53, Config3 = 0x54, Config4 = 0x55, Config5 = 0x56, MultiIntr = 0x5C, PHYAR = 0x60, TBICSR = 0x64, TBI_ANAR = 0x68, TBI_LPAR = 0x6A, PHYstatus = 0x6C, RxMaxSize = 0xDA, CPlusCmd = 0xE0, RxDescAddrLow = 0xE4, RxDescAddrHigh = 0xE8, EarlyTxThres = 0xEC, FuncEvent = 0xF0, FuncEventMask = 0xF4, FuncPresetState = 0xF8, FuncForceEvent = 0xFC,};enum RTL8169_register_content { /*InterruptStatusBits */ SYSErr = 0x8000, PCSTimeout = 0x4000, SWInt = 0x0100, TxDescUnavail = 0x80, RxFIFOOver = 0x40, LinkChg = 0x20, RxOverflow = 0x10, TxErr = 0x08, TxOK = 0x04, RxErr = 0x02, RxOK = 0x01, /*RxStatusDesc */ RxRES = 0x00200000, RxCRC = 0x00080000, RxRUNT = 0x00100000, RxRWT = 0x00400000, /*ChipCmdBits */ CmdReset = 0x10, CmdRxEnb = 0x08, CmdTxEnb = 0x04, RxBufEmpty = 0x01, /*Cfg9346Bits */ Cfg9346_Lock = 0x00, Cfg9346_Unlock = 0xC0, /*rx_mode_bits */ AcceptErr = 0x20, AcceptRunt = 0x10, AcceptBroadcast = 0x08, AcceptMulticast = 0x04, AcceptMyPhys = 0x02, AcceptAllPhys = 0x01, /*RxConfigBits */ RxCfgFIFOShift = 13, RxCfgDMAShift = 8, /*TxConfigBits */ TxInterFrameGapShift = 24, TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ /* TBICSR p.28 */ TBIReset = 0x80000000, TBILoopback = 0x40000000, TBINwEnable = 0x20000000, TBINwRestart = 0x10000000, TBILinkOk = 0x02000000, TBINwComplete = 0x01000000, /* CPlusCmd p.31 */ RxVlan = (1 << 6), RxChkSum = (1 << 5), PCIDAC = (1 << 4), PCIMulRW = (1 << 3), /*rtl8169_PHYstatus */ TBI_Enable = 0x80, TxFlowCtrl = 0x40, RxFlowCtrl = 0x20, _1000bpsF = 0x10, _100bps = 0x08, _10bps = 0x04, LinkStatus = 0x02, FullDup = 0x01, /*GIGABIT_PHY_registers */ PHY_CTRL_REG = 0, PHY_STAT_REG = 1, PHY_AUTO_NEGO_REG = 4, PHY_1000_CTRL_REG = 9, /*GIGABIT_PHY_REG_BIT */ PHY_Restart_Auto_Nego = 0x0200, PHY_Enable_Auto_Nego = 0x1000, //PHY_STAT_REG = 1; PHY_Auto_Neco_Comp = 0x0020, //PHY_AUTO_NEGO_REG = 4; PHY_Cap_10_Half = 0x0020, PHY_Cap_10_Full = 0x0040, PHY_Cap_100_Half = 0x0080, PHY_Cap_100_Full = 0x0100, //PHY_1000_CTRL_REG = 9; PHY_Cap_1000_Full = 0x0200, PHY_Cap_Null = 0x0, /*_MediaType*/ _10_Half = 0x01, _10_Full = 0x02, _100_Half = 0x04, _100_Full = 0x08, _1000_Full = 0x10, /*_TBICSRBit*/ TBILinkOK = 0x02000000,};enum _DescStatusBit { OWNbit = 0x80000000, EORbit = 0x40000000, FSbit = 0x20000000, LSbit = 0x10000000,};#define RsvdMask 0x3fffc000struct TxDesc { u32 status; u32 vlan_tag; u64 addr;};struct RxDesc { u32 status; u32 vlan_tag; u64 addr;};struct rtl8169_private { void *mmio_addr; /* memory map physical address */ struct pci_dev *pci_dev; /* Index of PCI device */ struct net_device_stats stats; /* statistics of net device */ spinlock_t lock; /* spin lock flag */ int chipset; int mac_version; int phy_version; u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */ u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */ u32 dirty_rx; u32 dirty_tx; struct TxDesc *TxDescArray; /* 256-aligned Tx descriptor ring */ struct RxDesc *RxDescArray; /* 256-aligned Rx descriptor ring */ dma_addr_t TxPhyAddr; dma_addr_t RxPhyAddr; struct sk_buff *Rx_skbuff[NUM_RX_DESC]; /* Rx data buffers */ struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Tx data buffers */ struct timer_list timer; u16 cp_cmd; u16 intr_mask; int phy_auto_nego_reg; int phy_1000_ctrl_reg; int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex); void (*get_settings)(struct net_device *, struct ethtool_cmd *); void (*phy_reset_enable)(void *); unsigned int (*phy_reset_pending)(void *); unsigned int (*link_ok)(void *);};MODULE_AUTHOR("Realtek");MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(rx_copybreak, "i");MODULE_PARM(use_dac, "i");MODULE_PARM_DESC(use_dac, "Enable PCI DAC. Unsafe on 32 bit PCI slot.");MODULE_LICENSE("GPL");static int rtl8169_open(struct net_device *dev);static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev);static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs);static int rtl8169_init_ring(struct net_device *dev);static void rtl8169_hw_start(struct net_device *dev);static int rtl8169_close(struct net_device *dev);static void rtl8169_set_rx_mode(struct net_device *dev);static void rtl8169_tx_timeout(struct net_device *dev);static struct net_device_stats *rtl8169_get_stats(struct net_device *netdev);#ifdef CONFIG_R8169_NAPIstatic int rtl8169_poll(struct net_device *dev, int *budget);#endifstatic const u16 rtl8169_intr_mask = SYSErr | LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;static const u16 rtl8169_napi_event = RxOK | RxOverflow | RxFIFOOver | TxOK | TxErr;static const unsigned int rtl8169_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);#define PHY_Cap_10_Half_Or_Less PHY_Cap_10_Half#define PHY_Cap_10_Full_Or_Less PHY_Cap_10_Full | PHY_Cap_10_Half_Or_Less#define PHY_Cap_100_Half_Or_Less PHY_Cap_100_Half | PHY_Cap_10_Full_Or_Less#define PHY_Cap_100_Full_Or_Less PHY_Cap_100_Full | PHY_Cap_100_Half_Or_Lessstatic void mdio_write(void *ioaddr, int RegAddr, int value){ int i; RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value); udelay(1000); for (i = 2000; i > 0; i--) { // Check if the RTL8169 has completed writing to the specified MII register if (!(RTL_R32(PHYAR) & 0x80000000)) break; udelay(100); }}static int mdio_read(void *ioaddr, int RegAddr){ int i, value = -1; RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16); udelay(1000); for (i = 2000; i > 0; i--) { // Check if the RTL8169 has completed retrieving data from the specified MII register if (RTL_R32(PHYAR) & 0x80000000) { value = (int) (RTL_R32(PHYAR) & 0xFFFF); break; } udelay(100); } return value;}static unsigned int rtl8169_tbi_reset_pending(void *ioaddr){ return RTL_R32(TBICSR) & TBIReset;}static unsigned int rtl8169_xmii_reset_pending(void *ioaddr){ return mdio_read(ioaddr, 0) & 0x8000;}static unsigned int rtl8169_tbi_link_ok(void *ioaddr){ return RTL_R32(TBICSR) & TBILinkOk;}static unsigned int rtl8169_xmii_link_ok(void *ioaddr){ return RTL_R8(PHYstatus) & LinkStatus;}static void rtl8169_tbi_reset_enable(void *ioaddr){ RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);}static void rtl8169_xmii_reset_enable(void *ioaddr){ unsigned int val; val = (mdio_read(ioaddr, PHY_CTRL_REG) | 0x8000) & 0xffff; mdio_write(ioaddr, PHY_CTRL_REG, val);}static void rtl8169_check_link_status(struct net_device *dev, struct rtl8169_private *tp, void *ioaddr){ unsigned long flags; spin_lock_irqsave(&tp->lock, flags); if (tp->link_ok(ioaddr)) { netif_carrier_on(dev); printk(KERN_INFO PFX "%s: link up\n", dev->name); } else netif_carrier_off(dev); spin_unlock_irqrestore(&tp->lock, flags);}static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex){ struct { u16 speed; u8 duplex; u8 autoneg; u8 media; } link_settings[] = { { SPEED_10, DUPLEX_HALF, AUTONEG_DISABLE, _10_Half }, { SPEED_10, DUPLEX_FULL, AUTONEG_DISABLE, _10_Full }, { SPEED_100, DUPLEX_HALF, AUTONEG_DISABLE, _100_Half }, { SPEED_100, DUPLEX_FULL, AUTONEG_DISABLE, _100_Full }, { SPEED_1000, DUPLEX_FULL, AUTONEG_DISABLE, _1000_Full }, /* Make TBI happy */ { SPEED_1000, DUPLEX_FULL, AUTONEG_ENABLE, 0xff } }, *p; unsigned char option; option = ((idx < MAX_UNITS) && (idx >= 0)) ? media[idx] : 0xff; if ((option != 0xff) && !idx) printk(KERN_WARNING PFX "media option is deprecated.\n"); for (p = link_settings; p->media != 0xff; p++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -