r8169:add support for RTL8168H and RTL8107E
authorChun-Hao Lin <hau@realtek.com>
Tue, 19 Aug 2014 17:54:04 +0000 (01:54 +0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 22 Aug 2014 19:33:47 +0000 (12:33 -0700)
RTL8168H is Realtek PCIe Gigabit Ethernet controller.
RTL8107E is Realtek PCIe Fast Ethernet controller.

This patch add support for these two chips.

Signed-off-by: Chun-Hao Lin <hau@realtek.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/realtek/r8169.c

index 91652e7..c8375f6 100644 (file)
 #define FIRMWARE_8106E_2       "rtl_nic/rtl8106e-2.fw"
 #define FIRMWARE_8168G_2       "rtl_nic/rtl8168g-2.fw"
 #define FIRMWARE_8168G_3       "rtl_nic/rtl8168g-3.fw"
+#define FIRMWARE_8168H_1       "rtl_nic/rtl8168h-1.fw"
+#define FIRMWARE_8168H_2       "rtl_nic/rtl8168h-2.fw"
+#define FIRMWARE_8107E_1       "rtl_nic/rtl8107e-1.fw"
+#define FIRMWARE_8107E_2       "rtl_nic/rtl8107e-2.fw"
 
 #ifdef RTL8169_DEBUG
 #define assert(expr) \
@@ -147,6 +151,10 @@ enum mac_version {
        RTL_GIGA_MAC_VER_42,
        RTL_GIGA_MAC_VER_43,
        RTL_GIGA_MAC_VER_44,
+       RTL_GIGA_MAC_VER_45,
+       RTL_GIGA_MAC_VER_46,
+       RTL_GIGA_MAC_VER_47,
+       RTL_GIGA_MAC_VER_48,
        RTL_GIGA_MAC_NONE   = 0xff,
 };
 
@@ -282,6 +290,18 @@ static const struct {
        [RTL_GIGA_MAC_VER_44] =
                _R("RTL8411",           RTL_TD_1, FIRMWARE_8411_2,
                                                        JUMBO_9K, false),
+       [RTL_GIGA_MAC_VER_45] =
+               _R("RTL8168h/8111h",    RTL_TD_1, FIRMWARE_8168H_1,
+                                                       JUMBO_9K, false),
+       [RTL_GIGA_MAC_VER_46] =
+               _R("RTL8168h/8111h",    RTL_TD_1, FIRMWARE_8168H_2,
+                                                       JUMBO_9K, false),
+       [RTL_GIGA_MAC_VER_47] =
+               _R("RTL8107e",          RTL_TD_1, FIRMWARE_8107E_1,
+                                                       JUMBO_1K, false),
+       [RTL_GIGA_MAC_VER_48] =
+               _R("RTL8107e",          RTL_TD_1, FIRMWARE_8107E_2,
+                                                       JUMBO_1K, false),
 };
 #undef _R
 
@@ -410,6 +430,7 @@ enum rtl8168_8101_registers {
 #define        EPHYAR_DATA_MASK                0xffff
        DLLPR                   = 0xd0,
 #define        PFM_EN                          (1 << 6)
+#define        TX_10M_PS_EN                    (1 << 7)
        DBG_REG                 = 0xd1,
 #define        FIX_NAK_1                       (1 << 4)
 #define        FIX_NAK_2                       (1 << 3)
@@ -429,6 +450,8 @@ enum rtl8168_8101_registers {
 #define        EFUSEAR_REG_MASK                0x03ff
 #define        EFUSEAR_REG_SHIFT               8
 #define        EFUSEAR_DATA_MASK               0xff
+       MISC_1                  = 0xf2,
+#define        PFM_D3COLD_EN                   (1 << 6)
 };
 
 enum rtl8168_registers {
@@ -447,6 +470,7 @@ enum rtl8168_registers {
 #define ERIAR_MASK_SHIFT               12
 #define ERIAR_MASK_0001                        (0x1 << ERIAR_MASK_SHIFT)
 #define ERIAR_MASK_0011                        (0x3 << ERIAR_MASK_SHIFT)
+#define ERIAR_MASK_0100                        (0x4 << ERIAR_MASK_SHIFT)
 #define ERIAR_MASK_0101                        (0x5 << ERIAR_MASK_SHIFT)
 #define ERIAR_MASK_1111                        (0xf << ERIAR_MASK_SHIFT)
        EPHY_RXER_NUM           = 0x7c,
@@ -598,6 +622,9 @@ enum rtl_register_content {
 
        /* DumpCounterCommand */
        CounterDump     = 0x8,
+
+       /* magic enable v2 */
+       MagicPacket_v2  = (1 << 16),    /* Wake up when receives a Magic Packet */
 };
 
 enum rtl_desc_bit {
@@ -823,6 +850,8 @@ MODULE_FIRMWARE(FIRMWARE_8106E_1);
 MODULE_FIRMWARE(FIRMWARE_8106E_2);
 MODULE_FIRMWARE(FIRMWARE_8168G_2);
 MODULE_FIRMWARE(FIRMWARE_8168G_3);
+MODULE_FIRMWARE(FIRMWARE_8168H_1);
+MODULE_FIRMWARE(FIRMWARE_8168H_2);
 
 static void rtl_lock_work(struct rtl8169_private *tp)
 {
@@ -1514,8 +1543,17 @@ static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
        options = RTL_R8(Config3);
        if (options & LinkUp)
                wolopts |= WAKE_PHY;
-       if (options & MagicPacket)
-               wolopts |= WAKE_MAGIC;
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               if (rtl_eri_read(tp, 0xdc, ERIAR_EXGMAC) & MagicPacket_v2)
+                       wolopts |= WAKE_MAGIC;
+               break;
+       default:
+               if (options & MagicPacket)
+                       wolopts |= WAKE_MAGIC;
+               break;
+       }
 
        options = RTL_R8(Config5);
        if (options & UWF)
@@ -1543,24 +1581,48 @@ static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
 {
        void __iomem *ioaddr = tp->mmio_addr;
-       unsigned int i;
+       unsigned int i, tmp;
        static const struct {
                u32 opt;
                u16 reg;
                u8  mask;
        } cfg[] = {
                { WAKE_PHY,   Config3, LinkUp },
-               { WAKE_MAGIC, Config3, MagicPacket },
                { WAKE_UCAST, Config5, UWF },
                { WAKE_BCAST, Config5, BWF },
                { WAKE_MCAST, Config5, MWF },
-               { WAKE_ANY,   Config5, LanWake }
+               { WAKE_ANY,   Config5, LanWake },
+               { WAKE_MAGIC, Config3, MagicPacket }
        };
        u8 options;
 
        RTL_W8(Cfg9346, Cfg9346_Unlock);
 
-       for (i = 0; i < ARRAY_SIZE(cfg); i++) {
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               tmp = ARRAY_SIZE(cfg) - 1;
+               if (wolopts & WAKE_MAGIC)
+                       rtl_w1w0_eri(tp,
+                                    0x0dc,
+                                    ERIAR_MASK_0100,
+                                    MagicPacket_v2,
+                                    0x0000,
+                                    ERIAR_EXGMAC);
+               else
+                       rtl_w1w0_eri(tp,
+                                    0x0dc,
+                                    ERIAR_MASK_0100,
+                                    0x0000,
+                                    MagicPacket_v2,
+                                    ERIAR_EXGMAC);
+               break;
+       default:
+               tmp = ARRAY_SIZE(cfg);
+               break;
+       }
+
+       for (i = 0; i < tmp; i++) {
                options = RTL_R8(cfg[i].reg) & ~cfg[i].mask;
                if (wolopts & cfg[i].opt)
                        options |= cfg[i].mask;
@@ -2044,6 +2106,10 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
                u32 val;
                int mac_version;
        } mac_info[] = {
+               /* 8168H family. */
+               { 0x7cf00000, 0x54100000,       RTL_GIGA_MAC_VER_46 },
+               { 0x7cf00000, 0x54000000,       RTL_GIGA_MAC_VER_45 },
+
                /* 8168G family. */
                { 0x7cf00000, 0x5c800000,       RTL_GIGA_MAC_VER_44 },
                { 0x7cf00000, 0x50900000,       RTL_GIGA_MAC_VER_42 },
@@ -2139,6 +2205,14 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
                tp->mac_version = tp->mii.supports_gmii ?
                                  RTL_GIGA_MAC_VER_42 :
                                  RTL_GIGA_MAC_VER_43;
+       } else if (tp->mac_version == RTL_GIGA_MAC_VER_45) {
+               tp->mac_version = tp->mii.supports_gmii ?
+                                 RTL_GIGA_MAC_VER_45 :
+                                 RTL_GIGA_MAC_VER_47;
+       } else if (tp->mac_version == RTL_GIGA_MAC_VER_46) {
+               tp->mac_version = tp->mii.supports_gmii ?
+                                 RTL_GIGA_MAC_VER_46 :
+                                 RTL_GIGA_MAC_VER_48;
        }
 }
 
@@ -3464,6 +3538,189 @@ static void rtl8168g_2_hw_phy_config(struct rtl8169_private *tp)
        rtl_apply_firmware(tp);
 }
 
+static void rtl8168h_1_hw_phy_config(struct rtl8169_private *tp)
+{
+       u16 dout_tapbin;
+       u32 data;
+
+       rtl_apply_firmware(tp);
+
+       /* CHN EST parameters adjust - giga master */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x809b);
+       rtl_w1w0_phy(tp, 0x14, 0x8000, 0xf800);
+       rtl_writephy(tp, 0x13, 0x80a2);
+       rtl_w1w0_phy(tp, 0x14, 0x8000, 0xff00);
+       rtl_writephy(tp, 0x13, 0x80a4);
+       rtl_w1w0_phy(tp, 0x14, 0x8500, 0xff00);
+       rtl_writephy(tp, 0x13, 0x809c);
+       rtl_w1w0_phy(tp, 0x14, 0xbd00, 0xff00);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* CHN EST parameters adjust - giga slave */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x80ad);
+       rtl_w1w0_phy(tp, 0x14, 0x7000, 0xf800);
+       rtl_writephy(tp, 0x13, 0x80b4);
+       rtl_w1w0_phy(tp, 0x14, 0x5000, 0xff00);
+       rtl_writephy(tp, 0x13, 0x80ac);
+       rtl_w1w0_phy(tp, 0x14, 0x4000, 0xff00);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* CHN EST parameters adjust - fnet */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x808e);
+       rtl_w1w0_phy(tp, 0x14, 0x1200, 0xff00);
+       rtl_writephy(tp, 0x13, 0x8090);
+       rtl_w1w0_phy(tp, 0x14, 0xe500, 0xff00);
+       rtl_writephy(tp, 0x13, 0x8092);
+       rtl_w1w0_phy(tp, 0x14, 0x9f00, 0xff00);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* enable R-tune & PGA-retune function */
+       dout_tapbin = 0;
+       rtl_writephy(tp, 0x1f, 0x0a46);
+       data = rtl_readphy(tp, 0x13);
+       data &= 3;
+       data <<= 2;
+       dout_tapbin |= data;
+       data = rtl_readphy(tp, 0x12);
+       data &= 0xc000;
+       data >>= 14;
+       dout_tapbin |= data;
+       dout_tapbin = ~(dout_tapbin^0x08);
+       dout_tapbin <<= 12;
+       dout_tapbin &= 0xf000;
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x827a);
+       rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000);
+       rtl_writephy(tp, 0x13, 0x827b);
+       rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000);
+       rtl_writephy(tp, 0x13, 0x827c);
+       rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000);
+       rtl_writephy(tp, 0x13, 0x827d);
+       rtl_w1w0_phy(tp, 0x14, dout_tapbin, 0xf000);
+
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x0811);
+       rtl_w1w0_phy(tp, 0x14, 0x0800, 0x0000);
+       rtl_writephy(tp, 0x1f, 0x0a42);
+       rtl_w1w0_phy(tp, 0x16, 0x0002, 0x0000);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* enable GPHY 10M */
+       rtl_writephy(tp, 0x1f, 0x0a44);
+       rtl_w1w0_phy(tp, 0x11, 0x0800, 0x0000);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* SAR ADC performance */
+       rtl_writephy(tp, 0x1f, 0x0bca);
+       rtl_w1w0_phy(tp, 0x17, 0x4000, 0x3000);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x803f);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x8047);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x804f);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x8057);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x805f);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x8067);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x13, 0x806f);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x3000);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* disable phy pfm mode */
+       rtl_writephy(tp, 0x1f, 0x0a44);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x0080);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* Check ALDPS bit, disable it if enabled */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       if (rtl_readphy(tp, 0x10) & 0x0004)
+               rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0004);
+
+       rtl_writephy(tp, 0x1f, 0x0000);
+}
+
+static void rtl8168h_2_hw_phy_config(struct rtl8169_private *tp)
+{
+       u16 ioffset_p3, ioffset_p2, ioffset_p1, ioffset_p0;
+       u16 rlen;
+       u32 data;
+
+       rtl_apply_firmware(tp);
+
+       /* CHIN EST parameter update */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x808a);
+       rtl_w1w0_phy(tp, 0x14, 0x000a, 0x003f);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* enable R-tune & PGA-retune function */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       rtl_writephy(tp, 0x13, 0x0811);
+       rtl_w1w0_phy(tp, 0x14, 0x0800, 0x0000);
+       rtl_writephy(tp, 0x1f, 0x0a42);
+       rtl_w1w0_phy(tp, 0x16, 0x0002, 0x0000);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* enable GPHY 10M */
+       rtl_writephy(tp, 0x1f, 0x0a44);
+       rtl_w1w0_phy(tp, 0x11, 0x0800, 0x0000);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       r8168_mac_ocp_write(tp, 0xdd02, 0x807d);
+       data = r8168_mac_ocp_read(tp, 0xdd02);
+       ioffset_p3 = ((data & 0x80)>>7);
+       ioffset_p3 <<= 3;
+
+       data = r8168_mac_ocp_read(tp, 0xdd00);
+       ioffset_p3 |= ((data & (0xe000))>>13);
+       ioffset_p2 = ((data & (0x1e00))>>9);
+       ioffset_p1 = ((data & (0x01e0))>>5);
+       ioffset_p0 = ((data & 0x0010)>>4);
+       ioffset_p0 <<= 3;
+       ioffset_p0 |= (data & (0x07));
+       data = (ioffset_p3<<12)|(ioffset_p2<<8)|(ioffset_p1<<4)|(ioffset_p0);
+
+       if ((ioffset_p3 != 0x0F) || (ioffset_p2 != 0x0F) ||
+           (ioffset_p1 != 0x0F) || (ioffset_p0 == 0x0F)) {
+               rtl_writephy(tp, 0x1f, 0x0bcf);
+               rtl_writephy(tp, 0x16, data);
+               rtl_writephy(tp, 0x1f, 0x0000);
+       }
+
+       /* Modify rlen (TX LPF corner frequency) level */
+       rtl_writephy(tp, 0x1f, 0x0bcd);
+       data = rtl_readphy(tp, 0x16);
+       data &= 0x000f;
+       rlen = 0;
+       if (data > 3)
+               rlen = data - 3;
+       data = rlen | (rlen<<4) | (rlen<<8) | (rlen<<12);
+       rtl_writephy(tp, 0x17, data);
+       rtl_writephy(tp, 0x1f, 0x0bcd);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* disable phy pfm mode */
+       rtl_writephy(tp, 0x1f, 0x0a44);
+       rtl_w1w0_phy(tp, 0x14, 0x0000, 0x0080);
+       rtl_writephy(tp, 0x1f, 0x0000);
+
+       /* Check ALDPS bit, disable it if enabled */
+       rtl_writephy(tp, 0x1f, 0x0a43);
+       if (rtl_readphy(tp, 0x10) & 0x0004)
+               rtl_w1w0_phy(tp, 0x10, 0x0000, 0x0004);
+
+       rtl_writephy(tp, 0x1f, 0x0000);
+}
+
 static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
 {
        static const struct phy_reg phy_reg_init[] = {
@@ -3654,6 +3911,14 @@ static void rtl_hw_phy_config(struct net_device *dev)
        case RTL_GIGA_MAC_VER_44:
                rtl8168g_2_hw_phy_config(tp);
                break;
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_47:
+               rtl8168h_1_hw_phy_config(tp);
+               break;
+       case RTL_GIGA_MAC_VER_46:
+       case RTL_GIGA_MAC_VER_48:
+               rtl8168h_2_hw_phy_config(tp);
+               break;
 
        case RTL_GIGA_MAC_VER_41:
        default:
@@ -3865,6 +4130,10 @@ static void rtl_init_mdio_ops(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
        case RTL_GIGA_MAC_VER_44:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
                ops->write      = r8168g_mdio_write;
                ops->read       = r8168g_mdio_read;
                break;
@@ -3919,6 +4188,10 @@ static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
        case RTL_GIGA_MAC_VER_44:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
                RTL_W32(RxConfig, RTL_R32(RxConfig) |
                        AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
                break;
@@ -3987,6 +4260,10 @@ static void r810x_pll_power_up(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_13:
        case RTL_GIGA_MAC_VER_16:
                break;
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
+               RTL_W8(PMCH, RTL_R8(PMCH) | 0xC0);
+               break;
        default:
                RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
                break;
@@ -4087,6 +4364,8 @@ static void r8168_pll_power_down(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_31:
        case RTL_GIGA_MAC_VER_32:
        case RTL_GIGA_MAC_VER_33:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
                RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
                break;
        case RTL_GIGA_MAC_VER_40:
@@ -4111,6 +4390,10 @@ static void r8168_pll_power_up(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_33:
                RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
                break;
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               RTL_W8(PMCH, RTL_R8(PMCH) | 0xC0);
+               break;
        case RTL_GIGA_MAC_VER_40:
        case RTL_GIGA_MAC_VER_41:
                rtl_w1w0_eri(tp, 0x1a8, ERIAR_MASK_1111, 0xfc000000,
@@ -4153,6 +4436,8 @@ static void rtl_init_pll_power_ops(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_37:
        case RTL_GIGA_MAC_VER_39:
        case RTL_GIGA_MAC_VER_43:
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
                ops->down       = r810x_pll_power_down;
                ops->up         = r810x_pll_power_up;
                break;
@@ -4182,6 +4467,8 @@ static void rtl_init_pll_power_ops(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_41:
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_44:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
                ops->down       = r8168_pll_power_down;
                ops->up         = r8168_pll_power_up;
                break;
@@ -4232,6 +4519,10 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
        case RTL_GIGA_MAC_VER_44:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
                RTL_W32(RxConfig, RX128_INT_EN | RX_DMA_BURST | RX_EARLY_OFF);
                break;
        default:
@@ -4393,6 +4684,10 @@ static void rtl_init_jumbo_ops(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
        case RTL_GIGA_MAC_VER_44:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
        default:
                ops->disable    = NULL;
                ops->enable     = NULL;
@@ -4495,15 +4790,19 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
            tp->mac_version == RTL_GIGA_MAC_VER_31) {
                rtl_udelay_loop_wait_low(tp, &rtl_npq_cond, 20, 42*42);
        } else if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_35 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_36 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_37 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_40 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_41 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_42 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_43 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_44 ||
-                  tp->mac_version == RTL_GIGA_MAC_VER_38) {
+                  tp->mac_version == RTL_GIGA_MAC_VER_35 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_36 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_37 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_38 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_40 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_41 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_42 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_43 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_44 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_45 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_46 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_47 ||
+                  tp->mac_version == RTL_GIGA_MAC_VER_48) {
                RTL_W8(ChipCmd, RTL_R8(ChipCmd) | StopReq);
                rtl_udelay_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666);
        } else {
@@ -5330,6 +5629,105 @@ static void rtl_hw_start_8411_2(struct rtl8169_private *tp)
        rtl_ephy_init(tp, e_info_8411_2, ARRAY_SIZE(e_info_8411_2));
 }
 
+static void rtl_hw_start_8168h_1(struct rtl8169_private *tp)
+{
+       void __iomem *ioaddr = tp->mmio_addr;
+       struct pci_dev *pdev = tp->pci_dev;
+       u16 rg_saw_cnt;
+       u32 data;
+       static const struct ephy_info e_info_8168h_1[] = {
+               { 0x1e, 0x0800, 0x0001 },
+               { 0x1d, 0x0000, 0x0800 },
+               { 0x05, 0xffff, 0x2089 },
+               { 0x06, 0xffff, 0x5881 },
+               { 0x04, 0xffff, 0x154a },
+               { 0x01, 0xffff, 0x068b }
+       };
+
+       /* disable aspm and clock request before access ephy */
+       RTL_W8(Config2, RTL_R8(Config2) & ~ClkReqEn);
+       RTL_W8(Config5, RTL_R8(Config5) & ~ASPM_en);
+       rtl_ephy_init(tp, e_info_8168h_1, ARRAY_SIZE(e_info_8168h_1));
+
+       RTL_W32(TxConfig, RTL_R32(TxConfig) | TXCFG_AUTO_FIFO);
+
+       rtl_eri_write(tp, 0xc8, ERIAR_MASK_0101, 0x00080002, ERIAR_EXGMAC);
+       rtl_eri_write(tp, 0xcc, ERIAR_MASK_0001, 0x38, ERIAR_EXGMAC);
+       rtl_eri_write(tp, 0xd0, ERIAR_MASK_0001, 0x48, ERIAR_EXGMAC);
+       rtl_eri_write(tp, 0xe8, ERIAR_MASK_1111, 0x00100006, ERIAR_EXGMAC);
+
+       rtl_csi_access_enable_1(tp);
+
+       rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+       rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x00, 0x01, ERIAR_EXGMAC);
+       rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_0001, 0x01, 0x00, ERIAR_EXGMAC);
+
+       rtl_w1w0_eri(tp, 0xdc, ERIAR_MASK_1111, 0x0010, 0x00, ERIAR_EXGMAC);
+
+       rtl_w1w0_eri(tp, 0xd4, ERIAR_MASK_1111, 0x1f00, 0x00, ERIAR_EXGMAC);
+
+       rtl_eri_write(tp, 0x5f0, ERIAR_MASK_0011, 0x4f87, ERIAR_EXGMAC);
+
+       RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+       RTL_W32(MISC, RTL_R32(MISC) & ~RXDV_GATED_EN);
+       RTL_W8(MaxTxPacketSize, EarlySize);
+
+       rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+       rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
+
+       /* Adjust EEE LED frequency */
+       RTL_W8(EEE_LED, RTL_R8(EEE_LED) & ~0x07);
+
+       RTL_W8(DLLPR, RTL_R8(DLLPR) & ~PFM_EN);
+       RTL_W8(DLLPR, RTL_R8(MISC_1) & ~PFM_D3COLD_EN);
+
+       RTL_W8(DLLPR, RTL_R8(DLLPR) & ~TX_10M_PS_EN);
+
+       rtl_w1w0_eri(tp, 0x1b0, ERIAR_MASK_0011, 0x0000, 0x1000, ERIAR_EXGMAC);
+
+       rtl_pcie_state_l2l3_enable(tp, false);
+
+       rtl_writephy(tp, 0x1f, 0x0c42);
+       rg_saw_cnt = rtl_readphy(tp, 0x13);
+       rtl_writephy(tp, 0x1f, 0x0000);
+       if (rg_saw_cnt > 0) {
+               u16 sw_cnt_1ms_ini;
+
+               sw_cnt_1ms_ini = 16000000/rg_saw_cnt;
+               sw_cnt_1ms_ini &= 0x0fff;
+               data = r8168_mac_ocp_read(tp, 0xd412);
+               data &= 0x0fff;
+               data |= sw_cnt_1ms_ini;
+               r8168_mac_ocp_write(tp, 0xd412, data);
+       }
+
+       data = r8168_mac_ocp_read(tp, 0xe056);
+       data &= 0xf0;
+       data |= 0x07;
+       r8168_mac_ocp_write(tp, 0xe056, data);
+
+       data = r8168_mac_ocp_read(tp, 0xe052);
+       data &= 0x8008;
+       data |= 0x6000;
+       r8168_mac_ocp_write(tp, 0xe052, data);
+
+       data = r8168_mac_ocp_read(tp, 0xe0d6);
+       data &= 0x01ff;
+       data |= 0x017f;
+       r8168_mac_ocp_write(tp, 0xe0d6, data);
+
+       data = r8168_mac_ocp_read(tp, 0xd420);
+       data &= 0x0fff;
+       data |= 0x047f;
+       r8168_mac_ocp_write(tp, 0xd420, data);
+
+       r8168_mac_ocp_write(tp, 0xe63e, 0x0001);
+       r8168_mac_ocp_write(tp, 0xe63e, 0x0000);
+       r8168_mac_ocp_write(tp, 0xc094, 0x0000);
+       r8168_mac_ocp_write(tp, 0xc09e, 0x0000);
+}
+
 static void rtl_hw_start_8168(struct net_device *dev)
 {
        struct rtl8169_private *tp = netdev_priv(dev);
@@ -5440,6 +5838,11 @@ static void rtl_hw_start_8168(struct net_device *dev)
                rtl_hw_start_8411_2(tp);
                break;
 
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               rtl_hw_start_8168h_1(tp);
+               break;
+
        default:
                printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
                        dev->name, tp->mac_version);
@@ -5655,6 +6058,10 @@ static void rtl_hw_start_8101(struct net_device *dev)
        case RTL_GIGA_MAC_VER_43:
                rtl_hw_start_8168g_2(tp);
                break;
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
+               rtl_hw_start_8168h_1(tp);
+               break;
        }
 
        RTL_W8(Cfg9346, Cfg9346_Lock);
@@ -5895,7 +6302,7 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
 {
        struct skb_shared_info *info = skb_shinfo(skb);
        unsigned int cur_frag, entry;
-       struct TxDesc * uninitialized_var(txd);
+       struct TxDesc *uninitialized_var(txd);
        struct device *d = &tp->pci_dev->dev;
 
        entry = tp->cur_tx;
@@ -7110,6 +7517,10 @@ static void rtl_hw_initialize(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_42:
        case RTL_GIGA_MAC_VER_43:
        case RTL_GIGA_MAC_VER_44:
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+       case RTL_GIGA_MAC_VER_47:
+       case RTL_GIGA_MAC_VER_48:
                rtl_hw_init_8168g(tp);
                break;
 
@@ -7255,8 +7666,19 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        RTL_W8(Cfg9346, Cfg9346_Unlock);
        RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
        RTL_W8(Config5, RTL_R8(Config5) & (BWF | MWF | UWF | LanWake | PMEStatus));
-       if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
-               tp->features |= RTL_FEATURE_WOL;
+       switch (tp->mac_version) {
+       case RTL_GIGA_MAC_VER_45:
+       case RTL_GIGA_MAC_VER_46:
+               if (rtl_eri_read(tp, 0xdc, ERIAR_EXGMAC) & MagicPacket_v2)
+                       tp->features |= RTL_FEATURE_WOL;
+               if ((RTL_R8(Config3) & LinkUp) != 0)
+                       tp->features |= RTL_FEATURE_WOL;
+               break;
+       default:
+               if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0)
+                       tp->features |= RTL_FEATURE_WOL;
+               break;
+       }
        if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0)
                tp->features |= RTL_FEATURE_WOL;
        tp->features |= rtl_try_msi(tp, cfg);
@@ -7283,6 +7705,18 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        u64_stats_init(&tp->tx_stats.syncp);
 
        /* Get MAC address */
+       if (tp->mac_version == RTL_GIGA_MAC_VER_45 ||
+           tp->mac_version == RTL_GIGA_MAC_VER_46 ||
+           tp->mac_version == RTL_GIGA_MAC_VER_47 ||
+           tp->mac_version == RTL_GIGA_MAC_VER_48) {
+               u16 mac_addr[3];
+
+               *(u32 *)&mac_addr[0] = rtl_eri_read(tp, 0xE0, ERIAR_EXGMAC);
+               *(u16 *)&mac_addr[2] = rtl_eri_read(tp, 0xE4, ERIAR_EXGMAC);
+
+               if (is_valid_ether_addr((u8 *)mac_addr))
+                       rtl_rar_set(tp, (u8 *)mac_addr);
+       }
        for (i = 0; i < ETH_ALEN; i++)
                dev->dev_addr[i] = RTL_R8(MAC0 + i);