WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 8 of 10] New/Updated drivers: Realtek 8169 gigabit et

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 8 of 10] New/Updated drivers: Realtek 8169 gigabit ethernet driver backported from Linux Kernel Ver. 2.6.29.2
From: Daniel Kiper <dkiper@xxxxxxxxxxxx>
Date: Tue, 24 Nov 2009 12:59:47 +0100
Delivery-date: Tue, 24 Nov 2009 04:02:47 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mutt/1.3.28i
# HG changeset patch
# User root@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Date 1259016676 -3600
# Node ID 906126acd27b7e0efc3c11fdfe707b18734ab218
# Parent  1db1bb63824b25f97d127449faeb3a56f1272c97
Realtek 8169 gigabit ethernet driver backported
from Linux Kernel Ver. 2.6.29.2
Signed-off-by: Daniel Kiper <dkiper@xxxxxxxxxxxx>

diff -r 1db1bb63824b -r 906126acd27b arch/mips/configs/tb0229_defconfig
--- a/arch/mips/configs/tb0229_defconfig        Mon Nov 23 07:32:47 2009 +0000
+++ b/arch/mips/configs/tb0229_defconfig        Mon Nov 23 23:51:16 2009 +0100
@@ -481,7 +481,6 @@ CONFIG_MII=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 CONFIG_R8169=y
-# CONFIG_R8169_NAPI is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
diff -r 1db1bb63824b -r 906126acd27b arch/mips/configs/tb0287_defconfig
--- a/arch/mips/configs/tb0287_defconfig        Mon Nov 23 07:32:47 2009 +0000
+++ b/arch/mips/configs/tb0287_defconfig        Mon Nov 23 23:51:16 2009 +0100
@@ -624,7 +624,6 @@ CONFIG_MII=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 CONFIG_R8169=y
-# CONFIG_R8169_NAPI is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SKGE is not set
 # CONFIG_SKY2 is not set
diff -r 1db1bb63824b -r 906126acd27b arch/ppc/configs/radstone_ppc7d_defconfig
--- a/arch/ppc/configs/radstone_ppc7d_defconfig Mon Nov 23 07:32:47 2009 +0000
+++ b/arch/ppc/configs/radstone_ppc7d_defconfig Mon Nov 23 23:51:16 2009 +0100
@@ -525,7 +525,6 @@ CONFIG_E100=y
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
 CONFIG_R8169=y
-CONFIG_R8169_NAPI=y
 # CONFIG_SKGE is not set
 CONFIG_SK98LIN=y
 # CONFIG_VIA_VELOCITY is not set
diff -r 1db1bb63824b -r 906126acd27b buildconfigs/linux-defconfig_xen_x86_32
--- a/buildconfigs/linux-defconfig_xen_x86_32   Mon Nov 23 07:32:47 2009 +0000
+++ b/buildconfigs/linux-defconfig_xen_x86_32   Mon Nov 23 23:51:16 2009 +0100
@@ -1401,7 +1401,6 @@ CONFIG_HAMACHI=m
 CONFIG_HAMACHI=m
 CONFIG_YELLOWFIN=m
 CONFIG_R8169=m
-# CONFIG_R8169_NAPI is not set
 CONFIG_R8169_VLAN=y
 CONFIG_SIS190=m
 CONFIG_SKGE=m
diff -r 1db1bb63824b -r 906126acd27b buildconfigs/linux-defconfig_xen_x86_64
--- a/buildconfigs/linux-defconfig_xen_x86_64   Mon Nov 23 07:32:47 2009 +0000
+++ b/buildconfigs/linux-defconfig_xen_x86_64   Mon Nov 23 23:51:16 2009 +0100
@@ -1340,7 +1340,6 @@ CONFIG_HAMACHI=m
 CONFIG_HAMACHI=m
 CONFIG_YELLOWFIN=m
 CONFIG_R8169=m
-CONFIG_R8169_NAPI=y
 CONFIG_R8169_VLAN=y
 CONFIG_SIS190=m
 CONFIG_SKGE=m
diff -r 1db1bb63824b -r 906126acd27b drivers/net/Kconfig
--- a/drivers/net/Kconfig       Mon Nov 23 07:32:47 2009 +0000
+++ b/drivers/net/Kconfig       Mon Nov 23 23:51:16 2009 +0100
@@ -2180,28 +2180,12 @@ config R8169
        tristate "Realtek 8169 gigabit ethernet support"
        depends on PCI
        select CRC32
+       select MII
        ---help---
          Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter.
 
          To compile this driver as a module, choose M here: the module
          will be called r8169.  This is recommended.
-
-config R8169_NAPI
-       bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)"
-       depends on R8169 && EXPERIMENTAL
-       help
-         NAPI is a new driver API designed to reduce CPU and interrupt load
-         when the driver is receiving lots of packets from the card. It is
-         still somewhat experimental and thus not yet enabled by default.
-
-         If your estimated Rx load is 10kpps or more, or if the card will be
-         deployed on potentially unfriendly networks (e.g. in a firewall),
-         then say Y here.
-
-         See <file:Documentation/networking/NAPI_HOWTO.txt> for more
-         information.
-
-         If in doubt, say N.
 
 config R8169_VLAN
        bool "VLAN support"
diff -r 1db1bb63824b -r 906126acd27b drivers/net/r8169.c
--- a/drivers/net/r8169.c       Mon Nov 23 07:32:47 2009 +0000
+++ b/drivers/net/r8169.c       Mon Nov 23 23:51:16 2009 +0100
@@ -1,53 +1,11 @@
 /*
-=========================================================================
- r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver for Linux kernel 2.4.x.
- --------------------------------------------------------------------
-
- History:
- Feb  4 2002   - created initially by ShuChen <shuchen@xxxxxxxxxxxxxx>.
- May 20 2002   - Add link status force-mode and TBI mode support.
-       2004    - Massive updates. See kernel SCM system for details.
-=========================================================================
-  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)
-
-VERSION 1.6LK  <2004/04/14>
-
-       - Merge of Realtek's version 1.6
-       - Conversion to DMA API
-       - Suspend/resume
-       - Endianness
-       - Misc Rx/Tx bugs
-
-VERSION 2.2LK  <2005/01/25>
-
-       - RX csum, TX csum/SG, TSO
-       - VLAN
-       - baby (< 7200) Jumbo frames support
-       - Merge of Realtek's version 2.2 (new phy)
+ * r8169.c: RealTek 8169/8168/8101 ethernet driver.
+ *
+ * Copyright (c) 2002 ShuChen <shuchen@xxxxxxxxxxxxxx>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu@xxxxxxxxxxxxx>
+ * Copyright (c) a lot of people too. Please respect their work.
+ *
+ * See MAINTAINERS file for support contact information.
  */
 
 #include <linux/module.h>
@@ -66,16 +24,11 @@ VERSION 2.2LK       <2005/01/25>
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
 
+#include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#ifdef CONFIG_R8169_NAPI
-#define NAPI_SUFFIX    "-NAPI"
-#else
-#define NAPI_SUFFIX    ""
-#endif
-
-#define RTL8169_VERSION "2.2LK" NAPI_SUFFIX
+#define RTL8169_VERSION "2.3LK-NAPI"
 #define MODULENAME "r8169"
 #define PFX MODULENAME ": "
 
@@ -83,9 +36,10 @@ VERSION 2.2LK        <2005/01/25>
 #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)
