rtl8139.txt Driver File Contents (Realtech.zip)

/* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. */
/*
        Written 1997-1999 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 table provided by Kinston <shangh@realtek.com.tw>.
*/

/* This version has CardBus support added. */
static const char *version =
"rtl8139.c:v1.08 6/25/99 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 = 20;
#define rtl8129_debug debug
static int rtl8129_debug = 1;

/* 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;

/* 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};

/* Size of the in-memory receive ring. */
#define RX_BUF_LEN_IDX  3                       /* 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               /* Calculate as 16<<val. */

/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT  (4*HZ)

#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
#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>
#include <linux/version.h>
#ifdef MODULE
#ifdef MODVERSIONS
#include <linux/modversions.h>
#endif
#include <linux/module.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/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>

/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
   This is only in the support-all-kernels source code. */

#define RUN_AT(x) (jiffies + (x))

#if LINUX_VERSION_CODE < 0x20123
#define test_and_set_bit(val, addr) set_bit(val, addr)
#endif
#if LINUX_VERSION_CODE <= 0x20139
#define net_device_stats enet_statistics
#else
#define NETSTATS_VER2
#endif
#if LINUX_VERSION_CODE < 0x20155  ||  defined(CARDBUS)
/* Grrrr, the PCI code changed, but did not consider CardBus... */
#include <linux/bios32.h>
#define PCI_SUPPORT_VER1
#else
#define PCI_SUPPORT_VER2
#endif
#if LINUX_VERSION_CODE < 0x20159
#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
#else
#define dev_free_skb(skb) dev_kfree_skb(skb);
#endif
#if ! defined(CAP_NET_ADMIN)
#define capable(CAP_XXX) (suser())
#endif

/* The I/O extent. */
#define RTL8129_TOTAL_SIZE 0x80

/*
                                Theory of Operation

I. Board Compatibility

This device driver is designed for the RealTek RTL8129, the RealTek Fast
Ethernet controllers for PCI.  This chip is used on a few clone boards.


II. Board-specific settings

PCI bus devices are configured by the system at boot time, so no jumpers
need to be set on the board.  The system BIOS will assign the
PCI INTA signal to a (preferably otherwise unused) system IRQ line.
Note: Kernel versions earlier than 1.3.73 do not support shared PCI
interrupt lines.

III. Driver operation

IIIa. Rx Ring buffers

The receive unit uses a single linear ring buffer rather than the more
common (and more efficient) descriptor-based architecture.  Incoming frames
are sequentially stored into the Rx region, and the host copies them into
skbuffs.

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 operation

The 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.  Linux
aligns the IP header on word boundaries, and 14 byte ethernet header means
that almost all frames will need to be copied to an alignment buffer.

IVb. References

http://www.realtek.com.tw/cn/cn.html
http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html

IVc. Errata

*/


/* This table drives the PCI probe routines.  It's mostly boilerplate in all
   of the drivers, and will likely be provided by some future kernel.
   Note the matching code -- the first table entry matchs all 56** cards but
   second only the 1234 card.
*/
enum pci_flags_bit {
        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
        PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
};
struct pci_id_info {
        const char *name;
        u16     vendor_id, device_id, device_id_mask, flags;
        int io_size;
        struct device *(*probe1)(int pci_bus, int pci_devfn, struct device *dev,
                                                         long ioaddr, int irq, int chip_idx, int fnd_cnt);
};

static struct device * rtl8129_probe1(int pci_bus, int pci_devfn,
                                                                          struct device *dev, long ioaddr,
                                                                          int irq, int chp_idx, int fnd_cnt);

