@@ -405,6 +405,11 @@ 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,
@@ -519,6 +524,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 */
@@ -12159,6 +12167,181 @@ 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,
+ unsigned int num)
+{
+ struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ num = 0;
+
+ 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 0;
+ }
+
+ if (hw->device_id == I40E_DEV_ID_25G_SFP28 ||
+ hw->device_id == I40E_DEV_ID_25G_B) {
+ if (speed_fec_capa) {
+ speed_fec_capa[num].speed = RTE_ETH_SPEED_NUM_25G;
+ speed_fec_capa[num].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);
+ }
+ num++;
+ }
+
+ if (hw->device_id == I40E_DEV_ID_KX_X722) {
+ if (speed_fec_capa) {
+ speed_fec_capa[num].speed = RTE_ETH_SPEED_NUM_25G;
+ speed_fec_capa[num].capa = RTE_ETH_FEC_MODE_CAPA_MASK(AUTO) |
+ RTE_ETH_FEC_MODE_CAPA_MASK(RS);
+ }
+ num++;
+ }
+
+ return num;
+}
+
+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_aq_get_phy_abilities_resp abilities;
+ u32 temp_fec_capa = 0;
+ u8 fec_cfg;
+ int ret = 0;
+
+ /* Get the current phy config */
+ memset(&abilities, 0, sizeof(abilities));
+ ret = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
+ NULL);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Failed to get PHY capabilities: %d\n",
+ ret);
+ return -ENOTSUP;
+ }
+
+ fec_cfg = abilities.fec_cfg_curr_mod_ext_info;
+ if (fec_cfg & I40E_AQ_SET_FEC_AUTO)
+ temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(AUTO);
+
+ if (fec_cfg & I40E_AQ_SET_FEC_REQUEST_KR ||
+ fec_cfg & I40E_AQ_SET_FEC_ABILITY_KR)
+ temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(BASER);
+
+ if (fec_cfg & I40E_AQ_SET_FEC_REQUEST_RS ||
+ fec_cfg & I40E_AQ_SET_FEC_ABILITY_RS)
+ temp_fec_capa = RTE_ETH_FEC_MODE_CAPA_MASK(RS);
+
+ if (fec_cfg == 0)
+ 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;
+ struct i40e_aq_set_phy_config config = { 0 };
+ enum i40e_status_code status;
+ u8 req_fec;
+ int ret = 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) {
+ ret = -ENOTSUP;
+ goto done;
+ }
+
+ 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.
+ */
+ switch (fec_capa) {
+ case RTE_ETH_FEC_MODE_CAPA_MASK(NOFEC):
+ req_fec = 0;
+ break;
+ case RTE_ETH_FEC_MODE_CAPA_MASK(AUTO):
+ if (hw->mac.type == I40E_MAC_X722) {
+ PMD_DRV_LOG(ERR, "X722 Unsupported FEC mode: AUTO");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ req_fec = I40E_AQ_SET_FEC_AUTO;
+ }
+ break;
+ case RTE_ETH_FEC_MODE_CAPA_MASK(BASER):
+ req_fec = (I40E_AQ_SET_FEC_REQUEST_KR |
+ I40E_AQ_SET_FEC_ABILITY_KR);
+ break;
+ case RTE_ETH_FEC_MODE_CAPA_MASK(RS):
+ if (hw->mac.type == I40E_MAC_X722) {
+ PMD_DRV_LOG(ERR, "X722 Unsupported FEC mode: RS");
+ ret = -EINVAL;
+ goto done;
+ } else {
+ req_fec = (I40E_AQ_SET_FEC_REQUEST_RS |
+ I40E_AQ_SET_FEC_ABILITY_RS);
+ }
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unsupported FEC mode: %d\n", fec_capa);
+ return -EINVAL;
+ }
+
+ /* 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);
+ ret = -ENOTSUP;
+ goto done;
+ }
+
+ 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);
+ ret = -ENOTSUP;
+ goto done;
+ }
+ }
+
+ status = i40e_update_link_info(hw);
+ if (status)
+ PMD_DRV_LOG(ERR, "Failed to set PHY capabilities: %d\n",
+ status);
+
+done:
+ return ret;
+}
+
RTE_LOG_REGISTER_SUFFIX(i40e_logtype_init, init, NOTICE);
RTE_LOG_REGISTER_SUFFIX(i40e_logtype_driver, driver, NOTICE);
#ifdef RTE_ETHDEV_DEBUG_RX