Module: xenomai-3
Branch: master
Commit: ad0aa8a00d9e5a377b48b8a74003479f34255fff
URL:    
http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=ad0aa8a00d9e5a377b48b8a74003479f34255fff

Author: Huy Cong Vu <huy-cong...@wandercraft.eu>
Date:   Wed Feb 11 21:05:58 2015 +0100

rtnet/e100e: update e1000e driver for Intel i217/i218

---

 kernel/drivers/net/drivers/e1000e/defines.h |    8 +
 kernel/drivers/net/drivers/e1000e/e1000.h   |   12 +
 kernel/drivers/net/drivers/e1000e/hw.h      |   13 ++
 kernel/drivers/net/drivers/e1000e/ich8lan.c |  337 +++++++++++++++++++++++++--
 kernel/drivers/net/drivers/e1000e/netdev.c  |   11 +-
 kernel/drivers/net/drivers/e1000e/phy.c     |    3 +
 6 files changed, 358 insertions(+), 26 deletions(-)

diff --git a/kernel/drivers/net/drivers/e1000e/defines.h 
b/kernel/drivers/net/drivers/e1000e/defines.h
index c516a74..ffa4c02 100644
--- a/kernel/drivers/net/drivers/e1000e/defines.h
+++ b/kernel/drivers/net/drivers/e1000e/defines.h
@@ -74,7 +74,9 @@
 #define E1000_WUS_BC           E1000_WUFC_BC
 
 /* Extended Device Control */
+#define E1000_CTRL_EXT_LPCD  0x00000004     /* LCD Power Cycle Done */
 #define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */
+#define E1000_CTRL_EXT_FORCE_SMBUS 0x00000004 /* Force SMBus mode*/
 #define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
 #define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
 #define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
@@ -564,6 +566,7 @@
 #define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
 
 /* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP 100TX Full Dplx Capable */
 #define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
 #define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
 
@@ -730,6 +733,7 @@
 #define I82577_E_PHY_ID      0x01540050
 #define I82578_E_PHY_ID      0x004DD040
 #define I82579_E_PHY_ID      0x01540090
+#define I217_E_PHY_ID        0x015400A0
 
 /* M88E1000 Specific Registers */
 #define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
@@ -841,4 +845,8 @@
 /* SerDes Control */
 #define E1000_GEN_POLL_TIMEOUT          640
 
+/* FW Semaphore */
+#define E1000_FWSM_WLOCK_MAC_MASK      0x0380
+#define E1000_FWSM_WLOCK_MAC_SHIFT     7
+
 #endif /* _E1000_DEFINES_H_ */
