} data;
 };
 
+/* DNL call command (indirect 0x0682)
+ * Struct is used for both command and response
+ */
+struct ice_aqc_dnl_call_command {
+       u8 ctx; /* Used in command, reserved in response */
+       u8 reserved;
+       __le16 activity_id;
+#define ICE_AQC_ACT_ID_DNL 0x1129
+       __le32 reserved1;
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+struct ice_aqc_dnl_equa_param {
+       __le16 data_in;
+#define ICE_AQC_RX_EQU_SHIFT 8
+#define ICE_AQC_RX_EQU_PRE2 (0x10 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_PRE1 (0x11 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_POST1 (0x12 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_BFLF (0x13 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_BFHF (0x14 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_RX_EQU_DRATE (0x15 << ICE_AQC_RX_EQU_SHIFT)
+#define ICE_AQC_TX_EQU_PRE1 0x0
+#define ICE_AQC_TX_EQU_PRE3 0x3
+#define ICE_AQC_TX_EQU_ATTEN 0x4
+#define ICE_AQC_TX_EQU_POST1 0x8
+#define ICE_AQC_TX_EQU_PRE2 0xC
+       __le16 op_code_serdes_sel;
+#define ICE_AQC_OP_CODE_SHIFT 4
+#define ICE_AQC_OP_CODE_RX_EQU (0x9 << ICE_AQC_OP_CODE_SHIFT)
+#define ICE_AQC_OP_CODE_TX_EQU (0x10 << ICE_AQC_OP_CODE_SHIFT)
+       __le32 reserved[3];
+};
+
+struct ice_aqc_dnl_equa_respon {
+       /* Equalization value can be negative */
+       int val;
+       __le32 reserved[3];
+};
+
+/* DNL call command/response buffer (indirect 0x0682) */
+struct ice_aqc_dnl_call {
+       union {
+               struct ice_aqc_dnl_equa_param txrx_equa_reqs;
+               __le32 stores[4];
+               struct ice_aqc_dnl_equa_respon txrx_equa_resp;
+       } sto;
+};
+
 struct ice_aqc_link_topo_params {
        u8 lport_num;
        u8 lport_num_valid;
                struct ice_aqc_get_link_status get_link_status;
                struct ice_aqc_event_lan_overflow lan_overflow;
                struct ice_aqc_get_link_topo get_link_topo;
+               struct ice_aqc_dnl_call_command dnl_call;
                struct ice_aqc_i2c read_write_i2c;
                struct ice_aqc_read_i2c_resp read_i2c_resp;
                struct ice_aqc_get_set_tx_topo get_set_tx_topo;
        ice_aqc_opc_set_phy_rec_clk_out                 = 0x0630,
        ice_aqc_opc_get_phy_rec_clk_out                 = 0x0631,
        ice_aqc_opc_get_sensor_reading                  = 0x0632,
+       ice_aqc_opc_dnl_call                            = 0x0682,
        ice_aqc_opc_get_link_topo                       = 0x06E0,
        ice_aqc_opc_read_i2c                            = 0x06E2,
        ice_aqc_opc_write_i2c                           = 0x06E3,
 
        return status;
 }
 
+/**
+ * ice_aq_get_phy_equalization - function to read serdes equaliser
+ * value from firmware using admin queue command.
+ * @hw: pointer to the HW struct
+ * @data_in: represents the serdes equalization parameter requested
+ * @op_code: represents the serdes number and flag to represent tx or rx
+ * @serdes_num: represents the serdes number
+ * @output: pointer to the caller-supplied buffer to return serdes equaliser
+ *
+ * Return: non-zero status on error and 0 on success.
+ */
+int ice_aq_get_phy_equalization(struct ice_hw *hw, u16 data_in, u16 op_code,
+                               u8 serdes_num, int *output)
+{
+       struct ice_aqc_dnl_call_command *cmd;
+       struct ice_aqc_dnl_call buf = {};
+       struct ice_aq_desc desc;
+       int err;
+
+       buf.sto.txrx_equa_reqs.data_in = cpu_to_le16(data_in);
+       buf.sto.txrx_equa_reqs.op_code_serdes_sel =
+               cpu_to_le16(op_code | (serdes_num & 0xF));
+       cmd = &desc.params.dnl_call;
+       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_dnl_call);
+       desc.flags |= cpu_to_le16(ICE_AQ_FLAG_BUF |
+                                 ICE_AQ_FLAG_RD |
+                                 ICE_AQ_FLAG_SI);
+       desc.datalen = cpu_to_le16(sizeof(struct ice_aqc_dnl_call));
+       cmd->activity_id = cpu_to_le16(ICE_AQC_ACT_ID_DNL);
+
+       err = ice_aq_send_cmd(hw, &desc, &buf, sizeof(struct ice_aqc_dnl_call),
+                             NULL);
+       *output = err ? 0 : buf.sto.txrx_equa_resp.val;
+
+       return err;
+}
+
 #define FEC_REG_PORT(port) {   \
        FEC_CORR_LOW_REG_PORT##port,            \
        FEC_CORR_HIGH_REG_PORT##port,   \
 
 ice_get_link_default_override(struct ice_link_default_override_tlv *ldo,
                              struct ice_port_info *pi);
 bool ice_is_phy_caps_an_enabled(struct ice_aqc_get_phy_caps_data *caps);
