[19/32] net/ngbe: add mailbox process operations

Message ID 20210908083758.312055-20-jiawenwu@trustnetic.com (mailing list archive)
State Changes Requested, archived
Delegated to: Ferruh Yigit
Headers
Series net/ngbe: add many features |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Jiawen Wu Sept. 8, 2021, 8:37 a.m. UTC
  Add check operation for vf function level reset,
mailbox messages and ack from vf.
Waiting to process the messages.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
 drivers/net/ngbe/base/ngbe.h       |   4 +
 drivers/net/ngbe/base/ngbe_dummy.h |  39 ++
 drivers/net/ngbe/base/ngbe_hw.c    | 215 +++++++++++
 drivers/net/ngbe/base/ngbe_hw.h    |   8 +
 drivers/net/ngbe/base/ngbe_mbx.c   | 297 +++++++++++++++
 drivers/net/ngbe/base/ngbe_mbx.h   |  78 ++++
 drivers/net/ngbe/base/ngbe_type.h  |  10 +
 drivers/net/ngbe/meson.build       |   2 +
 drivers/net/ngbe/ngbe_ethdev.c     |   7 +
 drivers/net/ngbe/ngbe_ethdev.h     |  13 +
 drivers/net/ngbe/ngbe_pf.c         | 564 +++++++++++++++++++++++++++++
 drivers/net/ngbe/rte_pmd_ngbe.h    |  39 ++
 12 files changed, 1276 insertions(+)
 create mode 100644 drivers/net/ngbe/rte_pmd_ngbe.h
  

Comments

Ferruh Yigit Sept. 15, 2021, 4:56 p.m. UTC | #1
On 9/8/2021 9:37 AM, Jiawen Wu wrote:
> Add check operation for vf function level reset,
> mailbox messages and ack from vf.
> Waiting to process the messages.
> 
> Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>

<...>

> --- a/drivers/net/ngbe/meson.build
> +++ b/drivers/net/ngbe/meson.build
> @@ -20,3 +20,5 @@ sources = files(
>  deps += ['hash']
>  
>  includes += include_directories('base')
> +
> +install_headers('rte_pmd_ngbe.h')

Why installing this header?

Normally it is not expected drivers to have public headers, only some PMDs has
public APIs (we call them PMD specific APIs) but that is not somehting we want.

For this case why driver needs public symbols, can you please describe?
  

Patch

diff --git a/drivers/net/ngbe/base/ngbe.h b/drivers/net/ngbe/base/ngbe.h
index fe85b07b57..1d17c2f115 100644
--- a/drivers/net/ngbe/base/ngbe.h
+++ b/drivers/net/ngbe/base/ngbe.h
@@ -6,6 +6,10 @@ 
 #define _NGBE_H_
 
 #include "ngbe_type.h"
+#include "ngbe_mng.h"
+#include "ngbe_mbx.h"
+#include "ngbe_eeprom.h"
+#include "ngbe_phy.h"
 #include "ngbe_hw.h"
 
 #endif /* _NGBE_H_ */
diff --git a/drivers/net/ngbe/base/ngbe_dummy.h b/drivers/net/ngbe/base/ngbe_dummy.h
index 5cb09bfcaa..940b448734 100644
--- a/drivers/net/ngbe/base/ngbe_dummy.h
+++ b/drivers/net/ngbe/base/ngbe_dummy.h
@@ -136,6 +136,16 @@  static inline s32 ngbe_mac_clear_vfta_dummy(struct ngbe_hw *TUP0)
 {
 	return NGBE_ERR_OPS_DUMMY;
 }
+static inline s32 ngbe_mac_set_vfta_dummy(struct ngbe_hw *TUP0, u32 TUP1,
+					u32 TUP2, bool TUP3, bool TUP4)
+{
+	return NGBE_ERR_OPS_DUMMY;
+}
+static inline s32 ngbe_mac_set_vlvf_dummy(struct ngbe_hw *TUP0, u32 TUP1,
+			u32 TUP2, bool TUP3, u32 *TUP4, u32 TUP5, bool TUP6)
+{
+	return NGBE_ERR_OPS_DUMMY;
+}
 static inline void ngbe_mac_set_mac_anti_spoofing_dummy(struct ngbe_hw *TUP0,
 					bool TUP1, int TUP2)
 {
@@ -200,6 +210,28 @@  static inline s32 ngbe_phy_check_link_dummy(struct ngbe_hw *TUP0, u32 *TUP1,
 static inline void ngbe_mbx_init_params_dummy(struct ngbe_hw *TUP0)
 {
 }
+static inline s32 ngbe_mbx_read_dummy(struct ngbe_hw *TUP0, u32 *TUP1,
+					u16 TUP2, u16 TUP3)
+{
+	return NGBE_ERR_OPS_DUMMY;
+}
+static inline s32 ngbe_mbx_write_dummy(struct ngbe_hw *TUP0, u32 *TUP1,
+					u16 TUP2, u16 TUP3)
+{
+	return NGBE_ERR_OPS_DUMMY;
+}
+static inline s32 ngbe_mbx_check_for_msg_dummy(struct ngbe_hw *TUP0, u16 TUP1)
+{
+	return NGBE_ERR_OPS_DUMMY;
+}
+static inline s32 ngbe_mbx_check_for_ack_dummy(struct ngbe_hw *TUP0, u16 TUP1)
+{
+	return NGBE_ERR_OPS_DUMMY;
+}
+static inline s32 ngbe_mbx_check_for_rst_dummy(struct ngbe_hw *TUP0, u16 TUP1)
+{
+	return NGBE_ERR_OPS_DUMMY;
+}
 
 static inline void ngbe_init_ops_dummy(struct ngbe_hw *hw)
 {
@@ -228,6 +260,8 @@  static inline void ngbe_init_ops_dummy(struct ngbe_hw *hw)
 	hw->mac.init_rx_addrs = ngbe_mac_init_rx_addrs_dummy;
 	hw->mac.update_mc_addr_list = ngbe_mac_update_mc_addr_list_dummy;
 	hw->mac.clear_vfta = ngbe_mac_clear_vfta_dummy;
+	hw->mac.set_vfta = ngbe_mac_set_vfta_dummy;
+	hw->mac.set_vlvf = ngbe_mac_set_vlvf_dummy;
 	hw->mac.set_mac_anti_spoofing = ngbe_mac_set_mac_anti_spoofing_dummy;
 	hw->mac.set_vlan_anti_spoofing = ngbe_mac_set_vlan_anti_spoofing_dummy;
 	hw->mac.init_thermal_sensor_thresh = ngbe_mac_init_thermal_ssth_dummy;
@@ -242,6 +276,11 @@  static inline void ngbe_init_ops_dummy(struct ngbe_hw *hw)
 	hw->phy.setup_link = ngbe_phy_setup_link_dummy;
 	hw->phy.check_link = ngbe_phy_check_link_dummy;
 	hw->mbx.init_params = ngbe_mbx_init_params_dummy;
+	hw->mbx.read = ngbe_mbx_read_dummy;
+	hw->mbx.write = ngbe_mbx_write_dummy;
+	hw->mbx.check_for_msg = ngbe_mbx_check_for_msg_dummy;
+	hw->mbx.check_for_ack = ngbe_mbx_check_for_ack_dummy;
+	hw->mbx.check_for_rst = ngbe_mbx_check_for_rst_dummy;
 }
 
 #endif /* _NGBE_TYPE_DUMMY_H_ */
diff --git a/drivers/net/ngbe/base/ngbe_hw.c b/drivers/net/ngbe/base/ngbe_hw.c
index 8b45a91f78..afde58a89e 100644
--- a/drivers/net/ngbe/base/ngbe_hw.c
+++ b/drivers/net/ngbe/base/ngbe_hw.c
@@ -914,6 +914,214 @@  s32 ngbe_init_uta_tables(struct ngbe_hw *hw)
 	return 0;
 }
 
+/**
+ *  ngbe_find_vlvf_slot - find the vlanid or the first empty slot
+ *  @hw: pointer to hardware structure
+ *  @vlan: VLAN id to write to VLAN filter
+ *  @vlvf_bypass: true to find vlanid only, false returns first empty slot if
+ *		  vlanid not found
+ *
+ *
+ *  return the VLVF index where this VLAN id should be placed
+ *
+ **/
+s32 ngbe_find_vlvf_slot(struct ngbe_hw *hw, u32 vlan, bool vlvf_bypass)
+{
+	s32 regindex, first_empty_slot;
+	u32 bits;
+
+	/* short cut the special case */
+	if (vlan == 0)
+		return 0;
+
+	/* if vlvf_bypass is set we don't want to use an empty slot, we
+	 * will simply bypass the VLVF if there are no entries present in the
+	 * VLVF that contain our VLAN
+	 */
+	first_empty_slot = vlvf_bypass ? NGBE_ERR_NO_SPACE : 0;
+
+	/* add VLAN enable bit for comparison */
+	vlan |= NGBE_PSRVLAN_EA;
+
+	/* Search for the vlan id in the VLVF entries. Save off the first empty
+	 * slot found along the way.
+	 *
+	 * pre-decrement loop covering (NGBE_NUM_POOL - 1) .. 1
+	 */
+	for (regindex = NGBE_NUM_POOL; --regindex;) {
+		wr32(hw, NGBE_PSRVLANIDX, regindex);
+		bits = rd32(hw, NGBE_PSRVLAN);
+		if (bits == vlan)
+			return regindex;
+		if (!first_empty_slot && !bits)
+			first_empty_slot = regindex;
+	}
+
+	/* If we are here then we didn't find the VLAN.  Return first empty
+	 * slot we found during our search, else error.
+	 */
+	if (!first_empty_slot)
+		DEBUGOUT("No space in VLVF.\n");
+
+	return first_empty_slot ? first_empty_slot : NGBE_ERR_NO_SPACE;
+}
+
+/**
+ *  ngbe_set_vfta - Set VLAN filter table
+ *  @hw: pointer to hardware structure
+ *  @vlan: VLAN id to write to VLAN filter
+ *  @vind: VMDq output index that maps queue to VLAN id in VLVFB
+ *  @vlan_on: boolean flag to turn on/off VLAN
+ *  @vlvf_bypass: boolean flag indicating updating default pool is okay
+ *
+ *  Turn on/off specified VLAN in the VLAN filter table.
+ **/
+s32 ngbe_set_vfta(struct ngbe_hw *hw, u32 vlan, u32 vind,
+			   bool vlan_on, bool vlvf_bypass)
+{
+	u32 regidx, vfta_delta, vfta;
+	s32 err;
+
+	DEBUGFUNC("ngbe_set_vfta");
+
+	if (vlan > 4095 || vind > 63)
+		return NGBE_ERR_PARAM;
+
+	/*
+	 * this is a 2 part operation - first the VFTA, then the
+	 * VLVF and VLVFB if VT Mode is set
+	 * We don't write the VFTA until we know the VLVF part succeeded.
+	 */
+
+	/* Part 1
+	 * The VFTA is a bitstring made up of 128 32-bit registers
+	 * that enable the particular VLAN id, much like the MTA:
+	 *    bits[11-5]: which register
+	 *    bits[4-0]:  which bit in the register
+	 */
+	regidx = vlan / 32;
+	vfta_delta = 1 << (vlan % 32);
+	vfta = rd32(hw, NGBE_VLANTBL(regidx));
+
+	/*
+	 * vfta_delta represents the difference between the current value
+	 * of vfta and the value we want in the register.  Since the diff
+	 * is an XOR mask we can just update the vfta using an XOR
+	 */
+	vfta_delta &= vlan_on ? ~vfta : vfta;
+	vfta ^= vfta_delta;
+
+	/* Part 2
+	 * Call ngbe_set_vlvf to set VLVFB and VLVF
+	 */
+	err = ngbe_set_vlvf(hw, vlan, vind, vlan_on, &vfta_delta,
+					 vfta, vlvf_bypass);
+	if (err != 0) {
+		if (vlvf_bypass)
+			goto vfta_update;
+		return err;
+	}
+
+vfta_update:
+	/* Update VFTA now that we are ready for traffic */
+	if (vfta_delta)
+		wr32(hw, NGBE_VLANTBL(regidx), vfta);
+
+	return 0;
+}
+
+/**
+ *  ngbe_set_vlvf - Set VLAN Pool Filter
+ *  @hw: pointer to hardware structure
+ *  @vlan: VLAN id to write to VLAN filter
+ *  @vind: VMDq output index that maps queue to VLAN id in PSRVLANPLM
+ *  @vlan_on: boolean flag to turn on/off VLAN in PSRVLAN
+ *  @vfta_delta: pointer to the difference between the current value
+ *		 of PSRVLANPLM and the desired value
+ *  @vfta: the desired value of the VFTA
+ *  @vlvf_bypass: boolean flag indicating updating default pool is okay
+ *
+ *  Turn on/off specified bit in VLVF table.
+ **/
+s32 ngbe_set_vlvf(struct ngbe_hw *hw, u32 vlan, u32 vind,
+			   bool vlan_on, u32 *vfta_delta, u32 vfta,
+			   bool vlvf_bypass)
+{
+	u32 bits;
+	u32 portctl;
+	s32 vlvf_index;
+
+	DEBUGFUNC("ngbe_set_vlvf");
+
+	if (vlan > 4095 || vind > 63)
+		return NGBE_ERR_PARAM;
+
+	/* If VT Mode is set
+	 *   Either vlan_on
+	 *     make sure the vlan is in PSRVLAN
+	 *     set the vind bit in the matching PSRVLANPLM
+	 *   Or !vlan_on
+	 *     clear the pool bit and possibly the vind
+	 */
+	portctl = rd32(hw, NGBE_PORTCTL);
+	if (!(portctl & NGBE_PORTCTL_NUMVT_MASK))
+		return 0;
+
+	vlvf_index = ngbe_find_vlvf_slot(hw, vlan, vlvf_bypass);
+	if (vlvf_index < 0)
+		return vlvf_index;
+
+	wr32(hw, NGBE_PSRVLANIDX, vlvf_index);
+	bits = rd32(hw, NGBE_PSRVLANPLM(vind / 32));
+
+	/* set the pool bit */
+	bits |= 1 << (vind % 32);
+	if (vlan_on)
+		goto vlvf_update;
+
+	/* clear the pool bit */
+	bits ^= 1 << (vind % 32);
+
+	if (!bits &&
+	    !rd32(hw, NGBE_PSRVLANPLM(vind / 32))) {
+		/* Clear PSRVLANPLM first, then disable PSRVLAN. Otherwise
+		 * we run the risk of stray packets leaking into
+		 * the PF via the default pool
+		 */
+		if (*vfta_delta)
+			wr32(hw, NGBE_PSRVLANPLM(vlan / 32), vfta);
+
+		/* disable VLVF and clear remaining bit from pool */
+		wr32(hw, NGBE_PSRVLAN, 0);
+		wr32(hw, NGBE_PSRVLANPLM(vind / 32), 0);
+
+		return 0;
+	}
+
+	/* If there are still bits set in the PSRVLANPLM registers
+	 * for the VLAN ID indicated we need to see if the
+	 * caller is requesting that we clear the PSRVLANPLM entry bit.
+	 * If the caller has requested that we clear the PSRVLANPLM
+	 * entry bit but there are still pools/VFs using this VLAN
+	 * ID entry then ignore the request.  We're not worried
+	 * about the case where we're turning the PSRVLANPLM VLAN ID
+	 * entry bit on, only when requested to turn it off as
+	 * there may be multiple pools and/or VFs using the
+	 * VLAN ID entry.  In that case we cannot clear the
+	 * PSRVLANPLM bit until all pools/VFs using that VLAN ID have also
+	 * been cleared.  This will be indicated by "bits" being
+	 * zero.
+	 */
+	*vfta_delta = 0;
+
+vlvf_update:
+	/* record pool change and enable VLAN ID if not already enabled */
+	wr32(hw, NGBE_PSRVLANPLM(vind / 32), bits);
+	wr32(hw, NGBE_PSRVLAN, NGBE_PSRVLAN_EA | vlan);
+
+	return 0;
+}
+
 /**
  *  ngbe_clear_vfta - Clear VLAN filter table
  *  @hw: pointer to hardware structure
@@ -1306,6 +1514,8 @@  s32 ngbe_init_ops_pf(struct ngbe_hw *hw)
 	mac->update_mc_addr_list = ngbe_update_mc_addr_list;
 	mac->set_vmdq = ngbe_set_vmdq;
 	mac->clear_vmdq = ngbe_clear_vmdq;
+	mac->set_vfta = ngbe_set_vfta;
+	mac->set_vlvf = ngbe_set_vlvf;
 	mac->clear_vfta = ngbe_clear_vfta;
 	mac->set_mac_anti_spoofing = ngbe_set_mac_anti_spoofing;
 	mac->set_vlan_anti_spoofing = ngbe_set_vlan_anti_spoofing;
@@ -1320,6 +1530,11 @@  s32 ngbe_init_ops_pf(struct ngbe_hw *hw)
 	mac->check_overtemp = ngbe_mac_check_overtemp;
 
 	mbx->init_params = ngbe_init_mbx_params_pf;
+	mbx->read = ngbe_read_mbx_pf;
+	mbx->write = ngbe_write_mbx_pf;
+	mbx->check_for_msg = ngbe_check_for_msg_pf;
+	mbx->check_for_ack = ngbe_check_for_ack_pf;
+	mbx->check_for_rst = ngbe_check_for_rst_pf;
 
 	/* EEPROM */
 	rom->init_params = ngbe_init_eeprom_params;
diff --git a/drivers/net/ngbe/base/ngbe_hw.h b/drivers/net/ngbe/base/ngbe_hw.h
index a27bd3e650..83ad646dde 100644
--- a/drivers/net/ngbe/base/ngbe_hw.h
+++ b/drivers/net/ngbe/base/ngbe_hw.h
@@ -49,8 +49,16 @@  void ngbe_release_swfw_sync(struct ngbe_hw *hw, u32 mask);
 s32 ngbe_set_vmdq(struct ngbe_hw *hw, u32 rar, u32 vmdq);
 s32 ngbe_clear_vmdq(struct ngbe_hw *hw, u32 rar, u32 vmdq);
 s32 ngbe_init_uta_tables(struct ngbe_hw *hw);
+s32 ngbe_set_vfta(struct ngbe_hw *hw, u32 vlan,
+			 u32 vind, bool vlan_on, bool vlvf_bypass);
+s32 ngbe_set_vlvf(struct ngbe_hw *hw, u32 vlan, u32 vind,
+			   bool vlan_on, u32 *vfta_delta, u32 vfta,
+			   bool vlvf_bypass);
 s32 ngbe_clear_vfta(struct ngbe_hw *hw);
+s32 ngbe_find_vlvf_slot(struct ngbe_hw *hw, u32 vlan, bool vlvf_bypass);
 
+void ngbe_set_mac_anti_spoofing(struct ngbe_hw *hw, bool enable, int vf);
+void ngbe_set_vlan_anti_spoofing(struct ngbe_hw *hw, bool enable, int vf);
 s32 ngbe_init_thermal_sensor_thresh(struct ngbe_hw *hw);
 s32 ngbe_mac_check_overtemp(struct ngbe_hw *hw);
 void ngbe_disable_rx(struct ngbe_hw *hw);
diff --git a/drivers/net/ngbe/base/ngbe_mbx.c b/drivers/net/ngbe/base/ngbe_mbx.c
index 1ac9531ceb..764ae81319 100644
--- a/drivers/net/ngbe/base/ngbe_mbx.c
+++ b/drivers/net/ngbe/base/ngbe_mbx.c
@@ -7,6 +7,303 @@ 
 
 #include "ngbe_mbx.h"
 
+/**
+ *  ngbe_read_mbx - Reads a message from the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to read
+ *
+ *  returns 0 if it successfully read message from buffer
+ **/
+s32 ngbe_read_mbx(struct ngbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+	struct ngbe_mbx_info *mbx = &hw->mbx;
+	s32 ret_val = NGBE_ERR_MBX;
+
+	DEBUGFUNC("ngbe_read_mbx");
+
+	/* limit read to size of mailbox */
+	if (size > mbx->size)
+		size = mbx->size;
+
+	if (mbx->read)
+		ret_val = mbx->read(hw, msg, size, mbx_id);
+
+	return ret_val;
+}
+
+/**
+ *  ngbe_write_mbx - Write a message to the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns 0 if it successfully copied message into the buffer
+ **/
+s32 ngbe_write_mbx(struct ngbe_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+	struct ngbe_mbx_info *mbx = &hw->mbx;
+	s32 ret_val = 0;
+
+	DEBUGFUNC("ngbe_write_mbx");
+
+	if (size > mbx->size) {
+		ret_val = NGBE_ERR_MBX;
+		DEBUGOUT("Invalid mailbox message size %d", size);
+	} else if (mbx->write) {
+		ret_val = mbx->write(hw, msg, size, mbx_id);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  ngbe_check_for_msg - checks to see if someone sent us mail
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns 0 if the Status bit was found or else ERR_MBX
+ **/
+s32 ngbe_check_for_msg(struct ngbe_hw *hw, u16 mbx_id)
+{
+	struct ngbe_mbx_info *mbx = &hw->mbx;
+	s32 ret_val = NGBE_ERR_MBX;
+
+	DEBUGFUNC("ngbe_check_for_msg");
+
+	if (mbx->check_for_msg)
+		ret_val = mbx->check_for_msg(hw, mbx_id);
+
+	return ret_val;
+}
+
+/**
+ *  ngbe_check_for_ack - checks to see if someone sent us ACK
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns 0 if the Status bit was found or else ERR_MBX
+ **/
+s32 ngbe_check_for_ack(struct ngbe_hw *hw, u16 mbx_id)
+{
+	struct ngbe_mbx_info *mbx = &hw->mbx;
+	s32 ret_val = NGBE_ERR_MBX;
+
+	DEBUGFUNC("ngbe_check_for_ack");
+
+	if (mbx->check_for_ack)
+		ret_val = mbx->check_for_ack(hw, mbx_id);
+
+	return ret_val;
+}
+
+/**
+ *  ngbe_check_for_rst - checks to see if other side has reset
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns 0 if the Status bit was found or else ERR_MBX
+ **/
+s32 ngbe_check_for_rst(struct ngbe_hw *hw, u16 mbx_id)
+{
+	struct ngbe_mbx_info *mbx = &hw->mbx;
+	s32 ret_val = NGBE_ERR_MBX;
+
+	DEBUGFUNC("ngbe_check_for_rst");
+
+	if (mbx->check_for_rst)
+		ret_val = mbx->check_for_rst(hw, mbx_id);
+
+	return ret_val;
+}
+
+STATIC s32 ngbe_check_for_bit_pf(struct ngbe_hw *hw, u32 mask)
+{
+	u32 mbvficr = rd32(hw, NGBE_MBVFICR);
+	s32 ret_val = NGBE_ERR_MBX;
+
+	if (mbvficr & mask) {
+		ret_val = 0;
+		wr32(hw, NGBE_MBVFICR, mask);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  ngbe_check_for_msg_pf - checks to see if the VF has sent mail
+ *  @hw: pointer to the HW structure
+ *  @vf_number: the VF index
+ *
+ *  returns 0 if the VF has set the Status bit or else ERR_MBX
+ **/
+s32 ngbe_check_for_msg_pf(struct ngbe_hw *hw, u16 vf_number)
+{
+	s32 ret_val = NGBE_ERR_MBX;
+	u32 vf_bit = vf_number;
+
+	DEBUGFUNC("ngbe_check_for_msg_pf");
+
+	if (!ngbe_check_for_bit_pf(hw, NGBE_MBVFICR_VFREQ_VF1 << vf_bit)) {
+		ret_val = 0;
+		hw->mbx.stats.reqs++;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  ngbe_check_for_ack_pf - checks to see if the VF has ACKed
+ *  @hw: pointer to the HW structure
+ *  @vf_number: the VF index
+ *
+ *  returns 0 if the VF has set the Status bit or else ERR_MBX
+ **/
+s32 ngbe_check_for_ack_pf(struct ngbe_hw *hw, u16 vf_number)
+{
+	s32 ret_val = NGBE_ERR_MBX;
+	u32 vf_bit = vf_number;
+
+	DEBUGFUNC("ngbe_check_for_ack_pf");
+
+	if (!ngbe_check_for_bit_pf(hw, NGBE_MBVFICR_VFACK_VF1 << vf_bit)) {
+		ret_val = 0;
+		hw->mbx.stats.acks++;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  ngbe_check_for_rst_pf - checks to see if the VF has reset
+ *  @hw: pointer to the HW structure
+ *  @vf_number: the VF index
+ *
+ *  returns 0 if the VF has set the Status bit or else ERR_MBX
+ **/
+s32 ngbe_check_for_rst_pf(struct ngbe_hw *hw, u16 vf_number)
+{
+	u32 vflre = 0;
+	s32 ret_val = NGBE_ERR_MBX;
+
+	DEBUGFUNC("ngbe_check_for_rst_pf");
+
+	vflre = rd32(hw, NGBE_FLRVFE);
+	if (vflre & (1 << vf_number)) {
+		ret_val = 0;
+		wr32(hw, NGBE_FLRVFEC, (1 << vf_number));
+		hw->mbx.stats.rsts++;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  ngbe_obtain_mbx_lock_pf - obtain mailbox lock
+ *  @hw: pointer to the HW structure
+ *  @vf_number: the VF index
+ *
+ *  return 0 if we obtained the mailbox lock
+ **/
+STATIC s32 ngbe_obtain_mbx_lock_pf(struct ngbe_hw *hw, u16 vf_number)
+{
+	s32 ret_val = NGBE_ERR_MBX;
+	u32 p2v_mailbox;
+
+	DEBUGFUNC("ngbe_obtain_mbx_lock_pf");
+
+	/* Take ownership of the buffer */
+	wr32(hw, NGBE_MBCTL(vf_number), NGBE_MBCTL_PFU);
+
+	/* reserve mailbox for vf use */
+	p2v_mailbox = rd32(hw, NGBE_MBCTL(vf_number));
+	if (p2v_mailbox & NGBE_MBCTL_PFU)
+		ret_val = 0;
+	else
+		DEBUGOUT("Failed to obtain mailbox lock for VF%d", vf_number);
+
+
+	return ret_val;
+}
+
+/**
+ *  ngbe_write_mbx_pf - Places a message in the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @vf_number: the VF index
+ *
+ *  returns 0 if it successfully copied message into the buffer
+ **/
+s32 ngbe_write_mbx_pf(struct ngbe_hw *hw, u32 *msg, u16 size, u16 vf_number)
+{
+	s32 ret_val;
+	u16 i;
+
+	DEBUGFUNC("ngbe_write_mbx_pf");
+
+	/* lock the mailbox to prevent pf/vf race condition */
+	ret_val = ngbe_obtain_mbx_lock_pf(hw, vf_number);
+	if (ret_val)
+		goto out_no_write;
+
+	/* flush msg and acks as we are overwriting the message buffer */
+	ngbe_check_for_msg_pf(hw, vf_number);
+	ngbe_check_for_ack_pf(hw, vf_number);
+
+	/* copy the caller specified message to the mailbox memory buffer */
+	for (i = 0; i < size; i++)
+		wr32a(hw, NGBE_MBMEM(vf_number), i, msg[i]);
+
+	/* Interrupt VF to tell it a message has been sent and release buffer*/
+	wr32(hw, NGBE_MBCTL(vf_number), NGBE_MBCTL_STS);
+
+	/* update stats */
+	hw->mbx.stats.msgs_tx++;
+
+out_no_write:
+	return ret_val;
+}
+
+/**
+ *  ngbe_read_mbx_pf - Read a message from the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @vf_number: the VF index
+ *
+ *  This function copies a message from the mailbox buffer to the caller's
+ *  memory buffer.  The presumption is that the caller knows that there was
+ *  a message due to a VF request so no polling for message is needed.
+ **/
+s32 ngbe_read_mbx_pf(struct ngbe_hw *hw, u32 *msg, u16 size, u16 vf_number)
+{
+	s32 ret_val;
+	u16 i;
+
+	DEBUGFUNC("ngbe_read_mbx_pf");
+
+	/* lock the mailbox to prevent pf/vf race condition */
+	ret_val = ngbe_obtain_mbx_lock_pf(hw, vf_number);
+	if (ret_val)
+		goto out_no_read;
+
+	/* copy the message to the mailbox memory buffer */
+	for (i = 0; i < size; i++)
+		msg[i] = rd32a(hw, NGBE_MBMEM(vf_number), i);
+
+	/* Acknowledge the message and release buffer */
+	wr32(hw, NGBE_MBCTL(vf_number), NGBE_MBCTL_ACK);
+
+	/* update stats */
+	hw->mbx.stats.msgs_rx++;
+
+out_no_read:
+	return ret_val;
+}
+
 /**
  *  ngbe_init_mbx_params_pf - set initial values for pf mailbox
  *  @hw: pointer to the HW structure
diff --git a/drivers/net/ngbe/base/ngbe_mbx.h b/drivers/net/ngbe/base/ngbe_mbx.h
index d280945baf..d47da2718c 100644
--- a/drivers/net/ngbe/base/ngbe_mbx.h
+++ b/drivers/net/ngbe/base/ngbe_mbx.h
@@ -6,6 +6,84 @@ 
 #ifndef _NGBE_MBX_H_
 #define _NGBE_MBX_H_
 
+#define NGBE_ERR_MBX		-100
+
+/* If it's a NGBE_VF_* msg then it originates in the VF and is sent to the
+ * PF.  The reverse is true if it is NGBE_PF_*.
+ * Message ACK's are the value or'd with 0xF0000000
+ */
+/* Messages below or'd with this are the ACK */
+#define NGBE_VT_MSGTYPE_ACK	0x80000000
+/* Messages below or'd with this are the NACK */
+#define NGBE_VT_MSGTYPE_NACK	0x40000000
+/* Indicates that VF is still clear to send requests */
+#define NGBE_VT_MSGTYPE_CTS	0x20000000
+
+#define NGBE_VT_MSGINFO_SHIFT	16
+/* bits 23:16 are used for extra info for certain messages */
+#define NGBE_VT_MSGINFO_MASK	(0xFF << NGBE_VT_MSGINFO_SHIFT)
+
+/*
+ * each element denotes a version of the API; existing numbers may not
+ * change; any additions must go at the end
+ */
+enum ngbe_pfvf_api_rev {
+	ngbe_mbox_api_null,
+	ngbe_mbox_api_10,	/* API version 1.0, linux/freebsd VF driver */
+	ngbe_mbox_api_11,	/* API version 1.1, linux/freebsd VF driver */
+	ngbe_mbox_api_12,	/* API version 1.2, linux/freebsd VF driver */
+	ngbe_mbox_api_13,	/* API version 1.3, linux/freebsd VF driver */
+	ngbe_mbox_api_20,	/* API version 2.0, solaris Phase1 VF driver */
+	/* This value should always be last */
+	ngbe_mbox_api_unknown,	/* indicates that API version is not known */
+};
+
+/* mailbox API, legacy requests */
+#define NGBE_VF_RESET		0x01 /* VF requests reset */
+#define NGBE_VF_SET_MAC_ADDR	0x02 /* VF requests PF to set MAC addr */
+#define NGBE_VF_SET_MULTICAST	0x03 /* VF requests PF to set MC addr */
+#define NGBE_VF_SET_VLAN	0x04 /* VF requests PF to set VLAN */
+
+/* mailbox API, version 1.0 VF requests */
+#define NGBE_VF_SET_LPE	0x05 /* VF requests PF to set VMOLR.LPE */
+#define NGBE_VF_SET_MACVLAN	0x06 /* VF requests PF for unicast filter */
+#define NGBE_VF_API_NEGOTIATE	0x08 /* negotiate API version */
+
+/* mailbox API, version 1.1 VF requests */
+#define NGBE_VF_GET_QUEUES	0x09 /* get queue configuration */
+
+/* mailbox API, version 1.2 VF requests */
+#define NGBE_VF_GET_RETA      0x0a    /* VF request for RETA */
+#define NGBE_VF_GET_RSS_KEY	0x0b    /* get RSS key */
+#define NGBE_VF_UPDATE_XCAST_MODE	0x0c
+
+/* mode choices for NGBE_VF_UPDATE_XCAST_MODE */
+enum ngbevf_xcast_modes {
+	NGBEVF_XCAST_MODE_NONE = 0,
+	NGBEVF_XCAST_MODE_MULTI,
+	NGBEVF_XCAST_MODE_ALLMULTI,
+	NGBEVF_XCAST_MODE_PROMISC,
+};
+
+/* GET_QUEUES return data indices within the mailbox */
+#define NGBE_VF_TX_QUEUES	1	/* number of Tx queues supported */
+#define NGBE_VF_RX_QUEUES	2	/* number of Rx queues supported */
+#define NGBE_VF_TRANS_VLAN	3	/* Indication of port vlan */
+#define NGBE_VF_DEF_QUEUE	4	/* Default queue offset */
+
+/* length of permanent address message returned from PF */
+#define NGBE_VF_PERMADDR_MSG_LEN	4
+s32 ngbe_read_mbx(struct ngbe_hw *hw, u32 *msg, u16 size, u16 mbx_id);
+s32 ngbe_write_mbx(struct ngbe_hw *hw, u32 *msg, u16 size, u16 mbx_id);
+s32 ngbe_check_for_msg(struct ngbe_hw *hw, u16 mbx_id);
+s32 ngbe_check_for_ack(struct ngbe_hw *hw, u16 mbx_id);
+s32 ngbe_check_for_rst(struct ngbe_hw *hw, u16 mbx_id);
 void ngbe_init_mbx_params_pf(struct ngbe_hw *hw);
 
+s32 ngbe_read_mbx_pf(struct ngbe_hw *hw, u32 *msg, u16 size, u16 vf_number);
+s32 ngbe_write_mbx_pf(struct ngbe_hw *hw, u32 *msg, u16 size, u16 vf_number);
+s32 ngbe_check_for_msg_pf(struct ngbe_hw *hw, u16 vf_number);
+s32 ngbe_check_for_ack_pf(struct ngbe_hw *hw, u16 vf_number);
+s32 ngbe_check_for_rst_pf(struct ngbe_hw *hw, u16 vf_number);
+
 #endif /* _NGBE_MBX_H_ */
diff --git a/drivers/net/ngbe/base/ngbe_type.h b/drivers/net/ngbe/base/ngbe_type.h
index bc95fcf609..7a85f82abd 100644
--- a/drivers/net/ngbe/base/ngbe_type.h
+++ b/drivers/net/ngbe/base/ngbe_type.h
@@ -254,6 +254,11 @@  struct ngbe_mac_info {
 				      u32 mc_addr_count,
 				      ngbe_mc_addr_itr func, bool clear);
 	s32 (*clear_vfta)(struct ngbe_hw *hw);
+	s32 (*set_vfta)(struct ngbe_hw *hw, u32 vlan,
+			 u32 vind, bool vlan_on, bool vlvf_bypass);
+	s32 (*set_vlvf)(struct ngbe_hw *hw, u32 vlan, u32 vind,
+			   bool vlan_on, u32 *vfta_delta, u32 vfta,
+			   bool vlvf_bypass);
 	void (*set_mac_anti_spoofing)(struct ngbe_hw *hw, bool enable, int vf);
 	void (*set_vlan_anti_spoofing)(struct ngbe_hw *hw,
 					bool enable, int vf);
@@ -319,6 +324,11 @@  struct ngbe_mbx_stats {
 
 struct ngbe_mbx_info {
 	void (*init_params)(struct ngbe_hw *hw);
+	s32  (*read)(struct ngbe_hw *hw, u32 *msg, u16 size, u16 vf_number);
+	s32  (*write)(struct ngbe_hw *hw, u32 *msg, u16 size, u16 vf_number);
+	s32  (*check_for_msg)(struct ngbe_hw *hw, u16 mbx_id);
+	s32  (*check_for_ack)(struct ngbe_hw *hw, u16 mbx_id);
+	s32  (*check_for_rst)(struct ngbe_hw *hw, u16 mbx_id);
 
 	struct ngbe_mbx_stats stats;
 	u32 timeout;
diff --git a/drivers/net/ngbe/meson.build b/drivers/net/ngbe/meson.build
index 8b5195aab3..b276ec3341 100644
--- a/drivers/net/ngbe/meson.build
+++ b/drivers/net/ngbe/meson.build
@@ -20,3 +20,5 @@  sources = files(
 deps += ['hash']
 
 includes += include_directories('base')
+
+install_headers('rte_pmd_ngbe.h')
diff --git a/drivers/net/ngbe/ngbe_ethdev.c b/drivers/net/ngbe/ngbe_ethdev.c
index 70e471b2c2..52d7b6376d 100644
--- a/drivers/net/ngbe/ngbe_ethdev.c
+++ b/drivers/net/ngbe/ngbe_ethdev.c
@@ -2123,6 +2123,11 @@  ngbe_dev_interrupt_action(struct rte_eth_dev *dev)
 
 	PMD_DRV_LOG(DEBUG, "intr action type %d", intr->flags);
 
+	if (intr->flags & NGBE_FLAG_MAILBOX) {
+		ngbe_pf_mbx_process(dev);
+		intr->flags &= ~NGBE_FLAG_MAILBOX;
+	}
+
 	if (intr->flags & NGBE_FLAG_NEED_LINK_UPDATE) {
 		struct rte_eth_link link;
 
@@ -2183,6 +2188,8 @@  ngbe_dev_interrupt_delayed_handler(void *param)
 	ngbe_disable_intr(hw);
 
 	eicr = ((u32 *)hw->isb_mem)[NGBE_ISB_MISC];
+	if (eicr & NGBE_ICRMISC_VFMBX)
+		ngbe_pf_mbx_process(dev);
 
 	if (intr->flags & NGBE_FLAG_NEED_LINK_UPDATE) {
 		ngbe_dev_link_update(dev, 0);
diff --git a/drivers/net/ngbe/ngbe_ethdev.h b/drivers/net/ngbe/ngbe_ethdev.h
index f5a1363d10..26911cc7d2 100644
--- a/drivers/net/ngbe/ngbe_ethdev.h
+++ b/drivers/net/ngbe/ngbe_ethdev.h
@@ -71,6 +71,11 @@  struct ngbe_hwstrip {
 	uint32_t bitmap[NGBE_HWSTRIP_BITMAP_SIZE];
 };
 
+/*
+ * VF data which used by PF host only
+ */
+#define NGBE_MAX_VF_MC_ENTRIES      30
+
 struct ngbe_uta_info {
 	uint8_t  uc_filter_type;
 	uint16_t uta_in_use;
@@ -79,8 +84,14 @@  struct ngbe_uta_info {
 
 struct ngbe_vf_info {
 	uint8_t vf_mac_addresses[RTE_ETHER_ADDR_LEN];
+	uint16_t vf_mc_hashes[NGBE_MAX_VF_MC_ENTRIES];
+	uint16_t num_vf_mc_hashes;
 	bool clear_to_send;
+	uint16_t vlan_count;
+	uint8_t api_version;
 	uint16_t switch_domain_id;
+	uint16_t xcast_mode;
+	uint16_t mac_count;
 };
 
 /*
@@ -233,6 +244,8 @@  int ngbe_pf_host_init(struct rte_eth_dev *eth_dev);
 
 void ngbe_pf_host_uninit(struct rte_eth_dev *eth_dev);
 
+void ngbe_pf_mbx_process(struct rte_eth_dev *eth_dev);
+
 int ngbe_pf_host_configure(struct rte_eth_dev *eth_dev);
 
 #define NGBE_LINK_DOWN_CHECK_TIMEOUT 4000 /* ms */
diff --git a/drivers/net/ngbe/ngbe_pf.c b/drivers/net/ngbe/ngbe_pf.c
index 2f9dfc4284..550f5d556b 100644
--- a/drivers/net/ngbe/ngbe_pf.c
+++ b/drivers/net/ngbe/ngbe_pf.c
@@ -10,8 +10,11 @@ 
 
 #include "base/ngbe.h"
 #include "ngbe_ethdev.h"
+#include "rte_pmd_ngbe.h"
 
 #define NGBE_MAX_VFTA     (128)
+#define NGBE_VF_MSG_SIZE_DEFAULT 1
+#define NGBE_VF_GET_QUEUE_MSG_SIZE 5
 
 static inline uint16_t
 dev_num_vf(struct rte_eth_dev *eth_dev)
@@ -39,6 +42,16 @@  int ngbe_vf_perm_addr_gen(struct rte_eth_dev *dev, uint16_t vf_num)
 	return 0;
 }
 
+static inline int
+ngbe_mb_intr_setup(struct rte_eth_dev *dev)
+{
+	struct ngbe_interrupt *intr = ngbe_dev_intr(dev);
+
+	intr->mask_misc |= NGBE_ICRMISC_VFMBX;
+
+	return 0;
+}
+
 int ngbe_pf_host_init(struct rte_eth_dev *eth_dev)
 {
 	struct ngbe_vf_info **vfinfo = NGBE_DEV_VFDATA(eth_dev);
@@ -85,6 +98,9 @@  int ngbe_pf_host_init(struct rte_eth_dev *eth_dev)
 	/* init_mailbox_params */
 	hw->mbx.init_params(hw);
 
+	/* set mb interrupt mask */
+	ngbe_mb_intr_setup(eth_dev);
+
 	return ret;
 }
 
@@ -194,3 +210,551 @@  int ngbe_pf_host_configure(struct rte_eth_dev *eth_dev)
 	return 0;
 }
 
+static void
+ngbe_set_rx_mode(struct rte_eth_dev *eth_dev)
+{
+	struct rte_eth_dev_data *dev_data = eth_dev->data;
+	struct ngbe_hw *hw = ngbe_dev_hw(eth_dev);
+	u32 fctrl, vmolr;
+	uint16_t vfn = dev_num_vf(eth_dev);
+
+	/* disable store-bad-packets */
+	wr32m(hw, NGBE_SECRXCTL, NGBE_SECRXCTL_SAVEBAD, 0);
+
+	/* Check for Promiscuous and All Multicast modes */
+	fctrl = rd32m(hw, NGBE_PSRCTL,
+			~(NGBE_PSRCTL_UCP | NGBE_PSRCTL_MCP));
+	fctrl |= NGBE_PSRCTL_BCA |
+		 NGBE_PSRCTL_MCHFENA;
+
+	vmolr = rd32m(hw, NGBE_POOLETHCTL(vfn),
+			~(NGBE_POOLETHCTL_UCP |
+			  NGBE_POOLETHCTL_MCP |
+			  NGBE_POOLETHCTL_UCHA |
+			  NGBE_POOLETHCTL_MCHA));
+	vmolr |= NGBE_POOLETHCTL_BCA |
+		 NGBE_POOLETHCTL_UTA |
+		 NGBE_POOLETHCTL_VLA;
+
+	if (dev_data->promiscuous) {
+		fctrl |= NGBE_PSRCTL_UCP |
+			 NGBE_PSRCTL_MCP;
+		/* pf don't want packets routing to vf, so clear UPE */
+		vmolr |= NGBE_POOLETHCTL_MCP;
+	} else if (dev_data->all_multicast) {
+		fctrl |= NGBE_PSRCTL_MCP;
+		vmolr |= NGBE_POOLETHCTL_MCP;
+	} else {
+		vmolr |= NGBE_POOLETHCTL_UCHA;
+		vmolr |= NGBE_POOLETHCTL_MCHA;
+	}
+
+	wr32(hw, NGBE_POOLETHCTL(vfn), vmolr);
+
+	wr32(hw, NGBE_PSRCTL, fctrl);
+
+	ngbe_vlan_hw_strip_config(eth_dev);
+}
+
+static inline void
+ngbe_vf_reset_event(struct rte_eth_dev *eth_dev, uint16_t vf)
+{
+	struct ngbe_hw *hw = ngbe_dev_hw(eth_dev);
+	struct ngbe_vf_info *vfinfo = *(NGBE_DEV_VFDATA(eth_dev));
+	int rar_entry = hw->mac.num_rar_entries - (vf + 1);
+	uint32_t vmolr = rd32(hw, NGBE_POOLETHCTL(vf));
+
+	vmolr |= (NGBE_POOLETHCTL_UCHA |
+			NGBE_POOLETHCTL_BCA | NGBE_POOLETHCTL_UTA);
+	wr32(hw, NGBE_POOLETHCTL(vf), vmolr);
+
+	wr32(hw, NGBE_POOLTAG(vf), 0);
+
+	/* reset multicast table array for vf */
+	vfinfo[vf].num_vf_mc_hashes = 0;
+
+	/* reset rx mode */
+	ngbe_set_rx_mode(eth_dev);
+
+	hw->mac.clear_rar(hw, rar_entry);
+}
+
+static inline void
+ngbe_vf_reset_msg(struct rte_eth_dev *eth_dev, uint16_t vf)
+{
+	struct ngbe_hw *hw = ngbe_dev_hw(eth_dev);
+	uint32_t reg;
+	uint32_t vf_shift;
+	const uint8_t VFRE_SHIFT = 5;  /* VFRE 32 bits per slot */
+	const uint8_t VFRE_MASK = (uint8_t)((1U << VFRE_SHIFT) - 1);
+	uint8_t  nb_q_per_pool;
+	int i;
+
+	vf_shift = vf & VFRE_MASK;
+
+	/* enable transmit for vf */
+	reg = rd32(hw, NGBE_POOLTXENA(0));
+	reg |= (1 << vf_shift);
+	wr32(hw, NGBE_POOLTXENA(0), reg);
+
+	/* enable all queue drop for IOV */
+	nb_q_per_pool = RTE_ETH_DEV_SRIOV(eth_dev).nb_q_per_pool;
+	for (i = vf * nb_q_per_pool; i < (vf + 1) * nb_q_per_pool; i++) {
+		ngbe_flush(hw);
+		reg = 1 << (i % 32);
+		wr32m(hw, NGBE_QPRXDROP, reg, reg);
+	}
+
+	/* enable receive for vf */
+	reg = rd32(hw, NGBE_POOLRXENA(0));
+	reg |= (reg | (1 << vf_shift));
+	wr32(hw, NGBE_POOLRXENA(0), reg);
+
+	ngbe_vf_reset_event(eth_dev, vf);
+}
+
+static int
+ngbe_disable_vf_mc_promisc(struct rte_eth_dev *eth_dev, uint32_t vf)
+{
+	struct ngbe_hw *hw = ngbe_dev_hw(eth_dev);
+	uint32_t vmolr;
+
+	vmolr = rd32(hw, NGBE_POOLETHCTL(vf));
+
+	PMD_DRV_LOG(INFO, "VF %u: disabling multicast promiscuous\n", vf);
+
+	vmolr &= ~NGBE_POOLETHCTL_MCP;
+
+	wr32(hw, NGBE_POOLETHCTL(vf), vmolr);
+
+	return 0;
+}
+
+static int
+ngbe_vf_reset(struct rte_eth_dev *eth_dev, uint16_t vf, uint32_t *msgbuf)
+{
+	struct ngbe_hw *hw = ngbe_dev_hw(eth_dev);
+	struct ngbe_vf_info *vfinfo = *(NGBE_DEV_VFDATA(eth_dev));
+	unsigned char *vf_mac = vfinfo[vf].vf_mac_addresses;
+	int rar_entry = hw->mac.num_rar_entries - (vf + 1);
+	uint8_t *new_mac = (uint8_t *)(&msgbuf[1]);
+
+	ngbe_vf_reset_msg(eth_dev, vf);
+
+	hw->mac.set_rar(hw, rar_entry, vf_mac, vf, true);
+
+	/* Disable multicast promiscuous at reset */
+	ngbe_disable_vf_mc_promisc(eth_dev, vf);
+
+	/* reply to reset with ack and vf mac address */
+	msgbuf[0] = NGBE_VF_RESET | NGBE_VT_MSGTYPE_ACK;
+	rte_memcpy(new_mac, vf_mac, RTE_ETHER_ADDR_LEN);
+	/*
+	 * Piggyback the multicast filter type so VF can compute the
+	 * correct vectors
+	 */
+	msgbuf[3] = hw->mac.mc_filter_type;
+	ngbe_write_mbx(hw, msgbuf, NGBE_VF_PERMADDR_MSG_LEN, vf);
+
+	return 0;
+}
+
+static int
+ngbe_vf_set_mac_addr(struct rte_eth_dev *eth_dev,
+		uint32_t vf, uint32_t *msgbuf)
+{
+	struct ngbe_hw *hw = ngbe_dev_hw(eth_dev);
+	struct ngbe_vf_info *vfinfo = *(NGBE_DEV_VFDATA(eth_dev));
+	int rar_entry = hw->mac.num_rar_entries - (vf + 1);
+	uint8_t *new_mac = (uint8_t *)(&msgbuf[1]);
+	struct rte_ether_addr *ea = (struct rte_ether_addr *)new_mac;
+
+	if (rte_is_valid_assigned_ether_addr(ea)) {
+		rte_memcpy(vfinfo[vf].vf_mac_addresses, new_mac, 6);
+		return hw->mac.set_rar(hw, rar_entry, new_mac, vf, true);
+	}
+	return -1;
+}
+
+static int
+ngbe_vf_set_multicast(struct rte_eth_dev *eth_dev,
+		uint32_t vf, uint32_t *msgbuf)
+{
+	struct ngbe_hw *hw = ngbe_dev_hw(eth_dev);
+	struct ngbe_vf_info *vfinfo = *(NGBE_DEV_VFDATA(eth_dev));
+	int nb_entries = (msgbuf[0] & NGBE_VT_MSGINFO_MASK) >>
+		NGBE_VT_MSGINFO_SHIFT;
+	uint16_t *hash_list = (uint16_t *)&msgbuf[1];
+	uint32_t mta_idx;
+	uint32_t mta_shift;
+	const uint32_t NGBE_MTA_INDEX_MASK = 0x7F;
+	const uint32_t NGBE_MTA_BIT_SHIFT = 5;
+	const uint32_t NGBE_MTA_BIT_MASK = (0x1 << NGBE_MTA_BIT_SHIFT) - 1;
+	uint32_t reg_val;
+	int i;
+	u32 vmolr = rd32(hw, NGBE_POOLETHCTL(vf));
+
+	/* Disable multicast promiscuous first */
+	ngbe_disable_vf_mc_promisc(eth_dev, vf);
+
+	/* only so many hash values supported */
+	nb_entries = RTE_MIN(nb_entries, NGBE_MAX_VF_MC_ENTRIES);
+
+	/* store the mc entries  */
+	vfinfo->num_vf_mc_hashes = (uint16_t)nb_entries;
+	for (i = 0; i < nb_entries; i++)
+		vfinfo->vf_mc_hashes[i] = hash_list[i];
+
+	if (nb_entries == 0) {
+		vmolr &= ~NGBE_POOLETHCTL_MCHA;
+		wr32(hw, NGBE_POOLETHCTL(vf), vmolr);
+		return 0;
+	}
+
+	for (i = 0; i < vfinfo->num_vf_mc_hashes; i++) {
+		mta_idx = (vfinfo->vf_mc_hashes[i] >> NGBE_MTA_BIT_SHIFT)
+				& NGBE_MTA_INDEX_MASK;
+		mta_shift = vfinfo->vf_mc_hashes[i] & NGBE_MTA_BIT_MASK;
+		reg_val = rd32(hw, NGBE_MCADDRTBL(mta_idx));
+		reg_val |= (1 << mta_shift);
+		wr32(hw, NGBE_MCADDRTBL(mta_idx), reg_val);
+	}
+
+	vmolr |= NGBE_POOLETHCTL_MCHA;
+	wr32(hw, NGBE_POOLETHCTL(vf), vmolr);
+
+	return 0;
+}
+
+static int
+ngbe_vf_set_vlan(struct rte_eth_dev *eth_dev, uint32_t vf, uint32_t *msgbuf)
+{
+	int add, vid;
+	struct ngbe_hw *hw = ngbe_dev_hw(eth_dev);
+	struct ngbe_vf_info *vfinfo = *(NGBE_DEV_VFDATA(eth_dev));
+
+	add = (msgbuf[0] & NGBE_VT_MSGINFO_MASK)
+		>> NGBE_VT_MSGINFO_SHIFT;
+	vid = NGBE_PSRVLAN_VID(msgbuf[1]);
+
+	if (add)
+		vfinfo[vf].vlan_count++;
+	else if (vfinfo[vf].vlan_count)
+		vfinfo[vf].vlan_count--;
+	return hw->mac.set_vfta(hw, vid, vf, (bool)add, false);
+}
+
+static int
+ngbe_set_vf_lpe(struct rte_eth_dev *eth_dev,
+		__rte_unused uint32_t vf, uint32_t *msgbuf)
+{
+	struct ngbe_hw *hw = ngbe_dev_hw(eth_dev);
+	uint32_t max_frame = msgbuf[1];
+	uint32_t max_frs;
+
+	if (max_frame < RTE_ETHER_MIN_LEN ||
+			max_frame > RTE_ETHER_MAX_JUMBO_FRAME_LEN)
+		return -1;
+
+	max_frs = rd32m(hw, NGBE_FRMSZ, NGBE_FRMSZ_MAX_MASK);
+	if (max_frs < max_frame) {
+		wr32m(hw, NGBE_FRMSZ, NGBE_FRMSZ_MAX_MASK,
+			NGBE_FRMSZ_MAX(max_frame));
+	}
+
+	return 0;
+}
+
+static int
+ngbe_negotiate_vf_api(struct rte_eth_dev *eth_dev,
+		uint32_t vf, uint32_t *msgbuf)
+{
+	uint32_t api_version = msgbuf[1];
+	struct ngbe_vf_info *vfinfo = *NGBE_DEV_VFDATA(eth_dev);
+
+	switch (api_version) {
+	case ngbe_mbox_api_10:
+	case ngbe_mbox_api_11:
+	case ngbe_mbox_api_12:
+	case ngbe_mbox_api_13:
+		vfinfo[vf].api_version = (uint8_t)api_version;
+		return 0;
+	default:
+		break;
+	}
+
+	PMD_DRV_LOG(ERR, "Negotiate invalid api version %u from VF %d\n",
+		api_version, vf);
+
+	return -1;
+}
+
+static int
+ngbe_get_vf_queues(struct rte_eth_dev *eth_dev, uint32_t vf, uint32_t *msgbuf)
+{
+	struct ngbe_vf_info *vfinfo = *NGBE_DEV_VFDATA(eth_dev);
+	uint32_t default_q = 0;
+
+	/* Verify if the PF supports the mbox APIs version or not */
+	switch (vfinfo[vf].api_version) {
+	case ngbe_mbox_api_20:
+	case ngbe_mbox_api_11:
+	case ngbe_mbox_api_12:
+	case ngbe_mbox_api_13:
+		break;
+	default:
+		return -1;
+	}
+
+	/* Notify VF of Rx and Tx queue number */
+	msgbuf[NGBE_VF_RX_QUEUES] = RTE_ETH_DEV_SRIOV(eth_dev).nb_q_per_pool;
+	msgbuf[NGBE_VF_TX_QUEUES] = RTE_ETH_DEV_SRIOV(eth_dev).nb_q_per_pool;
+
+	/* Notify VF of default queue */
+	msgbuf[NGBE_VF_DEF_QUEUE] = default_q;
+
+	msgbuf[NGBE_VF_TRANS_VLAN] = 0;
+
+	return 0;
+}
+
+static int
+ngbe_set_vf_mc_promisc(struct rte_eth_dev *eth_dev,
+		uint32_t vf, uint32_t *msgbuf)
+{
+	struct ngbe_vf_info *vfinfo = *(NGBE_DEV_VFDATA(eth_dev));
+	struct ngbe_hw *hw = ngbe_dev_hw(eth_dev);
+	int xcast_mode = msgbuf[1];	/* msgbuf contains the flag to enable */
+	u32 vmolr, fctrl, disable, enable;
+
+	switch (vfinfo[vf].api_version) {
+	case ngbe_mbox_api_12:
+		/* promisc introduced in 1.3 version */
+		if (xcast_mode == NGBEVF_XCAST_MODE_PROMISC)
+			return -EOPNOTSUPP;
+		break;
+		/* Fall threw */
+	case ngbe_mbox_api_13:
+		break;
+	default:
+		return -1;
+	}
+
+	if (vfinfo[vf].xcast_mode == xcast_mode)
+		goto out;
+
+	switch (xcast_mode) {
+	case NGBEVF_XCAST_MODE_NONE:
+		disable = NGBE_POOLETHCTL_BCA | NGBE_POOLETHCTL_MCHA |
+			  NGBE_POOLETHCTL_MCP | NGBE_POOLETHCTL_UCP |
+			  NGBE_POOLETHCTL_VLP;
+		enable = 0;
+		break;
+	case NGBEVF_XCAST_MODE_MULTI:
+		disable = NGBE_POOLETHCTL_MCP | NGBE_POOLETHCTL_UCP |
+			  NGBE_POOLETHCTL_VLP;
+		enable = NGBE_POOLETHCTL_BCA | NGBE_POOLETHCTL_MCHA;
+		break;
+	case NGBEVF_XCAST_MODE_ALLMULTI:
+		disable = NGBE_POOLETHCTL_UCP | NGBE_POOLETHCTL_VLP;
+		enable = NGBE_POOLETHCTL_BCA | NGBE_POOLETHCTL_MCHA |
+			 NGBE_POOLETHCTL_MCP;
+		break;
+	case NGBEVF_XCAST_MODE_PROMISC:
+		fctrl = rd32(hw, NGBE_PSRCTL);
+		if (!(fctrl & NGBE_PSRCTL_UCP)) {
+			/* VF promisc requires PF in promisc */
+			PMD_DRV_LOG(ERR,
+			       "Enabling VF promisc requires PF in promisc\n");
+			return -1;
+		}
+
+		disable = 0;
+		enable = NGBE_POOLETHCTL_BCA | NGBE_POOLETHCTL_MCHA |
+			 NGBE_POOLETHCTL_MCP | NGBE_POOLETHCTL_UCP |
+			 NGBE_POOLETHCTL_VLP;
+		break;
+	default:
+		return -1;
+	}
+
+	vmolr = rd32(hw, NGBE_POOLETHCTL(vf));
+	vmolr &= ~disable;
+	vmolr |= enable;
+	wr32(hw, NGBE_POOLETHCTL(vf), vmolr);
+	vfinfo[vf].xcast_mode = xcast_mode;
+
+out:
+	msgbuf[1] = xcast_mode;
+
+	return 0;
+}
+
+static int
+ngbe_set_vf_macvlan_msg(struct rte_eth_dev *dev, uint32_t vf, uint32_t *msgbuf)
+{
+	struct ngbe_hw *hw = ngbe_dev_hw(dev);
+	struct ngbe_vf_info *vf_info = *(NGBE_DEV_VFDATA(dev));
+	uint8_t *new_mac = (uint8_t *)(&msgbuf[1]);
+	struct rte_ether_addr *ea = (struct rte_ether_addr *)new_mac;
+	int index = (msgbuf[0] & NGBE_VT_MSGINFO_MASK) >>
+		    NGBE_VT_MSGINFO_SHIFT;
+
+	if (index) {
+		if (!rte_is_valid_assigned_ether_addr(ea)) {
+			PMD_DRV_LOG(ERR, "set invalid mac vf:%d\n", vf);
+			return -1;
+		}
+
+		vf_info[vf].mac_count++;
+
+		hw->mac.set_rar(hw, vf_info[vf].mac_count,
+				new_mac, vf, true);
+	} else {
+		if (vf_info[vf].mac_count) {
+			hw->mac.clear_rar(hw, vf_info[vf].mac_count);
+			vf_info[vf].mac_count = 0;
+		}
+	}
+	return 0;
+}
+
+static int
+ngbe_rcv_msg_from_vf(struct rte_eth_dev *eth_dev, uint16_t vf)
+{
+	uint16_t mbx_size = NGBE_P2VMBX_SIZE;
+	uint16_t msg_size = NGBE_VF_MSG_SIZE_DEFAULT;
+	uint32_t msgbuf[NGBE_P2VMBX_SIZE];
+	int32_t retval;
+	struct ngbe_hw *hw = ngbe_dev_hw(eth_dev);
+	struct ngbe_vf_info *vfinfo = *NGBE_DEV_VFDATA(eth_dev);
+	struct rte_pmd_ngbe_mb_event_param ret_param;
+
+	retval = ngbe_read_mbx(hw, msgbuf, mbx_size, vf);
+	if (retval) {
+		PMD_DRV_LOG(ERR, "Error mbx recv msg from VF %d", vf);
+		return retval;
+	}
+
+	/* do nothing with the message already been processed */
+	if (msgbuf[0] & (NGBE_VT_MSGTYPE_ACK | NGBE_VT_MSGTYPE_NACK))
+		return retval;
+
+	/* flush the ack before we write any messages back */
+	ngbe_flush(hw);
+
+	/**
+	 * initialise structure to send to user application
+	 * will return response from user in retval field
+	 */
+	ret_param.retval = RTE_PMD_NGBE_MB_EVENT_PROCEED;
+	ret_param.vfid = vf;
+	ret_param.msg_type = msgbuf[0] & 0xFFFF;
+	ret_param.msg = (void *)msgbuf;
+
+	/* perform VF reset */
+	if (msgbuf[0] == NGBE_VF_RESET) {
+		int ret = ngbe_vf_reset(eth_dev, vf, msgbuf);
+
+		vfinfo[vf].clear_to_send = true;
+
+		/* notify application about VF reset */
+		rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_VF_MBOX,
+					      &ret_param);
+		return ret;
+	}
+
+	/**
+	 * ask user application if we allowed to perform those functions
+	 * if we get ret_param.retval == RTE_PMD_COMPAT_MB_EVENT_PROCEED
+	 * then business as usual,
+	 * if 0, do nothing and send ACK to VF
+	 * if ret_param.retval > 1, do nothing and send NAK to VF
+	 */
+	rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_VF_MBOX,
+				      &ret_param);
+
+	retval = ret_param.retval;
+
+	/* check & process VF to PF mailbox message */
+	switch ((msgbuf[0] & 0xFFFF)) {
+	case NGBE_VF_SET_MAC_ADDR:
+		if (retval == RTE_PMD_NGBE_MB_EVENT_PROCEED)
+			retval = ngbe_vf_set_mac_addr(eth_dev, vf, msgbuf);
+		break;
+	case NGBE_VF_SET_MULTICAST:
+		if (retval == RTE_PMD_NGBE_MB_EVENT_PROCEED)
+			retval = ngbe_vf_set_multicast(eth_dev, vf, msgbuf);
+		break;
+	case NGBE_VF_SET_LPE:
+		if (retval == RTE_PMD_NGBE_MB_EVENT_PROCEED)
+			retval = ngbe_set_vf_lpe(eth_dev, vf, msgbuf);
+		break;
+	case NGBE_VF_SET_VLAN:
+		if (retval == RTE_PMD_NGBE_MB_EVENT_PROCEED)
+			retval = ngbe_vf_set_vlan(eth_dev, vf, msgbuf);
+		break;
+	case NGBE_VF_API_NEGOTIATE:
+		retval = ngbe_negotiate_vf_api(eth_dev, vf, msgbuf);
+		break;
+	case NGBE_VF_GET_QUEUES:
+		retval = ngbe_get_vf_queues(eth_dev, vf, msgbuf);
+		msg_size = NGBE_VF_GET_QUEUE_MSG_SIZE;
+		break;
+	case NGBE_VF_UPDATE_XCAST_MODE:
+		if (retval == RTE_PMD_NGBE_MB_EVENT_PROCEED)
+			retval = ngbe_set_vf_mc_promisc(eth_dev, vf, msgbuf);
+		break;
+	case NGBE_VF_SET_MACVLAN:
+		if (retval == RTE_PMD_NGBE_MB_EVENT_PROCEED)
+			retval = ngbe_set_vf_macvlan_msg(eth_dev, vf, msgbuf);
+		break;
+	default:
+		PMD_DRV_LOG(DEBUG, "Unhandled Msg %8.8x", (uint32_t)msgbuf[0]);
+		retval = NGBE_ERR_MBX;
+		break;
+	}
+
+	/* response the VF according to the message process result */
+	if (retval)
+		msgbuf[0] |= NGBE_VT_MSGTYPE_NACK;
+	else
+		msgbuf[0] |= NGBE_VT_MSGTYPE_ACK;
+
+	msgbuf[0] |= NGBE_VT_MSGTYPE_CTS;
+
+	ngbe_write_mbx(hw, msgbuf, msg_size, vf);
+
+	return retval;
+}
+
+static inline void
+ngbe_rcv_ack_from_vf(struct rte_eth_dev *eth_dev, uint16_t vf)
+{
+	uint32_t msg = NGBE_VT_MSGTYPE_NACK;
+	struct ngbe_hw *hw = ngbe_dev_hw(eth_dev);
+	struct ngbe_vf_info *vfinfo = *NGBE_DEV_VFDATA(eth_dev);
+
+	if (!vfinfo[vf].clear_to_send)
+		ngbe_write_mbx(hw, &msg, 1, vf);
+}
+
+void ngbe_pf_mbx_process(struct rte_eth_dev *eth_dev)
+{
+	uint16_t vf;
+	struct ngbe_hw *hw = ngbe_dev_hw(eth_dev);
+
+	for (vf = 0; vf < dev_num_vf(eth_dev); vf++) {
+		/* check & process vf function level reset */
+		if (!ngbe_check_for_rst(hw, vf))
+			ngbe_vf_reset_event(eth_dev, vf);
+
+		/* check & process vf mailbox messages */
+		if (!ngbe_check_for_msg(hw, vf))
+			ngbe_rcv_msg_from_vf(eth_dev, vf);
+
+		/* check & process acks from vf */
+		if (!ngbe_check_for_ack(hw, vf))
+			ngbe_rcv_ack_from_vf(eth_dev, vf);
+	}
+}
diff --git a/drivers/net/ngbe/rte_pmd_ngbe.h b/drivers/net/ngbe/rte_pmd_ngbe.h
new file mode 100644
index 0000000000..e895ecd7ef
--- /dev/null
+++ b/drivers/net/ngbe/rte_pmd_ngbe.h
@@ -0,0 +1,39 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
+ * Copyright(c) 2010-2017 Intel Corporation
+ */
+
+/**
+ * @file rte_pmd_ngbe.h
+ * ngbe PMD specific functions.
+ *
+ **/
+
+#ifndef _PMD_NGBE_H_
+#define _PMD_NGBE_H_
+
+#include <rte_compat.h>
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+
+/**
+ * Response sent back to ngbe driver from user app after callback
+ */
+enum rte_pmd_ngbe_mb_event_rsp {
+	RTE_PMD_NGBE_MB_EVENT_NOOP_ACK,  /**< skip mbox request and ACK */
+	RTE_PMD_NGBE_MB_EVENT_NOOP_NACK, /**< skip mbox request and NACK */
+	RTE_PMD_NGBE_MB_EVENT_PROCEED,  /**< proceed with mbox request  */
+	RTE_PMD_NGBE_MB_EVENT_MAX       /**< max value of this enum */
+};
+
+/**
+ * Data sent to the user application when the callback is executed.
+ */
+struct rte_pmd_ngbe_mb_event_param {
+	uint16_t vfid;     /**< Virtual Function number */
+	uint16_t msg_type; /**< VF to PF message type, defined in ngbe_mbx.h */
+	uint16_t retval;   /**< return value */
+	void *msg;         /**< pointer to message */
+};
+
+#endif /* _PMD_NGBE_H_ */