Merge remote-tracking branch 'torvalds/master' into perf/core
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_ethtool.c
index 53802e1..d6513ae 100644 (file)
@@ -34,6 +34,7 @@
 #include "en/port.h"
 #include "en/params.h"
 #include "en/xsk/pool.h"
+#include "en/ptp.h"
 #include "lib/clock.h"
 
 void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv,
@@ -325,7 +326,7 @@ static void mlx5e_get_ringparam(struct net_device *dev,
 int mlx5e_ethtool_set_ringparam(struct mlx5e_priv *priv,
                                struct ethtool_ringparam *param)
 {
-       struct mlx5e_channels new_channels = {};
+       struct mlx5e_params new_params;
        u8 log_rq_size;
        u8 log_sq_size;
        int err = 0;
@@ -364,20 +365,15 @@ int mlx5e_ethtool_set_ringparam(struct mlx5e_priv *priv,
 
        mutex_lock(&priv->state_lock);
 
-       new_channels.params = priv->channels.params;
-       new_channels.params.log_rq_mtu_frames = log_rq_size;
-       new_channels.params.log_sq_size = log_sq_size;
+       new_params = priv->channels.params;
+       new_params.log_rq_mtu_frames = log_rq_size;
+       new_params.log_sq_size = log_sq_size;
 
-       err = mlx5e_validate_params(priv, &new_channels.params);
+       err = mlx5e_validate_params(priv->mdev, &new_params);
        if (err)
                goto unlock;
 
-       if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
-               priv->channels.params = new_channels.params;
-               goto unlock;
-       }
-
-       err = mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL);
+       err = mlx5e_safe_switch_params(priv, &new_params, NULL, NULL, true);
 
 unlock:
        mutex_unlock(&priv->state_lock);
@@ -422,8 +418,9 @@ int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv,
 {
        struct mlx5e_params *cur_params = &priv->channels.params;
        unsigned int count = ch->combined_count;
-       struct mlx5e_channels new_channels = {};
+       struct mlx5e_params new_params;
        bool arfs_enabled;
+       bool opened;
        int err = 0;
 
        if (!count) {
@@ -458,28 +455,18 @@ int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv,
                goto out;
        }
 
-       new_channels.params = *cur_params;
-       new_channels.params.num_channels = count;
-
-       if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
-               struct mlx5e_params old_params;
+       new_params = *cur_params;
+       new_params.num_channels = count;
 
-               old_params = *cur_params;
-               *cur_params = new_channels.params;
-               err = mlx5e_num_channels_changed(priv);
-               if (err)
-                       *cur_params = old_params;
-
-               goto out;
-       }
+       opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
 
-       arfs_enabled = priv->netdev->features & NETIF_F_NTUPLE;
+       arfs_enabled = opened && (priv->netdev->features & NETIF_F_NTUPLE);
        if (arfs_enabled)
                mlx5e_arfs_disable(priv);
 
        /* Switch to new channels, set new parameters and close old ones */
-       err = mlx5e_safe_switch_channels(priv, &new_channels,
-                                        mlx5e_num_channels_changed_ctx, NULL);
+       err = mlx5e_safe_switch_params(priv, &new_params,
+                                      mlx5e_num_channels_changed_ctx, NULL, true);
 
        if (arfs_enabled) {
                int err2 = mlx5e_arfs_enable(priv);
@@ -574,8 +561,9 @@ int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
 {
        struct dim_cq_moder *rx_moder, *tx_moder;
        struct mlx5_core_dev *mdev = priv->mdev;
-       struct mlx5e_channels new_channels = {};
+       struct mlx5e_params new_params;
        bool reset_rx, reset_tx;
+       bool reset = true;
        int err = 0;
 
        if (!MLX5_CAP_GEN(mdev, cq_moderation))
@@ -596,51 +584,47 @@ int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
        }
 
        mutex_lock(&priv->state_lock);
-       new_channels.params = priv->channels.params;
+       new_params = priv->channels.params;
 
-       rx_moder          = &new_channels.params.rx_cq_moderation;
+       rx_moder          = &new_params.rx_cq_moderation;
        rx_moder->usec    = coal->rx_coalesce_usecs;
        rx_moder->pkts    = coal->rx_max_coalesced_frames;
-       new_channels.params.rx_dim_enabled = !!coal->use_adaptive_rx_coalesce;
+       new_params.rx_dim_enabled = !!coal->use_adaptive_rx_coalesce;
 
-       tx_moder          = &new_channels.params.tx_cq_moderation;
+       tx_moder          = &new_params.tx_cq_moderation;
        tx_moder->usec    = coal->tx_coalesce_usecs;
        tx_moder->pkts    = coal->tx_max_coalesced_frames;
-       new_channels.params.tx_dim_enabled = !!coal->use_adaptive_tx_coalesce;
+       new_params.tx_dim_enabled = !!coal->use_adaptive_tx_coalesce;
 
        reset_rx = !!coal->use_adaptive_rx_coalesce != priv->channels.params.rx_dim_enabled;
        reset_tx = !!coal->use_adaptive_tx_coalesce != priv->channels.params.tx_dim_enabled;
 
        if (reset_rx) {
-               u8 mode = MLX5E_GET_PFLAG(&new_channels.params,
+               u8 mode = MLX5E_GET_PFLAG(&new_params,
                                          MLX5E_PFLAG_RX_CQE_BASED_MODER);
 
-               mlx5e_reset_rx_moderation(&new_channels.params, mode);
+               mlx5e_reset_rx_moderation(&new_params, mode);
        }
        if (reset_tx) {
-               u8 mode = MLX5E_GET_PFLAG(&new_channels.params,
+               u8 mode = MLX5E_GET_PFLAG(&new_params,
                                          MLX5E_PFLAG_TX_CQE_BASED_MODER);
 
-               mlx5e_reset_tx_moderation(&new_channels.params, mode);
+               mlx5e_reset_tx_moderation(&new_params, mode);
        }
 
-       if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
-               priv->channels.params = new_channels.params;
-               goto out;
-       }
-
-       if (!reset_rx && !reset_tx) {
+       /* If DIM state hasn't changed, it's possible to modify interrupt
+        * moderation parameters on the fly, even if the channels are open.
+        */
+       if (!reset_rx && !reset_tx && test_bit(MLX5E_STATE_OPENED, &priv->state)) {
                if (!coal->use_adaptive_rx_coalesce)
                        mlx5e_set_priv_channels_rx_coalesce(priv, coal);
                if (!coal->use_adaptive_tx_coalesce)
                        mlx5e_set_priv_channels_tx_coalesce(priv, coal);
-               priv->channels.params = new_channels.params;
-               goto out;
+               reset = false;
        }
 
-       err = mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL);
+       err = mlx5e_safe_switch_params(priv, &new_params, NULL, NULL, reset);
 
-out:
        mutex_unlock(&priv->state_lock);
        return err;
 }
@@ -1601,6 +1585,14 @@ static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        return mlx5_set_port_wol(mdev, mlx5_wol_mode);
 }
 
+static void mlx5e_get_fec_stats(struct net_device *netdev,
+                               struct ethtool_fec_stats *fec_stats)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+
+       mlx5e_stats_fec_get(priv, fec_stats);
+}
+
 static int mlx5e_get_fecparam(struct net_device *netdev,
                              struct ethtool_fecparam *fecparam)
 {
@@ -1632,12 +1624,13 @@ static int mlx5e_set_fecparam(struct net_device *netdev,
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5_core_dev *mdev = priv->mdev;
+       unsigned long fec_bitmap;
        u16 fec_policy = 0;
        int mode;
        int err;
 
-       if (bitmap_weight((unsigned long *)&fecparam->fec,
-                         ETHTOOL_FEC_LLRS_BIT + 1) > 1)
+       bitmap_from_arr32(&fec_bitmap, &fecparam->fec, sizeof(fecparam->fec) * BITS_PER_BYTE);
+       if (bitmap_weight(&fec_bitmap, ETHTOOL_FEC_LLRS_BIT + 1) > 1)
                return -EOPNOTSUPP;
 
        for (mode = 0; mode < ARRAY_SIZE(pplm_fec_2_ethtool); mode++) {
@@ -1769,6 +1762,49 @@ static int mlx5e_get_module_eeprom(struct net_device *netdev,
        return 0;
 }
 
+static int mlx5e_get_module_eeprom_by_page(struct net_device *netdev,
+                                          const struct ethtool_module_eeprom *page_data,
+                                          struct netlink_ext_ack *extack)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       struct mlx5_module_eeprom_query_params query;
+       struct mlx5_core_dev *mdev = priv->mdev;
+       u8 *data = page_data->data;
+       int size_read;
+       int i = 0;
+
+       if (!page_data->length)
+               return -EINVAL;
+
+       memset(data, 0, page_data->length);
+
+       query.offset = page_data->offset;
+       query.i2c_address = page_data->i2c_address;
+       query.bank = page_data->bank;
+       query.page = page_data->page;
+       while (i < page_data->length) {
+               query.size = page_data->length - i;
+               size_read = mlx5_query_module_eeprom_by_page(mdev, &query, data + i);
+
+               /* Done reading, return how many bytes was read */
+               if (!size_read)
+                       return i;
+
+               if (size_read == -EINVAL)
+                       return -EINVAL;
+               if (size_read < 0) {
+                       netdev_err(priv->netdev, "%s: mlx5_query_module_eeprom_by_page failed:0x%x\n",
+                                  __func__, size_read);
+                       return i;
+               }
+
+               i += size_read;
+               query.offset += size_read;
+       }
+
+       return i;
+}
+
 int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv,
                               struct ethtool_flash *flash)
 {
@@ -1808,7 +1844,7 @@ static int set_pflag_cqe_based_moder(struct net_device *netdev, bool enable,
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5_core_dev *mdev = priv->mdev;
-       struct mlx5e_channels new_channels = {};
+       struct mlx5e_params new_params;
        bool mode_changed;
        u8 cq_period_mode, current_cq_period_mode;
 
@@ -1827,18 +1863,13 @@ static int set_pflag_cqe_based_moder(struct net_device *netdev, bool enable,
        if (!mode_changed)
                return 0;
 
-       new_channels.params = priv->channels.params;
+       new_params = priv->channels.params;
        if (is_rx_cq)
-               mlx5e_set_rx_cq_mode_params(&new_channels.params, cq_period_mode);
+               mlx5e_set_rx_cq_mode_params(&new_params, cq_period_mode);
        else
-               mlx5e_set_tx_cq_mode_params(&new_channels.params, cq_period_mode);
-
-       if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
-               priv->channels.params = new_channels.params;
-               return 0;
-       }
+               mlx5e_set_tx_cq_mode_params(&new_params, cq_period_mode);
 
-       return mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL);
+       return mlx5e_safe_switch_params(priv, &new_params, NULL, NULL, true);
 }
 
 static int set_pflag_tx_cqe_based_moder(struct net_device *netdev, bool enable)
@@ -1854,7 +1885,7 @@ static int set_pflag_rx_cqe_based_moder(struct net_device *netdev, bool enable)
 int mlx5e_modify_rx_cqe_compression_locked(struct mlx5e_priv *priv, bool new_val)
 {
        bool curr_val = MLX5E_GET_PFLAG(&priv->channels.params, MLX5E_PFLAG_RX_CQE_COMPRESS);
-       struct mlx5e_channels new_channels = {};
+       struct mlx5e_params new_params;
        int err = 0;
 
        if (!MLX5_CAP_GEN(priv->mdev, cqe_compression))
@@ -1863,15 +1894,23 @@ int mlx5e_modify_rx_cqe_compression_locked(struct mlx5e_priv *priv, bool new_val
        if (curr_val == new_val)
                return 0;
 
-       new_channels.params = priv->channels.params;
-       MLX5E_SET_PFLAG(&new_channels.params, MLX5E_PFLAG_RX_CQE_COMPRESS, new_val);
-
-       if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
-               priv->channels.params = new_channels.params;
-               return 0;
+       if (new_val && !priv->profile->rx_ptp_support &&
+           priv->tstamp.rx_filter != HWTSTAMP_FILTER_NONE) {
+               netdev_err(priv->netdev,
+                          "Profile doesn't support enabling of CQE compression while hardware time-stamping is enabled.\n");
+               return -EINVAL;
        }
 
-       err = mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL);
+       new_params = priv->channels.params;
+       MLX5E_SET_PFLAG(&new_params, MLX5E_PFLAG_RX_CQE_COMPRESS, new_val);
+       if (priv->tstamp.rx_filter != HWTSTAMP_FILTER_NONE)
+               new_params.ptp_rx = new_val;
+
+       if (new_params.ptp_rx == priv->channels.params.ptp_rx)
+               err = mlx5e_safe_switch_params(priv, &new_params, NULL, NULL, true);
+       else
+               err = mlx5e_safe_switch_params(priv, &new_params, mlx5e_ptp_rx_manage_fs_ctx,
+                                              &new_params.ptp_rx, true);
        if (err)
                return err;
 
@@ -1892,11 +1931,6 @@ static int set_pflag_rx_cqe_compress(struct net_device *netdev,
        if (!MLX5_CAP_GEN(mdev, cqe_compression))
                return -EOPNOTSUPP;
 
-       if (enable && priv->tstamp.rx_filter != HWTSTAMP_FILTER_NONE) {
-               netdev_err(netdev, "Can't enable cqe compression while timestamping is enabled.\n");
-               return -EINVAL;
-       }
-
        err = mlx5e_modify_rx_cqe_compression_locked(priv, enable);
        if (err)
                return err;
@@ -1910,7 +1944,7 @@ static int set_pflag_rx_striding_rq(struct net_device *netdev, bool enable)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5_core_dev *mdev = priv->mdev;
-       struct mlx5e_channels new_channels = {};
+       struct mlx5e_params new_params;
 
        if (enable) {
                if (!mlx5e_check_fragmented_striding_rq_cap(mdev))
@@ -1922,17 +1956,12 @@ static int set_pflag_rx_striding_rq(struct net_device *netdev, bool enable)
                return -EINVAL;
        }
 
-       new_channels.params = priv->channels.params;
-
-       MLX5E_SET_PFLAG(&new_channels.params, MLX5E_PFLAG_RX_STRIDING_RQ, enable);
-       mlx5e_set_rq_type(mdev, &new_channels.params);
+       new_params = priv->channels.params;
 
-       if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
-               priv->channels.params = new_channels.params;
-               return 0;
-       }
+       MLX5E_SET_PFLAG(&new_params, MLX5E_PFLAG_RX_STRIDING_RQ, enable);
+       mlx5e_set_rq_type(mdev, &new_params);
 
-       return mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL);
+       return mlx5e_safe_switch_params(priv, &new_params, NULL, NULL, true);
 }
 
 static int set_pflag_rx_no_csum_complete(struct net_device *netdev, bool enable)
