e1000e: Feature Enable PHY Ultra Low Power Mode (ULP)
authorDavid Ertman <davidx.m.ertman@intel.com>
Sat, 22 Feb 2014 03:15:17 +0000 (03:15 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Sat, 8 Mar 2014 06:52:07 +0000 (22:52 -0800)
ULP is a power saving feature that reduces the power consumption of the
PHY when a cable is not connected.

ULP is gated on the following conditions:
1) The hardware must support ULP.  Currently this is only I218
   devices from Intel
2) ULP is initiated by the driver, so, no driver results in no ULP.
3) ULP's implementation utilizes Runtime Power Management to toggle its
   execution.  ULP is enabled/disabled based on the state of Runtime PM.
4) ULP is not active when wake-on-unicast, multicast or broadcast is active
   as these features are mutually-exclusive.

Since the PHY is in an unavailable state while ULP is active, any access
of the PHY registers will fail.  This is resolved by utilizing kernel
calls that cause the device to exit Runtime PM (e.g. pm_runtime_get_sync)
and then, after PHY access is complete,  allow the device to resume
Runtime PM (e.g. pm_runtime_put_sync).

Under certain conditions, toggling the LANPHYPC is necessary to disable
ULP mode.  Break out existing code to toggle LANPHYPC to a new function
to avoid code duplication.

Signed-off-by: Dave Ertman <davidx.m.ertman@intel.com>
Cc: 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>
drivers/net/ethernet/intel/e1000e/defines.h
drivers/net/ethernet/intel/e1000e/hw.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/ich8lan.h
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/e1000e/regs.h

index 1b7c2685788147d2ba796bb005871865464e9136..d18e89212575626b880a173f08af119be2bdd20a 100644 (file)
 
 /* Definitions for power management and wakeup registers */
 /* Wake Up Control */
-#define E1000_WUC_APME       0x00000001 /* APM Enable */
-#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
-#define E1000_WUC_PHY_WAKE   0x00000100 /* if PHY supports wakeup */
+#define E1000_WUC_APME         0x00000001      /* APM Enable */
+#define E1000_WUC_PME_EN       0x00000002      /* PME Enable */
+#define E1000_WUC_PME_STATUS   0x00000004      /* PME Status */
+#define E1000_WUC_APMPME       0x00000008      /* Assert PME on APM Wakeup */
+#define E1000_WUC_PHY_WAKE     0x00000100      /* if PHY supports wakeup */
 
 /* Wake Up Filter Control */
 #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
index 016028350150e015b2837b0a6eee2fd5f361e738..6b3de5f39a97862e2f5742b14a24530ba6ecc33f 100644 (file)
@@ -648,12 +648,20 @@ struct e1000_shadow_ram {
 
 #define E1000_ICH8_SHADOW_RAM_WORDS            2048
 
+/* I218 PHY Ultra Low Power (ULP) states */
+enum e1000_ulp_state {
+       e1000_ulp_state_unknown,
+       e1000_ulp_state_off,
+       e1000_ulp_state_on,
+};
+
 struct e1000_dev_spec_ich8lan {
        bool kmrn_lock_loss_workaround_enabled;
        struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
        bool nvm_k1_enabled;
        bool eee_disable;
        u16 eee_lp_ability;
+       enum e1000_ulp_state ulp_state;
 };
 
 struct e1000_hw {
index 723410a60297d8e20d5bbbc0a4902fd3be382336..18984519a18d0f454b92ae6af5747c6cd72a8663 100644 (file)
@@ -143,7 +143,9 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index);
 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);
+static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force);
 static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw);
+static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state);
 
 static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
 {
@@ -239,6 +241,47 @@ out:
        return true;
 }
 
+/**
+ *  e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value
+ *  @hw: pointer to the HW structure
+ *
+ *  Toggling the LANPHYPC pin value fully power-cycles the PHY and is
+ *  used to reset the PHY to a quiescent state when necessary.
+ **/
+static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw)
+{
+       u32 mac_reg;
+
+       /* Set Phy Config Counter to 50msec */
+       mac_reg = er32(FEXTNVM3);
+       mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
+       mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
+       ew32(FEXTNVM3, mac_reg);
+
+       /* Toggle LANPHYPC Value bit */
+       mac_reg = er32(CTRL);
+       mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
+       mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
+       ew32(CTRL, mac_reg);
+       e1e_flush();
+       usleep_range(10, 20);
+       mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
+       ew32(CTRL, mac_reg);
+       e1e_flush();
+
+       if (hw->mac.type < e1000_pch_lpt) {
+               msleep(50);
+       } else {
+               u16 count = 20;
+
+               do {
+                       usleep_range(5000, 10000);
+               } while (!(er32(CTRL_EXT) & E1000_CTRL_EXT_LPCD) && count--);
+
+               msleep(30);
+       }
+}
+
 /**
  *  e1000_init_phy_workarounds_pchlan - PHY initialization workarounds
  *  @hw: pointer to the HW structure
@@ -257,6 +300,12 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
         */
        e1000_gate_hw_phy_config_ich8lan(hw, true);
 
