[v6,05/26] net/spnic: add mgmt module

Message ID ff238f00fa098c02e8fd15c2068f45229a6e9118.1640838702.git.songyl@ramaxel.com (mailing list archive)
State Changes Requested, archived
Delegated to: Ferruh Yigit
Headers
Series Net/SPNIC: support SPNIC into DPDK 22.03 |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Yanling Song Dec. 30, 2021, 6:08 a.m. UTC
  Mgmt module manage the message gerenated from the hardware.
This patch implements mgmt module initialization, related event
processing and message command definition.

Signed-off-by: Yanling Song <songyl@ramaxel.com>
---
 drivers/net/spnic/base/meson.build       |   4 +-
 drivers/net/spnic/base/spnic_cmd.h       | 222 ++++++++++++++
 drivers/net/spnic/base/spnic_eqs.c       |  46 ++-
 drivers/net/spnic/base/spnic_hwdev.c     |  91 +++++-
 drivers/net/spnic/base/spnic_hwdev.h     |  66 +++-
 drivers/net/spnic/base/spnic_mbox.c      |  16 +
 drivers/net/spnic/base/spnic_mgmt.c      | 367 +++++++++++++++++++++++
 drivers/net/spnic/base/spnic_mgmt.h      |  74 +++++
 drivers/net/spnic/base/spnic_nic_event.c | 162 ++++++++++
 drivers/net/spnic/base/spnic_nic_event.h |  29 ++
 10 files changed, 1066 insertions(+), 11 deletions(-)
 create mode 100644 drivers/net/spnic/base/spnic_cmd.h
 create mode 100644 drivers/net/spnic/base/spnic_mgmt.c
 create mode 100644 drivers/net/spnic/base/spnic_nic_event.c
 create mode 100644 drivers/net/spnic/base/spnic_nic_event.h
  

Comments

Ferruh Yigit Jan. 19, 2022, 5:22 p.m. UTC | #1
On 12/30/2021 6:08 AM, Yanling Song wrote:
> Mgmt module manage the message gerenated from the hardware.
> This patch implements mgmt module initialization, related event
> processing and message command definition.
> 
> Signed-off-by: Yanling Song <songyl@ramaxel.com>

<...>