@@ -1961,23 +1990,16 @@ static int set_pflag_tx_mpwqe_common(struct net_device *netdev, u32 flag, bool e
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5_core_dev *mdev = priv->mdev;
-       struct mlx5e_channels new_channels = {};
-       int err;
+       struct mlx5e_params new_params;
 
        if (enable && !MLX5_CAP_ETH(mdev, enhanced_multi_pkt_send_wqe))
                return -EOPNOTSUPP;
 
-       new_channels.params = priv->channels.params;
-
-       MLX5E_SET_PFLAG(&new_channels.params, flag, enable);
+       new_params = priv->channels.params;
 
-       if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
-               priv->channels.params = new_channels.params;
-               return 0;
-       }
+       MLX5E_SET_PFLAG(&new_params, flag, enable);
 
-       err = mlx5e_safe_switch_channels(priv, &new_channels, NULL, NULL);
-       return err;
+       return mlx5e_safe_switch_params(priv, &new_params, NULL, NULL, true);
 }
 
 static int set_pflag_xdp_tx_mpwqe(struct net_device *netdev, bool enable)
@@ -1994,7 +2016,7 @@ static int set_pflag_tx_port_ts(struct net_device *netdev, bool enable)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5_core_dev *mdev = priv->mdev;
-       struct mlx5e_channels new_channels = {};
+       struct mlx5e_params new_params;
        int err;
 
        if (!MLX5_CAP_GEN(mdev, ts_cqe_to_dest_cqn))