+       /* It is not possible to be certain of the current state of ULP
+        * so forcibly disable it.
+        */
+       hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown;
+       e1000_disable_ulp_lpt_lp(hw, true);
+
        ret_val = hw->phy.ops.acquire(hw);
        if (ret_val) {
                e_dbg("Failed to initialize PHY flow\n");
@@ -302,33 +351,9 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw)
                        break;
                }
 
-               e_dbg("Toggling LANPHYPC\n");
-
-               /* Set Phy Config Counter to 50msec */
-               mac_reg = er32(FEXTNVM3);
-               mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK;
-               mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC;
-               ew32(FEXTNVM3, mac_reg);
-
                /* Toggle LANPHYPC Value bit */
-               mac_reg = er32(CTRL);
-               mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE;
-               mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE;
-               ew32(CTRL, mac_reg);
-               e1e_flush();
-               usleep_range(10, 20);
-               mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE;
-               ew32(CTRL, mac_reg);
-               e1e_flush();
-               if (hw->mac.type < e1000_pch_lpt) {
-                       msleep(50);
-               } else {
-                       u16 count = 20;
-                       do {
-                               usleep_range(5000, 10000);
-                       } while (!(er32(CTRL_EXT) &
-                                  E1000_CTRL_EXT_LPCD) && count--);
-                       usleep_range(30000, 60000);
+               e1000_toggle_lanphypc_pch_lpt(hw);
+               if (hw->mac.type >= e1000_pch_lpt) {
                        if (e1000_phy_is_accessible_pchlan(hw))
                                break;
 
@@ -1005,6 +1030,253 @@ static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link)
        return 0;
 }
 
