/
phprus
/
github_dpdk
Обзор
Документация
Войти
/
phprus
/
github_dpdk
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
drivers/net/sxe2/sxe2_ethdev.c
2 361 строка
63 KB
Jie Liu
net/sxe2: support private dump info
30 июн 2026, 17:11
30 июн 2026, 17:11
9e19f8d
Код
Авторство
О чём код?
/* SPDX-License-Identifier: BSD-3-Clause * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd. */ #include <rte_string_fns.h> #include <ethdev_pci.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <rte_tailq.h> #include <rte_version.h> #include <bus_pci_driver.h> #include <dev_driver.h> #include <ethdev_driver.h> #include <rte_ethdev.h> #include <rte_alarm.h> #include <rte_dev_info.h> #include <rte_pci.h> #include <rte_mbuf_dyn.h> #include <rte_cycles.h> #include <rte_eal_paging.h> #include "sxe2_ethdev.h" #include "sxe2_irq.h" #include "sxe2_drv_cmd.h" #include "sxe2_cmd_chnl.h" #include "sxe2_tx.h" #include "sxe2_rx.h" #include "sxe2_txrx.h" #include "sxe2_mac.h" #include "sxe2_common.h" #include "sxe2_common_log.h" #include "sxe2_mp.h" #include "sxe2_flow.h" #include "sxe2_stats.h" #include "sxe2_host_regs.h" #include "sxe2_switchdev.h" #include "sxe2_ioctl_chnl_func.h" #include "sxe2_dump.h" #include "sxe2_ethdev_repr.h" #include "sxe2vf_regs.h" #include "sxe2_msg.h" #define SXE2_PCI_VENDOR_ID_1 0x1ff2 #define SXE2_PCI_DEVICE_ID_PF_1 0x10b1 #define SXE2_PCI_DEVICE_ID_VF_1 0x10b #define SXE2_PCI_VENDOR_ID_2 0x1d94 #define SXE2_PCI_DEVICE_ID_PF_2 0x1260 #define SXE2_PCI_DEVICE_ID_VF_2 0x126f #define SXE2_PCI_DEVICE_ID_PF_3 0x10b3 #define SXE2_PCI_DEVICE_ID_VF_3 0x10b4 #define SXE2_PCI_VENDOR_ID_206F 0x206f static const struct rte_pci_id pci_id_sxe2_tbl[] = { { RTE_PCI_DEVICE(SXE2_PCI_VENDOR_ID_1, SXE2_PCI_DEVICE_ID_PF_1)}, { RTE_PCI_DEVICE(SXE2_PCI_VENDOR_ID_1, SXE2_PCI_DEVICE_ID_VF_1)}, { RTE_PCI_DEVICE(SXE2_PCI_VENDOR_ID_2, SXE2_PCI_DEVICE_ID_PF_2)}, { RTE_PCI_DEVICE(SXE2_PCI_VENDOR_ID_2, SXE2_PCI_DEVICE_ID_VF_2)}, { RTE_PCI_DEVICE(SXE2_PCI_VENDOR_ID_1, SXE2_PCI_DEVICE_ID_PF_3)}, { RTE_PCI_DEVICE(SXE2_PCI_VENDOR_ID_1, SXE2_PCI_DEVICE_ID_VF_3)}, { RTE_PCI_DEVICE(SXE2_PCI_VENDOR_ID_206F, SXE2_PCI_DEVICE_ID_PF_1)}, { RTE_PCI_DEVICE(SXE2_PCI_VENDOR_ID_206F, SXE2_PCI_DEVICE_ID_VF_1)}, { .vendor_id = 0, }, }; #define SXE2_TXSCH_NODE_ADJ_LVL_MAX 3 #define SXE2_DEVARG_FLOW_DUP_PATTERN_MODE "flow-duplicate-pattern" #define SXE2_DEVARG_FUNC_FLOW_DIRCT "function-flow-direct" #define SXE2_DEVARG_FNAV_STAT_TYPE "fnav-stat-type" #define SXE2_DEVARG_NO_SCHED_MODE "no-sched-mode" #define SXE2_DEVARG_SCHED_LAYER_MODE "sched-layer-mode" #define SXE2_DEVARG_RX_LOW_LATENCY "rx-low-latency" static struct sxe2_pci_map_addr_info sxe2_net_map_addr_info_pf[SXE2_PCI_MAP_RES_MAX_COUNT] = { [SXE2_PCI_MAP_RES_INVALID] = {.addr_base = 0, .bar_idx = 0, .reg_width = 0}, [SXE2_PCI_MAP_RES_DOORBELL_TX] = {.addr_base = SXE2_TXQ_LEGACY_DBLL(0), .bar_idx = 0, .reg_width = 4}, [SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL] = {.addr_base = SXE2_RXQ_TAIL(0), .bar_idx = 0, .reg_width = 4}, [SXE2_PCI_MAP_RES_IRQ_DYN] = {.addr_base = SXE2_VF_DYN_CTL(0), .bar_idx = 0, .reg_width = 4}, [SXE2_PCI_MAP_RES_IRQ_ITR] = {.addr_base = SXE2_VF_INT_ITR(0, 0), .bar_idx = 0, .reg_width = 4}, [SXE2_PCI_MAP_RES_IRQ_MSIX] = {.addr_base = SXE2_BAR4_MSIX_CTL(0), .bar_idx = 4, .reg_width = 10}, }; static struct sxe2_pci_map_addr_info sxe2_net_map_addr_info_vf[SXE2_PCI_MAP_RES_MAX_COUNT] = { [SXE2_PCI_MAP_RES_INVALID] = {.addr_base = 0, .bar_idx = 0, .reg_width = 0}, [SXE2_PCI_MAP_RES_DOORBELL_TX] = {.addr_base = SXE2VF_TXQ_TAIL(0), .bar_idx = 0, .reg_width = 4}, [SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL] = {.addr_base = SXE2VF_RXQ_TAIL(0), .bar_idx = 0, .reg_width = 4}, [SXE2_PCI_MAP_RES_IRQ_DYN] = {.addr_base = SXE2VF_VF_DYN_CTL(0), .bar_idx = 0, .reg_width = 4}, [SXE2_PCI_MAP_RES_IRQ_ITR] = {.addr_base = SXE2VF_VF_INT_ITR(0, 0), .bar_idx = 0, .reg_width = 4}, [SXE2_PCI_MAP_RES_IRQ_MSIX] = {.addr_base = SXE2VF_BAR4_MSIX_CTL(0), .bar_idx = 4, .reg_width = 0x10}, }; static int32_t sxe2_dev_configure(struct rte_eth_dev *dev); static int32_t sxe2_dev_start(struct rte_eth_dev *dev); static int32_t sxe2_dev_stop(struct rte_eth_dev *dev); static int32_t sxe2_dev_close(struct rte_eth_dev *dev); static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info); static const uint32_t *sxe2_buffer_split_supported_hdr_ptypes_get(struct rte_eth_dev *dev __rte_unused, size_t *no_of_elements __rte_unused); static int32_t sxe2_udp_tunnel_port_add(struct rte_eth_dev *dev, struct rte_eth_udp_tunnel *tunnel_udp); static int32_t sxe2_udp_tunnel_port_del(struct rte_eth_dev *dev, struct rte_eth_udp_tunnel *tunnel_udp); static int32_t sxe2_fw_version_string_get(struct rte_eth_dev *dev, char *fw_version, size_t fw_size); static int32_t sxe2_get_module_info(struct rte_eth_dev *dev, struct rte_eth_dev_module_info *info); static int32_t sxe2_get_module_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *info); static const struct eth_dev_ops sxe2_eth_dev_ops = { .dev_configure = sxe2_dev_configure, .dev_start = sxe2_dev_start, .dev_stop = sxe2_dev_stop, .dev_close = sxe2_dev_close, .dev_infos_get = sxe2_dev_infos_get, .dev_supported_ptypes_get = sxe2_dev_supported_ptypes_get, .link_update = sxe2_link_update, .rx_queue_start = sxe2_rx_queue_start, .rx_queue_stop = sxe2_rx_queue_stop, .tx_queue_start = sxe2_tx_queue_start, .tx_queue_stop = sxe2_tx_queue_stop, .rx_queue_setup = sxe2_rx_queue_setup, .rx_queue_release = sxe2_rx_queue_release, .tx_queue_setup = sxe2_tx_queue_setup, .tx_queue_release = sxe2_tx_queue_release, .rx_queue_intr_enable = sxe2_rx_queue_intr_enable, .rx_queue_intr_disable = sxe2_rx_queue_intr_disable, .rxq_info_get = sxe2_rx_queue_info_get, .txq_info_get = sxe2_tx_queue_info_get, .rx_burst_mode_get = sxe2_rx_burst_mode_get, .tx_burst_mode_get = sxe2_tx_burst_mode_get, .tx_done_cleanup = sxe2_tx_done_cleanup, .promiscuous_enable = sxe2_promisc_enable, .promiscuous_disable = sxe2_promisc_disable, .allmulticast_enable = sxe2_allmulti_enable, .allmulticast_disable = sxe2_allmulti_disable, .mac_addr_add = sxe2_mac_addr_add, .mac_addr_remove = sxe2_mac_addr_del, .mac_addr_set = sxe2_mac_addr_set, .set_mc_addr_list = sxe2_set_mc_addr_list, .mtu_set = sxe2_mtu_set, .buffer_split_supported_hdr_ptypes_get = sxe2_buffer_split_supported_hdr_ptypes_get, .vlan_filter_set = sxe2_dev_vlan_filter_set, .vlan_offload_set = sxe2_dev_vlan_offload_set, .reta_update = sxe2_dev_rss_reta_update, .reta_query = sxe2_dev_rss_reta_query, .rss_hash_update = sxe2_dev_rss_hash_update, .rss_hash_conf_get = sxe2_dev_rss_hash_conf_get, .udp_tunnel_port_add = sxe2_udp_tunnel_port_add, .udp_tunnel_port_del = sxe2_udp_tunnel_port_del, .flow_ops_get = sxe2_flow_ops_get, .tm_ops_get = sxe2_tm_ops_get, .stats_get = sxe2_stats_info_get, .stats_reset = sxe2_stats_info_reset, .xstats_get = sxe2_xstats_info_get, .xstats_get_names = sxe2_xstats_names_get, .xstats_reset = sxe2_stats_info_reset, .queue_stats_mapping_set = sxe2_queue_stats_mapping_set, .fw_version_get = sxe2_fw_version_string_get, .get_monitor_addr = sxe2_get_monitor_addr, .get_module_info = sxe2_get_module_info, .get_module_eeprom = sxe2_get_module_eeprom, .eth_dev_priv_dump = sxe2_eth_dev_priv_dump, }; static int32_t sxe2_dev_configure(struct rte_eth_dev *dev) { int32_t ret = 0; PMD_INIT_FUNC_TRACE(); if (dev->data->dev_conf.rxmode.mq_mode & RTE_ETH_MQ_RX_RSS_FLAG) dev->data->dev_conf.rxmode.offloads |= RTE_ETH_RX_OFFLOAD_RSS_HASH; ret = sxe2_vlan_default_cfg(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to init vlan, ret=%d", ret); goto end; } ret = sxe2_rss_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to init rss, ret=%d", ret); goto end; } end: return ret; } static int32_t sxe2_dev_stop(struct rte_eth_dev *dev) { int32_t ret = 0; struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); PMD_INIT_FUNC_TRACE(); if (adapter->started == 0) goto l_end; sxe2_rxq_intr_disable(dev); sxe2_txqs_all_stop(dev); sxe2_rxqs_all_stop(dev); (void)sxe2_filter_rule_stop(dev); dev->data->dev_started = 0; adapter->started = 0; l_end: return ret; } static int32_t sxe2_dev_start(struct rte_eth_dev *dev) { int32_t ret = 0; struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); PMD_INIT_FUNC_TRACE(); ret = sxe2_flow_init_udp_tunnel_port(dev); if (ret) { PMD_LOG_ERR(DRV, "Failed to init udp tunnel port, ret: %d.", ret); goto l_end; } ret = sxe2_queues_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to init queues."); goto l_end; } sxe2_rx_mode_func_set(dev); sxe2_tx_mode_func_set(dev); ret = sxe2_link_update_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to initialize link update, ret:%d", ret); goto l_end; } ret = sxe2_filter_rule_start(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to add all mc addr to fw."); goto l_end; } ret = sxe2_rxq_intr_enable(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to enable rx queue intr"); goto l_rxq_intr_err; } ret = sxe2_queues_start(dev); if (ret) { PMD_LOG_ERR(INIT, "enable queues failed"); goto l_start_queues_err; } dev->data->dev_started = 1; adapter->started = 1; goto l_end; l_start_queues_err: (void)sxe2_rxq_intr_disable(dev); l_rxq_intr_err: (void)sxe2_filter_rule_stop(dev); l_end: return ret; } static int32_t sxe2_sfp_type_get(struct sxe2_adapter *adapter, uint8_t *type) { int32_t ret = -1; struct sxe2_sfp_read_info sfp_info; memset(&sfp_info, 0, sizeof(sfp_info)); sfp_info.bus_addr = SXE2_SFP_E2P_I2C_7BIT_ADDR0; sfp_info.len = 1; sfp_info.data = type; sfp_info.offset = 0; sfp_info.page_cnt = 0; sfp_info.is_qsfp = false; ret = sxe2_drv_sfp_eeprom_read(adapter, &sfp_info); if (ret) goto l_end; ret = 0; PMD_LOG_INFO(DRV, "Get sfp type success, type=%u", *type); l_end: return ret; } static int32_t sxe2_sfp_module_info_get(struct sxe2_adapter *adapter, struct rte_eth_dev_module_info *info) { int32_t ret = -1; bool page_swap = false; uint8_t sff8472_rev = 0; uint8_t addr_mode = 0; struct sxe2_sfp_read_info sfp_info; memset(&sfp_info, 0, sizeof(sfp_info)); sfp_info.bus_addr = SXE2_SFP_E2P_I2C_7BIT_ADDR0; sfp_info.is_qsfp = false; sfp_info.len = 1; sfp_info.data = &sff8472_rev; sfp_info.offset = SXE2_MODULE_SFF_8472_COMP; sfp_info.page_cnt = 0; ret = sxe2_drv_sfp_eeprom_read(adapter, &sfp_info); if (ret) { ret = -EIO; PMD_LOG_ERR(DRV, "Failed to read 8472 protocol, ret=%d", ret); goto l_end; } sfp_info.data = &addr_mode; sfp_info.offset = SXE2_MODULE_SFF_8472_SWAP; ret = sxe2_drv_sfp_eeprom_read(adapter, &sfp_info); if (ret) { ret = -EIO; PMD_LOG_ERR(DRV, "Failed to read A2 page, ret=%d", ret); goto l_end; } if (addr_mode & SXE2_MODULE_SFF_ADDR_MODE) { PMD_LOG_ERR(DRV, "address change required to access page 0xA2, " "but not supported. please report the module " "type to the driver maintainers."); page_swap = true; } PMD_LOG_INFO(DRV, "Read sfp module info, sff_8472=%u, a2_page=%u, swap_page=%d", sff8472_rev, addr_mode, page_swap); if (sff8472_rev == SXE2_MODULE_SFF_8472_UNSUP || page_swap || !(addr_mode & SXE2_MODULE_SFF_DDM_IMPLEMENTED)) { info->type = SXE2_MODULE_SFF_8079; info->eeprom_len = SXE2_MODULE_SFF_8079_LEN; } else { info->type = SXE2_MODULE_SFF_8472; info->eeprom_len = SXE2_MODULE_SFF_8472_LEN; } ret = 0; l_end: return ret; } static int32_t sxe2_qsfp_module_info_get(struct sxe2_adapter *adapter, struct rte_eth_dev_module_info *info) { int32_t ret = -1; uint8_t sff8636_rev = 0; struct sxe2_sfp_read_info sfp_info; memset(&sfp_info, 0, sizeof(sfp_info)); sfp_info.bus_addr = SXE2_SFP_E2P_I2C_7BIT_ADDR0; sfp_info.is_qsfp = true; sfp_info.len = 1; sfp_info.data = &sff8636_rev; sfp_info.offset = SXE2_MODULE_REVISION_ADDR; sfp_info.page_cnt = 0; ret = sxe2_drv_sfp_eeprom_read(adapter, &sfp_info); if (ret) { ret = -EIO; PMD_LOG_ERR(DRV, "Failed to read 8636 protocol, ret=%d", ret); goto l_end; } if (sff8636_rev > 0x02) { info->type = SXE2_MODULE_SFF_8636; info->eeprom_len = SXE2_MODULE_SFF_8636_MAX_LEN; } else { info->type = SXE2_MODULE_SFF_8436; info->eeprom_len = SXE2_MODULE_SFF_8436_MAX_LEN; } l_end: return ret; } static int32_t sxe2_get_module_info(struct rte_eth_dev *dev, struct rte_eth_dev_module_info *info) { int32_t ret = -1; uint8_t type = 0; struct sxe2_adapter *adapter = dev->data->dev_private; ret = sxe2_sfp_type_get(adapter, &type); if (ret) { ret = -EIO; PMD_LOG_ERR(DRV, "Failed to read sfp type, ret=%d", ret); goto l_end; } switch (type) { case SXE2_MODULE_SFF_SFP_TYPE: ret = sxe2_sfp_module_info_get(adapter, info); if (ret) goto l_end; break; case SXE2_MODULE_TYPE_QSFP_PLUS: case SXE2_MODULE_TYPE_QSFP28: ret = sxe2_qsfp_module_info_get(adapter, info); if (ret) goto l_end; break; default: ret = -ENXIO; PMD_LOG_ERR(DRV, "Invalid sfp type, type=%d.", type); goto l_end; } PMD_LOG_INFO(DRV, "sfp eeprom type=%x, eeprom len=%d.", info->type, info->eeprom_len); l_end: return ret; } static int32_t sxe2_get_sfp_eeprom(struct sxe2_adapter *adapter, struct sxe2_sfp_read_info *sfp_info) { int32_t ret = -1; uint16_t ori_len = sfp_info->len; uint16_t ori_offset = sfp_info->offset; if ((ori_len + ori_offset) > SXE2_SFP_EEP_LEN_MAX) { sfp_info->len = (uint16_t)(SXE2_SFP_EEP_LEN_MAX - ori_offset); ret = sxe2_drv_sfp_eeprom_read(adapter, sfp_info); if (ret) goto l_end; sfp_info->bus_addr = SXE2_SFP_E2P_I2C_7BIT_ADDR1; sfp_info->len = (uint16_t)(ori_len - (SXE2_SFP_EEP_LEN_MAX - ori_offset)); sfp_info->data = (uint8_t *)(sfp_info->data) + (SXE2_SFP_EEP_LEN_MAX - ori_offset); sfp_info->offset = 0; sfp_info->page_cnt = 0; ret = sxe2_drv_sfp_eeprom_read(adapter, sfp_info); } else { ret = sxe2_drv_sfp_eeprom_read(adapter, sfp_info); } l_end: if (ret) PMD_LOG_ERR(DRV, "Failed to read sfp."); return ret; } static int32_t sxe2_get_qsfp_eeprom(struct sxe2_adapter *adapter, struct sxe2_sfp_read_info *sfp_info) { int32_t ret = -1; uint16_t ori_len = sfp_info->len; uint16_t ori_offset = sfp_info->offset; uint16_t read_len = 0; uint16_t remain_len = 0; if ((ori_len + ori_offset) > SXE2_SFP_EEP_LEN_MAX) { sfp_info->len = (uint16_t)(SXE2_SFP_EEP_LEN_MAX - ori_offset); ret = sxe2_drv_sfp_eeprom_read(adapter, sfp_info); if (ret) goto l_end; do { read_len = read_len + sfp_info->len; sfp_info->data = (uint8_t *)(sfp_info->data) + sfp_info->len; sfp_info->offset = SXE2_QSFP_PAGE_OFST_START; sfp_info->page_cnt++; remain_len = (uint16_t)(ori_len - read_len); sfp_info->len = (remain_len > SXE2_QSFP_PAGE_OFST_START) ? SXE2_QSFP_PAGE_OFST_START : remain_len; ret = sxe2_drv_sfp_eeprom_read(adapter, sfp_info); if (ret) goto l_end; } while (remain_len > SXE2_QSFP_PAGE_OFST_START); } else { ret = sxe2_drv_sfp_eeprom_read(adapter, sfp_info); } l_end: if (ret) PMD_LOG_ERR(DRV, "Failed to read sfp."); return ret; } static int32_t sxe2_get_module_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *info) { int32_t ret = -1; uint8_t type = 0; struct sxe2_adapter *adapter = dev->data->dev_private; struct sxe2_sfp_read_info sfp_info; memset(&sfp_info, 0, sizeof(sfp_info)); if (!info || !info->length || !info->data || info->offset >= SXE2_SFP_EEP_LEN_MAX) { ret = -EINVAL; goto l_end; } PMD_LOG_INFO(DRV, "Dump sfp eeprom info offset=0x%x, len=0x%x.", info->offset, info->length); ret = sxe2_sfp_type_get(adapter, &type); if (ret) { ret = -EIO; PMD_LOG_ERR(DRV, "Failed to read sfp type, ret=%d", ret); goto l_end; } sfp_info.bus_addr = SXE2_SFP_E2P_I2C_7BIT_ADDR0; sfp_info.len = info->length; sfp_info.data = info->data; sfp_info.offset = info->offset; sfp_info.page_cnt = 0; switch (type) { case SXE2_MODULE_SFF_SFP_TYPE: if (info->length > SXE2_SFP_EEP_LEN_MAX * 2) { ret = -EINVAL; PMD_LOG_ERR(DRV, "sfp read size[%u] > eeprom max size[%d], ret=%d", info->length, SXE2_SFP_EEP_LEN_MAX * 2, ret); goto l_end; } sfp_info.is_qsfp = false; ret = sxe2_get_sfp_eeprom(adapter, &sfp_info); if (ret) goto l_end; break; case SXE2_MODULE_TYPE_QSFP_PLUS: case SXE2_MODULE_TYPE_QSFP28: if (info->length > SXE2_MODULE_SFF_8636_MAX_LEN) { ret = -EINVAL; PMD_LOG_ERR(DRV, "sfp read size[%u] > eeprom max size[%d], ret=%d", info->length, SXE2_SFP_EEP_LEN_MAX * 2, ret); goto l_end; } sfp_info.is_qsfp = true; ret = sxe2_get_qsfp_eeprom(adapter, &sfp_info); if (ret) goto l_end; break; default: ret = -ENXIO; PMD_LOG_ERR(DRV, "Invalid sfp type, type=%d.", type); goto l_end; } l_end: return ret; } static enum sxe2_udp_tunnel_protocol sxe2_udp_tunnel_type_rte_to_sxe2(enum rte_eth_tunnel_type rte_type) { static enum sxe2_udp_tunnel_protocol sxe2_udp_proto_map[RTE_ETH_TUNNEL_TYPE_MAX] = { [RTE_ETH_TUNNEL_TYPE_NONE] = SXE2_UDP_TUNNEL_MAX, [RTE_ETH_TUNNEL_TYPE_VXLAN] = SXE2_UDP_TUNNEL_PROTOCOL_VXLAN, [RTE_ETH_TUNNEL_TYPE_GENEVE] = SXE2_UDP_TUNNEL_PROTOCOL_GENEVE, [RTE_ETH_TUNNEL_TYPE_TEREDO] = SXE2_UDP_TUNNEL_PROTOCOL_TEREDO, [RTE_ETH_TUNNEL_TYPE_NVGRE] = SXE2_UDP_TUNNEL_PROTOCOL_NVGRE, [RTE_ETH_TUNNEL_TYPE_IP_IN_GRE] = SXE2_UDP_TUNNEL_MAX, [RTE_ETH_L2_TUNNEL_TYPE_E_TAG] = SXE2_UDP_TUNNEL_MAX, [RTE_ETH_TUNNEL_TYPE_VXLAN_GPE] = SXE2_UDP_TUNNEL_PROTOCOL_VXLAN_GPE, [RTE_ETH_TUNNEL_TYPE_ECPRI] = SXE2_UDP_TUNNEL_PROTOCOL_ECPRI }; if (rte_type >= RTE_ETH_TUNNEL_TYPE_MAX) { PMD_LOG_ERR(DRV, "Invalid rte_eth_tunnel_type %d!", rte_type); rte_type = RTE_ETH_TUNNEL_TYPE_NONE; } return sxe2_udp_proto_map[rte_type]; } int32_t sxe2_udp_tunnel_port_add_common(struct sxe2_adapter *ad, enum sxe2_udp_tunnel_protocol tunnel_proto, uint16_t udp_port) { struct sxe2_udp_tunnel_cfg *tunnel_config; int32_t ret = -1; rte_spinlock_lock(&ad->udp_tunnel_ctx.lock); tunnel_config = &ad->udp_tunnel_ctx.tunnel_conf[tunnel_proto]; if (tunnel_config->dev_status == SXE2_UDP_TUNNEL_ENABLE) { if (udp_port == tunnel_config->dev_port && tunnel_config->dev_ref_cnt < 0xFFFFU) { tunnel_config->dev_ref_cnt++; ret = 0; goto l_unlock_end; } else { PMD_LOG_ERR(DRV, "Adding multiple ports to the same protocol " "is not supported!"); ret = -EINVAL; goto l_unlock_end; } } else { ret = sxe2_drv_udp_tunnel_add(ad, tunnel_proto, udp_port); if (ret != 0) goto l_unlock_end; tunnel_config->protocol = tunnel_proto; tunnel_config->dev_port = udp_port; tunnel_config->dev_status = SXE2_UDP_TUNNEL_ENABLE; tunnel_config->dev_ref_cnt++; } l_unlock_end: rte_spinlock_unlock(&ad->udp_tunnel_ctx.lock); return ret; } int32_t sxe2_udp_tunnel_port_del_common(struct sxe2_adapter *ad, enum sxe2_udp_tunnel_protocol tunnel_proto, uint16_t udp_port) { struct sxe2_udp_tunnel_cfg *tunnel_config; int32_t ret = -1; rte_spinlock_lock(&ad->udp_tunnel_ctx.lock); tunnel_config = &ad->udp_tunnel_ctx.tunnel_conf[tunnel_proto]; if (tunnel_config->dev_status == SXE2_UDP_TUNNEL_ENABLE && udp_port == tunnel_config->dev_port) { if (tunnel_config->dev_ref_cnt > 1) { tunnel_config->dev_ref_cnt--; ret = 0; goto l_unlock_end; } else { ret = sxe2_drv_udp_tunnel_del(ad, tunnel_proto, udp_port); if (ret != 0) goto l_unlock_end; tunnel_config->dev_status = SXE2_UDP_TUNNEL_DISABLE; tunnel_config->dev_ref_cnt = 0; } goto l_unlock_end; } ret = -EINVAL; l_unlock_end: rte_spinlock_unlock(&ad->udp_tunnel_ctx.lock); return ret; } static int32_t sxe2_udp_tunnel_port_clear(struct rte_eth_dev *dev) { struct sxe2_adapter *ad = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); struct sxe2_udp_tunnel_cfg *tunnel_config; int32_t ret = 0; uint16_t tunnel_proto = 0; rte_spinlock_lock(&ad->udp_tunnel_ctx.lock); for (tunnel_proto = 0; tunnel_proto < SXE2_UDP_TUNNEL_MAX; tunnel_proto++) { tunnel_config = &ad->udp_tunnel_ctx.tunnel_conf[tunnel_proto]; if (tunnel_config->dev_status == SXE2_UDP_TUNNEL_ENABLE) { ret = sxe2_drv_udp_tunnel_del(ad, tunnel_config->protocol, tunnel_config->dev_port); if (ret) { PMD_LOG_ERR(DRV, "Failed to delete udp tunnel port %d, proto %d", tunnel_config->dev_port, tunnel_config->protocol); goto l_unlock_end; } tunnel_config->dev_status = SXE2_UDP_TUNNEL_DISABLE; tunnel_config->dev_ref_cnt = 0; } } l_unlock_end: rte_spinlock_unlock(&ad->udp_tunnel_ctx.lock); return ret; } static int32_t sxe2_udp_tunnel_port_add(struct rte_eth_dev *dev, struct rte_eth_udp_tunnel *tunnel_udp) { int32_t ret = 0; enum sxe2_udp_tunnel_protocol tunnel_proto; struct sxe2_adapter *ad = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); if (tunnel_udp->udp_port == 0) { ret = -EINVAL; goto l_end; } tunnel_proto = sxe2_udp_tunnel_type_rte_to_sxe2(tunnel_udp->prot_type); if (tunnel_proto >= SXE2_UDP_TUNNEL_MAX) { ret = -EINVAL; goto l_end; } ret = sxe2_udp_tunnel_port_add_common(ad, tunnel_proto, tunnel_udp->udp_port); if (ret) { PMD_LOG_ERR(DRV, "Add tunnel port failed, ret = %d", ret); goto l_end; } l_end: return ret; } static int32_t sxe2_udp_tunnel_port_del(struct rte_eth_dev *dev, struct rte_eth_udp_tunnel *tunnel_udp) { int32_t ret = 0; enum sxe2_udp_tunnel_protocol tunnel_proto; struct sxe2_adapter *ad = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); tunnel_proto = sxe2_udp_tunnel_type_rte_to_sxe2(tunnel_udp->prot_type); if (tunnel_proto >= SXE2_UDP_TUNNEL_MAX) { ret = -EINVAL; goto l_end; } ret = sxe2_udp_tunnel_port_del_common(ad, tunnel_proto, tunnel_udp->udp_port); if (ret) { PMD_LOG_ERR(DRV, "Delete tunnel port failed, ret = %d", ret); goto l_end; } l_end: return ret; } static int32_t sxe2_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) { struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); struct sxe2_vsi *vsi = adapter->vsi_ctxt.main_vsi; dev_info->max_rx_queues = vsi->rxqs.q_cnt; dev_info->max_tx_queues = vsi->txqs.q_cnt; dev_info->min_rx_bufsize = SXE2_MIN_BUF_SIZE; dev_info->max_rx_pktlen = SXE2_FRAME_SIZE_MAX; dev_info->max_lro_pkt_size = SXE2_FRAME_SIZE_MAX * SXE2_RX_LRO_DESC_MAX_NUM; dev_info->max_mtu = dev_info->max_rx_pktlen - SXE2_ETH_OVERHEAD; dev_info->min_mtu = RTE_ETHER_MIN_MTU; dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_VLAN_STRIP | RTE_ETH_RX_OFFLOAD_KEEP_CRC | RTE_ETH_RX_OFFLOAD_SCATTER | RTE_ETH_RX_OFFLOAD_IPV4_CKSUM | RTE_ETH_RX_OFFLOAD_UDP_CKSUM | RTE_ETH_RX_OFFLOAD_TCP_CKSUM | RTE_ETH_RX_OFFLOAD_SCTP_CKSUM | RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM | RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT | #ifndef RTE_LIBRTE_SXE2_16BYTE_RX_DESC RTE_ETH_RX_OFFLOAD_QINQ_STRIP | #endif RTE_ETH_RX_OFFLOAD_VLAN_EXTEND | RTE_ETH_RX_OFFLOAD_TCP_LRO; dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_VLAN_INSERT | RTE_ETH_TX_OFFLOAD_QINQ_INSERT | RTE_ETH_TX_OFFLOAD_MULTI_SEGS | RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE | RTE_ETH_TX_OFFLOAD_IPV4_CKSUM | RTE_ETH_TX_OFFLOAD_UDP_CKSUM | RTE_ETH_TX_OFFLOAD_TCP_CKSUM | RTE_ETH_TX_OFFLOAD_SCTP_CKSUM | RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM | RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM | RTE_ETH_TX_OFFLOAD_TCP_TSO | RTE_ETH_TX_OFFLOAD_UDP_TSO | RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO | RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO | RTE_ETH_TX_OFFLOAD_IPIP_TNL_TSO | RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO; dev_info->rx_queue_offload_capa = RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT | RTE_ETH_RX_OFFLOAD_KEEP_CRC | RTE_ETH_RX_OFFLOAD_SCATTER | RTE_ETH_RX_OFFLOAD_IPV4_CKSUM | RTE_ETH_RX_OFFLOAD_UDP_CKSUM | RTE_ETH_RX_OFFLOAD_TCP_CKSUM | RTE_ETH_RX_OFFLOAD_SCTP_CKSUM | RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM | RTE_ETH_RX_OFFLOAD_TCP_LRO; dev_info->tx_queue_offload_capa = RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE | RTE_ETH_TX_OFFLOAD_TCP_TSO | RTE_ETH_TX_OFFLOAD_UDP_TSO | RTE_ETH_TX_OFFLOAD_MULTI_SEGS | RTE_ETH_TX_OFFLOAD_IPV4_CKSUM | RTE_ETH_TX_OFFLOAD_UDP_CKSUM | RTE_ETH_TX_OFFLOAD_TCP_CKSUM | RTE_ETH_TX_OFFLOAD_SCTP_CKSUM | RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM | RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM | RTE_ETH_TX_OFFLOAD_VXLAN_TNL_TSO | RTE_ETH_TX_OFFLOAD_GRE_TNL_TSO | RTE_ETH_TX_OFFLOAD_IPIP_TNL_TSO | RTE_ETH_TX_OFFLOAD_GENEVE_TNL_TSO; if (adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_PTP) dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_TIMESTAMP; if (sxe2_ipsec_supported(adapter)) { dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_SECURITY; dev_info->tx_offload_capa |= RTE_ETH_TX_OFFLOAD_SECURITY; } if (adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_RSS) { dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_RSS_HASH; dev_info->flow_type_rss_offloads |= SXE2_RSS_HF_SUPPORT_ALL; dev_info->reta_size = adapter->rss_ctxt.rss_lut_size; dev_info->hash_key_size = adapter->rss_ctxt.rss_key_size; dev_info->rss_algo_capa = RTE_ETH_HASH_ALGO_TO_CAPA(RTE_ETH_HASH_FUNCTION_DEFAULT) | RTE_ETH_HASH_ALGO_TO_CAPA(RTE_ETH_HASH_FUNCTION_TOEPLITZ) | RTE_ETH_HASH_ALGO_TO_CAPA(RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) | RTE_ETH_HASH_ALGO_TO_CAPA(RTE_ETH_HASH_FUNCTION_SIMPLE_XOR); } dev_info->default_rxconf = (struct rte_eth_rxconf) { .rx_thresh = { .pthresh = SXE2_DEFAULT_RX_PTHRESH, .hthresh = SXE2_DEFAULT_RX_HTHRESH, .wthresh = SXE2_DEFAULT_RX_WTHRESH, }, .rx_free_thresh = SXE2_DEFAULT_RX_FREE_THRESH, .rx_drop_en = 0, .offloads = 0, }; dev_info->default_txconf = (struct rte_eth_txconf) { .tx_thresh = { .pthresh = SXE2_DEFAULT_TX_PTHRESH, .hthresh = SXE2_DEFAULT_TX_HTHRESH, .wthresh = SXE2_DEFAULT_TX_WTHRESH, }, .tx_free_thresh = SXE2_DEFAULT_TX_FREE_THRESH, .tx_rs_thresh = SXE2_DEFAULT_TX_RSBIT_THRESH, .offloads = 0, }; dev_info->rx_desc_lim = (struct rte_eth_desc_lim) { .nb_max = SXE2_MAX_RING_DESC, .nb_min = SXE2_MIN_RING_DESC, .nb_align = SXE2_ALIGN, }; dev_info->tx_desc_lim = (struct rte_eth_desc_lim) { .nb_max = SXE2_MAX_RING_DESC, .nb_min = SXE2_MIN_RING_DESC, .nb_align = SXE2_ALIGN, .nb_mtu_seg_max = SXE2_TX_MTU_SEG_MAX, .nb_seg_max = SXE2_MAX_RING_DESC, }; dev_info->speed_capa = RTE_ETH_LINK_SPEED_10G | RTE_ETH_LINK_SPEED_25G | RTE_ETH_LINK_SPEED_50G | RTE_ETH_LINK_SPEED_100G; dev_info->default_rxportconf.burst_size = SXE2_RX_MAX_BURST; dev_info->default_txportconf.burst_size = SXE2_TX_MAX_BURST; dev_info->default_rxportconf.nb_queues = 1; dev_info->default_txportconf.nb_queues = 1; dev_info->default_rxportconf.ring_size = SXE2_RING_SIZE_MIN; dev_info->default_txportconf.ring_size = SXE2_RING_SIZE_MIN; dev_info->rx_seg_capa.max_nseg = SXE2_RX_MAX_NSEG; dev_info->rx_seg_capa.multi_pools = true; dev_info->rx_seg_capa.offset_allowed = false; dev_info->rx_seg_capa.offset_align_log2 = false; return 0; } static const uint32_t * sxe2_buffer_split_supported_hdr_ptypes_get(struct rte_eth_dev *dev __rte_unused, size_t *no_of_elements __rte_unused) { static const uint32_t ptypes[] = { RTE_PTYPE_L2_ETHER, RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN, RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L4_UDP, RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L4_TCP, RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L4_SCTP, RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN, RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L4_UDP, RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L4_TCP, RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L4_SCTP, RTE_PTYPE_TUNNEL_GRENAT, RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER, RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN, RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN, RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_UDP, RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_TCP, RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_SCTP, RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_UDP, RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_TCP, RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_SCTP, RTE_PTYPE_UNKNOWN }; return ptypes; } static int32_t sxe2_parse_fnav_stat_type(const char *key, const char *value, void *args) { int32_t ret = -EINVAL; uint8_t *num = (uint8_t *)args; unsigned long fnav_stat_type; char *endptr = NULL; if (value == NULL || args == NULL) { ret = 0; goto l_end; } errno = 0; fnav_stat_type = strtoul(value, &endptr, 10); if (errno != 0 || endptr == value || *endptr != '\0') { PMD_LOG_WARN(INIT, "%s: \"%s\" is not a valid int value.", key, value); goto l_end; } if (fnav_stat_type > SXE2_FNAV_STAT_ENA_ALL || fnav_stat_type == SXE2_FNAV_STAT_ENA_NONE) { PMD_LOG_ERR(INIT, "%s: \"%s\" out of range [1-3].", key, value); goto l_end; } *num = (uint8_t)fnav_stat_type; ret = 0; l_end: return ret; } static int32_t sxe2_parse_sched_layer_mode(const char *key, const char *value, void *args) { int32_t ret = -EINVAL; uint8_t *num = (uint8_t *)args; unsigned long sched_layer_mode; char *endptr = NULL; if (value == NULL || args == NULL) { ret = 0; goto l_end; } errno = 0; sched_layer_mode = strtoul(value, &endptr, 10); if (errno != 0 || endptr == value || *endptr != '\0') { PMD_LOG_WARN(INIT, "%s: \"%s\" is not a valid int value.", key, value); goto l_end; } if (sched_layer_mode > SXE2_TXSCH_NODE_ADJ_LVL_MAX) { PMD_LOG_ERR(INIT, "%s: \"%s\" > 3.", key, value); goto l_end; } *num = (uint8_t)sched_layer_mode; ret = 0; l_end: return ret; } static int32_t sxe2_parse_flow_dup_pattern_mode(const char *key, const char *value, void *args) { uint8_t *num = (uint8_t *)args; char *end; unsigned long val; int32_t ret = -EINVAL; if (value == NULL || args == NULL) { ret = 0; goto l_end; } errno = 0; val = strtoul(value, &end, 10); if (errno != 0 || end == value || *end != '\0') { PMD_LOG_ERR(INIT, "Invalid 8-bit integer value for key %s: %s", key, value); goto l_end; } if (val >= SXE2_FLOW_SW_PATTERN_MAX) { PMD_LOG_ERR(INIT, "%s: \"%s\" out of range [0-%u].", key, value, SXE2_FLOW_SW_PATTERN_MAX - 1); goto l_end; } /* Convert user values to internal enum: * user 0 (reject) -> SXE2_FLOW_SW_PATTERN_ONLY (0) * user 1 (FIFO) -> SXE2_FLOW_SW_PATTERN_FIRST (2) * user 2 (LIFO) -> SXE2_FLOW_SW_PATTERN_LAST (1) */ static const uint8_t udc_tbl[] = { SXE2_FLOW_SW_PATTERN_ONLY, SXE2_FLOW_SW_PATTERN_FIRST, SXE2_FLOW_SW_PATTERN_LAST, }; *num = udc_tbl[val]; ret = 0; l_end: return ret; } static int32_t sxe2_parse_bool(const char *key, const char *value, void *args) { int32_t ret = -EINVAL; uint8_t *num = (uint8_t *)args; unsigned long bool_val; char *endptr = NULL; if (value == NULL || args == NULL) { ret = 0; goto l_end; } errno = 0; bool_val = strtoul(value, &endptr, 10); if (errno != 0 || endptr == value || *endptr != '\0') { PMD_LOG_WARN(INIT, "%s: \"%s\" is not a valid int value.", key, value); goto l_end; } if (bool_val != 0 && bool_val != 1) { PMD_LOG_ERR(INIT, "%s: \"%s\" out of range [0|1].", key, value); goto l_end; } *num = (uint8_t)bool_val; ret = 0; l_end: return ret; } struct sxe2_pci_map_bar_info *sxe2_dev_get_bar_info(struct sxe2_adapter *adapter, enum sxe2_pci_map_resource res_type) { struct sxe2_pci_map_context *map_ctxt = &adapter->map_ctxt; struct sxe2_pci_map_bar_info *bar_info = NULL; uint8_t bar_idx = SXE2_PCI_MAP_BAR_INVALID; uint8_t i; bar_idx = map_ctxt->addr_info[res_type].bar_idx; if (bar_idx == SXE2_PCI_MAP_BAR_INVALID) { PMD_DEV_LOG_ERR(adapter, INIT, "Invalid bar index with resource type %d", res_type); goto l_end; } for (i = 0; i < map_ctxt->bar_cnt; i++) { if (bar_idx == map_ctxt->bar_info[i].bar_idx) { bar_info = &map_ctxt->bar_info[i]; break; } } l_end: return bar_info; } void *sxe2_pci_map_addr_get(struct sxe2_adapter *adapter, enum sxe2_pci_map_resource res_type, uint16_t idx_in_func) { struct sxe2_pci_map_context *map_ctxt = &adapter->map_ctxt; struct sxe2_pci_map_segment_info *seg_info = NULL; struct sxe2_pci_map_bar_info *bar_info = NULL; void *addr = NULL; uintptr_t calc_addr = 0; uint8_t reg_width = 0; uint8_t i = 0; bar_info = sxe2_dev_get_bar_info(adapter, res_type); if (bar_info == NULL) { PMD_DEV_LOG_WARN(adapter, INIT, "Failed to get bar info, res_type=[%d]", res_type); goto l_end; } seg_info = bar_info->seg_info; reg_width = map_ctxt->addr_info[res_type].reg_width; if (reg_width == 0) { PMD_DEV_LOG_WARN(adapter, INIT, "Invalid reg width with resource type %d", res_type); goto l_end; } for (i = 0; i < bar_info->map_cnt; i++) { seg_info = &bar_info->seg_info[i]; if (res_type == seg_info->type) { calc_addr = (uintptr_t)seg_info->addr; calc_addr += (uintptr_t)seg_info->page_inner_offset; calc_addr += (uintptr_t)reg_width * (uintptr_t)idx_in_func; addr = (void *)calc_addr; goto l_end; } } l_end: return addr; } static int32_t sxe2_args_parse(struct rte_eth_dev *dev, struct sxe2_dev_kvargs_info *kvargs) { struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); int32_t ret = 0; PMD_INIT_FUNC_TRACE(); adapter->devargs.flow_dup_pattern_mode = SXE2_FLOW_SW_PATTERN_FIRST; if (kvargs == NULL) goto l_end; ret = sxe2_kvargs_process(kvargs, SXE2_DEVARG_FNAV_STAT_TYPE, &sxe2_parse_fnav_stat_type, &adapter->devargs.fnav_stat_type); if (ret) { PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse fnav stat type, ret:%d", ret); goto l_end; } ret = sxe2_kvargs_process(kvargs, SXE2_DEVARG_NO_SCHED_MODE, &sxe2_parse_bool, &adapter->devargs.no_sched_mode); if (ret) { PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse no sched mode, ret:%d", ret); goto l_end; } ret = sxe2_kvargs_process(kvargs, SXE2_DEVARG_SCHED_LAYER_MODE, &sxe2_parse_sched_layer_mode, &adapter->devargs.sched_layer_mode); if (ret) { PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse sched layer mode, ret:%d", ret); goto l_end; } ret = sxe2_kvargs_process(kvargs, SXE2_DEVARG_FLOW_DUP_PATTERN_MODE, &sxe2_parse_flow_dup_pattern_mode, &adapter->devargs.flow_dup_pattern_mode); if (ret) { PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse flow dup pattern mode, ret:%d", ret); goto l_end; } ret = sxe2_kvargs_process(kvargs, SXE2_DEVARG_FUNC_FLOW_DIRCT, &sxe2_parse_bool, &adapter->devargs.func_flow_direct_en); if (ret) { PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse function flow rule enable," "ret:%d", ret); goto l_end; } ret = sxe2_kvargs_process(kvargs, SXE2_DEVARG_RX_LOW_LATENCY, &sxe2_parse_bool, &adapter->devargs.rx_low_latency); if (ret) { PMD_DEV_LOG_ERR(adapter, INIT, "Failed to parse rx low latency, ret:%d", ret); goto l_end; } l_end: return ret; } static int32_t sxe2_eth_init(struct rte_eth_dev *dev) { int32_t ret = 0; ret = sxe2_filter_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to initialize l2 filter, ret:%d", ret); goto l_end; } ret = sxe2_link_update_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to initialize link update, ret:%d", ret); goto l_end; } ret = sxe2_mtu_set(dev, dev->data->mtu); if (ret) { PMD_LOG_ERR(INIT, "Failed to set mtu, ret=%d", ret); goto l_end; } ret = sxe2_mac_addr_init(dev); if (ret != 0) { PMD_LOG_ERR(INIT, "Failed to initialize mac address, ret:%d", ret); goto l_end; } ret = sxe2_mac_default_cfg(dev); if (ret != 0) { PMD_LOG_ERR(INIT, "Failed to configure default mac address, ret:%d", ret); goto l_err; } ret = sxe2_vlan_cfg_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to initialize vlan config, ret:%d", ret); goto l_err; } goto l_end; l_err: sxe2_mac_addr_uinit(dev); (void)sxe2_filter_uinit(dev); l_end: return ret; } void sxe2_eth_uinit(struct rte_eth_dev *dev __rte_unused) { sxe2_mac_addr_uinit(dev); (void)sxe2_filter_uinit(dev); } static void sxe2_drv_dev_caps_set(struct sxe2_adapter *adapter, struct sxe2_drv_dev_caps_resp *dev_caps) { adapter->port_idx = dev_caps->port_idx; adapter->cap_flags = 0; if (dev_caps->cap_flags & SXE2_DEV_CAPS_OFFLOAD_L2) adapter->cap_flags |= SXE2_DEV_CAPS_OFFLOAD_L2; if (dev_caps->cap_flags & SXE2_DEV_CAPS_OFFLOAD_VLAN) adapter->cap_flags |= SXE2_DEV_CAPS_OFFLOAD_VLAN; if (dev_caps->cap_flags & SXE2_DEV_CAPS_OFFLOAD_RSS) adapter->cap_flags |= SXE2_DEV_CAPS_OFFLOAD_RSS; if (dev_caps->cap_flags & SXE2_DEV_CAPS_OFFLOAD_IPSEC) adapter->cap_flags |= SXE2_DEV_CAPS_OFFLOAD_IPSEC; if (dev_caps->cap_flags & SXE2_DEV_CAPS_OFFLOAD_FNAV) adapter->cap_flags |= SXE2_DEV_CAPS_OFFLOAD_FNAV; if (dev_caps->cap_flags & SXE2_DEV_CAPS_OFFLOAD_TM) adapter->cap_flags |= SXE2_DEV_CAPS_OFFLOAD_TM; if (dev_caps->cap_flags & SXE2_DEV_CAPS_OFFLOAD_PTP) adapter->cap_flags |= SXE2_DEV_CAPS_OFFLOAD_PTP; if (dev_caps->cap_flags & SXE2_DEV_CAPS_OFFLOAD_Q_MAP) adapter->cap_flags |= SXE2_DEV_CAPS_OFFLOAD_Q_MAP; if (dev_caps->cap_flags & SXE2_DEV_CAPS_OFFLOAD_FC_STATE) adapter->cap_flags |= SXE2_DEV_CAPS_OFFLOAD_FC_STATE; } static void sxe2_sw_representor_ctx_hw_cap_set(struct sxe2_adapter *adapter, struct sxe2_drv_representor_caps *repr_caps) { adapter->repr_ctxt.nb_vf = repr_caps->cnt_repr_vf; if (adapter->repr_ctxt.nb_vf > 0) { memcpy(adapter->repr_ctxt.repr_vf_id, repr_caps->repr_vf_id, adapter->repr_ctxt.nb_vf * sizeof(struct sxe2_drv_vsi_caps)); } } static void sxe2_sw_sched_hw_cap_set(struct sxe2_adapter *adapter, struct sxe2_txsch_caps *txsch_caps) { adapter->sched_ctxt.tm_layers = txsch_caps->layer_cap; adapter->sched_ctxt.root_max_children = txsch_caps->tm_mid_node_num; adapter->sched_ctxt.prio_max = txsch_caps->prio_num; } static int32_t sxe2_func_caps_get(struct sxe2_adapter *adapter) { int32_t ret = -1; struct sxe2_drv_dev_caps_resp dev_caps = {0}; ret = sxe2_drv_dev_caps_get(adapter, &dev_caps); if (ret) goto l_end; adapter->dev_type = dev_caps.dev_type; sxe2_drv_dev_caps_set(adapter, &dev_caps); sxe2_sw_queue_ctx_hw_cap_set(adapter, &dev_caps.queue_caps); sxe2_sw_irq_ctx_hw_cap_set(adapter, &dev_caps.msix_caps); sxe2_sw_rss_ctx_hw_cap_set(adapter, &dev_caps.rss_hash_caps); sxe2_sw_vsi_ctx_hw_cap_set(adapter, &dev_caps.vsi_caps); sxe2_sw_representor_ctx_hw_cap_set(adapter, &dev_caps.repr_caps); sxe2_sw_sched_hw_cap_set(adapter, &dev_caps.txsch_caps); l_end: return ret; } static int32_t sxe2_switchdev_info_get(struct sxe2_adapter *adapter) { int32_t ret = 0; struct sxe2_switchdev_info switchdev_info = {0}; ret = sxe2_drv_switchdev_info_get(adapter, &switchdev_info); if (ret) goto l_end; if (switchdev_info.primary && switchdev_info.representor) { PMD_LOG_ERR(INIT, "device could not be both primary and representor"); ret = -ENODEV; goto l_end; } adapter->switchdev_info = switchdev_info; l_end: return ret; } static int32_t sxe2_dev_caps_get(struct sxe2_adapter *adapter) { int32_t ret = -1; ret = sxe2_func_caps_get(adapter); if (ret) { PMD_LOG_ERR(INIT, "get function caps failed, ret=%d", ret); goto l_end; } ret = sxe2_switchdev_info_get(adapter); if (ret) PMD_LOG_ERR(INIT, "get switchdev info failed, ret=%d", ret); l_end: return ret; } uint32_t sxe2_pci_map_read_reg(struct sxe2_adapter *adapter, enum sxe2_pci_map_resource res_type, uint16_t idx_in_func) { void *reg_addr; uint32_t value; reg_addr = sxe2_pci_map_addr_get(adapter, res_type, idx_in_func); if (unlikely(reg_addr == NULL)) { PMD_DEV_LOG_ERR(adapter, DRV, "reg addr:0x%p is error.", reg_addr); value = SXE2_PCI_MAP_INVALID_VAL; goto l_ret; } value = SXE2_PCI_REG_READ(reg_addr); l_ret: return value; } void sxe2_pci_map_write_reg(struct sxe2_adapter *adapter, enum sxe2_pci_map_resource res_type, uint16_t idx_in_func, uint32_t value) { void *reg_addr; reg_addr = sxe2_pci_map_addr_get(adapter, res_type, idx_in_func); if (unlikely(reg_addr == NULL)) { PMD_DEV_LOG_ERR(adapter, DRV, "reg addr:0x%p is error.", reg_addr); goto l_ret; } SXE2_PCI_REG_WRITE_WC(reg_addr, value); l_ret: return; } int32_t sxe2_dev_pci_seg_map(struct sxe2_adapter *adapter, enum sxe2_pci_map_resource res_type, uint64_t org_len, uint64_t org_offset) { struct sxe2_pci_map_bar_info *bar_info = NULL; struct sxe2_pci_map_segment_info *seg_info = NULL; void *map_addr = NULL; int32_t ret = 0; size_t page_size = 0; size_t aligned_len = 0; size_t page_inner_offset = 0; off_t aligned_offset = 0; uint8_t i = 0; if (org_len == 0) { PMD_DEV_LOG_ERR(adapter, INIT, "Invalid length, ori_len = 0"); ret = -EFAULT; goto l_end; } bar_info = sxe2_dev_get_bar_info(adapter, res_type); if (!bar_info) { PMD_LOG_ERR(INIT, "Failed to get bar info, res_type=[%d]", res_type); ret = -EFAULT; goto l_end; } seg_info = bar_info->seg_info; page_size = rte_mem_page_size(); aligned_offset = RTE_ALIGN_FLOOR(org_offset, page_size); page_inner_offset = org_offset - aligned_offset; aligned_len = RTE_ALIGN(page_inner_offset + org_len, page_size); map_addr = sxe2_drv_dev_mmap(adapter->cdev, bar_info->bar_idx, aligned_len, aligned_offset); if (!map_addr) { PMD_LOG_ERR(INIT, "Failed to mmap BAR space, type=%d, len=%" PRIu64 ", offset=%" PRIu64 ", page_size=%zu", res_type, org_len, org_offset, page_size); ret = -EFAULT; goto l_end; } for (i = 0; i < bar_info->map_cnt; i++) { if (seg_info[i].type != SXE2_PCI_MAP_RES_INVALID) continue; seg_info[i].type = res_type; seg_info[i].addr = map_addr; seg_info[i].page_inner_offset = page_inner_offset; seg_info[i].len = aligned_len; break; } if (i == bar_info->map_cnt) { PMD_LOG_ERR(INIT, "No memory to save resource, res_type=%d", res_type); ret = -ENOMEM; sxe2_drv_dev_munmap(adapter->cdev, map_addr, aligned_len); goto l_end; } l_end: return ret; } static int32_t sxe2_hw_init(struct rte_eth_dev *dev) { struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); int32_t ret = -1; PMD_INIT_FUNC_TRACE(); ret = sxe2_dev_caps_get(adapter); if (ret) PMD_LOG_ERR(INIT, "Failed to get device caps, ret=[%d]", ret); return ret; } static int32_t sxe2_sw_init(struct rte_eth_dev *dev) { int32_t ret = -1; PMD_INIT_FUNC_TRACE(); ret = sxe2_sw_irq_ctxt_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to sw irq ctxt init, ret=[%d]", ret); goto l_end; } l_end: return ret; } static void sxe2_sw_uninit(struct rte_eth_dev *dev) { sxe2_sw_irq_ctxt_uninit(dev); } int32_t sxe2_dev_pci_res_seg_map(struct sxe2_adapter *adapter, uint32_t res_type, uint32_t item_cnt, uint32_t item_base) { struct sxe2_pci_map_addr_info *addr_info = NULL; int32_t ret = 0; addr_info = &adapter->map_ctxt.addr_info[res_type]; if (!addr_info || addr_info->bar_idx == SXE2_PCI_MAP_BAR_INVALID) { PMD_DEV_LOG_ERR(adapter, INIT, "Invalid bar index with resource type %d", res_type); ret = -EFAULT; goto l_end; } ret = sxe2_dev_pci_seg_map(adapter, res_type, item_cnt * addr_info->reg_width, addr_info->addr_base + item_base * addr_info->reg_width); if (ret != 0) { PMD_DEV_LOG_ERR(adapter, INIT, "Failed to map resource, res_type=%d", res_type); goto l_end; } l_end: return ret; } void sxe2_dev_pci_seg_unmap(struct sxe2_adapter *adapter, uint32_t res_type) { struct sxe2_pci_map_bar_info *bar_info = NULL; struct sxe2_pci_map_segment_info *seg_info = NULL; uint32_t i = 0; bar_info = sxe2_dev_get_bar_info(adapter, res_type); if (bar_info == NULL) { PMD_DEV_LOG_WARN(adapter, INIT, "Failed to get bar info, res_type=[%d]", res_type); goto l_end; } seg_info = bar_info->seg_info; for (i = 0; i < bar_info->map_cnt; i++) { if (res_type == seg_info[i].type) { (void)sxe2_drv_dev_munmap(adapter->cdev, seg_info[i].addr, seg_info[i].len); memset(&seg_info[i], 0, sizeof(struct sxe2_pci_map_segment_info)); break; } } l_end: return; } static int32_t sxe2_dev_info_init(struct rte_eth_dev *dev) { struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); struct rte_pci_device *pci_dev = RTE_CLASS_TO_BUS_DEVICE(dev, *pci_dev); struct sxe2_dev_info *dev_info = &adapter->dev_info; struct sxe2_drv_dev_info_resp dev_info_resp = {0}; struct sxe2_drv_dev_fw_info_resp dev_fw_info_resp = {0}; int32_t ret = 0; dev_info->pci.bus_devid = pci_dev->addr.devid; dev_info->pci.bus_function = pci_dev->addr.function; ret = sxe2_drv_dev_info_get(adapter, &dev_info_resp); if (ret) { PMD_LOG_ERR(INIT, "Failed to get device info, ret=[%d]", ret); goto l_end; } dev_info->pci.serial_number = dev_info_resp.dsn; ret = sxe2_drv_dev_fw_info_get(adapter, &dev_fw_info_resp); if (ret) { PMD_LOG_ERR(INIT, "Failed to get device fw info, ret=[%d]", ret); goto l_end; } dev_info->fw.build_id = dev_fw_info_resp.build_id; dev_info->fw.fix_version_id = dev_fw_info_resp.fix_version_id; dev_info->fw.sub_version_id = dev_fw_info_resp.sub_version_id; dev_info->fw.main_version_id = dev_fw_info_resp.main_version_id; if (rte_is_valid_assigned_ether_addr((struct rte_ether_addr *)dev_info_resp.mac_addr)) rte_ether_addr_copy((struct rte_ether_addr *)dev_info_resp.mac_addr, (struct rte_ether_addr *)dev_info->mac.perm_addr); else rte_eth_random_addr(dev_info->mac.perm_addr); l_end: return ret; } int32_t sxe2_dev_pci_map_init(struct rte_eth_dev *dev) { struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); struct rte_pci_device *pci_dev = RTE_CLASS_TO_BUS_DEVICE(dev, *pci_dev); struct sxe2_pci_map_context *map_ctxt = &adapter->map_ctxt; struct sxe2_pci_map_bar_info *bar_info = NULL; struct sxe2_pci_map_segment_info *seg_info = NULL; uint16_t txq_cnt = adapter->q_ctxt.qp_cnt_assign; uint16_t txq_base = adapter->q_ctxt.base_idx_in_pf; uint16_t rxq_cnt = adapter->q_ctxt.qp_cnt_assign; uint16_t irq_cnt = adapter->irq_ctxt.max_cnt_hw; uint16_t irq_base = adapter->irq_ctxt.base_idx_in_func; uint16_t rxq_base = adapter->q_ctxt.base_idx_in_pf; int32_t ret = 0; PMD_INIT_FUNC_TRACE(); adapter->dev_info.dev_data = dev->data; if (!pci_dev->mem_resource[0].phys_addr) { PMD_LOG_ERR(INIT, "Physical address not scanned"); ret = -ENXIO; goto l_end; } map_ctxt->bar_cnt = 2; bar_info = rte_zmalloc(NULL, sizeof(*bar_info) * map_ctxt->bar_cnt, 0); if (!bar_info) { PMD_LOG_ERR(INIT, "Failed to alloc bar_info"); ret = -ENOMEM; goto l_end; } bar_info[0].bar_idx = 0; bar_info[0].map_cnt = SXE2_PCI_MAP_RES_MAX_COUNT; seg_info = rte_zmalloc(NULL, sizeof(*seg_info) * bar_info[0].map_cnt, 0); if (!seg_info) { PMD_LOG_ERR(INIT, "Failed to alloc seg_info"); ret = -ENOMEM; goto l_free_bar; } bar_info[0].seg_info = seg_info; bar_info[1].bar_idx = 4; bar_info[1].map_cnt = SXE2_PCI_MAP_RES_MAX_COUNT; seg_info = rte_zmalloc(NULL, sizeof(*seg_info) * bar_info[1].map_cnt, 0); if (!seg_info) { PMD_LOG_ERR(INIT, "Failed to alloc seg_info"); ret = -ENOMEM; goto l_free_seg0; } bar_info[1].seg_info = seg_info; map_ctxt->bar_info = bar_info; if (adapter->dev_type == SXE2_DEV_T_VF) map_ctxt->addr_info = sxe2_net_map_addr_info_vf; else map_ctxt->addr_info = sxe2_net_map_addr_info_pf; ret = sxe2_dev_pci_res_seg_map(adapter, SXE2_PCI_MAP_RES_DOORBELL_TX, txq_cnt, txq_base); if (ret) { PMD_LOG_ERR(INIT, "Failed to map txq doorbell addr, ret=%d", ret); goto l_free_seg1; } ret = sxe2_dev_pci_res_seg_map(adapter, SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL, rxq_cnt, rxq_base); if (ret) { PMD_LOG_ERR(INIT, "Failed to map rxq tail doorbell addr, ret=%d", ret); goto l_free_txq; } ret = sxe2_dev_pci_res_seg_map(adapter, SXE2_PCI_MAP_RES_IRQ_DYN, irq_cnt, irq_base); if (ret) { PMD_LOG_ERR(INIT, "Failed to map irq dyn addr, ret=%d", ret); goto l_free_rxq_tail; } ret = sxe2_dev_pci_res_seg_map(adapter, SXE2_PCI_MAP_RES_IRQ_ITR, irq_cnt, irq_base); if (ret) { PMD_LOG_ERR(INIT, "Failed to map irq itr addr, ret=%d", ret); goto l_free_irq_dyn; } ret = sxe2_dev_pci_res_seg_map(adapter, SXE2_PCI_MAP_RES_IRQ_MSIX, irq_cnt, irq_base); if (ret) { PMD_LOG_ERR(INIT, "Failed to map irq msix addr, ret=%d", ret); goto l_free_irq_itr; } goto l_end; l_free_irq_itr: (void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_IRQ_ITR); l_free_irq_dyn: (void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_IRQ_DYN); l_free_rxq_tail: (void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL); l_free_txq: (void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_DOORBELL_TX); l_free_seg1: if (bar_info[1].seg_info) { rte_free(bar_info[1].seg_info); bar_info[1].seg_info = NULL; } l_free_seg0: if (bar_info[0].seg_info) { rte_free(bar_info[0].seg_info); bar_info[0].seg_info = NULL; } l_free_bar: if (bar_info) { rte_free(bar_info); bar_info = NULL; } l_end: return ret; } void sxe2_dev_pci_map_uinit(struct rte_eth_dev *dev) { struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); struct sxe2_pci_map_context *map_ctxt = &adapter->map_ctxt; struct sxe2_pci_map_bar_info *bar_info = NULL; uint8_t i = 0; PMD_INIT_FUNC_TRACE(); (void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_DOORBELL_RX_TAIL); (void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_DOORBELL_TX); (void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_IRQ_DYN); (void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_IRQ_ITR); (void)sxe2_dev_pci_seg_unmap(adapter, SXE2_PCI_MAP_RES_IRQ_MSIX); if (map_ctxt != NULL && map_ctxt->bar_info != NULL) { for (i = 0; i < map_ctxt->bar_cnt; i++) { bar_info = &map_ctxt->bar_info[i]; if (bar_info != NULL && bar_info->seg_info != NULL) { rte_free(bar_info->seg_info); bar_info->seg_info = NULL; } } rte_free(map_ctxt->bar_info); map_ctxt->bar_info = NULL; } adapter->dev_info.dev_data = NULL; } static int32_t sxe2_fc_state_init(struct rte_eth_dev *dev) { struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); struct sxe2_drv_vsi_fc_get_resp fc_resp = {0}; int32_t ret; if (!(adapter->cap_flags & SXE2_DEV_CAPS_OFFLOAD_FC_STATE)) { adapter->fc_state_ctx.cfg_state = 0; adapter->fc_state_ctx.curr_state = 0; ret = 0; goto l_end; } ret = sxe2_drv_fc_state_get(adapter, &fc_resp); if (ret) { PMD_LOG_ERR(INIT, "Failed to get fc state, ret=[%d]", ret); goto l_end; } adapter->fc_state_ctx.cfg_state = fc_resp.fc_enable; adapter->fc_state_ctx.curr_state = 0; l_end: return ret; } static void sxe2_fc_state_uinit(struct rte_eth_dev *dev) { struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); adapter->fc_state_ctx.cfg_state = 0; adapter->fc_state_ctx.curr_state = 0; } uint32_t sxe2_sched_mode_get(struct sxe2_adapter *adapter) { uint32_t ret_mode = SXE2_SCHED_MODE_INVALID; struct sxe2_tm_context *tm_ctxt = &adapter->tm_ctxt; if (adapter->devargs.no_sched_mode) ret_mode = SXE2_SCHED_MODE_NO_SCHED; else if (tm_ctxt->committed) ret_mode = SXE2_SCHED_MODE_TM; else ret_mode = SXE2_SCHED_MODE_DEFAULT; return ret_mode; } static int32_t sxe2_sched_init(struct rte_eth_dev *dev) { struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); int32_t ret = 0; adapter->sched_ctxt.adj_lvl = adapter->devargs.sched_layer_mode; if (adapter->devargs.no_sched_mode) { PMD_LOG_DEBUG(DRV, "TM feature will be disabled in high-performance mode."); adapter->cap_flags &= ~(SXE2_DEV_CAPS_OFFLOAD_TM); } else { ret = sxe2_tm_init(dev); if (ret) goto l_end; ret = sxe2_drv_root_tree_alloc(dev); if (ret) goto l_end; } l_end: return ret; } static int32_t sxe2_sched_uinit(struct rte_eth_dev *dev) { struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); int32_t ret = 0; if (!adapter->devargs.no_sched_mode) { ret = sxe2_tm_uninit(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to uninit tm, ret=%d", ret); goto l_end; } ret = sxe2_drv_root_tree_release(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to release root tree, ret=%d", ret); goto l_end; } } l_end: return ret; } static int32_t sxe2_dev_init(struct rte_eth_dev *dev, __rte_unused struct sxe2_dev_kvargs_info *kvargs) { int32_t ret = 0; PMD_INIT_FUNC_TRACE(); sxe2_set_common_function(dev); dev->dev_ops = &sxe2_eth_dev_ops; if (rte_eal_process_type() != RTE_PROC_PRIMARY) { sxe2_rx_mode_func_set(dev); sxe2_tx_mode_func_set(dev); ret = sxe2_mp_init(dev); if (ret != 0) PMD_LOG_ERR(INIT, "Failed to mp init (secondary), ret=%d", ret); goto l_end; } ret = sxe2_args_parse(dev, kvargs); if (ret) { PMD_LOG_ERR(INIT, "Failed to parse devargs, ret=%d", ret); goto l_end; } ret = sxe2_hw_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to initialize hw, ret=[%d]", ret); goto l_end; } ret = sxe2_dev_pci_map_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to pci addr map, ret=[%d]", ret); goto l_end; } ret = sxe2_vsi_init(dev); if (ret) { PMD_LOG_ERR(INIT, "create main vsi failed, ret=%d", ret); goto init_vsi_err; } ret = sxe2_dev_info_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to get device info, ret=[%d]", ret); goto init_dev_info_err; } ret = sxe2_switchdev_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to initialize switchdev mode, ret=[%d]", ret); goto init_switchdev_err; } ret = sxe2_sw_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to initialize sw parameters, ret=[%d]", ret); goto init_sw_err; } ret = sxe2_intr_init(dev); if (ret != 0) { PMD_LOG_ERR(INIT, "Failed to initialize interrupt, ret:%d", ret); goto init_irq_err; } ret = sxe2_eth_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to initialize eth parameters, ret=%d", ret); goto init_eth_err; } ret = sxe2_security_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to initialize security, ret=%d", ret); goto init_security_err; } ret = sxe2_rss_disable(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to disable rss, ret=%d", ret); goto init_rss_err; } ret = sxe2_flow_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to init flow, ret=%d", ret); goto init_flow_err; } ret = sxe2_fc_state_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to init fc state, ret=%d", ret); goto init_fc_state_err; } ret = sxe2_sched_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to init sched, ret=%d", ret); goto init_sched_err; } ret = sxe2_stats_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to stats init, ret=%d", ret); goto init_xstats_err; } ret = sxe2_mp_init(dev); if (ret) { PMD_LOG_ERR(INIT, "Failed to mp init, ret=%d", ret); goto init_xstats_err; } goto l_end; init_xstats_err: (void)sxe2_sched_uinit(dev); init_sched_err: sxe2_fc_state_uinit(dev); init_fc_state_err: (void)sxe2_flow_uninit(dev); init_flow_err: init_rss_err: sxe2_security_uinit(dev); init_security_err: sxe2_eth_uinit(dev); init_eth_err: sxe2_intr_uninit(dev); init_irq_err: sxe2_sw_uninit(dev); init_sw_err: (void)sxe2_switchdev_uninit(dev); init_switchdev_err: init_dev_info_err: sxe2_vsi_uninit(dev); init_vsi_err: sxe2_dev_pci_map_uinit(dev); l_end: return ret; } static int32_t sxe2_dev_close(struct rte_eth_dev *dev) { if (rte_eal_process_type() != RTE_PROC_PRIMARY) { sxe2_mp_uninit(dev); goto l_end; } sxe2_repr_all_close(dev); (void)sxe2_dev_stop(dev); (void)sxe2_queues_release(dev); sxe2_mp_uninit(dev); (void)sxe2_sched_uinit(dev); (void)sxe2_rss_disable(dev); (void)sxe2_flow_uninit(dev); (void)sxe2_udp_tunnel_port_clear(dev); sxe2_vsi_uninit(dev); sxe2_security_uinit(dev); sxe2_intr_uninit(dev); (void)sxe2_switchdev_uninit(dev); sxe2_sw_uninit(dev); (void)sxe2_switchdev_uninit(dev); sxe2_dev_pci_map_uinit(dev); sxe2_eth_uinit(dev); sxe2_dev_pci_map_uinit(dev); sxe2_free_repr_info(dev); sxe2_fc_state_uinit(dev); l_end: return 0; } static int32_t sxe2_dev_uninit(struct rte_eth_dev *dev) { int32_t ret = 0; int32_t i = 0; struct sxe2_adapter *adapter = NULL; struct rte_eth_dev *rep_dev = NULL; if (rte_eal_process_type() != RTE_PROC_PRIMARY) goto l_end; adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); for (i = 0; i < adapter->repr_ctxt.nb_repr_vf; i++) { rep_dev = adapter->repr_ctxt.vf_rep_eth_dev[i]; if (rep_dev) { ret = rep_dev->dev_ops->dev_close(rep_dev); if (ret) goto l_end; if (rep_dev->intr_handle) rte_intr_instance_free(rep_dev->intr_handle); ret = rte_eth_dev_release_port(rep_dev); if (ret) goto l_end; adapter->repr_ctxt.vf_rep_eth_dev[i] = NULL; } } ret = sxe2_dev_close(dev); if (ret) { PMD_LOG_ERR(INIT, "Sxe2 dev close failed, ret=%d", ret); goto l_end; } l_end: return ret; } static int32_t sxe2_eth_pmd_remove(struct sxe2_common_device *cdev) { struct rte_eth_dev *eth_dev; struct rte_pci_device *pci_dev = RTE_BUS_DEVICE(cdev->dev, *pci_dev); int32_t ret = 0; eth_dev = rte_eth_dev_allocated(pci_dev->device.name); if (!eth_dev) { PMD_LOG_INFO(INIT, "Sxe2 dev allocated failed"); goto l_end; } ret = sxe2_dev_uninit(eth_dev); if (ret) { PMD_LOG_ERR(INIT, "Sxe2 dev uninit failed, ret=%d", ret); goto l_end; } (void)rte_eth_dev_release_port(eth_dev); l_end: return ret; } static int32_t sxe2_fw_version_string_get(struct rte_eth_dev *dev, char *fw_version, size_t fw_size) { struct sxe2_adapter *adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(dev); struct sxe2_fw_info *fw_info = &adapter->dev_info.fw; int32_t ret_len; int32_t ret; ret_len = snprintf(fw_version, fw_size, "%u.%u.%u.%u", fw_info->main_version_id, fw_info->sub_version_id, fw_info->fix_version_id, fw_info->build_id); if (ret_len < 0) { ret = -EINVAL; goto out; } ret_len += 1; if (fw_size < (size_t)ret_len) ret = -EINVAL; else ret = 0; out: return ret; } static uint16_t sxe2_switchdev_repr_id_encode_get(struct sxe2_switchdev_info *switchdev_info) { enum rte_eth_representor_type type; uint16_t repr = switchdev_info->vf_num; uint32_t pf = switchdev_info->pf_num; switch (switchdev_info->port_name_type) { case SXE2_PHYS_PORT_NAME_TYPE_UPLINK: if (!switchdev_info->representor) return UINT16_MAX; type = RTE_ETH_REPRESENTOR_PF; pf = switchdev_info->mpesw_owner; break; case SXE2_PHYS_PORT_NAME_TYPE_PFVF: default: type = RTE_ETH_REPRESENTOR_VF; break; } return SXE2_REPRESENTOR_ID(pf, type, repr); } static bool sxe2_switchdev_repr_match(struct sxe2_adapter *adapter, struct rte_eth_devargs *req_eth_da) { uint32_t port_idx = 0; uint32_t repr_idx; uint16_t kernel_repr_id = sxe2_switchdev_repr_id_encode_get(&adapter->switchdev_info); uint16_t repr_id; switch (req_eth_da->type) { case RTE_ETH_REPRESENTOR_PF: break; case RTE_ETH_REPRESENTOR_VF: if (adapter->switchdev_info.port_name_type != SXE2_PHYS_PORT_NAME_TYPE_PFVF) { rte_errno = EBUSY; return false; } break; case RTE_ETH_REPRESENTOR_NONE: rte_errno = EBUSY; return false; default: rte_errno = ENOTSUP; return false; } for (repr_idx = 0; repr_idx < req_eth_da->nb_representor_ports; ++repr_idx) { repr_id = SXE2_REPRESENTOR_ID(req_eth_da->ports[port_idx], req_eth_da->type, req_eth_da->representor_ports[repr_idx]); if (repr_id == kernel_repr_id) return true; } rte_errno = EBUSY; return false; } static int32_t sxe2_eth_pmd_probe_pf(struct sxe2_common_device *cdev, struct rte_eth_devargs *req_eth_da __rte_unused, uint16_t owner_id __rte_unused, struct sxe2_dev_kvargs_info *kvargs) { struct rte_pci_device *pci_dev = RTE_BUS_DEVICE(cdev->dev, *pci_dev); struct rte_eth_dev *eth_dev = NULL; struct sxe2_adapter *adapter = NULL; int32_t ret = 0; if (!cdev) { ret = -EINVAL; goto l_end; } eth_dev = rte_eth_dev_pci_allocate(pci_dev, sizeof(struct sxe2_adapter)); if (rte_eal_process_type() == RTE_PROC_PRIMARY) { if (eth_dev == NULL) { PMD_LOG_ERR(INIT, "Can not allocate ethdev"); ret = -ENOMEM; goto l_end; } } else { if (!eth_dev) { PMD_LOG_DEBUG(INIT, "Can not attach secondary ethdev"); ret = -EINVAL; goto l_end; } } adapter = SXE2_DEV_PRIVATE_TO_ADAPTER(eth_dev); adapter->dev_port_id = eth_dev->data->port_id; if (rte_eal_process_type() == RTE_PROC_PRIMARY) adapter->cdev = cdev; ret = sxe2_dev_init(eth_dev, kvargs); if (ret != 0) { PMD_DEV_LOG_ERR(adapter, INIT, "Sxe2 dev init failed, ret=%d", ret); goto l_release_port; } if (req_eth_da->nb_representor_ports > 0) { if (!adapter->switchdev_info.is_switchdev) { PMD_DEV_LOG_ERR(adapter, INIT, "Representor requested but Switchdev not enabled"); ret = -ENOTSUP; goto l_dev_uinit; } if (!sxe2_switchdev_repr_match(adapter, req_eth_da)) { PMD_DEV_LOG_ERR(adapter, INIT, "Representor parameters mismatch"); ret = -ENOTSUP; goto l_dev_uinit; } ret = sxe2_switchdev_repr_devs_init(adapter, req_eth_da); if (ret) { PMD_DEV_LOG_ERR(adapter, INIT, "Failed to init representor, ret=%d", ret); goto l_dev_uinit; } } else { PMD_DEV_LOG_DEBUG(adapter, INIT, "No representors requested, skipping."); } rte_eth_dev_probing_finish(eth_dev); PMD_DEV_LOG_DEBUG(adapter, INIT, "Sxe2 eth pmd probe successful!"); goto l_end; l_dev_uinit: (void)sxe2_dev_uninit(eth_dev); l_release_port: (void)rte_eth_dev_release_port(eth_dev); l_end: return ret; } static int32_t sxe2_parse_eth_devargs(struct rte_device *dev, struct rte_eth_devargs *eth_da) { int32_t ret = 0; if (dev->devargs == NULL) return 0; memset(eth_da, 0, sizeof(*eth_da)); if (dev->devargs->cls_str) { ret = rte_eth_devargs_parse(dev->devargs->cls_str, eth_da, 1); if (ret) { PMD_LOG_ERR(INIT, "Failed to parse device arguments: %s", dev->devargs->cls_str); return -rte_errno; } } if (eth_da->type == RTE_ETH_REPRESENTOR_NONE && dev->devargs->args) { ret = rte_eth_devargs_parse(dev->devargs->args, eth_da, 1); if (ret) { PMD_LOG_ERR(INIT, "Failed to parse device arguments: %s", dev->devargs->args); return -rte_errno; } } return 0; } static int32_t sxe2_eth_pmd_probe(struct sxe2_common_device *cdev, struct sxe2_dev_kvargs_info *kvargs) { struct rte_eth_devargs eth_da = { .nb_ports = 0 }; int32_t ret = 0; ret = sxe2_parse_eth_devargs(cdev->dev, ð_da); if (ret != 0) { ret = -EINVAL; goto l_end; } ret = sxe2_eth_pmd_probe_pf(cdev, ð_da, 0, kvargs); l_end: return ret; } static struct sxe2_class_driver sxe2_eth_pmd = { .drv_class = SXE2_CLASS_TYPE_ETH, .name = "SXE2_ETH_PMD_DRIVER_NAME", .probe = sxe2_eth_pmd_probe, .remove = sxe2_eth_pmd_remove, .id_table = pci_id_sxe2_tbl, .intr_lsc = 1, .intr_rmv = 1, }; bool sxe2_ethdev_check(struct rte_eth_dev *dev) { return !strcmp(dev->device->driver->name, "sxe2_pci"); } RTE_INIT(rte_sxe2_pmd_init) { sxe2_common_init(); sxe2_class_driver_register(&sxe2_eth_pmd); } RTE_PMD_EXPORT_NAME(net_sxe2); RTE_PMD_REGISTER_PCI_TABLE(net_sxe2, pci_id_sxe2_tbl); RTE_PMD_REGISTER_KMOD_DEP(net_sxe2, "* sxe2"); RTE_PMD_REGISTER_PARAM_STRING(net_sxe2, "flow-duplicate-pattern=<0|1|2> " "function-flow-direct=<0|1> " "fnav-stat-type=<1|2|3> " "no-sched-mode=<0|1> " "sched-layer-mode=<0-3> " "rx-low-latency=<0|1>"); RTE_LOG_REGISTER_SUFFIX(sxe2_log_init, init, NOTICE); RTE_LOG_REGISTER_SUFFIX(sxe2_log_driver, driver, NOTICE); RTE_LOG_REGISTER_SUFFIX(sxe2_log_rx, rx, NOTICE); RTE_LOG_REGISTER_SUFFIX(sxe2_log_tx, tx, NOTICE); RTE_LOG_REGISTER_SUFFIX(sxe2_log_hw, hw, NOTICE);