diff --git a/drivers/net/spnic/base/meson.build b/drivers/net/spnic/base/meson.build
index 3f6a060b37..5e4efac7be 100644
--- a/drivers/net/spnic/base/meson.build
+++ b/drivers/net/spnic/base/meson.build
@@ -7,7 +7,9 @@ sources = [
 	'spnic_hwif.c',
 	'spnic_mbox.c',
 	'spnic_mgmt.c',
-	'spnic_nic_event.c'
+	'spnic_nic_event.c',
+	'spnic_cmdq.c',
+	'spnic_hw_comm.c',
 ]
 
 extra_flags = []
diff --git a/drivers/net/spnic/base/spnic_cmdq.c b/drivers/net/spnic/base/spnic_cmdq.c
new file mode 100644
index 0000000000..ccfcf739a0
--- /dev/null
+++ b/drivers/net/spnic/base/spnic_cmdq.c
@@ -0,0 +1,202 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd
+ */
+
+#include <rte_mbuf.h>
+
+#include "spnic_compat.h"
+#include "spnic_hwdev.h"
+#include "spnic_hwif.h"
+#include "spnic_wq.h"
+#include "spnic_cmd.h"
+#include "spnic_mgmt.h"
+#include "spnic_cmdq.h"
+
+#define CMDQ_CTXT_CURR_WQE_PAGE_PFN_SHIFT		0
+#define CMDQ_CTXT_EQ_ID_SHIFT				53
+#define CMDQ_CTXT_CEQ_ARM_SHIFT				61
+#define CMDQ_CTXT_CEQ_EN_SHIFT				62
+#define CMDQ_CTXT_HW_BUSY_BIT_SHIFT			63
+
+#define CMDQ_CTXT_CURR_WQE_PAGE_PFN_MASK		0xFFFFFFFFFFFFF
+#define CMDQ_CTXT_EQ_ID_MASK				0xFF
+#define CMDQ_CTXT_CEQ_ARM_MASK				0x1
+#define CMDQ_CTXT_CEQ_EN_MASK				0x1
+#define CMDQ_CTXT_HW_BUSY_BIT_MASK			0x1
+
+#define CMDQ_CTXT_PAGE_INFO_SET(val, member)		\
+	(((u64)(val) & CMDQ_CTXT_##member##_MASK) << CMDQ_CTXT_##member##_SHIFT)
+
+#define CMDQ_CTXT_WQ_BLOCK_PFN_SHIFT			0
+#define CMDQ_CTXT_CI_SHIFT				52
+
+#define CMDQ_CTXT_WQ_BLOCK_PFN_MASK			0xFFFFFFFFFFFFF
+#define CMDQ_CTXT_CI_MASK				0xFFF
+
+#define CMDQ_CTXT_BLOCK_INFO_SET(val, member)		\
+	(((u64)(val) & CMDQ_CTXT_##member##_MASK) << CMDQ_CTXT_##member##_SHIFT)
+
+#define WAIT_CMDQ_ENABLE_TIMEOUT	300
+
+static int init_cmdq(struct spnic_cmdq *cmdq, struct spnic_hwdev *hwdev,
+		     struct spnic_wq *wq, enum spnic_cmdq_type q_type)
+{
+	void *db_base = NULL;
+	int err = 0;
+	size_t errcode_size;
+	size_t cmd_infos_size;
+
+	cmdq->wq = wq;
+	cmdq->cmdq_type = q_type;
+	cmdq->wrapped = 1;
+
+	rte_spinlock_init(&cmdq->cmdq_lock);
+
+	errcode_size = wq->q_depth * sizeof(*cmdq->errcode);
+	cmdq->errcode = rte_zmalloc(NULL, errcode_size, 0);
+	if (!cmdq->errcode) {
+		PMD_DRV_LOG(ERR, "Allocate errcode for cmdq failed");
+		return -ENOMEM;
+	}
+
+	cmd_infos_size = wq->q_depth * sizeof(*cmdq->cmd_infos);
+	cmdq->cmd_infos = rte_zmalloc(NULL, cmd_infos_size, 0);
+	if (!cmdq->cmd_infos) {
+		PMD_DRV_LOG(ERR, "Allocate cmd info for cmdq failed");
+		err = -ENOMEM;
+		goto cmd_infos_err;
+	}
+
+	err = spnic_alloc_db_addr(hwdev, &db_base, NULL);
+	if (err)
+		goto alloc_db_err;
+
+	cmdq->db_base = (u8 *)db_base;
+
+	return 0;
+
+alloc_db_err:
+	rte_free(cmdq->cmd_infos);
+
+cmd_infos_err:
+	rte_free(cmdq->errcode);
+
+	return err;
+}
+
+static void free_cmdq(struct spnic_hwdev *hwdev, struct spnic_cmdq *cmdq)
+{
+	spnic_free_db_addr(hwdev, cmdq->db_base, NULL);
+	rte_free(cmdq->cmd_infos);
+	rte_free(cmdq->errcode);
+}
+
+static int spnic_set_cmdq_ctxts(struct spnic_hwdev *hwdev)
+{
+	struct spnic_cmdqs *cmdqs = hwdev->cmdqs;
+	struct spnic_cmd_cmdq_ctxt cmdq_ctxt;
+	enum spnic_cmdq_type cmdq_type;
+	u16 out_size = sizeof(cmdq_ctxt);
+	int err;
+
+	cmdq_type = SPNIC_CMDQ_SYNC;
+	for (; cmdq_type < SPNIC_MAX_CMDQ_TYPES; cmdq_type++) {
+		memset(&cmdq_ctxt, 0, sizeof(cmdq_ctxt));
+		memcpy(&cmdq_ctxt.ctxt_info, &cmdqs->cmdq[cmdq_type].cmdq_ctxt,
+			sizeof(cmdq_ctxt.ctxt_info));
+		cmdq_ctxt.func_idx = spnic_global_func_id(hwdev);
+		cmdq_ctxt.cmdq_id = cmdq_type;
+
+		err = spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_COMM,
+					     MGMT_CMD_SET_CMDQ_CTXT,
+					     &cmdq_ctxt, sizeof(cmdq_ctxt),
+					     &cmdq_ctxt, &out_size, 0);
+		if (err || !out_size || cmdq_ctxt.status) {
+			PMD_DRV_LOG(ERR, "Set cmdq ctxt failed, err: %d, status: 0x%x, out_size: 0x%x",
+				    err, cmdq_ctxt.status, out_size);
+			return -EFAULT;
+		}
+	}
+
+	cmdqs->status |= SPNIC_CMDQ_ENABLE;
+
+	return 0;
+}
+
+int spnic_reinit_cmdq_ctxts(struct spnic_hwdev *hwdev)
+{
+	return spnic_set_cmdq_ctxts(hwdev);
+}
+
+int spnic_cmdqs_init(struct spnic_hwdev *hwdev)
+{
+	struct spnic_cmdqs *cmdqs = NULL;
+	enum spnic_cmdq_type type, cmdq_type;
+	char cmdq_pool_name[RTE_MEMPOOL_NAMESIZE];
+	int err;
+
+	cmdqs = rte_zmalloc(NULL, sizeof(*cmdqs), 0);
+	if (!cmdqs)
+		return -ENOMEM;
+
+	hwdev->cmdqs = cmdqs;
+	cmdqs->hwdev = hwdev;
+
+	memset(cmdq_pool_name, 0, RTE_MEMPOOL_NAMESIZE);
+	snprintf(cmdq_pool_name, sizeof(cmdq_pool_name), "spnic_cmdq_%u",
+		 hwdev->port_id);
+
+	cmdqs->cmd_buf_pool = rte_pktmbuf_pool_create(cmdq_pool_name,
+				SPNIC_CMDQ_DEPTH * SPNIC_MAX_CMDQ_TYPES,
+				0, 0, SPNIC_CMDQ_BUF_SIZE, rte_socket_id());
+	if (!cmdqs->cmd_buf_pool) {
+		PMD_DRV_LOG(ERR, "Create cmdq buffer pool failed");
+		err = -ENOMEM;
+		goto pool_create_err;
+	}
+
+	cmdq_type = SPNIC_CMDQ_SYNC;
+	for (; cmdq_type < SPNIC_MAX_CMDQ_TYPES; cmdq_type++) {
+		err = init_cmdq(&cmdqs->cmdq[cmdq_type], hwdev,
+				&cmdqs->saved_wqs[cmdq_type], cmdq_type);
+		if (err) {
+			PMD_DRV_LOG(ERR, "Initialize cmdq failed");
+			goto init_cmdq_err;
+		}
+	}
+
+	err = spnic_set_cmdq_ctxts(hwdev);
+	if (err)
+		goto init_cmdq_err;
+
+	return 0;
+
+init_cmdq_err:
+	type = SPNIC_CMDQ_SYNC;
+	for (; type < cmdq_type; type++)
+		free_cmdq(hwdev, &cmdqs->cmdq[type]);
+
+	rte_mempool_free(cmdqs->cmd_buf_pool);
+
+pool_create_err:
+	rte_free(cmdqs);
+
+	return err;
+}
+
+void spnic_cmdqs_free(struct spnic_hwdev *hwdev)
+{
+	struct spnic_cmdqs *cmdqs = hwdev->cmdqs;
+	enum spnic_cmdq_type cmdq_type = SPNIC_CMDQ_SYNC;
+
+	cmdqs->status &= ~SPNIC_CMDQ_ENABLE;
+
+	for (; cmdq_type < SPNIC_MAX_CMDQ_TYPES; cmdq_type++)
+		free_cmdq(cmdqs->hwdev, &cmdqs->cmdq[cmdq_type]);
+
+	rte_mempool_free(cmdqs->cmd_buf_pool);
+
+	rte_free(cmdqs->saved_wqs);
+
+	rte_free(cmdqs);
+}
diff --git a/drivers/net/spnic/base/spnic_cmdq.h b/drivers/net/spnic/base/spnic_cmdq.h
new file mode 100644
index 0000000000..49fc1b1684
--- /dev/null
+++ b/drivers/net/spnic/base/spnic_cmdq.h
@@ -0,0 +1,228 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd
+ */
+
+#ifndef _SPNIC_CMDQ_H_
+#define _SPNIC_CMDQ_H_
+
+#define SPNIC_SCMD_DATA_LEN		16
+
+/* Pmd driver uses 64, kernel l2nic uses 4096 */
+#define SPNIC_CMDQ_DEPTH		64
+
+#define SPNIC_CMDQ_BUF_SIZE		2048U
+#define SPNIC_CMDQ_BUF_HW_RSVD		8
+#define SPNIC_CMDQ_MAX_DATA_SIZE	(SPNIC_CMDQ_BUF_SIZE	\
+					 - SPNIC_CMDQ_BUF_HW_RSVD)
+
+#define SPNIC_CEQ_ID_CMDQ		0
+
+enum cmdq_scmd_type {
+	CMDQ_SET_ARM_CMD = 2,
+};
+
+enum cmdq_wqe_type {
+	WQE_LCMD_TYPE,
+	WQE_SCMD_TYPE
+};
+
+enum ctrl_sect_len {
+	CTRL_SECT_LEN = 1,
+	CTRL_DIRECT_SECT_LEN = 2
+};
+
+enum bufdesc_len {
+	BUFDESC_LCMD_LEN = 2,
+	BUFDESC_SCMD_LEN = 3
+};
+
+enum data_format {
+	DATA_SGE,
+};
+
+enum completion_format {
+	COMPLETE_DIRECT,
+	COMPLETE_SGE
+};
+
+enum completion_request {
+	CEQ_SET = 1,
+};
+
+enum cmdq_cmd_type {
+	SYNC_CMD_DIRECT_RESP,
+	SYNC_CMD_SGE_RESP,
+	ASYNC_CMD
+};
+
+enum spnic_cmdq_type {
+	SPNIC_CMDQ_SYNC,
+	SPNIC_CMDQ_ASYNC,
+	SPNIC_MAX_CMDQ_TYPES
+};
+
+enum spnic_db_src_type {
+	SPNIC_DB_SRC_CMDQ_TYPE,
+	SPNIC_DB_SRC_L2NIC_SQ_TYPE
+};
+
+enum spnic_cmdq_db_type {
+	SPNIC_DB_SQ_RQ_TYPE,
+	SPNIC_DB_CMDQ_TYPE
+};
+
+/* Cmdq ack type */
+enum spnic_ack_type {
+	SPNIC_ACK_TYPE_CMDQ,
+	SPNIC_ACK_TYPE_SHARE_CQN,
+	SPNIC_ACK_TYPE_APP_CQN,
+
+	SPNIC_MOD_ACK_MAX = 15
+};
+
+/* Cmdq wqe ctrls */
+struct spnic_cmdq_header {
+	u32 header_info;
+	u32 saved_data;
+};
+
+struct spnic_scmd_bufdesc {
+	u32 buf_len;
+	u32 rsvd;
+	u8  data[SPNIC_SCMD_DATA_LEN];
+};
+
+struct spnic_lcmd_bufdesc {
+	u32 rsvd1;
+	u64 saved_async_buf;
+	u64 rsvd3;
+};
+
+struct spnic_cmdq_db {
+	u32 db_head;
+	u32 db_info;
+};
+
+struct spnic_status {
+	u32 status_info;
+};
+
+struct spnic_ctrl {
+	u32 ctrl_info;
+};
+
+struct spnic_sge_resp {
+	u32 rsvd;
+};
+
+struct spnic_cmdq_completion {
+	/* HW format */
+	union {
+		struct spnic_sge_resp sge_resp;
+		u64 direct_resp;
+	};
+};
+
+struct spnic_cmdq_wqe_scmd {
+	struct spnic_cmdq_header       header;
+	u64                            rsvd;
+	struct spnic_status            status;
+	struct spnic_ctrl              ctrl;
+	struct spnic_cmdq_completion   completion;
+	struct spnic_scmd_bufdesc      buf_desc;
+};
+
+struct spnic_cmdq_wqe_lcmd {
+	struct spnic_cmdq_header       header;
+	struct spnic_status            status;
+	struct spnic_ctrl              ctrl;
+	struct spnic_cmdq_completion   completion;
+	struct spnic_lcmd_bufdesc      buf_desc;
+};
+
+struct spnic_cmdq_inline_wqe {
+	struct spnic_cmdq_wqe_scmd wqe_scmd;
+};
+
+struct spnic_cmdq_wqe {
+	/* HW format */
+	union {
+		struct spnic_cmdq_inline_wqe inline_wqe;
+		struct spnic_cmdq_wqe_lcmd wqe_lcmd;
+	};
+};
+
+struct spnic_cmdq_ctxt_info {
+	u64 curr_wqe_page_pfn;
+	u64 wq_block_pfn;
+};
+
+struct spnic_cmd_cmdq_ctxt {
+	u8 status;
+	u8 version;
+	u8 rsvd0[6];
+
+	u16 func_idx;
+	u8  cmdq_id;
+	u8  rsvd1[5];
+
+	struct spnic_cmdq_ctxt_info ctxt_info;
+};
+
+enum spnic_cmdq_status {
+	SPNIC_CMDQ_ENABLE = BIT(0),
+};
+
+enum spnic_cmdq_cmd_type {
+	SPNIC_CMD_TYPE_NONE,
+	SPNIC_CMD_TYPE_SET_ARM,
+	SPNIC_CMD_TYPE_DIRECT_RESP,
+	SPNIC_CMD_TYPE_SGE_RESP
+};
+
+struct spnic_cmdq_cmd_info {
+	enum spnic_cmdq_cmd_type cmd_type;
+};
+
+struct spnic_cmdq {
+	struct spnic_wq *wq;
+
+	enum spnic_cmdq_type cmdq_type;
+	int wrapped;
+
+	int *errcode;
+	u8  *db_base;
+
+	rte_spinlock_t cmdq_lock;
+
+	struct spnic_cmdq_ctxt_info cmdq_ctxt;
+
+	struct spnic_cmdq_cmd_info *cmd_infos;
+};
+
+struct spnic_cmdqs {
+	struct spnic_hwdev *hwdev;
+
+	struct rte_mempool *cmd_buf_pool;
+
+	struct spnic_wq *saved_wqs;
+
+	struct spnic_cmdq cmdq[SPNIC_MAX_CMDQ_TYPES];
+
+	u32 status;
+};
+
+struct spnic_cmd_buf {
+	void *buf;
+	uint64_t dma_addr;
+	struct rte_mbuf *mbuf;
+	u16 size;
+};
+
+int spnic_reinit_cmdq_ctxts(struct spnic_hwdev *hwdev);
+
+int spnic_cmdqs_init(struct spnic_hwdev *hwdev);
+
+void spnic_cmdqs_free(struct spnic_hwdev *hwdev);
+
+#endif /* _SPNIC_CMDQ_H_ */
diff --git a/drivers/net/spnic/base/spnic_hw_comm.c b/drivers/net/spnic/base/spnic_hw_comm.c
new file mode 100644
index 0000000000..7c58989c14
--- /dev/null
+++ b/drivers/net/spnic/base/spnic_hw_comm.c
@@ -0,0 +1,222 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd
+ */
+
+#include <ethdev_driver.h>
+#include <rte_bus_pci.h>
+#include <rte_hash.h>
+#include <rte_jhash.h>
+
+#include "spnic_compat.h"
+#include "spnic_csr.h"
+#include "spnic_hwdev.h"
+#include "spnic_hwif.h"
+#include "spnic_mgmt.h"
+#include "spnic_cmdq.h"
+#include "spnic_hw_comm.h"
+#include "spnic_cmd.h"
+
+#define	SPNIC_MSIX_CNT_LLI_TIMER_SHIFT			0
+#define	SPNIC_MSIX_CNT_LLI_CREDIT_SHIFT			8
+#define	SPNIC_MSIX_CNT_COALESC_TIMER_SHIFT		8
+#define	SPNIC_MSIX_CNT_PENDING_SHIFT			8
+#define	SPNIC_MSIX_CNT_RESEND_TIMER_SHIFT		29
+
+#define	SPNIC_MSIX_CNT_LLI_TIMER_MASK			0xFFU
+#define	SPNIC_MSIX_CNT_LLI_CREDIT_MASK			0xFFU
+#define	SPNIC_MSIX_CNT_COALESC_TIMER_MASK		0xFFU
+#define	SPNIC_MSIX_CNT_PENDING_MASK			0x1FU
+#define	SPNIC_MSIX_CNT_RESEND_TIMER_MASK		0x7U
+
+int spnic_get_interrupt_cfg(void *dev, struct interrupt_info *info)
+{
+	struct spnic_hwdev *hwdev = dev;
+	struct spnic_cmd_msix_config msix_cfg;
+	u16 out_size = sizeof(msix_cfg);
+	int err;
+
+	if (!hwdev || !info)
+		return -EINVAL;
+
+	memset(&msix_cfg, 0, sizeof(msix_cfg));
+	msix_cfg.func_id = spnic_global_func_id(hwdev);
+	msix_cfg.msix_index = info->msix_index;
+	msix_cfg.opcode = SPNIC_MGMT_CMD_OP_GET;
+
+	err = spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_COMM,
+				      MGMT_CMD_CFG_MSIX_CTRL_REG,
+				      &msix_cfg, sizeof(msix_cfg),
+				      &msix_cfg, &out_size, 0);
+	if (err || !out_size || msix_cfg.status) {
+		PMD_DRV_LOG(ERR, "Get interrupt config failed, err: %d, "
+			    "status: 0x%x, out size: 0x%x",
+			    err, msix_cfg.status, out_size);
+		return -EINVAL;
+	}
+
+	info->lli_credit_limit = msix_cfg.lli_credit_cnt;
+	info->lli_timer_cfg = msix_cfg.lli_tmier_cnt;
+	info->pending_limt = msix_cfg.pending_cnt;
+	info->coalesc_timer_cfg = msix_cfg.coalesct_timer_cnt;
+	info->resend_timer_cfg = msix_cfg.resend_timer_cnt;
+
+	return 0;
+}
+
+/**
+ * Set interrupt cfg
+ *
+ * @param[in] dev
+ *   The pointer to the private hardware device object
+ * @param[in] info
+ *   Interrupt info
+ *
+ * @retval zero : Success
+ * @retval negative : Failure.
+ */
+int spnic_set_interrupt_cfg(void *dev, struct interrupt_info info)
+{
+	struct spnic_hwdev *hwdev = dev;
+	struct spnic_cmd_msix_config msix_cfg;
+	struct interrupt_info temp_info;
+	u16 out_size = sizeof(msix_cfg);
+	int err;
+
+	if (!hwdev)
+		return -EINVAL;
+
+	temp_info.msix_index = info.msix_index;
+	err = spnic_get_interrupt_cfg(hwdev, &temp_info);
+	if (err)
+		return -EIO;
+
+	memset(&msix_cfg, 0, sizeof(msix_cfg));
+	msix_cfg.func_id = spnic_global_func_id(hwdev);
+	msix_cfg.msix_index = (u16)info.msix_index;
+	msix_cfg.opcode = SPNIC_MGMT_CMD_OP_SET;
+
+	msix_cfg.lli_credit_cnt = temp_info.lli_credit_limit;
+	msix_cfg.lli_tmier_cnt = temp_info.lli_timer_cfg;
+	msix_cfg.pending_cnt = temp_info.pending_limt;
+	msix_cfg.coalesct_timer_cnt = temp_info.coalesc_timer_cfg;
+	msix_cfg.resend_timer_cnt = temp_info.resend_timer_cfg;
+
+	if (info.lli_set) {
+		msix_cfg.lli_credit_cnt = info.lli_credit_limit;
+		msix_cfg.lli_tmier_cnt = info.lli_timer_cfg;
+	}
+
+	if (info.interrupt_coalesc_set) {
+		msix_cfg.pending_cnt = info.pending_limt;
+		msix_cfg.coalesct_timer_cnt = info.coalesc_timer_cfg;
+		msix_cfg.resend_timer_cnt = info.resend_timer_cfg;
+	}
+
+	err = spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_COMM,
+				     MGMT_CMD_CFG_MSIX_CTRL_REG,
+				     &msix_cfg, sizeof(msix_cfg),
+				     &msix_cfg, &out_size, 0);
+	if (err || !out_size || msix_cfg.status) {
+		PMD_DRV_LOG(ERR, "Set interrupt config failed, err: %d, "
+			    "status: 0x%x, out size: 0x%x",
+			    err, msix_cfg.status, out_size);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int spnic_set_wq_page_size(void *hwdev, u16 func_idx, u32 page_size)
+{
+	struct spnic_cmd_wq_page_size page_size_info;
+	u16 out_size = sizeof(page_size_info);
+	int err;
+
+	memset(&page_size_info, 0, sizeof(page_size_info));
+	page_size_info.func_idx = func_idx;
+	page_size_info.page_size = SPNIC_PAGE_SIZE_HW(page_size);
+	page_size_info.opcode = SPNIC_MGMT_CMD_OP_SET;
+
+	err = spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_COMM,
+				     MGMT_CMD_CFG_PAGESIZE,
+				     &page_size_info, sizeof(page_size_info),
+				     &page_size_info, &out_size, 0);
+	if (err || !out_size || page_size_info.status) {
+		PMD_DRV_LOG(ERR, "Set wq page size failed, err: %d, "
+			    "status: 0x%x, out_size: 0x%0x",
+			    err, page_size_info.status, out_size);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+int spnic_set_cmdq_depth(void *hwdev, u16 cmdq_depth)
+{
+	struct spnic_cmd_root_ctxt root_ctxt;
+	u16 out_size = sizeof(root_ctxt);
+	int err;
+
+	memset(&root_ctxt, 0, sizeof(root_ctxt));
+	root_ctxt.func_idx = spnic_global_func_id(hwdev);
+	root_ctxt.set_cmdq_depth = 1;
+	root_ctxt.cmdq_depth = (u8)ilog2(cmdq_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 cmdq depth failed, err: %d, status: 0x%x, out_size: 0x%x",
+			    err, root_ctxt.status, out_size);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+/**
+ * Set the dma attributes for entry
+ *
+ * @param[in] hwdev
+ *   The pointer to the private hardware device object
+ * @param[in] entry_idx
+ *   The entry index in the dma table
+ * @param[in] st
+ *   PCIE TLP steering tag
+ * @param[in] at
+ *   PCIE TLP AT field
+ * @param[in] ph
+ *   PCIE TLP Processing Hint field
+ * @param[in] no_snooping
+ *   PCIE TLP No snooping
+ * @param[in] tph_en
+ *   PCIE TLP Processing Hint Enable
+ */
+int spnic_set_dma_attr_tbl(struct spnic_hwdev *hwdev, u32 entry_idx, u8 st,
+			   u8 at, u8 ph, u8 no_snooping, u8 tph_en)
+{
+	struct comm_cmd_dma_attr_config dma_attr;
+	u16 out_size = sizeof(dma_attr);
+	int err;
+
+	memset(&dma_attr, 0, sizeof(dma_attr));
+	dma_attr.func_id = spnic_global_func_id(hwdev);
+	dma_attr.entry_idx = entry_idx;
+	dma_attr.st = st;
+	dma_attr.at = at;
+	dma_attr.ph = ph;
+	dma_attr.no_snooping = no_snooping;
+	dma_attr.tph_en = tph_en;
+
+	err = spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_COMM,
+				     MGMT_CMD_SET_DMA_ATTR,
+				     &dma_attr, sizeof(dma_attr),
+				     &dma_attr, &out_size, 0);
+	if (err || !out_size || dma_attr.head.status) {
+		PMD_DRV_LOG(ERR, "Failed to set dma attr, err: %d, status: 0x%x, out_size: 0x%x\n",
+			    err, dma_attr.head.status, out_size);
+		return -EINVAL;
+	}
+
+	return 0;
+}
diff --git a/drivers/net/spnic/base/spnic_hw_comm.h b/drivers/net/spnic/base/spnic_hw_comm.h
new file mode 100644
index 0000000000..3b2373e027
--- /dev/null
+++ b/drivers/net/spnic/base/spnic_hw_comm.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd
+ */
+
+#ifndef _SPNIC_HW_COMM_H_
+#define _SPNIC_HW_COMM_H_
+
+#define SPNIC_MGMT_CMD_OP_GET	0
+#define SPNIC_MGMT_CMD_OP_SET	1
+
+#define	SPNIC_MSIX_CNT_LLI_TIMER_SHIFT			0
+#define	SPNIC_MSIX_CNT_LLI_CREDIT_SHIFT			8
+#define	SPNIC_MSIX_CNT_COALESC_TIMER_SHIFT		8
+#define	SPNIC_MSIX_CNT_PENDING_SHIFT			8
+#define	SPNIC_MSIX_CNT_RESEND_TIMER_SHIFT		29
+
+#define	SPNIC_MSIX_CNT_LLI_TIMER_MASK			0xFFU
+#define	SPNIC_MSIX_CNT_LLI_CREDIT_MASK			0xFFU
+#define	SPNIC_MSIX_CNT_COALESC_TIMER_MASK		0xFFU
+#define	SPNIC_MSIX_CNT_PENDING_MASK			0x1FU
+#define	SPNIC_MSIX_CNT_RESEND_TIMER_MASK		0x7U
+
+#define SPNIC_MSIX_CNT_SET(val, member)		\
+		(((val) & SPNIC_MSIX_CNT_##member##_MASK) << \
+		SPNIC_MSIX_CNT_##member##_SHIFT)
+
+#define MSG_TO_MGMT_SYNC_RETURN_ERR(err, out_size, status)	\
+		((err) || (status) || !(out_size))
+
+struct spnic_cmd_msix_config {
+	u8  status;
+	u8  version;
+	u8  rsvd0[6];
+
+	u16 func_id;
+	u8 opcode;
+	u8 rsvd1;
+	u16 msix_index;
+	u8  pending_cnt;
+	u8  coalesct_timer_cnt;
+	u8  resend_timer_cnt;
+	u8  lli_tmier_cnt;
+	u8  lli_credit_cnt;
+	u8  rsvd2[5];
+};
+
+#define SPNIC_PAGE_SIZE_HW(pg_size)	((u8)ilog2((u32)((pg_size) >> 12)))
+
+struct spnic_cmd_wq_page_size {
+	u8  status;
+	u8  version;
+	u8  rsvd0[6];
+
+	u16 func_idx;
+	u8  opcode;
+	/*
+	 * Real size is 4KB * 2^page_size, range(0~20) must be checked
+	 * by driver
+	 */
+	u8  page_size;
+
+	u32 rsvd1;
+};
+
+struct spnic_reset {
+	u8  status;
+	u8  version;
+	u8  rsvd0[6];
+
+	u16 func_id;
+	u16 rsvd1[3];
+	u64 reset_flag;
+};
+
+struct spnic_cmd_root_ctxt {
+	u8  status;
+	u8  version;
+	u8  rsvd0[6];
+
+	u16 func_idx;
+	u8  set_cmdq_depth;
+	u8  cmdq_depth;
+	u16 rx_buf_sz;
+	u8  lro_en;
+	u8  rsvd1;
+	u16 sq_depth;
+	u16 rq_depth;
+	u64 rsvd2;
+};
+
+enum spnic_fw_ver_type {
+	SPNIC_FW_VER_TYPE_BOOT,
+	SPNIC_FW_VER_TYPE_MPU,
+	SPNIC_FW_VER_TYPE_NPU,
+	SPNIC_FW_VER_TYPE_SMU,
+	SPNIC_FW_VER_TYPE_CFG,
+};
+
+struct comm_cmd_dma_attr_config {
+	struct mgmt_msg_head head;
+
+	u16 func_id;
+	u8 entry_idx;
+	u8 st;
+	u8 at;
+	u8 ph;
+	u8 no_snooping;
+	u8 tph_en;
+	u32 resv1;
+};
+
+#define SPNIC_FW_VERSION_LEN		16
+#define SPNIC_FW_COMPILE_TIME_LEN	20
+#define SPNIC_MGMT_VERSION_MAX_LEN	32
+struct spnic_cmd_get_fw_version {
+	u8 status;
+	u8 version;
+	u8 rsvd0[6];
+
+	u16 fw_type;
+	u16 rsvd1;
+	u8 ver[SPNIC_FW_VERSION_LEN];
+	u8 time[SPNIC_FW_COMPILE_TIME_LEN];
+};
+
+struct spnic_cmd_clear_doorbell {
+	u8 status;
+	u8 version;
+	u8 rsvd0[6];
+
+	u16 func_idx;
+	u16 rsvd1[3];
+};
+
+struct spnic_cmd_clear_resource {
+	u8  status;
+	u8  version;
+	u8  rsvd0[6];
+
+	u16 func_idx;
+	u16 rsvd1[3];
+};
+
+struct spnic_cmd_board_info {
+	u8  status;
+	u8  version;
+	u8  rsvd0[6];
+
+	struct spnic_board_info info;
+
+	u32 rsvd1[25];
+};
+
+struct interrupt_info {
+	u32 lli_set;
+	u32 interrupt_coalesc_set;
+	u16 msix_index;
+	u8 lli_credit_limit;
+	u8 lli_timer_cfg;
+	u8 pending_limt;
+	u8 coalesc_timer_cfg;
+	u8 resend_timer_cfg;
+};
+
+int spnic_get_interrupt_cfg(void *dev, struct interrupt_info *info);
+
+int spnic_set_interrupt_cfg(void *dev, struct interrupt_info info);
+
+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_set_dma_attr_tbl(struct spnic_hwdev *hwdev, u32 entry_idx, u8 st,
+			   u8 at, u8 ph, u8 no_snooping, u8 tph_en);
+
+#endif
diff --git a/drivers/net/spnic/base/spnic_hwdev.c b/drivers/net/spnic/base/spnic_hwdev.c
index 1289ea58c7..241f9d4e0b 100644
--- a/drivers/net/spnic/base/spnic_hwdev.c
+++ b/drivers/net/spnic/base/spnic_hwdev.c
@@ -9,7 +9,64 @@
 #include "spnic_mgmt.h"
 #include "spnic_cmd.h"
 #include "spnic_mbox.h"
+#include "spnic_cmdq.h"
 #include "spnic_hwdev.h"
+#include "spnic_hw_comm.h"
+
+enum spnic_pcie_nosnoop {
+	SPNIC_PCIE_SNOOP = 0,
+	SPNIC_PCIE_NO_SNOOP = 1
+};
+
+enum spnic_pcie_tph {
+	SPNIC_PCIE_TPH_DISABLE = 0,
+	SPNIC_PCIE_TPH_ENABLE = 1
+};
+
+#define SPNIC_DMA_ATTR_INDIR_IDX_SHIFT				0
+
+#define SPNIC_DMA_ATTR_INDIR_IDX_MASK				0x3FF
+
+#define SPNIC_DMA_ATTR_INDIR_IDX_SET(val, member)			\
+		(((u32)(val) & SPNIC_DMA_ATTR_INDIR_##member##_MASK) << \
+			SPNIC_DMA_ATTR_INDIR_##member##_SHIFT)
+
+#define SPNIC_DMA_ATTR_INDIR_IDX_CLEAR(val, member)		\
+		((val) & (~(SPNIC_DMA_ATTR_INDIR_##member##_MASK	\
+			<< SPNIC_DMA_ATTR_INDIR_##member##_SHIFT)))
+
+#define SPNIC_DMA_ATTR_ENTRY_ST_SHIFT				0
+#define SPNIC_DMA_ATTR_ENTRY_AT_SHIFT				8
+#define SPNIC_DMA_ATTR_ENTRY_PH_SHIFT				10
+#define SPNIC_DMA_ATTR_ENTRY_NO_SNOOPING_SHIFT			12
+#define SPNIC_DMA_ATTR_ENTRY_TPH_EN_SHIFT			13
+
+#define SPNIC_DMA_ATTR_ENTRY_ST_MASK				0xFF
+#define SPNIC_DMA_ATTR_ENTRY_AT_MASK				0x3
+#define SPNIC_DMA_ATTR_ENTRY_PH_MASK				0x3
+#define SPNIC_DMA_ATTR_ENTRY_NO_SNOOPING_MASK			0x1
+#define SPNIC_DMA_ATTR_ENTRY_TPH_EN_MASK			0x1
+
+#define SPNIC_DMA_ATTR_ENTRY_SET(val, member)			\
+		(((u32)(val) & SPNIC_DMA_ATTR_ENTRY_##member##_MASK) << \
+			SPNIC_DMA_ATTR_ENTRY_##member##_SHIFT)
+
+#define SPNIC_DMA_ATTR_ENTRY_CLEAR(val, member)		\
+		((val) & (~(SPNIC_DMA_ATTR_ENTRY_##member##_MASK	\
+			<< SPNIC_DMA_ATTR_ENTRY_##member##_SHIFT)))
+
+#define SPNIC_PCIE_ST_DISABLE			0
+#define SPNIC_PCIE_AT_DISABLE			0
+#define SPNIC_PCIE_PH_DISABLE			0
+
+#define PCIE_MSIX_ATTR_ENTRY			0
+
+#define SPNIC_CHIP_PRESENT			1
+#define SPNIC_CHIP_ABSENT			0
+
+#define SPNIC_DEAULT_EQ_MSIX_PENDING_LIMIT	0
+#define SPNIC_DEAULT_EQ_MSIX_COALESC_TIMER_CFG	0xFF
+#define SPNIC_DEAULT_EQ_MSIX_RESEND_TIMER_CFG	7
 
 typedef void (*mgmt_event_cb)(void *handle, void *buf_in, u16 in_size,
 			      void *buf_out, u16 *out_size);
@@ -100,6 +157,78 @@ void spnic_pf_handle_mgmt_comm_event(void *handle, __rte_unused void *pri_handle
 	PMD_DRV_LOG(WARNING, "Unsupported mgmt cpu event %d to process", cmd);
 }
 
+/**
+ * Initialize the default dma attributes
+ *
+ * @param[in] hwdev
+ *   The pointer to the private hardware device object
+ *
+ * @retval zero: Success
+ * @retval non-zero: Failure
+ */
+static int dma_attr_table_init(struct spnic_hwdev *hwdev)
+{
+	u32 addr, val, dst_attr;
+
+	/* Use indirect access should set entry_idx first */
+	addr = SPNIC_CSR_DMA_ATTR_INDIR_IDX_ADDR;
+	val = spnic_hwif_read_reg(hwdev->hwif, addr);
+	val = SPNIC_DMA_ATTR_INDIR_IDX_CLEAR(val, IDX);
+
+	val |= SPNIC_DMA_ATTR_INDIR_IDX_SET(PCIE_MSIX_ATTR_ENTRY, IDX);
+
+	spnic_hwif_write_reg(hwdev->hwif, addr, val);
+
+	rte_wmb(); /* Write index before config */
+
+	addr = SPNIC_CSR_DMA_ATTR_TBL_ADDR;
+	val = spnic_hwif_read_reg(hwdev->hwif, addr);
+
+	dst_attr = SPNIC_DMA_ATTR_ENTRY_SET(SPNIC_PCIE_ST_DISABLE, ST)	|
+		SPNIC_DMA_ATTR_ENTRY_SET(SPNIC_PCIE_AT_DISABLE, AT)	|
+		SPNIC_DMA_ATTR_ENTRY_SET(SPNIC_PCIE_PH_DISABLE, PH)	|
+		SPNIC_DMA_ATTR_ENTRY_SET(SPNIC_PCIE_SNOOP, NO_SNOOPING)	|
+		SPNIC_DMA_ATTR_ENTRY_SET(SPNIC_PCIE_TPH_DISABLE, TPH_EN);
+
+	if (val == dst_attr)
+		return 0;
+
+	return spnic_set_dma_attr_tbl(hwdev, PCIE_MSIX_ATTR_ENTRY,
+				      SPNIC_PCIE_ST_DISABLE,
+				      SPNIC_PCIE_AT_DISABLE,
+				      SPNIC_PCIE_PH_DISABLE,
+				      SPNIC_PCIE_SNOOP,
+				      SPNIC_PCIE_TPH_DISABLE);
+}
+
+static int init_aeqs_msix_attr(struct spnic_hwdev *hwdev)
+{
+	struct spnic_aeqs *aeqs = hwdev->aeqs;
+	struct interrupt_info info = {0};
+	struct spnic_eq *eq = NULL;
+	u16 q_id;
+	int err;
+
+	info.lli_set = 0;
+	info.interrupt_coalesc_set = 1;
+	info.pending_limt = SPNIC_DEAULT_EQ_MSIX_PENDING_LIMIT;
+	info.coalesc_timer_cfg = SPNIC_DEAULT_EQ_MSIX_COALESC_TIMER_CFG;
+	info.resend_timer_cfg = SPNIC_DEAULT_EQ_MSIX_RESEND_TIMER_CFG;
+
+	for (q_id = 0; q_id < aeqs->num_aeqs; q_id++) {
+		eq = &aeqs->aeq[q_id];
+		info.msix_index = eq->eq_irq.msix_entry_idx;
+		err = spnic_set_interrupt_cfg(hwdev, info);
+		if (err) {
+			PMD_DRV_LOG(ERR, "Set msix attr for aeq %d failed",
+				q_id);
+			return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
 static int spnic_comm_pf_to_mgmt_init(struct spnic_hwdev *hwdev)
 {
 	int err;
@@ -124,6 +253,35 @@ static void spnic_comm_pf_to_mgmt_free(struct spnic_hwdev *hwdev)
 	spnic_pf_to_mgmt_free(hwdev);
 }
 
+static int spnic_comm_cmdqs_init(struct spnic_hwdev *hwdev)
+{
+	int err;
+
+	err = spnic_cmdqs_init(hwdev);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Init cmd queues failed");
+		return err;
+	}
+
+	err = spnic_set_cmdq_depth(hwdev, SPNIC_CMDQ_DEPTH);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Set cmdq depth failed");
+		goto set_cmdq_depth_err;
+	}
+
+	return 0;
+
+set_cmdq_depth_err:
+	spnic_cmdqs_free(hwdev);
+
+	return err;
+}
+
+static void spnic_comm_cmdqs_free(struct spnic_hwdev *hwdev)
+{
+	spnic_cmdqs_free(hwdev);
+}
+
 static int init_mgmt_channel(struct spnic_hwdev *hwdev)
 {
 	int err;
@@ -164,6 +322,51 @@ static void free_mgmt_channel(struct spnic_hwdev *hwdev)
 	spnic_aeqs_free(hwdev);
 }
 
+#define SPNIC_DEFAULT_WQ_PAGE_SIZE	0x100000
+#define SPNIC_HW_WQ_PAGE_SIZE		0x1000
+
+static int init_cmdqs_channel(struct spnic_hwdev *hwdev)
+{
+	int err;
+
+	err = dma_attr_table_init(hwdev);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Init dma attr table failed");
+		goto dma_attr_init_err;
+	}
+
+	err = init_aeqs_msix_attr(hwdev);
+	if (err)
+		goto init_aeqs_msix_err;
+
+	/* Set default wq page_size */
+	hwdev->wq_page_size = SPNIC_DEFAULT_WQ_PAGE_SIZE;
+	err = spnic_set_wq_page_size(hwdev, spnic_global_func_id(hwdev),
+				      hwdev->wq_page_size);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Set wq page size failed");
+		goto init_wq_pg_size_err;
+	}
+
+	err = spnic_comm_cmdqs_init(hwdev);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Init cmd queues failed");
+		goto cmdq_init_err;
+	}
+
+	return 0;
+
+cmdq_init_err:
+	if (SPNIC_FUNC_TYPE(hwdev) != TYPE_VF)
+		spnic_set_wq_page_size(hwdev, spnic_global_func_id(hwdev),
+					SPNIC_HW_WQ_PAGE_SIZE);
+init_wq_pg_size_err:
+init_aeqs_msix_err:
+dma_attr_init_err:
+
+	return err;
+}
+
 static int spnic_init_comm_ch(struct spnic_hwdev *hwdev)
 {
 	int err;
@@ -174,11 +377,23 @@ static int spnic_init_comm_ch(struct spnic_hwdev *hwdev)
 		return err;
 	}
 
+	err = init_cmdqs_channel(hwdev);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Init cmdq channel failed");
+		goto init_cmdqs_channel_err;
+	}
+
 	return 0;
+
+init_cmdqs_channel_err:
+	free_mgmt_channel(hwdev);
+
+	return err;
 }
 
 static void spnic_uninit_comm_ch(struct spnic_hwdev *hwdev)
 {
+	spnic_comm_cmdqs_free(hwdev);
 	free_mgmt_channel(hwdev);
 }
 
diff --git a/drivers/net/spnic/base/spnic_hwdev.h b/drivers/net/spnic/base/spnic_hwdev.h
index 1db004c6f2..48dba0934a 100644
--- a/drivers/net/spnic/base/spnic_hwdev.h
+++ b/drivers/net/spnic/base/spnic_hwdev.h
@@ -91,13 +91,17 @@ struct spnic_hwdev {
 	void *dev_handle; /* Pointer to spnic_nic_dev */
 	void *pci_dev; /* Pointer to rte_pci_device */
 	void *eth_dev; /* Pointer to rte_eth_dev */
-
+	struct spnic_hwif *hwif;
 	uint16_t port_id;
 
-	struct spnic_hwif *hwif;
+	u32 wq_page_size;
+
 	struct spnic_mbox *func_to_func;
 	struct cfg_mgmt_info *cfg_mgmt;
+
+	struct spnic_cmdqs *cmdqs;
 	struct spnic_aeqs *aeqs;
+
 	struct spnic_msg_pf_to_mgmt *pf_to_mgmt;
 	u8 *chip_fault_stats;
 	struct spnic_hw_stats hw_stats;
diff --git a/drivers/net/spnic/base/spnic_wq.h b/drivers/net/spnic/base/spnic_wq.h
new file mode 100644
index 0000000000..032d45e79e
--- /dev/null
+++ b/drivers/net/spnic/base/spnic_wq.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd
+ */
+
+#ifndef _SPNIC_WQ_H_
+#define _SPNIC_WQ_H_
+
+/* Use 0-level CLA, page size must be: SQ 16B(wqe) * 64k(max_q_depth) */
+#define SPNIC_DEFAULT_WQ_PAGE_SIZE	0x100000
+#define SPNIC_HW_WQ_PAGE_SIZE		0x1000
+
+#define CMDQ_BLOCKS_PER_PAGE		8
+#define CMDQ_BLOCK_SIZE			512UL
+#define CMDQ_PAGE_SIZE			RTE_ALIGN((CMDQ_BLOCKS_PER_PAGE * \
+						CMDQ_BLOCK_SIZE), PAGE_SIZE)
+
+#define CMDQ_BASE_VADDR(cmdq_pages, wq)	\
+			((u64 *)(((u64)((cmdq_pages)->cmdq_page_vaddr)) \
+				+ (u64)((wq)->block_idx * CMDQ_BLOCK_SIZE)))
+
+#define CMDQ_BASE_PADDR(cmdq_pages, wq)	\
+			(((u64)((cmdq_pages)->cmdq_page_paddr)) \
+				+ (u64)(wq)->block_idx * CMDQ_BLOCK_SIZE)
+
+#define CMDQ_BASE_ADDR(cmdq_pages, wq)	\
+			((u64 *)(((u64)((cmdq_pages)->cmdq_shadow_page_vaddr)) \
+				+ (u64)((wq)->block_idx * CMDQ_BLOCK_SIZE)))
+
+#define MASKED_WQE_IDX(wq, idx)	((idx) & (wq)->mask)
+
+#define	WQ_WQE_ADDR(wq, idx) ((void *)((u64)((wq)->queue_buf_vaddr) + \
+			      ((idx) << (wq)->wqebb_shift)))
+
+struct spnic_wq {
+	/* The addresses are 64 bit in the HW */
+	u64 queue_buf_vaddr;
+
+	u16 q_depth;
+	u16 mask;
+	rte_atomic32_t delta;
+
+	u32 cons_idx;
+	u32 prod_idx;
+
+	u64 queue_buf_paddr;
+
+	u32 wqebb_size;
+	u32 wqebb_shift;
+
+	u32 wq_buf_size;
+
+	const struct rte_memzone *wq_mz;
+
+	u32 rsvd[5];
+};
+
+#endif /* _SPNIC_WQ_H_ :*/