+/**
+ *  e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP
+ *  @hw: pointer to the HW structure
+ *  @to_sx: boolean indicating a system power state transition to Sx
+ *
+ *  When link is down, configure ULP mode to significantly reduce the power
+ *  to the PHY.  If on a Manageability Engine (ME) enabled system, tell the
+ *  ME firmware to start the ULP configuration.  If not on an ME enabled
+ *  system, configure the ULP mode by software.
+ */
+s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx)
+{
+       u32 mac_reg;
+       s32 ret_val = 0;
+       u16 phy_reg;
+
+       if ((hw->mac.type < e1000_pch_lpt) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) ||
+           (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on))
+               return 0;
+
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+               /* Request ME configure ULP mode in the PHY */
+               mac_reg = er32(H2ME);
+               mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS;
+               ew32(H2ME, mac_reg);
+
+               goto out;
+       }
+
+       if (!to_sx) {
+               int i = 0;
+
+               /* Poll up to 5 seconds for Cable Disconnected indication */
+               while (!(er32(FEXT) & E1000_FEXT_PHY_CABLE_DISCONNECTED)) {
+                       /* Bail if link is re-acquired */
+                       if (er32(STATUS) & E1000_STATUS_LU)
+                               return -E1000_ERR_PHY;
+
+                       if (i++ == 100)
+                               break;
+
+                       msleep(50);
+               }
+               e_dbg("CABLE_DISCONNECTED %s set after %dmsec\n",
+                     (er32(FEXT) &
+                      E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not", i * 50);
+       }
+
+       ret_val = hw->phy.ops.acquire(hw);
+       if (ret_val)
+               goto out;
+
+       /* Force SMBus mode in PHY */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
+       if (ret_val)
+               goto release;
+       phy_reg |= CV_SMB_CTRL_FORCE_SMBUS;
+       e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
+
+       /* Force SMBus mode in MAC */
+       mac_reg = er32(CTRL_EXT);
+       mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
+       ew32(CTRL_EXT, mac_reg);
+
+       /* Set Inband ULP Exit, Reset to SMBus mode and
+        * Disable SMBus Release on PERST# in PHY
+        */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
+       if (ret_val)
+               goto release;
+       phy_reg |= (I218_ULP_CONFIG1_RESET_TO_SMBUS |
+                   I218_ULP_CONFIG1_DISABLE_SMB_PERST);
+       if (to_sx) {
+               if (er32(WUFC) & E1000_WUFC_LNKC)
+                       phy_reg |= I218_ULP_CONFIG1_WOL_HOST;
+
+               phy_reg |= I218_ULP_CONFIG1_STICKY_ULP;
+       } else {
+               phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT;
+       }
+       e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+
+       /* Set Disable SMBus Release on PERST# in MAC */
+       mac_reg = er32(FEXTNVM7);
+       mac_reg |= E1000_FEXTNVM7_DISABLE_SMB_PERST;
+       ew32(FEXTNVM7, mac_reg);
+
+       /* Commit ULP changes in PHY by starting auto ULP configuration */
+       phy_reg |= I218_ULP_CONFIG1_START;
+       e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+release:
+       hw->phy.ops.release(hw);
+out:
+       if (ret_val)
+               e_dbg("Error in ULP enable flow: %d\n", ret_val);
+       else
+               hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_on;
+
+       return ret_val;
+}
+
+/**
+ *  e1000_disable_ulp_lpt_lp - unconfigure Ultra Low Power mode for LynxPoint-LP
+ *  @hw: pointer to the HW structure
+ *  @force: boolean indicating whether or not to force disabling ULP
+ *
+ *  Un-configure ULP mode when link is up, the system is transitioned from
+ *  Sx or the driver is unloaded.  If on a Manageability Engine (ME) enabled
+ *  system, poll for an indication from ME that ULP has been un-configured.
+ *  If not on an ME enabled system, un-configure the ULP mode by software.
+ *
+ *  During nominal operation, this function is called when link is acquired
+ *  to disable ULP mode (force=false); otherwise, for example when unloading
+ *  the driver or during Sx->S0 transitions, this is called with force=true
+ *  to forcibly disable ULP.
+ */
+static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force)
+{
+       s32 ret_val = 0;
+       u32 mac_reg;
+       u16 phy_reg;
+       int i = 0;
+
+       if ((hw->mac.type < e1000_pch_lpt) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) ||
+           (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) ||
+           (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_off))
+               return 0;
+
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) {
+               if (force) {
+                       /* Request ME un-configure ULP mode in the PHY */
+                       mac_reg = er32(H2ME);
+                       mac_reg &= ~E1000_H2ME_ULP;
+                       mac_reg |= E1000_H2ME_ENFORCE_SETTINGS;
+                       ew32(H2ME, mac_reg);
+               }
+
+               /* Poll up to 100msec for ME to clear ULP_CFG_DONE */
+               while (er32(FWSM) & E1000_FWSM_ULP_CFG_DONE) {
+                       if (i++ == 10) {
+                               ret_val = -E1000_ERR_PHY;
+                               goto out;
+                       }
+
+                       usleep_range(10000, 20000);
+               }
+               e_dbg("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10);
+
+               if (force) {
+                       mac_reg = er32(H2ME);
+                       mac_reg &= ~E1000_H2ME_ENFORCE_SETTINGS;
+                       ew32(H2ME, mac_reg);
+               } else {
+                       /* Clear H2ME.ULP after ME ULP configuration */
+                       mac_reg = er32(H2ME);
+                       mac_reg &= ~E1000_H2ME_ULP;
+                       ew32(H2ME, mac_reg);
+               }
+
+               goto out;
+       }
+
+       ret_val = hw->phy.ops.acquire(hw);
+       if (ret_val)
+               goto out;
+
+       if (force)
+               /* Toggle LANPHYPC Value bit */
+               e1000_toggle_lanphypc_pch_lpt(hw);
+
+       /* Unforce SMBus mode in PHY */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg);
+       if (ret_val) {
+               /* The MAC might be in PCIe mode, so temporarily force to
+                * SMBus mode in order to access the PHY.
+                */
+               mac_reg = er32(CTRL_EXT);
+               mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS;
+               ew32(CTRL_EXT, mac_reg);
+
+               msleep(50);
+
+               ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL,
+                                                      &phy_reg);
+               if (ret_val)
+                       goto release;
+       }
+       phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS;
+       e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg);
+
+       /* Unforce SMBus mode in MAC */
+       mac_reg = er32(CTRL_EXT);
+       mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS;
+       ew32(CTRL_EXT, mac_reg);
+
+       /* When ULP mode was previously entered, K1 was disabled by the
+        * hardware.  Re-Enable K1 in the PHY when exiting ULP.
+        */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, HV_PM_CTRL, &phy_reg);
+       if (ret_val)
+               goto release;
+       phy_reg |= HV_PM_CTRL_K1_ENABLE;
+       e1000_write_phy_reg_hv_locked(hw, HV_PM_CTRL, phy_reg);
+
+       /* Clear ULP enabled configuration */
+       ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg);
+       if (ret_val)
+               goto release;
+       phy_reg &= ~(I218_ULP_CONFIG1_IND |
+                    I218_ULP_CONFIG1_STICKY_ULP |
+                    I218_ULP_CONFIG1_RESET_TO_SMBUS |
+                    I218_ULP_CONFIG1_WOL_HOST |
+                    I218_ULP_CONFIG1_INBAND_EXIT |
+                    I218_ULP_CONFIG1_DISABLE_SMB_PERST);
+       e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+
+       /* Commit ULP changes by starting auto ULP configuration */
+       phy_reg |= I218_ULP_CONFIG1_START;
+       e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg);
+
+       /* Clear Disable SMBus Release on PERST# in MAC */
+       mac_reg = er32(FEXTNVM7);
+       mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST;
+       ew32(FEXTNVM7, mac_reg);
+
+release:
+       hw->phy.ops.release(hw);
+       if (force) {
+               e1000_phy_hw_reset(hw);
+               msleep(50);
+       }
+out:
+       if (ret_val)
+               e_dbg("Error in ULP disable flow: %d\n", ret_val);
+       else
+               hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_off;
+
+       return ret_val;
+}
+
 /**
  *  e1000_check_for_copper_link_ich8lan - Check for link (Copper)
  *  @hw: pointer to the HW structure
index 51e0b157a731bcbfd65daa9244345be0d3cc571d..553f05ec0278b8fa0c68b1a457035fad497665f4 100644 (file)
 
 #define E1000_FWSM_WLOCK_MAC_MASK      0x0380
 #define E1000_FWSM_WLOCK_MAC_SHIFT     7
+#define E1000_FWSM_ULP_CFG_DONE                0x00000400      /* Low power cfg done */
 
 /* Shared Receive Address Registers */
 #define E1000_SHRAL_PCH_LPT(_i)                (0x05408 + ((_i) * 8))
 #define E1000_SHRAH_PCH_LPT(_i)                (0x0540C + ((_i) * 8))
 
