Commit 24a372cd authored by Akeem G. Abodunrin's avatar Akeem G. Abodunrin Committed by David S. Miller

igb: Ethtool support to enable and disable EEE

This patch allows users to enable and disable EEE using Ethtool.
It also allows users to get EEE settings, as supported by the device.
Signed-off-by: default avatarAkeem G Abodunrin <akeem.g.abodunrin@intel.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 80d0759e
......@@ -874,6 +874,7 @@
#define E1000_EEER_FRC_AN 0x10000000 /* Enable EEE in loopback */
#define E1000_EEER_LPI_FC 0x00040000 /* EEE Enable on FC */
#define E1000_EEE_SU_LPI_CLK_STP 0X00800000 /* EEE LPI Clock Stop */
#define E1000_EEER_EEE_NEG 0x20000000 /* EEE capability nego */
/* SerDes Control */
#define E1000_GEN_CTL_READY 0x80000000
......
......@@ -2529,6 +2529,104 @@ static int igb_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
return ret;
}
static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
u32 ipcnfg, eeer;
if ((hw->mac.type < e1000_i350) ||
(hw->phy.media_type != e1000_media_type_copper))
return -EOPNOTSUPP;
edata->supported = (SUPPORTED_1000baseT_Full |
SUPPORTED_100baseT_Full);
ipcnfg = rd32(E1000_IPCNFG);
eeer = rd32(E1000_EEER);
/* EEE status on negotiated link */
if (ipcnfg & E1000_IPCNFG_EEE_1G_AN)
edata->advertised = ADVERTISED_1000baseT_Full;
if (ipcnfg & E1000_IPCNFG_EEE_100M_AN)
edata->advertised |= ADVERTISED_100baseT_Full;
if (eeer & E1000_EEER_EEE_NEG)
edata->eee_active = true;
edata->eee_enabled = !hw->dev_spec._82575.eee_disable;
if (eeer & E1000_EEER_TX_LPI_EN)
edata->tx_lpi_enabled = true;
/* Report correct negotiated EEE status for devices that
* wrongly report EEE at half-duplex
*/
if (adapter->link_duplex == HALF_DUPLEX) {
edata->eee_enabled = false;
edata->eee_active = false;
edata->tx_lpi_enabled = false;
edata->advertised &= ~edata->advertised;
}
return 0;
}
static int igb_set_eee(struct net_device *netdev,
struct ethtool_eee *edata)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
struct ethtool_eee eee_curr;
s32 ret_val;
if ((hw->mac.type < e1000_i350) ||
(hw->phy.media_type != e1000_media_type_copper))
return -EOPNOTSUPP;
ret_val = igb_get_eee(netdev, &eee_curr);
if (ret_val)
return ret_val;
if (eee_curr.eee_enabled) {
if (eee_curr.tx_lpi_enabled != edata->tx_lpi_enabled) {
dev_err(&adapter->pdev->dev,
"Setting EEE tx-lpi is not supported\n");
return -EINVAL;
}
/* Tx LPI timer is not implemented currently */
if (edata->tx_lpi_timer) {
dev_err(&adapter->pdev->dev,
"Setting EEE Tx LPI timer is not supported\n");
return -EINVAL;
}
if (eee_curr.advertised != edata->advertised) {
dev_err(&adapter->pdev->dev,
"Setting EEE Advertisement is not supported\n");
return -EINVAL;
}
} else if (!edata->eee_enabled) {
dev_err(&adapter->pdev->dev,
"Setting EEE options are not supported with EEE disabled\n");
return -EINVAL;
}
if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) {
hw->dev_spec._82575.eee_disable = !edata->eee_enabled;
igb_set_eee_i350(hw);
/* reset link */
if (!netif_running(netdev))
igb_reset(adapter);
}
return 0;
}
static int igb_ethtool_begin(struct net_device *netdev)
{
struct igb_adapter *adapter = netdev_priv(netdev);
......@@ -2571,6 +2669,8 @@ static const struct ethtool_ops igb_ethtool_ops = {
.get_ts_info = igb_get_ts_info,
.get_rxnfc = igb_get_rxnfc,
.set_rxnfc = igb_set_rxnfc,
.get_eee = igb_get_eee,
.set_eee = igb_set_eee,
.begin = igb_ethtool_begin,
.complete = igb_ethtool_complete,
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment