diff --git a/drivers/net/nfp/nfp_ethdev.c b/drivers/net/nfp/nfp_ethdev.c
index aa2b59af32..7022ef435f 100644
--- a/drivers/net/nfp/nfp_ethdev.c
+++ b/drivers/net/nfp/nfp_ethdev.c
@@ -479,7 +479,7 @@ nfp_net_init(struct rte_eth_dev *eth_dev)
 
 	rte_eth_copy_pci_info(eth_dev, pci_dev);
 
-	if (port == 0) {
+	if (port == 0 || pf_dev->multi_pf.enabled) {
 		uint32_t min_size;
 
 		hw->ctrl_bar = pf_dev->ctrl_bar;
@@ -712,6 +712,26 @@ nfp_fw_setup(struct rte_pci_device *dev,
 	return err;
 }
 
+static inline bool
+nfp_check_multi_pf_from_nsp(struct rte_pci_device *pci_dev,
+		struct nfp_cpp *cpp)
+{
+	bool flag;
+	struct nfp_nsp *nsp;
+
+	nsp = nfp_nsp_open(cpp);
+	if (nsp == NULL) {
+		PMD_DRV_LOG(ERR, "NFP error when obtaining NSP handle");
+		return false;
+	}
+
+	flag = (nfp_nsp_get_abi_ver_major(nsp) > 0) &&
+			(pci_dev->id.device_id == PCI_DEVICE_ID_NFP3800_PF_NIC);
+
+	nfp_nsp_close(nsp);
+	return flag;
+}
+
 static int
 nfp_init_app_fw_nic(struct nfp_pf_dev *pf_dev,
 		const struct nfp_dev_info *dev_info)
@@ -874,6 +894,14 @@ nfp_pf_init(struct rte_pci_device *pci_dev)
 		return -ENODEV;
 	}
 
+	/* Allocate memory for the PF "device" */
+	snprintf(name, sizeof(name), "nfp_pf%d", 0);
+	pf_dev = rte_zmalloc(name, sizeof(*pf_dev), 0);
+	if (pf_dev == NULL) {
+		PMD_INIT_LOG(ERR, "Can't allocate memory for the PF device");
+		return -ENOMEM;
+	}
+
 	/*
 	 * When device bound to UIO, the device could be used, by mistake,
 	 * by two DPDK apps, and the UIO driver does not avoid it. This
@@ -888,7 +916,8 @@ nfp_pf_init(struct rte_pci_device *pci_dev)
 
 	if (cpp == NULL) {
 		PMD_INIT_LOG(ERR, "A CPP handle can not be obtained");
-		return -EIO;
+		ret = -EIO;
+		goto pf_cleanup;
 	}
 
 	hwinfo = nfp_hwinfo_read(cpp);
@@ -906,6 +935,8 @@ nfp_pf_init(struct rte_pci_device *pci_dev)
 		goto hwinfo_cleanup;
 	}
 
+	pf_dev->multi_pf.enabled = nfp_check_multi_pf_from_nsp(pci_dev, cpp);
+
 	/* Force the physical port down to clear the possible DMA error */
 	for (i = 0; i < nfp_eth_table->count; i++)
 		nfp_eth_set_configured(cpp, nfp_eth_table->ports[i].index, 0);
@@ -932,14 +963,6 @@ nfp_pf_init(struct rte_pci_device *pci_dev)
 		goto sym_tbl_cleanup;
 	}
 
-	/* Allocate memory for the PF "device" */
-	snprintf(name, sizeof(name), "nfp_pf%d", 0);
-	pf_dev = rte_zmalloc(name, sizeof(*pf_dev), 0);
-	if (pf_dev == NULL) {
-		ret = -ENOMEM;
-		goto sym_tbl_cleanup;
-	}
-
 	/* Populate the newly created PF device */
 	pf_dev->app_fw_id = app_fw_id;
 	pf_dev->cpp = cpp;
