From patchwork Thu Dec 30 06:08:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yanling Song X-Patchwork-Id: 105514 X-Patchwork-Delegate: ferruh.yigit@amd.com 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 DC4C5A00C5; Thu, 30 Dec 2021 07:11:13 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id D065C426D5; Thu, 30 Dec 2021 07:09:55 +0100 (CET) Received: from VLXDG1SPAM1.ramaxel.com (email.ramaxel.com [221.4.138.186]) by mails.dpdk.org (Postfix) with ESMTP id 20B714120A for ; Thu, 30 Dec 2021 07:09:52 +0100 (CET) Received: from V12DG1MBS01.ramaxel.local (v12dg1mbs01.ramaxel.local [172.26.18.31]) by VLXDG1SPAM1.ramaxel.com with ESMTPS id 1BU69DWe040086 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 30 Dec 2021 14:09:13 +0800 (GMT-8) (envelope-from songyl@ramaxel.com) Received: from localhost.localdomain (10.64.9.47) by V12DG1MBS01.ramaxel.local (172.26.18.31) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2308.14; Thu, 30 Dec 2021 14:09:13 +0800 From: Yanling Song To: CC: , , , , , , Subject: [PATCH v6 13/26] net/spnic: support Rx congfiguration Date: Thu, 30 Dec 2021 14:08:51 +0800 Message-ID: X-Mailer: git-send-email 2.17.1 In-Reply-To: References: MIME-Version: 1.0 X-Originating-IP: [10.64.9.47] X-ClientProxiedBy: V12DG1MBS03.ramaxel.local (172.26.18.33) To V12DG1MBS01.ramaxel.local (172.26.18.31) X-DNSRBL: X-MAIL: VLXDG1SPAM1.ramaxel.com 1BU69DWe040086 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 This patch Rx/Tx configuration including Rx csum offload, LRO, RSS, VLAN filter and VLAN offload. Signed-off-by: Yanling Song --- 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 8c04295258..85eca39d68 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 = spnic_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 = spnic_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 = spnic_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 = spnic_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 = spnic_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 = spnic_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 = spnic_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 = spnic_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 = spnic_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 = spnic_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 = spnic_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 = spnic_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 609864ce77..9b926119d8 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 5911b1dba1..a10011e536 100644 --- a/drivers/net/spnic/spnic_ethdev.c +++ b/drivers/net/spnic/spnic_ethdev.c @@ -5,7 +5,10 @@ #include #include #include +#include #include +#include +#include #include #include @@ -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 b5e3fd012b..c20d162fa7 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 *