e1000e: initial support for 82579 LOMs
authorBruce Allan <bruce.w.allan@intel.com>
Wed, 16 Jun 2010 13:27:28 +0000 (13:27 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sat, 19 Jun 2010 05:12:16 +0000 (22:12 -0700)
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/e1000e/defines.h
drivers/net/e1000e/e1000.h
drivers/net/e1000e/ethtool.c
drivers/net/e1000e/hw.h
drivers/net/e1000e/ich8lan.c
drivers/net/e1000e/netdev.c
drivers/net/e1000e/phy.c

index 4dc02c71ffd6094417f7d742e0c2e768382fddd4..5a6de3419d364b7d7d0b2745ffe6b62d1094a16b 100644 (file)
 #define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE       0x00000001
 #define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE       0x00000008
 #define E1000_EXTCNF_CTRL_SWFLAG                 0x00000020
+#define E1000_EXTCNF_CTRL_GATE_PHY_CFG           0x00000080
 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK   0x00FF0000
 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT          16
 #define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK   0x0FFF0000
 #define BME1000_E_PHY_ID_R2  0x01410CB1
 #define I82577_E_PHY_ID      0x01540050
 #define I82578_E_PHY_ID      0x004DD040
+#define I82579_E_PHY_ID      0x01540090
 
 /* M88E1000 Specific Registers */
 #define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
index 79e7c4c187190e0e989a2185b55c004f649d3f23..0e59f15be11045c25b0873b34efc019d28ddac66 100644 (file)
@@ -164,6 +164,7 @@ enum e1000_boards {
        board_ich9lan,
        board_ich10lan,
        board_pchlan,
+       board_pch2lan,
 };
 
 struct e1000_queue_stats {
@@ -477,6 +478,7 @@ extern struct e1000_info e1000_ich8_info;
 extern struct e1000_info e1000_ich9_info;
 extern struct e1000_info e1000_ich10_info;
 extern struct e1000_info e1000_pch_info;
+extern struct e1000_info e1000_pch2_info;
 extern struct e1000_info e1000_es2_info;
 
 extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num);
@@ -495,6 +497,8 @@ extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
 extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
 extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw);
 extern s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
+extern s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
+extern void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw);
 
 extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
 extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
index 86c6a26c0a39901ae6580db39422587eebcf0a71..312c704aec343d8a5b2f6f737983bf60d9cca1ca 100644 (file)
@@ -880,6 +880,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
        switch (mac->type) {
        case e1000_ich10lan:
        case e1000_pchlan:
+       case e1000_pch2lan:
                mask |= (1 << 18);
                break;
        default:
@@ -1321,6 +1322,17 @@ static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
                /* Workaround: K1 must be disabled for stable 1Gbps operation */
                e1000_configure_k1_ich8lan(hw, false);
                break;
+       case e1000_phy_82579:
+               /* Disable PHY energy detect power down */
+               e1e_rphy(hw, PHY_REG(0, 21), &phy_reg);
+               e1e_wphy(hw, PHY_REG(0, 21), phy_reg & ~(1 << 3));
+               /* Disable full chip energy detect */
+               e1e_rphy(hw, PHY_REG(776, 18), &phy_reg);
+               e1e_wphy(hw, PHY_REG(776, 18), phy_reg | 1);
+               /* Enable loopback on the PHY */
+#define I82577_PHY_LBK_CTRL          19
+               e1e_wphy(hw, I82577_PHY_LBK_CTRL, 0x8001);
+               break;
        default:
                break;
        }
@@ -1878,6 +1890,7 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
 
        if ((hw->phy.type == e1000_phy_ife) ||
            (hw->mac.type == e1000_pchlan) ||
+           (hw->mac.type == e1000_pch2lan) ||
            (hw->mac.type == e1000_82583) ||
            (hw->mac.type == e1000_82574)) {
                INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task);
index 5d1220d188d46f88e29d6f8c9760a3fc3c92a54d..96116ce5e5cc8be6a0e7ed92a1c28b95393fd80d 100644 (file)
@@ -217,7 +217,10 @@ enum e1e_registers {
        E1000_SWSM      = 0x05B50, /* SW Semaphore */
        E1000_FWSM      = 0x05B54, /* FW Semaphore */
        E1000_SWSM2     = 0x05B58, /* Driver-only SW semaphore */
-       E1000_CRC_OFFSET = 0x05F50, /* CRC Offset register */
+       E1000_FFLT_DBG  = 0x05F04, /* Debug Register */
+       E1000_PCH_RAICC_BASE = 0x05F50, /* Receive Address Initial CRC */
+#define E1000_PCH_RAICC(_n)    (E1000_PCH_RAICC_BASE + ((_n) * 4))
+#define E1000_CRC_OFFSET       E1000_PCH_RAICC_BASE
        E1000_HICR      = 0x08F00, /* Host Interface Control */
 };
 
@@ -303,13 +306,14 @@ enum e1e_registers {
 #define E1000_KMRNCTRLSTA_OFFSET       0x001F0000
 #define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16
 #define E1000_KMRNCTRLSTA_REN          0x00200000
+#define E1000_KMRNCTRLSTA_CTRL_OFFSET  0x1    /* Kumeran Control */
 #define E1000_KMRNCTRLSTA_DIAG_OFFSET  0x3    /* Kumeran Diagnostic */
 #define E1000_KMRNCTRLSTA_TIMEOUTS     0x4    /* Kumeran Timeouts */
 #define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9    /* Kumeran InBand Parameters */
 #define E1000_KMRNCTRLSTA_DIAG_NELPBK  0x1000 /* Nearend Loopback mode */
 #define E1000_KMRNCTRLSTA_K1_CONFIG    0x7
 #define E1000_KMRNCTRLSTA_K1_ENABLE    0x140E
-#define E1000_KMRNCTRLSTA_K1_DISABLE   0x1400
+#define E1000_KMRNCTRLSTA_HD_CTRL      0x0002
 
 #define IFE_PHY_EXTENDED_STATUS_CONTROL        0x10
 #define IFE_PHY_SPECIAL_CONTROL                0x11 /* 100BaseTx PHY Special Control */
@@ -387,6 +391,8 @@ enum e1e_registers {
 #define E1000_DEV_ID_PCH_M_HV_LC               0x10EB
 #define E1000_DEV_ID_PCH_D_HV_DM               0x10EF
 #define E1000_DEV_ID_PCH_D_HV_DC               0x10F0
+#define E1000_DEV_ID_PCH2_LV_LM                        0x1502
+#define E1000_DEV_ID_PCH2_LV_V                 0x1503
 
 #define E1000_REVISION_4 4
 
@@ -406,6 +412,7 @@ enum e1000_mac_type {
        e1000_ich9lan,
        e1000_ich10lan,
        e1000_pchlan,
+       e1000_pch2lan,
 };
 
 enum e1000_media_type {
@@ -442,6 +449,7 @@ enum e1000_phy_type {
        e1000_phy_bm,
        e1000_phy_82578,
        e1000_phy_82577,
+       e1000_phy_82579,
 };
 
 enum e1000_bus_width {
index 7e2f98c24f960b0ba0e168a07cf8b2b757928f2a..8274499b7df62b21fe96602a4d36d95fea9d39df 100644 (file)
@@ -52,6 +52,8 @@
  * 82577LC Gigabit Network Connection
  * 82578DM Gigabit Network Connection
  * 82578DC Gigabit Network Connection
+ * 82579LM Gigabit Network Connection
+ * 82579V Gigabit Network Connection
  */
 
 #include "e1000.h"
 #define HV_SMB_ADDR_PEC_EN     0x0200
 #define HV_SMB_ADDR_VALID      0x0080
 
+/* PHY Power Management Control */
+#define HV_PM_CTRL             PHY_REG(770, 17)
+
 /* Strapping Option Register - RO */
 #define E1000_STRAP                     0x0000C
 #define E1000_STRAP_SMBUS_ADDRESS_MASK  0x00FE0000
@@ -279,13 +284,13 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
        phy->ops.power_down           = e1000_power_down_phy_copper_ich8lan;
        phy->autoneg_mask             = AUTONEG_ADVERTISE_SPEED_DEFAULT;
 
+       /*
+        * The MAC-PHY interconnect may still be in SMBus mode
+        * after Sx->S0.  If the manageability engine (ME) is
+        * disabled, then toggle the LANPHYPC Value bit to force
+        * the interconnect to PCIe mode.
+        */
        if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
-               /*
-                * The MAC-PHY interconnect may still be in SMBus mode
-                * after Sx->S0.  Toggle the LANPHYPC Value bit to force
-                * the interconnect to PCIe mode, but only if there is no
-                * firmware present otherwise firmware will have done it.
-                */
                ctrl = er32(CTRL);
                ctrl |=  E1000_CTRL_LANPHYPC_OVERRIDE;
                ctrl &= ~E1000_CTRL_LANPHYPC_VALUE;
@@ -326,6 +331,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
 
        switch (phy->type) {
        case e1000_phy_82577:
+       case e1000_phy_82579:
                phy->ops.check_polarity = e1000_check_polarity_82577;
                phy->ops.force_speed_duplex =
                        e1000_phy_force_speed_duplex_82577;
@@ -530,6 +536,7 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
                mac->ops.led_off = e1000_led_off_ich8lan;
                break;
        case e1000_pchlan:
+       case e1000_pch2lan:
                /* check management mode */
                mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan;
                /* ID LED init */
@@ -550,6 +557,14 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
        if (mac->type == e1000_ich8lan)
                e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
 
+       /* Disable PHY configuration by hardware, config by software */
+       if (mac->type == e1000_pch2lan) {
+               u32 extcnf_ctrl = er32(EXTCNF_CTRL);
+
+               extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG;
+               ew32(EXTCNF_CTRL, extcnf_ctrl);
+       }
+
        return 0;
 }
 
@@ -653,10 +668,19 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
        if (rc)
                return rc;
 
-       if (hw->mac.type == e1000_pchlan)
-               rc = e1000_init_phy_params_pchlan(hw);
-       else
+       switch (hw->mac.type) {
+       case e1000_ich8lan:
+       case e1000_ich9lan:
+       case e1000_ich10lan:
                rc = e1000_init_phy_params_ich8lan(hw);
+               break;
+       case e1000_pchlan:
+       case e1000_pch2lan:
+               rc = e1000_init_phy_params_pchlan(hw);
+               break;
+       default:
+               break;
+       }
        if (rc)
                return rc;
 
@@ -861,6 +885,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
                }
                /* Fall-thru */
        case e1000_pchlan:
+       case e1000_pch2lan:
                sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
                break;
        default:
@@ -880,8 +905,10 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
         * extended configuration before SW configuration
         */
        data = er32(EXTCNF_CTRL);
-       if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
-               goto out;
+       if (!(hw->mac.type == e1000_pch2lan)) {
+               if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+                       goto out;
+       }
 
        cnf_size = er32(EXTCNF_SIZE);
        cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
@@ -893,7 +920,8 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
        cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
 
        if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
-           (hw->mac.type == e1000_pchlan)) {
+           ((hw->mac.type == e1000_pchlan) ||
+            (hw->mac.type == e1000_pch2lan))) {
                /*
                 * HW configures the SMBus address and LEDs when the
                 * OEM and LCD Write Enable bits are set in the NVM.
@@ -1100,16 +1128,18 @@ static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
        u32 mac_reg;
        u16 oem_reg;
 
-       if (hw->mac.type != e1000_pchlan)
+       if ((hw->mac.type != e1000_pch2lan) && (hw->mac.type != e1000_pchlan))
                return ret_val;
 
        ret_val = hw->phy.ops.acquire(hw);
        if (ret_val)
                return ret_val;
 
-       mac_reg = er32(EXTCNF_CTRL);
-       if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
-               goto out;
+       if (!(hw->mac.type == e1000_pch2lan)) {
+               mac_reg = er32(EXTCNF_CTRL);
+               if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
+                       goto out;
+       }
 
        mac_reg = er32(FEXTNVM);
        if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
@@ -1249,6 +1279,243 @@ out:
        return ret_val;
 }
 
+/**
+ *  e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY
+ *  @hw:   pointer to the HW structure
+ **/
+void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
+{
+       u32 mac_reg;
+       u16 i;
+
+       /* Copy both RAL/H (rar_entry_count) and SHRAL/H (+4) to PHY */
+       for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+               mac_reg = er32(RAL(i));
+               e1e_wphy(hw, BM_RAR_L(i), (u16)(mac_reg & 0xFFFF));
+               e1e_wphy(hw, BM_RAR_M(i), (u16)((mac_reg >> 16) & 0xFFFF));
+               mac_reg = er32(RAH(i));
+               e1e_wphy(hw, BM_RAR_H(i), (u16)(mac_reg & 0xFFFF));
+               e1e_wphy(hw, BM_RAR_CTRL(i), (u16)((mac_reg >> 16) & 0x8000));
+       }
+}
+
+static u32 e1000_calc_rx_da_crc(u8 mac[])
+{
+       u32 poly = 0xEDB88320;  /* Polynomial for 802.3 CRC calculation */
+       u32 i, j, mask, crc;
+
+       crc = 0xffffffff;
+       for (i = 0; i < 6; i++) {
+               crc = crc ^ mac[i];
+               for (j = 8; j > 0; j--) {
+                       mask = (crc & 1) * (-1);
+                       crc = (crc >> 1) ^ (poly & mask);
+               }
+       }
+       return ~crc;
+}
+
+/**
+ *  e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation
+ *  with 82579 PHY
+ *  @hw: pointer to the HW structure
+ *  @enable: flag to enable/disable workaround when enabling/disabling jumbos
+ **/
+s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
+{
+       s32 ret_val = 0;
+       u16 phy_reg, data;
+       u32 mac_reg;
+       u16 i;
+
+       if (hw->mac.type != e1000_pch2lan)
+               goto out;
+
+       /* disable Rx path while enabling/disabling workaround */
+       e1e_rphy(hw, PHY_REG(769, 20), &phy_reg);
+       ret_val = e1e_wphy(hw, PHY_REG(769, 20), phy_reg | (1 << 14));
+       if (ret_val)
+               goto out;
+
+       if (enable) {
+               /*
+                * Write Rx addresses (rar_entry_count for RAL/H, +4 for
+                * SHRAL/H) and initial CRC values to the MAC
+                */
+               for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+                       u8 mac_addr[ETH_ALEN] = {0};
+                       u32 addr_high, addr_low;
+
+                       addr_high = er32(RAH(i));
+                       if (!(addr_high & E1000_RAH_AV))
+                               continue;
+                       addr_low = er32(RAL(i));
+                       mac_addr[0] = (addr_low & 0xFF);
+                       mac_addr[1] = ((addr_low >> 8) & 0xFF);
+                       mac_addr[2] = ((addr_low >> 16) & 0xFF);
+                       mac_addr[3] = ((addr_low >> 24) & 0xFF);
+                       mac_addr[4] = (addr_high & 0xFF);
+                       mac_addr[5] = ((addr_high >> 8) & 0xFF);
+
+                       ew32(PCH_RAICC(i),
+                                       e1000_calc_rx_da_crc(mac_addr));
+               }
+
+               /* Write Rx addresses to the PHY */
+               e1000_copy_rx_addrs_to_phy_ich8lan(hw);
+
+               /* Enable jumbo frame workaround in the MAC */
+               mac_reg = er32(FFLT_DBG);
+               mac_reg &= ~(1 << 14);
+               mac_reg |= (7 << 15);
+               ew32(FFLT_DBG, mac_reg);
+
+               mac_reg = er32(RCTL);
+               mac_reg |= E1000_RCTL_SECRC;
+               ew32(RCTL, mac_reg);
+
+               ret_val = e1000e_read_kmrn_reg(hw,
+                                               E1000_KMRNCTRLSTA_CTRL_OFFSET,
+                                               &data);
+               if (ret_val)
+                       goto out;
+               ret_val = e1000e_write_kmrn_reg(hw,
+                                               E1000_KMRNCTRLSTA_CTRL_OFFSET,
+                                               data | (1 << 0));
+               if (ret_val)
+                       goto out;
+               ret_val = e1000e_read_kmrn_reg(hw,
+                                               E1000_KMRNCTRLSTA_HD_CTRL,
+                                               &data);
+               if (ret_val)
+                       goto out;
+               data &= ~(0xF << 8);
+               data |= (0xB << 8);
+               ret_val = e1000e_write_kmrn_reg(hw,
+                                               E1000_KMRNCTRLSTA_HD_CTRL,
+                                               data);
+               if (ret_val)
+                       goto out;
+
+               /* Enable jumbo frame workaround in the PHY */
+               e1e_rphy(hw, PHY_REG(769, 20), &data);
+               ret_val = e1e_wphy(hw, PHY_REG(769, 20), data & ~(1 << 14));
+               if (ret_val)
+                       goto out;
+               e1e_rphy(hw, PHY_REG(769, 23), &data);
+               data &= ~(0x7F << 5);
+               data |= (0x37 << 5);
+               ret_val = e1e_wphy(hw, PHY_REG(769, 23), data);
+               if (ret_val)
+                       goto out;
+               e1e_rphy(hw, PHY_REG(769, 16), &data);
+               data &= ~(1 << 13);
+               data |= (1 << 12);
+               ret_val = e1e_wphy(hw, PHY_REG(769, 16), data);
+               if (ret_val)
+                       goto out;
+               e1e_rphy(hw, PHY_REG(776, 20), &data);
+               data &= ~(0x3FF << 2);
+               data |= (0x1A << 2);
+               ret_val = e1e_wphy(hw, PHY_REG(776, 20), data);
+               if (ret_val)
+                       goto out;
+               ret_val = e1e_wphy(hw, PHY_REG(776, 23), 0xFE00);
+               if (ret_val)
+                       goto out;
+               e1e_rphy(hw, HV_PM_CTRL, &data);
+               ret_val = e1e_wphy(hw, HV_PM_CTRL, data | (1 << 10));
+               if (ret_val)
+                       goto out;
+       } else {
+               /* Write MAC register values back to h/w defaults */
+               mac_reg = er32(FFLT_DBG);
+               mac_reg &= ~(0xF << 14);
+               ew32(FFLT_DBG, mac_reg);
+
+               mac_reg = er32(RCTL);
+               mac_reg &= ~E1000_RCTL_SECRC;
+               ew32(FFLT_DBG, mac_reg);
+
+               ret_val = e1000e_read_kmrn_reg(hw,
+                                               E1000_KMRNCTRLSTA_CTRL_OFFSET,
+                                               &data);
+               if (ret_val)
+                       goto out;
+               ret_val = e1000e_write_kmrn_reg(hw,
+                                               E1000_KMRNCTRLSTA_CTRL_OFFSET,
+                                               data & ~(1 << 0));
+               if (ret_val)
+                       goto out;
+               ret_val = e1000e_read_kmrn_reg(hw,
+                                               E1000_KMRNCTRLSTA_HD_CTRL,
+                                               &data);
+               if (ret_val)
+                       goto out;
+               data &= ~(0xF << 8);
+               data |= (0xB << 8);
+               ret_val = e1000e_write_kmrn_reg(hw,
+                                               E1000_KMRNCTRLSTA_HD_CTRL,
+                                               data);
+               if (ret_val)
+                       goto out;
+
+               /* Write PHY register values back to h/w defaults */
+               e1e_rphy(hw, PHY_REG(769, 20), &data);
+               ret_val = e1e_wphy(hw, PHY_REG(769, 20), data & ~(1 << 14));
+               if (ret_val)
+                       goto out;
+               e1e_rphy(hw, PHY_REG(769, 23), &data);
+               data &= ~(0x7F << 5);
+               ret_val = e1e_wphy(hw, PHY_REG(769, 23), data);
+               if (ret_val)
+                       goto out;
+               e1e_rphy(hw, PHY_REG(769, 16), &data);
+               data &= ~(1 << 12);
+               data |= (1 << 13);
+               ret_val = e1e_wphy(hw, PHY_REG(769, 16), data);
+               if (ret_val)
+                       goto out;
+               e1e_rphy(hw, PHY_REG(776, 20), &data);
+               data &= ~(0x3FF << 2);
+               data |= (0x8 << 2);
+               ret_val = e1e_wphy(hw, PHY_REG(776, 20), data);
+               if (ret_val)
+                       goto out;
+               ret_val = e1e_wphy(hw, PHY_REG(776, 23), 0x7E00);
+               if (ret_val)
+                       goto out;
+               e1e_rphy(hw, HV_PM_CTRL, &data);
+               ret_val = e1e_wphy(hw, HV_PM_CTRL, data & ~(1 << 10));
+               if (ret_val)
+                       goto out;
+       }
+
+       /* re-enable Rx path after enabling/disabling workaround */
+       ret_val = e1e_wphy(hw, PHY_REG(769, 20), phy_reg & ~(1 << 14));
+
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be
+ *  done after every PHY reset.
+ **/
+static s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw)
+{
+       s32 ret_val = 0;
+
+       if (hw->mac.type != e1000_pch2lan)
+               goto out;
+
+       /* Set MDIO slow mode before any other MDIO access */
+       ret_val = e1000_set_mdio_slow_mode_hv(hw);
+
+out:
+       return ret_val;
+}
+
 /**
  *  e1000_lan_init_done_ich8lan - Check for PHY config completion
  *  @hw: pointer to the HW structure
@@ -1300,12 +1567,17 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
                if (ret_val)
                        goto out;
                break;
+       case e1000_pch2lan:
+               ret_val = e1000_lv_phy_workarounds_ich8lan(hw);
+               if (ret_val)
+                       goto out;
+               break;
        default:
                break;
        }
 
        /* Dummy read to clear the phy wakeup bit after lcd reset */
-       if (hw->mac.type == e1000_pchlan)
+       if (hw->mac.type >= e1000_pchlan)
                e1e_rphy(hw, BM_WUC, &reg);
 
        /* Configure the LCD with the extended configuration region in NVM */
@@ -2829,6 +3101,7 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
 
        ew32(FCTTV, hw->fc.pause_time);
        if ((hw->phy.type == e1000_phy_82578) ||
+           (hw->phy.type == e1000_phy_82579) ||
            (hw->phy.type == e1000_phy_82577)) {
                ew32(FCRTV_PCH, hw->fc.refresh_time);
 
@@ -2892,6 +3165,7 @@ static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
                        return ret_val;
                break;
        case e1000_phy_82577:
+       case e1000_phy_82579:
                ret_val = e1000_copper_link_setup_82577(hw);
                if (ret_val)
                        return ret_val;
@@ -3399,6 +3673,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
 
        /* Clear PHY statistics registers */
        if ((hw->phy.type == e1000_phy_82578) ||
+           (hw->phy.type == e1000_phy_82579) ||
            (hw->phy.type == e1000_phy_82577)) {
                hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data);
                hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data);
@@ -3534,3 +3809,22 @@ struct e1000_info e1000_pch_info = {
        .phy_ops                = &ich8_phy_ops,
        .nvm_ops                = &ich8_nvm_ops,
 };
+
+struct e1000_info e1000_pch2_info = {
+       .mac                    = e1000_pch2lan,
+       .flags                  = FLAG_IS_ICH
+                                 | FLAG_HAS_WOL
+                                 | FLAG_RX_CSUM_ENABLED
+                                 | FLAG_HAS_CTRLEXT_ON_LOAD
+                                 | FLAG_HAS_AMT
+                                 | FLAG_HAS_FLASH
+                                 | FLAG_HAS_JUMBO_FRAMES
+                                 | FLAG_APME_IN_WUC,
+       .flags2                 = FLAG2_HAS_PHY_STATS,
+       .pba                    = 18,
+       .max_hw_frame_size      = DEFAULT_JUMBO,
+       .get_variants           = e1000_get_variants_ich8lan,
+       .mac_ops                = &ich8_mac_ops,
+       .phy_ops                = &ich8_phy_ops,
+       .nvm_ops                = &ich8_nvm_ops,
+};
index b4c431d8451678e9828f23a0629f632daa49dba6..f296f6f32a367ca4ed46f8bc3bc90c59aaab42a8 100644 (file)
@@ -67,6 +67,7 @@ static const struct e1000_info *e1000_info_tbl[] = {
        [board_ich9lan]         = &e1000_ich9_info,
        [board_ich10lan]        = &e1000_ich10_info,
        [board_pchlan]          = &e1000_pch_info,
+       [board_pch2lan]         = &e1000_pch2_info,
 };
 
 struct e1000_reg_info {
@@ -2723,6 +2724,16 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
                e1e_wphy(hw, 22, phy_data);
        }
 
+       /* Workaround Si errata on 82579 - configure jumbo frame flow */
+       if (hw->mac.type == e1000_pch2lan) {
+               s32 ret_val;
+
+               if (rctl & E1000_RCTL_LPE)
+                       ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, true);
+               else
+                       ret_val = e1000_lv_jumbo_workaround_ich8lan(hw, false);
+       }
+
        /* Setup buffer sizes */
        rctl &= ~E1000_RCTL_SZ_4096;
        rctl |= E1000_RCTL_BSEX;