@@ -957,7 +980,7 @@ nfp_pf_init(struct rte_pci_device *pci_dev)
 	if (pf_dev->qc_bar == NULL) {
 		PMD_INIT_LOG(ERR, "nfp_rtsym_map fails for net.qc");
 		ret = -EIO;
-		goto pf_cleanup;
+		goto sym_tbl_cleanup;
 	}
 
 	PMD_INIT_LOG(DEBUG, "qc_bar address: %p", pf_dev->qc_bar);
@@ -998,8 +1021,6 @@ nfp_pf_init(struct rte_pci_device *pci_dev)
 
 hwqueues_cleanup:
 	nfp_cpp_area_free(pf_dev->qc_area);
-pf_cleanup:
-	rte_free(pf_dev);
 sym_tbl_cleanup:
 	free(sym_tbl);
 eth_table_cleanup:
@@ -1008,6 +1029,8 @@ nfp_pf_init(struct rte_pci_device *pci_dev)
 	free(hwinfo);
 cpp_cleanup:
 	nfp_cpp_free(cpp);
+pf_cleanup:
+	rte_free(pf_dev);
 
 	return ret;
 }
diff --git a/drivers/net/nfp/nfp_net_common.h b/drivers/net/nfp/nfp_net_common.h
index b9df2fe563..bd0ed077c5 100644
--- a/drivers/net/nfp/nfp_net_common.h
+++ b/drivers/net/nfp/nfp_net_common.h
@@ -54,6 +54,11 @@ struct nfp_net_tlv_caps {
 	uint32_t mbox_cmsg_types;        /**< Cmsgs which can be passed through the mailbox */
 };
 
+struct nfp_multi_pf {
+	/** Support multiple PF */
+	bool enabled;
+};
+
 struct nfp_pf_dev {
 	/** Backpointer to associated pci device */
 	struct rte_pci_device *pci_dev;
@@ -79,6 +84,9 @@ struct nfp_pf_dev {
 
 	/** Service id of cpp bridge service */
 	uint32_t cpp_bridge_id;
+
+	/** Multiple PF configuration */
+	struct nfp_multi_pf multi_pf;
 };
 
 struct nfp_app_fw_nic {
diff --git a/drivers/net/nfp/nfpcore/nfp_nsp.c b/drivers/net/nfp/nfpcore/nfp_nsp.c
index a680b972b8..9f88b822f3 100644
--- a/drivers/net/nfp/nfpcore/nfp_nsp.c
+++ b/drivers/net/nfp/nfpcore/nfp_nsp.c
@@ -40,7 +40,17 @@
 #define   NSP_DFLT_BUFFER_SIZE_MB      GENMASK_ULL(7, 0)
 
 #define NSP_MAGIC               0xab10
-#define NSP_MAJOR               0
+
+/*
+ * ABI major version is bumped separately without resetting minor
+ * version when the change in NSP is not compatible to old driver.
+ */
+#define NSP_MAJOR               1
+
+/*
+ * ABI minor version is bumped when new feature is introduced
+ * while old driver can still work without this new feature.
+ */
 #define NSP_MINOR               8
 
 #define NSP_CODE_MAJOR          GENMASK_ULL(15, 12)
@@ -203,7 +213,7 @@ nfp_nsp_check(struct nfp_nsp *state)
 	state->ver.major = FIELD_GET(NSP_STATUS_MAJOR, reg);
 	state->ver.minor = FIELD_GET(NSP_STATUS_MINOR, reg);
 
-	if (state->ver.major != NSP_MAJOR || state->ver.minor < NSP_MINOR) {
+	if (state->ver.major > NSP_MAJOR || state->ver.minor < NSP_MINOR) {
 		PMD_DRV_LOG(ERR, "Unsupported ABI %hu.%hu", state->ver.major,
 				state->ver.minor);
 		return -EINVAL;
