net: add rte prefix to ether structures
[dpdk.git] / drivers / net / e1000 / igb_ethdev.c
index e0053fe..e21a772 100644 (file)
@@ -1,34 +1,5 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2016 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.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2016 Intel Corporation
  */
 
 #include <sys/queue.h>
 #include <stdint.h>
 #include <stdarg.h>
 
+#include <rte_string_fns.h>
 #include <rte_common.h>
 #include <rte_interrupts.h>
 #include <rte_byteorder.h>
 #include <rte_log.h>
 #include <rte_debug.h>
 #include <rte_pci.h>
+#include <rte_bus_pci.h>
 #include <rte_ether.h>
-#include <rte_ethdev.h>
+#include <rte_ethdev_driver.h>
+#include <rte_ethdev_pci.h>
 #include <rte_memory.h>
-#include <rte_memzone.h>
 #include <rte_eal.h>
-#include <rte_atomic.h>
 #include <rte_malloc.h>
 #include <rte_dev.h>
 
@@ -70,8 +42,6 @@
 #define IGB_DEFAULT_TX_HTHRESH      1
 #define IGB_DEFAULT_TX_WTHRESH      ((hw->mac.type == e1000_82576) ? 1 : 16)
 
-#define IGB_HKEY_MAX_INDEX 10
-
 /* Bit shift and mask */
 #define IGB_4_BIT_WIDTH  (CHAR_BIT / 2)
 #define IGB_4_BIT_MASK   RTE_LEN2MASK(IGB_4_BIT_WIDTH, uint8_t)
 #define E1000_INCVALUE_82576         (16 << IGB_82576_TSYNC_SHIFT)
 #define E1000_TSAUXC_DISABLE_SYSTIME 0x80000000
 
+#define E1000_VTIVAR_MISC                0x01740
+#define E1000_VTIVAR_MISC_MASK           0xFF
+#define E1000_VTIVAR_VALID               0x80
+#define E1000_VTIVAR_MISC_MAILBOX        0
+#define E1000_VTIVAR_MISC_INTR_MASK      0x3
+
+/* External VLAN Enable bit mask */
+#define E1000_CTRL_EXT_EXT_VLAN      (1 << 26)
+
+/* External VLAN Ether Type bit mask and shift */
+#define E1000_VET_VET_EXT            0xFFFF0000
+#define E1000_VET_VET_EXT_SHIFT      16
+
+/* MSI-X other interrupt vector */
+#define IGB_MSIX_OTHER_INTR_VEC      0
+
 static int  eth_igb_configure(struct rte_eth_dev *dev);
 static int  eth_igb_start(struct rte_eth_dev *dev);
 static void eth_igb_stop(struct rte_eth_dev *dev);
+static int  eth_igb_dev_set_link_up(struct rte_eth_dev *dev);
+static int  eth_igb_dev_set_link_down(struct rte_eth_dev *dev);
 static void eth_igb_close(struct rte_eth_dev *dev);
+static int eth_igb_reset(struct rte_eth_dev *dev);
 static void eth_igb_promiscuous_enable(struct rte_eth_dev *dev);
 static void eth_igb_promiscuous_disable(struct rte_eth_dev *dev);
 static void eth_igb_allmulticast_enable(struct rte_eth_dev *dev);
 static void eth_igb_allmulticast_disable(struct rte_eth_dev *dev);
 static int  eth_igb_link_update(struct rte_eth_dev *dev,
                                int wait_to_complete);
-static void eth_igb_stats_get(struct rte_eth_dev *dev,
+static int eth_igb_stats_get(struct rte_eth_dev *dev,
                                struct rte_eth_stats *rte_stats);
 static int eth_igb_xstats_get(struct rte_eth_dev *dev,
-                             struct rte_eth_xstats *xstats, unsigned n);
+                             struct rte_eth_xstat *xstats, unsigned n);
+static int eth_igb_xstats_get_by_id(struct rte_eth_dev *dev,
+               const uint64_t *ids,
+               uint64_t *values, unsigned int n);
+static int eth_igb_xstats_get_names(struct rte_eth_dev *dev,
+                                   struct rte_eth_xstat_name *xstats_names,
+                                   unsigned int size);
+static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
+               struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+               unsigned int limit);
 static void eth_igb_stats_reset(struct rte_eth_dev *dev);
 static void eth_igb_xstats_reset(struct rte_eth_dev *dev);
+static int eth_igb_fw_version_get(struct rte_eth_dev *dev,
+                                  char *fw_version, size_t fw_size);
 static void eth_igb_infos_get(struct rte_eth_dev *dev,
                              struct rte_eth_dev_info *dev_info);
 static const uint32_t *eth_igb_supported_ptypes_get(struct rte_eth_dev *dev);
@@ -111,12 +111,12 @@ static int  eth_igb_flow_ctrl_get(struct rte_eth_dev *dev,
                                struct rte_eth_fc_conf *fc_conf);
 static int  eth_igb_flow_ctrl_set(struct rte_eth_dev *dev,
                                struct rte_eth_fc_conf *fc_conf);
-static int eth_igb_lsc_interrupt_setup(struct rte_eth_dev *dev);
+static int eth_igb_lsc_interrupt_setup(struct rte_eth_dev *dev, uint8_t on);
 static int eth_igb_rxq_interrupt_setup(struct rte_eth_dev *dev);
 static int eth_igb_interrupt_get_status(struct rte_eth_dev *dev);
-static int eth_igb_interrupt_action(struct rte_eth_dev *dev);
-static void eth_igb_interrupt_handler(struct rte_intr_handle *handle,
-                                                       void *param);
+static int eth_igb_interrupt_action(struct rte_eth_dev *dev,
+                                   struct rte_intr_handle *handle);
+static void eth_igb_interrupt_handler(void *param);
 static int  igb_hardware_init(struct e1000_hw *hw);
 static void igb_hw_control_acquire(struct e1000_hw *hw);
 static void igb_hw_control_release(struct e1000_hw *hw);
@@ -130,7 +130,7 @@ static int eth_igb_vlan_filter_set(struct rte_eth_dev *dev,
 static int eth_igb_vlan_tpid_set(struct rte_eth_dev *dev,
                                 enum rte_vlan_type vlan_type,
                                 uint16_t tpid_id);
-static void eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 
 static void igb_vlan_hw_filter_enable(struct rte_eth_dev *dev);
 static void igb_vlan_hw_filter_disable(struct rte_eth_dev *dev);
@@ -142,14 +142,14 @@ static void igb_vlan_hw_extend_disable(struct rte_eth_dev *dev);
 static int eth_igb_led_on(struct rte_eth_dev *dev);
 static int eth_igb_led_off(struct rte_eth_dev *dev);
 
-static void igb_intr_disable(struct e1000_hw *hw);
+static void igb_intr_disable(struct rte_eth_dev *dev);
 static int  igb_get_rx_buffer_size(struct e1000_hw *hw);
-static void eth_igb_rar_set(struct rte_eth_dev *dev,
-               struct ether_addr *mac_addr,
-               uint32_t index, uint32_t pool);
+static int eth_igb_rar_set(struct rte_eth_dev *dev,
+                          struct rte_ether_addr *mac_addr,
+                          uint32_t index, uint32_t pool);
 static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index);
-static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
-               struct ether_addr *addr);
+static int eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
+               struct rte_ether_addr *addr);
 
 static void igbvf_intr_disable(struct e1000_hw *hw);
 static int igbvf_dev_configure(struct rte_eth_dev *dev);
@@ -161,17 +161,20 @@ static void igbvf_promiscuous_disable(struct rte_eth_dev *dev);
 static void igbvf_allmulticast_enable(struct rte_eth_dev *dev);
 static void igbvf_allmulticast_disable(struct rte_eth_dev *dev);
 static int eth_igbvf_link_update(struct e1000_hw *hw);
-static void eth_igbvf_stats_get(struct rte_eth_dev *dev,
+static int eth_igbvf_stats_get(struct rte_eth_dev *dev,
                                struct rte_eth_stats *rte_stats);
 static int eth_igbvf_xstats_get(struct rte_eth_dev *dev,
-                               struct rte_eth_xstats *xstats, unsigned n);
+                               struct rte_eth_xstat *xstats, unsigned n);
+static int eth_igbvf_xstats_get_names(struct rte_eth_dev *dev,
+                                     struct rte_eth_xstat_name *xstats_names,
+                                     unsigned limit);
 static void eth_igbvf_stats_reset(struct rte_eth_dev *dev);
 static int igbvf_vlan_filter_set(struct rte_eth_dev *dev,
                uint16_t vlan_id, int on);
 static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on);
 static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on);
-static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
-               struct ether_addr *addr);
+static int igbvf_default_mac_addr_set(struct rte_eth_dev *dev,
+               struct rte_ether_addr *addr);
 static int igbvf_get_reg_length(struct rte_eth_dev *dev);
 static int igbvf_get_regs(struct rte_eth_dev *dev,
                struct rte_dev_reg_info *regs);
@@ -183,9 +186,6 @@ static int eth_igb_rss_reta_query(struct rte_eth_dev *dev,
                                  struct rte_eth_rss_reta_entry64 *reta_conf,
                                  uint16_t reta_size);
 
-static int eth_igb_syn_filter_set(struct rte_eth_dev *dev,
-                       struct rte_eth_syn_filter *filter,
-                       bool add);
 static int eth_igb_syn_filter_get(struct rte_eth_dev *dev,
                        struct rte_eth_syn_filter *filter);
 static int eth_igb_syn_filter_handle(struct rte_eth_dev *dev,
@@ -195,9 +195,6 @@ static int igb_add_2tuple_filter(struct rte_eth_dev *dev,
                        struct rte_eth_ntuple_filter *ntuple_filter);
 static int igb_remove_2tuple_filter(struct rte_eth_dev *dev,
                        struct rte_eth_ntuple_filter *ntuple_filter);
-static int eth_igb_add_del_flex_filter(struct rte_eth_dev *dev,
-                       struct rte_eth_flex_filter *filter,
-                       bool add);
 static int eth_igb_get_flex_filter(struct rte_eth_dev *dev,
                        struct rte_eth_flex_filter *filter);
 static int eth_igb_flex_filter_handle(struct rte_eth_dev *dev,
@@ -207,17 +204,11 @@ static int igb_add_5tuple_filter_82576(struct rte_eth_dev *dev,
                        struct rte_eth_ntuple_filter *ntuple_filter);
 static int igb_remove_5tuple_filter_82576(struct rte_eth_dev *dev,
                        struct rte_eth_ntuple_filter *ntuple_filter);
-static int igb_add_del_ntuple_filter(struct rte_eth_dev *dev,
-                       struct rte_eth_ntuple_filter *filter,
-                       bool add);
 static int igb_get_ntuple_filter(struct rte_eth_dev *dev,
                        struct rte_eth_ntuple_filter *filter);
 static int igb_ntuple_filter_handle(struct rte_eth_dev *dev,
                                enum rte_filter_op filter_op,
                                void *arg);
-static int igb_add_del_ethertype_filter(struct rte_eth_dev *dev,
-                       struct rte_eth_ethertype_filter *filter,
-                       bool add);
 static int igb_ethertype_filter_handle(struct rte_eth_dev *dev,
                                enum rte_filter_op filter_op,
                                void *arg);
@@ -235,8 +226,12 @@ static int eth_igb_get_eeprom(struct rte_eth_dev *dev,
                struct rte_dev_eeprom_info *eeprom);
 static int eth_igb_set_eeprom(struct rte_eth_dev *dev,
                struct rte_dev_eeprom_info *eeprom);
+static int eth_igb_get_module_info(struct rte_eth_dev *dev,
+                                  struct rte_eth_dev_module_info *modinfo);
+static int eth_igb_get_module_eeprom(struct rte_eth_dev *dev,
+                                    struct rte_dev_eeprom_info *info);
 static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
-                                   struct ether_addr *mc_addr_set,
+                                   struct rte_ether_addr *mc_addr_set,
                                    uint32_t nb_mc_addr);
 static int igb_timesync_enable(struct rte_eth_dev *dev);
 static int igb_timesync_disable(struct rte_eth_dev *dev);
@@ -259,6 +254,9 @@ static void eth_igb_assign_msix_vector(struct e1000_hw *hw, int8_t direction,
 static void eth_igb_write_ivar(struct e1000_hw *hw, uint8_t msix_vector,
                               uint8_t index, uint8_t offset);
 static void eth_igb_configure_msix_intr(struct rte_eth_dev *dev);
+static void eth_igbvf_interrupt_handler(void *param);
+static void igbvf_mbx_process(struct rte_eth_dev *dev);
+static int igb_filter_restore(struct rte_eth_dev *dev);
 
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
@@ -282,22 +280,59 @@ static enum e1000_fc_mode igb_fc_setting = e1000_fc_full;
  * The set of PCI devices this driver supports
  */
 static const struct rte_pci_id pci_id_igb_map[] = {
-
-#define RTE_PCI_DEV_ID_DECL_IGB(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
-#include "rte_pci_dev_ids.h"
-
-{0},
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82576) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82576_FIBER) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82576_SERDES) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82576_QUAD_COPPER) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82576_QUAD_COPPER_ET2) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82576_NS) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82576_NS_SERDES) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82576_SERDES_QUAD) },
+
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82575EB_COPPER) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82575EB_FIBER_SERDES) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82575GB_QUAD_COPPER) },
+
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82580_COPPER) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82580_FIBER) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82580_SERDES) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82580_SGMII) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82580_COPPER_DUAL) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82580_QUAD_FIBER) },
+
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I350_COPPER) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I350_FIBER) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I350_SERDES) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I350_SGMII) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I350_DA4) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I210_COPPER) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I210_COPPER_OEM1) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I210_COPPER_IT) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I210_FIBER) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I210_SERDES) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I210_SGMII) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I210_COPPER_FLASHLESS) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I210_SERDES_FLASHLESS) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I211_COPPER) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I354_BACKPLANE_1GBPS) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I354_SGMII) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I354_BACKPLANE_2_5GBPS) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_DH89XXCC_SGMII) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_DH89XXCC_SERDES) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_DH89XXCC_BACKPLANE) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_DH89XXCC_SFP) },
+       { .vendor_id = 0, /* sentinel */ },
 };
 
 /*
  * The set of PCI devices this driver supports (for 82576&I350 VF)
  */
 static const struct rte_pci_id pci_id_igbvf_map[] = {
-
-#define RTE_PCI_DEV_ID_DECL_IGBVF(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
-#include "rte_pci_dev_ids.h"
-
-{0},
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82576_VF) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_82576_VF_HV) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I350_VF) },
+       { RTE_PCI_DEVICE(E1000_INTEL_VENDOR_ID, E1000_DEV_ID_I350_VF_HV) },
+       { .vendor_id = 0, /* sentinel */ },
 };
 
 static const struct rte_eth_desc_lim rx_desc_lim = {
@@ -310,13 +345,18 @@ static const struct rte_eth_desc_lim tx_desc_lim = {
        .nb_max = E1000_MAX_RING_DESC,
        .nb_min = E1000_MIN_RING_DESC,
        .nb_align = IGB_RXD_ALIGN,
+       .nb_seg_max = IGB_TX_MAX_SEG,
+       .nb_mtu_seg_max = IGB_TX_MAX_MTU_SEG,
 };
 
 static const struct eth_dev_ops eth_igb_ops = {
        .dev_configure        = eth_igb_configure,
        .dev_start            = eth_igb_start,
        .dev_stop             = eth_igb_stop,
+       .dev_set_link_up      = eth_igb_dev_set_link_up,
+       .dev_set_link_down    = eth_igb_dev_set_link_down,
        .dev_close            = eth_igb_close,
+       .dev_reset            = eth_igb_reset,
        .promiscuous_enable   = eth_igb_promiscuous_enable,
        .promiscuous_disable  = eth_igb_promiscuous_disable,
        .allmulticast_enable  = eth_igb_allmulticast_enable,
@@ -324,8 +364,12 @@ static const struct eth_dev_ops eth_igb_ops = {
        .link_update          = eth_igb_link_update,
        .stats_get            = eth_igb_stats_get,
        .xstats_get           = eth_igb_xstats_get,
+       .xstats_get_by_id     = eth_igb_xstats_get_by_id,
+       .xstats_get_names_by_id = eth_igb_xstats_get_names_by_id,
+       .xstats_get_names     = eth_igb_xstats_get_names,
        .stats_reset          = eth_igb_stats_reset,
        .xstats_reset         = eth_igb_xstats_reset,
+       .fw_version_get       = eth_igb_fw_version_get,
        .dev_infos_get        = eth_igb_infos_get,
        .dev_supported_ptypes_get = eth_igb_supported_ptypes_get,
        .mtu_set              = eth_igb_mtu_set,
@@ -338,8 +382,11 @@ static const struct eth_dev_ops eth_igb_ops = {
        .rx_queue_release     = eth_igb_rx_queue_release,
        .rx_queue_count       = eth_igb_rx_queue_count,
        .rx_descriptor_done   = eth_igb_rx_descriptor_done,
+       .rx_descriptor_status = eth_igb_rx_descriptor_status,
+       .tx_descriptor_status = eth_igb_tx_descriptor_status,
        .tx_queue_setup       = eth_igb_tx_queue_setup,
        .tx_queue_release     = eth_igb_tx_queue_release,
+       .tx_done_cleanup      = eth_igb_tx_done_cleanup,
        .dev_led_on           = eth_igb_led_on,
        .dev_led_off          = eth_igb_led_off,
        .flow_ctrl_get        = eth_igb_flow_ctrl_get,
@@ -359,11 +406,12 @@ static const struct eth_dev_ops eth_igb_ops = {
        .timesync_disable     = igb_timesync_disable,
        .timesync_read_rx_timestamp = igb_timesync_read_rx_timestamp,
        .timesync_read_tx_timestamp = igb_timesync_read_tx_timestamp,
-       .get_reg_length       = eth_igb_get_reg_length,
        .get_reg              = eth_igb_get_regs,
        .get_eeprom_length    = eth_igb_get_eeprom_length,
        .get_eeprom           = eth_igb_get_eeprom,
        .set_eeprom           = eth_igb_set_eeprom,
+       .get_module_info      = eth_igb_get_module_info,
+       .get_module_eeprom    = eth_igb_get_module_eeprom,
        .timesync_adjust_time = igb_timesync_adjust_time,
        .timesync_read_time   = igb_timesync_read_time,
        .timesync_write_time  = igb_timesync_write_time,
@@ -385,6 +433,7 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
        .link_update          = eth_igb_link_update,
        .stats_get            = eth_igbvf_stats_get,
        .xstats_get           = eth_igbvf_xstats_get,
+       .xstats_get_names     = eth_igbvf_xstats_get_names,
        .stats_reset          = eth_igbvf_stats_reset,
        .xstats_reset         = eth_igbvf_stats_reset,
        .vlan_filter_set      = igbvf_vlan_filter_set,
@@ -392,13 +441,15 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = {
        .dev_supported_ptypes_get = eth_igb_supported_ptypes_get,
        .rx_queue_setup       = eth_igb_rx_queue_setup,
        .rx_queue_release     = eth_igb_rx_queue_release,
+       .rx_descriptor_done   = eth_igb_rx_descriptor_done,
+       .rx_descriptor_status = eth_igb_rx_descriptor_status,
+       .tx_descriptor_status = eth_igb_tx_descriptor_status,
        .tx_queue_setup       = eth_igb_tx_queue_setup,
        .tx_queue_release     = eth_igb_tx_queue_release,
        .set_mc_addr_list     = eth_igb_set_mc_addr_list,
        .rxq_info_get         = igb_rxq_info_get,
        .txq_info_get         = igb_txq_info_get,
        .mac_addr_set         = igbvf_default_mac_addr_set,
-       .get_reg_length       = igbvf_get_reg_length,
        .get_reg              = igbvf_get_regs,
 };
 
@@ -483,75 +534,76 @@ static const struct rte_igb_xstats_name_off rte_igbvf_stats_strings[] = {
 #define IGBVF_NB_XSTATS (sizeof(rte_igbvf_stats_strings) / \
                sizeof(rte_igbvf_stats_strings[0]))
 
-/**
- * Atomically reads the link status information from global
- * structure rte_eth_dev.
- *
- * @param dev
- *   - Pointer to the structure rte_eth_dev to read from.
- *   - Pointer to the buffer to be saved with the link status.
- *
- * @return
- *   - On success, zero.
- *   - On failure, negative value.
- */
-static inline int
-rte_igb_dev_atomic_read_link_status(struct rte_eth_dev *dev,
-                               struct rte_eth_link *link)
+
+static inline void
+igb_intr_enable(struct rte_eth_dev *dev)
 {
-       struct rte_eth_link *dst = link;
-       struct rte_eth_link *src = &(dev->data->dev_link);
+       struct e1000_interrupt *intr =
+               E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
+       struct e1000_hw *hw =
+               E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
-       if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
-                                       *(uint64_t *)src) == 0)
-               return -1;
+       if (rte_intr_allow_others(intr_handle) &&
+               dev->data->dev_conf.intr_conf.lsc != 0) {
+               E1000_WRITE_REG(hw, E1000_EIMS, 1 << IGB_MSIX_OTHER_INTR_VEC);
+       }
 
-       return 0;
+       E1000_WRITE_REG(hw, E1000_IMS, intr->mask);
+       E1000_WRITE_FLUSH(hw);
 }
 
-/**
- * Atomically writes the link status information into global
- * structure rte_eth_dev.
- *
- * @param dev
- *   - Pointer to the structure rte_eth_dev to read from.
- *   - Pointer to the buffer to be saved with the link status.
- *
- * @return
- *   - On success, zero.
- *   - On failure, negative value.
- */
-static inline int
-rte_igb_dev_atomic_write_link_status(struct rte_eth_dev *dev,
-                               struct rte_eth_link *link)
+static void
+igb_intr_disable(struct rte_eth_dev *dev)
 {
-       struct rte_eth_link *dst = &(dev->data->dev_link);
-       struct rte_eth_link *src = link;
+       struct e1000_hw *hw =
+               E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
-       if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
-                                       *(uint64_t *)src) == 0)
-               return -1;
+       if (rte_intr_allow_others(intr_handle) &&
+               dev->data->dev_conf.intr_conf.lsc != 0) {
+               E1000_WRITE_REG(hw, E1000_EIMC, 1 << IGB_MSIX_OTHER_INTR_VEC);
+       }
 
-       return 0;
+       E1000_WRITE_REG(hw, E1000_IMC, ~0);
+       E1000_WRITE_FLUSH(hw);
 }
 
 static inline void
-igb_intr_enable(struct rte_eth_dev *dev)
+igbvf_intr_enable(struct rte_eth_dev *dev)
 {
-       struct e1000_interrupt *intr =
-               E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-       E1000_WRITE_REG(hw, E1000_IMS, intr->mask);
+       /* only for mailbox */
+       E1000_WRITE_REG(hw, E1000_EIAM, 1 << E1000_VTIVAR_MISC_MAILBOX);
+       E1000_WRITE_REG(hw, E1000_EIAC, 1 << E1000_VTIVAR_MISC_MAILBOX);
+       E1000_WRITE_REG(hw, E1000_EIMS, 1 << E1000_VTIVAR_MISC_MAILBOX);
        E1000_WRITE_FLUSH(hw);
 }
 
+/* only for mailbox now. If RX/TX needed, should extend this function.  */
 static void
-igb_intr_disable(struct e1000_hw *hw)
+igbvf_set_ivar_map(struct e1000_hw *hw, uint8_t msix_vector)
 {
-       E1000_WRITE_REG(hw, E1000_IMC, ~0);
-       E1000_WRITE_FLUSH(hw);
+       uint32_t tmp = 0;
+
+       /* mailbox */
+       tmp |= (msix_vector & E1000_VTIVAR_MISC_INTR_MASK);
+       tmp |= E1000_VTIVAR_VALID;
+       E1000_WRITE_REG(hw, E1000_VTIVAR_MISC, tmp);
+}
+
+static void
+eth_igbvf_configure_msix_intr(struct rte_eth_dev *dev)
+{
+       struct e1000_hw *hw =
+               E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       /* Configure VF other cause ivar */
+       igbvf_set_ivar_map(hw, E1000_VTIVAR_MISC_MAILBOX);
 }
 
 static inline int32_t
@@ -572,15 +624,16 @@ igb_pf_reset_hw(struct e1000_hw *hw)
 }
 
 static void
-igb_identify_hardware(struct rte_eth_dev *dev)
+igb_identify_hardware(struct rte_eth_dev *dev, struct rte_pci_device *pci_dev)
 {
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-       hw->vendor_id = dev->pci_dev->id.vendor_id;
-       hw->device_id = dev->pci_dev->id.device_id;
-       hw->subsystem_vendor_id = dev->pci_dev->id.subsystem_vendor_id;
-       hw->subsystem_device_id = dev->pci_dev->id.subsystem_device_id;
+
+       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;
 
        e1000_set_mac_type(hw);
 
@@ -643,11 +696,51 @@ igb_reset_swfw_lock(struct e1000_hw *hw)
        return E1000_SUCCESS;
 }
 
+/* Remove all ntuple filters of the device */
+static int igb_ntuple_filter_uninit(struct rte_eth_dev *eth_dev)
+{
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(eth_dev->data->dev_private);
+       struct e1000_5tuple_filter *p_5tuple;
+       struct e1000_2tuple_filter *p_2tuple;
+
+       while ((p_5tuple = TAILQ_FIRST(&filter_info->fivetuple_list))) {
+               TAILQ_REMOVE(&filter_info->fivetuple_list,
+                       p_5tuple, entries);
+                       rte_free(p_5tuple);
+       }
+       filter_info->fivetuple_mask = 0;
+       while ((p_2tuple = TAILQ_FIRST(&filter_info->twotuple_list))) {
+               TAILQ_REMOVE(&filter_info->twotuple_list,
+                       p_2tuple, entries);
+                       rte_free(p_2tuple);
+       }
+       filter_info->twotuple_mask = 0;
+
+       return 0;
+}
+
+/* Remove all flex filters of the device */
+static int igb_flex_filter_uninit(struct rte_eth_dev *eth_dev)
+{
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(eth_dev->data->dev_private);
+       struct e1000_flex_filter *p_flex;
+
+       while ((p_flex = TAILQ_FIRST(&filter_info->flex_list))) {
+               TAILQ_REMOVE(&filter_info->flex_list, p_flex, entries);
+               rte_free(p_flex);
+       }
+       filter_info->flex_mask = 0;
+
+       return 0;
+}
+
 static int
 eth_igb_dev_init(struct rte_eth_dev *eth_dev)
 {
        int error = 0;
-       struct rte_pci_device *pci_dev;
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
        struct e1000_vfta * shadow_vfta =
@@ -659,11 +752,10 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
 
        uint32_t ctrl_ext;
 
-       pci_dev = eth_dev->pci_dev;
-
        eth_dev->dev_ops = &eth_igb_ops;
        eth_dev->rx_pkt_burst = &eth_igb_recv_pkts;
        eth_dev->tx_pkt_burst = &eth_igb_xmit_pkts;
+       eth_dev->tx_pkt_prepare = &eth_igb_prep_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
@@ -678,7 +770,7 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
 
        hw->hw_addr= (void *)pci_dev->mem_resource[0].addr;
 
-       igb_identify_hardware(eth_dev);
+       igb_identify_hardware(eth_dev, pci_dev);
        if (e1000_setup_init_funcs(hw, FALSE) != E1000_SUCCESS) {
                error = -EIO;
                goto err_late;
@@ -748,7 +840,8 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
        }
 
        /* Copy the permanent MAC address */
-       ether_addr_copy((struct ether_addr *)hw->mac.addr, &eth_dev->data->mac_addrs[0]);
+       ether_addr_copy((struct rte_ether_addr *)hw->mac.addr,
+                       &eth_dev->data->mac_addrs[0]);
 
        /* initialize the vfta */
        memset(shadow_vfta, 0, sizeof(*shadow_vfta));
@@ -793,12 +886,20 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev)
        /* enable support intr */
        igb_intr_enable(eth_dev);
 
+       /* initialize filter info */
+       memset(filter_info, 0,
+              sizeof(struct e1000_filter_info));
+
        TAILQ_INIT(&filter_info->flex_list);
-       filter_info->flex_mask = 0;
        TAILQ_INIT(&filter_info->twotuple_list);
-       filter_info->twotuple_mask = 0;
        TAILQ_INIT(&filter_info->fivetuple_list);
-       filter_info->fivetuple_mask = 0;
+
+       TAILQ_INIT(&igb_filter_ntuple_list);
+       TAILQ_INIT(&igb_filter_ethertype_list);
+       TAILQ_INIT(&igb_filter_syn_list);
+       TAILQ_INIT(&igb_filter_flex_list);
+       TAILQ_INIT(&igb_filter_rss_list);
+       TAILQ_INIT(&igb_flow_list);
 
        return 0;
 
@@ -812,9 +913,12 @@ static int
 eth_igb_dev_uninit(struct rte_eth_dev *eth_dev)
 {
        struct rte_pci_device *pci_dev;
+       struct rte_intr_handle *intr_handle;
        struct e1000_hw *hw;
        struct e1000_adapter *adapter =
                E1000_DEV_PRIVATE(eth_dev->data->dev_private);
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(eth_dev->data->dev_private);
 
        PMD_INIT_FUNC_TRACE();
 
@@ -822,7 +926,8 @@ eth_igb_dev_uninit(struct rte_eth_dev *eth_dev)
                return -EPERM;
 
        hw = E1000_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
-       pci_dev = eth_dev->pci_dev;
+       pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+       intr_handle = &pci_dev->intr_handle;
 
        if (adapter->stopped == 0)
                eth_igb_close(eth_dev);
@@ -834,16 +939,34 @@ eth_igb_dev_uninit(struct rte_eth_dev *eth_dev)
        /* Reset any pending lock */
        igb_reset_swfw_lock(hw);
 
-       rte_free(eth_dev->data->mac_addrs);
-       eth_dev->data->mac_addrs = NULL;
-
        /* uninitialize PF if max_vfs not zero */
        igb_pf_host_uninit(eth_dev);
 
        /* disable uio intr before callback unregister */
-       rte_intr_disable(&(pci_dev->intr_handle));
-       rte_intr_callback_unregister(&(pci_dev->intr_handle),
-               eth_igb_interrupt_handler, (void *)eth_dev);
+       rte_intr_disable(intr_handle);
+       rte_intr_callback_unregister(intr_handle,
+                                    eth_igb_interrupt_handler, eth_dev);
+
+       /* clear the SYN filter info */
+       filter_info->syn_info = 0;
+
+       /* clear the ethertype filters info */
+       filter_info->ethertype_mask = 0;
+       memset(filter_info->ethertype_filters, 0,
+               E1000_MAX_ETQF_FILTERS * sizeof(struct igb_ethertype_filter));
+
+       /* clear the rss filter info */
+       memset(&filter_info->rss_info, 0,
+               sizeof(struct igb_rte_flow_rss_conf));
+
+       /* remove all ntuple filters of the device */
+       igb_ntuple_filter_uninit(eth_dev);
+
+       /* remove all flex filters of the device */
+       igb_flex_filter_uninit(eth_dev);
+
+       /* clear all the filters list */
+       igb_filterlist_flush(eth_dev);
 
        return 0;
 }
@@ -855,18 +978,21 @@ static int
 eth_igbvf_dev_init(struct rte_eth_dev *eth_dev)
 {
        struct rte_pci_device *pci_dev;
+       struct rte_intr_handle *intr_handle;
        struct e1000_adapter *adapter =
                E1000_DEV_PRIVATE(eth_dev->data->dev_private);
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
        int diag;
-       struct ether_addr *perm_addr = (struct ether_addr *)hw->mac.perm_addr;
+       struct rte_ether_addr *perm_addr =
+               (struct rte_ether_addr *)hw->mac.perm_addr;
 
        PMD_INIT_FUNC_TRACE();
 
        eth_dev->dev_ops = &igbvf_eth_dev_ops;
        eth_dev->rx_pkt_burst = &eth_igb_recv_pkts;
        eth_dev->tx_pkt_burst = &eth_igb_xmit_pkts;
+       eth_dev->tx_pkt_prepare = &eth_igb_prep_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
@@ -877,8 +1003,7 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev)
                return 0;
        }
 
-       pci_dev = eth_dev->pci_dev;
-
+       pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
        rte_eth_copy_pci_info(eth_dev, pci_dev);
 
        hw->device_id = pci_dev->id.device_id;
@@ -916,12 +1041,6 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev)
        /* Generate a random MAC address, if none was assigned by PF. */
        if (is_zero_ether_addr(perm_addr)) {
                eth_random_addr(perm_addr->addr_bytes);
-               diag = e1000_rar_set(hw, perm_addr->addr_bytes, 0);
-               if (diag) {
-                       rte_free(eth_dev->data->mac_addrs);
-                       eth_dev->data->mac_addrs = NULL;
-                       return diag;
-               }
                PMD_INIT_LOG(INFO, "\tVF MAC address not assigned by Host PF");
                PMD_INIT_LOG(INFO, "\tAssign randomly generated MAC address "
                             "%02x:%02x:%02x:%02x:%02x:%02x",
@@ -933,8 +1052,14 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev)
                             perm_addr->addr_bytes[5]);
        }
 
+       diag = e1000_rar_set(hw, perm_addr->addr_bytes, 0);
+       if (diag) {
+               rte_free(eth_dev->data->mac_addrs);
+               eth_dev->data->mac_addrs = NULL;
+               return diag;
+       }
        /* Copy the permanent MAC address */
-       ether_addr_copy((struct ether_addr *) hw->mac.perm_addr,
+       ether_addr_copy((struct rte_ether_addr *)hw->mac.perm_addr,
                        &eth_dev->data->mac_addrs[0]);
 
        PMD_INIT_LOG(DEBUG, "port %d vendorID=0x%x deviceID=0x%x "
@@ -942,6 +1067,10 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev)
                     eth_dev->data->port_id, pci_dev->id.vendor_id,
                     pci_dev->id.device_id, "igb_mac_82576_vf");
 
+       intr_handle = &pci_dev->intr_handle;
+       rte_intr_callback_register(intr_handle,
+                                  eth_igbvf_interrupt_handler, eth_dev);
+
        return 0;
 }
 
@@ -950,6 +1079,7 @@ eth_igbvf_dev_uninit(struct rte_eth_dev *eth_dev)
 {
        struct e1000_adapter *adapter =
                E1000_DEV_PRIVATE(eth_dev->data->dev_private);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
 
        PMD_INIT_FUNC_TRACE();
 
@@ -963,45 +1093,58 @@ eth_igbvf_dev_uninit(struct rte_eth_dev *eth_dev)
        eth_dev->rx_pkt_burst = NULL;
        eth_dev->tx_pkt_burst = NULL;
 
-       rte_free(eth_dev->data->mac_addrs);
-       eth_dev->data->mac_addrs = NULL;
+       /* disable uio intr before callback unregister */
+       rte_intr_disable(&pci_dev->intr_handle);
+       rte_intr_callback_unregister(&pci_dev->intr_handle,
+                                    eth_igbvf_interrupt_handler,
+                                    (void *)eth_dev);
 
        return 0;
 }
 
-static struct eth_driver rte_igb_pmd = {
-       .pci_drv = {
-               .name = "rte_igb_pmd",
-               .id_table = pci_id_igb_map,
-               .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
-                       RTE_PCI_DRV_DETACHABLE,
-       },
-       .eth_dev_init = eth_igb_dev_init,
-       .eth_dev_uninit = eth_igb_dev_uninit,
-       .dev_private_size = sizeof(struct e1000_adapter),
+static int eth_igb_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+       struct rte_pci_device *pci_dev)
+{
+       return rte_eth_dev_pci_generic_probe(pci_dev,
+               sizeof(struct e1000_adapter), eth_igb_dev_init);
+}
+
+static int eth_igb_pci_remove(struct rte_pci_device *pci_dev)
+{
+       return rte_eth_dev_pci_generic_remove(pci_dev, eth_igb_dev_uninit);
+}
+
+static struct rte_pci_driver rte_igb_pmd = {
+       .id_table = pci_id_igb_map,
+       .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
+                    RTE_PCI_DRV_IOVA_AS_VA,
+       .probe = eth_igb_pci_probe,
+       .remove = eth_igb_pci_remove,
 };
 
+
+static int eth_igbvf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+       struct rte_pci_device *pci_dev)
+{
+       return rte_eth_dev_pci_generic_probe(pci_dev,
+               sizeof(struct e1000_adapter), eth_igbvf_dev_init);
+}
+
+static int eth_igbvf_pci_remove(struct rte_pci_device *pci_dev)
+{
+       return rte_eth_dev_pci_generic_remove(pci_dev, eth_igbvf_dev_uninit);
+}
+
 /*
  * virtual function driver struct
  */
-static struct eth_driver rte_igbvf_pmd = {
-       .pci_drv = {
-               .name = "rte_igbvf_pmd",
-               .id_table = pci_id_igbvf_map,
-               .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_DETACHABLE,
-       },
-       .eth_dev_init = eth_igbvf_dev_init,
-       .eth_dev_uninit = eth_igbvf_dev_uninit,
-       .dev_private_size = sizeof(struct e1000_adapter),
+static struct rte_pci_driver rte_igbvf_pmd = {
+       .id_table = pci_id_igbvf_map,
+       .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_IOVA_AS_VA,
+       .probe = eth_igbvf_pci_probe,
+       .remove = eth_igbvf_pci_remove,
 };
 
-static int
-rte_igb_pmd_init(const char *name __rte_unused, const char *params __rte_unused)
-{
-       rte_eth_driver_register(&rte_igb_pmd);
-       return 0;
-}
-
 static void
 igb_vmdq_vlan_hw_filter_enable(struct rte_eth_dev *dev)
 {
@@ -1013,27 +1156,13 @@ igb_vmdq_vlan_hw_filter_enable(struct rte_eth_dev *dev)
        E1000_WRITE_REG(hw, E1000_RCTL, rctl);
 }
 
-/*
- * VF Driver initialization routine.
- * Invoked one at EAL init time.
- * Register itself as the [Virtual Poll Mode] Driver of PCI IGB devices.
- */
-static int
-rte_igbvf_pmd_init(const char *name __rte_unused, const char *params __rte_unused)
-{
-       PMD_INIT_FUNC_TRACE();
-
-       rte_eth_driver_register(&rte_igbvf_pmd);
-       return 0;
-}
-
 static int
 igb_check_mq_mode(struct rte_eth_dev *dev)
 {
        enum rte_eth_rx_mq_mode rx_mq_mode = dev->data->dev_conf.rxmode.mq_mode;
        enum rte_eth_tx_mq_mode tx_mq_mode = dev->data->dev_conf.txmode.mq_mode;
        uint16_t nb_rx_q = dev->data->nb_rx_queues;
-       uint16_t nb_tx_q = dev->data->nb_rx_queues;
+       uint16_t nb_tx_q = dev->data->nb_tx_queues;
 
        if ((rx_mq_mode & ETH_MQ_RX_DCB_FLAG) ||
            tx_mq_mode == ETH_MQ_TX_DCB ||
@@ -1122,6 +1251,31 @@ eth_igb_configure(struct rte_eth_dev *dev)
        return 0;
 }
 
+static void
+eth_igb_rxtx_control(struct rte_eth_dev *dev,
+                    bool enable)
+{
+       struct e1000_hw *hw =
+               E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t tctl, rctl;
+
+       tctl = E1000_READ_REG(hw, E1000_TCTL);
+       rctl = E1000_READ_REG(hw, E1000_RCTL);
+
+       if (enable) {
+               /* enable Tx/Rx */
+               tctl |= E1000_TCTL_EN;
+               rctl |= E1000_RCTL_EN;
+       } else {
+               /* disable Tx/Rx */
+               tctl &= ~E1000_TCTL_EN;
+               rctl &= ~E1000_RCTL_EN;
+       }
+       E1000_WRITE_REG(hw, E1000_TCTL, tctl);
+       E1000_WRITE_REG(hw, E1000_RCTL, rctl);
+       E1000_WRITE_FLUSH(hw);
+}
+
 static int
 eth_igb_start(struct rte_eth_dev *dev)
 {
@@ -1129,7 +1283,8 @@ eth_igb_start(struct rte_eth_dev *dev)
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct e1000_adapter *adapter =
                E1000_DEV_PRIVATE(dev->data->dev_private);
-       struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
        int ret, mask;
        uint32_t intr_vector = 0;
        uint32_t ctrl_ext;
@@ -1143,7 +1298,7 @@ eth_igb_start(struct rte_eth_dev *dev)
        rte_intr_disable(intr_handle);
 
        /* Power up the phy. Needed to make the link go Up */
-       e1000_power_up_phy(hw);
+       eth_igb_dev_set_link_up(dev);
 
        /*
         * Packet Buffer Allocation (PBA)
@@ -1193,7 +1348,7 @@ eth_igb_start(struct rte_eth_dev *dev)
                                    dev->data->nb_rx_queues * sizeof(int), 0);
                if (intr_handle->intr_vec == NULL) {
                        PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
-                                    " intr_vec\n", dev->data->nb_rx_queues);
+                                    " intr_vec", dev->data->nb_rx_queues);
                        return -ENOMEM;
                }
        }
@@ -1221,7 +1376,12 @@ eth_igb_start(struct rte_eth_dev *dev)
         */
        mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \
                        ETH_VLAN_EXTEND_MASK;
-       eth_igb_vlan_offload_set(dev, mask);
+       ret = eth_igb_vlan_offload_set(dev, mask);
+       if (ret) {
+               PMD_INIT_LOG(ERR, "Unable to set vlan offload");
+               igb_dev_clear_queues(dev);
+               return ret;
+       }
 
        if (dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_VMDQ_ONLY) {
                /* Enable VLAN filter since VMDq always use VLAN filter */
@@ -1239,6 +1399,7 @@ eth_igb_start(struct rte_eth_dev *dev)
        speeds = &dev->data->dev_conf.link_speeds;
        if (*speeds == ETH_LINK_SPEED_AUTONEG) {
                hw->phy.autoneg_advertised = E1000_ALL_SPEED_DUPLEX;
+               hw->mac.autoneg = 1;
        } else {
                num_speeds = 0;
                autoneg = (*speeds & ETH_LINK_SPEED_FIXED) == 0;
@@ -1274,6 +1435,17 @@ eth_igb_start(struct rte_eth_dev *dev)
                }
                if (num_speeds == 0 || (!autoneg && (num_speeds > 1)))
                        goto error_invalid_config;
+
+               /* Set/reset the mac.autoneg based on the link speed,
+                * fixed or not
+                */
+               if (!autoneg) {
+                       hw->mac.autoneg = 0;
+                       hw->mac.forced_speed_duplex =
+                                       hw->phy.autoneg_advertised;
+               } else {
+                       hw->mac.autoneg = 1;
+               }
        }
 
        e1000_setup_link(hw);
@@ -1281,14 +1453,16 @@ eth_igb_start(struct rte_eth_dev *dev)
        if (rte_intr_allow_others(intr_handle)) {
                /* check if lsc interrupt is enabled */
                if (dev->data->dev_conf.intr_conf.lsc != 0)
-                       eth_igb_lsc_interrupt_setup(dev);
+                       eth_igb_lsc_interrupt_setup(dev, TRUE);
+               else
+                       eth_igb_lsc_interrupt_setup(dev, FALSE);
        } else {
                rte_intr_callback_unregister(intr_handle,
                                             eth_igb_interrupt_handler,
                                             (void *)dev);
                if (dev->data->dev_conf.intr_conf.lsc != 0)
                        PMD_INIT_LOG(INFO, "lsc won't enable because of"
-                                    " no intr multiplex\n");
+                                    " no intr multiplex");
        }
 
        /* check if rxq interrupt is enabled */
@@ -1302,6 +1476,12 @@ eth_igb_start(struct rte_eth_dev *dev)
        /* resume enabled intr since hw reset */
        igb_intr_enable(dev);
 
+       /* restore all types filter */
+       igb_filter_restore(dev);
+
+       eth_igb_rxtx_control(dev, true);
+       eth_igb_link_update(dev, 0);
+
        PMD_INIT_LOG(DEBUG, "<<");
 
        return 0;
@@ -1323,15 +1503,13 @@ static void
 eth_igb_stop(struct rte_eth_dev *dev)
 {
        struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       struct e1000_filter_info *filter_info =
-               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_eth_link link;
-       struct e1000_flex_filter *p_flex;
-       struct e1000_5tuple_filter *p_5tuple, *p_5tuple_next;
-       struct e1000_2tuple_filter *p_2tuple, *p_2tuple_next;
-       struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+       struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
-       igb_intr_disable(hw);
+       eth_igb_rxtx_control(dev, false);
+
+       igb_intr_disable(dev);
 
        /* disable intr eventfd mapping */
        rte_intr_disable(intr_handle);
@@ -1349,41 +1527,13 @@ eth_igb_stop(struct rte_eth_dev *dev)
        }
 
        /* Power down the phy. Needed to make the link go Down */
-       if (hw->phy.media_type == e1000_media_type_copper)
-               e1000_power_down_phy(hw);
-       else
-               e1000_shutdown_fiber_serdes_link(hw);
+       eth_igb_dev_set_link_down(dev);
 
        igb_dev_clear_queues(dev);
 
        /* clear the recorded link status */
        memset(&link, 0, sizeof(link));
-       rte_igb_dev_atomic_write_link_status(dev, &link);
-
-       /* Remove all flex filters of the device */
-       while ((p_flex = TAILQ_FIRST(&filter_info->flex_list))) {
-               TAILQ_REMOVE(&filter_info->flex_list, p_flex, entries);
-               rte_free(p_flex);
-       }
-       filter_info->flex_mask = 0;
-
-       /* Remove all ntuple filters of the device */
-       for (p_5tuple = TAILQ_FIRST(&filter_info->fivetuple_list);
-            p_5tuple != NULL; p_5tuple = p_5tuple_next) {
-               p_5tuple_next = TAILQ_NEXT(p_5tuple, entries);
-               TAILQ_REMOVE(&filter_info->fivetuple_list,
-                            p_5tuple, entries);
-               rte_free(p_5tuple);
-       }
-       filter_info->fivetuple_mask = 0;
-       for (p_2tuple = TAILQ_FIRST(&filter_info->twotuple_list);
-            p_2tuple != NULL; p_2tuple = p_2tuple_next) {
-               p_2tuple_next = TAILQ_NEXT(p_2tuple, entries);
-               TAILQ_REMOVE(&filter_info->twotuple_list,
-                            p_2tuple, entries);
-               rte_free(p_2tuple);
-       }
-       filter_info->twotuple_mask = 0;
+       rte_eth_linkstatus_set(dev, &link);
 
        if (!rte_intr_allow_others(intr_handle))
                /* resume to the default handler */
@@ -1399,6 +1549,32 @@ eth_igb_stop(struct rte_eth_dev *dev)
        }
 }
 
+static int
+eth_igb_dev_set_link_up(struct rte_eth_dev *dev)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       if (hw->phy.media_type == e1000_media_type_copper)
+               e1000_power_up_phy(hw);
+       else
+               e1000_power_up_fiber_serdes_link(hw);
+
+       return 0;
+}
+
+static int
+eth_igb_dev_set_link_down(struct rte_eth_dev *dev)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       if (hw->phy.media_type == e1000_media_type_copper)
+               e1000_power_down_phy(hw);
+       else
+               e1000_shutdown_fiber_serdes_link(hw);
+
+       return 0;
+}
+
 static void
 eth_igb_close(struct rte_eth_dev *dev)
 {
@@ -1406,7 +1582,8 @@ eth_igb_close(struct rte_eth_dev *dev)
        struct e1000_adapter *adapter =
                E1000_DEV_PRIVATE(dev->data->dev_private);
        struct rte_eth_link link;
-       struct rte_pci_device *pci_dev;
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
        eth_igb_stop(dev);
        adapter->stopped = 1;
@@ -1426,16 +1603,42 @@ eth_igb_close(struct rte_eth_dev *dev)
 
        igb_dev_free_queues(dev);
 
-       pci_dev = dev->pci_dev;
-       if (pci_dev->intr_handle.intr_vec) {
-               rte_free(pci_dev->intr_handle.intr_vec);
-               pci_dev->intr_handle.intr_vec = NULL;
+       if (intr_handle->intr_vec) {
+               rte_free(intr_handle->intr_vec);
+               intr_handle->intr_vec = NULL;
        }
 
        memset(&link, 0, sizeof(link));
-       rte_igb_dev_atomic_write_link_status(dev, &link);
+       rte_eth_linkstatus_set(dev, &link);
+}
+
+/*
+ * Reset PF device.
+ */
+static int
+eth_igb_reset(struct rte_eth_dev *dev)
+{
+       int ret;
+
+       /* When a DPDK PMD PF begin to reset PF port, it should notify all
+        * its VF to make them align with it. The detailed notification
+        * mechanism is PMD specific and is currently not implemented.
+        * To avoid unexpected behavior in VF, currently reset of PF with
+        * SR-IOV activation is not supported. It might be supported later.
+        */
+       if (dev->data->sriov.active)
+               return -ENOTSUP;
+
+       ret = eth_igb_dev_uninit(dev);
+       if (ret)
+               return ret;
+
+       ret = eth_igb_dev_init(dev);
+
+       return ret;
 }
 
+
 static int
 igb_get_rx_buffer_size(struct e1000_hw *hw)
 {
@@ -1638,7 +1841,7 @@ igb_read_stats_registers(struct e1000_hw *hw, struct e1000_hw_stats *stats)
        stats->tsctfc += E1000_READ_REG(hw, E1000_TSCTFC);
 }
 
-static void
+static int
 eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
 {
        struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
@@ -1648,7 +1851,7 @@ eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
        igb_read_stats_registers(hw, stats);
 
        if (rte_stats == NULL)
-               return;
+               return -EINVAL;
 
        /* Rx Errors */
        rte_stats->imissed = stats->mpc;
@@ -1663,6 +1866,7 @@ eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
        rte_stats->opackets = stats->gptc;
        rte_stats->ibytes   = stats->gorc;
        rte_stats->obytes   = stats->gotc;
+       return 0;
 }
 
 static void
@@ -1691,30 +1895,83 @@ eth_igb_xstats_reset(struct rte_eth_dev *dev)
        memset(stats, 0, sizeof(*stats));
 }
 
-static int
-eth_igb_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstats *xstats,
-                  unsigned n)
+static int eth_igb_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+       struct rte_eth_xstat_name *xstats_names,
+       __rte_unused unsigned int size)
 {
-       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       struct e1000_hw_stats *hw_stats =
-                       E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private);
        unsigned i;
 
-       if (n < IGB_NB_XSTATS)
+       if (xstats_names == NULL)
                return IGB_NB_XSTATS;
 
-       igb_read_stats_registers(hw, hw_stats);
-
-       /* If this is a reset xstats is NULL, and we have cleared the
-        * registers by reading them.
-        */
-       if (!xstats)
-               return 0;
+       /* Note: limit checked in rte_eth_xstats_names() */
 
-       /* Extended stats */
        for (i = 0; i < IGB_NB_XSTATS; i++) {
-               snprintf(xstats[i].name, sizeof(xstats[i].name),
-                        "%s", rte_igb_stats_strings[i].name);
+               strlcpy(xstats_names[i].name, rte_igb_stats_strings[i].name,
+                       sizeof(xstats_names[i].name));
+       }
+
+       return IGB_NB_XSTATS;
+}
+
+static int eth_igb_xstats_get_names_by_id(struct rte_eth_dev *dev,
+               struct rte_eth_xstat_name *xstats_names, const uint64_t *ids,
+               unsigned int limit)
+{
+       unsigned int i;
+
+       if (!ids) {
+               if (xstats_names == NULL)
+                       return IGB_NB_XSTATS;
+
+               for (i = 0; i < IGB_NB_XSTATS; i++)
+                       strlcpy(xstats_names[i].name,
+                               rte_igb_stats_strings[i].name,
+                               sizeof(xstats_names[i].name));
+
+               return IGB_NB_XSTATS;
+
+       } else {
+               struct rte_eth_xstat_name xstats_names_copy[IGB_NB_XSTATS];
+
+               eth_igb_xstats_get_names_by_id(dev, xstats_names_copy, NULL,
+                               IGB_NB_XSTATS);
+
+               for (i = 0; i < limit; i++) {
+                       if (ids[i] >= IGB_NB_XSTATS) {
+                               PMD_INIT_LOG(ERR, "id value isn't valid");
+                               return -1;
+                       }
+                       strcpy(xstats_names[i].name,
+                                       xstats_names_copy[ids[i]].name);
+               }
+               return limit;
+       }
+}
+
+static int
+eth_igb_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
+                  unsigned n)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct e1000_hw_stats *hw_stats =
+                       E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private);
+       unsigned i;
+
+       if (n < IGB_NB_XSTATS)
+               return IGB_NB_XSTATS;
+
+       igb_read_stats_registers(hw, hw_stats);
+
+       /* If this is a reset xstats is NULL, and we have cleared the
+        * registers by reading them.
+        */
+       if (!xstats)
+               return 0;
+
+       /* Extended stats */
+       for (i = 0; i < IGB_NB_XSTATS; i++) {
+               xstats[i].id = i;
                xstats[i].value = *(uint64_t *)(((char *)hw_stats) +
                        rte_igb_stats_strings[i].offset);
        }
@@ -1722,6 +1979,53 @@ eth_igb_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstats *xstats,
        return IGB_NB_XSTATS;
 }
 
+static int
+eth_igb_xstats_get_by_id(struct rte_eth_dev *dev, const uint64_t *ids,
+               uint64_t *values, unsigned int n)
+{
+       unsigned int i;
+
+       if (!ids) {
+               struct e1000_hw *hw =
+                       E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+               struct e1000_hw_stats *hw_stats =
+                       E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private);
+
+               if (n < IGB_NB_XSTATS)
+                       return IGB_NB_XSTATS;
+
+               igb_read_stats_registers(hw, hw_stats);
+
+               /* If this is a reset xstats is NULL, and we have cleared the
+                * registers by reading them.
+                */
+               if (!values)
+                       return 0;
+
+               /* Extended stats */
+               for (i = 0; i < IGB_NB_XSTATS; i++)
+                       values[i] = *(uint64_t *)(((char *)hw_stats) +
+                                       rte_igb_stats_strings[i].offset);
+
+               return IGB_NB_XSTATS;
+
+       } else {
+               uint64_t values_copy[IGB_NB_XSTATS];
+
+               eth_igb_xstats_get_by_id(dev, NULL, values_copy,
+                               IGB_NB_XSTATS);
+
+               for (i = 0; i < n; i++) {
+                       if (ids[i] >= IGB_NB_XSTATS) {
+                               PMD_INIT_LOG(ERR, "id value isn't valid");
+                               return -1;
+                       }
+                       values[i] = values_copy[ids[i]];
+               }
+               return n;
+       }
+}
+
 static void
 igbvf_read_stats_registers(struct e1000_hw *hw, struct e1000_vf_stats *hw_stats)
 {
@@ -1762,8 +2066,23 @@ igbvf_read_stats_registers(struct e1000_hw *hw, struct e1000_vf_stats *hw_stats)
            hw_stats->last_gotlbc, hw_stats->gotlbc);
 }
 
+static int eth_igbvf_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
+                                    struct rte_eth_xstat_name *xstats_names,
+                                    __rte_unused unsigned limit)
+{
+       unsigned i;
+
+       if (xstats_names != NULL)
+               for (i = 0; i < IGBVF_NB_XSTATS; i++) {
+                       strlcpy(xstats_names[i].name,
+                               rte_igbvf_stats_strings[i].name,
+                               sizeof(xstats_names[i].name));
+               }
+       return IGBVF_NB_XSTATS;
+}
+
 static int
-eth_igbvf_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstats *xstats,
+eth_igbvf_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
                     unsigned n)
 {
        struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
@@ -1780,8 +2099,7 @@ eth_igbvf_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstats *xstats,
                return 0;
 
        for (i = 0; i < IGBVF_NB_XSTATS; i++) {
-               snprintf(xstats[i].name, sizeof(xstats[i].name), "%s",
-                        rte_igbvf_stats_strings[i].name);
+               xstats[i].id = i;
                xstats[i].value = *(uint64_t *)(((char *)hw_stats) +
                        rte_igbvf_stats_strings[i].offset);
        }
@@ -1789,7 +2107,7 @@ eth_igbvf_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstats *xstats,
        return IGBVF_NB_XSTATS;
 }
 
-static void
+static int
 eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
 {
        struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
@@ -1799,17 +2117,13 @@ eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats)
        igbvf_read_stats_registers(hw, hw_stats);
 
        if (rte_stats == NULL)
-               return;
+               return -EINVAL;
 
        rte_stats->ipackets = hw_stats->gprc;
        rte_stats->ibytes = hw_stats->gorc;
        rte_stats->opackets = hw_stats->gptc;
        rte_stats->obytes = hw_stats->gotc;
-       rte_stats->imcasts = hw_stats->mprc;
-       rte_stats->ilbpackets = hw_stats->gprlbc;
-       rte_stats->ilbbytes = hw_stats->gorlbc;
-       rte_stats->olbpackets = hw_stats->gptlbc;
-       rte_stats->olbbytes = hw_stats->gotlbc;
+       return 0;
 }
 
 static void
@@ -1826,6 +2140,58 @@ eth_igbvf_stats_reset(struct rte_eth_dev *dev)
               offsetof(struct e1000_vf_stats, gprc));
 }
 
+static int
+eth_igb_fw_version_get(struct rte_eth_dev *dev, char *fw_version,
+                      size_t fw_size)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct e1000_fw_version fw;
+       int ret;
+
+       e1000_get_fw_version(hw, &fw);
+
+       switch (hw->mac.type) {
+       case e1000_i210:
+       case e1000_i211:
+               if (!(e1000_get_flash_presence_i210(hw))) {
+                       ret = snprintf(fw_version, fw_size,
+                                "%2d.%2d-%d",
+                                fw.invm_major, fw.invm_minor,
+                                fw.invm_img_type);
+                       break;
+               }
+               /* fall through */
+       default:
+               /* if option rom is valid, display its version too */
+               if (fw.or_valid) {
+                       ret = snprintf(fw_version, fw_size,
+                                "%d.%d, 0x%08x, %d.%d.%d",
+                                fw.eep_major, fw.eep_minor, fw.etrack_id,
+                                fw.or_major, fw.or_build, fw.or_patch);
+               /* no option rom */
+               } else {
+                       if (fw.etrack_id != 0X0000) {
+                               ret = snprintf(fw_version, fw_size,
+                                        "%d.%d, 0x%08x",
+                                        fw.eep_major, fw.eep_minor,
+                                        fw.etrack_id);
+                       } else {
+                               ret = snprintf(fw_version, fw_size,
+                                        "%d.%d.%d",
+                                        fw.eep_major, fw.eep_minor,
+                                        fw.eep_build);
+                       }
+               }
+               break;
+       }
+
+       ret += 1; /* add the size of '\0' */
+       if (fw_size < (u32)ret)
+               return ret;
+       else
+               return 0;
+}
+
 static void
 eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
@@ -1834,18 +2200,12 @@ eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
        dev_info->min_rx_bufsize = 256; /* See BSIZE field of RCTL register. */
        dev_info->max_rx_pktlen  = 0x3FFF; /* See RLPML register. */
        dev_info->max_mac_addrs = hw->mac.rar_entry_count;
-       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  |
-               DEV_TX_OFFLOAD_TCP_TSO;
+       dev_info->rx_queue_offload_capa = igb_get_rx_queue_offloads_capa(dev);
+       dev_info->rx_offload_capa = igb_get_rx_port_offloads_capa(dev) |
+                                   dev_info->rx_queue_offload_capa;
+       dev_info->tx_queue_offload_capa = igb_get_tx_queue_offloads_capa(dev);
+       dev_info->tx_offload_capa = igb_get_tx_port_offloads_capa(dev) |
+                                   dev_info->tx_queue_offload_capa;
 
        switch (hw->mac.type) {
        case e1000_82575:
@@ -1908,6 +2268,7 @@ eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                },
                .rx_free_thresh = IGB_DEFAULT_RX_FREE_THRESH,
                .rx_drop_en = 0,
+               .offloads = 0,
        };
 
        dev_info->default_txconf = (struct rte_eth_txconf) {
@@ -1916,7 +2277,7 @@ eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                        .hthresh = IGB_DEFAULT_TX_HTHRESH,
                        .wthresh = IGB_DEFAULT_TX_WTHRESH,
                },
-               .txq_flags = 0,
+               .offloads = 0,
        };
 
        dev_info->rx_desc_lim = rx_desc_lim;
@@ -1925,6 +2286,10 @@ eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
        dev_info->speed_capa = ETH_LINK_SPEED_10M_HD | ETH_LINK_SPEED_10M |
                        ETH_LINK_SPEED_100M_HD | ETH_LINK_SPEED_100M |
                        ETH_LINK_SPEED_1G;
+
+       dev_info->max_mtu = dev_info->max_rx_pktlen - E1000_ETH_OVERHEAD;
+       dev_info->min_mtu = ETHER_MIN_MTU;
+
 }
 
 static const uint32_t *
@@ -1962,10 +2327,6 @@ eth_igbvf_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
        dev_info->min_rx_bufsize = 256; /* See BSIZE field of RCTL register. */
        dev_info->max_rx_pktlen  = 0x3FFF; /* See RLPML register. */
        dev_info->max_mac_addrs = hw->mac.rar_entry_count;
-       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   |
@@ -1986,6 +2347,13 @@ eth_igbvf_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                break;
        }
 
+       dev_info->rx_queue_offload_capa = igb_get_rx_queue_offloads_capa(dev);
+       dev_info->rx_offload_capa = igb_get_rx_port_offloads_capa(dev) |
+                                   dev_info->rx_queue_offload_capa;
+       dev_info->tx_queue_offload_capa = igb_get_tx_queue_offloads_capa(dev);
+       dev_info->tx_offload_capa = igb_get_tx_port_offloads_capa(dev) |
+                                   dev_info->tx_queue_offload_capa;
+
        dev_info->default_rxconf = (struct rte_eth_rxconf) {
                .rx_thresh = {
                        .pthresh = IGB_DEFAULT_RX_PTHRESH,
@@ -1994,6 +2362,7 @@ eth_igbvf_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                },
                .rx_free_thresh = IGB_DEFAULT_RX_FREE_THRESH,
                .rx_drop_en = 0,
+               .offloads = 0,
        };
 
        dev_info->default_txconf = (struct rte_eth_txconf) {
@@ -2002,7 +2371,7 @@ eth_igbvf_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                        .hthresh = IGB_DEFAULT_TX_HTHRESH,
                        .wthresh = IGB_DEFAULT_TX_WTHRESH,
                },
-               .txq_flags = 0,
+               .offloads = 0,
        };
 
        dev_info->rx_desc_lim = rx_desc_lim;
@@ -2015,7 +2384,7 @@ eth_igb_link_update(struct rte_eth_dev *dev, int wait_to_complete)
 {
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       struct rte_eth_link link, old;
+       struct rte_eth_link link;
        int link_check, count;
 
        link_check = 0;
@@ -2056,8 +2425,6 @@ eth_igb_link_update(struct rte_eth_dev *dev, int wait_to_complete)
                rte_delay_ms(IGB_LINK_UPDATE_CHECK_INTERVAL);
        }
        memset(&link, 0, sizeof(link));
-       rte_igb_dev_atomic_read_link_status(dev, &link);
-       old = link;
 
        /* Now we check if a transition has happened */
        if (link_check) {
@@ -2074,16 +2441,10 @@ eth_igb_link_update(struct rte_eth_dev *dev, int wait_to_complete)
                link.link_speed = 0;
                link.link_duplex = ETH_LINK_HALF_DUPLEX;
                link.link_status = ETH_LINK_DOWN;
-               link.link_autoneg = ETH_LINK_SPEED_FIXED;
+               link.link_autoneg = ETH_LINK_FIXED;
        }
-       rte_igb_dev_atomic_write_link_status(dev, &link);
 
-       /* not changed */
-       if (old.link_status == link.link_status)
-               return -1;
-
-       /* changed */
-       return 0;
+       return rte_eth_linkstatus_set(dev, &link);
 }
 
 /*
@@ -2242,21 +2603,25 @@ eth_igb_vlan_tpid_set(struct rte_eth_dev *dev,
 {
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       uint32_t reg = ETHER_TYPE_VLAN;
-       int ret = 0;
+       uint32_t reg, qinq;
 
-       switch (vlan_type) {
-       case ETH_VLAN_TYPE_INNER:
-               reg |= (tpid << 16);
+       qinq = E1000_READ_REG(hw, E1000_CTRL_EXT);
+       qinq &= E1000_CTRL_EXT_EXT_VLAN;
+
+       /* only outer TPID of double VLAN can be configured*/
+       if (qinq && vlan_type == ETH_VLAN_TYPE_OUTER) {
+               reg = E1000_READ_REG(hw, E1000_VET);
+               reg = (reg & (~E1000_VET_VET_EXT)) |
+                       ((uint32_t)tpid << E1000_VET_VET_EXT_SHIFT);
                E1000_WRITE_REG(hw, E1000_VET, reg);
-               break;
-       default:
-               ret = -EINVAL;
-               PMD_DRV_LOG(ERR, "Unsupported vlan type %d\n", vlan_type);
-               break;
+
+               return 0;
        }
 
-       return ret;
+       /* all other TPID values are read-only*/
+       PMD_DRV_LOG(ERR, "Not supported");
+
+       return -ENOTSUP;
 }
 
 static void
@@ -2333,7 +2698,7 @@ igb_vlan_hw_extend_disable(struct rte_eth_dev *dev)
        E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
 
        /* Update maximum packet length */
-       if (dev->data->dev_conf.rxmode.jumbo_frame == 1)
+       if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME)
                E1000_WRITE_REG(hw, E1000_RLPML,
                        dev->data->dev_conf.rxmode.max_rx_pkt_len +
                                                VLAN_TAG_SIZE);
@@ -2352,35 +2717,40 @@ igb_vlan_hw_extend_enable(struct rte_eth_dev *dev)
        E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
 
        /* Update maximum packet length */
-       if (dev->data->dev_conf.rxmode.jumbo_frame == 1)
+       if (dev->data->dev_conf.rxmode.offloads & DEV_RX_OFFLOAD_JUMBO_FRAME)
                E1000_WRITE_REG(hw, E1000_RLPML,
                        dev->data->dev_conf.rxmode.max_rx_pkt_len +
                                                2 * VLAN_TAG_SIZE);
 }
 
-static void
+static int
 eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
+       struct rte_eth_rxmode *rxmode;
+
+       rxmode = &dev->data->dev_conf.rxmode;
        if(mask & ETH_VLAN_STRIP_MASK){
-               if (dev->data->dev_conf.rxmode.hw_vlan_strip)
+               if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_STRIP)
                        igb_vlan_hw_strip_enable(dev);
                else
                        igb_vlan_hw_strip_disable(dev);
        }
 
        if(mask & ETH_VLAN_FILTER_MASK){
-               if (dev->data->dev_conf.rxmode.hw_vlan_filter)
+               if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_FILTER)
                        igb_vlan_hw_filter_enable(dev);
                else
                        igb_vlan_hw_filter_disable(dev);
        }
 
        if(mask & ETH_VLAN_EXTEND_MASK){
-               if (dev->data->dev_conf.rxmode.hw_vlan_extend)
+               if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_EXTEND)
                        igb_vlan_hw_extend_enable(dev);
                else
                        igb_vlan_hw_extend_disable(dev);
        }
+
+       return 0;
 }
 
 
@@ -2389,18 +2759,23 @@ eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask)
  *
  * @param dev
  *  Pointer to struct rte_eth_dev.
+ * @param on
+ *  Enable or Disable
  *
  * @return
  *  - On success, zero.
  *  - On failure, a negative value.
  */
 static int
-eth_igb_lsc_interrupt_setup(struct rte_eth_dev *dev)
+eth_igb_lsc_interrupt_setup(struct rte_eth_dev *dev, uint8_t on)
 {
        struct e1000_interrupt *intr =
                E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
 
-       intr->mask |= E1000_ICR_LSC;
+       if (on)
+               intr->mask |= E1000_ICR_LSC;
+       else
+               intr->mask &= ~E1000_ICR_LSC;
 
        return 0;
 }
@@ -2420,12 +2795,15 @@ static int eth_igb_rxq_interrupt_setup(struct rte_eth_dev *dev)
        uint32_t mask, regval;
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+       int misc_shift = rte_intr_allow_others(intr_handle) ? 1 : 0;
        struct rte_eth_dev_info dev_info;
 
        memset(&dev_info, 0, sizeof(dev_info));
        eth_igb_infos_get(dev, &dev_info);
 
-       mask = 0xFFFFFFFF >> (32 - dev_info.max_rx_queues);
+       mask = (0xFFFFFFFF >> (32 - dev_info.max_rx_queues)) << misc_shift;
        regval = E1000_READ_REG(hw, E1000_EIMS);
        E1000_WRITE_REG(hw, E1000_EIMS, regval | mask);
 
@@ -2452,7 +2830,7 @@ eth_igb_interrupt_get_status(struct rte_eth_dev *dev)
        struct e1000_interrupt *intr =
                E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
 
-       igb_intr_disable(hw);
+       igb_intr_disable(dev);
 
        /* read-on-clear nic registers here */
        icr = E1000_READ_REG(hw, E1000_ICR);
@@ -2479,13 +2857,14 @@ eth_igb_interrupt_get_status(struct rte_eth_dev *dev)
  *  - On failure, a negative value.
  */
 static int
-eth_igb_interrupt_action(struct rte_eth_dev *dev)
+eth_igb_interrupt_action(struct rte_eth_dev *dev,
+                        struct rte_intr_handle *intr_handle)
 {
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct e1000_interrupt *intr =
                E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
-       uint32_t tctl, rctl;
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_eth_link link;
        int ret;
 
@@ -2495,7 +2874,7 @@ eth_igb_interrupt_action(struct rte_eth_dev *dev)
        }
 
        igb_intr_enable(dev);
-       rte_intr_enable(&(dev->pci_dev->intr_handle));
+       rte_intr_enable(intr_handle);
 
        if (intr->flags & E1000_FLAG_NEED_LINK_UPDATE) {
                intr->flags &= ~E1000_FLAG_NEED_LINK_UPDATE;
@@ -2508,8 +2887,7 @@ eth_igb_interrupt_action(struct rte_eth_dev *dev)
                if (ret < 0)
                        return 0;
 
-               memset(&link, 0, sizeof(link));
-               rte_igb_dev_atomic_read_link_status(dev, &link);
+               rte_eth_linkstatus_get(dev, &link);
                if (link.link_status) {
                        PMD_INIT_LOG(INFO,
                                     " Port %d: Link Up - speed %u Mbps - %s",
@@ -2523,25 +2901,12 @@ eth_igb_interrupt_action(struct rte_eth_dev *dev)
                }
 
                PMD_INIT_LOG(DEBUG, "PCI Address: %04d:%02d:%02d:%d",
-                            dev->pci_dev->addr.domain,
-                            dev->pci_dev->addr.bus,
-                            dev->pci_dev->addr.devid,
-                            dev->pci_dev->addr.function);
-               tctl = E1000_READ_REG(hw, E1000_TCTL);
-               rctl = E1000_READ_REG(hw, E1000_RCTL);
-               if (link.link_status) {
-                       /* enable Tx/Rx */
-                       tctl |= E1000_TCTL_EN;
-                       rctl |= E1000_RCTL_EN;
-               } else {
-                       /* disable Tx/Rx */
-                       tctl &= ~E1000_TCTL_EN;
-                       rctl &= ~E1000_RCTL_EN;
-               }
-               E1000_WRITE_REG(hw, E1000_TCTL, tctl);
-               E1000_WRITE_REG(hw, E1000_RCTL, rctl);
-               E1000_WRITE_FLUSH(hw);
-               _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC);
+                            pci_dev->addr.domain,
+                            pci_dev->addr.bus,
+                            pci_dev->addr.devid,
+                            pci_dev->addr.function);
+               _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC,
+                                             NULL);
        }
 
        return 0;
@@ -2559,13 +2924,79 @@ eth_igb_interrupt_action(struct rte_eth_dev *dev)
  *  void
  */
 static void
-eth_igb_interrupt_handler(__rte_unused struct rte_intr_handle *handle,
-                                                       void *param)
+eth_igb_interrupt_handler(void *param)
 {
        struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
 
        eth_igb_interrupt_get_status(dev);
-       eth_igb_interrupt_action(dev);
+       eth_igb_interrupt_action(dev, dev->intr_handle);
+}
+
+static int
+eth_igbvf_interrupt_get_status(struct rte_eth_dev *dev)
+{
+       uint32_t eicr;
+       struct e1000_hw *hw =
+               E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct e1000_interrupt *intr =
+               E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
+
+       igbvf_intr_disable(hw);
+
+       /* read-on-clear nic registers here */
+       eicr = E1000_READ_REG(hw, E1000_EICR);
+       intr->flags = 0;
+
+       if (eicr == E1000_VTIVAR_MISC_MAILBOX)
+               intr->flags |= E1000_FLAG_MAILBOX;
+
+       return 0;
+}
+
+void igbvf_mbx_process(struct rte_eth_dev *dev)
+{
+       struct e1000_hw *hw =
+               E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct e1000_mbx_info *mbx = &hw->mbx;
+       u32 in_msg = 0;
+
+       /* peek the message first */
+       in_msg = E1000_READ_REG(hw, E1000_VMBMEM(0));
+
+       /* PF reset VF event */
+       if (in_msg == E1000_PF_CONTROL_MSG) {
+               /* dummy mbx read to ack pf */
+               if (mbx->ops.read(hw, &in_msg, 1, 0))
+                       return;
+               _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_RESET,
+                                             NULL);
+       }
+}
+
+static int
+eth_igbvf_interrupt_action(struct rte_eth_dev *dev, struct rte_intr_handle *intr_handle)
+{
+       struct e1000_interrupt *intr =
+               E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
+
+       if (intr->flags & E1000_FLAG_MAILBOX) {
+               igbvf_mbx_process(dev);
+               intr->flags &= ~E1000_FLAG_MAILBOX;
+       }
+
+       igbvf_intr_enable(dev);
+       rte_intr_enable(intr_handle);
+
+       return 0;
+}
+
+static void
+eth_igbvf_interrupt_handler(void *param)
+{
+       struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+
+       eth_igbvf_interrupt_get_status(dev);
+       eth_igbvf_interrupt_action(dev, dev->intr_handle);
 }
 
 static int
@@ -2689,9 +3120,9 @@ eth_igb_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
 }
 
 #define E1000_RAH_POOLSEL_SHIFT      (18)
-static void
-eth_igb_rar_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
-               uint32_t index, __rte_unused uint32_t pool)
+static int
+eth_igb_rar_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+               uint32_t index, uint32_t pool)
 {
        struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        uint32_t rah;
@@ -2700,6 +3131,7 @@ eth_igb_rar_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
        rah = E1000_READ_REG(hw, E1000_RAH(index));
        rah |= (0x1 << (E1000_RAH_POOLSEL_SHIFT + pool));
        E1000_WRITE_REG(hw, E1000_RAH(index), rah);
+       return 0;
 }
 
 static void
@@ -2713,13 +3145,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index)
        e1000_rar_set(hw, addr, index);
 }
 
-static void
+static int
 eth_igb_default_mac_addr_set(struct rte_eth_dev *dev,
-                               struct ether_addr *addr)
+                               struct rte_ether_addr *addr)
 {
        eth_igb_rar_clear(dev, 0);
-
        eth_igb_rar_set(dev, (void *)addr, 0, 0);
+
+       return 0;
 }
 /*
  * Virtual Function operations
@@ -2817,14 +3250,14 @@ igbvf_dev_configure(struct rte_eth_dev *dev)
         * Keep the persistent behavior the same as Host PF
         */
 #ifndef RTE_LIBRTE_E1000_PF_DISABLE_STRIP_CRC
-       if (!conf->rxmode.hw_strip_crc) {
+       if (conf->rxmode.offloads & DEV_RX_OFFLOAD_KEEP_CRC) {
                PMD_INIT_LOG(NOTICE, "VF can't disable HW CRC Strip");
-               conf->rxmode.hw_strip_crc = 1;
+               conf->rxmode.offloads &= ~DEV_RX_OFFLOAD_KEEP_CRC;
        }
 #else
-       if (conf->rxmode.hw_strip_crc) {
+       if (!(conf->rxmode.offloads & DEV_RX_OFFLOAD_KEEP_CRC)) {
                PMD_INIT_LOG(NOTICE, "VF can't enable HW CRC Strip");
-               conf->rxmode.hw_strip_crc = 0;
+               conf->rxmode.offloads |= DEV_RX_OFFLOAD_KEEP_CRC;
        }
 #endif
 
@@ -2838,7 +3271,10 @@ igbvf_dev_start(struct rte_eth_dev *dev)
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct e1000_adapter *adapter =
                E1000_DEV_PRIVATE(dev->data->dev_private);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
        int ret;
+       uint32_t intr_vector = 0;
 
        PMD_INIT_FUNC_TRACE();
 
@@ -2858,12 +3294,43 @@ igbvf_dev_start(struct rte_eth_dev *dev)
                return ret;
        }
 
+       /* check and configure queue intr-vector mapping */
+       if (rte_intr_cap_multiple(intr_handle) &&
+           dev->data->dev_conf.intr_conf.rxq) {
+               intr_vector = dev->data->nb_rx_queues;
+               ret = rte_intr_efd_enable(intr_handle, intr_vector);
+               if (ret)
+                       return ret;
+       }
+
+       if (rte_intr_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
+               intr_handle->intr_vec =
+                       rte_zmalloc("intr_vec",
+                                   dev->data->nb_rx_queues * sizeof(int), 0);
+               if (!intr_handle->intr_vec) {
+                       PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues"
+                                    " intr_vec", dev->data->nb_rx_queues);
+                       return -ENOMEM;
+               }
+       }
+
+       eth_igbvf_configure_msix_intr(dev);
+
+       /* enable uio/vfio intr/eventfd mapping */
+       rte_intr_enable(intr_handle);
+
+       /* resume enabled intr since hw reset */
+       igbvf_intr_enable(dev);
+
        return 0;
 }
 
 static void
 igbvf_dev_stop(struct rte_eth_dev *dev)
 {
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+
        PMD_INIT_FUNC_TRACE();
 
        igbvf_stop_adapter(dev);
@@ -2875,6 +3342,16 @@ igbvf_dev_stop(struct rte_eth_dev *dev)
        igbvf_set_vfta_all(dev,0);
 
        igb_dev_clear_queues(dev);
+
+       /* disable intr eventfd mapping */
+       rte_intr_disable(intr_handle);
+
+       /* Clean datapath event and queue/vec mapping */
+       rte_intr_efd_disable(intr_handle);
+       if (intr_handle->intr_vec) {
+               rte_free(intr_handle->intr_vec);
+               intr_handle->intr_vec = NULL;
+       }
 }
 
 static void
@@ -2883,7 +3360,7 @@ igbvf_dev_close(struct rte_eth_dev *dev)
        struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct e1000_adapter *adapter =
                E1000_DEV_PRIVATE(dev->data->dev_private);
-       struct ether_addr addr;
+       struct rte_ether_addr addr;
 
        PMD_INIT_FUNC_TRACE();
 
@@ -3027,14 +3504,15 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
        return 0;
 }
 
-static void
-igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr)
+static int
+igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *addr)
 {
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
        /* index is not used by rar_set() */
        hw->mac.ops.rar_set(hw, (void *)addr, 0);
+       return 0;
 }
 
 
@@ -3051,7 +3529,7 @@ eth_igb_rss_reta_update(struct rte_eth_dev *dev,
        if (reta_size != ETH_RSS_RETA_SIZE_128) {
                PMD_DRV_LOG(ERR, "The size of hash lookup table configured "
                        "(%d) doesn't match the number hardware can supported "
-                       "(%d)\n", reta_size, ETH_RSS_RETA_SIZE_128);
+                       "(%d)", reta_size, ETH_RSS_RETA_SIZE_128);
                return -EINVAL;
        }
 
@@ -3092,7 +3570,7 @@ eth_igb_rss_reta_query(struct rte_eth_dev *dev,
        if (reta_size != ETH_RSS_RETA_SIZE_128) {
                PMD_DRV_LOG(ERR, "The size of hash lookup table configured "
                        "(%d) doesn't match the number hardware can supported "
-                       "(%d)\n", reta_size, ETH_RSS_RETA_SIZE_128);
+                       "(%d)", reta_size, ETH_RSS_RETA_SIZE_128);
                return -EINVAL;
        }
 
@@ -3115,18 +3593,14 @@ eth_igb_rss_reta_query(struct rte_eth_dev *dev,
        return 0;
 }
 
-#define MAC_TYPE_FILTER_SUP(type)    do {\
-       if ((type) != e1000_82580 && (type) != e1000_i350 &&\
-               (type) != e1000_82576)\
-               return -ENOTSUP;\
-} while (0)
-
-static int
+int
 eth_igb_syn_filter_set(struct rte_eth_dev *dev,
                        struct rte_eth_syn_filter *filter,
                        bool add)
 {
        struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
        uint32_t synqf, rfctl;
 
        if (filter->queue >= IGB_MAX_RX_QUEUE_NUM)
@@ -3154,6 +3628,7 @@ eth_igb_syn_filter_set(struct rte_eth_dev *dev,
                synqf = 0;
        }
 
+       filter_info->syn_info = synqf;
        E1000_WRITE_REG(hw, E1000_SYNQF(0), synqf);
        E1000_WRITE_FLUSH(hw);
        return 0;
@@ -3213,7 +3688,7 @@ eth_igb_syn_filter_handle(struct rte_eth_dev *dev,
                                (struct rte_eth_syn_filter *)arg);
                break;
        default:
-               PMD_DRV_LOG(ERR, "unsupported operation %u\n", filter_op);
+               PMD_DRV_LOG(ERR, "unsupported operation %u", filter_op);
                ret = -EINVAL;
                break;
        }
@@ -3221,11 +3696,6 @@ eth_igb_syn_filter_handle(struct rte_eth_dev *dev,
        return ret;
 }
 
-#define MAC_TYPE_FILTER_SUP_EXT(type)    do {\
-       if ((type) != e1000_82580 && (type) != e1000_i350)\
-               return -ENOSYS; \
-} while (0)
-
 /* translate elements in struct rte_eth_ntuple_filter to struct e1000_2tuple_filter_info*/
 static inline int
 ntuple_filter_to_2tuple(struct rte_eth_ntuple_filter *filter,
@@ -3288,40 +3758,85 @@ igb_2tuple_filter_lookup(struct e1000_2tuple_filter_list *filter_list,
        return NULL;
 }
 
-/*
- * igb_add_2tuple_filter - add a 2tuple filter
- *
- * @param
- * dev: Pointer to struct rte_eth_dev.
- * ntuple_filter: ponter to the filter that will be added.
- *
- * @return
- *    - On success, zero.
- *    - On failure, a negative value.
- */
-static int
-igb_add_2tuple_filter(struct rte_eth_dev *dev,
-                       struct rte_eth_ntuple_filter *ntuple_filter)
+/* inject a igb 2tuple filter to HW */
+static inline void
+igb_inject_2uple_filter(struct rte_eth_dev *dev,
+                          struct e1000_2tuple_filter *filter)
 {
        struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       struct e1000_filter_info *filter_info =
-               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
-       struct e1000_2tuple_filter *filter;
        uint32_t ttqf = E1000_TTQF_DISABLE_MASK;
        uint32_t imir, imir_ext = E1000_IMIREXT_SIZE_BP;
-       int i, ret;
+       int i;
 
-       filter = rte_zmalloc("e1000_2tuple_filter",
-                       sizeof(struct e1000_2tuple_filter), 0);
-       if (filter == NULL)
-               return -ENOMEM;
+       i = filter->index;
+       imir = (uint32_t)(filter->filter_info.dst_port & E1000_IMIR_DSTPORT);
+       if (filter->filter_info.dst_port_mask == 1) /* 1b means not compare. */
+               imir |= E1000_IMIR_PORT_BP;
+       else
+               imir &= ~E1000_IMIR_PORT_BP;
 
-       ret = ntuple_filter_to_2tuple(ntuple_filter,
-                                     &filter->filter_info);
-       if (ret < 0) {
-               rte_free(filter);
-               return ret;
-       }
+       imir |= filter->filter_info.priority << E1000_IMIR_PRIORITY_SHIFT;
+
+       ttqf |= E1000_TTQF_QUEUE_ENABLE;
+       ttqf |= (uint32_t)(filter->queue << E1000_TTQF_QUEUE_SHIFT);
+       ttqf |= (uint32_t)(filter->filter_info.proto &
+                                               E1000_TTQF_PROTOCOL_MASK);
+       if (filter->filter_info.proto_mask == 0)
+               ttqf &= ~E1000_TTQF_MASK_ENABLE;
+
+       /* tcp flags bits setting. */
+       if (filter->filter_info.tcp_flags & TCP_FLAG_ALL) {
+               if (filter->filter_info.tcp_flags & TCP_URG_FLAG)
+                       imir_ext |= E1000_IMIREXT_CTRL_URG;
+               if (filter->filter_info.tcp_flags & TCP_ACK_FLAG)
+                       imir_ext |= E1000_IMIREXT_CTRL_ACK;
+               if (filter->filter_info.tcp_flags & TCP_PSH_FLAG)
+                       imir_ext |= E1000_IMIREXT_CTRL_PSH;
+               if (filter->filter_info.tcp_flags & TCP_RST_FLAG)
+                       imir_ext |= E1000_IMIREXT_CTRL_RST;
+               if (filter->filter_info.tcp_flags & TCP_SYN_FLAG)
+                       imir_ext |= E1000_IMIREXT_CTRL_SYN;
+               if (filter->filter_info.tcp_flags & TCP_FIN_FLAG)
+                       imir_ext |= E1000_IMIREXT_CTRL_FIN;
+       } else {
+               imir_ext |= E1000_IMIREXT_CTRL_BP;
+       }
+       E1000_WRITE_REG(hw, E1000_IMIR(i), imir);
+       E1000_WRITE_REG(hw, E1000_TTQF(i), ttqf);
+       E1000_WRITE_REG(hw, E1000_IMIREXT(i), imir_ext);
+}
+
+/*
+ * igb_add_2tuple_filter - add a 2tuple filter
+ *
+ * @param
+ * dev: Pointer to struct rte_eth_dev.
+ * ntuple_filter: ponter to the filter that will be added.
+ *
+ * @return
+ *    - On success, zero.
+ *    - On failure, a negative value.
+ */
+static int
+igb_add_2tuple_filter(struct rte_eth_dev *dev,
+                       struct rte_eth_ntuple_filter *ntuple_filter)
+{
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+       struct e1000_2tuple_filter *filter;
+       int i, ret;
+
+       filter = rte_zmalloc("e1000_2tuple_filter",
+                       sizeof(struct e1000_2tuple_filter), 0);
+       if (filter == NULL)
+               return -ENOMEM;
+
+       ret = ntuple_filter_to_2tuple(ntuple_filter,
+                                     &filter->filter_info);
+       if (ret < 0) {
+               rte_free(filter);
+               return ret;
+       }
        if (igb_2tuple_filter_lookup(&filter_info->twotuple_list,
                                         &filter->filter_info) != NULL) {
                PMD_DRV_LOG(ERR, "filter exists.");
@@ -3350,39 +3865,25 @@ igb_add_2tuple_filter(struct rte_eth_dev *dev,
                return -ENOSYS;
        }
 
-       imir = (uint32_t)(filter->filter_info.dst_port & E1000_IMIR_DSTPORT);
-       if (filter->filter_info.dst_port_mask == 1) /* 1b means not compare. */
-               imir |= E1000_IMIR_PORT_BP;
-       else
-               imir &= ~E1000_IMIR_PORT_BP;
+       igb_inject_2uple_filter(dev, filter);
+       return 0;
+}
 
-       imir |= filter->filter_info.priority << E1000_IMIR_PRIORITY_SHIFT;
+int
+igb_delete_2tuple_filter(struct rte_eth_dev *dev,
+                       struct e1000_2tuple_filter *filter)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
 
-       ttqf |= E1000_TTQF_QUEUE_ENABLE;
-       ttqf |= (uint32_t)(filter->queue << E1000_TTQF_QUEUE_SHIFT);
-       ttqf |= (uint32_t)(filter->filter_info.proto & E1000_TTQF_PROTOCOL_MASK);
-       if (filter->filter_info.proto_mask == 0)
-               ttqf &= ~E1000_TTQF_MASK_ENABLE;
+       filter_info->twotuple_mask &= ~(1 << filter->index);
+       TAILQ_REMOVE(&filter_info->twotuple_list, filter, entries);
+       rte_free(filter);
 
-       /* tcp flags bits setting. */
-       if (filter->filter_info.tcp_flags & TCP_FLAG_ALL) {
-               if (filter->filter_info.tcp_flags & TCP_URG_FLAG)
-                       imir_ext |= E1000_IMIREXT_CTRL_URG;
-               if (filter->filter_info.tcp_flags & TCP_ACK_FLAG)
-                       imir_ext |= E1000_IMIREXT_CTRL_ACK;
-               if (filter->filter_info.tcp_flags & TCP_PSH_FLAG)
-                       imir_ext |= E1000_IMIREXT_CTRL_PSH;
-               if (filter->filter_info.tcp_flags & TCP_RST_FLAG)
-                       imir_ext |= E1000_IMIREXT_CTRL_RST;
-               if (filter->filter_info.tcp_flags & TCP_SYN_FLAG)
-                       imir_ext |= E1000_IMIREXT_CTRL_SYN;
-               if (filter->filter_info.tcp_flags & TCP_FIN_FLAG)
-                       imir_ext |= E1000_IMIREXT_CTRL_FIN;
-       } else
-               imir_ext |= E1000_IMIREXT_CTRL_BP;
-       E1000_WRITE_REG(hw, E1000_IMIR(i), imir);
-       E1000_WRITE_REG(hw, E1000_TTQF(i), ttqf);
-       E1000_WRITE_REG(hw, E1000_IMIREXT(i), imir_ext);
+       E1000_WRITE_REG(hw, E1000_TTQF(filter->index), E1000_TTQF_DISABLE_MASK);
+       E1000_WRITE_REG(hw, E1000_IMIR(filter->index), 0);
+       E1000_WRITE_REG(hw, E1000_IMIREXT(filter->index), 0);
        return 0;
 }
 
@@ -3401,7 +3902,6 @@ static int
 igb_remove_2tuple_filter(struct rte_eth_dev *dev,
                        struct rte_eth_ntuple_filter *ntuple_filter)
 {
-       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct e1000_filter_info *filter_info =
                E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
        struct e1000_2tuple_filter_info filter_2tuple;
@@ -3421,16 +3921,50 @@ igb_remove_2tuple_filter(struct rte_eth_dev *dev,
                return -ENOENT;
        }
 
-       filter_info->twotuple_mask &= ~(1 << filter->index);
-       TAILQ_REMOVE(&filter_info->twotuple_list, filter, entries);
-       rte_free(filter);
+       igb_delete_2tuple_filter(dev, filter);
 
-       E1000_WRITE_REG(hw, E1000_TTQF(filter->index), E1000_TTQF_DISABLE_MASK);
-       E1000_WRITE_REG(hw, E1000_IMIR(filter->index), 0);
-       E1000_WRITE_REG(hw, E1000_IMIREXT(filter->index), 0);
        return 0;
 }
 
+/* inject a igb flex filter to HW */
+static inline void
+igb_inject_flex_filter(struct rte_eth_dev *dev,
+                          struct e1000_flex_filter *filter)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t wufc, queueing;
+       uint32_t reg_off;
+       uint8_t i, j = 0;
+
+       wufc = E1000_READ_REG(hw, E1000_WUFC);
+       if (filter->index < E1000_MAX_FHFT)
+               reg_off = E1000_FHFT(filter->index);
+       else
+               reg_off = E1000_FHFT_EXT(filter->index - E1000_MAX_FHFT);
+
+       E1000_WRITE_REG(hw, E1000_WUFC, wufc | E1000_WUFC_FLEX_HQ |
+                       (E1000_WUFC_FLX0 << filter->index));
+       queueing = filter->filter_info.len |
+               (filter->queue << E1000_FHFT_QUEUEING_QUEUE_SHIFT) |
+               (filter->filter_info.priority <<
+                       E1000_FHFT_QUEUEING_PRIO_SHIFT);
+       E1000_WRITE_REG(hw, reg_off + E1000_FHFT_QUEUEING_OFFSET,
+                       queueing);
+
+       for (i = 0; i < E1000_FLEX_FILTERS_MASK_SIZE; i++) {
+               E1000_WRITE_REG(hw, reg_off,
+                               filter->filter_info.dwords[j]);
+               reg_off += sizeof(uint32_t);
+               E1000_WRITE_REG(hw, reg_off,
+                               filter->filter_info.dwords[++j]);
+               reg_off += sizeof(uint32_t);
+               E1000_WRITE_REG(hw, reg_off,
+                       (uint32_t)filter->filter_info.mask[i]);
+               reg_off += sizeof(uint32_t) * 2;
+               ++j;
+       }
+}
+
 static inline struct e1000_flex_filter *
 eth_igb_flex_filter_lookup(struct e1000_flex_filter_list *filter_list,
                        struct e1000_flex_filter_info *key)
@@ -3446,18 +3980,48 @@ eth_igb_flex_filter_lookup(struct e1000_flex_filter_list *filter_list,
        return NULL;
 }
 
-static int
+/* remove a flex byte filter
+ * @param
+ * dev: Pointer to struct rte_eth_dev.
+ * filter: the pointer of the filter will be removed.
+ */
+void
+igb_remove_flex_filter(struct rte_eth_dev *dev,
+                       struct e1000_flex_filter *filter)
+{
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t wufc, i;
+       uint32_t reg_off;
+
+       wufc = E1000_READ_REG(hw, E1000_WUFC);
+       if (filter->index < E1000_MAX_FHFT)
+               reg_off = E1000_FHFT(filter->index);
+       else
+               reg_off = E1000_FHFT_EXT(filter->index - E1000_MAX_FHFT);
+
+       for (i = 0; i < E1000_FHFT_SIZE_IN_DWD; i++)
+               E1000_WRITE_REG(hw, reg_off + i * sizeof(uint32_t), 0);
+
+       E1000_WRITE_REG(hw, E1000_WUFC, wufc &
+               (~(E1000_WUFC_FLX0 << filter->index)));
+
+       filter_info->flex_mask &= ~(1 << filter->index);
+       TAILQ_REMOVE(&filter_info->flex_list, filter, entries);
+       rte_free(filter);
+}
+
+int
 eth_igb_add_del_flex_filter(struct rte_eth_dev *dev,
                        struct rte_eth_flex_filter *filter,
                        bool add)
 {
-       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct e1000_filter_info *filter_info =
                E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
        struct e1000_flex_filter *flex_filter, *it;
-       uint32_t wufc, queueing, mask;
-       uint32_t reg_off;
-       uint8_t shift, i, j = 0;
+       uint32_t mask;
+       uint8_t shift, i;
 
        flex_filter = rte_zmalloc("e1000_flex_filter",
                        sizeof(struct e1000_flex_filter), 0);
@@ -3477,19 +4041,20 @@ eth_igb_add_del_flex_filter(struct rte_eth_dev *dev,
                flex_filter->filter_info.mask[i] = mask;
        }
 
-       wufc = E1000_READ_REG(hw, E1000_WUFC);
-       if (flex_filter->index < E1000_MAX_FHFT)
-               reg_off = E1000_FHFT(flex_filter->index);
-       else
-               reg_off = E1000_FHFT_EXT(flex_filter->index - E1000_MAX_FHFT);
+       it = eth_igb_flex_filter_lookup(&filter_info->flex_list,
+                               &flex_filter->filter_info);
+       if (it == NULL && !add) {
+               PMD_DRV_LOG(ERR, "filter doesn't exist.");
+               rte_free(flex_filter);
+               return -ENOENT;
+       }
+       if (it != NULL && add) {
+               PMD_DRV_LOG(ERR, "filter exists.");
+               rte_free(flex_filter);
+               return -EEXIST;
+       }
 
        if (add) {
-               if (eth_igb_flex_filter_lookup(&filter_info->flex_list,
-                               &flex_filter->filter_info) != NULL) {
-                       PMD_DRV_LOG(ERR, "filter exists.");
-                       rte_free(flex_filter);
-                       return -EEXIST;
-               }
                flex_filter->queue = filter->queue;
                /*
                 * look for an unused flex filter index
@@ -3511,42 +4076,10 @@ eth_igb_add_del_flex_filter(struct rte_eth_dev *dev,
                        return -ENOSYS;
                }
 
-               E1000_WRITE_REG(hw, E1000_WUFC, wufc | E1000_WUFC_FLEX_HQ |
-                               (E1000_WUFC_FLX0 << flex_filter->index));
-               queueing = filter->len |
-                       (filter->queue << E1000_FHFT_QUEUEING_QUEUE_SHIFT) |
-                       (filter->priority << E1000_FHFT_QUEUEING_PRIO_SHIFT);
-               E1000_WRITE_REG(hw, reg_off + E1000_FHFT_QUEUEING_OFFSET,
-                               queueing);
-               for (i = 0; i < E1000_FLEX_FILTERS_MASK_SIZE; i++) {
-                       E1000_WRITE_REG(hw, reg_off,
-                                       flex_filter->filter_info.dwords[j]);
-                       reg_off += sizeof(uint32_t);
-                       E1000_WRITE_REG(hw, reg_off,
-                                       flex_filter->filter_info.dwords[++j]);
-                       reg_off += sizeof(uint32_t);
-                       E1000_WRITE_REG(hw, reg_off,
-                               (uint32_t)flex_filter->filter_info.mask[i]);
-                       reg_off += sizeof(uint32_t) * 2;
-                       ++j;
-               }
-       } else {
-               it = eth_igb_flex_filter_lookup(&filter_info->flex_list,
-                               &flex_filter->filter_info);
-               if (it == NULL) {
-                       PMD_DRV_LOG(ERR, "filter doesn't exist.");
-                       rte_free(flex_filter);
-                       return -ENOENT;
-               }
-
-               for (i = 0; i < E1000_FHFT_SIZE_IN_DWD; i++)
-                       E1000_WRITE_REG(hw, reg_off + i * sizeof(uint32_t), 0);
-               E1000_WRITE_REG(hw, E1000_WUFC, wufc &
-                       (~(E1000_WUFC_FLX0 << it->index)));
+               igb_inject_flex_filter(dev, flex_filter);
 
-               filter_info->flex_mask &= ~(1 << it->index);
-               TAILQ_REMOVE(&filter_info->flex_list, it, entries);
-               rte_free(it);
+       } else {
+               igb_remove_flex_filter(dev, it);
                rte_free(flex_filter);
        }
 
@@ -3568,7 +4101,7 @@ eth_igb_get_flex_filter(struct rte_eth_dev *dev,
        flex_filter.filter_info.priority = filter->priority;
        memcpy(flex_filter.filter_info.dwords, filter->bytes, filter->len);
        memcpy(flex_filter.filter_info.mask, filter->mask,
-                       RTE_ALIGN(filter->len, sizeof(char)) / sizeof(char));
+                       RTE_ALIGN(filter->len, CHAR_BIT) / CHAR_BIT);
 
        it = eth_igb_flex_filter_lookup(&filter_info->flex_list,
                                &flex_filter.filter_info);
@@ -3750,6 +4283,64 @@ igb_5tuple_filter_lookup_82576(struct e1000_5tuple_filter_list *filter_list,
        return NULL;
 }
 
+/* inject a igb 5-tuple filter to HW */
+static inline void
+igb_inject_5tuple_filter_82576(struct rte_eth_dev *dev,
+                          struct e1000_5tuple_filter *filter)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t ftqf = E1000_FTQF_VF_BP | E1000_FTQF_MASK;
+       uint32_t spqf, imir, imir_ext = E1000_IMIREXT_SIZE_BP;
+       uint8_t i;
+
+       i = filter->index;
+       ftqf |= filter->filter_info.proto & E1000_FTQF_PROTOCOL_MASK;
+       if (filter->filter_info.src_ip_mask == 0) /* 0b means compare. */
+               ftqf &= ~E1000_FTQF_MASK_SOURCE_ADDR_BP;
+       if (filter->filter_info.dst_ip_mask == 0)
+               ftqf &= ~E1000_FTQF_MASK_DEST_ADDR_BP;
+       if (filter->filter_info.src_port_mask == 0)
+               ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP;
+       if (filter->filter_info.proto_mask == 0)
+               ftqf &= ~E1000_FTQF_MASK_PROTO_BP;
+       ftqf |= (filter->queue << E1000_FTQF_QUEUE_SHIFT) &
+               E1000_FTQF_QUEUE_MASK;
+       ftqf |= E1000_FTQF_QUEUE_ENABLE;
+       E1000_WRITE_REG(hw, E1000_FTQF(i), ftqf);
+       E1000_WRITE_REG(hw, E1000_DAQF(i), filter->filter_info.dst_ip);
+       E1000_WRITE_REG(hw, E1000_SAQF(i), filter->filter_info.src_ip);
+
+       spqf = filter->filter_info.src_port & E1000_SPQF_SRCPORT;
+       E1000_WRITE_REG(hw, E1000_SPQF(i), spqf);
+
+       imir = (uint32_t)(filter->filter_info.dst_port & E1000_IMIR_DSTPORT);
+       if (filter->filter_info.dst_port_mask == 1) /* 1b means not compare. */
+               imir |= E1000_IMIR_PORT_BP;
+       else
+               imir &= ~E1000_IMIR_PORT_BP;
+       imir |= filter->filter_info.priority << E1000_IMIR_PRIORITY_SHIFT;
+
+       /* tcp flags bits setting. */
+       if (filter->filter_info.tcp_flags & TCP_FLAG_ALL) {
+               if (filter->filter_info.tcp_flags & TCP_URG_FLAG)
+                       imir_ext |= E1000_IMIREXT_CTRL_URG;
+               if (filter->filter_info.tcp_flags & TCP_ACK_FLAG)
+                       imir_ext |= E1000_IMIREXT_CTRL_ACK;
+               if (filter->filter_info.tcp_flags & TCP_PSH_FLAG)
+                       imir_ext |= E1000_IMIREXT_CTRL_PSH;
+               if (filter->filter_info.tcp_flags & TCP_RST_FLAG)
+                       imir_ext |= E1000_IMIREXT_CTRL_RST;
+               if (filter->filter_info.tcp_flags & TCP_SYN_FLAG)
+                       imir_ext |= E1000_IMIREXT_CTRL_SYN;
+               if (filter->filter_info.tcp_flags & TCP_FIN_FLAG)
+                       imir_ext |= E1000_IMIREXT_CTRL_FIN;
+       } else {
+               imir_ext |= E1000_IMIREXT_CTRL_BP;
+       }
+       E1000_WRITE_REG(hw, E1000_IMIR(i), imir);
+       E1000_WRITE_REG(hw, E1000_IMIREXT(i), imir_ext);
+}
+
 /*
  * igb_add_5tuple_filter_82576 - add a 5tuple filter
  *
@@ -3765,12 +4356,9 @@ static int
 igb_add_5tuple_filter_82576(struct rte_eth_dev *dev,
                        struct rte_eth_ntuple_filter *ntuple_filter)
 {
-       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct e1000_filter_info *filter_info =
                E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
        struct e1000_5tuple_filter *filter;
-       uint32_t ftqf = E1000_FTQF_VF_BP | E1000_FTQF_MASK;
-       uint32_t spqf, imir, imir_ext = E1000_IMIREXT_SIZE_BP;
        uint8_t i;
        int ret;
 
@@ -3814,50 +4402,29 @@ igb_add_5tuple_filter_82576(struct rte_eth_dev *dev,
                return -ENOSYS;
        }
 
-       ftqf |= filter->filter_info.proto & E1000_FTQF_PROTOCOL_MASK;
-       if (filter->filter_info.src_ip_mask == 0) /* 0b means compare. */
-               ftqf &= ~E1000_FTQF_MASK_SOURCE_ADDR_BP;
-       if (filter->filter_info.dst_ip_mask == 0)
-               ftqf &= ~E1000_FTQF_MASK_DEST_ADDR_BP;
-       if (filter->filter_info.src_port_mask == 0)
-               ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP;
-       if (filter->filter_info.proto_mask == 0)
-               ftqf &= ~E1000_FTQF_MASK_PROTO_BP;
-       ftqf |= (filter->queue << E1000_FTQF_QUEUE_SHIFT) &
-               E1000_FTQF_QUEUE_MASK;
-       ftqf |= E1000_FTQF_QUEUE_ENABLE;
-       E1000_WRITE_REG(hw, E1000_FTQF(i), ftqf);
-       E1000_WRITE_REG(hw, E1000_DAQF(i), filter->filter_info.dst_ip);
-       E1000_WRITE_REG(hw, E1000_SAQF(i), filter->filter_info.src_ip);
+       igb_inject_5tuple_filter_82576(dev, filter);
+       return 0;
+}
 
-       spqf = filter->filter_info.src_port & E1000_SPQF_SRCPORT;
-       E1000_WRITE_REG(hw, E1000_SPQF(i), spqf);
+int
+igb_delete_5tuple_filter_82576(struct rte_eth_dev *dev,
+                               struct e1000_5tuple_filter *filter)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
 
-       imir = (uint32_t)(filter->filter_info.dst_port & E1000_IMIR_DSTPORT);
-       if (filter->filter_info.dst_port_mask == 1) /* 1b means not compare. */
-               imir |= E1000_IMIR_PORT_BP;
-       else
-               imir &= ~E1000_IMIR_PORT_BP;
-       imir |= filter->filter_info.priority << E1000_IMIR_PRIORITY_SHIFT;
+       filter_info->fivetuple_mask &= ~(1 << filter->index);
+       TAILQ_REMOVE(&filter_info->fivetuple_list, filter, entries);
+       rte_free(filter);
 
-       /* tcp flags bits setting. */
-       if (filter->filter_info.tcp_flags & TCP_FLAG_ALL) {
-               if (filter->filter_info.tcp_flags & TCP_URG_FLAG)
-                       imir_ext |= E1000_IMIREXT_CTRL_URG;
-               if (filter->filter_info.tcp_flags & TCP_ACK_FLAG)
-                       imir_ext |= E1000_IMIREXT_CTRL_ACK;
-               if (filter->filter_info.tcp_flags & TCP_PSH_FLAG)
-                       imir_ext |= E1000_IMIREXT_CTRL_PSH;
-               if (filter->filter_info.tcp_flags & TCP_RST_FLAG)
-                       imir_ext |= E1000_IMIREXT_CTRL_RST;
-               if (filter->filter_info.tcp_flags & TCP_SYN_FLAG)
-                       imir_ext |= E1000_IMIREXT_CTRL_SYN;
-               if (filter->filter_info.tcp_flags & TCP_FIN_FLAG)
-                       imir_ext |= E1000_IMIREXT_CTRL_FIN;
-       } else
-               imir_ext |= E1000_IMIREXT_CTRL_BP;
-       E1000_WRITE_REG(hw, E1000_IMIR(i), imir);
-       E1000_WRITE_REG(hw, E1000_IMIREXT(i), imir_ext);
+       E1000_WRITE_REG(hw, E1000_FTQF(filter->index),
+                       E1000_FTQF_VF_BP | E1000_FTQF_MASK);
+       E1000_WRITE_REG(hw, E1000_DAQF(filter->index), 0);
+       E1000_WRITE_REG(hw, E1000_SAQF(filter->index), 0);
+       E1000_WRITE_REG(hw, E1000_SPQF(filter->index), 0);
+       E1000_WRITE_REG(hw, E1000_IMIR(filter->index), 0);
+       E1000_WRITE_REG(hw, E1000_IMIREXT(filter->index), 0);
        return 0;
 }
 
@@ -3876,7 +4443,6 @@ static int
 igb_remove_5tuple_filter_82576(struct rte_eth_dev *dev,
                                struct rte_eth_ntuple_filter *ntuple_filter)
 {
-       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct e1000_filter_info *filter_info =
                E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
        struct e1000_5tuple_filter_info filter_5tuple;
@@ -3896,17 +4462,8 @@ igb_remove_5tuple_filter_82576(struct rte_eth_dev *dev,
                return -ENOENT;
        }
 
-       filter_info->fivetuple_mask &= ~(1 << filter->index);
-       TAILQ_REMOVE(&filter_info->fivetuple_list, filter, entries);
-       rte_free(filter);
+       igb_delete_5tuple_filter_82576(dev, filter);
 
-       E1000_WRITE_REG(hw, E1000_FTQF(filter->index),
-                       E1000_FTQF_VF_BP | E1000_FTQF_MASK);
-       E1000_WRITE_REG(hw, E1000_DAQF(filter->index), 0);
-       E1000_WRITE_REG(hw, E1000_SAQF(filter->index), 0);
-       E1000_WRITE_REG(hw, E1000_SPQF(filter->index), 0);
-       E1000_WRITE_REG(hw, E1000_IMIR(filter->index), 0);
-       E1000_WRITE_REG(hw, E1000_IMIREXT(filter->index), 0);
        return 0;
 }
 
@@ -3916,8 +4473,7 @@ eth_igb_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
        uint32_t rctl;
        struct e1000_hw *hw;
        struct rte_eth_dev_info dev_info;
-       uint32_t frame_size = mtu + (ETHER_HDR_LEN + ETHER_CRC_LEN +
-                                    VLAN_TAG_SIZE);
+       uint32_t frame_size = mtu + E1000_ETH_OVERHEAD;
 
        hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
@@ -3943,10 +4499,12 @@ eth_igb_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 
        /* switch to jumbo mode if needed */
        if (frame_size > ETHER_MAX_LEN) {
-               dev->data->dev_conf.rxmode.jumbo_frame = 1;
+               dev->data->dev_conf.rxmode.offloads |=
+                       DEV_RX_OFFLOAD_JUMBO_FRAME;
                rctl |= E1000_RCTL_LPE;
        } else {
-               dev->data->dev_conf.rxmode.jumbo_frame = 0;
+               dev->data->dev_conf.rxmode.offloads &=
+                       ~DEV_RX_OFFLOAD_JUMBO_FRAME;
                rctl &= ~E1000_RCTL_LPE;
        }
        E1000_WRITE_REG(hw, E1000_RCTL, rctl);
@@ -3972,7 +4530,7 @@ eth_igb_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
  *    - On success, zero.
  *    - On failure, a negative value.
  */
-static int
+int
 igb_add_del_ntuple_filter(struct rte_eth_dev *dev,
                        struct rte_eth_ntuple_filter *ntuple_filter,
                        bool add)
@@ -3994,7 +4552,9 @@ igb_add_del_ntuple_filter(struct rte_eth_dev *dev,
                break;
        case RTE_2TUPLE_FLAGS:
        case (RTE_2TUPLE_FLAGS | RTE_NTUPLE_FLAGS_TCP_FLAG):
-               if (hw->mac.type != e1000_82580 && hw->mac.type != e1000_i350)
+               if (hw->mac.type != e1000_82580 && hw->mac.type != e1000_i350 &&
+                       hw->mac.type != e1000_i210 &&
+                       hw->mac.type != e1000_i211)
                        return -ENOTSUP;
                if (add)
                        ret = igb_add_2tuple_filter(dev, ntuple_filter);
@@ -4136,7 +4696,7 @@ igb_ethertype_filter_lookup(struct e1000_filter_info *filter_info,
        int i;
 
        for (i = 0; i < E1000_MAX_ETQF_FILTERS; i++) {
-               if (filter_info->ethertype_filters[i] == ethertype &&
+               if (filter_info->ethertype_filters[i].ethertype == ethertype &&
                    (filter_info->ethertype_mask & (1 << i)))
                        return i;
        }
@@ -4145,33 +4705,35 @@ igb_ethertype_filter_lookup(struct e1000_filter_info *filter_info,
 
 static inline int
 igb_ethertype_filter_insert(struct e1000_filter_info *filter_info,
-                       uint16_t ethertype)
+                       uint16_t ethertype, uint32_t etqf)
 {
        int i;
 
        for (i = 0; i < E1000_MAX_ETQF_FILTERS; i++) {
                if (!(filter_info->ethertype_mask & (1 << i))) {
                        filter_info->ethertype_mask |= 1 << i;
-                       filter_info->ethertype_filters[i] = ethertype;
+                       filter_info->ethertype_filters[i].ethertype = ethertype;
+                       filter_info->ethertype_filters[i].etqf = etqf;
                        return i;
                }
        }
        return -1;
 }
 
-static inline int
+int
 igb_ethertype_filter_remove(struct e1000_filter_info *filter_info,
                        uint8_t idx)
 {
        if (idx >= E1000_MAX_ETQF_FILTERS)
                return -1;
        filter_info->ethertype_mask &= ~(1 << idx);
-       filter_info->ethertype_filters[idx] = 0;
+       filter_info->ethertype_filters[idx].ethertype = 0;
+       filter_info->ethertype_filters[idx].etqf = 0;
        return idx;
 }
 
 
-static int
+int
 igb_add_del_ethertype_filter(struct rte_eth_dev *dev,
                        struct rte_eth_ethertype_filter *filter,
                        bool add)
@@ -4211,16 +4773,15 @@ igb_add_del_ethertype_filter(struct rte_eth_dev *dev,
        }
 
        if (add) {
+               etqf |= E1000_ETQF_FILTER_ENABLE | E1000_ETQF_QUEUE_ENABLE;
+               etqf |= (uint32_t)(filter->ether_type & E1000_ETQF_ETHERTYPE);
+               etqf |= filter->queue << E1000_ETQF_QUEUE_SHIFT;
                ret = igb_ethertype_filter_insert(filter_info,
-                       filter->ether_type);
+                               filter->ether_type, etqf);
                if (ret < 0) {
                        PMD_DRV_LOG(ERR, "ethertype filters are full.");
                        return -ENOSYS;
                }
-
-               etqf |= E1000_ETQF_FILTER_ENABLE | E1000_ETQF_QUEUE_ENABLE;
-               etqf |= (uint32_t)(filter->ether_type & E1000_ETQF_ETHERTYPE);
-               etqf |= filter->queue << E1000_ETQF_QUEUE_SHIFT;
        } else {
                ret = igb_ethertype_filter_remove(filter_info, (uint8_t)ret);
                if (ret < 0)
@@ -4315,7 +4876,7 @@ eth_igb_filter_ctrl(struct rte_eth_dev *dev,
                     enum rte_filter_op filter_op,
                     void *arg)
 {
-       int ret = -EINVAL;
+       int ret = 0;
 
        switch (filter_type) {
        case RTE_ETH_FILTER_NTUPLE:
@@ -4330,6 +4891,11 @@ eth_igb_filter_ctrl(struct rte_eth_dev *dev,
        case RTE_ETH_FILTER_FLEXIBLE:
                ret = eth_igb_flex_filter_handle(dev, filter_op, arg);
                break;
+       case RTE_ETH_FILTER_GENERIC:
+               if (filter_op != RTE_ETH_FILTER_GET)
+                       return -EINVAL;
+               *(const void **)arg = &igb_flow_ops;
+               break;
        default:
                PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
                                                        filter_type);
@@ -4341,7 +4907,7 @@ eth_igb_filter_ctrl(struct rte_eth_dev *dev,
 
 static int
 eth_igb_set_mc_addr_list(struct rte_eth_dev *dev,
-                        struct ether_addr *mc_addr_set,
+                        struct rte_ether_addr *mc_addr_set,
                         uint32_t nb_mc_addr)
 {
        struct e1000_hw *hw;
@@ -4713,6 +5279,12 @@ eth_igb_get_regs(struct rte_eth_dev *dev,
        int count = 0;
        const struct reg_info *reg_group;
 
+       if (data == NULL) {
+               regs->length = eth_igb_get_reg_length(dev);
+               regs->width = sizeof(uint32_t);
+               return 0;
+       }
+
        /* Support only full register dump */
        if ((regs->length == 0) ||
            (regs->length == (uint32_t)eth_igb_get_reg_length(dev))) {
@@ -4737,6 +5309,12 @@ igbvf_get_regs(struct rte_eth_dev *dev,
        int count = 0;
        const struct reg_info *reg_group;
 
+       if (data == NULL) {
+               regs->length = igbvf_get_reg_length(dev);
+               regs->width = sizeof(uint32_t);
+               return 0;
+       }
+
        /* Support only full register dump */
        if ((regs->length == 0) ||
            (regs->length == (uint32_t)igbvf_get_reg_length(dev))) {
@@ -4807,22 +5385,99 @@ eth_igb_set_eeprom(struct rte_eth_dev *dev,
        return nvm->ops.write(hw,  first, length, data);
 }
 
-static struct rte_driver pmd_igb_drv = {
-       .type = PMD_PDEV,
-       .init = rte_igb_pmd_init,
-};
+static int
+eth_igb_get_module_info(struct rte_eth_dev *dev,
+                       struct rte_eth_dev_module_info *modinfo)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-static struct rte_driver pmd_igbvf_drv = {
-       .type = PMD_PDEV,
-       .init = rte_igbvf_pmd_init,
-};
+       uint32_t status = 0;
+       uint16_t sff8472_rev, addr_mode;
+       bool page_swap = false;
+
+       if (hw->phy.media_type == e1000_media_type_copper ||
+           hw->phy.media_type == e1000_media_type_unknown)
+               return -EOPNOTSUPP;
+
+       /* Check whether we support SFF-8472 or not */
+       status = e1000_read_phy_reg_i2c(hw, IGB_SFF_8472_COMP, &sff8472_rev);
+       if (status)
+               return -EIO;
+
+       /* addressing mode is not supported */
+       status = e1000_read_phy_reg_i2c(hw, IGB_SFF_8472_SWAP, &addr_mode);
+       if (status)
+               return -EIO;
+
+       /* addressing mode is not supported */
+       if ((addr_mode & 0xFF) & IGB_SFF_ADDRESSING_MODE) {
+               PMD_DRV_LOG(ERR,
+                           "Address change required to access page 0xA2, "
+                           "but not supported. Please report the module "
+                           "type to the driver maintainers.\n");
+               page_swap = true;
+       }
+
+       if ((sff8472_rev & 0xFF) == IGB_SFF_8472_UNSUP || page_swap) {
+               /* We have an SFP, but it does not support SFF-8472 */
+               modinfo->type = RTE_ETH_MODULE_SFF_8079;
+               modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8079_LEN;
+       } else {
+               /* We have an SFP which supports a revision of SFF-8472 */
+               modinfo->type = RTE_ETH_MODULE_SFF_8472;
+               modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8472_LEN;
+       }
+
+       return 0;
+}
+
+static int
+eth_igb_get_module_eeprom(struct rte_eth_dev *dev,
+                         struct rte_dev_eeprom_info *info)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       uint32_t status = 0;
+       uint16_t dataword[RTE_ETH_MODULE_SFF_8472_LEN / 2 + 1];
+       u16 first_word, last_word;
+       int i = 0;
+
+       if (info->length == 0)
+               return -EINVAL;
+
+       first_word = info->offset >> 1;
+       last_word = (info->offset + info->length - 1) >> 1;
+
+       /* Read EEPROM block, SFF-8079/SFF-8472, word at a time */
+       for (i = 0; i < last_word - first_word + 1; i++) {
+               status = e1000_read_phy_reg_i2c(hw, (first_word + i) * 2,
+                                               &dataword[i]);
+               if (status) {
+                       /* Error occurred while reading module */
+                       return -EIO;
+               }
+
+               dataword[i] = rte_be_to_cpu_16(dataword[i]);
+       }
+
+       memcpy(info->data, (u8 *)dataword + (info->offset & 1), info->length);
+
+       return 0;
+}
 
 static int
 eth_igb_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       uint32_t mask = 1 << queue_id;
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+       uint32_t vec = E1000_MISC_VEC_ID;
+
+       if (rte_intr_allow_others(intr_handle))
+               vec = E1000_RX_VEC_START;
+
+       uint32_t mask = 1 << (queue_id + vec);
 
        E1000_WRITE_REG(hw, E1000_EIMC, mask);
        E1000_WRITE_FLUSH(hw);
@@ -4835,14 +5490,21 @@ eth_igb_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
        struct e1000_hw *hw =
                E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       uint32_t mask = 1 << queue_id;
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+       uint32_t vec = E1000_MISC_VEC_ID;
+
+       if (rte_intr_allow_others(intr_handle))
+               vec = E1000_RX_VEC_START;
+
+       uint32_t mask = 1 << (queue_id + vec);
        uint32_t regval;
 
        regval = E1000_READ_REG(hw, E1000_EIMS);
        E1000_WRITE_REG(hw, E1000_EIMS, regval | mask);
        E1000_WRITE_FLUSH(hw);
 
-       rte_intr_enable(&dev->pci_dev->intr_handle);
+       rte_intr_enable(intr_handle);
 
        return 0;
 }
@@ -4906,8 +5568,8 @@ eth_igb_configure_msix_intr(struct rte_eth_dev *dev)
        uint32_t vec = E1000_MISC_VEC_ID;
        uint32_t base = E1000_MISC_VEC_ID;
        uint32_t misc_shift = 0;
-
-       struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+       struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
 
        /* won't configure msix register if no mapping is done
         * between intr vector and event fd
@@ -4950,13 +5612,17 @@ eth_igb_configure_msix_intr(struct rte_eth_dev *dev)
                                        E1000_GPIE_NSICR);
                intr_mask = RTE_LEN2MASK(intr_handle->nb_efd, uint32_t) <<
                        misc_shift;
+
+               if (dev->data->dev_conf.intr_conf.lsc != 0)
+                       intr_mask |= (1 << IGB_MSIX_OTHER_INTR_VEC);
+
                regval = E1000_READ_REG(hw, E1000_EIAC);
                E1000_WRITE_REG(hw, E1000_EIAC, regval | intr_mask);
 
                /* enable msix_other interrupt */
                regval = E1000_READ_REG(hw, E1000_EIMS);
                E1000_WRITE_REG(hw, E1000_EIMS, regval | intr_mask);
-               tmpval = (dev->data->nb_rx_queues | E1000_IVAR_VALID) << 8;
+               tmpval = (IGB_MSIX_OTHER_INTR_VEC | E1000_IVAR_VALID) << 8;
                E1000_WRITE_REG(hw, E1000_IVAR_MISC, tmpval);
        }
 
@@ -4965,6 +5631,10 @@ eth_igb_configure_msix_intr(struct rte_eth_dev *dev)
         */
        intr_mask = RTE_LEN2MASK(intr_handle->nb_efd, uint32_t) <<
                misc_shift;
+
+       if (dev->data->dev_conf.intr_conf.lsc != 0)
+               intr_mask |= (1 << IGB_MSIX_OTHER_INTR_VEC);
+
        regval = E1000_READ_REG(hw, E1000_EIAM);
        E1000_WRITE_REG(hw, E1000_EIAM, regval | intr_mask);
 
@@ -4978,5 +5648,105 @@ eth_igb_configure_msix_intr(struct rte_eth_dev *dev)
        E1000_WRITE_FLUSH(hw);
 }
 
-PMD_REGISTER_DRIVER(pmd_igb_drv);
-PMD_REGISTER_DRIVER(pmd_igbvf_drv);
+/* restore n-tuple filter */
+static inline void
+igb_ntuple_filter_restore(struct rte_eth_dev *dev)
+{
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+       struct e1000_5tuple_filter *p_5tuple;
+       struct e1000_2tuple_filter *p_2tuple;
+
+       TAILQ_FOREACH(p_5tuple, &filter_info->fivetuple_list, entries) {
+               igb_inject_5tuple_filter_82576(dev, p_5tuple);
+       }
+
+       TAILQ_FOREACH(p_2tuple, &filter_info->twotuple_list, entries) {
+               igb_inject_2uple_filter(dev, p_2tuple);
+       }
+}
+
+/* restore SYN filter */
+static inline void
+igb_syn_filter_restore(struct rte_eth_dev *dev)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+       uint32_t synqf;
+
+       synqf = filter_info->syn_info;
+
+       if (synqf & E1000_SYN_FILTER_ENABLE) {
+               E1000_WRITE_REG(hw, E1000_SYNQF(0), synqf);
+               E1000_WRITE_FLUSH(hw);
+       }
+}
+
+/* restore ethernet type filter */
+static inline void
+igb_ethertype_filter_restore(struct rte_eth_dev *dev)
+{
+       struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+       int i;
+
+       for (i = 0; i < E1000_MAX_ETQF_FILTERS; i++) {
+               if (filter_info->ethertype_mask & (1 << i)) {
+                       E1000_WRITE_REG(hw, E1000_ETQF(i),
+                               filter_info->ethertype_filters[i].etqf);
+                       E1000_WRITE_FLUSH(hw);
+               }
+       }
+}
+
+/* restore flex byte filter */
+static inline void
+igb_flex_filter_restore(struct rte_eth_dev *dev)
+{
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+       struct e1000_flex_filter *flex_filter;
+
+       TAILQ_FOREACH(flex_filter, &filter_info->flex_list, entries) {
+               igb_inject_flex_filter(dev, flex_filter);
+       }
+}
+
+/* restore rss filter */
+static inline void
+igb_rss_filter_restore(struct rte_eth_dev *dev)
+{
+       struct e1000_filter_info *filter_info =
+               E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private);
+
+       if (filter_info->rss_info.conf.queue_num)
+               igb_config_rss_filter(dev, &filter_info->rss_info, TRUE);
+}
+
+/* restore all types filter */
+static int
+igb_filter_restore(struct rte_eth_dev *dev)
+{
+       igb_ntuple_filter_restore(dev);
+       igb_ethertype_filter_restore(dev);
+       igb_syn_filter_restore(dev);
+       igb_flex_filter_restore(dev);
+       igb_rss_filter_restore(dev);
+
+       return 0;
+}
+
+RTE_PMD_REGISTER_PCI(net_e1000_igb, rte_igb_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_e1000_igb, pci_id_igb_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_e1000_igb, "* igb_uio | uio_pci_generic | vfio-pci");
+RTE_PMD_REGISTER_PCI(net_e1000_igb_vf, rte_igbvf_pmd);
+RTE_PMD_REGISTER_PCI_TABLE(net_e1000_igb_vf, pci_id_igbvf_map);
+RTE_PMD_REGISTER_KMOD_DEP(net_e1000_igb_vf, "* igb_uio | vfio-pci");
+
+/* see e1000_logs.c */
+RTE_INIT(e1000_init_log)
+{
+       e1000_igb_init_log();
+}