High-speed links need a configurable FEC mode to interoperate with the peer, so add FEC get/set/capability callbacks.
Signed-off-by: Jiacheng Ye <[email protected]> --- doc/guides/rel_notes/release_26_11.rst | 1 + drivers/net/hinic3/base/hinic3_hwdev.h | 1 + drivers/net/hinic3/base/hinic3_nic_cfg.c | 110 +++++++++++++++++++++ drivers/net/hinic3/base/hinic3_nic_cfg.h | 42 ++++++++ drivers/net/hinic3/base/hinic3_nic_event.c | 1 + drivers/net/hinic3/hinic3_ethdev.c | 92 +++++++++++++++++ drivers/net/hinic3/hinic3_ethdev.h | 1 + 7 files changed, 248 insertions(+) diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst index 0c02cbf67f..31109a16a7 100644 --- a/doc/guides/rel_notes/release_26_11.rst +++ b/doc/guides/rel_notes/release_26_11.rst @@ -95,6 +95,7 @@ New Features * **Updated Huawei hinic3 ethernet driver.** * Added CIR drop statistics and VF link aggregation (LAG) support. + * Added FEC mode get and set support. * **Updated Intel iavf driver.** diff --git a/drivers/net/hinic3/base/hinic3_hwdev.h b/drivers/net/hinic3/base/hinic3_hwdev.h index c6661aa1a6..5601f93190 100644 --- a/drivers/net/hinic3/base/hinic3_hwdev.h +++ b/drivers/net/hinic3/base/hinic3_hwdev.h @@ -158,6 +158,7 @@ struct hinic3_hwdev { uint16_t max_vfs; uint16_t link_status; + uint32_t speed; uint64_t features[HINIC3_MAX_FEATURE_QWORD]; }; diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.c b/drivers/net/hinic3/base/hinic3_nic_cfg.c index 48dee29750..c67779349f 100644 --- a/drivers/net/hinic3/base/hinic3_nic_cfg.c +++ b/drivers/net/hinic3/base/hinic3_nic_cfg.c @@ -1752,6 +1752,116 @@ hinic3_set_link_status_follow(struct hinic3_hwdev *hwdev, return follow.head.status; } +static void +hinic3_fec_param_covert(uint32_t opcode, uint8_t in_fec_param, uint8_t *out_fec_param) +{ + uint8_t fec_value_table_length; + uint8_t i; + + struct hinic3_fec_param_value_map fec_value_table[] = { + {HINIC3_PORT_FEC_NOT_SET, RTE_BIT32(HINIC3_PORT_FEC_NOT_SET), HINIC3_FEC_MODE_NONE}, + {HINIC3_PORT_FEC_RSFEC, RTE_BIT32(HINIC3_PORT_FEC_RSFEC), HINIC3_FEC_MODE_RS}, + {HINIC3_PORT_FEC_BASEFEC, RTE_BIT32(HINIC3_PORT_FEC_BASEFEC), + HINIC3_FEC_MODE_BASER}, + {HINIC3_PORT_FEC_NOFEC, RTE_BIT32(HINIC3_PORT_FEC_NOFEC), HINIC3_FEC_MODE_OFF}, + {HINIC3_PORT_FEC_LLRSFEC, RTE_BIT32(HINIC3_PORT_FEC_LLRSFEC), HINIC3_FEC_MODE_LLRS}, + {HINIC3_PORT_FEC_AUTO, RTE_BIT32(HINIC3_PORT_FEC_AUTO), HINIC3_FEC_MODE_AUTO} + }; + + *out_fec_param = 0; + fec_value_table_length = + (uint8_t)(sizeof(fec_value_table) / sizeof(struct hinic3_fec_param_value_map)); + + if (opcode == HINIC3_FEC_MODE_OPCODE_SET) { + for (i = 0; i < fec_value_table_length; i++) { + if ((in_fec_param & fec_value_table[i].ethtool_fec_value) != 0) + *out_fec_param = fec_value_table[i].fec_offset; + } + } + + if (opcode == HINIC3_FEC_MODE_OPCODE_GET) { + for (i = 0; i < fec_value_table_length; i++) { + if ((in_fec_param & fec_value_table[i].hinic3_fec_value) != 0) + *out_fec_param |= fec_value_table[i].ethtool_fec_value; + } + } +} + +int +hinic3_set_fec_mode(struct hinic3_hwdev *hwdev, uint8_t fecparam) +{ + struct mag_cmd_cfg_fec_mode fec_msg = { 0 }; + uint16_t out_size = sizeof(fec_msg); + uint8_t advertised_fec = 0; + int err; + + if (!hwdev) + return -EINVAL; + + hinic3_fec_param_covert(HINIC3_FEC_MODE_OPCODE_SET, fecparam, &advertised_fec); + fec_msg.opcode = HINIC3_FEC_MODE_OPCODE_SET; + fec_msg.port_id = hinic3_physical_port_id(hwdev); + fec_msg.advertised_fec = advertised_fec; + + err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_HILINK, + MAG_CMD_CFG_FEC_MODE, + &fec_msg, sizeof(fec_msg), + &fec_msg, &out_size); + + if (fec_msg.head.status != 0 || err) { + PMD_DRV_LOG(ERR, "Failed to set fec mode failed, err: %d, status: 0x%x, out size: 0x%x", + err, fec_msg.head.status, out_size); + return -EINVAL; + } + + PMD_DRV_LOG(INFO, "Set fec mode success, active fec capa mode: %d", fecparam); + return 0; +} + +int +hinic3_get_fec_mode(struct hinic3_hwdev *hwdev, uint8_t *advertised_fec, + uint8_t *supported_fec) +{ + struct mag_cmd_cfg_fec_mode fec_msg = { 0 }; + uint16_t out_size = sizeof(fec_msg); + int err; + + if (!hwdev) + return -EINVAL; + + if (advertised_fec != NULL) + *advertised_fec = 0; + + if (supported_fec != NULL) + *supported_fec = 0; + + fec_msg.opcode = HINIC3_FEC_MODE_OPCODE_GET; + fec_msg.port_id = hinic3_physical_port_id(hwdev); + + err = hinic3_msg_to_mgmt_sync(hwdev, HINIC3_MOD_HILINK, + MAG_CMD_CFG_FEC_MODE, + &fec_msg, sizeof(fec_msg), + &fec_msg, &out_size); + + if (fec_msg.head.status != 0 || err) { + PMD_DRV_LOG(ERR, "Failed to get fec mode failed, err: %d, status: 0x%x, out size: 0x%x", + err, fec_msg.head.status, out_size); + return -EINVAL; + } + + if (advertised_fec != NULL) + hinic3_fec_param_covert(HINIC3_FEC_MODE_OPCODE_GET, + RTE_BIT32(fec_msg.advertised_fec), + advertised_fec); + + if (supported_fec != NULL) + hinic3_fec_param_covert(HINIC3_FEC_MODE_OPCODE_GET, + fec_msg.supported_fec, + supported_fec); + + return 0; +} + uint8_t hinic3_cmd_vf_lag(void *hwdev, uint16_t func_id, uint8_t opcode) { diff --git a/drivers/net/hinic3/base/hinic3_nic_cfg.h b/drivers/net/hinic3/base/hinic3_nic_cfg.h index 5f08d49a72..42a7b7010d 100644 --- a/drivers/net/hinic3/base/hinic3_nic_cfg.h +++ b/drivers/net/hinic3/base/hinic3_nic_cfg.h @@ -967,6 +967,43 @@ int hinic3_msg_to_mgmt_sync(struct hinic3_hwdev *hwdev, enum hinic3_mod_type mod int hinic3_set_ci_table(struct hinic3_hwdev *hwdev, struct hinic3_sq_attr *attr); +enum hinic3_fec_mode_opcode { + HINIC3_FEC_MODE_OPCODE_GET = 0, + HINIC3_FEC_MODE_OPCODE_SET = 1, +}; + +struct mag_cmd_cfg_fec_mode { + struct mgmt_msg_head head; + uint8_t port_id; + uint8_t opcode; + uint8_t advertised_fec; + uint8_t supported_fec; +}; + +enum hinic3_cmd_port_fec { + HINIC3_PORT_FEC_NOT_SET = 0, + HINIC3_PORT_FEC_RSFEC = 1, + HINIC3_PORT_FEC_BASEFEC = 2, + HINIC3_PORT_FEC_NOFEC = 3, + HINIC3_PORT_FEC_LLRSFEC = 4, + HINIC3_PORT_FEC_AUTO = 5, +}; + +enum hinic3_fec_mode { + HINIC3_FEC_MODE_NONE = 0, + HINIC3_FEC_MODE_OFF = 1, + HINIC3_FEC_MODE_AUTO = 2, + HINIC3_FEC_MODE_BASER = 4, + HINIC3_FEC_MODE_RS = 8, + HINIC3_FEC_MODE_LLRS = 16, +}; + +struct hinic3_fec_param_value_map { + uint8_t fec_offset; + uint8_t hinic3_fec_value; + uint8_t ethtool_fec_value; +}; + /** * Update MAC address to hardware. * @@ -1583,4 +1620,9 @@ int hinic3_get_cir_drop(void *hwdev, struct hinic3_cir_drop *stats); uint8_t hinic3_cmd_vf_lag(void *hwdev, uint16_t func_id, uint8_t opcode); +int hinic3_set_fec_mode(struct hinic3_hwdev *hwdev, uint8_t fecparam); + +int hinic3_get_fec_mode(struct hinic3_hwdev *hwdev, uint8_t *advertised_fec, + uint8_t *supported_fec); + #endif /* _HINIC3_NIC_CFG_H_ */ diff --git a/drivers/net/hinic3/base/hinic3_nic_event.c b/drivers/net/hinic3/base/hinic3_nic_event.c index 981a5f5083..be8a1fc576 100644 --- a/drivers/net/hinic3/base/hinic3_nic_event.c +++ b/drivers/net/hinic3/base/hinic3_nic_event.c @@ -57,6 +57,7 @@ hinic3_get_link_port_info(struct hinic3_hwdev *hwdev, uint8_t link_state, port_speed[port_info.speed % LINK_SPEED_LEVELS]; link->link_duplex = port_info.duplex; link->link_autoneg = port_info.autoneg_state; + hwdev->speed = link->link_speed; } } } diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c index ecf7df3ec0..6d789565d5 100644 --- a/drivers/net/hinic3/hinic3_ethdev.c +++ b/drivers/net/hinic3/hinic3_ethdev.c @@ -3335,6 +3335,95 @@ hinic3_dev_filter_ctrl(struct rte_eth_dev *dev, const struct rte_flow_ops **arg) return 0; } +static const uint32_t HINIC3_FEC_CAPA_NUM_PER_SPEED = 1; + +static bool +hinic3_fec_param_valid(uint32_t fec_param) +{ + if (fec_param == HINIC3_FEC_MODE_LLRS || + fec_param == HINIC3_FEC_MODE_RS || + fec_param == HINIC3_FEC_MODE_BASER || + fec_param == HINIC3_FEC_MODE_OFF) { + return true; + } + + return false; +} + +static int +hinic3_fec_set(struct rte_eth_dev *dev, uint32_t fec_capa) +{ + struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev); + int err; + + if (hinic3_fec_param_valid(fec_capa) == false) { + PMD_DRV_LOG(ERR, "Fec param is valid, failed to set fec param."); + return -EINVAL; + } + + err = hinic3_set_fec_mode(nic_dev->hwdev, (uint8_t)fec_capa); + if (err) { + PMD_DRV_LOG(ERR, "Set fec param failed: %d.", err); + return err; + } + + nic_dev->fec_mode = fec_capa; + + return 0; +} + +static int +hinic3_fec_get(struct rte_eth_dev *dev, uint32_t *fec_capa) +{ + struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev); + uint8_t advertised_fec = 0; + int err; + + err = hinic3_get_fec_mode(nic_dev->hwdev, &advertised_fec, 0); + if (err) { + PMD_DRV_LOG(ERR, "Get fec parma failed: %d.", err); + return err; + } + + *fec_capa = (uint32_t)advertised_fec; + + return 0; +} + +static int +hinic3_fec_capability_get(struct rte_eth_dev *dev, + struct rte_eth_fec_capa *speed_fec_capa, + unsigned int num) +{ + struct hinic3_nic_dev *nic_dev = HINIC3_ETH_DEV_TO_PRIVATE_NIC_DEV(dev); + uint8_t supported_fec = 0; + int err; + + if (speed_fec_capa == NULL) + return HINIC3_FEC_CAPA_NUM_PER_SPEED; + + if (num < HINIC3_FEC_CAPA_NUM_PER_SPEED) { + PMD_DRV_LOG(ERR, "Not enough array size(%u) to store FEC capabilities, should not be less than %u.", + num, HINIC3_FEC_CAPA_NUM_PER_SPEED); + return -EINVAL; + } + + err = hinic3_get_fec_mode(nic_dev->hwdev, 0, &supported_fec); + if (err) { + PMD_DRV_LOG(ERR, "Failed to get fec capability, err: %d.", err); + return err; + } + + speed_fec_capa->speed = nic_dev->hwdev->speed; + speed_fec_capa->capa = (uint32_t)supported_fec; + + if (speed_fec_capa->speed == RTE_ETH_SPEED_NUM_NONE || + speed_fec_capa->capa == 0) + return -ENOTSUP; + + return HINIC3_FEC_CAPA_NUM_PER_SPEED; +} + static const struct eth_dev_ops hinic3_pmd_ops = { .dev_configure = hinic3_dev_configure, .dev_infos_get = hinic3_dev_infos_get, @@ -3381,6 +3470,9 @@ static const struct eth_dev_ops hinic3_pmd_ops = { .mac_addr_add = hinic3_mac_addr_add, .set_mc_addr_list = hinic3_set_mc_addr_list, .flow_ops_get = hinic3_dev_filter_ctrl, + .fec_get_capability = hinic3_fec_capability_get, + .fec_get = hinic3_fec_get, + .fec_set = hinic3_fec_set, }; static const struct eth_dev_ops hinic3_pmd_vf_ops = { diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h index 6e21672a4d..c1bba21486 100644 --- a/drivers/net/hinic3/hinic3_ethdev.h +++ b/drivers/net/hinic3/hinic3_ethdev.h @@ -152,6 +152,7 @@ struct hinic3_nic_dev { struct hinic3_nic_cmdq_ops *cmdq_ops; struct hinic3_nic_rx_ops *rx_ops; struct hinic3_nic_tx_ops *tx_ops; + uint32_t fec_mode; /**< Current FEC mode for ethdev. */ }; -- 2.33.0

