From patchwork Fri Sep 1 09:35:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Renyong Wan X-Patchwork-Id: 131071 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id D96FB4221E; Fri, 1 Sep 2023 11:39:20 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 0D9D840E8A; Fri, 1 Sep 2023 11:36:21 +0200 (CEST) Received: from VLXDG1SPAM1.ramaxel.com (email.unionmem.com [221.4.138.186]) by mails.dpdk.org (Postfix) with ESMTP id C23C24064C for ; Fri, 1 Sep 2023 11:36:11 +0200 (CEST) Received: from V12DG1MBS03.ramaxel.local ([172.26.18.33]) by VLXDG1SPAM1.ramaxel.com with ESMTP id 3819ZXhD069869; Fri, 1 Sep 2023 17:35:33 +0800 (GMT-8) (envelope-from wanry@3snic.com) Received: from localhost.localdomain (10.64.136.151) by V12DG1MBS03.ramaxel.local (172.26.18.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2375.17; Fri, 1 Sep 2023 17:35:32 +0800 From: To: CC: , Renyong Wan , Steven Song Subject: [PATCH v4 25/32] net/sssnic: add RSS support Date: Fri, 1 Sep 2023 17:35:07 +0800 Message-ID: <20230901093514.224824-26-wanry@3snic.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230901093514.224824-1-wanry@3snic.com> References: <20230901093514.224824-1-wanry@3snic.com> MIME-Version: 1.0 X-Originating-IP: [10.64.136.151] X-ClientProxiedBy: V12DG1MBS03.ramaxel.local (172.26.18.33) To V12DG1MBS03.ramaxel.local (172.26.18.33) X-DNSRBL: X-SPAM-SOURCE-CHECK: pass X-MAIL: VLXDG1SPAM1.ramaxel.com 3819ZXhD069869 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Renyong Wan Signed-off-by: Steven Song Signed-off-by: Renyong Wan --- v2: * Removed error.h from including files. --- doc/guides/nics/features/sssnic.ini | 4 + drivers/net/sssnic/base/sssnic_api.c | 338 ++++++++++++++++++++++ drivers/net/sssnic/base/sssnic_api.h | 36 +++ drivers/net/sssnic/base/sssnic_cmd.h | 58 ++++ drivers/net/sssnic/meson.build | 1 + drivers/net/sssnic/sssnic_ethdev.c | 16 ++ drivers/net/sssnic/sssnic_ethdev.h | 2 + drivers/net/sssnic/sssnic_ethdev_rss.c | 377 +++++++++++++++++++++++++ drivers/net/sssnic/sssnic_ethdev_rss.h | 20 ++ drivers/net/sssnic/sssnic_ethdev_rx.c | 13 + 10 files changed, 865 insertions(+) create mode 100644 drivers/net/sssnic/sssnic_ethdev_rss.c create mode 100644 drivers/net/sssnic/sssnic_ethdev_rss.h diff --git a/doc/guides/nics/features/sssnic.ini b/doc/guides/nics/features/sssnic.ini index 7e6b70684a..020a9e7056 100644 --- a/doc/guides/nics/features/sssnic.ini +++ b/doc/guides/nics/features/sssnic.ini @@ -15,6 +15,10 @@ Promiscuous mode = Y Allmulticast mode = Y Unicast MAC filter = Y Multicast MAC filter = Y +RSS hash = Y +RSS key update = Y +RSS reta update = Y +Inner RSS = Y L3 checksum offload = Y L4 checksum offload = Y Inner L3 checksum = Y diff --git a/drivers/net/sssnic/base/sssnic_api.c b/drivers/net/sssnic/base/sssnic_api.c index 9f063112f2..32b24e841c 100644 --- a/drivers/net/sssnic/base/sssnic_api.c +++ b/drivers/net/sssnic/base/sssnic_api.c @@ -1159,3 +1159,341 @@ sssnic_mac_stats_clear(struct sssnic_hw *hw) return 0; } + +int +sssnic_rss_enable_set(struct sssnic_hw *hw, bool state) +{ + int ret; + struct sssnic_rss_enable_cmd cmd; + struct sssnic_msg msg; + uint32_t cmd_len; + + memset(&cmd, 0, sizeof(cmd)); + cmd.state = state ? 1 : 0; + cmd.function = SSSNIC_FUNC_IDX(hw); + cmd_len = sizeof(cmd); + + sssnic_msg_init(&msg, (uint8_t *)&cmd, cmd_len, SSSNIC_ENABLE_RSS_CMD, + SSSNIC_MPU_FUNC_IDX, SSSNIC_LAN_MODULE, SSSNIC_MSG_TYPE_REQ); + + ret = sssnic_mbox_send(hw, &msg, (uint8_t *)&cmd, &cmd_len, 0); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to send mbox message, ret=%d", ret); + return ret; + } + + if (cmd_len == 0 || cmd.common.status != 0) { + PMD_DRV_LOG(ERR, + "Bad response to SSSNIC_ENABLE_RSS_CMD, len=%u, status=%u", + cmd_len, cmd.common.status); + return -EIO; + } + + return 0; +} + +static int +sssnic_rss_profile_config(struct sssnic_hw *hw, bool new) +{ + int ret; + struct sssnic_rss_profile_cmd cmd; + struct sssnic_msg msg; + uint32_t cmd_len; + + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = new ? SSSNIC_RSS_PROFILE_CMD_OP_NEW : + SSSNIC_RSS_PROFILE_CMD_OP_DEL; + cmd.function = SSSNIC_FUNC_IDX(hw); + cmd_len = sizeof(cmd); + + sssnic_msg_init(&msg, (uint8_t *)&cmd, cmd_len, SSSNIC_RSS_PROFILE_CMD, + SSSNIC_MPU_FUNC_IDX, SSSNIC_LAN_MODULE, SSSNIC_MSG_TYPE_REQ); + + ret = sssnic_mbox_send(hw, &msg, (uint8_t *)&cmd, &cmd_len, 0); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to send mbox message, ret=%d", ret); + return ret; + } + + if (cmd_len == 0 || cmd.common.status != 0) { + PMD_DRV_LOG(ERR, + "Bad response to SSSNIC_RSS_PROFILE_CMD, len=%u, status=%u", + cmd_len, cmd.common.status); + return -EIO; + } + + return 0; +} + +int +sssnic_rss_profile_create(struct sssnic_hw *hw) +{ + return sssnic_rss_profile_config(hw, true); +} + +int +sssnic_rss_profile_destroy(struct sssnic_hw *hw) +{ + return sssnic_rss_profile_config(hw, false); +} + +int +sssnic_rss_hash_key_set(struct sssnic_hw *hw, uint8_t *key, uint16_t len) +{ + int ret; + struct sssnic_rss_hash_key_cmd cmd; + struct sssnic_msg msg; + uint32_t cmd_len; + + if (len > sizeof(cmd.key)) { + PMD_DRV_LOG(ERR, "Invalid rss hash key length: %u", len); + return -EINVAL; + } + + memset(&cmd, 0, sizeof(cmd)); + cmd.opcode = SSSNIC_CMD_OPCODE_SET; + cmd.function = SSSNIC_FUNC_IDX(hw); + rte_memcpy(cmd.key, key, len); + cmd_len = sizeof(cmd); + + sssnic_msg_init(&msg, (uint8_t *)&cmd, cmd_len, SSSNIC_RSS_HASH_KEY_CMD, + SSSNIC_MPU_FUNC_IDX, SSSNIC_LAN_MODULE, SSSNIC_MSG_TYPE_REQ); + + ret = sssnic_mbox_send(hw, &msg, (uint8_t *)&cmd, &cmd_len, 0); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to send mbox message, ret=%d", ret); + return ret; + } + + if (cmd_len == 0 || cmd.common.status != 0) { + PMD_DRV_LOG(ERR, + "Bad response to SSSNIC_RSS_PROFILE_CMD, len=%u, status=%u", + cmd_len, cmd.common.status); + return -EIO; + } + + return 0; +} + +static int +sssnic_rss_type_set_by_mbox(struct sssnic_hw *hw, struct sssnic_rss_type *type) +{ + int ret; + struct sssnic_rss_type_cmd cmd; + struct sssnic_msg msg; + uint32_t cmd_len; + + memset(&cmd, 0, sizeof(cmd)); + cmd.function = SSSNIC_FUNC_IDX(hw); + cmd.mask = type->mask; + cmd_len = sizeof(cmd); + + sssnic_msg_init(&msg, (uint8_t *)&cmd, cmd_len, SSSNIC_SET_RSS_TYPE_CMD, + SSSNIC_MPU_FUNC_IDX, SSSNIC_LAN_MODULE, SSSNIC_MSG_TYPE_REQ); + + ret = sssnic_mbox_send(hw, &msg, (uint8_t *)&cmd, &cmd_len, 0); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to send mbox message, ret=%d", ret); + return ret; + } + + if (cmd.common.status == 0xff) + return -EOPNOTSUPP; + + if (cmd_len == 0 || cmd.common.status != 0) { + PMD_DRV_LOG(ERR, + "Bad response to SSSNIC_SET_RSS_TYPE_CMD, len=%u, status=%u", + cmd_len, cmd.common.status); + return -EIO; + } + + return 0; +} + +static int +sssnic_rss_type_set_by_ctrlq(struct sssnic_hw *hw, struct sssnic_rss_type *type) +{ + struct sssnic_ctrlq_cmd cmd; + struct sssnic_rss_hash_type_ctrlq_cmd data; + int ret; + + memset(&data, 0, sizeof(data)); + data.mask = rte_cpu_to_be_32(type->mask); + + memset(&cmd, 0, sizeof(cmd)); + cmd.data = &data; + cmd.module = SSSNIC_LAN_MODULE; + cmd.data_len = sizeof(data); + cmd.cmd = SSSNIC_SET_RSS_KEY_CTRLQ_CMD; + + ret = sssnic_ctrlq_cmd_exec(hw, &cmd, 0); + if (ret || cmd.result) { + PMD_DRV_LOG(ERR, + "Failed to execulte ctrlq command %s, ret=%d, result=%" PRIu64, + "SSSNIC_SET_RSS_KEY_CTRLQ_CMD", ret, cmd.result); + return -EIO; + } + + return 0; +} + +int +sssnic_rss_type_set(struct sssnic_hw *hw, struct sssnic_rss_type *type) +{ + int ret; + + ret = sssnic_rss_type_set_by_mbox(hw, type); + if (ret == -EOPNOTSUPP) + ret = sssnic_rss_type_set_by_ctrlq(hw, type); + + return ret; +} + +int +sssnic_rss_type_get(struct sssnic_hw *hw, struct sssnic_rss_type *type) +{ + int ret; + struct sssnic_rss_type_cmd cmd; + struct sssnic_msg msg; + uint32_t cmd_len; + + memset(&cmd, 0, sizeof(cmd)); + cmd.function = SSSNIC_FUNC_IDX(hw); + cmd_len = sizeof(cmd); + + sssnic_msg_init(&msg, (uint8_t *)&cmd, cmd_len, SSSNIC_GET_RSS_TYPE_CMD, + SSSNIC_MPU_FUNC_IDX, SSSNIC_LAN_MODULE, SSSNIC_MSG_TYPE_REQ); + + ret = sssnic_mbox_send(hw, &msg, (uint8_t *)&cmd, &cmd_len, 0); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to send mbox message, ret=%d", ret); + return ret; + } + + if (cmd_len == 0 || cmd.common.status != 0) { + PMD_DRV_LOG(ERR, + "Bad response to SSSNIC_GET_RSS_TYPE_CMD, len=%u, status=%u", + cmd_len, cmd.common.status); + return -EIO; + } + + type->mask = cmd.mask; + + return 0; +} + +int +sssnic_rss_hash_engine_set(struct sssnic_hw *hw, + enum sssnic_rss_hash_engine_type engine) +{ + int ret; + struct sssnic_rss_hash_engine_cmd cmd; + struct sssnic_msg msg; + uint32_t cmd_len; + + memset(&cmd, 0, sizeof(cmd)); + cmd.function = SSSNIC_FUNC_IDX(hw); + cmd.engine = engine; + cmd.opcode = SSSNIC_CMD_OPCODE_SET; + cmd_len = sizeof(cmd); + + sssnic_msg_init(&msg, (uint8_t *)&cmd, cmd_len, + SSSNIC_RSS_HASH_ENGINE_CMD, SSSNIC_MPU_FUNC_IDX, + SSSNIC_LAN_MODULE, SSSNIC_MSG_TYPE_REQ); + + ret = sssnic_mbox_send(hw, &msg, (uint8_t *)&cmd, &cmd_len, 0); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to send mbox message, ret=%d", ret); + return ret; + } + + if (cmd_len == 0 || cmd.common.status != 0) { + PMD_DRV_LOG(ERR, + "Bad response to SSSNIC_RSS_HASH_ENGINE_CMD, len=%u, status=%u", + cmd_len, cmd.common.status); + return -EIO; + } + + return 0; +} + +int +sssnic_rss_indir_table_set(struct sssnic_hw *hw, const uint16_t *entry, + uint32_t num_entries) +{ + struct sssnic_ctrlq_cmd *cmd; + struct sssnic_rss_indir_table_cmd *data; + uint32_t i; + int ret; + + cmd = sssnic_ctrlq_cmd_alloc(hw); + if (cmd == NULL) { + PMD_DRV_LOG(ERR, "Failed to alloc ctrlq command"); + return -ENOMEM; + } + + data = cmd->data; + memset(data, 0, sizeof(struct sssnic_rss_indir_table_cmd)); + for (i = 0; i < num_entries; i++) + data->entry[i] = entry[i]; + + rte_wmb(); + + sssnic_mem_cpu_to_be_32(data->entry, data->entry, sizeof(data->entry)); + + cmd->data_len = sizeof(struct sssnic_rss_indir_table_cmd); + cmd->module = SSSNIC_LAN_MODULE; + cmd->cmd = SSSNIC_SET_RSS_INDIR_TABLE_CMD; + + ret = sssnic_ctrlq_cmd_exec(hw, cmd, 0); + if (ret != 0 || cmd->result != 0) { + PMD_DRV_LOG(ERR, + "Failed to execulte ctrlq command %s, ret=%d, result=%" PRIu64, + "SSSNIC_SET_RSS_INDIR_TABLE_CMD", ret, cmd->result); + ret = -EIO; + } + + sssnic_ctrlq_cmd_destroy(hw, cmd); + + return ret; +} + +int +sssnic_rss_indir_table_get(struct sssnic_hw *hw, uint16_t *entry, + uint32_t num_entries) +{ + struct sssnic_ctrlq_cmd *cmd; + struct sssnic_rss_indir_table_cmd *data; + uint32_t i; + int ret = 0; + + cmd = sssnic_ctrlq_cmd_alloc(hw); + if (cmd == NULL) { + PMD_DRV_LOG(ERR, "Failed to alloc ctrlq command"); + return -ENOMEM; + } + + data = cmd->data; + memset(data, 0, sizeof(struct sssnic_rss_indir_table_cmd)); + cmd->data_len = sizeof(struct sssnic_rss_indir_table_cmd); + cmd->module = SSSNIC_LAN_MODULE; + cmd->cmd = SSSNIC_GET_RSS_INDIR_TABLE_CMD; + cmd->response_len = sizeof(data->entry); + cmd->response_data = data->entry; + + ret = sssnic_ctrlq_cmd_exec(hw, cmd, 0); + if (ret != 0) { + PMD_DRV_LOG(ERR, + "Failed to execulte ctrlq command %s, ret=%d, result=%" PRIu64, + "SSSNIC_GET_RSS_INDIR_TABLE_CMD", ret, cmd->result); + ret = -EIO; + goto out; + } + + for (i = 0; i < num_entries; i++) + entry[i] = data->entry[i]; + +out: + sssnic_ctrlq_cmd_destroy(hw, cmd); + return ret; +} diff --git a/drivers/net/sssnic/base/sssnic_api.h b/drivers/net/sssnic/base/sssnic_api.h index c2f4f90209..1d80b93e38 100644 --- a/drivers/net/sssnic/base/sssnic_api.h +++ b/drivers/net/sssnic/base/sssnic_api.h @@ -378,6 +378,30 @@ struct sssnic_mac_stats { uint64_t rx_unfilter_pkts; }; +struct sssnic_rss_type { + union { + uint32_t mask; + struct { + uint32_t resvd : 23; + uint32_t valid : 1; + uint32_t ipv6_tcp_ex : 1; + uint32_t ipv6_ex : 1; + uint32_t ipv6_tcp : 1; + uint32_t ipv6 : 1; + uint32_t ipv4_tcp : 1; + uint32_t ipv4 : 1; + uint32_t ipv6_udp : 1; + uint32_t ipv4_udp : 1; + }; + }; +}; + +enum sssnic_rss_hash_engine_type { + SSSNIC_RSS_HASH_ENGINE_XOR, + SSSNIC_RSS_HASH_ENGINE_TOEP, + SSSNIC_RSS_HASH_ENGINE_COUNT, +}; + int sssnic_msix_attr_get(struct sssnic_hw *hw, uint16_t msix_idx, struct sssnic_msix_attr *attr); int sssnic_msix_attr_set(struct sssnic_hw *hw, uint16_t msix_idx, @@ -420,5 +444,17 @@ int sssnic_port_stats_get(struct sssnic_hw *hw, int sssnic_port_stats_clear(struct sssnic_hw *hw); int sssnic_mac_stats_get(struct sssnic_hw *hw, struct sssnic_mac_stats *stats); int sssnic_mac_stats_clear(struct sssnic_hw *hw); +int sssnic_rss_enable_set(struct sssnic_hw *hw, bool state); +int sssnic_rss_profile_create(struct sssnic_hw *hw); +int sssnic_rss_profile_destroy(struct sssnic_hw *hw); +int sssnic_rss_hash_key_set(struct sssnic_hw *hw, uint8_t *key, uint16_t len); +int sssnic_rss_type_set(struct sssnic_hw *hw, struct sssnic_rss_type *type); +int sssnic_rss_type_get(struct sssnic_hw *hw, struct sssnic_rss_type *type); +int sssnic_rss_hash_engine_set(struct sssnic_hw *hw, + enum sssnic_rss_hash_engine_type engine); +int sssnic_rss_indir_table_set(struct sssnic_hw *hw, const uint16_t *entry, + uint32_t num_entries); +int sssnic_rss_indir_table_get(struct sssnic_hw *hw, uint16_t *entry, + uint32_t num_entries); #endif /* _SSSNIC_API_H_ */ diff --git a/drivers/net/sssnic/base/sssnic_cmd.h b/drivers/net/sssnic/base/sssnic_cmd.h index bc7303ff57..56818471b6 100644 --- a/drivers/net/sssnic/base/sssnic_cmd.h +++ b/drivers/net/sssnic/base/sssnic_cmd.h @@ -66,6 +66,15 @@ enum sssnic_ctrlq_cmd_id { SSSNIC_FLUSH_RXQ_CMD = 10, }; +enum sssnic_rss_cmd_id { + SSSNIC_ENABLE_RSS_CMD = 60, + SSSNIC_RSS_PROFILE_CMD = 61, + SSSNIC_GET_RSS_TYPE_CMD = 62, + SSSNIC_RSS_HASH_KEY_CMD = 63, + SSSNIC_RSS_HASH_ENGINE_CMD = 64, + SSSNIC_SET_RSS_TYPE_CMD = 65, +}; + struct sssnic_cmd_common { uint8_t status; uint8_t version; @@ -348,4 +357,53 @@ struct sssnic_mac_stats_cmd { uint8_t resvd[3]; }; +struct sssnic_rss_enable_cmd { + struct sssnic_cmd_common common; + uint16_t function; + uint8_t state; + uint8_t resvd[13]; +}; + +#define SSSNIC_RSS_PROFILE_CMD_OP_NEW 1 /* Allocate RSS profile */ +#define SSSNIC_RSS_PROFILE_CMD_OP_DEL 2 /* Delete RSS profile */ +struct sssnic_rss_profile_cmd { + struct sssnic_cmd_common common; + uint16_t function; + uint8_t opcode; /* see SSSNIC_RSS_PROFILE_CMD_OP_xx */ + uint8_t profile; + uint32_t resvd[4]; +}; + +struct sssnic_rss_hash_key_cmd { + struct sssnic_cmd_common common; + uint16_t function; + uint8_t opcode; + uint8_t resvd; + uint8_t key[40]; +}; + +struct sssnic_rss_type_cmd { + struct sssnic_cmd_common common; + uint16_t function; + uint16_t resvd0; + uint32_t mask; /* mask of types */ +}; + +struct sssnic_rss_hash_type_ctrlq_cmd { + uint32_t resvd[4]; + uint32_t mask; +}; +struct sssnic_rss_hash_engine_cmd { + struct sssnic_cmd_common common; + uint16_t function; + uint8_t opcode; + uint8_t engine; + uint8_t resvd[4]; +}; + +struct sssnic_rss_indir_table_cmd { + uint32_t resvd[4]; + uint16_t entry[256]; +}; + #endif /* _SSSNIC_CMD_H_ */ diff --git a/drivers/net/sssnic/meson.build b/drivers/net/sssnic/meson.build index dea24f4b06..3541b75c30 100644 --- a/drivers/net/sssnic/meson.build +++ b/drivers/net/sssnic/meson.build @@ -22,4 +22,5 @@ sources = files( 'sssnic_ethdev_rx.c', 'sssnic_ethdev_tx.c', 'sssnic_ethdev_stats.c', + 'sssnic_ethdev_rss.c', ) diff --git a/drivers/net/sssnic/sssnic_ethdev.c b/drivers/net/sssnic/sssnic_ethdev.c index 328fb85d30..a00e96bebe 100644 --- a/drivers/net/sssnic/sssnic_ethdev.c +++ b/drivers/net/sssnic/sssnic_ethdev.c @@ -13,6 +13,7 @@ #include "sssnic_ethdev_rx.h" #include "sssnic_ethdev_tx.h" #include "sssnic_ethdev_stats.h" +#include "sssnic_ethdev_rss.h" static int sssnic_ethdev_init(struct rte_eth_dev *ethdev); @@ -542,6 +543,13 @@ sssnic_ethdev_start(struct rte_eth_dev *ethdev) goto rx_mode_reset; } + /* setup RSS */ + ret = sssnic_ethdev_rss_setup(ethdev); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to setup RSS"); + goto rx_mode_reset; + } + /* start all rx queues */ ret = sssnic_ethdev_rx_queue_all_start(ethdev); if (ret != 0) { @@ -572,6 +580,7 @@ sssnic_ethdev_start(struct rte_eth_dev *ethdev) clean_port_res: sssnic_ethdev_resource_clean(ethdev); rx_mode_reset: + sssnic_ethdev_rss_shutdown(ethdev); sssnic_ethdev_rx_mode_set(ethdev, SSSNIC_ETHDEV_RX_MODE_NONE); rxtx_ctx_clean: sssnic_ethdev_rxtx_ctx_clean(ethdev); @@ -614,6 +623,9 @@ sssnic_ethdev_stop(struct rte_eth_dev *ethdev) /* shut down rx queue interrupt */ sssnic_ethdev_rx_intr_shutdown(ethdev); + /* Disable RSS */ + sssnic_ethdev_rss_shutdown(ethdev); + /* clean rxtx context */ sssnic_ethdev_rxtx_ctx_clean(ethdev); @@ -754,6 +766,10 @@ static const struct eth_dev_ops sssnic_ethdev_ops = { .xstats_get_names = sssnic_ethdev_xstats_get_names, .xstats_get = sssnic_ethdev_xstats_get, .xstats_reset = sssnic_ethdev_xstats_reset, + .rss_hash_conf_get = sssnic_ethdev_rss_hash_config_get, + .rss_hash_update = sssnic_ethdev_rss_hash_update, + .reta_update = sssnic_ethdev_rss_reta_update, + .reta_query = sssnic_ethdev_rss_reta_query, }; static int diff --git a/drivers/net/sssnic/sssnic_ethdev.h b/drivers/net/sssnic/sssnic_ethdev.h index 1f1e991780..f19b2bd88f 100644 --- a/drivers/net/sssnic/sssnic_ethdev.h +++ b/drivers/net/sssnic/sssnic_ethdev.h @@ -88,6 +88,8 @@ struct sssnic_netdev { uint16_t num_started_txqs; uint16_t max_rx_size; uint32_t rx_mode; + uint32_t rss_enable; + uint8_t rss_hash_key[SSSNIC_ETHDEV_RSS_KEY_SZ]; }; #define SSSNIC_ETHDEV_PRIVATE(eth_dev) \ diff --git a/drivers/net/sssnic/sssnic_ethdev_rss.c b/drivers/net/sssnic/sssnic_ethdev_rss.c new file mode 100644 index 0000000000..690a30d7bc --- /dev/null +++ b/drivers/net/sssnic/sssnic_ethdev_rss.c @@ -0,0 +1,377 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018-2022 Shenzhen 3SNIC Information Technology Co., Ltd. + */ + +#include +#include + +#include "sssnic_log.h" +#include "sssnic_ethdev.h" +#include "sssnic_ethdev_rx.h" +#include "sssnic_ethdev_tx.h" +#include "sssnic_ethdev_stats.h" +#include "sssnic_ethdev_rss.h" +#include "base/sssnic_hw.h" +#include "base/sssnic_api.h" + +static uint8_t default_rss_hash_key[SSSNIC_ETHDEV_RSS_KEY_SZ] = { 0x6d, 0x5a, + 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, + 0x8f, 0xb0, 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4, 0x77, 0xcb, + 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c, 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, + 0x01, 0xfa }; + +#define SSSNIC_ETHDEV_RSS_IPV4 \ + (RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_FRAG_IPV4 | \ + RTE_ETH_RSS_NONFRAG_IPV4_OTHER) +#define SSSNIC_ETHDEV_RSS_IPV6 \ + (RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_FRAG_IPV6 | \ + RTE_ETH_RSS_NONFRAG_IPV6_OTHER) + +static inline void +sssnic_ethdev_rss_type_from_rss_hf(struct sssnic_rss_type *rss_type, + uint64_t rss_hf) +{ + rss_type->mask = 0; + rss_type->ipv4 = (rss_hf & SSSNIC_ETHDEV_RSS_IPV4) ? 1 : 0; + rss_type->ipv6 = (rss_hf & SSSNIC_ETHDEV_RSS_IPV6) ? 1 : 0; + rss_type->ipv6_ex = (rss_hf & RTE_ETH_RSS_IPV6_EX) ? 1 : 0; + rss_type->ipv4_tcp = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_TCP) ? 1 : 0; + rss_type->ipv6_tcp = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_TCP) ? 1 : 0; + rss_type->ipv6_tcp_ex = (rss_hf & RTE_ETH_RSS_IPV6_TCP_EX) ? 1 : 0; + rss_type->ipv4_udp = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_UDP) ? 1 : 0; + rss_type->ipv6_udp = (rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_UDP) ? 1 : 0; +} + +static inline uint64_t +sssnic_ethdev_rss_type_to_rss_hf(struct sssnic_rss_type *rss_type) +{ + uint64_t rss_hf = 0; + + rss_hf |= (rss_type->ipv4 == 0) ? 0 : SSSNIC_ETHDEV_RSS_IPV4; + rss_hf |= (rss_type->ipv6 == 0) ? 0 : SSSNIC_ETHDEV_RSS_IPV6; + rss_hf |= (rss_type->ipv6_ex == 0) ? 0 : RTE_ETH_RSS_IPV6_EX; + rss_hf |= (rss_type->ipv4_tcp == 0) ? 0 : RTE_ETH_RSS_NONFRAG_IPV4_TCP; + rss_hf |= (rss_type->ipv6_tcp == 0) ? 0 : RTE_ETH_RSS_NONFRAG_IPV6_TCP; + rss_hf |= (rss_type->ipv6_tcp_ex == 0) ? 0 : RTE_ETH_RSS_IPV6_TCP_EX; + rss_hf |= (rss_type->ipv4_udp == 0) ? 0 : RTE_ETH_RSS_NONFRAG_IPV4_UDP; + rss_hf |= (rss_type->ipv6_udp == 0) ? 0 : RTE_ETH_RSS_NONFRAG_IPV6_UDP; + + return rss_hf; +} + +int +sssnic_ethdev_rss_hash_update(struct rte_eth_dev *ethdev, + struct rte_eth_rss_conf *rss_conf) +{ + struct sssnic_netdev *netdev = SSSNIC_ETHDEV_PRIVATE(ethdev); + struct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev); + struct sssnic_rss_type rss_type; + uint64_t rss_hf; + uint8_t *rss_key; + uint16_t rss_key_len; + int ret; + + rss_key = rss_conf->rss_key; + rss_key_len = rss_conf->rss_key_len; + if (rss_key == NULL) { + rss_key = default_rss_hash_key; + rss_key_len = SSSNIC_ETHDEV_RSS_KEY_SZ; + } else if (rss_key_len > SSSNIC_ETHDEV_RSS_KEY_SZ) { + PMD_DRV_LOG(ERR, "RSS hash key length too long"); + return -EINVAL; + } + + ret = sssnic_rss_hash_key_set(hw, rss_key, rss_key_len); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to set RSS hash key"); + return ret; + } + + rte_memcpy(netdev->rss_hash_key, rss_key, rss_key_len); + + rss_hf = rss_conf->rss_hf; + + if (rss_hf == 0) + rss_hf = SSSNIC_ETHDEV_RSS_OFFLOAD_FLOW_TYPES; + else + rss_hf &= SSSNIC_ETHDEV_RSS_OFFLOAD_FLOW_TYPES; + + sssnic_ethdev_rss_type_from_rss_hf(&rss_type, rss_hf); + rss_type.valid = 1; + ret = sssnic_rss_type_set(hw, &rss_type); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to set RSS type: %x", rss_type.mask); + return ret; + } + + return 0; +} + +int +sssnic_ethdev_rss_hash_config_get(struct rte_eth_dev *ethdev, + struct rte_eth_rss_conf *rss_conf) +{ + struct sssnic_netdev *netdev = SSSNIC_ETHDEV_PRIVATE(ethdev); + struct sssnic_hw *hw; + struct sssnic_rss_type rss_type; + int ret; + + hw = SSSNIC_NETDEV_TO_HW(netdev); + + if (!netdev->rss_enable) { + PMD_DRV_LOG(NOTICE, "Port %u RSS is not enabled", + ethdev->data->port_id); + rss_conf->rss_hf = 0; + return 0; + } + + ret = sssnic_rss_type_get(hw, &rss_type); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to get RSS type"); + return ret; + } + rss_conf->rss_hf = sssnic_ethdev_rss_type_to_rss_hf(&rss_type); + + if (rss_conf->rss_key != NULL && + rss_conf->rss_key_len >= SSSNIC_ETHDEV_RSS_KEY_SZ) { + rte_memcpy(rss_conf->rss_key, netdev->rss_hash_key, + SSSNIC_ETHDEV_RSS_KEY_SZ); + rss_conf->rss_key_len = SSSNIC_ETHDEV_RSS_KEY_SZ; + } + + return 0; +} + +int +sssnic_ethdev_rss_reta_update(struct rte_eth_dev *ethdev, + struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size) +{ + struct sssnic_netdev *netdev = SSSNIC_ETHDEV_PRIVATE(ethdev); + struct sssnic_hw *hw; + uint16_t *entries; + int i, group, idx; + int ret; + + if (!netdev->rss_enable) { + PMD_DRV_LOG(ERR, "Port %u RSS is not enabled", + ethdev->data->port_id); + return -EINVAL; + } + + if (reta_size != SSSNIC_ETHDEV_RSS_RETA_SZ) { + PMD_DRV_LOG(ERR, "Invalid reta size:%u, expected reta size:%u ", + reta_size, SSSNIC_ETHDEV_RSS_RETA_SZ); + return -EINVAL; + } + + hw = SSSNIC_NETDEV_TO_HW(netdev); + + entries = rte_zmalloc(NULL, + SSSNIC_ETHDEV_RSS_RETA_SZ * sizeof(uint16_t), 0); + if (entries == NULL) { + PMD_DRV_LOG(ERR, "Could not allocate memory"); + return -ENOMEM; + } + + ret = sssnic_rss_indir_table_get(hw, entries, + SSSNIC_ETHDEV_RSS_RETA_SZ); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to get RSS indirect table"); + goto out; + } + + for (i = 0; i < SSSNIC_ETHDEV_RSS_RETA_SZ; i++) { + group = i / RTE_ETH_RETA_GROUP_SIZE; + idx = i % RTE_ETH_RETA_GROUP_SIZE; + if ((reta_conf[group].mask & RTE_BIT64(idx)) != 0) + entries[i] = reta_conf[group].reta[idx]; + } + + ret = sssnic_rss_indir_table_set(hw, entries, + SSSNIC_ETHDEV_RSS_RETA_SZ); + if (ret != 0) + PMD_DRV_LOG(ERR, "Failed to set RSS indirect table"); + +out: + rte_free(entries); + return ret; +} + +int +sssnic_ethdev_rss_reta_query(struct rte_eth_dev *ethdev, + struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size) +{ + struct sssnic_netdev *netdev = SSSNIC_ETHDEV_PRIVATE(ethdev); + struct sssnic_hw *hw; + uint16_t *entries; + int i, group, idx; + int ret; + + if (!netdev->rss_enable) { + PMD_DRV_LOG(ERR, "Port %u RSS is not enabled", + ethdev->data->port_id); + return -EINVAL; + } + + if (reta_size != SSSNIC_ETHDEV_RSS_RETA_SZ) { + PMD_DRV_LOG(ERR, "Invalid reta size:%u, expected reta size:%u ", + reta_size, SSSNIC_ETHDEV_RSS_RETA_SZ); + return -EINVAL; + } + + hw = SSSNIC_NETDEV_TO_HW(netdev); + + entries = rte_zmalloc(NULL, + SSSNIC_ETHDEV_RSS_RETA_SZ * sizeof(uint16_t), 0); + if (entries == NULL) { + PMD_DRV_LOG(ERR, "Could not allocate memory"); + return -ENOMEM; + } + + ret = sssnic_rss_indir_table_get(hw, entries, + SSSNIC_ETHDEV_RSS_RETA_SZ); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to get RSS indirect table"); + goto out; + } + + for (i = 0; i < SSSNIC_ETHDEV_RSS_RETA_SZ; i++) { + group = i / RTE_ETH_RETA_GROUP_SIZE; + idx = i % RTE_ETH_RETA_GROUP_SIZE; + if ((reta_conf[group].mask & RTE_BIT64(idx)) != 0) + reta_conf[group].reta[idx] = entries[i]; + } + +out: + rte_free(entries); + return ret; +} + +int +sssnic_ethdev_rss_reta_reset(struct rte_eth_dev *ethdev) +{ + struct sssnic_netdev *netdev = SSSNIC_ETHDEV_PRIVATE(ethdev); + struct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev); + uint16_t *entries; + uint16_t nb_rxq; + uint8_t rxq_state; + uint16_t qid, i = 0; + int ret; + + if (!netdev->rss_enable) + return 0; + + entries = rte_zmalloc(NULL, + SSSNIC_ETHDEV_RSS_RETA_SZ * sizeof(uint16_t), 0); + if (entries == NULL) { + PMD_DRV_LOG(ERR, "Could not allocate memory"); + return -ENOMEM; + } + + nb_rxq = ethdev->data->nb_rx_queues; + + if (netdev->num_started_rxqs == 0) { + while (i < SSSNIC_ETHDEV_RSS_RETA_SZ) + entries[i++] = 0xffff; + } else { + while (i < SSSNIC_ETHDEV_RSS_RETA_SZ) { + for (qid = 0; qid < nb_rxq; qid++) { + if (i >= SSSNIC_ETHDEV_RSS_RETA_SZ) + break; + rxq_state = ethdev->data->rx_queue_state[qid]; + if (rxq_state == RTE_ETH_QUEUE_STATE_STARTED) + entries[i++] = qid; + } + } + } + + ret = sssnic_rss_indir_table_set(hw, entries, + SSSNIC_ETHDEV_RSS_RETA_SZ); + if (ret != 0) + PMD_DRV_LOG(ERR, "Failed to set RSS indirect table"); + + rte_free(entries); + + return ret; +} + +int +sssnic_ethdev_rss_setup(struct rte_eth_dev *ethdev) +{ + struct sssnic_netdev *netdev = SSSNIC_ETHDEV_PRIVATE(ethdev); + struct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev); + struct rte_eth_conf *dev_conf = ðdev->data->dev_conf; + struct rte_eth_rss_conf *rss_conf; + int ret; + + if (!((dev_conf->rxmode.offloads & RTE_ETH_RX_OFFLOAD_RSS_HASH) && + ethdev->data->nb_rx_queues > 1)) { + PMD_DRV_LOG(INFO, "RSS is not enabled"); + return 0; + } + + if (netdev->rss_enable) + return 0; + + ret = sssnic_rss_profile_create(hw); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to create RSS profile"); + return ret; + } + + rss_conf = &dev_conf->rx_adv_conf.rss_conf; + ret = sssnic_ethdev_rss_hash_update(ethdev, rss_conf); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to setup RSS config"); + goto err_out; + } + + ret = sssnic_rss_hash_engine_set(hw, SSSNIC_RSS_HASH_ENGINE_TOEP); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to set RSS hash engine"); + goto err_out; + } + + ret = sssnic_rss_enable_set(hw, true); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to enable RSS"); + goto err_out; + } + + netdev->rss_enable = true; + + PMD_DRV_LOG(INFO, "Enabled RSS"); + + return 0; + +err_out: + sssnic_rss_profile_destroy(hw); + return ret; +} + +int +sssnic_ethdev_rss_shutdown(struct rte_eth_dev *ethdev) +{ + struct sssnic_netdev *netdev = SSSNIC_ETHDEV_PRIVATE(ethdev); + struct sssnic_hw *hw = SSSNIC_ETHDEV_TO_HW(ethdev); + int ret; + + if (!netdev->rss_enable) + return 0; + + ret = sssnic_rss_enable_set(hw, false); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to disable rss"); + return ret; + } + + ret = sssnic_rss_profile_destroy(hw); + if (ret != 0) { + PMD_DRV_LOG(ERR, "Failed to delete rss profile"); + return ret; + } + + netdev->rss_enable = false; + + return 0; +} diff --git a/drivers/net/sssnic/sssnic_ethdev_rss.h b/drivers/net/sssnic/sssnic_ethdev_rss.h new file mode 100644 index 0000000000..559722eec7 --- /dev/null +++ b/drivers/net/sssnic/sssnic_ethdev_rss.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018-2022 Shenzhen 3SNIC Information Technology Co., Ltd. + */ + +#ifndef _SSSNIC_ETHDEV_RSS_H_ +#define _SSSNIC_ETHDEV_RSS_H_ + +int sssnic_ethdev_rss_hash_update(struct rte_eth_dev *ethdev, + struct rte_eth_rss_conf *rss_conf); +int sssnic_ethdev_rss_hash_config_get(struct rte_eth_dev *ethdev, + struct rte_eth_rss_conf *rss_conf); +int sssnic_ethdev_rss_reta_update(struct rte_eth_dev *ethdev, + struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size); +int sssnic_ethdev_rss_reta_query(struct rte_eth_dev *ethdev, + struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size); +int sssnic_ethdev_rss_reta_reset(struct rte_eth_dev *ethdev); +int sssnic_ethdev_rss_setup(struct rte_eth_dev *ethdev); +int sssnic_ethdev_rss_shutdown(struct rte_eth_dev *ethdev); + +#endif /* _SSSNIC_ETHDEV_RSS_H_ */ diff --git a/drivers/net/sssnic/sssnic_ethdev_rx.c b/drivers/net/sssnic/sssnic_ethdev_rx.c index 82e65f2482..2874a93a54 100644 --- a/drivers/net/sssnic/sssnic_ethdev_rx.c +++ b/drivers/net/sssnic/sssnic_ethdev_rx.c @@ -10,6 +10,7 @@ #include "sssnic_log.h" #include "sssnic_ethdev.h" #include "sssnic_ethdev_rx.h" +#include "sssnic_ethdev_rss.h" #include "base/sssnic_hw.h" #include "base/sssnic_workq.h" #include "base/sssnic_api.h" @@ -640,6 +641,10 @@ sssnic_ethdev_rx_queue_start(struct rte_eth_dev *ethdev, uint16_t queue_id) netdev->num_started_rxqs++; ethdev->data->rx_queue_state[queue_id] = RTE_ETH_QUEUE_STATE_STARTED; + ret = sssnic_ethdev_rss_reta_reset(ethdev); + if (ret) + PMD_DRV_LOG(WARNING, "Failed to reset RSS reta"); + PMD_DRV_LOG(DEBUG, "port %u rxq %u started", ethdev->data->port_id, queue_id); @@ -673,6 +678,10 @@ sssnic_ethdev_rx_queue_stop(struct rte_eth_dev *ethdev, uint16_t queue_id) netdev->num_started_rxqs--; ethdev->data->rx_queue_state[queue_id] = RTE_ETH_QUEUE_STATE_STOPPED; + ret = sssnic_ethdev_rss_reta_reset(ethdev); + if (ret) + PMD_DRV_LOG(WARNING, "Failed to reset RSS reta"); + PMD_DRV_LOG(DEBUG, "port %u rxq %u stopped", ethdev->data->port_id, queue_id); @@ -704,6 +713,10 @@ sssnic_ethdev_rx_queue_all_start(struct rte_eth_dev *ethdev) ethdev->data->port_id, qid); } + ret = sssnic_ethdev_rss_reta_reset(ethdev); + if (ret) + PMD_DRV_LOG(WARNING, "Failed to reset RSS reta"); + ret = sssnic_port_enable_set(hw, true); if (ret) { PMD_DRV_LOG(ERR, "Failed to enable port:%u",