[dpdk-dev] [PATCH v2 02/27] i40e: add PMD source files

Helin Zhang helin.zhang at intel.com
Thu Jun 5 07:08:46 CEST 2014


Add PMD source files to support Intel(R) 40G Ethernet Controllers.
The new files are,
i40e_osdep.h
i40e_ethdev.c
i40e_ethdev.h
i40e_ethdev_vf.c
i40e_logs.h
i40e_pf.c
i40e_pf.h
i40e_rxtx.c
i40e_rxtx.h
Makefile

Signed-off-by: Helin Zhang <helin.zhang at intel.com>
Signed-off-by: Jing Chen <jing.d.chen at intel.com>
Acked-by: Cunming Liang <cunming.liang at intel.com>
Acked-by: Jijiang Liu <jijiang.liu at intel.com>
Acked-by: Jingjing Wu <jingjing.wu at intel.com>
Tested-by: Waterman Cao <waterman.cao at intel.com>
---
 lib/librte_pmd_i40e/Makefile          |   85 +
 lib/librte_pmd_i40e/i40e/i40e_osdep.h |  197 ++
 lib/librte_pmd_i40e/i40e_ethdev.c     | 4019 +++++++++++++++++++++++++++++++++
 lib/librte_pmd_i40e/i40e_ethdev.h     |  356 +++
 lib/librte_pmd_i40e/i40e_ethdev_vf.c  | 1336 +++++++++++
 lib/librte_pmd_i40e/i40e_logs.h       |   74 +
 lib/librte_pmd_i40e/i40e_pf.c         |  928 ++++++++
 lib/librte_pmd_i40e/i40e_pf.h         |   67 +
 lib/librte_pmd_i40e/i40e_rxtx.c       | 2204 ++++++++++++++++++
 lib/librte_pmd_i40e/i40e_rxtx.h       |  189 ++
 10 files changed, 9455 insertions(+)
 create mode 100644 lib/librte_pmd_i40e/Makefile
 create mode 100644 lib/librte_pmd_i40e/i40e/i40e_osdep.h
 create mode 100644 lib/librte_pmd_i40e/i40e_ethdev.c
 create mode 100644 lib/librte_pmd_i40e/i40e_ethdev.h
 create mode 100644 lib/librte_pmd_i40e/i40e_ethdev_vf.c
 create mode 100644 lib/librte_pmd_i40e/i40e_logs.h
 create mode 100644 lib/librte_pmd_i40e/i40e_pf.c
 create mode 100644 lib/librte_pmd_i40e/i40e_pf.h
 create mode 100644 lib/librte_pmd_i40e/i40e_rxtx.c
 create mode 100644 lib/librte_pmd_i40e/i40e_rxtx.h

diff --git a/lib/librte_pmd_i40e/Makefile b/lib/librte_pmd_i40e/Makefile
new file mode 100644
index 0000000..09f2087
--- /dev/null
+++ b/lib/librte_pmd_i40e/Makefile
@@ -0,0 +1,85 @@
+#   BSD LICENSE
+#
+#   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+#   All rights reserved.
+#
+#   Redistribution and use in source and binary forms, with or without
+#   modification, are permitted provided that the following conditions
+#   are met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in
+#       the documentation and/or other materials provided with the
+#       distribution.
+#     * Neither the name of Intel Corporation nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+#
+# library name
+#
+LIB = librte_pmd_i40e.a
+
+CFLAGS += -O3
+CFLAGS += $(WERROR_FLAGS)
+
+ifeq ($(CC), icc)
+CFLAGS_SHARED_DRIVERS = -wd593
+else
+CFLAGS_SHARED_DRIVERS =  -Wno-unused-but-set-variable
+CFLAGS_SHARED_DRIVERS += -Wno-sign-compare
+CFLAGS_SHARED_DRIVERS += -Wno-unused-value
+CFLAGS_SHARED_DRIVERS += -Wno-unused-parameter
+CFLAGS_SHARED_DRIVERS += -Wno-strict-aliasing
+CFLAGS_SHARED_DRIVERS += -Wno-format
+CFLAGS_SHARED_DRIVERS += -Wno-missing-field-initializers
+CFLAGS_SHARED_DRIVERS += -Wno-pointer-to-int-cast
+CFLAGS_SHARED_DRIVERS += -Wno-format-nonliteral
+CFLAGS_SHARED_DRIVERS += -Wno-format-security
+endif
+
+#
+# Add extra flags for ND source files to disable warnings
+#
+SHARED_DRIVERS_OBJS=$(patsubst %.c,%.o,$(notdir $(wildcard $(RTE_SDK)/lib/librte_pmd_i40e/i40e/*.c)))
+$(foreach obj, $(SHARED_DRIVERS_OBJS), $(eval CFLAGS_$(obj)+=$(CFLAGS_SHARED_DRIVERS)))
+
+VPATH += $(RTE_SDK)/lib/librte_pmd_i40e/i40e
+
+#
+# all source are stored in SRCS-y
+#
+SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_adminq.c
+SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_common.c
+SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_diag.c
+SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_hmc.c
+SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_lan_hmc.c
+SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_nvm.c
+SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_dcb.c
+
+SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_ethdev.c
+SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_rxtx.c
+SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_ethdev_vf.c
+SRCS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += i40e_pf.c
+# this lib depends upon:
+DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_eal lib/librte_ether
+DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_mempool lib/librte_mbuf
+DEPDIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += lib/librte_net lib/librte_malloc
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_pmd_i40e/i40e/i40e_osdep.h b/lib/librte_pmd_i40e/i40e/i40e_osdep.h
new file mode 100644
index 0000000..0ed4b65
--- /dev/null
+++ b/lib/librte_pmd_i40e/i40e/i40e_osdep.h
@@ -0,0 +1,197 @@
+/******************************************************************************
+
+  Copyright (c) 2001-2014, Intel Corporation
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+   3. Neither the name of the Intel Corporation nor the names of its
+      contributors may be used to endorse or promote products derived from
+      this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  POSSIBILITY OF SUCH DAMAGE.
+******************************************************************************/
+
+#ifndef _I40E_OSDEP_H_
+#define _I40E_OSDEP_H_
+
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <rte_common.h>
+#include <rte_memcpy.h>
+#include <rte_byteorder.h>
+#include <rte_cycles.h>
+#include <rte_spinlock.h>
+#include <rte_log.h>
+
+#include "../i40e_logs.h"
+
+#define INLINE inline
+#define STATIC static
+
+typedef uint8_t         u8;
+typedef int8_t          s8;
+typedef uint16_t        u16;
+typedef uint32_t        u32;
+typedef int32_t         s32;
+typedef uint64_t        u64;
+typedef int             bool;
+
+typedef enum i40e_status_code i40e_status;
+#define __iomem
+#define hw_dbg(hw, S, A...) do {} while (0)
+#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
+#define lower_32_bits(n) ((u32)(n))
+#define low_16_bits(x)   ((x) & 0xFFFF)
+#define high_16_bits(x)  (((x) & 0xFFFF0000) >> 16)
+
+#ifndef ETH_ADDR_LEN
+#define ETH_ADDR_LEN                  6
+#endif
+
+#ifndef __le16
+#define __le16          uint16_t
+#endif
+#ifndef __le32
+#define __le32          uint32_t
+#endif
+#ifndef __le64
+#define __le64          uint64_t
+#endif
+#ifndef __be16
+#define __be16          uint16_t
+#endif
+#ifndef __be32
+#define __be32          uint32_t
+#endif
+#ifndef __be64
+#define __be64          uint64_t
+#endif
+
+#define FALSE           0
+#define TRUE            1
+#define false           0
+#define true            1
+
+#define min(a,b) RTE_MIN(a,b)
+#define max(a,b) RTE_MAX(a,b)
+
+#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+#define ASSERT(x) if(!(x)) rte_panic("IXGBE: x")
+
+#define DEBUGOUT(S)        PMD_DRV_LOG(DEBUG, S)
+#define DEBUGOUT1(S, A...) PMD_DRV_LOG(DEBUG, S, ##A)
+
+#define DEBUGFUNC(F) DEBUGOUT(F)
+#define DEBUGOUT2 DEBUGOUT1
+#define DEBUGOUT3 DEBUGOUT2
+#define DEBUGOUT6 DEBUGOUT3
+#define DEBUGOUT7 DEBUGOUT6
+
+#define i40e_debug(h, m, s, ...)                                \
+do {                                                            \
+	if (((m) & (h)->debug_mask))                            \
+		PMD_DRV_LOG(DEBUG, "i40e %02x.%x " s,           \
+			(h)->bus.device, (h)->bus.func,         \
+					##__VA_ARGS__);         \
+} while (0)
+
+#define I40E_PCI_REG(reg)         (*((volatile uint32_t *)(reg)))
+#define I40E_PCI_REG_ADDR(a, reg) \
+	((volatile uint32_t *)((char *)(a)->hw_addr + (reg)))
+static inline uint32_t i40e_read_addr(volatile void *addr)
+{
+	return I40E_PCI_REG(addr);
+}
+#define I40E_PCI_REG_WRITE(reg, value) \
+	do {I40E_PCI_REG((reg)) = (value);} while(0)
+
+#define I40E_WRITE_FLUSH(a) I40E_READ_REG(a, I40E_GLGEN_STAT)
+#define I40EVF_WRITE_FLUSH(a) I40E_READ_REG(a, I40E_VFGEN_RSTAT)
+
+#define I40E_READ_REG(hw, reg) i40e_read_addr(I40E_PCI_REG_ADDR((hw), (reg)))
+#define I40E_WRITE_REG(hw, reg, value) \
+	I40E_PCI_REG_WRITE(I40E_PCI_REG_ADDR((hw), (reg)), (value))
+
+#define rd32(a, reg) i40e_read_addr(I40E_PCI_REG_ADDR((a), (reg)))
+#define wr32(a, reg, value) \
+	I40E_PCI_REG_WRITE(I40E_PCI_REG_ADDR((a), (reg)), (value))
+#define flush(a) i40e_read_addr(I40E_PCI_REG_ADDR((a), (I40E_GLGEN_STAT)))
+
+#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
+
+/* memory allocation tracking */
+struct i40e_dma_mem {
+	void *va;
+	u64 pa;
+	u32 size;
+	u64 id;
+} __attribute__((packed));
+
+#define i40e_allocate_dma_mem(h, m, unused, s, a) \
+			i40e_allocate_dma_mem_d(h, m, s, a)
+#define i40e_free_dma_mem(h, m) i40e_free_dma_mem_d(h, m)
+
+struct i40e_virt_mem {
+	void *va;
+	u32 size;
+} __attribute__((packed));
+
+#define i40e_allocate_virt_mem(h, m, s) i40e_allocate_virt_mem_d(h, m, s)
+#define i40e_free_virt_mem(h, m) i40e_free_virt_mem_d(h, m)
+
+#define CPU_TO_LE16(o) rte_cpu_to_le_16(o)
+#define CPU_TO_LE32(s) rte_cpu_to_le_32(s)
+#define CPU_TO_LE64(h) rte_cpu_to_le_64(h)
+#define LE16_TO_CPU(a) rte_le_to_cpu_16(a)
+#define LE32_TO_CPU(c) rte_le_to_cpu_32(c)
+#define LE64_TO_CPU(k) rte_le_to_cpu_64(k)
+
+/* SW spinlock */
+struct i40e_spinlock {
+	rte_spinlock_t spinlock;
+};
+
+#define i40e_init_spinlock(_sp) i40e_init_spinlock_d(_sp)
+#define i40e_acquire_spinlock(_sp) i40e_acquire_spinlock_d(_sp)
+#define i40e_release_spinlock(_sp) i40e_release_spinlock_d(_sp)
+#define i40e_destroy_spinlock(_sp) i40e_destroy_spinlock_d(_sp)
+
+#define I40E_NTOHS(a) rte_be_to_cpu_16(a)
+#define I40E_NTOHL(a) rte_be_to_cpu_32(a)
+#define I40E_HTONS(a) rte_cpu_to_be_16(a)
+#define I40E_HTONL(a) rte_cpu_to_be_32(a)
+
+#define i40e_memset(a, b, c, d) memset((a), (b), (c))
+#define i40e_memcpy(a, b, c, d) rte_memcpy((a), (b), (c))
+
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+#define DELAY(x) rte_delay_us(x)
+#define i40e_usec_delay(x) rte_delay_us(x)
+#define i40e_msec_delay(x) rte_delay_us(1000*(x))
+#define udelay(x) DELAY(x)
+#define msleep(x) DELAY(1000*(x))
+#define usleep_range(min, max) msleep(DIV_ROUND_UP(min, 1000))
+
+#endif /* _I40E_OSDEP_H_ */
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
new file mode 100644
index 0000000..e78538f
--- /dev/null
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -0,0 +1,4019 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+
+#include <rte_string_fns.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_memzone.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_dev.h>
+
+#include "i40e_logs.h"
+#include "i40e/i40e_register_x710_int.h"
+#include "i40e/i40e_prototype.h"
+#include "i40e/i40e_adminq_cmd.h"
+#include "i40e/i40e_type.h"
+#include "i40e_ethdev.h"
+#include "i40e_rxtx.h"
+#include "i40e_pf.h"
+
+/* Maximun number of MAC addresses */
+#define I40E_NUM_MACADDR_MAX       64
+#define I40E_CLEAR_PXE_WAIT_MS     200
+
+/* Maximun number of capability elements */
+#define I40E_MAX_CAP_ELE_NUM       128
+
+/* Wait count and inteval */
+#define I40E_CHK_Q_ENA_COUNT       1000
+#define I40E_CHK_Q_ENA_INTERVAL_US 1000
+
+/* Maximun number of VSI */
+#define I40E_MAX_NUM_VSIS          (384UL)
+
+/* Bit shift and mask */
+#define I40E_16_BIT_SHIFT 16
+#define I40E_16_BIT_MASK  0xFFFF
+#define I40E_32_BIT_SHIFT 32
+#define I40E_32_BIT_MASK  0xFFFFFFFF
+#define I40E_48_BIT_SHIFT 48
+#define I40E_48_BIT_MASK  0xFFFFFFFFFFFFULL
+
+/* Default queue interrupt throttling time in microseconds*/
+#define I40E_ITR_INDEX_DEFAULT          0
+#define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
+#define I40E_QUEUE_ITR_INTERVAL_MAX     8160 /* 8160 us */
+
+#define I40E_RSS_OFFLOAD_ALL ( \
+	ETH_RSS_NONF_IPV4_UDP | \
+	ETH_RSS_NONF_IPV4_TCP | \
+	ETH_RSS_NONF_IPV4_SCTP | \
+	ETH_RSS_NONF_IPV4_OTHER | \
+	ETH_RSS_FRAG_IPV4 | \
+	ETH_RSS_NONF_IPV6_UDP | \
+	ETH_RSS_NONF_IPV6_TCP | \
+	ETH_RSS_NONF_IPV6_SCTP | \
+	ETH_RSS_NONF_IPV6_OTHER | \
+	ETH_RSS_FRAG_IPV6 | \
+	ETH_RSS_L2_PAYLOAD)
+
+/* All bits of RSS hash enable */
+#define I40E_RSS_HENA_ALL ( \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \
+	(1ULL << I40E_FILTER_PCTYPE_FRAG_IPV4) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \
+	(1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \
+	(1ULL << I40E_FILTER_PCTYPE_FRAG_IPV6) | \
+	(1ULL << I40E_FILTER_PCTYPE_FCOE_OX) | \
+	(1ULL << I40E_FILTER_PCTYPE_FCOE_RX) | \
+	(1ULL << I40E_FILTER_PCTYPE_FCOE_OTHER) | \
+	(1ULL << I40E_FILTER_PCTYPE_L2_PAYLOAD))
+
+static int eth_i40e_dev_init(\
+			__attribute__((unused)) struct eth_driver *eth_drv,
+			struct rte_eth_dev *eth_dev);
+static int i40e_dev_configure(struct rte_eth_dev *dev);
+static int i40e_dev_start(struct rte_eth_dev *dev);
+static void i40e_dev_stop(struct rte_eth_dev *dev);
+static void i40e_dev_close(struct rte_eth_dev *dev);
+static void i40e_dev_promiscuous_enable(struct rte_eth_dev *dev);
+static void i40e_dev_promiscuous_disable(struct rte_eth_dev *dev);
+static void i40e_dev_allmulticast_enable(struct rte_eth_dev *dev);
+static void i40e_dev_allmulticast_disable(struct rte_eth_dev *dev);
+static void i40e_dev_stats_get(struct rte_eth_dev *dev,
+			       struct rte_eth_stats *stats);
+static void i40e_dev_stats_reset(struct rte_eth_dev *dev);
+static int i40e_dev_queue_stats_mapping_set(struct rte_eth_dev *dev,
+					    uint16_t queue_id,
+					    uint8_t stat_idx,
+					    uint8_t is_rx);
+static void i40e_dev_info_get(struct rte_eth_dev *dev,
+			      struct rte_eth_dev_info *dev_info);
+static int i40e_vlan_filter_set(struct rte_eth_dev *dev,
+				uint16_t vlan_id,
+				int on);
+static void i40e_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid);
+static void i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static void i40e_vlan_strip_queue_set(struct rte_eth_dev *dev,
+				      uint16_t queue,
+				      int on);
+static int i40e_vlan_pvid_set(struct rte_eth_dev *dev, uint16_t pvid, int on);
+static int i40e_dev_led_on(struct rte_eth_dev *dev);
+static int i40e_dev_led_off(struct rte_eth_dev *dev);
+static int i40e_flow_ctrl_set(struct rte_eth_dev *dev,
+			      struct rte_eth_fc_conf *fc_conf);
+static int i40e_priority_flow_ctrl_set(struct rte_eth_dev *dev,
+				       struct rte_eth_pfc_conf *pfc_conf);
+static void i40e_macaddr_add(struct rte_eth_dev *dev,
+			  struct ether_addr *mac_addr,
+			  uint32_t index,
+			  uint32_t pool);
+static void i40e_macaddr_remove(struct rte_eth_dev *dev, uint32_t index);
+static int i40e_dev_rss_reta_update(struct rte_eth_dev *dev,
+				    struct rte_eth_rss_reta *reta_conf);
+static int i40e_dev_rss_reta_query(struct rte_eth_dev *dev,
+				   struct rte_eth_rss_reta *reta_conf);
+
+static int i40e_get_cap(struct i40e_hw *hw);
+static int i40e_pf_parameter_init(struct rte_eth_dev *dev);
+static int i40e_pf_setup(struct i40e_pf *pf);
+static int i40e_vsi_init(struct i40e_vsi *vsi);
+static void i40e_stat_update_32(struct i40e_hw *hw, uint32_t reg,
+		bool offset_loaded, uint64_t *offset, uint64_t *stat);
+static void i40e_stat_update_48(struct i40e_hw *hw,
+			       uint32_t hireg,
+			       uint32_t loreg,
+			       bool offset_loaded,
+			       uint64_t *offset,
+			       uint64_t *stat);
+static void i40e_pf_config_irq0(struct i40e_hw *hw);
+static void i40e_dev_interrupt_handler(
+		__rte_unused struct rte_intr_handle *handle, void *param);
+static int i40e_res_pool_init(struct i40e_res_pool_info *pool,
+				uint32_t base, uint32_t num);
+static void i40e_res_pool_destroy(struct i40e_res_pool_info *pool);
+static int i40e_res_pool_free(struct i40e_res_pool_info *pool,
+			uint32_t base);
+static int i40e_res_pool_alloc(struct i40e_res_pool_info *pool,
+			uint16_t num);
+static int i40e_vsi_init_vlan(struct i40e_vsi *vsi);
+static int i40e_veb_release(struct i40e_veb *veb);
+static struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf,
+						struct i40e_vsi *vsi);
+static int i40e_vsi_config_vlan_stripping(struct i40e_vsi *vsi, bool on);
+static int i40e_pf_config_mq_rx(struct i40e_pf *pf);
+static int i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int on);
+static int i40e_pf_disable_all_queues(struct i40e_hw *hw);
+static inline int i40e_find_all_vlan_for_mac(struct i40e_vsi *vsi,
+					     struct i40e_macvlan_filter *mv_f,
+					     int num,
+					     struct ether_addr *addr);
+static inline int i40e_find_all_mac_for_vlan(struct i40e_vsi *vsi,
+					     struct i40e_macvlan_filter *mv_f,
+					     int num,
+					     uint16_t vlan);
+static int i40e_vsi_remove_all_macvlan_filter(struct i40e_vsi *vsi);
+static int i40e_dev_rss_hash_update(struct rte_eth_dev *dev,
+				    struct rte_eth_rss_conf *rss_conf);
+static int i40e_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+				      struct rte_eth_rss_conf *rss_conf);
+
+/* Default hash key buffer for RSS */
+static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1];
+
+static struct rte_pci_id pci_id_i40e_map[] = {
+#define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
+#include "rte_pci_dev_ids.h"
+{ .vendor_id = 0, /* sentinel */ },
+};
+
+static struct eth_dev_ops i40e_eth_dev_ops = {
+	.dev_configure                = i40e_dev_configure,
+	.dev_start                    = i40e_dev_start,
+	.dev_stop                     = i40e_dev_stop,
+	.dev_close                    = i40e_dev_close,
+	.promiscuous_enable           = i40e_dev_promiscuous_enable,
+	.promiscuous_disable          = i40e_dev_promiscuous_disable,
+	.allmulticast_enable          = i40e_dev_allmulticast_enable,
+	.allmulticast_disable         = i40e_dev_allmulticast_disable,
+	.link_update                  = i40e_dev_link_update,
+	.stats_get                    = i40e_dev_stats_get,
+	.stats_reset                  = i40e_dev_stats_reset,
+	.queue_stats_mapping_set      = i40e_dev_queue_stats_mapping_set,
+	.dev_infos_get                = i40e_dev_info_get,
+	.vlan_filter_set              = i40e_vlan_filter_set,
+	.vlan_tpid_set                = i40e_vlan_tpid_set,
+	.vlan_offload_set             = i40e_vlan_offload_set,
+	.vlan_strip_queue_set         = i40e_vlan_strip_queue_set,
+	.vlan_pvid_set                = i40e_vlan_pvid_set,
+	.rx_queue_setup               = i40e_dev_rx_queue_setup,
+	.rx_queue_release             = i40e_dev_rx_queue_release,
+	.rx_queue_count               = i40e_dev_rx_queue_count,
+	.rx_descriptor_done           = i40e_dev_rx_descriptor_done,
+	.tx_queue_setup               = i40e_dev_tx_queue_setup,
+	.tx_queue_release             = i40e_dev_tx_queue_release,
+	.dev_led_on                   = i40e_dev_led_on,
+	.dev_led_off                  = i40e_dev_led_off,
+	.flow_ctrl_set                = i40e_flow_ctrl_set,
+	.priority_flow_ctrl_set       = i40e_priority_flow_ctrl_set,
+	.mac_addr_add                 = i40e_macaddr_add,
+	.mac_addr_remove              = i40e_macaddr_remove,
+	.reta_update                  = i40e_dev_rss_reta_update,
+	.reta_query                   = i40e_dev_rss_reta_query,
+	.rss_hash_update              = i40e_dev_rss_hash_update,
+	.rss_hash_conf_get            = i40e_dev_rss_hash_conf_get,
+};
+
+static struct eth_driver rte_i40e_pmd = {
+	{
+		.name = "rte_i40e_pmd",
+		.id_table = pci_id_i40e_map,
+		.drv_flags = RTE_PCI_DRV_NEED_IGB_UIO,
+	},
+	.eth_dev_init = eth_i40e_dev_init,
+	.dev_private_size = sizeof(struct i40e_adapter),
+};
+
+static inline int
+i40e_prev_power_of_2(int n)
+{
+       int p = n;
+
+       --p;
+       p |= p >> 1;
+       p |= p >> 2;
+       p |= p >> 4;
+       p |= p >> 8;
+       p |= p >> 16;
+       if (p == (n - 1))
+               return n;
+       p >>= 1;
+
+       return ++p;
+}
+
+static inline int
+rte_i40e_dev_atomic_read_link_status(struct rte_eth_dev *dev,
+				     struct rte_eth_link *link)
+{
+	struct rte_eth_link *dst = link;
+	struct rte_eth_link *src = &(dev->data->dev_link);
+
+	if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
+					*(uint64_t *)src) == 0)
+		return -1;
+
+	return 0;
+}
+
+static inline int
+rte_i40e_dev_atomic_write_link_status(struct rte_eth_dev *dev,
+				      struct rte_eth_link *link)
+{
+	struct rte_eth_link *dst = &(dev->data->dev_link);
+	struct rte_eth_link *src = link;
+
+	if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
+					*(uint64_t *)src) == 0)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * Driver initialization routine.
+ * Invoked once at EAL init time.
+ * Register itself as the [Poll Mode] Driver of PCI IXGBE devices.
+ */
+static int
+rte_i40e_pmd_init(const char *name __rte_unused,
+		  const char *params __rte_unused)
+{
+	PMD_INIT_FUNC_TRACE();
+	rte_eth_driver_register(&rte_i40e_pmd);
+
+	return 0;
+}
+
+static struct rte_driver rte_i40e_driver = {
+	.type = PMD_PDEV,
+	.init = rte_i40e_pmd_init,
+};
+
+PMD_REGISTER_DRIVER(rte_i40e_driver);
+
+static int
+eth_i40e_dev_init(__rte_unused struct eth_driver *eth_drv,
+                  struct rte_eth_dev *dev)
+{
+	struct rte_pci_device *pci_dev;
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_vsi *vsi;
+	int ret;
+	uint32_t len;
+	uint8_t aq_fail = 0;
+
+	PMD_INIT_FUNC_TRACE();
+
+	dev->dev_ops = &i40e_eth_dev_ops;
+	dev->rx_pkt_burst = i40e_recv_pkts;
+	dev->tx_pkt_burst = i40e_xmit_pkts;
+
+	/* for secondary processes, we don't initialise any further as primary
+	 * has already done this work. Only check we don't need a different
+	 * RX function */
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY){
+		if (dev->data->scattered_rx)
+			dev->rx_pkt_burst = i40e_recv_scattered_pkts;
+		return 0;
+	}
+	pci_dev = dev->pci_dev;
+	pf->adapter = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+	pf->adapter->eth_dev = dev;
+	pf->dev_data = dev->data;
+
+	hw->back = I40E_PF_TO_ADAPTER(pf);
+	hw->hw_addr = (uint8_t *)(pci_dev->mem_resource[0].addr);
+	if (!hw->hw_addr) {
+		PMD_INIT_LOG(ERR, "Hardware is not available, "
+					"as address is NULL\n");
+		return -ENODEV;
+	}
+
+	hw->vendor_id = pci_dev->id.vendor_id;
+	hw->device_id = pci_dev->id.device_id;
+	hw->subsystem_vendor_id = pci_dev->id.subsystem_vendor_id;
+	hw->subsystem_device_id = pci_dev->id.subsystem_device_id;
+	hw->bus.device = pci_dev->addr.devid;
+	hw->bus.func = pci_dev->addr.function;
+
+	/* Disable all queues before PF reset, as required */
+	ret = i40e_pf_disable_all_queues(hw);
+	if (ret != I40E_SUCCESS) {
+		PMD_INIT_LOG(ERR, "Failed to disable queues %u\n", ret);
+		return ret;
+	}
+
+	/* Reset here to make sure all is clean for each PF */
+	ret = i40e_pf_reset(hw);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "Failed to reset pf: %d", ret);
+		return ret;
+	}
+
+	/* Initialize the shared code */
+	ret = i40e_init_shared_code(hw);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "Failed to init shared code: %d", ret);
+		return ret;
+	}
+
+	/* Initialize the parameters for adminq */
+	i40e_init_adminq_parameter(hw);
+	ret = i40e_init_adminq(hw);
+	if (ret != I40E_SUCCESS) {
+		PMD_INIT_LOG(ERR, "Failed to init adminq: %d", ret);
+		return -EIO;
+	}
+	PMD_INIT_LOG(INFO, "FW %d.%d API %d.%d NVM "
+			"%02d.%02d.%02d eetrack %04x\n",
+			hw->aq.fw_maj_ver, hw->aq.fw_min_ver,
+			hw->aq.api_maj_ver, hw->aq.api_min_ver,
+			((hw->nvm.version >> 12) & 0xf),
+			((hw->nvm.version >> 4) & 0xff),
+			(hw->nvm.version & 0xf), hw->nvm.eetrack);
+
+	/* Disable LLDP */
+	ret = i40e_aq_stop_lldp(hw, true, NULL);
+	if (ret != I40E_SUCCESS) /* Its failure can be ignored */
+		PMD_INIT_LOG(INFO, "Failed to stop lldp\n");
+
+	/* Clear PXE mode */
+	i40e_clear_pxe_mode(hw);
+
+	/* Get hw capabilities */
+	ret = i40e_get_cap(hw);
+	if (ret != I40E_SUCCESS) {
+		PMD_INIT_LOG(ERR, "Failed to get capabilities: %d", ret);
+		goto err_get_capabilities;
+	}
+
+	/* Initialize parameters for PF */
+	ret = i40e_pf_parameter_init(dev);
+	if (ret != 0) {
+		PMD_INIT_LOG(ERR, "Failed to do parameter init: %d", ret);
+		goto err_parameter_init;
+	}
+
+	/* Initialize the queue management */
+	ret = i40e_res_pool_init(&pf->qp_pool, 0, hw->func_caps.num_tx_qp);
+	if (ret < 0) {
+		PMD_INIT_LOG(ERR, "Failed to init queue pool\n");
+		goto err_qp_pool_init;
+	}
+	ret = i40e_res_pool_init(&pf->msix_pool, 1,
+				hw->func_caps.num_msix_vectors - 1);
+	if (ret < 0) {
+		PMD_INIT_LOG(ERR, "Failed to init MSIX pool\n");
+		goto err_msix_pool_init;
+	}
+
+	/* Initialize lan hmc */
+	ret = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
+				hw->func_caps.num_rx_qp, 0, 0);
+	if (ret != I40E_SUCCESS) {
+		PMD_INIT_LOG(ERR, "Failed to init lan hmc: %d", ret);
+		goto err_init_lan_hmc;
+	}
+
+	/* Configure lan hmc */
+	ret = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
+	if (ret != I40E_SUCCESS) {
+		PMD_INIT_LOG(ERR, "Failed to configure lan hmc: %d", ret);
+		goto err_configure_lan_hmc;
+	}
+
+	/* Get and check the mac address */
+	i40e_get_mac_addr(hw, hw->mac.addr);
+	if (i40e_validate_mac_addr(hw->mac.addr) != I40E_SUCCESS) {
+		PMD_INIT_LOG(ERR, "mac address is not valid");
+		ret = -EIO;
+		goto err_get_mac_addr;
+	}
+	/* Copy the permanent MAC address */
+	ether_addr_copy((struct ether_addr *) hw->mac.addr,
+			(struct ether_addr *) hw->mac.perm_addr);
+
+	/* Disable flow control */
+	hw->fc.requested_mode = I40E_FC_NONE;
+	i40e_set_fc(hw, &aq_fail, TRUE);
+
+	/* PF setup, which includes VSI setup */
+	ret = i40e_pf_setup(pf);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "Failed to setup pf switch: %d", ret);
+		goto err_setup_pf_switch;
+	}
+
+	vsi = pf->main_vsi;
+	if (!vsi->max_macaddrs)
+		len = ETHER_ADDR_LEN;
+	else
+		len = ETHER_ADDR_LEN * vsi->max_macaddrs;
+
+	/* Should be after VSI initialized */
+	dev->data->mac_addrs = rte_zmalloc("i40e", len, 0);
+	if (!dev->data->mac_addrs) {
+		PMD_INIT_LOG(ERR, "Failed to allocated memory "
+					"for storing mac address");
+		goto err_get_mac_addr;
+	}
+	ether_addr_copy((struct ether_addr *)hw->mac.perm_addr,
+					&dev->data->mac_addrs[0]);
+
+	/* initialize pf host driver to setup SRIOV resource if applicable */
+	i40e_pf_host_init(dev);
+
+	/* register callback func to eal lib */
+	rte_intr_callback_register(&(pci_dev->intr_handle),
+		i40e_dev_interrupt_handler, (void *)dev);
+
+	/* configure and enable device interrupt */
+	i40e_pf_config_irq0(hw);
+	i40e_pf_enable_irq0(hw);
+
+	/* enable uio intr after callback register */
+	rte_intr_enable(&(pci_dev->intr_handle));
+
+	return 0;
+
+err_setup_pf_switch:
+	rte_free(pf->main_vsi);
+err_get_mac_addr:
+err_configure_lan_hmc:
+	(void)i40e_shutdown_lan_hmc(hw);
+err_init_lan_hmc:
+	i40e_res_pool_destroy(&pf->msix_pool);
+err_msix_pool_init:
+	i40e_res_pool_destroy(&pf->qp_pool);
+err_qp_pool_init:
+err_parameter_init:
+err_get_capabilities:
+	(void)i40e_shutdown_adminq(hw);
+
+	return ret;
+}
+
+static int
+i40e_dev_configure(struct rte_eth_dev *dev)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_vsi *vsi = pf->main_vsi;
+	int ret;
+
+	ret = i40e_vsi_init_vlan(vsi);
+
+	return ret;
+}
+
+void
+i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
+{
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	uint16_t msix_vect = vsi->msix_intr;
+	uint16_t i;
+
+	for (i = 0; i < vsi->nb_qps; i++) {
+		I40E_WRITE_REG(hw, I40E_QINT_TQCTL(vsi->base_queue + i), 0);
+		I40E_WRITE_REG(hw, I40E_QINT_RQCTL(vsi->base_queue + i), 0);
+		rte_wmb();
+	}
+
+	if (vsi->type != I40E_VSI_SRIOV) {
+		I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1), 0);
+		I40E_WRITE_REG(hw, I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
+				msix_vect - 1), 0);
+	} else {
+		uint32_t reg;
+		reg = (hw->func_caps.num_msix_vectors_vf - 1) *
+			vsi->user_param + (msix_vect - 1);
+
+		I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg), 0);
+	}
+	I40E_WRITE_FLUSH(hw);
+}
+
+static inline uint16_t
+i40e_calc_itr_interval(int16_t interval)
+{
+	if (interval < 0 || interval > I40E_QUEUE_ITR_INTERVAL_MAX)
+		interval = I40E_QUEUE_ITR_INTERVAL_DEFAULT;
+
+	/* Convert to hardware count, as writing each 1 represents 2 us */
+	return (interval/2);
+}
+
+void
+i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
+{
+	uint32_t val;
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	uint16_t msix_vect = vsi->msix_intr;
+	uint16_t interval = i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);
+	int i;
+
+	for (i = 0; i < vsi->nb_qps; i++)
+		I40E_WRITE_REG(hw, I40E_QINT_TQCTL(vsi->base_queue + i), 0);
+
+	/* Bind all RX queues to allocated MSIX interrupt */
+	for (i = 0; i < vsi->nb_qps; i++) {
+		val = (msix_vect << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
+			(interval << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
+			((vsi->base_queue + i + 1) <<
+			I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
+			(0 << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
+			I40E_QINT_RQCTL_CAUSE_ENA_MASK;
+
+		if (i == vsi->nb_qps - 1)
+			val |= I40E_QINT_RQCTL_NEXTQ_INDX_MASK;
+		I40E_WRITE_REG(hw, I40E_QINT_RQCTL(vsi->base_queue + i), val);
+	}
+
+	/* Write first RX queue to Link list register as the head element */
+	if (vsi->type != I40E_VSI_SRIOV) {
+		I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(msix_vect - 1),
+			(vsi->base_queue << I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+			(0x0 << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+
+		I40E_WRITE_REG(hw, I40E_PFINT_ITRN(I40E_ITR_INDEX_DEFAULT,
+				msix_vect - 1), interval);
+
+		/* Disable auto-mask on enabling of all none-zero  interrupt */
+		I40E_WRITE_REG(hw, I40E_GLINT_CTL,
+				I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK);
+	}
+	else {
+		uint32_t reg;
+		/* num_msix_vectors_vf needs to minus irq0 */
+		reg = (hw->func_caps.num_msix_vectors_vf - 1) *
+			vsi->user_param + (msix_vect - 1);
+
+		I40E_WRITE_REG(hw, I40E_VPINT_LNKLSTN(reg),
+			(vsi->base_queue << I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
+			(0x0 << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT));
+	}
+
+	I40E_WRITE_FLUSH(hw);
+}
+
+static void
+i40e_vsi_enable_queues_intr(struct i40e_vsi *vsi)
+{
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	uint16_t interval = i40e_calc_itr_interval(\
+			RTE_LIBRTE_I40E_ITR_INTERVAL);
+
+	I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vsi->msix_intr - 1),
+					I40E_PFINT_DYN_CTLN_INTENA_MASK |
+					I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+				(0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
+			(interval << I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+}
+
+static void
+i40e_vsi_disable_queues_intr(struct i40e_vsi *vsi)
+{
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+
+	I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vsi->msix_intr - 1), 0);
+}
+
+static int
+i40e_dev_start(struct rte_eth_dev *dev)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_vsi *vsi = pf->main_vsi;
+	int ret;
+
+	/* Initialize VSI */
+	ret = i40e_vsi_init(vsi);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to init VSI\n");
+		goto err_up;
+	}
+
+	/* Map queues with MSIX interrupt */
+	i40e_vsi_queues_bind_intr(vsi);
+	i40e_vsi_enable_queues_intr(vsi);
+
+	/* Enable all queues which have been configured */
+	ret = i40e_vsi_switch_queues(vsi, TRUE);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to enable VSI\n");
+		goto err_up;
+	}
+
+	/* Enable receiving broadcast packets */
+	if ((vsi->type == I40E_VSI_MAIN) || (vsi->type == I40E_VSI_VMDQ2)) {
+		ret = i40e_aq_set_vsi_broadcast(hw, vsi->seid, true, NULL);
+		if (ret != I40E_SUCCESS)
+			PMD_DRV_LOG(INFO, "fail to set vsi broadcast\n");
+	}
+
+	return I40E_SUCCESS;
+
+err_up:
+	i40e_vsi_switch_queues(vsi, FALSE);
+	i40e_dev_clear_queues(dev);
+
+	return ret;
+}
+
+static void
+i40e_dev_stop(struct rte_eth_dev *dev)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_vsi *vsi = pf->main_vsi;
+
+	/* Disable all queues */
+	i40e_vsi_switch_queues(vsi, FALSE);
+
+	/* Clear all queues and release memory */
+	i40e_dev_clear_queues(dev);
+
+	/* un-map queues with interrupt registers */
+	i40e_vsi_disable_queues_intr(vsi);
+	i40e_vsi_queues_unbind_intr(vsi);
+}
+
+static void
+i40e_dev_close(struct rte_eth_dev *dev)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t reg;
+
+	PMD_INIT_FUNC_TRACE();
+
+	i40e_dev_stop(dev);
+
+	/* Disable interrupt */
+	i40e_pf_disable_irq0(hw);
+	rte_intr_disable(&(dev->pci_dev->intr_handle));
+
+	/* shutdown and destroy the HMC */
+	i40e_shutdown_lan_hmc(hw);
+
+	/* release all the existing VSIs and VEBs */
+	i40e_vsi_release(pf->main_vsi);
+
+	/* shutdown the adminq */
+	i40e_aq_queue_shutdown(hw, true);
+	i40e_shutdown_adminq(hw);
+
+	i40e_res_pool_destroy(&pf->qp_pool);
+
+	/* force a PF reset to clean anything leftover */
+	reg = I40E_READ_REG(hw, I40E_PFGEN_CTRL);
+	I40E_WRITE_REG(hw, I40E_PFGEN_CTRL,
+			(reg | I40E_PFGEN_CTRL_PFSWR_MASK));
+	I40E_WRITE_FLUSH(hw);
+}
+
+static void
+i40e_dev_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_vsi *vsi = pf->main_vsi;
+	int status;
+
+	status = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid,
+							true, NULL);
+	if (status != I40E_SUCCESS)
+		PMD_DRV_LOG(ERR, "Failed to enable unicast promiscuous\n");
+}
+
+static void
+i40e_dev_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_vsi *vsi = pf->main_vsi;
+	int status;
+
+	status = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid,
+							false, NULL);
+	if (status != I40E_SUCCESS)
+		PMD_DRV_LOG(ERR, "Failed to disable unicast promiscuous\n");
+}
+
+static void
+i40e_dev_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_vsi *vsi = pf->main_vsi;
+	int ret;
+
+	ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid, TRUE, NULL);
+	if (ret != I40E_SUCCESS)
+		PMD_DRV_LOG(ERR, "Failed to enable multicast promiscuous\n");
+}
+
+static void
+i40e_dev_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_vsi *vsi = pf->main_vsi;
+	int ret;
+
+	ret = i40e_aq_set_vsi_multicast_promiscuous(hw,
+				vsi->seid, FALSE, NULL);
+	if (ret != I40E_SUCCESS)
+		PMD_DRV_LOG(ERR, "Failed to disable multicast promiscuous\n");
+}
+
+int
+i40e_dev_link_update(struct rte_eth_dev *dev,
+		     __rte_unused int wait_to_complete)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_link_status link_status;
+	struct rte_eth_link link, old;
+	int status;
+
+	memset(&link, 0, sizeof(link));
+	memset(&old, 0, sizeof(old));
+	memset(&link_status, 0, sizeof(link_status));
+	rte_i40e_dev_atomic_read_link_status(dev, &old);
+
+	/* Get link status information from hardware */
+	status = i40e_aq_get_link_info(hw, false, &link_status, NULL);
+	if (status != I40E_SUCCESS) {
+		link.link_speed = ETH_LINK_SPEED_100;
+		link.link_duplex = ETH_LINK_FULL_DUPLEX;
+		PMD_DRV_LOG(ERR, "Failed to get link info\n");
+		goto out;
+	}
+
+	link.link_status = link_status.link_info & I40E_AQ_LINK_UP;
+
+	if (!link.link_status)
+		goto out;
+
+	/* i40e uses full duplex only */
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
+
+	/* Parse the link status */
+	switch (link_status.link_speed) {
+	case I40E_LINK_SPEED_100MB:
+		link.link_speed = ETH_LINK_SPEED_100;
+		break;
+	case I40E_LINK_SPEED_1GB:
+		link.link_speed = ETH_LINK_SPEED_1000;
+		break;
+	case I40E_LINK_SPEED_10GB:
+		link.link_speed = ETH_LINK_SPEED_10G;
+		break;
+	case I40E_LINK_SPEED_20GB:
+		link.link_speed = ETH_LINK_SPEED_20G;
+		break;
+	case I40E_LINK_SPEED_40GB:
+		link.link_speed = ETH_LINK_SPEED_40G;
+		break;
+	default:
+		link.link_speed = ETH_LINK_SPEED_100;
+		break;
+	}
+
+out:
+	rte_i40e_dev_atomic_write_link_status(dev, &link);
+	if (link.link_status == old.link_status)
+		return -1;
+
+	return 0;
+}
+
+/* Get all the statistics of a VSI */
+void
+i40e_update_vsi_stats(struct i40e_vsi *vsi)
+{
+	struct i40e_eth_stats *oes = &vsi->eth_stats_offset;
+	struct i40e_eth_stats *nes = &vsi->eth_stats;
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	int idx = rte_le_to_cpu_16(vsi->info.stat_counter_idx);
+
+	i40e_stat_update_48(hw, I40E_GLV_GORCH(idx), I40E_GLV_GORCL(idx),
+			    vsi->offset_loaded, &oes->rx_bytes,
+			    &nes->rx_bytes);
+	i40e_stat_update_48(hw, I40E_GLV_UPRCH(idx), I40E_GLV_UPRCL(idx),
+			    vsi->offset_loaded, &oes->rx_unicast,
+			    &nes->rx_unicast);
+	i40e_stat_update_48(hw, I40E_GLV_MPRCH(idx), I40E_GLV_MPRCL(idx),
+			    vsi->offset_loaded, &oes->rx_multicast,
+			    &nes->rx_multicast);
+	i40e_stat_update_48(hw, I40E_GLV_BPRCH(idx), I40E_GLV_BPRCL(idx),
+			    vsi->offset_loaded, &oes->rx_broadcast,
+			    &nes->rx_broadcast);
+	i40e_stat_update_32(hw, I40E_GLV_RDPC(idx), vsi->offset_loaded,
+			    &oes->rx_discards, &nes->rx_discards);
+	/* GLV_REPC not supported */
+	/* GLV_RMPC not supported */
+	i40e_stat_update_32(hw, I40E_GLV_RUPP(idx), vsi->offset_loaded,
+			    &oes->rx_unknown_protocol,
+			    &nes->rx_unknown_protocol);
+	i40e_stat_update_48(hw, I40E_GLV_GOTCH(idx), I40E_GLV_GOTCL(idx),
+			    vsi->offset_loaded, &oes->tx_bytes,
+			    &nes->tx_bytes);
+	i40e_stat_update_48(hw, I40E_GLV_UPTCH(idx), I40E_GLV_UPTCL(idx),
+			    vsi->offset_loaded, &oes->tx_unicast,
+			    &nes->tx_unicast);
+	i40e_stat_update_48(hw, I40E_GLV_MPTCH(idx), I40E_GLV_MPTCL(idx),
+			    vsi->offset_loaded, &oes->tx_multicast,
+			    &nes->tx_multicast);
+	i40e_stat_update_48(hw, I40E_GLV_BPTCH(idx), I40E_GLV_BPTCL(idx),
+			    vsi->offset_loaded,  &oes->tx_broadcast,
+			    &nes->tx_broadcast);
+	/* GLV_TDPC not supported */
+	i40e_stat_update_32(hw, I40E_GLV_TEPC(idx), vsi->offset_loaded,
+			    &oes->tx_errors, &nes->tx_errors);
+	vsi->offset_loaded = true;
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_DRIVER
+	printf("***************** VSI[%u] stats start *******************\n",
+								vsi->vsi_id);
+	printf("rx_bytes:            %lu\n", nes->rx_bytes);
+	printf("rx_unicast:          %lu\n", nes->rx_unicast);
+	printf("rx_multicast:        %lu\n", nes->rx_multicast);
+	printf("rx_broadcast:        %lu\n", nes->rx_broadcast);
+	printf("rx_discards:         %lu\n", nes->rx_discards);
+	printf("rx_unknown_protocol: %lu\n", nes->rx_unknown_protocol);
+	printf("tx_bytes:            %lu\n", nes->tx_bytes);
+	printf("tx_unicast:          %lu\n", nes->tx_unicast);
+	printf("tx_multicast:        %lu\n", nes->tx_multicast);
+	printf("tx_broadcast:        %lu\n", nes->tx_broadcast);
+	printf("tx_discards:         %lu\n", nes->tx_discards);
+	printf("tx_errors:           %lu\n", nes->tx_errors);
+	printf("***************** VSI[%u] stats end *******************\n",
+								vsi->vsi_id);
+#endif /* RTE_LIBRTE_I40E_DEBUG_DRIVER */
+}
+
+/* Get all statistics of a port */
+static void
+i40e_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	uint32_t i;
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_hw_port_stats *ns = &pf->stats; /* new stats */
+	struct i40e_hw_port_stats *os = &pf->stats_offset; /* old stats */
+
+	/* Get statistics of struct i40e_eth_stats */
+	i40e_stat_update_48(hw, I40E_GLPRT_GORCH(hw->port),
+			    I40E_GLPRT_GORCL(hw->port),
+			    pf->offset_loaded, &os->eth.rx_bytes,
+			    &ns->eth.rx_bytes);
+	i40e_stat_update_48(hw, I40E_GLPRT_UPRCH(hw->port),
+			    I40E_GLPRT_UPRCL(hw->port),
+			    pf->offset_loaded, &os->eth.rx_unicast,
+			    &ns->eth.rx_unicast);
+	i40e_stat_update_48(hw, I40E_GLPRT_MPRCH(hw->port),
+			    I40E_GLPRT_MPRCL(hw->port),
+			    pf->offset_loaded, &os->eth.rx_multicast,
+			    &ns->eth.rx_multicast);
+	i40e_stat_update_48(hw, I40E_GLPRT_BPRCH(hw->port),
+			    I40E_GLPRT_BPRCL(hw->port),
+			    pf->offset_loaded, &os->eth.rx_broadcast,
+			    &ns->eth.rx_broadcast);
+	i40e_stat_update_32(hw, I40E_GLPRT_RDPC(hw->port),
+			    pf->offset_loaded, &os->eth.rx_discards,
+			    &ns->eth.rx_discards);
+	/* GLPRT_REPC not supported */
+	/* GLPRT_RMPC not supported */
+	i40e_stat_update_32(hw, I40E_GLPRT_RUPP(hw->port),
+			    pf->offset_loaded,
+			    &os->eth.rx_unknown_protocol,
+			    &ns->eth.rx_unknown_protocol);
+	i40e_stat_update_48(hw, I40E_GLPRT_GOTCH(hw->port),
+			    I40E_GLPRT_GOTCL(hw->port),
+			    pf->offset_loaded, &os->eth.tx_bytes,
+			    &ns->eth.tx_bytes);
+	i40e_stat_update_48(hw, I40E_GLPRT_UPTCH(hw->port),
+			    I40E_GLPRT_UPTCL(hw->port),
+			    pf->offset_loaded, &os->eth.tx_unicast,
+			    &ns->eth.tx_unicast);
+	i40e_stat_update_48(hw, I40E_GLPRT_MPTCH(hw->port),
+			    I40E_GLPRT_MPTCL(hw->port),
+			    pf->offset_loaded, &os->eth.tx_multicast,
+			    &ns->eth.tx_multicast);
+	i40e_stat_update_48(hw, I40E_GLPRT_BPTCH(hw->port),
+			    I40E_GLPRT_BPTCL(hw->port),
+			    pf->offset_loaded, &os->eth.tx_broadcast,
+			    &ns->eth.tx_broadcast);
+	i40e_stat_update_32(hw, I40E_GLPRT_TDPC(hw->port),
+			    pf->offset_loaded, &os->eth.tx_discards,
+			    &ns->eth.tx_discards);
+	/* GLPRT_TEPC not supported */
+
+	/* additional port specific stats */
+	i40e_stat_update_32(hw, I40E_GLPRT_TDOLD(hw->port),
+			    pf->offset_loaded, &os->tx_dropped_link_down,
+			    &ns->tx_dropped_link_down);
+	i40e_stat_update_32(hw, I40E_GLPRT_CRCERRS(hw->port),
+			    pf->offset_loaded, &os->crc_errors,
+			    &ns->crc_errors);
+	i40e_stat_update_32(hw, I40E_GLPRT_ILLERRC(hw->port),
+			    pf->offset_loaded, &os->illegal_bytes,
+			    &ns->illegal_bytes);
+	/* GLPRT_ERRBC not supported */
+	i40e_stat_update_32(hw, I40E_GLPRT_MLFC(hw->port),
+			    pf->offset_loaded, &os->mac_local_faults,
+			    &ns->mac_local_faults);
+	i40e_stat_update_32(hw, I40E_GLPRT_MRFC(hw->port),
+			    pf->offset_loaded, &os->mac_remote_faults,
+			    &ns->mac_remote_faults);
+	i40e_stat_update_32(hw, I40E_GLPRT_RLEC(hw->port),
+			    pf->offset_loaded, &os->rx_length_errors,
+			    &ns->rx_length_errors);
+	i40e_stat_update_32(hw, I40E_GLPRT_LXONRXC(hw->port),
+			    pf->offset_loaded, &os->link_xon_rx,
+			    &ns->link_xon_rx);
+	i40e_stat_update_32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
+			    pf->offset_loaded, &os->link_xoff_rx,
+			    &ns->link_xoff_rx);
+	for (i = 0; i < 8; i++) {
+		i40e_stat_update_32(hw, I40E_GLPRT_PXONRXC(hw->port, i),
+				    pf->offset_loaded,
+				    &os->priority_xon_rx[i],
+				    &ns->priority_xon_rx[i]);
+		i40e_stat_update_32(hw, I40E_GLPRT_PXOFFRXC(hw->port, i),
+				    pf->offset_loaded,
+				    &os->priority_xoff_rx[i],
+				    &ns->priority_xoff_rx[i]);
+	}
+	i40e_stat_update_32(hw, I40E_GLPRT_LXONTXC(hw->port),
+			    pf->offset_loaded, &os->link_xon_tx,
+			    &ns->link_xon_tx);
+	i40e_stat_update_32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
+			    pf->offset_loaded, &os->link_xoff_tx,
+			    &ns->link_xoff_tx);
+	for (i = 0; i < 8; i++) {
+		i40e_stat_update_32(hw, I40E_GLPRT_PXONTXC(hw->port, i),
+				    pf->offset_loaded,
+				    &os->priority_xon_tx[i],
+				    &ns->priority_xon_tx[i]);
+		i40e_stat_update_32(hw, I40E_GLPRT_PXOFFTXC(hw->port, i),
+				    pf->offset_loaded,
+				    &os->priority_xoff_tx[i],
+				    &ns->priority_xoff_tx[i]);
+		i40e_stat_update_32(hw, I40E_GLPRT_RXON2OFFCNT(hw->port, i),
+				    pf->offset_loaded,
+				    &os->priority_xon_2_xoff[i],
+				    &ns->priority_xon_2_xoff[i]);
+	}
+	i40e_stat_update_48(hw, I40E_GLPRT_PRC64H(hw->port),
+			    I40E_GLPRT_PRC64L(hw->port),
+			    pf->offset_loaded, &os->rx_size_64,
+			    &ns->rx_size_64);
+	i40e_stat_update_48(hw, I40E_GLPRT_PRC127H(hw->port),
+			    I40E_GLPRT_PRC127L(hw->port),
+			    pf->offset_loaded, &os->rx_size_127,
+			    &ns->rx_size_127);
+	i40e_stat_update_48(hw, I40E_GLPRT_PRC255H(hw->port),
+			    I40E_GLPRT_PRC255L(hw->port),
+			    pf->offset_loaded, &os->rx_size_255,
+			    &ns->rx_size_255);
+	i40e_stat_update_48(hw, I40E_GLPRT_PRC511H(hw->port),
+			    I40E_GLPRT_PRC511L(hw->port),
+			    pf->offset_loaded, &os->rx_size_511,
+			    &ns->rx_size_511);
+	i40e_stat_update_48(hw, I40E_GLPRT_PRC1023H(hw->port),
+			    I40E_GLPRT_PRC1023L(hw->port),
+			    pf->offset_loaded, &os->rx_size_1023,
+			    &ns->rx_size_1023);
+	i40e_stat_update_48(hw, I40E_GLPRT_PRC1522H(hw->port),
+			    I40E_GLPRT_PRC1522L(hw->port),
+			    pf->offset_loaded, &os->rx_size_1522,
+			    &ns->rx_size_1522);
+	i40e_stat_update_48(hw, I40E_GLPRT_PRC9522H(hw->port),
+			    I40E_GLPRT_PRC9522L(hw->port),
+			    pf->offset_loaded, &os->rx_size_big,
+			    &ns->rx_size_big);
+	i40e_stat_update_32(hw, I40E_GLPRT_RUC(hw->port),
+			    pf->offset_loaded, &os->rx_undersize,
+			    &ns->rx_undersize);
+	i40e_stat_update_32(hw, I40E_GLPRT_RFC(hw->port),
+			    pf->offset_loaded, &os->rx_fragments,
+			    &ns->rx_fragments);
+	i40e_stat_update_32(hw, I40E_GLPRT_ROC(hw->port),
+			    pf->offset_loaded, &os->rx_oversize,
+			    &ns->rx_oversize);
+	i40e_stat_update_32(hw, I40E_GLPRT_RJC(hw->port),
+			    pf->offset_loaded, &os->rx_jabber,
+			    &ns->rx_jabber);
+	i40e_stat_update_48(hw, I40E_GLPRT_PTC64H(hw->port),
+			    I40E_GLPRT_PTC64L(hw->port),
+			    pf->offset_loaded, &os->tx_size_64,
+			    &ns->tx_size_64);
+	i40e_stat_update_48(hw, I40E_GLPRT_PTC127H(hw->port),
+			    I40E_GLPRT_PTC127L(hw->port),
+			    pf->offset_loaded, &os->tx_size_127,
+			    &ns->tx_size_127);
+	i40e_stat_update_48(hw, I40E_GLPRT_PTC255H(hw->port),
+			    I40E_GLPRT_PTC255L(hw->port),
+			    pf->offset_loaded, &os->tx_size_255,
+			    &ns->tx_size_255);
+	i40e_stat_update_48(hw, I40E_GLPRT_PTC511H(hw->port),
+			    I40E_GLPRT_PTC511L(hw->port),
+			    pf->offset_loaded, &os->tx_size_511,
+			    &ns->tx_size_511);
+	i40e_stat_update_48(hw, I40E_GLPRT_PTC1023H(hw->port),
+			    I40E_GLPRT_PTC1023L(hw->port),
+			    pf->offset_loaded, &os->tx_size_1023,
+			    &ns->tx_size_1023);
+	i40e_stat_update_48(hw, I40E_GLPRT_PTC1522H(hw->port),
+			    I40E_GLPRT_PTC1522L(hw->port),
+			    pf->offset_loaded, &os->tx_size_1522,
+			    &ns->tx_size_1522);
+	i40e_stat_update_48(hw, I40E_GLPRT_PTC9522H(hw->port),
+			    I40E_GLPRT_PTC9522L(hw->port),
+			    pf->offset_loaded, &os->tx_size_big,
+			    &ns->tx_size_big);
+	/* GLPRT_MSPDC not supported */
+	/* GLPRT_XEC not supported */
+
+	pf->offset_loaded = true;
+
+	stats->ipackets = ns->eth.rx_unicast + ns->eth.rx_multicast +
+						ns->eth.rx_broadcast;
+	stats->opackets = ns->eth.tx_unicast + ns->eth.tx_multicast +
+						ns->eth.tx_broadcast;
+	stats->ibytes   = ns->eth.rx_bytes;
+	stats->obytes   = ns->eth.tx_bytes;
+	stats->oerrors  = ns->eth.tx_errors;
+	stats->imcasts  = ns->eth.rx_multicast;
+
+	if (pf->main_vsi)
+		i40e_update_vsi_stats(pf->main_vsi);
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_DRIVER
+	printf("***************** PF stats start *******************\n");
+	printf("rx_bytes:            %lu\n", ns->eth.rx_bytes);
+	printf("rx_unicast:          %lu\n", ns->eth.rx_unicast);
+	printf("rx_multicast:        %lu\n", ns->eth.rx_multicast);
+	printf("rx_broadcast:        %lu\n", ns->eth.rx_broadcast);
+	printf("rx_discards:         %lu\n", ns->eth.rx_discards);
+	printf("rx_unknown_protocol: %lu\n", ns->eth.rx_unknown_protocol);
+	printf("tx_bytes:            %lu\n", ns->eth.tx_bytes);
+	printf("tx_unicast:          %lu\n", ns->eth.tx_unicast);
+	printf("tx_multicast:        %lu\n", ns->eth.tx_multicast);
+	printf("tx_broadcast:        %lu\n", ns->eth.tx_broadcast);
+	printf("tx_discards:         %lu\n", ns->eth.tx_discards);
+	printf("tx_errors:           %lu\n", ns->eth.tx_errors);
+
+	printf("tx_dropped_link_down:     %lu\n", ns->tx_dropped_link_down);
+	printf("crc_errors:               %lu\n", ns->crc_errors);
+	printf("illegal_bytes:            %lu\n", ns->illegal_bytes);
+	printf("error_bytes:              %lu\n", ns->error_bytes);
+	printf("mac_local_faults:         %lu\n", ns->mac_local_faults);
+	printf("mac_remote_faults:        %lu\n", ns->mac_remote_faults);
+	printf("rx_length_errors:         %lu\n", ns->rx_length_errors);
+	printf("link_xon_rx:              %lu\n", ns->link_xon_rx);
+	printf("link_xoff_rx:             %lu\n", ns->link_xoff_rx);
+	for (i = 0; i < 8; i++) {
+		printf("priority_xon_rx[%d]:      %lu\n",
+				i, ns->priority_xon_rx[i]);
+		printf("priority_xoff_rx[%d]:     %lu\n",
+				i, ns->priority_xoff_rx[i]);
+	}
+	printf("link_xon_tx:              %lu\n", ns->link_xon_tx);
+	printf("link_xoff_tx:             %lu\n", ns->link_xoff_tx);
+	for (i = 0; i < 8; i++) {
+		printf("priority_xon_tx[%d]:      %lu\n",
+				i, ns->priority_xon_tx[i]);
+		printf("priority_xoff_tx[%d]:     %lu\n",
+				i, ns->priority_xoff_tx[i]);
+		printf("priority_xon_2_xoff[%d]:  %lu\n",
+				i, ns->priority_xon_2_xoff[i]);
+	}
+	printf("rx_size_64:               %lu\n", ns->rx_size_64);
+	printf("rx_size_127:              %lu\n", ns->rx_size_127);
+	printf("rx_size_255:              %lu\n", ns->rx_size_255);
+	printf("rx_size_511:              %lu\n", ns->rx_size_511);
+	printf("rx_size_1023:             %lu\n", ns->rx_size_1023);
+	printf("rx_size_1522:             %lu\n", ns->rx_size_1522);
+	printf("rx_size_big:              %lu\n", ns->rx_size_big);
+	printf("rx_undersize:             %lu\n", ns->rx_undersize);
+	printf("rx_fragments:             %lu\n", ns->rx_fragments);
+	printf("rx_oversize:              %lu\n", ns->rx_oversize);
+	printf("rx_jabber:                %lu\n", ns->rx_jabber);
+	printf("tx_size_64:               %lu\n", ns->tx_size_64);
+	printf("tx_size_127:              %lu\n", ns->tx_size_127);
+	printf("tx_size_255:              %lu\n", ns->tx_size_255);
+	printf("tx_size_511:              %lu\n", ns->tx_size_511);
+	printf("tx_size_1023:             %lu\n", ns->tx_size_1023);
+	printf("tx_size_1522:             %lu\n", ns->tx_size_1522);
+	printf("tx_size_big:              %lu\n", ns->tx_size_big);
+	printf("mac_short_packet_dropped: %lu\n",
+			ns->mac_short_packet_dropped);
+	printf("checksum_error:           %lu\n", ns->checksum_error);
+	printf("***************** PF stats end ********************\n");
+#endif /* RTE_LIBRTE_I40E_DEBUG_DRIVER */
+}
+
+/* Reset the statistics */
+static void
+i40e_dev_stats_reset(struct rte_eth_dev *dev)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+
+	/* It results in reloading the start point of each counter */
+	pf->offset_loaded = false;
+}
+
+static int
+i40e_dev_queue_stats_mapping_set(__rte_unused struct rte_eth_dev *dev,
+				 __rte_unused uint16_t queue_id,
+				 __rte_unused uint8_t stat_idx,
+				 __rte_unused uint8_t is_rx)
+{
+	PMD_INIT_FUNC_TRACE();
+
+	return -ENOSYS;
+}
+
+static void
+i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_vsi *vsi = pf->main_vsi;
+
+	dev_info->max_rx_queues = vsi->nb_qps;
+	dev_info->max_tx_queues = vsi->nb_qps;
+	dev_info->min_rx_bufsize = I40E_BUF_SIZE_MIN;
+	dev_info->max_rx_pktlen = I40E_FRAME_SIZE_MAX;
+	dev_info->max_mac_addrs = vsi->max_macaddrs;
+	dev_info->max_vfs = dev->pci_dev->max_vfs;
+	dev_info->rx_offload_capa =
+		DEV_RX_OFFLOAD_VLAN_STRIP |
+		DEV_RX_OFFLOAD_IPV4_CKSUM |
+		DEV_RX_OFFLOAD_UDP_CKSUM |
+		DEV_RX_OFFLOAD_TCP_CKSUM;
+	dev_info->tx_offload_capa =
+		DEV_TX_OFFLOAD_VLAN_INSERT |
+		DEV_TX_OFFLOAD_IPV4_CKSUM |
+		DEV_TX_OFFLOAD_UDP_CKSUM |
+		DEV_TX_OFFLOAD_TCP_CKSUM |
+		DEV_TX_OFFLOAD_SCTP_CKSUM;
+}
+
+static int
+i40e_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_vsi *vsi = pf->main_vsi;
+	PMD_INIT_FUNC_TRACE();
+
+	if (on)
+		return i40e_vsi_add_vlan(vsi, vlan_id);
+	else
+		return i40e_vsi_delete_vlan(vsi, vlan_id);
+}
+
+static void
+i40e_vlan_tpid_set(__rte_unused struct rte_eth_dev *dev,
+		   __rte_unused uint16_t tpid)
+{
+	PMD_INIT_FUNC_TRACE();
+}
+
+static void
+i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_vsi *vsi = pf->main_vsi;
+
+	if (mask & ETH_VLAN_STRIP_MASK) {
+		/* Enable or disable VLAN stripping */
+		if (dev->data->dev_conf.rxmode.hw_vlan_strip)
+			i40e_vsi_config_vlan_stripping(vsi, TRUE);
+		else
+			i40e_vsi_config_vlan_stripping(vsi, FALSE);
+	}
+
+	if (mask & ETH_VLAN_EXTEND_MASK) {
+		if (dev->data->dev_conf.rxmode.hw_vlan_extend)
+			i40e_vsi_config_double_vlan(vsi, TRUE);
+		else
+			i40e_vsi_config_double_vlan(vsi, FALSE);
+	}
+}
+
+static void
+i40e_vlan_strip_queue_set(__rte_unused struct rte_eth_dev *dev,
+			  __rte_unused uint16_t queue,
+			  __rte_unused int on)
+{
+	PMD_INIT_FUNC_TRACE();
+}
+
+static int
+i40e_vlan_pvid_set(struct rte_eth_dev *dev, uint16_t pvid, int on)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	struct i40e_vsi *vsi = pf->main_vsi;
+	struct rte_eth_dev_data *data = I40E_VSI_TO_DEV_DATA(vsi);
+	struct i40e_vsi_context ctxt;
+	uint8_t vlan_flags = 0;
+	int ret;
+
+	if (on) {
+		/**
+		 * If insert pvid is enabled, only tagged pkts are
+		 * allowed to be sent out.
+		 */
+		vlan_flags |= I40E_AQ_VSI_PVLAN_INSERT_PVID |
+				I40E_AQ_VSI_PVLAN_MODE_TAGGED;
+	} else {
+		if (data->dev_conf.txmode.hw_vlan_reject_tagged == 0)
+			vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_TAGGED;
+		if (data->dev_conf.txmode.hw_vlan_reject_untagged == 0)
+			vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_UNTAGGED;
+	}
+	vsi->info.port_vlan_flags &= ~(I40E_AQ_VSI_PVLAN_INSERT_PVID |
+					I40E_AQ_VSI_PVLAN_MODE_MASK);
+	vsi->info.port_vlan_flags |= vlan_flags;
+	vsi->info.pvid = pvid;
+	vsi->info.valid_sections =
+		rte_cpu_to_le_16(I40E_AQ_VSI_PROP_VLAN_VALID);
+	(void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
+	ctxt.seid = vsi->seid;
+	ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
+	if (ret != I40E_SUCCESS)
+		PMD_DRV_LOG(INFO, "Failed to update VSI params\n");
+
+	return ret;
+}
+
+static int
+i40e_dev_led_on(struct rte_eth_dev *dev)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t mode = i40e_led_get(hw);
+
+	if (mode == 0)
+		i40e_led_set(hw, 0xf, true); /* 0xf means led always true */
+
+	return 0;
+}
+
+static int
+i40e_dev_led_off(struct rte_eth_dev *dev)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t mode = i40e_led_get(hw);
+
+	if (mode != 0)
+		i40e_led_set(hw, 0, false);
+
+	return 0;
+}
+
+static int
+i40e_flow_ctrl_set(__rte_unused struct rte_eth_dev *dev,
+		   __rte_unused struct rte_eth_fc_conf *fc_conf)
+{
+	PMD_INIT_FUNC_TRACE();
+
+	return -ENOSYS;
+}
+
+static int
+i40e_priority_flow_ctrl_set(__rte_unused struct rte_eth_dev *dev,
+			    __rte_unused struct rte_eth_pfc_conf *pfc_conf)
+{
+	PMD_INIT_FUNC_TRACE();
+
+	return -ENOSYS;
+}
+
+/* Add a MAC address, and update filters */
+static void
+i40e_macaddr_add(struct rte_eth_dev *dev,
+		 struct ether_addr *mac_addr,
+		 __attribute__((unused)) uint32_t index,
+		 __attribute__((unused)) uint32_t pool)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_vsi *vsi = pf->main_vsi;
+	struct ether_addr old_mac;
+	int ret;
+
+	if (!is_valid_assigned_ether_addr(mac_addr)) {
+		PMD_DRV_LOG(ERR, "Invalid ethernet address\n");
+		return;
+	}
+
+	if (is_same_ether_addr(mac_addr, &(pf->dev_addr))) {
+		PMD_DRV_LOG(INFO, "Ignore adding permanent mac address\n");
+		return;
+	}
+
+	/* Write mac address */
+	ret = i40e_aq_mac_address_write(hw, I40E_AQC_WRITE_TYPE_LAA_ONLY,
+					mac_addr->addr_bytes, NULL);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to write mac address\n");
+		return;
+	}
+
+	(void)rte_memcpy(&old_mac, hw->mac.addr, ETHER_ADDR_LEN);
+	(void)rte_memcpy(hw->mac.addr, mac_addr->addr_bytes,
+			ETHER_ADDR_LEN);
+
+	ret = i40e_vsi_add_mac(vsi, mac_addr);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to add MACVLAN filter\n");
+		return;
+	}
+
+	ether_addr_copy(mac_addr, &pf->dev_addr);
+	i40e_vsi_delete_mac(vsi, &old_mac);
+}
+
+/* Remove a MAC address, and update filters */
+static void
+i40e_macaddr_remove(struct rte_eth_dev *dev, uint32_t index)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_vsi *vsi = pf->main_vsi;
+	struct rte_eth_dev_data *data = I40E_VSI_TO_DEV_DATA(vsi);
+	struct ether_addr *macaddr;
+	int ret;
+	struct i40e_hw *hw =
+		I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	if (index >= vsi->max_macaddrs)
+		return;
+
+	macaddr = &(data->mac_addrs[index]);
+	if (!is_valid_assigned_ether_addr(macaddr))
+		return;
+
+	ret = i40e_aq_mac_address_write(hw, I40E_AQC_WRITE_TYPE_LAA_ONLY,
+					hw->mac.perm_addr, NULL);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to write mac address\n");
+		return;
+	}
+
+	(void)rte_memcpy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
+
+	ret = i40e_vsi_delete_mac(vsi, macaddr);
+	if (ret != I40E_SUCCESS)
+		return;
+
+	/* Clear device address as it has been removed */
+	if (is_same_ether_addr(&(pf->dev_addr), macaddr))
+		memset(&pf->dev_addr, 0, sizeof(struct ether_addr));
+}
+
+static int
+i40e_dev_rss_reta_update(struct rte_eth_dev *dev,
+			 struct rte_eth_rss_reta *reta_conf)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t lut, l;
+	uint8_t i, j, mask, max = ETH_RSS_RETA_NUM_ENTRIES / 2;
+
+	for (i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) {
+		if (i < max)
+			mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF);
+		else
+			mask = (uint8_t)((reta_conf->mask_hi >>
+						(i - max)) & 0xF);
+
+		if (!mask)
+			continue;
+
+		if (mask == 0xF)
+			l = 0;
+		else
+			l = I40E_READ_REG(hw, I40E_PFQF_HLUT(i >> 2));
+
+		for (j = 0, lut = 0; j < 4; j++) {
+			if (mask & (0x1 < j))
+				lut |= reta_conf->reta[i + j] << (8 * j);
+			else
+				lut |= l & (0xFF << (8 * j));
+		}
+		I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut);
+	}
+
+	return 0;
+}
+
+static int
+i40e_dev_rss_reta_query(struct rte_eth_dev *dev,
+			struct rte_eth_rss_reta *reta_conf)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t lut;
+	uint8_t i, j, mask, max = ETH_RSS_RETA_NUM_ENTRIES / 2;
+
+	for (i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) {
+		if (i < max)
+			mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF);
+		else
+			mask = (uint8_t)((reta_conf->mask_hi >>
+						(i - max)) & 0xF);
+
+		if (!mask)
+			continue;
+
+		lut = I40E_READ_REG(hw, I40E_PFQF_HLUT(i >> 2));
+		for (j = 0; j < 4; j++) {
+			if (mask & (0x1 << j))
+				reta_conf->reta[i + j] =
+					(uint8_t)((lut >> (8 * j)) & 0xFF);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * i40e_allocate_dma_mem_d - specific memory alloc for shared code
+ * @hw:   pointer to the HW structure
+ * @mem:  pointer to mem struct to fill out
+ * @size: size of memory requested
+ * @alignment: what to align the allocation to
+ **/
+enum i40e_status_code
+i40e_allocate_dma_mem_d(__attribute__((unused)) struct i40e_hw *hw,
+			struct i40e_dma_mem *mem,
+			u64 size,
+			u32 alignment)
+{
+	static uint64_t id = 0;
+	const struct rte_memzone *mz = NULL;
+	char z_name[RTE_MEMZONE_NAMESIZE];
+
+	if (!mem)
+		return I40E_ERR_PARAM;
+
+	id++;
+	rte_snprintf(z_name, sizeof(z_name), "i40e_dma_%lu", id);
+	mz = rte_memzone_reserve_aligned(z_name, size, 0, 0, alignment);
+	if (!mz)
+		return I40E_ERR_NO_MEMORY;
+
+	mem->id = id;
+	mem->size = size;
+	mem->va = mz->addr;
+	mem->pa = mz->phys_addr;
+
+	return I40E_SUCCESS;
+}
+
+/**
+ * i40e_free_dma_mem_d - specific memory free for shared code
+ * @hw:   pointer to the HW structure
+ * @mem:  ptr to mem struct to free
+ **/
+enum i40e_status_code
+i40e_free_dma_mem_d(__attribute__((unused)) struct i40e_hw *hw,
+		    struct i40e_dma_mem *mem)
+{
+	if (!mem || !mem->va)
+		return I40E_ERR_PARAM;
+
+	mem->va = NULL;
+	mem->pa = (u64)0;
+
+	return I40E_SUCCESS;
+}
+
+/**
+ * i40e_allocate_virt_mem_d - specific memory alloc for shared code
+ * @hw:   pointer to the HW structure
+ * @mem:  pointer to mem struct to fill out
+ * @size: size of memory requested
+ **/
+enum i40e_status_code
+i40e_allocate_virt_mem_d(__attribute__((unused)) struct i40e_hw *hw,
+			 struct i40e_virt_mem *mem,
+			 u32 size)
+{
+	if (!mem)
+		return I40E_ERR_PARAM;
+
+	mem->size = size;
+	mem->va = rte_zmalloc("i40e", size, 0);
+
+	if (mem->va)
+		return I40E_SUCCESS;
+	else
+		return I40E_ERR_NO_MEMORY;
+}
+
+/**
+ * i40e_free_virt_mem_d - specific memory free for shared code
+ * @hw:   pointer to the HW structure
+ * @mem:  pointer to mem struct to free
+ **/
+enum i40e_status_code
+i40e_free_virt_mem_d(__attribute__((unused)) struct i40e_hw *hw,
+		     struct i40e_virt_mem *mem)
+{
+	if (!mem)
+		return I40E_ERR_PARAM;
+
+	rte_free(mem->va);
+	mem->va = NULL;
+
+	return I40E_SUCCESS;
+}
+
+void
+i40e_init_spinlock_d(struct i40e_spinlock *sp)
+{
+	rte_spinlock_init(&sp->spinlock);
+}
+
+void
+i40e_acquire_spinlock_d(struct i40e_spinlock *sp)
+{
+	rte_spinlock_lock(&sp->spinlock);
+}
+
+void
+i40e_release_spinlock_d(struct i40e_spinlock *sp)
+{
+	rte_spinlock_unlock(&sp->spinlock);
+}
+
+void
+i40e_destroy_spinlock_d(__attribute__((unused)) struct i40e_spinlock *sp)
+{
+	return;
+}
+
+/**
+ * Get the hardware capabilities, which will be parsed
+ * and saved into struct i40e_hw.
+ */
+static int
+i40e_get_cap(struct i40e_hw *hw)
+{
+	struct i40e_aqc_list_capabilities_element_resp *buf;
+	uint16_t len, size = 0;
+	int ret;
+
+	/* Calculate a huge enough buff for saving response data temporarily */
+	len = sizeof(struct i40e_aqc_list_capabilities_element_resp) *
+						I40E_MAX_CAP_ELE_NUM;
+	buf = rte_zmalloc("i40e", len, 0);
+	if (!buf) {
+		PMD_DRV_LOG(ERR, "Failed to allocate memory\n");
+		return I40E_ERR_NO_MEMORY;
+	}
+
+	/* Get, parse the capabilities and save it to hw */
+	ret = i40e_aq_discover_capabilities(hw, buf, len, &size,
+			i40e_aqc_opc_list_func_capabilities, NULL);
+	if (ret != I40E_SUCCESS)
+		PMD_DRV_LOG(ERR, "Failed to discover capabilities\n");
+
+	/* Free the temporary buffer after being used */
+	rte_free(buf);
+
+	return ret;
+}
+
+static int
+i40e_pf_parameter_init(struct rte_eth_dev *dev)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	uint16_t sum_queues = 0, sum_vsis;
+
+	/* First check if FW support SRIOV */
+	if (dev->pci_dev->max_vfs && !hw->func_caps.sr_iov_1_1) {
+		PMD_INIT_LOG(ERR, "HW configuration doesn't support SRIOV\n");
+		return -EINVAL;
+	}
+
+	pf->flags = I40E_FLAG_HEADER_SPLIT_DISABLED;
+	pf->max_num_vsi = RTE_MIN(hw->func_caps.num_vsis, I40E_MAX_NUM_VSIS);
+	PMD_INIT_LOG(INFO, "Max supported VSIs:%u\n", pf->max_num_vsi);
+	/* Allocate queues for pf */
+	if (hw->func_caps.rss) {
+		pf->flags |= I40E_FLAG_RSS;
+		pf->lan_nb_qps = RTE_MIN(hw->func_caps.num_tx_qp,
+			(uint32_t)(1 << hw->func_caps.rss_table_entry_width));
+		pf->lan_nb_qps = i40e_prev_power_of_2(pf->lan_nb_qps);
+	} else
+		pf->lan_nb_qps = 1;
+	sum_queues = pf->lan_nb_qps;
+	/* Default VSI is not counted in */
+	sum_vsis = 0;
+	PMD_INIT_LOG(INFO, "PF queue pairs:%u\n", pf->lan_nb_qps);
+
+	if (hw->func_caps.sr_iov_1_1 && dev->pci_dev->max_vfs) {
+		pf->flags |= I40E_FLAG_SRIOV;
+		pf->vf_nb_qps = RTE_LIBRTE_I40E_QUEUE_NUM_PER_VF;
+		if (dev->pci_dev->max_vfs > hw->func_caps.num_vfs) {
+			PMD_INIT_LOG(ERR, "Config VF number %u, "
+				"max supported %u.\n", dev->pci_dev->max_vfs,
+						hw->func_caps.num_vfs);
+			return -EINVAL;
+		}
+		if (pf->vf_nb_qps > I40E_MAX_QP_NUM_PER_VF) {
+			PMD_INIT_LOG(ERR, "FVL VF queue %u, "
+				"max support %u queues.\n", pf->vf_nb_qps,
+						I40E_MAX_QP_NUM_PER_VF);
+			return -EINVAL;
+		}
+		pf->vf_num = dev->pci_dev->max_vfs;
+		sum_queues += pf->vf_nb_qps * pf->vf_num;
+		sum_vsis   += pf->vf_num;
+		PMD_INIT_LOG(INFO, "Max VF num:%u each has queue pairs:%u\n",
+						pf->vf_num, pf->vf_nb_qps);
+	} else
+		pf->vf_num = 0;
+
+	if (hw->func_caps.vmdq) {
+		pf->flags |= I40E_FLAG_VMDQ;
+		pf->vmdq_nb_qps = I40E_DEFAULT_QP_NUM_VMDQ;
+		sum_queues += pf->vmdq_nb_qps;
+		sum_vsis += 1;
+		PMD_INIT_LOG(INFO, "VMDQ queue pairs:%u\n", pf->vmdq_nb_qps);
+	}
+
+	if (hw->func_caps.fd) {
+		pf->flags |= I40E_FLAG_FDIR;
+		pf->fdir_nb_qps = I40E_DEFAULT_QP_NUM_FDIR;
+		/**
+		 * Each flow director consumes one VSI and one queue,
+		 * but can't calculate out predictably here.
+		 */
+	}
+
+	if (sum_vsis > pf->max_num_vsi ||
+		sum_queues > hw->func_caps.num_rx_qp) {
+		PMD_INIT_LOG(ERR, "VSI/QUEUE setting can't be satisfied\n");
+		PMD_INIT_LOG(ERR, "Max VSIs: %u, asked:%u\n",
+				pf->max_num_vsi, sum_vsis);
+		PMD_INIT_LOG(ERR, "Total queue pairs:%u, asked:%u\n",
+				hw->func_caps.num_rx_qp, sum_queues);
+		return -EINVAL;
+	}
+
+	/* Each VSI occupy 1 MSIX interrupt at least, plus IRQ0 for misc intr cause */
+	if (sum_vsis > hw->func_caps.num_msix_vectors - 1) {
+		PMD_INIT_LOG(ERR, "Too many VSIs(%u), MSIX intr(%u) not enough\n",
+				sum_vsis, hw->func_caps.num_msix_vectors);
+		return -EINVAL;
+	}
+	return I40E_SUCCESS;
+}
+
+static int
+i40e_pf_get_switch_config(struct i40e_pf *pf)
+{
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	struct i40e_aqc_get_switch_config_resp *switch_config;
+	struct i40e_aqc_switch_config_element_resp *element;
+	uint16_t start_seid = 0, num_reported;
+	int ret;
+
+	switch_config = (struct i40e_aqc_get_switch_config_resp *)\
+			rte_zmalloc("i40e", I40E_AQ_LARGE_BUF, 0);
+	if (!switch_config) {
+		PMD_DRV_LOG(ERR, "Failed to allocated memory\n");
+		return -ENOMEM;
+	}
+
+	/* Get the switch configurations */
+	ret = i40e_aq_get_switch_config(hw, switch_config,
+		I40E_AQ_LARGE_BUF, &start_seid, NULL);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to get switch configurations\n");
+		goto fail;
+	}
+	num_reported = rte_le_to_cpu_16(switch_config->header.num_reported);
+	if (num_reported != 1) { /* The number should be 1 */
+		PMD_DRV_LOG(ERR, "Wrong number of switch config reported\n");
+		goto fail;
+	}
+
+	/* Parse the switch configuration elements */
+	element = &(switch_config->element[0]);
+	if (element->element_type == I40E_SWITCH_ELEMENT_TYPE_VSI) {
+		pf->mac_seid = rte_le_to_cpu_16(element->uplink_seid);
+		pf->main_vsi_seid = rte_le_to_cpu_16(element->seid);
+	} else
+		PMD_DRV_LOG(INFO, "Unknown element type\n");
+
+fail:
+	rte_free(switch_config);
+
+	return ret;
+}
+
+static int
+i40e_res_pool_init (struct i40e_res_pool_info *pool, uint32_t base,
+			uint32_t num)
+{
+	struct pool_entry *entry;
+
+	if (pool == NULL || num == 0)
+		return -EINVAL;
+
+	entry = rte_zmalloc("i40e", sizeof(*entry), 0);
+	if (entry == NULL) {
+		PMD_DRV_LOG(ERR, "Failed to allocate memory for "
+						"resource pool\n");
+		return -ENOMEM;
+	}
+
+	/* queue heap initialize */
+	pool->num_free = num;
+	pool->num_alloc = 0;
+	pool->base = base;
+	LIST_INIT(&pool->alloc_list);
+	LIST_INIT(&pool->free_list);
+
+	/* Initialize element  */
+	entry->base = 0;
+	entry->len = num;
+
+	LIST_INSERT_HEAD(&pool->free_list, entry, next);
+	return 0;
+}
+
+static void
+i40e_res_pool_destroy(struct i40e_res_pool_info *pool)
+{
+	struct pool_entry *entry;
+
+	if (pool == NULL)
+		return;
+
+	LIST_FOREACH(entry, &pool->alloc_list, next) {
+		LIST_REMOVE(entry, next);
+		rte_free(entry);
+	}
+
+	LIST_FOREACH(entry, &pool->free_list, next) {
+		LIST_REMOVE(entry, next);
+		rte_free(entry);
+	}
+
+	pool->num_free = 0;
+	pool->num_alloc = 0;
+	pool->base = 0;
+	LIST_INIT(&pool->alloc_list);
+	LIST_INIT(&pool->free_list);
+}
+
+static int
+i40e_res_pool_free(struct i40e_res_pool_info *pool,
+		       uint32_t base)
+{
+	struct pool_entry *entry, *next, *prev, *valid_entry = NULL;
+	uint32_t pool_offset;
+	int insert;
+
+	if (pool == NULL) {
+		PMD_DRV_LOG(ERR, "Invalid parameter\n");
+		return -EINVAL;
+	}
+
+	pool_offset = base - pool->base;
+	/* Lookup in alloc list */
+	LIST_FOREACH(entry, &pool->alloc_list, next) {
+		if (entry->base == pool_offset) {
+			valid_entry = entry;
+			LIST_REMOVE(entry, next);
+			break;
+		}
+	}
+
+	/* Not find, return */
+	if (valid_entry == NULL) {
+		PMD_DRV_LOG(ERR, "Failed to find entry\n");
+		return -EINVAL;
+	}
+
+	/**
+	 * Found it, move it to free list  and try to merge.
+	 * In order to make merge easier, always sort it by qbase.
+	 * Find adjacent prev and last entries.
+	 */
+	prev = next = NULL;
+	LIST_FOREACH(entry, &pool->free_list, next) {
+		if (entry->base > valid_entry->base) {
+			next = entry;
+			break;
+		}
+		prev = entry;
+	}
+
+	insert = 0;
+	/* Try to merge with next one*/
+	if (next != NULL) {
+		/* Merge with next one */
+		if (valid_entry->base + valid_entry->len == next->base) {
+			next->base = valid_entry->base;
+			next->len += valid_entry->len;
+			rte_free(valid_entry);
+			valid_entry = next;
+			insert = 1;
+		}
+	}
+
+	if (prev != NULL) {
+		/* Merge with previous one */
+		if (prev->base + prev->len == valid_entry->base) {
+			prev->len += valid_entry->len;
+			/* If it merge with next one, remove next node */
+			if (insert == 1) {
+				LIST_REMOVE(valid_entry, next);
+				rte_free(valid_entry);
+			} else {
+				rte_free(valid_entry);
+				insert = 1;
+			}
+		}
+	}
+
+	/* Not find any entry to merge, insert */
+	if (insert == 0) {
+		if (prev != NULL)
+			LIST_INSERT_AFTER(prev, valid_entry, next);
+		else if (next != NULL)
+			LIST_INSERT_BEFORE(next, valid_entry, next);
+		else /* It's empty list, insert to head */
+			LIST_INSERT_HEAD(&pool->free_list, valid_entry, next);
+	}
+
+	pool->num_free += valid_entry->len;
+	pool->num_alloc -= valid_entry->len;
+
+	return 0;
+}
+
+static int
+i40e_res_pool_alloc(struct i40e_res_pool_info *pool,
+		       uint16_t num)
+{
+	struct pool_entry *entry, *valid_entry;
+
+	if (pool == NULL || num == 0) {
+		PMD_DRV_LOG(ERR, "Invalid parameter\n");
+		return -EINVAL;
+	}
+
+	if (pool->num_free < num) {
+		PMD_DRV_LOG(ERR, "No resource. ask:%u, available:%u\n",
+				num, pool->num_free);
+		return -ENOMEM;
+	}
+
+	valid_entry = NULL;
+	/* Lookup  in free list and find most fit one */
+	LIST_FOREACH(entry, &pool->free_list, next) {
+		if (entry->len >= num) {
+			/* Find best one */
+			if (entry->len == num) {
+				valid_entry = entry;
+				break;
+			}
+			if (valid_entry == NULL || valid_entry->len > entry->len)
+				valid_entry = entry;
+		}
+	}
+
+	/* Not find one to satisfy the request, return */
+	if (valid_entry == NULL) {
+		PMD_DRV_LOG(ERR, "No valid entry found\n");
+		return -ENOMEM;
+	}
+	/**
+	 * The entry have equal queue number as requested,
+	 * remove it from alloc_list.
+	 */
+	if (valid_entry->len == num) {
+		LIST_REMOVE(valid_entry, next);
+	} else {
+		/**
+		 * The entry have more numbers than requested,
+		 * create a new entry for alloc_list and minus its
+		 * queue base and number in free_list.
+		 */
+		entry = rte_zmalloc("res_pool", sizeof(*entry), 0);
+		if (entry == NULL) {
+			PMD_DRV_LOG(ERR, "Failed to allocate memory for "
+					"resource pool\n");
+			return -ENOMEM;
+		}
+		entry->base = valid_entry->base;
+		entry->len = num;
+		valid_entry->base += num;
+		valid_entry->len -= num;
+		valid_entry = entry;
+	}
+
+	/* Insert it into alloc list, not sorted */
+	LIST_INSERT_HEAD(&pool->alloc_list, valid_entry, next);
+
+	pool->num_free -= valid_entry->len;
+	pool->num_alloc += valid_entry->len;
+
+	return (valid_entry->base + pool->base);
+}
+
+/**
+ * bitmap_is_subset - Check whether src2 is subset of src1
+ **/
+static inline int
+bitmap_is_subset(uint8_t src1, uint8_t src2)
+{
+	return !((src1 ^ src2) & src2);
+}
+
+static int
+validate_tcmap_parameter(struct i40e_vsi *vsi, uint8_t enabled_tcmap)
+{
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+
+	/* If DCB is not supported, only default TC is supported */
+	if (!hw->func_caps.dcb && enabled_tcmap != I40E_DEFAULT_TCMAP) {
+		PMD_DRV_LOG(ERR, "DCB is not enabled, "
+				"only TC0 is supported\n");
+		return -EINVAL;
+	}
+
+	if (!bitmap_is_subset(hw->func_caps.enabled_tcmap, enabled_tcmap)) {
+		PMD_DRV_LOG(ERR, "Enabled TC map 0x%x not applicable to "
+			"HW support 0x%x\n", hw->func_caps.enabled_tcmap,
+							enabled_tcmap);
+		return -EINVAL;
+	}
+	return I40E_SUCCESS;
+}
+
+static int
+i40e_vsi_update_tc_bandwidth(struct i40e_vsi *vsi, uint8_t enabled_tcmap)
+{
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	int i, ret;
+	struct i40e_aqc_configure_vsi_tc_bw_data tc_bw_data;
+
+	ret = validate_tcmap_parameter(vsi, enabled_tcmap);
+	if (ret != I40E_SUCCESS)
+		return ret;
+
+	if (!vsi->seid) {
+		PMD_DRV_LOG(ERR, "seid not valid\n");
+		return -EINVAL;
+	}
+
+	memset(&tc_bw_data, 0, sizeof(tc_bw_data));
+	tc_bw_data.tc_valid_bits = enabled_tcmap;
+	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+		tc_bw_data.tc_bw_credits[i] =
+			(enabled_tcmap & (1 << i)) ? 1 : 0;
+
+	ret = i40e_aq_config_vsi_tc_bw(hw, vsi->seid, &tc_bw_data, NULL);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to configure TC BW\n");
+		return ret;
+	}
+
+	(void)rte_memcpy(vsi->info.qs_handle, tc_bw_data.qs_handles,
+					sizeof(vsi->info.qs_handle));
+	return I40E_SUCCESS;
+}
+
+static int
+i40e_vsi_config_tc_queue_mapping(struct i40e_vsi *vsi,
+				 struct i40e_aqc_vsi_properties_data *info,
+				 uint8_t enabled_tcmap)
+{
+	int ret, total_tc = 0, i;
+	uint16_t qpnum_per_tc, bsf, qp_idx;
+
+	ret = validate_tcmap_parameter(vsi, enabled_tcmap);
+	if (ret != I40E_SUCCESS)
+		return ret;
+
+	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+		if (enabled_tcmap & (1 << i))
+			total_tc++;
+	vsi->enabled_tc = enabled_tcmap;
+
+	/* Number of queues per enabled TC */
+	qpnum_per_tc = i40e_prev_power_of_2(vsi->nb_qps / total_tc);
+	qpnum_per_tc = RTE_MIN(qpnum_per_tc, I40E_MAX_Q_PER_TC);
+	bsf = rte_bsf32(qpnum_per_tc);
+
+	/* Adjust the queue number to actual queues that can be applied */
+	vsi->nb_qps = qpnum_per_tc * total_tc;
+
+	/**
+	 * Configure TC and queue mapping parameters, for enabled TC,
+	 * allocate qpnum_per_tc queues to this traffic. For disabled TC,
+	 * default queue will serve it.
+	 */
+	qp_idx = 0;
+	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+		if (vsi->enabled_tc & (1 << i)) {
+			info->tc_mapping[i] = rte_cpu_to_le_16((qp_idx <<
+					I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
+				(bsf << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT));
+			qp_idx += qpnum_per_tc;
+		} else
+			info->tc_mapping[i] = 0;
+	}
+
+	/* Associate queue number with VSI */
+	if (vsi->type == I40E_VSI_SRIOV) {
+		info->mapping_flags |=
+			rte_cpu_to_le_16(I40E_AQ_VSI_QUE_MAP_NONCONTIG);
+		for (i = 0; i < vsi->nb_qps; i++)
+			info->queue_mapping[i] =
+				rte_cpu_to_le_16(vsi->base_queue + i);
+	} else {
+		info->mapping_flags |=
+			rte_cpu_to_le_16(I40E_AQ_VSI_QUE_MAP_CONTIG);
+		info->queue_mapping[0] = rte_cpu_to_le_16(vsi->base_queue);
+	}
+	info->valid_sections =
+		rte_cpu_to_le_16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID);
+
+	return I40E_SUCCESS;
+}
+
+static int
+i40e_veb_release(struct i40e_veb *veb)
+{
+	struct i40e_vsi *vsi;
+	struct i40e_hw *hw;
+
+	if (veb == NULL || veb->associate_vsi == NULL)
+		return -EINVAL;
+
+	if (!TAILQ_EMPTY(&veb->head)) {
+		PMD_DRV_LOG(ERR, "VEB still has VSI attached, can't remove\n");
+		return -EACCES;
+	}
+
+	vsi = veb->associate_vsi;
+	hw = I40E_VSI_TO_HW(vsi);
+
+	vsi->uplink_seid = veb->uplink_seid;
+	i40e_aq_delete_element(hw, veb->seid, NULL);
+	rte_free(veb);
+	vsi->veb = NULL;
+	return I40E_SUCCESS;
+}
+
+/* Setup a veb */
+static struct i40e_veb *
+i40e_veb_setup(struct i40e_pf *pf, struct i40e_vsi *vsi)
+{
+	struct i40e_veb *veb;
+	int ret;
+	struct i40e_hw *hw;
+
+	if (NULL == pf || vsi == NULL) {
+		PMD_DRV_LOG(ERR, "veb setup failed, "
+			"associated VSI shouldn't null\n");
+		return NULL;
+	}
+	hw = I40E_PF_TO_HW(pf);
+
+	veb = rte_zmalloc("i40e_veb", sizeof(struct i40e_veb), 0);
+	if (!veb) {
+		PMD_DRV_LOG(ERR, "Failed to allocate memory for veb\n");
+		goto fail;
+	}
+
+	veb->associate_vsi = vsi;
+	TAILQ_INIT(&veb->head);
+	veb->uplink_seid = vsi->uplink_seid;
+
+	ret = i40e_aq_add_veb(hw, veb->uplink_seid, vsi->seid,
+		I40E_DEFAULT_TCMAP, false, false, &veb->seid, NULL);
+
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Add veb failed, aq_err: %d\n",
+					hw->aq.asq_last_status);
+		goto fail;
+	}
+
+	/* get statistics index */
+	ret = i40e_aq_get_veb_parameters(hw, veb->seid, NULL, NULL,
+				&veb->stats_idx, NULL, NULL, NULL);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Get veb statics index failed, aq_err: %d\n",
+						hw->aq.asq_last_status);
+		goto fail;
+	}
+
+	/* Get VEB bandwidth, to be implemented */
+	/* Now associated vsi binding to the VEB, set uplink to this VEB */
+	vsi->uplink_seid = veb->seid;
+
+	return veb;
+fail:
+	rte_free(veb);
+	return NULL;
+}
+
+int
+i40e_vsi_release(struct i40e_vsi *vsi)
+{
+	struct i40e_pf *pf;
+	struct i40e_hw *hw;
+	struct i40e_vsi_list *vsi_list;
+	int ret;
+	struct i40e_mac_filter *f;
+
+	if (!vsi)
+		return I40E_SUCCESS;
+
+	pf = I40E_VSI_TO_PF(vsi);
+	hw = I40E_VSI_TO_HW(vsi);
+
+	/* VSI has child to attach, release child first */
+	if (vsi->veb) {
+		TAILQ_FOREACH(vsi_list, &vsi->veb->head, list) {
+			if (i40e_vsi_release(vsi_list->vsi) != I40E_SUCCESS)
+				return -1;
+			TAILQ_REMOVE(&vsi->veb->head, vsi_list, list);
+		}
+		i40e_veb_release(vsi->veb);
+	}
+
+	/* Remove all macvlan filters of the VSI */
+	i40e_vsi_remove_all_macvlan_filter(vsi);
+	TAILQ_FOREACH(f, &vsi->mac_list, next)
+		rte_free(f);
+
+	if (vsi->type != I40E_VSI_MAIN) {
+		/* Remove vsi from parent's sibling list */
+		if (vsi->parent_vsi == NULL || vsi->parent_vsi->veb == NULL) {
+			PMD_DRV_LOG(ERR, "VSI's parent VSI is NULL\n");
+			return I40E_ERR_PARAM;
+		}
+		TAILQ_REMOVE(&vsi->parent_vsi->veb->head,
+				&vsi->sib_vsi_list, list);
+
+		/* Remove all switch element of the VSI */
+		ret = i40e_aq_delete_element(hw, vsi->seid, NULL);
+		if (ret != I40E_SUCCESS)
+			PMD_DRV_LOG(ERR, "Failed to delete element\n");
+	}
+	i40e_res_pool_free(&pf->qp_pool, vsi->base_queue);
+
+	if (vsi->type != I40E_VSI_SRIOV)
+		i40e_res_pool_free(&pf->msix_pool, vsi->msix_intr);
+	rte_free(vsi);
+
+	return I40E_SUCCESS;
+}
+
+static int
+i40e_update_default_filter_setting(struct i40e_vsi *vsi)
+{
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	struct i40e_aqc_remove_macvlan_element_data def_filter;
+	int ret;
+
+	if (vsi->type != I40E_VSI_MAIN)
+		return I40E_ERR_CONFIG;
+	memset(&def_filter, 0, sizeof(def_filter));
+	(void)rte_memcpy(def_filter.mac_addr, hw->mac.perm_addr,
+					ETH_ADDR_LEN);
+	def_filter.vlan_tag = 0;
+	def_filter.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH |
+				I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
+	ret = i40e_aq_remove_macvlan(hw, vsi->seid, &def_filter, 1, NULL);
+	if (ret != I40E_SUCCESS)
+		return ret;
+
+	return i40e_vsi_add_mac(vsi, (struct ether_addr *)(hw->mac.perm_addr));
+}
+
+static int
+i40e_vsi_dump_bw_config(struct i40e_vsi *vsi)
+{
+	struct i40e_aqc_query_vsi_bw_config_resp bw_config;
+	struct i40e_aqc_query_vsi_ets_sla_config_resp ets_sla_config;
+	struct i40e_hw *hw = &vsi->adapter->hw;
+	i40e_status ret;
+	int i;
+
+	memset(&bw_config, 0, sizeof(bw_config));
+	ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "VSI failed to get bandwidth "
+			"configuration %u\n", hw->aq.asq_last_status);
+		return ret;
+	}
+
+	memset(&ets_sla_config, 0, sizeof(ets_sla_config));
+	ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid,
+					&ets_sla_config, NULL);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "VSI failed to get TC bandwdith "
+			"configuration %u\n", hw->aq.asq_last_status);
+		return ret;
+	}
+
+	/* Not store the info yet, just print out */
+	PMD_DRV_LOG(INFO, "VSI bw limit:%u\n", bw_config.port_bw_limit);
+	PMD_DRV_LOG(INFO, "VSI max_bw:%u\n", bw_config.max_bw);
+	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+		PMD_DRV_LOG(INFO, "\tVSI TC%u:share credits %u\n", i,
+					ets_sla_config.share_credits[i]);
+		PMD_DRV_LOG(INFO, "\tVSI TC%u:credits %u\n", i,
+			rte_le_to_cpu_16(ets_sla_config.credits[i]));
+		PMD_DRV_LOG(INFO, "\tVSI TC%u: max credits: %u", i,
+			rte_le_to_cpu_16(ets_sla_config.credits[i / 4]) >>
+								(i * 4));
+	}
+
+	return 0;
+}
+
+/* Setup a VSI */
+struct i40e_vsi *
+i40e_vsi_setup(struct i40e_pf *pf,
+	       enum i40e_vsi_type type,
+	       struct i40e_vsi *uplink_vsi,
+	       uint16_t user_param)
+{
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	struct i40e_vsi *vsi;
+	int ret;
+	struct i40e_vsi_context ctxt;
+	struct ether_addr broadcast =
+		{.addr_bytes = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
+
+	if (type != I40E_VSI_MAIN && uplink_vsi == NULL) {
+		PMD_DRV_LOG(ERR, "VSI setup failed, "
+			"VSI link shouldn't be NULL\n");
+		return NULL;
+	}
+
+	if (type == I40E_VSI_MAIN && uplink_vsi != NULL) {
+		PMD_DRV_LOG(ERR, "VSI setup failed, MAIN VSI "
+				"uplink VSI should be NULL\n");
+		return NULL;
+	}
+
+	/* If uplink vsi didn't setup VEB, create one first */
+	if (type != I40E_VSI_MAIN && uplink_vsi->veb == NULL) {
+		uplink_vsi->veb = i40e_veb_setup(pf, uplink_vsi);
+
+		if (NULL == uplink_vsi->veb) {
+			PMD_DRV_LOG(ERR, "VEB setup failed\n");
+			return NULL;
+		}
+	}
+
+	vsi = rte_zmalloc("i40e_vsi", sizeof(struct i40e_vsi), 0);
+	if (!vsi) {
+		PMD_DRV_LOG(ERR, "Failed to allocate memory for vsi\n");
+		return NULL;
+	}
+	TAILQ_INIT(&vsi->mac_list);
+	vsi->type = type;
+	vsi->adapter = I40E_PF_TO_ADAPTER(pf);
+	vsi->max_macaddrs = I40E_NUM_MACADDR_MAX;
+	vsi->parent_vsi = uplink_vsi;
+	vsi->user_param = user_param;
+	/* Allocate queues */
+	switch (vsi->type) {
+	case I40E_VSI_MAIN  :
+		vsi->nb_qps = pf->lan_nb_qps;
+		break;
+	case I40E_VSI_SRIOV :
+		vsi->nb_qps = pf->vf_nb_qps;
+		break;
+	default:
+		goto fail_mem;
+	}
+	ret = i40e_res_pool_alloc(&pf->qp_pool, vsi->nb_qps);
+	if (ret < 0) {
+		PMD_DRV_LOG(ERR, "VSI %d allocate queue failed %d",
+				vsi->seid, ret);
+		goto fail_mem;
+	}
+	vsi->base_queue = ret;
+
+	/* VF has MSIX interrupt in VF range, don't allocate here */
+	if (type != I40E_VSI_SRIOV) {
+		ret = i40e_res_pool_alloc(&pf->msix_pool, 1);
+		if (ret < 0) {
+			PMD_DRV_LOG(ERR, "VSI %d get heap failed %d", vsi->seid, ret);
+			goto fail_queue_alloc;
+		}
+		vsi->msix_intr = ret;
+	} else
+		vsi->msix_intr = 0;
+	/* Add VSI */
+	if (type == I40E_VSI_MAIN) {
+		/* For main VSI, no need to add since it's default one */
+		vsi->uplink_seid = pf->mac_seid;
+		vsi->seid = pf->main_vsi_seid;
+		/* Bind queues with specific MSIX interrupt */
+		/**
+		 * Needs 2 interrupt at least, one for misc cause which will
+		 * enabled from OS side, Another for queues binding the
+		 * interrupt from device side only.
+		 */
+
+		/* Get default VSI parameters from hardware */
+		memset(&ctxt, 0, sizeof(ctxt));
+		ctxt.seid = vsi->seid;
+		ctxt.pf_num = hw->pf_id;
+		ctxt.uplink_seid = vsi->uplink_seid;
+		ctxt.vf_num = 0;
+		ret = i40e_aq_get_vsi_params(hw, &ctxt, NULL);
+		if (ret != I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Failed to get VSI params\n");
+			goto fail_msix_alloc;
+		}
+		(void)rte_memcpy(&vsi->info, &ctxt.info,
+			sizeof(struct i40e_aqc_vsi_properties_data));
+		vsi->vsi_id = ctxt.vsi_number;
+		vsi->info.valid_sections = 0;
+
+		/* Configure tc, enabled TC0 only */
+		if (i40e_vsi_update_tc_bandwidth(vsi, I40E_DEFAULT_TCMAP) !=
+			I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Failed to update TC bandwidth\n");
+			goto fail_msix_alloc;
+		}
+
+		/* TC, queue mapping */
+		memset(&ctxt, 0, sizeof(ctxt));
+		vsi->info.valid_sections |=
+			rte_cpu_to_le_16(I40E_AQ_VSI_PROP_VLAN_VALID);
+		vsi->info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
+					I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
+		(void)rte_memcpy(&ctxt.info, &vsi->info,
+			sizeof(struct i40e_aqc_vsi_properties_data));
+		ret = i40e_vsi_config_tc_queue_mapping(vsi, &ctxt.info,
+						I40E_DEFAULT_TCMAP);
+		if (ret != I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Failed to configure "
+					"TC queue mapping\n");
+			goto fail_msix_alloc;
+		}
+		ctxt.seid = vsi->seid;
+		ctxt.pf_num = hw->pf_id;
+		ctxt.uplink_seid = vsi->uplink_seid;
+		ctxt.vf_num = 0;
+
+		/* Update VSI parameters */
+		ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
+		if (ret != I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Failed to update VSI params\n");
+			goto fail_msix_alloc;
+		}
+
+		(void)rte_memcpy(&vsi->info.tc_mapping, &ctxt.info.tc_mapping,
+						sizeof(vsi->info.tc_mapping));
+		(void)rte_memcpy(&vsi->info.queue_mapping,
+				&ctxt.info.queue_mapping,
+			sizeof(vsi->info.queue_mapping));
+		vsi->info.mapping_flags = ctxt.info.mapping_flags;
+		vsi->info.valid_sections = 0;
+
+		(void)rte_memcpy(pf->dev_addr.addr_bytes, hw->mac.perm_addr,
+				ETH_ADDR_LEN);
+		ret = i40e_update_default_filter_setting(vsi);
+		if (ret != I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Failed to remove default "
+						"filter setting\n");
+			goto fail_msix_alloc;
+		}
+	}
+	else if (type == I40E_VSI_SRIOV) {
+		memset(&ctxt, 0, sizeof(ctxt));
+		/**
+		 * For other VSI, the uplink_seid equals to uplink VSI's
+		 * uplink_seid since they share same VEB
+		 */
+		vsi->uplink_seid = uplink_vsi->uplink_seid;
+		ctxt.pf_num = hw->pf_id;
+		ctxt.vf_num = hw->func_caps.vf_base_id + user_param;
+		ctxt.uplink_seid = vsi->uplink_seid;
+		ctxt.connection_type = 0x1;
+		ctxt.flags = I40E_AQ_VSI_TYPE_VF;
+
+		/* Configure switch ID */
+		ctxt.info.valid_sections |=
+			rte_cpu_to_le_16(I40E_AQ_VSI_PROP_SWITCH_VALID);
+		ctxt.info.switch_id =
+			rte_cpu_to_le_16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
+		/* Configure port/vlan */
+		ctxt.info.valid_sections |=
+			rte_cpu_to_le_16(I40E_AQ_VSI_PROP_VLAN_VALID);
+		ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_ALL;
+		ret = i40e_vsi_config_tc_queue_mapping(vsi, &ctxt.info,
+						I40E_DEFAULT_TCMAP);
+		if (ret != I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Failed to configure "
+					"TC queue mapping\n");
+			goto fail_msix_alloc;
+		}
+		ctxt.info.up_enable_bits = I40E_DEFAULT_TCMAP;
+		ctxt.info.valid_sections |=
+			rte_cpu_to_le_16(I40E_AQ_VSI_PROP_SCHED_VALID);
+		/**
+		 * Since VSI is not created yet, only configure parameter,
+		 * will add vsi below.
+		 */
+	}
+	else {
+		PMD_DRV_LOG(ERR, "VSI: Not support other type VSI yet\n");
+		goto fail_msix_alloc;
+	}
+
+	if (vsi->type != I40E_VSI_MAIN) {
+		ret = i40e_aq_add_vsi(hw, &ctxt, NULL);
+		if (ret) {
+			PMD_DRV_LOG(ERR, "add vsi failed, aq_err=%d\n",
+				 hw->aq.asq_last_status);
+			goto fail_msix_alloc;
+		}
+		memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info));
+		vsi->info.valid_sections = 0;
+		vsi->seid = ctxt.seid;
+		vsi->vsi_id = ctxt.vsi_number;
+		vsi->sib_vsi_list.vsi = vsi;
+		TAILQ_INSERT_TAIL(&uplink_vsi->veb->head,
+				&vsi->sib_vsi_list, list);
+	}
+
+	/* MAC/VLAN configuration */
+	ret = i40e_vsi_add_mac(vsi, &broadcast);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to add MACVLAN filter\n");
+		goto fail_msix_alloc;
+	}
+
+	/* Get VSI BW information */
+	i40e_vsi_dump_bw_config(vsi);
+	return vsi;
+fail_msix_alloc:
+	i40e_res_pool_free(&pf->msix_pool,vsi->msix_intr);
+fail_queue_alloc:
+	i40e_res_pool_free(&pf->qp_pool,vsi->base_queue);
+fail_mem:
+	rte_free(vsi);
+	return NULL;
+}
+
+/* Configure vlan stripping on or off */
+static int
+i40e_vsi_config_vlan_stripping(struct i40e_vsi *vsi, bool on)
+{
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	struct i40e_vsi_context ctxt;
+	uint8_t vlan_flags;
+	int ret = I40E_SUCCESS;
+
+	/* Check if it has been already on or off */
+	if (vsi->info.valid_sections &
+		rte_cpu_to_le_16(I40E_AQ_VSI_PROP_VLAN_VALID)) {
+		if (on) {
+			if ((vsi->info.port_vlan_flags &
+				I40E_AQ_VSI_PVLAN_EMOD_MASK) == 0)
+				return 0; /* already on */
+		} else {
+			if ((vsi->info.port_vlan_flags &
+				I40E_AQ_VSI_PVLAN_EMOD_MASK) ==
+				I40E_AQ_VSI_PVLAN_EMOD_MASK)
+				return 0; /* already off */
+		}
+	}
+
+	if (on)
+		vlan_flags = I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
+	else
+		vlan_flags = I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
+	vsi->info.valid_sections =
+		rte_cpu_to_le_16(I40E_AQ_VSI_PROP_VLAN_VALID);
+	vsi->info.port_vlan_flags &= ~(I40E_AQ_VSI_PVLAN_EMOD_MASK);
+	vsi->info.port_vlan_flags |= vlan_flags;
+	ctxt.seid = vsi->seid;
+	(void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
+	ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
+	if (ret)
+		PMD_DRV_LOG(INFO, "Update VSI failed to %s vlan stripping\n",
+						on ? "enable" : "disable");
+
+	return ret;
+}
+
+static int
+i40e_vsi_init_vlan(struct i40e_vsi *vsi)
+{
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	struct rte_eth_dev_data *data = I40E_VSI_TO_DEV_DATA(vsi);
+	struct i40e_vsi_context ctxt;
+	uint8_t vlan_flags = 0;
+	int ret;
+
+	/* Set PVID */
+	if (data->dev_conf.txmode.hw_vlan_insert_pvid == 1) {
+		/**
+		 * If insert pvid is enabled, only tagged pkts are
+		 * allowed to be sent out.
+		 */
+		vlan_flags |= I40E_AQ_VSI_PVLAN_INSERT_PVID |
+				I40E_AQ_VSI_PVLAN_MODE_TAGGED;
+	} else {
+		if (data->dev_conf.txmode.hw_vlan_reject_tagged == 0)
+			vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_TAGGED;
+		if (data->dev_conf.txmode.hw_vlan_reject_untagged == 0)
+			vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_UNTAGGED;
+	}
+
+	/* Strip VLAN tag or not */
+	if (data->dev_conf.rxmode.hw_vlan_strip == 0)
+		vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
+
+	vsi->info.port_vlan_flags &= ~(I40E_AQ_VSI_PVLAN_MODE_MASK |
+		I40E_AQ_VSI_PVLAN_INSERT_PVID | I40E_AQ_VSI_PVLAN_EMOD_MASK);
+	vsi->info.port_vlan_flags |= vlan_flags;
+	vsi->info.pvid = data->dev_conf.txmode.pvid;
+	vsi->info.valid_sections =
+		rte_cpu_to_le_16(I40E_AQ_VSI_PROP_VLAN_VALID);
+
+	(void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
+	ctxt.seid = vsi->seid;
+	ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
+	if (ret != I40E_SUCCESS)
+		PMD_DRV_LOG(INFO, "Failed to update VSI params\n");
+
+	return ret;
+}
+
+static int
+i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int on)
+{
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+
+	return i40e_aq_set_port_parameters(hw, vsi->seid, 0, 1, on, NULL);
+}
+
+static int
+i40e_update_flow_control(struct i40e_hw *hw)
+{
+#define I40E_LINK_PAUSE_RXTX (I40E_AQ_LINK_PAUSE_RX | I40E_AQ_LINK_PAUSE_TX)
+	struct i40e_link_status link_status;
+	uint32_t rxfc = 0, txfc = 0, reg;
+	uint8_t an_info;
+	int ret;
+
+	memset(&link_status, 0, sizeof(link_status));
+	ret = i40e_aq_get_link_info(hw, FALSE, &link_status, NULL);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to get link status information\n");
+		goto write_reg; /* Disable flow control */
+	}
+
+	an_info = hw->phy.link_info.an_info;
+	if (!(an_info & I40E_AQ_AN_COMPLETED)) {
+		PMD_DRV_LOG(INFO, "Link auto negotiation not completed\n");
+		ret = I40E_ERR_NOT_READY;
+		goto write_reg; /* Disable flow control */
+	}
+	/**
+	 * If link auto negotiation is enabled, flow control needs to
+	 * be configured according to it
+	 */
+	switch (an_info & I40E_LINK_PAUSE_RXTX) {
+	case I40E_LINK_PAUSE_RXTX:
+		rxfc = 1;
+		txfc = 1;
+		hw->fc.current_mode = I40E_FC_FULL;
+		break;
+	case I40E_AQ_LINK_PAUSE_RX:
+		rxfc = 1;
+		hw->fc.current_mode = I40E_FC_RX_PAUSE;
+		break;
+	case I40E_AQ_LINK_PAUSE_TX:
+		txfc = 1;
+		hw->fc.current_mode = I40E_FC_TX_PAUSE;
+		break;
+	default:
+		hw->fc.current_mode = I40E_FC_NONE;
+		break;
+	}
+
+write_reg:
+	I40E_WRITE_REG(hw, I40E_PRTDCB_FCCFG,
+		txfc << I40E_PRTDCB_FCCFG_TFCE_SHIFT);
+	reg = I40E_READ_REG(hw, I40E_PRTDCB_MFLCN);
+	reg &= ~I40E_PRTDCB_MFLCN_RFCE_MASK;
+	reg |= rxfc << I40E_PRTDCB_MFLCN_RFCE_SHIFT;
+	I40E_WRITE_REG(hw, I40E_PRTDCB_MFLCN, reg);
+
+	return ret;
+}
+
+/* PF setup */
+static int
+i40e_pf_setup(struct i40e_pf *pf)
+{
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	struct i40e_filter_control_settings settings;
+	struct rte_eth_dev_data *dev_data = pf->dev_data;
+	struct i40e_vsi *vsi;
+	int ret;
+
+	/* Clear all stats counters */
+	pf->offset_loaded = FALSE;
+	memset(&pf->stats, 0, sizeof(struct i40e_hw_port_stats));
+	memset(&pf->stats_offset, 0, sizeof(struct i40e_hw_port_stats));
+
+	ret = i40e_pf_get_switch_config(pf);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Could not get switch config, err %d", ret);
+		return ret;
+	}
+
+	/* VSI setup */
+	vsi = i40e_vsi_setup(pf, I40E_VSI_MAIN, NULL, 0);
+	if (!vsi) {
+		PMD_DRV_LOG(ERR, "Setup of main vsi failed");
+		return I40E_ERR_NOT_READY;
+	}
+	pf->main_vsi = vsi;
+	dev_data->nb_rx_queues = vsi->nb_qps;
+	dev_data->nb_tx_queues = vsi->nb_qps;
+
+	/* Configure filter control */
+	memset(&settings, 0, sizeof(settings));
+	settings.hash_lut_size = I40E_HASH_LUT_SIZE_128;
+	/* Enable ethtype and macvlan filters */
+	settings.enable_ethtype = TRUE;
+	settings.enable_macvlan = TRUE;
+	ret = i40e_set_filter_control(hw, &settings);
+	if (ret)
+		PMD_INIT_LOG(WARNING, "setup_pf_filter_control failed: %d",
+								ret);
+
+	/* Update flow control according to the auto negotiation */
+	i40e_update_flow_control(hw);
+
+	return I40E_SUCCESS;
+}
+
+int
+i40e_switch_tx_queue(struct i40e_hw *hw, uint16_t q_idx, bool on)
+{
+	uint32_t reg;
+	uint16_t j;
+
+	/* Wait until the request is finished */
+	for (j = 0; j < I40E_CHK_Q_ENA_COUNT; j++) {
+		rte_delay_us(I40E_CHK_Q_ENA_INTERVAL_US);
+		reg = I40E_READ_REG(hw, I40E_QTX_ENA(q_idx));
+		if (!(((reg >> I40E_QTX_ENA_QENA_REQ_SHIFT) & 0x1) ^
+			((reg >> I40E_QTX_ENA_QENA_STAT_SHIFT)
+							& 0x1))) {
+			break;
+		}
+	}
+	if (on) {
+		if (reg & I40E_QTX_ENA_QENA_STAT_MASK)
+			return I40E_SUCCESS; /* already on, skip next steps */
+		reg |= I40E_QTX_ENA_QENA_REQ_MASK;
+	} else {
+		if (!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
+			return I40E_SUCCESS; /* already off, skip next steps */
+		reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
+	}
+	/* Write the register */
+	I40E_WRITE_REG(hw, I40E_QTX_ENA(q_idx), reg);
+	/* Check the result */
+	for (j = 0; j < I40E_CHK_Q_ENA_COUNT; j++) {
+		rte_delay_us(I40E_CHK_Q_ENA_INTERVAL_US);
+		reg = I40E_READ_REG(hw, I40E_QTX_ENA(q_idx));
+		if (on) {
+			if ((reg & I40E_QTX_ENA_QENA_REQ_MASK) &&
+				(reg & I40E_QTX_ENA_QENA_STAT_MASK))
+				break;
+		} else {
+			if (!(reg & I40E_QTX_ENA_QENA_REQ_MASK) &&
+				!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
+				break;
+		}
+	}
+	/* Check if it is timeout */
+	if (j >= I40E_CHK_Q_ENA_COUNT) {
+		PMD_DRV_LOG(ERR, "Failed to %s tx queue[%u]\n",
+			(on ? "enable" : "disable"), q_idx);
+		return I40E_ERR_TIMEOUT;
+	}
+	return I40E_SUCCESS;
+}
+/* Swith on or off the tx queues */
+static int
+i40e_vsi_switch_tx_queues(struct i40e_vsi *vsi, bool on)
+{
+	struct rte_eth_dev_data *dev_data = I40E_VSI_TO_DEV_DATA(vsi);
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	struct i40e_tx_queue *txq;
+	uint16_t i, pf_q;
+	int ret;
+
+	pf_q = vsi->base_queue;
+	for (i = 0; i < dev_data->nb_tx_queues; i++, pf_q++) {
+		txq = dev_data->tx_queues[i];
+		if (!txq->q_set)
+			continue; /* Queue not configured */
+		ret = i40e_switch_tx_queue(hw, pf_q, on);
+		if ( ret != I40E_SUCCESS)
+			return ret;
+	}
+
+	return I40E_SUCCESS;
+}
+
+int
+i40e_switch_rx_queue(struct i40e_hw *hw, uint16_t q_idx, bool on)
+{
+	uint32_t reg;
+	uint16_t j;
+
+	/* Wait until the request is finished */
+	for (j = 0; j < I40E_CHK_Q_ENA_COUNT; j++) {
+		rte_delay_us(I40E_CHK_Q_ENA_INTERVAL_US);
+		reg = I40E_READ_REG(hw, I40E_QRX_ENA(q_idx));
+		if (!((reg >> I40E_QRX_ENA_QENA_REQ_SHIFT) & 0x1) ^
+			((reg >> I40E_QRX_ENA_QENA_STAT_SHIFT) & 0x1))
+			break;
+	}
+
+	if (on) {
+		if (reg & I40E_QRX_ENA_QENA_STAT_MASK)
+			return I40E_SUCCESS; /* Already on, skip next steps */
+		reg |= I40E_QRX_ENA_QENA_REQ_MASK;
+	} else {
+		if (!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
+			return I40E_SUCCESS; /* Already off, skip next steps */
+		reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
+	}
+
+	/* Write the register */
+	I40E_WRITE_REG(hw, I40E_QRX_ENA(q_idx), reg);
+	/* Check the result */
+	for (j = 0; j < I40E_CHK_Q_ENA_COUNT; j++) {
+		rte_delay_us(I40E_CHK_Q_ENA_INTERVAL_US);
+		reg = I40E_READ_REG(hw, I40E_QRX_ENA(q_idx));
+		if (on) {
+			if ((reg & I40E_QRX_ENA_QENA_REQ_MASK) &&
+				(reg & I40E_QRX_ENA_QENA_STAT_MASK))
+				break;
+		} else {
+			if (!(reg & I40E_QRX_ENA_QENA_REQ_MASK) &&
+				!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
+				break;
+		}
+	}
+
+	/* Check if it is timeout */
+	if (j >= I40E_CHK_Q_ENA_COUNT) {
+		PMD_DRV_LOG(ERR, "Failed to %s rx queue[%u]\n",
+			(on ? "enable" : "disable"), q_idx);
+		return I40E_ERR_TIMEOUT;
+	}
+
+	return I40E_SUCCESS;
+}
+/* Switch on or off the rx queues */
+static int
+i40e_vsi_switch_rx_queues(struct i40e_vsi *vsi, bool on)
+{
+	struct rte_eth_dev_data *dev_data = I40E_VSI_TO_DEV_DATA(vsi);
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	struct i40e_rx_queue *rxq;
+	uint16_t i, pf_q;
+	int ret;
+
+	pf_q = vsi->base_queue;
+	for (i = 0; i < dev_data->nb_rx_queues; i++, pf_q++) {
+		rxq = dev_data->rx_queues[i];
+		if (!rxq->q_set)
+			continue; /* Queue not configured */
+		ret = i40e_switch_rx_queue(hw, pf_q, on);
+		if ( ret != I40E_SUCCESS)
+			return ret;
+	}
+
+	return I40E_SUCCESS;
+}
+
+/* Switch on or off all the rx/tx queues */
+int
+i40e_vsi_switch_queues(struct i40e_vsi *vsi, bool on)
+{
+	int ret;
+
+	if (on) {
+		/* enable rx queues before enabling tx queues */
+		ret = i40e_vsi_switch_rx_queues(vsi, on);
+		if (ret) {
+			PMD_DRV_LOG(ERR, "Failed to switch rx queues\n");
+			return ret;
+		}
+		ret = i40e_vsi_switch_tx_queues(vsi, on);
+	} else {
+		/* Stop tx queues before stopping rx queues */
+		ret = i40e_vsi_switch_tx_queues(vsi, on);
+		if (ret) {
+			PMD_DRV_LOG(ERR, "Failed to switch tx queues\n");
+			return ret;
+		}
+		ret = i40e_vsi_switch_rx_queues(vsi, on);
+	}
+
+	return ret;
+}
+
+/* Initialize VSI for TX */
+static int
+i40e_vsi_tx_init(struct i40e_vsi *vsi)
+{
+	struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
+	struct rte_eth_dev_data *data = pf->dev_data;
+	uint16_t i;
+	uint32_t ret = I40E_SUCCESS;
+
+	for (i = 0; i < data->nb_tx_queues; i++) {
+		ret = i40e_tx_queue_init(data->tx_queues[i]);
+		if (ret != I40E_SUCCESS)
+			break;
+	}
+
+	return ret;
+}
+
+/* Initialize VSI for RX */
+static int
+i40e_vsi_rx_init(struct i40e_vsi *vsi)
+{
+	struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
+	struct rte_eth_dev_data *data = pf->dev_data;
+	int ret = I40E_SUCCESS;
+	uint16_t i;
+
+	i40e_pf_config_mq_rx(pf);
+	for (i = 0; i < data->nb_rx_queues; i++) {
+		ret = i40e_rx_queue_init(data->rx_queues[i]);
+		if (ret != I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Failed to do RX queue "
+					"initialization\n");
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/* Initialize VSI */
+static int
+i40e_vsi_init(struct i40e_vsi *vsi)
+{
+	int err;
+
+	err = i40e_vsi_tx_init(vsi);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to do vsi TX initialization\n");
+		return err;
+	}
+	err = i40e_vsi_rx_init(vsi);
+	if (err) {
+		PMD_DRV_LOG(ERR, "Failed to do vsi RX initialization\n");
+		return err;
+	}
+
+	return err;
+}
+
+static void
+i40e_stat_update_32(struct i40e_hw *hw,
+		   uint32_t reg,
+		   bool offset_loaded,
+		   uint64_t *offset,
+		   uint64_t *stat)
+{
+	uint64_t new_data;
+
+	new_data = (uint64_t)I40E_READ_REG(hw, reg);
+	if (!offset_loaded)
+		*offset = new_data;
+
+	if (new_data >= *offset)
+		*stat = (uint64_t)(new_data - *offset);
+	else
+		*stat = (uint64_t)((new_data +
+			((uint64_t)1 << I40E_32_BIT_SHIFT)) - *offset);
+}
+
+static void
+i40e_stat_update_48(struct i40e_hw *hw,
+		   uint32_t hireg,
+		   uint32_t loreg,
+		   bool offset_loaded,
+		   uint64_t *offset,
+		   uint64_t *stat)
+{
+	uint64_t new_data;
+
+	new_data = (uint64_t)I40E_READ_REG(hw, loreg);
+	new_data |= ((uint64_t)(I40E_READ_REG(hw, hireg) &
+			I40E_16_BIT_MASK)) << I40E_32_BIT_SHIFT;
+
+	if (!offset_loaded)
+		*offset = new_data;
+
+	if (new_data >= *offset)
+		*stat = new_data - *offset;
+	else
+		*stat = (uint64_t)((new_data +
+			((uint64_t)1 << I40E_48_BIT_SHIFT)) - *offset);
+
+	*stat &= I40E_48_BIT_MASK;
+}
+
+/* Disable IRQ0 */
+void
+i40e_pf_disable_irq0(struct i40e_hw *hw)
+{
+	/* Disable all interrupt types */
+	I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, 0);
+	I40E_WRITE_FLUSH(hw);
+}
+
+/* Enable IRQ0 */
+void
+i40e_pf_enable_irq0(struct i40e_hw *hw)
+{
+	I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
+		I40E_PFINT_DYN_CTL0_INTENA_MASK |
+		I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
+		I40E_PFINT_DYN_CTL0_ITR_INDX_MASK);
+	I40E_WRITE_FLUSH(hw);
+}
+
+static void
+i40e_pf_config_irq0(struct i40e_hw *hw)
+{
+	uint32_t enable;
+
+	/* read pending request and disable first */
+	i40e_pf_disable_irq0(hw);
+	/**
+	 * Enable all interrupt error options to detect possible errors,
+	 * other informative int are ignored
+	 */
+	enable = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK |
+	         I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK |
+	         I40E_PFINT_ICR0_ENA_GRST_MASK |
+	         I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK |
+	         I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK |
+	         I40E_PFINT_ICR0_ENA_HMC_ERR_MASK |
+	         I40E_PFINT_ICR0_ENA_VFLR_MASK |
+	         I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
+
+	I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, enable);
+	I40E_WRITE_REG(hw, I40E_PFINT_STAT_CTL0,
+		I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_MASK);
+
+	/* Link no queues with irq0 */
+	I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
+		I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK);
+}
+
+static void
+i40e_dev_handle_vfr_event(struct rte_eth_dev *dev)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	int i;
+	uint16_t abs_vf_id;
+	uint32_t index, offset, val;
+
+	if (!pf->vfs)
+		return;
+	/**
+	 * Try to find which VF trigger a reset, use absolute VF id to access
+	 * since the reg is global register.
+	 */
+	for (i = 0; i < pf->vf_num; i++) {
+		abs_vf_id = hw->func_caps.vf_base_id + i;
+		index = abs_vf_id / I40E_UINT32_BIT_SIZE;
+		offset = abs_vf_id % I40E_UINT32_BIT_SIZE;
+		val = I40E_READ_REG(hw, I40E_GLGEN_VFLRSTAT(index));
+		/* VFR event occured */
+		if (val & (0x1 << offset)) {
+			int ret;
+
+			/* Clear the event first */
+			I40E_WRITE_REG(hw, I40E_GLGEN_VFLRSTAT(index),
+							(0x1 << offset));
+			PMD_DRV_LOG(INFO, "VF %u reset occured\n", abs_vf_id);
+			/**
+			 * Only notify a VF reset event occured,
+			 * don't trigger another SW reset
+			 */
+			ret = i40e_pf_host_vf_reset(&pf->vfs[i], 0);
+			if (ret != I40E_SUCCESS)
+				PMD_DRV_LOG(ERR, "Failed to do VF reset\n");
+		}
+	}
+}
+
+static void
+i40e_dev_handle_aq_msg(struct rte_eth_dev *dev)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_arq_event_info info;
+	uint16_t pending, opcode;
+	int ret;
+
+	info.msg_size = I40E_AQ_BUF_SZ;
+	info.msg_buf = rte_zmalloc("msg_buffer", I40E_AQ_BUF_SZ, 0);
+	if (!info.msg_buf) {
+		PMD_DRV_LOG(ERR, "Failed to allocate mem\n");
+		return;
+	}
+
+	pending = 1;
+	while (pending) {
+		ret = i40e_clean_arq_element(hw, &info, &pending);
+
+		if (ret != I40E_SUCCESS) {
+			PMD_DRV_LOG(INFO, "Failed to read msg from AdminQ, "
+				"aq_err: %u\n", hw->aq.asq_last_status);
+			break;
+		}
+		opcode = rte_le_to_cpu_16(info.desc.opcode);
+
+		switch (opcode) {
+		case i40e_aqc_opc_send_msg_to_pf:
+			/* Refer to i40e_aq_send_msg_to_pf() for argument layout*/
+			i40e_pf_host_handle_vf_msg(dev,
+					rte_le_to_cpu_16(info.desc.retval),
+					rte_le_to_cpu_32(info.desc.cookie_high),
+					rte_le_to_cpu_32(info.desc.cookie_low),
+					info.msg_buf,
+					info.msg_size);
+			break;
+		default:
+			PMD_DRV_LOG(ERR, "Request %u is not supported yet\n",
+				opcode);
+			break;
+		}
+		/* Reset the buffer after processing one */
+		info.msg_size = I40E_AQ_BUF_SZ;
+	}
+	rte_free(info.msg_buf);
+}
+
+/**
+ * Interrupt handler triggered by NIC  for handling
+ * specific interrupt.
+ *
+ * @param handle
+ *  Pointer to interrupt handle.
+ * @param param
+ *  The address of parameter (struct rte_eth_dev *) regsitered before.
+ *
+ * @return
+ *  void
+ */
+static void
+i40e_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
+			   void *param)
+{
+	struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t cause, enable;
+
+	i40e_pf_disable_irq0(hw);
+
+	cause = I40E_READ_REG(hw, I40E_PFINT_ICR0);
+	enable = I40E_READ_REG(hw, I40E_PFINT_ICR0_ENA);
+
+	/* Shared IRQ case, return */
+	if (!(cause & I40E_PFINT_ICR0_INTEVENT_MASK)) {
+		PMD_DRV_LOG(INFO, "Port%d INT0:share IRQ case, "
+			"no INT event to process\n", hw->pf_id);
+		goto done;
+	}
+
+	if (cause & I40E_PFINT_ICR0_LINK_STAT_CHANGE_MASK) {
+		PMD_DRV_LOG(INFO, "INT:Link status changed\n");
+		i40e_dev_link_update(dev, 0);
+	}
+
+	if (cause & I40E_PFINT_ICR0_ECC_ERR_MASK)
+		PMD_DRV_LOG(INFO, "INT:Unrecoverable ECC Error\n");
+
+	if (cause & I40E_PFINT_ICR0_MAL_DETECT_MASK)
+		PMD_DRV_LOG(INFO, "INT:Malicious programming detected\n");
+
+	if (cause & I40E_PFINT_ICR0_GRST_MASK)
+		PMD_DRV_LOG(INFO, "INT:Global Resets Requested\n");
+
+	if (cause & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK)
+		PMD_DRV_LOG(INFO, "INT:PCI EXCEPTION occured\n");
+
+	if (cause & I40E_PFINT_ICR0_HMC_ERR_MASK)
+		PMD_DRV_LOG(INFO, "INT:HMC error occured\n");
+
+	/* Add processing func to deal with VF reset vent */
+	if (cause & I40E_PFINT_ICR0_VFLR_MASK) {
+		PMD_DRV_LOG(INFO, "INT:VF reset detected\n");
+		i40e_dev_handle_vfr_event(dev);
+	}
+	/* Find admin queue event */
+	if (cause & I40E_PFINT_ICR0_ADMINQ_MASK) {
+		PMD_DRV_LOG(INFO, "INT:ADMINQ event\n");
+		i40e_dev_handle_aq_msg(dev);
+	}
+
+done:
+	I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, enable);
+	/* Re-enable interrupt from device side */
+	i40e_pf_enable_irq0(hw);
+	/* Re-enable interrupt from host side */
+	rte_intr_enable(&(dev->pci_dev->intr_handle));
+}
+
+static int
+i40e_add_macvlan_filters(struct i40e_vsi *vsi,
+			 struct i40e_macvlan_filter *filter,
+			 int total)
+{
+	int ele_num, ele_buff_size;
+	int num, actual_num, i;
+	int ret = I40E_SUCCESS;
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	struct i40e_aqc_add_macvlan_element_data *req_list;
+
+	if (filter == NULL  || total == 0)
+		return I40E_ERR_PARAM;
+	ele_num = hw->aq.asq_buf_size / sizeof(*req_list);
+	ele_buff_size = hw->aq.asq_buf_size;
+
+	req_list = rte_zmalloc("macvlan_add", ele_buff_size, 0);
+	if (req_list == NULL) {
+		PMD_DRV_LOG(ERR, "Fail to allocate memory\n");
+		return I40E_ERR_NO_MEMORY;
+	}
+
+	num = 0;
+	do {
+		actual_num = (num + ele_num > total) ? (total - num) : ele_num;
+		memset(req_list, 0, ele_buff_size);
+
+		for (i = 0; i < actual_num; i++) {
+			(void)rte_memcpy(req_list[i].mac_addr,
+				&filter[num + i].macaddr, ETH_ADDR_LEN);
+			req_list[i].vlan_tag =
+				rte_cpu_to_le_16(filter[num + i].vlan_id);
+			req_list[i].flags = rte_cpu_to_le_16(\
+				I40E_AQC_MACVLAN_ADD_PERFECT_MATCH);
+			req_list[i].queue_number = 0;
+		}
+
+		ret = i40e_aq_add_macvlan(hw, vsi->seid, req_list,
+						actual_num, NULL);
+		if (ret != I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Failed to add macvlan filter\n");
+			goto DONE;
+		}
+		num += actual_num;
+	} while (num < total);
+
+DONE:
+	rte_free(req_list);
+	return ret;
+}
+
+static int
+i40e_remove_macvlan_filters(struct i40e_vsi *vsi,
+			    struct i40e_macvlan_filter *filter,
+			    int total)
+{
+	int ele_num, ele_buff_size;
+	int num, actual_num, i;
+	int ret = I40E_SUCCESS;
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	struct i40e_aqc_remove_macvlan_element_data *req_list;
+
+	if (filter == NULL  || total == 0)
+		return I40E_ERR_PARAM;
+
+	ele_num = hw->aq.asq_buf_size / sizeof(*req_list);
+	ele_buff_size = hw->aq.asq_buf_size;
+
+	req_list = rte_zmalloc("macvlan_remove", ele_buff_size, 0);
+	if (req_list == NULL) {
+		PMD_DRV_LOG(ERR, "Fail to allocate memory\n");
+		return I40E_ERR_NO_MEMORY;
+	}
+
+	num = 0;
+	do {
+		actual_num = (num + ele_num > total) ? (total - num) : ele_num;
+		memset(req_list, 0, ele_buff_size);
+
+		for (i = 0; i < actual_num; i++) {
+			(void)rte_memcpy(req_list[i].mac_addr,
+				&filter[num + i].macaddr, ETH_ADDR_LEN);
+			req_list[i].vlan_tag =
+				rte_cpu_to_le_16(filter[num + i].vlan_id);
+			req_list[i].flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
+		}
+
+		ret = i40e_aq_remove_macvlan(hw, vsi->seid, req_list,
+						actual_num, NULL);
+		if (ret != I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Failed to remove macvlan filter\n");
+			goto DONE;
+		}
+		num += actual_num;
+	} while (num < total);
+
+DONE:
+	rte_free(req_list);
+	return ret;
+}
+
+/* Find out specific MAC filter */
+static struct i40e_mac_filter *
+i40e_find_mac_filter(struct i40e_vsi *vsi,
+			 struct ether_addr *macaddr)
+{
+	struct i40e_mac_filter *f;
+
+	TAILQ_FOREACH(f, &vsi->mac_list, next) {
+		if (is_same_ether_addr(macaddr, &(f->macaddr)))
+			return f;
+	}
+
+	return NULL;
+}
+
+static bool
+i40e_find_vlan_filter(struct i40e_vsi *vsi,
+			 uint16_t vlan_id)
+{
+	uint32_t vid_idx, vid_bit;
+
+	vid_idx = (uint32_t) ((vlan_id >> 5) & 0x7F);
+	vid_bit = (uint32_t) (1 << (vlan_id & 0x1F));
+
+	if (vsi->vfta[vid_idx] & vid_bit)
+		return 1;
+	else
+		return 0;
+}
+
+static void
+i40e_set_vlan_filter(struct i40e_vsi *vsi,
+			 uint16_t vlan_id, bool on)
+{
+	uint32_t vid_idx, vid_bit;
+
+#define UINT32_BIT_MASK      0x1F
+#define VALID_VLAN_BIT_MASK  0xFFF
+	/* VFTA is 32-bits size array, each element contains 32 vlan bits, Find the
+	 *  element first, then find the bits it belongs to
+	 */
+	vid_idx = (uint32_t) ((vlan_id & VALID_VLAN_BIT_MASK) >>
+		  sizeof(uint32_t));
+	vid_bit = (uint32_t) (1 << (vlan_id & UINT32_BIT_MASK));
+
+	if (on)
+		vsi->vfta[vid_idx] |= vid_bit;
+	else
+		vsi->vfta[vid_idx] &= ~vid_bit;
+}
+
+/**
+ * Find all vlan options for specific mac addr,
+ * return with actual vlan found.
+ */
+static inline int
+i40e_find_all_vlan_for_mac(struct i40e_vsi *vsi,
+			   struct i40e_macvlan_filter *mv_f,
+			   int num, struct ether_addr *addr)
+{
+	int i;
+	uint32_t j, k;
+
+	/**
+	 * Not to use i40e_find_vlan_filter to decrease the loop time,
+	 * although the code looks complex.
+	  */
+	if (num < vsi->vlan_num)
+		return I40E_ERR_PARAM;
+
+	i = 0;
+	for (j = 0; j < I40E_VFTA_SIZE; j++) {
+		if (vsi->vfta[j]) {
+			for (k = 0; k < I40E_UINT32_BIT_SIZE; k++) {
+				if (vsi->vfta[j] & (1 << k)) {
+					if (i > num - 1) {
+						PMD_DRV_LOG(ERR, "vlan number "
+								"not match\n");
+						return I40E_ERR_PARAM;
+					}
+					(void)rte_memcpy(&mv_f[i].macaddr,
+							addr, ETH_ADDR_LEN);
+					mv_f[i].vlan_id =
+						j * I40E_UINT32_BIT_SIZE + k;
+					i++;
+				}
+			}
+		}
+	}
+	return I40E_SUCCESS;
+}
+
+static inline int
+i40e_find_all_mac_for_vlan(struct i40e_vsi *vsi,
+			   struct i40e_macvlan_filter *mv_f,
+			   int num,
+			   uint16_t vlan)
+{
+	int i = 0;
+	struct i40e_mac_filter *f;
+
+	if (num < vsi->mac_num)
+		return I40E_ERR_PARAM;
+
+	TAILQ_FOREACH(f, &vsi->mac_list, next) {
+		if (i > num - 1) {
+			PMD_DRV_LOG(ERR, "buffer number not match\n");
+			return I40E_ERR_PARAM;
+		}
+		(void)rte_memcpy(&mv_f[i].macaddr, &f->macaddr, ETH_ADDR_LEN);
+		mv_f[i].vlan_id = vlan;
+		i++;
+	}
+
+	return I40E_SUCCESS;
+}
+
+static int
+i40e_vsi_remove_all_macvlan_filter(struct i40e_vsi *vsi)
+{
+	int i, num;
+	struct i40e_mac_filter *f;
+	struct i40e_macvlan_filter *mv_f;
+	int ret = I40E_SUCCESS;
+
+	if (vsi == NULL || vsi->mac_num == 0)
+		return I40E_ERR_PARAM;
+
+	/* Case that no vlan is set */
+	if (vsi->vlan_num == 0)
+		num = vsi->mac_num;
+	else
+		num = vsi->mac_num * vsi->vlan_num;
+
+	mv_f = rte_zmalloc("macvlan_data", num * sizeof(*mv_f), 0);
+	if (mv_f == NULL) {
+		PMD_DRV_LOG(ERR, "failed to allocate memory\n");
+		return I40E_ERR_NO_MEMORY;
+	}
+
+	i = 0;
+	if (vsi->vlan_num == 0) {
+		TAILQ_FOREACH(f, &vsi->mac_list, next) {
+			(void)rte_memcpy(&mv_f[i].macaddr,
+				&f->macaddr, ETH_ADDR_LEN);
+			mv_f[i].vlan_id = 0;
+			i++;
+		}
+	} else {
+		TAILQ_FOREACH(f, &vsi->mac_list, next) {
+			ret = i40e_find_all_vlan_for_mac(vsi,&mv_f[i],
+					vsi->vlan_num, &f->macaddr);
+			if (ret != I40E_SUCCESS)
+				goto DONE;
+			i += vsi->vlan_num;
+		}
+	}
+
+	ret = i40e_remove_macvlan_filters(vsi, mv_f, num);
+DONE:
+	rte_free(mv_f);
+
+	return ret;
+}
+
+int
+i40e_vsi_add_vlan(struct i40e_vsi *vsi, uint16_t vlan)
+{
+	struct i40e_macvlan_filter *mv_f;
+	int mac_num;
+	int ret = I40E_SUCCESS;
+
+	if (!vsi || vlan > ETHER_MAX_VLAN_ID)
+		return I40E_ERR_PARAM;
+
+	/* If it's already set, just return */
+	if (i40e_find_vlan_filter(vsi,vlan))
+		return I40E_SUCCESS;
+
+	mac_num = vsi->mac_num;
+
+	if (mac_num == 0) {
+		PMD_DRV_LOG(ERR, "Error! VSI doesn't have a mac addr\n");
+		return I40E_ERR_PARAM;
+	}
+
+	mv_f = rte_zmalloc("macvlan_data", mac_num * sizeof(*mv_f), 0);
+
+	if (mv_f == NULL) {
+		PMD_DRV_LOG(ERR, "failed to allocate memory\n");
+		return I40E_ERR_NO_MEMORY;
+	}
+
+	ret = i40e_find_all_mac_for_vlan(vsi, mv_f, mac_num, vlan);
+
+	if (ret != I40E_SUCCESS)
+		goto DONE;
+
+	ret = i40e_add_macvlan_filters(vsi, mv_f, mac_num);
+
+	if (ret != I40E_SUCCESS)
+		goto DONE;
+
+	i40e_set_vlan_filter(vsi, vlan, 1);
+
+	vsi->vlan_num++;
+	ret = I40E_SUCCESS;
+DONE:
+	rte_free(mv_f);
+	return ret;
+}
+
+int
+i40e_vsi_delete_vlan(struct i40e_vsi *vsi, uint16_t vlan)
+{
+	struct i40e_macvlan_filter *mv_f;
+	int mac_num;
+	int ret = I40E_SUCCESS;
+
+	/**
+	 * Vlan 0 is the generic filter for untagged packets
+	 * and can't be removed.
+	 */
+	if (!vsi || vlan == 0 || vlan > ETHER_MAX_VLAN_ID)
+		return I40E_ERR_PARAM;
+
+	/* If can't find it, just return */
+	if (!i40e_find_vlan_filter(vsi, vlan))
+		return I40E_ERR_PARAM;
+
+	mac_num = vsi->mac_num;
+
+	if (mac_num == 0) {
+		PMD_DRV_LOG(ERR, "Error! VSI doesn't have a mac addr\n");
+		return I40E_ERR_PARAM;
+	}
+
+	mv_f = rte_zmalloc("macvlan_data", mac_num * sizeof(*mv_f), 0);
+
+	if (mv_f == NULL) {
+		PMD_DRV_LOG(ERR, "failed to allocate memory\n");
+		return I40E_ERR_NO_MEMORY;
+	}
+
+	ret = i40e_find_all_mac_for_vlan(vsi, mv_f, mac_num, vlan);
+
+	if (ret != I40E_SUCCESS)
+		goto DONE;
+
+	ret = i40e_remove_macvlan_filters(vsi, mv_f, mac_num);
+
+	if (ret != I40E_SUCCESS)
+		goto DONE;
+
+	/* This is last vlan to remove, replace all mac filter with vlan 0 */
+	if (vsi->vlan_num == 1) {
+		ret = i40e_find_all_mac_for_vlan(vsi, mv_f, mac_num, 0);
+		if (ret != I40E_SUCCESS)
+			goto DONE;
+
+		ret = i40e_add_macvlan_filters(vsi, mv_f, mac_num);
+		if (ret != I40E_SUCCESS)
+			goto DONE;
+	}
+
+	i40e_set_vlan_filter(vsi, vlan, 0);
+
+	vsi->vlan_num--;
+	ret = I40E_SUCCESS;
+DONE:
+	rte_free(mv_f);
+	return ret;
+}
+
+int
+i40e_vsi_add_mac(struct i40e_vsi *vsi, struct ether_addr *addr)
+{
+	struct i40e_mac_filter *f;
+	struct i40e_macvlan_filter *mv_f;
+	int vlan_num;
+	int ret = I40E_SUCCESS;
+
+	/* If it's add and we've config it, return */
+	f = i40e_find_mac_filter(vsi, addr);
+	if (f != NULL)
+		return I40E_SUCCESS;
+
+	/**
+	 * If vlan_num is 0, that's the first time to add mac,
+	 * set mask for vlan_id 0.
+	 */
+	if (vsi->vlan_num == 0) {
+		i40e_set_vlan_filter(vsi, 0, 1);
+		vsi->vlan_num = 1;
+	}
+
+	vlan_num = vsi->vlan_num;
+
+	mv_f = rte_zmalloc("macvlan_data", vlan_num * sizeof(*mv_f), 0);
+	if (mv_f == NULL) {
+		PMD_DRV_LOG(ERR, "failed to allocate memory\n");
+		return I40E_ERR_NO_MEMORY;
+	}
+
+	ret = i40e_find_all_vlan_for_mac(vsi, mv_f, vlan_num, addr);
+	if (ret != I40E_SUCCESS)
+		goto DONE;
+
+	ret = i40e_add_macvlan_filters(vsi, mv_f, vlan_num);
+	if (ret != I40E_SUCCESS)
+		goto DONE;
+
+	/* Add the mac addr into mac list */
+	f = rte_zmalloc("macv_filter", sizeof(*f), 0);
+	if (f == NULL) {
+		PMD_DRV_LOG(ERR, "failed to allocate memory\n");
+		ret = I40E_ERR_NO_MEMORY;
+		goto DONE;
+	}
+	(void)rte_memcpy(&f->macaddr, addr, ETH_ADDR_LEN);
+	TAILQ_INSERT_TAIL(&vsi->mac_list, f, next);
+	vsi->mac_num++;
+
+	ret = I40E_SUCCESS;
+DONE:
+	rte_free(mv_f);
+
+	return ret;
+}
+
+int
+i40e_vsi_delete_mac(struct i40e_vsi *vsi, struct ether_addr *addr)
+{
+	struct i40e_mac_filter *f;
+	struct i40e_macvlan_filter *mv_f;
+	int vlan_num;
+	int ret = I40E_SUCCESS;
+
+	/* Can't find it, return an error */
+	f = i40e_find_mac_filter(vsi, addr);
+	if (f == NULL)
+		return I40E_ERR_PARAM;
+
+	vlan_num = vsi->vlan_num;
+	if (vlan_num == 0) {
+		PMD_DRV_LOG(ERR, "VLAN number shouldn't be 0\n");
+		return I40E_ERR_PARAM;
+	}
+	mv_f = rte_zmalloc("macvlan_data", vlan_num * sizeof(*mv_f), 0);
+	if (mv_f == NULL) {
+		PMD_DRV_LOG(ERR, "failed to allocate memory\n");
+		return I40E_ERR_NO_MEMORY;
+	}
+
+	ret = i40e_find_all_vlan_for_mac(vsi, mv_f, vlan_num, addr);
+	if (ret != I40E_SUCCESS)
+		goto DONE;
+
+	ret = i40e_remove_macvlan_filters(vsi, mv_f, vlan_num);
+	if (ret != I40E_SUCCESS)
+		goto DONE;
+
+	/* Remove the mac addr into mac list */
+	TAILQ_REMOVE(&vsi->mac_list, f, next);
+	rte_free(f);
+	vsi->mac_num--;
+
+	ret = I40E_SUCCESS;
+DONE:
+	rte_free(mv_f);
+	return ret;
+}
+
+/* Configure hash enable flags for RSS */
+static uint64_t
+i40e_config_hena(uint64_t flags)
+{
+	uint64_t hena = 0;
+
+	if (!flags)
+		return hena;
+
+	if (flags & ETH_RSS_NONF_IPV4_UDP)
+		hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
+	if (flags & ETH_RSS_NONF_IPV4_TCP)
+		hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
+	if (flags & ETH_RSS_NONF_IPV4_SCTP)
+		hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP;
+	if (flags & ETH_RSS_NONF_IPV4_OTHER)
+		hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
+	if (flags & ETH_RSS_FRAG_IPV4)
+		hena |= 1ULL << I40E_FILTER_PCTYPE_FRAG_IPV4;
+	if (flags & ETH_RSS_NONF_IPV6_UDP)
+		hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_UDP;
+	if (flags & ETH_RSS_NONF_IPV6_TCP)
+		hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP;
+	if (flags & ETH_RSS_NONF_IPV6_SCTP)
+		hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP;
+	if (flags & ETH_RSS_NONF_IPV6_OTHER)
+		hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER;
+	if (flags & ETH_RSS_FRAG_IPV6)
+		hena |= 1ULL << I40E_FILTER_PCTYPE_FRAG_IPV6;
+	if (flags & ETH_RSS_L2_PAYLOAD)
+		hena |= 1ULL << I40E_FILTER_PCTYPE_L2_PAYLOAD;
+
+	return hena;
+}
+
+/* Parse the hash enable flags */
+static uint64_t
+i40e_parse_hena(uint64_t flags)
+{
+	uint64_t rss_hf = 0;
+
+	if (!flags)
+		return rss_hf;
+
+	if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_UDP))
+		rss_hf |= ETH_RSS_NONF_IPV4_UDP;
+	if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP))
+		rss_hf |= ETH_RSS_NONF_IPV4_TCP;
+	if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP))
+		rss_hf |= ETH_RSS_NONF_IPV4_SCTP;
+	if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER))
+		rss_hf |= ETH_RSS_NONF_IPV4_OTHER;
+	if (flags & (1ULL << I40E_FILTER_PCTYPE_FRAG_IPV4))
+		rss_hf |= ETH_RSS_FRAG_IPV4;
+	if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_UDP))
+		rss_hf |= ETH_RSS_NONF_IPV6_UDP;
+	if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP))
+		rss_hf |= ETH_RSS_NONF_IPV6_TCP;
+	if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP))
+		rss_hf |= ETH_RSS_NONF_IPV6_SCTP;
+	if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER))
+		rss_hf |= ETH_RSS_NONF_IPV6_OTHER;
+	if (flags & (1ULL << I40E_FILTER_PCTYPE_FRAG_IPV6))
+		rss_hf |= ETH_RSS_FRAG_IPV6;
+	if (flags & (1ULL << I40E_FILTER_PCTYPE_L2_PAYLOAD))
+		rss_hf |= ETH_RSS_L2_PAYLOAD;
+
+	return rss_hf;
+}
+
+/* Disable RSS */
+static void
+i40e_pf_disable_rss(struct i40e_pf *pf)
+{
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	uint64_t hena;
+
+	hena = (uint64_t)I40E_READ_REG(hw, I40E_PFQF_HENA(0));
+	hena |= ((uint64_t)I40E_READ_REG(hw, I40E_PFQF_HENA(1))) << 32;
+	hena &= ~I40E_RSS_HENA_ALL;
+	I40E_WRITE_REG(hw, I40E_PFQF_HENA(0), (uint32_t)hena);
+	I40E_WRITE_REG(hw, I40E_PFQF_HENA(1), (uint32_t)(hena >> 32));
+	I40E_WRITE_FLUSH(hw);
+}
+
+static int
+i40e_hw_rss_hash_set(struct i40e_hw *hw, struct rte_eth_rss_conf *rss_conf)
+{
+	uint32_t *hash_key;
+	uint8_t hash_key_len;
+	uint64_t rss_hf;
+	uint16_t i;
+	uint64_t hena;
+
+	hash_key = (uint32_t *)(rss_conf->rss_key);
+	hash_key_len = rss_conf->rss_key_len;
+	if (hash_key != NULL && hash_key_len >=
+		(I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
+		/* Fill in RSS hash key */
+		for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
+			I40E_WRITE_REG(hw, I40E_PFQF_HKEY(i), hash_key[i]);
+	}
+
+	rss_hf = rss_conf->rss_hf;
+	hena = (uint64_t)I40E_READ_REG(hw, I40E_PFQF_HENA(0));
+	hena |= ((uint64_t)I40E_READ_REG(hw, I40E_PFQF_HENA(1))) << 32;
+	hena &= ~I40E_RSS_HENA_ALL;
+	hena |= i40e_config_hena(rss_hf);
+	I40E_WRITE_REG(hw, I40E_PFQF_HENA(0), (uint32_t)hena);
+	I40E_WRITE_REG(hw, I40E_PFQF_HENA(1), (uint32_t)(hena >> 32));
+	I40E_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+static int
+i40e_dev_rss_hash_update(struct rte_eth_dev *dev,
+			 struct rte_eth_rss_conf *rss_conf)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint64_t rss_hf = rss_conf->rss_hf & I40E_RSS_OFFLOAD_ALL;
+	uint64_t hena;
+
+	hena = (uint64_t)I40E_READ_REG(hw, I40E_PFQF_HENA(0));
+	hena |= ((uint64_t)I40E_READ_REG(hw, I40E_PFQF_HENA(1))) << 32;
+	if (!(hena & I40E_RSS_HENA_ALL)) { /* RSS disabled */
+		if (rss_hf != 0) /* Enable RSS */
+			return -EINVAL;
+		return 0; /* Nothing to do */
+	}
+	/* RSS enabled */
+	if (rss_hf == 0) /* Disable RSS */
+		return -EINVAL;
+
+	return i40e_hw_rss_hash_set(hw, rss_conf);
+}
+
+static int
+i40e_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+			   struct rte_eth_rss_conf *rss_conf)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint32_t *hash_key = (uint32_t *)(rss_conf->rss_key);
+	uint64_t hena;
+	uint16_t i;
+
+	if (hash_key != NULL) {
+		for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
+			hash_key[i] = I40E_READ_REG(hw, I40E_PFQF_HKEY(i));
+		rss_conf->rss_key_len = i * sizeof(uint32_t);
+	}
+	hena = (uint64_t)I40E_READ_REG(hw, I40E_PFQF_HENA(0));
+	hena |= ((uint64_t)I40E_READ_REG(hw, I40E_PFQF_HENA(1))) << 32;
+	rss_conf->rss_hf = i40e_parse_hena(hena);
+
+	return 0;
+}
+
+/* Configure RSS */
+static int
+i40e_pf_config_rss(struct i40e_pf *pf)
+{
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	struct rte_eth_rss_conf rss_conf;
+	uint32_t i, lut = 0;
+	uint16_t j, num = i40e_prev_power_of_2(pf->dev_data->nb_rx_queues);
+
+	for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) {
+		if (j == num)
+			j = 0;
+		lut = (lut << 8) | (j & ((0x1 <<
+			hw->func_caps.rss_table_entry_width) - 1));
+		if ((i & 3) == 3)
+			I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut);
+	}
+
+	rss_conf = pf->dev_data->dev_conf.rx_adv_conf.rss_conf;
+	if ((rss_conf.rss_hf & I40E_RSS_OFFLOAD_ALL) == 0) {
+		i40e_pf_disable_rss(pf);
+		return 0;
+	}
+	if (rss_conf.rss_key == NULL || rss_conf.rss_key_len <
+		(I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
+		/* Calculate the default hash key */
+		for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
+			rss_key_default[i] = (uint32_t)rte_rand();
+		rss_conf.rss_key = (uint8_t *)rss_key_default;
+		rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
+							sizeof(uint32_t);
+	}
+
+	return i40e_hw_rss_hash_set(hw, &rss_conf);
+}
+
+static int
+i40e_pf_config_mq_rx(struct i40e_pf *pf)
+{
+	if (!pf->dev_data->sriov.active) {
+		switch (pf->dev_data->dev_conf.rxmode.mq_mode) {
+		case ETH_MQ_RX_RSS:
+			i40e_pf_config_rss(pf);
+			break;
+		default:
+			i40e_pf_disable_rss(pf);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int
+i40e_disable_queue(struct i40e_hw *hw, uint16_t q_idx)
+{
+	uint16_t i;
+	uint32_t reg;
+
+	/* Disable TX queue */
+	for (i = 0; i < I40E_CHK_Q_ENA_COUNT; i++) {
+		reg = I40E_READ_REG(hw, I40E_QTX_ENA(q_idx));
+		if (!(((reg >> I40E_QTX_ENA_QENA_REQ_SHIFT) & 0x1) ^
+			((reg >> I40E_QTX_ENA_QENA_STAT_SHIFT) & 0x1)))
+			break;
+		rte_delay_us(I40E_CHK_Q_ENA_INTERVAL_US);
+	}
+	if (i >= I40E_CHK_Q_ENA_COUNT) {
+		PMD_DRV_LOG(ERR, "Failed to disable "
+			"tx queue[%u]\n", q_idx);
+		return I40E_ERR_TIMEOUT;
+	}
+
+	if (reg & I40E_QTX_ENA_QENA_STAT_MASK) {
+		reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
+		I40E_WRITE_REG(hw, I40E_QTX_ENA(q_idx), reg);
+		for (i = 0; i < I40E_CHK_Q_ENA_COUNT; i++) {
+			rte_delay_us(I40E_CHK_Q_ENA_INTERVAL_US);
+			reg = I40E_READ_REG(hw, I40E_QTX_ENA(q_idx));
+			if (!(reg & I40E_QTX_ENA_QENA_REQ_MASK) &&
+				!(reg & I40E_QTX_ENA_QENA_STAT_MASK))
+				break;
+		}
+		if (i >= I40E_CHK_Q_ENA_COUNT) {
+			PMD_DRV_LOG(ERR, "Failed to disable "
+				"tx queue[%u]\n", q_idx);
+			return I40E_ERR_TIMEOUT;
+		}
+	}
+
+	/* Disable RX queue */
+	for (i = 0; i < I40E_CHK_Q_ENA_COUNT; i++) {
+		reg = I40E_READ_REG(hw, I40E_QRX_ENA(q_idx));
+		if (!((reg >> I40E_QRX_ENA_QENA_REQ_SHIFT) & 0x1) ^
+			((reg >> I40E_QRX_ENA_QENA_STAT_SHIFT) & 0x1))
+			break;
+		rte_delay_us(I40E_CHK_Q_ENA_INTERVAL_US);
+	}
+	if (i >= I40E_CHK_Q_ENA_COUNT) {
+		PMD_DRV_LOG(ERR, "Failed to disable "
+			"rx queue[%u]\n", q_idx);
+		return I40E_ERR_TIMEOUT;
+	}
+
+	if (reg & I40E_QRX_ENA_QENA_STAT_MASK) {
+		reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
+		I40E_WRITE_REG(hw, I40E_QRX_ENA(q_idx), reg);
+		for (i = 0; i < I40E_CHK_Q_ENA_COUNT; i++) {
+			rte_delay_us(I40E_CHK_Q_ENA_INTERVAL_US);
+			reg = I40E_READ_REG(hw, I40E_QRX_ENA(q_idx));
+			if (!(reg & I40E_QRX_ENA_QENA_REQ_MASK) &&
+				!(reg & I40E_QRX_ENA_QENA_STAT_MASK))
+				break;
+		}
+		if (i >= I40E_CHK_Q_ENA_COUNT) {
+			PMD_DRV_LOG(ERR, "Failed to disable "
+				"rx queue[%u]\n", q_idx);
+			return I40E_ERR_TIMEOUT;
+		}
+	}
+
+	return I40E_SUCCESS;
+}
+
+static int
+i40e_pf_disable_all_queues(struct i40e_hw *hw)
+{
+	uint32_t reg;
+	uint16_t firstq, lastq, maxq, i;
+	int ret;
+	reg = I40E_READ_REG(hw, I40E_PFLAN_QALLOC);
+	if (!(reg & I40E_PFLAN_QALLOC_VALID_MASK)) {
+		PMD_DRV_LOG(INFO, "PF queue allocation is invalid\n");
+		return I40E_ERR_PARAM;
+	}
+	firstq = reg & I40E_PFLAN_QALLOC_FIRSTQ_MASK;
+	lastq = (reg & I40E_PFLAN_QALLOC_LASTQ_MASK) >>
+			I40E_PFLAN_QALLOC_LASTQ_SHIFT;
+	maxq = lastq - firstq;
+	for (i = 0; i <= maxq; i++) {
+		ret = i40e_disable_queue(hw, i);
+		if (ret != I40E_SUCCESS)
+			return ret;
+	}
+	return I40E_SUCCESS;
+}
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.h b/lib/librte_pmd_i40e/i40e_ethdev.h
new file mode 100644
index 0000000..e00895d
--- /dev/null
+++ b/lib/librte_pmd_i40e/i40e_ethdev.h
@@ -0,0 +1,356 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _I40E_ETHDEV_H_
+#define _I40E_ETHDEV_H_
+
+#define I40E_AQ_LEN               32
+#define I40E_AQ_BUF_SZ            4096
+/* Number of queues per TC should be one of 1, 2, 4, 8, 16, 32, 64 */
+#define I40E_MAX_Q_PER_TC         64
+#define I40E_NUM_DESC_DEFAULT     512
+#define I40E_NUM_DESC_ALIGN       32
+#define I40E_BUF_SIZE_MIN         1024
+#define I40E_FRAME_SIZE_MAX       9728
+#define I40E_QUEUE_BASE_ADDR_UNIT 128
+/* number of VSIs and queue default setting */
+#define I40E_MAX_QP_NUM_PER_VF    16
+#define I40E_DEFAULT_QP_NUM_VMDQ  64
+#define I40E_DEFAULT_QP_NUM_FDIR  64
+#define I40E_UINT32_BIT_SIZE      (CHAR_BIT * sizeof(uint32_t))
+#define I40E_VFTA_SIZE            (4096 / I40E_UINT32_BIT_SIZE)
+/* Default TC traffic in case DCB is not enabled */
+#define I40E_DEFAULT_TCMAP        0x1
+
+/* i40e flags */
+#define I40E_FLAG_RSS                   (1ULL << 0)
+#define I40E_FLAG_DCB                   (1ULL << 1)
+#define I40E_FLAG_VMDQ                  (1ULL << 2)
+#define I40E_FLAG_SRIOV                 (1ULL << 3)
+#define I40E_FLAG_HEADER_SPLIT_DISABLED (1ULL << 4)
+#define I40E_FLAG_HEADER_SPLIT_ENABLED  (1ULL << 5)
+#define I40E_FLAG_FDIR                  (1ULL << 6)
+#define I40E_FLAG_ALL (I40E_FLAG_RSS | \
+		       I40E_FLAG_DCB | \
+		       I40E_FLAG_VMDQ | \
+		       I40E_FLAG_SRIOV | \
+		       I40E_FLAG_HEADER_SPLIT_DISABLED | \
+		       I40E_FLAG_HEADER_SPLIT_ENABLED | \
+		       I40E_FLAG_FDIR)
+
+struct i40e_adapter;
+
+TAILQ_HEAD(i40e_mac_filter_list, i40e_mac_filter);
+
+/* MAC filter list structure */
+struct i40e_mac_filter {
+	TAILQ_ENTRY(i40e_mac_filter) next;
+	struct ether_addr macaddr;
+};
+
+TAILQ_HEAD(i40e_vsi_list_head, i40e_vsi_list);
+
+struct i40e_vsi;
+
+/* VSI list structure */
+struct i40e_vsi_list {
+	TAILQ_ENTRY(i40e_vsi_list) list;
+	struct i40e_vsi *vsi;
+};
+
+struct i40e_rx_queue;
+struct i40e_tx_queue;
+
+/* Structure that defines a VEB */
+struct i40e_veb {
+	struct i40e_vsi_list_head head;
+	struct i40e_vsi *associate_vsi; /* Associate VSI who owns the VEB */
+	uint16_t seid; /* The seid of VEB itself */
+	uint16_t uplink_seid; /* The uplink seid of this VEB */
+	uint16_t stats_idx;
+	struct i40e_eth_stats stats;
+};
+
+/* MACVLAN filter structure */
+struct i40e_macvlan_filter {
+	struct ether_addr macaddr;
+	uint16_t vlan_id;
+};
+/*
+ * Structure that defines a VSI, associated with a adapter.
+ */
+struct i40e_vsi {
+	struct i40e_adapter *adapter; /* Backreference to associated adapter */
+	struct i40e_aqc_vsi_properties_data info; /* VSI properties */
+
+	struct i40e_eth_stats eth_stats_offset;
+	struct i40e_eth_stats eth_stats;
+	/*
+	 * When drivers loaded, only a default main VSI exists. In case new VSI
+	 * needs to add, HW needs to know the layout that VSIs are organized.
+	 * Besides that, VSI isan element and can't switch packets, which needs
+	 * to add new component VEB to perform switching. So, a new VSI needs
+	 * to specify the the uplink VSI (Parent VSI) before created. The
+	 * uplink VSI will check whether it had a VEB to switch packets. If no,
+	 * it will try to create one. Then, uplink VSI will move the new VSI
+	 * into its' sib_vsi_list to manage all the downlink VSI.
+	 *  sib_vsi_list: the VSI list that shared the same uplink VSI.
+	 *  parent_vsi  : the uplink VSI. It's NULL for main VSI.
+	 *  veb         : the VEB associates with the VSI.
+	 */
+	struct i40e_vsi_list sib_vsi_list; /* sibling vsi list */
+	struct i40e_vsi *parent_vsi;
+	struct i40e_veb *veb;    /* Associated veb, could be null */
+	bool offset_loaded;
+	enum i40e_vsi_type type; /* VSI types */
+	uint16_t vlan_num;       /* Total VLAN number */
+	uint16_t mac_num;        /* Total mac number */
+	uint32_t vfta[I40E_VFTA_SIZE];        /* VLAN bitmap */
+	struct i40e_mac_filter_list mac_list; /* macvlan filter list */
+	/* specific VSI-defined parameters, SRIOV stored the vf_id */
+	uint32_t user_param;
+	uint16_t seid;           /* The seid of VSI itself */
+	uint16_t uplink_seid;    /* The uplink seid of this VSI */
+	uint16_t nb_qps;         /* Number of queue pairs VSI can occupy */
+	uint16_t max_macaddrs;   /* Maximum number of MAC addresses */
+	uint16_t base_queue;     /* The first queue index of this VSI */
+	/*
+	 * The offset to visit VSI related register, assigned by HW when
+	 * creating VSI
+	 */
+	uint16_t vsi_id;
+	uint16_t msix_intr; /* The MSIX interrupt binds to VSI */
+	uint8_t enabled_tc; /* The traffic class enabled */
+};
+
+struct pool_entry {
+	LIST_ENTRY(pool_entry) next;
+	uint16_t base;
+	uint16_t len;
+};
+
+LIST_HEAD(res_list, pool_entry);
+
+struct i40e_res_pool_info {
+	uint32_t base;              /* Resource start index */
+	uint32_t num_alloc;         /* Allocated resource number */
+	uint32_t num_free;          /* Total available resource number */
+	struct res_list alloc_list; /* Allocated resource list */
+	struct res_list free_list;  /* Available resource list */
+};
+
+enum I40E_VF_STATE {
+	I40E_VF_INACTIVE = 0,
+	I40E_VF_INRESET,
+	I40E_VF_ININIT,
+	I40E_VF_ACTIVE,
+};
+
+/*
+ * Structure to store private data for PF host.
+ */
+struct i40e_pf_vf {
+	struct i40e_pf *pf;
+	struct i40e_vsi *vsi;
+	enum I40E_VF_STATE state; /* The number of queue pairs availiable */
+	uint16_t vf_idx; /* VF index in pf->vfs */
+	uint16_t lan_nb_qps; /* Actual queues allocated */
+	uint16_t reset_cnt; /* Total vf reset times */
+};
+
+/*
+ * Structure to store private data specific for PF instance.
+ */
+struct i40e_pf {
+	struct i40e_adapter *adapter; /* The adapter this PF associate to */
+	struct i40e_vsi *main_vsi; /* pointer to main VSI structure */
+	uint16_t mac_seid; /* The seid of the MAC of this PF */
+	uint16_t main_vsi_seid; /* The seid of the main VSI */
+	uint16_t max_num_vsi;
+	struct i40e_res_pool_info qp_pool;    /*Queue pair pool */
+	struct i40e_res_pool_info msix_pool;  /* MSIX interrupt pool */
+
+	struct i40e_hw_port_stats stats_offset;
+	struct i40e_hw_port_stats stats;
+	bool offset_loaded;
+
+	struct rte_eth_dev_data *dev_data; /* Pointer to the device data */
+	struct ether_addr dev_addr; /* PF device mac address */
+	uint64_t flags; /* PF featuer flags */
+	/* All kinds of queue pair setting for different VSIs */
+	struct i40e_pf_vf *vfs;
+	uint16_t vf_num;
+	/* Each of below queue pairs should be power of 2 since it's the
+	   precondition after TC configuration applied */
+	uint16_t lan_nb_qps; /* The number of queue pairs of LAN */
+	uint16_t vmdq_nb_qps; /* The number of queue pairs of VMDq */
+	uint16_t vf_nb_qps; /* The number of queue pairs of VF */
+	uint16_t fdir_nb_qps; /* The number of queue pairs of Flow Director */
+};
+
+enum pending_msg {
+	PFMSG_LINK_CHANGE = 0x1,
+	PFMSG_RESET_IMPENDING = 0x2,
+	PFMSG_DRIVER_CLOSE = 0x4,
+};
+
+struct i40e_vf_rx_queues {
+	uint64_t rx_dma_addr;
+	uint32_t rx_ring_len;
+	uint32_t buff_size;
+};
+
+struct i40e_vf_tx_queues {
+	uint64_t tx_dma_addr;
+	uint32_t tx_ring_len;
+};
+
+/*
+ * Structure to store private data specific for VF instance.
+ */
+struct i40e_vf {
+	uint16_t num_queue_pairs;
+	uint16_t max_pkt_len; /* Maximum packet length */
+	bool promisc_unicast_enabled;
+	bool promisc_multicast_enabled;
+
+	bool host_is_dpdk; /* The flag indicates if the host is DPDK */
+	uint16_t promisc_flags; /* Promiscuous setting */
+	uint32_t vlan[I40E_VFTA_SIZE]; /* VLAN bit map */
+
+	/* Event from pf */
+	bool dev_closed;
+	bool link_up;
+	bool vf_reset;
+	volatile uint32_t pend_cmd; /* pending command not finished yet */
+	u16 pend_msg; /* flags indicates events from pf not handled yet */
+
+	/* VSI info */
+	struct i40e_virtchnl_vf_resource *vf_res; /* All VSIs */
+	struct i40e_virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+	struct i40e_vsi vsi;
+};
+
+/*
+ * Structure to store private data for each PF/VF instance.
+ */
+struct i40e_adapter {
+	/* Common for both PF and VF */
+	struct i40e_hw hw;
+	struct rte_eth_dev *eth_dev;
+
+	/* Specific for PF or VF */
+	union {
+		struct i40e_pf pf;
+		struct i40e_vf vf;
+	};
+};
+
+int i40e_vsi_switch_queues(struct i40e_vsi *vsi, bool on);
+int i40e_vsi_release(struct i40e_vsi *vsi);
+struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf,
+				enum i40e_vsi_type type,
+				struct i40e_vsi *uplink_vsi,
+				uint16_t user_param);
+int i40e_switch_rx_queue(struct i40e_hw *hw, uint16_t q_idx, bool on);
+int i40e_switch_tx_queue(struct i40e_hw *hw, uint16_t q_idx, bool on);
+int i40e_vsi_add_vlan(struct i40e_vsi *vsi, uint16_t vlan);
+int i40e_vsi_delete_vlan(struct i40e_vsi *vsi, uint16_t vlan);
+int i40e_vsi_add_mac(struct i40e_vsi *vsi, struct ether_addr *addr);
+int i40e_vsi_delete_mac(struct i40e_vsi *vsi, struct ether_addr *addr);
+void i40e_update_vsi_stats(struct i40e_vsi *vsi);
+void i40e_pf_disable_irq0(struct i40e_hw *hw);
+void i40e_pf_enable_irq0(struct i40e_hw *hw);
+int i40e_dev_link_update(struct rte_eth_dev *dev,
+			 __rte_unused int wait_to_complete);
+void i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi);
+void i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi);
+
+/* I40E_DEV_PRIVATE_TO */
+#define I40E_DEV_PRIVATE_TO_PF(adapter) \
+	(&((struct i40e_adapter *)adapter)->pf)
+#define I40E_DEV_PRIVATE_TO_HW(adapter) \
+	(&((struct i40e_adapter *)adapter)->hw)
+#define I40E_DEV_PRIVATE_TO_ADAPTER(adapter) \
+	((struct i40e_adapter *)adapter)
+
+/* I40EVF_DEV_PRIVATE_TO */
+#define I40EVF_DEV_PRIVATE_TO_VF(adapter) \
+	(&((struct i40e_adapter *)adapter)->vf)
+
+static inline struct i40e_vsi *
+i40e_get_vsi_from_adapter(struct i40e_adapter *adapter)
+{
+	struct i40e_hw *hw;
+
+        if (!adapter)
+                return NULL;
+
+	hw = I40E_DEV_PRIVATE_TO_HW(adapter);
+	if (hw->mac.type == I40E_MAC_VF) {
+		struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(adapter);
+		return &vf->vsi;
+	} else {
+		struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(adapter);
+		return pf->main_vsi;
+	}
+}
+#define I40E_DEV_PRIVATE_TO_VSI(adapter) \
+	i40e_get_vsi_from_adapter((struct i40e_adapter *)adapter)
+
+/* I40E_VSI_TO */
+#define I40E_VSI_TO_HW(vsi) \
+	(&(((struct i40e_vsi *)vsi)->adapter->hw))
+#define I40E_VSI_TO_PF(vsi) \
+	(&(((struct i40e_vsi *)vsi)->adapter->pf))
+#define I40E_VSI_TO_DEV_DATA(vsi) \
+	(((struct i40e_vsi *)vsi)->adapter->pf.dev_data)
+#define I40E_VSI_TO_ETH_DEV(vsi) \
+	(((struct i40e_vsi *)vsi)->adapter->eth_dev)
+
+/* I40E_PF_TO */
+#define I40E_PF_TO_HW(pf) \
+	(&(((struct i40e_pf *)pf)->adapter->hw))
+#define I40E_PF_TO_ADAPTER(pf) \
+	((struct i40e_adapter *)pf->adapter)
+
+static inline void
+i40e_init_adminq_parameter(struct i40e_hw *hw)
+{
+	hw->aq.num_arq_entries = I40E_AQ_LEN;
+	hw->aq.num_asq_entries = I40E_AQ_LEN;
+	hw->aq.arq_buf_size = I40E_AQ_BUF_SZ;
+	hw->aq.asq_buf_size = I40E_AQ_BUF_SZ;
+}
+
+#endif /* _I40E_ETHDEV_H_ */
diff --git a/lib/librte_pmd_i40e/i40e_ethdev_vf.c b/lib/librte_pmd_i40e/i40e_ethdev_vf.c
new file mode 100644
index 0000000..14fb818
--- /dev/null
+++ b/lib/librte_pmd_i40e/i40e_ethdev_vf.c
@@ -0,0 +1,1336 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <rte_byteorder.h>
+#include <rte_common.h>
+#include <rte_cycles.h>
+
+#include <rte_interrupts.h>
+#include <rte_log.h>
+#include <rte_debug.h>
+#include <rte_pci.h>
+#include <rte_atomic.h>
+#include <rte_branch_prediction.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_tailq.h>
+#include <rte_eal.h>
+#include <rte_alarm.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_atomic.h>
+#include <rte_malloc.h>
+#include <rte_dev.h>
+
+#include "i40e_logs.h"
+#include "i40e/i40e_prototype.h"
+#include "i40e/i40e_adminq_cmd.h"
+#include "i40e/i40e_type.h"
+
+#include "i40e_rxtx.h"
+#include "i40e_ethdev.h"
+#include "i40e_pf.h"
+#define I40EVF_VSI_DEFAULT_MSIX_INTR 1
+
+/* busy wait delay in msec */
+#define I40EVF_BUSY_WAIT_DELAY 10
+#define I40EVF_BUSY_WAIT_COUNT 50
+#define MAX_RESET_WAIT_CNT     20
+
+struct i40evf_arq_msg_info {
+	enum i40e_virtchnl_ops ops;
+	enum i40e_status_code result;
+	uint16_t msg_len;
+	uint8_t *msg;
+};
+
+struct vf_cmd_info {
+	enum i40e_virtchnl_ops ops;
+	uint8_t *in_args;
+	uint32_t in_args_size;
+	uint8_t *out_buffer;
+	/* Input & output type. pass in buffer size and pass out
+	 * actual return result
+	 */
+	uint32_t out_size;
+};
+
+enum i40evf_aq_result {
+	I40EVF_MSG_ERR = -1, /* Meet error when accessing admin queue */
+	I40EVF_MSG_NON,      /* Read nothing from admin queue */
+	I40EVF_MSG_SYS,      /* Read system msg from admin queue */
+	I40EVF_MSG_CMD,      /* Read async command result */
+};
+
+/* A share buffer to store the command result from PF driver */
+static uint8_t cmd_result_buffer[I40E_AQ_BUF_SZ];
+
+static int i40evf_dev_configure(struct rte_eth_dev *dev);
+static int i40evf_dev_start(struct rte_eth_dev *dev);
+static void i40evf_dev_stop(struct rte_eth_dev *dev);
+static void i40evf_dev_info_get(struct rte_eth_dev *dev,
+				struct rte_eth_dev_info *dev_info);
+static int i40evf_dev_link_update(struct rte_eth_dev *dev,
+				  __rte_unused int wait_to_complete);
+static void i40evf_dev_stats_get(struct rte_eth_dev *dev,
+				struct rte_eth_stats *stats);
+static int i40evf_vlan_filter_set(struct rte_eth_dev *dev,
+				  uint16_t vlan_id, int on);
+static void i40evf_dev_close(struct rte_eth_dev *dev);
+static void i40evf_dev_promiscuous_enable(struct rte_eth_dev *dev);
+static void i40evf_dev_promiscuous_disable(struct rte_eth_dev *dev);
+static void i40evf_dev_allmulticast_enable(struct rte_eth_dev *dev);
+static void i40evf_dev_allmulticast_disable(struct rte_eth_dev *dev);
+static int i40evf_get_link_status(struct rte_eth_dev *dev,
+				  struct rte_eth_link *link);
+static struct eth_dev_ops i40evf_eth_dev_ops = {
+	.dev_configure        = i40evf_dev_configure,
+	.dev_start            = i40evf_dev_start,
+	.dev_stop             = i40evf_dev_stop,
+	.promiscuous_enable   = i40evf_dev_promiscuous_enable,
+	.promiscuous_disable  = i40evf_dev_promiscuous_disable,
+	.allmulticast_enable  = i40evf_dev_allmulticast_enable,
+	.allmulticast_disable = i40evf_dev_allmulticast_disable,
+	.link_update          = i40evf_dev_link_update,
+	.stats_get            = i40evf_dev_stats_get,
+	.dev_close            = i40evf_dev_close,
+	.dev_infos_get        = i40evf_dev_info_get,
+	.vlan_filter_set      = i40evf_vlan_filter_set,
+	.rx_queue_setup       = i40e_dev_rx_queue_setup,
+	.rx_queue_release     = i40e_dev_rx_queue_release,
+	.tx_queue_setup       = i40e_dev_tx_queue_setup,
+	.tx_queue_release     = i40e_dev_tx_queue_release,
+};
+
+static int
+i40evf_set_mac_type(struct i40e_hw *hw)
+{
+	int status = I40E_ERR_DEVICE_NOT_SUPPORTED;
+
+	if (hw->vendor_id == I40E_INTEL_VENDOR_ID) {
+		switch (hw->device_id) {
+		case I40E_DEV_ID_VF:
+		case I40E_DEV_ID_VF_HV:
+			hw->mac.type = I40E_MAC_VF;
+			status = I40E_SUCCESS;
+			break;
+		default:
+			;
+		}
+	}
+
+	return status;
+}
+
+/*
+ * Parse admin queue message.
+ *
+ * return value:
+ *  < 0: meet error
+ *  0: read sys msg
+ *  > 0: read cmd result
+ */
+static enum i40evf_aq_result
+i40evf_parse_pfmsg(struct i40e_vf *vf,
+		   struct i40e_arq_event_info *event,
+		   struct i40evf_arq_msg_info *data)
+{
+	enum i40e_virtchnl_ops opcode = (enum i40e_virtchnl_ops)\
+			rte_le_to_cpu_32(event->desc.cookie_high);
+	enum i40e_status_code retval = (enum i40e_status_code)\
+			rte_le_to_cpu_32(event->desc.cookie_low);
+	enum i40evf_aq_result ret = I40EVF_MSG_CMD;
+
+	/* pf sys event */
+	if (opcode == I40E_VIRTCHNL_OP_EVENT) {
+		struct i40e_virtchnl_pf_event *vpe =
+			(struct i40e_virtchnl_pf_event *)event->msg_buf;
+
+		/* Initialize ret to sys event */
+		ret = I40EVF_MSG_SYS;
+		switch (vpe->event) {
+		case I40E_VIRTCHNL_EVENT_LINK_CHANGE:
+			vf->link_up =
+				vpe->event_data.link_event.link_status;
+			vf->pend_msg |= PFMSG_LINK_CHANGE;
+			PMD_DRV_LOG(INFO, "Link status update:%s\n",
+					vf->link_up ? "up" : "down");
+			break;
+		case I40E_VIRTCHNL_EVENT_RESET_IMPENDING:
+			vf->vf_reset = true;
+			vf->pend_msg |= PFMSG_RESET_IMPENDING;
+			PMD_DRV_LOG(INFO, "vf is reseting\n");
+			break;
+		case I40E_VIRTCHNL_EVENT_PF_DRIVER_CLOSE:
+			vf->dev_closed = true;
+			vf->pend_msg |= PFMSG_DRIVER_CLOSE;
+			PMD_DRV_LOG(INFO, "PF driver closed\n");
+			break;
+		default:
+			PMD_DRV_LOG(ERR,
+				"%s: Unknown event %d from pf\n",
+				__func__, vpe->event);
+		}
+	} else {
+		/* async reply msg on command issued by vf previously */
+		ret = I40EVF_MSG_CMD;
+		/* Actual buffer length read from PF */
+		data->msg_len = event->msg_size;
+	}
+	/* fill the ops and result to notify VF */
+	data->result = retval;
+	data->ops = opcode;
+
+	return ret;
+}
+
+/*
+ * Read data in admin queue to get msg from pf driver
+ */
+static enum i40evf_aq_result
+i40evf_read_pfmsg(struct rte_eth_dev *dev, struct i40evf_arq_msg_info *data)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	struct i40e_arq_event_info event;
+	int ret;
+	enum i40evf_aq_result result = I40EVF_MSG_NON;
+
+	event.msg_size = data->msg_len;
+	event.msg_buf = data->msg;
+	ret = i40e_clean_arq_element(hw, &event, NULL);
+	/* Can't read any msg from adminQ */
+	if (ret) {
+		if (ret == I40E_ERR_ADMIN_QUEUE_NO_WORK)
+			result = I40EVF_MSG_NON;
+		else
+			result = I40EVF_MSG_ERR;
+		return result;
+	}
+
+	/* Parse the event */
+	result = i40evf_parse_pfmsg(vf, &event, data);
+
+	return result;
+}
+
+/*
+ * Polling read until command result return from pf driver or meet error.
+ */
+static int
+i40evf_wait_cmd_done(struct rte_eth_dev *dev,
+		     struct i40evf_arq_msg_info *data)
+{
+	int i = 0;
+	enum i40evf_aq_result ret;
+
+#define MAX_TRY_TIMES 10
+#define ASQ_DELAY_MS  50
+	do {
+		/* Delay some time first */
+		rte_delay_ms(ASQ_DELAY_MS);
+		ret = i40evf_read_pfmsg(dev, data);
+
+		if (ret == I40EVF_MSG_CMD)
+			return 0;
+		else if (ret == I40EVF_MSG_ERR)
+			return -1;
+
+		/* If don't read msg or read sys event, continue */
+	} while(i++ < MAX_TRY_TIMES);
+
+	return -1;
+}
+
+/**
+ * clear current command. Only call in case execute
+ * _atomic_set_cmd successfully.
+ */
+static inline void
+_clear_cmd(struct i40e_vf *vf)
+{
+	rte_wmb();
+	vf->pend_cmd = I40E_VIRTCHNL_OP_UNKNOWN;
+}
+
+/*
+ * Check there is pending cmd in execution. If none, set new command.
+ */
+static inline int
+_atomic_set_cmd(struct i40e_vf *vf, enum i40e_virtchnl_ops ops)
+{
+	int ret = rte_atomic32_cmpset(&vf->pend_cmd,
+			I40E_VIRTCHNL_OP_UNKNOWN, ops);
+
+	if (!ret)
+		PMD_DRV_LOG(ERR, "There is incomplete cmd %d\n", vf->pend_cmd);
+
+	return !ret;
+}
+
+static int
+i40evf_execute_vf_cmd(struct rte_eth_dev *dev, struct vf_cmd_info *args)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	int err = -1;
+	struct i40evf_arq_msg_info info;
+
+	if (_atomic_set_cmd(vf, args->ops))
+		return -1;
+
+	info.msg = args->out_buffer;
+	info.msg_len = args->out_size;
+	info.ops = I40E_VIRTCHNL_OP_UNKNOWN;
+	info.result = I40E_SUCCESS;
+
+	err = i40e_aq_send_msg_to_pf(hw, args->ops, I40E_SUCCESS,
+		     args->in_args, args->in_args_size, NULL);
+	if (err) {
+		PMD_DRV_LOG(ERR, "fail to send cmd %d\n", args->ops);
+		return err;
+	}
+
+	err = i40evf_wait_cmd_done(dev, &info);
+	/* read message and it's expected one */
+	if (!err && args->ops == info.ops)
+		_clear_cmd(vf);
+	else if (err)
+		PMD_DRV_LOG(ERR, "Failed to read message from AdminQ\n");
+	else if (args->ops != info.ops)
+		PMD_DRV_LOG(ERR, "command mismatch, expect %u, get %u\n",
+				args->ops, info.ops);
+
+	return (err | info.result);
+}
+
+/*
+ * Check API version with sync wait until version read or fail from admin queue
+ */
+static int
+i40evf_check_api_version(struct rte_eth_dev *dev)
+{
+	struct i40e_virtchnl_version_info version, *pver;
+	int err;
+	struct vf_cmd_info args;
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+
+	version.major = I40E_VIRTCHNL_VERSION_MAJOR;
+	version.minor = I40E_VIRTCHNL_VERSION_MINOR;
+
+	args.ops = I40E_VIRTCHNL_OP_VERSION;
+	args.in_args = (uint8_t *)&version;
+	args.in_args_size = sizeof(version);
+	args.out_buffer = cmd_result_buffer;
+	args.out_size = I40E_AQ_BUF_SZ;
+
+	err = i40evf_execute_vf_cmd(dev, &args);
+	if (err) {
+		PMD_INIT_LOG(ERR, "fail to execute command OP_VERSION\n");
+		return err;
+	}
+
+	pver = (struct i40e_virtchnl_version_info *)args.out_buffer;
+	/* We are talking with DPDK host */
+	if (pver->major == I40E_DPDK_VERSION_MAJOR) {
+		vf->host_is_dpdk = TRUE;
+		PMD_DRV_LOG(INFO, "Detect PF host is DPDK app\n");
+	}
+	/* It's linux host driver */
+	else if ((pver->major != version.major) ||
+	    (pver->minor != version.minor)) {
+		PMD_INIT_LOG(ERR, "pf/vf API version mismatch. "
+			"(%u.%u)-(%u.%u)\n", pver->major, pver->minor,
+					version.major, version.minor);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+i40evf_get_vf_resource(struct rte_eth_dev *dev)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	int err;
+	struct vf_cmd_info args;
+	uint32_t len;
+
+	args.ops = I40E_VIRTCHNL_OP_GET_VF_RESOURCES;
+	args.in_args = NULL;
+	args.in_args_size = 0;
+	args.out_buffer = cmd_result_buffer;
+	args.out_size = I40E_AQ_BUF_SZ;
+
+	err = i40evf_execute_vf_cmd(dev, &args);
+
+	if (err) {
+		PMD_DRV_LOG(ERR, "fail to execute command "
+					"OP_GET_VF_RESOURCE\n");
+		return err;
+	}
+
+	len =  sizeof(struct i40e_virtchnl_vf_resource) +
+		I40E_MAX_VF_VSI * sizeof(struct i40e_virtchnl_vsi_resource);
+
+	(void)rte_memcpy(vf->vf_res, args.out_buffer,
+			RTE_MIN(args.out_size, len));
+	i40e_vf_parse_hw_config(hw, vf->vf_res);
+
+	return 0;
+}
+
+static int
+i40evf_config_promisc(struct rte_eth_dev *dev,
+		      bool enable_unicast,
+		      bool enable_multicast)
+{
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	int err;
+	struct vf_cmd_info args;
+	struct i40e_virtchnl_promisc_info promisc;
+
+	promisc.flags = 0;
+	promisc.vsi_id = vf->vsi_res->vsi_id;
+
+	if (enable_unicast)
+		promisc.flags |= I40E_FLAG_VF_UNICAST_PROMISC;
+
+	if (enable_multicast)
+		promisc.flags |= I40E_FLAG_VF_MULTICAST_PROMISC;
+
+	args.ops = I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE;
+	args.in_args = (uint8_t *)&promisc;
+	args.in_args_size = sizeof(promisc);
+	args.out_buffer = cmd_result_buffer;
+	args.out_size = I40E_AQ_BUF_SZ;
+
+	err = i40evf_execute_vf_cmd(dev, &args);
+
+	if (err)
+		PMD_DRV_LOG(ERR, "fail to execute command "
+				"CONFIG_PROMISCUOUS_MODE\n");
+
+	return err;
+}
+
+static int
+i40evf_configure_queues(struct rte_eth_dev *dev)
+{
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	struct i40e_virtchnl_vsi_queue_config_info *queue_info;
+	struct i40e_virtchnl_queue_pair_info *queue_cfg;
+	struct i40e_rx_queue **rxq =
+		(struct i40e_rx_queue **)dev->data->rx_queues;
+	struct i40e_tx_queue **txq =
+		(struct i40e_tx_queue **)dev->data->tx_queues;
+	int i, len, nb_qpairs, num_rxq, num_txq;
+	int err;
+	struct vf_cmd_info args;
+	struct rte_pktmbuf_pool_private *mbp_priv;
+
+	nb_qpairs = vf->num_queue_pairs;
+	len = sizeof(*queue_info) + sizeof(*queue_cfg) * nb_qpairs;
+	queue_info = rte_zmalloc("queue_info", len, 0);
+	if (queue_info == NULL) {
+		PMD_INIT_LOG(ERR, "failed alloc memory for queue_info\n");
+		return -1;
+	}
+	queue_info->vsi_id = vf->vsi_res->vsi_id;
+	queue_info->num_queue_pairs = nb_qpairs;
+	queue_cfg = queue_info->qpair;
+
+	num_rxq = dev->data->nb_rx_queues;
+	num_txq = dev->data->nb_tx_queues;
+	/*
+	 * PF host driver required to configure queues in pairs, which means
+	 * rxq_num should equals to txq_num. The actual usage won't always
+	 * work that way. The solution is fills 0 with HW ring option in case
+	 * they are not equal.
+	 */
+	for (i = 0; i < nb_qpairs; i++) {
+		/*Fill TX info */
+		queue_cfg->txq.vsi_id = queue_info->vsi_id;
+		queue_cfg->txq.queue_id = i;
+		if (i < num_txq) {
+			queue_cfg->txq.ring_len = txq[i]->nb_tx_desc;
+			queue_cfg->txq.dma_ring_addr = txq[i]->tx_ring_phys_addr;
+		} else {
+			queue_cfg->txq.ring_len = 0;
+			queue_cfg->txq.dma_ring_addr = 0;
+		}
+
+		/* Fill RX info */
+		queue_cfg->rxq.vsi_id = queue_info->vsi_id;
+		queue_cfg->rxq.queue_id = i;
+		queue_cfg->rxq.max_pkt_size = vf->max_pkt_len;
+		if (i < num_rxq) {
+			mbp_priv = rte_mempool_get_priv(rxq[i]->mp);
+			queue_cfg->rxq.databuffer_size = mbp_priv->mbuf_data_room_size -
+						   RTE_PKTMBUF_HEADROOM;;
+			queue_cfg->rxq.ring_len = rxq[i]->nb_rx_desc;
+			queue_cfg->rxq.dma_ring_addr = rxq[i]->rx_ring_phys_addr;;
+		} else {
+			queue_cfg->rxq.ring_len = 0;
+			queue_cfg->rxq.dma_ring_addr = 0;
+			queue_cfg->rxq.databuffer_size = 0;
+		}
+		queue_cfg++;
+	}
+
+	args.ops = I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES;
+	args.in_args = (u8 *)queue_info;
+	args.in_args_size = len;
+	args.out_buffer = cmd_result_buffer;
+	args.out_size = I40E_AQ_BUF_SZ;
+	err = i40evf_execute_vf_cmd(dev, &args);
+	if (err)
+		PMD_DRV_LOG(ERR, "fail to execute command "
+				"OP_CONFIG_VSI_QUEUES\n");
+	rte_free(queue_info);
+
+	return err;
+}
+
+static int
+i40evf_config_irq_map(struct rte_eth_dev *dev)
+{
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	struct vf_cmd_info args;
+	uint8_t cmd_buffer[sizeof(struct i40e_virtchnl_irq_map_info) + \
+		sizeof(struct i40e_virtchnl_vector_map)];
+	struct i40e_virtchnl_irq_map_info *map_info;
+	int i, err;
+	map_info = (struct i40e_virtchnl_irq_map_info *)cmd_buffer;
+	map_info->num_vectors = 1;
+	map_info->vecmap[0].rxitr_idx = RTE_LIBRTE_I40E_ITR_INTERVAL / 2;
+	map_info->vecmap[0].txitr_idx = RTE_LIBRTE_I40E_ITR_INTERVAL / 2;
+	map_info->vecmap[0].vsi_id = vf->vsi_res->vsi_id;
+	/* Alway use default dynamic MSIX interrupt */
+	map_info->vecmap[0].vector_id = I40EVF_VSI_DEFAULT_MSIX_INTR;
+	/* Don't map any tx queue */
+	map_info->vecmap[0].txq_map = 0;
+	map_info->vecmap[0].rxq_map = 0;
+	for (i = 0; i < dev->data->nb_rx_queues; i++)
+		map_info->vecmap[0].rxq_map |= 1 << i;
+
+	args.ops = I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP;
+	args.in_args = (u8 *)cmd_buffer;
+	args.in_args_size = sizeof(cmd_buffer);
+	args.out_buffer = cmd_result_buffer;
+	args.out_size = I40E_AQ_BUF_SZ;
+	err = i40evf_execute_vf_cmd(dev, &args);
+	if (err)
+		PMD_DRV_LOG(ERR, "fail to execute command OP_ENABLE_QUEUES\n");
+
+	return err;
+}
+
+static int
+i40evf_enable_queues(struct rte_eth_dev *dev)
+{
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	struct i40e_virtchnl_queue_select queue_select;
+	int err, i;
+	struct vf_cmd_info args;
+
+	queue_select.vsi_id = vf->vsi_res->vsi_id;
+
+	queue_select.rx_queues = 0;
+	/* Enable configured RX queues */
+	for (i = 0; i < dev->data->nb_rx_queues; i++)
+		queue_select.rx_queues |= 1 << i;
+
+	/* Enable configured TX queues */
+	queue_select.tx_queues = 0;
+	for (i = 0; i < dev->data->nb_tx_queues; i++)
+		queue_select.tx_queues |= 1 << i;
+
+	args.ops = I40E_VIRTCHNL_OP_ENABLE_QUEUES;
+	args.in_args = (u8 *)&queue_select;
+	args.in_args_size = sizeof(queue_select);
+	args.out_buffer = cmd_result_buffer;
+	args.out_size = I40E_AQ_BUF_SZ;
+	err = i40evf_execute_vf_cmd(dev, &args);
+	if (err)
+		PMD_DRV_LOG(ERR, "fail to execute command OP_ENABLE_QUEUES\n");
+
+	return err;
+}
+
+static int
+i40evf_disable_queues(struct rte_eth_dev *dev)
+{
+	struct i40e_virtchnl_queue_select queue_select;
+	int err, i;
+	struct vf_cmd_info args;
+
+	/* Enable configured RX queues */
+	queue_select.rx_queues = 0;
+	for (i = 0; i < dev->data->nb_rx_queues; i++)
+		queue_select.rx_queues |= 1 << i;
+
+	/* Enable configured TX queues */
+	queue_select.tx_queues = 0;
+	for (i = 0; i < dev->data->nb_tx_queues; i++)
+		queue_select.tx_queues |= 1 << i;
+
+	args.ops = I40E_VIRTCHNL_OP_DISABLE_QUEUES;
+	args.in_args = (u8 *)&queue_select;
+	args.in_args_size = sizeof(queue_select);
+	args.out_buffer = cmd_result_buffer;
+	args.out_size = I40E_AQ_BUF_SZ;
+	err = i40evf_execute_vf_cmd(dev, &args);
+	if (err)
+		PMD_DRV_LOG(ERR, "fail to execute command "
+					"OP_DISABLE_QUEUES\n");
+
+	return err;
+}
+
+static int
+i40evf_add_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct i40e_virtchnl_ether_addr_list *list;
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	uint8_t cmd_buffer[sizeof(struct i40e_virtchnl_ether_addr_list) + \
+			sizeof(struct i40e_virtchnl_ether_addr)];
+	int err;
+	struct vf_cmd_info args;
+
+	if (i40e_validate_mac_addr(addr->addr_bytes) != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Invalid mac:%x:%x:%x:%x:%x:%x\n",
+			addr->addr_bytes[0], addr->addr_bytes[1],
+			addr->addr_bytes[2], addr->addr_bytes[3],
+			addr->addr_bytes[4], addr->addr_bytes[5]);
+		return -1;
+	}
+
+	list = (struct i40e_virtchnl_ether_addr_list *)cmd_buffer;
+	list->vsi_id = vf->vsi_res->vsi_id;
+	list->num_elements = 1;
+	(void)rte_memcpy(list->list[0].addr, addr->addr_bytes,
+					sizeof(addr->addr_bytes));
+
+	args.ops = I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS;
+	args.in_args = cmd_buffer;
+	args.in_args_size = sizeof(cmd_buffer);
+	args.out_buffer = cmd_result_buffer;
+	args.out_size = I40E_AQ_BUF_SZ;
+	err = i40evf_execute_vf_cmd(dev, &args);
+	if (err)
+		PMD_DRV_LOG(ERR, "fail to execute command "
+				"OP_ADD_ETHER_ADDRESS\n");
+
+	return err;
+}
+
+static int
+i40evf_del_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+	struct i40e_virtchnl_ether_addr_list *list;
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	uint8_t cmd_buffer[sizeof(struct i40e_virtchnl_ether_addr_list) + \
+			sizeof(struct i40e_virtchnl_ether_addr)];
+	int err;
+	struct vf_cmd_info args;
+
+	if (i40e_validate_mac_addr(addr->addr_bytes) != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Invalid mac:%x-%x-%x-%x-%x-%x\n",
+			addr->addr_bytes[0], addr->addr_bytes[1],
+			addr->addr_bytes[2], addr->addr_bytes[3],
+			addr->addr_bytes[4], addr->addr_bytes[5]);
+		return -1;
+	}
+
+	list = (struct i40e_virtchnl_ether_addr_list *)cmd_buffer;
+	list->vsi_id = vf->vsi_res->vsi_id;
+	list->num_elements = 1;
+	(void)rte_memcpy(list->list[0].addr, addr->addr_bytes,
+			sizeof(addr->addr_bytes));
+
+	args.ops = I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS;
+	args.in_args = cmd_buffer;
+	args.in_args_size = sizeof(cmd_buffer);
+	args.out_buffer = cmd_result_buffer;
+	args.out_size = I40E_AQ_BUF_SZ;
+	err = i40evf_execute_vf_cmd(dev, &args);
+	if (err)
+		PMD_DRV_LOG(ERR, "fail to execute command "
+				"OP_DEL_ETHER_ADDRESS\n");
+
+	return err;
+}
+
+static int
+i40evf_get_statics(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	struct i40e_virtchnl_queue_select q_stats;
+	struct i40e_eth_stats *pstats;
+	int err;
+	struct vf_cmd_info args;
+
+	memset(&q_stats, 0, sizeof(q_stats));
+	q_stats.vsi_id = vf->vsi_res->vsi_id;
+	args.ops = I40E_VIRTCHNL_OP_GET_STATS;
+	args.in_args = (u8 *)&q_stats;
+	args.in_args_size = sizeof(q_stats);
+	args.out_buffer = cmd_result_buffer;
+	args.out_size = I40E_AQ_BUF_SZ;
+
+	err = i40evf_execute_vf_cmd(dev, &args);
+	if (err) {
+		PMD_DRV_LOG(ERR, "fail to execute command OP_GET_STATS\n");
+		return err;
+	}
+	pstats = (struct i40e_eth_stats *)args.out_buffer;
+	stats->ipackets = pstats->rx_unicast + pstats->rx_multicast +
+						pstats->rx_broadcast;
+	stats->opackets = pstats->tx_broadcast + pstats->tx_multicast +
+						pstats->tx_unicast;
+	stats->ierrors = pstats->rx_discards;
+	stats->oerrors = pstats->tx_errors + pstats->tx_discards;
+	stats->ibytes = pstats->rx_bytes;
+	stats->obytes = pstats->tx_bytes;
+
+	return 0;
+}
+
+static int
+i40evf_add_vlan(struct rte_eth_dev *dev, uint16_t vlanid)
+{
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	struct i40e_virtchnl_vlan_filter_list *vlan_list;
+	uint8_t cmd_buffer[sizeof(struct i40e_virtchnl_vlan_filter_list) +
+							sizeof(uint16_t)];
+	int err;
+	struct vf_cmd_info args;
+
+	vlan_list = (struct i40e_virtchnl_vlan_filter_list *)cmd_buffer;
+	vlan_list->vsi_id = vf->vsi_res->vsi_id;
+	vlan_list->num_elements = 1;
+	vlan_list->vlan_id[0] = vlanid;
+
+	args.ops = I40E_VIRTCHNL_OP_ADD_VLAN;
+	args.in_args = (u8 *)&cmd_buffer;
+	args.in_args_size = sizeof(cmd_buffer);
+	args.out_buffer = cmd_result_buffer;
+	args.out_size = I40E_AQ_BUF_SZ;
+	err = i40evf_execute_vf_cmd(dev, &args);
+	if (err)
+		PMD_DRV_LOG(ERR, "fail to execute command OP_ADD_VLAN\n");
+
+	return err;
+}
+
+static int
+i40evf_del_vlan(struct rte_eth_dev *dev, uint16_t vlanid)
+{
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	struct i40e_virtchnl_vlan_filter_list *vlan_list;
+	uint8_t cmd_buffer[sizeof(struct i40e_virtchnl_vlan_filter_list) +
+							sizeof(uint16_t)];
+	int err;
+	struct vf_cmd_info args;
+
+	vlan_list = (struct i40e_virtchnl_vlan_filter_list *)cmd_buffer;
+	vlan_list->vsi_id = vf->vsi_res->vsi_id;
+	vlan_list->num_elements = 1;
+	vlan_list->vlan_id[0] = vlanid;
+
+	args.ops = I40E_VIRTCHNL_OP_DEL_VLAN;
+	args.in_args = (u8 *)&cmd_buffer;
+	args.in_args_size = sizeof(cmd_buffer);
+	args.out_buffer = cmd_result_buffer;
+	args.out_size = I40E_AQ_BUF_SZ;
+	err = i40evf_execute_vf_cmd(dev, &args);
+	if (err)
+		PMD_DRV_LOG(ERR, "fail to execute command OP_DEL_VLAN\n");
+
+	return err;
+}
+
+static int
+i40evf_get_link_status(struct rte_eth_dev *dev, struct rte_eth_link *link)
+{
+	int err;
+	struct vf_cmd_info args;
+	struct rte_eth_link *new_link;
+
+	args.ops = (enum i40e_virtchnl_ops)I40E_VIRTCHNL_OP_GET_LINK_STAT;
+	args.in_args = NULL;
+	args.in_args_size = 0;
+	args.out_buffer = cmd_result_buffer;
+	args.out_size = I40E_AQ_BUF_SZ;
+	err = i40evf_execute_vf_cmd(dev, &args);
+	if (err) {
+		PMD_DRV_LOG(ERR, "fail to execute command OP_GET_LINK_STAT\n");
+		return err;
+	}
+
+	new_link = (struct rte_eth_link *)args.out_buffer;
+	(void)rte_memcpy(link, new_link, sizeof(link));
+
+	return 0;
+}
+
+static struct rte_pci_id pci_id_i40evf_map[] = {
+#define RTE_PCI_DEV_ID_DECL_I40EVF(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
+#include "rte_pci_dev_ids.h"
+{ .vendor_id = 0, /* sentinel */ },
+};
+
+static inline int
+i40evf_dev_atomic_read_link_status(struct rte_eth_dev *dev,
+				   struct rte_eth_link *link)
+{
+	struct rte_eth_link *dst = link;
+	struct rte_eth_link *src = &(dev->data->dev_link);
+
+	if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
+					*(uint64_t *)src) == 0)
+		return -1;
+
+	return 0;
+}
+
+static inline int
+i40evf_dev_atomic_write_link_status(struct rte_eth_dev *dev,
+				    struct rte_eth_link *link)
+{
+	struct rte_eth_link *dst = &(dev->data->dev_link);
+	struct rte_eth_link *src = link;
+
+	if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
+					*(uint64_t *)src) == 0)
+		return -1;
+
+	return 0;
+}
+
+static int
+i40evf_reset_vf(struct i40e_hw *hw)
+{
+	int i, reset;
+
+	if (i40e_vf_reset(hw) != I40E_SUCCESS) {
+		PMD_INIT_LOG(ERR, "Reset VF NIC failed\n");
+		return -1;
+	}
+	/**
+	  * After issuing vf reset command to pf, pf won't necessarily
+	  * reset vf, it depends on what state it exactly is. If it's not
+	  * initialized yet, it won't have vf reset since it's in a certain
+	  * state. If not, it will try to reset. Even vf is reset, pf will
+	  * set I40E_VFGEN_RSTAT to COMPLETE first, then wait 10ms and set
+	  * it to ACTIVE. In this duration, vf may not catch the moment that
+	  * COMPLETE is set. So, for vf, we'll try to wait a long time.
+	  */
+	rte_delay_ms(200);
+
+	for (i = 0; i < MAX_RESET_WAIT_CNT; i++) {
+		reset = rd32(hw, I40E_VFGEN_RSTAT) &
+			I40E_VFGEN_RSTAT_VFR_STATE_MASK;
+		reset = reset >> I40E_VFGEN_RSTAT_VFR_STATE_SHIFT;
+		if (I40E_VFR_COMPLETED == reset || I40E_VFR_VFACTIVE == reset)
+			break;
+		else
+			rte_delay_ms(50);
+	}
+
+	if (i >= MAX_RESET_WAIT_CNT) {
+		PMD_INIT_LOG(ERR, "Reset VF NIC failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int
+i40evf_init_vf(struct rte_eth_dev *dev)
+{
+	int i, err, bufsz;
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+
+	err = i40evf_set_mac_type(hw);
+	if (err) {
+		PMD_INIT_LOG(ERR, "set_mac_type failed: %d\n", err);
+		goto err;
+	}
+
+	i40e_init_adminq_parameter(hw);
+	err = i40e_init_adminq(hw);
+	if (err) {
+		PMD_INIT_LOG(ERR, "init_adminq failed: %d\n", err);
+		goto err;
+	}
+
+
+	/* Reset VF and wait until it's complete */
+	if (i40evf_reset_vf(hw)) {
+		PMD_INIT_LOG(ERR, "reset NIC failed\n");
+		goto err_aq;
+	}
+
+	/* VF reset, shutdown admin queue and initialize again */
+	if (i40e_shutdown_adminq(hw) != I40E_SUCCESS) {
+		PMD_INIT_LOG(ERR, "i40e_shutdown_adminq failed\n");
+		return -1;
+	}
+
+	i40e_init_adminq_parameter(hw);
+	if (i40e_init_adminq(hw) != I40E_SUCCESS) {
+		PMD_INIT_LOG(ERR, "init_adminq failed\n");
+		return -1;
+	}
+	if (i40evf_check_api_version(dev) != 0) {
+		PMD_INIT_LOG(ERR, "check_api version failed\n");
+		goto err_aq;
+	}
+	bufsz = sizeof(struct i40e_virtchnl_vf_resource) +
+		(I40E_MAX_VF_VSI * sizeof(struct i40e_virtchnl_vsi_resource));
+	vf->vf_res = rte_zmalloc("vf_res", bufsz, 0);
+	if (!vf->vf_res) {
+		PMD_INIT_LOG(ERR, "unable to allocate vf_res memory\n");
+			goto err_aq;
+	}
+
+	if (i40evf_get_vf_resource(dev) != 0) {
+		PMD_INIT_LOG(ERR, "i40evf_get_vf_config failed\n");
+		goto err_alloc;
+	}
+
+	/* got VF config message back from PF, now we can parse it */
+	for (i = 0; i < vf->vf_res->num_vsis; i++) {
+		if (vf->vf_res->vsi_res[i].vsi_type == I40E_VSI_SRIOV)
+			vf->vsi_res = &vf->vf_res->vsi_res[i];
+	}
+
+	if (!vf->vsi_res) {
+		PMD_INIT_LOG(ERR, "no LAN VSI found\n");
+		goto err_alloc;
+	}
+
+	vf->vsi.vsi_id = vf->vsi_res->vsi_id;
+	vf->vsi.type = vf->vsi_res->vsi_type;
+	vf->vsi.nb_qps = vf->vsi_res->num_queue_pairs;
+
+	/* check mac addr, if it's not valid, genrate one */
+	if (I40E_SUCCESS != i40e_validate_mac_addr(\
+			vf->vsi_res->default_mac_addr))
+		eth_random_addr(vf->vsi_res->default_mac_addr);
+
+	ether_addr_copy((struct ether_addr *)vf->vsi_res->default_mac_addr,
+					(struct ether_addr *)hw->mac.addr);
+
+	return 0;
+
+err_alloc:
+	rte_free(vf->vf_res);
+err_aq:
+	i40e_shutdown_adminq(hw); /* ignore error */
+err:
+	return -1;
+}
+
+static int
+i40evf_dev_init(__rte_unused struct eth_driver *eth_drv,
+		struct rte_eth_dev *eth_dev)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(\
+			eth_dev->data->dev_private);
+
+	PMD_INIT_FUNC_TRACE();
+
+	/* assign ops func pointer */
+	eth_dev->dev_ops = &i40evf_eth_dev_ops;
+	eth_dev->rx_pkt_burst = &i40e_recv_pkts;
+	eth_dev->tx_pkt_burst = &i40e_xmit_pkts;
+
+	/*
+	 * For secondary processes, we don't initialise any further as primary
+	 * has already done this work.
+	 */
+	if (rte_eal_process_type() != RTE_PROC_PRIMARY){
+		if (eth_dev->data->scattered_rx)
+			eth_dev->rx_pkt_burst = i40e_recv_scattered_pkts;
+		return 0;
+	}
+
+	hw->vendor_id = eth_dev->pci_dev->id.vendor_id;
+	hw->device_id = eth_dev->pci_dev->id.device_id;
+	hw->subsystem_vendor_id = eth_dev->pci_dev->id.subsystem_vendor_id;
+	hw->subsystem_device_id = eth_dev->pci_dev->id.subsystem_device_id;
+	hw->bus.device = eth_dev->pci_dev->addr.devid;
+	hw->bus.func = eth_dev->pci_dev->addr.function;
+	hw->hw_addr = (void *)eth_dev->pci_dev->mem_resource[0].addr;
+
+	if(i40evf_init_vf(eth_dev) != 0) {
+		PMD_INIT_LOG(ERR, "Init vf failed\n");
+		return -1;
+	}
+
+	/* copy mac addr */
+	eth_dev->data->mac_addrs = rte_zmalloc("i40evf_mac",
+					ETHER_ADDR_LEN, 0);
+	if (eth_dev->data->mac_addrs == NULL) {
+		PMD_INIT_LOG(ERR, "Failed to allocate %d bytes needed to "
+				"store MAC addresses", ETHER_ADDR_LEN);
+		return -ENOMEM;
+	}
+	ether_addr_copy((struct ether_addr *)hw->mac.addr,
+		(struct ether_addr *)eth_dev->data->mac_addrs);
+
+	return 0;
+}
+
+/*
+ * virtual function driver struct
+ */
+static struct eth_driver rte_i40evf_pmd = {
+	{
+		.name = "rte_i40evf_pmd",
+		.id_table = pci_id_i40evf_map,
+		.drv_flags = RTE_PCI_DRV_NEED_IGB_UIO,
+	},
+	.eth_dev_init = i40evf_dev_init,
+	.dev_private_size = sizeof(struct i40e_vf),
+};
+
+/*
+ * VF Driver initialization routine.
+ * Invoked one at EAL init time.
+ * Register itself as the [Virtual Poll Mode] Driver of PCI Fortville devices.
+ */
+static int
+rte_i40evf_pmd_init(const char *name __rte_unused,
+		    const char *params __rte_unused)
+{
+	DEBUGFUNC("rte_i40evf_pmd_init");
+
+	rte_eth_driver_register(&rte_i40evf_pmd);
+
+	return 0;
+}
+
+static struct rte_driver rte_i40evf_driver = {
+	.type = PMD_PDEV,
+	.init = rte_i40evf_pmd_init,
+};
+
+PMD_REGISTER_DRIVER(rte_i40evf_driver);
+
+static int
+i40evf_dev_configure(__rte_unused struct rte_eth_dev *dev)
+{
+	return 0;
+}
+
+static int
+i40evf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
+{
+	int ret;
+
+	if (on)
+		ret = i40evf_add_vlan(dev, vlan_id);
+	else
+		ret = i40evf_del_vlan(dev,vlan_id);
+
+	return ret;
+}
+
+static int
+i40evf_rx_init(struct rte_eth_dev *dev)
+{
+	uint16_t i, j;
+	struct i40e_rx_queue **rxq =
+		(struct i40e_rx_queue **)dev->data->rx_queues;
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		if (i40e_alloc_rx_queue_mbufs(rxq[i]) != 0) {
+			PMD_DRV_LOG(ERR, "alloc rx queues mbufs failed\n");
+			goto err;
+		}
+		rxq[i]->qrx_tail = hw->hw_addr + I40E_QRX_TAIL1(i);
+		I40E_PCI_REG_WRITE(rxq[i]->qrx_tail, rxq[i]->nb_rx_desc - 1);
+	}
+
+	/* Flush the operation to write registers */
+	I40EVF_WRITE_FLUSH(hw);
+
+	return 0;
+
+err:
+	/* Release all mbufs */
+	for (j = 0; j < i; j++)
+		i40e_rx_queue_release_mbufs(rxq[j]);
+
+	return -1;
+}
+
+static void
+i40evf_tx_init(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+	struct i40e_tx_queue **txq =
+		(struct i40e_tx_queue **)dev->data->tx_queues;
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	for (i = 0; i < dev->data->nb_tx_queues; i++)
+		txq[i]->qtx_tail = hw->hw_addr + I40E_QTX_TAIL1(i);
+}
+
+static inline void
+i40evf_enable_queues_intr(struct i40e_hw *hw)
+{
+	I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR - 1),
+			I40E_VFINT_DYN_CTLN1_INTENA_MASK |
+			I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
+}
+
+static inline void
+i40evf_disable_queues_intr(struct i40e_hw *hw)
+{
+	I40E_WRITE_REG(hw, I40E_VFINT_DYN_CTLN1(I40EVF_VSI_DEFAULT_MSIX_INTR - 1),
+			0);
+}
+
+static int
+i40evf_dev_start(struct rte_eth_dev *dev)
+{
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ether_addr mac_addr;
+
+	PMD_DRV_LOG(DEBUG, "i40evf_dev_start");
+
+	vf->max_pkt_len = dev->data->dev_conf.rxmode.max_rx_pkt_len;
+	if (dev->data->dev_conf.rxmode.jumbo_frame == 1) {
+		if (vf->max_pkt_len <= ETHER_MAX_LEN ||
+			vf->max_pkt_len > I40E_FRAME_SIZE_MAX) {
+			PMD_DRV_LOG(ERR, "maximum packet length must "
+				"be larger than %u and smaller than %u,"
+					"as jumbo frame is enabled\n",
+						(uint32_t)ETHER_MAX_LEN,
+					(uint32_t)I40E_FRAME_SIZE_MAX);
+			return I40E_ERR_CONFIG;
+		}
+	} else {
+		if (vf->max_pkt_len < ETHER_MIN_LEN ||
+			vf->max_pkt_len > ETHER_MAX_LEN) {
+			PMD_DRV_LOG(ERR, "maximum packet length must be "
+					"larger than %u and smaller than %u, "
+					"as jumbo frame is disabled\n",
+						(uint32_t)ETHER_MIN_LEN,
+						(uint32_t)ETHER_MAX_LEN);
+			return I40E_ERR_CONFIG;
+		}
+	}
+
+	vf->num_queue_pairs = RTE_MAX(dev->data->nb_rx_queues,
+					dev->data->nb_tx_queues);
+
+	if (i40evf_rx_init(dev) != 0){
+		PMD_DRV_LOG(ERR, "failed to do RX init\n");
+		return -1;
+	}
+
+	i40evf_tx_init(dev);
+
+	if (i40evf_configure_queues(dev) != 0) {
+		PMD_DRV_LOG(ERR, "configure queues failed\n");
+		goto err_queue;
+	}
+	if (i40evf_config_irq_map(dev)) {
+		PMD_DRV_LOG(ERR, "config_irq_map failed\n");
+		goto err_queue;
+	}
+
+	/* Set mac addr */
+	(void)rte_memcpy(mac_addr.addr_bytes, hw->mac.addr,
+				sizeof(mac_addr.addr_bytes));
+	if (i40evf_add_mac_addr(dev, &mac_addr)) {
+		PMD_DRV_LOG(ERR, "Failed to add mac addr\n");
+		goto err_queue;
+	}
+
+	if (i40evf_enable_queues(dev) != 0) {
+		PMD_DRV_LOG(ERR, "enable queues failed\n");
+		goto err_mac;
+	}
+	i40evf_enable_queues_intr(hw);
+	return 0;
+
+err_mac:
+	i40evf_del_mac_addr(dev, &mac_addr);
+err_queue:
+	i40e_dev_clear_queues(dev);
+	return -1;
+}
+
+static void
+i40evf_dev_stop(struct rte_eth_dev *dev)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	PMD_INIT_FUNC_TRACE();
+
+	i40evf_disable_queues_intr(hw);
+	i40evf_disable_queues(dev);
+	i40e_dev_clear_queues(dev);
+}
+
+static int
+i40evf_dev_link_update(struct rte_eth_dev *dev,
+		       __rte_unused int wait_to_complete)
+{
+	struct rte_eth_link new_link;
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	/*
+	 * DPDK pf host provide interfacet to acquire link status
+	 * while Linux driver does not
+	 */
+	if (vf->host_is_dpdk)
+		i40evf_get_link_status(dev, &new_link);
+	else {
+		/* Always assume it's up, for Linux driver PF host */
+		new_link.link_duplex = ETH_LINK_AUTONEG_DUPLEX;
+		new_link.link_speed  = ETH_LINK_SPEED_10000;
+		new_link.link_status = 1;
+	}
+	i40evf_dev_atomic_write_link_status(dev, &new_link);
+
+	return 0;
+}
+
+static void
+i40evf_dev_promiscuous_enable(struct rte_eth_dev *dev)
+{
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	int ret;
+
+	/* If enabled, just return */
+	if (vf->promisc_unicast_enabled)
+		return;
+
+	ret = i40evf_config_promisc(dev, 1, vf->promisc_multicast_enabled);
+	if (ret == 0)
+		vf->promisc_unicast_enabled = TRUE;
+}
+
+static void
+i40evf_dev_promiscuous_disable(struct rte_eth_dev *dev)
+{
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	int ret;
+
+	/* If disabled, just return */
+	if (!vf->promisc_unicast_enabled)
+		return;
+
+	ret = i40evf_config_promisc(dev, 0, vf->promisc_multicast_enabled);
+	if (ret == 0)
+		vf->promisc_unicast_enabled = FALSE;
+}
+
+static void
+i40evf_dev_allmulticast_enable(struct rte_eth_dev *dev)
+{
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	int ret;
+
+	/* If enabled, just return */
+	if (vf->promisc_multicast_enabled)
+		return;
+
+	ret = i40evf_config_promisc(dev, vf->promisc_unicast_enabled, 1);
+	if (ret == 0)
+		vf->promisc_multicast_enabled = TRUE;
+}
+
+static void
+i40evf_dev_allmulticast_disable(struct rte_eth_dev *dev)
+{
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+	int ret;
+
+	/* If enabled, just return */
+	if (!vf->promisc_multicast_enabled)
+		return;
+
+	ret = i40evf_config_promisc(dev, vf->promisc_unicast_enabled, 0);
+	if (ret == 0)
+		vf->promisc_multicast_enabled = FALSE;
+}
+
+static void
+i40evf_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
+{
+	struct i40e_vf *vf = I40EVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);
+
+	memset(dev_info, 0, sizeof(*dev_info));
+	dev_info->max_rx_queues = vf->vsi_res->num_queue_pairs;
+	dev_info->max_tx_queues = vf->vsi_res->num_queue_pairs;
+	dev_info->min_rx_bufsize = I40E_BUF_SIZE_MIN;
+	dev_info->max_rx_pktlen = I40E_FRAME_SIZE_MAX;
+}
+
+static void
+i40evf_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+	memset(stats, 0, sizeof(*stats));
+	if (i40evf_get_statics(dev, stats))
+		PMD_DRV_LOG(ERR, "Get statics failed\n");
+}
+
+static void
+i40evf_dev_close(struct rte_eth_dev *dev)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	i40evf_dev_stop(dev);
+	i40evf_reset_vf(hw);
+	i40e_shutdown_adminq(hw);
+}
diff --git a/lib/librte_pmd_i40e/i40e_logs.h b/lib/librte_pmd_i40e/i40e_logs.h
new file mode 100644
index 0000000..f991dd2
--- /dev/null
+++ b/lib/librte_pmd_i40e/i40e_logs.h
@@ -0,0 +1,74 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _I40E_LOGS_H_
+#define _I40E_LOGS_H_
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_INIT
+#define PMD_INIT_LOG(level, fmt, args...) \
+	RTE_LOG(level, PMD, "%s(): " fmt "\n", __func__, ## args)
+#define PMD_INIT_FUNC_TRACE() PMD_INIT_LOG(DEBUG, " >>")
+#else
+#define PMD_INIT_LOG(level, fmt, args...) do { } while(0)
+#define PMD_INIT_FUNC_TRACE() do { } while(0)
+#endif
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_RX
+#define PMD_RX_LOG(level, fmt, args...) \
+	RTE_LOG(level, PMD, "%s(): " fmt "\n", __func__, ## args)
+#else
+#define PMD_RX_LOG(level, fmt, args...) do { } while(0)
+#endif
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_TX
+#define PMD_TX_LOG(level, fmt, args...) \
+	RTE_LOG(level, PMD, "%s(): " fmt "\n", __func__, ## args)
+#else
+#define PMD_TX_LOG(level, fmt, args...) do { } while(0)
+#endif
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_TX_FREE
+#define PMD_TX_FREE_LOG(level, fmt, args...) \
+	RTE_LOG(level, PMD, "%s(): " fmt "\n", __func__, ## args)
+#else
+#define PMD_TX_FREE_LOG(level, fmt, args...) do { } while(0)
+#endif
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_DRIVER
+#define PMD_DRV_LOG(level, fmt, args...) \
+	RTE_LOG(level, PMD, "%s(): " fmt "\n", __func__, ## args)
+#else
+#define PMD_DRV_LOG(level, fmt, args...) do { } while(0)
+#endif
+
+#endif /* _I40E_LOGS_H_ */
diff --git a/lib/librte_pmd_i40e/i40e_pf.c b/lib/librte_pmd_i40e/i40e_pf.c
new file mode 100644
index 0000000..76405d3
--- /dev/null
+++ b/lib/librte_pmd_i40e/i40e_pf.c
@@ -0,0 +1,928 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+
+#include <rte_string_fns.h>
+#include <rte_pci.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_memzone.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+
+#include "i40e_logs.h"
+#include "i40e/i40e_prototype.h"
+#include "i40e/i40e_adminq_cmd.h"
+#include "i40e/i40e_type.h"
+#include "i40e_ethdev.h"
+#include "i40e_rxtx.h"
+#include "i40e_pf.h"
+
+static int
+i40e_pf_host_switch_queues(struct i40e_pf_vf *vf,
+			   struct i40e_virtchnl_queue_select *qsel,
+			   bool on);
+
+/**
+ * Bind PF queues with VSI and VF.
+ **/
+static int
+i40e_pf_vf_queues_mapping(struct i40e_pf_vf *vf)
+{
+	int i;
+	struct i40e_hw *hw = I40E_PF_TO_HW(vf->pf);
+	uint16_t vsi_id = vf->vsi->vsi_id;
+	uint16_t vf_id  = vf->vf_idx;
+	uint16_t nb_qps = vf->vsi->nb_qps;
+	uint16_t qbase  = vf->vsi->base_queue;
+	uint16_t q1, q2;
+	uint32_t val;
+
+	/*
+	 * VF should use scatter range queues. So, it needn't
+	 * to set QBASE in this register.
+	 */
+	I40E_WRITE_REG(hw, I40E_VSILAN_QBASE(vsi_id),
+	     I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
+
+	/* Set to enable VFLAN_QTABLE[] registers valid */
+	I40E_WRITE_REG(hw, I40E_VPLAN_MAPENA(vf_id),
+		I40E_VPLAN_MAPENA_TXRX_ENA_MASK);
+
+	/* map PF queues to VF */
+	for (i = 0; i < nb_qps; i++) {
+		val = ((qbase + i) & I40E_VPLAN_QTABLE_QINDEX_MASK);
+		I40E_WRITE_REG(hw, I40E_VPLAN_QTABLE(i, vf_id), val);
+	}
+
+	/* map PF queues to VSI */
+	for (i = 0; i < I40E_MAX_QP_NUM_PER_VF / 2; i++) {
+		if (2 * i > nb_qps - 1)
+			q1 = I40E_VSILAN_QTABLE_QINDEX_0_MASK;
+		else
+			q1 = qbase + 2 * i;
+
+		if (2 * i + 1 > nb_qps - 1)
+			q2 = I40E_VSILAN_QTABLE_QINDEX_0_MASK;
+		else
+			q2 = qbase + 2 * i + 1;
+
+		val = (q2 << I40E_VSILAN_QTABLE_QINDEX_1_SHIFT) + q1;
+		I40E_WRITE_REG(hw, I40E_VSILAN_QTABLE(i, vsi_id), val);
+	}
+	I40E_WRITE_FLUSH(hw);
+
+	return I40E_SUCCESS;
+}
+
+
+/**
+ * Proceed VF reset operation.
+ */
+int
+i40e_pf_host_vf_reset(struct i40e_pf_vf *vf, bool do_hw_reset)
+{
+	uint32_t val, i;
+	struct i40e_hw *hw = I40E_PF_TO_HW(vf->pf);
+	uint16_t vf_id, abs_vf_id, vf_msix_num;
+	int ret;
+	struct i40e_virtchnl_queue_select qsel;
+
+	if (vf == NULL)
+		return -EINVAL;
+
+	vf_id = vf->vf_idx;
+	abs_vf_id = vf_id + hw->func_caps.vf_base_id;
+
+	/* Notify VF that we are in VFR progress */
+	I40E_WRITE_REG(hw, I40E_VFGEN_RSTAT1(vf_id), I40E_PF_VFR_INPROGRESS);
+
+	/*
+	 * If require a SW VF reset, a VFLR interrupt will be generated,
+	 * this function will be called again. To avoid it,
+	 * disable interrupt first.
+	 */
+	if (do_hw_reset) {
+		vf->state = I40E_VF_INRESET;
+		val = I40E_READ_REG(hw, I40E_VPGEN_VFRTRIG(vf_id));
+		val |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
+		I40E_WRITE_REG(hw, I40E_VPGEN_VFRTRIG(vf_id), val);
+		I40E_WRITE_FLUSH(hw);
+	}
+
+#define VFRESET_MAX_WAIT_CNT 100
+	/* Wait until VF reset is done */
+	for (i = 0; i < VFRESET_MAX_WAIT_CNT; i++) {
+		rte_delay_us(10);
+		val = I40E_READ_REG(hw, I40E_VPGEN_VFRSTAT(vf_id));
+		if (val & I40E_VPGEN_VFRSTAT_VFRD_MASK)
+			break;
+	}
+
+	if (i >= VFRESET_MAX_WAIT_CNT) {
+		PMD_DRV_LOG(ERR, "VF reset timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	/* This is not first time to do reset, do cleanup job first */
+	if (vf->vsi) {
+		/* Disable queues */
+		memset(&qsel, 0, sizeof(qsel));
+		for (i = 0; i < vf->vsi->nb_qps; i++)
+			qsel.rx_queues |= 1 << i;
+		qsel.tx_queues = qsel.rx_queues;
+		ret = i40e_pf_host_switch_queues(vf, &qsel, false);
+		if (ret != I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Disable VF queues failed\n");
+			return -EFAULT;
+		}
+
+		/* Disable VF interrupt setting */
+		vf_msix_num = hw->func_caps.num_msix_vectors_vf;
+		for (i = 0; i < vf_msix_num; i++) {
+			if (!i)
+				val = I40E_VFINT_DYN_CTL0(vf_id);
+			else
+				val = I40E_VFINT_DYN_CTLN(((vf_msix_num - 1) *
+							(vf_id)) + (i - 1));
+			I40E_WRITE_REG(hw, val, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
+		}
+		I40E_WRITE_FLUSH(hw);
+
+		/* remove VSI */
+		ret = i40e_vsi_release(vf->vsi);
+		if (ret != I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Release VSI failed\n");
+			return -EFAULT;
+		}
+	}
+
+#define I40E_VF_PCI_ADDR  0xAA
+#define I40E_VF_PEND_MASK 0x20
+	/* Check the pending transactions of this VF */
+	/* Use absolute VF id, refer to datasheet for details */
+	I40E_WRITE_REG(hw, I40E_PF_PCI_CIAA, I40E_VF_PCI_ADDR |
+		(abs_vf_id << I40E_PF_PCI_CIAA_VF_NUM_SHIFT));
+	for (i = 0; i < VFRESET_MAX_WAIT_CNT; i++) {
+		rte_delay_us(1);
+		val = I40E_READ_REG(hw, I40E_PF_PCI_CIAD);
+		if ((val & I40E_VF_PEND_MASK) == 0)
+			break;
+	}
+
+	if (i >= VFRESET_MAX_WAIT_CNT) {
+		PMD_DRV_LOG(ERR, "Wait VF PCI transaction end timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	/* Reset done, Set COMPLETE flag and clear reset bit */
+	I40E_WRITE_REG(hw, I40E_VFGEN_RSTAT1(vf_id), I40E_PF_VFR_COMPLETED);
+	val = I40E_READ_REG(hw, I40E_VPGEN_VFRTRIG(vf_id));
+	val &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
+	I40E_WRITE_REG(hw, I40E_VPGEN_VFRTRIG(vf_id), val);
+	vf->reset_cnt++;
+	I40E_WRITE_FLUSH(hw);
+
+	/* Allocate resource again */
+	vf->vsi = i40e_vsi_setup(vf->pf, I40E_VSI_SRIOV,
+			vf->pf->main_vsi, vf->vf_idx);
+	if (vf->vsi == NULL) {
+		PMD_DRV_LOG(ERR, "Add vsi failed\n");
+		return -EFAULT;
+	}
+
+	ret = i40e_pf_vf_queues_mapping(vf);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "queue mapping error\n");
+		i40e_vsi_release(vf->vsi);
+		return -EFAULT;
+	}
+
+	return ret;
+}
+
+static int
+i40e_pf_host_send_msg_to_vf(struct i40e_pf_vf *vf,
+			    uint32_t opcode,
+			    uint32_t retval,
+			    uint8_t *msg,
+			    uint16_t msglen)
+{
+	struct i40e_hw *hw = I40E_PF_TO_HW(vf->pf);
+	uint16_t abs_vf_id = hw->func_caps.vf_base_id + vf->vf_idx;
+	int ret;
+
+	ret = i40e_aq_send_msg_to_vf(hw, abs_vf_id, opcode, retval,
+						msg, msglen, NULL);
+	if (ret) {
+		PMD_DRV_LOG(ERR, "Fail to send message to VF, err %u\n",
+			hw->aq.asq_last_status);
+		printf("Fail to send message to VF, err %u\n",
+					hw->aq.asq_last_status);
+	}
+
+	return ret;
+}
+
+static void
+i40e_pf_host_process_cmd_version(struct i40e_pf_vf *vf)
+{
+	struct i40e_virtchnl_version_info info;
+
+	info.major = I40E_DPDK_VERSION_MAJOR;
+	info.minor = I40E_DPDK_VERSION_MINOR;
+	i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_VERSION,
+		I40E_SUCCESS, (uint8_t *)&info, sizeof(info));
+}
+
+static int
+i40e_pf_host_process_cmd_reset_vf(struct i40e_pf_vf *vf)
+{
+	i40e_pf_host_vf_reset(vf, 1);
+
+	/* No feedback will be sent to VF for VFLR */
+	return I40E_SUCCESS;
+}
+
+static int
+i40e_pf_host_process_cmd_get_vf_resource(struct i40e_pf_vf *vf)
+{
+	struct i40e_virtchnl_vf_resource *vf_res = NULL;
+	struct i40e_hw *hw = I40E_PF_TO_HW(vf->pf);
+	uint32_t len = 0;
+	int ret = I40E_SUCCESS;
+
+	/* only have 1 VSI by default */
+	len =  sizeof(struct i40e_virtchnl_vf_resource) +
+				I40E_DEFAULT_VF_VSI_NUM *
+		sizeof(struct i40e_virtchnl_vsi_resource);
+
+	vf_res = rte_zmalloc("i40e_vf_res", len, 0);
+	if (vf_res == NULL) {
+		PMD_DRV_LOG(ERR, "failed to allocate mem\n");
+		ret = I40E_ERR_NO_MEMORY;
+		vf_res = NULL;
+		len = 0;
+		goto send_msg;
+	}
+
+	vf_res->vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2;
+	vf_res->max_vectors = hw->func_caps.num_msix_vectors_vf;
+	vf_res->num_queue_pairs = vf->vsi->nb_qps;
+	vf_res->num_vsis = I40E_DEFAULT_VF_VSI_NUM;
+
+	/* Change below setting if PF host can support more VSIs for VF */
+	vf_res->vsi_res[0].vsi_type = I40E_VSI_SRIOV;
+	/* As assume Vf only has single VSI now, always return 0 */
+	vf_res->vsi_res[0].vsi_id = 0;
+	vf_res->vsi_res[0].num_queue_pairs = vf->vsi->nb_qps;
+
+send_msg:
+	i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
+					ret, (uint8_t *)vf_res, len);
+	rte_free(vf_res);
+
+	return ret;
+}
+
+static int
+i40e_pf_host_hmc_config_rxq(struct i40e_hw *hw,
+			    struct i40e_pf_vf *vf,
+			    struct i40e_virtchnl_rxq_info *rxq)
+{
+	int err = I40E_SUCCESS;
+	struct i40e_hmc_obj_rxq rx_ctx;
+	uint16_t abs_queue_id = vf->vsi->base_queue + rxq->queue_id;
+
+	/* Clear the context structure first */
+	memset(&rx_ctx, 0, sizeof(struct i40e_hmc_obj_rxq));
+	rx_ctx.dbuff = rxq->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT;
+	rx_ctx.hbuff = rxq->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT;
+	rx_ctx.base = rxq->dma_ring_addr / I40E_QUEUE_BASE_ADDR_UNIT;
+	rx_ctx.qlen = rxq->ring_len;
+#ifndef RTE_LIBRTE_I40E_16BYTE_RX_DESC
+	rx_ctx.dsize = 1;
+#endif
+
+	if (rxq->splithdr_enabled) {
+		rx_ctx.hsplit_0 = I40E_HEADER_SPLIT_ALL;
+		rx_ctx.dtype = i40e_header_split_enabled;
+	} else {
+		rx_ctx.hsplit_0 = I40E_HEADER_SPLIT_NONE;
+		rx_ctx.dtype = i40e_header_split_none;
+	}
+	rx_ctx.rxmax = rxq->max_pkt_size;
+	rx_ctx.tphrdesc_ena = 1;
+	rx_ctx.tphwdesc_ena = 1;
+	rx_ctx.tphdata_ena = 1;
+	rx_ctx.tphhead_ena = 1;
+	rx_ctx.lrxqthresh = 2;
+	rx_ctx.crcstrip = 1;
+	rx_ctx.prefena = 1;
+
+	err = i40e_clear_lan_rx_queue_context(hw, abs_queue_id);
+	if (err != I40E_SUCCESS)
+		return err;
+	err = i40e_set_lan_rx_queue_context(hw, abs_queue_id, &rx_ctx);
+
+	return err;
+}
+
+static int
+i40e_pf_host_hmc_config_txq(struct i40e_hw *hw,
+			    struct i40e_pf_vf *vf,
+			    struct i40e_virtchnl_txq_info *txq)
+{
+	int err = I40E_SUCCESS;
+	struct i40e_hmc_obj_txq tx_ctx;
+	uint32_t qtx_ctl;
+	uint16_t abs_queue_id = vf->vsi->base_queue + txq->queue_id;
+
+
+	/* clear the context structure first */
+	memset(&tx_ctx, 0, sizeof(tx_ctx));
+	tx_ctx.new_context = 1;
+	tx_ctx.base = txq->dma_ring_addr / I40E_QUEUE_BASE_ADDR_UNIT;
+	tx_ctx.qlen = txq->ring_len;
+	tx_ctx.rdylist = rte_le_to_cpu_16(vf->vsi->info.qs_handle[0]);
+	err = i40e_clear_lan_tx_queue_context(hw, abs_queue_id);
+	if (err != I40E_SUCCESS)
+		return err;
+
+	err = i40e_set_lan_tx_queue_context(hw, abs_queue_id, &tx_ctx);
+	if (err != I40E_SUCCESS)
+		return err;
+
+	/* bind queue with VF function, since TX/QX will appear in pair,
+	 * so only has QTX_CTL to set.
+	 */
+	qtx_ctl = (I40E_QTX_CTL_VF_QUEUE << I40E_QTX_CTL_PFVF_Q_SHIFT) |
+				((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
+				I40E_QTX_CTL_PF_INDX_MASK) |
+				(((vf->vf_idx + hw->func_caps.vf_base_id) <<
+				I40E_QTX_CTL_VFVM_INDX_SHIFT) &
+				I40E_QTX_CTL_VFVM_INDX_MASK);
+	I40E_WRITE_REG(hw, I40E_QTX_CTL(abs_queue_id), qtx_ctl);
+	I40E_WRITE_FLUSH(hw);
+
+	return I40E_SUCCESS;
+}
+
+static int
+i40e_pf_host_process_cmd_config_vsi_queues(struct i40e_pf_vf *vf,
+					   uint8_t *msg,
+					   uint16_t msglen)
+{
+	struct i40e_hw *hw = I40E_PF_TO_HW(vf->pf);
+	struct i40e_vsi *vsi = vf->vsi;
+	int ret = I40E_SUCCESS;
+	struct i40e_virtchnl_vsi_queue_config_info *qconfig =
+	    (struct i40e_virtchnl_vsi_queue_config_info *)msg;
+	int i;
+	struct i40e_virtchnl_queue_pair_info *qpair;
+
+	if (msglen <= sizeof(*qconfig) ||
+		qconfig->num_queue_pairs > vsi->nb_qps) {
+		PMD_DRV_LOG(ERR, "vsi_queue_config_info argument wrong\n");
+		ret = I40E_ERR_PARAM;
+		goto send_msg;
+	}
+
+	qpair = qconfig->qpair;
+	for (i = 0; i < qconfig->num_queue_pairs; i++) {
+		if (qpair[i].rxq.queue_id > vsi->nb_qps - 1 ||
+			qpair[i].txq.queue_id > vsi->nb_qps - 1) {
+			ret = I40E_ERR_PARAM;
+			goto send_msg;
+		}
+
+		/* Apply VF RX queue setting to HMC */
+		if (i40e_pf_host_hmc_config_rxq(hw, vf, &qpair[i].rxq)
+			!= I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Configure RX queue HMC failed");
+			ret = I40E_ERR_PARAM;
+			goto send_msg;
+		}
+
+		/* Apply VF TX queue setting to HMC */
+		if (i40e_pf_host_hmc_config_txq(hw, vf, &qpair[i].txq)
+			!= I40E_SUCCESS) {
+			PMD_DRV_LOG(ERR, "Configure TX queue HMC failed");
+			ret = I40E_ERR_PARAM;
+			goto send_msg;
+		}
+	}
+
+send_msg:
+	i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
+							ret, NULL, 0);
+	return ret;
+}
+
+static int
+i40e_pf_host_process_cmd_config_irq_map(struct i40e_pf_vf *vf,
+					uint8_t *msg, uint16_t msglen)
+{
+	int ret = I40E_SUCCESS;
+	struct i40e_virtchnl_irq_map_info *irqmap =
+	    (struct i40e_virtchnl_irq_map_info *)msg;
+
+	if (msglen < sizeof(struct i40e_virtchnl_irq_map_info)) {
+		PMD_DRV_LOG(ERR, "buffer too short\n");
+		ret = I40E_ERR_PARAM;
+		goto send_msg;
+	}
+
+	/* Assume VF only have 1 vector to bind all queues */
+	if (irqmap->num_vectors != 1) {
+		PMD_DRV_LOG(ERR, "DKDK host only support 1 vector\n");
+		ret = I40E_ERR_PARAM;
+		goto send_msg;
+	}
+
+	if (irqmap->vecmap[0].vector_id == 0) {
+		PMD_DRV_LOG(ERR, "DPDK host don't support use IRQ0\n");
+		ret = I40E_ERR_PARAM;
+		goto send_msg;
+	}
+	/* This MSIX intr store the intr in VF range */
+	vf->vsi->msix_intr = irqmap->vecmap[0].vector_id;
+
+	/* Don't care how the TX/RX queue mapping with this vector.
+	 * Link all VF RX queues together. Only did mapping work.
+	 * VF can disable/enable the intr by itself.
+	 */
+	i40e_vsi_queues_bind_intr(vf->vsi);
+send_msg:
+	i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
+							ret, NULL, 0);
+
+	return ret;
+}
+
+static int
+i40e_pf_host_switch_queues(struct i40e_pf_vf *vf,
+			   struct i40e_virtchnl_queue_select *qsel,
+			   bool on)
+{
+	int ret = I40E_SUCCESS;
+	int i;
+	struct i40e_hw *hw = I40E_PF_TO_HW(vf->pf);
+	uint16_t baseq = vf->vsi->base_queue;
+
+	if (qsel->rx_queues + qsel->tx_queues == 0)
+		return I40E_ERR_PARAM;
+
+	/* always enable RX first and disable last */
+	/* Enable RX if it's enable */
+	if (on) {
+		for (i = 0; i < I40E_MAX_QP_NUM_PER_VF; i++)
+			if (qsel->rx_queues & (1 << i)) {
+				ret = i40e_switch_rx_queue(hw, baseq + i, on);
+				if (ret != I40E_SUCCESS)
+					return ret;
+			}
+	}
+
+	/* Enable/Disable TX */
+	for (i = 0; i < I40E_MAX_QP_NUM_PER_VF; i++)
+		if (qsel->tx_queues & (1 << i)) {
+			ret = i40e_switch_tx_queue(hw, baseq + i, on);
+			if (ret != I40E_SUCCESS)
+				return ret;
+		}
+
+	/* disable RX last if it's disable */
+	if (!on) {
+		/* disable RX */
+		for (i = 0; i < I40E_MAX_QP_NUM_PER_VF; i++)
+			if (qsel->rx_queues & (1 << i)) {
+				ret = i40e_switch_rx_queue(hw, baseq + i, on);
+				if (ret != I40E_SUCCESS)
+					return ret;
+			}
+	}
+
+	return ret;
+}
+
+static int
+i40e_pf_host_process_cmd_enable_queues(struct i40e_pf_vf *vf,
+				       uint8_t *msg,
+				       uint16_t msglen)
+{
+	int ret = I40E_SUCCESS;
+	struct i40e_virtchnl_queue_select *q_sel =
+		(struct i40e_virtchnl_queue_select *)msg;
+
+	if (msglen != sizeof(*q_sel)) {
+		ret = I40E_ERR_PARAM;
+		goto send_msg;
+	}
+	ret = i40e_pf_host_switch_queues(vf, q_sel, true);
+
+send_msg:
+	i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
+							ret, NULL, 0);
+
+	return ret;
+}
+
+static int
+i40e_pf_host_process_cmd_disable_queues(struct i40e_pf_vf *vf,
+					uint8_t *msg,
+					uint16_t msglen)
+{
+	int ret = I40E_SUCCESS;
+	struct i40e_virtchnl_queue_select *q_sel =
+		(struct i40e_virtchnl_queue_select *)msg;
+
+	if (msglen != sizeof(*q_sel)) {
+		ret = I40E_ERR_PARAM;
+		goto send_msg;
+	}
+	ret = i40e_pf_host_switch_queues(vf, q_sel, false);
+
+send_msg:
+	i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
+							ret, NULL, 0);
+
+	return ret;
+}
+
+
+static int
+i40e_pf_host_process_cmd_add_ether_address(struct i40e_pf_vf *vf,
+					   uint8_t *msg,
+					   uint16_t msglen)
+{
+	int ret = I40E_SUCCESS;
+	struct i40e_virtchnl_ether_addr_list *addr_list =
+			(struct i40e_virtchnl_ether_addr_list *)msg;
+	int i;
+	struct ether_addr *mac;
+
+	if (msglen <= sizeof(*addr_list)) {
+		PMD_DRV_LOG(ERR, "add_ether_address argument too short\n");
+		ret = I40E_ERR_PARAM;
+		goto send_msg;
+	}
+
+	for (i = 0; i < addr_list->num_elements; i++) {
+		mac = (struct ether_addr *)(addr_list->list[i].addr);
+		if(!is_valid_assigned_ether_addr(mac) ||
+			i40e_vsi_add_mac(vf->vsi, mac)) {
+			ret = I40E_ERR_INVALID_MAC_ADDR;
+			goto send_msg;
+		}
+	}
+
+send_msg:
+	i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
+							ret, NULL, 0);
+
+	return ret;
+}
+
+static int
+i40e_pf_host_process_cmd_del_ether_address(struct i40e_pf_vf *vf,
+					   uint8_t *msg,
+					   uint16_t msglen)
+{
+	int ret = I40E_SUCCESS;
+	struct i40e_virtchnl_ether_addr_list *addr_list =
+		(struct i40e_virtchnl_ether_addr_list *)msg;
+	int i;
+	struct ether_addr *mac;
+
+	if (msglen <= sizeof(*addr_list)) {
+		PMD_DRV_LOG(ERR, "delete_ether_address argument too short\n");
+		ret = I40E_ERR_PARAM;
+		goto send_msg;
+	}
+
+	for (i = 0; i < addr_list->num_elements; i++) {
+		mac = (struct ether_addr *)(addr_list->list[i].addr);
+		if(!is_valid_assigned_ether_addr(mac) ||
+			i40e_vsi_delete_mac(vf->vsi, mac)) {
+			ret = I40E_ERR_INVALID_MAC_ADDR;
+			goto send_msg;
+		}
+	}
+
+send_msg:
+	i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS,
+							ret, NULL, 0);
+
+	return ret;
+}
+
+
+static int
+i40e_pf_host_process_cmd_add_vlan(struct i40e_pf_vf *vf,
+				uint8_t *msg, uint16_t msglen)
+{
+	int ret = I40E_SUCCESS;
+	struct i40e_virtchnl_vlan_filter_list *vlan_filter_list =
+		(struct i40e_virtchnl_vlan_filter_list *)msg;
+	int i;
+	uint16_t *vid;
+
+	if (msglen <= sizeof(*vlan_filter_list)) {
+		PMD_DRV_LOG(ERR, "add_vlan argument too short\n");
+		ret = I40E_ERR_PARAM;
+		goto send_msg;
+	}
+
+	vid = vlan_filter_list->vlan_id;
+
+	for (i = 0; i < vlan_filter_list->num_elements; i++) {
+		ret = i40e_vsi_add_vlan(vf->vsi, vid[i]);
+		if(ret != I40E_SUCCESS)
+			goto send_msg;
+	}
+
+send_msg:
+	i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_ADD_VLAN,
+						ret, NULL, 0);
+
+	return ret;
+}
+
+static int
+i40e_pf_host_process_cmd_del_vlan(struct i40e_pf_vf *vf,
+				  uint8_t *msg,
+				  uint16_t msglen)
+{
+	int ret = I40E_SUCCESS;
+	struct i40e_virtchnl_vlan_filter_list *vlan_filter_list =
+			(struct i40e_virtchnl_vlan_filter_list *)msg;
+	int i;
+	uint16_t *vid;
+
+	if (msglen <= sizeof(*vlan_filter_list)) {
+		PMD_DRV_LOG(ERR, "delete_vlan argument too short\n");
+		ret = I40E_ERR_PARAM;
+		goto send_msg;
+	}
+
+	vid = vlan_filter_list->vlan_id;
+	for (i = 0; i < vlan_filter_list->num_elements; i++) {
+		ret = i40e_vsi_delete_vlan(vf->vsi, vid[i]);
+		if(ret != I40E_SUCCESS)
+			goto send_msg;
+	}
+
+send_msg:
+	i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_DEL_VLAN,
+						ret, NULL, 0);
+
+	return ret;
+}
+
+static int
+i40e_pf_host_process_cmd_config_promisc_mode(
+					struct i40e_pf_vf *vf,
+					uint8_t *msg,
+					__rte_unused uint16_t msglen)
+{
+	int ret = I40E_SUCCESS;
+	struct i40e_virtchnl_promisc_info *promisc =
+				(struct i40e_virtchnl_promisc_info *)msg;
+	struct i40e_hw *hw = I40E_PF_TO_HW(vf->pf);
+	bool unicast = FALSE, multicast = FALSE;
+
+	if (promisc->flags & I40E_FLAG_VF_UNICAST_PROMISC)
+		unicast = TRUE;
+	ret = i40e_aq_set_vsi_unicast_promiscuous(hw,
+			vf->vsi->seid, unicast, NULL);
+	if (ret != I40E_SUCCESS)
+		goto send_msg;
+
+	if (promisc->flags & I40E_FLAG_VF_MULTICAST_PROMISC)
+		multicast = TRUE;
+	ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vf->vsi->seid,
+						multicast, NULL);
+
+send_msg:
+	i40e_pf_host_send_msg_to_vf(vf,
+		I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE, ret, NULL, 0);
+
+	return ret;
+}
+
+static int
+i40e_pf_host_process_cmd_get_stats(struct i40e_pf_vf *vf)
+{
+	i40e_update_vsi_stats(vf->vsi);
+
+	i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_GET_STATS,
+		I40E_SUCCESS, (uint8_t *)&vf->vsi->eth_stats,
+				sizeof(vf->vsi->eth_stats));
+
+	return I40E_SUCCESS;
+}
+
+static void
+i40e_pf_host_process_cmd_get_link_status(struct i40e_pf_vf *vf)
+{
+	struct rte_eth_dev *dev = I40E_VSI_TO_ETH_DEV(vf->pf->main_vsi);
+
+	/* Update link status first to acquire latest link change */
+	i40e_dev_link_update(dev, 1);
+	i40e_pf_host_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_GET_LINK_STAT,
+		I40E_SUCCESS, (uint8_t *)&dev->data->dev_link,
+				sizeof(struct rte_eth_link));
+}
+
+void
+i40e_pf_host_handle_vf_msg(struct rte_eth_dev *dev,
+			   uint16_t abs_vf_id, uint32_t opcode,
+			   __rte_unused uint32_t retval,
+			   uint8_t *msg,
+			   uint16_t msglen)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct i40e_pf_vf *vf;
+	/* AdminQ will pass absolute VF id, transfer to internal vf id */
+	uint16_t vf_id = abs_vf_id - hw->func_caps.vf_base_id;
+
+	if (!dev || vf_id > pf->vf_num - 1 || !pf->vfs) {
+		PMD_DRV_LOG(ERR, "invalid argument\n");
+		return;
+	}
+
+	vf = &pf->vfs[vf_id];
+	if (!vf->vsi) {
+		PMD_DRV_LOG(ERR, "NO VSI associated with VF found\n");
+		i40e_pf_host_send_msg_to_vf(vf, opcode,
+			I40E_ERR_NO_AVAILABLE_VSI, NULL, 0);
+		return;
+	}
+
+	switch (opcode) {
+	case I40E_VIRTCHNL_OP_VERSION :
+		PMD_DRV_LOG(INFO, "OP_VERSION received\n");
+		i40e_pf_host_process_cmd_version(vf);
+		break;
+	case I40E_VIRTCHNL_OP_RESET_VF :
+		PMD_DRV_LOG(INFO, "OP_RESET_VF received\n");
+		i40e_pf_host_process_cmd_reset_vf(vf);
+		break;
+	case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
+		PMD_DRV_LOG(INFO, "OP_GET_VF_RESOURCES received\n");
+		i40e_pf_host_process_cmd_get_vf_resource(vf);
+		break;
+	case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
+		PMD_DRV_LOG(INFO, "OP_CONFIG_VSI_QUEUES received\n");
+		i40e_pf_host_process_cmd_config_vsi_queues(vf,
+						msg, msglen);
+		break;
+	case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
+		PMD_DRV_LOG(INFO, "OP_CONFIG_IRQ_MAP received\n");
+		i40e_pf_host_process_cmd_config_irq_map(vf, msg, msglen);
+		break;
+	case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
+		PMD_DRV_LOG(INFO, "OP_ENABLE_QUEUES received\n");
+		i40e_pf_host_process_cmd_enable_queues(vf,
+						msg, msglen);
+		break;
+	case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
+		PMD_DRV_LOG(INFO, "OP_DISABLE_QUEUE received\n");
+		i40e_pf_host_process_cmd_disable_queues(vf,
+						msg, msglen);
+		break;
+	case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
+		PMD_DRV_LOG(INFO, "OP_ADD_ETHER_ADDRESS received\n");
+		i40e_pf_host_process_cmd_add_ether_address(vf,
+						msg, msglen);
+		break;
+	case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
+		PMD_DRV_LOG(INFO, "OP_DEL_ETHER_ADDRESS received\n");
+		i40e_pf_host_process_cmd_del_ether_address(vf,
+						msg, msglen);
+		break;
+	case I40E_VIRTCHNL_OP_ADD_VLAN:
+		PMD_DRV_LOG(INFO, "OP_ADD_VLAN received\n");
+		i40e_pf_host_process_cmd_add_vlan(vf, msg, msglen);
+		break;
+	case I40E_VIRTCHNL_OP_DEL_VLAN:
+		PMD_DRV_LOG(INFO, "OP_DEL_VLAN received\n");
+		i40e_pf_host_process_cmd_del_vlan(vf, msg, msglen);
+		break;
+	case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
+		PMD_DRV_LOG(INFO, "OP_CONFIG_PROMISCUOUS_MODE received\n");
+		i40e_pf_host_process_cmd_config_promisc_mode(vf, msg, msglen);
+		break;
+	case I40E_VIRTCHNL_OP_GET_STATS:
+		PMD_DRV_LOG(INFO, "OP_GET_STATS received\n");
+		i40e_pf_host_process_cmd_get_stats(vf);
+		break;
+	case I40E_VIRTCHNL_OP_GET_LINK_STAT:
+		PMD_DRV_LOG(INFO, "OP_GET_LINK_STAT received\n");
+		i40e_pf_host_process_cmd_get_link_status(vf);
+		break;
+	 /* Don't add command supported below, which will
+	 *  return an error code.
+	 */
+	case I40E_VIRTCHNL_OP_FCOE:
+		PMD_DRV_LOG(ERR, "OP_FCOE received, not supported\n");
+	default:
+		PMD_DRV_LOG(ERR, "%u received, not supported\n",
+							opcode);
+		i40e_pf_host_send_msg_to_vf(vf, opcode,
+				I40E_ERR_PARAM, NULL, 0);
+		break;
+	}
+}
+
+int
+i40e_pf_host_init(struct rte_eth_dev *dev)
+{
+	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+	int ret, i;
+	uint32_t val;
+
+	PMD_INIT_FUNC_TRACE();
+
+	/**
+	 * return if SRIOV not enabled, VF number not configured or
+	 * no queue assigned.
+	 */
+	if(!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 || pf->vf_nb_qps == 0)
+		return I40E_SUCCESS;
+
+	/* Allocate memory to store VF structure */
+	pf->vfs = rte_zmalloc("i40e_pf_vf",sizeof(*pf->vfs) * pf->vf_num, 0);
+	if(pf->vfs == NULL)
+		return -ENOMEM;
+
+	/* Disable irq0 for VFR event */
+	i40e_pf_disable_irq0(hw);
+
+	/* Disable VF link status interrupt */
+	val = I40E_READ_REG(hw, I40E_PFGEN_PORTMDIO_NUM);
+	val &= ~I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK;
+	I40E_WRITE_REG(hw, I40E_PFGEN_PORTMDIO_NUM, val);
+	I40E_WRITE_FLUSH(hw);
+
+	for (i = 0; i < pf->vf_num; i++) {
+		pf->vfs[i].pf = pf;
+		pf->vfs[i].state = I40E_VF_INACTIVE;
+		pf->vfs[i].vf_idx = i;
+		ret = i40e_pf_host_vf_reset(&pf->vfs[i], 0);
+		if (ret != I40E_SUCCESS)
+			goto fail;
+	}
+
+	/* restore irq0 */
+	i40e_pf_enable_irq0(hw);
+
+	return I40E_SUCCESS;
+
+fail:
+	rte_free(pf->vfs);
+	i40e_pf_enable_irq0(hw);
+
+	return ret;
+}
diff --git a/lib/librte_pmd_i40e/i40e_pf.h b/lib/librte_pmd_i40e/i40e_pf.h
new file mode 100644
index 0000000..ccbd0d8
--- /dev/null
+++ b/lib/librte_pmd_i40e/i40e_pf.h
@@ -0,0 +1,67 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _I40E_PF_H_
+#define _I40E_PF_H_
+
+/* VERSION info to exchange between VF and PF host. In case VF works with
+ *  ND kernel driver, it reads I40E_VIRTCHNL_VERSION_MAJOR/MINOR. In
+ *  case works with DPDK host, it reads version below. Then VF realize who it
+ *  is talking to and use proper language to communicate.
+ * */
+#define I40E_DPDK_SIGNATURE     ('D' << 24 | 'P' << 16 | 'D' << 8 | 'K')
+#define I40E_DPDK_VERSION_MAJOR I40E_DPDK_SIGNATURE
+#define I40E_DPDK_VERSION_MINOR 0
+
+/* Default setting on number of VSIs that VF can contain */
+#define I40E_DEFAULT_VF_VSI_NUM 1
+
+enum i40e_pf_vfr_state {
+	I40E_PF_VFR_INPROGRESS = 0,
+	I40E_PF_VFR_COMPLETED = 1,
+};
+
+/* DPDK pf driver specific command to VF */
+enum i40e_virtchnl_ops_DPDK {
+	/* Keep some gap between Linu PF commands and DPDK PF specific commands */
+	I40E_VIRTCHNL_OP_GET_LINK_STAT = I40E_VIRTCHNL_OP_EVENT + 0x100,
+};
+
+int i40e_pf_host_vf_reset(struct i40e_pf_vf *vf, bool do_hw_reset);
+void i40e_pf_host_handle_vf_msg(struct rte_eth_dev *dev,
+				uint16_t abs_vf_id, uint32_t opcode,
+				__rte_unused uint32_t retval,
+				uint8_t *msg, uint16_t msglen);
+int i40e_pf_host_init(struct rte_eth_dev *dev);
+
+#endif /* _I40E_PF_H_ */
diff --git a/lib/librte_pmd_i40e/i40e_rxtx.c b/lib/librte_pmd_i40e/i40e_rxtx.c
new file mode 100644
index 0000000..d802894
--- /dev/null
+++ b/lib/librte_pmd_i40e/i40e_rxtx.c
@@ -0,0 +1,2204 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <endian.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/queue.h>
+
+#include <rte_string_fns.h>
+#include <rte_memzone.h>
+#include <rte_mbuf.h>
+#include <rte_malloc.h>
+#include <rte_ether.h>
+#include <rte_ethdev.h>
+#include <rte_tcp.h>
+#include <rte_sctp.h>
+#include <rte_udp.h>
+
+#include "i40e_logs.h"
+#include "i40e/i40e_prototype.h"
+#include "i40e/i40e_type.h"
+#include "i40e_ethdev.h"
+#include "i40e_rxtx.h"
+
+#define I40E_MIN_RING_DESC     64
+#define I40E_MAX_RING_DESC     4096
+#define I40E_ALIGN             128
+#define DEFAULT_TX_RS_THRESH   32
+#define DEFAULT_TX_FREE_THRESH 32
+#define I40E_MAX_PKT_TYPE      256
+
+#define I40E_VLAN_TAG_SIZE 4
+#define I40E_TX_MAX_BURST  32
+
+#define I40E_DMA_MEM_ALIGN 4096
+
+#define I40E_SIMPLE_FLAGS ((uint32_t)ETH_TXQ_FLAGS_NOMULTSEGS | \
+					ETH_TXQ_FLAGS_NOOFFLOADS)
+
+#define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+
+#define RTE_MBUF_DATA_DMA_ADDR_DEFAULT(mb) \
+	(uint64_t) ((mb)->buf_physaddr + RTE_PKTMBUF_HEADROOM)
+
+#define RTE_MBUF_DATA_DMA_ADDR(mb) \
+	((uint64_t)((mb)->buf_physaddr + \
+	(uint64_t)((char *)((mb)->pkt.data) - \
+	(char *)(mb)->buf_addr)))
+
+static const struct rte_memzone *
+i40e_ring_dma_zone_reserve(struct rte_eth_dev *dev,
+			   const char *ring_name,
+			   uint16_t queue_id,
+			   uint32_t ring_size,
+			   int socket_id);
+static void i40e_reset_rx_queue(struct i40e_rx_queue *rxq);
+static void i40e_reset_tx_queue(struct i40e_tx_queue *txq);
+static void i40e_tx_queue_release_mbufs(struct i40e_tx_queue *txq);
+static uint16_t i40e_xmit_pkts_simple(void *tx_queue,
+				      struct rte_mbuf **tx_pkts,
+				      uint16_t nb_pkts);
+
+/* Translate the rx descriptor status to pkt flags */
+static inline uint16_t
+i40e_rxd_status_to_pkt_flags(uint64_t qword)
+{
+	uint16_t flags;
+
+	/* Check if VLAN packet */
+	flags = (uint16_t)(qword & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) ?
+							PKT_RX_VLAN_PKT : 0);
+
+	/* Check if RSS_HASH */
+	flags |= (uint16_t)((((qword >> I40E_RX_DESC_STATUS_FLTSTAT_SHIFT) &
+					I40E_RX_DESC_FLTSTAT_RSS_HASH) ==
+			I40E_RX_DESC_FLTSTAT_RSS_HASH) ? PKT_RX_RSS_HASH : 0);
+
+	return flags;
+}
+
+static inline uint16_t
+i40e_rxd_error_to_pkt_flags(uint64_t qword)
+{
+	uint16_t flags = 0;
+	uint64_t error_bits = (qword >> I40E_RXD_QW1_ERROR_SHIFT);
+
+#define I40E_RX_ERR_BITS 0x3f
+	if (likely((error_bits & I40E_RX_ERR_BITS) == 0))
+		return flags;
+	/* If RXE bit set, all other status bits are meaningless */
+	if (unlikely(error_bits & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) {
+		flags |= PKT_RX_MAC_ERR;
+		return flags;
+	}
+
+	/* If RECIPE bit set, all other status indications should be ignored */
+	if (unlikely(error_bits & (1 << I40E_RX_DESC_ERROR_RECIPE_SHIFT))) {
+		flags |= PKT_RX_RECIP_ERR;
+		return flags;
+	}
+	if (unlikely(error_bits & (1 << I40E_RX_DESC_ERROR_HBO_SHIFT)))
+		flags |= PKT_RX_HBUF_OVERFLOW;
+	if (unlikely(error_bits & (1 << I40E_RX_DESC_ERROR_IPE_SHIFT)))
+		flags |= PKT_RX_IP_CKSUM_BAD;
+	if (unlikely(error_bits & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT)))
+		flags |= PKT_RX_L4_CKSUM_BAD;
+	if (unlikely(error_bits & (1 << I40E_RX_DESC_ERROR_EIPE_SHIFT)))
+		flags |= PKT_RX_EIP_CKSUM_BAD;
+	if (unlikely(error_bits & (1 << I40E_RX_DESC_ERROR_OVERSIZE_SHIFT)))
+		flags |= PKT_RX_OVERSIZE;
+
+	return flags;
+}
+
+/* Translate pkt types to pkt flags */
+static inline uint16_t
+i40e_rxd_ptype_to_pkt_flags(uint64_t qword)
+{
+	uint8_t ptype = (uint8_t)((qword & I40E_RXD_QW1_PTYPE_MASK) >>
+					I40E_RXD_QW1_PTYPE_SHIFT);
+	static const uint16_t ip_ptype_map[I40E_MAX_PKT_TYPE] = {
+		0, /* PTYPE 0 */
+		0, /* PTYPE 1 */
+		0, /* PTYPE 2 */
+		0, /* PTYPE 3 */
+		0, /* PTYPE 4 */
+		0, /* PTYPE 5 */
+		0, /* PTYPE 6 */
+		0, /* PTYPE 7 */
+		0, /* PTYPE 8 */
+		0, /* PTYPE 9 */
+		0, /* PTYPE 10 */
+		0, /* PTYPE 11 */
+		0, /* PTYPE 12 */
+		0, /* PTYPE 13 */
+		0, /* PTYPE 14 */
+		0, /* PTYPE 15 */
+		0, /* PTYPE 16 */
+		0, /* PTYPE 17 */
+		0, /* PTYPE 18 */
+		0, /* PTYPE 19 */
+		0, /* PTYPE 20 */
+		0, /* PTYPE 21 */
+		PKT_RX_IPV4_HDR, /* PTYPE 22 */
+		PKT_RX_IPV4_HDR, /* PTYPE 23 */
+		PKT_RX_IPV4_HDR, /* PTYPE 24 */
+		0, /* PTYPE 25 */
+		PKT_RX_IPV4_HDR, /* PTYPE 26 */
+		PKT_RX_IPV4_HDR, /* PTYPE 27 */
+		PKT_RX_IPV4_HDR, /* PTYPE 28 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 29 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 30 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 31 */
+		0, /* PTYPE 32 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 33 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 34 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 35 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 36 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 37 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 38 */
+		0, /* PTYPE 39 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 40 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 41 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 42 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 43 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 44 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 45 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 46 */
+		0, /* PTYPE 47 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 48 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 49 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 50 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 51 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 52 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 53 */
+		0, /* PTYPE 54 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 55 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 56 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 57 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 58 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 59 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 60 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 61 */
+		0, /* PTYPE 62 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 63 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 64 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 65 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 66 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 67 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 68 */
+		0, /* PTYPE 69 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 70 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 71 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 72 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 73 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 74 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 75 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 76 */
+		0, /* PTYPE 77 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 78 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 79 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 80 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 81 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 82 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 83 */
+		0, /* PTYPE 84 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 85 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 86 */
+		PKT_RX_IPV4_HDR_EXT, /* PTYPE 87 */
+		PKT_RX_IPV6_HDR, /* PTYPE 88 */
+		PKT_RX_IPV6_HDR, /* PTYPE 89 */
+		PKT_RX_IPV6_HDR, /* PTYPE 90 */
+		0, /* PTYPE 91 */
+		PKT_RX_IPV6_HDR, /* PTYPE 92 */
+		PKT_RX_IPV6_HDR, /* PTYPE 93 */
+		PKT_RX_IPV6_HDR, /* PTYPE 94 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 95 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 96 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 97 */
+		0, /* PTYPE 98 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 99 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 100 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 101 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 102 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 103 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 104 */
+		0, /* PTYPE 105 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 106 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 107 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 108 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 109 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 110 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 111 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 112 */
+		0, /* PTYPE 113 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 114 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 115 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 116 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 117 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 118 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 119 */
+		0, /* PTYPE 120 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 121 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 122 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 123 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 124 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 125 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 126 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 127 */
+		0, /* PTYPE 128 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 129 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 130 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 131 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 132 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 133 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 134 */
+		0, /* PTYPE 135 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 136 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 137 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 138 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 139 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 140 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 141 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 142 */
+		0, /* PTYPE 143 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 144 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 145 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 146 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 147 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 148 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 149 */
+		0, /* PTYPE 150 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 151 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 152 */
+		PKT_RX_IPV6_HDR_EXT, /* PTYPE 153 */
+		0, /* PTYPE 154 */
+		0, /* PTYPE 155 */
+		0, /* PTYPE 156 */
+		0, /* PTYPE 157 */
+		0, /* PTYPE 158 */
+		0, /* PTYPE 159 */
+		0, /* PTYPE 160 */
+		0, /* PTYPE 161 */
+		0, /* PTYPE 162 */
+		0, /* PTYPE 163 */
+		0, /* PTYPE 164 */
+		0, /* PTYPE 165 */
+		0, /* PTYPE 166 */
+		0, /* PTYPE 167 */
+		0, /* PTYPE 168 */
+		0, /* PTYPE 169 */
+		0, /* PTYPE 170 */
+		0, /* PTYPE 171 */
+		0, /* PTYPE 172 */
+		0, /* PTYPE 173 */
+		0, /* PTYPE 174 */
+		0, /* PTYPE 175 */
+		0, /* PTYPE 176 */
+		0, /* PTYPE 177 */
+		0, /* PTYPE 178 */
+		0, /* PTYPE 179 */
+		0, /* PTYPE 180 */
+		0, /* PTYPE 181 */
+		0, /* PTYPE 182 */
+		0, /* PTYPE 183 */
+		0, /* PTYPE 184 */
+		0, /* PTYPE 185 */
+		0, /* PTYPE 186 */
+		0, /* PTYPE 187 */
+		0, /* PTYPE 188 */
+		0, /* PTYPE 189 */
+		0, /* PTYPE 190 */
+		0, /* PTYPE 191 */
+		0, /* PTYPE 192 */
+		0, /* PTYPE 193 */
+		0, /* PTYPE 194 */
+		0, /* PTYPE 195 */
+		0, /* PTYPE 196 */
+		0, /* PTYPE 197 */
+		0, /* PTYPE 198 */
+		0, /* PTYPE 199 */
+		0, /* PTYPE 200 */
+		0, /* PTYPE 201 */
+		0, /* PTYPE 202 */
+		0, /* PTYPE 203 */
+		0, /* PTYPE 204 */
+		0, /* PTYPE 205 */
+		0, /* PTYPE 206 */
+		0, /* PTYPE 207 */
+		0, /* PTYPE 208 */
+		0, /* PTYPE 209 */
+		0, /* PTYPE 210 */
+		0, /* PTYPE 211 */
+		0, /* PTYPE 212 */
+		0, /* PTYPE 213 */
+		0, /* PTYPE 214 */
+		0, /* PTYPE 215 */
+		0, /* PTYPE 216 */
+		0, /* PTYPE 217 */
+		0, /* PTYPE 218 */
+		0, /* PTYPE 219 */
+		0, /* PTYPE 220 */
+		0, /* PTYPE 221 */
+		0, /* PTYPE 222 */
+		0, /* PTYPE 223 */
+		0, /* PTYPE 224 */
+		0, /* PTYPE 225 */
+		0, /* PTYPE 226 */
+		0, /* PTYPE 227 */
+		0, /* PTYPE 228 */
+		0, /* PTYPE 229 */
+		0, /* PTYPE 230 */
+		0, /* PTYPE 231 */
+		0, /* PTYPE 232 */
+		0, /* PTYPE 233 */
+		0, /* PTYPE 234 */
+		0, /* PTYPE 235 */
+		0, /* PTYPE 236 */
+		0, /* PTYPE 237 */
+		0, /* PTYPE 238 */
+		0, /* PTYPE 239 */
+		0, /* PTYPE 240 */
+		0, /* PTYPE 241 */
+		0, /* PTYPE 242 */
+		0, /* PTYPE 243 */
+		0, /* PTYPE 244 */
+		0, /* PTYPE 245 */
+		0, /* PTYPE 246 */
+		0, /* PTYPE 247 */
+		0, /* PTYPE 248 */
+		0, /* PTYPE 249 */
+		0, /* PTYPE 250 */
+		0, /* PTYPE 251 */
+		0, /* PTYPE 252 */
+		0, /* PTYPE 253 */
+		0, /* PTYPE 254 */
+		0, /* PTYPE 255 */
+	};
+
+	return ip_ptype_map[ptype];
+}
+
+static inline void
+i40e_txd_enable_checksum(uint32_t ol_flags,
+			uint32_t *td_cmd,
+			uint32_t *td_offset,
+			uint8_t l2_len,
+			uint8_t l3_len)
+{
+	if (!l2_len) {
+		PMD_DRV_LOG(DEBUG, "L2 length set to 0\n");
+		return;
+	}
+	*td_offset |= (l2_len >> 1) << I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
+
+	if (!l3_len) {
+		PMD_DRV_LOG(DEBUG, "L3 length set to 0\n");
+		return;
+	}
+
+	/* Enable L3 checksum offloads */
+	if (ol_flags & PKT_TX_IPV4_CSUM) {
+		*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM;
+		*td_offset |= (l3_len >> 2) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
+	} else if (ol_flags & PKT_TX_IPV4) {
+		*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
+		*td_offset |= (l3_len >> 2) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
+	} else if (ol_flags & PKT_TX_IPV6) {
+		*td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
+		*td_offset |= (l3_len >> 2) << I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
+	}
+
+	/* Enable L4 checksum offloads */
+	switch (ol_flags & PKT_TX_L4_MASK) {
+	case PKT_TX_TCP_CKSUM:
+		*td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
+		*td_offset |= (sizeof(struct tcp_hdr) >> 2) <<
+				I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+		break;
+	case PKT_TX_SCTP_CKSUM:
+		*td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP;
+		*td_offset |= (sizeof(struct sctp_hdr) >> 2) <<
+				I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+		break;
+	case PKT_TX_UDP_CKSUM:
+		*td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP;
+		*td_offset |= (sizeof(struct udp_hdr) >> 2) <<
+				I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+		break;
+	default:
+		break;
+	}
+}
+
+static inline struct rte_mbuf *
+rte_rxmbuf_alloc(struct rte_mempool *mp)
+{
+	struct rte_mbuf *m;
+
+	m = __rte_mbuf_raw_alloc(mp);
+	__rte_mbuf_sanity_check_raw(m, RTE_MBUF_PKT, 0);
+
+	return m;
+}
+
+/* Construct the tx flags */
+static inline uint64_t
+i40e_build_ctob(uint32_t td_cmd,
+		uint32_t td_offset,
+		unsigned int size,
+		uint32_t td_tag)
+{
+	return rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DATA |
+			((uint64_t)td_cmd  << I40E_TXD_QW1_CMD_SHIFT) |
+			((uint64_t)td_offset << I40E_TXD_QW1_OFFSET_SHIFT) |
+			((uint64_t)size  << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) |
+			((uint64_t)td_tag  << I40E_TXD_QW1_L2TAG1_SHIFT));
+}
+
+static inline int
+i40e_xmit_cleanup(struct i40e_tx_queue *txq)
+{
+	struct i40e_tx_entry *sw_ring = txq->sw_ring;
+	volatile struct i40e_tx_desc *txd = txq->tx_ring;
+	uint16_t last_desc_cleaned = txq->last_desc_cleaned;
+	uint16_t nb_tx_desc = txq->nb_tx_desc;
+	uint16_t desc_to_clean_to;
+	uint16_t nb_tx_to_clean;
+
+	desc_to_clean_to = (uint16_t)(last_desc_cleaned + txq->tx_rs_thresh);
+	if (desc_to_clean_to >= nb_tx_desc)
+		desc_to_clean_to = (uint16_t)(desc_to_clean_to - nb_tx_desc);
+
+	desc_to_clean_to = sw_ring[desc_to_clean_to].last_id;
+	if (!(txd[desc_to_clean_to].cmd_type_offset_bsz &
+		rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE))) {
+		PMD_TX_FREE_LOG(DEBUG, "TX descriptor %4u is not done "
+			"(port=%d queue=%d)", desc_to_clean_to,
+				txq->port_id, txq->queue_id);
+		return -1;
+	}
+
+	if (last_desc_cleaned > desc_to_clean_to)
+		nb_tx_to_clean = (uint16_t)((nb_tx_desc - last_desc_cleaned) +
+							desc_to_clean_to);
+	else
+		nb_tx_to_clean = (uint16_t)(desc_to_clean_to -
+					last_desc_cleaned);
+
+	txd[desc_to_clean_to].cmd_type_offset_bsz = 0;
+
+	txq->last_desc_cleaned = desc_to_clean_to;
+	txq->nb_tx_free = (uint16_t)(txq->nb_tx_free + nb_tx_to_clean);
+
+	return 0;
+}
+
+static inline int
+#ifdef RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC
+check_rx_burst_bulk_alloc_preconditions(struct i40e_rx_queue *rxq)
+#else
+check_rx_burst_bulk_alloc_preconditions(__rte_unused struct i40e_rx_queue *rxq)
+#endif
+{
+	int ret = 0;
+
+#ifdef RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC
+	if (!(rxq->rx_free_thresh >= RTE_PMD_I40E_RX_MAX_BURST))
+		ret = -EINVAL;
+	else if (!(rxq->rx_free_thresh < rxq->nb_rx_desc))
+		ret = -EINVAL;
+	else if (!(rxq->nb_rx_desc % rxq->rx_free_thresh) == 0)
+		ret = -EINVAL;
+	else if (!(rxq->nb_rx_desc < (I40E_MAX_RING_DESC -
+				RTE_PMD_I40E_RX_MAX_BURST)))
+		ret = -EINVAL;
+#else
+	ret = -EINVAL;
+#endif
+
+	return ret;
+}
+
+#ifdef RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC
+#define I40E_LOOK_AHEAD 8
+#if (I40E_LOOK_AHEAD != 8)
+#error "PMD I40E: I40E_LOOK_AHEAD must be 8\n"
+#endif
+static inline int
+i40e_rx_scan_hw_ring(struct i40e_rx_queue *rxq)
+{
+	volatile union i40e_rx_desc *rxdp;
+	struct i40e_rx_entry *rxep;
+	struct rte_mbuf *mb;
+	uint16_t pkt_len;
+	uint64_t qword1;
+	uint32_t rx_status;
+	int32_t s[I40E_LOOK_AHEAD], nb_dd;
+	int32_t i, j, nb_rx = 0;
+	uint16_t pkt_flags;
+
+	rxdp = &rxq->rx_ring[rxq->rx_tail];
+	rxep = &rxq->sw_ring[rxq->rx_tail];
+
+	qword1 = rte_le_to_cpu_64(rxdp->wb.qword1.status_error_len);
+	rx_status = (qword1 & I40E_RXD_QW1_STATUS_MASK) >>
+				I40E_RXD_QW1_STATUS_SHIFT;
+
+	/* Make sure there is at least 1 packet to receive */
+	if (!(rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)))
+		return 0;
+
+	/**
+	 * Scan LOOK_AHEAD descriptors at a time to determine which
+	 * descriptors reference packets that are ready to be received.
+	 */
+	for (i = 0; i < RTE_PMD_I40E_RX_MAX_BURST; i+=I40E_LOOK_AHEAD,
+			rxdp += I40E_LOOK_AHEAD, rxep += I40E_LOOK_AHEAD) {
+		/* Read desc statuses backwards to avoid race condition */
+		for (j = I40E_LOOK_AHEAD - 1; j >= 0; j--) {
+			qword1 = rte_le_to_cpu_64(\
+				rxdp[j].wb.qword1.status_error_len);
+			s[j] = (qword1 & I40E_RXD_QW1_STATUS_MASK) >>
+					I40E_RXD_QW1_STATUS_SHIFT;
+		}
+
+		/* Compute how many status bits were set */
+		for (j = 0, nb_dd = 0; j < I40E_LOOK_AHEAD; j++)
+			nb_dd += s[j] & (1 << I40E_RX_DESC_STATUS_DD_SHIFT);
+
+		nb_rx += nb_dd;
+
+		/* Translate descriptor info to mbuf parameters */
+		for (j = 0; j < nb_dd; j++) {
+			mb = rxep[j].mbuf;
+			qword1 = rte_le_to_cpu_64(\
+				rxdp[j].wb.qword1.status_error_len);
+			rx_status = (qword1 & I40E_RXD_QW1_STATUS_MASK) >>
+						I40E_RXD_QW1_STATUS_SHIFT;
+			pkt_len = ((qword1 & I40E_RXD_QW1_LENGTH_PBUF_MASK) >>
+				I40E_RXD_QW1_LENGTH_PBUF_SHIFT) - rxq->crc_len;
+			mb->pkt.data_len = pkt_len;
+			mb->pkt.pkt_len = pkt_len;
+			mb->pkt.vlan_macip.f.vlan_tci = rx_status &
+				(1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) ?
+			rte_le_to_cpu_16(\
+				rxdp[j].wb.qword0.lo_dword.l2tag1) : 0;
+			pkt_flags = i40e_rxd_status_to_pkt_flags(qword1);
+			pkt_flags |= i40e_rxd_error_to_pkt_flags(qword1);
+			pkt_flags |= i40e_rxd_ptype_to_pkt_flags(qword1);
+			mb->ol_flags = pkt_flags;
+			if (pkt_flags & PKT_RX_RSS_HASH)
+				mb->pkt.hash.rss = rte_le_to_cpu_32(\
+					rxdp->wb.qword0.hi_dword.rss);
+		}
+
+		for (j = 0; j < I40E_LOOK_AHEAD; j++)
+			rxq->rx_stage[i + j] = rxep[j].mbuf;
+
+		if (nb_dd != I40E_LOOK_AHEAD)
+			break;
+	}
+
+	/* Clear software ring entries */
+	for (i = 0; i < nb_rx; i++)
+		rxq->sw_ring[rxq->rx_tail + i].mbuf = NULL;
+
+	return nb_rx;
+}
+
+static inline uint16_t
+i40e_rx_fill_from_stage(struct i40e_rx_queue *rxq,
+			struct rte_mbuf **rx_pkts,
+			uint16_t nb_pkts)
+{
+	uint16_t i;
+	struct rte_mbuf **stage = &rxq->rx_stage[rxq->rx_next_avail];
+
+	nb_pkts = (uint16_t)RTE_MIN(nb_pkts, rxq->rx_nb_avail);
+
+	for (i = 0; i < nb_pkts; i++)
+		rx_pkts[i] = stage[i];
+
+	rxq->rx_nb_avail = (uint16_t)(rxq->rx_nb_avail - nb_pkts);
+	rxq->rx_next_avail = (uint16_t)(rxq->rx_next_avail + nb_pkts);
+
+	return nb_pkts;
+}
+
+static inline int
+i40e_rx_alloc_bufs(struct i40e_rx_queue *rxq)
+{
+	volatile union i40e_rx_desc *rxdp;
+	struct i40e_rx_entry *rxep;
+	struct rte_mbuf *mb;
+	uint16_t alloc_idx, i;
+	uint64_t dma_addr;
+	int diag;
+
+	/* Allocate buffers in bulk */
+	alloc_idx = (uint16_t)(rxq->rx_free_trigger -
+				(rxq->rx_free_thresh - 1));
+	rxep = &(rxq->sw_ring[alloc_idx]);
+	diag = rte_mempool_get_bulk(rxq->mp, (void *)rxep,
+					rxq->rx_free_thresh);
+	if (unlikely(diag != 0)) {
+		PMD_DRV_LOG(ERR, "Failed to get mbufs in bulk\n");
+		return -ENOMEM;
+	}
+
+	rxdp = &rxq->rx_ring[alloc_idx];
+	for (i = 0; i < rxq->rx_free_thresh; i++) {
+		mb = rxep[i].mbuf;
+		rte_mbuf_refcnt_set(mb, 1);
+		mb->type = RTE_MBUF_PKT;
+		mb->pkt.next = NULL;
+		mb->pkt.data = (char *)mb->buf_addr + RTE_PKTMBUF_HEADROOM;
+		mb->pkt.nb_segs = 1;
+		mb->pkt.in_port = rxq->port_id;
+		dma_addr = rte_cpu_to_le_64(\
+			RTE_MBUF_DATA_DMA_ADDR_DEFAULT(mb));
+		rxdp[i].read.hdr_addr = dma_addr;
+		rxdp[i].read.pkt_addr = dma_addr;
+	}
+
+	/* Update rx tail regsiter */
+	rte_wmb();
+	I40E_PCI_REG_WRITE(rxq->qrx_tail, rxq->rx_free_trigger);
+
+	rxq->rx_free_trigger =
+		(uint16_t)(rxq->rx_free_trigger + rxq->rx_free_thresh);
+	if (rxq->rx_free_trigger >= rxq->nb_rx_desc)
+		rxq->rx_free_trigger = (uint16_t)(rxq->rx_free_thresh - 1);
+
+	return 0;
+}
+
+static inline uint16_t
+rx_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+	struct i40e_rx_queue *rxq = (struct i40e_rx_queue *)rx_queue;
+	uint16_t nb_rx = 0;
+
+	if (!nb_pkts)
+		return 0;
+
+	if (rxq->rx_nb_avail)
+		return i40e_rx_fill_from_stage(rxq, rx_pkts, nb_pkts);
+
+	nb_rx = (uint16_t)i40e_rx_scan_hw_ring(rxq);
+	rxq->rx_next_avail = 0;
+	rxq->rx_nb_avail = nb_rx;
+	rxq->rx_tail = (uint16_t)(rxq->rx_tail + nb_rx);
+
+	if (rxq->rx_tail > rxq->rx_free_trigger) {
+		if (i40e_rx_alloc_bufs(rxq) != 0) {
+			uint16_t i, j;
+
+			PMD_RX_LOG(DEBUG, "Rx mbuf alloc failed for "
+					"port_id=%u, queue_id=%u\n",
+					rxq->port_id, rxq->queue_id);
+			rxq->rx_nb_avail = 0;
+			rxq->rx_tail = (uint16_t)(rxq->rx_tail - nb_rx);
+			for (i = 0, j = rxq->rx_tail; i < nb_rx; i++, j++)
+				rxq->sw_ring[j].mbuf = rxq->rx_stage[i];
+
+			return 0;
+		}
+	}
+
+	if (rxq->rx_tail >= rxq->nb_rx_desc)
+		rxq->rx_tail = 0;
+
+	if (rxq->rx_nb_avail)
+		return i40e_rx_fill_from_stage(rxq, rx_pkts, nb_pkts);
+
+	return 0;
+}
+
+static uint16_t
+i40e_recv_pkts_bulk_alloc(void *rx_queue,
+			  struct rte_mbuf **rx_pkts,
+			  uint16_t nb_pkts)
+{
+	uint16_t nb_rx = 0, n, count;
+
+	if (unlikely(nb_pkts == 0))
+		return 0;
+
+	if (likely(nb_pkts <= RTE_PMD_I40E_RX_MAX_BURST))
+		return rx_recv_pkts(rx_queue, rx_pkts, nb_pkts);
+
+	while (nb_pkts) {
+		n = RTE_MIN(nb_pkts, RTE_PMD_I40E_RX_MAX_BURST);
+		count = rx_recv_pkts(rx_queue, &rx_pkts[nb_rx], n);
+		nb_rx = (uint16_t)(nb_rx + count);
+		nb_pkts = (uint16_t)(nb_pkts - count);
+		if (count < n)
+			break;
+	}
+
+	return nb_rx;
+}
+#endif /* RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC */
+
+uint16_t
+i40e_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+	struct i40e_rx_queue *rxq;
+	volatile union i40e_rx_desc *rx_ring;
+	volatile union i40e_rx_desc *rxdp;
+	union i40e_rx_desc rxd;
+	struct i40e_rx_entry *sw_ring;
+	struct i40e_rx_entry *rxe;
+	struct rte_mbuf *rxm;
+	struct rte_mbuf *nmb;
+	uint16_t nb_rx;
+	uint32_t rx_status;
+	uint64_t qword1;
+	uint16_t rx_packet_len;
+	uint16_t rx_id, nb_hold;
+	uint64_t dma_addr;
+	uint16_t pkt_flags;
+
+	nb_rx = 0;
+	nb_hold = 0;
+	rxq = rx_queue;
+	rx_id = rxq->rx_tail;
+	rx_ring = rxq->rx_ring;
+	sw_ring = rxq->sw_ring;
+
+	while (nb_rx < nb_pkts) {
+		rxdp = &rx_ring[rx_id];
+		qword1 = rte_le_to_cpu_64(rxdp->wb.qword1.status_error_len);
+		rx_status = (qword1 & I40E_RXD_QW1_STATUS_MASK)
+				>> I40E_RXD_QW1_STATUS_SHIFT;
+		/* Check the DD bit first */
+		if (!(rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)))
+			break;
+
+		nmb = rte_rxmbuf_alloc(rxq->mp);
+		if (unlikely(!nmb))
+			break;
+		rxd = *rxdp;
+
+		nb_hold++;
+		rxe = &sw_ring[rx_id];
+		rx_id++;
+		if (unlikely(rx_id == rxq->nb_rx_desc))
+			rx_id = 0;
+
+		/* Prefetch next mbuf */
+		rte_prefetch0(sw_ring[rx_id].mbuf);
+
+		/**
+		 * When next RX descriptor is on a cache line boundary,
+		 * prefetch the next 4 RX descriptors and next 8 pointers
+		 * to mbufs.
+		 */
+		if ((rx_id & 0x3) == 0) {
+			rte_prefetch0(&rx_ring[rx_id]);
+			rte_prefetch0(&sw_ring[rx_id]);
+		}
+		rxm = rxe->mbuf;
+		rxe->mbuf = nmb;
+		dma_addr =
+			rte_cpu_to_le_64(RTE_MBUF_DATA_DMA_ADDR_DEFAULT(nmb));
+		rxdp->read.hdr_addr = dma_addr;
+		rxdp->read.pkt_addr = dma_addr;
+
+		rx_packet_len = ((qword1 & I40E_RXD_QW1_LENGTH_PBUF_MASK) >>
+				I40E_RXD_QW1_LENGTH_PBUF_SHIFT) - rxq->crc_len;
+
+		rxm->pkt.data = (char *)rxm->buf_addr + RTE_PKTMBUF_HEADROOM;
+		rte_prefetch0(rxm->pkt.data);
+		rxm->pkt.nb_segs = 1;
+		rxm->pkt.next = NULL;
+		rxm->pkt.pkt_len = rx_packet_len;
+		rxm->pkt.data_len = rx_packet_len;
+		rxm->pkt.in_port = rxq->port_id;
+
+		rxm->pkt.vlan_macip.f.vlan_tci = rx_status &
+			(1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) ?
+			rte_le_to_cpu_16(rxd.wb.qword0.lo_dword.l2tag1) : 0;
+		pkt_flags = i40e_rxd_status_to_pkt_flags(qword1);
+		pkt_flags |= i40e_rxd_error_to_pkt_flags(qword1);
+		pkt_flags |= i40e_rxd_ptype_to_pkt_flags(qword1);
+		rxm->ol_flags = pkt_flags;
+		if (pkt_flags & PKT_RX_RSS_HASH)
+			rxm->pkt.hash.rss =
+				rte_le_to_cpu_32(rxdp->wb.qword0.hi_dword.rss);
+
+		rx_pkts[nb_rx++] = rxm;
+	}
+	rxq->rx_tail = rx_id;
+
+	/**
+	 * If the number of free RX descriptors is greater than the RX free
+	 * threshold of the queue, advance the receive tail register of queue.
+	 * Update that register with the value of the last processed RX
+	 * descriptor minus 1.
+	 */
+	nb_hold = (uint16_t)(nb_hold + rxq->nb_rx_hold);
+	if (nb_hold > rxq->rx_free_thresh) {
+		rx_id = (uint16_t) ((rx_id == 0) ?
+			(rxq->nb_rx_desc - 1) : (rx_id - 1));
+		I40E_PCI_REG_WRITE(rxq->qrx_tail, rx_id);
+		nb_hold = 0;
+	}
+	rxq->nb_rx_hold = nb_hold;
+
+	return nb_rx;
+}
+
+uint16_t
+i40e_recv_scattered_pkts(void *rx_queue,
+			 struct rte_mbuf **rx_pkts,
+			 uint16_t nb_pkts)
+{
+	struct i40e_rx_queue *rxq = rx_queue;
+	volatile union i40e_rx_desc *rx_ring = rxq->rx_ring;
+	volatile union i40e_rx_desc *rxdp;
+	union i40e_rx_desc rxd;
+	struct i40e_rx_entry *sw_ring = rxq->sw_ring;
+	struct i40e_rx_entry *rxe;
+	struct rte_mbuf *first_seg = rxq->pkt_first_seg;
+	struct rte_mbuf *last_seg = rxq->pkt_last_seg;
+	struct rte_mbuf *nmb, *rxm;
+	uint16_t rx_id = rxq->rx_tail;
+	uint16_t nb_rx = 0, nb_hold = 0, rx_packet_len, pkt_flags;
+	uint32_t rx_status;
+	uint64_t qword1;
+	uint64_t dma_addr;
+
+	while (nb_rx < nb_pkts) {
+		rxdp = &rx_ring[rx_id];
+		qword1 = rte_le_to_cpu_64(rxdp->wb.qword1.status_error_len);
+		rx_status = (qword1 & I40E_RXD_QW1_STATUS_MASK) >>
+					I40E_RXD_QW1_STATUS_SHIFT;
+		/* Check the DD bit */
+		if (!(rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)))
+			break;
+
+		nmb = rte_rxmbuf_alloc(rxq->mp);
+		if (unlikely(!nmb))
+			break;
+		rxd = *rxdp;
+		nb_hold++;
+		rxe = &sw_ring[rx_id];
+		rx_id++;
+		if (rx_id == rxq->nb_rx_desc)
+			rx_id = 0;
+
+		/* Prefetch next mbuf */
+		rte_prefetch0(sw_ring[rx_id].mbuf);
+
+		/**
+		 * When next RX descriptor is on a cache line boundary,
+		 * prefetch the next 4 RX descriptors and next 8 pointers
+		 * to mbufs.
+		 */
+		if ((rx_id & 0x3) == 0) {
+			rte_prefetch0(&rx_ring[rx_id]);
+			rte_prefetch0(&sw_ring[rx_id]);
+		}
+
+		rxm = rxe->mbuf;
+		rxe->mbuf = nmb;
+		dma_addr =
+			rte_cpu_to_le_64(RTE_MBUF_DATA_DMA_ADDR_DEFAULT(nmb));
+
+		/* Set data buffer address and data length of the mbuf */
+		rxdp->read.hdr_addr = dma_addr;
+		rxdp->read.pkt_addr = dma_addr;
+		rx_packet_len = (qword1 & I40E_RXD_QW1_LENGTH_PBUF_MASK) >>
+					I40E_RXD_QW1_LENGTH_PBUF_SHIFT;
+		rxm->pkt.data_len = rx_packet_len;
+		rxm->pkt.data = (char *)rxm->buf_addr + RTE_PKTMBUF_HEADROOM;
+
+		/**
+		 * If this is the first buffer of the received packet, set the
+		 * pointer to the first mbuf of the packet and initialize its
+		 * context. Otherwise, update the total length and the number
+		 * of segments of the current scattered packet, and update the
+		 * pointer to the last mbuf of the current packet.
+		 */
+		if (!first_seg) {
+			first_seg = rxm;
+			first_seg->pkt.nb_segs = 1;
+			first_seg->pkt.pkt_len = rx_packet_len;
+		} else {
+			first_seg->pkt.pkt_len =
+				(uint16_t)(first_seg->pkt.pkt_len +
+						rx_packet_len);
+			first_seg->pkt.nb_segs++;
+			last_seg->pkt.next = rxm;
+		}
+
+		/**
+		 * If this is not the last buffer of the received packet,
+		 * update the pointer to the last mbuf of the current scattered
+		 * packet and continue to parse the RX ring.
+		 */
+		if (!(rx_status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT))) {
+			last_seg = rxm;
+			continue;
+		}
+
+		/**
+		 * This is the last buffer of the received packet. If the CRC
+		 * is not stripped by the hardware:
+		 *  - Subtract the CRC length from the total packet length.
+		 *  - If the last buffer only contains the whole CRC or a part
+		 *  of it, free the mbuf associated to the last buffer. If part
+		 *  of the CRC is also contained in the previous mbuf, subtract
+		 *  the length of that CRC part from the data length of the
+		 *  previous mbuf.
+		 */
+		rxm->pkt.next = NULL;
+		if (unlikely(rxq->crc_len > 0)) {
+			first_seg->pkt.pkt_len -= ETHER_CRC_LEN;
+			if (rx_packet_len <= ETHER_CRC_LEN) {
+				rte_pktmbuf_free_seg(rxm);
+				first_seg->pkt.nb_segs--;
+				last_seg->pkt.data_len =
+					(uint16_t)(last_seg->pkt.data_len -
+					(ETHER_CRC_LEN - rx_packet_len));
+				last_seg->pkt.next = NULL;
+			} else
+				rxm->pkt.data_len = (uint16_t)(rx_packet_len -
+								ETHER_CRC_LEN);
+		}
+
+		first_seg->pkt.in_port = rxq->port_id;
+		first_seg->pkt.vlan_macip.f.vlan_tci = (rx_status &
+			(1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)) ?
+			rte_le_to_cpu_16(rxd.wb.qword0.lo_dword.l2tag1) : 0;
+		pkt_flags = i40e_rxd_status_to_pkt_flags(qword1);
+		pkt_flags |= i40e_rxd_error_to_pkt_flags(qword1);
+		pkt_flags |= i40e_rxd_ptype_to_pkt_flags(qword1);
+		first_seg->ol_flags = pkt_flags;
+		if (pkt_flags & PKT_RX_RSS_HASH)
+			rxm->pkt.hash.rss =
+				rte_le_to_cpu_32(rxdp->wb.qword0.hi_dword.rss);
+
+		/* Prefetch data of first segment, if configured to do so. */
+		rte_prefetch0(first_seg->pkt.data);
+		rx_pkts[nb_rx++] = first_seg;
+		first_seg = NULL;
+	}
+
+	/* Record index of the next RX descriptor to probe. */
+	rxq->rx_tail = rx_id;
+	rxq->pkt_first_seg = first_seg;
+	rxq->pkt_last_seg = last_seg;
+
+	/**
+	 * If the number of free RX descriptors is greater than the RX free
+	 * threshold of the queue, advance the Receive Descriptor Tail (RDT)
+	 * register. Update the RDT with the value of the last processed RX
+	 * descriptor minus 1, to guarantee that the RDT register is never
+	 * equal to the RDH register, which creates a "full" ring situtation
+	 * from the hardware point of view.
+	 */
+	nb_hold = (uint16_t)(nb_hold + rxq->nb_rx_hold);
+	if (nb_hold > rxq->rx_free_thresh) {
+		rx_id = (uint16_t)(rx_id == 0 ?
+			(rxq->nb_rx_desc - 1) : (rx_id - 1));
+		I40E_PCI_REG_WRITE(rxq->qrx_tail, rx_id);
+		nb_hold = 0;
+	}
+	rxq->nb_rx_hold = nb_hold;
+
+	return nb_rx;
+}
+
+/* Check if the context descriptor is needed for TX offloading */
+static inline uint16_t
+i40e_calc_context_desc(uint16_t flags)
+{
+	uint16_t mask = 0;
+
+#ifdef RTE_LIBRTE_IEEE1588
+	mask |= PKT_TX_IEEE1588_TMST;
+#endif
+	if (flags & mask)
+		return 1;
+
+	return 0;
+}
+
+uint16_t
+i40e_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+	struct i40e_tx_queue *txq;
+	struct i40e_tx_entry *sw_ring;
+	struct i40e_tx_entry *txe, *txn;
+	volatile struct i40e_tx_desc *txd;
+	volatile struct i40e_tx_desc *txr;
+	struct rte_mbuf *tx_pkt;
+	struct rte_mbuf *m_seg;
+	uint16_t tx_id;
+	uint16_t nb_tx;
+	uint32_t td_cmd;
+	uint32_t td_offset;
+	uint32_t tx_flags;
+	uint32_t td_tag;
+	uint16_t ol_flags;
+	uint8_t l2_len;
+	uint8_t l3_len;
+	uint16_t nb_used;
+	uint16_t nb_ctx;
+	uint16_t tx_last;
+	uint16_t slen;
+	uint64_t buf_dma_addr;
+
+	txq = tx_queue;
+	sw_ring = txq->sw_ring;
+	txr = txq->tx_ring;
+	tx_id = txq->tx_tail;
+	txe = &sw_ring[tx_id];
+
+	/* Check if the descriptor ring needs to be cleaned. */
+	if ((txq->nb_tx_desc - txq->nb_tx_free) > txq->tx_free_thresh)
+		i40e_xmit_cleanup(txq);
+
+	for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
+		td_cmd = 0;
+		td_tag = 0;
+		td_offset = 0;
+		tx_flags = 0;
+
+		tx_pkt = *tx_pkts++;
+		RTE_MBUF_PREFETCH_TO_FREE(txe->mbuf);
+
+		ol_flags = tx_pkt->ol_flags;
+		l2_len = tx_pkt->pkt.vlan_macip.f.l2_len;
+		l3_len = tx_pkt->pkt.vlan_macip.f.l3_len;
+
+		/* Calculate the number of context descriptors needed. */
+		nb_ctx = i40e_calc_context_desc(ol_flags);
+
+		/**
+		 * The number of descriptors that must be allocated for
+		 * a packet equals to the number of the segments of that
+		 * packet plus 1 context descriptor if needed.
+		 */
+		nb_used = (uint16_t)(tx_pkt->pkt.nb_segs + nb_ctx);
+		tx_last = (uint16_t)(tx_id + nb_used - 1);
+
+		/* Circular ring */
+		if (tx_last >= txq->nb_tx_desc)
+			tx_last = (uint16_t)(tx_last - txq->nb_tx_desc);
+
+		if (nb_used > txq->nb_tx_free) {
+			if (i40e_xmit_cleanup(txq) != 0) {
+				if (nb_tx == 0)
+					return 0;
+				goto end_of_tx;
+			}
+			if (unlikely(nb_used > txq->tx_rs_thresh)) {
+				while (nb_used > txq->nb_tx_free) {
+					if (i40e_xmit_cleanup(txq) != 0) {
+						if (nb_tx == 0)
+							return 0;
+						goto end_of_tx;
+					}
+				}
+			}
+		}
+
+		/* Descriptor based VLAN insertion */
+		if (ol_flags & PKT_TX_VLAN_PKT) {
+			tx_flags |= tx_pkt->pkt.vlan_macip.f.vlan_tci <<
+						I40E_TX_FLAG_L2TAG1_SHIFT;
+			tx_flags |= I40E_TX_FLAG_INSERT_VLAN;
+			td_cmd |= I40E_TX_DESC_CMD_IL2TAG1;
+			td_tag = (tx_flags & I40E_TX_FLAG_L2TAG1_MASK) >>
+						I40E_TX_FLAG_L2TAG1_SHIFT;
+		}
+
+		/* Always enable CRC offload insertion */
+		td_cmd |= I40E_TX_DESC_CMD_ICRC;
+
+		/* Enable checksum offloading */
+		i40e_txd_enable_checksum(ol_flags, &td_cmd, &td_offset,
+							l2_len, l3_len);
+
+		if (unlikely(nb_ctx)) {
+			/* Setup TX context descriptor if required */
+			volatile struct i40e_tx_context_desc *ctx_txd =
+				(volatile struct i40e_tx_context_desc *)\
+							&txr[tx_id];
+			uint32_t cd_tunneling_params = 0;
+			uint16_t cd_l2tag2 = 0;
+			uint64_t cd_type_cmd_tso_mss =
+				I40E_TX_DESC_DTYPE_CONTEXT;
+
+			txn = &sw_ring[txe->next_id];
+			RTE_MBUF_PREFETCH_TO_FREE(txn->mbuf);
+			if (txe->mbuf != NULL) {
+				rte_pktmbuf_free_seg(txe->mbuf);
+				txe->mbuf = NULL;
+			}
+#ifdef RTE_LIBRTE_IEEE1588
+			if (ol_flags & PKT_TX_IEEE1588_TMST)
+				cd_type_cmd_tso_mss |=
+					((uint64_t)I40E_TX_CTX_DESC_TSYN <<
+						I40E_TXD_CTX_QW1_CMD_SHIFT);
+#endif
+			ctx_txd->tunneling_params =
+				rte_cpu_to_le_32(cd_tunneling_params);
+			ctx_txd->l2tag2 = rte_cpu_to_le_16(cd_l2tag2);
+			ctx_txd->type_cmd_tso_mss =
+				rte_cpu_to_le_64(cd_type_cmd_tso_mss);
+			txe->last_id = tx_last;
+			tx_id = txe->next_id;
+			txe = txn;
+		}
+
+		m_seg = tx_pkt;
+		do {
+			txd = &txr[tx_id];
+			txn = &sw_ring[txe->next_id];
+
+			if (txe->mbuf)
+				rte_pktmbuf_free_seg(txe->mbuf);
+			txe->mbuf = m_seg;
+
+			/* Setup TX Descriptor */
+			slen = m_seg->pkt.data_len;
+			buf_dma_addr = RTE_MBUF_DATA_DMA_ADDR(m_seg);
+			txd->buffer_addr = rte_cpu_to_le_64(buf_dma_addr);
+			txd->cmd_type_offset_bsz = i40e_build_ctob(td_cmd,
+						td_offset, slen, td_tag);
+			txe->last_id = tx_last;
+			tx_id = txe->next_id;
+			txe = txn;
+			m_seg = m_seg->pkt.next;
+		} while (m_seg != NULL);
+
+		/* The last packet data descriptor needs End Of Packet (EOP) */
+		td_cmd |= I40E_TX_DESC_CMD_EOP;
+		txq->nb_tx_used = (uint16_t)(txq->nb_tx_used + nb_used);
+		txq->nb_tx_free = (uint16_t)(txq->nb_tx_free - nb_used);
+
+		if (txq->nb_tx_used >= txq->tx_rs_thresh) {
+			PMD_TX_FREE_LOG(DEBUG,
+					"Setting RS bit on TXD id="
+					"%4u (port=%d queue=%d)",
+					tx_last, txq->port_id, txq->queue_id);
+
+			td_cmd |= I40E_TX_DESC_CMD_RS;
+
+			/* Update txq RS bit counters */
+			txq->nb_tx_used = 0;
+		}
+
+		txd->cmd_type_offset_bsz |=
+			rte_cpu_to_le_64(((uint64_t)td_cmd) <<
+					I40E_TXD_QW1_CMD_SHIFT);
+	}
+
+end_of_tx:
+	rte_wmb();
+
+	PMD_TX_LOG(DEBUG, "port_id=%u queue_id=%u tx_tail=%u nb_tx=%u",
+		   (unsigned) txq->port_id, (unsigned) txq->queue_id,
+		   (unsigned) tx_id, (unsigned) nb_tx);
+
+	I40E_PCI_REG_WRITE(txq->qtx_tail, tx_id);
+	txq->tx_tail = tx_id;
+
+	return nb_tx;
+}
+
+static inline int __attribute__((always_inline))
+i40e_tx_free_bufs(struct i40e_tx_queue *txq)
+{
+	struct i40e_tx_entry *txep;
+	uint16_t i;
+
+	if (!(txq->tx_ring[txq->tx_next_dd].cmd_type_offset_bsz &
+			rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE)))
+		return 0;
+
+	txep = &(txq->sw_ring[txq->tx_next_dd - (txq->tx_rs_thresh - 1)]);
+
+	for (i = 0; i < txq->tx_rs_thresh; i++)
+		rte_prefetch0((txep + i)->mbuf);
+
+	if (!(txq->txq_flags & (uint32_t)ETH_TXQ_FLAGS_NOREFCOUNT)) {
+		for (i = 0; i < txq->tx_rs_thresh; ++i, ++txep) {
+			rte_mempool_put(txep->mbuf->pool, txep->mbuf);
+			txep->mbuf = NULL;
+		}
+	} else {
+		for (i = 0; i < txq->tx_rs_thresh; ++i, ++txep) {
+			rte_pktmbuf_free_seg(txep->mbuf);
+			txep->mbuf = NULL;
+		}
+	}
+
+	txq->nb_tx_free = (uint16_t)(txq->nb_tx_free + txq->tx_rs_thresh);
+	txq->tx_next_dd = (uint16_t)(txq->tx_next_dd + txq->tx_rs_thresh);
+	if (txq->tx_next_dd >= txq->nb_tx_desc)
+		txq->tx_next_dd = (uint16_t)(txq->tx_rs_thresh - 1);
+
+	return txq->tx_rs_thresh;
+}
+
+#define I40E_TD_CMD (I40E_TX_DESC_CMD_ICRC |\
+		     I40E_TX_DESC_CMD_EOP)
+
+/* Populate 4 descriptors with data from 4 mbufs */
+static inline void
+tx4(volatile struct i40e_tx_desc *txdp, struct rte_mbuf **pkts)
+{
+	uint64_t dma_addr;
+	uint32_t i;
+
+	for (i = 0; i < 4; i++, txdp++, pkts++) {
+		dma_addr = RTE_MBUF_DATA_DMA_ADDR(*pkts);
+		txdp->buffer_addr = rte_cpu_to_le_64(dma_addr);
+		txdp->cmd_type_offset_bsz =
+			i40e_build_ctob((uint32_t)I40E_TD_CMD, 0,
+					(*pkts)->pkt.data_len, 0);
+	}
+}
+
+/* Populate 1 descriptor with data from 1 mbuf */
+static inline void
+tx1(volatile struct i40e_tx_desc *txdp, struct rte_mbuf **pkts)
+{
+	uint64_t dma_addr;
+
+	dma_addr = RTE_MBUF_DATA_DMA_ADDR(*pkts);
+	txdp->buffer_addr = rte_cpu_to_le_64(dma_addr);
+	txdp->cmd_type_offset_bsz =
+		i40e_build_ctob((uint32_t)I40E_TD_CMD, 0,
+				(*pkts)->pkt.data_len, 0);
+}
+
+/* Fill hardware descriptor ring with mbuf data */
+static inline void
+i40e_tx_fill_hw_ring(struct i40e_tx_queue *txq,
+		     struct rte_mbuf **pkts,
+		     uint16_t nb_pkts)
+{
+	volatile struct i40e_tx_desc *txdp = &(txq->tx_ring[txq->tx_tail]);
+	struct i40e_tx_entry *txep = &(txq->sw_ring[txq->tx_tail]);
+	const int N_PER_LOOP = 4;
+	const int N_PER_LOOP_MASK = N_PER_LOOP - 1;
+	int mainpart, leftover;
+	int i, j;
+
+	mainpart = (nb_pkts & ((uint32_t) ~N_PER_LOOP_MASK));
+	leftover = (nb_pkts & ((uint32_t)  N_PER_LOOP_MASK));
+	for (i = 0; i < mainpart; i += N_PER_LOOP) {
+		for (j = 0; j < N_PER_LOOP; ++j) {
+			(txep + i + j)->mbuf = *(pkts + i + j);
+		}
+		tx4(txdp + i, pkts + i);
+	}
+	if (unlikely(leftover > 0)) {
+		for (i = 0; i < leftover; ++i) {
+			(txep + mainpart + i)->mbuf = *(pkts + mainpart + i);
+			tx1(txdp + mainpart + i, pkts + mainpart + i);
+		}
+	}
+}
+
+static inline uint16_t
+tx_xmit_pkts(struct i40e_tx_queue *txq,
+	     struct rte_mbuf **tx_pkts,
+	     uint16_t nb_pkts)
+{
+	volatile struct i40e_tx_desc *txr = txq->tx_ring;
+	uint16_t n = 0;
+
+	/**
+	 * Begin scanning the H/W ring for done descriptors when the number
+	 * of available descriptors drops below tx_free_thresh. For each done
+	 * descriptor, free the associated buffer.
+	 */
+	if (txq->nb_tx_free < txq->tx_free_thresh)
+		i40e_tx_free_bufs(txq);
+
+	/* Use available descriptor only */
+	nb_pkts = (uint16_t)RTE_MIN(txq->nb_tx_free, nb_pkts);
+	if (unlikely(!nb_pkts))
+		return 0;
+
+	txq->nb_tx_free = (uint16_t)(txq->nb_tx_free - nb_pkts);
+	if ((txq->tx_tail + nb_pkts) > txq->nb_tx_desc) {
+		n = (uint16_t)(txq->nb_tx_desc - txq->tx_tail);
+		i40e_tx_fill_hw_ring(txq, tx_pkts, n);
+		txr[txq->tx_next_rs].cmd_type_offset_bsz |=
+			rte_cpu_to_le_64(((uint64_t)I40E_TX_DESC_CMD_RS) <<
+						I40E_TXD_QW1_CMD_SHIFT);
+		txq->tx_next_rs = (uint16_t)(txq->tx_rs_thresh - 1);
+		txq->tx_tail = 0;
+	}
+
+	/* Fill hardware descriptor ring with mbuf data */
+	i40e_tx_fill_hw_ring(txq, tx_pkts + n, (uint16_t)(nb_pkts - n));
+	txq->tx_tail = (uint16_t)(txq->tx_tail + (nb_pkts - n));
+
+	/* Determin if RS bit needs to be set */
+	if (txq->tx_tail > txq->tx_next_rs) {
+		txr[txq->tx_next_rs].cmd_type_offset_bsz |=
+			rte_cpu_to_le_64(((uint64_t)I40E_TX_DESC_CMD_RS) <<
+						I40E_TXD_QW1_CMD_SHIFT);
+		txq->tx_next_rs =
+			(uint16_t)(txq->tx_next_rs + txq->tx_rs_thresh);
+		if (txq->tx_next_rs >= txq->nb_tx_desc)
+			txq->tx_next_rs = (uint16_t)(txq->tx_rs_thresh - 1);
+	}
+
+	if (txq->tx_tail >= txq->nb_tx_desc)
+		txq->tx_tail = 0;
+
+	/* Update the tx tail register */
+	rte_wmb();
+	I40E_PCI_REG_WRITE(txq->qtx_tail, txq->tx_tail);
+
+	return nb_pkts;
+}
+
+static uint16_t
+i40e_xmit_pkts_simple(void *tx_queue,
+		      struct rte_mbuf **tx_pkts,
+		      uint16_t nb_pkts)
+{
+	uint16_t nb_tx = 0;
+
+	if (likely(nb_pkts <= I40E_TX_MAX_BURST))
+		return tx_xmit_pkts((struct i40e_tx_queue *)tx_queue,
+						tx_pkts, nb_pkts);
+
+	while (nb_pkts) {
+		uint16_t ret, num = (uint16_t)RTE_MIN(nb_pkts,
+						I40E_TX_MAX_BURST);
+
+		ret = tx_xmit_pkts((struct i40e_tx_queue *)tx_queue,
+						&tx_pkts[nb_tx], num);
+		nb_tx = (uint16_t)(nb_tx + ret);
+		nb_pkts = (uint16_t)(nb_pkts - ret);
+		if (ret < num)
+			break;
+	}
+
+	return nb_tx;
+}
+
+int
+i40e_dev_rx_queue_setup(struct rte_eth_dev *dev,
+			uint16_t queue_idx,
+			uint16_t nb_desc,
+			unsigned int socket_id,
+			const struct rte_eth_rxconf *rx_conf,
+			struct rte_mempool *mp)
+{
+	struct i40e_vsi *vsi = I40E_DEV_PRIVATE_TO_VSI(dev->data->dev_private);
+	struct i40e_rx_queue *rxq;
+	const struct rte_memzone *rz;
+	uint32_t ring_size;
+	uint16_t len;
+	int use_def_burst_func = 1;
+
+	if (!vsi || queue_idx >= vsi->nb_qps) {
+		PMD_DRV_LOG(ERR, "VSI not available or queue "
+				"index exceeds the maximum\n");
+		return I40E_ERR_PARAM;
+	}
+	if (((nb_desc * sizeof(union i40e_rx_desc)) % I40E_ALIGN) != 0 ||
+					(nb_desc > I40E_MAX_RING_DESC) ||
+					(nb_desc < I40E_MIN_RING_DESC)) {
+		PMD_DRV_LOG(ERR, "Number (%u) of receive descriptors is "
+						"invalid\n", nb_desc);
+		return I40E_ERR_PARAM;
+	}
+
+	/* Free memory if needed */
+	if (dev->data->rx_queues[queue_idx]) {
+		i40e_dev_rx_queue_release(dev->data->rx_queues[queue_idx]);
+		dev->data->rx_queues[queue_idx] = NULL;
+	}
+
+	/* Allocate the rx queue data structure */
+	rxq = rte_zmalloc_socket("i40e rx queue",
+				 sizeof(struct i40e_rx_queue),
+				 CACHE_LINE_SIZE,
+				 socket_id);
+	if (!rxq) {
+		PMD_DRV_LOG(ERR, "Failed to allocate memory for "
+					"rx queue data structure\n");
+		return (-ENOMEM);
+	}
+	rxq->mp = mp;
+	rxq->nb_rx_desc = nb_desc;
+	rxq->rx_free_thresh = rx_conf->rx_free_thresh;
+	rxq->queue_id = queue_idx;
+	rxq->reg_idx = vsi->base_queue + queue_idx;
+	rxq->port_id = dev->data->port_id;
+	rxq->crc_len = (uint8_t) ((dev->data->dev_conf.rxmode.hw_strip_crc) ?
+							0 : ETHER_CRC_LEN);
+	rxq->drop_en = rx_conf->rx_drop_en;
+	rxq->vsi = vsi;
+
+	/* Allocate the maximun number of RX ring hardware descriptor. */
+	ring_size = sizeof(union i40e_rx_desc) * I40E_MAX_RING_DESC;
+	ring_size = RTE_ALIGN(ring_size, I40E_DMA_MEM_ALIGN);
+	rz = i40e_ring_dma_zone_reserve(dev,
+					"rx_ring",
+					queue_idx,
+					ring_size,
+					socket_id);
+	if (!rz) {
+		i40e_dev_rx_queue_release(rxq);
+		PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for RX\n");
+		return (-ENOMEM);
+	}
+
+	/* Zero all the descriptors in the ring. */
+	memset(rz->addr, 0, ring_size);
+
+#ifdef RTE_LIBRTE_XEN_DOM0
+	rxq->rx_ring_phys_addr = rte_mem_phy2mch(rz->memseg_id, rz->phys_addr);
+#else
+	rxq->rx_ring_phys_addr = (uint64_t)rz->phys_addr;
+#endif
+
+	rxq->rx_ring = (union i40e_rx_desc *)rz->addr;
+
+#ifdef RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC
+	len = (uint16_t)(nb_desc + RTE_PMD_I40E_RX_MAX_BURST);
+#else
+	len = nb_desc;
+#endif
+
+	/* Allocate the software ring. */
+	rxq->sw_ring =
+		rte_zmalloc_socket("i40e rx sw ring",
+				   sizeof(struct i40e_rx_entry) * len,
+				   CACHE_LINE_SIZE,
+				   socket_id);
+	if (!rxq->sw_ring) {
+		i40e_dev_rx_queue_release(rxq);
+		PMD_DRV_LOG(ERR, "Failed to allocate memory for SW ring\n");
+		return (-ENOMEM);
+	}
+
+	i40e_reset_rx_queue(rxq);
+	rxq->q_set = TRUE;
+	dev->data->rx_queues[queue_idx] = rxq;
+
+	use_def_burst_func = check_rx_burst_bulk_alloc_preconditions(rxq);
+
+	if (!use_def_burst_func && !dev->data->scattered_rx) {
+#ifdef RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC
+		PMD_INIT_LOG(DEBUG, "Rx Burst Bulk Alloc Preconditions are "
+			"satisfied. Rx Burst Bulk Alloc function will be "
+					"used on port=%d, queue=%d.\n",
+					rxq->port_id, rxq->queue_id);
+		dev->rx_pkt_burst = i40e_recv_pkts_bulk_alloc;
+#endif /* RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC */
+	} else {
+		PMD_INIT_LOG(DEBUG, "Rx Burst Bulk Alloc Preconditions are "
+				"not satisfied, Scattered Rx is requested, "
+				"or RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC is "
+					"not enabled on port=%d, queue=%d.\n",
+						rxq->port_id, rxq->queue_id);
+	}
+
+	return 0;
+}
+
+void
+i40e_dev_rx_queue_release(void *rxq)
+{
+	struct i40e_rx_queue *q = (struct i40e_rx_queue *)rxq;
+
+	if (!q) {
+		PMD_DRV_LOG(DEBUG, "Pointer to rxq is NULL\n");
+		return;
+	}
+
+	i40e_rx_queue_release_mbufs(q);
+	rte_free(q->sw_ring);
+	rte_free(q);
+}
+
+uint32_t
+i40e_dev_rx_queue_count(struct rte_eth_dev *dev, uint16_t rx_queue_id)
+{
+#define I40E_RXQ_SCAN_INTERVAL 4
+	volatile union i40e_rx_desc *rxdp;
+	struct i40e_rx_queue *rxq;
+	uint16_t desc = 0;
+
+	if (unlikely(rx_queue_id >= dev->data->nb_rx_queues)) {
+		PMD_DRV_LOG(ERR, "Invalid RX queue id %u\n", rx_queue_id);
+		return 0;
+	}
+
+	rxq = dev->data->rx_queues[rx_queue_id];
+	rxdp = &(rxq->rx_ring[rxq->rx_tail]);
+	while ((desc < rxq->nb_rx_desc) &&
+		((rte_le_to_cpu_64(rxdp->wb.qword1.status_error_len) &
+		I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT) &
+				(1 << I40E_RX_DESC_STATUS_DD_SHIFT)) {
+		/**
+		 * Check the DD bit of a rx descriptor of each 4 in a group,
+		 * to avoid checking too frequently and downgrading performance
+		 * too much.
+		 */
+		desc += I40E_RXQ_SCAN_INTERVAL;
+		rxdp += I40E_RXQ_SCAN_INTERVAL;
+		if (rxq->rx_tail + desc >= rxq->nb_rx_desc)
+			rxdp = &(rxq->rx_ring[rxq->rx_tail +
+					desc - rxq->nb_rx_desc]);
+	}
+
+	return desc;
+}
+
+int
+i40e_dev_rx_descriptor_done(void *rx_queue, uint16_t offset)
+{
+	volatile union i40e_rx_desc *rxdp;
+	struct i40e_rx_queue *rxq = rx_queue;
+	uint16_t desc;
+	int ret;
+
+	if (unlikely(offset >= rxq->nb_rx_desc)) {
+		PMD_DRV_LOG(ERR, "Invalid RX queue id %u\n", offset);
+		return 0;
+	}
+
+	desc = rxq->rx_tail + offset;
+	if (desc >= rxq->nb_rx_desc)
+		desc -= rxq->nb_rx_desc;
+
+	rxdp = &(rxq->rx_ring[desc]);
+
+	ret = !!(((rte_le_to_cpu_64(rxdp->wb.qword1.status_error_len) &
+		I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT) &
+				(1 << I40E_RX_DESC_STATUS_DD_SHIFT));
+
+	return ret;
+}
+
+int
+i40e_dev_tx_queue_setup(struct rte_eth_dev *dev,
+			uint16_t queue_idx,
+			uint16_t nb_desc,
+			unsigned int socket_id,
+			const struct rte_eth_txconf *tx_conf)
+{
+	struct i40e_vsi *vsi = I40E_DEV_PRIVATE_TO_VSI(dev->data->dev_private);
+	struct i40e_tx_queue *txq;
+	const struct rte_memzone *tz;
+	uint32_t ring_size;
+	uint16_t tx_rs_thresh, tx_free_thresh;
+
+	if (!vsi || queue_idx >= vsi->nb_qps) {
+		PMD_DRV_LOG(ERR, "VSI is NULL, or queue index (%u) "
+				"exceeds the maximum\n", queue_idx);
+		return I40E_ERR_PARAM;
+	}
+
+	if (((nb_desc * sizeof(struct i40e_tx_desc)) % I40E_ALIGN) != 0 ||
+					(nb_desc > I40E_MAX_RING_DESC) ||
+					(nb_desc < I40E_MIN_RING_DESC)) {
+		PMD_DRV_LOG(ERR, "Number (%u) of transmit descriptors is "
+                                                "invalid\n", nb_desc);
+		return I40E_ERR_PARAM;
+	}
+
+	/**
+	 * The following two parameters control the setting of the RS bit on
+	 * transmit descriptors. TX descriptors will have their RS bit set
+	 * after txq->tx_rs_thresh descriptors have been used. The TX
+	 * descriptor ring will be cleaned after txq->tx_free_thresh
+	 * descriptors are used or if the number of descriptors required to
+	 * transmit a packet is greater than the number of free TX descriptors.
+	 *
+	 * The following constraints must be satisfied:
+	 *  - tx_rs_thresh must be greater than 0.
+	 *  - tx_rs_thresh must be less than the size of the ring minus 2.
+	 *  - tx_rs_thresh must be less than or equal to tx_free_thresh.
+	 *  - tx_rs_thresh must be a divisor of the ring size.
+	 *  - tx_free_thresh must be greater than 0.
+	 *  - tx_free_thresh must be less than the size of the ring minus 3.
+	 *
+	 * One descriptor in the TX ring is used as a sentinel to avoid a H/W
+	 * race condition, hence the maximum threshold constraints. When set
+	 * to zero use default values.
+	 */
+	tx_rs_thresh = (uint16_t)((tx_conf->tx_rs_thresh) ?
+		tx_conf->tx_rs_thresh : DEFAULT_TX_RS_THRESH);
+	tx_free_thresh = (uint16_t)((tx_conf->tx_free_thresh) ?
+		tx_conf->tx_free_thresh : DEFAULT_TX_FREE_THRESH);
+	if (tx_rs_thresh >= (nb_desc - 2)) {
+		RTE_LOG(ERR, PMD, "tx_rs_thresh must be less than the "
+				"number of TX descriptors minus 2. "
+				"(tx_rs_thresh=%u port=%d queue=%d)\n",
+					(unsigned int)tx_rs_thresh,
+					(int)dev->data->port_id,
+						(int)queue_idx);
+		return I40E_ERR_PARAM;
+	}
+	if (tx_free_thresh >= (nb_desc - 3)) {
+		RTE_LOG(ERR, PMD, "tx_rs_thresh must be less than the "
+				"tx_free_thresh must be less than the "
+				"number of TX descriptors minus 3. "
+				"(tx_free_thresh=%u port=%d queue=%d)\n",
+					(unsigned int)tx_free_thresh,
+						(int)dev->data->port_id,
+							(int)queue_idx);
+		return I40E_ERR_PARAM;
+	}
+	if (tx_rs_thresh > tx_free_thresh) {
+		RTE_LOG(ERR, PMD, "tx_rs_thresh must be less than or "
+				"equal to tx_free_thresh. (tx_free_thresh=%u"
+				" tx_rs_thresh=%u port=%d queue=%d)\n",
+						(unsigned int)tx_free_thresh,
+						(unsigned int)tx_rs_thresh,
+						(int)dev->data->port_id,
+							(int)queue_idx);
+		return I40E_ERR_PARAM;
+	}
+	if ((nb_desc % tx_rs_thresh) != 0) {
+		RTE_LOG(ERR, PMD, "tx_rs_thresh must be a divisor of the "
+				"number of TX descriptors. (tx_rs_thresh=%u"
+						" port=%d queue=%d)\n",
+						(unsigned int)tx_rs_thresh,
+						(int)dev->data->port_id,
+							(int)queue_idx);
+		return I40E_ERR_PARAM;
+	}
+	if ((tx_rs_thresh > 1) && (tx_conf->tx_thresh.wthresh != 0)) {
+		RTE_LOG(ERR, PMD, "TX WTHRESH must be set to 0 if "
+				"tx_rs_thresh is greater than 1. "
+				"(tx_rs_thresh=%u port=%d queue=%d)\n",
+					(unsigned int)tx_rs_thresh,
+					(int)dev->data->port_id,
+						(int)queue_idx);
+		return I40E_ERR_PARAM;
+	}
+
+	/* Free memory if needed. */
+	if (dev->data->tx_queues[queue_idx]) {
+		i40e_dev_tx_queue_release(dev->data->tx_queues[queue_idx]);
+		dev->data->tx_queues[queue_idx] = NULL;
+	}
+
+	/* Allocate the TX queue data structure. */
+	txq = rte_zmalloc_socket("i40e tx queue",
+				  sizeof(struct i40e_tx_queue),
+				  CACHE_LINE_SIZE,
+				  socket_id);
+	if (!txq) {
+		PMD_DRV_LOG(ERR, "Failed to allocate memory for "
+					"tx queue structure\n");
+		return (-ENOMEM);
+	}
+
+	/* Allocate TX hardware ring descriptors. */
+	ring_size = sizeof(struct i40e_tx_desc) * I40E_MAX_RING_DESC;
+	ring_size = RTE_ALIGN(ring_size, I40E_DMA_MEM_ALIGN);
+	tz = i40e_ring_dma_zone_reserve(dev,
+					"tx_ring",
+					queue_idx,
+					ring_size,
+					socket_id);
+	if (!tz) {
+		i40e_dev_tx_queue_release(txq);
+		PMD_DRV_LOG(ERR, "Failed to reserve DMA memory for TX\n");
+		return (-ENOMEM);
+	}
+
+	txq->nb_tx_desc = nb_desc;
+	txq->tx_rs_thresh = tx_rs_thresh;
+	txq->tx_free_thresh = tx_free_thresh;
+	txq->pthresh = tx_conf->tx_thresh.pthresh;
+	txq->hthresh = tx_conf->tx_thresh.hthresh;
+	txq->wthresh = tx_conf->tx_thresh.wthresh;
+	txq->queue_id = queue_idx;
+	txq->reg_idx = vsi->base_queue + queue_idx;
+	txq->port_id = dev->data->port_id;
+	txq->txq_flags = tx_conf->txq_flags;
+	txq->vsi = vsi;
+
+#ifdef RTE_LIBRTE_XEN_DOM0
+	txq->tx_ring_phys_addr = rte_mem_phy2mch(tz->memseg_id, tz->phys_addr);
+#else
+	txq->tx_ring_phys_addr = (uint64_t)tz->phys_addr;
+#endif
+	txq->tx_ring = (struct i40e_tx_desc *)tz->addr;
+
+	/* Allocate software ring */
+	txq->sw_ring =
+		rte_zmalloc_socket("i40e tx sw ring",
+				   sizeof(struct i40e_tx_entry) * nb_desc,
+				   CACHE_LINE_SIZE,
+				   socket_id);
+	if (!txq->sw_ring) {
+		i40e_dev_tx_queue_release(txq);
+		PMD_DRV_LOG(ERR, "Failed to allocate memory for SW TX ring\n");
+		return (-ENOMEM);
+	}
+
+	i40e_reset_tx_queue(txq);
+	txq->q_set = TRUE;
+	dev->data->tx_queues[queue_idx] = txq;
+
+	/* Use a simple TX queue without offloads or multi segs if possible */
+	if (((txq->txq_flags & I40E_SIMPLE_FLAGS) == I40E_SIMPLE_FLAGS) &&
+				(txq->tx_rs_thresh >= I40E_TX_MAX_BURST)) {
+		PMD_INIT_LOG(INFO, "Using simple tx path\n");
+		dev->tx_pkt_burst = i40e_xmit_pkts_simple;
+	} else {
+		PMD_INIT_LOG(INFO, "Using full-featured tx path\n");
+		dev->tx_pkt_burst = i40e_xmit_pkts;
+	}
+
+	return 0;
+}
+
+void
+i40e_dev_tx_queue_release(void *txq)
+{
+	struct i40e_tx_queue *q = (struct i40e_tx_queue *)txq;
+
+	if (!q) {
+		PMD_DRV_LOG(DEBUG, "Pointer to TX queue is NULL\n");
+		return;
+	}
+
+	i40e_tx_queue_release_mbufs(q);
+	rte_free(q->sw_ring);
+	rte_free(q);
+}
+
+static const struct rte_memzone *
+i40e_ring_dma_zone_reserve(struct rte_eth_dev *dev,
+			   const char *ring_name,
+			   uint16_t queue_id,
+			   uint32_t ring_size,
+			   int socket_id)
+{
+	char z_name[RTE_MEMZONE_NAMESIZE];
+	const struct rte_memzone *mz;
+
+	rte_snprintf(z_name, sizeof(z_name), "%s_%s_%d_%d",
+			dev->driver->pci_drv.name, ring_name,
+				dev->data->port_id, queue_id);
+	mz = rte_memzone_lookup(z_name);
+	if (mz)
+		return mz;
+
+#ifdef RTE_LIBRTE_XEN_DOM0
+	return rte_memzone_reserve_bounded(z_name, ring_size,
+		socket_id, 0, I40E_ALIGN, RTE_PGSIZE_2M);
+#else
+	return rte_memzone_reserve_aligned(z_name, ring_size,
+				socket_id, 0, I40E_ALIGN);
+#endif
+}
+
+void
+i40e_rx_queue_release_mbufs(struct i40e_rx_queue *rxq)
+{
+	uint16_t i;
+
+	if (!rxq || !rxq->sw_ring) {
+		PMD_DRV_LOG(DEBUG, "Pointer to rxq or sw_ring is NULL\n");
+		return;
+	}
+
+	for (i = 0; i < rxq->nb_rx_desc; i++) {
+		if (rxq->sw_ring[i].mbuf) {
+			rte_pktmbuf_free_seg(rxq->sw_ring[i].mbuf);
+			rxq->sw_ring[i].mbuf = NULL;
+		}
+	}
+#ifdef RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC
+	if (rxq->rx_nb_avail == 0)
+		return;
+	for (i = 0; i < rxq->rx_nb_avail; i++) {
+		struct rte_mbuf *mbuf;
+
+		mbuf = rxq->rx_stage[rxq->rx_next_avail + i];
+		rte_pktmbuf_free_seg(mbuf);
+	}
+	rxq->rx_nb_avail = 0;
+#endif /* RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC */
+}
+
+static void
+i40e_reset_rx_queue(struct i40e_rx_queue *rxq)
+{
+	unsigned i;
+	uint16_t len;
+
+#ifdef RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC
+	if (check_rx_burst_bulk_alloc_preconditions(rxq) == 0)
+		len = (uint16_t)(rxq->nb_rx_desc + RTE_PMD_I40E_RX_MAX_BURST);
+	else
+#endif /* RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC */
+		len = rxq->nb_rx_desc;
+
+	for (i = 0; i < len * sizeof(union i40e_rx_desc); i++)
+		((volatile char *)rxq->rx_ring)[i] = 0;
+
+#ifdef RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC
+	memset(&rxq->fake_mbuf, 0x0, sizeof(rxq->fake_mbuf));
+	for (i = 0; i < RTE_PMD_I40E_RX_MAX_BURST; ++i)
+		rxq->sw_ring[rxq->nb_rx_desc + i].mbuf = &rxq->fake_mbuf;
+
+	rxq->rx_nb_avail = 0;
+	rxq->rx_next_avail = 0;
+	rxq->rx_free_trigger = (uint16_t)(rxq->rx_free_thresh - 1);
+#endif /* RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC */
+	rxq->rx_tail = 0;
+	rxq->nb_rx_hold = 0;
+	rxq->pkt_first_seg = NULL;
+	rxq->pkt_last_seg = NULL;
+}
+
+static void
+i40e_tx_queue_release_mbufs(struct i40e_tx_queue *txq)
+{
+	uint16_t i;
+
+	if (!txq || !txq->sw_ring) {
+		PMD_DRV_LOG(DEBUG, "Pointer to rxq or sw_ring is NULL\n");
+		return;
+	}
+
+	for (i = 0; i < txq->nb_tx_desc; i++) {
+		if (txq->sw_ring[i].mbuf) {
+			rte_pktmbuf_free_seg(txq->sw_ring[i].mbuf);
+			txq->sw_ring[i].mbuf = NULL;
+		}
+	}
+}
+
+static void
+i40e_reset_tx_queue(struct i40e_tx_queue *txq)
+{
+	struct i40e_tx_entry *txe;
+	uint16_t i, prev, size;
+
+	if (!txq) {
+		PMD_DRV_LOG(DEBUG, "Pointer to txq is NULL\n");
+		return;
+	}
+
+	txe = txq->sw_ring;
+	size = sizeof(struct i40e_tx_desc) * txq->nb_tx_desc;
+	for (i = 0; i < size; i++)
+		((volatile char *)txq->tx_ring)[i] = 0;
+
+	prev = (uint16_t)(txq->nb_tx_desc - 1);
+	for (i = 0; i < txq->nb_tx_desc; i++) {
+		volatile struct i40e_tx_desc *txd = &txq->tx_ring[i];
+
+		txd[i].cmd_type_offset_bsz =
+			rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE);
+		txe[i].mbuf =  NULL;
+		txe[i].last_id = i;
+		txe[prev].next_id = i;
+		prev = i;
+	}
+
+	txq->tx_next_dd = (uint16_t)(txq->tx_rs_thresh - 1);
+	txq->tx_next_rs = (uint16_t)(txq->tx_rs_thresh - 1);
+
+	txq->tx_tail = 0;
+	txq->nb_tx_used = 0;
+
+	txq->last_desc_cleaned = (uint16_t)(txq->nb_tx_desc - 1);
+	txq->nb_tx_free = (uint16_t)(txq->nb_tx_desc - 1);
+}
+
+/* Init the TX queue in hardware */
+int
+i40e_tx_queue_init(struct i40e_tx_queue *txq)
+{
+	enum i40e_status_code err = I40E_SUCCESS;
+	struct i40e_vsi *vsi = txq->vsi;
+	struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+	uint16_t pf_q = txq->reg_idx;
+	struct i40e_hmc_obj_txq tx_ctx;
+	uint32_t qtx_ctl;
+
+	/* clear the context structure first */
+	memset(&tx_ctx, 0, sizeof(tx_ctx));
+	tx_ctx.new_context = 1;
+	tx_ctx.base = txq->tx_ring_phys_addr / I40E_QUEUE_BASE_ADDR_UNIT;
+	tx_ctx.qlen = txq->nb_tx_desc;
+	tx_ctx.rdylist = rte_le_to_cpu_16(vsi->info.qs_handle[0]);
+
+	err = i40e_clear_lan_tx_queue_context(hw, pf_q);
+	if (err != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failure of clean lan tx queue context\n");
+		return err;
+	}
+
+	err = i40e_set_lan_tx_queue_context(hw, pf_q, &tx_ctx);
+	if (err != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failure of set lan tx queue context\n");
+		return err;
+	}
+
+	/* Now associate this queue with this PCI function */
+	qtx_ctl = I40E_QTX_CTL_PF_QUEUE;
+	qtx_ctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
+					I40E_QTX_CTL_PF_INDX_MASK);
+	I40E_WRITE_REG(hw, I40E_QTX_CTL(pf_q), qtx_ctl);
+	I40E_WRITE_FLUSH(hw);
+
+	txq->qtx_tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+
+	return err;
+}
+
+int
+i40e_alloc_rx_queue_mbufs(struct i40e_rx_queue *rxq)
+{
+	struct i40e_rx_entry *rxe = rxq->sw_ring;
+	uint64_t dma_addr;
+	uint16_t i;
+
+	for (i = 0; i < rxq->nb_rx_desc; i++) {
+		volatile union i40e_rx_desc *rxd;
+		struct rte_mbuf *mbuf = rte_rxmbuf_alloc(rxq->mp);
+
+		if (unlikely(!mbuf)) {
+			PMD_DRV_LOG(ERR, "Failed to allocate mbuf for RX\n");
+			return -ENOMEM;
+		}
+
+		rte_mbuf_refcnt_set(mbuf, 1);
+		mbuf->type = RTE_MBUF_PKT;
+		mbuf->pkt.next = NULL;
+		mbuf->pkt.data = (char *)mbuf->buf_addr + RTE_PKTMBUF_HEADROOM;
+		mbuf->pkt.nb_segs = 1;
+		mbuf->pkt.in_port = rxq->port_id;
+
+		dma_addr =
+			rte_cpu_to_le_64(RTE_MBUF_DATA_DMA_ADDR_DEFAULT(mbuf));
+
+		rxd = &rxq->rx_ring[i];
+		rxd->read.pkt_addr = dma_addr;
+		rxd->read.hdr_addr = dma_addr;
+#ifndef RTE_LIBRTE_I40E_16BYTE_RX_DESC
+		rxd->read.rsvd1 = 0;
+		rxd->read.rsvd2 = 0;
+#endif /* RTE_LIBRTE_I40E_16BYTE_RX_DESC */
+
+		rxe[i].mbuf = mbuf;
+	}
+
+	return 0;
+}
+
+/*
+ * Calculate the buffer length, and check the jumbo frame
+ * and maximum packet length.
+ */
+static int
+i40e_rx_queue_config(struct i40e_rx_queue *rxq)
+{
+	struct i40e_pf *pf = I40E_VSI_TO_PF(rxq->vsi);
+	struct i40e_hw *hw = I40E_VSI_TO_HW(rxq->vsi);
+	struct rte_eth_dev_data *data = pf->dev_data;
+	struct rte_pktmbuf_pool_private *mbp_priv =
+			rte_mempool_get_priv(rxq->mp);
+	uint16_t buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+						RTE_PKTMBUF_HEADROOM);
+	uint16_t len;
+
+	switch (pf->flags & (I40E_FLAG_HEADER_SPLIT_DISABLED |
+			I40E_FLAG_HEADER_SPLIT_ENABLED)) {
+	case I40E_FLAG_HEADER_SPLIT_ENABLED: /* Not supported */
+		rxq->rx_hdr_len = RTE_ALIGN(I40E_RXBUF_SZ_1024,
+				(1 << I40E_RXQ_CTX_HBUFF_SHIFT));
+		rxq->rx_buf_len = RTE_ALIGN(I40E_RXBUF_SZ_2048,
+				(1 << I40E_RXQ_CTX_DBUFF_SHIFT));
+		rxq->hs_mode = i40e_header_split_enabled;
+		break;
+	case I40E_FLAG_HEADER_SPLIT_DISABLED:
+	default:
+		rxq->rx_hdr_len = 0;
+		rxq->rx_buf_len = RTE_ALIGN(buf_size,
+			(1 << I40E_RXQ_CTX_DBUFF_SHIFT));
+		rxq->hs_mode = i40e_header_split_none;
+		break;
+	}
+
+	len = hw->func_caps.rx_buf_chain_len * rxq->rx_buf_len;
+	rxq->max_pkt_len = RTE_MIN(len, data->dev_conf.rxmode.max_rx_pkt_len);
+	if (data->dev_conf.rxmode.jumbo_frame == 1) {
+		if (rxq->max_pkt_len <= ETHER_MAX_LEN ||
+			rxq->max_pkt_len > I40E_FRAME_SIZE_MAX) {
+			PMD_DRV_LOG(ERR, "maximum packet length must "
+				"be larger than %u and smaller than %u,"
+					"as jumbo frame is enabled\n",
+						(uint32_t)ETHER_MAX_LEN,
+					(uint32_t)I40E_FRAME_SIZE_MAX);
+			return I40E_ERR_CONFIG;
+		}
+	} else {
+		if (rxq->max_pkt_len < ETHER_MIN_LEN ||
+			rxq->max_pkt_len > ETHER_MAX_LEN) {
+			PMD_DRV_LOG(ERR, "maximum packet length must be "
+					"larger than %u and smaller than %u, "
+					"as jumbo frame is disabled\n",
+						(uint32_t)ETHER_MIN_LEN,
+						(uint32_t)ETHER_MAX_LEN);
+			return I40E_ERR_CONFIG;
+		}
+	}
+
+	return 0;
+}
+
+/* Init the RX queue in hardware */
+int
+i40e_rx_queue_init(struct i40e_rx_queue *rxq)
+{
+	int err = I40E_SUCCESS;
+	struct i40e_hw *hw = I40E_VSI_TO_HW(rxq->vsi);
+	struct rte_eth_dev_data *dev_data = I40E_VSI_TO_DEV_DATA(rxq->vsi);
+	struct rte_eth_dev *dev = I40E_VSI_TO_ETH_DEV(rxq->vsi);
+	uint16_t pf_q = rxq->reg_idx;
+	uint16_t buf_size;
+	struct i40e_hmc_obj_rxq rx_ctx;
+	struct rte_pktmbuf_pool_private *mbp_priv;
+
+	err = i40e_rx_queue_config(rxq);
+	if (err < 0) {
+		PMD_DRV_LOG(ERR, "Failed to config RX queue\n");
+		return err;
+	}
+
+	/* Clear the context structure first */
+	memset(&rx_ctx, 0, sizeof(struct i40e_hmc_obj_rxq));
+	rx_ctx.dbuff = rxq->rx_buf_len >> I40E_RXQ_CTX_DBUFF_SHIFT;
+	rx_ctx.hbuff = rxq->rx_hdr_len >> I40E_RXQ_CTX_HBUFF_SHIFT;
+
+	rx_ctx.base = rxq->rx_ring_phys_addr / I40E_QUEUE_BASE_ADDR_UNIT;
+	rx_ctx.qlen = rxq->nb_rx_desc;
+#ifndef RTE_LIBRTE_I40E_16BYTE_RX_DESC
+	rx_ctx.dsize = 1;
+#endif
+	rx_ctx.dtype = rxq->hs_mode;
+	if (rxq->hs_mode)
+		rx_ctx.hsplit_0 = I40E_HEADER_SPLIT_ALL;
+	else
+		rx_ctx.hsplit_0 = I40E_HEADER_SPLIT_NONE;
+	rx_ctx.rxmax = rxq->max_pkt_len;
+	rx_ctx.tphrdesc_ena = 1;
+	rx_ctx.tphwdesc_ena = 1;
+	rx_ctx.tphdata_ena = 1;
+	rx_ctx.tphhead_ena = 1;
+	rx_ctx.lrxqthresh = 2;
+	rx_ctx.crcstrip = (rxq->crc_len == 0) ? 1 : 0;
+	rx_ctx.l2tsel = 1;
+	rx_ctx.showiv = 1;
+	rx_ctx.prefena = 1;
+
+	err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+	if (err != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to clear LAN RX queue context\n");
+		return err;
+	}
+	err = i40e_set_lan_rx_queue_context(hw, pf_q, &rx_ctx);
+	if (err != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Failed to set LAN RX queue context\n");
+		return err;
+	}
+
+	rxq->qrx_tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+	err = i40e_alloc_rx_queue_mbufs(rxq);
+	mbp_priv = rte_mempool_get_priv(rxq->mp);
+	buf_size = (uint16_t)(mbp_priv->mbuf_data_room_size -
+					RTE_PKTMBUF_HEADROOM);
+
+	/* Check if scattered RX needs to be used. */
+	if ((rxq->max_pkt_len + 2 * I40E_VLAN_TAG_SIZE) > buf_size) {
+		dev_data->scattered_rx = 1;
+		dev->rx_pkt_burst = i40e_recv_scattered_pkts;
+	}
+
+	rte_wmb();
+
+	/* Init the RX tail regieter. */
+	I40E_PCI_REG_WRITE(rxq->qrx_tail, 0);
+	I40E_PCI_REG_WRITE(rxq->qrx_tail, rxq->nb_rx_desc - 1);
+
+	if (err)
+		PMD_DRV_LOG(ERR, "Failed to allocate RX queue mbuf\n");
+
+	return err;
+}
+
+void
+i40e_dev_clear_queues(struct rte_eth_dev *dev)
+{
+	uint16_t i;
+
+	PMD_INIT_FUNC_TRACE();
+
+	for (i = 0; i < dev->data->nb_tx_queues; i++) {
+		i40e_tx_queue_release_mbufs(dev->data->tx_queues[i]);
+		i40e_reset_tx_queue(dev->data->tx_queues[i]);
+	}
+
+	for (i = 0; i < dev->data->nb_rx_queues; i++) {
+		i40e_rx_queue_release_mbufs(dev->data->rx_queues[i]);
+		i40e_reset_rx_queue(dev->data->rx_queues[i]);
+	}
+}
diff --git a/lib/librte_pmd_i40e/i40e_rxtx.h b/lib/librte_pmd_i40e/i40e_rxtx.h
new file mode 100644
index 0000000..6db2faf
--- /dev/null
+++ b/lib/librte_pmd_i40e/i40e_rxtx.h
@@ -0,0 +1,189 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _I40E_RXTX_H_
+#define _I40E_RXTX_H_
+
+/**
+ * 32 bits tx flags, high 16 bits for L2TAG1 (VLAN),
+ * low 16 bits for others.
+ */
+#define I40E_TX_FLAG_L2TAG1_SHIFT 16
+#define I40E_TX_FLAG_L2TAG1_MASK  0xffff0000
+#define I40E_TX_FLAG_CSUM         ((uint32_t)(1 << 0))
+#define I40E_TX_FLAG_INSERT_VLAN  ((uint32_t)(1 << 1))
+#define I40E_TX_FLAG_TSYN         ((uint32_t)(1 << 2))
+
+#ifdef RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC
+#define RTE_PMD_I40E_RX_MAX_BURST 32
+#endif
+
+#define I40E_RXBUF_SZ_1024 1024
+#define I40E_RXBUF_SZ_2048 2048
+
+enum i40e_header_split_mode {
+	i40e_header_split_none = 0,
+	i40e_header_split_enabled = 1,
+	i40e_header_split_always = 2,
+	i40e_header_split_reserved
+};
+
+#define I40E_HEADER_SPLIT_NONE    ((uint8_t)0)
+#define I40E_HEADER_SPLIT_L2      ((uint8_t)(1 << 0))
+#define I40E_HEADER_SPLIT_IP      ((uint8_t)(1 << 1))
+#define I40E_HEADER_SPLIT_UDP_TCP ((uint8_t)(1 << 2))
+#define I40E_HEADER_SPLIT_SCTP    ((uint8_t)(1 << 3))
+#define I40E_HEADER_SPLIT_ALL (I40E_HEADER_SPLIT_L2 | \
+			       I40E_HEADER_SPLIT_IP | \
+			       I40E_HEADER_SPLIT_UDP_TCP | \
+			       I40E_HEADER_SPLIT_SCTP)
+
+/* HW desc structure, both 16-byte and 32-byte types are supported */
+#ifdef RTE_LIBRTE_I40E_16BYTE_RX_DESC
+#define i40e_rx_desc i40e_16byte_rx_desc
+#else
+#define i40e_rx_desc i40e_32byte_rx_desc
+#endif
+
+struct i40e_rx_entry {
+	struct rte_mbuf *mbuf;
+};
+
+/*
+ * Structure associated with each RX queue.
+ */
+struct i40e_rx_queue {
+	struct rte_mempool *mp; /**< mbuf pool to populate RX ring */
+	volatile union i40e_rx_desc *rx_ring;/**< RX ring virtual address */
+	uint64_t rx_ring_phys_addr; /**< RX ring DMA address */
+	struct i40e_rx_entry *sw_ring; /**< address of RX soft ring */
+	uint16_t nb_rx_desc; /**< number of RX descriptors */
+	uint16_t rx_free_thresh; /**< max free RX desc to hold */
+	uint16_t rx_tail; /**< current value of tail */
+	uint16_t nb_rx_hold; /**< number of held free RX desc */
+	struct rte_mbuf *pkt_first_seg; /**< first segment of current packet */
+	struct rte_mbuf *pkt_last_seg; /**< last segment of current packet */
+#ifdef RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC
+	uint16_t rx_nb_avail; /**< number of staged packets ready */
+	uint16_t rx_next_avail; /**< index of next staged packets */
+	uint16_t rx_free_trigger; /**< triggers rx buffer allocation */
+	struct rte_mbuf fake_mbuf; /**< dummy mbuf */
+	struct rte_mbuf *rx_stage[RTE_PMD_I40E_RX_MAX_BURST * 2];
+#endif
+	uint8_t port_id; /**< device port ID */
+	uint8_t crc_len; /**< 0 if CRC stripped, 4 otherwise */
+	uint16_t queue_id; /**< RX queue index */
+	uint16_t reg_idx; /**< RX queue register index */
+	uint8_t drop_en; /**< if not 0, set register bit */
+	volatile uint8_t *qrx_tail; /**< register address of tail */
+	struct i40e_vsi *vsi; /**< the VSI this queue belongs to */
+	uint16_t rx_buf_len; /* The packet buffer size */
+	uint16_t rx_hdr_len; /* The header buffer size */
+	uint16_t max_pkt_len; /* Maximum packet length */
+	uint8_t hs_mode; /* Header Split mode */
+	bool q_set; /**< indicate if rx queue has been configured */
+};
+
+struct i40e_tx_entry {
+	struct rte_mbuf *mbuf;
+	uint16_t next_id;
+	uint16_t last_id;
+};
+
+/*
+ * Structure associated with each TX queue.
+ */
+struct i40e_tx_queue {
+	uint16_t nb_tx_desc; /**< number of TX descriptors */
+	uint64_t tx_ring_phys_addr; /**< TX ring DMA address */
+	volatile struct i40e_tx_desc *tx_ring; /**< TX ring virtual address */
+	struct i40e_tx_entry *sw_ring; /**< virtual address of SW ring */
+	uint16_t tx_tail; /**< current value of tail register */
+	volatile uint8_t *qtx_tail; /**< register address of tail */
+	uint16_t nb_tx_used; /**< number of TX desc used since RS bit set */
+	/**< index to last TX descriptor to have been cleaned */
+	uint16_t last_desc_cleaned;
+	/**< Total number of TX descriptors ready to be allocated. */
+	uint16_t nb_tx_free;
+	/**< Number of TX descriptors to use before RS bit is set. */
+	uint16_t tx_free_thresh; /**< minimum TX before freeing. */
+	/** Number of TX descriptors to use before RS bit is set. */
+	uint16_t tx_rs_thresh;
+	uint8_t pthresh; /**< Prefetch threshold register. */
+	uint8_t hthresh; /**< Host threshold register. */
+	uint8_t wthresh; /**< Write-back threshold reg. */
+	uint8_t port_id; /**< Device port identifier. */
+	uint16_t queue_id; /**< TX queue index. */
+	uint16_t reg_idx;
+	uint32_t txq_flags;
+	struct i40e_vsi *vsi; /**< the VSI this queue belongs to */
+	uint16_t tx_next_dd;
+	uint16_t tx_next_rs;
+	bool q_set; /**< indicate if tx queue has been configured */
+};
+
+int i40e_dev_rx_queue_setup(struct rte_eth_dev *dev,
+			    uint16_t queue_idx,
+			    uint16_t nb_desc,
+			    unsigned int socket_id,
+			    const struct rte_eth_rxconf *rx_conf,
+			    struct rte_mempool *mp);
+int i40e_dev_tx_queue_setup(struct rte_eth_dev *dev,
+			    uint16_t queue_idx,
+			    uint16_t nb_desc,
+			    unsigned int socket_id,
+			    const struct rte_eth_txconf *tx_conf);
+void i40e_dev_rx_queue_release(void *rxq);
+void i40e_dev_tx_queue_release(void *txq);
+uint16_t i40e_recv_pkts(void *rx_queue,
+			struct rte_mbuf **rx_pkts,
+			uint16_t nb_pkts);
+uint16_t i40e_recv_scattered_pkts(void *rx_queue,
+				  struct rte_mbuf **rx_pkts,
+				  uint16_t nb_pkts);
+uint16_t i40e_xmit_pkts(void *tx_queue,
+			struct rte_mbuf **tx_pkts,
+			uint16_t nb_pkts);
+int i40e_tx_queue_init(struct i40e_tx_queue *txq);
+int i40e_rx_queue_init(struct i40e_rx_queue *rxq);
+void i40e_free_tx_resources(struct i40e_tx_queue *txq);
+void i40e_free_rx_resources(struct i40e_rx_queue *rxq);
+void i40e_dev_clear_queues(struct rte_eth_dev *dev);
+int i40e_alloc_rx_queue_mbufs(struct i40e_rx_queue *rxq);
+void i40e_rx_queue_release_mbufs(struct i40e_rx_queue *rxq);
+
+uint32_t i40e_dev_rx_queue_count(struct rte_eth_dev *dev,
+				 uint16_t rx_queue_id);
+int i40e_dev_rx_descriptor_done(void *rx_queue, uint16_t offset);
+
+#endif /* _I40E_RXTX_H_ */
-- 
1.8.1.4



More information about the dev mailing list