This patch enable three FEC related ops in ice driver. As no speed information can get from HW, this patch only show FEC capability.
Signed-off-by: Qiming Yang <qiming.y...@intel.com> --- drivers/net/ice/ice_ethdev.c | 175 +++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c index 3ccba4db80..9ef4538626 100644 --- a/drivers/net/ice/ice_ethdev.c +++ b/drivers/net/ice/ice_ethdev.c @@ -178,6 +178,12 @@ static int ice_timesync_read_time(struct rte_eth_dev *dev, static int ice_timesync_write_time(struct rte_eth_dev *dev, const struct timespec *timestamp); static int ice_timesync_disable(struct rte_eth_dev *dev); +static int ice_fec_get_capability(struct rte_eth_dev *dev, struct rte_eth_fec_capa *speed_fec_capa, + unsigned int num); +static int ice_fec_get(struct rte_eth_dev *dev, uint32_t *fec_capa); +static int ice_fec_set(struct rte_eth_dev *dev, uint32_t fec_capa); + + static const uint32_t *ice_buffer_split_supported_hdr_ptypes_get(struct rte_eth_dev *dev); static const struct rte_pci_id pci_id_ice_map[] = { @@ -294,6 +300,9 @@ static const struct eth_dev_ops ice_eth_dev_ops = { .timesync_write_time = ice_timesync_write_time, .timesync_disable = ice_timesync_disable, .tm_ops_get = ice_tm_ops_get, + .fec_get_capability = ice_fec_get_capability, + .fec_get = ice_fec_get, + .fec_set = ice_fec_set, .buffer_split_supported_hdr_ptypes_get = ice_buffer_split_supported_hdr_ptypes_get, }; @@ -6513,6 +6522,172 @@ ice_buffer_split_supported_hdr_ptypes_get(struct rte_eth_dev *dev __rte_unused) return ptypes; } +static int +ice_fec_get_capa_num(struct ice_aqc_get_phy_caps_data *pcaps, struct rte_eth_fec_capa *speed_fec_capa) +{ + int num = 0; + + if (pcaps->caps & ICE_AQC_PHY_EN_AUTO_FEC) { + if (speed_fec_capa) + speed_fec_capa[num].capa = RTE_ETH_FEC_MODE_CAPA_MASK(AUTO); + num++; + } + + if (pcaps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_EN || + pcaps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ || + pcaps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_CLAUSE74_EN || + pcaps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ) { + if (speed_fec_capa) + speed_fec_capa[num].capa = RTE_ETH_FEC_MODE_CAPA_MASK(BASER); + num++; + } + + if (pcaps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ || + pcaps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ || + pcaps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_CLAUSE91_EN) { + if (speed_fec_capa) + speed_fec_capa[num].capa = RTE_ETH_FEC_MODE_CAPA_MASK(RS); + num++; + } + + if (pcaps->link_fec_options == 0) { + if (speed_fec_capa) + speed_fec_capa[num].capa = RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC); + num++; + } + + return num; +} + +static int +ice_fec_get_capability(struct rte_eth_dev *dev, struct rte_eth_fec_capa *speed_fec_capa, + unsigned int num) +{ + struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ice_aqc_get_phy_caps_data *pcaps; + unsigned int capa_num; + int ret = 0; + + pcaps = (struct ice_aqc_get_phy_caps_data *) + ice_malloc(hw, sizeof(*pcaps)); + if (!pcaps) + return ICE_ERR_NO_MEMORY; + + ret = ice_aq_get_phy_caps(hw->port_info, false, ICE_AQC_REPORT_TOPO_CAP_MEDIA, + pcaps, NULL); + + printf("cap support: %d\n", pcaps->link_fec_options); + if (ret) + goto done; + + /* first time to get capa_num */ + capa_num = ice_fec_get_capa_num(pcaps, NULL); + if (!speed_fec_capa || num < capa_num) { + ret = capa_num; + goto done; + } + + ret = ice_fec_get_capa_num(pcaps, speed_fec_capa); + if (ret) + goto done; + +done: + ice_free(hw, pcaps); + return ret; +} +static int +ice_fec_get(struct rte_eth_dev *dev, uint32_t *fec_capa) +{ + struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ice_port_info *pi = hw->port_info; + u32 temp_fec_capa = 0; + int ret = 0; + + if (!pi) + return -ENOTSUP; + + /* Get current FEC mode from port info */ + switch (pi->phy.curr_user_fec_req) { + case ICE_FEC_NONE: + temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC); + break; + case ICE_FEC_AUTO: + case ICE_FEC_DIS_AUTO: + temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(AUTO); + break; + case ICE_FEC_BASER: + temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(BASER); + break; + case ICE_FEC_RS: + temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(RS); + break; + default: + ret = -ENOTSUP; + break; + } + *fec_capa = temp_fec_capa; + return ret; +} + +static int +ice_fec_set(struct rte_eth_dev *dev, uint32_t fec_capa) +{ + struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ice_port_info *pi = hw->port_info; + struct ice_aqc_set_phy_cfg_data config = { 0 }; + enum ice_fec_mode req_fec; + int ret = 0; + + if (!pi) + return -ENOTSUP; + + /* Copy the current user PHY configuration. The current user PHY + * configuration is initialized during probe from PHY capabilities + * software mode, and updated on set PHY configuration. + */ + memcpy(&config, &pi->phy.curr_user_phy_cfg, sizeof(config)); + + switch (fec_capa) { + case RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC): + req_fec = ICE_FEC_NONE; + break; + case RTE_ETH_FEC_MODE_CAPA_MASK(AUTO): + if (ice_fw_supports_fec_dis_auto(hw)) + req_fec = ICE_FEC_DIS_AUTO; + else + req_fec = ICE_FEC_AUTO; + break; + case RTE_ETH_FEC_MODE_CAPA_MASK(BASER): + req_fec = ICE_FEC_BASER; + break; + case RTE_ETH_FEC_MODE_CAPA_MASK(RS): + req_fec = ICE_FEC_RS; + break; + default: + PMD_DRV_LOG(ERR, "Unsupported FEC mode: %d\n", fec_capa); + return -EINVAL; + } + + ret = ice_cfg_phy_fec(pi, &config, req_fec); + if (ret) { + PMD_DRV_LOG(ERR, "Failed to set FEC mode"); + return -EINVAL; + } + + config.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; + + if (ice_aq_set_phy_cfg(pi->hw, pi, &config, NULL)) + return -EAGAIN; + + /* Save requested FEC config */ + pi->phy.curr_user_fec_req = req_fec; + printf("set current mode: %d\n", pi->phy.curr_user_fec_req); + + return 0; +} + + + static int ice_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, struct rte_pci_device *pci_dev) -- 2.25.1