@@ -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
@@ -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;
+}
@@ -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_ */
@@ -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_ */
@@ -22,4 +22,5 @@ sources = files(
'sssnic_ethdev_rx.c',
'sssnic_ethdev_tx.c',
'sssnic_ethdev_stats.c',
+ 'sssnic_ethdev_rss.c',
)
@@ -14,6 +14,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);
@@ -543,6 +544,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) {
@@ -573,6 +581,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);
@@ -615,6 +624,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);
@@ -755,6 +767,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
@@ -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) \
new file mode 100644
@@ -0,0 +1,378 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2022 Shenzhen 3SNIC Information Technology Co., Ltd.
+ */
+
+#include <error.h>
+#include <rte_common.h>
+#include <ethdev_pci.h>
+
+#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;
+}
new file mode 100644
@@ -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_ */
@@ -11,6 +11,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"
@@ -641,6 +642,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);
@@ -674,6 +679,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);
@@ -705,6 +714,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",