summaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/intel/e1000e/ethtool.c
diff options
context:
space:
mode:
authorBruce Allan <bruce.w.allan@intel.com>2013-03-20 08:23:11 +0100
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2013-03-28 08:01:52 +0100
commitd495bcb84d2c3abb5ad5e43cfeea0e305ceffb30 (patch)
tree6edb94fb74a39dee627bbaeb39b3d21df84acc29 /drivers/net/ethernet/intel/e1000e/ethtool.c
parente1000e: long access timeouts when I217/I218 MAC and PHY are out of sync (diff)
downloadlinux-d495bcb84d2c3abb5ad5e43cfeea0e305ceffb30.tar.xz
linux-d495bcb84d2c3abb5ad5e43cfeea0e305ceffb30.zip
e1000e: EEE capability advertisement not set/disabled as required
Devices supported by the driver which support EEE (currently 82579, I217 and I218) are advertising EEE capabilities during auto-negotiation even when EEE has been disabled. In addition to not acting as expected, this also caused the EEE status reported by 'ethtool --show-eee' to be wrong when two of these devices are connected back-to-back and EEE is disabled on one. In addition to fixing this issue, the ability for the user to specify which speeds (100 or 1000 full-duplex) to advertise EEE support has been added. 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>
Diffstat (limited to 'drivers/net/ethernet/intel/e1000e/ethtool.c')
-rw-r--r--drivers/net/ethernet/intel/e1000e/ethtool.c63
1 files changed, 19 insertions, 44 deletions
diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c
index e835e7b95f81..7c8ca658d553 100644
--- a/drivers/net/ethernet/intel/e1000e/ethtool.c
+++ b/drivers/net/ethernet/intel/e1000e/ethtool.c
@@ -35,7 +35,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
-#include <linux/mdio.h>
#include <linux/pm_runtime.h>
#include "e1000.h"
@@ -2076,23 +2075,20 @@ static int e1000e_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- u16 cap_addr, adv_addr, lpa_addr, pcs_stat_addr, phy_data, lpi_ctrl;
- u32 status, ret_val;
+ u16 cap_addr, lpa_addr, pcs_stat_addr, phy_data;
+ u32 ret_val;
- if (!(adapter->flags & FLAG_IS_ICH) ||
- !(adapter->flags2 & FLAG2_HAS_EEE))
+ if (!(adapter->flags2 & FLAG2_HAS_EEE))
return -EOPNOTSUPP;
switch (hw->phy.type) {
case e1000_phy_82579:
cap_addr = I82579_EEE_CAPABILITY;
- adv_addr = I82579_EEE_ADVERTISEMENT;
lpa_addr = I82579_EEE_LP_ABILITY;
pcs_stat_addr = I82579_EEE_PCS_STATUS;
break;
case e1000_phy_i217:
cap_addr = I217_EEE_CAPABILITY;
- adv_addr = I217_EEE_ADVERTISEMENT;
lpa_addr = I217_EEE_LP_ABILITY;
pcs_stat_addr = I217_EEE_PCS_STATUS;
break;
@@ -2111,10 +2107,7 @@ static int e1000e_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
edata->supported = mmd_eee_cap_to_ethtool_sup_t(phy_data);
/* EEE Advertised */
- ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &phy_data);
- if (ret_val)
- goto release;
- edata->advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data);
+ edata->advertised = mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert);
/* EEE Link Partner Advertised */
ret_val = e1000_read_emi_reg_locked(hw, lpa_addr, &phy_data);
@@ -2132,25 +2125,11 @@ release:
if (ret_val)
return -ENODATA;
- e1e_rphy(hw, I82579_LPI_CTRL, &lpi_ctrl);
- status = er32(STATUS);
-
/* Result of the EEE auto negotiation - there is no register that
* has the status of the EEE negotiation so do a best-guess based
- * on whether both Tx and Rx LPI indications have been received or
- * base it on the link speed, the EEE advertised speeds on both ends
- * and the speeds on which EEE is enabled locally.
+ * on whether Tx or Rx LPI indications have been received.
*/
- if (((phy_data & E1000_EEE_TX_LPI_RCVD) &&
- (phy_data & E1000_EEE_RX_LPI_RCVD)) ||
- ((status & E1000_STATUS_SPEED_100) &&
- (edata->advertised & ADVERTISED_100baseT_Full) &&
- (edata->lp_advertised & ADVERTISED_100baseT_Full) &&
- (lpi_ctrl & I82579_LPI_CTRL_100_ENABLE)) ||
- ((status & E1000_STATUS_SPEED_1000) &&
- (edata->advertised & ADVERTISED_1000baseT_Full) &&
- (edata->lp_advertised & ADVERTISED_1000baseT_Full) &&
- (lpi_ctrl & I82579_LPI_CTRL_1000_ENABLE)))
+ if (phy_data & (E1000_EEE_TX_LPI_RCVD | E1000_EEE_RX_LPI_RCVD))
edata->eee_active = true;
edata->eee_enabled = !hw->dev_spec.ich8lan.eee_disable;
@@ -2167,19 +2146,10 @@ static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
struct ethtool_eee eee_curr;
s32 ret_val;
- if (!(adapter->flags & FLAG_IS_ICH) ||
- !(adapter->flags2 & FLAG2_HAS_EEE))
- return -EOPNOTSUPP;
-
ret_val = e1000e_get_eee(netdev, &eee_curr);
if (ret_val)
return ret_val;
- if (eee_curr.advertised != edata->advertised) {
- e_err("Setting EEE advertisement is not supported\n");
- return -EINVAL;
- }
-
if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) {
e_err("Setting EEE tx-lpi is not supported\n");
return -EINVAL;
@@ -2190,16 +2160,21 @@ static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata)
return -EINVAL;
}
- if (hw->dev_spec.ich8lan.eee_disable != !edata->eee_enabled) {
- hw->dev_spec.ich8lan.eee_disable = !edata->eee_enabled;
-
- /* reset the link */
- if (netif_running(netdev))
- e1000e_reinit_locked(adapter);
- else
- e1000e_reset(adapter);
+ if (edata->advertised & ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) {
+ e_err("EEE advertisement supports only 100TX and/or 1000T full-duplex\n");
+ return -EINVAL;
}
+ adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised);
+
+ hw->dev_spec.ich8lan.eee_disable = !edata->eee_enabled;
+
+ /* reset the link */
+ if (netif_running(netdev))
+ e1000e_reinit_locked(adapter);
+ else
+ e1000e_reset(adapter);
+
return 0;
}