This patch adds the initialization of Tx/Rx queues
context and negotiation of NIC features.

Signed-off-by: Yanling Song <son...@ramaxel.com>
---
 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 207f0aaeae..f960fbb53f 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 98cad645d2..ce9792f8ee 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 042d2fe6e1..20d5151a8d 100644
--- a/drivers/net/spnic/meson.build
+++ b/drivers/net/spnic/meson.build
@@ -6,6 +6,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..b4358f530a
--- /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 <rte_io.h>
+#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>
+#include <rte_ethdev_core.h>
+#include <ethdev_driver.h>
+
+#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..c59b2f42ec
--- /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 coverting */
+       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.27.0

Reply via email to