hw_link_info->an_info = link_data.an_info;
        hw_link_info->ext_info = link_data.ext_info;
        hw_link_info->max_frame_size = le16_to_cpu(link_data.max_frame_size);
+       hw_link_info->fec_info = link_data.cfg & ICE_AQ_FEC_MASK;
+       hw_link_info->topo_media_conflict = link_data.topo_media_conflict;
        hw_link_info->pacing = link_data.cfg & ICE_AQ_CFG_PACING_M;
 
        /* update fc info */
        return status;
 }
 
+/**
+ * ice_copy_phy_caps_to_cfg - Copy PHY ability data to configuration data
+ * @caps: PHY ability structure to copy date from
+ * @cfg: PHY configuration structure to copy data to
+ *
+ * Helper function to copy AQC PHY get ability data to PHY set configuration
+ * data structure
+ */
+void
+ice_copy_phy_caps_to_cfg(struct ice_aqc_get_phy_caps_data *caps,
+                        struct ice_aqc_set_phy_cfg_data *cfg)
+{
+       if (!caps || !cfg)
+               return;
+
+       cfg->phy_type_low = caps->phy_type_low;
+       cfg->phy_type_high = caps->phy_type_high;
+       cfg->caps = caps->caps;
+       cfg->low_power_ctrl = caps->low_power_ctrl;
+       cfg->eee_cap = caps->eee_cap;
+       cfg->eeer_value = caps->eeer_value;
+       cfg->link_fec_opt = caps->link_fec_options;
+}
+
+/**
+ * ice_cfg_phy_fec - Configure PHY FEC data based on FEC mode
+ * @cfg: PHY configuration data to set FEC mode
+ * @fec: FEC mode to configure
+ *
+ * Caller should copy ice_aqc_get_phy_caps_data.caps ICE_AQC_PHY_EN_AUTO_FEC
+ * (bit 7) and ice_aqc_get_phy_caps_data.link_fec_options to cfg.caps
+ * ICE_AQ_PHY_ENA_AUTO_FEC (bit 7) and cfg.link_fec_options before calling.
+ */
+void
+ice_cfg_phy_fec(struct ice_aqc_set_phy_cfg_data *cfg, enum ice_fec_mode fec)
+{
+       switch (fec) {
+       case ICE_FEC_BASER:
+               /* Clear auto FEC and RS bits, and AND BASE-R ability
+                * bits and OR request bits.
+                */
+               cfg->caps &= ~ICE_AQC_PHY_EN_AUTO_FEC;
+               cfg->link_fec_opt &= ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN |
+                                    ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN;
+               cfg->link_fec_opt |= ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ |
+                                    ICE_AQC_PHY_FEC_25G_KR_REQ;
+               break;
+       case ICE_FEC_RS:
+               /* Clear auto FEC and BASE-R bits, and AND RS ability
+                * bits and OR request bits.
+                */
+               cfg->caps &= ~ICE_AQC_PHY_EN_AUTO_FEC;
+               cfg->link_fec_opt &= ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN;
+               cfg->link_fec_opt |= ICE_AQC_PHY_FEC_25G_RS_528_REQ |
+                                    ICE_AQC_PHY_FEC_25G_RS_544_REQ;
+               break;
+       case ICE_FEC_NONE:
+               /* Clear auto FEC and all FEC option bits. */
+               cfg->caps &= ~ICE_AQC_PHY_EN_AUTO_FEC;
+               cfg->link_fec_opt &= ~ICE_AQC_PHY_FEC_MASK;
+               break;
+       case ICE_FEC_AUTO:
+               /* AND auto FEC bit, and all caps bits. */
+               cfg->caps &= ICE_AQC_PHY_CAPS_MASK;
+               break;
+       }
+}
+
 /**
  * ice_get_link_status - get status of the HW network link
  * @pi: port information structure
 
        return 0;
 }
 
+/**
+ * ice_set_fec_cfg - Set link FEC options
+ * @netdev: network interface device structure
+ * @req_fec: FEC mode to configure
+ */
+static int ice_set_fec_cfg(struct net_device *netdev, enum ice_fec_mode req_fec)
+{
+       struct ice_netdev_priv *np = netdev_priv(netdev);
+       struct ice_aqc_set_phy_cfg_data config = { 0 };
+       struct ice_aqc_get_phy_caps_data *caps;
+       struct ice_vsi *vsi = np->vsi;
+       u8 sw_cfg_caps, sw_cfg_fec;
+       struct ice_port_info *pi;
+       enum ice_status status;
+       int err = 0;
+
+       pi = vsi->port_info;
+       if (!pi)
+               return -EOPNOTSUPP;
+
+       /* Changing the FEC parameters is not supported if not the PF VSI */
+       if (vsi->type != ICE_VSI_PF) {
+               netdev_info(netdev, "Changing FEC parameters only supported for PF VSI\n");
+               return -EOPNOTSUPP;
+       }
+
+       /* Get last SW configuration */
+       caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL);
+       if (!caps)
+               return -ENOMEM;
+
+       status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_SW_CFG,
+                                    caps, NULL);
+       if (status) {
+               err = -EAGAIN;
+               goto done;
+       }
+
+       /* Copy SW configuration returned from PHY caps to PHY config */
+       ice_copy_phy_caps_to_cfg(caps, &config);
+       sw_cfg_caps = caps->caps;
+       sw_cfg_fec = caps->link_fec_options;
+
+       /* Get toloplogy caps, then copy PHY FEC topoloy caps to PHY config */
+       memset(caps, 0, sizeof(*caps));
+
+       status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP,
+                                    caps, NULL);
+       if (status) {
+               err = -EAGAIN;
+               goto done;
+       }
+
+       config.caps |= (caps->caps & ICE_AQC_PHY_EN_AUTO_FEC);
+       config.link_fec_opt = caps->link_fec_options;
+
+       ice_cfg_phy_fec(&config, req_fec);
+
+       /* If FEC mode has changed, then set PHY configuration and enable AN. */
+       if ((config.caps & ICE_AQ_PHY_ENA_AUTO_FEC) !=
+           (sw_cfg_caps & ICE_AQC_PHY_EN_AUTO_FEC) ||
+           config.link_fec_opt != sw_cfg_fec) {
+               if (caps->caps & ICE_AQC_PHY_AN_MODE)
+                       config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
+
+               status = ice_aq_set_phy_cfg(pi->hw, pi->lport, &config, NULL);
+
+               if (status)
+                       err = -EAGAIN;
+       }
+
+done:
+       devm_kfree(&vsi->back->pdev->dev, caps);
+       return err;
+}
+
+/**
+ * ice_set_fecparam - Set FEC link options
+ * @netdev: network interface device structure
+ * @fecparam: Ethtool structure to retrieve FEC parameters
+ */
+static int
+ice_set_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam)
+{
+       struct ice_netdev_priv *np = netdev_priv(netdev);
+       struct ice_vsi *vsi = np->vsi;
+       enum ice_fec_mode fec;
+
+       switch (fecparam->fec) {
+       case ETHTOOL_FEC_AUTO:
+               fec = ICE_FEC_AUTO;
+               break;
+       case ETHTOOL_FEC_RS:
+               fec = ICE_FEC_RS;
+               break;
+       case ETHTOOL_FEC_BASER:
+               fec = ICE_FEC_BASER;
+               break;
+       case ETHTOOL_FEC_OFF:
+       case ETHTOOL_FEC_NONE:
+               fec = ICE_FEC_NONE;
+               break;
+       default:
+               dev_warn(&vsi->back->pdev->dev, "Unsupported FEC mode: %d\n",
+                        fecparam->fec);
+               return -EINVAL;
+       }
+
+       return ice_set_fec_cfg(netdev, fec);
+}
+
+/**
+ * ice_get_fecparam - Get link FEC options
+ * @netdev: network interface device structure
+ * @fecparam: Ethtool structure to retrieve FEC parameters
+ */
+static int
+ice_get_fecparam(struct net_device *netdev, struct ethtool_fecparam *fecparam)
+{
+       struct ice_netdev_priv *np = netdev_priv(netdev);
+       struct ice_aqc_get_phy_caps_data *caps;
+       struct ice_link_status *link_info;
+       struct ice_vsi *vsi = np->vsi;
+       struct ice_port_info *pi;
+       enum ice_status status;
+       int err = 0;
+
+       pi = vsi->port_info;
+
+       if (!pi)
+               return -EOPNOTSUPP;
+       link_info = &pi->phy.link_info;
+
+       /* Set FEC mode based on negotiated link info */
+       switch (link_info->fec_info) {
+       case ICE_AQ_LINK_25G_KR_FEC_EN:
+               fecparam->active_fec = ETHTOOL_FEC_BASER;
+               break;
+       case ICE_AQ_LINK_25G_RS_528_FEC_EN:
+               /* fall through */
+       case ICE_AQ_LINK_25G_RS_544_FEC_EN:
+               fecparam->active_fec = ETHTOOL_FEC_RS;
+               break;
+       default:
+               fecparam->active_fec = ETHTOOL_FEC_OFF;
+               break;
+       }
+
+       caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL);
+       if (!caps)
+               return -ENOMEM;
+
+       status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP,
+                                    caps, NULL);
+       if (status) {
+               err = -EAGAIN;
+               goto done;
+       }
+
+       /* Set supported/configured FEC modes based on PHY capability */
+       if (caps->caps & ICE_AQC_PHY_EN_AUTO_FEC)
+               fecparam->fec |= ETHTOOL_FEC_AUTO;
+       if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN ||
+           caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ ||
+           caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN ||
+           caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ)
+               fecparam->fec |= ETHTOOL_FEC_BASER;
+       if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ ||
+           caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ ||
+           caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN)
+               fecparam->fec |= ETHTOOL_FEC_RS;
+       if (caps->link_fec_options == 0)
+               fecparam->fec |= ETHTOOL_FEC_OFF;
+
+done:
+       devm_kfree(&vsi->back->pdev->dev, caps);
+       return err;
+}
+
 /**
  * ice_get_priv_flags - report device private flags
  * @netdev: network interface device structure
                       struct ethtool_link_ksettings *ks)
 {
        struct ice_netdev_priv *np = netdev_priv(netdev);
+       struct ice_aqc_get_phy_caps_data *caps;
        struct ice_link_status *hw_link_info;
        struct ice_vsi *vsi = np->vsi;
 
                break;
        }
 
+       caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL);
+       if (!caps)
+               goto done;
+
+       if (ice_aq_get_phy_caps(vsi->port_info, false, ICE_AQC_REPORT_TOPO_CAP,
+                               caps, NULL))
+               netdev_info(netdev, "Get phy capability failed.\n");
+
+       /* Set supported FEC modes based on PHY capability */
+       ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
+
+       if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN ||
+           caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN)
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
+       if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN)
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
+
+       if (ice_aq_get_phy_caps(vsi->port_info, false, ICE_AQC_REPORT_SW_CFG,
+                               caps, NULL))
+               netdev_info(netdev, "Get phy capability failed.\n");
+
+       /* Set advertised FEC modes based on PHY capability */
+       ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE);
+
+       if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ ||
+           caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ)
+               ethtool_link_ksettings_add_link_mode(ks, advertising,
+                                                    FEC_BASER);
+       if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ ||
+           caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ)
+               ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
+
+done:
+       devm_kfree(&vsi->back->pdev->dev, caps);
        return 0;
 }
 
        .get_ts_info            = ethtool_op_get_ts_info,
        .get_per_queue_coalesce = ice_get_per_q_coalesce,
        .set_per_queue_coalesce = ice_set_per_q_coalesce,
+       .get_fecparam           = ice_get_fecparam,
+       .set_fecparam           = ice_set_fecparam,
 };
 
 /**
 
  */
 void ice_print_link_msg(struct ice_vsi *vsi, bool isup)
 {
+       struct ice_aqc_get_phy_caps_data *caps;
+       enum ice_status status;
+       const char *fec_req;
        const char *speed;
+       const char *fec;
        const char *fc;
 
        if (!vsi)
                break;
        }
 
-       netdev_info(vsi->netdev, "NIC Link is up %sbps, Flow Control: %s\n",
-                   speed, fc);
+       /* Get FEC mode based on negotiated link info */
+       switch (vsi->port_info->phy.link_info.fec_info) {
+       case ICE_AQ_LINK_25G_RS_528_FEC_EN:
+               /* fall through */
+       case ICE_AQ_LINK_25G_RS_544_FEC_EN:
+               fec = "RS-FEC";
+               break;
+       case ICE_AQ_LINK_25G_KR_FEC_EN:
+               fec = "FC-FEC/BASE-R";
+               break;
+       default:
+               fec = "NONE";
+               break;
+       }
+
+       /* Get FEC mode requested based on PHY caps last SW configuration */
+       caps = devm_kzalloc(&vsi->back->pdev->dev, sizeof(*caps), GFP_KERNEL);
+       if (!caps) {
+               fec_req = "Unknown";
+               goto done;
+       }
+
+       status = ice_aq_get_phy_caps(vsi->port_info, false,
+                                    ICE_AQC_REPORT_SW_CFG, caps, NULL);
+       if (status)
+               netdev_info(vsi->netdev, "Get phy capability failed.\n");
+
+       if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ ||
+           caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ)
+               fec_req = "RS-FEC";
+       else if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ ||
+                caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ)
+               fec_req = "FC-FEC/BASE-R";
+       else
+               fec_req = "NONE";
+
+       devm_kfree(&vsi->back->pdev->dev, caps);
+
+done:
+       netdev_info(vsi->netdev, "NIC Link is up %sbps, Requested FEC: %s, FEC: %s, Flow Control: %s\n",
+                   speed, fec_req, fec, fc);
 }
 
 /**