> +static void spnic_get_port_link_info(u8 link_state, struct rte_eth_link *link)
> +{
> +	if (!link_state) {
> +		link->link_status = ETH_LINK_DOWN;
> +		link->link_speed = ETH_SPEED_NUM_NONE;
> +		link->link_duplex = ETH_LINK_HALF_DUPLEX;
> +		link->link_autoneg = ETH_LINK_FIXED;
> +	}

The driver is using deprecated macros. If you can rebase on top of latest
next-net, you will get the warnings.

Since it is hard to continue with bunch of build errors, I will wait for
next version and can continue the reviews with it.
  
Yanling Song Jan. 21, 2022, 9:33 a.m. UTC | #2
On Wed, 19 Jan 2022 17:22:51 +0000
Ferruh Yigit <ferruh.yigit@intel.com> wrote:

> On 12/30/2021 6:08 AM, Yanling Song wrote:
> > Mgmt module manage the message gerenated from the hardware.
> > This patch implements mgmt module initialization, related event
> > processing and message command definition.
> > 
> > Signed-off-by: Yanling Song <songyl@ramaxel.com>  
> 
> <...>
> 
> > +static void spnic_get_port_link_info(u8 link_state, struct
> > rte_eth_link *link) +{
> > +	if (!link_state) {
> > +		link->link_status = ETH_LINK_DOWN;
> > +		link->link_speed = ETH_SPEED_NUM_NONE;
> > +		link->link_duplex = ETH_LINK_HALF_DUPLEX;
> > +		link->link_autoneg = ETH_LINK_FIXED;
> > +	}  
> 
> The driver is using deprecated macros. If you can rebase on top of
> latest next-net, you will get the warnings.
> 
> Since it is hard to continue with bunch of build errors, I will wait
> for next version and can continue the reviews with it.

Thanks for pointing it out. Will use new macros to replace the old ones
in the next version.
  

Patch

diff --git a/drivers/net/spnic/base/meson.build b/drivers/net/spnic/base/meson.build
index ce7457f400..3f6a060b37 100644
--- a/drivers/net/spnic/base/meson.build
+++ b/drivers/net/spnic/base/meson.build
@@ -5,7 +5,9 @@  sources = [
 	'spnic_eqs.c',
 	'spnic_hwdev.c',
 	'spnic_hwif.c',
-	'spnic_mbox.c'
+	'spnic_mbox.c',
+	'spnic_mgmt.c',
+	'spnic_nic_event.c'
 ]
 
 extra_flags = []
diff --git a/drivers/net/spnic/base/spnic_cmd.h b/drivers/net/spnic/base/spnic_cmd.h
new file mode 100644
index 0000000000..4f0c46f900
--- /dev/null
+++ b/drivers/net/spnic/base/spnic_cmd.h
@@ -0,0 +1,222 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd
+ */
+
+#ifndef _SPNIC_CMD_H_
+#define _SPNIC_CMD_H_
+
+#define NIC_RSS_TEMP_ID_TO_CTX_LT_IDX(tmp_id)	tmp_id
+/* Begin of one temp tbl */
+#define NIC_RSS_TEMP_ID_TO_INDIR_LT_IDX(tmp_id)	((tmp_id) << 4)
+/* 4 ctx in one entry */
+#define NIC_RSS_CTX_TBL_ENTRY_SIZE		0x10
+/* Entry size = 16B, 16 entry/template */
+#define NIC_RSS_INDIR_TBL_ENTRY_SIZE		0x10
+/* Entry size = 16B, so entry_num = 256B/16B */
+#define NIC_RSS_INDIR_TBL_ENTRY_NUM		0x10
+
+#define NIC_UP_RSS_INVALID_TEMP_ID		0xFF
+#define NIC_UP_RSS_INVALID_FUNC_ID		0xFFFF
+#define NIC_UP_RSS_INVALID			0x00
+#define NIC_UP_RSS_EN				0x01
+#define NIC_UP_RSS_INVALID_GROUP_ID		0x7F
+
+#define NIC_RSS_CMD_TEMP_ALLOC			0x01
+#define NIC_RSS_CMD_TEMP_FREE			0x02
+
+#define SPNIC_RSS_TYPE_VALID_SHIFT		23
+#define SPNIC_RSS_TYPE_TCP_IPV6_EXT_SHIFT	24
+#define SPNIC_RSS_TYPE_IPV6_EXT_SHIFT		25
+#define SPNIC_RSS_TYPE_TCP_IPV6_SHIFT		26
+#define SPNIC_RSS_TYPE_IPV6_SHIFT		27
+#define SPNIC_RSS_TYPE_TCP_IPV4_SHIFT		28
+#define SPNIC_RSS_TYPE_IPV4_SHIFT		29
+#define SPNIC_RSS_TYPE_UDP_IPV6_SHIFT		30
+#define SPNIC_RSS_TYPE_UDP_IPV4_SHIFT		31
+#define SPNIC_RSS_TYPE_SET(val, member)	\
+	(((u32)(val) & 0x1) << SPNIC_RSS_TYPE_##member##_SHIFT)
+
+#define SPNIC_RSS_TYPE_GET(val, member)	\
+	(((u32)(val) >> SPNIC_RSS_TYPE_##member##_SHIFT) & 0x1)
+
+/* NIC CMDQ MODE */
+typedef enum spnic_ucode_cmd {
+	SPNIC_UCODE_CMD_MODIFY_QUEUE_CTX = 0,
+	SPNIC_UCODE_CMD_CLEAN_QUEUE_CONTEXT,
+	SPNIC_UCODE_CMD_ARM_SQ,
+	SPNIC_UCODE_CMD_ARM_RQ,
+	SPNIC_UCODE_CMD_SET_RSS_INDIR_TABLE,
+	SPNIC_UCODE_CMD_SET_RSS_CONTEXT_TABLE,
+	SPNIC_UCODE_CMD_GET_RSS_INDIR_TABLE,
+	SPNIC_UCODE_CMD_GET_RSS_CONTEXT_TABLE,
+	SPNIC_UCODE_CMD_SET_IQ_ENABLE,
+	SPNIC_UCODE_CMD_SET_RQ_FLUSH = 10,
+	SPNIC_UCODE_CMD_MODIFY_VLAN_CTX,
+	SPNIC_UCODE_CMD_DPI_FLOW
+} cmdq_nic_subtype_e;
+
+/*
+ * Commands between NIC and MPU
+ */
+enum spnic_cmd {
+	SPNIC_CMD_VF_REGISTER = 0, /* only for PFD and VFD */
+
+	/* FUNC CFG */
+	SPNIC_CMD_SET_FUNC_TBL = 5,
+	SPNIC_CMD_SET_VPORT_ENABLE,
+	SPNIC_CMD_SET_RX_MODE,
+	SPNIC_CMD_SQ_CI_ATTR_SET,
+	SPNIC_CMD_GET_VPORT_STAT,
+	SPNIC_CMD_CLEAN_VPORT_STAT,
+	SPNIC_CMD_CLEAR_QP_RESOURCE,
+	SPNIC_CMD_CFG_FLEX_QUEUE,
+	/* LRO CFG */
+	SPNIC_CMD_CFG_RX_LRO,
+	SPNIC_CMD_CFG_LRO_TIMER,
+	SPNIC_CMD_FEATURE_NEGO,
+
+	/* MAC & VLAN CFG */
+	SPNIC_CMD_GET_MAC = 20,
+	SPNIC_CMD_SET_MAC,
+	SPNIC_CMD_DEL_MAC,
+	SPNIC_CMD_UPDATE_MAC,
+	SPNIC_CMD_GET_ALL_DEFAULT_MAC,
+
+	SPNIC_CMD_CFG_FUNC_VLAN,
+	SPNIC_CMD_SET_VLAN_FILTER_EN,
+	SPNIC_CMD_SET_RX_VLAN_OFFLOAD,
+
+	/* SR-IOV */
+	SPNIC_CMD_CFG_VF_VLAN = 40,
+	SPNIC_CMD_SET_SPOOPCHK_STATE,
+	/* RATE LIMIT */
+	SPNIC_CMD_SET_MAX_MIN_RATE,
+
+	/* RSS CFG */
+	SPNIC_CMD_RSS_CFG = 60,
+	SPNIC_CMD_RSS_TEMP_MGR,
+	SPNIC_CMD_GET_RSS_CTX_TBL,
+	SPNIC_CMD_CFG_RSS_HASH_KEY,
+	SPNIC_CMD_CFG_RSS_HASH_ENGINE,
+	SPNIC_CMD_GET_INDIR_TBL,
+
+	/* DPI/FDIR */
+	SPNIC_CMD_ADD_TC_FLOW = 80,
+	SPNIC_CMD_DEL_TC_FLOW,
+	SPNIC_CMD_GET_TC_FLOW,
+	SPNIC_CMD_FLUSH_TCAM,
+	SPNIC_CMD_CFG_TCAM_BLOCK,
+	SPNIC_CMD_ENABLE_TCAM,
+	SPNIC_CMD_GET_TCAM_BLOCK,
+
+	/* PORT CFG */
+	SPNIC_CMD_SET_PORT_ENABLE = 100,
+	SPNIC_CMD_CFG_PAUSE_INFO,
+
+	SPNIC_CMD_SET_PORT_CAR,
+	SPNIC_CMD_SET_ER_DROP_PKT,
+
+	SPNIC_CMD_VF_COS,
+	SPNIC_CMD_SETUP_COS_MAPPING,
+	SPNIC_CMD_SET_ETS,
+	SPNIC_CMD_SET_PFC,
+
+	/* MISC */
+	SPNIC_CMD_BIOS_CFG = 120,
+	SPNIC_CMD_SET_FIRMWARE_CUSTOM_PACKETS_MSG,
+
+	/* DFX */
+	SPNIC_CMD_GET_SM_TABLE = 140,
+	SPNIC_CMD_RD_LINE_TBL,
+
+	SPNIC_CMD_MAX = 256
+};
+
+/* COMM commands between driver to MPU */
+enum spnic_mgmt_cmd {
+	MGMT_CMD_FUNC_RESET = 0,
+	MGMT_CMD_FEATURE_NEGO,
+	MGMT_CMD_FLUSH_DOORBELL,
+	MGMT_CMD_START_FLUSH,
+	MGMT_CMD_SET_FUNC_FLR,
+
+	MGMT_CMD_SET_CMDQ_CTXT = 20,
+	MGMT_CMD_SET_VAT,
+	MGMT_CMD_CFG_PAGESIZE,
+	MGMT_CMD_CFG_MSIX_CTRL_REG,
+	MGMT_CMD_SET_CEQ_CTRL_REG,
+	MGMT_CMD_SET_DMA_ATTR,
+
+	MGMT_CMD_GET_MQM_FIX_INFO = 40,
+	MGMT_CMD_SET_MQM_CFG_INFO,
+	MGMT_CMD_SET_MQM_SRCH_GPA,
+	MGMT_CMD_SET_PPF_TMR,
+	MGMT_CMD_SET_PPF_HT_GPA,
+	MGMT_CMD_SET_FUNC_TMR_BITMAT,
+
+	MGMT_CMD_GET_FW_VERSION = 60,
+	MGMT_CMD_GET_BOARD_INFO,
+	MGMT_CMD_SYNC_TIME,
+	MGMT_CMD_GET_HW_PF_INFOS,
+	MGMT_CMD_SEND_BDF_INFO,
+
+	MGMT_CMD_UPDATE_FW = 80,
+	MGMT_CMD_ACTIVE_FW,
+	MGMT_CMD_HOT_ACTIVE_FW,
+	MGMT_CMD_HOT_ACTIVE_DONE_NOTICE,
+	MGMT_CMD_SWITCH_CFG,
+	MGMT_CMD_CHECK_FLASH,
+	MGMT_CMD_CHECK_FLASH_RW,
+	MGMT_CMD_RESOURCE_CFG,
+	MGMT_CMD_UPDATE_BIOS,
+
+	MGMT_CMD_FAULT_REPORT = 100,
+	MGMT_CMD_WATCHDOG_INFO,
+	MGMT_CMD_MGMT_RESET,
+	MGMT_CMD_FFM_SET,
+
+	MGMT_CMD_GET_LOG = 120,
+	MGMT_CMD_TEMP_OP,
+	MGMT_CMD_EN_AUTO_RST_CHIP,
+	MGMT_CMD_CFG_REG,
+	MGMT_CMD_GET_CHIP_ID,
+	MGMT_CMD_SYSINFO_DFX,
+	MGMT_CMD_PCIE_DFX_NTC,
+};
+
+enum mag_cmd {
+	SERDES_CMD_PROCESS = 0,
+
+	MAG_CMD_SET_PORT_CFG      = 1,
+	MAG_CMD_SET_PORT_ADAPT    = 2,
+	MAG_CMD_CFG_LOOPBACK_MODE = 3,
+
+	MAG_CMD_GET_PORT_ENABLE   = 5,
+	MAG_CMD_SET_PORT_ENABLE   = 6,
+	MAG_CMD_GET_LINK_STATUS   = 7,
+	MAG_CMD_SET_LINK_FOLLOW   = 8,
+	MAG_CMD_SET_PMA_ENABLE    = 9,
+	MAG_CMD_CFG_FEC_MODE      = 10,
+
+	/* PHY */
+	MAG_CMD_GET_XSFP_INFO        = 60,
+	MAG_CMD_SET_XSFP_ENABLE      = 61,
+	MAG_CMD_GET_XSFP_PRESENT     = 62,
+	MAG_CMD_SET_XSFP_RW          = 63,
+	MAG_CMD_CFG_XSFP_TEMPERATURE = 64,
+
+	MAG_CMD_WIRE_EVENT        = 100,
+	MAG_CMD_LINK_ERR_EVENT    = 101,
+
+	MAG_CMD_EVENT_PORT_INFO   = 150,
+	MAG_CMD_GET_PORT_STAT     = 151,
+	MAG_CMD_CLR_PORT_STAT     = 152,
+	MAG_CMD_GET_PORT_INFO     = 153,
+	MAG_CMD_GET_PCS_ERR_CNT   = 154,
+	MAG_CMD_GET_MAG_CNT       = 155,
+	MAG_CMD_DUMP_ANTRAIN_INFO = 156,
+
+	MAG_CMD_MAX = 0xFF
+};
+
+#endif /* _SPNIC_CMD_H_ */
diff --git a/drivers/net/spnic/base/spnic_eqs.c b/drivers/net/spnic/base/spnic_eqs.c
index 7953976441..ee52252ecc 100644
--- a/drivers/net/spnic/base/spnic_eqs.c
+++ b/drivers/net/spnic/base/spnic_eqs.c
@@ -12,6 +12,7 @@ 
 #include "spnic_eqs.h"
 #include "spnic_mgmt.h"
 #include "spnic_mbox.h"
+#include "spnic_nic_event.h"
 
 #define AEQ_CTRL_0_INTR_IDX_SHIFT		0
 #define AEQ_CTRL_0_DMA_ATTR_SHIFT		12
@@ -510,6 +511,39 @@  void spnic_aeqs_free(struct spnic_hwdev *hwdev)
 	rte_free(aeqs);
 }
 
+void spnic_dump_aeq_info(struct spnic_hwdev *hwdev)
+{
+	struct spnic_aeq_elem *aeqe_pos = NULL;
+	struct spnic_eq *eq = NULL;
+	u32 addr, ci, pi, ctrl0, idx;
+	int q_id;
+
+	for (q_id = 0; q_id < hwdev->aeqs->num_aeqs; q_id++) {
+		eq = &hwdev->aeqs->aeq[q_id];
+		/* Indirect access should set q_id first */
+		spnic_hwif_write_reg(eq->hwdev->hwif, SPNIC_AEQ_INDIR_IDX_ADDR,
+				     eq->q_id);
+		rte_wmb(); /* Write index before config */
+
+		addr = SPNIC_CSR_AEQ_CTRL_0_ADDR;
+
+		ctrl0 = spnic_hwif_read_reg(hwdev->hwif, addr);
+
+		idx = spnic_hwif_read_reg(hwdev->hwif,
+					  SPNIC_AEQ_INDIR_IDX_ADDR);
+
+		addr = SPNIC_CSR_AEQ_CONS_IDX_ADDR;
+		ci = spnic_hwif_read_reg(hwdev->hwif, addr);
+		addr = SPNIC_CSR_AEQ_PROD_IDX_ADDR;
+		pi = spnic_hwif_read_reg(hwdev->hwif, addr);
+		aeqe_pos = GET_CURR_AEQ_ELEM(eq);
+		PMD_DRV_LOG(ERR, "Aeq id: %d, idx: %u, ctrl0: 0x%08x, wrap: %d,"
+			    " pi: 0x%x, ci: 0x%08x,  desc: 0x%x", q_id, idx,
+			    ctrl0, eq->wrapped, pi, ci,
+			    be32_to_cpu(aeqe_pos->desc));
+	}
+}
+
 static int aeq_elem_handler(struct spnic_eq *eq, u32 aeqe_desc,
 			    struct spnic_aeq_elem *aeqe_pos, void *param)
 {
@@ -518,12 +552,22 @@  static int aeq_elem_handler(struct spnic_eq *eq, u32 aeqe_desc,
 	u8 size;
 
 	event = EQ_ELEM_DESC_GET(aeqe_desc, TYPE);
+	if (EQ_ELEM_DESC_GET(aeqe_desc, SRC)) {
+		/* SW event uses only the first 8B */
+		memcpy(data, aeqe_pos->aeqe_data, SPNIC_AEQE_DATA_SIZE);
+		spnic_be32_to_cpu(data, SPNIC_AEQE_DATA_SIZE);
+		/* Just support SPNIC_STATELESS_EVENT */
+		return spnic_nic_sw_aeqe_handler(eq->hwdev, event, data);
+	}
 
 	memcpy(data, aeqe_pos->aeqe_data, SPNIC_AEQE_DATA_SIZE);
 	spnic_be32_to_cpu(data, SPNIC_AEQE_DATA_SIZE);
 	size = EQ_ELEM_DESC_GET(aeqe_desc, SIZE);
 
-	if (event == SPNIC_MBX_FROM_FUNC) {
+	if (event == SPNIC_MSG_FROM_MGMT_CPU) {
+		return spnic_mgmt_msg_aeqe_handler(eq->hwdev, data, size,
+						   param);
+	} else if (event == SPNIC_MBX_FROM_FUNC) {
 		return spnic_mbox_func_aeqe_handler(eq->hwdev, data, size,
 						    param);
 	} else {
diff --git a/drivers/net/spnic/base/spnic_hwdev.c b/drivers/net/spnic/base/spnic_hwdev.c
index ec02a20839..1289ea58c7 100644
--- a/drivers/net/spnic/base/spnic_hwdev.c
+++ b/drivers/net/spnic/base/spnic_hwdev.c
@@ -7,6 +7,7 @@ 
 #include "spnic_hwif.h"
 #include "spnic_eqs.h"
 #include "spnic_mgmt.h"
+#include "spnic_cmd.h"
 #include "spnic_mbox.h"
 #include "spnic_hwdev.h"
 
@@ -18,7 +19,62 @@  struct mgmt_event_handle {
 	mgmt_event_cb proc;
 };
 
+int spnic_vf_handle_pf_comm_mbox(void *handle, __rte_unused void *pri_handle,
+			   __rte_unused u16 cmd, __rte_unused void *buf_in,
+			   __rte_unused u16 in_size, __rte_unused void *buf_out,
+			   __rte_unused u16 *out_size)
+{
+	struct spnic_hwdev *hwdev = handle;
+
+	if (!hwdev)
+		return -EINVAL;
+
+	PMD_DRV_LOG(WARNING, "Unsupported pf mbox event %d to process", cmd);
+
+	return 0;
+}
+
+static void fault_event_handler(__rte_unused void *hwdev,
+				__rte_unused void *buf_in,
+				__rte_unused u16 in_size,
+				__rte_unused void *buf_out,
+				__rte_unused u16 *out_size)
+{
+	PMD_DRV_LOG(WARNING, "Unsupported fault event handler");
+}
+
+static void ffm_event_msg_handler(__rte_unused void *hwdev,
+				  void *buf_in, u16 in_size,
+				  __rte_unused void *buf_out, u16 *out_size)
+{
+	struct ffm_intr_info *intr = NULL;
+
+	if (in_size != sizeof(*intr)) {
+		PMD_DRV_LOG(ERR, "Invalid fault event report, length: %d, should be %d",
+			    in_size, (int)(sizeof(*intr)));
+		return;
+	}
+
+	intr = buf_in;
+
+	PMD_DRV_LOG(ERR, "node_id: 0x%x, err_type: 0x%x, err_level: %d, "
+		    "err_csr_addr: 0x%08x, err_csr_value: 0x%08x",
+		    intr->node_id, intr->err_type, intr->err_level,
+		    intr->err_csr_addr, intr->err_csr_value);
+
+	*out_size = sizeof(*intr);
+}
+
 const struct mgmt_event_handle mgmt_event_proc[] = {
+	{
+		.cmd	= MGMT_CMD_FAULT_REPORT,
+		.proc	= fault_event_handler,
+	},
+
+	{
+		.cmd	= MGMT_CMD_FFM_SET,
+		.proc	= ffm_event_msg_handler,
+	},
 };
 
 void spnic_pf_handle_mgmt_comm_event(void *handle, __rte_unused void *pri_handle,
@@ -44,21 +100,30 @@  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);
 }
 
-int spnic_vf_handle_pf_comm_mbox(void *handle, __rte_unused void *pri_handle,
-			   __rte_unused u16 cmd, __rte_unused void *buf_in,
-			   __rte_unused u16 in_size, __rte_unused void *buf_out,
-			   __rte_unused u16 *out_size)
+static int spnic_comm_pf_to_mgmt_init(struct spnic_hwdev *hwdev)
 {
-	struct spnic_hwdev *hwdev = handle;
+	int err;
 
-	if (!hwdev)
-		return -EINVAL;
+	/* VF does not support send msg to mgmt directly */
+	if (spnic_func_type(hwdev) == TYPE_VF)
+		return 0;
 
-	PMD_DRV_LOG(WARNING, "Unsupported pf mbox event %d to process", cmd);
+	err = spnic_pf_to_mgmt_init(hwdev);
+	if (err)
+		return err;
 
 	return 0;
 }
 
+static void spnic_comm_pf_to_mgmt_free(struct spnic_hwdev *hwdev)
+{
+	/* VF does not support send msg to mgmt directly */
+	if (spnic_func_type(hwdev) == TYPE_VF)
+		return;
+
+	spnic_pf_to_mgmt_free(hwdev);
+}
+
 static int init_mgmt_channel(struct spnic_hwdev *hwdev)
 {
 	int err;
@@ -69,6 +134,12 @@  static int init_mgmt_channel(struct spnic_hwdev *hwdev)
 		return err;
 	}
 
+	err = spnic_comm_pf_to_mgmt_init(hwdev);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Init mgmt channel failed");
+		goto msg_init_err;
+	}
+
 	err = spnic_func_to_func_init(hwdev);
 	if (err) {
 		PMD_DRV_LOG(ERR, "Init mailbox channel failed");
@@ -78,6 +149,9 @@  static int init_mgmt_channel(struct spnic_hwdev *hwdev)
 	return 0;
 
 func_to_func_init_err:
+	spnic_comm_pf_to_mgmt_free(hwdev);
+
+msg_init_err:
 	spnic_aeqs_free(hwdev);
 
 	return err;
@@ -86,6 +160,7 @@  static int init_mgmt_channel(struct spnic_hwdev *hwdev)
 static void free_mgmt_channel(struct spnic_hwdev *hwdev)
 {
 	spnic_func_to_func_free(hwdev);
+	spnic_comm_pf_to_mgmt_free(hwdev);
 	spnic_aeqs_free(hwdev);
 }
 
diff --git a/drivers/net/spnic/base/spnic_hwdev.h b/drivers/net/spnic/base/spnic_hwdev.h
index 5de3575a96..1db004c6f2 100644
--- a/drivers/net/spnic/base/spnic_hwdev.h
+++ b/drivers/net/spnic/base/spnic_hwdev.h
@@ -7,7 +7,6 @@ 
 
 #include <rte_ether.h>
 
-#define SPNIC_CHIP_FAULT_SIZE		(110 * 1024)
 struct cfg_mgmt_info;
 struct spnic_hwif;
 struct spnic_aeqs;
@@ -24,6 +23,70 @@  struct ffm_intr_info {
 	u32 err_csr_value;
 };
 
+struct link_event_stats {
+	u32 link_down_stats;
+	u32 link_up_stats;
+};
+
+enum spnic_fault_err_level {
+	FAULT_LEVEL_FATAL,
+	FAULT_LEVEL_SERIOUS_RESET,
+	FAULT_LEVEL_SERIOUS_FLR,
+	FAULT_LEVEL_GENERAL,
+	FAULT_LEVEL_SUGGESTION,
+	FAULT_LEVEL_MAX
+};
+
+enum spnic_fault_type {
+	FAULT_TYPE_CHIP,
+	FAULT_TYPE_UCODE,
+	FAULT_TYPE_MEM_RD_TIMEOUT,
+	FAULT_TYPE_MEM_WR_TIMEOUT,
+	FAULT_TYPE_REG_RD_TIMEOUT,
+	FAULT_TYPE_REG_WR_TIMEOUT,
+	FAULT_TYPE_PHY_FAULT,
+	FAULT_TYPE_MAX
+};
+
+struct fault_event_stats {
+	rte_atomic32_t chip_fault_stats[22][FAULT_LEVEL_MAX];
+	rte_atomic32_t fault_type_stat[FAULT_TYPE_MAX];
+	rte_atomic32_t pcie_fault_stats;
+};
+
+struct spnic_hw_stats {
+	rte_atomic32_t heart_lost_stats;
+	struct link_event_stats link_event_stats;
+	struct fault_event_stats fault_event_stats;
+};
+
+#define SPNIC_CHIP_FAULT_SIZE		(110 * 1024)
+#define MAX_DRV_BUF_SIZE		4096
+
+struct nic_cmd_chip_fault_stats {
+	u32 offset;
+	u8 chip_fault_stats[MAX_DRV_BUF_SIZE];
+};
+
+struct spnic_board_info {
+	u8 board_type;
+	u8 port_num;
+	u8 port_speed;
+	u8 pcie_width;
+	u8 host_num;
+	u8 pf_num;
+	u16 vf_total_num;
+	u8 tile_num;
+	u8 qcm_num;
+	u8 core_num;
+	u8 work_mode;
+	u8 service_mode;
+	u8 pcie_mode;
+	u8 boot_sel;
+	u8 board_id;
+	u32 cfg_addr;
+};
+
 struct spnic_hwdev {
 	void *dev_handle; /* Pointer to spnic_nic_dev */
 	void *pci_dev; /* Pointer to rte_pci_device */
@@ -37,6 +100,7 @@  struct spnic_hwdev {
 	struct spnic_aeqs *aeqs;
 	struct spnic_msg_pf_to_mgmt *pf_to_mgmt;
 	u8 *chip_fault_stats;
+	struct spnic_hw_stats hw_stats;
 
 	u16 max_vfs;
 	u16 link_status;
diff --git a/drivers/net/spnic/base/spnic_mbox.c b/drivers/net/spnic/base/spnic_mbox.c
index 6063ca0653..4b4c4311eb 100644
--- a/drivers/net/spnic/base/spnic_mbox.c
+++ b/drivers/net/spnic/base/spnic_mbox.c
@@ -6,10 +6,12 @@ 
 #include "spnic_compat.h"
 #include "spnic_hwdev.h"
 #include "spnic_csr.h"
+#include "spnic_cmd.h"
 #include "spnic_mgmt.h"
 #include "spnic_hwif.h"
 #include "spnic_eqs.h"
 #include "spnic_mbox.h"
+#include "spnic_nic_event.h"
 
 #define SPNIC_MBOX_INT_DST_FUNC_SHIFT				0
 #define SPNIC_MBOX_INT_DST_AEQN_SHIFT				10
@@ -148,6 +150,20 @@  static int recv_vf_mbox_handler(struct spnic_mbox *func_to_func,
 					     recv_mbox->mbox_len,
 					     buf_out, out_size);
 		break;
+	case SPNIC_MOD_L2NIC:
+		err = spnic_vf_event_handler(func_to_func->hwdev,
+					     func_to_func->hwdev->cfg_mgmt,
+					     recv_mbox->cmd, recv_mbox->mbox,
+					     recv_mbox->mbox_len,
+					     buf_out, out_size);
+		break;
+	case SPNIC_MOD_HILINK:
+		err = spnic_vf_mag_event_handler(func_to_func->hwdev,
+						 recv_mbox->cmd,
+						 recv_mbox->mbox,
+						 recv_mbox->mbox_len,
+						 buf_out, out_size);
+		break;
 	default:
 		PMD_DRV_LOG(ERR, "No handler, mod: %d", recv_mbox->mod);
 		err = SPNIC_MBOX_VF_CMD_ERROR;
diff --git a/drivers/net/spnic/base/spnic_mgmt.c b/drivers/net/spnic/base/spnic_mgmt.c
new file mode 100644
index 0000000000..98f58867e7
--- /dev/null
+++ b/drivers/net/spnic/base/spnic_mgmt.c
@@ -0,0 +1,367 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd
+ */
+
+#include <rte_ethdev.h>
+
+#include "spnic_compat.h"
+#include "spnic_hwdev.h"
+#include "spnic_eqs.h"
+#include "spnic_mgmt.h"
+#include "spnic_mbox.h"
+#include "spnic_nic_event.h"
+
+#define SPNIC_MSG_TO_MGMT_MAX_LEN		2016
+
+#define MAX_PF_MGMT_BUF_SIZE			2048UL
+#define SEGMENT_LEN				48
+#define ASYNC_MSG_FLAG				0x20
+#define MGMT_MSG_MAX_SEQ_ID	(RTE_ALIGN(SPNIC_MSG_TO_MGMT_MAX_LEN, \
+					   SEGMENT_LEN) / SEGMENT_LEN)
+
+#define BUF_OUT_DEFAULT_SIZE			1
+
+#define MGMT_MSG_SIZE_MIN			20
+#define MGMT_MSG_SIZE_STEP			16
+#define	MGMT_MSG_RSVD_FOR_DEV			8
+
+#define SYNC_MSG_ID_MASK			0x1F
+#define ASYNC_MSG_ID_MASK			0x1F
+
+#define SYNC_FLAG				0
+#define ASYNC_FLAG				1
+
+#define MSG_NO_RESP				0xFFFF
+
+#define MGMT_MSG_TIMEOUT			300000 /* Millisecond */
+
+int spnic_msg_to_mgmt_sync(void *hwdev, enum spnic_mod_type mod, u16 cmd,
+			   void *buf_in, u16 in_size, void *buf_out,
+			   u16 *out_size, u32 timeout)
+{
+	int err;
+
+	if (!hwdev)
+		return -EINVAL;
+
+	err = spnic_send_mbox_to_mgmt(hwdev, mod, cmd, buf_in, in_size,
+				      buf_out, out_size, timeout);
+	return err;
+}
+
+static void send_mgmt_ack(struct spnic_msg_pf_to_mgmt *pf_to_mgmt,
+			  enum spnic_mod_type mod, u16 cmd, void *buf_in,
+			  u16 in_size, u16 msg_id)
+{
+	u16 buf_size;
+
+	if (!in_size)
+		buf_size = BUF_OUT_DEFAULT_SIZE;
+	else
+		buf_size = in_size;
+
+	spnic_response_mbox_to_mgmt(pf_to_mgmt->hwdev, mod, cmd, buf_in,
+				    buf_size, msg_id);
+}
+
+static bool check_mgmt_seq_id_and_seg_len(struct spnic_recv_msg *recv_msg,
+					  u8 seq_id, u8 seg_len, u16 msg_id)
+{
+	if (seq_id > MGMT_MSG_MAX_SEQ_ID || seg_len > SEGMENT_LEN)
+		return false;
+
+	if (seq_id == 0) {
+		recv_msg->seq_id = seq_id;
+		recv_msg->msg_id = msg_id;
+	} else {
+		if ((seq_id != recv_msg->seq_id + 1) ||
+		    msg_id != recv_msg->msg_id) {
+			recv_msg->seq_id = 0;
+			return false;
+		}
+
+		recv_msg->seq_id = seq_id;
+	}
+
+	return true;
+}
+
+static void spnic_mgmt_recv_msg_handler(struct spnic_msg_pf_to_mgmt *pf_to_mgmt,
+					struct spnic_recv_msg *recv_msg,
+					__rte_unused void *param)
+{
+	void *buf_out = pf_to_mgmt->mgmt_ack_buf;
+	bool ack_first = false;
+	u16 out_size = 0;
+
+	memset(buf_out, 0, MAX_PF_MGMT_BUF_SIZE);
+
+	switch (recv_msg->mod) {
+	case SPNIC_MOD_COMM:
+		spnic_pf_handle_mgmt_comm_event(pf_to_mgmt->hwdev, pf_to_mgmt,
+					  recv_msg->cmd, recv_msg->msg,
+					  recv_msg->msg_len,
+					  buf_out, &out_size);
+		break;
+	case SPNIC_MOD_L2NIC:
+		spnic_pf_event_handler(pf_to_mgmt->hwdev, pf_to_mgmt,
+				       recv_msg->cmd, recv_msg->msg,
+				       recv_msg->msg_len, buf_out, &out_size);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Not support mod, maybe need to response, mod: %d",
+			    recv_msg->mod);
+		break;
+	}
+
+	if (!ack_first && !recv_msg->async_mgmt_to_pf)
+		/* Mgmt sends async msg, sends the response */
+		send_mgmt_ack(pf_to_mgmt, recv_msg->mod, recv_msg->cmd, buf_out,
+			      out_size, recv_msg->msg_id);
+}
+
+/**
+ * Handler a message from mgmt cpu
+ *
+ * @param[in] pf_to_mgmt
+ *   PF to mgmt channel
+ * @param[in] recv_msg
+ *   Received message details
+ * @param[in] param
+ *   Customized parameter (unused_)
+ *
+ * @retval 0 : When aeqe is response message
+ * @retval -1 : Default result, when wrong message or not last message.
+ */
+static int recv_mgmt_msg_handler(struct spnic_msg_pf_to_mgmt *pf_to_mgmt,
+				 u8 *header, struct spnic_recv_msg *recv_msg,
+				 void *param)
+{
+	u64 mbox_header = *((u64 *)header);
+	void *msg_body = header + sizeof(mbox_header);
+	u8 seq_id, seq_len;
+	u32 offset;
+	u8 front_id;
+	u16 msg_id;
+
+	/* Don't need to get anything from hw when cmd is async */
+	if (SPNIC_MSG_HEADER_GET(mbox_header, DIRECTION) == SPNIC_MSG_RESPONSE)
+		return 0;
+
+	seq_len = SPNIC_MSG_HEADER_GET(mbox_header, SEG_LEN);
+	seq_id  = SPNIC_MSG_HEADER_GET(mbox_header, SEQID);
+	msg_id = SPNIC_MSG_HEADER_GET(mbox_header, MSG_ID);
+	front_id = recv_msg->seq_id;
+
+	if (!check_mgmt_seq_id_and_seg_len(recv_msg, seq_id, seq_len, msg_id)) {
+		PMD_DRV_LOG(ERR, "Mgmt msg sequence id and segment length check failed, "
+			    "front seq_id: 0x%x, current seq_id: 0x%x, seg len: 0x%x "
+			    "front msg_id: %d, cur msg_id: %d",
+			    front_id, seq_id, seq_len,
+			    recv_msg->msg_id, msg_id);
+		/* Set seq_id to invalid seq_id */
+		recv_msg->seq_id = MGMT_MSG_MAX_SEQ_ID;
+		return SPNIC_MSG_HANDLER_RES;
+	}
+
+	offset  = seq_id * SEGMENT_LEN;
+	memcpy((u8 *)recv_msg->msg + offset, msg_body, seq_len);
+
+	if (!SPNIC_MSG_HEADER_GET(mbox_header, LAST))
+		return SPNIC_MSG_HANDLER_RES;
+
+	recv_msg->cmd = SPNIC_MSG_HEADER_GET(mbox_header, CMD);
+	recv_msg->mod = SPNIC_MSG_HEADER_GET(mbox_header, MODULE);
+	recv_msg->async_mgmt_to_pf = SPNIC_MSG_HEADER_GET(mbox_header, NO_ACK);
+	recv_msg->msg_len = SPNIC_MSG_HEADER_GET(mbox_header, MSG_LEN);
+	recv_msg->msg_id = SPNIC_MSG_HEADER_GET(mbox_header, MSG_ID);
+	recv_msg->seq_id = MGMT_MSG_MAX_SEQ_ID;
+
+	spnic_mgmt_recv_msg_handler(pf_to_mgmt, recv_msg, param);
+
+	return SPNIC_MSG_HANDLER_RES;
+}
+
+/**
+ * Handler for a mgmt message event
+ *
+ * @param[in] hwdev
+ *   The pointer to the private hardware device object
+ * @param[in] header
+ *   The header of the message
+ * @param[in] size
+ *   Size (unused_)
+ * @param[in] param
+ *   Customized parameter
+ *
+ * @retval zero : When aeqe is response message
+ * @retval negative : When wrong message or not last message.
+ */
+int spnic_mgmt_msg_aeqe_handler(void *hwdev, u8 *header, u8 size, void *param)
+{
+	struct spnic_hwdev *dev = (struct spnic_hwdev *)hwdev;
+	struct spnic_msg_pf_to_mgmt *pf_to_mgmt = NULL;
+	struct spnic_recv_msg *recv_msg = NULL;
+	bool is_send_dir = false;
+
+	if ((SPNIC_MSG_HEADER_GET(*(u64 *)header, SOURCE) ==
+	     SPNIC_MSG_FROM_MBOX)) {
+		return spnic_mbox_func_aeqe_handler(hwdev, header, size, param);
+	}
+
+	pf_to_mgmt = dev->pf_to_mgmt;
+
+	is_send_dir = (SPNIC_MSG_HEADER_GET(*(u64 *)header, DIRECTION) ==
+		       SPNIC_MSG_DIRECT_SEND) ? true : false;
+
+	recv_msg = is_send_dir ? &pf_to_mgmt->recv_msg_from_mgmt :
+		   &pf_to_mgmt->recv_resp_msg_from_mgmt;
+
+	return recv_mgmt_msg_handler(pf_to_mgmt, header, recv_msg, param);
+}
+
+/**
+ * Allocate received message memory
+ *
+ * @param[in] recv_msg
+ *   Pointer that will hold the allocated data
+ *
+ * @retval zero : Success
+ * @retval negative : Failure.
+ */
+static int alloc_recv_msg(struct spnic_recv_msg *recv_msg)
+{
+	recv_msg->seq_id = MGMT_MSG_MAX_SEQ_ID;
+
+	recv_msg->msg = rte_zmalloc("recv_msg", MAX_PF_MGMT_BUF_SIZE,
+				    SPNIC_MEM_ALLOC_ALIGN_MIN);
+	if (!recv_msg->msg)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * Free received message memory
+ *
+ * @param[in] recv_msg
+ *   Pointer that will hold the allocated data
+ */
+static void free_recv_msg(struct spnic_recv_msg *recv_msg)
+{
+	rte_free(recv_msg->msg);
+}
+
+/**
+ * Allocate all the message buffers of PF to mgmt channel
+ *
+ * @param[in] pf_to_mgmt
+ *   PF to mgmt channel
+ *
+ * @retval zero : Success
+ * @retval negative : Failure.
+ */
+static int alloc_msg_buf(struct spnic_msg_pf_to_mgmt *pf_to_mgmt)
+{
+	int err;
+
+	err = alloc_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Allocate recv msg failed");
+		return err;
+	}
+
+	err = alloc_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Allocate resp recv msg failed");
+		goto alloc_msg_for_resp_err;
+	}
+
+	pf_to_mgmt->mgmt_ack_buf = rte_zmalloc("mgmt_ack_buf",
+					       MAX_PF_MGMT_BUF_SIZE,
+					       SPNIC_MEM_ALLOC_ALIGN_MIN);
+	if (!pf_to_mgmt->mgmt_ack_buf) {
+		err = -ENOMEM;
+		goto ack_msg_buf_err;
+	}
+
+	return 0;
+
+ack_msg_buf_err:
+	free_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt);
+
+alloc_msg_for_resp_err:
+	free_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt);
+	return err;
+}
+
+/**
+ * Free all the message buffers of PF to mgmt channel
+ *
+ * @param[in] pf_to_mgmt
+ *   PF to mgmt channel
+ */
+static void free_msg_buf(struct spnic_msg_pf_to_mgmt *pf_to_mgmt)
+{
+	rte_free(pf_to_mgmt->mgmt_ack_buf);
+	free_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt);
+	free_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt);
+}
+
+/**
+ * Initialize PF to mgmt channel
+ *
+ * @param[in] hwdev
+ *   The pointer to the private hardware device object
+ *
+ * @retval zero : Success
+ * @retval negative : Failure.
+ */
+int spnic_pf_to_mgmt_init(struct spnic_hwdev *hwdev)
+{
+	struct spnic_msg_pf_to_mgmt *pf_to_mgmt;
+	int err;
+
+	pf_to_mgmt = rte_zmalloc("pf_to_mgmt", sizeof(*pf_to_mgmt),
+				 SPNIC_MEM_ALLOC_ALIGN_MIN);
+	if (!pf_to_mgmt)
+		return -ENOMEM;
+
+	hwdev->pf_to_mgmt = pf_to_mgmt;
+	pf_to_mgmt->hwdev = hwdev;
+
+	err = spnic_mutex_init(&pf_to_mgmt->sync_msg_mutex, NULL);
+	if (err)
+		goto mutex_init_err;
+
+	err = alloc_msg_buf(pf_to_mgmt);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Allocate msg buffers failed");
+		goto alloc_msg_buf_err;
+	}
+
+	return 0;
+
+alloc_msg_buf_err:
+	spnic_mutex_destroy(&pf_to_mgmt->sync_msg_mutex);
+
+mutex_init_err:
+	rte_free(pf_to_mgmt);
+
+	return err;
+}
+
+/**
+ * Free PF to mgmt channel
+ *
+ * @param[in] hwdev
+ *   The pointer to the private hardware device object
+ */
+void spnic_pf_to_mgmt_free(struct spnic_hwdev *hwdev)
+{
+	struct spnic_msg_pf_to_mgmt *pf_to_mgmt = hwdev->pf_to_mgmt;
+
+	free_msg_buf(pf_to_mgmt);
+	spnic_mutex_destroy(&pf_to_mgmt->sync_msg_mutex);
+	rte_free(pf_to_mgmt);
+}
diff --git a/drivers/net/spnic/base/spnic_mgmt.h b/drivers/net/spnic/base/spnic_mgmt.h
index c161adb0b7..7325fc4d03 100644
--- a/drivers/net/spnic/base/spnic_mgmt.h
+++ b/drivers/net/spnic/base/spnic_mgmt.h
@@ -7,6 +7,13 @@ 
 
 #define SPNIC_MSG_HANDLER_RES	(-1)
 