/* Note: change the marked constant in _attach() if the RTL8139B entry moves.*/
static struct pci_id_info pci_tbl[] =
{{ "RealTek RTL8129 Fast Ethernet",
   0x10ec, 0x8129, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
 { "RealTek RTL8139 Fast Ethernet",
   0x10ec, 0x8139, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
 { "RealTek RTL8139B PCI/CardBus",
   0x10ec, 0x8138, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
 { "SMC1211TX EZCard 10/100 (RealTek RTL8139)",
   0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
 { "Accton MPX5030 (RealTek RTL8139)",
   0x1113, 0x1211, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
 { "SiS 900 (RealTek RTL8139) Fast Ethernet",
   0x1039, 0x0900, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
 { "SiS 7016 (RealTek RTL8139) Fast Ethernet",
   0x1039, 0x7016, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 0x80, rtl8129_probe1},
 {0,},                                          /* 0 terminated list. */
};

/* The capability table matches the chip table above. */
enum {HAS_MII_XCVR=0x01, HAS_CHIP_XCVR=0x02, HAS_LNK_CHNG=0x04};
static int rtl_cap_tbl[] = {
        HAS_MII_XCVR,
        HAS_CHIP_XCVR|HAS_LNK_CHNG, HAS_CHIP_XCVR|HAS_LNK_CHNG,
        HAS_CHIP_XCVR|HAS_LNK_CHNG, HAS_CHIP_XCVR|HAS_LNK_CHNG,
        HAS_CHIP_XCVR|HAS_LNK_CHNG, HAS_CHIP_XCVR|HAS_LNK_CHNG,
};


/* 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 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,
};

/* 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,
};
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;
        unsigned char pci_bus, pci_devfn;
        struct net_device_stats stats;
        struct timer_list timer;        /* Media selection timer. */
        unsigned int cur_rx;            /* Index into the Rx buffer of next Rx pkt. */
        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 *rx_ring;
        unsigned char *tx_bufs;                         /* Tx bounce buffer region. */
        char phys[4];                                           /* MII device addresses. */
        char twistie, twist_cnt;                        /* 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. */
};

#ifdef MODULE
#if LINUX_VERSION_CODE > 0x20115
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
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");
#endif
#endif

static int rtl8129_open(struct device *dev);
static int read_eeprom(long ioaddr, int location, int addr_len);
static int mdio_read(struct device *dev, int phy_id, int location);
static void mdio_write(struct device *dev, int phy_id, int location, int val);
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 int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd);
static struct enet_statistics *rtl8129_get_stats(struct device *dev);
static inline u32 ether_crc(int length, unsigned char *data);
static void set_rx_mode(struct device *dev);


/* A list of all installed RTL8129 devices, for removing the driver module. */
static struct device *root_rtl8129_dev = NULL;

/* 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 when dynamically adding drivers.  So instead we detect just the
   Rtl81*9 cards in slot order. */

int rtl8139_probe(struct device *dev)
{
        int cards_found = 0;
        int pci_index = 0;
        unsigned char pci_bus, pci_device_fn;

        if ( ! pcibios_present())
                return -ENODEV;

        for (; pci_index < 0xff; pci_index++) {
                u16 vendor, device, pci_command, new_command;
                int chip_idx, irq;
                long ioaddr;

                if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
                                                                &pci_bus, &pci_device_fn)
                        != PCIBIOS_SUCCESSFUL)
                        break;
                pcibios_read_config_word(pci_bus, pci_device_fn,
                                                                 PCI_VENDOR_ID, &vendor);
                pcibios_read_config_word(pci_bus, pci_device_fn,
                                                                 PCI_DEVICE_ID, &device);

                for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
                        if (vendor == pci_tbl[chip_idx].vendor_id
                                && (device & pci_tbl[chip_idx].device_id_mask) ==
                                pci_tbl[chip_idx].device_id)
                                break;
                if (pci_tbl[chip_idx].vendor_id == 0)           /* Compiled out! */
                        continue;

                {
#if defined(PCI_SUPPORT_VER2)
                        struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
                        ioaddr = pdev->base_address[0] & ~3;
                        irq = pdev->irq;
#else
                        u32 pci_ioaddr;
                        u8 pci_irq_line;
                        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);
                        ioaddr = pci_ioaddr & ~3;
                        irq = pci_irq_line;
#endif
                }

                if ((pci_tbl[chip_idx].flags & PCI_USES_IO) &&
                        check_region(ioaddr, pci_tbl[chip_idx].io_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_tbl[chip_idx].flags & 7);
                if (pci_command != new_command) {
                        printk(KERN_INFO "  The PCI BIOS has not enabled the"
                                   " device at %d/%d!  Updating PCI command %4.4x->%4.4x.\n",
                                   pci_bus, pci_device_fn, pci_command, new_command);
                        pcibios_write_config_word(pci_bus, pci_device_fn,
                                                                          PCI_COMMAND, new_command);
                }

                dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr,
                                                                           irq, chip_idx, cards_found);

                if (dev  && (pci_tbl[chip_idx].flags & PCI_COMMAND_MASTER)) {
                        u8 pci_latency;
                        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);
                        }
                }
                dev = 0;
                cards_found++;
        }

        return cards_found ? 0 : -ENODEV;
}

static struct device *rtl8129_probe1(int pci_bus, int pci_devfn,
                                                                         struct device *dev, long ioaddr,
                                                                         int irq, int chip_idx, int found_cnt)
{
        static int did_version = 0;                     /* Already printed version info. */
        struct rtl8129_private *tp;
        int i, option = found_cnt < MAX_UNITS ? options[found_cnt] : 0;

        if (rtl8129_debug > 0  &&  did_version++ == 0)
                printk(KERN_INFO "%s", version);

        dev = init_etherdev(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);

        {
                int addr_len = read_eeprom(ioaddr, 0, 8) == 0x8129 ? 8 : 6;
                for (i = 0; i < 3; i++)
                        ((u16 *)(dev->dev_addr))[i] = read_eeprom(ioaddr, i+7, addr_len);
        }

        for (i = 0; i < 5; i++)
                printk("%2.2x:", dev->dev_addr[i]);
        printk("%2.2x.\n", dev->dev_addr[i]);

        /* We do a request_region() to register /proc/ioports info. */
        request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);

        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;

        tp->next_module = root_rtl8129_dev;
        root_rtl8129_dev = dev;

        tp->chip_id = chip_idx;
        tp->pci_bus = pci_bus;
        tp->pci_devfn = pci_devfn;

        /* Find the connected MII xcvrs.
           Doing this in open() would allow detecting external xcvrs later, but
           takes too much time. */
        if (rtl_cap_tbl[chip_idx] & HAS_MII_XCVR) {
                int phy, phy_idx;
                for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
                         phy++) {
                        int mii_status = mdio_read(dev, 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);
                        }
                }
                if (phy_idx == 0) {
                        printk(KERN_INFO "%s: No MII transceivers found!  Assuming SYM "
                                   "transceiver.\n",
                                   dev->name);
                        tp->phys[0] = -1;
                }
        } else
                tp->phys[0] = 32;

Download Driver Pack

How To Update Drivers Manually

After your driver has been downloaded, follow these simple steps to install it.

  • Expand the archive file (if the download file is in zip or rar format).

  • If the expanded file has an .exe extension, double click it and follow the installation instructions.

  • Otherwise, open Device Manager by right-clicking the Start menu and selecting Device Manager.

  • Find the device and model you want to update in the device list.

  • Double-click on it to open the Properties dialog box.

  • From the Properties dialog box, select the Driver tab.

  • Click the Update Driver button, then follow the instructions.

Very important: You must reboot your system to ensure that any driver updates have taken effect.

For more help, visit our Driver Support section for step-by-step videos on how to install drivers for every file type.

server: web3, load: 1.78