From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 2AAE4A04A2; Sat, 25 Dec 2021 12:31:15 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 3897D411E6; Sat, 25 Dec 2021 12:30:09 +0100 (CET) Received: from VLXDG1SPAM1.ramaxel.com (email.ramaxel.com [221.4.138.186]) by mails.dpdk.org (Postfix) with ESMTP id F2ACC411B8 for ; Sat, 25 Dec 2021 12:30:06 +0100 (CET) Received: from V12DG1MBS01.ramaxel.local (v12dg1mbs01.ramaxel.local [172.26.18.31]) by VLXDG1SPAM1.ramaxel.com with ESMTPS id 1BPBTZRt059951 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Sat, 25 Dec 2021 19:29:36 +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; Sat, 25 Dec 2021 19:29:35 +0800 From: Yanling Song To: CC: , , , , Subject: [PATCH v4 11/25] net/spnic: add queue pairs context initialization Date: Sat, 25 Dec 2021 19:28:59 +0800 Message-ID: X-Mailer: git-send-email 2.17.1 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain 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 1BPBTZRt059951 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 adds the initialization of Tx/Rx queues context and negotiation of NIC features. Signed-off-by: Yanling Song --- drivers/net/spnic/base/spnic_hw_comm.c | 101 ++++ drivers/net/spnic/base/spnic_hw_comm.h | 6 + drivers/net/spnic/base/spnic_nic_cfg.c | 76 +++ drivers/net/spnic/base/spnic_nic_cfg.h | 65 ++- drivers/net/spnic/meson.build | 3 +- drivers/net/spnic/spnic_ethdev.c | 57 +- drivers/net/spnic/spnic_io.c | 738 +++++++++++++++++++++++++ drivers/net/spnic/spnic_io.h | 154 ++++++ drivers/net/spnic/spnic_rx.h | 113 ++++ drivers/net/spnic/spnic_tx.h | 62 +++ 10 files changed, 1370 insertions(+), 5 deletions(-) create mode 100644 drivers/net/spnic/spnic_io.c create mode 100644 drivers/net/spnic/spnic_io.h create mode 100644 drivers/net/spnic/spnic_rx.h create mode 100644 drivers/net/spnic/spnic_tx.h diff --git a/drivers/net/spnic/base/spnic_hw_comm.c b/drivers/net/spnic/base/spnic_hw_comm.c index 5cb607cf03..1c751f2403 100644 --- a/drivers/net/spnic/base/spnic_hw_comm.c +++ b/drivers/net/spnic/base/spnic_hw_comm.c @@ -217,6 +217,107 @@ int spnic_func_reset(void *hwdev, u64 reset_flag) return 0; } +int spnic_convert_rx_buf_size(u32 rx_buf_sz, u32 *match_sz) +{ + u32 i, num_hw_types, best_match_sz; + + if (unlikely(!match_sz || rx_buf_sz < SPNIC_RX_BUF_SIZE_32B)) + return -EINVAL; + + if (rx_buf_sz >= SPNIC_RX_BUF_SIZE_16K) { + best_match_sz = SPNIC_RX_BUF_SIZE_16K; + goto size_matched; + } + + num_hw_types = sizeof(spnic_hw_rx_buf_size) / + sizeof(spnic_hw_rx_buf_size[0]); + best_match_sz = spnic_hw_rx_buf_size[0]; + for (i = 0; i < num_hw_types; i++) { + if (rx_buf_sz == spnic_hw_rx_buf_size[i]) { + best_match_sz = spnic_hw_rx_buf_size[i]; + break; + } else if (rx_buf_sz < spnic_hw_rx_buf_size[i]) { + break; + } + best_match_sz = spnic_hw_rx_buf_size[i]; + } + +size_matched: + *match_sz = best_match_sz; + + return 0; +} + +static u16 get_hw_rx_buf_size(u32 rx_buf_sz) +{ + u16 num_hw_types = sizeof(spnic_hw_rx_buf_size) / + sizeof(spnic_hw_rx_buf_size[0]); + u16 i; + + for (i = 0; i < num_hw_types; i++) { + if (spnic_hw_rx_buf_size[i] == rx_buf_sz) + return i; + } + + PMD_DRV_LOG(WARNING, "Chip can't support rx buf size of %d", rx_buf_sz); + + return DEFAULT_RX_BUF_SIZE; /* Default 2K */ +} + +int spnic_set_root_ctxt(void *hwdev, u32 rq_depth, u32 sq_depth, u16 rx_buf_sz) +{ + struct spnic_cmd_root_ctxt root_ctxt; + u16 out_size = sizeof(root_ctxt); + int err; + + if (!hwdev) + return -EINVAL; + + memset(&root_ctxt, 0, sizeof(root_ctxt)); + root_ctxt.func_idx = spnic_global_func_id(hwdev); + root_ctxt.set_cmdq_depth = 0; + root_ctxt.cmdq_depth = 0; + root_ctxt.lro_en = 1; + root_ctxt.rq_depth = (u16)ilog2(rq_depth); + root_ctxt.rx_buf_sz = get_hw_rx_buf_size(rx_buf_sz); + root_ctxt.sq_depth = (u16)ilog2(sq_depth); + + err = spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_COMM, MGMT_CMD_SET_VAT, + &root_ctxt, sizeof(root_ctxt), + &root_ctxt, &out_size, 0); + if (err || !out_size || root_ctxt.status) { + PMD_DRV_LOG(ERR, "Set root context failed, err: %d, status: 0x%x, out_size: 0x%x", + err, root_ctxt.status, out_size); + return -EFAULT; + } + + return 0; +} + +int spnic_clean_root_ctxt(void *hwdev) +{ + struct spnic_cmd_root_ctxt root_ctxt; + u16 out_size = sizeof(root_ctxt); + int err; + + if (!hwdev) + return -EINVAL; + + memset(&root_ctxt, 0, sizeof(root_ctxt)); + root_ctxt.func_idx = spnic_global_func_id(hwdev); + + err = spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_COMM, MGMT_CMD_SET_VAT, + &root_ctxt, sizeof(root_ctxt), + &root_ctxt, &out_size, 0); + if (err || !out_size || root_ctxt.status) { + PMD_DRV_LOG(ERR, "Clean root context failed, err: %d, status: 0x%x, out_size: 0x%x", + err, root_ctxt.status, out_size); + return -EFAULT; + } + + return 0; +} + int spnic_set_cmdq_depth(void *hwdev, u16 cmdq_depth) { struct spnic_cmd_root_ctxt root_ctxt; diff --git a/drivers/net/spnic/base/spnic_hw_comm.h b/drivers/net/spnic/base/spnic_hw_comm.h index cf4328a04b..4573595a89 100644 --- a/drivers/net/spnic/base/spnic_hw_comm.h +++ b/drivers/net/spnic/base/spnic_hw_comm.h @@ -180,6 +180,10 @@ int spnic_get_mgmt_version(void *hwdev, char *mgmt_ver, int max_mgmt_len); int spnic_get_board_info(void *hwdev, struct spnic_board_info *info); +int spnic_set_root_ctxt(void *hwdev, u32 rq_depth, u32 sq_depth, u16 rx_buf_sz); + +int spnic_clean_root_ctxt(void *hwdev); + int spnic_get_interrupt_cfg(void *dev, struct interrupt_info *info); int spnic_set_interrupt_cfg(void *dev, struct interrupt_info info); @@ -188,6 +192,8 @@ int spnic_set_wq_page_size(void *hwdev, u16 func_idx, u32 page_size); int spnic_set_cmdq_depth(void *hwdev, u16 cmdq_depth); +int spnic_convert_rx_buf_size(u32 rx_buf_sz, u32 *match_sz); + int spnic_get_comm_features(void *hwdev, u64 *s_feature, u16 size); int spnic_set_comm_features(void *hwdev, u64 *s_feature, u16 size); diff --git a/drivers/net/spnic/base/spnic_nic_cfg.c b/drivers/net/spnic/base/spnic_nic_cfg.c index 886aaea384..25d98d67dd 100644 --- a/drivers/net/spnic/base/spnic_nic_cfg.c +++ b/drivers/net/spnic/base/spnic_nic_cfg.c @@ -75,6 +75,42 @@ int l2nic_msg_to_mgmt_sync(void *hwdev, u16 cmd, void *buf_in, u16 in_size, in_size, buf_out, out_size, 0); } +int spnic_set_ci_table(void *hwdev, struct spnic_sq_attr *attr) +{ + struct spnic_cmd_cons_idx_attr cons_idx_attr; + u16 out_size = sizeof(cons_idx_attr); + int err; + + if (!hwdev || !attr) + return -EINVAL; + + memset(&cons_idx_attr, 0, sizeof(cons_idx_attr)); + cons_idx_attr.func_idx = spnic_global_func_id(hwdev); + cons_idx_attr.dma_attr_off = attr->dma_attr_off; + cons_idx_attr.pending_limit = attr->pending_limit; + cons_idx_attr.coalescing_time = attr->coalescing_time; + + if (attr->intr_en) { + cons_idx_attr.intr_en = attr->intr_en; + cons_idx_attr.intr_idx = attr->intr_idx; + } + + cons_idx_attr.l2nic_sqn = attr->l2nic_sqn; + cons_idx_attr.ci_addr = attr->ci_dma_base; + + err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_SQ_CI_ATTR_SET, + &cons_idx_attr, sizeof(cons_idx_attr), + &cons_idx_attr, &out_size); + if (err || !out_size || cons_idx_attr.msg_head.status) { + PMD_DRV_LOG(ERR, "Set ci attribute table failed, err: %d, " + "status: 0x%x, out_size: 0x%x", + err, cons_idx_attr.msg_head.status, out_size); + return -EFAULT; + } + + return 0; +} + static int spnic_check_mac_info(u8 status, u16 vlan_id) { if ((status && status != SPNIC_MGMT_STATUS_EXIST && @@ -406,6 +442,46 @@ int spnic_set_port_mtu(void *hwdev, u16 new_mtu) &func_tbl_cfg); } +static int nic_feature_nego(void *hwdev, u8 opcode, u64 *s_feature, u16 size) +{ + struct spnic_cmd_feature_nego feature_nego; + u16 out_size = sizeof(feature_nego); + int err; + + if (!hwdev || !s_feature || size > MAX_FEATURE_QWORD) + return -EINVAL; + + memset(&feature_nego, 0, sizeof(feature_nego)); + feature_nego.func_id = spnic_global_func_id(hwdev); + feature_nego.opcode = opcode; + if (opcode == SPNIC_CMD_OP_SET) + memcpy(feature_nego.s_feature, s_feature, size * sizeof(u64)); + + err = l2nic_msg_to_mgmt_sync(hwdev, SPNIC_CMD_FEATURE_NEGO, + &feature_nego, sizeof(feature_nego), + &feature_nego, &out_size); + if (err || !out_size || feature_nego.msg_head.status) { + PMD_DRV_LOG(ERR, "Failed to negotiate nic feature, err:%d, status: 0x%x, out_size: 0x%x\n", + err, feature_nego.msg_head.status, out_size); + return -EFAULT; + } + + if (opcode == SPNIC_CMD_OP_GET) + memcpy(s_feature, feature_nego.s_feature, size * sizeof(u64)); + + return 0; +} + +int spnic_get_feature_from_hw(void *hwdev, u64 *s_feature, u16 size) +{ + return nic_feature_nego(hwdev, SPNIC_CMD_OP_GET, s_feature, size); +} + +int spnic_set_feature_to_hw(void *hwdev, u64 *s_feature, u16 size) +{ + return nic_feature_nego(hwdev, SPNIC_CMD_OP_SET, s_feature, size); +} + static int spnic_vf_func_init(void *hwdev) { struct spnic_cmd_register_vf register_info; diff --git a/drivers/net/spnic/base/spnic_nic_cfg.h b/drivers/net/spnic/base/spnic_nic_cfg.h index 0af4588c1a..a7ff44a891 100644 --- a/drivers/net/spnic/base/spnic_nic_cfg.h +++ b/drivers/net/spnic/base/spnic_nic_cfg.h @@ -36,6 +36,15 @@ #define SPNIC_MGMT_STATUS_EXIST 0x6 #define CHECK_IPSU_15BIT 0x8000 +struct spnic_cmd_feature_nego { + struct mgmt_msg_head msg_head; + + u16 func_id; + u8 opcode; /* 1: set, 0: get */ + u8 rsvd; + u64 s_feature[MAX_FEATURE_QWORD]; +}; + /* Structures for port info */ struct nic_port_info { u8 port_type; @@ -69,6 +78,30 @@ enum nic_speed_level { LINK_SPEED_LEVELS, }; +struct spnic_sq_attr { + u8 dma_attr_off; + u8 pending_limit; + u8 coalescing_time; + u8 intr_en; + u16 intr_idx; + u32 l2nic_sqn; + u64 ci_dma_base; +}; + +struct spnic_cmd_cons_idx_attr { + struct mgmt_msg_head msg_head; + + u16 func_idx; + u8 dma_attr_off; + u8 pending_limit; + u8 coalescing_time; + u8 intr_en; + u16 intr_idx; + u32 l2nic_sqn; + u32 rsvd; + u64 ci_addr; +}; + struct spnic_port_mac_set { struct mgmt_msg_head msg_head; @@ -88,7 +121,6 @@ struct spnic_port_mac_update { u16 rsvd2; u8 new_mac[ETH_ALEN]; }; - struct spnic_cmd_port_info { struct mgmt_msg_head msg_head; @@ -193,6 +225,9 @@ struct spnic_cmd_set_func_tbl { struct spnic_func_tbl_cfg tbl_cfg; }; +#define SPNIC_CMD_OP_GET 0 +#define SPNIC_CMD_OP_SET 1 + enum { SPNIC_IFLA_VF_LINK_STATE_AUTO, /* Link state of the uplink */ SPNIC_IFLA_VF_LINK_STATE_ENABLE, /* Link always up */ @@ -223,6 +258,8 @@ struct spnic_cmd_register_vf { int l2nic_msg_to_mgmt_sync(void *hwdev, u16 cmd, void *buf_in, u16 in_size, void *buf_out, u16 *out_size); +int spnic_set_ci_table(void *hwdev, struct spnic_sq_attr *attr); + /** * Update MAC address to hardware * @@ -390,4 +427,30 @@ int spnic_init_function_table(void *hwdev, u16 rx_buff_len); * @retval non-zero : Failure */ int spnic_vf_get_default_cos(void *hwdev, u8 *cos_id); + +/** + * Get service feature HW supported + * + * @param[in] dev + * Device pointer to hwdev + * @param[in] size + * s_feature's array size + * @param[out] s_feature + * s_feature HW supported + * @retval zero: Success + * @retval non-zero: Failure + */ +int spnic_get_feature_from_hw(void *hwdev, u64 *s_feature, u16 size); + +/** + * Set service feature driver supported to hardware + * + * @param[in] dev + * Device pointer to hwdev + * + * @retval zero: Success + * @retval non-zero: Failure + */ +int spnic_set_feature_to_hw(void *hwdev, u64 *s_feature, u16 size); + #endif /* _SPNIC_NIC_CFG_H_ */ diff --git a/drivers/net/spnic/meson.build b/drivers/net/spnic/meson.build index c585aaf7f6..16056679f8 100644 --- a/drivers/net/spnic/meson.build +++ b/drivers/net/spnic/meson.build @@ -12,6 +12,7 @@ objs = [base_objs] sources = files( 'spnic_ethdev.c', - ) + 'spnic_io.c', +) includes += include_directories('base') diff --git a/drivers/net/spnic/spnic_ethdev.c b/drivers/net/spnic/spnic_ethdev.c index 7f73e70df1..4205ab43a4 100644 --- a/drivers/net/spnic/spnic_ethdev.c +++ b/drivers/net/spnic/spnic_ethdev.c @@ -22,14 +22,25 @@ #include "base/spnic_hw_comm.h" #include "base/spnic_nic_cfg.h" #include "base/spnic_nic_event.h" +#include "spnic_io.h" +#include "spnic_tx.h" +#include "spnic_rx.h" #include "spnic_ethdev.h" /* Driver-specific log messages type */ int spnic_logtype; +#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 +#define SPNIC_MAX_QUEUE_DEPTH 16384 +#define SPNIC_MIN_QUEUE_DEPTH 128 +#define SPNIC_TXD_ALIGN 1 +#define SPNIC_RXD_ALIGN 1 + /** * Deinit mac_vlan table in hardware. * @@ -219,6 +230,7 @@ static void spnic_deinit_sw_rxtxqs(struct spnic_nic_dev *nic_dev) static int spnic_dev_start(struct rte_eth_dev *eth_dev) { struct spnic_nic_dev *nic_dev; + u64 nic_features; int err; nic_dev = SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev); @@ -230,6 +242,26 @@ static int spnic_dev_start(struct rte_eth_dev *eth_dev) goto init_func_tbl_fail; } + nic_features = spnic_get_driver_feature(nic_dev->hwdev); + nic_features &= DEFAULT_DRV_FEATURE; + spnic_update_driver_feature(nic_dev->hwdev, nic_features); + + err = spnic_set_feature_to_hw(nic_dev->hwdev, &nic_dev->feature_cap, 1); + if (err) { + PMD_DRV_LOG(ERR, "Failed to set nic features to hardware, err %d\n", + err); + goto get_feature_err; + } + + + /* Init txq and rxq context */ + err = spnic_init_qp_ctxts(nic_dev); + if (err) { + PMD_DRV_LOG(ERR, "Init qp context failed, dev_name: %s", + eth_dev->data->name); + goto init_qp_fail; + } + /* Set default mtu */ err = spnic_set_port_mtu(nic_dev->hwdev, nic_dev->mtu_size); if (err) { @@ -238,7 +270,6 @@ static int spnic_dev_start(struct rte_eth_dev *eth_dev) goto set_mtu_fail; } - /* Update eth_dev link status */ if (eth_dev->data->dev_conf.intr_conf.lsc != 0) (void)spnic_link_update(eth_dev, 0); @@ -248,6 +279,10 @@ static int spnic_dev_start(struct rte_eth_dev *eth_dev) return 0; set_mtu_fail: + spnic_free_qp_ctxts(nic_dev->hwdev); + +init_qp_fail: +get_feature_err: init_func_tbl_fail: return err; @@ -278,6 +313,9 @@ static int spnic_dev_stop(struct rte_eth_dev *dev) memset(&link, 0, sizeof(link)); (void)rte_eth_linkstatus_set(dev, &link); + /* Clean root context */ + spnic_free_qp_ctxts(nic_dev->hwdev); + return 0; } @@ -290,7 +328,7 @@ static int spnic_dev_stop(struct rte_eth_dev *dev) static int spnic_dev_close(struct rte_eth_dev *eth_dev) { struct spnic_nic_dev *nic_dev = - SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev); + SPNIC_ETH_DEV_TO_PRIVATE_NIC_DEV(eth_dev); if (rte_bit_relaxed_test_and_set32(SPNIC_DEV_CLOSE, &nic_dev->dev_status)) { PMD_DRV_LOG(WARNING, "Device %s already closed", @@ -306,7 +344,6 @@ static int spnic_dev_close(struct rte_eth_dev *eth_dev) rte_bit_relaxed_clear32(SPNIC_DEV_INTR_EN, &nic_dev->dev_status); - /* Destroy rx mode mutex */ spnic_mutex_destroy(&nic_dev->rx_mode_mutex); @@ -736,6 +773,12 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev) goto init_hwdev_fail; } + if (!spnic_support_nic(nic_dev->hwdev)) { + PMD_DRV_LOG(ERR, "Hw of %s don't support nic\n", + eth_dev->data->name); + goto init_hwdev_fail; + } + nic_dev->max_sqs = spnic_func_max_sqs(nic_dev->hwdev); nic_dev->max_rqs = spnic_func_max_rqs(nic_dev->hwdev); @@ -751,6 +794,13 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev) goto init_nic_hwdev_fail; } + err = spnic_get_feature_from_hw(nic_dev->hwdev, &nic_dev->feature_cap, 1); + if (err) { + PMD_DRV_LOG(ERR, "Get nic feature from hardware failed, dev_name: %s", + eth_dev->data->name); + goto get_cap_fail; + } + err = spnic_init_sw_rxtxqs(nic_dev); if (err) { PMD_DRV_LOG(ERR, "Init sw rxqs or txqs failed, dev_name: %s", @@ -792,6 +842,7 @@ static int spnic_func_init(struct rte_eth_dev *eth_dev) init_sw_rxtxqs_fail: spnic_free_nic_hwdev(nic_dev->hwdev); +get_cap_fail: init_nic_hwdev_fail: spnic_free_hwdev(nic_dev->hwdev); eth_dev->dev_ops = NULL; diff --git a/drivers/net/spnic/spnic_io.c b/drivers/net/spnic/spnic_io.c new file mode 100644 index 0000000000..3603d83e5f --- /dev/null +++ b/drivers/net/spnic/spnic_io.c @@ -0,0 +1,738 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Ramaxel Memory Technology, Ltd + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "base/spnic_compat.h" +#include "base/spnic_cmd.h" +#include "base/spnic_wq.h" +#include "base/spnic_mgmt.h" +#include "base/spnic_cmdq.h" +#include "base/spnic_hwdev.h" +#include "base/spnic_hw_comm.h" +#include "base/spnic_nic_cfg.h" +#include "base/spnic_hw_cfg.h" +#include "spnic_io.h" +#include "spnic_tx.h" +#include "spnic_rx.h" +#include "spnic_ethdev.h" + +#define SPNIC_DEAULT_TX_CI_PENDING_LIMIT 0 +#define SPNIC_DEAULT_TX_CI_COALESCING_TIME 0 +#define SPNIC_DEAULT_DROP_THD_ON 0xFFFF +#define SPNIC_DEAULT_DROP_THD_OFF 0 + +#define WQ_PREFETCH_MAX 4 +#define WQ_PREFETCH_MIN 1 +#define WQ_PREFETCH_THRESHOLD 256 + +#define SPNIC_Q_CTXT_MAX 31 + +enum spnic_qp_ctxt_type { + SPNIC_QP_CTXT_TYPE_SQ, + SPNIC_QP_CTXT_TYPE_RQ, +}; + +struct spnic_qp_ctxt_header { + u16 num_queues; + u16 queue_type; + u16 start_qid; + u16 rsvd; +}; + +struct spnic_sq_ctxt { + u32 ci_pi; + u32 drop_mode_sp; + u32 wq_pfn_hi_owner; + u32 wq_pfn_lo; + + u32 rsvd0; + u32 pkt_drop_thd; + u32 global_sq_id; + u32 vlan_ceq_attr; + + u32 pref_cache; + u32 pref_ci_owner; + u32 pref_wq_pfn_hi_ci; + u32 pref_wq_pfn_lo; + + u32 rsvd8; + u32 rsvd9; + u32 wq_block_pfn_hi; + u32 wq_block_pfn_lo; +}; + +struct spnic_rq_ctxt { + u32 ci_pi; + u32 ceq_attr; + u32 wq_pfn_hi_type_owner; + u32 wq_pfn_lo; + + u32 rsvd[3]; + u32 cqe_sge_len; + + u32 pref_cache; + u32 pref_ci_owner; + u32 pref_wq_pfn_hi_ci; + u32 pref_wq_pfn_lo; + + u32 pi_paddr_hi; + u32 pi_paddr_lo; + u32 wq_block_pfn_hi; + u32 wq_block_pfn_lo; +}; + +struct spnic_sq_ctxt_block { + struct spnic_qp_ctxt_header cmdq_hdr; + struct spnic_sq_ctxt sq_ctxt[SPNIC_Q_CTXT_MAX]; +}; + +struct spnic_rq_ctxt_block { + struct spnic_qp_ctxt_header cmdq_hdr; + struct spnic_rq_ctxt rq_ctxt[SPNIC_Q_CTXT_MAX]; +}; + +struct spnic_clean_queue_ctxt { + struct spnic_qp_ctxt_header cmdq_hdr; + u32 rsvd; +}; + +#define SQ_CTXT_SIZE(num_sqs) ((u16)(sizeof(struct spnic_qp_ctxt_header) \ + + (num_sqs) * sizeof(struct spnic_sq_ctxt))) + +#define RQ_CTXT_SIZE(num_rqs) ((u16)(sizeof(struct spnic_qp_ctxt_header) \ + + (num_rqs) * sizeof(struct spnic_rq_ctxt))) + +#define CI_IDX_HIGH_SHIFH 12 + +#define CI_HIGN_IDX(val) ((val) >> CI_IDX_HIGH_SHIFH) + +#define SQ_CTXT_PI_IDX_SHIFT 0 +#define SQ_CTXT_CI_IDX_SHIFT 16 + +#define SQ_CTXT_PI_IDX_MASK 0xFFFFU +#define SQ_CTXT_CI_IDX_MASK 0xFFFFU + +#define SQ_CTXT_CI_PI_SET(val, member) (((val) & \ + SQ_CTXT_##member##_MASK) \ + << SQ_CTXT_##member##_SHIFT) + +#define SQ_CTXT_MODE_SP_FLAG_SHIFT 0 +#define SQ_CTXT_MODE_PKT_DROP_SHIFT 1 + +#define SQ_CTXT_MODE_SP_FLAG_MASK 0x1U +#define SQ_CTXT_MODE_PKT_DROP_MASK 0x1U + +#define SQ_CTXT_MODE_SET(val, member) (((val) & \ + SQ_CTXT_MODE_##member##_MASK) \ + << SQ_CTXT_MODE_##member##_SHIFT) + +#define SQ_CTXT_WQ_PAGE_HI_PFN_SHIFT 0 +#define SQ_CTXT_WQ_PAGE_OWNER_SHIFT 23 + +#define SQ_CTXT_WQ_PAGE_HI_PFN_MASK 0xFFFFFU +#define SQ_CTXT_WQ_PAGE_OWNER_MASK 0x1U + +#define SQ_CTXT_WQ_PAGE_SET(val, member) (((val) & \ + SQ_CTXT_WQ_PAGE_##member##_MASK) \ + << SQ_CTXT_WQ_PAGE_##member##_SHIFT) + +#define SQ_CTXT_PKT_DROP_THD_ON_SHIFT 0 +#define SQ_CTXT_PKT_DROP_THD_OFF_SHIFT 16 + +#define SQ_CTXT_PKT_DROP_THD_ON_MASK 0xFFFFU +#define SQ_CTXT_PKT_DROP_THD_OFF_MASK 0xFFFFU + +#define SQ_CTXT_PKT_DROP_THD_SET(val, member) (((val) & \ + SQ_CTXT_PKT_DROP_##member##_MASK) \ + << SQ_CTXT_PKT_DROP_##member##_SHIFT) + +#define SQ_CTXT_GLOBAL_SQ_ID_SHIFT 0 + +#define SQ_CTXT_GLOBAL_SQ_ID_MASK 0x1FFFU + +#define SQ_CTXT_GLOBAL_QUEUE_ID_SET(val, member) (((val) & \ + SQ_CTXT_##member##_MASK) \ + << SQ_CTXT_##member##_SHIFT) + + +#define SQ_CTXT_VLAN_TAG_SHIFT 0 +#define SQ_CTXT_VLAN_TYPE_SEL_SHIFT 16 +#define SQ_CTXT_VLAN_INSERT_MODE_SHIFT 19 +#define SQ_CTXT_VLAN_CEQ_EN_SHIFT 23 + +#define SQ_CTXT_VLAN_TAG_MASK 0xFFFFU +#define SQ_CTXT_VLAN_TYPE_SEL_MASK 0x7U +#define SQ_CTXT_VLAN_INSERT_MODE_MASK 0x3U +#define SQ_CTXT_VLAN_CEQ_EN_MASK 0x1U + +#define SQ_CTXT_VLAN_CEQ_SET(val, member) (((val) & \ + SQ_CTXT_VLAN_##member##_MASK) \ + << SQ_CTXT_VLAN_##member##_SHIFT) + +#define SQ_CTXT_PREF_CACHE_THRESHOLD_SHIFT 0 +#define SQ_CTXT_PREF_CACHE_MAX_SHIFT 14 +#define SQ_CTXT_PREF_CACHE_MIN_SHIFT 25 + +#define SQ_CTXT_PREF_CACHE_THRESHOLD_MASK 0x3FFFU +#define SQ_CTXT_PREF_CACHE_MAX_MASK 0x7FFU +#define SQ_CTXT_PREF_CACHE_MIN_MASK 0x7FU + +#define SQ_CTXT_PREF_CI_HI_SHIFT 0 +#define SQ_CTXT_PREF_OWNER_SHIFT 4 + +#define SQ_CTXT_PREF_CI_HI_MASK 0xFU +#define SQ_CTXT_PREF_OWNER_MASK 0x1U + +#define SQ_CTXT_PREF_WQ_PFN_HI_SHIFT 0 +#define SQ_CTXT_PREF_CI_LOW_SHIFT 20 + +#define SQ_CTXT_PREF_WQ_PFN_HI_MASK 0xFFFFFU +#define SQ_CTXT_PREF_CI_LOW_MASK 0xFFFU + +#define SQ_CTXT_PREF_SET(val, member) (((val) & \ + SQ_CTXT_PREF_##member##_MASK) \ + << SQ_CTXT_PREF_##member##_SHIFT) + +#define SQ_CTXT_WQ_BLOCK_PFN_HI_SHIFT 0 + +#define SQ_CTXT_WQ_BLOCK_PFN_HI_MASK 0x7FFFFFU + +#define SQ_CTXT_WQ_BLOCK_SET(val, member) (((val) & \ + SQ_CTXT_WQ_BLOCK_##member##_MASK) \ + << SQ_CTXT_WQ_BLOCK_##member##_SHIFT) + +#define RQ_CTXT_PI_IDX_SHIFT 0 +#define RQ_CTXT_CI_IDX_SHIFT 16 + +#define RQ_CTXT_PI_IDX_MASK 0xFFFFU +#define RQ_CTXT_CI_IDX_MASK 0xFFFFU + +#define RQ_CTXT_CI_PI_SET(val, member) (((val) & \ + RQ_CTXT_##member##_MASK) \ + << RQ_CTXT_##member##_SHIFT) + +#define RQ_CTXT_CEQ_ATTR_INTR_SHIFT 21 +#define RQ_CTXT_CEQ_ATTR_INTR_ARM_SHIFT 30 +#define RQ_CTXT_CEQ_ATTR_EN_SHIFT 31 + +#define RQ_CTXT_CEQ_ATTR_INTR_MASK 0x3FFU +#define RQ_CTXT_CEQ_ATTR_INTR_ARM_MASK 0x1U +#define RQ_CTXT_CEQ_ATTR_EN_MASK 0x1U + +#define RQ_CTXT_CEQ_ATTR_SET(val, member) (((val) & \ + RQ_CTXT_CEQ_ATTR_##member##_MASK) \ + << RQ_CTXT_CEQ_ATTR_##member##_SHIFT) + +#define RQ_CTXT_WQ_PAGE_HI_PFN_SHIFT 0 +#define RQ_CTXT_WQ_PAGE_WQE_TYPE_SHIFT 28 +#define RQ_CTXT_WQ_PAGE_OWNER_SHIFT 31 + +#define RQ_CTXT_WQ_PAGE_HI_PFN_MASK 0xFFFFFU +#define RQ_CTXT_WQ_PAGE_WQE_TYPE_MASK 0x3U +#define RQ_CTXT_WQ_PAGE_OWNER_MASK 0x1U + +#define RQ_CTXT_WQ_PAGE_SET(val, member) (((val) & \ + RQ_CTXT_WQ_PAGE_##member##_MASK) << \ + RQ_CTXT_WQ_PAGE_##member##_SHIFT) + +#define RQ_CTXT_CQE_LEN_SHIFT 28 + +#define RQ_CTXT_CQE_LEN_MASK 0x3U + +#define RQ_CTXT_CQE_LEN_SET(val, member) (((val) & \ + RQ_CTXT_##member##_MASK) << \ + RQ_CTXT_##member##_SHIFT) + +#define RQ_CTXT_PREF_CACHE_THRESHOLD_SHIFT 0 +#define RQ_CTXT_PREF_CACHE_MAX_SHIFT 14 +#define RQ_CTXT_PREF_CACHE_MIN_SHIFT 25 + +#define RQ_CTXT_PREF_CACHE_THRESHOLD_MASK 0x3FFFU +#define RQ_CTXT_PREF_CACHE_MAX_MASK 0x7FFU +#define RQ_CTXT_PREF_CACHE_MIN_MASK 0x7FU + +#define RQ_CTXT_PREF_CI_HI_SHIFT 0 +#define RQ_CTXT_PREF_OWNER_SHIFT 4 + +#define RQ_CTXT_PREF_CI_HI_MASK 0xFU +#define RQ_CTXT_PREF_OWNER_MASK 0x1U + +#define RQ_CTXT_PREF_WQ_PFN_HI_SHIFT 0 +#define RQ_CTXT_PREF_CI_LOW_SHIFT 20 + +#define RQ_CTXT_PREF_WQ_PFN_HI_MASK 0xFFFFFU +#define RQ_CTXT_PREF_CI_LOW_MASK 0xFFFU + +#define RQ_CTXT_PREF_SET(val, member) (((val) & \ + RQ_CTXT_PREF_##member##_MASK) << \ + RQ_CTXT_PREF_##member##_SHIFT) + +#define RQ_CTXT_WQ_BLOCK_PFN_HI_SHIFT 0 + +#define RQ_CTXT_WQ_BLOCK_PFN_HI_MASK 0x7FFFFFU + +#define RQ_CTXT_WQ_BLOCK_SET(val, member) (((val) & \ + RQ_CTXT_WQ_BLOCK_##member##_MASK) << \ + RQ_CTXT_WQ_BLOCK_##member##_SHIFT) + +#define SIZE_16BYTES(size) (RTE_ALIGN((size), 16) >> 4) + +#define WQ_PAGE_PFN_SHIFT 12 +#define WQ_BLOCK_PFN_SHIFT 9 + +#define WQ_PAGE_PFN(page_addr) ((page_addr) >> WQ_PAGE_PFN_SHIFT) +#define WQ_BLOCK_PFN(page_addr) ((page_addr) >> WQ_BLOCK_PFN_SHIFT) + +static void +spnic_qp_prepare_cmdq_header(struct spnic_qp_ctxt_header *qp_ctxt_hdr, + enum spnic_qp_ctxt_type ctxt_type, + u16 num_queues, u16 q_id) +{ + qp_ctxt_hdr->queue_type = ctxt_type; + qp_ctxt_hdr->num_queues = num_queues; + qp_ctxt_hdr->start_qid = q_id; + qp_ctxt_hdr->rsvd = 0; + + spnic_cpu_to_be32(qp_ctxt_hdr, sizeof(*qp_ctxt_hdr)); +} + +static void spnic_sq_prepare_ctxt(struct spnic_txq *sq, u16 sq_id, + struct spnic_sq_ctxt *sq_ctxt) +{ + u64 wq_page_addr; + u64 wq_page_pfn, wq_block_pfn; + u32 wq_page_pfn_hi, wq_page_pfn_lo; + u32 wq_block_pfn_hi, wq_block_pfn_lo; + u16 pi_start, ci_start; + + ci_start = sq->cons_idx & sq->q_mask; + pi_start = sq->prod_idx & sq->q_mask; + + /* Read the first page from hardware table */ + wq_page_addr = sq->queue_buf_paddr; + + wq_page_pfn = WQ_PAGE_PFN(wq_page_addr); + wq_page_pfn_hi = upper_32_bits(wq_page_pfn); + wq_page_pfn_lo = lower_32_bits(wq_page_pfn); + + /* Use 0-level CLA */ + wq_block_pfn = WQ_BLOCK_PFN(wq_page_addr); + wq_block_pfn_hi = upper_32_bits(wq_block_pfn); + wq_block_pfn_lo = lower_32_bits(wq_block_pfn); + + sq_ctxt->ci_pi = SQ_CTXT_CI_PI_SET(ci_start, CI_IDX) | + SQ_CTXT_CI_PI_SET(pi_start, PI_IDX); + + sq_ctxt->drop_mode_sp = SQ_CTXT_MODE_SET(0, SP_FLAG) | + SQ_CTXT_MODE_SET(0, PKT_DROP); + + sq_ctxt->wq_pfn_hi_owner = SQ_CTXT_WQ_PAGE_SET(wq_page_pfn_hi, HI_PFN) | + SQ_CTXT_WQ_PAGE_SET(1, OWNER); + + sq_ctxt->wq_pfn_lo = wq_page_pfn_lo; + + sq_ctxt->pkt_drop_thd = + SQ_CTXT_PKT_DROP_THD_SET(SPNIC_DEAULT_DROP_THD_ON, THD_ON) | + SQ_CTXT_PKT_DROP_THD_SET(SPNIC_DEAULT_DROP_THD_OFF, THD_OFF); + + sq_ctxt->global_sq_id = + SQ_CTXT_GLOBAL_QUEUE_ID_SET(sq_id, GLOBAL_SQ_ID); + + /* Insert c-vlan in default */ + sq_ctxt->vlan_ceq_attr = SQ_CTXT_VLAN_CEQ_SET(0, CEQ_EN) | + SQ_CTXT_VLAN_CEQ_SET(1, INSERT_MODE); + + sq_ctxt->rsvd0 = 0; + + sq_ctxt->pref_cache = SQ_CTXT_PREF_SET(WQ_PREFETCH_MIN, CACHE_MIN) | + SQ_CTXT_PREF_SET(WQ_PREFETCH_MAX, CACHE_MAX) | + SQ_CTXT_PREF_SET(WQ_PREFETCH_THRESHOLD, + CACHE_THRESHOLD); + + sq_ctxt->pref_ci_owner = + SQ_CTXT_PREF_SET(CI_HIGN_IDX(ci_start), CI_HI) | + SQ_CTXT_PREF_SET(1, OWNER); + + sq_ctxt->pref_wq_pfn_hi_ci = + SQ_CTXT_PREF_SET(ci_start, CI_LOW) | + SQ_CTXT_PREF_SET(wq_page_pfn_hi, WQ_PFN_HI); + + sq_ctxt->pref_wq_pfn_lo = wq_page_pfn_lo; + + sq_ctxt->wq_block_pfn_hi = + SQ_CTXT_WQ_BLOCK_SET(wq_block_pfn_hi, PFN_HI); + + sq_ctxt->wq_block_pfn_lo = wq_block_pfn_lo; + + spnic_cpu_to_be32(sq_ctxt, sizeof(*sq_ctxt)); +} + +static void spnic_rq_prepare_ctxt(struct spnic_rxq *rq, + struct spnic_rq_ctxt *rq_ctxt) +{ + u64 wq_page_addr; + u64 wq_page_pfn, wq_block_pfn; + u32 wq_page_pfn_hi, wq_page_pfn_lo; + u32 wq_block_pfn_hi, wq_block_pfn_lo; + u16 pi_start, ci_start; + u16 wqe_type = rq->wqebb_shift - SPNIC_RQ_WQEBB_SHIFT; + u8 intr_disable; + + /* RQ depth is in unit of 8 Bytes */ + ci_start = (u16)((rq->cons_idx & rq->q_mask) << wqe_type); + pi_start = (u16)((rq->prod_idx & rq->q_mask) << wqe_type); + + /* Read the first page from hardware table */ + wq_page_addr = rq->queue_buf_paddr; + + wq_page_pfn = WQ_PAGE_PFN(wq_page_addr); + wq_page_pfn_hi = upper_32_bits(wq_page_pfn); + wq_page_pfn_lo = lower_32_bits(wq_page_pfn); + + /* Use 0-level CLA */ + wq_block_pfn = WQ_BLOCK_PFN(wq_page_addr); + + wq_block_pfn_hi = upper_32_bits(wq_block_pfn); + wq_block_pfn_lo = lower_32_bits(wq_block_pfn); + + rq_ctxt->ci_pi = RQ_CTXT_CI_PI_SET(ci_start, CI_IDX) | + RQ_CTXT_CI_PI_SET(pi_start, PI_IDX); + + intr_disable = rq->dp_intr_en ? 0 : 1; + rq_ctxt->ceq_attr = RQ_CTXT_CEQ_ATTR_SET(intr_disable, EN) | + RQ_CTXT_CEQ_ATTR_SET(0, INTR_ARM) | + RQ_CTXT_CEQ_ATTR_SET(rq->msix_entry_idx, INTR); + + /* Use 32Byte WQE with SGE for CQE in default */ + rq_ctxt->wq_pfn_hi_type_owner = + RQ_CTXT_WQ_PAGE_SET(wq_page_pfn_hi, HI_PFN) | + RQ_CTXT_WQ_PAGE_SET(1, OWNER); + + switch (wqe_type) { + case SPNIC_EXTEND_RQ_WQE: + /* Use 32Byte WQE with SGE for CQE */ + rq_ctxt->wq_pfn_hi_type_owner |= + RQ_CTXT_WQ_PAGE_SET(0, WQE_TYPE); + break; + case SPNIC_NORMAL_RQ_WQE: + /* Use 16Byte WQE with 32Bytes SGE for CQE */ + rq_ctxt->wq_pfn_hi_type_owner |= + RQ_CTXT_WQ_PAGE_SET(2, WQE_TYPE); + rq_ctxt->cqe_sge_len = RQ_CTXT_CQE_LEN_SET(1, CQE_LEN); + break; + default: + PMD_DRV_LOG(INFO, "Invalid rq wqe type: %u", wqe_type); + } + + rq_ctxt->wq_pfn_lo = wq_page_pfn_lo; + + rq_ctxt->pref_cache = + RQ_CTXT_PREF_SET(WQ_PREFETCH_MIN, CACHE_MIN) | + RQ_CTXT_PREF_SET(WQ_PREFETCH_MAX, CACHE_MAX) | + RQ_CTXT_PREF_SET(WQ_PREFETCH_THRESHOLD, CACHE_THRESHOLD); + + rq_ctxt->pref_ci_owner = + RQ_CTXT_PREF_SET(CI_HIGN_IDX(ci_start), CI_HI) | + RQ_CTXT_PREF_SET(1, OWNER); + + rq_ctxt->pref_wq_pfn_hi_ci = + RQ_CTXT_PREF_SET(wq_page_pfn_hi, WQ_PFN_HI) | + RQ_CTXT_PREF_SET(ci_start, CI_LOW); + + rq_ctxt->pref_wq_pfn_lo = wq_page_pfn_lo; + + rq_ctxt->pi_paddr_hi = upper_32_bits(rq->pi_dma_addr); + rq_ctxt->pi_paddr_lo = lower_32_bits(rq->pi_dma_addr); + + rq_ctxt->wq_block_pfn_hi = + RQ_CTXT_WQ_BLOCK_SET(wq_block_pfn_hi, PFN_HI); + + rq_ctxt->wq_block_pfn_lo = wq_block_pfn_lo; + + spnic_cpu_to_be32(rq_ctxt, sizeof(*rq_ctxt)); +} + +static int init_sq_ctxts(struct spnic_nic_dev *nic_dev) +{ + struct spnic_sq_ctxt_block *sq_ctxt_block = NULL; + struct spnic_sq_ctxt *sq_ctxt = NULL; + struct spnic_cmd_buf *cmd_buf = NULL; + struct spnic_txq *sq = NULL; + u64 out_param = 0; + u16 q_id, curr_id, max_ctxts, i; + int err = 0; + + cmd_buf = spnic_alloc_cmd_buf(nic_dev->hwdev); + if (!cmd_buf) { + PMD_DRV_LOG(ERR, "Allocate cmd buf for sq ctx failed"); + return -ENOMEM; + } + + q_id = 0; + while (q_id < nic_dev->num_sqs) { + sq_ctxt_block = cmd_buf->buf; + sq_ctxt = sq_ctxt_block->sq_ctxt; + + max_ctxts = (nic_dev->num_sqs - q_id) > SPNIC_Q_CTXT_MAX ? + SPNIC_Q_CTXT_MAX : (nic_dev->num_sqs - q_id); + + spnic_qp_prepare_cmdq_header(&sq_ctxt_block->cmdq_hdr, + SPNIC_QP_CTXT_TYPE_SQ, + max_ctxts, q_id); + + for (i = 0; i < max_ctxts; i++) { + curr_id = q_id + i; + sq = nic_dev->txqs[curr_id]; + spnic_sq_prepare_ctxt(sq, curr_id, &sq_ctxt[i]); + } + + cmd_buf->size = SQ_CTXT_SIZE(max_ctxts); + err = spnic_cmdq_direct_resp(nic_dev->hwdev, SPNIC_MOD_L2NIC, + SPNIC_UCODE_CMD_MODIFY_QUEUE_CTX, + cmd_buf, &out_param, 0); + if (err || out_param != 0) { + PMD_DRV_LOG(ERR, "Set SQ ctxts failed, " + "err: %d, out_param: %" PRIu64 "", + err, out_param); + + err = -EFAULT; + break; + } + + q_id += max_ctxts; + } + + spnic_free_cmd_buf(cmd_buf); + return err; +} + +static int init_rq_ctxts(struct spnic_nic_dev *nic_dev) +{ + struct spnic_rq_ctxt_block *rq_ctxt_block = NULL; + struct spnic_rq_ctxt *rq_ctxt = NULL; + struct spnic_cmd_buf *cmd_buf = NULL; + struct spnic_rxq *rq = NULL; + u64 out_param = 0; + u16 q_id, curr_id, max_ctxts, i; + int err = 0; + + cmd_buf = spnic_alloc_cmd_buf(nic_dev->hwdev); + if (!cmd_buf) { + PMD_DRV_LOG(ERR, "Allocate cmd buf for rq ctx failed"); + return -ENOMEM; + } + + q_id = 0; + while (q_id < nic_dev->num_rqs) { + rq_ctxt_block = cmd_buf->buf; + rq_ctxt = rq_ctxt_block->rq_ctxt; + + max_ctxts = (nic_dev->num_rqs - q_id) > SPNIC_Q_CTXT_MAX ? + SPNIC_Q_CTXT_MAX : (nic_dev->num_rqs - q_id); + + spnic_qp_prepare_cmdq_header(&rq_ctxt_block->cmdq_hdr, + SPNIC_QP_CTXT_TYPE_RQ, max_ctxts, + q_id); + + for (i = 0; i < max_ctxts; i++) { + curr_id = q_id + i; + rq = nic_dev->rxqs[curr_id]; + + spnic_rq_prepare_ctxt(rq, &rq_ctxt[i]); + } + + cmd_buf->size = RQ_CTXT_SIZE(max_ctxts); + err = spnic_cmdq_direct_resp(nic_dev->hwdev, SPNIC_MOD_L2NIC, + SPNIC_UCODE_CMD_MODIFY_QUEUE_CTX, + cmd_buf, &out_param, 0); + if (err || out_param != 0) { + PMD_DRV_LOG(ERR, "Set RQ ctxts failed, " + "err: %d, out_param: %" PRIu64 "", + err, out_param); + err = -EFAULT; + break; + } + + q_id += max_ctxts; + } + + spnic_free_cmd_buf(cmd_buf); + return err; +} + +static int clean_queue_offload_ctxt(struct spnic_nic_dev *nic_dev, + enum spnic_qp_ctxt_type ctxt_type) +{ + struct spnic_clean_queue_ctxt *ctxt_block = NULL; + struct spnic_cmd_buf *cmd_buf; + u64 out_param = 0; + int err; + + cmd_buf = spnic_alloc_cmd_buf(nic_dev->hwdev); + if (!cmd_buf) { + PMD_DRV_LOG(ERR, "Allocate cmd buf for LRO/TSO space failed"); + return -ENOMEM; + } + + ctxt_block = cmd_buf->buf; + ctxt_block->cmdq_hdr.num_queues = nic_dev->max_sqs; + ctxt_block->cmdq_hdr.queue_type = ctxt_type; + ctxt_block->cmdq_hdr.start_qid = 0; + + spnic_cpu_to_be32(ctxt_block, sizeof(*ctxt_block)); + + cmd_buf->size = sizeof(*ctxt_block); + + err = spnic_cmdq_direct_resp(nic_dev->hwdev, SPNIC_MOD_L2NIC, + SPNIC_UCODE_CMD_CLEAN_QUEUE_CONTEXT, + cmd_buf, &out_param, 0); + if ((err) || (out_param)) { + PMD_DRV_LOG(ERR, "Clean queue offload ctxts failed, " + "err: %d, out_param: %" PRIu64 "", err, out_param); + err = -EFAULT; + } + + spnic_free_cmd_buf(cmd_buf); + return err; +} + +static int clean_qp_offload_ctxt(struct spnic_nic_dev *nic_dev) +{ + /* Clean LRO/TSO context space */ + return (clean_queue_offload_ctxt(nic_dev, SPNIC_QP_CTXT_TYPE_SQ) || + clean_queue_offload_ctxt(nic_dev, SPNIC_QP_CTXT_TYPE_RQ)); +} + +void spnic_get_func_rx_buf_size(void *dev) +{ + struct spnic_nic_dev *nic_dev = (struct spnic_nic_dev *)dev; + struct spnic_rxq *rxq = NULL; + u16 q_id; + u16 buf_size = 0; + + for (q_id = 0; q_id < nic_dev->num_rqs; q_id++) { + rxq = nic_dev->rxqs[q_id]; + + if (rxq == NULL) + continue; + + if (q_id == 0) + buf_size = rxq->buf_len; + + buf_size = buf_size > rxq->buf_len ? rxq->buf_len : buf_size; + } + + nic_dev->rx_buff_len = buf_size; +} + +/* Init qps ctxt and set sq ci attr and arm all sq */ +int spnic_init_qp_ctxts(void *dev) +{ + struct spnic_nic_dev *nic_dev = NULL; + struct spnic_hwdev *hwdev = NULL; + struct spnic_sq_attr sq_attr; + u32 rq_depth; + u16 q_id; + int err; + + if (!dev) + return -EINVAL; + + nic_dev = (struct spnic_nic_dev *)dev; + hwdev = nic_dev->hwdev; + + err = init_sq_ctxts(nic_dev); + if (err) { + PMD_DRV_LOG(ERR, "Init SQ ctxts failed"); + return err; + } + + err = init_rq_ctxts(nic_dev); + if (err) { + PMD_DRV_LOG(ERR, "Init RQ ctxts failed"); + return err; + } + + err = clean_qp_offload_ctxt(nic_dev); + if (err) { + PMD_DRV_LOG(ERR, "Clean qp offload ctxts failed"); + return err; + } + + rq_depth = ((u32)nic_dev->rxqs[0]->q_depth) << + nic_dev->rxqs[0]->wqe_type; + err = spnic_set_root_ctxt(hwdev, rq_depth, nic_dev->txqs[0]->q_depth, + nic_dev->rx_buff_len); + if (err) { + PMD_DRV_LOG(ERR, "Set root context failed"); + return err; + } + + for (q_id = 0; q_id < nic_dev->num_sqs; q_id++) { + sq_attr.ci_dma_base = nic_dev->txqs[q_id]->ci_dma_base >> 2; + sq_attr.pending_limit = SPNIC_DEAULT_TX_CI_PENDING_LIMIT; + sq_attr.coalescing_time = SPNIC_DEAULT_TX_CI_COALESCING_TIME; + sq_attr.intr_en = 0; + sq_attr.intr_idx = 0; /* Tx doesn't need intr */ + sq_attr.l2nic_sqn = q_id; + sq_attr.dma_attr_off = 0; + err = spnic_set_ci_table(hwdev, &sq_attr); + if (err) { + PMD_DRV_LOG(ERR, "Set ci table failed"); + goto set_cons_idx_table_err; + } + } + + return 0; + +set_cons_idx_table_err: + spnic_clean_root_ctxt(hwdev); + return err; +} + +void spnic_free_qp_ctxts(void *hwdev) +{ + if (!hwdev) + return; + + spnic_clean_root_ctxt(hwdev); +} + +void spnic_update_driver_feature(void *dev, u64 s_feature) +{ + struct spnic_nic_dev *nic_dev = NULL; + + if (!dev) + return; + + nic_dev = (struct spnic_nic_dev *)dev; + nic_dev->feature_cap = s_feature; + + PMD_DRV_LOG(INFO, "Update nic feature to %" PRIu64 "\n", + nic_dev->feature_cap); +} + +u64 spnic_get_driver_feature(void *dev) +{ + struct spnic_nic_dev *nic_dev = NULL; + + if (!dev) + return -EINVAL; + + nic_dev = (struct spnic_nic_dev *)dev; + + return nic_dev->feature_cap; +} diff --git a/drivers/net/spnic/spnic_io.h b/drivers/net/spnic/spnic_io.h new file mode 100644 index 0000000000..ccb8044481 --- /dev/null +++ b/drivers/net/spnic/spnic_io.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Ramaxel Memory Technology, Ltd + */ + +#ifndef _SPNIC_IO_H_ +#define _SPNIC_IO_H_ + +#define SPNIC_SQ_WQEBB_SHIFT 4 +#define SPNIC_RQ_WQEBB_SHIFT 3 + +#define SPNIC_SQ_WQEBB_SIZE BIT(SPNIC_SQ_WQEBB_SHIFT) +#define SPNIC_CQE_SIZE_SHIFT 4 + +/* Ci addr should RTE_CACHE_SIZE(64B) alignment for performance */ +#define SPNIC_CI_Q_ADDR_SIZE 64 + +#define CI_TABLE_SIZE(num_qps, pg_sz) \ + (RTE_ALIGN((num_qps) * SPNIC_CI_Q_ADDR_SIZE, pg_sz)) + +#define SPNIC_CI_VADDR(base_addr, q_id) ((u8 *)(base_addr) + \ + (q_id) * SPNIC_CI_Q_ADDR_SIZE) + +#define SPNIC_CI_PADDR(base_paddr, q_id) ((base_paddr) + \ + (q_id) * SPNIC_CI_Q_ADDR_SIZE) + +enum spnic_rq_wqe_type { + SPNIC_COMPACT_RQ_WQE, + SPNIC_NORMAL_RQ_WQE, + SPNIC_EXTEND_RQ_WQE, +}; + +enum spnic_queue_type { + SPNIC_SQ, + SPNIC_RQ, + SPNIC_MAX_QUEUE_TYPE +}; + +/* Doorbell info */ +struct spnic_db { + u32 db_info; + u32 pi_hi; +}; + +#define DB_INFO_QID_SHIFT 0 +#define DB_INFO_NON_FILTER_SHIFT 22 +#define DB_INFO_CFLAG_SHIFT 23 +#define DB_INFO_COS_SHIFT 24 +#define DB_INFO_TYPE_SHIFT 27 + +#define DB_INFO_QID_MASK 0x1FFFU +#define DB_INFO_NON_FILTER_MASK 0x1U +#define DB_INFO_CFLAG_MASK 0x1U +#define DB_INFO_COS_MASK 0x7U +#define DB_INFO_TYPE_MASK 0x1FU +#define DB_INFO_SET(val, member) (((u32)(val) & \ + DB_INFO_##member##_MASK) << \ + DB_INFO_##member##_SHIFT) + +#define DB_PI_LOW_MASK 0xFFU +#define DB_PI_HIGH_MASK 0xFFU +#define DB_PI_LOW(pi) ((pi) & DB_PI_LOW_MASK) +#define DB_PI_HI_SHIFT 8 +#define DB_PI_HIGH(pi) (((pi) >> DB_PI_HI_SHIFT) & DB_PI_HIGH_MASK) +#define DB_INFO_UPPER_32(val) (((u64)val) << 32) + +#define DB_ADDR(db_addr, pi) ((u64 *)(db_addr) + DB_PI_LOW(pi)) +#define SRC_TYPE 1 + +/* Cflag data path */ +#define SQ_CFLAG_DP 0 +#define RQ_CFLAG_DP 1 + +#define MASKED_QUEUE_IDX(queue, idx) ((idx) & (queue)->q_mask) + +#define NIC_WQE_ADDR(queue, idx) ((void *)((u64)((queue)->queue_buf_vaddr) + \ + ((idx) << (queue)->wqebb_shift))) + +#define SPNIC_FLUSH_QUEUE_TIMEOUT 3000 + +/** + * Write send queue doorbell + * + * @param[in] db_addr + * Doorbell address + * @param[in] q_id + * Send queue id + * @param[in] cos + * Send queue cos + * @param[in] cflag + * Cflag data path + * @param[in] pi + * Send queue pi + */ +static inline void spnic_write_db(void *db_addr, u16 q_id, int cos, u8 cflag, + u16 pi) +{ + u64 db; + + /* Hardware will do endianness converting */ + db = DB_PI_HIGH(pi); + db = DB_INFO_UPPER_32(db) | DB_INFO_SET(SRC_TYPE, TYPE) | + DB_INFO_SET(cflag, CFLAG) | DB_INFO_SET(cos, COS) | + DB_INFO_SET(q_id, QID); + + rte_wmb(); /* Write all before the doorbell */ + + rte_write64(*((u64 *)&db), DB_ADDR(db_addr, pi)); +} + +void spnic_get_func_rx_buf_size(void *dev); + +/** + * Init queue pair context + * + * @param[in] dev + * Device pointer to nic device + * + * @retval zero: Success + * @retval non-zero: Failure + */ +int spnic_init_qp_ctxts(void *dev); + +/** + * Free queue pair context + * + * @param[in] hwdev + * Device pointer to hwdev + */ +void spnic_free_qp_ctxts(void *hwdev); + +/** + * Update service feature driver supported + * + * @param[in] dev + * Device pointer to nic device + * @param[out] s_feature + * s_feature driver supported + * @retval zero: Success + * @retval non-zero: Failure + */ +void spnic_update_driver_feature(void *dev, u64 s_feature); + +/** + * Get service feature driver supported + * + * @param[in] dev + * Device pointer to nic device + * @param[out] s_feature + * s_feature driver supported + * @retval zero: Success + * @retval non-zero: Failure + */ +u64 spnic_get_driver_feature(void *dev); +#endif /* _SPNIC_IO_H_ */ diff --git a/drivers/net/spnic/spnic_rx.h b/drivers/net/spnic/spnic_rx.h new file mode 100644 index 0000000000..b2f0052533 --- /dev/null +++ b/drivers/net/spnic/spnic_rx.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Ramaxel Memory Technology, Ltd + */ + +#ifndef _SPNIC_RX_H_ +#define _SPNIC_RX_H_ + +struct spnic_rxq_stats { + u64 packets; + u64 bytes; + u64 errors; + u64 csum_errors; + u64 other_errors; + u64 unlock_bp; + u64 dropped; + + u64 rx_nombuf; + u64 rx_discards; + u64 burst_pkts; +}; + +struct spnic_rq_cqe { + u32 status; + u32 vlan_len; + + u32 offload_type; + u32 hash_val; + u32 xid; + u32 decrypt_info; + u32 rsvd6; + u32 pkt_info; +}; + +/* + * Attention: please do not add any member in spnic_rx_info because rxq bulk + * rearm mode will write mbuf in rx_info + */ +struct spnic_rx_info { + struct rte_mbuf *mbuf; +}; + +struct spnic_sge_sect { + struct spnic_sge sge; + u32 rsvd; +}; + +struct spnic_rq_extend_wqe { + struct spnic_sge_sect buf_desc; + struct spnic_sge_sect cqe_sect; +}; + +struct spnic_rq_normal_wqe { + u32 buf_hi_addr; + u32 buf_lo_addr; + u32 cqe_hi_addr; + u32 cqe_lo_addr; +}; + +struct spnic_rq_wqe { + union { + struct spnic_rq_normal_wqe normal_wqe; + struct spnic_rq_extend_wqe extend_wqe; + }; +}; + +struct spnic_rxq { + struct spnic_nic_dev *nic_dev; + + u16 q_id; + u16 q_depth; + u16 q_mask; + u16 buf_len; + + u32 rx_buff_shift; + + u16 rx_free_thresh; + u16 rxinfo_align_end; + u16 wqebb_shift; + u16 wqebb_size; + + u16 wqe_type; + u16 cons_idx; + u16 prod_idx; + u16 delta; + + u16 next_to_update; + u16 port_id; + + const struct rte_memzone *rq_mz; + void *queue_buf_vaddr; /* Rq dma info */ + rte_iova_t queue_buf_paddr; + + const struct rte_memzone *pi_mz; + u16 *pi_virt_addr; + void *db_addr; + rte_iova_t pi_dma_addr; + + struct spnic_rx_info *rx_info; + struct spnic_rq_cqe *rx_cqe; + struct rte_mempool *mb_pool; + + const struct rte_memzone *cqe_mz; + rte_iova_t cqe_start_paddr; + void *cqe_start_vaddr; + u8 dp_intr_en; + u16 msix_entry_idx; + + unsigned long status; + + struct spnic_rxq_stats rxq_stats; +} __rte_cache_aligned; + +#endif /* _SPNIC_RX_H_ */ diff --git a/drivers/net/spnic/spnic_tx.h b/drivers/net/spnic/spnic_tx.h new file mode 100644 index 0000000000..7528b27bd9 --- /dev/null +++ b/drivers/net/spnic/spnic_tx.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Ramaxel Memory Technology, Ltd + */ + +#ifndef _SPNIC_TX_H_ +#define _SPNIC_TX_H_ + +/* Txq info */ +struct spnic_txq_stats { + u64 packets; + u64 bytes; + u64 tx_busy; + u64 off_errs; + u64 burst_pkts; + u64 sge_len0; + u64 mbuf_null; + u64 cpy_pkts; + u64 sge_len_too_large; +}; + +struct spnic_tx_info { + struct rte_mbuf *mbuf; + struct rte_mbuf *cpy_mbuf; + int wqebb_cnt; +}; + +struct spnic_txq { + struct spnic_nic_dev *nic_dev; + + u16 q_id; + u16 q_depth; + u16 q_mask; + u16 wqebb_size; + + u16 wqebb_shift; + u16 cons_idx; + u16 prod_idx; + + u16 tx_free_thresh; + u16 owner; /* Used for sq */ + + void *db_addr; + + struct spnic_tx_info *tx_info; + + const struct rte_memzone *sq_mz; + void *queue_buf_vaddr; + rte_iova_t queue_buf_paddr; /* Sq dma info */ + + const struct rte_memzone *ci_mz; + void *ci_vaddr_base; + rte_iova_t ci_dma_base; + + u64 sq_head_addr; + u64 sq_bot_sge_addr; + + u32 cos; + + struct spnic_txq_stats txq_stats; +} __rte_cache_aligned; + +#endif /* _SPNIC_TX_H_ */ -- 2.32.0