/* PHY Low Power Idle Control */
 #define I82579_LPI_CTRL                                PHY_REG(772, 20)
+#define I82579_LPI_CTRL_100_ENABLE             0x2000
+#define I82579_LPI_CTRL_1000_ENABLE            0x4000
 #define I82579_LPI_CTRL_ENABLE_MASK            0x6000
 #define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT   0x80
 
 #define I82579_MSE_THRESHOLD    0x084F /* 82579 Mean Square Error Threshold */
 #define I82577_MSE_THRESHOLD    0x0887 /* 82577 Mean Square Error Threshold */
 #define I82579_MSE_LINK_DOWN    0x2411 /* MSE count before dropping link */
+#define I82579_EEE_PCS_STATUS  0x182D  /* IEEE MMD Register 3.1 >> 8 */
+#define I82579_EEE_LP_ABILITY  0x040F  /* IEEE MMD Register 7.61 */
+#define I82579_EEE_100_SUPPORTED       (1 << 1) /* 100BaseTx EEE supported */
+#define I82579_EEE_1000_SUPPORTED      (1 << 2) /* 1000BaseTx EEE supported */
+#define I217_EEE_PCS_STATUS    0x9401  /* IEEE MMD Register 3.1 */
 #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                 BM_PHY_REG(BM_WUC_PAGE, 70)
  *  e1000_set_eee_pchlan - Enable/disable EEE support
  *  @hw: pointer to the HW structure
  *
- *  Enable/disable EEE based on setting in dev_spec structure.  The bits in
- *  the LPI Control register will remain set only if/when link is up.
+ *  Enable/disable EEE based on setting in dev_spec structure, the duplex of
+ *  the link and the EEE capabilities of the link partner.  The LPI Control
+ *  register bits will remain set only if/when link is up.
  **/
 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;
+       s32 ret_val;
+       u16 lpi_ctrl;
 
        if ((hw->phy.type != e1000_phy_82579) &&
            (hw->phy.type != e1000_phy_i217))
                return 0;
 
-       ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg);
+       ret_val = hw->phy.ops.acquire(hw);
        if (ret_val)
                return ret_val;
 
-       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);
+       ret_val = e1e_rphy_locked(hw, I82579_LPI_CTRL, &lpi_ctrl);
        if (ret_val)
-               return ret_val;
+               goto release;
+
+       /* Clear bits that enable EEE in various speeds */
+       lpi_ctrl &= ~I82579_LPI_CTRL_ENABLE_MASK;
+
+       /* Enable EEE if not disabled by user */
+       if (!dev_spec->eee_disable) {
+               u16 lpa, pcs_status, data;
 
-       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 = e1000_read_emi_reg_locked(hw,
-                                                   I217_EEE_LP_ABILITY,
+               switch (hw->phy.type) {
+               case e1000_phy_82579:
+                       lpa = I82579_EEE_LP_ABILITY;
+                       pcs_status = I82579_EEE_PCS_STATUS;
+                       break;
+               case e1000_phy_i217:
+                       lpa = I217_EEE_LP_ABILITY;
+                       pcs_status = I217_EEE_PCS_STATUS;
+                       break;
+               default:
+                       ret_val = -E1000_ERR_PHY;
+                       goto release;
+               }
+               ret_val = e1000_read_emi_reg_locked(hw, lpa,
                                                    &dev_spec->eee_lp_ability);
                if (ret_val)
                        goto release;
 
-               /* EEE is not supported in 100Half, so ignore partner's EEE
-                * in 100 ability if full-duplex is not advertised.
+               /* Enable EEE only for speeds in which the link partner is
+                * EEE capable.
                 */
-               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);
+               if (dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED)
+                       lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE;
+
+               if (dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) {
+                       e1e_rphy_locked(hw, PHY_LP_ABILITY, &data);
+                       if (data & NWAY_LPAR_100TX_FD_CAPS)
+                               lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE;
+                       else
+                               /* EEE is not supported in 100Half, so ignore
+                                * partner's EEE in 100 ability if full-duplex
+                                * is not advertised.
+                                */
+                               dev_spec->eee_lp_ability &=
+                                   ~I82579_EEE_100_SUPPORTED;
+               }
+
+               /* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */
+               ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data);
+               if (ret_val)
+                       goto release;
        }
 
-       return 0;
+       ret_val = e1e_wphy_locked(hw, I82579_LPI_CTRL, lpi_ctrl);
+release:
+       hw->phy.ops.release(hw);
+
+       return ret_val;
 }
 
 /**
                         * EEE and 100Full is advertised on both ends of the
                         * link.
                         */
-                       if ((eee_advert & I217_EEE_100_SUPPORTED) &&
+                       if ((eee_advert & I82579_EEE_100_SUPPORTED) &&
                            (dev_spec->eee_lp_ability &
-                            I217_EEE_100_SUPPORTED) &&
+                            I82579_EEE_100_SUPPORTED) &&
                            (hw->phy.autoneg_advertised & ADVERTISE_100_FULL))
                                phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU |
                                              E1000_PHY_CTRL_NOND0A_LPLU);