diff --git a/drivers/net/nfp/nfp_ethdev.c b/drivers/net/nfp/nfp_ethdev.c
index 0a5c703190..4e3a6a964d 100644
--- a/drivers/net/nfp/nfp_ethdev.c
+++ b/drivers/net/nfp/nfp_ethdev.c
@@ -309,6 +309,94 @@ nfp_net_nfd3_close(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static int
+nfp_net_nfdk_stop(struct rte_eth_dev *dev)
+{
+	struct nfp_net_hw *hw;
+
+	PMD_INIT_LOG(DEBUG, "Stop");
+
+	hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	nfp_net_disable_queues(dev);
+
+	/* Clear queues */
+	nfp_net_nfdk_stop_tx_queue(dev);
+
+	nfp_net_stop_rx_queue(dev);
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+		/* Configure the physical port down */
+		nfp_eth_set_configured(hw->cpp, hw->nfp_idx, 0);
+	else
+		nfp_eth_set_configured(dev->process_private, hw->nfp_idx, 0);
+
+	return 0;
+}
+
+static int
+nfp_net_nfdk_close(struct rte_eth_dev *dev)
+{
+	int i;
+	struct nfp_net_hw *hw;
+	struct rte_pci_device *pci_dev;
+	struct nfp_pf_dev *pf_dev;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	PMD_INIT_LOG(DEBUG, "Close");
+
+	pf_dev = NFP_NET_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	hw = NFP_NET_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+
+	/*
+	 * We assume that the DPDK application is stopping all the
+	 * threads/queues before calling the device close function.
+	 */
+
+	nfp_net_disable_queues(dev);
+
+	/* Clear queues */
+	nfp_net_nfdk_close_tx_queue(dev);
+
+	nfp_net_close_rx_queue(dev);
+
+	/* Cancel possible impending LSC work here before releasing the port*/
+	rte_eal_alarm_cancel(nfp_net_dev_interrupt_delayed_handler, (void *)dev);
+
+	/* Only free PF resources after all physical ports have been closed */
+	/* Mark this port as unused and free device priv resources*/
+	nn_cfg_writeb(hw, NFP_NET_CFG_LSC, 0xff);
+	pf_dev->ports[hw->idx] = NULL;
+	rte_eth_dev_release_port(dev);
+
+	for (i = 0; i < pf_dev->total_phyports; i++) {
+		/* Check to see if ports are still in use */
+		if (pf_dev->ports[i])
+			return 0;
+	}
+
+	/* Now it is safe to free all PF resources */
+	PMD_INIT_LOG(INFO, "Freeing PF resources");
+	nfp_cpp_area_free(pf_dev->ctrl_area);
+	nfp_cpp_area_free(pf_dev->hwqueues_area);
+	free(pf_dev->hwinfo);
+	free(pf_dev->sym_tbl);
+	nfp_cpp_free(pf_dev->cpp);
+	rte_free(pf_dev);
+
+	rte_intr_disable(pci_dev->intr_handle);
+
+	/* unregister callback func from eal lib */
+	rte_intr_callback_unregister(pci_dev->intr_handle,
+				nfp_net_dev_interrupt_handler,
+				(void *)dev);
+
+	return 0;
+}
+
 /* Initialise and register driver with DPDK Application */
 static const struct eth_dev_ops nfp_net_nfd3_eth_dev_ops = {
 	.dev_configure		= nfp_net_configure,
@@ -342,10 +430,10 @@ static const struct eth_dev_ops nfp_net_nfd3_eth_dev_ops = {
 static const struct eth_dev_ops nfp_net_nfdk_eth_dev_ops = {
 	.dev_configure		= nfp_net_configure,
 	.dev_start		= nfp_net_start,
-	.dev_stop		= nfp_net_nfd3_stop,
+	.dev_stop		= nfp_net_nfdk_stop,
 	.dev_set_link_up	= nfp_net_set_link_up,
 	.dev_set_link_down	= nfp_net_set_link_down,
-	.dev_close		= nfp_net_nfd3_close,
+	.dev_close		= nfp_net_nfdk_close,
 	.promiscuous_enable	= nfp_net_promisc_enable,
 	.promiscuous_disable	= nfp_net_promisc_disable,
 	.link_update		= nfp_net_link_update,
diff --git a/drivers/net/nfp/nfp_ethdev_vf.c b/drivers/net/nfp/nfp_ethdev_vf.c
index d347c98134..a5c6aceb32 100644
--- a/drivers/net/nfp/nfp_ethdev_vf.c
+++ b/drivers/net/nfp/nfp_ethdev_vf.c
@@ -214,6 +214,58 @@ nfp_netvf_nfd3_close(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static int
+nfp_netvf_nfdk_stop(struct rte_eth_dev *dev)
+{
+	PMD_INIT_LOG(DEBUG, "Stop");
+
+	nfp_net_disable_queues(dev);
+
+	/* Clear queues */
+	nfp_net_nfdk_stop_tx_queue(dev);
+
+	nfp_net_stop_rx_queue(dev);
+
+	return 0;
+}
+
+static int
+nfp_netvf_nfdk_close(struct rte_eth_dev *dev)
+{
+	struct rte_pci_device *pci_dev;
+
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
+		return 0;
+
+	PMD_INIT_LOG(DEBUG, "Close");
+
+	pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+
+	/*
+	 * We assume that the DPDK application is stopping all the
+	 * threads/queues before calling the device close function.
+	 */
+
+	nfp_net_disable_queues(dev);
+
+	/* Clear queues */
+	nfp_net_nfdk_close_tx_queue(dev);
+
+	nfp_net_close_rx_queue(dev);
+
+	rte_intr_disable(pci_dev->intr_handle);
+
+	/* unregister callback func from eal lib */
+	rte_intr_callback_unregister(pci_dev->intr_handle,
+				nfp_net_dev_interrupt_handler,
+				(void *)dev);
+
+	/* Cancel possible impending LSC work here before releasing the port*/
+	rte_eal_alarm_cancel(nfp_net_dev_interrupt_delayed_handler, (void *)dev);
+
+	return 0;
+}
+
 /* Initialise and register VF driver with DPDK Application */
 static const struct eth_dev_ops nfp_netvf_nfd3_eth_dev_ops = {
 	.dev_configure		= nfp_net_configure,
@@ -247,10 +299,10 @@ static const struct eth_dev_ops nfp_netvf_nfd3_eth_dev_ops = {
 static const struct eth_dev_ops nfp_netvf_nfdk_eth_dev_ops = {
 	.dev_configure		= nfp_net_configure,
 	.dev_start		= nfp_netvf_start,
-	.dev_stop		= nfp_netvf_nfd3_stop,
+	.dev_stop		= nfp_netvf_nfdk_stop,
 	.dev_set_link_up	= nfp_netvf_set_link_up,
 	.dev_set_link_down	= nfp_netvf_set_link_down,
-	.dev_close		= nfp_netvf_nfd3_close,
+	.dev_close		= nfp_netvf_nfdk_close,
 	.promiscuous_enable	= nfp_net_promisc_enable,
 	.promiscuous_disable	= nfp_net_promisc_disable,
 	.link_update		= nfp_net_link_update,
@@ -498,7 +550,13 @@ static const struct rte_pci_id pci_id_nfp_vf_net_map[] = {
 static int nfp_vf_pci_uninit(struct rte_eth_dev *eth_dev)
 {
 	/* VF cleanup, just free private port data */
-	return nfp_netvf_nfd3_close(eth_dev);
+	struct nfp_net_hw *hw;
+
+	hw = NFP_NET_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
+	if (NFD_CFG_CLASS_VER_of(hw->ver) == NFP_NET_CFG_VERSION_DP_NFD3)
+		return nfp_netvf_nfd3_close(eth_dev);
+	else
+		return nfp_netvf_nfdk_close(eth_dev);
 }
 
 static int eth_nfp_vf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