+/* Structures for l2nic and mag msg to mgmt sync interface */
+struct mgmt_msg_head {
+	u8 status;
+	u8 version;
+	u8 rsvd0[6];
+};
+
 /* Cmdq module type */
 enum spnic_mod_type {
 	SPNIC_MOD_COMM = 0, /* HW communication module */
@@ -33,4 +40,71 @@  enum spnic_mod_type {
 	SPNIC_MOD_MAX
 };
 
+typedef enum {
+	RES_TYPE_FLUSH_BIT = 0,
+	RES_TYPE_MQM,
+	RES_TYPE_SMF,
+
+	RES_TYPE_COMM = 10,
+	/* clear mbox and aeq, The RES_TYPE_COMM bit must be set */
+	RES_TYPE_COMM_MGMT_CH,
+	/* clear cmdq, The RES_TYPE_COMM bit must be set */
+	RES_TYPE_COMM_CMD_CH,
+	RES_TYPE_NIC,
+	RES_TYPE_OVS,
+	RES_TYPE_MAX = 20,
+} func_reset_flag_e;
+
+#define SPNIC_COMM_RES		((1 << RES_TYPE_COMM) | \
+				(1 << RES_TYPE_FLUSH_BIT) | \
+				(1 << RES_TYPE_MQM) | \
+				(1 << RES_TYPE_SMF) | \
+				(1 << RES_TYPE_COMM_CMD_CH))
+#define SPNIC_NIC_RES		(1 << RES_TYPE_NIC)
+#define SPNIC_OVS_RES		(1 << RES_TYPE_OVS)
+
+struct spnic_recv_msg {
+	void *msg;
+
+	u16 msg_len;
+	enum spnic_mod_type mod;
+	u16 cmd;
+	u8 seq_id;
+	u16 msg_id;
+	int async_mgmt_to_pf;
+};
+
+enum comm_pf_to_mgmt_event_state {
+	SEND_EVENT_UNINIT = 0,
+	SEND_EVENT_START,
+	SEND_EVENT_SUCCESS,
+	SEND_EVENT_FAIL,
+	SEND_EVENT_TIMEOUT,
+	SEND_EVENT_END
+};
+
+struct spnic_msg_pf_to_mgmt {
+	struct spnic_hwdev *hwdev;
+
+	/* Mutex for sync message */
+	pthread_mutex_t sync_msg_mutex;
+
+	void *mgmt_ack_buf;
+
+	struct spnic_recv_msg recv_msg_from_mgmt;
+	struct spnic_recv_msg recv_resp_msg_from_mgmt;
+
+	u16 sync_msg_id;
+};
+
+int spnic_mgmt_msg_aeqe_handler(void *hwdev, u8 *header, u8 size, void *param);
+
+int spnic_pf_to_mgmt_init(struct spnic_hwdev *hwdev);
+
+void spnic_pf_to_mgmt_free(struct spnic_hwdev *hwdev);
+
+int spnic_msg_to_mgmt_sync(void *hwdev, enum spnic_mod_type mod, u16 cmd,
+			   void *buf_in, u16 in_size, void *buf_out,
+			   u16 *out_size, u32 timeout);
+
 #endif /* _SPNIC_MGMT_H_ */
diff --git a/drivers/net/spnic/base/spnic_nic_event.c b/drivers/net/spnic/base/spnic_nic_event.c
new file mode 100644
index 0000000000..b8dbe65646
--- /dev/null
+++ b/drivers/net/spnic/base/spnic_nic_event.c
@@ -0,0 +1,162 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd
+ */
+
+#include <ethdev_driver.h>
+
+#include "spnic_compat.h"
+#include "spnic_cmd.h"
+#include "spnic_hwif.h"
+#include "spnic_hwdev.h"
+#include "spnic_mgmt.h"
+#include "spnic_hwdev.h"
+#include "spnic_nic_event.h"
+
+static void spnic_get_port_link_info(u8 link_state, struct rte_eth_link *link)
+{
+	if (!link_state) {
+		link->link_status = ETH_LINK_DOWN;
+		link->link_speed = ETH_SPEED_NUM_NONE;
+		link->link_duplex = ETH_LINK_HALF_DUPLEX;
+		link->link_autoneg = ETH_LINK_FIXED;
+	}
+}
+
+static void spnic_link_event_stats(void *dev, u8 link)
+{
+	struct spnic_hwdev *hwdev = dev;
+	struct link_event_stats *stats = &hwdev->hw_stats.link_event_stats;
+
+	if (link)
+		__atomic_fetch_add(&stats->link_up_stats, 1, __ATOMIC_RELAXED);
+	else
+		__atomic_fetch_add(&stats->link_down_stats, 1, __ATOMIC_RELAXED);
+}
+
+static void link_status_event_handler(void *hwdev, void *buf_in,
+				      __rte_unused u16 in_size,
+				      __rte_unused void *buf_out,
+				      __rte_unused u16 *out_size)
+{
+	struct spnic_cmd_link_state *link_status = NULL;
+	struct rte_eth_link link;
+	struct spnic_hwdev *dev = hwdev;
+	int err;
+
+	link_status = buf_in;
+	PMD_DRV_LOG(INFO, "Link status report received, func_id: %d, status: %d(%s)",
+		    spnic_global_func_id(hwdev), link_status->state,
+		    link_status->state ? "UP" : "DOWN");
+
+	spnic_link_event_stats(hwdev, link_status->state);
+
+	/* Link event reported only after set vport enable */
+	spnic_get_port_link_info(link_status->state, &link);
+	err = rte_eth_linkstatus_set((struct rte_eth_dev *)(dev->eth_dev),
+				     &link);
+	if (!err)
+		rte_eth_dev_callback_process(dev->eth_dev,
+					      RTE_ETH_EVENT_INTR_LSC, NULL);
+}
+
+struct nic_event_handler {
+	u16 cmd;
+	void (*handler)(void *hwdev, void *buf_in, u16 in_size,
+			void *buf_out, u16 *out_size);
+};
+
+struct nic_event_handler nic_cmd_handler[] = {
+};
+
+static void nic_event_handler(void *hwdev, u16 cmd, void *buf_in, u16 in_size,
+			      void *buf_out, u16 *out_size)
+{
+	u32 i, size = ARRAY_LEN(nic_cmd_handler);
+
+	if (!hwdev)
+		return;
+
+	*out_size = 0;
+
+	for (i = 0; i < size; i++) {
+		if (cmd == nic_cmd_handler[i].cmd) {
+			nic_cmd_handler[i].handler(hwdev, buf_in, in_size,
+						   buf_out, out_size);
+			break;
+		}
+	}
+
+	if (i == size)
+		PMD_DRV_LOG(WARNING,
+			    "Unsupported nic event cmd(%d) to process", cmd);
+}
+
+/*
+ * VF handler mbox msg from ppf/pf
+ * VF link change event
+ * VF fault report event
+ */
+int spnic_vf_event_handler(void *hwdev, __rte_unused void *pri_handle,
+			   u16 cmd, void *buf_in, u16 in_size,
+			   void *buf_out, u16 *out_size)
+{
+	nic_event_handler(hwdev, cmd, buf_in, in_size, buf_out, out_size);
+	return 0;
+}
+
+/*  NIC event of PF/PPF handler reported by mgmt cpu */
+void spnic_pf_event_handler(void *hwdev, __rte_unused void *pri_handle,
+			    u16 cmd, void *buf_in, u16 in_size,
+			    void *buf_out, u16 *out_size)
+{
+	nic_event_handler(hwdev, cmd, buf_in, in_size, buf_out, out_size);
+}
+
+static struct nic_event_handler mag_cmd_handler[] = {
+	{
+		.cmd = MAG_CMD_GET_LINK_STATUS,
+		.handler = link_status_event_handler,
+	},
+};
+
+static int spnic_mag_event_handler(void *hwdev, u16 cmd, void *buf_in,
+				   u16 in_size, void *buf_out,
+				   u16 *out_size)
+{
+	u32 size = ARRAY_LEN(mag_cmd_handler);
+	u32 i;
+
+	if (!hwdev)
+		return -EINVAL;
+
+	*out_size = 0;
+	for (i = 0; i < size; i++) {
+		if (cmd == mag_cmd_handler[i].cmd) {
+			mag_cmd_handler[i].handler(hwdev, buf_in, in_size,
+						   buf_out, out_size);
+			break;
+		}
+	}
+
+	/* can't find this event cmd */
+	if (i == size)
+		PMD_DRV_LOG(ERR, "Unsupported mag event, cmd: %u\n", cmd);
+
+	return 0;
+}
+
+int spnic_vf_mag_event_handler(void *hwdev, u16 cmd, void *buf_in, u16 in_size, void *buf_out,
+			       u16 *out_size)
+{
+	return spnic_mag_event_handler(hwdev, cmd, buf_in, in_size, buf_out,
+				       out_size);
+}
+
+u8 spnic_nic_sw_aeqe_handler(__rte_unused void *hwdev, u8 event, u8 *data)
+{
+	PMD_DRV_LOG(ERR,
+		    "Received nic ucode aeq event type: 0x%x, data: %" PRIu64 "",
+		    event, *((u64 *)data));
+
+	return 0;
+}
diff --git a/drivers/net/spnic/base/spnic_nic_event.h b/drivers/net/spnic/base/spnic_nic_event.h
new file mode 100644
index 0000000000..bf1c15941e
--- /dev/null
+++ b/drivers/net/spnic/base/spnic_nic_event.h
@@ -0,0 +1,29 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd
+ */
+
+#ifndef _SPNIC_NIC_EVENT_H_
+#define _SPNIC_NIC_EVENT_H_
+
+struct spnic_cmd_link_state {
+	struct mgmt_msg_head msg_head;
+
+	u8 port_id;
+	u8 state;
+	u16 rsvd1;
+};
+
+void spnic_pf_event_handler(void *hwdev, __rte_unused void *pri_handle,
+			    u16 cmd, void *buf_in, u16 in_size,
+			    void *buf_out, u16 *out_size);
+
+int spnic_vf_event_handler(void *hwdev, __rte_unused void *pri_handle,
+			   u16 cmd, void *buf_in, u16 in_size,
+			   void *buf_out, u16 *out_size);
+
+int spnic_vf_mag_event_handler(void *hwdev, u16 cmd, void *buf_in, u16 in_size, void *buf_out,
+			       u16 *out_size);
+
+u8 spnic_nic_sw_aeqe_handler(__rte_unused void *hwdev, u8 event, u8 *data);
+
+#endif /* _SPNIC_NIC_EVENT_H_ */