@@ -2010,29 +2032,17 @@ static int set_pflag_tx_port_ts(struct net_device *netdev, bool enable)
                return -EINVAL;
        }
 
-       new_channels.params = priv->channels.params;
-       MLX5E_SET_PFLAG(&new_channels.params, MLX5E_PFLAG_TX_PORT_TS, enable);
+       new_params = priv->channels.params;
+       MLX5E_SET_PFLAG(&new_params, MLX5E_PFLAG_TX_PORT_TS, enable);
        /* No need to verify SQ stop room as
         * ptpsq.txqsq.stop_room <= generic_sq->stop_room, and both
         * has the same log_sq_size.
         */
 
-       if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) {
-               struct mlx5e_params old_params;
-
-               old_params = priv->channels.params;
-               priv->channels.params = new_channels.params;
-               err = mlx5e_num_channels_changed(priv);
-               if (err)
-                       priv->channels.params = old_params;
-               goto out;
-       }
-
-       err = mlx5e_safe_switch_channels(priv, &new_channels,
-                                        mlx5e_num_channels_changed_ctx, NULL);
-out:
+       err = mlx5e_safe_switch_params(priv, &new_params,
+                                      mlx5e_num_channels_changed_ctx, NULL, true);
        if (!err)
-               priv->port_ptp_opened = true;
+               priv->tx_ptp_opened = true;
 
        return err;
 }
