Hi Vladimir: Thanks for your comments, some responses and questions are inline.
> From: Medvedkin, Vladimir <vladimir.medved...@intel.com> > Sent: Monday, March 11, 2024 11:59 PM > To: Zeng, ZhichaoX <zhichaox.z...@intel.com>; dev@dpdk.org > Cc: Cui, KaixinX <kaixinx....@intel.com>; Yang, Qiming > <qiming.y...@intel.com>; Zhang, Yuying <yuying.zh...@intel.com> > Subject: Re: [PATCH v4] net/i40e: support FEC feature > > Hi Zhicha, > It would be good to reflect FEC feature here: > https://doc.dpdk.org/guides/nics/overview.html > in " Table 1.1 Features availability in networking drivers " After modifying "doc/guides/nics/features/i40e.ini", the corresponding "overview.html" will be generated after compiling the document. > please find the rest comments inline > On 06/03/2024 10:41, Zhichao Zeng wrote: > This patch enabled querying Forward Error Correction(FEC) capabilities, > set FEC mode and get current FEC mode functions. > > Signed-off-by: Qiming Yang mailto:qiming.y...@intel.com > Signed-off-by: Zhichao Zeng mailto:zhichaox.z...@intel.com > > --- > v4: fix some logic > v3: optimize code details > v2: update NIC feature document > --- > doc/guides/nics/features/i40e.ini | 1 + > doc/guides/rel_notes/release_24_03.rst | 5 + > drivers/net/i40e/i40e_ethdev.c | 192 +++++++++++++++++++++++++ > 3 files changed, 198 insertions(+) > > diff --git a/doc/guides/nics/features/i40e.ini > b/doc/guides/nics/features/i40e.ini > index e241dad047..aac2c1a6a1 100644 > --- a/doc/guides/nics/features/i40e.ini > +++ b/doc/guides/nics/features/i40e.ini > @@ -30,6 +30,7 @@ Flow control = Y > CRC offload = Y > VLAN offload = Y > QinQ offload = P > +FEC = Y > L3 checksum offload = P > L4 checksum offload = P > Inner L3 checksum = P > diff --git a/doc/guides/rel_notes/release_24_03.rst > b/doc/guides/rel_notes/release_24_03.rst > index 161f77112b..862a5f8fb8 100644 > --- a/doc/guides/rel_notes/release_24_03.rst > +++ b/doc/guides/rel_notes/release_24_03.rst > @@ -110,6 +110,11 @@ New Features > > * Added support for 5760X device family. > > +* **Updated Intel i40e driver.** > + > + * Added support for configuring the Forward Error Correction(FEC) mode, > querying > + * FEC capabilities and current FEC mode from a device. > + > * **Updated Marvell cnxk net driver.** > > * Added support for port representors. > diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c > index 380ce1a720..2bc6675a04 100644 > --- a/drivers/net/i40e/i40e_ethdev.c > +++ b/drivers/net/i40e/i40e_ethdev.c > @@ -406,6 +406,10 @@ static void i40e_ethertype_filter_restore(struct i40e_pf > *pf); > static void i40e_tunnel_filter_restore(struct i40e_pf *pf); > static void i40e_filter_restore(struct i40e_pf *pf); > static void i40e_notify_all_vfs_link_status(struct rte_eth_dev *dev); > +static int i40e_fec_get_capability(struct rte_eth_dev *dev, > + struct rte_eth_fec_capa *speed_fec_capa, unsigned int num); > +static int i40e_fec_get(struct rte_eth_dev *dev, uint32_t *fec_capa); > +static int i40e_fec_set(struct rte_eth_dev *dev, uint32_t fec_capa); > > static const char *const valid_keys[] = { > ETH_I40E_FLOATING_VEB_ARG, > @@ -521,6 +525,9 @@ static const struct eth_dev_ops i40e_eth_dev_ops = { > .tm_ops_get = i40e_tm_ops_get, > .tx_done_cleanup = i40e_tx_done_cleanup, > .get_monitor_addr = i40e_get_monitor_addr, > + .fec_get_capability = i40e_fec_get_capability, > + .fec_get = i40e_fec_get, > + .fec_set = i40e_fec_set, > }; > > /* store statistics names and its offset in stats structure */ > @@ -12297,6 +12304,191 @@ i40e_cloud_filter_qinq_create(struct i40e_pf *pf) > return ret; > } > > +static int > +i40e_fec_get_capability(struct rte_eth_dev *dev, > + struct rte_eth_fec_capa *speed_fec_capa, __rte_unused unsigned int num) > +{ > + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); > + > + if (hw->mac.type == I40E_MAC_X722 && > + !(hw->flags & I40E_HW_FLAG_X722_FEC_REQUEST_CAPABLE)) { > + PMD_DRV_LOG(ERR, "Setting FEC encoding not supported by" > + " firmware. Please update the NVM image.\n"); > + return -ENOTSUP; > + } > + > + if (hw->device_id == I40E_DEV_ID_25G_SFP28 || > + hw->device_id == I40E_DEV_ID_25G_B) { > + if (speed_fec_capa) { > + speed_fec_capa->speed = RTE_ETH_SPEED_NUM_25G; > + speed_fec_capa->capa = > RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC) | > + RTE_ETH_FEC_MODE_CAPA_MASK(BASER) | > + RTE_ETH_FEC_MODE_CAPA_MASK(AUTO) | > + RTE_ETH_FEC_MODE_CAPA_MASK(RS); > + } > + > + /* since HW only supports 25G */ > + return 1; > + } else if (hw->device_id == I40E_DEV_ID_KX_X722) { > + if (speed_fec_capa) { > + speed_fec_capa->speed = RTE_ETH_SPEED_NUM_25G; > + speed_fec_capa->capa = RTE_ETH_FEC_MODE_CAPA_MASK(AUTO) > | > + RTE_ETH_FEC_MODE_CAPA_MASK(RS); > + } > + return 1; > + } > + > + return -ENOTSUP; > +} > + > +static int > +i40e_fec_get(struct rte_eth_dev *dev, uint32_t *fec_capa) > +{ > + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); > + struct i40e_link_status link_status = {0}; > + uint8_t configured_fec_cfg = 0, current_fec_cfg; > + uint32_t temp_fec_capa = 0; > + bool link_up, enable_lse; > + int ret = 0; > + > + enable_lse = dev->data->dev_conf.intr_conf.lsc ? true : false; > + /* Get FEC info */ > + ret = i40e_aq_get_link_info(hw, enable_lse, &link_status, NULL); > + if (ret != I40E_SUCCESS) { > + PMD_DRV_LOG(ERR, "Failed to get link information"); > + return -ENOTSUP; > + } > + > + link_up = link_status.link_info & I40E_AQ_LINK_UP; > + > + /** > + * If link is down and AUTO is enabled, AUTO is returned, > + * otherwise, configured FEC mode is returned. > + * If link is up, current FEC mode is returned. > + */ > + configured_fec_cfg = link_status.req_fec_info; > here we need to better understand the difference between [FC,RS]-FEC ability > bit (aka I40E_AQ_ENABLE_FEC_[KR,RS]) from [FC,RS]-FEC Request bit (aka > I40E_AQ_REQUEST_FEC_[KR,RS]), since link_status.req_fec_info has only > "Request" bits for each FEC algo (see i40e_update_link_info()). > From what I found on the internet, it seems that we don't need to use them at > all, because, for example for FC-FEC (aka Clause 74), from: > https://www.ieee802.org/3/25GSG/public/Nov14/baden_25GE_02_1114.pdf > Key phrase: "If both LPs advertise the FEC Ability, and EITHER LP requests > the FEC, it is enabled." > So I'd suggest not to use these "Request" bits here. > For configured fec (case when link is DOWN) please use struct > i40e_aq_get_phy_abilities_resp abilities. Will fix in next version. > > + current_fec_cfg = link_status.fec_info; > + > + if (!link_up) { > This section should be rewritten according to bit flags from > abilities.fec_cfg_curr_mod_ext_info. > + if (current_fec_cfg & (I40E_AQ_ENABLE_FEC_KR | > I40E_AQ_ENABLE_FEC_RS)) { > + temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(AUTO); > + } else { > + if (configured_fec_cfg == (I40E_AQ_REQUEST_FEC_KR | > I40E_AQ_REQUEST_FEC_RS)) > + temp_fec_capa = > RTE_ETH_FEC_MODE_CAPA_MASK(AUTO); > + else if (configured_fec_cfg & I40E_AQ_REQUEST_FEC_KR) > + temp_fec_capa = > RTE_ETH_FEC_MODE_CAPA_MASK(BASER); > + else if (configured_fec_cfg & I40E_AQ_REQUEST_FEC_RS) > + temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(RS); > + else > + temp_fec_capa = > RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC); > + } Should current_fec_cfg (link_status.fec_info) be rewritten this way since it only has KR or RS bit and no AUTO bit? any suggestion please? if (configured_fec_cfg & I40E_AQ_ENABLE_FEC_AUTO) temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(AUTO); else if (configured_fec_cfg & I40E_AQ_ENABLE_FEC_KR) temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(BASER); else if (configured_fec_cfg & I40E_AQ_ENABLE_FEC_RS) temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(RS); else temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC); > + } else { > + if (current_fec_cfg & (I40E_AQ_ENABLE_FEC_KR | > I40E_AQ_ENABLE_FEC_RS)) > + temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(AUTO); > In case when FEC was successfully negotiated current_fec_cfg is containing > only single bit (since 2 algos can not be enabled at the same time), so this > part is meaningless. Also here and below in this else section (i.e. in > section if link is UP), for consistency please use corresponding macros > defined for struct i40e_aqc_get_link_status - I40E_AQ_CONFIG_FEC_KR_ENA and > I40E_AQ_CONFIG_FEC_RS_ENA instead of I40E_AQ_ENABLE_FEC_ . > + else if (current_fec_cfg & I40E_AQ_ENABLE_FEC_KR) > + temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(BASER); > + else if (current_fec_cfg & I40E_AQ_ENABLE_FEC_RS) > + temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(RS); > + else > + temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC); Is there any issue with this change? if (current_fec_cfg & I40E_AQ_CONFIG_FEC_KR_ENA) temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(BASER); else if (current_fec_cfg & I40E_AQ_CONFIG_FEC_RS_ENA) temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(RS); else temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC); > + } > + > + *fec_capa = temp_fec_capa; > + > + return 0; > +} > + > +static int > +i40e_fec_set(struct rte_eth_dev *dev, uint32_t fec_capa) > +{ > + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); > + struct i40e_aq_get_phy_abilities_resp abilities = {0}; > + struct i40e_aq_set_phy_config config = {0}; > + enum i40e_status_code status; > + uint8_t req_fec = 0; > + > + if (hw->device_id != I40E_DEV_ID_25G_SFP28 && > + hw->device_id != I40E_DEV_ID_25G_B && > + hw->device_id != I40E_DEV_ID_KX_X722) { > + return -ENOTSUP; > + } > + > + if (hw->mac.type == I40E_MAC_X722 && > + !(hw->flags & I40E_HW_FLAG_X722_FEC_REQUEST_CAPABLE)) { > + PMD_DRV_LOG(ERR, "Setting FEC encoding not supported by" > + " firmware. Please update the NVM image.\n"); > + 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. > + */ > + if (fec_capa != 0) > + return -EINVAL; > Did you mean if (fec_capa == 0)? Yes...sorry for mistake, will fix in next version. > > + > + if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(AUTO)) { > + if (hw->mac.type == I40E_MAC_X722) { > + PMD_DRV_LOG(ERR, "X722 Unsupported FEC mode: AUTO"); > + return -EINVAL; > + } > + req_fec = I40E_AQ_SET_FEC_AUTO; > + goto set_fec; > + } > + > + if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC)) > + req_fec = 0; > + > + if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(BASER)) > + req_fec |= I40E_AQ_SET_FEC_REQUEST_KR; > + > + if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(RS)) { > + if (hw->mac.type == I40E_MAC_X722) { > + PMD_DRV_LOG(ERR, "X722 Unsupported FEC mode: RS"); > + return -EINVAL; > + } > + req_fec |= I40E_AQ_SET_FEC_REQUEST_RS; > + } > This part is not looking correct to me: > - only I40E_AQ_SET_FEC_AUTO bit is set w/o enabling specific protocols > - "if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC))" makes no sense if other > bitfields are set > - only I40E_AQ_SET_FEC_REQUEST_* is set without I40E_AQ_SET_FEC_ABILITY_* > According to API : "If only the AUTO bit is set, the decision on which FEC > mode to use will be made by HW/FW or driver. If the AUTO bit is set with some > FEC modes, only specified FEC modes can be set. If AUTO bit is clear, specify > FEC mode to be used (only one valid mode per speed may be set)." I'd suggest: > - In case when AUTO bit is set we need to check for other bit flags. In case > of absence let's decide to add all supported by mac type algorithms (i.e. > set corresponding _enable_ and _request_ bit fields for each supported algo). > - In case if there are more bits apart from AUTO - check for their validity > and support and specify corresponding _enable_ and _request_ flags. > - In case if AUTO is not set check that only single mode was specified, check > its validity + support and so on. Based on your suggestions, any other suggestion for the following rework? if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(AUTO)) fec_auto = 1; if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(BASER)) fec_kr = 1; if (fec_capa & RTE_ETH_FEC_MODE_CAPA_MASK(RS)) fec_rs = 1; if (fec_auto) { if (hw->mac.type == I40E_MAC_X722) { PMD_DRV_LOG(ERR, "X722 Unsupported FEC mode: AUTO"); return -EINVAL; } if (fec_kr ^ fec_rs) { if (fec_kr) req_fec = I40E_AQ_SET_FEC_ABILITY_KR | I40E_AQ_SET_FEC_REQUEST_KR; else { if (hw->mac.type == I40E_MAC_X722) { PMD_DRV_LOG(ERR, "X722 Unsupported FEC mode: RS"); return -EINVAL; } req_fec = I40E_AQ_SET_FEC_ABILITY_RS | I40E_AQ_SET_FEC_REQUEST_RS; } } else { if (hw->mac.type == I40E_MAC_X722) { req_fec = I40E_AQ_SET_FEC_ABILITY_KR | I40E_AQ_SET_FEC_REQUEST_KR; } else { req_fec = I40E_AQ_SET_FEC_ABILITY_KR | I40E_AQ_SET_FEC_REQUEST_KR | I40E_AQ_SET_FEC_ABILITY_RS | I40E_AQ_SET_FEC_REQUEST_RS; } } } else { if (fec_kr ^ fec_rs) { if (fec_kr) req_fec = I40E_AQ_SET_FEC_ABILITY_KR | I40E_AQ_SET_FEC_REQUEST_KR; else { if (hw->mac.type == I40E_MAC_X722) { PMD_DRV_LOG(ERR, "X722 Unsupported FEC mode: RS"); return -EINVAL; } req_fec = I40E_AQ_SET_FEC_ABILITY_RS | I40E_AQ_SET_FEC_REQUEST_RS; } } else { return -EINVAL; } } > + > +set_fec: > + /* Get the current phy config */ > + status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities, > + NULL); > + if (status) { > + PMD_DRV_LOG(ERR, "Failed to get PHY capabilities: %d\n", > + status); > + return -ENOTSUP; > + } > + > + if (abilities.fec_cfg_curr_mod_ext_info != req_fec) { > + config.phy_type = abilities.phy_type; > + config.abilities = abilities.abilities | > + I40E_AQ_PHY_ENABLE_ATOMIC_LINK; > + config.phy_type_ext = abilities.phy_type_ext; > + config.link_speed = abilities.link_speed; > + config.eee_capability = abilities.eee_capability; > + config.eeer = abilities.eeer_val; > + config.low_power_ctrl = abilities.d3_lpan; > + config.fec_config = req_fec & I40E_AQ_PHY_FEC_CONFIG_MASK; > + status = i40e_aq_set_phy_config(hw, &config, NULL); > + if (status) { > + PMD_DRV_LOG(ERR, "Failed to set PHY capabilities: %d\n", > + status); > + return -ENOTSUP; > + } > + } > + > + status = i40e_update_link_info(hw); > + if (status) { > + PMD_DRV_LOG(ERR, "Failed to set PHY capabilities: %d\n", > + status); > + return -EAGAIN; > This is a new return status of this API. It needs to be added in doxygen > documentation for this function and be reflected in release notes My bad, will fix in next version. > > + } > + > + return 0; > +} > + > RTE_LOG_REGISTER_SUFFIX(i40e_logtype_init, init, NOTICE); > RTE_LOG_REGISTER_SUFFIX(i40e_logtype_driver, driver, NOTICE); > #ifdef RTE_ETHDEV_DEBUG_RX > -- > Regards, > Vladimir > Regards, Zhichao