+int ice_aq_get_phy_equalization(struct ice_hw *hw, u16 data_in, u16 op_code,
+                               u8 serdes_num, int *output);
 int
 ice_aq_get_fec_stats(struct ice_hw *hw, u16 pcs_quad, u16 pcs_port,
                     enum ice_fec_stats_types fec_type, u32 *output);
 
 
 static int ice_get_regs_len(struct net_device __always_unused *netdev)
 {
-       return sizeof(ice_regs_dump_list);
+       return (sizeof(ice_regs_dump_list) +
+               sizeof(struct ice_regdump_to_ethtool));
 }
 
 /**
        return 0;
 }
 
+/**
+ * ice_get_tx_rx_equa - read serdes tx rx equaliser param
+ * @hw: pointer to the HW struct
+ * @serdes_num: represents the serdes number
+ * @ptr: structure to read all serdes parameter for given serdes
+ *
+ * Return: all serdes equalization parameter supported per serdes number
+ */
+static int ice_get_tx_rx_equa(struct ice_hw *hw, u8 serdes_num,
+                             struct ice_serdes_equalization_to_ethtool *ptr)
+{
+       int err;
+
+       err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_PRE1,
+                                         ICE_AQC_OP_CODE_TX_EQU, serdes_num,
+                                         &ptr->tx_equalization_pre1);
+       if (err)
+               return err;
+
+       err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_PRE3,
+                                         ICE_AQC_OP_CODE_TX_EQU, serdes_num,
+                                         &ptr->tx_equalization_pre3);
+       if (err)
+               return err;
+
+       err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_ATTEN,
+                                         ICE_AQC_OP_CODE_TX_EQU, serdes_num,
+                                         &ptr->tx_equalization_atten);
+       if (err)
+               return err;
+
+       err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_POST1,
+                                         ICE_AQC_OP_CODE_TX_EQU, serdes_num,
+                                         &ptr->tx_equalization_post1);
+       if (err)
+               return err;
+
+       err = ice_aq_get_phy_equalization(hw, ICE_AQC_TX_EQU_PRE2,
+                                         ICE_AQC_OP_CODE_TX_EQU, serdes_num,
+                                         &ptr->tx_equalization_pre2);
+       if (err)
+               return err;
+
+       err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_PRE2,
+                                         ICE_AQC_OP_CODE_RX_EQU, serdes_num,
+                                         &ptr->rx_equalization_pre2);
+       if (err)
+               return err;
+
+       err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_PRE1,
+                                         ICE_AQC_OP_CODE_RX_EQU, serdes_num,
+                                         &ptr->rx_equalization_pre1);
+       if (err)
+               return err;
+
+       err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_POST1,
+                                         ICE_AQC_OP_CODE_RX_EQU, serdes_num,
+                                         &ptr->rx_equalization_post1);
+       if (err)
+               return err;
+
+       err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_BFLF,
+                                         ICE_AQC_OP_CODE_RX_EQU, serdes_num,
+                                         &ptr->rx_equalization_bflf);
+       if (err)
+               return err;
+
+       err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_BFHF,
+                                         ICE_AQC_OP_CODE_RX_EQU, serdes_num,
+                                         &ptr->rx_equalization_bfhf);
+       if (err)
+               return err;
+
+       err = ice_aq_get_phy_equalization(hw, ICE_AQC_RX_EQU_DRATE,
+                                         ICE_AQC_OP_CODE_RX_EQU, serdes_num,
+                                         &ptr->rx_equalization_drate);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+/**
+ * ice_get_extended_regs - returns FEC correctable, uncorrectable stats per
+ *                         pcsquad, pcsport
+ * @netdev: pointer to net device structure
+ * @p: output buffer to fill requested register dump
+ *
+ * Return: 0 on success, negative on failure.
+ */
+static int ice_get_extended_regs(struct net_device *netdev, void *p)
+{
+       struct ice_netdev_priv *np = netdev_priv(netdev);
+       struct ice_regdump_to_ethtool *ice_prv_regs_buf;
+       struct ice_port_topology port_topology = {};
+       struct ice_port_info *pi;
+       struct ice_pf *pf;
+       struct ice_hw *hw;
+       unsigned int i;
+       int err;
+
+       pf = np->vsi->back;
+       hw = &pf->hw;
+       pi = np->vsi->port_info;
+
+       /* Serdes parameters are not supported if not the PF VSI */
+       if (np->vsi->type != ICE_VSI_PF || !pi)
+               return -EINVAL;
+
+       err = ice_get_port_topology(hw, pi->lport, &port_topology);
+       if (err)
+               return -EINVAL;
+       if (port_topology.serdes_lane_count > 4)
+               return -EINVAL;
+
+       ice_prv_regs_buf = p;
+
+       /* Get serdes equalization parameter for available serdes */
+       for (i = 0; i < port_topology.serdes_lane_count; i++) {
+               u8 serdes_num = 0;
+
+               serdes_num = port_topology.primary_serdes_lane + i;
+               err = ice_get_tx_rx_equa(hw, serdes_num,
+                                        &ice_prv_regs_buf->equalization[i]);
+               if (err)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 static void
 ice_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
 {
        u32 *regs_buf = (u32 *)p;
        unsigned int i;
 
-       regs->version = 1;
+       regs->version = 2;
 
        for (i = 0; i < ARRAY_SIZE(ice_regs_dump_list); ++i)
                regs_buf[i] = rd32(hw, ice_regs_dump_list[i]);
+
+       ice_get_extended_regs(netdev, (void *)®s_buf[i]);
 }
 
 static u32 ice_get_msglevel(struct net_device *netdev)
 
        u8 link_mode;
 };
 
+struct ice_serdes_equalization_to_ethtool {
+       int rx_equalization_pre2;
+       int rx_equalization_pre1;
+       int rx_equalization_post1;
+       int rx_equalization_bflf;
+       int rx_equalization_bfhf;
+       int rx_equalization_drate;
+       int tx_equalization_pre1;
+       int tx_equalization_pre3;
+       int tx_equalization_atten;
+       int tx_equalization_post1;
+       int tx_equalization_pre2;
+};
+
+struct ice_regdump_to_ethtool {
+       /* A multilane port can have max 4 serdes */
+       struct ice_serdes_equalization_to_ethtool equalization[4];
+};
+
 /* Port topology from lport i.e.
  * serdes mapping, pcsquad, macport, cage etc...
  */