@@ -2123,12 +2133,216 @@ int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
        return mlx5e_ethtool_set_rxnfc(dev, cmd);
 }
 
+static int query_port_status_opcode(struct mlx5_core_dev *mdev, u32 *status_opcode)
+{
+       struct mlx5_ifc_pddr_troubleshooting_page_bits *pddr_troubleshooting_page;
+       u32 in[MLX5_ST_SZ_DW(pddr_reg)] = {};
+       u32 out[MLX5_ST_SZ_DW(pddr_reg)];
+       int err;
+
+       MLX5_SET(pddr_reg, in, local_port, 1);
+       MLX5_SET(pddr_reg, in, page_select,
+                MLX5_PDDR_REG_PAGE_SELECT_TROUBLESHOOTING_INFO_PAGE);
+
+       pddr_troubleshooting_page = MLX5_ADDR_OF(pddr_reg, in, page_data);
+       MLX5_SET(pddr_troubleshooting_page, pddr_troubleshooting_page,
+                group_opcode, MLX5_PDDR_REG_TRBLSH_GROUP_OPCODE_MONITOR);
+       err = mlx5_core_access_reg(mdev, in, sizeof(in), out,
+                                  sizeof(out), MLX5_REG_PDDR, 0, 0);
+       if (err)
+               return err;
+
+       pddr_troubleshooting_page = MLX5_ADDR_OF(pddr_reg, out, page_data);
+       *status_opcode = MLX5_GET(pddr_troubleshooting_page, pddr_troubleshooting_page,
+                                 status_opcode);
+       return 0;
+}
+
+struct mlx5e_ethtool_link_ext_state_opcode_mapping {
+       u32 status_opcode;
+       enum ethtool_link_ext_state link_ext_state;
+       u8 link_ext_substate;
+};
+
+static const struct mlx5e_ethtool_link_ext_state_opcode_mapping
+mlx5e_link_ext_state_opcode_map[] = {
+       /* States relating to the autonegotiation or issues therein */
+       {2, ETHTOOL_LINK_EXT_STATE_AUTONEG,
+               ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED},
+       {3, ETHTOOL_LINK_EXT_STATE_AUTONEG,
+               ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED},
+       {4, ETHTOOL_LINK_EXT_STATE_AUTONEG,
+               ETHTOOL_LINK_EXT_SUBSTATE_AN_NEXT_PAGE_EXCHANGE_FAILED},
+       {36, ETHTOOL_LINK_EXT_STATE_AUTONEG,
+               ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED_FORCE_MODE},
+       {38, ETHTOOL_LINK_EXT_STATE_AUTONEG,
+               ETHTOOL_LINK_EXT_SUBSTATE_AN_FEC_MISMATCH_DURING_OVERRIDE},
+       {39, ETHTOOL_LINK_EXT_STATE_AUTONEG,
+               ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD},
+
+       /* Failure during link training */
+       {5, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
+               ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_FRAME_LOCK_NOT_ACQUIRED},
+       {6, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
+               ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT},
+       {7, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
+               ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY},
+       {8, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE, 0},
+       {14, ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE,
+               ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT},
+
+       /* Logical mismatch in physical coding sublayer or forward error correction sublayer */
+       {9, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
+               ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK},
+       {10, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
+               ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_AM_LOCK},
+       {11, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
+               ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_GET_ALIGN_STATUS},
+       {12, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
+               ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED},
+       {13, ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH,
+               ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED},
+
+       /* Signal integrity issues */
+       {15, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY, 0},
+       {17, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
+               ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS},
+       {42, ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY,
+               ETHTOOL_LINK_EXT_SUBSTATE_BSI_UNSUPPORTED_RATE},
+
+       /* No cable connected */
+       {1024, ETHTOOL_LINK_EXT_STATE_NO_CABLE, 0},
+
+       /* Failure is related to cable, e.g., unsupported cable */
+       {16, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
+               ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
+       {20, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
+               ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
+       {29, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
+               ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
+       {1025, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
+               ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
+       {1029, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE,
+               ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE},
+       {1031, ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE, 0},
+
+       /* Failure is related to EEPROM, e.g., failure during reading or parsing the data */
+       {1027, ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE, 0},
+
+       /* Failure during calibration algorithm */
+       {23, ETHTOOL_LINK_EXT_STATE_CALIBRATION_FAILURE, 0},
+
+       /* The hardware is not able to provide the power required from cable or module */
+       {1032, ETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED, 0},
+
+       /* The module is overheated */
+       {1030, ETHTOOL_LINK_EXT_STATE_OVERHEAT, 0},
+};
+
+static void
+mlx5e_set_link_ext_state(struct mlx5e_ethtool_link_ext_state_opcode_mapping
+                        link_ext_state_mapping,
+                        struct ethtool_link_ext_state_info *link_ext_state_info)
+{
+       switch (link_ext_state_mapping.link_ext_state) {
+       case ETHTOOL_LINK_EXT_STATE_AUTONEG:
+               link_ext_state_info->autoneg =
+                       link_ext_state_mapping.link_ext_substate;
+               break;
+       case ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE:
+               link_ext_state_info->link_training =
+                       link_ext_state_mapping.link_ext_substate;
+               break;
+       case ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH:
+               link_ext_state_info->link_logical_mismatch =
+                       link_ext_state_mapping.link_ext_substate;
+               break;
+       case ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY:
+               link_ext_state_info->bad_signal_integrity =
+                       link_ext_state_mapping.link_ext_substate;
+               break;
+       case ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE:
+               link_ext_state_info->cable_issue =
+                       link_ext_state_mapping.link_ext_substate;
+               break;
+       default:
+               break;
+       }
+
+       link_ext_state_info->link_ext_state = link_ext_state_mapping.link_ext_state;
+}
+
+static int
+mlx5e_get_link_ext_state(struct net_device *dev,
+                        struct ethtool_link_ext_state_info *link_ext_state_info)
+{
+       struct mlx5e_ethtool_link_ext_state_opcode_mapping link_ext_state_mapping;
+       struct mlx5e_priv *priv = netdev_priv(dev);
+       u32 status_opcode = 0;
+       int i;
+
+       /* Exit without data if the interface state is OK, since no extended data is
+        * available in such case
+        */
+       if (netif_carrier_ok(dev))
+               return -ENODATA;
+
+       if (query_port_status_opcode(priv->mdev, &status_opcode) ||
+           !status_opcode)
+               return -ENODATA;
+
+       for (i = 0; i < ARRAY_SIZE(mlx5e_link_ext_state_opcode_map); i++) {
+               link_ext_state_mapping = mlx5e_link_ext_state_opcode_map[i];
+               if (link_ext_state_mapping.status_opcode == status_opcode) {
+                       mlx5e_set_link_ext_state(link_ext_state_mapping,
+                                                link_ext_state_info);
+                       return 0;
+               }
+       }
+
+       return -ENODATA;
+}
+
+static void mlx5e_get_eth_phy_stats(struct net_device *netdev,
+                                   struct ethtool_eth_phy_stats *phy_stats)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+
+       mlx5e_stats_eth_phy_get(priv, phy_stats);
+}
+
+static void mlx5e_get_eth_mac_stats(struct net_device *netdev,
+                                   struct ethtool_eth_mac_stats *mac_stats)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+
+       mlx5e_stats_eth_mac_get(priv, mac_stats);
+}
+
+static void mlx5e_get_eth_ctrl_stats(struct net_device *netdev,
+                                    struct ethtool_eth_ctrl_stats *ctrl_stats)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+
+       mlx5e_stats_eth_ctrl_get(priv, ctrl_stats);
+}
+
+static void mlx5e_get_rmon_stats(struct net_device *netdev,
+                                struct ethtool_rmon_stats *rmon_stats,
+                                const struct ethtool_rmon_hist_range **ranges)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+
+       mlx5e_stats_rmon_get(priv, rmon_stats, ranges);
+}
+
 const struct ethtool_ops mlx5e_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
                                     ETHTOOL_COALESCE_MAX_FRAMES |
                                     ETHTOOL_COALESCE_USE_ADAPTIVE,
        .get_drvinfo       = mlx5e_get_drvinfo,
        .get_link          = ethtool_op_get_link,
+       .get_link_ext_state  = mlx5e_get_link_ext_state,
        .get_strings       = mlx5e_get_strings,
        .get_sset_count    = mlx5e_get_sset_count,
        .get_ethtool_stats = mlx5e_get_ethtool_stats,
@@ -2157,12 +2371,18 @@ const struct ethtool_ops mlx5e_ethtool_ops = {
        .set_wol           = mlx5e_set_wol,
        .get_module_info   = mlx5e_get_module_info,
        .get_module_eeprom = mlx5e_get_module_eeprom,
+       .get_module_eeprom_by_page = mlx5e_get_module_eeprom_by_page,
        .flash_device      = mlx5e_flash_device,
        .get_priv_flags    = mlx5e_get_priv_flags,
        .set_priv_flags    = mlx5e_set_priv_flags,
        .self_test         = mlx5e_self_test,
        .get_msglevel      = mlx5e_get_msglevel,
        .set_msglevel      = mlx5e_set_msglevel,
+       .get_fec_stats     = mlx5e_get_fec_stats,
        .get_fecparam      = mlx5e_get_fecparam,
        .set_fecparam      = mlx5e_set_fecparam,
+       .get_eth_phy_stats = mlx5e_get_eth_phy_stats,
+       .get_eth_mac_stats = mlx5e_get_eth_mac_stats,
+       .get_eth_ctrl_stats = mlx5e_get_eth_ctrl_stats,
+       .get_rmon_stats    = mlx5e_get_rmon_stats,
 };