diff --git a/kernel/drivers/net/drivers/e1000e/e1000.h 
b/kernel/drivers/net/drivers/e1000e/e1000.h
index 04c0d46..2de6814 100644
--- a/kernel/drivers/net/drivers/e1000e/e1000.h
+++ b/kernel/drivers/net/drivers/e1000e/e1000.h
@@ -202,6 +202,7 @@ enum e1000_boards {
        board_ich10lan,
        board_pchlan,
        board_pch2lan,
+       board_pch_lpt,
 };
 
 struct e1000_ps_page {
@@ -527,6 +528,7 @@ extern const struct e1000_info e1000_ich9_info;
 extern const struct e1000_info e1000_ich10_info;
 extern const struct e1000_info e1000_pch_info;
 extern const struct e1000_info e1000_pch2_info;
+extern const struct e1000_info e1000_pch_lpt_info;
 extern const struct e1000_info e1000_es2_info;
 
 extern s32 e1000_read_pba_string_generic(struct e1000_hw *hw, u8 *pba_num,
@@ -677,11 +679,21 @@ static inline s32 e1e_rphy(struct e1000_hw *hw, u32 
offset, u16 *data)
        return hw->phy.ops.read_reg(hw, offset, data);
 }
 
+static inline s32 e1e_rphy_locked(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+       return hw->phy.ops.read_reg_locked(hw, offset, data);
+}
+
 static inline s32 e1e_wphy(struct e1000_hw *hw, u32 offset, u16 data)
 {
        return hw->phy.ops.write_reg(hw, offset, data);
 }
 
+static inline s32 e1e_wphy_locked(struct e1000_hw *hw, u32 offset, u16 data)
+{
+       return hw->phy.ops.write_reg_locked(hw, offset, data);
+}
+
 static inline s32 e1000_get_cable_length(struct e1000_hw *hw)
 {
        return hw->phy.ops.get_cable_length(hw);
diff --git a/kernel/drivers/net/drivers/e1000e/hw.h 
b/kernel/drivers/net/drivers/e1000e/hw.h
index 2967039..247f79e 100644
--- a/kernel/drivers/net/drivers/e1000e/hw.h
+++ b/kernel/drivers/net/drivers/e1000e/hw.h
@@ -200,6 +200,10 @@ enum e1e_registers {
 #define E1000_RA        (E1000_RAL(0))
        E1000_RAH_BASE = 0x05404, /* Receive Address High - RW */
 #define E1000_RAH(_n)   (E1000_RAH_BASE + ((_n) * 8))
+       E1000_SHRAL_PCH_LPT_BASE = 0x05408,
+#define E1000_SHRAL_PCH_LPT(_n)   (E1000_SHRAL_PCH_LPT_BASE + ((_n) * 8))
+       E1000_SHRAH_PCH_LTP_BASE = 0x0540C,
+#define E1000_SHRAH_PCH_LPT(_n)   (E1000_SHRAH_PCH_LTP_BASE + ((_n) * 8))
        E1000_VFTA     = 0x05600, /* VLAN Filter Table Array - RW Array */
        E1000_WUC      = 0x05800, /* Wakeup Control - RW */
        E1000_WUFC     = 0x05808, /* Wakeup Filter Control - RW */
@@ -397,6 +401,10 @@ enum e1e_registers {
 #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_DEV_ID_PCH_LPT_I217_LM           0x153A
+#define E1000_DEV_ID_PCH_LPT_I217_V            0x153B
+#define E1000_DEV_ID_PCH_LPTLP_I218_LM         0x155A
+#define E1000_DEV_ID_PCH_LPTLP_I218_V          0x1559
 
 #define E1000_REVISION_4 4
 
@@ -417,6 +425,7 @@ enum e1000_mac_type {
        e1000_ich10lan,
        e1000_pchlan,
        e1000_pch2lan,
+       e1000_pch_lpt,
 };
 
 enum e1000_media_type {
@@ -454,6 +463,7 @@ enum e1000_phy_type {
        e1000_phy_82578,
        e1000_phy_82577,
        e1000_phy_82579,
+       e1000_phy_i217,
 };
 
 enum e1000_bus_width {
@@ -776,6 +786,8 @@ struct e1000_mac_operations {
        s32  (*setup_physical_interface)(struct e1000_hw *);
        s32  (*setup_led)(struct e1000_hw *);
        void (*write_vfta)(struct e1000_hw *, u32, u32);
+       void (*config_collision_dist)(struct e1000_hw *);
+       void (*rar_set)(struct e1000_hw *, u8 *, u32);
        s32  (*read_mac_addr)(struct e1000_hw *);
 };
 
@@ -959,6 +971,7 @@ struct e1000_dev_spec_ich8lan {
        struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
        bool nvm_k1_enabled;
        bool eee_disable;
+       u16 eee_lp_ability;
 };
 
 struct e1000_hw {
diff --git a/kernel/drivers/net/drivers/e1000e/ich8lan.c 
b/kernel/drivers/net/drivers/e1000e/ich8lan.c
index 6a17c62..4e2e530 100644
--- a/kernel/drivers/net/drivers/e1000e/ich8lan.c
+++ b/kernel/drivers/net/drivers/e1000e/ich8lan.c
@@ -105,6 +105,9 @@
 #define E1000_FEXTNVM_SW_CONFIG                1
 #define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M :/ 
*/
 
+#define E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK    0x0C000000
+#define E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC  0x08000000
+
 #define E1000_FEXTNVM4_BEACON_DURATION_MASK    0x7
 #define E1000_FEXTNVM4_BEACON_DURATION_8USEC   0x7
 #define E1000_FEXTNVM4_BEACON_DURATION_16USEC  0x3
@@ -112,6 +115,8 @@
 #define PCIE_ICH8_SNOOP_ALL            PCIE_NO_SNOOP_ALL
 
 #define E1000_ICH_RAR_ENTRIES          7
+#define E1000_PCH2_RAR_ENTRIES         5 /* RAR[0], SHRA[0-3] */
+#define E1000_PCH_LPT_RAR_ENTRIES      12 /* RAR[0], SHRA[0-10] */
 
 #define PHY_PAGE_SHIFT 5
 #define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
@@ -127,14 +132,22 @@
 
 #define SW_FLAG_TIMEOUT    1000 /* SW Semaphore flag timeout in milliseconds */
 
+/* SMBus Control Phy Register */
+#define CV_SMB_CTRL            PHY_REG(769, 23)
+#define CV_SMB_CTRL_FORCE_SMBUS        0x0001
+
 /* SMBus Address Phy Register */
 #define HV_SMB_ADDR            PHY_REG(768, 26)
 #define HV_SMB_ADDR_MASK       0x007F
 #define HV_SMB_ADDR_PEC_EN     0x0200
 #define HV_SMB_ADDR_VALID      0x0080
+#define HV_SMB_ADDR_FREQ_MASK           0x1100
+#define HV_SMB_ADDR_FREQ_LOW_SHIFT      8
+#define HV_SMB_ADDR_FREQ_HIGH_SHIFT     12
 
 /* PHY Power Management Control */
 #define HV_PM_CTRL             PHY_REG(770, 17)
+#define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100
 
 /* PHY Low Power Idle Control */
 #define I82579_LPI_CTRL                                PHY_REG(772, 20)
@@ -146,10 +159,26 @@
 #define I82579_EMI_DATA         0x11
 #define I82579_LPI_UPDATE_TIMER 0x4805 /* in 40ns units + 40 ns base value */
 
+#define I217_EEE_ADVERTISEMENT  0x8001 /* IEEE MMD Register 7.60 */
+#define I217_EEE_LP_ABILITY     0x8002 /* IEEE MMD Register 7.61 */
+#define I217_EEE_100_SUPPORTED  (1 << 1)       /* 100BaseTx EEE supported */
+
+/* Intel Rapid Start Technology Support */
+#define I217_PROXY_CTRL                 PHY_REG(BM_WUC_PAGE, 70)
+#define I217_PROXY_CTRL_AUTO_DISABLE    0x0080
+#define I217_SxCTRL                     PHY_REG(BM_PORT_CTRL_PAGE, 28)
+#define I217_SxCTRL_MASK                0x1000
+#define I217_CGFREG                     PHY_REG(772, 29)
+#define I217_CGFREG_MASK                0x0002
+#define I217_MEMPWR                     PHY_REG(772, 26)
+#define I217_MEMPWR_MASK                0x0010
+
 /* Strapping Option Register - RO */
 #define E1000_STRAP                     0x0000C
 #define E1000_STRAP_SMBUS_ADDRESS_MASK  0x00FE0000
 #define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17
+#define E1000_STRAP_SMT_FREQ_MASK       0x00003000
+#define E1000_STRAP_SMT_FREQ_SHIFT      12
 
 /* OEM Bits Phy Register */
 #define HV_OEM_BITS            PHY_REG(768, 25)
@@ -253,6 +282,7 @@ static s32  e1000_k1_gig_workaround_hv(struct e1000_hw *hw, 
bool link);
 static s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw);
 static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
 static bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw);
+static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index);
 static s32 e1000_k1_workaround_lv(struct e1000_hw *hw);
 static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate);
 
@@ -369,6 +399,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
                        break;
                /* fall-through */
        case e1000_pch2lan:
+       case e1000_pch_lpt:
                /*
                 * In case the PHY needs to be in mdio slow mode,
                 * set slow mode and try to get the PHY id again.
@@ -386,6 +417,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
        switch (phy->type) {
        case e1000_phy_82577:
        case e1000_phy_82579:
+       case e1000_phy_i217:
                phy->ops.check_polarity = e1000_check_polarity_82577;
                phy->ops.force_speed_duplex =
                    e1000_phy_force_speed_duplex_82577;
@@ -591,6 +623,7 @@ static s32 e1000_init_mac_params_ich8lan(struct 
e1000_adapter *adapter)
                mac->ops.led_on = e1000_led_on_ich8lan;
                mac->ops.led_off = e1000_led_off_ich8lan;
                break;
+       case e1000_pch_lpt:
        case e1000_pchlan:
        case e1000_pch2lan:
                /* check management mode */
@@ -609,12 +642,19 @@ static s32 e1000_init_mac_params_ich8lan(struct 
e1000_adapter *adapter)
                break;
        }
 
+       if (mac->type == e1000_pch_lpt) {
+               mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES;
+               mac->ops.rar_set = e1000_rar_set_pch_lpt;
+       }
+
        /* Enable PCS Lock-loss workaround for ICH8 */
        if (mac->type == e1000_ich8lan)
                e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
 
-       /* Gate automatic PHY configuration by hardware on managed 82579 */
-       if ((mac->type == e1000_pch2lan) &&
+       /* Gate automatic PHY configuration by hardware on managed
+        * 82579 and i217
+        */
+       if ((mac->type == e1000_pch2lan || mac->type == e1000_pch_lpt) &&
            (er32(FWSM) & E1000_ICH_FWSM_FW_VALID))
                e1000_gate_hw_phy_config_ich8lan(hw, true);
 
@@ -630,24 +670,50 @@ static s32 e1000_init_mac_params_ich8lan(struct 
e1000_adapter *adapter)
  **/
 static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
 {
+       struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
        s32 ret_val = 0;
        u16 phy_reg;
 
-       if (hw->phy.type != e1000_phy_82579)
-               goto out;
+       if ((hw->phy.type != e1000_phy_82579) &&
+           (hw->phy.type != e1000_phy_i217))
+               return ret_val;
 
        ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg);
        if (ret_val)
-               goto out;
+               return ret_val;
 
-       if (hw->dev_spec.ich8lan.eee_disable)
+       if (dev_spec->eee_disable)
                phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK;
        else
                phy_reg |= I82579_LPI_CTRL_ENABLE_MASK;
 
        ret_val = e1e_wphy(hw, I82579_LPI_CTRL, phy_reg);
-out:
-       return ret_val;
+
+       if (ret_val)
+               return ret_val;
+
+       if ((hw->phy.type == e1000_phy_i217) && !dev_spec->eee_disable) {
+               /* Save off link partner's EEE ability */
+               ret_val = hw->phy.ops.acquire(hw);
+               if (ret_val)
+                       return ret_val;
+               ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR,
+                                         I217_EEE_LP_ABILITY);
+               if (ret_val)
+                       goto release;
+               e1e_rphy_locked(hw, I82579_EMI_DATA, &dev_spec->eee_lp_ability);
+
+               /* EEE is not supported in 100Half, so ignore partner's EEE
+                * in 100 ability if full-duplex is not advertised.
+                */
+               e1e_rphy_locked(hw, PHY_LP_ABILITY, &phy_reg);
+               if (!(phy_reg & NWAY_LPAR_100TX_FD_CAPS))
+                       dev_spec->eee_lp_ability &= ~I217_EEE_100_SUPPORTED;
+release:
+               hw->phy.ops.release(hw);
+       }
+
+       return 0;
 }
 
 /**
@@ -691,6 +757,9 @@ static s32 e1000_check_for_copper_link_ich8lan(struct 
e1000_hw *hw)
                        goto out;
        }
 
+       /* Clear link partner's EEE ability */
+       hw->dev_spec.ich8lan.eee_lp_ability = 0;
+
        if (!link)
                goto out; /* No link detected */
 
@@ -789,6 +858,7 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter 
*adapter)
                break;
        case e1000_pchlan:
        case e1000_pch2lan:
+       case e1000_pch_lpt:
                rc = e1000_init_phy_params_pchlan(hw);
                break;
        default:
@@ -976,6 +1046,79 @@ static bool e1000_check_mng_mode_pchlan(struct e1000_hw 
*hw)
 }
 
 /**
+ *  e1000_rar_set_pch_lpt - Set receive address registers
+ *  @hw: pointer to the HW structure
+ *  @addr: pointer to the receive address
+ *  @index: receive address array register
+ *
+ *  Sets the receive address register array at index to the address passed
+ *  in by addr. For LPT, RAR[0] is the base address register that is to
+ *  contain the MAC address. SHRA[0-10] are the shared receive address
+ *  registers that are shared between the Host and manageability engine (ME).
+ **/
+static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+       u32 rar_low, rar_high;
+       u32 wlock_mac;
+
+       /* HW expects these in little endian so we reverse the byte order
+        * from network order (big endian) to little endian
+        */
+       rar_low = ((u32)addr[0] | ((u32)addr[1] << 8) |
+                  ((u32)addr[2] << 16) | ((u32)addr[3] << 24));
+
+       rar_high = ((u32)addr[4] | ((u32)addr[5] << 8));
+
+       /* If MAC address zero, no need to set the AV bit */
+       if (rar_low || rar_high)
+               rar_high |= E1000_RAH_AV;
+
+       if (index == 0) {
+               ew32(RAL(index), rar_low);
+               e1e_flush();
+               ew32(RAH(index), rar_high);
+               e1e_flush();
+               return;
+       }
+
+       /* The manageability engine (ME) can lock certain SHRAR registers that
+        * it is using - those registers are unavailable for use.
+        */
+       if (index < hw->mac.rar_entry_count) {
+               wlock_mac = er32(FWSM) & E1000_FWSM_WLOCK_MAC_MASK;
+               wlock_mac >>= E1000_FWSM_WLOCK_MAC_SHIFT;
+
+               /* Check if all SHRAR registers are locked */
+               if (wlock_mac == 1)
+                       goto out;
+
+               if ((wlock_mac == 0) || (index <= wlock_mac)) {
+                       s32 ret_val;
+
+                       ret_val = e1000_acquire_swflag_ich8lan(hw);
+
+                       if (ret_val)
+                               goto out;
+
+                       ew32(SHRAL_PCH_LPT(index - 1), rar_low);
+                       e1e_flush();
+                       ew32(SHRAH_PCH_LPT(index - 1), rar_high);
+                       e1e_flush();
+
+                       e1000_release_swflag_ich8lan(hw);
+
+                       /* verify the register updates */
+                       if ((er32(SHRAL_PCH_LPT(index - 1)) == rar_low) &&
+                           (er32(SHRAH_PCH_LPT(index - 1)) == rar_high))
+                               return;
+               }
+       }
+
+out:
+       e_dbg("Failed to write receive address at index %d\n", index);
+}
+
+/**
  *  e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
  *  @hw: pointer to the HW structure
  *
@@ -1003,6 +1146,8 @@ static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
 {
        u16 phy_data;
        u32 strap = er32(STRAP);
+       u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >>
+           E1000_STRAP_SMT_FREQ_SHIFT;
        s32 ret_val = 0;
 
        strap &= E1000_STRAP_SMBUS_ADDRESS_MASK;
@@ -1014,6 +1159,20 @@ static s32 e1000_write_smbus_addr(struct e1000_hw *hw)
        phy_data &= ~HV_SMB_ADDR_MASK;
        phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT);
        phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
+
+       if (hw->phy.type == e1000_phy_i217) {
+               /* Restore SMBus frequency */
+               if (freq--) {
+                       phy_data &= ~HV_SMB_ADDR_FREQ_MASK;
+                       phy_data |= (freq & (1 << 0)) <<
+                           HV_SMB_ADDR_FREQ_LOW_SHIFT;
+                       phy_data |= (freq & (1 << 1)) <<
+                           (HV_SMB_ADDR_FREQ_HIGH_SHIFT - 1);
+               } else {
+                       e_dbg("Unsupported SMB frequency in PHY\n");
+               }
+       }
+
        ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data);
 
 out:
@@ -1054,6 +1213,7 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw 
*hw)
                /* Fall-thru */
        case e1000_pchlan:
        case e1000_pch2lan:
+       case e1000_pch_lpt:
                sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
                break;
        default:
@@ -1073,10 +1233,9 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw 
*hw)
         * extended configuration before SW configuration
         */
        data = er32(EXTCNF_CTRL);
-       if (!(hw->mac.type == e1000_pch2lan)) {
-               if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
-                       goto out;
-       }
+       if ((hw->mac.type < e1000_pch2lan) &&
+           (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE))
+               goto out;
 
        cnf_size = er32(EXTCNF_SIZE);
        cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
@@ -1087,9 +1246,9 @@ static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw 
*hw)
        cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
        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_pch2lan)) {
+       if (((hw->mac.type == e1000_pchlan) &&
+            !(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)) ||
+           (hw->mac.type > e1000_pchlan)) {
                /*
                 * HW configures the SMBus address and LEDs when the
                 * OEM and LCD Write Enable bits are set in the NVM.
@@ -1293,14 +1452,14 @@ 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_pch2lan) && (hw->mac.type != e1000_pchlan))
+       if (hw->mac.type < e1000_pchlan)
                return ret_val;
 
        ret_val = hw->phy.ops.acquire(hw);
        if (ret_val)
                return ret_val;
 
-       if (!(hw->mac.type == e1000_pch2lan)) {
+       if (hw->mac.type == e1000_pchlan) {
                mac_reg = er32(EXTCNF_CTRL);
                if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
                        goto out;
@@ -1497,7 +1656,7 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw 
*hw, bool enable)
        u32 mac_reg;
        u16 i;
 
-       if (hw->mac.type != e1000_pch2lan)
+       if (hw->mac.type < e1000_pch2lan)
                goto out;
 
        /* disable Rx path while enabling/disabling workaround */
@@ -1664,7 +1823,7 @@ static s32 e1000_lv_phy_workarounds_ich8lan(struct 
e1000_hw *hw)
 {
        s32 ret_val = 0;
 
-       if (hw->mac.type != e1000_pch2lan)
+       if (hw->mac.type < e1000_pch2lan)
                goto out;
 
        /* Set MDIO slow mode before any other MDIO access */
@@ -1867,12 +2026,9 @@ static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw 
*hw)
 
        ret_val = e1000e_phy_hw_reset_generic(hw);
        if (ret_val)
-               goto out;
-
-       ret_val = e1000_post_phy_reset_ich8lan(hw);
+               return ret_val;
 
-out:
-       return ret_val;
+       return e1000_post_phy_reset_ich8lan(hw);
 }
 
 /**
@@ -3373,6 +3529,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_i217) ||
            (hw->phy.type == e1000_phy_82577)) {
                ew32(FCRTV_PCH, hw->fc.refresh_time);
 
@@ -3436,6 +3593,7 @@ static s32 e1000_setup_copper_link_ich8lan(struct 
e1000_hw *hw)
                break;
        case e1000_phy_82577:
        case e1000_phy_82579:
+       case e1000_phy_i217:
                ret_val = e1000_copper_link_setup_82577(hw);
                if (ret_val)
                        return ret_val;
@@ -3680,14 +3838,85 @@ void e1000e_gig_downshift_workaround_ich8lan(struct 
e1000_hw *hw)
  *  'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
  *  to a lower speed.  For PCH and newer parts, the OEM bits PHY register
  *  (LED, GbE disable and LPLU configurations) also needs to be written.
+ *  Parts that support (and are linked to a partner which support) EEE in
+ *  100Mbps should disable LPLU since 100Mbps w/ EEE requires less power
+ *  than 10Mbps w/o EEE.
  **/
 void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
 {
+       struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
        u32 phy_ctrl;
        s32 ret_val;
 
        phy_ctrl = er32(PHY_CTRL);
        phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | E1000_PHY_CTRL_GBE_DISABLE;
+
+       if (hw->phy.type == e1000_phy_i217) {
+               u16 phy_reg;
+
+               ret_val = hw->phy.ops.acquire(hw);
+               if (ret_val)
+                       goto out;
+
+               if (!dev_spec->eee_disable) {
+                       u16 eee_advert;
+
+                       ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR,
+                                                 I217_EEE_ADVERTISEMENT);
+                       if (ret_val)
+                               goto release;
+                       e1e_rphy_locked(hw, I82579_EMI_DATA, &eee_advert);
+
+                       /* Disable LPLU if both link partners support 100BaseT
+                        * EEE and 100Full is advertised on both ends of the
+                        * link.
+                        */
+                       if ((eee_advert & I217_EEE_100_SUPPORTED) &&
+                           (dev_spec->eee_lp_ability &
+                            I217_EEE_100_SUPPORTED) &&
+                           (hw->phy.autoneg_advertised & ADVERTISE_100_FULL))
+                               phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU |
+                                             E1000_PHY_CTRL_NOND0A_LPLU);
+               }
+
+               /* For i217 Intel Rapid Start Technology support,
+                * when the system is going into Sx and no manageability engine
+                * is present, the driver must configure proxy to reset only on
+                * power good.  LPI (Low Power Idle) state must also reset only
+                * on power good, as well as the MTA (Multicast table array).
+                * The SMBus release must also be disabled on LCD reset.
+                */
+               if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
+
+                       /* Enable proxy to reset only on power good. */
+                       e1e_rphy_locked(hw, I217_PROXY_CTRL, &phy_reg);
+                       phy_reg |= I217_PROXY_CTRL_AUTO_DISABLE;
+                       e1e_wphy_locked(hw, I217_PROXY_CTRL, phy_reg);
+
+                       /* Set bit enable LPI (EEE) to reset only on
+                        * power good.
+                        */
+                       e1e_rphy_locked(hw, I217_SxCTRL, &phy_reg);
+                       phy_reg |= I217_SxCTRL_MASK;
+                       e1e_wphy_locked(hw, I217_SxCTRL, phy_reg);
+
+                       /* Disable the SMB release on LCD reset. */
+                       e1e_rphy_locked(hw, I217_MEMPWR, &phy_reg);
+                       phy_reg &= ~I217_MEMPWR;
+                       e1e_wphy_locked(hw, I217_MEMPWR, phy_reg);
+               }
+
+               /* Enable MTA to reset for Intel Rapid Start Technology
+                * Support
+                */
+               e1e_rphy_locked(hw, I217_CGFREG, &phy_reg);
+               phy_reg |= I217_CGFREG_MASK;
+               e1e_wphy_locked(hw, I217_CGFREG, phy_reg);
+
+release:
+               hw->phy.ops.release(hw);
+       }
+out:
        ew32(PHY_CTRL, phy_ctrl);
 
        if (hw->mac.type == e1000_ich8lan)
@@ -3712,6 +3941,7 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw 
*hw)
  *  on which PHY resets are not blocked, if the PHY registers cannot be
  *  accessed properly by the s/w toggle the LANPHYPC value to power cycle
  *  the PHY.
+ *  On i217, setup Intel Rapid Start Technology.
  **/
 void e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
 {
@@ -3731,6 +3961,45 @@ void e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
                        return;
                }
 
+       /* For i217 Intel Rapid Start Technology support when the system
+        * is transitioning from Sx and no manageability engine is present
+        * configure SMBus to restore on reset, disable proxy, and enable
+        * the reset on MTA (Multicast table array).
+        */
+       if (hw->phy.type == e1000_phy_i217) {
+               u16 phy_reg;
+
+               ret_val = hw->phy.ops.acquire(hw);
+               if (ret_val) {
+                       e_dbg("Failed to setup iRST\n");
+                       return;
+               }
+
+               if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
+                       /* Restore clear on SMB if no manageability engine
+                        * is present
+                        */
+                       ret_val = e1e_rphy_locked(hw, I217_MEMPWR, &phy_reg);
+                       if (ret_val)
+                               goto _release;
+                       phy_reg |= I217_MEMPWR_MASK;
+                       e1e_wphy_locked(hw, I217_MEMPWR, phy_reg);
+
+                       /* Disable Proxy */
+                       e1e_wphy_locked(hw, I217_PROXY_CTRL, 0);
+               }
+               /* Enable reset on MTA */
+               ret_val = e1e_rphy_locked(hw, I217_CGFREG, &phy_reg);
+               if (ret_val)
+                       goto _release;
+               phy_reg &= ~I217_CGFREG_MASK;
+               e1e_wphy_locked(hw, I217_CGFREG, phy_reg);
+       _release:
+               if (ret_val)
+                       e_dbg("Error %d in resume workarounds\n", ret_val);
+               hw->phy.ops.release(hw);
+       }
+
                /* Test access to the PHY registers by reading the ID regs */
                ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_id1);
                if (ret_val)
@@ -3996,6 +4265,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_i217) || 
            (hw->phy.type == e1000_phy_82577)) {
                ret_val = hw->phy.ops.acquire(hw);
                if (ret_val)
@@ -4155,3 +4425,22 @@ const struct e1000_info e1000_pch2_info = {
        .phy_ops                = &ich8_phy_ops,
        .nvm_ops                = &ich8_nvm_ops,
 };
+
+const struct e1000_info e1000_pch_lpt_info = {
+       .mac                    = e1000_pch_lpt,
+       .flags                  = FLAG_IS_ICH
+                                 | FLAG_HAS_WOL
+                                 | FLAG_HAS_CTRLEXT_ON_LOAD
+                                 | FLAG_HAS_AMT
+                                 | FLAG_HAS_FLASH
+                                 | FLAG_HAS_JUMBO_FRAMES
+                                 | FLAG_APME_IN_WUC,
+       .flags2                 = FLAG2_HAS_PHY_STATS
+                                 | FLAG2_HAS_EEE,
+       .pba                    = 26,
+       .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,
+};
diff --git a/kernel/drivers/net/drivers/e1000e/netdev.c 
b/kernel/drivers/net/drivers/e1000e/netdev.c
index 65534c3..775ee08 100644
--- a/kernel/drivers/net/drivers/e1000e/netdev.c
+++ b/kernel/drivers/net/drivers/e1000e/netdev.c
@@ -77,6 +77,7 @@ static const struct e1000_info *e1000_info_tbl[] = {
        [board_ich10lan]        = &e1000_ich10_info,
        [board_pchlan]          = &e1000_pch_info,
        [board_pch2lan]         = &e1000_pch2_info,
+       [board_pch_lpt]         = &e1000_pch_lpt_info,
 };
 
 struct e1000_reg_info {
@@ -1970,8 +1971,8 @@ static void e1000_setup_rctl(struct e1000_adapter 
*adapter)
        struct e1000_hw *hw = &adapter->hw;
        u32 rctl, rfctl;
 
-       /* Workaround Si errata on 82579 - configure jumbo frame flow */
-       if (hw->mac.type == e1000_pch2lan) {
+       /* Workaround Si errata on PCHx - configure jumbo frame flow */
+       if (hw->mac.type >= e1000_pch2lan) {
                s32 ret_val;
 
                if (adapter->netdev->mtu > ETH_DATA_LEN)
@@ -2366,6 +2367,7 @@ void e1000e_reset(struct e1000_adapter *adapter)
                fc->refresh_time = 0x1000;
                break;
        case e1000_pch2lan:
+       case e1000_pch_lpt:
                fc->high_water = 0x05C20;
                fc->low_water = 0x05048;
                fc->pause_time = 0x0650;
@@ -4339,6 +4341,11 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_LM), board_pch2lan },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH2_LV_V), board_pch2lan },
 
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPT_I217_LM), board_pch_lpt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPT_I217_V), board_pch_lpt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPTLP_I218_LM), board_pch_lpt },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LPTLP_I218_V), board_pch_lpt },
+
        { }     /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
diff --git a/kernel/drivers/net/drivers/e1000e/phy.c 
b/kernel/drivers/net/drivers/e1000e/phy.c
index 8666476..21f9182 100644
--- a/kernel/drivers/net/drivers/e1000e/phy.c
+++ b/kernel/drivers/net/drivers/e1000e/phy.c
@@ -2352,6 +2352,9 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 
phy_id)
        case I82579_E_PHY_ID:
                phy_type = e1000_phy_82579;
                break;
+       case I217_E_PHY_ID:
+               phy_type = e1000_phy_i217;
+               break;
        default:
                phy_type = e1000_phy_unknown;
                break;


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://www.xenomai.org/mailman/listinfo/xenomai-git

Reply via email to