@@ -3118,7 +3129,27 @@ void e1000e_reset(struct e1000_adapter *adapter)
         *   with ERT support assuming ERT set to E1000_ERT_2048), or
         * - the full Rx FIFO size minus one full frame
         */
-       if (hw->mac.type == e1000_pchlan) {
+       if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME)
+               fc->pause_time = 0xFFFF;
+       else
+               fc->pause_time = E1000_FC_PAUSE_TIME;
+       fc->send_xon = 1;
+       fc->current_mode = fc->requested_mode;
+
+       switch (hw->mac.type) {
+       default:
+               if ((adapter->flags & FLAG_HAS_ERT) &&
+                   (adapter->netdev->mtu > ETH_DATA_LEN))
+                       hwm = min(((pba << 10) * 9 / 10),
+                                 ((pba << 10) - (E1000_ERT_2048 << 3)));
+               else
+                       hwm = min(((pba << 10) * 9 / 10),
+                                 ((pba << 10) - adapter->max_frame_size));
+
+               fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */
+               fc->low_water = fc->high_water - 8;
+               break;
+       case e1000_pchlan:
                /*
                 * Workaround PCH LOM adapter hangs with certain network
                 * loads.  If hangs persist, try disabling Tx flow control.
@@ -3131,26 +3162,15 @@ void e1000e_reset(struct e1000_adapter *adapter)
                        fc->low_water  = 0x3000;
                }
                fc->refresh_time = 0x1000;
-       } else {
-               if ((adapter->flags & FLAG_HAS_ERT) &&
-                   (adapter->netdev->mtu > ETH_DATA_LEN))
-                       hwm = min(((pba << 10) * 9 / 10),
-                                 ((pba << 10) - (E1000_ERT_2048 << 3)));
-               else
-                       hwm = min(((pba << 10) * 9 / 10),
-                                 ((pba << 10) - adapter->max_frame_size));
-
-               fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */
-               fc->low_water = fc->high_water - 8;
+               break;
+       case e1000_pch2lan:
+               fc->high_water = 0x05C20;
+               fc->low_water = 0x05048;
+               fc->pause_time = 0x0650;
+               fc->refresh_time = 0x0400;
+               break;
        }
 