+#define E1000_H2ME             0x05B50 /* Host to ME */
+#define E1000_H2ME_ULP         0x00000800      /* ULP Indication Bit */
+#define E1000_H2ME_ENFORCE_SETTINGS    0x00001000      /* Enforce Settings */
+
 #define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \
                                 (ID_LED_OFF1_OFF2 <<  8) | \
                                 (ID_LED_OFF1_ON2  <<  4) | \
@@ -75,6 +80,9 @@
 
 #define E1000_ICH8_LAN_INIT_TIMEOUT    1500
 
+/* FEXT register bit definition */
+#define E1000_FEXT_PHY_CABLE_DISCONNECTED      0x00000004
+
 #define E1000_FEXTNVM_SW_CONFIG                1
 #define E1000_FEXTNVM_SW_CONFIG_ICH8M  (1 << 27)       /* different on ICH8M */
 
@@ -88,6 +96,8 @@
 #define E1000_FEXTNVM6_REQ_PLL_CLK     0x00000100
 #define E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION       0x00000200
 
+#define E1000_FEXTNVM7_DISABLE_SMB_PERST       0x00000020
+
 #define PCIE_ICH8_SNOOP_ALL    PCIE_NO_SNOOP_ALL
 
 #define E1000_ICH_RAR_ENTRIES  7
 #define CV_SMB_CTRL            PHY_REG(769, 23)
 #define CV_SMB_CTRL_FORCE_SMBUS        0x0001
 
