[net-next,v2,8/9] octeon_ep: add PF-VF mailbox communication

Message ID 20221129130933.25231-9-vburru@marvell.com
State New
Headers
Series octeon_ep: Update PF mailbox for VF |

Commit Message

Veerasenareddy Burru Nov. 29, 2022, 1:09 p.m. UTC
  Implement mailbox communication between PF and VFs.
PF-VF mailbox is used for all control commands from VF to PF and
asynchronous notification messages from PF to VF.

Signed-off-by: Veerasenareddy Burru <vburru@marvell.com>
Signed-off-by: Sathesh Edara <sedara@marvell.com>
Signed-off-by: Abhijit Ayarekar <aayarekar@marvell.com>
---
v1 -> v2:
 * reworked the patch for changes made to preceding patches.
 * removed device status oct->status, as it is not required with the
   modified implementation.

 .../net/ethernet/marvell/octeon_ep/Makefile   |   3 +-
 .../marvell/octeon_ep/octep_cn9k_pf.c         |  42 ++-
 .../ethernet/marvell/octeon_ep/octep_main.c   |  15 +-
 .../ethernet/marvell/octeon_ep/octep_main.h   |  44 +--
 .../marvell/octeon_ep/octep_pfvf_mbox.c       | 305 ++++++++++++++++++
 .../marvell/octeon_ep/octep_pfvf_mbox.h       | 126 ++++++++
 .../marvell/octeon_ep/octep_regs_cn9k_pf.h    |   9 +
 .../net/ethernet/marvell/octeon_ep/octep_tx.h |  24 +-
 8 files changed, 523 insertions(+), 45 deletions(-)
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c
 create mode 100644 drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.h
  

Comments

Dan Carpenter Dec. 9, 2022, 8:48 a.m. UTC | #1
Hi Veerasenareddy,

url:    https://github.com/intel-lab-lkp/linux/commits/Veerasenareddy-Burru/octeon_ep-Update-PF-mailbox-for-VF/20221130-110134
base:   7a168f560e3c3829b74a893d3655caab14a7aef8
patch link:    https://lore.kernel.org/r/20221129130933.25231-9-vburru%40marvell.com
patch subject: [PATCH net-next v2 8/9] octeon_ep: add PF-VF mailbox communication
config: ia64-randconfig-m041-20221204
compiler: ia64-linux-gcc (GCC) 12.1.0

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <error27@gmail.com>

New smatch warnings:
drivers/net/ethernet/marvell/octeon_ep/octep_main.c:1105 octep_probe() warn: missing unwind goto?

vim +1105 drivers/net/ethernet/marvell/octeon_ep/octep_main.c

862cd659a6fbac Veerasenareddy Burru 2022-04-12  1046  static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1047  {
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1048  	struct octep_device *octep_dev = NULL;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1049  	struct net_device *netdev;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1050  	int err;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1051  
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1052  	err = pci_enable_device(pdev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1053  	if (err) {
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1054  		dev_err(&pdev->dev, "Failed to enable PCI device\n");
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1055  		return  err;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1056  	}
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1057  
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1058  	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1059  	if (err) {
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1060  		dev_err(&pdev->dev, "Failed to set DMA mask !!\n");
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1061  		goto err_dma_mask;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1062  	}
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1063  
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1064  	err = pci_request_mem_regions(pdev, OCTEP_DRV_NAME);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1065  	if (err) {
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1066  		dev_err(&pdev->dev, "Failed to map PCI memory regions\n");
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1067  		goto err_pci_regions;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1068  	}
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1069  
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1070  	pci_enable_pcie_error_reporting(pdev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1071  	pci_set_master(pdev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1072  
a36869e03997c0 Veerasenareddy Burru 2022-11-29  1073  #define FW_STATUS_READY    1
a36869e03997c0 Veerasenareddy Burru 2022-11-29  1074  	if (get_fw_ready_status(pdev) != FW_STATUS_READY) {
a36869e03997c0 Veerasenareddy Burru 2022-11-29  1075  		dev_notice(&pdev->dev, "Firmware not ready; defer probe.\n");
a36869e03997c0 Veerasenareddy Burru 2022-11-29  1076  		err = -EPROBE_DEFER;
a36869e03997c0 Veerasenareddy Burru 2022-11-29  1077  		goto err_alloc_netdev;
a36869e03997c0 Veerasenareddy Burru 2022-11-29  1078  	}
a36869e03997c0 Veerasenareddy Burru 2022-11-29  1079  
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1080  	netdev = alloc_etherdev_mq(sizeof(struct octep_device),
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1081  				   OCTEP_MAX_QUEUES);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1082  	if (!netdev) {
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1083  		dev_err(&pdev->dev, "Failed to allocate netdev\n");
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1084  		err = -ENOMEM;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1085  		goto err_alloc_netdev;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1086  	}
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1087  	SET_NETDEV_DEV(netdev, &pdev->dev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1088  
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1089  	octep_dev = netdev_priv(netdev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1090  	octep_dev->netdev = netdev;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1091  	octep_dev->pdev = pdev;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1092  	octep_dev->dev = &pdev->dev;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1093  	pci_set_drvdata(pdev, octep_dev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1094  
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1095  	err = octep_device_setup(octep_dev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1096  	if (err) {
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1097  		dev_err(&pdev->dev, "Device setup failed\n");
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1098  		goto err_octep_config;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1099  	}
f13f1764c1708a Veerasenareddy Burru 2022-11-29  1100  
f13f1764c1708a Veerasenareddy Burru 2022-11-29  1101  	err = octep_setup_pfvf_mbox(octep_dev);
f13f1764c1708a Veerasenareddy Burru 2022-11-29  1102  	if (err) {
f13f1764c1708a Veerasenareddy Burru 2022-11-29  1103  		dev_err(&pdev->dev, " pfvf mailbox setup failed\n");
f13f1764c1708a Veerasenareddy Burru 2022-11-29  1104  		octep_ctrl_net_uninit(octep_dev);
f13f1764c1708a Veerasenareddy Burru 2022-11-29 @1105  		return err;

This doesn't call free_netdev(netdev); so it's a leak.

The octep_device_cleanup() function calls octep_ctrl_net_uninit() but
presumably calling octep_device_cleanup() if octep_setup_pfvf_mbox()
fails is a bug...  Ideally there would be a function which could clean
up octep_device_setup() and a different function which could clean up
octep_setup_pfvf_mbox() but maybe that's impossible because of weird
ordering constraints.

f13f1764c1708a Veerasenareddy Burru 2022-11-29  1106  	}
f13f1764c1708a Veerasenareddy Burru 2022-11-29  1107  
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1108  	INIT_WORK(&octep_dev->tx_timeout_task, octep_tx_timeout_task);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1109  	INIT_WORK(&octep_dev->ctrl_mbox_task, octep_ctrl_mbox_task);
c310a95e2434e5 Veerasenareddy Burru 2022-11-29  1110  	INIT_DELAYED_WORK(&octep_dev->intr_poll_task, octep_intr_poll_task);
c310a95e2434e5 Veerasenareddy Burru 2022-11-29  1111  	octep_dev->poll_non_ioq_intr = true;
c310a95e2434e5 Veerasenareddy Burru 2022-11-29  1112  	queue_delayed_work(octep_wq, &octep_dev->intr_poll_task,
c310a95e2434e5 Veerasenareddy Burru 2022-11-29  1113  			   msecs_to_jiffies(OCTEP_INTR_POLL_TIME_MSECS));
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1114  
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1115  	netdev->netdev_ops = &octep_netdev_ops;
5cc256e79bff06 Veerasenareddy Burru 2022-04-12  1116  	octep_set_ethtool_ops(netdev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1117  	netif_carrier_off(netdev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1118  
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1119  	netdev->hw_features = NETIF_F_SG;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1120  	netdev->features |= netdev->hw_features;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1121  	netdev->min_mtu = OCTEP_MIN_MTU;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1122  	netdev->max_mtu = OCTEP_MAX_MTU;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1123  	netdev->mtu = OCTEP_DEFAULT_MTU;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1124  
6494f39ec1f4be Veerasenareddy Burru 2022-11-29  1125  	err = octep_ctrl_net_get_mac_addr(octep_dev, OCTEP_CTRL_NET_INVALID_VFID,
6494f39ec1f4be Veerasenareddy Burru 2022-11-29  1126  					  octep_dev->mac_addr);
848ffce2f0c93f Ziyang Xuan          2022-11-11  1127  	if (err) {
848ffce2f0c93f Ziyang Xuan          2022-11-11  1128  		dev_err(&pdev->dev, "Failed to get mac address\n");
848ffce2f0c93f Ziyang Xuan          2022-11-11  1129  		goto register_dev_err;
848ffce2f0c93f Ziyang Xuan          2022-11-11  1130  	}
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1131  	eth_hw_addr_set(netdev, octep_dev->mac_addr);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1132  
0a03f3c511f57d Yang Yingliang       2022-04-15  1133  	err = register_netdev(netdev);
0a03f3c511f57d Yang Yingliang       2022-04-15  1134  	if (err) {
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1135  		dev_err(&pdev->dev, "Failed to register netdev\n");
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1136  		goto register_dev_err;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1137  	}
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1138  	dev_info(&pdev->dev, "Device probe successful\n");
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1139  	return 0;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1140  
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1141  register_dev_err:
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1142  	octep_device_cleanup(octep_dev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1143  err_octep_config:
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1144  	free_netdev(netdev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1145  err_alloc_netdev:
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1146  	pci_disable_pcie_error_reporting(pdev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1147  	pci_release_mem_regions(pdev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1148  err_pci_regions:
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1149  err_dma_mask:
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1150  	pci_disable_device(pdev);
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1151  	return err;
862cd659a6fbac Veerasenareddy Burru 2022-04-12  1152  }
  

Patch

diff --git a/drivers/net/ethernet/marvell/octeon_ep/Makefile b/drivers/net/ethernet/marvell/octeon_ep/Makefile
index 2026c8118158..6cfa7198fdbd 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/Makefile
+++ b/drivers/net/ethernet/marvell/octeon_ep/Makefile
@@ -6,4 +6,5 @@ 
 obj-$(CONFIG_OCTEON_EP) += octeon_ep.o
 
 octeon_ep-y := octep_main.o octep_cn9k_pf.o octep_tx.o octep_rx.o \
-	       octep_ethtool.o octep_ctrl_mbox.o octep_ctrl_net.o
+	       octep_ethtool.o octep_ctrl_mbox.o octep_ctrl_net.o \
+	       octep_pfvf_mbox.o
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c
index e307bae62673..4840133477dc 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_cn9k_pf.c
@@ -354,26 +354,50 @@  static void octep_setup_mbox_regs_cn93_pf(struct octep_device *oct, int q_no)
 {
 	struct octep_mbox *mbox = oct->mbox[q_no];
 
-	mbox->q_no = q_no;
-
-	/* PF mbox interrupt reg */
-	mbox->mbox_int_reg = oct->mmio[0].hw_addr + CN93_SDP_EPF_MBOX_RINT(0);
-
 	/* PF to VF DATA reg. PF writes into this reg */
-	mbox->mbox_write_reg = oct->mmio[0].hw_addr + CN93_SDP_R_MBOX_PF_VF_DATA(q_no);
+	mbox->pf_vf_data_reg = oct->mmio[0].hw_addr + CN93_SDP_MBOX_PF_VF_DATA(q_no);
 
 	/* VF to PF DATA reg. PF reads from this reg */
-	mbox->mbox_read_reg = oct->mmio[0].hw_addr + CN93_SDP_R_MBOX_VF_PF_DATA(q_no);
+	mbox->vf_pf_data_reg = oct->mmio[0].hw_addr + CN93_SDP_MBOX_VF_PF_DATA(q_no);
 }
 
 /* Process non-ioq interrupts required to keep pf interface running.
  * OEI_RINT is needed for control mailbox
+ * MBOX_RINT is needed for pfvf mailbox
  */
 static int octep_poll_non_ioq_interrupts_cn93_pf(struct octep_device *oct)
 {
-	u64 reg0;
+	u32 vf, active_vfs, active_rings_per_vf, vf_mbox_queue;
+	u64 reg0, reg1;
 	int handled = 0;
 
+	reg0 = octep_read_csr64(oct, CN93_SDP_EPF_MBOX_RINT(0));
+	reg1 = octep_read_csr64(oct, CN93_SDP_EPF_MBOX_RINT(1));
+	if (reg0 || reg1) {
+		dev_info(&oct->pdev->dev,
+			 "Received MBOX_RINT intr: reg0 0x%llx reg1 0x%llx\n",
+			 reg0, reg1);
+
+		active_vfs = CFG_GET_ACTIVE_VFS(oct->conf);
+		active_rings_per_vf = CFG_GET_ACTIVE_RPVF(oct->conf);
+		for (vf = 0; vf < active_vfs; vf++) {
+			vf_mbox_queue = vf * active_rings_per_vf;
+			if (!(reg0 & (0x1UL << vf_mbox_queue)))
+				continue;
+
+			if (!oct->mbox[vf_mbox_queue]) {
+				dev_err(&oct->pdev->dev, "bad mbox vf %d\n", vf);
+				continue;
+			}
+			schedule_work(&oct->mbox[vf_mbox_queue]->wk.work);
+		}
+		if (reg0)
+			octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT(0), reg0);
+		if (reg1)
+			octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT(1), reg1);
+
+		handled = 1;
+	}
 	/* Check for OEI INTR */
 	reg0 = octep_read_csr64(oct, CN93_SDP_EPF_OEI_RINT);
 	if (reg0) {
@@ -562,6 +586,8 @@  static void octep_enable_interrupts_cn93_pf(struct octep_device *oct)
 	octep_write_csr64(oct, CN93_SDP_EPF_OEI_RINT_ENA_W1S, -1ULL);
 	octep_write_csr64(oct, CN93_SDP_EPF_MISC_RINT_ENA_W1S, intr_mask);
 	octep_write_csr64(oct, CN93_SDP_EPF_DMA_RINT_ENA_W1S, intr_mask);
+	octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT_ENA_W1S(0), -1ULL);
+	octep_write_csr64(oct, CN93_SDP_EPF_MBOX_RINT_ENA_W1S(1), -1ULL);
 }
 
 /* Disable all interrupts */
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
index d43161d1e38a..cd0d77ceb868 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
@@ -17,6 +17,7 @@ 
 #include "octep_config.h"
 #include "octep_main.h"
 #include "octep_ctrl_net.h"
+#include "octep_pfvf_mbox.h"
 
 #define OCTEP_INTR_POLL_TIME_MSECS    100
 struct workqueue_struct *octep_wq;
@@ -1001,11 +1002,7 @@  static void octep_device_cleanup(struct octep_device *oct)
 
 	dev_info(&oct->pdev->dev, "Cleaning up Octeon Device ...\n");
 
-	for (i = 0; i < OCTEP_MAX_VF; i++) {
-		vfree(oct->mbox[i]);
-		oct->mbox[i] = NULL;
-	}
-
+	octep_delete_pfvf_mbox(oct);
 	octep_ctrl_net_uninit(oct);
 
 	oct->hw_ops.soft_reset(oct);
@@ -1100,6 +1097,14 @@  static int octep_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		dev_err(&pdev->dev, "Device setup failed\n");
 		goto err_octep_config;
 	}
+
+	err = octep_setup_pfvf_mbox(octep_dev);
+	if (err) {
+		dev_err(&pdev->dev, " pfvf mailbox setup failed\n");
+		octep_ctrl_net_uninit(octep_dev);
+		return err;
+	}
+
 	INIT_WORK(&octep_dev->tx_timeout_task, octep_tx_timeout_task);
 	INIT_WORK(&octep_dev->ctrl_mbox_task, octep_ctrl_mbox_task);
 	INIT_DELAYED_WORK(&octep_dev->intr_poll_task, octep_intr_poll_task);
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h
index 70cc3e236cb4..ad6d324bd525 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.h
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.h
@@ -94,28 +94,27 @@  struct octep_mbox_data {
 	u64 *data;
 };
 
+#define MAX_VF_PF_MBOX_DATA_SIZE 384
+/* wrappers around work structs */
+struct octep_pfvf_mbox_wk {
+	struct work_struct work;
+	void *ctxptr;
+	u64 ctxul;
+};
+
 /* Octeon device mailbox */
 struct octep_mbox {
-	/* A spinlock to protect access to this q_mbox. */
-	spinlock_t lock;
-
-	u32 q_no;
-	u32 state;
-
-	/* SLI_MAC_PF_MBOX_INT for PF, SLI_PKT_MBOX_INT for VF. */
-	u8 __iomem *mbox_int_reg;
-
-	/* SLI_PKT_PF_VF_MBOX_SIG(0) for PF,
-	 * SLI_PKT_PF_VF_MBOX_SIG(1) for VF.
-	 */
-	u8 __iomem *mbox_write_reg;
-
-	/* SLI_PKT_PF_VF_MBOX_SIG(1) for PF,
-	 * SLI_PKT_PF_VF_MBOX_SIG(0) for VF.
-	 */
-	u8 __iomem *mbox_read_reg;
-
+	/* A mutex to protect access to this q_mbox. */
+	struct mutex lock;
+	u32 vf_id;
+	u32 config_data_index;
+	u32 message_len;
+	u8 __iomem *pf_vf_data_reg;
+	u8 __iomem *vf_pf_data_reg;
+	struct octep_pfvf_mbox_wk wk;
+	struct octep_device *oct;
 	struct octep_mbox_data mbox_data;
+	u8 config_data[MAX_VF_PF_MBOX_DATA_SIZE];
 };
 
 /* Tx/Rx queue vector per interrupt. */
@@ -193,6 +192,11 @@  struct octep_iface_link_info {
 	u8  oper_up;
 };
 
+/* The Octeon VF device specific info data structure.*/
+struct octep_pfvf_info {
+	u8 mac_addr[ETH_ALEN];
+};
+
 /* The Octeon device specific private data structure.
  * Each Octeon device has this structure to represent all its components.
  */
@@ -259,6 +263,8 @@  struct octep_device {
 
 	/* Mailbox to talk to VFs */
 	struct octep_mbox *mbox[OCTEP_MAX_VF];
+	/* VFs info */
+	struct octep_pfvf_info vf_info[OCTEP_MAX_VF];
 
 	/* Work entry to handle Tx timeout */
 	struct work_struct tx_timeout_task;
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c b/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c
new file mode 100644
index 000000000000..01ead735a2e8
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.c
@@ -0,0 +1,305 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Marvell Octeon EP (EndPoint) Ethernet Driver
+ *
+ * Copyright (C) 2020 Marvell.
+ *
+ */
+#include <linux/types.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/sched/signal.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+
+#include "octep_config.h"
+#include "octep_main.h"
+#include "octep_pfvf_mbox.h"
+#include "octep_ctrl_net.h"
+
+static void octep_pfvf_validate_version(struct octep_device *oct,  u32 vf_id,
+					union octep_pfvf_mbox_word cmd,
+					union octep_pfvf_mbox_word *rsp)
+{
+	u32 vf_version = (u32)cmd.s_version.version;
+
+	if (vf_version <= OCTEP_PF_MBOX_VERSION)
+		rsp->s_version.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+	else
+		rsp->s_version.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+}
+
+static void octep_pfvf_get_link_status(struct octep_device *oct, u32 vf_id,
+				       union octep_pfvf_mbox_word cmd,
+				       union octep_pfvf_mbox_word *rsp)
+{
+	int status;
+
+	status = octep_ctrl_net_get_link_status(oct, vf_id);
+	if (status < 0) {
+		rsp->s_link_status.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+		dev_err(&oct->pdev->dev, "Get VF link status failed via host control Mbox\n");
+		return;
+	}
+	rsp->s_link_status.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+	rsp->s_link_status.status = status;
+}
+
+static void octep_pfvf_set_link_status(struct octep_device *oct, u32 vf_id,
+				       union octep_pfvf_mbox_word cmd,
+				       union octep_pfvf_mbox_word *rsp)
+{
+	int err;
+
+	err = octep_ctrl_net_set_link_status(oct, vf_id, cmd.s_link_status.status, true);
+	if (err) {
+		rsp->s_link_status.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+		dev_err(&oct->pdev->dev, "Set VF link status failed via host control Mbox\n");
+		return;
+	}
+	rsp->s_link_status.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+static void octep_pfvf_set_rx_state(struct octep_device *oct, u32 vf_id,
+				    union octep_pfvf_mbox_word cmd,
+				    union octep_pfvf_mbox_word *rsp)
+{
+	int err;
+
+	err = octep_ctrl_net_set_rx_state(oct, vf_id, cmd.s_link_state.state, true);
+	if (err) {
+		rsp->s_link_state.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+		dev_err(&oct->pdev->dev, "Set VF Rx link state failed via host control Mbox\n");
+		return;
+	}
+	rsp->s_link_state.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+static void octep_pfvf_set_mtu(struct octep_device *oct, u32 vf_id,
+			       union octep_pfvf_mbox_word cmd,
+			       union octep_pfvf_mbox_word *rsp)
+{
+	int err;
+
+	err = octep_ctrl_net_set_mtu(oct, vf_id, cmd.s_set_mtu.mtu, true);
+	if (err) {
+		rsp->s_set_mtu.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+		dev_err(&oct->pdev->dev, "Set VF MTU failed via host control Mbox\n");
+		return;
+	}
+	rsp->s_set_mtu.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+static void octep_pfvf_set_mac_addr(struct octep_device *oct,  u32 vf_id,
+				    union octep_pfvf_mbox_word cmd,
+				    union octep_pfvf_mbox_word *rsp)
+{
+	int err;
+
+	err = octep_ctrl_net_set_mac_addr(oct, vf_id, cmd.s_set_mac.mac_addr, true);
+	if (err) {
+		rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+		dev_err(&oct->pdev->dev, "Set VF MAC address failed via host control Mbox\n");
+		return;
+	}
+	rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+static void octep_pfvf_get_mac_addr(struct octep_device *oct,  u32 vf_id,
+				    union octep_pfvf_mbox_word cmd,
+				    union octep_pfvf_mbox_word *rsp)
+{
+	int err;
+
+	err = octep_ctrl_net_get_mac_addr(oct, vf_id, rsp->s_set_mac.mac_addr);
+	if (err) {
+		rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+		dev_err(&oct->pdev->dev, "Get VF MAC address failed via host control Mbox\n");
+		return;
+	}
+	rsp->s_set_mac.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+}
+
+int octep_setup_pfvf_mbox(struct octep_device *oct)
+{
+	int i = 0, num_vfs = 0, rings_per_vf = 0;
+	int ring = 0;
+
+	num_vfs = oct->conf->sriov_cfg.active_vfs;
+	rings_per_vf = oct->conf->sriov_cfg.max_rings_per_vf;
+
+	for (i = 0; i < num_vfs; i++) {
+		ring  = rings_per_vf * i;
+		oct->mbox[ring] = vzalloc(sizeof(*oct->mbox[ring]));
+
+		if (!oct->mbox[ring])
+			goto free_mbox;
+
+		memset(oct->mbox[ring], 0, sizeof(struct octep_mbox));
+		mutex_init(&oct->mbox[ring]->lock);
+		INIT_WORK(&oct->mbox[ring]->wk.work, octep_pfvf_mbox_work);
+		oct->mbox[ring]->wk.ctxptr = oct->mbox[i];
+
+		if (!oct->mbox[i])
+			oct->mbox[ring]->wk.ctxptr = oct->mbox[ring];
+
+		oct->mbox[ring]->oct = oct;
+		oct->mbox[ring]->vf_id = i;
+		oct->hw_ops.setup_mbox_regs(oct, ring);
+	}
+	return 0;
+
+free_mbox:
+	while (i) {
+		i--;
+		ring  = rings_per_vf * i;
+		cancel_work_sync(&oct->mbox[ring]->wk.work);
+		mutex_destroy(&oct->mbox[ring]->lock);
+		vfree(oct->mbox[ring]);
+		oct->mbox[ring] = NULL;
+	}
+	return 1;
+}
+
+void octep_delete_pfvf_mbox(struct octep_device *oct)
+{
+	int rings_per_vf = oct->conf->sriov_cfg.max_rings_per_vf;
+	int num_vfs = oct->conf->sriov_cfg.active_vfs;
+	int i = 0, ring = 0, vf_srn = 0;
+
+	for (i = 0; i < num_vfs; i++) {
+		ring  = vf_srn + rings_per_vf * i;
+		if (!oct->mbox[ring])
+			continue;
+
+		if (work_pending(&oct->mbox[ring]->wk.work))
+			cancel_work_sync(&oct->mbox[ring]->wk.work);
+		vfree(oct->mbox[ring]);
+		oct->mbox[ring] = NULL;
+	}
+}
+
+static void octep_pfvf_pf_get_data(struct octep_device *oct,
+				   struct octep_mbox *mbox, int vf_id,
+				   union octep_pfvf_mbox_word cmd,
+				   union octep_pfvf_mbox_word *rsp)
+{
+	int length = 0;
+	int i = 0;
+	int err;
+	struct octep_iface_link_info link_info;
+	struct octep_iface_rx_stats rx_stats;
+	struct octep_iface_tx_stats tx_stats;
+
+	rsp->s_data.type = OCTEP_PFVF_MBOX_TYPE_RSP_ACK;
+
+	if (cmd.s_data.frag != OCTEP_PFVF_MBOX_MORE_FRAG_FLAG) {
+		mbox->config_data_index = 0;
+		memset(mbox->config_data, 0, MAX_VF_PF_MBOX_DATA_SIZE);
+		/* Based on the OPCODE CMD the PF driver
+		 * specific API should be called to fetch
+		 * the requested data
+		 */
+		switch (cmd.s.opcode) {
+		case OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO:
+			memset(&link_info, 0, sizeof(link_info));
+			err = octep_ctrl_net_get_link_info(oct, vf_id, &link_info);
+			if (!err) {
+				mbox->message_len = sizeof(link_info);
+				*((int32_t *)rsp->s_data.data) = mbox->message_len;
+				memcpy(mbox->config_data, (u8 *)&link_info, sizeof(link_info));
+			} else {
+				rsp->s_data.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+				return;
+			}
+			break;
+		case OCTEP_PFVF_MBOX_CMD_GET_STATS:
+			memset(&rx_stats, 0, sizeof(rx_stats));
+			memset(&tx_stats, 0, sizeof(tx_stats));
+			err = octep_ctrl_net_get_if_stats(oct, vf_id, &rx_stats, &tx_stats);
+			if (!err) {
+				mbox->message_len = sizeof(rx_stats) + sizeof(tx_stats);
+				*((int32_t *)rsp->s_data.data) = mbox->message_len;
+				memcpy(mbox->config_data, (u8 *)&rx_stats, sizeof(rx_stats));
+				memcpy(mbox->config_data + sizeof(rx_stats), (u8 *)&tx_stats,
+				       sizeof(tx_stats));
+
+			} else {
+				rsp->s_data.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+				return;
+			}
+			break;
+		}
+		*((int32_t *)rsp->s_data.data) = mbox->message_len;
+		return;
+	}
+
+	if (mbox->message_len > OCTEP_PFVF_MBOX_MAX_DATA_SIZE)
+		length = OCTEP_PFVF_MBOX_MAX_DATA_SIZE;
+	else
+		length = mbox->message_len;
+
+	mbox->message_len -= length;
+
+	for (i = 0; i < length; i++) {
+		rsp->s_data.data[i] =
+			mbox->config_data[mbox->config_data_index];
+		mbox->config_data_index++;
+	}
+}
+
+void octep_pfvf_mbox_work(struct work_struct *work)
+{
+	struct octep_pfvf_mbox_wk *wk = container_of(work, struct octep_pfvf_mbox_wk, work);
+	union octep_pfvf_mbox_word cmd = { 0 };
+	union octep_pfvf_mbox_word rsp = { 0 };
+	struct octep_mbox *mbox = NULL;
+	struct octep_device *oct = NULL;
+	int vf_id;
+
+	mbox = (struct octep_mbox *)wk->ctxptr;
+	oct = (struct octep_device *)mbox->oct;
+	vf_id = mbox->vf_id;
+
+	mutex_lock(&mbox->lock);
+	cmd.u64 = readq(mbox->vf_pf_data_reg);
+	rsp.u64 = 0;
+
+	switch (cmd.s.opcode) {
+	case OCTEP_PFVF_MBOX_CMD_VERSION:
+		octep_pfvf_validate_version(oct, vf_id, cmd, &rsp);
+		break;
+	case OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS:
+		octep_pfvf_get_link_status(oct, vf_id, cmd, &rsp);
+		break;
+	case OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS:
+		octep_pfvf_set_link_status(oct, vf_id, cmd, &rsp);
+		break;
+	case OCTEP_PFVF_MBOX_CMD_SET_RX_STATE:
+		octep_pfvf_set_rx_state(oct, vf_id, cmd, &rsp);
+		break;
+	case OCTEP_PFVF_MBOX_CMD_SET_MTU:
+		octep_pfvf_set_mtu(oct, vf_id, cmd, &rsp);
+		break;
+	case OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR:
+		octep_pfvf_set_mac_addr(oct, vf_id, cmd, &rsp);
+		break;
+	case OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR:
+		octep_pfvf_get_mac_addr(oct, vf_id, cmd, &rsp);
+		break;
+	case OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO:
+	case OCTEP_PFVF_MBOX_CMD_GET_STATS:
+		octep_pfvf_pf_get_data(oct, mbox, vf_id, cmd, &rsp);
+		break;
+	default:
+		dev_err(&oct->pdev->dev, "PF-VF mailbox: invalid opcode %d\n", cmd.s.opcode);
+		rsp.s.type = OCTEP_PFVF_MBOX_TYPE_RSP_NACK;
+		break;
+	}
+	writeq(rsp.u64, mbox->vf_pf_data_reg);
+	mutex_unlock(&mbox->lock);
+}
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.h b/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.h
new file mode 100644
index 000000000000..d113f1310655
--- /dev/null
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_pfvf_mbox.h
@@ -0,0 +1,126 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Marvell Octeon EP (EndPoint) Ethernet Driver
+ *
+ * Copyright (C) 2020 Marvell.
+ *
+ */
+#ifndef _OCTEP_PFVF_MBOX_H_
+#define _OCTEP_PFVF_MBOX_H_
+
+#define OCTEP_PF_MBOX_VERSION 1
+
+enum octep_pfvf_mbox_opcode {
+	OCTEP_PFVF_MBOX_CMD_VERSION,
+	OCTEP_PFVF_MBOX_CMD_SET_MTU,
+	OCTEP_PFVF_MBOX_CMD_SET_MAC_ADDR,
+	OCTEP_PFVF_MBOX_CMD_GET_MAC_ADDR,
+	OCTEP_PFVF_MBOX_CMD_GET_LINK_INFO,
+	OCTEP_PFVF_MBOX_CMD_GET_STATS,
+	OCTEP_PFVF_MBOX_CMD_SET_RX_STATE,
+	OCTEP_PFVF_MBOX_CMD_SET_LINK_STATUS,
+	OCTEP_PFVF_MBOX_CMD_GET_LINK_STATUS,
+	OCTEP_PFVF_MBOX_CMD_LAST,
+};
+
+enum octep_pfvf_mbox_word_type {
+	OCTEP_PFVF_MBOX_TYPE_CMD,
+	OCTEP_PFVF_MBOX_TYPE_RSP_ACK,
+	OCTEP_PFVF_MBOX_TYPE_RSP_NACK,
+};
+
+enum octep_pfvf_mbox_cmd_status {
+	OCTEP_PFVF_MBOX_CMD_STATUS_NOT_SETUP = 1,
+	OCTEP_PFVF_MBOX_CMD_STATUS_TIMEDOUT = 2,
+	OCTEP_PFVF_MBOX_CMD_STATUS_NACK = 3,
+	OCTEP_PFVF_MBOX_CMD_STATUS_BUSY = 4
+};
+
+enum octep_pfvf_mbox_state {
+	OCTEP_PFVF_MBOX_STATE_IDLE = 0,
+	OCTEP_PFVF_MBOX_STATE_BUSY = 1,
+};
+
+enum octep_pfvf_link_status {
+	OCTEP_PFVF_LINK_STATUS_DOWN,
+	OCTEP_PFVF_LINK_STATUS_UP,
+};
+
+enum octep_pfvf_link_speed {
+	OCTEP_PFVF_LINK_SPEED_NONE,
+	OCTEP_PFVF_LINK_SPEED_1000,
+	OCTEP_PFVF_LINK_SPEED_10000,
+	OCTEP_PFVF_LINK_SPEED_25000,
+	OCTEP_PFVF_LINK_SPEED_40000,
+	OCTEP_PFVF_LINK_SPEED_50000,
+	OCTEP_PFVF_LINK_SPEED_100000,
+	OCTEP_PFVF_LINK_SPEED_LAST,
+};
+
+enum octep_pfvf_link_duplex {
+	OCTEP_PFVF_LINK_HALF_DUPLEX,
+	OCTEP_PFVF_LINK_FULL_DUPLEX,
+};
+
+enum octep_pfvf_link_autoneg {
+	OCTEP_PFVF_LINK_AUTONEG,
+	OCTEP_PFVF_LINK_FIXED,
+};
+
+#define OCTEP_PFVF_MBOX_TIMEOUT_MS     500
+#define OCTEP_PFVF_MBOX_MAX_RETRIES    2
+#define OCTEP_PFVF_MBOX_VERSION        0
+#define OCTEP_PFVF_MBOX_MAX_DATA_SIZE  6
+#define OCTEP_PFVF_MBOX_MORE_FRAG_FLAG 1
+#define OCTEP_PFVF_MBOX_WRITE_WAIT_TIME msecs_to_jiffies(1)
+
+union octep_pfvf_mbox_word {
+	u64 u64;
+	struct {
+		u64 opcode:8;
+		u64 type:2;
+		u64 rsvd:6;
+		u64 data:48;
+	} s;
+	struct {
+		u64 opcode:8;
+		u64 type:2;
+		u64 frag:1;
+		u64 rsvd:5;
+		u8 data[6];
+	} s_data;
+	struct {
+		u64 opcode:8;
+		u64 type:2;
+		u64 rsvd:6;
+		u64 version:48;
+	} s_version;
+	struct {
+		u64 opcode:8;
+		u64 type:2;
+		u64 rsvd:6;
+		u8 mac_addr[6];
+	} s_set_mac;
+	struct {
+		u64 opcode:8;
+		u64 type:2;
+		u64 rsvd:6;
+		u64 mtu:48;
+	} s_set_mtu;
+	struct {
+		u64 opcode:8;
+		u64 type:2;
+		u64 state:1;
+		u64 rsvd:53;
+	} s_link_state;
+	struct {
+		u64 opcode:8;
+		u64 type:2;
+		u64 status:1;
+		u64 rsvd:53;
+	} s_link_status;
+} __packed;
+
+void octep_pfvf_mbox_work(struct work_struct *work);
+int octep_setup_pfvf_mbox(struct octep_device *oct);
+void octep_delete_pfvf_mbox(struct octep_device *oct);
+#endif
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h
index 0466fd9a002d..f29c4344fc41 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_regs_cn9k_pf.h
@@ -208,6 +208,9 @@ 
 #define    CN93_SDP_R_MBOX_PF_VF_INT_START        0x10220
 #define    CN93_SDP_R_MBOX_VF_PF_DATA_START       0x10230
 
+#define    CN93_SDP_MBOX_VF_PF_DATA_START       0x24000
+#define    CN93_SDP_MBOX_PF_VF_DATA_START       0x22000
+
 #define    CN93_SDP_R_MBOX_PF_VF_DATA(ring)		\
 	(CN93_SDP_R_MBOX_PF_VF_DATA_START + ((ring) * CN93_RING_OFFSET))
 
@@ -217,6 +220,12 @@ 
 #define    CN93_SDP_R_MBOX_VF_PF_DATA(ring)		\
 	(CN93_SDP_R_MBOX_VF_PF_DATA_START + ((ring) * CN93_RING_OFFSET))
 
+#define    CN93_SDP_MBOX_VF_PF_DATA(ring)          \
+	(CN93_SDP_MBOX_VF_PF_DATA_START + ((ring) * CN93_EPVF_RING_OFFSET))
+
+#define    CN93_SDP_MBOX_PF_VF_DATA(ring)      \
+	(CN93_SDP_MBOX_PF_VF_DATA_START + ((ring) * CN93_EPVF_RING_OFFSET))
+
 /* ##################### Interrupt Registers ########################## */
 #define	   CN93_SDP_R_ERR_TYPE_START	          0x10400
 
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h
index 2ef57980eb47..05788bf2cf08 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h
@@ -45,6 +45,18 @@  struct octep_tx_buffer {
 
 /* Hardware interface Tx statistics */
 struct octep_iface_tx_stats {
+	/* Total frames sent on the interface */
+	u64 pkts;
+
+	/* Total octets sent on the interface */
+	u64 octs;
+
+	/* Packets sent to a broadcast DMAC */
+	u64 bcst;
+
+	/* Packets sent to the multicast DMAC */
+	u64 mcst;
+
 	/* Packets dropped due to excessive collisions */
 	u64 xscol;
 
@@ -61,12 +73,6 @@  struct octep_iface_tx_stats {
 	 */
 	u64 scol;
 
-	/* Total octets sent on the interface */
-	u64 octs;
-
-	/* Total frames sent on the interface */
-	u64 pkts;
-
 	/* Packets sent with an octet count < 64 */
 	u64 hist_lt64;
 
@@ -91,12 +97,6 @@  struct octep_iface_tx_stats {
 	/* Packets sent with an octet count of > 1518 */
 	u64 hist_gt1518;
 
-	/* Packets sent to a broadcast DMAC */
-	u64 bcst;
-
-	/* Packets sent to the multicast DMAC */
-	u64 mcst;
-
 	/* Packets sent that experienced a transmit underflow and were
 	 * truncated
 	 */