-       if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME)
-               fc->pause_time = 0xFFFF;
-       else
-               fc->pause_time = E1000_FC_PAUSE_TIME;
-       fc->send_xon = 1;
-       fc->current_mode = fc->requested_mode;
-
        /* Allow time for pending master requests to run */
        mac->ops.reset_hw(hw);
 
@@ -4918,14 +4938,7 @@ static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
        int retval = 0;
 
        /* copy MAC RARs to PHY RARs */
-       for (i = 0; i < adapter->hw.mac.rar_entry_count; i++) {
-               mac_reg = er32(RAL(i));
-               e1e_wphy(hw, BM_RAR_L(i), (u16)(mac_reg & 0xFFFF));
-               e1e_wphy(hw, BM_RAR_M(i), (u16)((mac_reg >> 16) & 0xFFFF));
-               mac_reg = er32(RAH(i));
-               e1e_wphy(hw, BM_RAR_H(i), (u16)(mac_reg & 0xFFFF));
-               e1e_wphy(hw, BM_RAR_CTRL(i), (u16)((mac_reg >> 16) & 0xFFFF));
-       }
+       e1000_copy_rx_addrs_to_phy_ich8lan(hw);
 
        /* copy MAC MTA to PHY MTA */
        for (i = 0; i < adapter->hw.mac.mta_reg_count; i++) {
@@ -5976,6 +5989,9 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DM), board_pchlan },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_D_HV_DC), board_pchlan },
 
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_LM), board_pch2lan },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_V), board_pch2lan },
+
        { }     /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
index b4ac82d51b2016809a2aee7e1dd61cb644868d5e..e471357be302394a3156d4543db30e534f61c458 100644 (file)
@@ -2319,6 +2319,9 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
        case I82577_E_PHY_ID:
                phy_type = e1000_phy_82577;
                break;
+       case I82579_E_PHY_ID:
+               phy_type = e1000_phy_82579;
+               break;
        default:
                phy_type = e1000_phy_unknown;
                break;