Commit ed90d9a9 authored by Jeff Garzik's avatar Jeff Garzik

[netdrvr] add "r8169", new driver for Realtek 8169 gigabit ethernet

parent 648532a4
...@@ -1719,6 +1719,17 @@ config YELLOWFIN ...@@ -1719,6 +1719,17 @@ config YELLOWFIN
say M here and read <file:Documentation/modules.txt>. This is say M here and read <file:Documentation/modules.txt>. This is
recommended. The module will be called yellowfin.o. recommended. The module will be called yellowfin.o.
config R8169
tristate "Realtek 8169 gigabit ethernet support"
depends on PCI
---help---
Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter.
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. This is
recommended. The module will be called r8169.o.
config SK98LIN config SK98LIN
tristate "SysKonnect SK-98xx support" tristate "SysKonnect SK-98xx support"
depends on PCI depends on PCI
......
...@@ -182,6 +182,7 @@ obj-$(CONFIG_MACMACE) += macmace.o ...@@ -182,6 +182,7 @@ obj-$(CONFIG_MACMACE) += macmace.o
obj-$(CONFIG_MAC89x0) += mac89x0.o obj-$(CONFIG_MAC89x0) += mac89x0.o
obj-$(CONFIG_TUN) += tun.o obj-$(CONFIG_TUN) += tun.o
obj-$(CONFIG_DL2K) += dl2k.o obj-$(CONFIG_DL2K) += dl2k.o
obj-$(CONFIG_R8169) += r8169.o
obj-$(CONFIG_ARCH_ACORN) += ../acorn/net/ obj-$(CONFIG_ARCH_ACORN) += ../acorn/net/
obj-$(CONFIG_NET_FC) += fc/ obj-$(CONFIG_NET_FC) += fc/
......
...@@ -36,6 +36,7 @@ obj-$(CONFIG_TULIP) += crc32.o ...@@ -36,6 +36,7 @@ obj-$(CONFIG_TULIP) += crc32.o
obj-$(CONFIG_VIA_RHINE) += crc32.o obj-$(CONFIG_VIA_RHINE) += crc32.o
obj-$(CONFIG_YELLOWFIN) += crc32.o obj-$(CONFIG_YELLOWFIN) += crc32.o
obj-$(CONFIG_WINBOND_840) += crc32.o obj-$(CONFIG_WINBOND_840) += crc32.o
obj-$(CONFIG_R8169) += crc32.o
# These rely on drivers/net/7990.o which requires crc32.o # These rely on drivers/net/7990.o which requires crc32.o
......
/*
=========================================================================
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. 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.
//=========================================================================
RTL8169_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).
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#define RTL8169_VERSION "1.1"
#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__); \
}
#else
#define assert(expr) do {} while (0)
#endif // end of #ifdef RTL8169_DEBUG
/* media options */
#define MAX_UNITS 8
static 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 NUM_TX_DESC 64 /* Number of Tx descriptor registers*/
#define NUM_RX_DESC 64 /* Number of Rx descriptor registers*/
#define RX_BUF_SIZE 1536 /* Rx Buffer size */
#define RTL_MIN_IO_SIZE 0x80
#define TX_TIMEOUT (6*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)))
static struct {
const char *name;
} board_info[] __devinitdata = {
{ "RealTek RTL8169 Gigabit Ethernet"},
};
static struct pci_device_id rtl8169_pci_tbl[] __devinitdata = {
{ 0x10ec, 0x8169, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{0,},
};
MODULE_DEVICE_TABLE (pci, rtl8169_pci_tbl);
enum RTL8169_registers {
MAC0 = 0, /* Ethernet hardware address. */
MAR0 = 8, /* Multicast filter. */
TxDescStartAddr = 0x20,
TxHDescStartAddr= 0x28,
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,
RxDescStartAddr = 0xE4,
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,
RxUnderrun = 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 */
/*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,
};
const static struct {
const char *name;
u8 version; /* depend on RTL8169 docs */
u32 RxConfigMask; /* should clear the bits supported by this chip */
} rtl_chip_info[] = {
{ "RTL-8169",
0x00,
0xff7e1880,
},
};
enum _DescStatusBit {
OWNbit = 0x80000000,
EORbit = 0x40000000,
FSbit = 0x20000000,
LSbit = 0x10000000,
};
struct TxDesc {
u32 status;
u32 vlan_tag;
u32 buf_addr;
u32 buf_Haddr;
};
struct RxDesc {
u32 status;
u32 vlan_tag;
u32 buf_addr;
u32 buf_Haddr;
};
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;
unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
unsigned long dirty_tx;
unsigned char *TxDescArrays; /* Index of Tx Descriptor buffer */
unsigned char *RxDescArrays; /* Index of Rx Descriptor buffer */
struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */
struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */
unsigned char *RxBufferRings; /* Index of Rx Buffer */
unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */
struct sk_buff *Tx_skbuff[NUM_TX_DESC]; /* Index of Transmit data buffer */
};
MODULE_AUTHOR ("Realtek");
MODULE_DESCRIPTION ("RealTek RTL-8169 Gigabit Ethernet driver");
MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i");
static int rtl8169_open (struct net_device *dev);
static int rtl8169_start_xmit (struct sk_buff *skb, struct net_device *dev);
static void rtl8169_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
static void 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 inline u32 ether_crc (int length, unsigned char *data);
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);
static const u16 rtl8169_intr_mask = SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
TxErr | TxOK | RxErr | RxOK ;
static const unsigned int rtl8169_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift) ;
//=================================================================
// PHYAR
// bit Symbol
// 31 Flag
// 30-21 reserved
// 20-16 5-bit GMII/MII register address
// 15-0 16-bit GMII/MII register data
//=================================================================
void RTL8169_WRITE_GMII_REG( 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;
}
else{
udelay(100);
}// end of if( ! (RTL_R32(PHYAR)&0x80000000) )
}// end of for() loop
}
//=================================================================
int RTL8169_READ_GMII_REG( 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;
}
else{
udelay(100);
}// end of if( RTL_R32(PHYAR) & 0x80000000 )
}// end of for() loop
return value;
}
//======================================================================================================
//======================================================================================================
static int __devinit rtl8169_init_board ( struct pci_dev *pdev, struct net_device **dev_out, void **ioaddr_out)
{
void *ioaddr = NULL;
struct net_device *dev;
struct rtl8169_private *tp;
int rc, i;
unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
u32 tmp;
assert (pdev != NULL);
assert (ioaddr_out != NULL);
*ioaddr_out = NULL;
*dev_out = NULL;
// dev zeroed in init_etherdev
dev = init_etherdev (NULL, sizeof (*tp));
if (dev == NULL) {
printk (KERN_ERR PFX "unable to alloc new ethernet\n");
return -ENOMEM;
}
SET_MODULE_OWNER(dev);
tp = dev->priv;
// enable device (incl. PCI PM wakeup and hotplug setup)
rc = pci_enable_device (pdev);
if (rc)
goto err_out;
mmio_start = pci_resource_start (pdev, 1);
mmio_end = pci_resource_end (pdev, 1);
mmio_flags = pci_resource_flags (pdev, 1);
mmio_len = pci_resource_len (pdev, 1);
// make sure PCI base addr 1 is MMIO
if (!(mmio_flags & IORESOURCE_MEM)) {
printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
// check for weird/broken PCI region reporting
if ( mmio_len < RTL_MIN_IO_SIZE ) {
printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
rc = -ENODEV;
goto err_out;
}
rc = pci_request_regions (pdev, dev->name);
if (rc)
goto err_out;
// enable PCI bus-mastering
pci_set_master (pdev);
// ioremap MMIO region
ioaddr = ioremap (mmio_start, mmio_len);
if (ioaddr == NULL) {
printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");
rc = -EIO;
goto err_out_free_res;
}
// Soft reset the chip.
RTL_W8 ( ChipCmd, CmdReset);
// Check that the chip has finished the reset.
for (i = 1000; i > 0; i--)
if ( (RTL_R8(ChipCmd) & CmdReset) == 0)
break;
else
udelay (10);
// identify chip attached to board
tmp = RTL_R32 (TxConfig);
tmp = ( (tmp&0x7c000000) + ( (tmp&0x00800000)<<2 ) )>>24;
for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--)
if (tmp == rtl_chip_info[i].version) {
tp->chipset = i;
goto match;
}
//if unknown chip, assume array element #0, original RTL-8169 in this case
printk (KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming RTL-8169\n", pdev->slot_name);
printk (KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n", pdev->slot_name, (unsigned long)RTL_R32(TxConfig));
tp->chipset = 0;
match:
*ioaddr_out = ioaddr;
*dev_out = dev;
return 0;
//err_out_iounmap:
assert (ioaddr > 0);
iounmap (ioaddr);
err_out_free_res:
pci_release_regions (pdev);
err_out:
unregister_netdev (dev);
kfree (dev);
return rc;
}
//======================================================================================================
static int __devinit rtl8169_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct net_device *dev = NULL;
struct rtl8169_private *tp = NULL;
void *ioaddr = NULL;
static int board_idx = -1;
static int printed_version = 0;
int i;
int option = -1, Cap10_100 = 0, Cap1000 = 0;
assert (pdev != NULL);
assert (ent != NULL);
board_idx++;
if (!printed_version) {
printk (KERN_INFO RTL8169_DRIVER_NAME " loaded\n");
printed_version = 1;
}
i = rtl8169_init_board (pdev, &dev, &ioaddr);
if (i < 0) {
return i;
}
tp = dev->priv;
assert (ioaddr != NULL);
assert (dev != NULL);
assert (tp != NULL);
// Get MAC address //
for (i = 0; i < MAC_ADDR_LEN ; i++){
dev->dev_addr[i] = RTL_R8( MAC0 + i );
}
dev->open = rtl8169_open;
dev->hard_start_xmit = rtl8169_start_xmit;
dev->get_stats = rtl8169_get_stats;
dev->stop = rtl8169_close;
dev->tx_timeout = rtl8169_tx_timeout;
dev->set_multicast_list = rtl8169_set_rx_mode;
dev->watchdog_timeo = TX_TIMEOUT;
dev->irq = pdev->irq;
dev->base_addr = (unsigned long) ioaddr;
// dev->do_ioctl = mii_ioctl;
tp = dev->priv; // private data //
tp->pci_dev = pdev;
tp->mmio_addr = ioaddr;
printk (KERN_DEBUG "%s: Identified chip type is '%s'.\n",dev->name,rtl_chip_info[tp->chipset].name);
spin_lock_init (&tp->lock);
pdev->driver_data = dev;
printk (KERN_INFO "%s: %s at 0x%lx, "
"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
"IRQ %d\n",
dev->name,
board_info[ent->driver_data].name,
dev->base_addr,
dev->dev_addr[0], dev->dev_addr[1],
dev->dev_addr[2], dev->dev_addr[3],
dev->dev_addr[4], dev->dev_addr[5],
dev->irq);
// if TBI is not endbled
if( !(RTL_R8(PHYstatus) & TBI_Enable) ){
int val = RTL8169_READ_GMII_REG( ioaddr, PHY_AUTO_NEGO_REG );
option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
// Force RTL8169 in 10/100/1000 Full/Half mode.
if( option > 0 ){
printk(KERN_INFO "%s: Force-mode Enabled.\n", dev->name);
Cap10_100 = 0, Cap1000 = 0;
switch( option ){
case _10_Half: Cap10_100 = PHY_Cap_10_Half; Cap1000 = PHY_Cap_Null; break;
case _10_Full: Cap10_100 = PHY_Cap_10_Full; Cap1000 = PHY_Cap_Null; break;
case _100_Half: Cap10_100 = PHY_Cap_100_Half; Cap1000 = PHY_Cap_Null; break;
case _100_Full: Cap10_100 = PHY_Cap_100_Full; Cap1000 = PHY_Cap_Null; break;
case _1000_Full:Cap10_100 = PHY_Cap_Null; Cap1000 = PHY_Cap_1000_Full;break;
default: break;
}
RTL8169_WRITE_GMII_REG( ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | ( val&0x1F ) ); //leave PHY_AUTO_NEGO_REG bit4:0 unchanged
RTL8169_WRITE_GMII_REG( ioaddr, PHY_1000_CTRL_REG, Cap1000 );
}
else{
printk(KERN_INFO "%s: Auto-negotiation Enabled.\n", dev->name);
// enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
RTL8169_WRITE_GMII_REG( ioaddr, PHY_AUTO_NEGO_REG,
PHY_Cap_10_Half | PHY_Cap_10_Full | PHY_Cap_100_Half | PHY_Cap_100_Full | ( val&0x1F ) );
// enable 1000 Full Mode
RTL8169_WRITE_GMII_REG( ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full );
}// end of if( option > 0 )
// Enable auto-negotiation and restart auto-nigotiation
RTL8169_WRITE_GMII_REG( ioaddr, PHY_CTRL_REG, PHY_Enable_Auto_Nego | PHY_Restart_Auto_Nego );
udelay(100);
// wait for auto-negotiation process
for( i = 10000; i > 0; i-- ){
//check if auto-negotiation complete
if( RTL8169_READ_GMII_REG(ioaddr, PHY_STAT_REG) & PHY_Auto_Neco_Comp ){
udelay(100);
option = RTL_R8(PHYstatus);
if( option & _1000bpsF ){
printk(KERN_INFO "%s: 1000Mbps Full-duplex operation.\n", dev->name);
}
else{
printk(KERN_INFO "%s: %sMbps %s-duplex operation.\n", dev->name,
(option & _100bps) ? "100" : "10", (option & FullDup) ? "Full" : "Half" );
}
break;
}
else{
udelay(100);
}// end of if( RTL8169_READ_GMII_REG(ioaddr, 1) & 0x20 )
}// end for-loop to wait for auto-negotiation process
}// end of TBI is not enabled
else{
udelay(100);
printk(KERN_INFO "%s: 1000Mbps Full-duplex operation, TBI Link %s!\n",
dev->name, (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed" );
}// end of TBI is not enabled
return 0;
}
//======================================================================================================
static void __devexit rtl8169_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pdev->driver_data;
struct rtl8169_private *tp = (struct rtl8169_private *) (dev->priv);
assert (dev != NULL);
assert (tp != NULL);
unregister_netdev (dev);
iounmap (tp->mmio_addr);
pci_release_regions (pdev);
// poison memory before freeing
memset (dev, 0xBC, sizeof (struct net_device) + sizeof (struct rtl8169_private));
kfree (dev);
pdev->driver_data = NULL;
}
//======================================================================================================
static int rtl8169_open (struct net_device *dev)
{
struct rtl8169_private *tp = dev->priv;
int retval;
u8 diff;
u32 TxPhyAddr, RxPhyAddr;
retval = request_irq (dev->irq, rtl8169_interrupt, SA_SHIRQ, dev->name, dev);
if (retval) {
return retval;
}
//////////////////////////////////////////////////////////////////////////////
tp->TxDescArrays = kmalloc( NUM_TX_DESC * sizeof(struct TxDesc)+256 , GFP_KERNEL );
// Tx Desscriptor needs 256 bytes alignment;
TxPhyAddr = virt_to_bus(tp->TxDescArrays);
diff = 256 - (TxPhyAddr-((TxPhyAddr >> 8)<< 8));
TxPhyAddr += diff;
tp->TxDescArray = (struct TxDesc *)(tp->TxDescArrays + diff);
tp->RxDescArrays = kmalloc( NUM_RX_DESC * sizeof(struct RxDesc)+256 , GFP_KERNEL );
// Rx Desscriptor needs 256 bytes alignment;
RxPhyAddr = virt_to_bus(tp->RxDescArrays);
diff = 256 - (RxPhyAddr-((RxPhyAddr >> 8)<< 8));
RxPhyAddr += diff;
tp->RxDescArray = (struct RxDesc *)(tp->RxDescArrays + diff);
if ( tp->TxDescArrays == NULL || tp->RxDescArrays == NULL ) {
printk(KERN_INFO"Allocate RxDescArray or TxDescArray failed\n");
free_irq(dev->irq, dev);
if (tp->TxDescArrays) kfree(tp->TxDescArrays);
if (tp->RxDescArrays) kfree(tp->RxDescArrays);
return -ENOMEM;
}
tp->RxBufferRings = kmalloc( RX_BUF_SIZE*NUM_RX_DESC, GFP_KERNEL );
if( tp->RxBufferRings == NULL ){
printk( KERN_INFO"Allocate RxBufferRing failed\n" );
}
//////////////////////////////////////////////////////////////////////////////
rtl8169_init_ring (dev);
rtl8169_hw_start (dev);
return 0;
}//end of rtl8169_open (struct net_device *dev)
//======================================================================================================
static void rtl8169_hw_start (struct net_device *dev)
{
struct rtl8169_private *tp = dev->priv;
void *ioaddr = tp->mmio_addr;
u32 i;
/* Soft reset the chip. */
RTL_W8 ( ChipCmd, CmdReset);
/* Check that the chip has finished the reset. */
for (i = 1000; i > 0; i--){
if ((RTL_R8( ChipCmd ) & CmdReset) == 0) break;
else udelay (10);
}
RTL_W8 ( Cfg9346, Cfg9346_Unlock);
RTL_W8 ( ChipCmd, CmdTxEnb | CmdRxEnb);
RTL_W8 ( EarlyTxThres, EarlyTxThld);
// For gigabit rtl8169
RTL_W16 ( RxMaxSize, RxPacketMaxSize );
// Set Rx Config register
i = rtl8169_rx_config | ( RTL_R32( RxConfig ) & rtl_chip_info[tp->chipset].RxConfigMask);
RTL_W32 ( RxConfig, i);
/* Set DMA burst size and Interframe Gap Time */
RTL_W32 ( TxConfig, (TX_DMA_BURST << TxDMAShift) | (InterFrameGap << TxInterFrameGapShift) );
tp->cur_rx = 0;
RTL_W32 ( TxDescStartAddr, virt_to_bus(tp->TxDescArray));
RTL_W32 ( RxDescStartAddr, virt_to_bus(tp->RxDescArray));
RTL_W8 ( Cfg9346, Cfg9346_Lock );
udelay (10);
RTL_W32 ( RxMissed, 0 );
rtl8169_set_rx_mode (dev);
/* no early-rx interrupts */
RTL_W16 ( MultiIntr, RTL_R16(MultiIntr) & 0xF000);
/* Enable all known interrupts by setting the interrupt mask. */
RTL_W16 ( IntrMask, rtl8169_intr_mask);
netif_start_queue (dev);
}//end of rtl8169_hw_start (struct net_device *dev)
//======================================================================================================
static void rtl8169_init_ring (struct net_device *dev)
{
struct rtl8169_private *tp = dev->priv;
int i;
tp->cur_rx = 0;
tp->cur_tx = 0;
tp->dirty_tx = 0;
memset(tp->TxDescArray, 0x0, NUM_TX_DESC*sizeof(struct TxDesc));
memset(tp->RxDescArray, 0x0, NUM_RX_DESC*sizeof(struct RxDesc));
for (i=0 ; i<NUM_TX_DESC ; i++){
tp->Tx_skbuff[i]=NULL;
}
for (i=0; i <NUM_RX_DESC; i++) {
if(i==(NUM_RX_DESC-1))
tp->RxDescArray[i].status = (OWNbit | EORbit) + RX_BUF_SIZE;
else
tp->RxDescArray[i].status = OWNbit + RX_BUF_SIZE;
tp->RxBufferRing[i]= &(tp->RxBufferRings[i*RX_BUF_SIZE]);
tp->RxDescArray[i].buf_addr=virt_to_bus(tp->RxBufferRing[i]);
}
}
//======================================================================================================
static void rtl8169_tx_clear (struct rtl8169_private *tp)
{
int i;
tp->cur_tx = 0;
for ( i = 0 ; i < NUM_TX_DESC ; i++ ){
if ( tp->Tx_skbuff[i] != NULL ) {
dev_kfree_skb ( tp->Tx_skbuff[i] );
tp->Tx_skbuff[i] = NULL;
tp->stats.tx_dropped++;
}
}
}
//======================================================================================================
static void rtl8169_tx_timeout (struct net_device *dev)
{
struct rtl8169_private *tp = dev->priv;
void *ioaddr = tp->mmio_addr;
u8 tmp8;
/* disable Tx, if not already */
tmp8 = RTL_R8( ChipCmd );
if (tmp8 & CmdTxEnb){
RTL_W8 ( ChipCmd, tmp8 & ~CmdTxEnb);
}
/* Disable interrupts by clearing the interrupt mask. */
RTL_W16 ( IntrMask, 0x0000);
/* Stop a shared interrupt from scavenging while we are. */
spin_lock_irq (&tp->lock);
rtl8169_tx_clear (tp);
spin_unlock_irq (&tp->lock);
/* ...and finally, reset everything */
rtl8169_hw_start (dev);
netif_wake_queue (dev);
}
//======================================================================================================
static int rtl8169_start_xmit (struct sk_buff *skb, struct net_device *dev)
{
struct rtl8169_private *tp = dev->priv;
void *ioaddr = tp->mmio_addr;
int entry = tp->cur_tx % NUM_TX_DESC;
spin_lock_irq (&tp->lock);
if( (tp->TxDescArray[entry].status & OWNbit)==0 ){
tp->Tx_skbuff[entry] = skb;
tp->TxDescArray[entry].buf_addr = virt_to_bus(skb->data);
if( entry != (NUM_TX_DESC-1) )
tp->TxDescArray[entry].status = (OWNbit | FSbit | LSbit) | ( (skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN);
else
tp->TxDescArray[entry].status = (OWNbit | EORbit | FSbit | LSbit) | ( (skb->len > ETH_ZLEN) ? skb->len : ETH_ZLEN);
RTL_W8 ( TxPoll, 0x40); //set polling bit
dev->trans_start = jiffies;
tp->cur_tx++;
}//end of if( (tp->TxDescArray[entry].status & 0x80000000)==0 )
spin_unlock_irq (&tp->lock);
if ( (tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx ){
netif_stop_queue (dev);
}
return 0;
}
//======================================================================================================
static void rtl8169_tx_interrupt (struct net_device *dev, struct rtl8169_private *tp, void *ioaddr)
{
unsigned long dirty_tx, tx_left=0;
int entry = tp->cur_tx % NUM_TX_DESC;
assert (dev != NULL);
assert (tp != NULL);
assert (ioaddr != NULL);
dirty_tx = tp->dirty_tx;
tx_left = tp->cur_tx - dirty_tx;
while (tx_left > 0) {
if( (tp->TxDescArray[entry].status & OWNbit) == 0 ){
dev_kfree_skb_irq( tp->Tx_skbuff[dirty_tx % NUM_TX_DESC] );
tp->Tx_skbuff[dirty_tx % NUM_TX_DESC] = NULL;
tp->stats.tx_packets++;
dirty_tx++;
tx_left--;
entry++;
}
}
if (tp->dirty_tx != dirty_tx) {
tp->dirty_tx = dirty_tx;
if (netif_queue_stopped (dev))
netif_wake_queue (dev);
}
}
//======================================================================================================
static void rtl8169_rx_interrupt (struct net_device *dev, struct rtl8169_private *tp, void *ioaddr)
{
int cur_rx;
struct sk_buff *skb;
int pkt_size = 0 ;
assert (dev != NULL);
assert (tp != NULL);
assert (ioaddr != NULL);
cur_rx = tp->cur_rx;
while ( (tp->RxDescArray[cur_rx].status & OWNbit)== 0) {
if( tp->RxDescArray[cur_rx].status & RxRES ){
printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
tp->stats.rx_errors++;
if (tp->RxDescArray[cur_rx].status & (RxRWT|RxRUNT) )
tp->stats.rx_length_errors++;
if (tp->RxDescArray[cur_rx].status & RxCRC)
tp->stats.rx_crc_errors++;
}
else{
pkt_size=(int)(tp->RxDescArray[cur_rx].status & 0x00001FFF)-4;
skb = dev_alloc_skb(pkt_size + 2);
if (skb != NULL) {
skb->dev = dev;
skb_reserve (skb, 2); // 16 byte align the IP fields. //
eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx], pkt_size, 0);
skb_put(skb, pkt_size);
skb->protocol = eth_type_trans(skb, dev);
netif_rx (skb);
if( cur_rx == (NUM_RX_DESC-1) )
tp->RxDescArray[cur_rx].status = (OWNbit | EORbit) + RX_BUF_SIZE;
else
tp->RxDescArray[cur_rx].status = OWNbit + RX_BUF_SIZE;
tp->RxDescArray[cur_rx].buf_addr = virt_to_bus( tp->RxBufferRing[cur_rx] );
dev->last_rx = jiffies;
tp->stats.rx_bytes += pkt_size;
tp->stats.rx_packets++;
}
else{
printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n",dev->name);
/* We should check that some rx space is free.
If not, free one and mark stats->rx_dropped++. */
tp->stats.rx_dropped++;
}// end of if (skb != NULL)
}// end of if( tp->RxDescArray[cur_rx].status & RxRES )
cur_rx = (cur_rx +1) % NUM_RX_DESC;
}// end of while ( (tp->RxDescArray[cur_rx].status & 0x80000000)== 0)
tp->cur_rx = cur_rx;
}
//======================================================================================================
/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
static void rtl8169_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct rtl8169_private *tp = dev->priv;
int boguscnt = max_interrupt_work;
void *ioaddr = tp->mmio_addr;
int status = 0;
do {
status = RTL_R16(IntrStatus);
/* h/w no longer present (hotplug?) or major error, bail */
if (status == 0xFFFF)
break;
/*
if (status & RxUnderrun)
link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit;
*/
RTL_W16( IntrStatus, (status & RxFIFOOver) ? (status | RxOverflow) : status);
if ( (status & ( SYSErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK) ) == 0 )
break;
// Rx interrupt
if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver)){
rtl8169_rx_interrupt (dev, tp, ioaddr);
}
// Tx interrupt
if (status & (TxOK | TxErr)) {
spin_lock (&tp->lock);
rtl8169_tx_interrupt (dev, tp, ioaddr);
spin_unlock (&tp->lock);
}
boguscnt--;
} while (boguscnt > 0);
if (boguscnt <= 0) {
printk (KERN_WARNING "%s: Too much work at interrupt!\n", dev->name);
/* Clear all interrupt sources. */
RTL_W16( IntrStatus, 0xffff);
}
}
//======================================================================================================
static int rtl8169_close (struct net_device *dev)
{
struct rtl8169_private *tp = dev->priv;
void *ioaddr = tp->mmio_addr;
int i;
netif_stop_queue (dev);
spin_lock_irq (&tp->lock);
/* Stop the chip's Tx and Rx DMA processes. */
RTL_W8 ( ChipCmd, 0x00);
/* Disable interrupts by clearing the interrupt mask. */
RTL_W16 ( IntrMask, 0x0000);
/* Update the error counts. */
tp->stats.rx_missed_errors += RTL_R32(RxMissed);
RTL_W32( RxMissed, 0);
spin_unlock_irq (&tp->lock);
synchronize_irq ();
free_irq (dev->irq, dev);
rtl8169_tx_clear (tp);
kfree(tp->TxDescArrays);
kfree(tp->RxDescArrays);
tp->TxDescArrays = NULL;
tp->RxDescArrays = NULL;
tp->TxDescArray = NULL;
tp->RxDescArray = NULL;
kfree(tp->RxBufferRings);
for (i=0; i <NUM_RX_DESC; i++){
tp->RxBufferRing[i] = NULL;
}
return 0;
}
//======================================================================================================
static unsigned const ethernet_polynomial = 0x04c11db7U;
static inline u32 ether_crc (int length, unsigned char *data)
{
int crc = -1;
while (--length >= 0) {
unsigned char current_octet = *data++;
int bit;
for (bit = 0; bit < 8; bit++, current_octet >>= 1)
crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
}
return crc;
}
//======================================================================================================
static void rtl8169_set_rx_mode (struct net_device *dev)
{
struct rtl8169_private *tp = dev->priv;
void *ioaddr = tp->mmio_addr;
unsigned long flags;
u32 mc_filter[2]; /* Multicast hash filter */
int i, rx_mode;
u32 tmp=0;
if (dev->flags & IFF_PROMISC) {
/* Unconditionally log net taps. */
printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
} else if ((dev->mc_count > multicast_filter_limit) || (dev->flags & IFF_ALLMULTI)) {
/* Too many to filter perfectly -- accept all multicasts. */
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0xffffffff;
} else {
struct dev_mc_list *mclist;
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0;
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next)
set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter);
}
spin_lock_irqsave (&tp->lock, flags);
tmp = rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
RTL_W32 ( RxConfig, tmp);
RTL_W32 ( MAR0 + 0, mc_filter[0]);
RTL_W32 ( MAR0 + 4, mc_filter[1]);
spin_unlock_irqrestore (&tp->lock, flags);
}//end of rtl8169_set_rx_mode (struct net_device *dev)
//================================================================================
struct net_device_stats *rtl8169_get_stats(struct net_device *dev)
{
struct rtl8169_private *tp = dev->priv;
return &tp->stats;
}
//================================================================================
static struct pci_driver rtl8169_pci_driver = {
name: MODULENAME,
id_table: rtl8169_pci_tbl,
probe: rtl8169_init_one,
remove: rtl8169_remove_one,
suspend: NULL,
resume: NULL,
};
//======================================================================================================
static int __init rtl8169_init_module (void)
{
return pci_module_init (&rtl8169_pci_driver); // pci_register_driver (drv)
}
//======================================================================================================
static void __exit rtl8169_cleanup_module (void)
{
pci_unregister_driver (&rtl8169_pci_driver);
}
//======================================================================================================
module_init(rtl8169_init_module);
module_exit(rtl8169_cleanup_module);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment