i40e: new poll mode driver
authorHelin Zhang <helin.zhang@intel.com>
Thu, 5 Jun 2014 05:08:46 +0000 (13:08 +0800)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Tue, 17 Jun 2014 16:22:19 +0000 (18:22 +0200)
Signed-off-by: Helin Zhang <helin.zhang@intel.com>
Signed-off-by: Jing Chen <jing.d.chen@intel.com>
Acked-by: Cunming Liang <cunming.liang@intel.com>
Acked-by: Jijiang Liu <jijiang.liu@intel.com>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
Acked-by: Heqing Zhu <heqing.zhu@intel.com>
Tested-by: Waterman Cao <waterman.cao@intel.com>
14 files changed:
config/common_bsdapp
config/common_linuxapp
lib/Makefile
lib/librte_pmd_i40e/Makefile [new file with mode: 0644]
lib/librte_pmd_i40e/i40e/i40e_osdep.h [new file with mode: 0644]
lib/librte_pmd_i40e/i40e_ethdev.c [new file with mode: 0644]
lib/librte_pmd_i40e/i40e_ethdev.h [new file with mode: 0644]
lib/librte_pmd_i40e/i40e_ethdev_vf.c [new file with mode: 0644]
lib/librte_pmd_i40e/i40e_logs.h [new file with mode: 0644]
lib/librte_pmd_i40e/i40e_pf.c [new file with mode: 0644]
lib/librte_pmd_i40e/i40e_pf.h [new file with mode: 0644]
lib/librte_pmd_i40e/i40e_rxtx.c [new file with mode: 0644]
lib/librte_pmd_i40e/i40e_rxtx.h [new file with mode: 0644]
mk/rte.app.mk

index 578d510..989e1da 100644 (file)
@@ -166,6 +166,23 @@ CONFIG_RTE_LIBRTE_IXGBE_ALLOW_UNSUPPORTED_SFP=n
 CONFIG_RTE_IXGBE_INC_VECTOR=n
 CONFIG_RTE_IXGBE_RX_OLFLAGS_DISABLE=n
 
+#
+# Compile burst-oriented I40E PMD driver
+#
+CONFIG_RTE_LIBRTE_I40E_PMD=y
+CONFIG_RTE_LIBRTE_I40E_DEBUG_INIT=y
+CONFIG_RTE_LIBRTE_I40E_DEBUG_RX=y
+CONFIG_RTE_LIBRTE_I40E_DEBUG_TX=y
+CONFIG_RTE_LIBRTE_I40E_DEBUG_TX_FREE=y
+CONFIG_RTE_LIBRTE_I40E_DEBUG_DRIVER=y
+CONFIG_RTE_LIBRTE_I40E_PF_DISABLE_STRIP_CRC=y
+CONFIG_RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC=n
+CONFIG_RTE_LIBRTE_I40E_ALLOW_UNSUPPORTED_SFP=y
+CONFIG_RTE_LIBRTE_I40E_16BYTE_RX_DESC=n
+CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_VF=4
+# interval up to 8160 us, aligned to 2 (or default value)
+CONFIG_RTE_LIBRTE_I40E_ITR_INTERVAL=-1
+
 #
 # Compile burst-oriented VIRTIO PMD driver
 #
index 416e26d..5b896c3 100644 (file)
@@ -194,6 +194,23 @@ CONFIG_RTE_LIBRTE_IXGBE_ALLOW_UNSUPPORTED_SFP=n
 CONFIG_RTE_IXGBE_INC_VECTOR=y
 CONFIG_RTE_IXGBE_RX_OLFLAGS_DISABLE=n
 
+#
+# Compile burst-oriented I40E PMD driver
+#
+CONFIG_RTE_LIBRTE_I40E_PMD=y
+CONFIG_RTE_LIBRTE_I40E_DEBUG_INIT=n
+CONFIG_RTE_LIBRTE_I40E_DEBUG_RX=n
+CONFIG_RTE_LIBRTE_I40E_DEBUG_TX=n
+CONFIG_RTE_LIBRTE_I40E_DEBUG_TX_FREE=n
+CONFIG_RTE_LIBRTE_I40E_DEBUG_DRIVER=n
+CONFIG_RTE_LIBRTE_I40E_PF_DISABLE_STRIP_CRC=n
+CONFIG_RTE_LIBRTE_I40E_RX_ALLOW_BULK_ALLOC=y
+CONFIG_RTE_LIBRTE_I40E_ALLOW_UNSUPPORTED_SFP=n
+CONFIG_RTE_LIBRTE_I40E_16BYTE_RX_DESC=n
+CONFIG_RTE_LIBRTE_I40E_QUEUE_NUM_PER_VF=4
+# interval up to 8160 us, aligned to 2 (or default value)
+CONFIG_RTE_LIBRTE_I40E_ITR_INTERVAL=-1
+
 #
 # Compile burst-oriented VIRTIO PMD driver
 #
index 7c02cb6..c58c0c9 100644 (file)
@@ -43,6 +43,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
 DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_E1000_PMD) += librte_pmd_e1000
 DIRS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += librte_pmd_ixgbe
+DIRS-$(CONFIG_RTE_LIBRTE_I40E_PMD) += librte_pmd_i40e
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_RING) += librte_pmd_ring
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_PCAP) += librte_pmd_pcap
 DIRS-$(CONFIG_RTE_LIBRTE_VIRTIO_PMD) += librte_pmd_virtio
diff --git a/lib/librte_pmd_i40e/Makefile b/lib/librte_pmd_i40e/Makefile
new file mode 100644 (file)
index 0000000..09f2087
--- /dev/null
@@ -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 (file)
index 0000000..0ed4b65
--- /dev/null
@@ -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 (file)
index 0000000..a335242
--- /dev/null
@@ -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_MAPPING,
+       },
+       .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 (file)
index 0000000..e00895d
--- /dev/null
@@ -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 (file)
index 0000000..4851df9
--- /dev/null
@@ -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_MAPPING,
+       },
+       .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 (file)
index 0000000..f991dd2
--- /dev/null
@@ -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 (file)
index 0000000..76405d3
--- /dev/null
@@ -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 (file)
index 0000000..ccbd0d8
--- /dev/null
@@ -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 (file)
index 0000000..d802894
--- /dev/null
@@ -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 (file)
index 0000000..6db2faf
--- /dev/null
@@ -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_ */
index 7cd593e..8db9cde 100644 (file)
@@ -185,6 +185,10 @@ ifeq ($(CONFIG_RTE_LIBRTE_VIRTIO_PMD),y)
 LDLIBS += -lrte_pmd_virtio_uio
 endif
 
+ifeq ($(CONFIG_RTE_LIBRTE_I40E_PMD),y)
+LDLIBS += -lrte_pmd_i40e
+endif
+
 ifeq ($(CONFIG_RTE_LIBRTE_IXGBE_PMD),y)
 LDLIBS += -lrte_pmd_ixgbe
 endif