+/* I218 Ultra Low Power Configuration 1 Register */
+#define I218_ULP_CONFIG1               PHY_REG(779, 16)
+#define I218_ULP_CONFIG1_START         0x0001  /* Start auto ULP config */
+#define I218_ULP_CONFIG1_IND           0x0004  /* Pwr up from ULP indication */
+#define I218_ULP_CONFIG1_STICKY_ULP    0x0010  /* Set sticky ULP mode */
+#define I218_ULP_CONFIG1_INBAND_EXIT   0x0020  /* Inband on ULP exit */
+#define I218_ULP_CONFIG1_WOL_HOST      0x0040  /* WoL Host on ULP exit */
+#define I218_ULP_CONFIG1_RESET_TO_SMBUS        0x0100  /* Reset to SMBus mode */
+#define I218_ULP_CONFIG1_DISABLE_SMB_PERST     0x1000  /* Disable on PERST# */
+
 /* SMBus Address Phy Register */
 #define HV_SMB_ADDR            PHY_REG(768, 26)
 #define HV_SMB_ADDR_MASK       0x007F
 /* PHY Power Management Control */
 #define HV_PM_CTRL             PHY_REG(770, 17)
 #define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100
+#define HV_PM_CTRL_K1_ENABLE           0x4000
 
 #define SW_FLAG_TIMEOUT                1000    /* SW Semaphore flag timeout in ms */
 
@@ -262,4 +283,5 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
 s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data);
 s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data);
 s32 e1000_set_eee_pchlan(struct e1000_hw *hw);
+s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx);
 #endif /* _E1000E_ICH8LAN_H_ */
index 7fd1feaeb40523286df1c7edee3b9bee6af29c4f..5129c4cd14bc600512cc23213410b272f331da1f 100644 (file)
@@ -5856,7 +5856,7 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
 static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
 {
        struct e1000_hw *hw = &adapter->hw;
-       u32 i, mac_reg;
+       u32 i, mac_reg, wuc;
        u16 phy_reg, wuc_enable;
        int retval;
 
@@ -5903,13 +5903,18 @@ static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc)
                phy_reg |= BM_RCTL_RFCE;
        hw->phy.ops.write_reg_page(&adapter->hw, BM_RCTL, phy_reg);
 
+       wuc = E1000_WUC_PME_EN;
+       if (wufc & (E1000_WUFC_MAG | E1000_WUFC_LNKC))
+               wuc |= E1000_WUC_APME;
+
        /* enable PHY wakeup in MAC register */
        ew32(WUFC, wufc);
-       ew32(WUC, E1000_WUC_PHY_WAKE | E1000_WUC_PME_EN);
+       ew32(WUC, (E1000_WUC_PHY_WAKE | E1000_WUC_APMPME |
+                  E1000_WUC_PME_STATUS | wuc));
 
        /* configure and enable PHY wakeup in PHY registers */
        hw->phy.ops.write_reg_page(&adapter->hw, BM_WUFC, wufc);
-       hw->phy.ops.write_reg_page(&adapter->hw, BM_WUC, E1000_WUC_PME_EN);
+       hw->phy.ops.write_reg_page(&adapter->hw, BM_WUC, wuc);
 
        /* activate PHY wakeup */
        wuc_enable |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT;
@@ -6012,8 +6017,19 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
                e1000_power_down_phy(adapter);
        }
 
-       if (adapter->hw.phy.type == e1000_phy_igp_3)
+       if (adapter->hw.phy.type == e1000_phy_igp_3) {
                e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw);
+       } else if (hw->mac.type == e1000_pch_lpt) {
+               if (!(wufc & (E1000_WUFC_EX | E1000_WUFC_MC | E1000_WUFC_BC)))
+                       /* ULP does not support wake from unicast, multicast
+                        * or broadcast.
+                        */
+                       retval = e1000_enable_ulp_lpt_lp(hw, !runtime);
+
+               if (retval)
+                       return retval;
+       }
+
 
        /* Release control of h/w to f/w.  If f/w is AMT enabled, this
         * would have already happened in close and is redundant.
index 5c55ef348fc2b1b6157664a96f586662f887918f..ea235bbe50d3c3d32361f505cd98ddfcec5d9744 100644 (file)
@@ -32,6 +32,7 @@
 #define E1000_SCTL     0x00024 /* SerDes Control - RW */
 #define E1000_FCAL     0x00028 /* Flow Control Address Low - RW */
 #define E1000_FCAH     0x0002C /* Flow Control Address High -RW */
+#define E1000_FEXT     0x0002C /* Future Extended - RW */
 #define E1000_FEXTNVM  0x00028 /* Future Extended NVM - RW */
 #define E1000_FEXTNVM3 0x0003C /* Future Extended NVM 3 - RW */
 #define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */