[v5,08/26] net/spnic: add hardware info initialization

Message ID 8c302de368b0f3f95bf779554e07422851a47639.1640783513.git.songyl@ramaxel.com (mailing list archive)
State Superseded, archived
Headers
Series Net/SPNIC: support SPNIC into DPDK 22.03 |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Yanling Song Dec. 29, 2021, 1:37 p.m. UTC
  This commits add hardware info initialization, including
that device capability initialization, common feature
negotiation, and two interfaces spnic_get_board_info(),
spnic_get_mgmt_version() to get hardware info and
firmware version.

Signed-off-by: Yanling Song <songyl@ramaxel.com>
---
 drivers/net/spnic/base/meson.build     |   3 +-
 drivers/net/spnic/base/spnic_hw_cfg.c  | 157 +++++++++++++++++++++++++
 drivers/net/spnic/base/spnic_hw_cfg.h  | 117 ++++++++++++++++++
 drivers/net/spnic/base/spnic_hw_comm.c | 121 +++++++++++++++++++
 drivers/net/spnic/base/spnic_hw_comm.h |  22 ++++
 drivers/net/spnic/base/spnic_hwdev.c   |  70 +++++++++++
 drivers/net/spnic/base/spnic_hwdev.h   |   5 +
 drivers/net/spnic/base/spnic_mbox.c    |   8 ++
 8 files changed, 502 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/spnic/base/spnic_hw_cfg.c
 create mode 100644 drivers/net/spnic/base/spnic_hw_cfg.h
  

Patch

diff --git a/drivers/net/spnic/base/meson.build b/drivers/net/spnic/base/meson.build
index da6d6ee4a2..77a56ca41e 100644
--- a/drivers/net/spnic/base/meson.build
+++ b/drivers/net/spnic/base/meson.build
@@ -10,7 +10,8 @@  sources = [
 	'spnic_nic_event.c',
 	'spnic_cmdq.c',
 	'spnic_hw_comm.c',
-	'spnic_wq.c'
+	'spnic_wq.c',
+	'spnic_hw_cfg.c'
 ]
 
 extra_flags = []
diff --git a/drivers/net/spnic/base/spnic_hw_cfg.c b/drivers/net/spnic/base/spnic_hw_cfg.c
new file mode 100644
index 0000000000..ac76b2632e
--- /dev/null
+++ b/drivers/net/spnic/base/spnic_hw_cfg.c
@@ -0,0 +1,157 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd
+ */
+
+#include "spnic_compat.h"
+#include "spnic_mgmt.h"
+#include "spnic_mbox.h"
+#include "spnic_hwdev.h"
+#include "spnic_hwif.h"
+#include "spnic_hw_cfg.h"
+
+static void parse_pub_res_cap(struct service_cap *cap,
+			      struct spnic_cfg_cmd_dev_cap *dev_cap,
+			      enum func_type type)
+{
+	cap->host_id = dev_cap->host_id;
+	cap->ep_id = dev_cap->ep_id;
+	cap->er_id = dev_cap->er_id;
+	cap->port_id = dev_cap->port_id;
+
+	cap->svc_type = dev_cap->svc_cap_en;
+	cap->chip_svc_type = cap->svc_type;
+
+	cap->cos_valid_bitmap = dev_cap->valid_cos_bitmap;
+	cap->flexq_en = dev_cap->flexq_en;
+
+	cap->host_total_function = dev_cap->host_total_func;
+	cap->max_vf = 0;
+	if (type == TYPE_PF || type == TYPE_PPF) {
+		cap->max_vf = dev_cap->max_vf;
+		cap->pf_num = dev_cap->host_pf_num;
+		cap->pf_id_start = dev_cap->pf_id_start;
+		cap->vf_num = dev_cap->host_vf_num;
+		cap->vf_id_start = dev_cap->vf_id_start;
+	}
+
+	PMD_DRV_LOG(INFO, "Get public resource capability: ");
+	PMD_DRV_LOG(INFO, "host_id: 0x%x, ep_id: 0x%x, er_id: 0x%x, "
+		    "port_id: 0x%x",
+		    cap->host_id, cap->ep_id, cap->er_id, cap->port_id);
+	PMD_DRV_LOG(INFO, "host_total_function: 0x%x, max_vf: 0x%x",
+		    cap->host_total_function, cap->max_vf);
+	PMD_DRV_LOG(INFO, "host_pf_num: 0x%x, pf_id_start: 0x%x, host_vf_num: 0x%x, vf_id_start: 0x%x",
+		    cap->pf_num, cap->pf_id_start,
+		    cap->vf_num, cap->vf_id_start);
+}
+
+static void parse_l2nic_res_cap(struct service_cap *cap,
+				struct spnic_cfg_cmd_dev_cap *dev_cap)
+{
+	struct nic_service_cap *nic_cap = &cap->nic_cap;
+
+	nic_cap->max_sqs = dev_cap->nic_max_sq_id + 1;
+	nic_cap->max_rqs = dev_cap->nic_max_rq_id + 1;
+
+	PMD_DRV_LOG(INFO, "L2nic resource capbility, max_sqs: 0x%x, "
+		    "max_rqs: 0x%x",
+		    nic_cap->max_sqs, nic_cap->max_rqs);
+}
+
+static void parse_dev_cap(struct spnic_hwdev *dev,
+			  struct spnic_cfg_cmd_dev_cap *dev_cap,
+			  enum func_type type)
+{
+	struct service_cap *cap = &dev->cfg_mgmt->svc_cap;
+
+	parse_pub_res_cap(cap, dev_cap, type);
+
+	if (IS_NIC_TYPE(dev))
+		parse_l2nic_res_cap(cap, dev_cap);
+}
+
+static int get_cap_from_fw(struct spnic_hwdev *hwdev, enum func_type type)
+{
+	struct spnic_cfg_cmd_dev_cap dev_cap;
+	u16 out_len = sizeof(dev_cap);
+	int err;
+
+	memset(&dev_cap, 0, sizeof(dev_cap));
+	dev_cap.func_id = spnic_global_func_id(hwdev);
+	err = spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_CFGM,
+				     SPNIC_CFG_CMD_GET_DEV_CAP,
+				     &dev_cap, sizeof(dev_cap),
+				     &dev_cap, &out_len, 0);
+	if (err || dev_cap.status || !out_len) {
+		PMD_DRV_LOG(ERR, "Get capability from FW failed, err: %d, "
+			    "status: 0x%x, out size: 0x%x",
+			    err, dev_cap.status, out_len);
+		return -EFAULT;
+	}
+
+	parse_dev_cap(hwdev, &dev_cap, type);
+	return 0;
+}
+
+static int get_dev_cap(struct spnic_hwdev *hwdev)
+{
+	enum func_type type = SPNIC_FUNC_TYPE(hwdev);
+
+	switch (type) {
+	case TYPE_PF:
+	case TYPE_PPF:
+	case TYPE_VF:
+		if (get_cap_from_fw(hwdev, type) != 0)
+			return -EFAULT;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Unsupported PCIe function type: %d", type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int spnic_cfg_mbx_vf_proc_msg(void *hwdev, __rte_unused void *pri_handle, 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 *dev = hwdev;
+
+	if (!dev)
+		return -EINVAL;
+
+	PMD_DRV_LOG(WARNING,
+		    "Unsupported cfg mbox vf event %d to process", cmd);
+
+	return 0;
+}
+
+int spnic_init_capability(void *dev)
+{
+	struct spnic_hwdev *hwdev = (struct spnic_hwdev *)dev;
+	struct cfg_mgmt_info *cfg_mgmt = NULL;
+	int err;
+
+	cfg_mgmt = rte_zmalloc("cfg_mgmt", sizeof(*cfg_mgmt),
+			       SPNIC_MEM_ALLOC_ALIGN_MIN);
+	if (!cfg_mgmt)
+		return -ENOMEM;
+
+	memset(cfg_mgmt, 0, sizeof(struct cfg_mgmt_info));
+	hwdev->cfg_mgmt = cfg_mgmt;
+	cfg_mgmt->hwdev = hwdev;
+
+	err = get_dev_cap(hwdev);
+	if (err) {
+		rte_free(cfg_mgmt);
+		hwdev->cfg_mgmt = NULL;
+	}
+
+	return err;
+}
+
+void spnic_free_capability(void *dev)
+{
+	rte_free(((struct spnic_hwdev *)dev)->cfg_mgmt);
+}
diff --git a/drivers/net/spnic/base/spnic_hw_cfg.h b/drivers/net/spnic/base/spnic_hw_cfg.h
new file mode 100644
index 0000000000..5003d048e6
--- /dev/null
+++ b/drivers/net/spnic/base/spnic_hw_cfg.h
@@ -0,0 +1,117 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2021 Ramaxel Memory Technology, Ltd
+ */
+
+#ifndef _SPNIC_HW_CFG_H_
+#define _SPNIC_HW_CFG_H_
+
+#define CFG_MAX_CMD_TIMEOUT	30000 /* ms */
+
+#define K_UNIT              BIT(10)
+#define M_UNIT              BIT(20)
+#define G_UNIT              BIT(30)
+
+/* Number of PFs and VFs */
+#define HOST_PF_NUM		4
+#define HOST_VF_NUM		0
+#define HOST_OQID_MASK_VAL	2
+
+#define L2NIC_SQ_DEPTH      (4 * K_UNIT)
+#define L2NIC_RQ_DEPTH      (4 * K_UNIT)
+
+enum intr_type {
+	INTR_TYPE_MSIX,
+	INTR_TYPE_MSI,
+	INTR_TYPE_INT,
+	INTR_TYPE_NONE
+};
+
+/* Service type relates define */
+enum cfg_svc_type_en {
+	CFG_SVC_NIC_BIT0 = (1 << 0)
+};
+
+struct nic_service_cap {
+	u16 max_sqs;
+	u16 max_rqs;
+};
+
+/* Device capability */
+struct service_cap {
+	enum cfg_svc_type_en svc_type; /* User input service type */
+	enum cfg_svc_type_en chip_svc_type; /* HW supported service type */
+
+	u8 host_id;
+	u8 ep_id;
+	u8 er_id;	/* PF/VF's ER */
+	u8 port_id;	/* PF/VF's physical port */
+
+	u16 host_total_function;
+	u8 pf_num;
+	u8 pf_id_start;
+	u16 vf_num;	/* max numbers of vf in current host */
+	u16 vf_id_start;
+
+	u8 flexq_en;
+	u8 cos_valid_bitmap;
+	u16 max_vf;	/* max VF number that PF supported */
+
+	struct nic_service_cap nic_cap; /* NIC capability */
+};
+
+struct cfg_mgmt_info {
+	void *hwdev;
+	struct service_cap svc_cap;
+};
+
+enum spnic_cfg_cmd {
+	SPNIC_CFG_CMD_GET_DEV_CAP = 0,
+};
+
+struct spnic_cfg_cmd_dev_cap {
+	u8 status;
+	u8 version;
+	u8 rsvd0[6];
+
+	u16 func_id;
+	u16 rsvd1;
+
+	/* Public resource */
+	u8 host_id;
+	u8 ep_id;
+	u8 er_id;
+	u8 port_id;
+
+	u16 host_total_func;
+	u8 host_pf_num;
+	u8 pf_id_start;
+	u16 host_vf_num;
+	u16 vf_id_start;
+	u32 rsvd_host;
+
+	u16 svc_cap_en;
+	u16 max_vf;
+	u8 flexq_en;
+	u8 valid_cos_bitmap;
+	/* Reserved for func_valid_cos_bitmap */
+	u16 rsvd_cos;
+
+	u32 rsvd[11];
+
+	/* l2nic */
+	u16 nic_max_sq_id;
+	u16 nic_max_rq_id;
+	u32 rsvd_nic[3];
+
+	u32 rsvd_glb[60];
+};
+
+#define IS_NIC_TYPE(dev) \
+	(((u32)(dev)->cfg_mgmt->svc_cap.chip_svc_type) & CFG_SVC_NIC_BIT0)
+
+int spnic_init_capability(void *dev);
+void spnic_free_capability(void *dev);
+
+int spnic_cfg_mbx_vf_proc_msg(void *hwdev, void *pri_handle, u16 cmd, void *buf_in,
+			u16 in_size, void *buf_out, u16 *out_size);
+#endif /* _SPNIC_HW_CFG_H_ */
diff --git a/drivers/net/spnic/base/spnic_hw_comm.c b/drivers/net/spnic/base/spnic_hw_comm.c
index 48730ce7fe..5cb607cf03 100644
--- a/drivers/net/spnic/base/spnic_hw_comm.c
+++ b/drivers/net/spnic/base/spnic_hw_comm.c
@@ -192,6 +192,31 @@  int spnic_set_wq_page_size(void *hwdev, u16 func_idx, u32 page_size)
 	return 0;
 }
 
+int spnic_func_reset(void *hwdev, u64 reset_flag)
+{
+	struct spnic_reset func_reset;
+	struct spnic_hwif *hwif = ((struct spnic_hwdev *)hwdev)->hwif;
+	u16 out_size = sizeof(func_reset);
+	int err = 0;
+
+	PMD_DRV_LOG(INFO, "Function is reset");
+
+	memset(&func_reset, 0, sizeof(func_reset));
+	func_reset.func_id = SPNIC_HWIF_GLOBAL_IDX(hwif);
+	func_reset.reset_flag = reset_flag;
+	err = spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_COMM, MGMT_CMD_FUNC_RESET,
+				     &func_reset, sizeof(func_reset),
+				     &func_reset, &out_size, 0);
+	if (err || !out_size || func_reset.status) {
+		PMD_DRV_LOG(ERR, "Reset func resources failed, err: %d, "
+			    "status: 0x%x, out_size: 0x%x",
+			    err, func_reset.status, out_size);
+		return -EIO;
+	}
+
+	return 0;
+}
+
 int spnic_set_cmdq_depth(void *hwdev, u16 cmdq_depth)
 {
 	struct spnic_cmd_root_ctxt root_ctxt;
@@ -261,3 +286,99 @@  int spnic_set_dma_attr_tbl(struct spnic_hwdev *hwdev, u32 entry_idx, u8 st,
 
 	return 0;
 }
+
+int spnic_get_mgmt_version(void *hwdev, char *mgmt_ver, int max_mgmt_len)
+{
+	struct spnic_cmd_get_fw_version fw_ver;
+	u16 out_size = sizeof(fw_ver);
+	int err;
+
+	if (!hwdev || !mgmt_ver)
+		return -EINVAL;
+
+	memset(&fw_ver, 0, sizeof(fw_ver));
+	fw_ver.fw_type = SPNIC_FW_VER_TYPE_MPU;
+
+	err = spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_COMM,
+				     MGMT_CMD_GET_FW_VERSION,
+				     &fw_ver, sizeof(fw_ver), &fw_ver,
+				     &out_size, 0);
+	if (MSG_TO_MGMT_SYNC_RETURN_ERR(err, out_size, fw_ver.status)) {
+		PMD_DRV_LOG(ERR, "Get mgmt version failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, fw_ver.status, out_size);
+		return -EIO;
+	}
+
+	snprintf(mgmt_ver, max_mgmt_len, "%s", fw_ver.ver);
+
+	return 0;
+}
+
+int spnic_get_board_info(void *hwdev, struct spnic_board_info *info)
+{
+	struct spnic_cmd_board_info board_info;
+	u16 out_size = sizeof(board_info);
+	int err;
+
+	if (!hwdev || !info)
+		return -EINVAL;
+
+	memset(&board_info, 0, sizeof(board_info));
+	err = spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_COMM,
+				     MGMT_CMD_GET_BOARD_INFO,
+				     &board_info, sizeof(board_info),
+				     &board_info, &out_size, 0);
+	if (err || board_info.status || !out_size) {
+		PMD_DRV_LOG(ERR, "Get board info failed, err: %d, status: 0x%x, out size: 0x%x",
+			    err, board_info.status, out_size);
+		return -EFAULT;
+	}
+
+	memcpy(info, &board_info.info, sizeof(*info));
+
+	return 0;
+}
+
+static int spnic_comm_features_nego(void *hwdev, u8 opcode, u64 *s_feature,
+				     u16 size)
+{
+	struct comm_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 == MGMT_MSG_CMD_OP_SET)
+		memcpy(feature_nego.s_feature, s_feature, (size * sizeof(u64)));
+
+	err = spnic_msg_to_mgmt_sync(hwdev, SPNIC_MOD_COMM,
+				     MGMT_CMD_FEATURE_NEGO,
+				     &feature_nego, sizeof(feature_nego),
+				     &feature_nego, &out_size, 0);
+	if (err || !out_size || feature_nego.head.status) {
+		PMD_DRV_LOG(ERR, "Failed to negotiate feature, err: %d, status: 0x%x, out size: 0x%x\n",
+			err, feature_nego.head.status, out_size);
+		return -EINVAL;
+	}
+
+	if (opcode == MGMT_MSG_CMD_OP_GET)
+		memcpy(s_feature, feature_nego.s_feature, (size * sizeof(u64)));
+
+	return 0;
+}
+
+int spnic_get_comm_features(void *hwdev, u64 *s_feature, u16 size)
+{
+	return spnic_comm_features_nego(hwdev, MGMT_MSG_CMD_OP_GET, s_feature,
+					 size);
+}
+
+int spnic_set_comm_features(void *hwdev, u64 *s_feature, u16 size)
+{
+	return spnic_comm_features_nego(hwdev, MGMT_MSG_CMD_OP_SET, s_feature,
+					 size);
+}
diff --git a/drivers/net/spnic/base/spnic_hw_comm.h b/drivers/net/spnic/base/spnic_hw_comm.h
index 3b2373e027..cf4328a04b 100644
--- a/drivers/net/spnic/base/spnic_hw_comm.h
+++ b/drivers/net/spnic/base/spnic_hw_comm.h
@@ -96,6 +96,18 @@  enum spnic_fw_ver_type {
 	SPNIC_FW_VER_TYPE_CFG,
 };
 
+#define MGMT_MSG_CMD_OP_SET	1
+#define MGMT_MSG_CMD_OP_GET	0
+
+struct comm_cmd_feature_nego {
+	struct mgmt_msg_head head;
+
+	u16 func_id;
+	u8 opcode;	/* 1: set, 0: get */
+	u8 rsvd;
+	u64 s_feature[MAX_FEATURE_QWORD];
+};
+
 struct comm_cmd_dma_attr_config {
 	struct mgmt_msg_head head;
 
@@ -162,6 +174,12 @@  struct interrupt_info {
 	u8 resend_timer_cfg;
 };
 
+int spnic_func_reset(void *hwdev, u64 reset_flag);
+
+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_get_interrupt_cfg(void *dev, struct interrupt_info *info);
 
 int spnic_set_interrupt_cfg(void *dev, struct interrupt_info info);
@@ -170,6 +188,10 @@  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_get_comm_features(void *hwdev, u64 *s_feature, u16 size);
+
+int spnic_set_comm_features(void *hwdev, u64 *s_feature, u16 size);
+
 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);
 
diff --git a/drivers/net/spnic/base/spnic_hwdev.c b/drivers/net/spnic/base/spnic_hwdev.c
index 7e348c3139..9dc4fdc2d6 100644
--- a/drivers/net/spnic/base/spnic_hwdev.c
+++ b/drivers/net/spnic/base/spnic_hwdev.c
@@ -11,6 +11,7 @@ 
 #include "spnic_mbox.h"
 #include "spnic_wq.h"
 #include "spnic_cmdq.h"
+#include "spnic_hw_cfg.h"
 #include "spnic_hwdev.h"
 #include "spnic_hw_comm.h"
 
@@ -283,6 +284,35 @@  static void spnic_comm_cmdqs_free(struct spnic_hwdev *hwdev)
 	spnic_cmdqs_free(hwdev);
 }
 
+static void spnic_sync_mgmt_func_state(struct spnic_hwdev *hwdev)
+{
+	spnic_set_pf_status(hwdev->hwif, SPNIC_PF_STATUS_ACTIVE_FLAG);
+}
+
+static int __get_func_misc_info(struct spnic_hwdev *hwdev)
+{
+	int err;
+
+	err = spnic_get_board_info(hwdev, &hwdev->board_info);
+	if (err) {
+		/* For the PF/VF of secondary host, return error */
+		if (spnic_pcie_itf_id(hwdev))
+			return err;
+
+		memset(&hwdev->board_info, 0xff,
+		       sizeof(struct spnic_board_info));
+	}
+
+	err = spnic_get_mgmt_version(hwdev, hwdev->mgmt_ver,
+			SPNIC_MGMT_VERSION_MAX_LEN);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Get mgmt cpu version failed");
+		return err;
+	}
+
+	return 0;
+}
+
 static int init_mgmt_channel(struct spnic_hwdev *hwdev)
 {
 	int err;
@@ -375,15 +405,31 @@  static int spnic_init_comm_ch(struct spnic_hwdev *hwdev)
 		return err;
 	}
 
+	err = __get_func_misc_info(hwdev);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Get function msic information failed");
+		goto get_func_info_err;
+	}
+
+	err = spnic_func_reset(hwdev, SPNIC_NIC_RES | SPNIC_COMM_RES);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Reset function failed");
+		goto func_reset_err;
+	}
+
 	err = init_cmdqs_channel(hwdev);
 	if (err) {
 		PMD_DRV_LOG(ERR, "Init cmdq channel failed");
 		goto init_cmdqs_channel_err;
 	}
 
+	spnic_sync_mgmt_func_state(hwdev);
+
 	return 0;
 
 init_cmdqs_channel_err:
+func_reset_err:
+get_func_info_err:
 	free_mgmt_channel(hwdev);
 
 	return err;
@@ -391,11 +437,14 @@  static int spnic_init_comm_ch(struct spnic_hwdev *hwdev)
 
 static void spnic_uninit_comm_ch(struct spnic_hwdev *hwdev)
 {
+	spnic_set_pf_status(hwdev->hwif, SPNIC_PF_STATUS_INIT);
+
 	spnic_comm_cmdqs_free(hwdev);
 
 	if (SPNIC_FUNC_TYPE(hwdev) != TYPE_VF)
 		spnic_set_wq_page_size(hwdev, spnic_global_func_id(hwdev),
 					SPNIC_HW_WQ_PAGE_SIZE);
+
 	free_mgmt_channel(hwdev);
 }
 
@@ -423,8 +472,27 @@  int spnic_init_hwdev(struct spnic_hwdev *hwdev)
 		goto init_comm_ch_err;
 	}
 
+	err = spnic_init_capability(hwdev);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Init capability failed");
+		goto init_cap_err;
+	}
+
+	err = spnic_set_comm_features(hwdev, hwdev->features,
+				       MAX_FEATURE_QWORD);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to set comm features\n");
+		goto set_feature_err;
+	}
+
 	return 0;
 
+set_feature_err:
+	spnic_free_capability(hwdev);
+
+init_cap_err:
+	spnic_uninit_comm_ch(hwdev);
+
 init_comm_ch_err:
 	spnic_free_hwif(hwdev);
 
@@ -436,6 +504,8 @@  int spnic_init_hwdev(struct spnic_hwdev *hwdev)
 
 void spnic_free_hwdev(struct spnic_hwdev *hwdev)
 {
+	spnic_free_capability(hwdev);
+
 	spnic_uninit_comm_ch(hwdev);
 
 	spnic_free_hwif(hwdev);
diff --git a/drivers/net/spnic/base/spnic_hwdev.h b/drivers/net/spnic/base/spnic_hwdev.h
index 2f25c0d0d3..3bb8a3c31f 100644
--- a/drivers/net/spnic/base/spnic_hwdev.h
+++ b/drivers/net/spnic/base/spnic_hwdev.h
@@ -100,6 +100,7 @@  struct spnic_board_info {
 	u32 cfg_addr;
 };
 
+#define MAX_FEATURE_QWORD	4
 struct spnic_hwdev {
 	void *dev_handle; /* Pointer to spnic_nic_dev */
 	void *pci_dev; /* Pointer to rte_pci_device */
@@ -117,7 +118,11 @@  struct spnic_hwdev {
 
 	struct spnic_msg_pf_to_mgmt *pf_to_mgmt;
 	u8 *chip_fault_stats;
+
 	struct spnic_hw_stats hw_stats;
+	struct spnic_board_info board_info;
+	char mgmt_ver[MGMT_VERSION_MAX_LEN];
+	u64 features[MAX_FEATURE_QWORD];
 
 	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 4b4c4311eb..9cde0a122f 100644
--- a/drivers/net/spnic/base/spnic_mbox.c
+++ b/drivers/net/spnic/base/spnic_mbox.c
@@ -10,6 +10,7 @@ 
 #include "spnic_mgmt.h"
 #include "spnic_hwif.h"
 #include "spnic_eqs.h"
+#include "spnic_hw_cfg.h"
 #include "spnic_mbox.h"
 #include "spnic_nic_event.h"
 
@@ -150,6 +151,13 @@  static int recv_vf_mbox_handler(struct spnic_mbox *func_to_func,
 					     recv_mbox->mbox_len,
 					     buf_out, out_size);
 		break;
+	case SPNIC_MOD_CFGM:
+		err = spnic_cfg_mbx_vf_proc_msg(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_L2NIC:
 		err = spnic_vf_event_handler(func_to_func->hwdev,
 					     func_to_func->hwdev->cfg_mgmt,