From: Yanling Song <songyl@ramaxel.com>
To: <dev@dpdk.org>
Cc: <songyl@ramaxel.com>, <yanling.song@linux.dev>,
<yanggan@ramaxel.com>, <xuyun@ramaxel.com>,
<ferruh.yigit@intel.com>
Subject: [PATCH v3 13/25] net/spnic: support Rx congfiguration
Date: Fri, 24 Dec 2021 16:32:31 +0800 [thread overview]
Message-ID: <cb5fd4553441d685e26a7db95fce869c10898f9a.1640332922.git.songyl@ramaxel.com> (raw)
In-Reply-To: <cover.1640332922.git.songyl@ramaxel.com>
This patch Rx/Tx configuration including Rx csum offload, LRO, RSS,
VLAN filter and VLAN offload.
Signed-off-by: Yanling Song <songyl@ramaxel.com>
---
drivers/net/spnic/base/spnic_nic_cfg.c | 525 +++++++++++++++++++++++++
drivers/net/spnic/base/spnic_nic_cfg.h | 387 ++++++++++++++++++
drivers/net/spnic/spnic_ethdev.c | 187 ++++++++-
drivers/net/spnic/spnic_ethdev.h | 2 +
drivers/net/spnic/spnic_rx.c | 221 +++++++++++
drivers/net/spnic/spnic_rx.h | 31 ++
6 files changed, 1349 insertions(+), 4 deletions(-)
diff --git a/drivers/net/spnic/base/spnic_nic_cfg.c b/drivers/net/spnic/base/spnic_nic_cfg.c
index f6914f6f6d..ddaecba95d 100644
--- a/drivers/net/spnic/base/spnic_nic_cfg.c
+++ b/drivers/net/spnic/base/spnic_nic_cfg.c
@@ -271,6 +271,37 @@ int spnic_get_default_mac(void *hwdev, u8 *mac_addr, int ether_len)
return 0;
}
+static int spnic_config_vlan(void *hwdev, u8 opcode, u16 vlan_id, u16 func_id)
+{
+ struct spnic_cmd_vlan_config vlan_info;
+ u16 out_size = sizeof(vlan_info);
+ int err;
+
+ memset(&vlan_info, 0, sizeof(vlan_info));
+ vlan_info.opcode = opcode;
+ vlan_info.func_id = func_id;
+ vlan_info.vlan_id = vlan_id;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_CFG_FUNC_VLAN, &vlan_info,
+ sizeof(vlan_info), &vlan_info, &out_size);
+ if (err || !out_size || vlan_info.msg_head.status) {
+ PMD_DRV_LOG(ERR, "%s vlan failed, err: %d, status: 0x%x, out size: 0x%x",
+ opcode == SPNIC_CMD_OP_ADD ? "Add" : "Delete",
+ err, vlan_info.msg_head.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int spnic_del_vlan(void *hwdev, u16 vlan_id, u16 func_id)
+{
+ if (!hwdev)
+ return -EINVAL;
+
+ return spnic_config_vlan(hwdev, SPNIC_CMD_OP_DEL, vlan_id, func_id);
+}
+
int spnic_get_port_info(void *hwdev, struct nic_port_info *port_info)
{
struct spnic_cmd_port_info port_msg;
@@ -564,6 +595,500 @@ void spnic_free_nic_hwdev(void *hwdev)
spnic_vf_func_free(hwdev);
}
+int spnic_set_rx_mode(void *hwdev, u32 enable)
+{
+ struct spnic_rx_mode_config rx_mode_cfg;
+ u16 out_size = sizeof(rx_mode_cfg);
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ memset(&rx_mode_cfg, 0, sizeof(rx_mode_cfg));
+ rx_mode_cfg.func_id = spnic_global_func_id(hwdev);
+ rx_mode_cfg.rx_mode = enable;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_SET_RX_MODE,
+ &rx_mode_cfg, sizeof(rx_mode_cfg),
+ &rx_mode_cfg, &out_size);
+ if (err || !out_size || rx_mode_cfg.msg_head.status) {
+ PMD_DRV_LOG(ERR, "Set rx mode failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, rx_mode_cfg.msg_head.status, out_size);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int spnic_set_rx_vlan_offload(void *hwdev, u8 en)
+{
+ struct spnic_cmd_vlan_offload vlan_cfg;
+ u16 out_size = sizeof(vlan_cfg);
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ memset(&vlan_cfg, 0, sizeof(vlan_cfg));
+ vlan_cfg.func_id = spnic_global_func_id(hwdev);
+ vlan_cfg.vlan_offload = en;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_SET_RX_VLAN_OFFLOAD,
+ &vlan_cfg, sizeof(vlan_cfg),
+ &vlan_cfg, &out_size);
+ if (err || !out_size || vlan_cfg.msg_head.status) {
+ PMD_DRV_LOG(ERR, "Set rx vlan offload failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, vlan_cfg.msg_head.status, out_size);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int spnic_set_vlan_fliter(void *hwdev, u32 vlan_filter_ctrl)
+{
+ struct spnic_cmd_set_vlan_filter vlan_filter;
+ u16 out_size = sizeof(vlan_filter);
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ memset(&vlan_filter, 0, sizeof(vlan_filter));
+ vlan_filter.func_id = spnic_global_func_id(hwdev);
+ vlan_filter.vlan_filter_ctrl = vlan_filter_ctrl;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_SET_VLAN_FILTER_EN,
+ &vlan_filter, sizeof(vlan_filter),
+ &vlan_filter, &out_size);
+ if (err || !out_size || vlan_filter.msg_head.status) {
+ PMD_DRV_LOG(ERR, "Failed to set vlan filter, err: %d, status: 0x%x, out size: 0x%x",
+ err, vlan_filter.msg_head.status, out_size);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int spnic_set_rx_lro(void *hwdev, u8 ipv4_en, u8 ipv6_en,
+ u8 lro_max_pkt_len)
+{
+ struct spnic_cmd_lro_config lro_cfg;
+ u16 out_size = sizeof(lro_cfg);
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ memset(&lro_cfg, 0, sizeof(lro_cfg));
+ lro_cfg.func_id = spnic_global_func_id(hwdev);
+ lro_cfg.opcode = SPNIC_CMD_OP_SET;
+ lro_cfg.lro_ipv4_en = ipv4_en;
+ lro_cfg.lro_ipv6_en = ipv6_en;
+ lro_cfg.lro_max_pkt_len = lro_max_pkt_len;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_CFG_RX_LRO, &lro_cfg,
+ sizeof(lro_cfg), &lro_cfg, &out_size);
+ if (err || !out_size || lro_cfg.msg_head.status) {
+ PMD_DRV_LOG(ERR, "Set lro offload failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, lro_cfg.msg_head.status, out_size);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int spnic_set_rx_lro_timer(void *hwdev, u32 timer_value)
+{
+ struct spnic_cmd_lro_timer lro_timer;
+ u16 out_size = sizeof(lro_timer);
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ memset(&lro_timer, 0, sizeof(lro_timer));
+ lro_timer.opcode = SPNIC_CMD_OP_SET;
+ lro_timer.timer = timer_value;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_CFG_LRO_TIMER, &lro_timer,
+ sizeof(lro_timer), &lro_timer, &out_size);
+ if (err || !out_size || lro_timer.msg_head.status) {
+ PMD_DRV_LOG(ERR, "Set lro timer failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, lro_timer.msg_head.status, out_size);
+
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int spnic_set_rx_lro_state(void *hwdev, u8 lro_en, u32 lro_timer,
+ u32 lro_max_pkt_len)
+{
+ u8 ipv4_en = 0, ipv6_en = 0;
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ ipv4_en = lro_en ? 1 : 0;
+ ipv6_en = lro_en ? 1 : 0;
+
+ PMD_DRV_LOG(INFO, "Set LRO max coalesce packet size to %uK",
+ lro_max_pkt_len);
+
+ err = spnic_set_rx_lro(hwdev, ipv4_en, ipv6_en, (u8)lro_max_pkt_len);
+ if (err)
+ return err;
+
+ /* We don't set LRO timer for VF */
+ if (spnic_func_type(hwdev) == TYPE_VF)
+ return 0;
+
+ PMD_DRV_LOG(INFO, "Set LRO timer to %u", lro_timer);
+
+ return spnic_set_rx_lro_timer(hwdev, lro_timer);
+}
+
+/* RSS config */
+int spnic_rss_template_alloc(void *hwdev)
+{
+ struct spnic_rss_template_mgmt template_mgmt;
+ u16 out_size = sizeof(template_mgmt);
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ memset(&template_mgmt, 0, sizeof(struct spnic_rss_template_mgmt));
+ template_mgmt.func_id = spnic_global_func_id(hwdev);
+ template_mgmt.cmd = NIC_RSS_CMD_TEMP_ALLOC;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_RSS_TEMP_MGR,
+ &template_mgmt, sizeof(template_mgmt),
+ &template_mgmt, &out_size);
+ if (err || !out_size || template_mgmt.msg_head.status) {
+ if (template_mgmt.msg_head.status ==
+ SPNIC_MGMT_STATUS_TABLE_FULL) {
+ PMD_DRV_LOG(ERR, "There is no more template available");
+ return -ENOSPC;
+ }
+ PMD_DRV_LOG(ERR, "Alloc rss template failed, err: %d, "
+ "status: 0x%x, out size: 0x%x",
+ err, template_mgmt.msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int spnic_rss_template_free(void *hwdev)
+{
+ struct spnic_rss_template_mgmt template_mgmt;
+ u16 out_size = sizeof(template_mgmt);
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ memset(&template_mgmt, 0, sizeof(struct spnic_rss_template_mgmt));
+ template_mgmt.func_id = spnic_global_func_id(hwdev);
+ template_mgmt.cmd = NIC_RSS_CMD_TEMP_FREE;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_RSS_TEMP_MGR,
+ &template_mgmt, sizeof(template_mgmt),
+ &template_mgmt, &out_size);
+ if (err || !out_size || template_mgmt.msg_head.status) {
+ PMD_DRV_LOG(ERR, "Free rss template failed, err: %d, "
+ "status: 0x%x, out size: 0x%x",
+ err, template_mgmt.msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int spnic_rss_cfg_hash_key(void *hwdev, u8 opcode, u8 *key)
+{
+ struct spnic_cmd_rss_hash_key hash_key;
+ u16 out_size = sizeof(hash_key);
+ int err;
+
+ if (!hwdev || !key)
+ return -EINVAL;
+
+ memset(&hash_key, 0, sizeof(struct spnic_cmd_rss_hash_key));
+ hash_key.func_id = spnic_global_func_id(hwdev);
+ hash_key.opcode = opcode;
+ if (opcode == SPNIC_CMD_OP_SET)
+ memcpy(hash_key.key, key, SPNIC_RSS_KEY_SIZE);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_CFG_RSS_HASH_KEY,
+ &hash_key, sizeof(hash_key),
+ &hash_key, &out_size);
+ if (err || !out_size || hash_key.msg_head.status) {
+ PMD_DRV_LOG(ERR, "%s hash key failed, err: %d, "
+ "status: 0x%x, out size: 0x%x",
+ opcode == SPNIC_CMD_OP_SET ? "Set" : "Get",
+ err, hash_key.msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ if (opcode == SPNIC_CMD_OP_GET)
+ memcpy(key, hash_key.key, SPNIC_RSS_KEY_SIZE);
+
+ return 0;
+}
+
+int spnic_rss_set_hash_key(void *hwdev, u8 *key)
+{
+ if (!hwdev || !key)
+ return -EINVAL;
+
+ return spnic_rss_cfg_hash_key(hwdev, SPNIC_CMD_OP_SET, key);
+}
+
+int spnic_rss_get_hash_key(void *hwdev, u8 *key)
+{
+ if (!hwdev || !key)
+ return -EINVAL;
+
+ return spnic_rss_cfg_hash_key(hwdev, SPNIC_CMD_OP_GET, key);
+}
+
+int spnic_rss_get_indir_tbl(void *hwdev, u32 *indir_table)
+{
+ struct spnic_cmd_buf *cmd_buf = NULL;
+ u16 *indir_tbl = NULL;
+ int err, i;
+
+ if (!hwdev || !indir_table)
+ return -EINVAL;
+
+ cmd_buf = spnic_alloc_cmd_buf(hwdev);
+ if (!cmd_buf) {
+ PMD_DRV_LOG(ERR, "Allocate cmd buf failed");
+ return -ENOMEM;
+ }
+
+ cmd_buf->size = sizeof(struct nic_rss_indirect_tbl);
+ err = spnic_cmdq_detail_resp(hwdev, SPNIC_MOD_L2NIC,
+ SPNIC_UCODE_CMD_GET_RSS_INDIR_TABLE,
+ cmd_buf, cmd_buf, 0);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Get rss indir table failed");
+ spnic_free_cmd_buf(cmd_buf);
+ return err;
+ }
+
+ indir_tbl = (u16 *)cmd_buf->buf;
+ for (i = 0; i < SPNIC_RSS_INDIR_SIZE; i++)
+ indir_table[i] = *(indir_tbl + i);
+
+ spnic_free_cmd_buf(cmd_buf);
+ return 0;
+}
+
+int spnic_rss_set_indir_tbl(void *hwdev, const u32 *indir_table)
+{
+ struct nic_rss_indirect_tbl *indir_tbl = NULL;
+ struct spnic_cmd_buf *cmd_buf = NULL;
+ u32 i, size;
+ u32 *temp = NULL;
+ u64 out_param = 0;
+ int err;
+
+ if (!hwdev || !indir_table)
+ return -EINVAL;
+
+ cmd_buf = spnic_alloc_cmd_buf(hwdev);
+ if (!cmd_buf) {
+ PMD_DRV_LOG(ERR, "Allocate cmd buf failed");
+ return -ENOMEM;
+ }
+
+ cmd_buf->size = sizeof(struct nic_rss_indirect_tbl);
+ indir_tbl = (struct nic_rss_indirect_tbl *)cmd_buf->buf;
+ memset(indir_tbl, 0, sizeof(*indir_tbl));
+
+ for (i = 0; i < SPNIC_RSS_INDIR_SIZE; i++)
+ indir_tbl->entry[i] = (u16)(*(indir_table + i));
+
+ size = (sizeof(indir_tbl->entry)) / (sizeof(u32));
+ temp = (u32 *)indir_tbl->entry;
+ for (i = 0; i < size; i++)
+ temp[i] = cpu_to_be32(temp[i]);
+
+ err = spnic_cmdq_direct_resp(hwdev, SPNIC_MOD_L2NIC,
+ SPNIC_UCODE_CMD_SET_RSS_INDIR_TABLE,
+ cmd_buf, &out_param, 0);
+ if (err || out_param != 0) {
+ PMD_DRV_LOG(ERR, "Set rss indir table failed");
+ err = -EFAULT;
+ }
+
+ spnic_free_cmd_buf(cmd_buf);
+ return err;
+}
+
+int spnic_set_rss_type(void *hwdev, struct spnic_rss_type rss_type)
+{
+ struct nic_rss_context_tbl *ctx_tbl = NULL;
+ struct spnic_cmd_buf *cmd_buf = NULL;
+ u32 ctx = 0;
+ u64 out_param = 0;
+ int err;
+
+ if (!hwdev)
+ return -EINVAL;
+
+ cmd_buf = spnic_alloc_cmd_buf(hwdev);
+ if (!cmd_buf) {
+ PMD_DRV_LOG(ERR, "Allocate cmd buf failed");
+ return -ENOMEM;
+ }
+
+ ctx |= SPNIC_RSS_TYPE_SET(1, VALID) |
+ SPNIC_RSS_TYPE_SET(rss_type.ipv4, IPV4) |
+ SPNIC_RSS_TYPE_SET(rss_type.ipv6, IPV6) |
+ SPNIC_RSS_TYPE_SET(rss_type.ipv6_ext, IPV6_EXT) |
+ SPNIC_RSS_TYPE_SET(rss_type.tcp_ipv4, TCP_IPV4) |
+ SPNIC_RSS_TYPE_SET(rss_type.tcp_ipv6, TCP_IPV6) |
+ SPNIC_RSS_TYPE_SET(rss_type.tcp_ipv6_ext, TCP_IPV6_EXT) |
+ SPNIC_RSS_TYPE_SET(rss_type.udp_ipv4, UDP_IPV4) |
+ SPNIC_RSS_TYPE_SET(rss_type.udp_ipv6, UDP_IPV6);
+
+ cmd_buf->size = sizeof(struct nic_rss_context_tbl);
+ ctx_tbl = (struct nic_rss_context_tbl *)cmd_buf->buf;
+ memset(ctx_tbl, 0, sizeof(*ctx_tbl));
+ ctx_tbl->ctx = cpu_to_be32(ctx);
+
+ /* Cfg the RSS context table by command queue */
+ err = spnic_cmdq_direct_resp(hwdev, SPNIC_MOD_L2NIC,
+ SPNIC_UCODE_CMD_SET_RSS_CONTEXT_TABLE,
+ cmd_buf, &out_param, 0);
+
+ spnic_free_cmd_buf(cmd_buf);
+
+ if (err || out_param != 0) {
+ PMD_DRV_LOG(ERR, "Set rss context table failed, err: %d", err);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int spnic_get_rss_type(void *hwdev, struct spnic_rss_type *rss_type)
+{
+ struct spnic_rss_context_table ctx_tbl;
+ u16 out_size = sizeof(ctx_tbl);
+ int err;
+
+ if (!hwdev || !rss_type)
+ return -EINVAL;
+
+ memset(&ctx_tbl, 0, sizeof(struct spnic_rss_context_table));
+ ctx_tbl.func_id = spnic_global_func_id(hwdev);
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_GET_RSS_CTX_TBL,
+ &ctx_tbl, sizeof(ctx_tbl),
+ &ctx_tbl, &out_size);
+ if (err || !out_size || ctx_tbl.msg_head.status) {
+ PMD_DRV_LOG(ERR, "Get hash type failed, err: %d, status: 0x%x, out size: 0x%x",
+ err, ctx_tbl.msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ rss_type->ipv4 = SPNIC_RSS_TYPE_GET(ctx_tbl.context, IPV4);
+ rss_type->ipv6 = SPNIC_RSS_TYPE_GET(ctx_tbl.context, IPV6);
+ rss_type->ipv6_ext = SPNIC_RSS_TYPE_GET(ctx_tbl.context, IPV6_EXT);
+ rss_type->tcp_ipv4 = SPNIC_RSS_TYPE_GET(ctx_tbl.context, TCP_IPV4);
+ rss_type->tcp_ipv6 = SPNIC_RSS_TYPE_GET(ctx_tbl.context, TCP_IPV6);
+ rss_type->tcp_ipv6_ext = SPNIC_RSS_TYPE_GET(ctx_tbl.context,
+ TCP_IPV6_EXT);
+ rss_type->udp_ipv4 = SPNIC_RSS_TYPE_GET(ctx_tbl.context, UDP_IPV4);
+ rss_type->udp_ipv6 = SPNIC_RSS_TYPE_GET(ctx_tbl.context, UDP_IPV6);
+
+ return 0;
+}
+
+static int spnic_rss_cfg_hash_engine(void *hwdev, u8 opcode, u8 *type)
+{
+ struct spnic_cmd_rss_engine_type hash_type;
+ u16 out_size = sizeof(hash_type);
+ int err;
+
+ if (!hwdev || !type)
+ return -EINVAL;
+
+ memset(&hash_type, 0, sizeof(struct spnic_cmd_rss_engine_type));
+ hash_type.func_id = spnic_global_func_id(hwdev);
+ hash_type.opcode = opcode;
+ if (opcode == SPNIC_CMD_OP_SET)
+ hash_type.hash_engine = *type;
+
+ err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_CFG_RSS_HASH_ENGINE,
+ &hash_type, sizeof(hash_type),
+ &hash_type, &out_size);
+ if (err || !out_size || hash_type.msg_head.status) {
+ PMD_DRV_LOG(ERR, "%s hash engine failed, err: %d, "
+ "status: 0x%x, out size: 0x%x",
+ opcode == SPNIC_CMD_OP_SET ? "Set" : "Get",
+ err, hash_type.msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ if (opcode == SPNIC_CMD_OP_GET)
+ *type = hash_type.hash_engine;
+
+ return 0;
+}
+
+int spnic_rss_get_hash_engine(void *hwdev, u8 *type)
+{
+ if (!hwdev || !type)
+ return -EINVAL;
+
+ return spnic_rss_cfg_hash_engine(hwdev, SPNIC_CMD_OP_GET, type);
+}
+
+int spnic_rss_set_hash_engine(void *hwdev, u8 type)
+{
+ if (!hwdev)
+ return -EINVAL;
+
+ return spnic_rss_cfg_hash_engine(hwdev, SPNIC_CMD_OP_SET, &type);
+}
+
+int spnic_rss_cfg(void *hwdev, u8 rss_en, u8 tc_num, u8 *prio_tc)
+{
+ struct spnic_cmd_rss_config rss_cfg;
+ u16 out_size = sizeof(rss_cfg);
+ int err;
+
+ /* Ucode requires number of TC should be power of 2 */
+ if (!hwdev || !prio_tc || (tc_num & (tc_num - 1)))
+ return -EINVAL;
+
+ memset(&rss_cfg, 0, sizeof(struct spnic_cmd_rss_config));
+ rss_cfg.func_id = spnic_global_func_id(hwdev);
+ rss_cfg.rss_en = rss_en;
+ rss_cfg.rq_priority_number = tc_num ? (u8)ilog2(tc_num) : 0;
+
+ memcpy(rss_cfg.prio_tc, prio_tc, SPNIC_DCB_UP_MAX);
+ err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_RSS_CFG, &rss_cfg,
+ sizeof(rss_cfg), &rss_cfg, &out_size);
+ if (err || !out_size || rss_cfg.msg_head.status) {
+ PMD_DRV_LOG(ERR, "Set rss cfg failed, err: %d, "
+ "status: 0x%x, out size: 0x%x",
+ err, rss_cfg.msg_head.status, out_size);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
int spnic_vf_get_default_cos(void *hwdev, u8 *cos_id)
{
struct spnic_cmd_vf_dcb_state vf_dcb;
diff --git a/drivers/net/spnic/base/spnic_nic_cfg.h b/drivers/net/spnic/base/spnic_nic_cfg.h
index 31d2607234..1044af3dcc 100644
--- a/drivers/net/spnic/base/spnic_nic_cfg.h
+++ b/drivers/net/spnic/base/spnic_nic_cfg.h
@@ -12,6 +12,8 @@
#define OS_VF_ID_TO_HW(os_vf_id) ((os_vf_id) + 1)
#define HW_VF_ID_TO_OS(hw_vf_id) ((hw_vf_id) - 1)
+#define SPNIC_VLAN_PRIORITY_SHIFT 13
+
#define SPNIC_DCB_UP_MAX 0x8
#define SPNIC_MAX_NUM_RQ 256
@@ -36,6 +38,38 @@
#define SPNIC_MGMT_STATUS_EXIST 0x6
#define CHECK_IPSU_15BIT 0x8000
+#define SPNIC_MGMT_STATUS_TABLE_EMPTY 0xB
+#define SPNIC_MGMT_STATUS_TABLE_FULL 0xC
+
+#define SPNIC_MGMT_CMD_UNSUPPORTED 0xFF
+
+#define SPNIC_MAX_UC_MAC_ADDRS 128
+#define SPNIC_MAX_MC_MAC_ADDRS 128
+
+/* Structures for RSS config */
+#define SPNIC_RSS_INDIR_SIZE 256
+#define SPNIC_RSS_INDIR_CMDQ_SIZE 128
+#define SPNIC_RSS_KEY_SIZE 40
+#define SPNIC_RSS_ENABLE 0x01
+#define SPNIC_RSS_DISABLE 0x00
+
+struct spnic_rss_type {
+ u8 tcp_ipv6_ext;
+ u8 ipv6_ext;
+ u8 tcp_ipv6;
+ u8 ipv6;
+ u8 tcp_ipv4;
+ u8 ipv4;
+ u8 udp_ipv6;
+ u8 udp_ipv4;
+};
+
+enum spnic_rss_hash_type {
+ SPNIC_RSS_HASH_ENGINE_TYPE_XOR = 0,
+ SPNIC_RSS_HASH_ENGINE_TYPE_TOEP,
+ SPNIC_RSS_HASH_ENGINE_TYPE_MAX,
+};
+
struct spnic_cmd_feature_nego {
struct mgmt_msg_head msg_head;
@@ -121,6 +155,29 @@ struct spnic_port_mac_update {
u16 rsvd2;
u8 new_mac[ETH_ALEN];
};
+
+#define SPNIC_CMD_OP_ADD 1
+#define SPNIC_CMD_OP_DEL 0
+
+struct spnic_cmd_vlan_config {
+ struct mgmt_msg_head msg_head;
+
+ u16 func_id;
+ u8 opcode;
+ u8 rsvd1;
+ u16 vlan_id;
+ u16 rsvd2;
+};
+
+struct spnic_cmd_set_vlan_filter {
+ struct mgmt_msg_head msg_head;
+
+ u16 func_id;
+ u8 resvd[2];
+ /* Bit0: vlan filter en; bit1: broadcast filter en */
+ u32 vlan_filter_ctrl;
+};
+
struct spnic_cmd_port_info {
struct mgmt_msg_head msg_head;
@@ -225,9 +282,109 @@ struct spnic_cmd_set_func_tbl {
struct spnic_func_tbl_cfg tbl_cfg;
};
+struct spnic_rx_mode_config {
+ struct mgmt_msg_head msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+ u32 rx_mode;
+};
+
+struct spnic_cmd_vlan_offload {
+ struct mgmt_msg_head msg_head;
+
+ u16 func_id;
+ u8 vlan_offload;
+ u8 rsvd1[5];
+};
+
#define SPNIC_CMD_OP_GET 0
#define SPNIC_CMD_OP_SET 1
+struct spnic_cmd_lro_config {
+ struct mgmt_msg_head msg_head;
+
+ u16 func_id;
+ u8 opcode;
+ u8 rsvd1;
+ u8 lro_ipv4_en;
+ u8 lro_ipv6_en;
+ u8 lro_max_pkt_len; /* Unit size is 1K */
+ u8 resv2[13];
+};
+
+struct spnic_cmd_lro_timer {
+ struct mgmt_msg_head msg_head;
+
+ u8 opcode; /* 1: set timer value, 0: get timer value */
+ u8 rsvd1;
+ u16 rsvd2;
+ u32 timer;
+};
+
+struct spnic_rss_template_mgmt {
+ struct mgmt_msg_head msg_head;
+
+ u16 func_id;
+ u8 cmd;
+ u8 template_id;
+ u8 rsvd1[4];
+};
+
+struct spnic_cmd_rss_hash_key {
+ struct mgmt_msg_head msg_head;
+
+ u16 func_id;
+ u8 opcode;
+ u8 rsvd1;
+ u8 key[SPNIC_RSS_KEY_SIZE];
+};
+
+struct spnic_rss_indir_table {
+ struct mgmt_msg_head msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+ u8 indir[SPNIC_RSS_INDIR_SIZE];
+};
+
+struct nic_rss_indirect_tbl {
+ u32 rsvd[4]; /* Make sure that 16B beyond entry[] */
+ u16 entry[SPNIC_RSS_INDIR_SIZE];
+};
+
+struct nic_rss_context_tbl {
+ u32 rsvd[4];
+ u32 ctx;
+};
+
+struct spnic_rss_context_table {
+ struct mgmt_msg_head msg_head;
+
+ u16 func_id;
+ u16 rsvd1;
+ u32 context;
+};
+
+struct spnic_cmd_rss_engine_type {
+ struct mgmt_msg_head msg_head;
+
+ u16 func_id;
+ u8 opcode;
+ u8 hash_engine;
+ u8 rsvd1[4];
+};
+
+struct spnic_cmd_rss_config {
+ struct mgmt_msg_head msg_head;
+
+ u16 func_id;
+ u8 rss_en;
+ u8 rq_priority_number;
+ u8 prio_tc[SPNIC_DCB_UP_MAX];
+ u32 rsvd1;
+};
+
enum {
SPNIC_IFLA_VF_LINK_STATE_AUTO, /* Link state of the uplink */
SPNIC_IFLA_VF_LINK_STATE_ENABLE, /* Link always up */
@@ -423,6 +580,50 @@ int spnic_init_nic_hwdev(void *hwdev);
*/
void spnic_free_nic_hwdev(void *hwdev);
+/**
+ * Set function rx mode
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[in] enable
+ * Rx mode state, 0-disable, 1-enable
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_set_rx_mode(void *hwdev, u32 enable);
+
+/**
+ * Set function vlan offload valid state
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[in] enable
+ * Rx mode state, 0-disable, 1-enable
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_set_rx_vlan_offload(void *hwdev, u8 en);
+
+/**
+ * Set rx LRO configuration
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[in] lro_en
+ * LRO enable state, 0-disable, 1-enable
+ * @param[in] lro_timer
+ * LRO aggregation timeout
+ * @param[in] lro_max_pkt_len
+ * LRO coalesce packet size(unit size is 1K)
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_set_rx_lro_state(void *hwdev, u8 lro_en, u32 lro_timer,
+ u32 lro_max_pkt_len);
+
/**
* Get port info
*
@@ -438,6 +639,192 @@ int spnic_get_port_info(void *hwdev, struct nic_port_info *port_info);
int spnic_init_function_table(void *hwdev, u16 rx_buff_len);
+/**
+ * Alloc RSS template table
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_rss_template_alloc(void *hwdev);
+
+/**
+ * Free RSS template table
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_rss_template_free(void *hwdev);
+
+/**
+ * Set RSS indirect table
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[in] indir_table
+ * RSS indirect table
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_rss_set_indir_tbl(void *hwdev, const u32 *indir_table);
+
+/**
+ * Get RSS indirect table
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[out] indir_table
+ * RSS indirect table
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_rss_get_indir_tbl(void *hwdev, u32 *indir_table);
+
+/**
+ * Set RSS type
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[in] rss_type
+ * RSS type, including ipv4, tcpv4, ipv6, tcpv6 and etc.
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_set_rss_type(void *hwdev, struct spnic_rss_type rss_type);
+
+/**
+ * Get RSS type
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[out] rss_type
+ * RSS type, including ipv4, tcpv4, ipv6, tcpv6 and etc.
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_get_rss_type(void *hwdev, struct spnic_rss_type *rss_type);
+
+/**
+ * Get RSS hash engine
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[out] type
+ * RSS hash engine, pmd driver only supports Toeplitz
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_rss_get_hash_engine(void *hwdev, u8 *type);
+
+/**
+ * Set RSS hash engine
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[in] type
+ * RSS hash engine, pmd driver only supports Toeplitz
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_rss_set_hash_engine(void *hwdev, u8 type);
+
+/**
+ * Set RSS configuration
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[in] rss_en
+ * RSS enable lag, 0-disable, 1-enable
+ * @param[in] tc_num
+ * Number of TC
+ * @param[in] prio_tc
+ * Priority of TC
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_rss_cfg(void *hwdev, u8 rss_en, u8 tc_num, u8 *prio_tc);
+
+/**
+ * Set RSS hash key
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[in] key
+ * RSS hash key
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_rss_set_hash_key(void *hwdev, u8 *key);
+
+/**
+ * Get RSS hash key
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[out] key
+ * RSS hash key
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_rss_get_hash_key(void *hwdev, u8 *key);
+
+/**
+ * Add vlan to hardware
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[in] vlan_id
+ * Vlan id
+ * @param[in] func_id
+ * Function id
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_add_vlan(void *hwdev, u16 vlan_id, u16 func_id);
+
+/**
+ * Delete vlan
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[in] vlan_id
+ * Vlan id
+ * @param[in] func_id
+ * Function id
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_del_vlan(void *hwdev, u16 vlan_id, u16 func_id);
+
+/**
+ * Set vlan filter
+ *
+ * @param[in] hwdev
+ * Device pointer to hwdev
+ * @param[in] vlan_filter_ctrl
+ * Vlan filter enable flag, 0-disable, 1-enable
+ *
+ * @retval zero : Success
+ * @retval non-zero : Failure
+ */
+int spnic_set_vlan_fliter(void *hwdev, u32 vlan_filter_ctrl);
+
/**
* Get VF function default cos
*
diff --git a/drivers/net/spnic/spnic_ethdev.c b/drivers/net/spnic/spnic_ethdev.c
index 27942e5d68..74d09bafac 100644
--- a/drivers/net/spnic/spnic_ethdev.c
+++ b/drivers/net/spnic/spnic_ethdev.c
@@ -5,7 +5,10 @@
#include <rte_pci.h>
#include <rte_bus_pci.h>
#include <ethdev_pci.h>
+#include <rte_mbuf.h>
#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_mempool.h>
#include <rte_errno.h>
#include <rte_ether.h>
@@ -27,14 +30,41 @@
#include "spnic_rx.h"
#include "spnic_ethdev.h"
-/* Driver-specific log messages type */
-int spnic_logtype;
+#define SPNIC_MIN_RX_BUF_SIZE 1024
+
+#define SPNIC_DEFAULT_BURST_SIZE 32
+#define SPNIC_DEFAULT_NB_QUEUES 1
+#define SPNIC_DEFAULT_RING_SIZE 1024
+#define SPNIC_MAX_LRO_SIZE 65536
#define SPNIC_DEFAULT_RX_FREE_THRESH 32
#define SPNIC_DEFAULT_TX_FREE_THRESH 32
-#define SPNIC_MAX_UC_MAC_ADDRS 128
-#define SPNIC_MAX_MC_MAC_ADDRS 128
+/*
+ * Vlan_id is a 12 bit number. The VFTA array is actually a 4096 bit array,
+ * 128 of 32bit elements. 2^5 = 32. The val of lower 5 bits specifies the bit
+ * in the 32bit element. The higher 7 bit val specifies VFTA array index.
+ */
+#define SPNIC_VFTA_BIT(vlan_id) (1 << ((vlan_id) & 0x1F))
+#define SPNIC_VFTA_IDX(vlan_id) ((vlan_id) >> 5)
+
+#define SPNIC_LRO_DEFAULT_COAL_PKT_SIZE 32
+#define SPNIC_LRO_DEFAULT_TIME_LIMIT 16
+#define SPNIC_LRO_UNIT_WQE_SIZE 1024 /* Bytes */
+
+/* Driver-specific log messages type */
+int spnic_logtype;
+
+enum spnic_rx_mod {
+ SPNIC_RX_MODE_UC = 1 << 0,
+ SPNIC_RX_MODE_MC = 1 << 1,
+ SPNIC_RX_MODE_BC = 1 << 2,
+ SPNIC_RX_MODE_MC_ALL = 1 << 3,
+ SPNIC_RX_MODE_PROMISC = 1 << 4,
+};
+
+#define SPNIC_DEFAULT_RX_MODE (SPNIC_RX_MODE_UC | SPNIC_RX_MODE_MC | \
+ SPNIC_RX_MODE_BC)
#define SPNIC_MAX_QUEUE_DEPTH 16384
#define SPNIC_MIN_QUEUE_DEPTH 128
@@ -638,6 +668,139 @@ static void spnic_deinit_mac_addr(struct rte_eth_dev *eth_dev)
spnic_delete_mc_addr_list(nic_dev);
}
+static int spnic_set_rxtx_configure(struct rte_eth_dev *dev)
+{
+ struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+ struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
+ struct rte_eth_rss_conf *rss_conf = NULL;
+ bool lro_en, vlan_filter, vlan_strip;
+ int max_lro_size, lro_max_pkt_len;
+ int err;
+
+ /* Config rx mode */
+ err = spnic_set_rx_mode(nic_dev->hwdev, SPNIC_DEFAULT_RX_MODE);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Set rx_mode: 0x%x failed",
+ SPNIC_DEFAULT_RX_MODE);
+ return err;
+ }
+ nic_dev->rx_mode = SPNIC_DEFAULT_RX_MODE;
+
+ /* Config rx checksum offload */
+ if (dev_conf->rxmode.offloads & DEV_RX_OFFLOAD_CHECKSUM)
+ nic_dev->rx_csum_en = SPNIC_DEFAULT_RX_CSUM_OFFLOAD;
+
+ /* Config lro */
+ lro_en = dev_conf->rxmode.offloads & DEV_RX_OFFLOAD_TCP_LRO ?
+ true : false;
+ max_lro_size = dev->data->dev_conf.rxmode.max_lro_pkt_size;
+ lro_max_pkt_len = max_lro_size / SPNIC_LRO_UNIT_WQE_SIZE ?
+ max_lro_size / SPNIC_LRO_UNIT_WQE_SIZE : 1;
+
+ PMD_DRV_LOG(INFO, "max_lro_size: %d, rx_buff_len: %d, lro_max_pkt_len: %d mtu: %d",
+ max_lro_size, nic_dev->rx_buff_len, lro_max_pkt_len,
+ dev->data->dev_conf.rxmode.mtu);
+
+ err = spnic_set_rx_lro_state(nic_dev->hwdev, lro_en,
+ SPNIC_LRO_DEFAULT_TIME_LIMIT,
+ lro_max_pkt_len);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Set lro state failed, err: %d", err);
+ return err;
+ }
+
+ /* Config RSS */
+ if ((dev_conf->rxmode.mq_mode & ETH_MQ_RX_RSS_FLAG) &&
+ nic_dev->num_rqs > 1) {
+ rss_conf = &dev_conf->rx_adv_conf.rss_conf;
+ err = spnic_update_rss_config(dev, rss_conf);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Set rss config failed, err: %d", err);
+ return err;
+ }
+ }
+
+ /* Config vlan filter */
+ vlan_filter = dev_conf->rxmode.offloads & DEV_RX_OFFLOAD_VLAN_FILTER ?
+ true : false;
+
+ err = spnic_set_vlan_fliter(nic_dev->hwdev, vlan_filter);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Config vlan filter failed, device: %s, port_id: %d, err: %d",
+ nic_dev->dev_name, dev->data->port_id, err);
+ return err;
+ }
+
+ /* Config vlan stripping */
+ vlan_strip = dev_conf->rxmode.offloads & DEV_RX_OFFLOAD_VLAN_STRIP ?
+ true : false;
+
+ err = spnic_set_rx_vlan_offload(nic_dev->hwdev, vlan_strip);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Config vlan strip failed, device: %s, port_id: %d, err: %d",
+ nic_dev->dev_name, dev->data->port_id, err);
+ return err;
+ }
+
+ spnic_init_rx_queue_list(nic_dev);
+
+ return 0;
+}
+
+static void spnic_remove_rxtx_configure(struct rte_eth_dev *dev)
+{
+ struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+ u8 prio_tc[SPNIC_DCB_UP_MAX] = {0};
+
+ spnic_set_rx_mode(nic_dev->hwdev, 0);
+
+ if (nic_dev->rss_state == SPNIC_RSS_ENABLE) {
+ spnic_rss_cfg(nic_dev->hwdev, SPNIC_RSS_DISABLE, 0, prio_tc);
+ spnic_rss_template_free(nic_dev->hwdev);
+ }
+}
+
+static bool spnic_find_vlan_filter(struct spnic_nic_dev *nic_dev,
+ uint16_t vlan_id)
+{
+ u32 vid_idx, vid_bit;
+
+ vid_idx = SPNIC_VFTA_IDX(vlan_id);
+ vid_bit = SPNIC_VFTA_BIT(vlan_id);
+
+ return (nic_dev->vfta[vid_idx] & vid_bit) ? true : false;
+}
+
+static void spnic_store_vlan_filter(struct spnic_nic_dev *nic_dev,
+ u16 vlan_id, bool on)
+{
+ u32 vid_idx, vid_bit;
+
+ vid_idx = SPNIC_VFTA_IDX(vlan_id);
+ vid_bit = SPNIC_VFTA_BIT(vlan_id);
+
+ if (on)
+ nic_dev->vfta[vid_idx] |= vid_bit;
+ else
+ nic_dev->vfta[vid_idx] &= ~vid_bit;
+}
+
+static void spnic_remove_all_vlanid(struct rte_eth_dev *dev)
+{
+ struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+ int vlan_id;
+ u16 func_id;
+
+ func_id = spnic_global_func_id(nic_dev->hwdev);
+
+ for (vlan_id = 1; vlan_id < RTE_ETHER_MAX_VLAN_ID; vlan_id++) {
+ if (spnic_find_vlan_filter(nic_dev, vlan_id)) {
+ spnic_del_vlan(nic_dev->hwdev, vlan_id, func_id);
+ spnic_store_vlan_filter(nic_dev, vlan_id, false);
+ }
+ }
+}
+
static int spnic_init_sw_rxtxqs(struct spnic_nic_dev *nic_dev)
{
u32 txq_size;
@@ -736,6 +899,14 @@ static int spnic_dev_start(struct rte_eth_dev *eth_dev)
goto set_mtu_fail;
}
+ /* Set rx configuration: rss/checksum/rxmode/lro */
+ err = spnic_set_rxtx_configure(eth_dev);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Set rx config failed, dev_name: %s",
+ eth_dev->data->name);
+ goto set_rxtx_config_fail;
+ }
+
err = spnic_start_all_rqs(eth_dev);
if (err) {
PMD_DRV_LOG(ERR, "Set rx config failed, dev_name: %s",
@@ -754,6 +925,9 @@ static int spnic_dev_start(struct rte_eth_dev *eth_dev)
return 0;
start_rqs_fail:
+ spnic_remove_rxtx_configure(eth_dev);
+
+set_rxtx_config_fail:
set_mtu_fail:
spnic_free_qp_ctxts(nic_dev->hwdev);
@@ -793,6 +967,10 @@ static int spnic_dev_stop(struct rte_eth_dev *dev)
spnic_flush_txqs(nic_dev);
spnic_flush_qps_res(nic_dev->hwdev);
+
+ /* Clean RSS table and rx_mode */
+ spnic_remove_rxtx_configure(dev);
+
/* Clean root context */
spnic_free_qp_ctxts(nic_dev->hwdev);
@@ -833,6 +1011,7 @@ static int spnic_dev_close(struct rte_eth_dev *eth_dev)
spnic_deinit_sw_rxtxqs(nic_dev);
spnic_deinit_mac_addr(eth_dev);
rte_free(nic_dev->mc_list);
+ spnic_remove_all_vlanid(eth_dev);
rte_bit_relaxed_clear32(SPNIC_DEV_INTR_EN, &nic_dev->dev_status);
diff --git a/drivers/net/spnic/spnic_ethdev.h b/drivers/net/spnic/spnic_ethdev.h
index 321db389dc..996b4e4b8f 100644
--- a/drivers/net/spnic/spnic_ethdev.h
+++ b/drivers/net/spnic/spnic_ethdev.h
@@ -63,6 +63,8 @@ struct spnic_nic_dev {
u32 default_cos;
u32 rx_csum_en;
+ u8 rss_key[SPNIC_RSS_KEY_SIZE];
+
u32 dev_status;
bool pause_set;
diff --git a/drivers/net/spnic/spnic_rx.c b/drivers/net/spnic/spnic_rx.c
index a81b12cd04..e135b90162 100644
--- a/drivers/net/spnic/spnic_rx.c
+++ b/drivers/net/spnic/spnic_rx.c
@@ -265,19 +265,240 @@ static inline void spnic_rearm_rxq_mbuf(struct spnic_rxq *rxq)
((pi + rearm_wqebbs) & rxq->q_mask) << rxq->wqe_type);
}
+static int spnic_init_rss_key(struct spnic_nic_dev *nic_dev,
+ struct rte_eth_rss_conf *rss_conf)
+{
+ u8 default_rss_key[SPNIC_RSS_KEY_SIZE] = {
+ 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};
+ u8 hashkey[SPNIC_RSS_KEY_SIZE] = {0};
+ int err;
+
+ if (rss_conf->rss_key == NULL ||
+ rss_conf->rss_key_len > SPNIC_RSS_KEY_SIZE)
+ memcpy(hashkey, default_rss_key, SPNIC_RSS_KEY_SIZE);
+ else
+ memcpy(hashkey, rss_conf->rss_key, rss_conf->rss_key_len);
+
+ err = spnic_rss_set_hash_key(nic_dev->hwdev, hashkey);
+ if (err)
+ return err;
+
+ memcpy(nic_dev->rss_key, hashkey, SPNIC_RSS_KEY_SIZE);
+ return 0;
+}
+
+void spnic_add_rq_to_rx_queue_list(struct spnic_nic_dev *nic_dev,
+ u16 queue_id)
+{
+ u8 rss_queue_count = nic_dev->num_rss;
+
+ RTE_ASSERT(rss_queue_count <= (RTE_DIM(nic_dev->rx_queue_list) - 1));
+
+ nic_dev->rx_queue_list[rss_queue_count] = (u8)queue_id;
+ nic_dev->num_rss++;
+}
+
+void spnic_init_rx_queue_list(struct spnic_nic_dev *nic_dev)
+{
+ nic_dev->num_rss = 0;
+}
+
+static void spnic_fill_indir_tbl(struct spnic_nic_dev *nic_dev,
+ u32 *indir_tbl)
+{
+ u8 rss_queue_count = nic_dev->num_rss;
+ int i = 0;
+ int j;
+
+ if (rss_queue_count == 0) {
+ /* delete q_id from indir tbl */
+ for (i = 0; i < SPNIC_RSS_INDIR_SIZE; i++)
+ indir_tbl[i] = 0xFF; /* Invalid value in indir tbl */
+ } else {
+ while (i < SPNIC_RSS_INDIR_SIZE)
+ for (j = 0; (j < rss_queue_count) &&
+ (i < SPNIC_RSS_INDIR_SIZE); j++)
+ indir_tbl[i++] = nic_dev->rx_queue_list[j];
+ }
+}
+
+int spnic_refill_indir_rqid(struct spnic_rxq *rxq)
+{
+ struct spnic_nic_dev *nic_dev = rxq->nic_dev;
+ u32 *indir_tbl;
+ int err;
+
+ indir_tbl = rte_zmalloc(NULL, SPNIC_RSS_INDIR_SIZE * sizeof(u32), 0);
+ if (!indir_tbl) {
+ PMD_DRV_LOG(ERR, "Alloc indir_tbl mem failed, eth_dev:%s, queue_idx:%d\n",
+ nic_dev->dev_name, rxq->q_id);
+ return -ENOMEM;
+ }
+
+ /* build indir tbl according to the number of rss queue */
+ spnic_fill_indir_tbl(nic_dev, indir_tbl);
+
+ err = spnic_rss_set_indir_tbl(nic_dev->hwdev, indir_tbl);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Set indrect table failed, eth_dev:%s, queue_idx:%d\n",
+ nic_dev->dev_name, rxq->q_id);
+ goto out;
+ }
+
+out:
+ rte_free(indir_tbl);
+ return err;
+}
+
+static int spnic_init_rss_type(struct spnic_nic_dev *nic_dev,
+ struct rte_eth_rss_conf *rss_conf)
+{
+ struct spnic_rss_type rss_type = {0};
+ u64 rss_hf = rss_conf->rss_hf;
+ int err;
+
+ rss_type.ipv4 = (rss_hf & (ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4)) ? 1 : 0;
+ rss_type.tcp_ipv4 = (rss_hf & ETH_RSS_NONFRAG_IPV4_TCP) ? 1 : 0;
+ rss_type.ipv6 = (rss_hf & (ETH_RSS_IPV6 | ETH_RSS_FRAG_IPV6)) ? 1 : 0;
+ rss_type.ipv6_ext = (rss_hf & ETH_RSS_IPV6_EX) ? 1 : 0;
+ rss_type.tcp_ipv6 = (rss_hf & ETH_RSS_NONFRAG_IPV6_TCP) ? 1 : 0;
+ rss_type.tcp_ipv6_ext = (rss_hf & ETH_RSS_IPV6_TCP_EX) ? 1 : 0;
+ rss_type.udp_ipv4 = (rss_hf & ETH_RSS_NONFRAG_IPV4_UDP) ? 1 : 0;
+ rss_type.udp_ipv6 = (rss_hf & ETH_RSS_NONFRAG_IPV6_UDP) ? 1 : 0;
+
+ err = spnic_set_rss_type(nic_dev->hwdev, rss_type);
+ return err;
+}
+
+int spnic_update_rss_config(struct rte_eth_dev *dev,
+ struct rte_eth_rss_conf *rss_conf)
+{
+ struct spnic_nic_dev *nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(dev);
+ u8 prio_tc[SPNIC_DCB_UP_MAX] = {0};
+ u8 num_tc = 0;
+ int err;
+
+ if (rss_conf->rss_hf == 0) {
+ rss_conf->rss_hf = SPNIC_RSS_OFFLOAD_ALL;
+ } else if ((rss_conf->rss_hf & SPNIC_RSS_OFFLOAD_ALL) == 0) {
+ PMD_DRV_LOG(ERR, "Doesn't support rss hash type: %" PRIu64 "",
+ rss_conf->rss_hf);
+ return -EINVAL;
+ }
+
+ err = spnic_rss_template_alloc(nic_dev->hwdev);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Alloc rss template failed, err: %d", err);
+ return err;
+ }
+
+ err = spnic_init_rss_key(nic_dev, rss_conf);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Init rss hash key failed, err: %d", err);
+ goto init_rss_fail;
+ }
+
+ err = spnic_init_rss_type(nic_dev, rss_conf);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Init rss hash type failed, err: %d", err);
+ goto init_rss_fail;
+ }
+
+ err = spnic_rss_set_hash_engine(nic_dev->hwdev,
+ SPNIC_RSS_HASH_ENGINE_TYPE_TOEP);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Init rss hash function failed, err: %d", err);
+ goto init_rss_fail;
+ }
+
+ err = spnic_rss_cfg(nic_dev->hwdev, SPNIC_RSS_ENABLE, num_tc,
+ prio_tc);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Enable rss failed, err: %d", err);
+ goto init_rss_fail;
+ }
+
+ nic_dev->rss_state = SPNIC_RSS_ENABLE;
+ return 0;
+
+init_rss_fail:
+ if (spnic_rss_template_free(nic_dev->hwdev))
+ PMD_DRV_LOG(WARNING, "Free rss template failed");
+
+ return err;
+}
+
+static u8 spnic_find_queue_pos_by_rq_id(u8 *queues, u8 queues_count,
+ u8 queue_id)
+{
+ u8 pos;
+
+ for (pos = 0; pos < queues_count; pos++) {
+ if (queue_id == queues[pos])
+ break;
+ }
+
+ return pos;
+}
+
+void spnic_remove_rq_from_rx_queue_list(struct spnic_nic_dev *nic_dev,
+ u16 queue_id)
+{
+ u8 queue_pos;
+ u8 rss_queue_count = nic_dev->num_rss;
+
+ queue_pos = spnic_find_queue_pos_by_rq_id(nic_dev->rx_queue_list,
+ rss_queue_count,
+ (u8)queue_id);
+
+ if (queue_pos < rss_queue_count) {
+ rss_queue_count--;
+ memmove(nic_dev->rx_queue_list + queue_pos,
+ nic_dev->rx_queue_list + queue_pos + 1,
+ (rss_queue_count - queue_pos) *
+ sizeof(nic_dev->rx_queue_list[0]));
+ }
+
+ RTE_ASSERT(rss_queue_count < RTE_DIM(nic_dev->rx_queue_list));
+ nic_dev->num_rss = rss_queue_count;
+}
+
int spnic_start_all_rqs(struct rte_eth_dev *eth_dev)
{
struct spnic_nic_dev *nic_dev = NULL;
struct spnic_rxq *rxq = NULL;
+ int err = 0;
int i;
nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev);
for (i = 0; i < nic_dev->num_rqs; i++) {
rxq = eth_dev->data->rx_queues[i];
+ spnic_add_rq_to_rx_queue_list(nic_dev, rxq->q_id);
spnic_rearm_rxq_mbuf(rxq);
eth_dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
}
+ if (nic_dev->rss_state == SPNIC_RSS_ENABLE) {
+ err = spnic_refill_indir_rqid(rxq);
+ if (err) {
+ PMD_DRV_LOG(ERR, "Refill rq to indrect table failed, eth_dev:%s, queue_idx:%d err:%d\n",
+ rxq->nic_dev->dev_name, rxq->q_id, err);
+ goto out;
+ }
+ }
+
return 0;
+out:
+ for (i = 0; i < nic_dev->num_rqs; i++) {
+ rxq = eth_dev->data->rx_queues[i];
+ spnic_remove_rq_from_rx_queue_list(nic_dev, rxq->q_id);
+ spnic_free_rxq_mbufs(rxq);
+ eth_dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
+ }
+ return err;
}
diff --git a/drivers/net/spnic/spnic_rx.h b/drivers/net/spnic/spnic_rx.h
index 46f4e1276d..0b534f1904 100644
--- a/drivers/net/spnic/spnic_rx.h
+++ b/drivers/net/spnic/spnic_rx.h
@@ -5,6 +5,23 @@
#ifndef _SPNIC_RX_H_
#define _SPNIC_RX_H_
+#define SPNIC_DEFAULT_RX_CSUM_OFFLOAD 0xFFF
+
+#define SPNIC_RSS_OFFLOAD_ALL ( \
+ ETH_RSS_IPV4 | \
+ ETH_RSS_FRAG_IPV4 | \
+ ETH_RSS_NONFRAG_IPV4_TCP | \
+ ETH_RSS_NONFRAG_IPV4_UDP | \
+ ETH_RSS_NONFRAG_IPV4_OTHER | \
+ ETH_RSS_IPV6 | \
+ ETH_RSS_FRAG_IPV6 | \
+ ETH_RSS_NONFRAG_IPV6_TCP | \
+ ETH_RSS_NONFRAG_IPV6_UDP | \
+ ETH_RSS_NONFRAG_IPV6_OTHER | \
+ ETH_RSS_IPV6_EX | \
+ ETH_RSS_IPV6_TCP_EX | \
+ ETH_RSS_IPV6_UDP_EX)
+
struct spnic_rxq_stats {
u64 packets;
u64 bytes;
@@ -118,7 +135,21 @@ void spnic_free_rxq_mbufs(struct spnic_rxq *rxq);
void spnic_free_all_rxq_mbufs(struct spnic_nic_dev *nic_dev);
+int spnic_update_rss_config(struct rte_eth_dev *dev,
+ struct rte_eth_rss_conf *rss_conf);
+
int spnic_start_all_rqs(struct rte_eth_dev *eth_dev);
+
+void spnic_add_rq_to_rx_queue_list(struct spnic_nic_dev *nic_dev,
+ u16 queue_id);
+
+int spnic_refill_indir_rqid(struct spnic_rxq *rxq);
+
+void spnic_init_rx_queue_list(struct spnic_nic_dev *nic_dev);
+
+void spnic_remove_rq_from_rx_queue_list(struct spnic_nic_dev *nic_dev,
+ u16 queue_id);
+
/**
* Get receive queue local ci
*
--
2.32.0
next prev parent reply other threads:[~2021-12-24 8:34 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-12-24 8:32 [PATCH v3 00/25] Net/SPNIC: support SPNIC into DPDK 22.03 Yanling Song
2021-12-24 8:32 ` [PATCH v3 01/25] drivers/net: introduce a new PMD driver Yanling Song
2021-12-24 8:32 ` [PATCH v3 02/25] net/spnic: initialize the HW interface Yanling Song
2021-12-24 8:32 ` [PATCH v3 03/25] net/spnic: add mbox message channel Yanling Song
2021-12-24 8:32 ` [PATCH v3 04/25] net/spnic: introduce event queue Yanling Song
2021-12-24 8:32 ` [PATCH v3 05/25] net/spnic: add mgmt module Yanling Song
2021-12-28 15:59 ` Stephen Hemminger
2021-12-29 10:26 ` Yanling Song
2021-12-24 8:32 ` [PATCH v3 06/25] net/spnic: add cmdq and work queue Yanling Song
2021-12-24 8:32 ` [PATCH v3 07/25] net/spnic: add interface handling cmdq message Yanling Song
2021-12-24 8:32 ` [PATCH v3 08/25] net/spnic: add hardware info initialization Yanling Song
2021-12-24 8:32 ` [PATCH v3 09/25] net/spnic: support MAC and link event handling Yanling Song
2021-12-24 8:32 ` [PATCH v3 10/25] net/spnic: add function info initialization Yanling Song
2021-12-24 8:32 ` [PATCH v3 11/25] net/spnic: add queue pairs context initialization Yanling Song
2021-12-24 8:32 ` [PATCH v3 12/25] net/spnic: support mbuf handling of Tx/Rx Yanling Song
2021-12-24 8:32 ` Yanling Song [this message]
2021-12-24 8:32 ` [PATCH v3 14/25] net/spnic: add port/vport enable Yanling Song
2021-12-24 8:32 ` [PATCH v3 15/25] net/spnic: support IO packets handling Yanling Song
2021-12-24 8:32 ` [PATCH v3 16/25] net/spnic: add device configure/version/info Yanling Song
2021-12-24 8:32 ` [PATCH v3 17/25] net/spnic: support RSS configuration update and get Yanling Song
2021-12-24 8:32 ` [PATCH v3 18/25] net/spnic: support VLAN filtering and offloading Yanling Song
2021-12-24 8:32 ` [PATCH v3 19/25] net/spnic: support promiscuous and allmulticast Rx modes Yanling Song
2021-12-24 8:32 ` [PATCH v3 20/25] net/spnic: support flow control Yanling Song
2021-12-24 8:32 ` [PATCH v3 21/25] net/spnic: support getting Tx/Rx queues info Yanling Song
2021-12-24 8:32 ` [PATCH v3 22/25] net/spnic: net/spnic: support xstats statistics Yanling Song
2021-12-24 8:32 ` [PATCH v3 23/25] net/spnic: support VFIO interrupt Yanling Song
2021-12-24 8:32 ` [PATCH v3 24/25] net/spnic: support Tx/Rx queue start/stop Yanling Song
2021-12-24 8:32 ` [PATCH v3 25/25] net/spnic: add doc infrastructure Yanling Song
2021-12-24 17:44 ` [PATCH v3 00/25] Net/SPNIC: support SPNIC into DPDK 22.03 Stephen Hemminger
2021-12-28 7:01 ` Yanling Song
2021-12-28 15:55 ` Stephen Hemminger
2021-12-29 12:11 ` Yanling Song
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cb5fd4553441d685e26a7db95fce869c10898f9a.1640332922.git.songyl@ramaxel.com \
--to=songyl@ramaxel.com \
--cc=dev@dpdk.org \
--cc=ferruh.yigit@intel.com \
--cc=xuyun@ramaxel.com \
--cc=yanggan@ramaxel.com \
--cc=yanling.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).