+               #expr,__FILE__,__func__,__LINE__);              \
+       }
+#define dprintk(fmt, args...) \
+       do { printk(KERN_DEBUG PFX fmt, ## args); } while (0)
 #else
 #define assert(expr) do {} while (0)
 #define dprintk(fmt, args...)  do {} while (0)
@@ -97,21 +51,6 @@ VERSION 2.2LK        <2005/01/25>
 #define TX_BUFFS_AVAIL(tp) \
        (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx - 1)
 
-#ifdef CONFIG_R8169_NAPI
-#define rtl8169_rx_skb                 netif_receive_skb
-#define rtl8169_rx_hwaccel_skb         vlan_hwaccel_receive_skb
-#define rtl8169_rx_quota(count, quota) min(count, quota)
-#else
-#define rtl8169_rx_skb                 netif_rx
-#define rtl8169_rx_hwaccel_skb         vlan_hwaccel_rx
-#define rtl8169_rx_quota(count, quota) count
-#endif
-
-/* media options */
-#define MAX_UNITS 8
-static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
-static int num_media = 0;
-
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static const int max_interrupt_work = 20;
 
@@ -122,10 +61,11 @@ static const int multicast_filter_limit 
 /* MAC address length */
 #define MAC_ADDR_LEN   6
 
+#define MAX_READ_REQUEST_SHIFT 12
 #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 EarlyTxThld    0x3F    /* 0x3F means NO early transmit */
 #define RxPacketMaxSize        0x3FE8  /* 16K - 1 - ETH_HLEN - VLAN - CRC... */
 #define SafeMtu                0x1c20  /* ... actually life sucks beyond ~7k */
 #define InterFrameGap  0x03    /* 3 means InterFrameGap = the shortest one */
@@ -141,6 +81,10 @@ static const int multicast_filter_limit 
 #define RTL8169_TX_TIMEOUT     (6*HZ)
 #define RTL8169_PHY_TIMEOUT    (10*HZ)
 
+#define RTL_EEPROM_SIG         cpu_to_le32(0x8129)
+#define RTL_EEPROM_SIG_MASK    cpu_to_le32(0xffff)
+#define RTL_EEPROM_SIG_ADDR    0x0000
+
 /* write/read MMIO register */
 #define RTL_W8(reg, val8)      writeb ((val8), ioaddr + (reg))
 #define RTL_W16(reg, val16)    writew ((val16), ioaddr + (reg))
@@ -150,25 +94,31 @@ static const int multicast_filter_limit 
 #define RTL_R32(reg)           ((unsigned long) readl (ioaddr + (reg)))
 
 enum mac_version {
-       RTL_GIGA_MAC_VER_01 = 0x00,
-       RTL_GIGA_MAC_VER_02 = 0x01,
-       RTL_GIGA_MAC_VER_03 = 0x02,
-       RTL_GIGA_MAC_VER_04 = 0x03,
-       RTL_GIGA_MAC_VER_05 = 0x04,
-       RTL_GIGA_MAC_VER_11 = 0x0b,
-       RTL_GIGA_MAC_VER_12 = 0x0c,
-       RTL_GIGA_MAC_VER_13 = 0x0d,
-       RTL_GIGA_MAC_VER_14 = 0x0e,
-       RTL_GIGA_MAC_VER_15 = 0x0f
-};
-
-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 */
-       RTL_GIGA_PHY_VER_H = 0x08, /* PHY Reg 0x03 bit0-3 == 0x0003 */
+       RTL_GIGA_MAC_VER_01 = 0x01, // 8169
+       RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
+       RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
+       RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB
+       RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
+       RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
+       RTL_GIGA_MAC_VER_07 = 0x07, // 8102e
+       RTL_GIGA_MAC_VER_08 = 0x08, // 8102e
+       RTL_GIGA_MAC_VER_09 = 0x09, // 8102e
+       RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e
+       RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
+       RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be
+       RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb
+       RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ?
+       RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ?
+       RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec
+       RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf
+       RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP
+       RTL_GIGA_MAC_VER_19 = 0x13, // 8168C
+       RTL_GIGA_MAC_VER_20 = 0x14, // 8168C
+       RTL_GIGA_MAC_VER_21 = 0x15, // 8168C
+       RTL_GIGA_MAC_VER_22 = 0x16, // 8168C
+       RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP
+       RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP
+       RTL_GIGA_MAC_VER_25 = 0x19  // 8168D
 };
 
 #define _R(NAME,MAC,MASK) \
@@ -179,16 +129,31 @@ static const struct {
        u8 mac_version;
        u32 RxConfigMask;       /* Clears the bits supported by this chip */
 } rtl_chip_info[] = {
-       _R("RTL8169",           RTL_GIGA_MAC_VER_01, 0xff7e1880),
-       _R("RTL8169s/8110s",    RTL_GIGA_MAC_VER_02, 0xff7e1880),
-       _R("RTL8169s/8110s",    RTL_GIGA_MAC_VER_03, 0xff7e1880),
-       _R("RTL8169sb/8110sb",  RTL_GIGA_MAC_VER_04, 0xff7e1880),
-       _R("RTL8169sc/8110sc",  RTL_GIGA_MAC_VER_05, 0xff7e1880),
+       _R("RTL8169",           RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169
+       _R("RTL8169s",          RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S
+       _R("RTL8110s",          RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S
+       _R("RTL8169sb/8110sb",  RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB
+       _R("RTL8169sc/8110sc",  RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd
+       _R("RTL8169sc/8110sc",  RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe
+       _R("RTL8102e",          RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E
+       _R("RTL8102e",          RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E
+       _R("RTL8102e",          RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E
+       _R("RTL8101e",          RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E
        _R("RTL8168b/8111b",    RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E
        _R("RTL8168b/8111b",    RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E
        _R("RTL8101e",          RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139
        _R("RTL8100e",          RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139
-       _R("RTL8100e",          RTL_GIGA_MAC_VER_15, 0xff7e1880)  // PCI-E 8139
+       _R("RTL8100e",          RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139
+       _R("RTL8168b/8111b",    RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E
+       _R("RTL8101e",          RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E
+       _R("RTL8168cp/8111cp",  RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E
+       _R("RTL8168c/8111c",    RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E
+       _R("RTL8168c/8111c",    RTL_GIGA_MAC_VER_20, 0xff7e1880), // PCI-E
+       _R("RTL8168c/8111c",    RTL_GIGA_MAC_VER_21, 0xff7e1880), // PCI-E
+       _R("RTL8168c/8111c",    RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E
+       _R("RTL8168cp/8111cp",  RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E
+       _R("RTL8168cp/8111cp",  RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E
+       _R("RTL8168d/8111d",    RTL_GIGA_MAC_VER_25, 0xff7e1880)  // PCI-E
 };
 #undef _R
 
@@ -198,26 +163,23 @@ enum cfg_version {
        RTL_CFG_2
 };
 
-static const struct {
-       unsigned int region;
-       unsigned int align;
-} rtl_cfg_info[] = {
-       [RTL_CFG_0] = { 1, NET_IP_ALIGN },
-       [RTL_CFG_1] = { 2, NET_IP_ALIGN },
-       [RTL_CFG_2] = { 2, 8 }
-};
+static void rtl_hw_start_8169(struct net_device *);
+static void rtl_hw_start_8168(struct net_device *);
+static void rtl_hw_start_8101(struct net_device *);
 
 static struct pci_device_id rtl8169_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8129), 0, 0, RTL_CFG_0 },
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8136), 0, 0, RTL_CFG_2 },
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8167), 0, 0, RTL_CFG_0 },
-       { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8168), 0, 0, RTL_CFG_2 },
+       { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8168), 0, 0, RTL_CFG_1 },
        { PCI_DEVICE(PCI_VENDOR_ID_REALTEK,     0x8169), 0, 0, RTL_CFG_0 },
        { PCI_DEVICE(PCI_VENDOR_ID_DLINK,       0x4300), 0, 0, RTL_CFG_0 },
-       { PCI_DEVICE(0x1259,                    0xc107), 0, 0, RTL_CFG_0 },
+       { PCI_DEVICE(PCI_VENDOR_ID_AT,          0xc107), 0, 0, RTL_CFG_0 },
        { PCI_DEVICE(0x16ec,                    0x0116), 0, 0, RTL_CFG_0 },
        { PCI_VENDOR_ID_LINKSYS,                0x1032,
                PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
+       { 0x0001,                               0x8168,
+               PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },
        {0,},
 };
 
@@ -229,62 +191,86 @@ static struct {
        u32 msg_enable;
 } debug = { -1 };
 
-enum RTL8169_registers {
-       MAC0 = 0,               /* Ethernet hardware address. */
-       MAR0 = 8,               /* Multicast filter. */
-       CounterAddrLow = 0x10,
-       CounterAddrHigh = 0x14,
-       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,
-       IntrMitigate = 0xE2,
-       RxDescAddrLow = 0xE4,
-       RxDescAddrHigh = 0xE8,
-       EarlyTxThres = 0xEC,
-       FuncEvent = 0xF0,
-       FuncEventMask = 0xF4,
-       FuncPresetState = 0xF8,
-       FuncForceEvent = 0xFC,
+enum rtl_registers {
+       MAC0            = 0,    /* Ethernet hardware address. */
+       MAC4            = 4,
+       MAR0            = 8,    /* Multicast filter. */
+       CounterAddrLow          = 0x10,
+       CounterAddrHigh         = 0x14,
+       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,
+       PHYstatus       = 0x6c,
+       RxMaxSize       = 0xda,
+       CPlusCmd        = 0xe0,
+       IntrMitigate    = 0xe2,
+       RxDescAddrLow   = 0xe4,
+       RxDescAddrHigh  = 0xe8,
+       EarlyTxThres    = 0xec,
+       FuncEvent       = 0xf0,
+       FuncEventMask   = 0xf4,
+       FuncPresetState = 0xf8,
+       FuncForceEvent  = 0xfc,
 };
 
-enum RTL8169_register_content {
+enum rtl8110_registers {
+       TBICSR                  = 0x64,
+       TBI_ANAR                = 0x68,
+       TBI_LPAR                = 0x6a,
+};
+
+enum rtl8168_8101_registers {
+       CSIDR                   = 0x64,
+       CSIAR                   = 0x68,
+#define        CSIAR_FLAG                      0x80000000
+#define        CSIAR_WRITE_CMD                 0x80000000
+#define        CSIAR_BYTE_ENABLE               0x0f
+#define        CSIAR_BYTE_ENABLE_SHIFT         12
+#define        CSIAR_ADDR_MASK                 0x0fff
+
+       EPHYAR                  = 0x80,
+#define        EPHYAR_FLAG                     0x80000000
+#define        EPHYAR_WRITE_CMD                0x80000000
+#define        EPHYAR_REG_MASK                 0x1f
+#define        EPHYAR_REG_SHIFT                16
+#define        EPHYAR_DATA_MASK                0xffff
+       DBG_REG                 = 0xd1,
+#define        FIX_NAK_1                       (1 << 4)
+#define        FIX_NAK_2                       (1 << 3)
+};
+
+enum rtl_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,
+       SYSErr          = 0x8000,
+       PCSTimeout      = 0x4000,
+       SWInt           = 0x0100,
+       TxDescUnavail   = 0x0080,
+       RxFIFOOver      = 0x0040,
+       LinkChg         = 0x0020,
+       RxOverflow      = 0x0010,
+       TxErr           = 0x0008,
+       TxOK            = 0x0004,
+       RxErr           = 0x0002,
+       RxOK            = 0x0001,
 
        /* RxStatusDesc */
        RxFOVF  = (1 << 23),
@@ -294,37 +280,54 @@ enum RTL8169_register_content {
        RxCRC   = (1 << 19),
 
        /* ChipCmdBits */
-       CmdReset = 0x10,
-       CmdRxEnb = 0x08,
-       CmdTxEnb = 0x04,
-       RxBufEmpty = 0x01,
+       CmdReset        = 0x10,
+       CmdRxEnb        = 0x08,
+       CmdTxEnb        = 0x04,
+       RxBufEmpty      = 0x01,
+
+       /* TXPoll register p.5 */
+       HPQ             = 0x80,         /* Poll cmd on the high prio queue */
+       NPQ             = 0x40,         /* Poll cmd on the low prio queue */
+       FSWInt          = 0x01,         /* Forced software interrupt */
 
        /* Cfg9346Bits */
-       Cfg9346_Lock = 0x00,
-       Cfg9346_Unlock = 0xC0,
+       Cfg9346_Lock    = 0x00,
+       Cfg9346_Unlock  = 0xc0,
 
        /* rx_mode_bits */
-       AcceptErr = 0x20,
-       AcceptRunt = 0x10,
-       AcceptBroadcast = 0x08,
-       AcceptMulticast = 0x04,
-       AcceptMyPhys = 0x02,
-       AcceptAllPhys = 0x01,
+       AcceptErr       = 0x20,
+       AcceptRunt      = 0x10,
+       AcceptBroadcast = 0x08,
+       AcceptMulticast = 0x04,
+       AcceptMyPhys    = 0x02,
+       AcceptAllPhys   = 0x01,
 
        /* RxConfigBits */
-       RxCfgFIFOShift = 13,
-       RxCfgDMAShift = 8,
+       RxCfgFIFOShift  = 13,
+       RxCfgDMAShift   =  8,
 
        /* TxConfigBits */
        TxInterFrameGapShift = 24,
        TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
 
        /* Config1 register p.24 */
+       LEDS1           = (1 << 7),
+       LEDS0           = (1 << 6),
+       MSIEnable       = (1 << 5),     /* Enable Message Signaled Interrupt */
+       Speed_down      = (1 << 4),
+       MEMMAP          = (1 << 3),
+       IOMAP           = (1 << 2),
+       VPD             = (1 << 1),
        PMEnable        = (1 << 0),     /* Power Management Enable */
+
+       /* Config2 register p. 25 */
+       PCI_Clock_66MHz = 0x01,
+       PCI_Clock_33MHz = 0x00,
 
        /* Config3 register p.25 */
        MagicPacket     = (1 << 5),     /* Wake up when receives a Magic Packet 
*/
        LinkUp          = (1 << 4),     /* Wake up when the cable connection is 
re-established */
+       Beacon_en       = (1 << 0),     /* 8168 only. Reserved in the 8168b */
 
        /* Config5 register p.27 */
        BWF             = (1 << 6),     /* Accept Broadcast wakeup frame */
@@ -342,36 +345,43 @@ enum RTL8169_register_content {
        TBINwComplete   = 0x01000000,
 
        /* CPlusCmd p.31 */
+       EnableBist      = (1 << 15),    // 8168 8101
+       Mac_dbgo_oe     = (1 << 14),    // 8168 8101
+       Normal_mode     = (1 << 13),    // unused
+       Force_half_dup  = (1 << 12),    // 8168 8101
+       Force_rxflow_en = (1 << 11),    // 8168 8101
+       Force_txflow_en = (1 << 10),    // 8168 8101
+       Cxpl_dbg_sel    = (1 << 9),     // 8168 8101
+       ASF             = (1 << 8),     // 8168 8101
+       PktCntrDisable  = (1 << 7),     // 8168 8101
+       Mac_dbgo_sel    = 0x001c,       // 8168
        RxVlan          = (1 << 6),
        RxChkSum        = (1 << 5),
        PCIDAC          = (1 << 4),
        PCIMulRW        = (1 << 3),
+       INTT_0          = 0x0000,       // 8168
+       INTT_1          = 0x0001,       // 8168
+       INTT_2          = 0x0002,       // 8168
+       INTT_3          = 0x0003,       // 8168
 
        /* rtl8169_PHYstatus */
-       TBI_Enable = 0x80,
-       TxFlowCtrl = 0x40,
-       RxFlowCtrl = 0x20,
-       _1000bpsF = 0x10,
-       _100bps = 0x08,
-       _10bps = 0x04,
-       LinkStatus = 0x02,
-       FullDup = 0x01,
-
-       /* _MediaType */
-       _10_Half = 0x01,
-       _10_Full = 0x02,
-       _100_Half = 0x04,
-       _100_Full = 0x08,
-       _1000_Full = 0x10,
+       TBI_Enable      = 0x80,
+       TxFlowCtrl      = 0x40,
+       RxFlowCtrl      = 0x20,
+       _1000bpsF       = 0x10,
+       _100bps         = 0x08,
+       _10bps          = 0x04,
+       LinkStatus      = 0x02,
+       FullDup         = 0x01,
 
        /* _TBICSRBit */
-       TBILinkOK = 0x02000000,
+       TBILinkOK       = 0x02000000,
 
        /* DumpCounterCommand */
-       CounterDump = 0x8,
+       CounterDump     = 0x8,
 };
 
-enum _DescStatusBit {
+enum desc_status_bit {
        DescOwn         = (1 << 31), /* Descriptor is owned by NIC */
        RingEnd         = (1 << 30), /* End of descriptor ring */
        FirstFrag       = (1 << 29), /* First segment of a packet */
@@ -404,21 +414,43 @@ enum _DescStatusBit {
 #define RsvdMask       0x3fffc000
 
 struct TxDesc {
-       u32 opts1;
-       u32 opts2;
-       u64 addr;
+       __le32 opts1;
+       __le32 opts2;
+       __le64 addr;
 };
 
 struct RxDesc {
-       u32 opts1;
-       u32 opts2;
-       u64 addr;
+       __le32 opts1;
+       __le32 opts2;
+       __le64 addr;
 };
 
 struct ring_info {
        struct sk_buff  *skb;
        u32             len;
        u8              __pad[sizeof(void *) - sizeof(u32)];
+};
+
+enum features {
+       RTL_FEATURE_WOL         = (1 << 0),
+       RTL_FEATURE_MSI         = (1 << 1),
+       RTL_FEATURE_GMII        = (1 << 2),
+};
+
+struct rtl8169_counters {
+       __le64  tx_packets;
+       __le64  rx_packets;
+       __le64  tx_errors;
+       __le32  rx_errors;
+       __le16  rx_missed;
+       __le16  align_errors;
+       __le32  tx_one_collision;
+       __le32  tx_multi_collision;
+       __le64  rx_unicast;
+       __le64  rx_broadcast;
+       __le32  rx_multicast;
+       __le16  tx_aborted;
+       __le16  tx_underun;
 };
 
 struct rtl8169_private {
@@ -430,7 +462,6 @@ struct rtl8169_private {
        u32 msg_enable;
        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;
@@ -445,6 +476,8 @@ struct rtl8169_private {
        unsigned rx_buf_sz;
        struct timer_list timer;
        u16 cp_cmd;
+       u16 intr_event;
+       u16 napi_event;
        u16 intr_mask;
        int phy_auto_nego_reg;
        int phy_1000_ctrl_reg;
@@ -452,18 +485,22 @@ struct rtl8169_private {
        struct vlan_group *vlgrp;
 #endif
        int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex);
-       void (*get_settings)(struct net_device *, struct ethtool_cmd *);
+       int (*get_settings)(struct net_device *, struct ethtool_cmd *);
        void (*phy_reset_enable)(void __iomem *);
+       void (*hw_start)(struct net_device *);
        unsigned int (*phy_reset_pending)(void __iomem *);
        unsigned int (*link_ok)(void __iomem *);
+       int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data 
*data, int cmd);
+       int pcie_cap;
        struct work_struct task;
-       unsigned wol_enabled : 1;
+       unsigned features;
+
+       struct mii_if_info mii;
+       struct rtl8169_counters counters;
 };
 
 MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@xxxxxxxxxxxxxxx>");
 MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
-module_param_array(media, int, &num_media, 0);
-MODULE_PARM_DESC(media, "force phy operation. Deprecated by ethtool (8).");
 module_param(rx_copybreak, int, 0);
 MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
 module_param(use_dac, int, 0);
@@ -477,51 +514,51 @@ static int rtl8169_start_xmit(struct sk_
 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 void rtl_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 rtl_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 *dev);
 static int rtl8169_rx_interrupt(struct net_device *, struct rtl8169_private *,
                                void __iomem *);
 static int rtl8169_change_mtu(struct net_device *dev, int new_mtu);
 static void rtl8169_down(struct net_device *dev);
-
-#ifdef CONFIG_R8169_NAPI
+static void rtl8169_rx_clear(struct rtl8169_private *tp);
 static int rtl8169_poll(struct net_device *dev, int *budget);
-#endif
-
-static 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);
 
-static void mdio_write(void __iomem *ioaddr, int RegAddr, int value)
+static void mdio_write(void __iomem *ioaddr, int reg_addr, int value)
 {
        int i;
 
-       RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
+       RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0x1f) << 16 | (value & 0xffff));
 
        for (i = 20; i > 0; i--) {
-               /* Check if the RTL8169 has completed writing to the specified 
MII register */
+               /*
+                * Check if the RTL8169 has completed writing to the specified
+                * MII register.
+                */
                if (!(RTL_R32(PHYAR) & 0x80000000))
                        break;
                udelay(25);
        }
 }
 
-static int mdio_read(void __iomem *ioaddr, int RegAddr)
+static int mdio_read(void __iomem *ioaddr, int reg_addr)
 {
        int i, value = -1;
 
-       RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
+       RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16);
 
        for (i = 20; i > 0; i--) {
-               /* Check if the RTL8169 has completed retrieving data from the 
specified MII register */
+               /*
+                * Check if the RTL8169 has completed retrieving data from
+                * the specified MII register.
+                */
                if (RTL_R32(PHYAR) & 0x80000000) {
-                       value = (int) (RTL_R32(PHYAR) & 0xFFFF);
+                       value = RTL_R32(PHYAR) & 0xffff;
                        break;
                }
                udelay(25);
@@ -529,6 +566,94 @@ static int mdio_read(void __iomem *ioadd
        return value;
 }
 
+static void mdio_patch(void __iomem *ioaddr, int reg_addr, int value)
+{
+       mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value);
+}
+
+static void rtl_mdio_write(struct net_device *dev, int phy_id, int location,
+                          int val)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+
+       mdio_write(ioaddr, location, val);
+}
+
+static int rtl_mdio_read(struct net_device *dev, int phy_id, int location)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+
+       return mdio_read(ioaddr, location);
+}
+
+static void rtl_ephy_write(void __iomem *ioaddr, int reg_addr, int value)
+{
+       unsigned int i;
+
+       RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
+               (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
+
+       for (i = 0; i < 100; i++) {
+               if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG))
+                       break;
+               udelay(10);
+       }
+}
+
+static u16 rtl_ephy_read(void __iomem *ioaddr, int reg_addr)
+{
+       u16 value = 0xffff;
+       unsigned int i;
+
+       RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
+
+       for (i = 0; i < 100; i++) {
+               if (RTL_R32(EPHYAR) & EPHYAR_FLAG) {
+                       value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK;
+                       break;
+               }
+               udelay(10);
+       }
+
+       return value;
+}
+
+static void rtl_csi_write(void __iomem *ioaddr, int addr, int value)
+{
+       unsigned int i;
+
+       RTL_W32(CSIDR, value);
+       RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
+               CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
+
+       for (i = 0; i < 100; i++) {
+               if (!(RTL_R32(CSIAR) & CSIAR_FLAG))
+                       break;
+               udelay(10);
+       }
+}
+
+static u32 rtl_csi_read(void __iomem *ioaddr, int addr)
+{
+       u32 value = ~0x00;
+       unsigned int i;
+
+       RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
+               CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
+
+       for (i = 0; i < 100; i++) {
+               if (RTL_R32(CSIAR) & CSIAR_FLAG) {
+                       value = RTL_R32(CSIDR);
+                       break;
+               }
+               udelay(10);
+       }
+
+       return value;
+}
+
 static void rtl8169_irq_mask_and_ack(void __iomem *ioaddr)
 {
        RTL_W16(IntrMask, 0x0000);
@@ -572,12 +697,13 @@ static void rtl8169_xmii_reset_enable(vo
 {
        unsigned int val;
 
-       mdio_write(ioaddr, MII_BMCR, BMCR_RESET);
-       val = mdio_read(ioaddr, MII_BMCR);
+       val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET;
+       mdio_write(ioaddr, MII_BMCR, val & 0xffff);
 }
 
 static void rtl8169_check_link_status(struct net_device *dev,
-                                     struct rtl8169_private *tp, void __iomem 
*ioaddr)
+                                     struct rtl8169_private *tp,
+                                     void __iomem *ioaddr)
 {
        unsigned long flags;
 
@@ -594,38 +720,6 @@ static void rtl8169_check_link_status(st
        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 && netif_msg_drv(&debug))
-               printk(KERN_WARNING PFX "media option is deprecated.\n");
-
-       for (p = link_settings; p->media != 0xff; p++) {
-               if (p->media == option)
-                       break;
-       }
-       *autoneg = p->autoneg;
-       *speed = p->speed;
-       *duplex = p->duplex;
-}
-
 static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo 
*wol)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
@@ -665,7 +759,7 @@ static int rtl8169_set_wol(struct net_de
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
-       int i;
+       unsigned int i;
        static struct {
                u32 opt;
                u16 reg;
@@ -693,7 +787,11 @@ static int rtl8169_set_wol(struct net_de
 
        RTL_W8(Cfg9346, Cfg9346_Lock);
 
-       tp->wol_enabled = (wol->wolopts) ? 1 : 0;
+       if (wol->wolopts)
+               tp->features |= RTL_FEATURE_WOL;
+       else
+               tp->features &= ~RTL_FEATURE_WOL;
+       device_set_wakeup_enable(&tp->pci_dev->dev, wol->wolopts);
 
        spin_unlock_irq(&tp->lock);
 
@@ -774,15 +872,21 @@ static int rtl8169_set_speed_xmii(struct
 
                /* This tweak comes straight from Realtek's driver. */
                if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) &&
-                   (tp->mac_version == RTL_GIGA_MAC_VER_13)) {
+                   ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+                    (tp->mac_version == RTL_GIGA_MAC_VER_16))) {
                        auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA;
                }
        }
 
-       /* The 8100e/8101e do Fast Ethernet only. */
-       if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+       /* The 8100e/8101e/8102e do Fast Ethernet only. */
+       if ((tp->mac_version == RTL_GIGA_MAC_VER_07) ||
+           (tp->mac_version == RTL_GIGA_MAC_VER_08) ||
+           (tp->mac_version == RTL_GIGA_MAC_VER_09) ||
+           (tp->mac_version == RTL_GIGA_MAC_VER_10) ||
+           (tp->mac_version == RTL_GIGA_MAC_VER_13) ||
            (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
-           (tp->mac_version == RTL_GIGA_MAC_VER_15)) {
+           (tp->mac_version == RTL_GIGA_MAC_VER_15) ||
+           (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
                if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) &&
                    netif_msg_link(tp)) {
                        printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n",
@@ -792,6 +896,17 @@ static int rtl8169_set_speed_xmii(struct
        }
 
        auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+
+       if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
+           (tp->mac_version == RTL_GIGA_MAC_VER_12) ||
+           (tp->mac_version >= RTL_GIGA_MAC_VER_17)) {
+               /*
+                * Wake up the PHY.
+                * Vendor specific (0x1f) and reserved (0x0e) MII registers.
+                */
+               mdio_write(ioaddr, 0x1f, 0x0000);
+               mdio_write(ioaddr, 0x0e, 0x0000);
+       }
 
        tp->phy_auto_nego_reg = auto_nego;
        tp->phy_1000_ctrl_reg = giga_ctrl;
@@ -884,26 +999,15 @@ static void rtl8169_vlan_rx_register(str
        spin_unlock_irqrestore(&tp->lock, flags);
 }
 
-static void rtl8169_vlan_rx_kill_vid(struct net_device *dev, unsigned short 
vid)
-{
-       struct rtl8169_private *tp = netdev_priv(dev);
-       unsigned long flags;
-
-       spin_lock_irqsave(&tp->lock, flags);
-       if (tp->vlgrp)
-               tp->vlgrp->vlan_devices[vid] = NULL;
-       spin_unlock_irqrestore(&tp->lock, flags);
-}
-
 static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
                               struct sk_buff *skb)
 {
        u32 opts2 = le32_to_cpu(desc->opts2);
+       struct vlan_group *vlgrp = tp->vlgrp;
        int ret;
 
-       if (tp->vlgrp && (opts2 & RxVlanTag)) {
-               rtl8169_rx_hwaccel_skb(skb, tp->vlgrp,
-                                      swab16(opts2 & 0xffff));
+       if (vlgrp && (opts2 & RxVlanTag)) {
+               vlan_hwaccel_receive_skb(skb, vlgrp, swab16(opts2 & 0xffff));
                ret = 0;
        } else
                ret = -1;
@@ -927,7 +1031,7 @@ static int rtl8169_rx_vlan_skb(struct rt
 
 #endif
 
-static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
+static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
@@ -944,65 +1048,29 @@ static void rtl8169_gset_tbi(struct net_
 
        cmd->speed = SPEED_1000;
        cmd->duplex = DUPLEX_FULL; /* Always set */
-}
-
-static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
-{
-       struct rtl8169_private *tp = netdev_priv(dev);
-       void __iomem *ioaddr = tp->mmio_addr;
-       u8 status;
-
-       cmd->supported = SUPPORTED_10baseT_Half |
-                        SUPPORTED_10baseT_Full |
-                        SUPPORTED_100baseT_Half |
-                        SUPPORTED_100baseT_Full |
-                        SUPPORTED_1000baseT_Full |
-                        SUPPORTED_Autoneg |
-                        SUPPORTED_TP;
-
-       cmd->autoneg = 1;
-       cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg;
-
-       if (tp->phy_auto_nego_reg & ADVERTISE_10HALF)
-               cmd->advertising |= ADVERTISED_10baseT_Half;
-       if (tp->phy_auto_nego_reg & ADVERTISE_10FULL)
-               cmd->advertising |= ADVERTISED_10baseT_Full;
-       if (tp->phy_auto_nego_reg & ADVERTISE_100HALF)
-               cmd->advertising |= ADVERTISED_100baseT_Half;
-       if (tp->phy_auto_nego_reg & ADVERTISE_100FULL)
-               cmd->advertising |= ADVERTISED_100baseT_Full;
-       if (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL)
-               cmd->advertising |= ADVERTISED_1000baseT_Full;
-
-       status = RTL_R8(PHYstatus);
-
-       if (status & _1000bpsF)
-               cmd->speed = SPEED_1000;
-       else if (status & _100bps)
-               cmd->speed = SPEED_100;
-       else if (status & _10bps)
-               cmd->speed = SPEED_10;
-
-       if (status & TxFlowCtrl)
-               cmd->advertising |= ADVERTISED_Asym_Pause;
-       if (status & RxFlowCtrl)
-               cmd->advertising |= ADVERTISED_Pause;
-
-       cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ?
-                     DUPLEX_FULL : DUPLEX_HALF;
+
+       return 0;
+}
+
+static int rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+
+       return mii_ethtool_gset(&tp->mii, cmd);
 }
 
 static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd 
*cmd)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        unsigned long flags;
+       int rc;
 
        spin_lock_irqsave(&tp->lock, flags);
 
-       tp->get_settings(dev, cmd);
+       rc = tp->get_settings(dev, cmd);
 
        spin_unlock_irqrestore(&tp->lock, flags);
-       return 0;
+       return rc;
 }
 
 static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
@@ -1049,37 +1117,26 @@ static const char rtl8169_gstrings[][ETH
        "tx_underrun",
 };
 
-struct rtl8169_counters {
-       u64     tx_packets;
-       u64     rx_packets;
-       u64     tx_errors;
-       u32     rx_errors;
-       u16     rx_missed;
-       u16     align_errors;
-       u32     tx_one_collision;
-       u32     tx_multi_collision;
-       u64     rx_unicast;
-       u64     rx_broadcast;
-       u32     rx_multicast;
-       u16     tx_aborted;
-       u16     tx_underun;
-};
-
 static int rtl8169_get_stats_count(struct net_device *dev)
 {
        return ARRAY_SIZE(rtl8169_gstrings);
 }
 
-static void rtl8169_get_ethtool_stats(struct net_device *dev,
-                                     struct ethtool_stats *stats, u64 *data)
+static void rtl8169_update_counters(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
        struct rtl8169_counters *counters;
        dma_addr_t paddr;
        u32 cmd;
-
-       ASSERT_RTNL();
+       int wait = 1000;
+
+       /*
+        * Some chips are unable to dump tally counters when the receiver
+        * is disabled.
+        */
+       if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0)
+               return;
 
        counters = pci_alloc_consistent(tp->pci_dev, sizeof(*counters), &paddr);
        if (!counters)
@@ -1090,29 +1147,43 @@ static void rtl8169_get_ethtool_stats(st
        RTL_W32(CounterAddrLow, cmd);
        RTL_W32(CounterAddrLow, cmd | CounterDump);
 
-       while (RTL_R32(CounterAddrLow) & CounterDump) {
-               if (msleep_interruptible(1))
+       while (wait--) {
+               if ((RTL_R32(CounterAddrLow) & CounterDump) == 0) {
+                       /* copy updated counters */
+                       memcpy(&tp->counters, counters, sizeof(*counters));
                        break;
+               }
+               udelay(10);
        }
 
        RTL_W32(CounterAddrLow, 0);
        RTL_W32(CounterAddrHigh, 0);
 
-       data[0] = le64_to_cpu(counters->tx_packets);
-       data[1] = le64_to_cpu(counters->rx_packets);
-       data[2] = le64_to_cpu(counters->tx_errors);
-       data[3] = le32_to_cpu(counters->rx_errors);
-       data[4] = le16_to_cpu(counters->rx_missed);
-       data[5] = le16_to_cpu(counters->align_errors);
-       data[6] = le32_to_cpu(counters->tx_one_collision);
-       data[7] = le32_to_cpu(counters->tx_multi_collision);
-       data[8] = le64_to_cpu(counters->rx_unicast);
-       data[9] = le64_to_cpu(counters->rx_broadcast);
-       data[10] = le32_to_cpu(counters->rx_multicast);
-       data[11] = le16_to_cpu(counters->tx_aborted);
-       data[12] = le16_to_cpu(counters->tx_underun);
-
        pci_free_consistent(tp->pci_dev, sizeof(*counters), counters, paddr);
+}
+
+static void rtl8169_get_ethtool_stats(struct net_device *dev,
+                                     struct ethtool_stats *stats, u64 *data)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+
+       ASSERT_RTNL();
+
+       rtl8169_update_counters(dev);
+
+       data[0] = le64_to_cpu(tp->counters.tx_packets);
+       data[1] = le64_to_cpu(tp->counters.rx_packets);
+       data[2] = le64_to_cpu(tp->counters.tx_errors);
+       data[3] = le32_to_cpu(tp->counters.rx_errors);
+       data[4] = le16_to_cpu(tp->counters.rx_missed);
+       data[5] = le16_to_cpu(tp->counters.align_errors);
+       data[6] = le32_to_cpu(tp->counters.tx_one_collision);
+       data[7] = le32_to_cpu(tp->counters.tx_multi_collision);
+       data[8] = le64_to_cpu(tp->counters.rx_unicast);
+       data[9] = le64_to_cpu(tp->counters.rx_broadcast);
+       data[10] = le32_to_cpu(tp->counters.rx_multicast);
+       data[11] = le16_to_cpu(tp->counters.tx_aborted);
+       data[12] = le16_to_cpu(tp->counters.tx_underun);
 }
 
 static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 
*data)
@@ -1124,8 +1195,7 @@ static void rtl8169_get_strings(struct n
        }
 }
 
-
-static /*const*/ struct ethtool_ops rtl8169_ethtool_ops = {
+static struct ethtool_ops rtl8169_ethtool_ops = {
        .get_drvinfo            = rtl8169_get_drvinfo,
        .get_regs_len           = rtl8169_get_regs_len,
        .get_link               = ethtool_op_get_link,
@@ -1150,8 +1220,8 @@ static /*const*/ struct ethtool_ops rtl8
        .get_perm_addr          = ethtool_op_get_perm_addr,
 };
 
-static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int 
bitnum,
-                                      int bitval)
+static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg,
+                                      int bitnum, int bitval)
 {
        int val;
 
@@ -1161,29 +1231,84 @@ static void rtl8169_write_gmii_reg_bit(v
        mdio_write(ioaddr, reg, val & 0xffff);
 }
 
-static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem 
*ioaddr)
-{
+static void rtl8169_get_mac_version(struct rtl8169_private *tp,
+                                   void __iomem *ioaddr)
+{
+       /*
+        * The driver currently handles the 8168Bf and the 8168Be identically
+        * but they can be identified more specifically through the test below
+        * if needed:
+        *
+        * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
+        *
+        * Same thing for the 8101Eb and the 8101Ec:
+        *
+        * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
+        */
        const struct {
                u32 mask;
+               u32 val;
                int mac_version;
        } mac_info[] = {
-               { 0x38800000,   RTL_GIGA_MAC_VER_15 },
-               { 0x38000000,   RTL_GIGA_MAC_VER_12 },
-               { 0x34000000,   RTL_GIGA_MAC_VER_13 },
-               { 0x30800000,   RTL_GIGA_MAC_VER_14 },
-               { 0x30000000,   RTL_GIGA_MAC_VER_11 },
-               { 0x18000000,   RTL_GIGA_MAC_VER_05 },
-               { 0x10000000,   RTL_GIGA_MAC_VER_04 },
-               { 0x04000000,   RTL_GIGA_MAC_VER_03 },
-               { 0x00800000,   RTL_GIGA_MAC_VER_02 },
-               { 0x00000000,   RTL_GIGA_MAC_VER_01 }   /* Catch-all */
+               /* 8168D family. */
+               { 0x7c800000, 0x28000000,       RTL_GIGA_MAC_VER_25 },
+
+               /* 8168C family. */
+               { 0x7cf00000, 0x3ca00000,       RTL_GIGA_MAC_VER_24 },
+               { 0x7cf00000, 0x3c900000,       RTL_GIGA_MAC_VER_23 },
+               { 0x7cf00000, 0x3c800000,       RTL_GIGA_MAC_VER_18 },
+               { 0x7c800000, 0x3c800000,       RTL_GIGA_MAC_VER_24 },
+               { 0x7cf00000, 0x3c000000,       RTL_GIGA_MAC_VER_19 },
+               { 0x7cf00000, 0x3c200000,       RTL_GIGA_MAC_VER_20 },
+               { 0x7cf00000, 0x3c300000,       RTL_GIGA_MAC_VER_21 },
+               { 0x7cf00000, 0x3c400000,       RTL_GIGA_MAC_VER_22 },
+               { 0x7c800000, 0x3c000000,       RTL_GIGA_MAC_VER_22 },
+
+               /* 8168B family. */
+               { 0x7cf00000, 0x38000000,       RTL_GIGA_MAC_VER_12 },
+               { 0x7cf00000, 0x38500000,       RTL_GIGA_MAC_VER_17 },
+               { 0x7c800000, 0x38000000,       RTL_GIGA_MAC_VER_17 },
+               { 0x7c800000, 0x30000000,       RTL_GIGA_MAC_VER_11 },
+
+               /* 8101 family. */
+               { 0x7cf00000, 0x34a00000,       RTL_GIGA_MAC_VER_09 },
+               { 0x7cf00000, 0x24a00000,       RTL_GIGA_MAC_VER_09 },
+               { 0x7cf00000, 0x34900000,       RTL_GIGA_MAC_VER_08 },
+               { 0x7cf00000, 0x24900000,       RTL_GIGA_MAC_VER_08 },
+               { 0x7cf00000, 0x34800000,       RTL_GIGA_MAC_VER_07 },
+               { 0x7cf00000, 0x24800000,       RTL_GIGA_MAC_VER_07 },
+               { 0x7cf00000, 0x34000000,       RTL_GIGA_MAC_VER_13 },
+               { 0x7cf00000, 0x34300000,       RTL_GIGA_MAC_VER_10 },
+               { 0x7cf00000, 0x34200000,       RTL_GIGA_MAC_VER_16 },
+               { 0x7c800000, 0x34800000,       RTL_GIGA_MAC_VER_09 },
+               { 0x7c800000, 0x24800000,       RTL_GIGA_MAC_VER_09 },
+               { 0x7c800000, 0x34000000,       RTL_GIGA_MAC_VER_16 },
+               /* FIXME: where did these entries come from ? -- FR */
+               { 0xfc800000, 0x38800000,       RTL_GIGA_MAC_VER_15 },
+               { 0xfc800000, 0x30800000,       RTL_GIGA_MAC_VER_14 },
+
+               /* 8110 family. */
+               { 0xfc800000, 0x98000000,       RTL_GIGA_MAC_VER_06 },
+               { 0xfc800000, 0x18000000,       RTL_GIGA_MAC_VER_05 },
+               { 0xfc800000, 0x10000000,       RTL_GIGA_MAC_VER_04 },
+               { 0xfc800000, 0x04000000,       RTL_GIGA_MAC_VER_03 },
+               { 0xfc800000, 0x00800000,       RTL_GIGA_MAC_VER_02 },
+               { 0xfc800000, 0x00000000,       RTL_GIGA_MAC_VER_01 },
+
+               { 0x00000000, 0x00000000,       RTL_GIGA_MAC_VER_01 }   /* 
Catch-all */
        }, *p = mac_info;
        u32 reg;
 
-       reg = RTL_R32(TxConfig) & 0x7c800000;
-       while ((reg & p->mask) != p->mask)
+       reg = RTL_R32(TxConfig);
+       while ((reg & p->mask) != p->val)
                p++;
        tp->mac_version = p->mac_version;
+
+       if (p->mask == 0x00000000) {
+               struct pci_dev *pdev = tp->pci_dev;
+
+               dev_info(&pdev->dev, "unknown MAC (%08x)\n", reg);
+       }
 }
 
 static void rtl8169_print_mac_version(struct rtl8169_private *tp)
@@ -1191,53 +1316,21 @@ static void rtl8169_print_mac_version(st
        dprintk("mac_version = 0x%02x\n", tp->mac_version);
 }
 
-static void rtl8169_get_phy_version(struct rtl8169_private *tp, void __iomem 
*ioaddr)
-{
-       const struct {
-               u16 mask;
-               u16 set;
-               int phy_version;
-       } phy_info[] = {
-               { 0x000f, 0x0002, RTL_GIGA_PHY_VER_G },
-               { 0x000f, 0x0001, RTL_GIGA_PHY_VER_F },
-               { 0x000f, 0x0000, RTL_GIGA_PHY_VER_E },
-               { 0x0000, 0x0000, RTL_GIGA_PHY_VER_D } /* Catch-all */
-       }, *p = phy_info;
+struct phy_reg {
        u16 reg;
-
-       reg = mdio_read(ioaddr, MII_PHYSID2) & 0xffff;
-       while ((reg & p->mask) != p->set)
-               p++;
-       tp->phy_version = p->phy_version;
-}
-
-static void rtl8169_print_phy_version(struct rtl8169_private *tp)
-{
-       struct {
-               int version;
-               char *msg;
-               u32 reg;
-       } phy_print[] = {
-               { RTL_GIGA_PHY_VER_G, "RTL_GIGA_PHY_VER_G", 0x0002 },
-               { RTL_GIGA_PHY_VER_F, "RTL_GIGA_PHY_VER_F", 0x0001 },
-               { RTL_GIGA_PHY_VER_E, "RTL_GIGA_PHY_VER_E", 0x0000 },
-               { RTL_GIGA_PHY_VER_D, "RTL_GIGA_PHY_VER_D", 0x0000 },
-               { 0, NULL, 0x0000 }
-       }, *p;
-
-       for (p = phy_print; p->msg; p++) {
-               if (tp->phy_version == p->version) {
-                       dprintk("phy_version == %s (%04x)\n", p->msg, p->reg);
-                       return;
-               }
-       }
-       dprintk("phy_version == Unknown\n");
-}
-
-static void rtl8169_hw_phy_config(struct net_device *dev)
-{
-       struct rtl8169_private *tp = netdev_priv(dev);
-       void __iomem *ioaddr = tp->mmio_addr;
+       u16 val;
+};
+
+static void rtl_phy_write(void __iomem *ioaddr, struct phy_reg *regs, int len)
+{
+       while (len-- > 0) {
+               mdio_write(ioaddr, regs->reg, regs->val);
+               regs++;
+       }
+}
+
+static void rtl8169s_hw_phy_config(void __iomem *ioaddr)
+{
        struct {
                u16 regs[5]; /* Beware of bit-sign propagation */
        } phy_magic[5] = { {
@@ -1268,32 +1361,11 @@ static void rtl8169_hw_phy_config(struct
                  0xbf00 }      //w 0 15 0 bf00
                }
        }, *p = phy_magic;
-       int i;
-
-       rtl8169_print_mac_version(tp);
-       rtl8169_print_phy_version(tp);
-
-       if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
-               return;
-       if (tp->phy_version >= RTL_GIGA_PHY_VER_H)
-               return;
-
-       dprintk("MAC version != 0 && PHY version == 0 or 1\n");
-       dprintk("Do final_reg2.cfg\n");
-
-       /* Shazam ! */
-
-       if (tp->mac_version == RTL_GIGA_MAC_VER_04) {
-               mdio_write(ioaddr, 31, 0x0002);
-               mdio_write(ioaddr,  1, 0x90d0);
-               mdio_write(ioaddr, 31, 0x0000);
-               return;
-       }
-
-       /* phy config for RTL8169s mac_version C chip */
-       mdio_write(ioaddr, 31, 0x0001);                 //w 31 2 0 1
-       mdio_write(ioaddr, 21, 0x1000);                 //w 21 15 0 1000
-       mdio_write(ioaddr, 24, 0x65c7);                 //w 24 15 0 65c7
+       unsigned int i;
+
+       mdio_write(ioaddr, 0x1f, 0x0001);               //w 31 2 0 1
+       mdio_write(ioaddr, 0x15, 0x1000);               //w 21 15 0 1000
+       mdio_write(ioaddr, 0x18, 0x65c7);               //w 24 15 0 65c7
        rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0);   //w 4 11 11 0
 
        for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) {
@@ -1306,7 +1378,299 @@ static void rtl8169_hw_phy_config(struct
                rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1
                rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
        }
-       mdio_write(ioaddr, 31, 0x0000); //w 31 2 0 0
+       mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0
+}
+
+static void rtl8169sb_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0002 },
+               { 0x01, 0x90d0 },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168bb_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x10, 0xf41b },
+               { 0x1f, 0x0000 }
+       };
+
+       mdio_write(ioaddr, 0x1f, 0x0001);
+       mdio_patch(ioaddr, 0x16, 1 << 0);
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168bef_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0001 },
+               { 0x10, 0xf41b },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cp_1_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0000 },
+               { 0x1d, 0x0f00 },
+               { 0x1f, 0x0002 },
+               { 0x0c, 0x1ec8 },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cp_2_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0001 },
+               { 0x1d, 0x3d98 },
+               { 0x1f, 0x0000 }
+       };
+
+       mdio_write(ioaddr, 0x1f, 0x0000);
+       mdio_patch(ioaddr, 0x14, 1 << 5);
+       mdio_patch(ioaddr, 0x0d, 1 << 5);
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168c_1_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0001 },
+               { 0x12, 0x2300 },
+               { 0x1f, 0x0002 },
+               { 0x00, 0x88d4 },
+               { 0x01, 0x82b1 },
+               { 0x03, 0x7002 },
+               { 0x08, 0x9e30 },
+               { 0x09, 0x01f0 },
+               { 0x0a, 0x5500 },
+               { 0x0c, 0x00c8 },
+               { 0x1f, 0x0003 },
+               { 0x12, 0xc096 },
+               { 0x16, 0x000a },
+               { 0x1f, 0x0000 },
+               { 0x1f, 0x0000 },
+               { 0x09, 0x2000 },
+               { 0x09, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+       mdio_patch(ioaddr, 0x14, 1 << 5);
+       mdio_patch(ioaddr, 0x0d, 1 << 5);
+       mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_2_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0001 },
+               { 0x12, 0x2300 },
+               { 0x03, 0x802f },
+               { 0x02, 0x4f02 },
+               { 0x01, 0x0409 },
+               { 0x00, 0xf099 },
+               { 0x04, 0x9800 },
+               { 0x04, 0x9000 },
+               { 0x1d, 0x3d98 },
+               { 0x1f, 0x0002 },
+               { 0x0c, 0x7eb8 },
+               { 0x06, 0x0761 },
+               { 0x1f, 0x0003 },
+               { 0x16, 0x0f0a },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+       mdio_patch(ioaddr, 0x16, 1 << 0);
+       mdio_patch(ioaddr, 0x14, 1 << 5);
+       mdio_patch(ioaddr, 0x0d, 1 << 5);
+       mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_3_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0001 },
+               { 0x12, 0x2300 },
+               { 0x1d, 0x3d98 },
+               { 0x1f, 0x0002 },
+               { 0x0c, 0x7eb8 },
+               { 0x06, 0x5461 },
+               { 0x1f, 0x0003 },
+               { 0x16, 0x0f0a },
+               { 0x1f, 0x0000 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+       mdio_patch(ioaddr, 0x16, 1 << 0);
+       mdio_patch(ioaddr, 0x14, 1 << 5);
+       mdio_patch(ioaddr, 0x0d, 1 << 5);
+       mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_4_hw_phy_config(void __iomem *ioaddr)
+{
+       rtl8168c_3_hw_phy_config(ioaddr);
+}
+
+static void rtl8168d_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init_0[] = {
+               { 0x1f, 0x0001 },
+               { 0x09, 0x2770 },
+               { 0x08, 0x04d0 },
+               { 0x0b, 0xad15 },
+               { 0x0c, 0x5bf0 },
+               { 0x1c, 0xf101 },
+               { 0x1f, 0x0003 },
+               { 0x14, 0x94d7 },
+               { 0x12, 0xf4d6 },
+               { 0x09, 0xca0f },
+               { 0x1f, 0x0002 },
+               { 0x0b, 0x0b10 },
+               { 0x0c, 0xd1f7 },
+               { 0x1f, 0x0002 },
+               { 0x06, 0x5461 },
+               { 0x1f, 0x0002 },
+               { 0x05, 0x6662 },
+               { 0x1f, 0x0000 },
+               { 0x14, 0x0060 },
+               { 0x1f, 0x0000 },
+               { 0x0d, 0xf8a0 },
+               { 0x1f, 0x0005 },
+               { 0x05, 0xffc2 }
+       };
+
+       rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
+
+       if (mdio_read(ioaddr, 0x06) == 0xc400) {
+               struct phy_reg phy_reg_init_1[] = {
+                       { 0x1f, 0x0005 },
+                       { 0x01, 0x0300 },
+                       { 0x1f, 0x0000 },
+                       { 0x11, 0x401c },
+                       { 0x16, 0x4100 },
+                       { 0x1f, 0x0005 },
+                       { 0x07, 0x0010 },
+                       { 0x05, 0x83dc },
+                       { 0x06, 0x087d },
+                       { 0x05, 0x8300 },
+                       { 0x06, 0x0101 },
+                       { 0x06, 0x05f8 },
+                       { 0x06, 0xf9fa },
+                       { 0x06, 0xfbef },
+                       { 0x06, 0x79e2 },
+                       { 0x06, 0x835f },
+                       { 0x06, 0xe0f8 },
+                       { 0x06, 0x9ae1 },
+                       { 0x06, 0xf89b },
+                       { 0x06, 0xef31 },
+                       { 0x06, 0x3b65 },
+                       { 0x06, 0xaa07 },
+                       { 0x06, 0x81e4 },
+                       { 0x06, 0xf89a },
+                       { 0x06, 0xe5f8 },
+                       { 0x06, 0x9baf },
+                       { 0x06, 0x06ae },
+                       { 0x05, 0x83dc },
+                       { 0x06, 0x8300 },
+               };
+
+               rtl_phy_write(ioaddr, phy_reg_init_1,
+                             ARRAY_SIZE(phy_reg_init_1));
+       }
+
+       mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8102e_hw_phy_config(void __iomem *ioaddr)
+{
+       struct phy_reg phy_reg_init[] = {
+               { 0x1f, 0x0003 },
+               { 0x08, 0x441d },
+               { 0x01, 0x9100 },
+               { 0x1f, 0x0000 }
+       };
+
+       mdio_write(ioaddr, 0x1f, 0x0000);
+       mdio_patch(ioaddr, 0x11, 1 << 12);
+       mdio_patch(ioaddr, 0x19, 1 << 13);
+
+       rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl_hw_phy_config(struct net_device *dev)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+
+       rtl8169_print_mac_version(tp);
+
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_01:
+               break;
+       case RTL_GIGA_MAC_VER_02:
+       case RTL_GIGA_MAC_VER_03:
+               rtl8169s_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_04:
+               rtl8169sb_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_07:
+       case RTL_GIGA_MAC_VER_08:
+       case RTL_GIGA_MAC_VER_09:
+               rtl8102e_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_11:
+               rtl8168bb_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_12:
+               rtl8168bef_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_17:
+               rtl8168bef_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_18:
+               rtl8168cp_1_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_19:
+               rtl8168c_1_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_20:
+               rtl8168c_2_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_21:
+               rtl8168c_3_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_22:
+               rtl8168c_4_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_23:
+       case RTL_GIGA_MAC_VER_24:
+               rtl8168cp_2_hw_phy_config(ioaddr);
+               break;
+       case RTL_GIGA_MAC_VER_25:
+               rtl8168d_hw_phy_config(ioaddr);
+               break;
+
+       default:
+               break;
+       }
 }
 
 static void rtl8169_phy_timer(unsigned long __opaque)
@@ -1318,7 +1682,6 @@ static void rtl8169_phy_timer(unsigned l
        unsigned long timeout = RTL8169_PHY_TIMEOUT;
 
        assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
-       assert(tp->phy_version < RTL_GIGA_PHY_VER_H);
 
        if (!(tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL))
                return;
@@ -1353,8 +1716,7 @@ static inline void rtl8169_delete_timer(
        struct rtl8169_private *tp = netdev_priv(dev);
        struct timer_list *timer = &tp->timer;
 
-       if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) ||
-           (tp->phy_version >= RTL_GIGA_PHY_VER_H))
+       if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
                return;
 
        del_timer_sync(timer);
@@ -1365,15 +1727,10 @@ static inline void rtl8169_request_timer
        struct rtl8169_private *tp = netdev_priv(dev);
        struct timer_list *timer = &tp->timer;
 
-       if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) ||
-           (tp->phy_version >= RTL_GIGA_PHY_VER_H))
+       if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
                return;
 
-       init_timer(timer);
-       timer->expires = jiffies + RTL8169_PHY_TIMEOUT;
-       timer->data = (unsigned long)(dev);
-       timer->function = rtl8169_phy_timer;
-       add_timer(timer);
+       mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT);
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1406,7 +1763,7 @@ static void rtl8169_phy_reset(struct net
                              struct rtl8169_private *tp)
 {
        void __iomem *ioaddr = tp->mmio_addr;
-       int i;
+       unsigned int i;
 
        tp->phy_reset_enable(ioaddr);
        for (i = 0; i < 100; i++) {
@@ -1421,21 +1778,18 @@ static void rtl8169_init_phy(struct net_
 static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private 
*tp)
 {
        void __iomem *ioaddr = tp->mmio_addr;
-       static int board_idx = -1;
-       u8 autoneg, duplex;
-       u16 speed;
-
-       board_idx++;
-
-       rtl8169_hw_phy_config(dev);
-
-       dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
-       RTL_W8(0x82, 0x01);
-
-       if (tp->mac_version < RTL_GIGA_MAC_VER_03) {
-               dprintk("Set PCI Latency=0x40\n");
-               pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
-       }
+
+       rtl_hw_phy_config(dev);
+
+       if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
+               dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
+               RTL_W8(0x82, 0x01);
+       }
+
+       pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
+
+       if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+               pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
 
        if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
                dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
@@ -1444,24 +1798,62 @@ static void rtl8169_init_phy(struct net_
                mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
        }
 
-       rtl8169_link_option(board_idx, &autoneg, &speed, &duplex);
-
        rtl8169_phy_reset(dev, tp);
 
-       rtl8169_set_speed(dev, autoneg, speed, duplex);
+       /*
+        * rtl8169_set_speed_xmii takes good care of the Fast Ethernet
+        * only 8101. Don't panic.
+        */
+       rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL);
 
        if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp))
                printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);
 }
 
+static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
+{
+       void __iomem *ioaddr = tp->mmio_addr;
+       u32 high;
+       u32 low;
+
+       low  = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
+       high = addr[4] | (addr[5] << 8);
+
+       spin_lock_irq(&tp->lock);
+
+       RTL_W8(Cfg9346, Cfg9346_Unlock);
+       RTL_W32(MAC0, low);
+       RTL_W32(MAC4, high);
+       RTL_W8(Cfg9346, Cfg9346_Lock);
+
+       spin_unlock_irq(&tp->lock);
+}
+
+static int rtl_set_mac_address(struct net_device *dev, void *p)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       struct sockaddr *addr = p;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+       rtl_rar_set(tp, dev->dev_addr);
+
+       return 0;
+}
+
 static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        struct mii_ioctl_data *data = if_mii(ifr);
 
-       if (!netif_running(dev))
-               return -ENODEV;
-
+       return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV;
+}
+
+static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data 
*data, int cmd)
+{
        switch (cmd) {
        case SIOCGMIIPHY:
                data->phy_id = 32; /* Internal PHY */
@@ -1480,15 +1872,87 @@ static int rtl8169_ioctl(struct net_devi
        return -EOPNOTSUPP;
 }
 
+static int rtl_tbi_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data 
*data, int cmd)
+{
+       return -EOPNOTSUPP;
+}
+
+static const struct rtl_cfg_info {
+       void (*hw_start)(struct net_device *);
+       unsigned int region;
+       unsigned int align;
+       u16 intr_event;
+       u16 napi_event;
+       unsigned features;
+} rtl_cfg_infos [] = {
+       [RTL_CFG_0] = {
+               .hw_start       = rtl_hw_start_8169,
+               .region         = 1,
+               .align          = 0,
+               .intr_event     = SYSErr | LinkChg | RxOverflow |
+                                 RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+               .napi_event     = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+               .features       = RTL_FEATURE_GMII
+       },
+       [RTL_CFG_1] = {
+               .hw_start       = rtl_hw_start_8168,
+               .region         = 2,
+               .align          = 8,
+               .intr_event     = SYSErr | LinkChg | RxOverflow |
+                                 TxErr | TxOK | RxOK | RxErr,
+               .napi_event     = TxErr | TxOK | RxOK | RxOverflow,
+               .features       = RTL_FEATURE_GMII | RTL_FEATURE_MSI
+       },
+       [RTL_CFG_2] = {
+               .hw_start       = rtl_hw_start_8101,
+               .region         = 2,
+               .align          = 8,
+               .intr_event     = SYSErr | LinkChg | RxOverflow | PCSTimeout |
+                                 RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+               .napi_event     = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+               .features       = RTL_FEATURE_MSI
+       }
+};
+
+/* Cfg9346_Unlock assumed. */
+static unsigned rtl_try_msi(struct pci_dev *pdev, void __iomem *ioaddr,
+                           const struct rtl_cfg_info *cfg)
+{
+       unsigned msi = 0;
+       u8 cfg2;
+
+       cfg2 = RTL_R8(Config2) & ~MSIEnable;
+       if (cfg->features & RTL_FEATURE_MSI) {
+               if (pci_enable_msi(pdev)) {
+                       dev_info(&pdev->dev, "no MSI. Back to INTx.\n");
+               } else {
+                       cfg2 |= MSIEnable;
+                       msi = RTL_FEATURE_MSI;
+               }
+       }
+       RTL_W8(Config2, cfg2);
+       return msi;
+}
+
+static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp)
+{
+       if (tp->features & RTL_FEATURE_MSI) {
+               pci_disable_msi(pdev);
+               tp->features &= ~RTL_FEATURE_MSI;
+       }
+}
+
 static int __devinit
 rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
-       const unsigned int region = rtl_cfg_info[ent->driver_data].region;
+       const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;
+       const unsigned int region = cfg->region;
        struct rtl8169_private *tp;
+       struct mii_if_info *mii;
        struct net_device *dev;
        void __iomem *ioaddr;
-       unsigned int pm_cap;
-       int i, rc;
+       unsigned int i;
+       int rc;
 
        if (netif_msg_drv(&debug)) {
                printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
@@ -1503,11 +1967,19 @@ rtl8169_init_one(struct pci_dev *pdev, c
                goto out;
        }
 
-       SET_MODULE_OWNER(dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
        tp = netdev_priv(dev);
        tp->dev = dev;
+       tp->pci_dev = pdev;
        tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
+
+       mii = &tp->mii;
+       mii->dev = dev;
+       mii->mdio_read = rtl_mdio_read;
+       mii->mdio_write = rtl_mdio_write;
+       mii->phy_id_mask = 0x1f;
+       mii->reg_num_mask = 0x1f;
+       mii->supports_gmii = !!(cfg->features & RTL_FEATURE_GMII);
 
        /* enable device (incl. PCI PM wakeup and hotplug setup) */
        rc = pci_enable_device(pdev);
@@ -1520,20 +1992,6 @@ rtl8169_init_one(struct pci_dev *pdev, c
        rc = pci_set_mwi(pdev);
        if (rc < 0)
                goto err_out_disable_2;
-
-       /* save power state before pci_enable_device overwrites it */
-       pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
-       if (pm_cap) {
-               u16 pwr_command, acpi_idle_state;
-
-               pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
-               acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
-       } else {
-               if (netif_msg_probe(tp)) {
-                       dev_err(&pdev->dev,
-                               "PowerManagement capability not found.\n");
-               }
-       }
 
        /* make sure PCI base addr 1 is MMIO */
        if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {
@@ -1591,6 +2049,10 @@ rtl8169_init_one(struct pci_dev *pdev, c
                goto err_out_free_res_4;
        }
 
+       tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+       if (!tp->pcie_cap && netif_msg_probe(tp))
+               dev_info(&pdev->dev, "no PCI Express capability\n");
+
        /* Unneeded ? Don't mess with Mrs. Murphy. */
        rtl8169_irq_mask_and_ack(ioaddr);
 
@@ -1598,7 +2060,7 @@ rtl8169_init_one(struct pci_dev *pdev, c
        RTL_W8(ChipCmd, CmdReset);
 
        /* Check that the chip has finished the reset. */
-       for (i = 100; i > 0; i--) {
+       for (i = 0; i < 100; i++) {
                if ((RTL_R8(ChipCmd) & CmdReset) == 0)
                        break;
                msleep_interruptible(1);
@@ -1606,37 +2068,42 @@ rtl8169_init_one(struct pci_dev *pdev, c
 
        /* Identify chip attached to board */
        rtl8169_get_mac_version(tp, ioaddr);
-       rtl8169_get_phy_version(tp, ioaddr);
 
        rtl8169_print_mac_version(tp);
-       rtl8169_print_phy_version(tp);
-
-       for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) {
+
+       for (i = 0; i < ARRAY_SIZE(rtl_chip_info); i++) {
                if (tp->mac_version == rtl_chip_info[i].mac_version)
                        break;
        }
-       if (i < 0) {
+       if (i == ARRAY_SIZE(rtl_chip_info)) {
                /* Unknown chip: assume array element #0, original RTL-8169 */
                if (netif_msg_probe(tp)) {
                        dev_printk(KERN_DEBUG, &pdev->dev,
                                "unknown chip version, assuming %s\n",
                                rtl_chip_info[0].name);
                }
-               i++;
+               i = 0;
        }
        tp->chipset = i;
 
        RTL_W8(Cfg9346, Cfg9346_Unlock);
        RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
        RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
+       if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
+               tp->features |= RTL_FEATURE_WOL;
+       if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
+               tp->features |= RTL_FEATURE_WOL;
+       tp->features |= rtl_try_msi(pdev, ioaddr, cfg);
        RTL_W8(Cfg9346, Cfg9346_Lock);
 
-       if (RTL_R8(PHYstatus) & TBI_Enable) {
+       if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) &&
+           (RTL_R8(PHYstatus) & TBI_Enable)) {
                tp->set_speed = rtl8169_set_speed_tbi;
                tp->get_settings = rtl8169_gset_tbi;
                tp->phy_reset_enable = rtl8169_tbi_reset_enable;
                tp->phy_reset_pending = rtl8169_tbi_reset_pending;
                tp->link_ok = rtl8169_tbi_link_ok;
+               tp->do_ioctl = rtl_tbi_ioctl;
 
                tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */
        } else {
@@ -1645,11 +2112,15 @@ rtl8169_init_one(struct pci_dev *pdev, c
                tp->phy_reset_enable = rtl8169_xmii_reset_enable;
                tp->phy_reset_pending = rtl8169_xmii_reset_pending;
                tp->link_ok = rtl8169_xmii_link_ok;
-
+               tp->do_ioctl = rtl_xmii_ioctl;
                dev->do_ioctl = rtl8169_ioctl;
        }
 
-       /* Get MAC address.  FIXME: read EEPROM */
+       spin_lock_init(&tp->lock);
+
+       tp->mmio_addr = ioaddr;
+
+       /* Get MAC address */
        for (i = 0; i < MAC_ADDR_LEN; i++)
                dev->dev_addr[i] = RTL_R8(MAC0 + i);
        memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
@@ -1660,21 +2131,19 @@ rtl8169_init_one(struct pci_dev *pdev, c
        SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
        dev->stop = rtl8169_close;
        dev->tx_timeout = rtl8169_tx_timeout;
-       dev->set_multicast_list = rtl8169_set_rx_mode;
        dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
        dev->irq = pdev->irq;
        dev->base_addr = (unsigned long) ioaddr;
        dev->change_mtu = rtl8169_change_mtu;
-
-#ifdef CONFIG_R8169_NAPI
+       dev->set_mac_address = rtl_set_mac_address;
+       dev->set_multicast_list = rtl_set_rx_mode;
+
        dev->poll = rtl8169_poll;
        dev->weight = R8169_NAPI_WEIGHT;
-#endif
 
 #ifdef CONFIG_R8169_VLAN
        dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
        dev->vlan_rx_register = rtl8169_vlan_rx_register;
-       dev->vlan_rx_kill_vid = rtl8169_vlan_rx_kill_vid;
 #endif
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1682,36 +2151,43 @@ rtl8169_init_one(struct pci_dev *pdev, c
 #endif
 
        tp->intr_mask = 0xffff;
-       tp->pci_dev = pdev;
-       tp->mmio_addr = ioaddr;
-       tp->align = rtl_cfg_info[ent->driver_data].align;
-
-       spin_lock_init(&tp->lock);
+       tp->align = cfg->align;
+       tp->hw_start = cfg->hw_start;
+       tp->intr_event = cfg->intr_event;
+       tp->napi_event = cfg->napi_event;
+
+       init_timer(&tp->timer);
+       tp->timer.data = (unsigned long) dev;
+       tp->timer.function = rtl8169_phy_timer;
 
        rc = register_netdev(dev);
        if (rc < 0)
-               goto err_out_unmap_5;
+               goto err_out_msi_5;
 
        pci_set_drvdata(pdev, dev);
 
        if (netif_msg_probe(tp)) {
+               u32 xid = RTL_R32(TxConfig) & 0x7cf0f8ff;
+
                printk(KERN_INFO "%s: %s at 0x%lx, "
                       "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
-                      "IRQ %d\n",
+                      "XID %08x IRQ %d\n",
                       dev->name,
                       rtl_chip_info[tp->chipset].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);
+                      dev->dev_addr[4], dev->dev_addr[5], xid, dev->irq);
        }
 
        rtl8169_init_phy(dev, tp);
+       device_set_wakeup_enable(&pdev->dev, tp->features & RTL_FEATURE_WOL);
 
 out:
        return rc;
 
-err_out_unmap_5:
+err_out_msi_5:
+       rtl_disable_msi(pdev, tp);
        iounmap(ioaddr);
 err_out_free_res_4:
        pci_release_regions(pdev);
@@ -1724,16 +2200,15 @@ err_out_free_dev_1:
        goto out;
 }
 
-static void __devexit
-rtl8169_remove_one(struct pci_dev *pdev)
+static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct rtl8169_private *tp = netdev_priv(dev);
 
-       assert(dev != NULL);
-       assert(tp != NULL);
+       flush_scheduled_work();
 
        unregister_netdev(dev);
+       rtl_disable_msi(pdev, tp);
        rtl8169_release_board(pdev, dev, tp->mmio_addr);
        pci_set_drvdata(pdev, NULL);
 }
@@ -1750,16 +2225,10 @@ static int rtl8169_open(struct net_devic
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        struct pci_dev *pdev = tp->pci_dev;
-       int retval;
+       int retval = -ENOMEM;
+
 
        rtl8169_set_rxbufsize(tp, dev);
-
-       retval =
-           request_irq(dev->irq, rtl8169_interrupt, IRQF_SHARED, dev->name, 
dev);
-       if (retval < 0)
-               goto out;
-
-       retval = -ENOMEM;
 
        /*
         * Rx and Tx desscriptors needs 256 bytes alignment.
@@ -1768,20 +2237,30 @@ static int rtl8169_open(struct net_devic
        tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES,
                                               &tp->TxPhyAddr);
        if (!tp->TxDescArray)
-               goto err_free_irq;
+               goto out;
 
        tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES,
                                               &tp->RxPhyAddr);
        if (!tp->RxDescArray)
-               goto err_free_tx;
+               goto err_free_tx_0;
 
        retval = rtl8169_init_ring(dev);
        if (retval < 0)
-               goto err_free_rx;
+               goto err_free_rx_1;
 
        INIT_WORK(&tp->task, NULL, dev);
 
-       rtl8169_hw_start(dev);
+       smp_mb();
+
+       retval = request_irq(dev->irq, rtl8169_interrupt,
+                            (tp->features & RTL_FEATURE_MSI) ? 0 : IRQF_SHARED,
+                            dev->name, dev);
+       if (retval < 0)
+               goto err_release_ring_2;
+
+       netif_poll_enable(dev);
+
+       rtl_hw_start(dev);
 
        rtl8169_request_timer(dev);
 
@@ -1789,14 +2268,14 @@ out:
 out:
        return retval;
 
-err_free_rx:
+err_release_ring_2:
+       rtl8169_rx_clear(tp);
+err_free_rx_1:
        pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
                            tp->RxPhyAddr);
-err_free_tx:
+err_free_tx_0:
        pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,
                            tp->TxPhyAddr);
-err_free_irq:
-       free_irq(dev->irq, dev);
        goto out;
 }
 
@@ -1812,7 +2291,7 @@ static void rtl8169_hw_reset(void __iome
        RTL_R8(ChipCmd);
 }
 
-static void rtl8169_set_rx_tx_config_registers(struct rtl8169_private *tp)
+static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
 {
        void __iomem *ioaddr = tp->mmio_addr;
        u32 cfg = rtl8169_rx_config;
@@ -1825,45 +2304,90 @@ static void rtl8169_set_rx_tx_config_reg
                (InterFrameGap << TxInterFrameGapShift));
 }
 
-static void rtl8169_hw_start(struct net_device *dev)
+static void rtl_hw_start(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
-       struct pci_dev *pdev = tp->pci_dev;
-       u16 cmd;
-       u32 i;
+       unsigned int i;
 
        /* Soft reset the chip. */
        RTL_W8(ChipCmd, CmdReset);
 
        /* Check that the chip has finished the reset. */
-       for (i = 100; i > 0; i--) {
+       for (i = 0; i < 100; i++) {
                if ((RTL_R8(ChipCmd) & CmdReset) == 0)
                        break;
                msleep_interruptible(1);
        }
 
+       tp->hw_start(dev);
+
+       netif_start_queue(dev);
+}
+
+
+static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
+                                        void __iomem *ioaddr)
+{
+       /*
+        * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
+        * register to be written before TxDescAddrLow to work.
+        * Switching from MMIO to I/O access fixes the issue as well.
+        */
+       RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
+       RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_32BIT_MASK);
+       RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
+       RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_32BIT_MASK);
+}
+
+static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
+{
+       u16 cmd;
+
+       cmd = RTL_R16(CPlusCmd);
+       RTL_W16(CPlusCmd, cmd);
+       return cmd;
+}
+
+static void rtl_set_rx_max_size(void __iomem *ioaddr)
+{
+       /* Low hurts. Let's disable the filtering. */
+       RTL_W16(RxMaxSize, 16383);
+}
+
+static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
+{
+       struct {
+               u32 mac_version;
+               u32 clk;
+               u32 val;
+       } cfg2_info [] = {
+               { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
+               { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
+               { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
+               { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
+       }, *p = cfg2_info;
+       unsigned int i;
+       u32 clk;
+
+       clk = RTL_R8(Config2) & PCI_Clock_66MHz;
+       for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
+               if ((p->mac_version == mac_version) && (p->clk == clk)) {
+                       RTL_W32(0x7c, p->val);
+                       break;
+               }
+       }
+}
+
+static void rtl_hw_start_8169(struct net_device *dev)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       struct pci_dev *pdev = tp->pci_dev;
+
        if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
                RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
                pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
-       }
-
-       if (tp->mac_version == RTL_GIGA_MAC_VER_13) {
-               pci_write_config_word(pdev, 0x68, 0x00);
-               pci_write_config_word(pdev, 0x69, 0x08);
-       }
-
-       /* Undocumented stuff. */
-       if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
-               /* Realtek's r1000_n.c driver uses '&& 0x01' here. Well... */
-               if ((RTL_R8(Config2) & 0x07) & 0x01)
-                       RTL_W32(0x7c, 0x0007ffff);
-
-               RTL_W32(0x7c, 0x0007ff00);
-
-               pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-               cmd = cmd & 0xef;
-               pci_write_config_word(pdev, PCI_COMMAND, cmd);
        }
 
        RTL_W8(Cfg9346, Cfg9346_Unlock);
@@ -1875,28 +2399,26 @@ static void rtl8169_hw_start(struct net_
 
        RTL_W8(EarlyTxThres, EarlyTxThld);
 
-       /* Low hurts. Let's disable the filtering. */
-       RTL_W16(RxMaxSize, 16383);
+       rtl_set_rx_max_size(ioaddr);
 
        if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
            (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
            (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
            (tp->mac_version == RTL_GIGA_MAC_VER_04))
-               rtl8169_set_rx_tx_config_registers(tp);
-
-       cmd = RTL_R16(CPlusCmd);
-       RTL_W16(CPlusCmd, cmd);
-
-       tp->cp_cmd |= cmd | PCIMulRW;
+               rtl_set_rx_tx_config_registers(tp);
+
+       tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
 
        if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
            (tp->mac_version == RTL_GIGA_MAC_VER_03)) {
-               dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0. "
+               dprintk("Set MAC Reg C+CR Offset 0xE0. "
                        "Bit-3 and bit-14 MUST be 1\n");
                tp->cp_cmd |= (1 << 14);
        }
 
        RTL_W16(CPlusCmd, tp->cp_cmd);
+
+       rtl8169_set_magic_reg(ioaddr, tp->mac_version);
 
        /*
         * Undocumented corner. Supposedly:
@@ -1904,22 +2426,14 @@ static void rtl8169_hw_start(struct net_
         */
        RTL_W16(IntrMitigate, 0x0000);
 
-       /*
-        * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
-        * register to be written before TxDescAddrLow to work.
-        * Switching from MMIO to I/O access fixes the issue as well.
-        */
-       RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr >> 32));
-       RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr & DMA_32BIT_MASK));
-       RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr >> 32));
-       RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr & DMA_32BIT_MASK));
+       rtl_set_rx_tx_desc_registers(tp, ioaddr);
 
        if ((tp->mac_version != RTL_GIGA_MAC_VER_01) &&
            (tp->mac_version != RTL_GIGA_MAC_VER_02) &&
            (tp->mac_version != RTL_GIGA_MAC_VER_03) &&
            (tp->mac_version != RTL_GIGA_MAC_VER_04)) {
                RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
-               rtl8169_set_rx_tx_config_registers(tp);
+               rtl_set_rx_tx_config_registers(tp);
        }
 
        RTL_W8(Cfg9346, Cfg9346_Lock);
@@ -1929,15 +2443,406 @@ static void rtl8169_hw_start(struct net_
 
        RTL_W32(RxMissed, 0);
 
-       rtl8169_set_rx_mode(dev);
+       rtl_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);
+       RTL_W16(IntrMask, tp->intr_event);
+}
+
+static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct rtl8169_private *tp = netdev_priv(dev);
+       int cap = tp->pcie_cap;
+
+       if (cap) {
+               u16 ctl;
+
+               pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
+               ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
+               pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
+       }
+}
+
+static void rtl_csi_access_enable(void __iomem *ioaddr)
+{
+       u32 csi;
+
+       csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff;
+       rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000);
+}
+
+struct ephy_info {
+       unsigned int offset;
+       u16 mask;
+       u16 bits;
+};
+
+static void rtl_ephy_init(void __iomem *ioaddr, struct ephy_info *e, int len)
+{
+       u16 w;
+
+       while (len-- > 0) {
+               w = (rtl_ephy_read(ioaddr, e->offset) & ~e->mask) | e->bits;
+               rtl_ephy_write(ioaddr, e->offset, w);
+               e++;
+       }
+}
+
+#define R8168_CPCMD_QUIRK_MASK (\
+       EnableBist | \
+       Mac_dbgo_oe | \
+       Force_half_dup | \
+       Force_rxflow_en | \
+       Force_txflow_en | \
+       Cxpl_dbg_sel | \
+       ASF | \
+       PktCntrDisable | \
+       Mac_dbgo_sel)
+
+static void rtl_hw_start_8168bb(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+       RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+
+       rtl_tx_performance_tweak(pdev,
+               (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
+}
+
+static void rtl_hw_start_8168bef(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       rtl_hw_start_8168bb(ioaddr, pdev);
+
+       RTL_W8(EarlyTxThres, EarlyTxThld);
+
+       RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
+}
+
+static void __rtl_hw_start_8168cp(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       RTL_W8(Config1, RTL_R8(Config1) | Speed_down);
+
+       RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+       rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+       RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168cp_1(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       static struct ephy_info e_info_8168cp[] = {
+               { 0x01, 0,      0x0001 },
+               { 0x02, 0x0800, 0x1000 },
+               { 0x03, 0,      0x0042 },
+               { 0x06, 0x0080, 0x0000 },
+               { 0x07, 0,      0x2000 }
+       };
+
+       rtl_csi_access_enable(ioaddr);
+
+       rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
+
+       __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168cp_2(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       rtl_csi_access_enable(ioaddr);
+
+       RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+       rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+       RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168cp_3(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       rtl_csi_access_enable(ioaddr);
+
+       RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+       /* Magic. */
+       RTL_W8(DBG_REG, 0x20);
+
+       RTL_W8(EarlyTxThres, EarlyTxThld);
+
+       rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+       RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168c_1(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       static struct ephy_info e_info_8168c_1[] = {
+               { 0x02, 0x0800, 0x1000 },
+               { 0x03, 0,      0x0002 },
+               { 0x06, 0x0080, 0x0000 }
+       };
+
+       rtl_csi_access_enable(ioaddr);
+
+       RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
+
+       rtl_ephy_init(ioaddr, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1));
+
+       __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_2(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       static struct ephy_info e_info_8168c_2[] = {
+               { 0x01, 0,      0x0001 },
+               { 0x03, 0x0400, 0x0220 }
+       };
+
+       rtl_csi_access_enable(ioaddr);
+
+       rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
+
+       __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_3(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       rtl_hw_start_8168c_2(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_4(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       rtl_csi_access_enable(ioaddr);
+
+       __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168d(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       rtl_csi_access_enable(ioaddr);
+
+       RTL_W8(EarlyTxThres, EarlyTxThld);
+
+       rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+       RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168(struct net_device *dev)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       struct pci_dev *pdev = tp->pci_dev;
+
+       RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+       RTL_W8(EarlyTxThres, EarlyTxThld);
+
+       rtl_set_rx_max_size(ioaddr);
+
+       tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
+
+       RTL_W16(CPlusCmd, tp->cp_cmd);
+
+       RTL_W16(IntrMitigate, 0x5151);
+
+       /* Work around for RxFIFO overflow. */
+       if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
+               tp->intr_event |= RxFIFOOver | PCSTimeout;
+               tp->intr_event &= ~RxOverflow;
+       }
+
+       rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+       rtl_set_rx_mode(dev);
+
+       RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+               (InterFrameGap << TxInterFrameGapShift));
+
+       RTL_R8(IntrMask);
+
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_11:
+               rtl_hw_start_8168bb(ioaddr, pdev);
+       break;
+
+       case RTL_GIGA_MAC_VER_12:
+       case RTL_GIGA_MAC_VER_17:
+               rtl_hw_start_8168bef(ioaddr, pdev);
+       break;
+
+       case RTL_GIGA_MAC_VER_18:
+               rtl_hw_start_8168cp_1(ioaddr, pdev);
+       break;
+
+       case RTL_GIGA_MAC_VER_19:
+               rtl_hw_start_8168c_1(ioaddr, pdev);
+       break;
+
+       case RTL_GIGA_MAC_VER_20:
+               rtl_hw_start_8168c_2(ioaddr, pdev);
+       break;
+
+       case RTL_GIGA_MAC_VER_21:
+               rtl_hw_start_8168c_3(ioaddr, pdev);
+       break;
+
+       case RTL_GIGA_MAC_VER_22:
+               rtl_hw_start_8168c_4(ioaddr, pdev);
+       break;
+
+       case RTL_GIGA_MAC_VER_23:
+               rtl_hw_start_8168cp_2(ioaddr, pdev);
+       break;
+
+       case RTL_GIGA_MAC_VER_24:
+               rtl_hw_start_8168cp_3(ioaddr, pdev);
+       break;
+
+       case RTL_GIGA_MAC_VER_25:
+               rtl_hw_start_8168d(ioaddr, pdev);
+       break;
+
+       default:
+               printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
+                       dev->name, tp->mac_version);
+       break;
+       }
+
+       RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+       RTL_W8(Cfg9346, Cfg9346_Lock);
+
+       RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+       RTL_W16(IntrMask, tp->intr_event);
+}
+
+#define R810X_CPCMD_QUIRK_MASK (\
+       EnableBist | \
+       Mac_dbgo_oe | \
+       Force_half_dup | \
+       Force_half_dup | \
+       Force_txflow_en | \
+       Cxpl_dbg_sel | \
+       ASF | \
+       PktCntrDisable | \
+       PCIDAC | \
+       PCIMulRW)
+
+static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       static struct ephy_info e_info_8102e_1[] = {
+               { 0x01, 0, 0x6e65 },
+               { 0x02, 0, 0x091f },
+               { 0x03, 0, 0xc2f9 },
+               { 0x06, 0, 0xafb5 },
+               { 0x07, 0, 0x0e00 },
+               { 0x19, 0, 0xec80 },
+               { 0x01, 0, 0x2e65 },
+               { 0x01, 0, 0x6e65 }
+       };
+       u8 cfg1;
+
+       rtl_csi_access_enable(ioaddr);
+
+       RTL_W8(DBG_REG, FIX_NAK_1);
+
+       rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+       RTL_W8(Config1,
+              LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
+       RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+       cfg1 = RTL_R8(Config1);
+       if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
+               RTL_W8(Config1, cfg1 & ~LEDS0);
+
+       RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
+
+       rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
+}
+
+static void rtl_hw_start_8102e_2(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       rtl_csi_access_enable(ioaddr);
+
+       rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+       RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
+       RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+       RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8102e_3(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+       rtl_hw_start_8102e_2(ioaddr, pdev);
+
+       rtl_ephy_write(ioaddr, 0x03, 0xc2f9);
+}
+
+static void rtl_hw_start_8101(struct net_device *dev)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       struct pci_dev *pdev = tp->pci_dev;
+
+       if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+           (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
+               int cap = tp->pcie_cap;
+
+               if (cap) {
+                       pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL,
+                                             PCI_EXP_DEVCTL_NOSNOOP_EN);
+               }
+       }
+
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_07:
+               rtl_hw_start_8102e_1(ioaddr, pdev);
+               break;
+
+       case RTL_GIGA_MAC_VER_08:
+               rtl_hw_start_8102e_3(ioaddr, pdev);
+               break;
+
+       case RTL_GIGA_MAC_VER_09:
+               rtl_hw_start_8102e_2(ioaddr, pdev);
+               break;
+       }
+
+       RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+       RTL_W8(EarlyTxThres, EarlyTxThld);
+
+       rtl_set_rx_max_size(ioaddr);
+
+       tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
+
+       RTL_W16(CPlusCmd, tp->cp_cmd);
+
+       RTL_W16(IntrMitigate, 0x0000);
+
+       rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+       RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+       rtl_set_rx_tx_config_registers(tp);
+
+       RTL_W8(Cfg9346, Cfg9346_Lock);
+
+       RTL_R8(IntrMask);
+
+       rtl_set_rx_mode(dev);
+
+       RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+       RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
+
+       RTL_W16(IntrMask, tp->intr_event);
 }
 
 static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
@@ -1963,7 +2868,7 @@ static int rtl8169_change_mtu(struct net
 
        netif_poll_enable(dev);
 
-       rtl8169_hw_start(dev);
+       rtl_hw_start(dev);
 
        rtl8169_request_timer(dev);
 
@@ -1973,7 +2878,7 @@ out:
 
 static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
 {
-       desc->addr = 0x0badbadbadbadbadull;
+       desc->addr = cpu_to_le64(0x0badbadbadbadbadull);
        desc->opts1 &= ~cpu_to_le32(DescOwn | RsvdMask);
 }
 
@@ -2004,38 +2909,38 @@ static inline void rtl8169_map_to_asic(s
        rtl8169_mark_to_asic(desc, rx_buf_sz);
 }
 
-static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
-                               struct RxDesc *desc, int rx_buf_sz,
-                               unsigned int align)
+static struct sk_buff *rtl8169_alloc_rx_skb(struct pci_dev *pdev,
+                                           struct net_device *dev,
+                                           struct RxDesc *desc, int rx_buf_sz,
+                                           unsigned int align)
 {
        struct sk_buff *skb;
        dma_addr_t mapping;
-       int ret = 0;
-
-       skb = dev_alloc_skb(rx_buf_sz + align);
+       unsigned int pad;
+
+       pad = align ? align : NET_IP_ALIGN;
+
+       skb = netdev_alloc_skb(dev, rx_buf_sz + pad);
        if (!skb)
                goto err_out;
 
-       skb_reserve(skb, (align - 1) & (u32)skb->data);
-       *sk_buff = skb;
+       skb_reserve(skb, align ? ((pad - 1) & (unsigned long)skb->data) : pad);
 
        mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
                                 PCI_DMA_FROMDEVICE);
 
        rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
-
 out:
-       return ret;
+       return skb;
 
 err_out:
-       ret = -ENOMEM;
        rtl8169_make_unusable_by_asic(desc);
        goto out;
 }
 
 static void rtl8169_rx_clear(struct rtl8169_private *tp)
 {
-       int i;
+       unsigned int i;
 
        for (i = 0; i < NUM_RX_DESC; i++) {
                if (tp->Rx_skbuff[i]) {
@@ -2050,16 +2955,22 @@ static u32 rtl8169_rx_fill(struct rtl816
 {
        u32 cur;
 
-       for (cur = start; end - cur > 0; cur++) {
-               int ret, i = cur % NUM_RX_DESC;
+       for (cur = start; end - cur != 0; cur++) {
+               struct sk_buff *skb;
+               unsigned int i = cur % NUM_RX_DESC;
+
+               WARN_ON((s32)(end - cur) < 0);
 
                if (tp->Rx_skbuff[i])
                        continue;
 
-               ret = rtl8169_alloc_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
-                       tp->RxDescArray + i, tp->rx_buf_sz, tp->align);
-               if (ret < 0)
+               skb = rtl8169_alloc_rx_skb(tp->pci_dev, dev,
+                                          tp->RxDescArray + i,
+                                          tp->rx_buf_sz, tp->align);
+               if (!skb)
                        break;
+
+               tp->Rx_skbuff[i] = skb;
        }
        return cur - start;
 }
@@ -2151,32 +3062,36 @@ static void rtl8169_wait_for_quiescence(
 
        rtl8169_irq_mask_and_ack(ioaddr);
 
+       tp->intr_mask = 0xffff;
+       RTL_W16(IntrMask, tp->intr_event);
        netif_poll_enable(dev);
 }
 
 static void rtl8169_reinit_task(void *_data)
 {
        struct net_device *dev = _data;
+       struct rtl8169_private *tp = netdev_priv(dev);
        int ret;
 
-       if (netif_running(dev)) {
-               rtl8169_wait_for_quiescence(dev);
-               rtl8169_close(dev);
-       }
+       rtnl_lock();
+
+       if (!netif_running(dev))
+               goto out_unlock;
+
+       rtl8169_wait_for_quiescence(dev);
+       rtl8169_close(dev);
 
        ret = rtl8169_open(dev);
        if (unlikely(ret < 0)) {
-               if (net_ratelimit()) {
-                       struct rtl8169_private *tp = netdev_priv(dev);
-
-                       if (netif_msg_drv(tp)) {
-                               printk(PFX KERN_ERR
-                                      "%s: reinit failure (status = %d)."
-                                      " Rescheduling.\n", dev->name, ret);
-                       }
+               if (net_ratelimit() && netif_msg_drv(tp)) {
+                       printk(KERN_ERR PFX "%s: reinit failure (status = %d)."
+                              " Rescheduling.\n", dev->name, ret);
                }
                rtl8169_schedule_work(dev, rtl8169_reinit_task);
        }
+
+out_unlock:
+       rtnl_unlock();
 }
 
 static void rtl8169_reset_task(void *_data)
@@ -2184,8 +3099,10 @@ static void rtl8169_reset_task(void *_da
        struct net_device *dev = _data;
        struct rtl8169_private *tp = netdev_priv(dev);
 
+       rtnl_lock();
+
        if (!netif_running(dev))
-               return;
+               goto out_unlock;
 
        rtl8169_wait_for_quiescence(dev);
 
@@ -2194,19 +3111,19 @@ static void rtl8169_reset_task(void *_da
 
        if (tp->dirty_rx == tp->cur_rx) {
                rtl8169_init_ring_indexes(tp);
-               rtl8169_hw_start(dev);
+               rtl_hw_start(dev);
                netif_wake_queue(dev);
+               rtl8169_check_link_status(dev, tp, tp->mmio_addr);
        } else {
-               if (net_ratelimit()) {
-                       struct rtl8169_private *tp = netdev_priv(dev);
-
-                       if (netif_msg_intr(tp)) {
-                               printk(PFX KERN_EMERG
-                                      "%s: Rx buffers shortage\n", dev->name);
-                       }
+               if (net_ratelimit() && netif_msg_intr(tp)) {
+                       printk(KERN_EMERG PFX "%s: Rx buffers shortage\n",
+                              dev->name);
                }
                rtl8169_schedule_work(dev, rtl8169_reset_task);
        }
+
+out_unlock:
+       rtnl_unlock();
 }
 
 static void rtl8169_tx_timeout(struct net_device *dev)
@@ -2264,15 +3181,6 @@ static inline u32 rtl8169_tso_csum(struc
 
                if (mss)
                        return LargeSend | ((mss & MSSMask) << MSSShift);
-       }
-       if (skb->ip_summed == CHECKSUM_HW) {
-               const struct iphdr *ip = skb->nh.iph;
-
-               if (ip->protocol == IPPROTO_TCP)
-                       return IPCS | TCPCS;
-               else if (ip->protocol == IPPROTO_UDP)
-                       return IPCS | UDPCS;
-               WARN_ON(1);     /* we need a WARN() */
        }
        return 0;
 }
@@ -2308,13 +3216,6 @@ static int rtl8169_start_xmit(struct sk_
                opts1 |= FirstFrag;
        } else {
                len = skb->len;
-
-               if (unlikely(len < ETH_ZLEN)) {
-                       if (skb_padto(skb, ETH_ZLEN))
-                               goto err_update_stats;
-                       len = ETH_ZLEN;
-               }
-
                opts1 |= FirstFrag | LastFrag;
                tp->tx_skb[entry].skb = skb;
        }
@@ -2337,7 +3238,7 @@ static int rtl8169_start_xmit(struct sk_
 
        smp_wmb();
 
-       RTL_W8(TxPoll, 0x40);   /* set polling bit */
+       RTL_W8(TxPoll, NPQ);    /* set polling bit */
 
        if (TX_BUFFS_AVAIL(tp) < MAX_SKB_FRAGS) {
                netif_stop_queue(dev);
@@ -2352,7 +3253,6 @@ err_stop:
 err_stop:
        netif_stop_queue(dev);
        ret = NETDEV_TX_BUSY;
-err_update_stats:
        tp->stats.tx_dropped++;
        goto out;
 }
@@ -2407,15 +3307,11 @@ static void rtl8169_pcierr_interrupt(str
        rtl8169_schedule_work(dev, rtl8169_reinit_task);
 }
 
-static void
-rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
-                    void __iomem *ioaddr)
+static void rtl8169_tx_interrupt(struct net_device *dev,
+                                struct rtl8169_private *tp,
+                                void __iomem *ioaddr)
 {
        unsigned int dirty_tx, tx_left;
-
-       assert(dev != NULL);
-       assert(tp != NULL);
-       assert(ioaddr != NULL);
 
        dirty_tx = tp->dirty_tx;
        smp_rmb();
@@ -2452,6 +3348,15 @@ rtl8169_tx_interrupt(struct net_device *
                    (TX_BUFFS_AVAIL(tp) >= MAX_SKB_FRAGS)) {
                        netif_wake_queue(dev);
                }
+               /*
+                * 8168 hack: TxPoll requests are lost when the Tx packets are
+                * too close. Let's kick an extra TxPoll request when a burst
+                * of start_xmit activity is detected (if it is not detected,
+                * it is slow enough). -- FR
+                */
+               smp_rmb();
+               if (tp->cur_tx != dirty_tx)
+                       RTL_W8(TxPoll, NPQ);
        }
 }
 
@@ -2473,41 +3378,36 @@ static inline void rtl8169_rx_csum(struc
                skb->ip_summed = CHECKSUM_NONE;
 }
 
-static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
-                                     struct RxDesc *desc, int rx_buf_sz,
-                                     unsigned int align)
-{
-       int ret = -1;
-
-       if (pkt_size < rx_copybreak) {
-               struct sk_buff *skb;
-
-               skb = dev_alloc_skb(pkt_size + align);
-               if (skb) {
-                       skb_reserve(skb, (align - 1) & (u32)skb->data);
-                       eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
-                       *sk_buff = skb;
-                       rtl8169_mark_to_asic(desc, rx_buf_sz);
-                       ret = 0;
-               }
-       }
-       return ret;
-}
-
-static int
-rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
-                    void __iomem *ioaddr)
+static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, struct 
rtl8169_private *tp,
+                                     int pkt_size, dma_addr_t addr)
+{
+       struct sk_buff *skb;
+
+       if (pkt_size >= rx_copybreak)
+               return 0;
+
+       skb = netdev_alloc_skb(tp->dev, pkt_size + NET_IP_ALIGN);
+       if (!skb)
+               return 0;
+
+       pci_dma_sync_single_for_cpu(tp->pci_dev, addr, pkt_size,
+                                   PCI_DMA_FROMDEVICE);
+       skb_reserve(skb, NET_IP_ALIGN);
+       memcpy(skb->data, (*sk_buff)->data, pkt_size);
+       *sk_buff = skb;
+       return 1;
+}
+
+static int rtl8169_rx_interrupt(struct net_device *dev,
+                               struct rtl8169_private *tp,
+                               void __iomem *ioaddr)
 {
        unsigned int cur_rx, rx_left;
        unsigned int delta, count;
 
-       assert(dev != NULL);
-       assert(tp != NULL);
-       assert(ioaddr != NULL);
-
        cur_rx = tp->cur_rx;
        rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
-       rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota);
+       rx_left = min(rx_left, (u32) dev->quota);
 
        for (; rx_left > 0; rx_left--, cur_rx++) {
                unsigned int entry = cur_rx % NUM_RX_DESC;
@@ -2537,9 +3437,9 @@ rtl8169_rx_interrupt(struct net_device *
                        rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
                } else {
                        struct sk_buff *skb = tp->Rx_skbuff[entry];
+                       dma_addr_t addr = le64_to_cpu(desc->addr);
                        int pkt_size = (status & 0x00001FFF) - 4;
-                       void (*pci_action)(struct pci_dev *, dma_addr_t,
-                               size_t, int) = pci_dma_sync_single_for_device;
+                       struct pci_dev *pdev = tp->pci_dev;
 
                        /*
                         * The driver does not support incoming fragmented
@@ -2555,29 +3455,31 @@ rtl8169_rx_interrupt(struct net_device *
 
                        rtl8169_rx_csum(skb, desc);
 
-                       pci_dma_sync_single_for_cpu(tp->pci_dev,
-                               le64_to_cpu(desc->addr), tp->rx_buf_sz,
-                               PCI_DMA_FROMDEVICE);
-
-                       if (rtl8169_try_rx_copy(&skb, pkt_size, desc,
-                                               tp->rx_buf_sz, tp->align)) {
-                               pci_action = pci_unmap_single;
+                       if (rtl8169_try_rx_copy(&skb, tp, pkt_size, addr)) {
+                               pci_dma_sync_single_for_device(pdev, addr,
+                                       pkt_size, PCI_DMA_FROMDEVICE);
+                               rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
+                       } else {
+                               pci_unmap_single(pdev, addr, tp->rx_buf_sz,
+                                                PCI_DMA_FROMDEVICE);
                                tp->Rx_skbuff[entry] = NULL;
                        }
 
-                       pci_action(tp->pci_dev, le64_to_cpu(desc->addr),
-                                  tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
-                       skb->dev = dev;
                        skb_put(skb, pkt_size);
                        skb->protocol = eth_type_trans(skb, dev);
 
                        if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0)
-                               rtl8169_rx_skb(skb);
-
-                       dev->last_rx = jiffies;
+                               netif_receive_skb(skb);
+
                        tp->stats.rx_bytes += pkt_size;
                        tp->stats.rx_packets++;
+               }
+
+               /* Work around for AMD plateform. */
+               if ((desc->opts2 & cpu_to_le32(0xfffe000)) &&
+                   (tp->mac_version == RTL_GIGA_MAC_VER_05)) {
+                       desc->opts2 = 0;
+                       cur_rx++;
                }
        }
 
@@ -2602,83 +3504,65 @@ rtl8169_rx_interrupt(struct net_device *
        return count;
 }
 
-/* The interrupt handler does all of the Rx thread work and cleans up after 
the Tx thread. */
-static irqreturn_t
-rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
-{
-       struct net_device *dev = (struct net_device *) dev_instance;
-       struct rtl8169_private *tp = netdev_priv(dev);
-       int boguscnt = max_interrupt_work;
+static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance, struct 
pt_regs *regs)
+{
+       struct net_device *dev = dev_instance;
+       struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
+       int handled = 0;
        int status;
-       int handled = 0;
-
-       do {
-               status = RTL_R16(IntrStatus);
-
-               /* hotplug/major error/no more work/shared irq */
-               if ((status == 0xFFFF) || !status)
-                       break;
-
-               handled = 1;
-
-               if (unlikely(!netif_running(dev))) {
-                       rtl8169_asic_down(ioaddr);
-                       goto out;
-               }
-
-               status &= tp->intr_mask;
-               RTL_W16(IntrStatus,
-                       (status & RxFIFOOver) ? (status | RxOverflow) : status);
-
-               if (!(status & rtl8169_intr_mask))
-                       break;
-
-               if (unlikely(status & SYSErr)) {
-                       rtl8169_pcierr_interrupt(dev);
-                       break;
-               }
-
-               if (status & LinkChg)
-                       rtl8169_check_link_status(dev, tp, ioaddr);
-
-#ifdef CONFIG_R8169_NAPI
-               RTL_W16(IntrMask, rtl8169_intr_mask & ~rtl8169_napi_event);
-               tp->intr_mask = ~rtl8169_napi_event;
+
+       status = RTL_R16(IntrStatus);
+
+       /* hotplug/major error/no more work/shared irq */
+       if ((status == 0xffff) || !status)
+               goto out;
+
+       handled = 1;
+
+       if (unlikely(!netif_running(dev))) {
+               rtl8169_asic_down(ioaddr);
+               goto out;
+       }
+
+       status &= tp->intr_mask;
+       RTL_W16(IntrStatus,
+               (status & RxFIFOOver) ? (status | RxOverflow) : status);
+
+       if (!(status & tp->intr_event))
+               goto out;
+
+       /* Work around for rx fifo overflow */
+       if (unlikely(status & RxFIFOOver) &&
+           (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
+               netif_stop_queue(dev);
+               rtl8169_tx_timeout(dev);
+               goto out;
+       }
+
+       if (unlikely(status & SYSErr)) {
+               rtl8169_pcierr_interrupt(dev);
+               goto out;
+       }
+
+       if (status & LinkChg)
+               rtl8169_check_link_status(dev, tp, ioaddr);
+
+       if (status & tp->napi_event) {
+               RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
+               tp->intr_mask = ~tp->napi_event;
 
                if (likely(netif_rx_schedule_prep(dev)))
                        __netif_rx_schedule(dev);
                else if (netif_msg_intr(tp)) {
-                       printk(KERN_INFO "%s: interrupt %04x taken in poll\n",
+                       printk(KERN_INFO "%s: interrupt %04x in poll\n",
                               dev->name, status);
                }
-               break;
-#else
-               /* Rx interrupt */
-               if (status & (RxOK | RxOverflow | RxFIFOOver)) {
-                       rtl8169_rx_interrupt(dev, tp, ioaddr);
-               }
-               /* Tx interrupt */
-               if (status & (TxOK | TxErr))
-                       rtl8169_tx_interrupt(dev, tp, ioaddr);
-#endif
-
-               boguscnt--;
-       } while (boguscnt > 0);
-
-       if (boguscnt <= 0) {
-               if (netif_msg_intr(tp) && net_ratelimit() ) {
-                       printk(KERN_WARNING
-                              "%s: Too much work at interrupt!\n", dev->name);
-               }
-               /* Clear all interrupt sources. */
-               RTL_W16(IntrStatus, 0xffff);
        }
 out:
        return IRQ_RETVAL(handled);
 }
 
-#ifdef CONFIG_R8169_NAPI
 static int rtl8169_poll(struct net_device *dev, int *budget)
 {
        unsigned int work_done, work_to_do = min(*budget, dev->quota);
@@ -2701,43 +3585,45 @@ static int rtl8169_poll(struct net_devic
                 * write is safe - FR
                 */
                smp_wmb();
-               RTL_W16(IntrMask, rtl8169_intr_mask);
+               RTL_W16(IntrMask, tp->intr_event);
        }
 
        return (work_done >= work_to_do);
 }
-#endif
+
+static void rtl8169_rx_missed(struct net_device *dev, void __iomem *ioaddr)
+{
+       struct rtl8169_private *tp = netdev_priv(dev);
+
+       if (tp->mac_version > RTL_GIGA_MAC_VER_06)
+               return;
+
+       tp->stats.rx_missed_errors += (RTL_R32(RxMissed) & 0xffffff);
+       RTL_W32(RxMissed, 0);
+}
 
 static void rtl8169_down(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
-       unsigned int poll_locked = 0;
        unsigned int intrmask;
 
        rtl8169_delete_timer(dev);
 
        netif_stop_queue(dev);
 
-       flush_scheduled_work();
+       netif_poll_disable(dev);
 
 core_down:
        spin_lock_irq(&tp->lock);
 
        rtl8169_asic_down(ioaddr);
 
-       /* Update the error counts. */
-       tp->stats.rx_missed_errors += RTL_R32(RxMissed);
-       RTL_W32(RxMissed, 0);
+       rtl8169_rx_missed(dev, ioaddr);
 
        spin_unlock_irq(&tp->lock);
 
        synchronize_irq(dev->irq);
-
-       if (!poll_locked) {
-               netif_poll_disable(dev);
-               poll_locked++;
-       }
 
        /* Give a racing hard_start_xmit a few cycles to complete. */
        synchronize_sched();  /* FIXME: should this be synchronize_irq()? */
@@ -2769,11 +3655,12 @@ static int rtl8169_close(struct net_devi
        struct rtl8169_private *tp = netdev_priv(dev);
        struct pci_dev *pdev = tp->pci_dev;
 
+       /* update counters before going down */
+       rtl8169_update_counters(dev);
+
        rtl8169_down(dev);
 
        free_irq(dev->irq, dev);
-
-       netif_poll_enable(dev);
 
        pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
                            tp->RxPhyAddr);
@@ -2785,14 +3672,13 @@ static int rtl8169_close(struct net_devi
        return 0;
 }
 
-static void
-rtl8169_set_rx_mode(struct net_device *dev)
+static void rtl_set_rx_mode(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
        void __iomem *ioaddr = tp->mmio_addr;
        unsigned long flags;
        u32 mc_filter[2];       /* Multicast hash filter */
-       int i, rx_mode;
+       int rx_mode;
        u32 tmp = 0;
 
        if (dev->flags & IFF_PROMISC) {
@@ -2812,6 +3698,8 @@ rtl8169_set_rx_mode(struct net_device *d
                mc_filter[1] = mc_filter[0] = 0xffffffff;
        } else {
                struct dev_mc_list *mclist;
+               unsigned int i;
+
                rx_mode = AcceptBroadcast | AcceptMyPhys;
                mc_filter[1] = mc_filter[0] = 0;
                for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
@@ -2827,18 +3715,17 @@ rtl8169_set_rx_mode(struct net_device *d
        tmp = rtl8169_rx_config | rx_mode |
              (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
 
-       if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
-           (tp->mac_version == RTL_GIGA_MAC_VER_12) ||
-           (tp->mac_version == RTL_GIGA_MAC_VER_13) ||
-           (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
-           (tp->mac_version == RTL_GIGA_MAC_VER_15)) {
-               mc_filter[0] = 0xffffffff;
-               mc_filter[1] = 0xffffffff;
-       }
-
-       RTL_W32(RxConfig, tmp);
+       if (tp->mac_version > RTL_GIGA_MAC_VER_06) {
+               u32 data = mc_filter[0];
+
+               mc_filter[0] = swab32(mc_filter[1]);
+               mc_filter[1] = swab32(data);
+       }
+
        RTL_W32(MAR0 + 0, mc_filter[0]);
        RTL_W32(MAR0 + 4, mc_filter[1]);
+
+       RTL_W32(RxConfig, tmp);
 
        spin_unlock_irqrestore(&tp->lock, flags);
 }
@@ -2857,8 +3744,7 @@ static struct net_device_stats *rtl8169_
 
        if (netif_running(dev)) {
                spin_lock_irqsave(&tp->lock, flags);
-               tp->stats.rx_missed_errors += RTL_R32(RxMissed);
-               RTL_W32(RxMissed, 0);
+               rtl8169_rx_missed(dev, ioaddr);
                spin_unlock_irqrestore(&tp->lock, flags);
        }
 
@@ -2874,7 +3760,7 @@ static int rtl8169_suspend(struct pci_de
        void __iomem *ioaddr = tp->mmio_addr;
 
        if (!netif_running(dev))
-               goto out;
+               goto out_pci_suspend;
 
        netif_device_detach(dev);
        netif_stop_queue(dev);
@@ -2883,34 +3769,40 @@ static int rtl8169_suspend(struct pci_de
 
        rtl8169_asic_down(ioaddr);
 
-       tp->stats.rx_missed_errors += RTL_R32(RxMissed);
-       RTL_W32(RxMissed, 0);
+       rtl8169_rx_missed(dev, ioaddr);
 
        spin_unlock_irq(&tp->lock);
 
+out_pci_suspend:
        pci_save_state(pdev);
-       pci_enable_wake(pdev, pci_choose_state(pdev, state), tp->wol_enabled);
+       pci_enable_wake(pdev, pci_choose_state(pdev, state),
+               (tp->features & RTL_FEATURE_WOL) ? 1 : 0);
        pci_set_power_state(pdev, pci_choose_state(pdev, state));
-out:
+
        return 0;
 }
 
 static int rtl8169_resume(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
-
-       if (!netif_running(dev))
-               goto out;
-
-       netif_device_attach(dev);
 
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
        pci_enable_wake(pdev, PCI_D0, 0);
 
+       if (!netif_running(dev))
+               goto out;
+
+       netif_device_attach(dev);
+
        rtl8169_schedule_work(dev, rtl8169_reset_task);
 out:
        return 0;
+}
+
+static void rtl_shutdown(struct pci_dev *pdev)
+{
+       rtl8169_suspend(pdev, PMSG_SUSPEND);
 }
 
 #endif /* CONFIG_PM */
@@ -2923,17 +3815,16 @@ static struct pci_driver rtl8169_pci_dri
 #ifdef CONFIG_PM
        .suspend        = rtl8169_suspend,
        .resume         = rtl8169_resume,
+       .shutdown       = rtl_shutdown,
 #endif
 };
 
-static int __init
-rtl8169_init_module(void)
+static int __init rtl8169_init_module(void)
 {
        return pci_register_driver(&rtl8169_pci_driver);
 }
 
-static void __exit
-rtl8169_cleanup_module(void)
+static void __exit rtl8169_cleanup_module(void)
 {
        pci_unregister_driver(&rtl8169_pci_driver);
 }

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH 8 of 10] New/Updated drivers: Realtek 8169 gigabit ethernet driver backported from Linux Kernel Ver. 2.6.29.2, Daniel Kiper <=