Add "EEE: Enabled/Disabled" to dmesg for supported X710 Base-T/KR/KX cards.
According to the IEEE standard report the EEE ability and and the
EEE Link Partner ability. Use the kernel's 'ethtool_keee' structure
and report EEE link modes.

Example:
dmesg | grep 'NIC Link is'
ethtool --show-eee <device>

Before:
        NIC Link is Up, 10 Gbps Full Duplex, Flow Control: None

        Supported EEE link modes:  Not reported
        Advertised EEE link modes:  Not reported
        Link partner advertised EEE link modes:  Not reported

After:
        NIC Link is Up, 10 Gbps Full Duplex, Flow Control: None, EEE: Enabled

        Supported EEE link modes:  100baseT/Full
                                   1000baseT/Full
                                   10000baseT/Full
        Advertised EEE link modes:  100baseT/Full
                                    1000baseT/Full
                                    10000baseT/Full
        Link partner advertised EEE link modes:  100baseT/Full
                                                 1000baseT/Full
                                                 10000baseT/Full

Reviewed-by: Arkadiusz Kubalewski <[email protected]>
Signed-off-by: Aleksandr Loktionov <[email protected]>
---
v2->v3 removed double space from code
v1->v2 removed some not mandatory changes, some style improvements
---
 drivers/net/ethernet/intel/i40e/i40e.h        |  1 +
 .../net/ethernet/intel/i40e/i40e_ethtool.c    | 36 ++++++++++++++++---
 drivers/net/ethernet/intel/i40e/i40e_main.c   | 23 ++++++++++--
 3 files changed, 53 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e.h 
b/drivers/net/ethernet/intel/i40e/i40e.h
index d546567..0f25a48 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -7,6 +7,7 @@
 #include <linux/pci.h>
 #include <linux/ptp_clock_kernel.h>
 #include <linux/types.h>
+#include <linux/linkmode.h>
 #include <linux/avf/virtchnl.h>
 #include <linux/net/intel/i40e_client.h>
 #include <net/devlink.h>
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c 
b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index 1d0d2e5..47c5d05 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -5641,50 +5641,78 @@ static int i40e_get_module_eeprom(struct net_device 
*netdev,
        return 0;
 }
 
+static void i40e_eee_capability_to_kedata_supported(__le16 eee_capability_,
+                                                   unsigned long *supported)
+{
+       const int eee_capability = le16_to_cpu(eee_capability_);
+       static const int lut[] = {
+               ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+               ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+               ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+               ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+               ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+               ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
+               ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
+       };
+
+       linkmode_zero(supported);
+       for (unsigned int i = ARRAY_SIZE(lut); i--; )
+               if (eee_capability & BIT(i + 1))
+                       linkmode_set_bit(lut[i], supported);
+}
+
 static int i40e_get_eee(struct net_device *netdev, struct ethtool_keee *edata)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_aq_get_phy_abilities_resp phy_cfg;
        struct i40e_vsi *vsi = np->vsi;
        struct i40e_pf *pf = vsi->back;
        struct i40e_hw *hw = &pf->hw;
-       int status = 0;
+       int status;
 
        /* Get initial PHY capabilities */
        status = i40e_aq_get_phy_capabilities(hw, false, true, &phy_cfg, NULL);
        if (status)
                return -EAGAIN;
 
        /* Check whether NIC configuration is compatible with Energy Efficient
         * Ethernet (EEE) mode.
         */
        if (phy_cfg.eee_capability == 0)
                return -EOPNOTSUPP;
 
+       i40e_eee_capability_to_kedata_supported(phy_cfg.eee_capability,
+                                               edata->supported);
+       linkmode_copy(edata->lp_advertised, edata->supported);
+
        /* Get current configuration */
        status = i40e_aq_get_phy_capabilities(hw, false, false, &phy_cfg, NULL);
        if (status)
                return -EAGAIN;
 
+       linkmode_zero(edata->advertised);
+       if (phy_cfg.eee_capability)
+               linkmode_copy(edata->advertised, edata->supported);
        edata->eee_enabled = !!phy_cfg.eee_capability;
        edata->tx_lpi_enabled = pf->stats.tx_lpi_status;
 
        edata->eee_active = pf->stats.tx_lpi_status && pf->stats.rx_lpi_status;
 
        return 0;
 }
 
 static int i40e_is_eee_param_supported(struct net_device *netdev,
                                       struct ethtool_keee *edata)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
        struct i40e_pf *pf = vsi->back;
        struct i40e_ethtool_not_used {
-               u32 value;
+               bool value;
                const char *name;
        } param[] = {
-               {edata->tx_lpi_timer, "tx-timer"},
+               {!!(edata->advertised[0] & ~edata->supported[0]), "advertise"},
+               {!!edata->tx_lpi_timer, "tx-timer"},
                {edata->tx_lpi_enabled != pf->stats.tx_lpi_status, "tx-lpi"}
        };
        int i;
@@ -5710,7 +5738,7 @@ static int i40e_set_eee(struct net_device *netdev, struct 
ethtool_keee *edata)
        struct i40e_pf *pf = vsi->back;
        struct i40e_hw *hw = &pf->hw;
        __le16 eee_capability;
-       int status = 0;
+       int status;
 
        /* Deny parameters we don't support */
        if (i40e_is_eee_param_supported(netdev, edata))
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c 
b/drivers/net/ethernet/intel/i40e/i40e_main.c
index cbcfada..5c102f8 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -7263,6 +7263,25 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf)
        return err;
 }
 #endif /* CONFIG_I40E_DCB */
+static void i40e_print_link_message_eee(struct i40e_vsi *vsi,
+                           const char *speed, const char *fc)
+{
+       struct ethtool_keee kedata;
+
+       memzero_explicit(&kedata, sizeof(kedata));
+       if (vsi->netdev->ethtool_ops->get_eee)
+               vsi->netdev->ethtool_ops->get_eee(vsi->netdev, &kedata);
+
+       if (!linkmode_empty(kedata.supported))
+               netdev_info(vsi->netdev,
+                           "NIC Link is Up, %sbps Full Duplex, Flow Control: 
%s, EEE: %s\n",
+                           speed, fc,
+                           kedata.eee_enabled ? "Enabled" : "Disabled");
+       else
+               netdev_info(vsi->netdev,
+                           "NIC Link is Up, %sbps Full Duplex, Flow Control: 
%s\n",
+                           speed, fc);
+}
 
 /**
  * i40e_print_link_message - print link up or down
@@ -7395,9 +7414,7 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool 
isup)
                            "NIC Link is Up, %sbps Full Duplex, Requested FEC: 
%s, Negotiated FEC: %s, Autoneg: %s, Flow Control: %s\n",
                            speed, req_fec, fec, an, fc);
        } else {
-               netdev_info(vsi->netdev,
-                           "NIC Link is Up, %sbps Full Duplex, Flow Control: 
%s\n",
-                           speed, fc);
+               i40e_print_link_message_eee(vsi, speed, fc);
        }
 
 }
-- 
2.25.1

Reply via email to