net: add rte prefix to ether structures
[dpdk.git] / drivers / net / i40e / i40e_ethdev.c
index 00079bb..85fdf35 100644 (file)
@@ -1,34 +1,5 @@
-/*-
- *   BSD LICENSE
- *
- *   Copyright(c) 2010-2017 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-2017 Intel Corporation
  */
 
 #include <stdio.h>
 #include <inttypes.h>
 #include <assert.h>
 
+#include <rte_common.h>
+#include <rte_eal.h>
 #include <rte_string_fns.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_memzone.h>
 #include <rte_malloc.h>
 #include <rte_memcpy.h>
 #include <rte_alarm.h>
 #include <rte_dev.h>
-#include <rte_eth_ctrl.h>
 #include <rte_tailq.h>
 #include <rte_hash_crc.h>
 
 
 #define ETH_I40E_FLOATING_VEB_ARG      "enable_floating_veb"
 #define ETH_I40E_FLOATING_VEB_LIST_ARG "floating_veb_list"
+#define ETH_I40E_SUPPORT_MULTI_DRIVER  "support-multi-driver"
+#define ETH_I40E_QUEUE_NUM_PER_VF_ARG  "queue-num-per-vf"
+#define ETH_I40E_USE_LATEST_VEC        "use-latest-supported-vec"
 
 #define I40E_CLEAR_PXE_WAIT_MS     200
 
 /* Maximun number of capability elements */
 #define I40E_MAX_CAP_ELE_NUM       128
 
-/* Wait count and inteval */
+/* Wait count and interval */
 #define I40E_CHK_Q_ENA_COUNT       1000
 #define I40E_CHK_Q_ENA_INTERVAL_US 1000
 
 /* Flow control default timer */
 #define I40E_DEFAULT_PAUSE_TIME 0xFFFFU
 
-/* Flow control default high water */
-#define I40E_DEFAULT_HIGH_WATER (0x1C40/1024)
-
-/* Flow control default low water */
-#define I40E_DEFAULT_LOW_WATER  (0x1A40/1024)
-
 /* Flow control enable fwd bit */
 #define I40E_PRTMAC_FWD_CTRL   0x00000001
 
 /* Kilobytes shift */
 #define I40E_KILOSHIFT 10
 
+/* Flow control default high water */
+#define I40E_DEFAULT_HIGH_WATER (0xF2000 >> I40E_KILOSHIFT)
+
+/* Flow control default low water */
+#define I40E_DEFAULT_LOW_WATER  (0xF2000 >> I40E_KILOSHIFT)
+
 /* Receive Average Packet Size in Byte*/
 #define I40E_PACKET_AVERAGE_SIZE 128
 
 #define I40E_PRTTSYN_TSYNTYPE    0x0e000000
 #define I40E_CYCLECOUNTER_MASK   0xffffffffffffffffULL
 
-#define I40E_MAX_PERCENT            100
-#define I40E_DEFAULT_DCB_APP_NUM    1
-#define I40E_DEFAULT_DCB_APP_PRIO   3
-
 /**
  * Below are values for writing un-exposed registers suggested
  * by silicon experts
 /* Bit mask of Extended Tag enable/disable */
 #define PCI_DEV_CTRL_EXT_TAG_MASK  (1 << PCI_DEV_CTRL_EXT_TAG_SHIFT)
 
-/* The max bandwidth of i40e is 40Gbps. */
-#define I40E_QOS_BW_MAX 40000
-/* The bandwidth should be the multiple of 50Mbps. */
-#define I40E_QOS_BW_GRANULARITY 50
-/* The min bandwidth weight is 1. */
-#define I40E_QOS_BW_WEIGHT_MIN 1
-/* The max bandwidth weight is 127. */
-#define I40E_QOS_BW_WEIGHT_MAX 127
-
-static int eth_i40e_dev_init(struct rte_eth_dev *eth_dev);
+static int eth_i40e_dev_init(struct rte_eth_dev *eth_dev, void *init_params);
 static int eth_i40e_dev_uninit(struct rte_eth_dev *eth_dev);
 static int i40e_dev_configure(struct rte_eth_dev *dev);
 static int i40e_dev_start(struct rte_eth_dev *dev);
 static void i40e_dev_stop(struct rte_eth_dev *dev);
 static void i40e_dev_close(struct rte_eth_dev *dev);
+static int  i40e_dev_reset(struct rte_eth_dev *dev);
 static void i40e_dev_promiscuous_enable(struct rte_eth_dev *dev);
 static void i40e_dev_promiscuous_disable(struct rte_eth_dev *dev);
 static void i40e_dev_allmulticast_enable(struct rte_eth_dev *dev);
 static void i40e_dev_allmulticast_disable(struct rte_eth_dev *dev);
 static int i40e_dev_set_link_up(struct rte_eth_dev *dev);
 static int i40e_dev_set_link_down(struct rte_eth_dev *dev);
-static void i40e_dev_stats_get(struct rte_eth_dev *dev,
+static int i40e_dev_stats_get(struct rte_eth_dev *dev,
                               struct rte_eth_stats *stats);
 static int i40e_dev_xstats_get(struct rte_eth_dev *dev,
                               struct rte_eth_xstat *xstats, unsigned n);
@@ -286,7 +251,7 @@ static int i40e_vlan_filter_set(struct rte_eth_dev *dev,
 static int i40e_vlan_tpid_set(struct rte_eth_dev *dev,
                              enum rte_vlan_type vlan_type,
                              uint16_t tpid);
-static void i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void i40e_vlan_strip_queue_set(struct rte_eth_dev *dev,
                                      uint16_t queue,
                                      int on);
@@ -299,10 +264,10 @@ static int i40e_flow_ctrl_set(struct rte_eth_dev *dev,
                              struct rte_eth_fc_conf *fc_conf);
 static int i40e_priority_flow_ctrl_set(struct rte_eth_dev *dev,
                                       struct rte_eth_pfc_conf *pfc_conf);
-static void i40e_macaddr_add(struct rte_eth_dev *dev,
-                         struct ether_addr *mac_addr,
-                         uint32_t index,
-                         uint32_t pool);
+static int i40e_macaddr_add(struct rte_eth_dev *dev,
+                           struct rte_ether_addr *mac_addr,
+                           uint32_t index,
+                           uint32_t pool);
 static void i40e_macaddr_remove(struct rte_eth_dev *dev, uint32_t index);
 static int i40e_dev_rss_reta_update(struct rte_eth_dev *dev,
                                    struct rte_eth_rss_reta_entry64 *reta_conf,
@@ -316,7 +281,6 @@ static int i40e_pf_parameter_init(struct rte_eth_dev *dev);
 static int i40e_pf_setup(struct i40e_pf *pf);
 static int i40e_dev_rxtx_init(struct i40e_pf *pf);
 static int i40e_vmdq_setup(struct rte_eth_dev *dev);
-static int i40e_dcb_init_configure(struct rte_eth_dev *dev, bool sw_dcb);
 static int i40e_dcb_setup(struct rte_eth_dev *dev);
 static void i40e_stat_update_32(struct i40e_hw *hw, uint32_t reg,
                bool offset_loaded, uint64_t *offset, uint64_t *stat);
@@ -327,8 +291,8 @@ static void i40e_stat_update_48(struct i40e_hw *hw,
                               uint64_t *offset,
                               uint64_t *stat);
 static void i40e_pf_config_irq0(struct i40e_hw *hw, bool no_queue);
-static void i40e_dev_interrupt_handler(struct rte_intr_handle *handle,
-                                      void *param);
+static void i40e_dev_interrupt_handler(void *param);
+static void i40e_dev_alarm_handler(void *param);
 static int i40e_res_pool_init(struct i40e_res_pool_info *pool,
                                uint32_t base, uint32_t num);
 static void i40e_res_pool_destroy(struct i40e_res_pool_info *pool);
@@ -342,10 +306,6 @@ static struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf,
                                                struct i40e_vsi *vsi);
 static int i40e_pf_config_mq_rx(struct i40e_pf *pf);
 static int i40e_vsi_config_double_vlan(struct i40e_vsi *vsi, int on);
-static inline int i40e_find_all_vlan_for_mac(struct i40e_vsi *vsi,
-                                            struct i40e_macvlan_filter *mv_f,
-                                            int num,
-                                            struct ether_addr *addr);
 static inline int i40e_find_all_mac_for_vlan(struct i40e_vsi *vsi,
                                             struct i40e_macvlan_filter *mv_f,
                                             int num,
@@ -373,6 +333,12 @@ static int i40e_dev_sync_phy_type(struct i40e_hw *hw);
 static void i40e_configure_registers(struct i40e_hw *hw);
 static void i40e_hw_init(struct rte_eth_dev *dev);
 static int i40e_config_qinq(struct i40e_hw *hw, struct i40e_vsi *vsi);
+static enum i40e_status_code i40e_aq_del_mirror_rule(struct i40e_hw *hw,
+                                                    uint16_t seid,
+                                                    uint16_t rule_type,
+                                                    uint16_t *entries,
+                                                    uint16_t count,
+                                                    uint16_t rule_id);
 static int i40e_mirror_rule_set(struct rte_eth_dev *dev,
                        struct rte_eth_mirror_conf *mirror_conf,
                        uint8_t sw_id, uint8_t on);
@@ -407,8 +373,13 @@ static int i40e_get_eeprom_length(struct rte_eth_dev *dev);
 static int i40e_get_eeprom(struct rte_eth_dev *dev,
                           struct rte_dev_eeprom_info *eeprom);
 
-static void i40e_set_default_mac_addr(struct rte_eth_dev *dev,
-                                     struct ether_addr *mac_addr);
+static int i40e_get_module_info(struct rte_eth_dev *dev,
+                               struct rte_eth_dev_module_info *modinfo);
+static int i40e_get_module_eeprom(struct rte_eth_dev *dev,
+                                 struct rte_dev_eeprom_info *info);
+
+static int i40e_set_default_mac_addr(struct rte_eth_dev *dev,
+                                     struct rte_ether_addr *mac_addr);
 
 static int i40e_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
 
@@ -419,14 +390,27 @@ static int i40e_sw_ethertype_filter_insert(struct i40e_pf *pf,
                                   struct i40e_ethertype_filter *filter);
 
 static int i40e_tunnel_filter_convert(
-       struct i40e_aqc_add_rm_cloud_filt_elem_ext *cld_filter,
+       struct i40e_aqc_cloud_filters_element_bb *cld_filter,
        struct i40e_tunnel_filter *tunnel_filter);
 static int i40e_sw_tunnel_filter_insert(struct i40e_pf *pf,
                                struct i40e_tunnel_filter *tunnel_filter);
+static int i40e_cloud_filter_qinq_create(struct i40e_pf *pf);
 
 static void i40e_ethertype_filter_restore(struct i40e_pf *pf);
 static void i40e_tunnel_filter_restore(struct i40e_pf *pf);
 static void i40e_filter_restore(struct i40e_pf *pf);
+static void i40e_notify_all_vfs_link_status(struct rte_eth_dev *dev);
+
+int i40e_logtype_init;
+int i40e_logtype_driver;
+
+static const char *const valid_keys[] = {
+       ETH_I40E_FLOATING_VEB_ARG,
+       ETH_I40E_FLOATING_VEB_LIST_ARG,
+       ETH_I40E_SUPPORT_MULTI_DRIVER,
+       ETH_I40E_QUEUE_NUM_PER_VF_ARG,
+       ETH_I40E_USE_LATEST_VEC,
+       NULL};
 
 static const struct rte_pci_id pci_id_i40e_map[] = {
        { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710) },
@@ -449,6 +433,9 @@ static const struct rte_pci_id pci_id_i40e_map[] = {
        { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722) },
        { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722) },
        { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_X710_N3000) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_XXV710_N3000) },
+       { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_BC) },
        { .vendor_id = 0, /* sentinel */ },
 };
 
@@ -457,6 +444,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
        .dev_start                    = i40e_dev_start,
        .dev_stop                     = i40e_dev_stop,
        .dev_close                    = i40e_dev_close,
+       .dev_reset                    = i40e_dev_reset,
        .promiscuous_enable           = i40e_dev_promiscuous_enable,
        .promiscuous_disable          = i40e_dev_promiscuous_disable,
        .allmulticast_enable          = i40e_dev_allmulticast_enable,
@@ -521,8 +509,11 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
        .get_reg                      = i40e_get_regs,
        .get_eeprom_length            = i40e_get_eeprom_length,
        .get_eeprom                   = i40e_get_eeprom,
+       .get_module_info              = i40e_get_module_info,
+       .get_module_eeprom            = i40e_get_module_eeprom,
        .mac_addr_set                 = i40e_set_default_mac_addr,
        .mtu_set                      = i40e_dev_mtu_set,
+       .tm_ops_get                   = i40e_tm_ops_get,
 };
 
 /* store statistics names and its offset in stats structure */
@@ -638,49 +629,104 @@ static const struct rte_i40e_xstats_name_off rte_i40e_txq_prio_strings[] = {
 #define I40E_NB_TXQ_PRIO_XSTATS (sizeof(rte_i40e_txq_prio_strings) / \
                sizeof(rte_i40e_txq_prio_strings[0]))
 
-static struct eth_driver rte_i40e_pmd = {
-       .pci_drv = {
-               .id_table = pci_id_i40e_map,
-               .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
-               .probe = rte_eth_dev_pci_probe,
-               .remove = rte_eth_dev_pci_remove,
-       },
-       .eth_dev_init = eth_i40e_dev_init,
-       .eth_dev_uninit = eth_i40e_dev_uninit,
-       .dev_private_size = sizeof(struct i40e_adapter),
-};
-
-static inline int
-rte_i40e_dev_atomic_read_link_status(struct rte_eth_dev *dev,
-                                    struct rte_eth_link *link)
+static int
+eth_i40e_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+       struct rte_pci_device *pci_dev)
 {
-       struct rte_eth_link *dst = link;
-       struct rte_eth_link *src = &(dev->data->dev_link);
+       char name[RTE_ETH_NAME_MAX_LEN];
+       struct rte_eth_devargs eth_da = { .nb_representor_ports = 0 };
+       int i, retval;
 
-       if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
-                                       *(uint64_t *)src) == 0)
-               return -1;
+       if (pci_dev->device.devargs) {
+               retval = rte_eth_devargs_parse(pci_dev->device.devargs->args,
+                               &eth_da);
+               if (retval)
+                       return retval;
+       }
+
+       retval = rte_eth_dev_create(&pci_dev->device, pci_dev->device.name,
+               sizeof(struct i40e_adapter),
+               eth_dev_pci_specific_init, pci_dev,
+               eth_i40e_dev_init, NULL);
+
+       if (retval || eth_da.nb_representor_ports < 1)
+               return retval;
+
+       /* probe VF representor ports */
+       struct rte_eth_dev *pf_ethdev = rte_eth_dev_allocated(
+               pci_dev->device.name);
+
+       if (pf_ethdev == NULL)
+               return -ENODEV;
+
+       for (i = 0; i < eth_da.nb_representor_ports; i++) {
+               struct i40e_vf_representor representor = {
+                       .vf_id = eth_da.representor_ports[i],
+                       .switch_domain_id = I40E_DEV_PRIVATE_TO_PF(
+                               pf_ethdev->data->dev_private)->switch_domain_id,
+                       .adapter = I40E_DEV_PRIVATE_TO_ADAPTER(
+                               pf_ethdev->data->dev_private)
+               };
+
+               /* representor port net_bdf_port */
+               snprintf(name, sizeof(name), "net_%s_representor_%d",
+                       pci_dev->device.name, eth_da.representor_ports[i]);
+
+               retval = rte_eth_dev_create(&pci_dev->device, name,
+                       sizeof(struct i40e_vf_representor), NULL, NULL,
+                       i40e_vf_representor_init, &representor);
+
+               if (retval)
+                       PMD_DRV_LOG(ERR, "failed to create i40e vf "
+                               "representor %s.", name);
+       }
 
        return 0;
 }
 
-static inline int
-rte_i40e_dev_atomic_write_link_status(struct rte_eth_dev *dev,
-                                     struct rte_eth_link *link)
+static int eth_i40e_pci_remove(struct rte_pci_device *pci_dev)
 {
-       struct rte_eth_link *dst = &(dev->data->dev_link);
-       struct rte_eth_link *src = link;
+       struct rte_eth_dev *ethdev;
 
-       if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
-                                       *(uint64_t *)src) == 0)
-               return -1;
+       ethdev = rte_eth_dev_allocated(pci_dev->device.name);
+       if (!ethdev)
+               return -ENODEV;
 
-       return 0;
+
+       if (ethdev->data->dev_flags & RTE_ETH_DEV_REPRESENTOR)
+               return rte_eth_dev_destroy(ethdev, i40e_vf_representor_uninit);
+       else
+               return rte_eth_dev_destroy(ethdev, eth_i40e_dev_uninit);
+}
+
+static struct rte_pci_driver rte_i40e_pmd = {
+       .id_table = pci_id_i40e_map,
+       .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC |
+                    RTE_PCI_DRV_IOVA_AS_VA,
+       .probe = eth_i40e_pci_probe,
+       .remove = eth_i40e_pci_remove,
+};
+
+static inline void
+i40e_write_global_rx_ctl(struct i40e_hw *hw, uint32_t reg_addr,
+                        uint32_t reg_val)
+{
+       uint32_t ori_reg_val;
+       struct rte_eth_dev *dev;
+
+       ori_reg_val = i40e_read_rx_ctl(hw, reg_addr);
+       dev = ((struct i40e_adapter *)hw->back)->eth_dev;
+       i40e_write_rx_ctl(hw, reg_addr, reg_val);
+       if (ori_reg_val != reg_val)
+               PMD_DRV_LOG(WARNING,
+                           "i40e device %s changed global register [0x%08x]."
+                           " original: 0x%08x, new: 0x%08x",
+                           dev->device->name, reg_addr, ori_reg_val, reg_val);
 }
 
-RTE_PMD_REGISTER_PCI(net_i40e, rte_i40e_pmd.pci_drv);
+RTE_PMD_REGISTER_PCI(net_i40e, rte_i40e_pmd);
 RTE_PMD_REGISTER_PCI_TABLE(net_i40e, pci_id_i40e_map);
-RTE_PMD_REGISTER_KMOD_DEP(net_i40e, "* igb_uio | uio_pci_generic | vfio");
+RTE_PMD_REGISTER_KMOD_DEP(net_i40e, "* igb_uio | uio_pci_generic | vfio-pci");
 
 #ifndef I40E_GLQF_ORT
 #define I40E_GLQF_ORT(_i)    (0x00268900 + ((_i) * 4))
@@ -688,29 +734,37 @@ RTE_PMD_REGISTER_KMOD_DEP(net_i40e, "* igb_uio | uio_pci_generic | vfio");
 #ifndef I40E_GLQF_PIT
 #define I40E_GLQF_PIT(_i)    (0x00268C80 + ((_i) * 4))
 #endif
+#ifndef I40E_GLQF_L3_MAP
+#define I40E_GLQF_L3_MAP(_i) (0x0026C700 + ((_i) * 4))
+#endif
 
 static inline void i40e_GLQF_reg_init(struct i40e_hw *hw)
 {
        /*
-        * Initialize registers for flexible payload, which should be set by NVM.
-        * This should be removed from code once it is fixed in NVM.
+        * Initialize registers for parsing packet type of QinQ
+        * This should be removed from code once proper
+        * configuration API is added to avoid configuration conflicts
+        * between ports of the same device.
         */
-       I40E_WRITE_REG(hw, I40E_GLQF_ORT(18), 0x00000030);
-       I40E_WRITE_REG(hw, I40E_GLQF_ORT(19), 0x00000030);
-       I40E_WRITE_REG(hw, I40E_GLQF_ORT(26), 0x0000002B);
-       I40E_WRITE_REG(hw, I40E_GLQF_ORT(30), 0x0000002B);
-       I40E_WRITE_REG(hw, I40E_GLQF_ORT(33), 0x000000E0);
-       I40E_WRITE_REG(hw, I40E_GLQF_ORT(34), 0x000000E3);
-       I40E_WRITE_REG(hw, I40E_GLQF_ORT(35), 0x000000E6);
-       I40E_WRITE_REG(hw, I40E_GLQF_ORT(20), 0x00000031);
-       I40E_WRITE_REG(hw, I40E_GLQF_ORT(23), 0x00000031);
-       I40E_WRITE_REG(hw, I40E_GLQF_ORT(63), 0x0000002D);
-       I40E_WRITE_REG(hw, I40E_GLQF_PIT(16), 0x00007480);
-       I40E_WRITE_REG(hw, I40E_GLQF_PIT(17), 0x00007440);
-
-       /* Initialize registers for parsing packet type of QinQ */
-       I40E_WRITE_REG(hw, I40E_GLQF_ORT(40), 0x00000029);
-       I40E_WRITE_REG(hw, I40E_GLQF_PIT(9), 0x00009420);
+       I40E_WRITE_GLB_REG(hw, I40E_GLQF_ORT(40), 0x00000029);
+       I40E_WRITE_GLB_REG(hw, I40E_GLQF_PIT(9), 0x00009420);
+}
+
+static inline void i40e_config_automask(struct i40e_pf *pf)
+{
+       struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+       uint32_t val;
+
+       /* INTENA flag is not auto-cleared for interrupt */
+       val = I40E_READ_REG(hw, I40E_GLINT_CTL);
+       val |= I40E_GLINT_CTL_DIS_AUTOMASK_PF0_MASK |
+               I40E_GLINT_CTL_DIS_AUTOMASK_VF0_MASK;
+
+       /* If support multi-driver, PF will use INT0. */
+       if (!pf->support_multi_driver)
+               val |= I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK;
+
+       I40E_WRITE_REG(hw, I40E_GLINT_CTL, val);
 }
 
 #define I40E_FLOW_CONTROL_ETHERTYPE  0x8808
@@ -812,7 +866,7 @@ config_vf_floating_veb(struct rte_devargs *devargs,
        if (devargs == NULL)
                return;
 
-       kvlist = rte_kvargs_parse(devargs->args, NULL);
+       kvlist = rte_kvargs_parse(devargs->args, valid_keys);
        if (kvlist == NULL)
                return;
 
@@ -853,7 +907,7 @@ is_floating_veb_supported(struct rte_devargs *devargs)
        if (devargs == NULL)
                return 0;
 
-       kvlist = rte_kvargs_parse(devargs->args, NULL);
+       kvlist = rte_kvargs_parse(devargs->args, valid_keys);
        if (kvlist == NULL)
                return 0;
 
@@ -877,7 +931,7 @@ is_floating_veb_supported(struct rte_devargs *devargs)
 static void
 config_floating_veb(struct rte_eth_dev *dev)
 {
-       struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
@@ -917,7 +971,7 @@ i40e_init_ethtype_filter_list(struct rte_eth_dev *dev)
        /* Initialize ethertype filter rule list and hash */
        TAILQ_INIT(&ethertype_rule->ethertype_list);
        snprintf(ethertype_hash_name, RTE_HASH_NAMESIZE,
-                "ethertype_%s", dev->data->name);
+                "ethertype_%s", dev->device->name);
        ethertype_rule->hash_table = rte_hash_create(&ethertype_hash_params);
        if (!ethertype_rule->hash_table) {
                PMD_INIT_LOG(ERR, "Failed to create ethertype hash table!");
@@ -962,7 +1016,7 @@ i40e_init_tunnel_filter_list(struct rte_eth_dev *dev)
        /* Initialize tunnel filter rule list and hash */
        TAILQ_INIT(&tunnel_rule->tunnel_list);
        snprintf(tunnel_hash_name, RTE_HASH_NAMESIZE,
-                "tunnel_%s", dev->data->name);
+                "tunnel_%s", dev->device->name);
        tunnel_rule->hash_table = rte_hash_create(&tunnel_hash_params);
        if (!tunnel_rule->hash_table) {
                PMD_INIT_LOG(ERR, "Failed to create tunnel hash table!");
@@ -998,7 +1052,7 @@ i40e_init_fdir_filter_list(struct rte_eth_dev *dev)
        struct rte_hash_parameters fdir_hash_params = {
                .name = fdir_hash_name,
                .entries = I40E_MAX_FDIR_FILTER_NUM,
-               .key_len = sizeof(struct rte_eth_fdir_input),
+               .key_len = sizeof(struct i40e_fdir_input),
                .hash_func = rte_hash_crc,
                .hash_func_init_val = 0,
                .socket_id = rte_socket_id(),
@@ -1007,7 +1061,7 @@ i40e_init_fdir_filter_list(struct rte_eth_dev *dev)
        /* Initialize flow director filter rule list and hash */
        TAILQ_INIT(&fdir_info->fdir_list);
        snprintf(fdir_hash_name, RTE_HASH_NAMESIZE,
-                "fdir_%s", dev->data->name);
+                "fdir_%s", dev->device->name);
        fdir_info->hash_table = rte_hash_create(&fdir_hash_params);
        if (!fdir_info->hash_table) {
                PMD_INIT_LOG(ERR, "Failed to create fdir hash table!");
@@ -1031,8 +1085,189 @@ err_fdir_hash_map_alloc:
        return ret;
 }
 
+static void
+i40e_init_customized_info(struct i40e_pf *pf)
+{
+       int i;
+
+       /* Initialize customized pctype */
+       for (i = I40E_CUSTOMIZED_GTPC; i < I40E_CUSTOMIZED_MAX; i++) {
+               pf->customized_pctype[i].index = i;
+               pf->customized_pctype[i].pctype = I40E_FILTER_PCTYPE_INVALID;
+               pf->customized_pctype[i].valid = false;
+       }
+
+       pf->gtp_support = false;
+}
+
+void
+i40e_init_queue_region_conf(struct rte_eth_dev *dev)
+{
+       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct i40e_queue_regions *info = &pf->queue_region;
+       uint16_t i;
+
+       for (i = 0; i < I40E_PFQF_HREGION_MAX_INDEX; i++)
+               i40e_write_rx_ctl(hw, I40E_PFQF_HREGION(i), 0);
+
+       memset(info, 0, sizeof(struct i40e_queue_regions));
+}
+
+static int
+i40e_parse_multi_drv_handler(__rte_unused const char *key,
+                              const char *value,
+                              void *opaque)
+{
+       struct i40e_pf *pf;
+       unsigned long support_multi_driver;
+       char *end;
+
+       pf = (struct i40e_pf *)opaque;
+
+       errno = 0;
+       support_multi_driver = strtoul(value, &end, 10);
+       if (errno != 0 || end == value || *end != 0) {
+               PMD_DRV_LOG(WARNING, "Wrong global configuration");
+               return -(EINVAL);
+       }
+
+       if (support_multi_driver == 1 || support_multi_driver == 0)
+               pf->support_multi_driver = (bool)support_multi_driver;
+       else
+               PMD_DRV_LOG(WARNING, "%s must be 1 or 0,",
+                           "enable global configuration by default."
+                           ETH_I40E_SUPPORT_MULTI_DRIVER);
+       return 0;
+}
+
+static int
+i40e_support_multi_driver(struct rte_eth_dev *dev)
+{
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct rte_kvargs *kvlist;
+       int kvargs_count;
+
+       /* Enable global configuration by default */
+       pf->support_multi_driver = false;
+
+       if (!dev->device->devargs)
+               return 0;
+
+       kvlist = rte_kvargs_parse(dev->device->devargs->args, valid_keys);
+       if (!kvlist)
+               return -EINVAL;
+
+       kvargs_count = rte_kvargs_count(kvlist, ETH_I40E_SUPPORT_MULTI_DRIVER);
+       if (!kvargs_count) {
+               rte_kvargs_free(kvlist);
+               return 0;
+       }
+
+       if (kvargs_count > 1)
+               PMD_DRV_LOG(WARNING, "More than one argument \"%s\" and only "
+                           "the first invalid or last valid one is used !",
+                           ETH_I40E_SUPPORT_MULTI_DRIVER);
+
+       if (rte_kvargs_process(kvlist, ETH_I40E_SUPPORT_MULTI_DRIVER,
+                              i40e_parse_multi_drv_handler, pf) < 0) {
+               rte_kvargs_free(kvlist);
+               return -EINVAL;
+       }
+
+       rte_kvargs_free(kvlist);
+       return 0;
+}
+
+static int
+i40e_aq_debug_write_global_register(struct i40e_hw *hw,
+                                   uint32_t reg_addr, uint64_t reg_val,
+                                   struct i40e_asq_cmd_details *cmd_details)
+{
+       uint64_t ori_reg_val;
+       struct rte_eth_dev *dev;
+       int ret;
+
+       ret = i40e_aq_debug_read_register(hw, reg_addr, &ori_reg_val, NULL);
+       if (ret != I40E_SUCCESS) {
+               PMD_DRV_LOG(ERR,
+                           "Fail to debug read from 0x%08x",
+                           reg_addr);
+               return -EIO;
+       }
+       dev = ((struct i40e_adapter *)hw->back)->eth_dev;
+
+       if (ori_reg_val != reg_val)
+               PMD_DRV_LOG(WARNING,
+                           "i40e device %s changed global register [0x%08x]."
+                           " original: 0x%"PRIx64", after: 0x%"PRIx64,
+                           dev->device->name, reg_addr, ori_reg_val, reg_val);
+
+       return i40e_aq_debug_write_register(hw, reg_addr, reg_val, cmd_details);
+}
+
+static int
+i40e_parse_latest_vec_handler(__rte_unused const char *key,
+                               const char *value,
+                               void *opaque)
+{
+       struct i40e_adapter *ad;
+       int use_latest_vec;
+
+       ad = (struct i40e_adapter *)opaque;
+
+       use_latest_vec = atoi(value);
+
+       if (use_latest_vec != 0 && use_latest_vec != 1)
+               PMD_DRV_LOG(WARNING, "Value should be 0 or 1, set it as 1!");
+
+       ad->use_latest_vec = (uint8_t)use_latest_vec;
+
+       return 0;
+}
+
+static int
+i40e_use_latest_vec(struct rte_eth_dev *dev)
+{
+       struct i40e_adapter *ad =
+               I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+       struct rte_kvargs *kvlist;
+       int kvargs_count;
+
+       ad->use_latest_vec = false;
+
+       if (!dev->device->devargs)
+               return 0;
+
+       kvlist = rte_kvargs_parse(dev->device->devargs->args, valid_keys);
+       if (!kvlist)
+               return -EINVAL;
+
+       kvargs_count = rte_kvargs_count(kvlist, ETH_I40E_USE_LATEST_VEC);
+       if (!kvargs_count) {
+               rte_kvargs_free(kvlist);
+               return 0;
+       }
+
+       if (kvargs_count > 1)
+               PMD_DRV_LOG(WARNING, "More than one argument \"%s\" and only "
+                           "the first invalid or last valid one is used !",
+                           ETH_I40E_USE_LATEST_VEC);
+
+       if (rte_kvargs_process(kvlist, ETH_I40E_USE_LATEST_VEC,
+                               i40e_parse_latest_vec_handler, ad) < 0) {
+               rte_kvargs_free(kvlist);
+               return -EINVAL;
+       }
+
+       rte_kvargs_free(kvlist);
+       return 0;
+}
+
+#define I40E_ALARM_INTERVAL 50000 /* us */
+
 static int
-eth_i40e_dev_init(struct rte_eth_dev *dev)
+eth_i40e_dev_init(struct rte_eth_dev *dev, void *init_params __rte_unused)
 {
        struct rte_pci_device *pci_dev;
        struct rte_intr_handle *intr_handle;
@@ -1040,7 +1275,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct i40e_vsi *vsi;
        int ret;
-       uint32_t len;
+       uint32_t len, val;
        uint8_t aq_fail = 0;
 
        PMD_INIT_FUNC_TRACE();
@@ -1058,11 +1293,11 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
                i40e_set_tx_function(dev);
                return 0;
        }
-       pci_dev = I40E_DEV_TO_PCI(dev);
+       i40e_set_default_ptype_table(dev);
+       pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        intr_handle = &pci_dev->intr_handle;
 
        rte_eth_copy_pci_info(dev, pci_dev);
-       dev->data->dev_flags |= RTE_ETH_DEV_DETACHABLE;
 
        pf->adapter = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
        pf->adapter->eth_dev = dev;
@@ -1083,13 +1318,32 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
        hw->bus.device = pci_dev->addr.devid;
        hw->bus.func = pci_dev->addr.function;
        hw->adapter_stopped = 0;
+       hw->adapter_closed = 0;
+
+       /*
+        * Switch Tag value should not be identical to either the First Tag
+        * or Second Tag values. So set something other than common Ethertype
+        * for internal switching.
+        */
+       hw->switch_tag = 0xffff;
+
+       val = I40E_READ_REG(hw, I40E_GL_FWSTS);
+       if (val & I40E_GL_FWSTS_FWS1B_MASK) {
+               PMD_INIT_LOG(ERR, "\nERROR: "
+                       "Firmware recovery mode detected. Limiting functionality.\n"
+                       "Refer to the Intel(R) Ethernet Adapters and Devices "
+                       "User Guide for details on firmware recovery mode.");
+               return -EIO;
+       }
+
+       /* Check if need to support multi-driver */
+       i40e_support_multi_driver(dev);
+       /* Check if users want the latest supported vec path */
+       i40e_use_latest_vec(dev);
 
        /* Make sure all is clean before doing PF reset */
        i40e_clear_hw(hw);
 
-       /* Initialize the hardware */
-       i40e_hw_init(dev);
-
        /* Reset here to make sure all is clean for each PF */
        ret = i40e_pf_reset(hw);
        if (ret) {
@@ -1104,17 +1358,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
                return ret;
        }
 
-       /*
-        * To work around the NVM issue, initialize registers
-        * for flexible payload and packet type of QinQ by
-        * software. It should be removed once issues are fixed
-        * in NVM.
-        */
-       i40e_GLQF_reg_init(hw);
-
-       /* Initialize the input set for filters (hash and fd) to default value */
-       i40e_filter_input_set_init(pf);
-
        /* Initialize the parameters for adminq */
        i40e_init_adminq_parameter(hw);
        ret = i40e_init_adminq(hw);
@@ -1129,15 +1372,43 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
                     ((hw->nvm.version >> 4) & 0xff),
                     (hw->nvm.version & 0xf), hw->nvm.eetrack);
 
+       /* Initialize the hardware */
+       i40e_hw_init(dev);
+
+       i40e_config_automask(pf);
+
+       i40e_set_default_pctype_table(dev);
+
+       /*
+        * To work around the NVM issue, initialize registers
+        * for packet type of QinQ by software.
+        * It should be removed once issues are fixed in NVM.
+        */
+       if (!pf->support_multi_driver)
+               i40e_GLQF_reg_init(hw);
+
+       /* Initialize the input set for filters (hash and fd) to default value */
+       i40e_filter_input_set_init(pf);
+
+       /* initialise the L3_MAP register */
+       if (!pf->support_multi_driver) {
+               ret = i40e_aq_debug_write_global_register(hw,
+                                                  I40E_GLQF_L3_MAP(40),
+                                                  0x00000028,  NULL);
+               if (ret)
+                       PMD_INIT_LOG(ERR, "Failed to write L3 MAP register %d",
+                                    ret);
+               PMD_INIT_LOG(DEBUG,
+                            "Global register 0x%08x is changed with 0x28",
+                            I40E_GLQF_L3_MAP(40));
+       }
+
        /* Need the special FW version to support floating VEB */
        config_floating_veb(dev);
        /* Clear PXE mode */
        i40e_clear_pxe_mode(hw);
-       ret = i40e_dev_sync_phy_type(hw);
-       if (ret) {
-               PMD_INIT_LOG(ERR, "Failed to sync phy type: %d", ret);
-               goto err_sync_phy_type;
-       }
+       i40e_dev_sync_phy_type(hw);
+
        /*
         * On X710, performance number is far from the expectation on recent
         * firmware versions. The fix for this issue may not be integrated in
@@ -1198,19 +1469,23 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
                goto err_get_mac_addr;
        }
        /* Copy the permanent MAC address */
-       ether_addr_copy((struct ether_addr *) hw->mac.addr,
-                       (struct ether_addr *) hw->mac.perm_addr);
+       ether_addr_copy((struct rte_ether_addr *)hw->mac.addr,
+                       (struct rte_ether_addr *)hw->mac.perm_addr);
 
        /* Disable flow control */
        hw->fc.requested_mode = I40E_FC_NONE;
        i40e_set_fc(hw, &aq_fail, TRUE);
 
        /* Set the global registers with default ether type value */
-       ret = i40e_vlan_tpid_set(dev, ETH_VLAN_TYPE_OUTER, ETHER_TYPE_VLAN);
-       if (ret != I40E_SUCCESS) {
-               PMD_INIT_LOG(ERR,
-                       "Failed to set the default outer VLAN ether type");
-               goto err_setup_pf_switch;
+       if (!pf->support_multi_driver) {
+               ret = i40e_vlan_tpid_set(dev, ETH_VLAN_TYPE_OUTER,
+                                        ETHER_TYPE_VLAN);
+               if (ret != I40E_SUCCESS) {
+                       PMD_INIT_LOG(ERR,
+                                    "Failed to set the default outer "
+                                    "VLAN ether type");
+                       goto err_setup_pf_switch;
+               }
        }
 
        /* PF setup, which includes VSI setup */
@@ -1220,9 +1495,6 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
                goto err_setup_pf_switch;
        }
 
-       /* reset all stats of the device, including pf and main vsi */
-       i40e_dev_stats_reset(dev);
-
        vsi = pf->main_vsi;
 
        /* Disable double vlan by default */
@@ -1249,7 +1521,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
                        "Failed to allocated memory for storing mac address");
                goto err_mac_alloc;
        }
-       ether_addr_copy((struct ether_addr *)hw->mac.perm_addr,
+       ether_addr_copy((struct rte_ether_addr *)hw->mac.perm_addr,
                                        &dev->data->mac_addrs[0]);
 
        /* Init dcb to sw mode by default */
@@ -1274,6 +1546,11 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
 
        /* enable uio intr after callback register */
        rte_intr_enable(intr_handle);
+
+       /* By default disable flexible payload in global configuration */
+       if (!pf->support_multi_driver)
+               i40e_flex_payload_reg_set_default(hw);
+
        /*
         * Add an ethertype filter to drop all flow control frames transmitted
         * from VSIs. By doing so, we stop VF from sending out PAUSE or PFC
@@ -1289,6 +1566,12 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
        /* initialize mirror rule list */
        TAILQ_INIT(&pf->mirror_list);
 
+       /* initialize Traffic Manager configuration */
+       i40e_tm_conf_init(dev);
+
+       /* Initialize customized information */
+       i40e_init_customized_info(pf);
+
        ret = i40e_init_ethtype_filter_list(dev);
        if (ret < 0)
                goto err_init_ethtype_filter_list;
@@ -1299,6 +1582,16 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
        if (ret < 0)
                goto err_init_fdir_filter_list;
 
+       /* initialize queue region configuration */
+       i40e_init_queue_region_conf(dev);
+
+       /* initialize rss configuration from rte_flow */
+       memset(&pf->rss_info, 0,
+               sizeof(struct i40e_rte_flow_rss_conf));
+
+       /* reset all stats of the device, including pf and main vsi */
+       i40e_dev_stats_reset(dev);
+
        return 0;
 
 err_init_fdir_filter_list:
@@ -1322,7 +1615,6 @@ err_msix_pool_init:
 err_qp_pool_init:
 err_parameter_init:
 err_get_capabilities:
-err_sync_phy_type:
        (void)i40e_shutdown_adminq(hw);
 
        return ret;
@@ -1386,6 +1678,17 @@ i40e_rm_fdir_filter_list(struct i40e_pf *pf)
        }
 }
 
+void i40e_flex_payload_reg_set_default(struct i40e_hw *hw)
+{
+       /*
+        * Disable by default flexible payload
+        * for corresponding L2/L3/L4 layers.
+        */
+       I40E_WRITE_GLB_REG(hw, I40E_GLQF_ORT(33), 0x00000000);
+       I40E_WRITE_GLB_REG(hw, I40E_GLQF_ORT(34), 0x00000000);
+       I40E_WRITE_GLB_REG(hw, I40E_GLQF_ORT(35), 0x00000000);
+}
+
 static int
 eth_i40e_dev_uninit(struct rte_eth_dev *dev)
 {
@@ -1397,6 +1700,7 @@ eth_i40e_dev_uninit(struct rte_eth_dev *dev)
        struct rte_flow *p_flow;
        int ret;
        uint8_t aq_fail = 0;
+       int retries = 0;
 
        PMD_INIT_FUNC_TRACE();
 
@@ -1405,10 +1709,14 @@ eth_i40e_dev_uninit(struct rte_eth_dev *dev)
 
        pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       pci_dev = I40E_DEV_TO_PCI(dev);
+       pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        intr_handle = &pci_dev->intr_handle;
 
-       if (hw->adapter_stopped == 0)
+       ret = rte_eth_switch_domain_free(pf->switch_domain_id);
+       if (ret)
+               PMD_INIT_LOG(WARNING, "failed to free switch domain: %d", ret);
+
+       if (hw->adapter_closed == 0)
                i40e_dev_close(dev);
 
        dev->dev_ops = NULL;
@@ -1432,15 +1740,23 @@ eth_i40e_dev_uninit(struct rte_eth_dev *dev)
        /* uninitialize pf host driver */
        i40e_pf_host_uninit(dev);
 
-       rte_free(dev->data->mac_addrs);
-       dev->data->mac_addrs = NULL;
-
        /* disable uio intr before callback unregister */
        rte_intr_disable(intr_handle);
 
-       /* register callback func to eal lib */
-       rte_intr_callback_unregister(intr_handle,
-                                    i40e_dev_interrupt_handler, dev);
+       /* unregister callback func to eal lib */
+       do {
+               ret = rte_intr_callback_unregister(intr_handle,
+                               i40e_dev_interrupt_handler, dev);
+               if (ret >= 0) {
+                       break;
+               } else if (ret != -EAGAIN) {
+                       PMD_INIT_LOG(ERR,
+                                "intr callback unregister failed: %d",
+                                ret);
+                       return ret;
+               }
+               i40e_msec_delay(500);
+       } while (retries++ < 5);
 
        i40e_rm_ethtype_filter_list(pf);
        i40e_rm_tunnel_filter_list(pf);
@@ -1452,6 +1768,9 @@ eth_i40e_dev_uninit(struct rte_eth_dev *dev)
                rte_free(p_flow);
        }
 
+       /* Remove all Traffic Manager configuration */
+       i40e_tm_conf_uninit(dev);
+
        return 0;
 }
 
@@ -1461,9 +1780,14 @@ i40e_dev_configure(struct rte_eth_dev *dev)
        struct i40e_adapter *ad =
                I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        enum rte_eth_rx_mq_mode mq_mode = dev->data->dev_conf.rxmode.mq_mode;
        int i, ret;
 
+       ret = i40e_dev_sync_phy_type(hw);
+       if (ret)
+               return ret;
+
        /* Initialize to TRUE. If any of Rx queues doesn't meet the
         * bulk allocation or vector Rx preconditions we will reset it.
         */
@@ -1472,6 +1796,10 @@ i40e_dev_configure(struct rte_eth_dev *dev)
        ad->tx_simple_allowed = true;
        ad->tx_vec_allowed = true;
 
+       /* Only legacy filter API needs the following fdir config. So when the
+        * legacy filter API is deprecated, the following codes should also be
+        * removed.
+        */
        if (dev->data->dev_conf.fdir_conf.mode == RTE_FDIR_MODE_PERFECT) {
                ret = i40e_fdir_setup(pf);
                if (ret != I40E_SUCCESS) {
@@ -1529,7 +1857,11 @@ err_dcb:
        rte_free(pf->vmdq);
        pf->vmdq = NULL;
 err:
-       /* need to release fdir resource if exists */
+       /* Need to release fdir resource if exists.
+        * Only legacy filter API needs the following fdir config. So when the
+        * legacy filter API is deprecated, the following code should also be
+        * removed.
+        */
        i40e_fdir_teardown(pf);
        return ret;
 }
@@ -1538,7 +1870,7 @@ void
 i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
 {
        struct rte_eth_dev *dev = vsi->adapter->eth_dev;
-       struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
        struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
        uint16_t msix_vect = vsi->msix_intr;
@@ -1577,16 +1909,18 @@ i40e_vsi_queues_unbind_intr(struct i40e_vsi *vsi)
 
 static void
 __vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
-                      int base_queue, int nb_queue)
+                      int base_queue, int nb_queue,
+                      uint16_t itr_idx)
 {
        int i;
        uint32_t val;
        struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+       struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
 
        /* Bind all RX queues to allocated MSIX interrupt */
        for (i = 0; i < nb_queue; i++) {
                val = (msix_vect << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
-                       I40E_QINT_RQCTL_ITR_INDX_MASK |
+                       itr_idx << I40E_QINT_RQCTL_ITR_INDX_SHIFT |
                        ((base_queue + i + 1) <<
                         I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
                        (0 << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
@@ -1600,7 +1934,7 @@ __vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
        /* Write first RX queue to Link list register as the head element */
        if (vsi->type != I40E_VSI_SRIOV) {
                uint16_t interval =
-                       i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);
+                       i40e_calc_itr_interval(1, pf->support_multi_driver);
 
                if (msix_vect == I40E_MISC_VEC_ID) {
                        I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0,
@@ -1649,17 +1983,16 @@ __vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t msix_vect,
 }
 
 void
-i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
+i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi, uint16_t itr_idx)
 {
        struct rte_eth_dev *dev = vsi->adapter->eth_dev;
-       struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
        struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
        uint16_t msix_vect = vsi->msix_intr;
        uint16_t nb_msix = RTE_MIN(vsi->nb_msix, intr_handle->nb_efd);
        uint16_t queue_idx = 0;
        int record = 0;
-       uint32_t val;
        int i;
 
        for (i = 0; i < vsi->nb_qps; i++) {
@@ -1667,17 +2000,11 @@ i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
                I40E_WRITE_REG(hw, I40E_QINT_RQCTL(vsi->base_queue + i), 0);
        }
 
-       /* INTENA flag is not auto-cleared for interrupt */
-       val = I40E_READ_REG(hw, I40E_GLINT_CTL);
-       val |= I40E_GLINT_CTL_DIS_AUTOMASK_PF0_MASK |
-               I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK |
-               I40E_GLINT_CTL_DIS_AUTOMASK_VF0_MASK;
-       I40E_WRITE_REG(hw, I40E_GLINT_CTL, val);
-
        /* VF bind interrupt */
        if (vsi->type == I40E_VSI_SRIOV) {
                __vsi_queues_bind_intr(vsi, msix_vect,
-                                      vsi->base_queue, vsi->nb_qps);
+                                      vsi->base_queue, vsi->nb_qps,
+                                      itr_idx);
                return;
        }
 
@@ -1703,7 +2030,8 @@ i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
                        /* no enough msix_vect, map all to one */
                        __vsi_queues_bind_intr(vsi, msix_vect,
                                               vsi->base_queue + i,
-                                              vsi->nb_used_qps - i);
+                                              vsi->nb_used_qps - i,
+                                              itr_idx);
                        for (; !!record && i < vsi->nb_used_qps; i++)
                                intr_handle->intr_vec[queue_idx + i] =
                                        msix_vect;
@@ -1711,7 +2039,8 @@ i40e_vsi_queues_bind_intr(struct i40e_vsi *vsi)
                }
                /* 1:1 queue/msix_vect mapping */
                __vsi_queues_bind_intr(vsi, msix_vect,
-                                      vsi->base_queue + i, 1);
+                                      vsi->base_queue + i, 1,
+                                      itr_idx);
                if (!!record)
                        intr_handle->intr_vec[queue_idx + i] = msix_vect;
 
@@ -1724,30 +2053,25 @@ static void
 i40e_vsi_enable_queues_intr(struct i40e_vsi *vsi)
 {
        struct rte_eth_dev *dev = vsi->adapter->eth_dev;
-       struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
        struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
-       uint16_t interval = i40e_calc_itr_interval(\
-               RTE_LIBRTE_I40E_ITR_INTERVAL);
+       struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
        uint16_t msix_intr, i;
 
-       if (rte_intr_allow_others(intr_handle))
+       if (rte_intr_allow_others(intr_handle) && !pf->support_multi_driver)
                for (i = 0; i < vsi->nb_msix; i++) {
                        msix_intr = vsi->msix_intr + i;
                        I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(msix_intr - 1),
                                I40E_PFINT_DYN_CTLN_INTENA_MASK |
                                I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
-                               (0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
-                               (interval <<
-                                I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+                               I40E_PFINT_DYN_CTLN_ITR_INDX_MASK);
                }
        else
                I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
                               I40E_PFINT_DYN_CTL0_INTENA_MASK |
                               I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
-                              (0 << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT) |
-                              (interval <<
-                               I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT));
+                              I40E_PFINT_DYN_CTL0_ITR_INDX_MASK);
 
        I40E_WRITE_FLUSH(hw);
 }
@@ -1756,19 +2080,21 @@ static void
 i40e_vsi_disable_queues_intr(struct i40e_vsi *vsi)
 {
        struct rte_eth_dev *dev = vsi->adapter->eth_dev;
-       struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
        struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+       struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
        uint16_t msix_intr, i;
 
-       if (rte_intr_allow_others(intr_handle))
+       if (rte_intr_allow_others(intr_handle) && !pf->support_multi_driver)
                for (i = 0; i < vsi->nb_msix; i++) {
                        msix_intr = vsi->msix_intr + i;
                        I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(msix_intr - 1),
-                                      0);
+                                      I40E_PFINT_DYN_CTLN_ITR_INDX_MASK);
                }
        else
-               I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, 0);
+               I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
+                              I40E_PFINT_DYN_CTL0_ITR_INDX_MASK);
 
        I40E_WRITE_FLUSH(hw);
 }
@@ -1797,27 +2123,48 @@ i40e_parse_link_speeds(uint16_t link_speeds)
 static int
 i40e_phy_conf_link(struct i40e_hw *hw,
                   uint8_t abilities,
-                  uint8_t force_speed)
+                  uint8_t force_speed,
+                  bool is_up)
 {
        enum i40e_status_code status;
        struct i40e_aq_get_phy_abilities_resp phy_ab;
        struct i40e_aq_set_phy_config phy_conf;
+       enum i40e_aq_phy_type cnt;
+       uint8_t avail_speed;
+       uint32_t phy_type_mask = 0;
+
        const uint8_t mask = I40E_AQ_PHY_FLAG_PAUSE_TX |
                        I40E_AQ_PHY_FLAG_PAUSE_RX |
                        I40E_AQ_PHY_FLAG_PAUSE_RX |
                        I40E_AQ_PHY_FLAG_LOW_POWER;
-       const uint8_t advt = I40E_LINK_SPEED_40GB |
-                       I40E_LINK_SPEED_25GB |
-                       I40E_LINK_SPEED_10GB |
-                       I40E_LINK_SPEED_1GB |
-                       I40E_LINK_SPEED_100MB;
        int ret = -ENOTSUP;
 
-
-       status = i40e_aq_get_phy_capabilities(hw, false, false, &phy_ab,
+       /* To get phy capabilities of available speeds. */
+       status = i40e_aq_get_phy_capabilities(hw, false, true, &phy_ab,
                                              NULL);
-       if (status)
+       if (status) {
+               PMD_DRV_LOG(ERR, "Failed to get PHY capabilities: %d\n",
+                               status);
+               return ret;
+       }
+       avail_speed = phy_ab.link_speed;
+
+       /* To get the current phy config. */
+       status = i40e_aq_get_phy_capabilities(hw, false, false, &phy_ab,
+                                             NULL);
+       if (status) {
+               PMD_DRV_LOG(ERR, "Failed to get the current PHY config: %d\n",
+                               status);
                return ret;
+       }
+
+       /* If link needs to go up and it is in autoneg mode the speed is OK,
+        * no need to set up again.
+        */
+       if (is_up && phy_ab.phy_type != 0 &&
+                    abilities & I40E_AQ_PHY_AN_ENABLED &&
+                    phy_ab.link_speed != 0)
+               return I40E_SUCCESS;
 
        memset(&phy_conf, 0, sizeof(phy_conf));
 
@@ -1825,17 +2172,27 @@ i40e_phy_conf_link(struct i40e_hw *hw,
        abilities &= ~mask;
        abilities |= phy_ab.abilities & mask;
 
-       /* update ablities and speed */
-       if (abilities & I40E_AQ_PHY_AN_ENABLED)
-               phy_conf.link_speed = advt;
-       else
-               phy_conf.link_speed = force_speed;
-
        phy_conf.abilities = abilities;
 
+       /* If link needs to go up, but the force speed is not supported,
+        * Warn users and config the default available speeds.
+        */
+       if (is_up && !(force_speed & avail_speed)) {
+               PMD_DRV_LOG(WARNING, "Invalid speed setting, set to default!\n");
+               phy_conf.link_speed = avail_speed;
+       } else {
+               phy_conf.link_speed = is_up ? force_speed : avail_speed;
+       }
+
+       /* PHY type mask needs to include each type except PHY type extension */
+       for (cnt = I40E_PHY_TYPE_SGMII; cnt < I40E_PHY_TYPE_25GBASE_KR; cnt++)
+               phy_type_mask |= 1 << cnt;
+
        /* use get_phy_abilities_resp value for the rest */
-       phy_conf.phy_type = phy_ab.phy_type;
-       phy_conf.phy_type_ext = phy_ab.phy_type_ext;
+       phy_conf.phy_type = is_up ? cpu_to_le32(phy_type_mask) : 0;
+       phy_conf.phy_type_ext = is_up ? (I40E_AQ_PHY_TYPE_EXT_25G_KR |
+               I40E_AQ_PHY_TYPE_EXT_25G_CR | I40E_AQ_PHY_TYPE_EXT_25G_SR |
+               I40E_AQ_PHY_TYPE_EXT_25G_LR) : 0;
        phy_conf.fec_config = phy_ab.fec_cfg_curr_mod_ext_info;
        phy_conf.eee_capability = phy_ab.eee_capability;
        phy_conf.eeer = phy_ab.eeer_val;
@@ -1861,19 +2218,20 @@ i40e_apply_link_speed(struct rte_eth_dev *dev)
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct rte_eth_conf *conf = &dev->data->dev_conf;
 
-       speed = i40e_parse_link_speeds(conf->link_speeds);
-       abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
-       if (!(conf->link_speeds & ETH_LINK_SPEED_FIXED))
-               abilities |= I40E_AQ_PHY_AN_ENABLED;
-       abilities |= I40E_AQ_PHY_LINK_ENABLED;
-
-       /* Skip changing speed on 40G interfaces, FW does not support */
-       if (I40E_PHY_TYPE_SUPPORT_40G(hw->phy.phy_types)) {
-               speed =  I40E_LINK_SPEED_UNKNOWN;
-               abilities |= I40E_AQ_PHY_AN_ENABLED;
+       if (conf->link_speeds == ETH_LINK_SPEED_AUTONEG) {
+               conf->link_speeds = ETH_LINK_SPEED_40G |
+                                   ETH_LINK_SPEED_25G |
+                                   ETH_LINK_SPEED_20G |
+                                   ETH_LINK_SPEED_10G |
+                                   ETH_LINK_SPEED_1G |
+                                   ETH_LINK_SPEED_100M;
        }
+       speed = i40e_parse_link_speeds(conf->link_speeds);
+       abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK |
+                    I40E_AQ_PHY_AN_ENABLED |
+                    I40E_AQ_PHY_LINK_ENABLED;
 
-       return i40e_phy_conf_link(hw, abilities, speed);
+       return i40e_phy_conf_link(hw, abilities, speed, true);
 }
 
 static int
@@ -1883,7 +2241,7 @@ i40e_dev_start(struct rte_eth_dev *dev)
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct i40e_vsi *main_vsi = pf->main_vsi;
        int ret, i;
-       struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
        uint32_t intr_vector = 0;
        struct i40e_vsi *vsi;
@@ -1891,8 +2249,9 @@ i40e_dev_start(struct rte_eth_dev *dev)
        hw->adapter_stopped = 0;
 
        if (dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED) {
-               PMD_INIT_LOG(ERR, "Invalid link_speeds for port %hhu; autonegotiation disabled",
-                            dev->data->port_id);
+               PMD_INIT_LOG(ERR,
+               "Invalid link_speeds for port %u, autonegotiation disabled",
+                             dev->data->port_id);
                return -EINVAL;
        }
 
@@ -1930,19 +2289,21 @@ i40e_dev_start(struct rte_eth_dev *dev)
        /* Map queues with MSIX interrupt */
        main_vsi->nb_used_qps = dev->data->nb_rx_queues -
                pf->nb_cfg_vmdq_vsi * RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM;
-       i40e_vsi_queues_bind_intr(main_vsi);
+       i40e_vsi_queues_bind_intr(main_vsi, I40E_ITR_INDEX_DEFAULT);
        i40e_vsi_enable_queues_intr(main_vsi);
 
        /* Map VMDQ VSI queues with MSIX interrupt */
        for (i = 0; i < pf->nb_cfg_vmdq_vsi; i++) {
                pf->vmdq[i].vsi->nb_used_qps = RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM;
-               i40e_vsi_queues_bind_intr(pf->vmdq[i].vsi);
+               i40e_vsi_queues_bind_intr(pf->vmdq[i].vsi,
+                                         I40E_ITR_INDEX_DEFAULT);
                i40e_vsi_enable_queues_intr(pf->vmdq[i].vsi);
        }
 
        /* enable FDIR MSIX interrupt */
        if (pf->fdir.fdir_vsi) {
-               i40e_vsi_queues_bind_intr(pf->fdir.fdir_vsi);
+               i40e_vsi_queues_bind_intr(pf->fdir.fdir_vsi,
+                                         I40E_ITR_INDEX_NONE);
                i40e_vsi_enable_queues_intr(pf->fdir.fdir_vsi);
        }
 
@@ -1974,14 +2335,17 @@ i40e_dev_start(struct rte_eth_dev *dev)
                }
        }
 
-       /* Apply link configure */
-       if (dev->data->dev_conf.link_speeds & ~(ETH_LINK_SPEED_100M |
-                               ETH_LINK_SPEED_1G | ETH_LINK_SPEED_10G |
-                               ETH_LINK_SPEED_20G | ETH_LINK_SPEED_25G |
-                               ETH_LINK_SPEED_40G)) {
-               PMD_DRV_LOG(ERR, "Invalid link setting");
-               goto err_up;
+       /* Enable mac loopback mode */
+       if (dev->data->dev_conf.lpbk_mode == I40E_AQ_LB_MODE_NONE ||
+           dev->data->dev_conf.lpbk_mode == I40E_AQ_LB_PHY_LOCAL) {
+               ret = i40e_aq_set_lb_modes(hw, dev->data->dev_conf.lpbk_mode, NULL);
+               if (ret != I40E_SUCCESS) {
+                       PMD_DRV_LOG(ERR, "fail to set loopback link");
+                       goto err_up;
+               }
        }
+
+       /* Apply link configure */
        ret = i40e_apply_link_speed(dev);
        if (I40E_SUCCESS != ret) {
                PMD_DRV_LOG(ERR, "Fail to apply link setting");
@@ -1999,7 +2363,7 @@ i40e_dev_start(struct rte_eth_dev *dev)
                if (dev->data->dev_conf.intr_conf.lsc != 0)
                        PMD_INIT_LOG(INFO,
                                "lsc won't enable because of no intr multiplex");
-       } else if (dev->data->dev_conf.intr_conf.lsc != 0) {
+       } else {
                ret = i40e_aq_set_phy_int_mask(hw,
                                               ~(I40E_AQ_EVENT_LINK_UPDOWN |
                                               I40E_AQ_EVENT_MODULE_QUAL_FAIL |
@@ -2007,15 +2371,25 @@ i40e_dev_start(struct rte_eth_dev *dev)
                if (ret != I40E_SUCCESS)
                        PMD_DRV_LOG(WARNING, "Fail to set phy mask");
 
-               /* Call get_link_info aq commond to enable LSE */
+               /* Call get_link_info aq commond to enable/disable LSE */
                i40e_dev_link_update(dev, 0);
        }
 
-       /* enable uio intr after callback register */
-       rte_intr_enable(intr_handle);
+       if (dev->data->dev_conf.intr_conf.rxq == 0) {
+               rte_eal_alarm_set(I40E_ALARM_INTERVAL,
+                                 i40e_dev_alarm_handler, dev);
+       } else {
+               /* enable uio intr after callback register */
+               rte_intr_enable(intr_handle);
+       }
 
        i40e_filter_restore(pf);
 
+       if (pf->tm_conf.root && !pf->tm_conf.committed)
+               PMD_DRV_LOG(WARNING,
+                           "please call hierarchy_commit() "
+                           "before starting the port");
+
        return I40E_SUCCESS;
 
 err_up:
@@ -2029,12 +2403,20 @@ static void
 i40e_dev_stop(struct rte_eth_dev *dev)
 {
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct i40e_vsi *main_vsi = pf->main_vsi;
-       struct i40e_mirror_rule *p_mirror;
-       struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
        int i;
 
+       if (hw->adapter_stopped == 1)
+               return;
+
+       if (dev->data->dev_conf.intr_conf.rxq == 0) {
+               rte_eal_alarm_cancel(i40e_dev_alarm_handler, dev);
+               rte_intr_enable(intr_handle);
+       }
+
        /* Disable all queues */
        i40e_dev_switch_queues(pf, FALSE);
 
@@ -2057,13 +2439,6 @@ i40e_dev_stop(struct rte_eth_dev *dev)
        /* Set link down */
        i40e_dev_set_link_down(dev);
 
-       /* Remove all mirror rules */
-       while ((p_mirror = TAILQ_FIRST(&pf->mirror_list))) {
-               TAILQ_REMOVE(&pf->mirror_list, p_mirror, rules);
-               rte_free(p_mirror);
-       }
-       pf->nb_mirror_rule = 0;
-
        if (!rte_intr_allow_others(intr_handle))
                /* resume to the default handler */
                rte_intr_callback_register(intr_handle,
@@ -2076,6 +2451,13 @@ i40e_dev_stop(struct rte_eth_dev *dev)
                rte_free(intr_handle->intr_vec);
                intr_handle->intr_vec = NULL;
        }
+
+       /* reset hierarchy commit */
+       pf->tm_conf.committed = false;
+
+       hw->adapter_stopped = 1;
+
+       pf->adapter->rss_reta_updated = 0;
 }
 
 static void
@@ -2083,21 +2465,49 @@ i40e_dev_close(struct rte_eth_dev *dev)
 {
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
+       struct i40e_mirror_rule *p_mirror;
        uint32_t reg;
        int i;
+       int ret;
 
        PMD_INIT_FUNC_TRACE();
 
        i40e_dev_stop(dev);
-       hw->adapter_stopped = 1;
+
+       /* Remove all mirror rules */
+       while ((p_mirror = TAILQ_FIRST(&pf->mirror_list))) {
+               ret = i40e_aq_del_mirror_rule(hw,
+                                             pf->main_vsi->veb->seid,
+                                             p_mirror->rule_type,
+                                             p_mirror->entries,
+                                             p_mirror->num_entries,
+                                             p_mirror->id);
+               if (ret < 0)
+                       PMD_DRV_LOG(ERR, "failed to remove mirror rule: "
+                                   "status = %d, aq_err = %d.", ret,
+                                   hw->aq.asq_last_status);
+
+               /* remove mirror software resource anyway */
+               TAILQ_REMOVE(&pf->mirror_list, p_mirror, rules);
+               rte_free(p_mirror);
+               pf->nb_mirror_rule--;
+       }
+
        i40e_dev_free_queues(dev);
 
        /* Disable interrupt */
        i40e_pf_disable_irq0(hw);
        rte_intr_disable(intr_handle);
 
+       /*
+        * Only legacy filter API needs the following fdir config. So when the
+        * legacy filter API is deprecated, the following code should also be
+        * removed.
+        */
+       i40e_fdir_teardown(pf);
+
        /* shutdown and destroy the HMC */
        i40e_shutdown_lan_hmc(hw);
 
@@ -2109,7 +2519,6 @@ i40e_dev_close(struct rte_eth_dev *dev)
        pf->vmdq = NULL;
 
        /* release all the existing VSIs and VEBs */
-       i40e_fdir_teardown(pf);
        i40e_vsi_release(pf->main_vsi);
 
        /* shutdown the adminq */
@@ -2119,11 +2528,43 @@ i40e_dev_close(struct rte_eth_dev *dev)
        i40e_res_pool_destroy(&pf->qp_pool);
        i40e_res_pool_destroy(&pf->msix_pool);
 
+       /* Disable flexible payload in global configuration */
+       if (!pf->support_multi_driver)
+               i40e_flex_payload_reg_set_default(hw);
+
        /* force a PF reset to clean anything leftover */
        reg = I40E_READ_REG(hw, I40E_PFGEN_CTRL);
        I40E_WRITE_REG(hw, I40E_PFGEN_CTRL,
                        (reg | I40E_PFGEN_CTRL_PFSWR_MASK));
        I40E_WRITE_FLUSH(hw);
+
+       hw->adapter_closed = 1;
+}
+
+/*
+ * Reset PF device only to re-initialize resources in PMD layer
+ */
+static int
+i40e_dev_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. As to i40e PF, it is rather complex.
+        * 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_i40e_dev_uninit(dev);
+       if (ret)
+               return ret;
+
+       ret = eth_i40e_dev_init(dev, NULL);
+
+       return ret;
 }
 
 static void
@@ -2159,6 +2600,10 @@ i40e_dev_promiscuous_disable(struct rte_eth_dev *dev)
        if (status != I40E_SUCCESS)
                PMD_DRV_LOG(ERR, "Failed to disable unicast promiscuous");
 
+       /* must remain in all_multicast mode */
+       if (dev->data->all_multicast == 1)
+               return;
+
        status = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid,
                                                        false, NULL);
        if (status != I40E_SUCCESS)
@@ -2216,85 +2661,155 @@ i40e_dev_set_link_down(struct rte_eth_dev *dev)
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
        abilities = I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
-       return i40e_phy_conf_link(hw, abilities, speed);
+       return i40e_phy_conf_link(hw, abilities, speed, false);
+}
+
+static __rte_always_inline void
+update_link_reg(struct i40e_hw *hw, struct rte_eth_link *link)
+{
+/* Link status registers and values*/
+#define I40E_PRTMAC_LINKSTA            0x001E2420
+#define I40E_REG_LINK_UP               0x40000080
+#define I40E_PRTMAC_MACC               0x001E24E0
+#define I40E_REG_MACC_25GB             0x00020000
+#define I40E_REG_SPEED_MASK            0x38000000
+#define I40E_REG_SPEED_0               0x00000000
+#define I40E_REG_SPEED_1               0x08000000
+#define I40E_REG_SPEED_2               0x10000000
+#define I40E_REG_SPEED_3               0x18000000
+#define I40E_REG_SPEED_4               0x20000000
+       uint32_t link_speed;
+       uint32_t reg_val;
+
+       reg_val = I40E_READ_REG(hw, I40E_PRTMAC_LINKSTA);
+       link_speed = reg_val & I40E_REG_SPEED_MASK;
+       reg_val &= I40E_REG_LINK_UP;
+       link->link_status = (reg_val == I40E_REG_LINK_UP) ? 1 : 0;
+
+       if (unlikely(link->link_status == 0))
+               return;
+
+       /* Parse the link status */
+       switch (link_speed) {
+       case I40E_REG_SPEED_0:
+               link->link_speed = ETH_SPEED_NUM_100M;
+               break;
+       case I40E_REG_SPEED_1:
+               link->link_speed = ETH_SPEED_NUM_1G;
+               break;
+       case I40E_REG_SPEED_2:
+               if (hw->mac.type == I40E_MAC_X722)
+                       link->link_speed = ETH_SPEED_NUM_2_5G;
+               else
+                       link->link_speed = ETH_SPEED_NUM_10G;
+               break;
+       case I40E_REG_SPEED_3:
+               if (hw->mac.type == I40E_MAC_X722) {
+                       link->link_speed = ETH_SPEED_NUM_5G;
+               } else {
+                       reg_val = I40E_READ_REG(hw, I40E_PRTMAC_MACC);
+
+                       if (reg_val & I40E_REG_MACC_25GB)
+                               link->link_speed = ETH_SPEED_NUM_25G;
+                       else
+                               link->link_speed = ETH_SPEED_NUM_40G;
+               }
+               break;
+       case I40E_REG_SPEED_4:
+               if (hw->mac.type == I40E_MAC_X722)
+                       link->link_speed = ETH_SPEED_NUM_10G;
+               else
+                       link->link_speed = ETH_SPEED_NUM_20G;
+               break;
+       default:
+               PMD_DRV_LOG(ERR, "Unknown link speed info %u", link_speed);
+               break;
+       }
 }
 
-int
-i40e_dev_link_update(struct rte_eth_dev *dev,
-                    int wait_to_complete)
+static __rte_always_inline void
+update_link_aq(struct i40e_hw *hw, struct rte_eth_link *link,
+       bool enable_lse, int wait_to_complete)
 {
-#define CHECK_INTERVAL 100  /* 100ms */
-#define MAX_REPEAT_TIME 10  /* 1s (10 * 100ms) in total */
-       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+#define CHECK_INTERVAL             100  /* 100ms */
+#define MAX_REPEAT_TIME            10  /* 1s (10 * 100ms) in total */
+       uint32_t rep_cnt = MAX_REPEAT_TIME;
        struct i40e_link_status link_status;
-       struct rte_eth_link link, old;
        int status;
-       unsigned rep_cnt = MAX_REPEAT_TIME;
-       bool enable_lse = dev->data->dev_conf.intr_conf.lsc ? true : false;
 
-       memset(&link, 0, sizeof(link));
-       memset(&old, 0, sizeof(old));
        memset(&link_status, 0, sizeof(link_status));
-       rte_i40e_dev_atomic_read_link_status(dev, &old);
 
        do {
+               memset(&link_status, 0, sizeof(link_status));
+
                /* Get link status information from hardware */
                status = i40e_aq_get_link_info(hw, enable_lse,
                                                &link_status, NULL);
-               if (status != I40E_SUCCESS) {
-                       link.link_speed = ETH_SPEED_NUM_100M;
-                       link.link_duplex = ETH_LINK_FULL_DUPLEX;
+               if (unlikely(status != I40E_SUCCESS)) {
+                       link->link_speed = ETH_SPEED_NUM_100M;
+                       link->link_duplex = ETH_LINK_FULL_DUPLEX;
                        PMD_DRV_LOG(ERR, "Failed to get link info");
-                       goto out;
+                       return;
                }
 
-               link.link_status = link_status.link_info & I40E_AQ_LINK_UP;
-               if (!wait_to_complete || link.link_status)
+               link->link_status = link_status.link_info & I40E_AQ_LINK_UP;
+               if (!wait_to_complete || link->link_status)
                        break;
 
                rte_delay_ms(CHECK_INTERVAL);
        } while (--rep_cnt);
 
-       if (!link.link_status)
-               goto out;
-
-       /* i40e uses full duplex only */
-       link.link_duplex = ETH_LINK_FULL_DUPLEX;
-
        /* Parse the link status */
        switch (link_status.link_speed) {
        case I40E_LINK_SPEED_100MB:
-               link.link_speed = ETH_SPEED_NUM_100M;
+               link->link_speed = ETH_SPEED_NUM_100M;
                break;
        case I40E_LINK_SPEED_1GB:
-               link.link_speed = ETH_SPEED_NUM_1G;
+               link->link_speed = ETH_SPEED_NUM_1G;
                break;
        case I40E_LINK_SPEED_10GB:
-               link.link_speed = ETH_SPEED_NUM_10G;
+               link->link_speed = ETH_SPEED_NUM_10G;
                break;
        case I40E_LINK_SPEED_20GB:
-               link.link_speed = ETH_SPEED_NUM_20G;
+               link->link_speed = ETH_SPEED_NUM_20G;
                break;
        case I40E_LINK_SPEED_25GB:
-               link.link_speed = ETH_SPEED_NUM_25G;
+               link->link_speed = ETH_SPEED_NUM_25G;
                break;
        case I40E_LINK_SPEED_40GB:
-               link.link_speed = ETH_SPEED_NUM_40G;
+               link->link_speed = ETH_SPEED_NUM_40G;
                break;
        default:
-               link.link_speed = ETH_SPEED_NUM_100M;
+               link->link_speed = ETH_SPEED_NUM_100M;
                break;
        }
+}
+
+int
+i40e_dev_link_update(struct rte_eth_dev *dev,
+                    int wait_to_complete)
+{
+       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct rte_eth_link link;
+       bool enable_lse = dev->data->dev_conf.intr_conf.lsc ? true : false;
+       int ret;
+
+       memset(&link, 0, sizeof(link));
 
+       /* i40e uses full duplex only */
+       link.link_duplex = ETH_LINK_FULL_DUPLEX;
        link.link_autoneg = !(dev->data->dev_conf.link_speeds &
                        ETH_LINK_SPEED_FIXED);
 
-out:
-       rte_i40e_dev_atomic_write_link_status(dev, &link);
-       if (link.link_status == old.link_status)
-               return -1;
+       if (!wait_to_complete && !enable_lse)
+               update_link_reg(hw, &link);
+       else
+               update_link_aq(hw, &link, enable_lse, wait_to_complete);
 
-       return 0;
+       ret = rte_eth_linkstatus_set(dev, &link);
+       i40e_notify_all_vfs_link_status(dev);
+
+       return ret;
 }
 
 /* Get all the statistics of a VSI */
@@ -2318,6 +2833,10 @@ i40e_update_vsi_stats(struct i40e_vsi *vsi)
        i40e_stat_update_48(hw, I40E_GLV_BPRCH(idx), I40E_GLV_BPRCL(idx),
                            vsi->offset_loaded, &oes->rx_broadcast,
                            &nes->rx_broadcast);
+       /* exclude CRC bytes */
+       nes->rx_bytes -= (nes->rx_unicast + nes->rx_multicast +
+               nes->rx_broadcast) * ETHER_CRC_LEN;
+
        i40e_stat_update_32(hw, I40E_GLV_RDPC(idx), vsi->offset_loaded,
                            &oes->rx_discards, &nes->rx_discards);
        /* GLV_REPC not supported */
@@ -2368,6 +2887,56 @@ i40e_read_stats_registers(struct i40e_pf *pf, struct i40e_hw *hw)
        struct i40e_hw_port_stats *ns = &pf->stats; /* new stats */
        struct i40e_hw_port_stats *os = &pf->stats_offset; /* old stats */
 
+       /* Get rx/tx bytes of internal transfer packets */
+       i40e_stat_update_48(hw, I40E_GLV_GORCH(hw->port),
+                       I40E_GLV_GORCL(hw->port),
+                       pf->offset_loaded,
+                       &pf->internal_stats_offset.rx_bytes,
+                       &pf->internal_stats.rx_bytes);
+
+       i40e_stat_update_48(hw, I40E_GLV_GOTCH(hw->port),
+                       I40E_GLV_GOTCL(hw->port),
+                       pf->offset_loaded,
+                       &pf->internal_stats_offset.tx_bytes,
+                       &pf->internal_stats.tx_bytes);
+       /* Get total internal rx packet count */
+       i40e_stat_update_48(hw, I40E_GLV_UPRCH(hw->port),
+                           I40E_GLV_UPRCL(hw->port),
+                           pf->offset_loaded,
+                           &pf->internal_stats_offset.rx_unicast,
+                           &pf->internal_stats.rx_unicast);
+       i40e_stat_update_48(hw, I40E_GLV_MPRCH(hw->port),
+                           I40E_GLV_MPRCL(hw->port),
+                           pf->offset_loaded,
+                           &pf->internal_stats_offset.rx_multicast,
+                           &pf->internal_stats.rx_multicast);
+       i40e_stat_update_48(hw, I40E_GLV_BPRCH(hw->port),
+                           I40E_GLV_BPRCL(hw->port),
+                           pf->offset_loaded,
+                           &pf->internal_stats_offset.rx_broadcast,
+                           &pf->internal_stats.rx_broadcast);
+       /* Get total internal tx packet count */
+       i40e_stat_update_48(hw, I40E_GLV_UPTCH(hw->port),
+                           I40E_GLV_UPTCL(hw->port),
+                           pf->offset_loaded,
+                           &pf->internal_stats_offset.tx_unicast,
+                           &pf->internal_stats.tx_unicast);
+       i40e_stat_update_48(hw, I40E_GLV_MPTCH(hw->port),
+                           I40E_GLV_MPTCL(hw->port),
+                           pf->offset_loaded,
+                           &pf->internal_stats_offset.tx_multicast,
+                           &pf->internal_stats.tx_multicast);
+       i40e_stat_update_48(hw, I40E_GLV_BPTCH(hw->port),
+                           I40E_GLV_BPTCL(hw->port),
+                           pf->offset_loaded,
+                           &pf->internal_stats_offset.tx_broadcast,
+                           &pf->internal_stats.tx_broadcast);
+
+       /* exclude CRC size */
+       pf->internal_stats.rx_bytes -= (pf->internal_stats.rx_unicast +
+               pf->internal_stats.rx_multicast +
+               pf->internal_stats.rx_broadcast) * ETHER_CRC_LEN;
+
        /* Get statistics of struct i40e_eth_stats */
        i40e_stat_update_48(hw, I40E_GLPRT_GORCH(hw->port),
                            I40E_GLPRT_GORCL(hw->port),
@@ -2391,6 +2960,32 @@ i40e_read_stats_registers(struct i40e_pf *pf, struct i40e_hw *hw)
        ns->eth.rx_bytes -= (ns->eth.rx_unicast + ns->eth.rx_multicast +
                ns->eth.rx_broadcast) * ETHER_CRC_LEN;
 
+       /* exclude internal rx bytes
+        * Workaround: it is possible I40E_GLV_GORCH[H/L] is updated before
+        * I40E_GLPRT_GORCH[H/L], so there is a small window that cause negative
+        * value.
+        * same to I40E_GLV_UPRC[H/L], I40E_GLV_MPRC[H/L], I40E_GLV_BPRC[H/L].
+        */
+       if (ns->eth.rx_bytes < pf->internal_stats.rx_bytes)
+               ns->eth.rx_bytes = 0;
+       else
+               ns->eth.rx_bytes -= pf->internal_stats.rx_bytes;
+
+       if (ns->eth.rx_unicast < pf->internal_stats.rx_unicast)
+               ns->eth.rx_unicast = 0;
+       else
+               ns->eth.rx_unicast -= pf->internal_stats.rx_unicast;
+
+       if (ns->eth.rx_multicast < pf->internal_stats.rx_multicast)
+               ns->eth.rx_multicast = 0;
+       else
+               ns->eth.rx_multicast -= pf->internal_stats.rx_multicast;
+
+       if (ns->eth.rx_broadcast < pf->internal_stats.rx_broadcast)
+               ns->eth.rx_broadcast = 0;
+       else
+               ns->eth.rx_broadcast -= pf->internal_stats.rx_broadcast;
+
        i40e_stat_update_32(hw, I40E_GLPRT_RDPC(hw->port),
                            pf->offset_loaded, &os->eth.rx_discards,
                            &ns->eth.rx_discards);
@@ -2418,6 +3013,33 @@ i40e_read_stats_registers(struct i40e_pf *pf, struct i40e_hw *hw)
                            &ns->eth.tx_broadcast);
        ns->eth.tx_bytes -= (ns->eth.tx_unicast + ns->eth.tx_multicast +
                ns->eth.tx_broadcast) * ETHER_CRC_LEN;
+
+       /* exclude internal tx bytes
+        * Workaround: it is possible I40E_GLV_GOTCH[H/L] is updated before
+        * I40E_GLPRT_GOTCH[H/L], so there is a small window that cause negative
+        * value.
+        * same to I40E_GLV_UPTC[H/L], I40E_GLV_MPTC[H/L], I40E_GLV_BPTC[H/L].
+        */
+       if (ns->eth.tx_bytes < pf->internal_stats.tx_bytes)
+               ns->eth.tx_bytes = 0;
+       else
+               ns->eth.tx_bytes -= pf->internal_stats.tx_bytes;
+
+       if (ns->eth.tx_unicast < pf->internal_stats.tx_unicast)
+               ns->eth.tx_unicast = 0;
+       else
+               ns->eth.tx_unicast -= pf->internal_stats.tx_unicast;
+
+       if (ns->eth.tx_multicast < pf->internal_stats.tx_multicast)
+               ns->eth.tx_multicast = 0;
+       else
+               ns->eth.tx_multicast -= pf->internal_stats.tx_multicast;
+
+       if (ns->eth.tx_broadcast < pf->internal_stats.tx_broadcast)
+               ns->eth.tx_broadcast = 0;
+       else
+               ns->eth.tx_broadcast -= pf->internal_stats.tx_broadcast;
+
        /* GLPRT_TEPC not supported */
 
        /* additional port specific stats */
@@ -2557,12 +3179,13 @@ i40e_read_stats_registers(struct i40e_pf *pf, struct i40e_hw *hw)
 }
 
 /* Get all statistics of a port */
-static void
+static int
 i40e_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
 {
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct i40e_hw_port_stats *ns = &pf->stats; /* new stats */
+       struct i40e_vsi *vsi;
        unsigned i;
 
        /* call read registers - updates values, now write them to struct */
@@ -2572,10 +3195,10 @@ i40e_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
                        pf->main_vsi->eth_stats.rx_multicast +
                        pf->main_vsi->eth_stats.rx_broadcast -
                        pf->main_vsi->eth_stats.rx_discards;
-       stats->opackets = pf->main_vsi->eth_stats.tx_unicast +
-                       pf->main_vsi->eth_stats.tx_multicast +
-                       pf->main_vsi->eth_stats.tx_broadcast;
-       stats->ibytes   = ns->eth.rx_bytes;
+       stats->opackets = ns->eth.tx_unicast +
+                       ns->eth.tx_multicast +
+                       ns->eth.tx_broadcast;
+       stats->ibytes   = pf->main_vsi->eth_stats.rx_bytes;
        stats->obytes   = ns->eth.tx_bytes;
        stats->oerrors  = ns->eth.tx_errors +
                        pf->main_vsi->eth_stats.tx_errors;
@@ -2587,6 +3210,21 @@ i40e_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
                        ns->rx_length_errors + ns->rx_undersize +
                        ns->rx_oversize + ns->rx_fragments + ns->rx_jabber;
 
+       if (pf->vfs) {
+               for (i = 0; i < pf->vf_num; i++) {
+                       vsi = pf->vfs[i].vsi;
+                       i40e_update_vsi_stats(vsi);
+
+                       stats->ipackets += (vsi->eth_stats.rx_unicast +
+                                       vsi->eth_stats.rx_multicast +
+                                       vsi->eth_stats.rx_broadcast -
+                                       vsi->eth_stats.rx_discards);
+                       stats->ibytes   += vsi->eth_stats.rx_bytes;
+                       stats->oerrors  += vsi->eth_stats.tx_errors;
+                       stats->imissed  += vsi->eth_stats.rx_discards;
+               }
+       }
+
        PMD_DRV_LOG(DEBUG, "***************** PF stats start *******************");
        PMD_DRV_LOG(DEBUG, "rx_bytes:            %"PRIu64"", ns->eth.rx_bytes);
        PMD_DRV_LOG(DEBUG, "rx_unicast:          %"PRIu64"", ns->eth.rx_unicast);
@@ -2656,6 +3294,7 @@ i40e_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
                    ns->checksum_error);
        PMD_DRV_LOG(DEBUG, "fdir_match:               %"PRIu64"", ns->fd_sb_match);
        PMD_DRV_LOG(DEBUG, "***************** PF stats end ********************");
+       return 0;
 }
 
 /* Reset the statistics */
@@ -2696,17 +3335,17 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 
        /* Get stats from i40e_eth_stats struct */
        for (i = 0; i < I40E_NB_ETH_XSTATS; i++) {
-               snprintf(xstats_names[count].name,
-                        sizeof(xstats_names[count].name),
-                        "%s", rte_i40e_stats_strings[i].name);
+               strlcpy(xstats_names[count].name,
+                       rte_i40e_stats_strings[i].name,
+                       sizeof(xstats_names[count].name));
                count++;
        }
 
        /* Get individiual stats from i40e_hw_port struct */
        for (i = 0; i < I40E_NB_HW_PORT_XSTATS; i++) {
-               snprintf(xstats_names[count].name,
-                       sizeof(xstats_names[count].name),
-                        "%s", rte_i40e_hw_port_strings[i].name);
+               strlcpy(xstats_names[count].name,
+                       rte_i40e_hw_port_strings[i].name,
+                       sizeof(xstats_names[count].name));
                count++;
        }
 
@@ -2832,27 +3471,62 @@ i40e_fw_version_get(struct rte_eth_dev *dev, char *fw_version, size_t fw_size)
                return 0;
 }
 
+/*
+ * When using NVM 6.01(for X710 XL710 XXV710)/3.33(for X722) or later,
+ * the Rx data path does not hang if the FW LLDP is stopped.
+ * return true if lldp need to stop
+ * return false if we cannot disable the LLDP to avoid Rx data path blocking.
+ */
+static bool
+i40e_need_stop_lldp(struct rte_eth_dev *dev)
+{
+       double nvm_ver;
+       char ver_str[64] = {0};
+       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       i40e_fw_version_get(dev, ver_str, 64);
+       nvm_ver = atof(ver_str);
+       if ((hw->mac.type == I40E_MAC_X722 ||
+            hw->mac.type == I40E_MAC_X722_VF) &&
+            ((uint32_t)(nvm_ver * 1000) >= (uint32_t)(3.33 * 1000)))
+               return true;
+       else if ((uint32_t)(nvm_ver * 1000) >= (uint32_t)(6.01 * 1000))
+               return true;
+
+       return false;
+}
+
 static void
 i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        struct i40e_vsi *vsi = pf->main_vsi;
-       struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
 
-       dev_info->pci_dev = pci_dev;
        dev_info->max_rx_queues = vsi->nb_qps;
        dev_info->max_tx_queues = vsi->nb_qps;
        dev_info->min_rx_bufsize = I40E_BUF_SIZE_MIN;
        dev_info->max_rx_pktlen = I40E_FRAME_SIZE_MAX;
        dev_info->max_mac_addrs = vsi->max_macaddrs;
        dev_info->max_vfs = pci_dev->max_vfs;
+       dev_info->max_mtu = dev_info->max_rx_pktlen - I40E_ETH_OVERHEAD;
+       dev_info->min_mtu = ETHER_MIN_MTU;
+       dev_info->rx_queue_offload_capa = 0;
        dev_info->rx_offload_capa =
                DEV_RX_OFFLOAD_VLAN_STRIP |
                DEV_RX_OFFLOAD_QINQ_STRIP |
                DEV_RX_OFFLOAD_IPV4_CKSUM |
                DEV_RX_OFFLOAD_UDP_CKSUM |
-               DEV_RX_OFFLOAD_TCP_CKSUM;
+               DEV_RX_OFFLOAD_TCP_CKSUM |
+               DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM |
+               DEV_RX_OFFLOAD_KEEP_CRC |
+               DEV_RX_OFFLOAD_SCATTER |
+               DEV_RX_OFFLOAD_VLAN_EXTEND |
+               DEV_RX_OFFLOAD_VLAN_FILTER |
+               DEV_RX_OFFLOAD_JUMBO_FRAME;
+
+       dev_info->tx_queue_offload_capa = DEV_TX_OFFLOAD_MBUF_FAST_FREE;
        dev_info->tx_offload_capa =
                DEV_TX_OFFLOAD_VLAN_INSERT |
                DEV_TX_OFFLOAD_QINQ_INSERT |
@@ -2865,11 +3539,17 @@ i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
                DEV_TX_OFFLOAD_GRE_TNL_TSO |
                DEV_TX_OFFLOAD_IPIP_TNL_TSO |
-               DEV_TX_OFFLOAD_GENEVE_TNL_TSO;
+               DEV_TX_OFFLOAD_GENEVE_TNL_TSO |
+               DEV_TX_OFFLOAD_MULTI_SEGS |
+               dev_info->tx_queue_offload_capa;
+       dev_info->dev_capa =
+               RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP |
+               RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP;
+
        dev_info->hash_key_size = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
                                                sizeof(uint32_t);
        dev_info->reta_size = pf->hash_lut_size;
-       dev_info->flow_type_rss_offloads = I40E_RSS_OFFLOAD_ALL;
+       dev_info->flow_type_rss_offloads = pf->adapter->flow_types_mask;
 
        dev_info->default_rxconf = (struct rte_eth_rxconf) {
                .rx_thresh = {
@@ -2879,6 +3559,7 @@ i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                },
                .rx_free_thresh = I40E_DEFAULT_RX_FREE_THRESH,
                .rx_drop_en = 0,
+               .offloads = 0,
        };
 
        dev_info->default_txconf = (struct rte_eth_txconf) {
@@ -2889,8 +3570,7 @@ i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                },
                .tx_free_thresh = I40E_DEFAULT_TX_FREE_THRESH,
                .tx_rs_thresh = I40E_DEFAULT_TX_RSBIT_THRESH,
-               .txq_flags = ETH_TXQ_FLAGS_NOMULTSEGS |
-                               ETH_TXQ_FLAGS_NOOFFLOADS,
+               .offloads = 0,
        };
 
        dev_info->rx_desc_lim = (struct rte_eth_desc_lim) {
@@ -2917,15 +3597,42 @@ i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                dev_info->max_tx_queues += dev_info->vmdq_queue_num;
        }
 
-       if (I40E_PHY_TYPE_SUPPORT_40G(hw->phy.phy_types))
+       if (I40E_PHY_TYPE_SUPPORT_40G(hw->phy.phy_types)) {
                /* For XL710 */
                dev_info->speed_capa = ETH_LINK_SPEED_40G;
-       else if (I40E_PHY_TYPE_SUPPORT_25G(hw->phy.phy_types))
+               dev_info->default_rxportconf.nb_queues = 2;
+               dev_info->default_txportconf.nb_queues = 2;
+               if (dev->data->nb_rx_queues == 1)
+                       dev_info->default_rxportconf.ring_size = 2048;
+               else
+                       dev_info->default_rxportconf.ring_size = 1024;
+               if (dev->data->nb_tx_queues == 1)
+                       dev_info->default_txportconf.ring_size = 1024;
+               else
+                       dev_info->default_txportconf.ring_size = 512;
+
+       } else if (I40E_PHY_TYPE_SUPPORT_25G(hw->phy.phy_types)) {
                /* For XXV710 */
                dev_info->speed_capa = ETH_LINK_SPEED_25G;
-       else
+               dev_info->default_rxportconf.nb_queues = 1;
+               dev_info->default_txportconf.nb_queues = 1;
+               dev_info->default_rxportconf.ring_size = 256;
+               dev_info->default_txportconf.ring_size = 256;
+       } else {
                /* For X710 */
                dev_info->speed_capa = ETH_LINK_SPEED_1G | ETH_LINK_SPEED_10G;
+               dev_info->default_rxportconf.nb_queues = 1;
+               dev_info->default_txportconf.nb_queues = 1;
+               if (dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_10G) {
+                       dev_info->default_rxportconf.ring_size = 512;
+                       dev_info->default_txportconf.ring_size = 256;
+               } else {
+                       dev_info->default_rxportconf.ring_size = 256;
+                       dev_info->default_txportconf.ring_size = 256;
+               }
+       }
+       dev_info->default_rxportconf.burst_size = 32;
+       dev_info->default_txportconf.burst_size = 32;
 }
 
 static int
@@ -2942,83 +3649,116 @@ i40e_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 }
 
 static int
-i40e_vlan_tpid_set(struct rte_eth_dev *dev,
-                  enum rte_vlan_type vlan_type,
-                  uint16_t tpid)
+i40e_vlan_tpid_set_by_registers(struct rte_eth_dev *dev,
+                               enum rte_vlan_type vlan_type,
+                               uint16_t tpid, int qinq)
 {
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       uint64_t reg_r = 0, reg_w = 0;
-       uint16_t reg_id = 0;
-       int ret = 0;
-       int qinq = dev->data->dev_conf.rxmode.hw_vlan_extend;
+       uint64_t reg_r = 0;
+       uint64_t reg_w = 0;
+       uint16_t reg_id = 3;
+       int ret;
 
-       switch (vlan_type) {
-       case ETH_VLAN_TYPE_OUTER:
-               if (qinq)
+       if (qinq) {
+               if (vlan_type == ETH_VLAN_TYPE_OUTER)
                        reg_id = 2;
-               else
-                       reg_id = 3;
-               break;
-       case ETH_VLAN_TYPE_INNER:
-               if (qinq)
-                       reg_id = 3;
-               else {
-                       ret = -EINVAL;
-                       PMD_DRV_LOG(ERR,
-                               "Unsupported vlan type in single vlan.");
-                       return ret;
-               }
-               break;
-       default:
-               ret = -EINVAL;
-               PMD_DRV_LOG(ERR, "Unsupported vlan type %d", vlan_type);
-               return ret;
        }
+
        ret = i40e_aq_debug_read_register(hw, I40E_GL_SWT_L2TAGCTRL(reg_id),
                                          &reg_r, NULL);
        if (ret != I40E_SUCCESS) {
                PMD_DRV_LOG(ERR,
                           "Fail to debug read from I40E_GL_SWT_L2TAGCTRL[%d]",
                           reg_id);
-               ret = -EIO;
-               return ret;
+               return -EIO;
        }
        PMD_DRV_LOG(DEBUG,
-               "Debug read from I40E_GL_SWT_L2TAGCTRL[%d]: 0x%08"PRIx64,
-               reg_id, reg_r);
+                   "Debug read from I40E_GL_SWT_L2TAGCTRL[%d]: 0x%08"PRIx64,
+                   reg_id, reg_r);
 
        reg_w = reg_r & (~(I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_MASK));
        reg_w |= ((uint64_t)tpid << I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_SHIFT);
        if (reg_r == reg_w) {
-               ret = 0;
                PMD_DRV_LOG(DEBUG, "No need to write");
-               return ret;
+               return 0;
        }
 
-       ret = i40e_aq_debug_write_register(hw, I40E_GL_SWT_L2TAGCTRL(reg_id),
+       ret = i40e_aq_debug_write_global_register(hw,
+                                          I40E_GL_SWT_L2TAGCTRL(reg_id),
                                           reg_w, NULL);
        if (ret != I40E_SUCCESS) {
-               ret = -EIO;
                PMD_DRV_LOG(ERR,
-                       "Fail to debug write to I40E_GL_SWT_L2TAGCTRL[%d]",
-                       reg_id);
-               return ret;
+                           "Fail to debug write to I40E_GL_SWT_L2TAGCTRL[%d]",
+                           reg_id);
+               return -EIO;
        }
        PMD_DRV_LOG(DEBUG,
-               "Debug write 0x%08"PRIx64" to I40E_GL_SWT_L2TAGCTRL[%d]",
-               reg_w, reg_id);
+                   "Global register 0x%08x is changed with value 0x%08x",
+                   I40E_GL_SWT_L2TAGCTRL(reg_id), (uint32_t)reg_w);
+
+       return 0;
+}
+
+static int
+i40e_vlan_tpid_set(struct rte_eth_dev *dev,
+                  enum rte_vlan_type vlan_type,
+                  uint16_t tpid)
+{
+       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       int qinq = dev->data->dev_conf.rxmode.offloads &
+                  DEV_RX_OFFLOAD_VLAN_EXTEND;
+       int ret = 0;
+
+       if ((vlan_type != ETH_VLAN_TYPE_INNER &&
+            vlan_type != ETH_VLAN_TYPE_OUTER) ||
+           (!qinq && vlan_type == ETH_VLAN_TYPE_INNER)) {
+               PMD_DRV_LOG(ERR,
+                           "Unsupported vlan type.");
+               return -EINVAL;
+       }
+
+       if (pf->support_multi_driver) {
+               PMD_DRV_LOG(ERR, "Setting TPID is not supported.");
+               return -ENOTSUP;
+       }
+
+       /* 802.1ad frames ability is added in NVM API 1.7*/
+       if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
+               if (qinq) {
+                       if (vlan_type == ETH_VLAN_TYPE_OUTER)
+                               hw->first_tag = rte_cpu_to_le_16(tpid);
+                       else if (vlan_type == ETH_VLAN_TYPE_INNER)
+                               hw->second_tag = rte_cpu_to_le_16(tpid);
+               } else {
+                       if (vlan_type == ETH_VLAN_TYPE_OUTER)
+                               hw->second_tag = rte_cpu_to_le_16(tpid);
+               }
+               ret = i40e_aq_set_switch_config(hw, 0, 0, 0, NULL);
+               if (ret != I40E_SUCCESS) {
+                       PMD_DRV_LOG(ERR,
+                                   "Set switch config failed aq_err: %d",
+                                   hw->aq.asq_last_status);
+                       ret = -EIO;
+               }
+       } else
+               /* If NVM API < 1.7, keep the register setting */
+               ret = i40e_vlan_tpid_set_by_registers(dev, vlan_type,
+                                                     tpid, qinq);
 
        return ret;
 }
 
-static void
+static int
 i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct i40e_vsi *vsi = pf->main_vsi;
+       struct rte_eth_rxmode *rxmode;
 
+       rxmode = &dev->data->dev_conf.rxmode;
        if (mask & ETH_VLAN_FILTER_MASK) {
-               if (dev->data->dev_conf.rxmode.hw_vlan_filter)
+               if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_FILTER)
                        i40e_vsi_config_vlan_filter(vsi, TRUE);
                else
                        i40e_vsi_config_vlan_filter(vsi, FALSE);
@@ -3026,16 +3766,16 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 
        if (mask & ETH_VLAN_STRIP_MASK) {
                /* Enable or disable VLAN stripping */
-               if (dev->data->dev_conf.rxmode.hw_vlan_strip)
+               if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_STRIP)
                        i40e_vsi_config_vlan_stripping(vsi, TRUE);
                else
                        i40e_vsi_config_vlan_stripping(vsi, FALSE);
        }
 
        if (mask & ETH_VLAN_EXTEND_MASK) {
-               if (dev->data->dev_conf.rxmode.hw_vlan_extend) {
+               if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_EXTEND) {
                        i40e_vsi_config_double_vlan(vsi, TRUE);
-                       /* Set global registers with default ether type value */
+                       /* Set global registers with default ethertype. */
                        i40e_vlan_tpid_set(dev, ETH_VLAN_TYPE_OUTER,
                                           ETHER_TYPE_VLAN);
                        i40e_vlan_tpid_set(dev, ETH_VLAN_TYPE_INNER,
@@ -3044,7 +3784,9 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
                else
                        i40e_vsi_config_double_vlan(vsi, FALSE);
        }
-}
+
+       return 0;
+}
 
 static void
 i40e_vlan_strip_queue_set(__rte_unused struct rte_eth_dev *dev,
@@ -3107,6 +3849,13 @@ i40e_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
 
        fc_conf->pause_time = pf->fc_conf.pause_time;
+
+       /* read out from register, in case they are modified by other port */
+       pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS] =
+               I40E_READ_REG(hw, I40E_GLRPB_GHW) >> I40E_KILOSHIFT;
+       pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS] =
+               I40E_READ_REG(hw, I40E_GLRPB_GLW) >> I40E_KILOSHIFT;
+
        fc_conf->high_water =  pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS];
        fc_conf->low_water = pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS];
 
@@ -3227,19 +3976,24 @@ i40e_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
                I40E_WRITE_REG(hw, I40E_PRTDCB_MFLCN, mflcn_reg);
        }
 
-       /* config the water marker both based on the packets and bytes */
-       I40E_WRITE_REG(hw, I40E_GLRPB_PHW,
-                      (pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS]
-                      << I40E_KILOSHIFT) / I40E_PACKET_AVERAGE_SIZE);
-       I40E_WRITE_REG(hw, I40E_GLRPB_PLW,
-                      (pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS]
-                      << I40E_KILOSHIFT) / I40E_PACKET_AVERAGE_SIZE);
-       I40E_WRITE_REG(hw, I40E_GLRPB_GHW,
-                      pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS]
-                      << I40E_KILOSHIFT);
-       I40E_WRITE_REG(hw, I40E_GLRPB_GLW,
-                      pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS]
-                      << I40E_KILOSHIFT);
+       if (!pf->support_multi_driver) {
+               /* config water marker both based on the packets and bytes */
+               I40E_WRITE_GLB_REG(hw, I40E_GLRPB_PHW,
+                                (pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS]
+                                << I40E_KILOSHIFT) / I40E_PACKET_AVERAGE_SIZE);
+               I40E_WRITE_GLB_REG(hw, I40E_GLRPB_PLW,
+                                 (pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS]
+                                << I40E_KILOSHIFT) / I40E_PACKET_AVERAGE_SIZE);
+               I40E_WRITE_GLB_REG(hw, I40E_GLRPB_GHW,
+                                 pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS]
+                                 << I40E_KILOSHIFT);
+               I40E_WRITE_GLB_REG(hw, I40E_GLRPB_GLW,
+                                  pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS]
+                                  << I40E_KILOSHIFT);
+       } else {
+               PMD_DRV_LOG(ERR,
+                           "Water marker configuration is not supported.");
+       }
 
        I40E_WRITE_FLUSH(hw);
 
@@ -3256,15 +4010,16 @@ i40e_priority_flow_ctrl_set(__rte_unused struct rte_eth_dev *dev,
 }
 
 /* Add a MAC address, and update filters */
-static void
+static int
 i40e_macaddr_add(struct rte_eth_dev *dev,
-                struct ether_addr *mac_addr,
+                struct rte_ether_addr *mac_addr,
                 __rte_unused uint32_t index,
                 uint32_t pool)
 {
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct i40e_mac_filter_info mac_filter;
        struct i40e_vsi *vsi;
+       struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;
        int ret;
 
        /* If VMDQ not enabled or configured, return */
@@ -3273,17 +4028,17 @@ i40e_macaddr_add(struct rte_eth_dev *dev,
                PMD_DRV_LOG(ERR, "VMDQ not %s, can't set mac to pool %u",
                        pf->flags & I40E_FLAG_VMDQ ? "configured" : "enabled",
                        pool);
-               return;
+               return -ENOTSUP;
        }
 
        if (pool > pf->nb_cfg_vmdq_vsi) {
                PMD_DRV_LOG(ERR, "Pool number %u invalid. Max pool is %u",
                                pool, pf->nb_cfg_vmdq_vsi);
-               return;
+               return -EINVAL;
        }
 
-       (void)rte_memcpy(&mac_filter.mac_addr, mac_addr, ETHER_ADDR_LEN);
-       if (dev->data->dev_conf.rxmode.hw_vlan_filter)
+       rte_memcpy(&mac_filter.mac_addr, mac_addr, ETHER_ADDR_LEN);
+       if (rxmode->offloads & DEV_RX_OFFLOAD_VLAN_FILTER)
                mac_filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
        else
                mac_filter.filter_type = RTE_MAC_PERFECT_MATCH;
@@ -3296,8 +4051,9 @@ i40e_macaddr_add(struct rte_eth_dev *dev,
        ret = i40e_vsi_add_mac(vsi, &mac_filter);
        if (ret != I40E_SUCCESS) {
                PMD_DRV_LOG(ERR, "Failed to add MACVLAN filter");
-               return;
+               return -ENODEV;
        }
+       return 0;
 }
 
 /* Remove a MAC address, and update filters */
@@ -3307,7 +4063,7 @@ i40e_macaddr_remove(struct rte_eth_dev *dev, uint32_t index)
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct i40e_vsi *vsi;
        struct rte_eth_dev_data *data = dev->data;
-       struct ether_addr *macaddr;
+       struct rte_ether_addr *macaddr;
        int ret;
        uint32_t i;
        uint64_t pool_sel;
@@ -3348,8 +4104,8 @@ i40e_vf_mac_filter_set(struct i40e_pf *pf,
 {
        struct i40e_hw *hw;
        struct i40e_mac_filter_info mac_filter;
-       struct ether_addr old_mac;
-       struct ether_addr *new_mac;
+       struct rte_ether_addr old_mac;
+       struct rte_ether_addr *new_mac;
        struct i40e_pf_vf *vf = NULL;
        uint16_t vf_id;
        int ret;
@@ -3386,10 +4142,10 @@ i40e_vf_mac_filter_set(struct i40e_pf *pf,
        }
 
        if (add) {
-               (void)rte_memcpy(&old_mac, hw->mac.addr, ETHER_ADDR_LEN);
-               (void)rte_memcpy(hw->mac.addr, new_mac->addr_bytes,
+               rte_memcpy(&old_mac, hw->mac.addr, ETHER_ADDR_LEN);
+               rte_memcpy(hw->mac.addr, new_mac->addr_bytes,
                                ETHER_ADDR_LEN);
-               (void)rte_memcpy(&mac_filter.mac_addr, &filter->mac_addr,
+               rte_memcpy(&mac_filter.mac_addr, &filter->mac_addr,
                                 ETHER_ADDR_LEN);
 
                mac_filter.filter_type = filter->filter_type;
@@ -3400,7 +4156,7 @@ i40e_vf_mac_filter_set(struct i40e_pf *pf,
                }
                ether_addr_copy(new_mac, &pf->dev_addr);
        } else {
-               (void)rte_memcpy(hw->mac.addr, hw->mac.perm_addr,
+               rte_memcpy(hw->mac.addr, hw->mac.perm_addr,
                                ETHER_ADDR_LEN);
                ret = i40e_vsi_delete_mac(vf->vsi, &filter->mac_addr);
                if (ret != I40E_SUCCESS) {
@@ -3410,7 +4166,7 @@ i40e_vf_mac_filter_set(struct i40e_pf *pf,
 
                /* Clear device address as it has been removed */
                if (is_same_ether_addr(&(pf->dev_addr), new_mac))
-                       memset(&pf->dev_addr, 0, sizeof(struct ether_addr));
+                       memset(&pf->dev_addr, 0, sizeof(struct rte_ether_addr));
        }
 
        return 0;
@@ -3458,13 +4214,15 @@ i40e_get_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size)
 {
        struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
        struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+       uint32_t reg;
        int ret;
 
        if (!lut)
                return -EINVAL;
 
        if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) {
-               ret = i40e_aq_get_rss_lut(hw, vsi->vsi_id, TRUE,
+               ret = i40e_aq_get_rss_lut(hw, vsi->vsi_id,
+                                         vsi->type != I40E_VSI_SRIOV,
                                          lut, lut_size);
                if (ret) {
                        PMD_DRV_LOG(ERR, "Failed to get RSS lookup table");
@@ -3474,14 +4232,22 @@ i40e_get_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size)
                uint32_t *lut_dw = (uint32_t *)lut;
                uint16_t i, lut_size_dw = lut_size / 4;
 
-               for (i = 0; i < lut_size_dw; i++)
-                       lut_dw[i] = I40E_READ_REG(hw, I40E_PFQF_HLUT(i));
+               if (vsi->type == I40E_VSI_SRIOV) {
+                       for (i = 0; i <= lut_size_dw; i++) {
+                               reg = I40E_VFQF_HLUT1(i, vsi->user_param);
+                               lut_dw[i] = i40e_read_rx_ctl(hw, reg);
+                       }
+               } else {
+                       for (i = 0; i < lut_size_dw; i++)
+                               lut_dw[i] = I40E_READ_REG(hw,
+                                                         I40E_PFQF_HLUT(i));
+               }
        }
 
        return 0;
 }
 
-static int
+int
 i40e_set_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size)
 {
        struct i40e_pf *pf;
@@ -3495,7 +4261,8 @@ i40e_set_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size)
        hw = I40E_VSI_TO_HW(vsi);
 
        if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) {
-               ret = i40e_aq_set_rss_lut(hw, vsi->vsi_id, TRUE,
+               ret = i40e_aq_set_rss_lut(hw, vsi->vsi_id,
+                                         vsi->type != I40E_VSI_SRIOV,
                                          lut, lut_size);
                if (ret) {
                        PMD_DRV_LOG(ERR, "Failed to set RSS lookup table");
@@ -3505,8 +4272,17 @@ i40e_set_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size)
                uint32_t *lut_dw = (uint32_t *)lut;
                uint16_t i, lut_size_dw = lut_size / 4;
 
-               for (i = 0; i < lut_size_dw; i++)
-                       I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i), lut_dw[i]);
+               if (vsi->type == I40E_VSI_SRIOV) {
+                       for (i = 0; i < lut_size_dw; i++)
+                               I40E_WRITE_REG(
+                                       hw,
+                                       I40E_VFQF_HLUT1(i, vsi->user_param),
+                                       lut_dw[i]);
+               } else {
+                       for (i = 0; i < lut_size_dw; i++)
+                               I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i),
+                                              lut_dw[i]);
+               }
                I40E_WRITE_FLUSH(hw);
        }
 
@@ -3548,6 +4324,8 @@ i40e_dev_rss_reta_update(struct rte_eth_dev *dev,
        }
        ret = i40e_set_rss_lut(pf->main_vsi, lut, reta_size);
 
+       pf->adapter->rss_reta_updated = 1;
+
 out:
        rte_free(lut);
 
@@ -3615,14 +4393,14 @@ i40e_allocate_dma_mem_d(__attribute__((unused)) struct i40e_hw *hw,
                return I40E_ERR_PARAM;
 
        snprintf(z_name, sizeof(z_name), "i40e_dma_%"PRIu64, rte_rand());
-       mz = rte_memzone_reserve_bounded(z_name, size, SOCKET_ID_ANY, 0,
-                                        alignment, RTE_PGSIZE_2M);
+       mz = rte_memzone_reserve_bounded(z_name, size, SOCKET_ID_ANY,
+                       RTE_MEMZONE_IOVA_CONTIG, alignment, RTE_PGSIZE_2M);
        if (!mz)
                return I40E_ERR_NO_MEMORY;
 
        mem->size = size;
        mem->va = mz->addr;
-       mem->pa = rte_mem_phy2mch(mz->memseg_id, mz->phys_addr);
+       mem->pa = mz->iova;
        mem->zone = (const void *)mz;
        PMD_DRV_LOG(DEBUG,
                "memzone %s allocated with physical address: %"PRIu64,
@@ -3751,18 +4529,88 @@ i40e_get_cap(struct i40e_hw *hw)
        return ret;
 }
 
+#define RTE_LIBRTE_I40E_QUEUE_NUM_PER_VF       4
+
+static int i40e_pf_parse_vf_queue_number_handler(const char *key,
+               const char *value,
+               void *opaque)
+{
+       struct i40e_pf *pf;
+       unsigned long num;
+       char *end;
+
+       pf = (struct i40e_pf *)opaque;
+       RTE_SET_USED(key);
+
+       errno = 0;
+       num = strtoul(value, &end, 0);
+       if (errno != 0 || end == value || *end != 0) {
+               PMD_DRV_LOG(WARNING, "Wrong VF queue number = %s, Now it is "
+                           "kept the value = %hu", value, pf->vf_nb_qp_max);
+               return -(EINVAL);
+       }
+
+       if (num <= I40E_MAX_QP_NUM_PER_VF && rte_is_power_of_2(num))
+               pf->vf_nb_qp_max = (uint16_t)num;
+       else
+               /* here return 0 to make next valid same argument work */
+               PMD_DRV_LOG(WARNING, "Wrong VF queue number = %lu, it must be "
+                           "power of 2 and equal or less than 16 !, Now it is "
+                           "kept the value = %hu", num, pf->vf_nb_qp_max);
+
+       return 0;
+}
+
+static int i40e_pf_config_vf_rxq_number(struct rte_eth_dev *dev)
+{
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct rte_kvargs *kvlist;
+       int kvargs_count;
+
+       /* set default queue number per VF as 4 */
+       pf->vf_nb_qp_max = RTE_LIBRTE_I40E_QUEUE_NUM_PER_VF;
+
+       if (dev->device->devargs == NULL)
+               return 0;
+
+       kvlist = rte_kvargs_parse(dev->device->devargs->args, valid_keys);
+       if (kvlist == NULL)
+               return -(EINVAL);
+
+       kvargs_count = rte_kvargs_count(kvlist, ETH_I40E_QUEUE_NUM_PER_VF_ARG);
+       if (!kvargs_count) {
+               rte_kvargs_free(kvlist);
+               return 0;
+       }
+
+       if (kvargs_count > 1)
+               PMD_DRV_LOG(WARNING, "More than one argument \"%s\" and only "
+                           "the first invalid or last valid one is used !",
+                           ETH_I40E_QUEUE_NUM_PER_VF_ARG);
+
+       rte_kvargs_process(kvlist, ETH_I40E_QUEUE_NUM_PER_VF_ARG,
+                          i40e_pf_parse_vf_queue_number_handler, pf);
+
+       rte_kvargs_free(kvlist);
+
+       return 0;
+}
+
 static int
 i40e_pf_parameter_init(struct rte_eth_dev *dev)
 {
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct i40e_hw *hw = I40E_PF_TO_HW(pf);
-       struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        uint16_t qp_count = 0, vsi_count = 0;
 
        if (pci_dev->max_vfs && !hw->func_caps.sr_iov_1_1) {
                PMD_INIT_LOG(ERR, "HW configuration doesn't support SRIOV");
                return -EINVAL;
        }
+
+       i40e_pf_config_vf_rxq_number(dev);
+
        /* Add the parameter init for LFC */
        pf->fc_conf.pause_time = I40E_DEFAULT_PAUSE_TIME;
        pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS] = I40E_DEFAULT_HIGH_WATER;
@@ -3772,7 +4620,6 @@ i40e_pf_parameter_init(struct rte_eth_dev *dev)
        pf->max_num_vsi = hw->func_caps.num_vsis;
        pf->lan_nb_qp_max = RTE_LIBRTE_I40E_QUEUE_NUM_PER_PF;
        pf->vmdq_nb_qp_max = RTE_LIBRTE_I40E_QUEUE_NUM_PER_VM;
-       pf->vf_nb_qp_max = RTE_LIBRTE_I40E_QUEUE_NUM_PER_VF;
 
        /* FDir queue/VSI allocation */
        pf->fdir_qp_offset = 0;
@@ -3802,7 +4649,7 @@ i40e_pf_parameter_init(struct rte_eth_dev *dev)
        pf->vf_qp_offset = pf->lan_qp_offset + pf->lan_nb_qps;
        if (hw->func_caps.sr_iov_1_1 && pci_dev->max_vfs) {
                pf->flags |= I40E_FLAG_SRIOV;
-               pf->vf_nb_qps = RTE_LIBRTE_I40E_QUEUE_NUM_PER_VF;
+               pf->vf_nb_qps = pf->vf_nb_qp_max;
                pf->vf_num = pci_dev->max_vfs;
                PMD_DRV_LOG(DEBUG,
                        "%u VF VSIs, %u queues per VF VSI, in total %u queues",
@@ -4192,7 +5039,7 @@ i40e_vsi_vlan_pvid_set(struct i40e_vsi *vsi,
        vsi->info.valid_sections =
                rte_cpu_to_le_16(I40E_AQ_VSI_PROP_VLAN_VALID);
        memset(&ctxt, 0, sizeof(ctxt));
-       (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
+       rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
        ctxt.seid = vsi->seid;
 
        hw = I40E_VSI_TO_HW(vsi);
@@ -4231,7 +5078,7 @@ i40e_vsi_update_tc_bandwidth(struct i40e_vsi *vsi, uint8_t enabled_tcmap)
                return ret;
        }
 
-       (void)rte_memcpy(vsi->info.qs_handle, tc_bw_data.qs_handles,
+       rte_memcpy(vsi->info.qs_handle, tc_bw_data.qs_handles,
                                        sizeof(vsi->info.qs_handle));
        return I40E_SUCCESS;
 }
@@ -4252,6 +5099,8 @@ i40e_vsi_config_tc_queue_mapping(struct i40e_vsi *vsi,
        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
                if (enabled_tcmap & (1 << i))
                        total_tc++;
+       if (total_tc == 0)
+               total_tc = 1;
        vsi->enabled_tc = enabled_tcmap;
 
        /* Number of queues per enabled TC */
@@ -4486,7 +5335,7 @@ i40e_update_default_filter_setting(struct i40e_vsi *vsi)
        if (vsi->type != I40E_VSI_MAIN)
                return I40E_ERR_CONFIG;
        memset(&def_filter, 0, sizeof(def_filter));
-       (void)rte_memcpy(def_filter.mac_addr, hw->mac.perm_addr,
+       rte_memcpy(def_filter.mac_addr, hw->mac.perm_addr,
                                        ETH_ADDR_LEN);
        def_filter.vlan_tag = 0;
        def_filter.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH |
@@ -4494,10 +5343,10 @@ i40e_update_default_filter_setting(struct i40e_vsi *vsi)
        ret = i40e_aq_remove_macvlan(hw, vsi->seid, &def_filter, 1, NULL);
        if (ret != I40E_SUCCESS) {
                struct i40e_mac_filter *f;
-               struct ether_addr *mac;
+               struct rte_ether_addr *mac;
 
-               PMD_DRV_LOG(WARNING,
-                       "Cannot remove the default macvlan filter");
+               PMD_DRV_LOG(DEBUG,
+                           "Cannot remove the default macvlan filter");
                /* It needs to add the permanent mac into mac list */
                f = rte_zmalloc("macv_filter", sizeof(*f), 0);
                if (f == NULL) {
@@ -4505,7 +5354,7 @@ i40e_update_default_filter_setting(struct i40e_vsi *vsi)
                        return I40E_ERR_NO_MEMORY;
                }
                mac = &f->mac_info.mac_addr;
-               (void)rte_memcpy(&mac->addr_bytes, hw->mac.perm_addr,
+               rte_memcpy(&mac->addr_bytes, hw->mac.perm_addr,
                                ETH_ADDR_LEN);
                f->mac_info.filter_type = RTE_MACVLAN_PERFECT_MATCH;
                TAILQ_INSERT_TAIL(&vsi->mac_list, f, next);
@@ -4513,8 +5362,8 @@ i40e_update_default_filter_setting(struct i40e_vsi *vsi)
 
                return ret;
        }
-       (void)rte_memcpy(&filter.mac_addr,
-               (struct ether_addr *)(hw->mac.perm_addr), ETH_ADDR_LEN);
+       rte_memcpy(&filter.mac_addr,
+               (struct rte_ether_addr *)(hw->mac.perm_addr), ETH_ADDR_LEN);
        filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
        return i40e_vsi_add_mac(vsi, &filter);
 }
@@ -4594,7 +5443,7 @@ i40e_enable_pf_lb(struct i40e_pf *pf)
        int ret;
 
        /* Use the FW API if FW >= v5.0 */
-       if (hw->aq.fw_maj_ver < 5) {
+       if (hw->aq.fw_maj_ver < 5 && hw->mac.type != I40E_MAC_X722) {
                PMD_INIT_LOG(ERR, "FW < v5.0, cannot enable loopback");
                return;
        }
@@ -4632,7 +5481,7 @@ i40e_vsi_setup(struct i40e_pf *pf,
        struct i40e_mac_filter_info filter;
        int ret;
        struct i40e_vsi_context ctxt;
-       struct ether_addr broadcast =
+       struct rte_ether_addr broadcast =
                {.addr_bytes = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}};
 
        if (type != I40E_VSI_MAIN && type != I40E_VSI_SRIOV &&
@@ -4728,16 +5577,28 @@ i40e_vsi_setup(struct i40e_pf *pf,
 
        /* VF has MSIX interrupt in VF range, don't allocate here */
        if (type == I40E_VSI_MAIN) {
-               ret = i40e_res_pool_alloc(&pf->msix_pool,
-                                         RTE_MIN(vsi->nb_qps,
-                                                 RTE_MAX_RXTX_INTR_VEC_ID));
-               if (ret < 0) {
-                       PMD_DRV_LOG(ERR, "VSI MAIN %d get heap failed %d",
-                                   vsi->seid, ret);
-                       goto fail_queue_alloc;
+               if (pf->support_multi_driver) {
+                       /* If support multi-driver, need to use INT0 instead of
+                        * allocating from msix pool. The Msix pool is init from
+                        * INT1, so it's OK just set msix_intr to 0 and nb_msix
+                        * to 1 without calling i40e_res_pool_alloc.
+                        */
+                       vsi->msix_intr = 0;
+                       vsi->nb_msix = 1;
+               } else {
+                       ret = i40e_res_pool_alloc(&pf->msix_pool,
+                                                 RTE_MIN(vsi->nb_qps,
+                                                    RTE_MAX_RXTX_INTR_VEC_ID));
+                       if (ret < 0) {
+                               PMD_DRV_LOG(ERR,
+                                           "VSI MAIN %d get heap failed %d",
+                                           vsi->seid, ret);
+                               goto fail_queue_alloc;
+                       }
+                       vsi->msix_intr = ret;
+                       vsi->nb_msix = RTE_MIN(vsi->nb_qps,
+                                              RTE_MAX_RXTX_INTR_VEC_ID);
                }
-               vsi->msix_intr = ret;
-               vsi->nb_msix = RTE_MIN(vsi->nb_qps, RTE_MAX_RXTX_INTR_VEC_ID);
        } else if (type != I40E_VSI_SRIOV) {
                ret = i40e_res_pool_alloc(&pf->msix_pool, 1);
                if (ret < 0) {
@@ -4774,7 +5635,7 @@ i40e_vsi_setup(struct i40e_pf *pf,
                        PMD_DRV_LOG(ERR, "Failed to get VSI params");
                        goto fail_msix_alloc;
                }
-               (void)rte_memcpy(&vsi->info, &ctxt.info,
+               rte_memcpy(&vsi->info, &ctxt.info,
                        sizeof(struct i40e_aqc_vsi_properties_data));
                vsi->vsi_id = ctxt.vsi_number;
                vsi->info.valid_sections = 0;
@@ -4792,7 +5653,7 @@ i40e_vsi_setup(struct i40e_pf *pf,
                        rte_cpu_to_le_16(I40E_AQ_VSI_PROP_VLAN_VALID);
                vsi->info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
                                        I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
-               (void)rte_memcpy(&ctxt.info, &vsi->info,
+               rte_memcpy(&ctxt.info, &vsi->info,
                        sizeof(struct i40e_aqc_vsi_properties_data));
                ret = i40e_vsi_config_tc_queue_mapping(vsi, &ctxt.info,
                                                I40E_DEFAULT_TCMAP);
@@ -4813,15 +5674,15 @@ i40e_vsi_setup(struct i40e_pf *pf,
                        goto fail_msix_alloc;
                }
 
-               (void)rte_memcpy(&vsi->info.tc_mapping, &ctxt.info.tc_mapping,
+               rte_memcpy(&vsi->info.tc_mapping, &ctxt.info.tc_mapping,
                                                sizeof(vsi->info.tc_mapping));
-               (void)rte_memcpy(&vsi->info.queue_mapping,
+               rte_memcpy(&vsi->info.queue_mapping,
                                &ctxt.info.queue_mapping,
                        sizeof(vsi->info.queue_mapping));
                vsi->info.mapping_flags = ctxt.info.mapping_flags;
                vsi->info.valid_sections = 0;
 
-               (void)rte_memcpy(pf->dev_addr.addr_bytes, hw->mac.perm_addr,
+               rte_memcpy(pf->dev_addr.addr_bytes, hw->mac.perm_addr,
                                ETH_ADDR_LEN);
 
                /**
@@ -4853,7 +5714,7 @@ i40e_vsi_setup(struct i40e_pf *pf,
                ctxt.flags = I40E_AQ_VSI_TYPE_VF;
 
                /* Use the VEB configuration if FW >= v5.0 */
-               if (hw->aq.fw_maj_ver >= 5) {
+               if (hw->aq.fw_maj_ver >= 5 || hw->mac.type == I40E_MAC_X722) {
                        /* Configure switch ID */
                        ctxt.info.valid_sections |=
                        rte_cpu_to_le_16(I40E_AQ_VSI_PROP_SWITCH_VALID);
@@ -4964,7 +5825,7 @@ i40e_vsi_setup(struct i40e_pf *pf,
        }
 
        /* MAC/VLAN configuration */
-       (void)rte_memcpy(&filter.mac_addr, &broadcast, ETHER_ADDR_LEN);
+       rte_memcpy(&filter.mac_addr, &broadcast, ETHER_ADDR_LEN);
        filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
 
        ret = i40e_vsi_add_mac(vsi, &filter);
@@ -5076,7 +5937,7 @@ i40e_vsi_config_vlan_stripping(struct i40e_vsi *vsi, bool on)
        vsi->info.port_vlan_flags &= ~(I40E_AQ_VSI_PVLAN_EMOD_MASK);
        vsi->info.port_vlan_flags |= vlan_flags;
        ctxt.seid = vsi->seid;
-       (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
+       rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
        ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
        if (ret)
                PMD_DRV_LOG(INFO, "Update VSI failed to %s vlan stripping",
@@ -5093,10 +5954,14 @@ i40e_dev_init_vlan(struct rte_eth_dev *dev)
        int mask = 0;
 
        /* Apply vlan offload setting */
-       mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK;
-       i40e_vlan_offload_set(dev, mask);
-
-       /* Apply double-vlan setting, not implemented yet */
+       mask = ETH_VLAN_STRIP_MASK |
+              ETH_VLAN_FILTER_MASK |
+              ETH_VLAN_EXTEND_MASK;
+       ret = i40e_vlan_offload_set(dev, mask);
+       if (ret) {
+               PMD_DRV_LOG(INFO, "Failed to update vlan offload");
+               return ret;
+       }
 
        /* Apply pvid setting */
        ret = i40e_vlan_pvid_set(dev, data->dev_conf.txmode.pvid,
@@ -5184,12 +6049,20 @@ i40e_pf_setup(struct i40e_pf *pf)
        pf->offset_loaded = FALSE;
        memset(&pf->stats, 0, sizeof(struct i40e_hw_port_stats));
        memset(&pf->stats_offset, 0, sizeof(struct i40e_hw_port_stats));
+       memset(&pf->internal_stats, 0, sizeof(struct i40e_eth_stats));
+       memset(&pf->internal_stats_offset, 0, sizeof(struct i40e_eth_stats));
 
        ret = i40e_pf_get_switch_config(pf);
        if (ret != I40E_SUCCESS) {
                PMD_DRV_LOG(ERR, "Could not get switch config, err %d", ret);
                return ret;
        }
+
+       ret = rte_eth_switch_domain_alloc(&pf->switch_domain_id);
+       if (ret)
+               PMD_INIT_LOG(WARNING,
+                       "failed to allocate switch domain for device %d", ret);
+
        if (pf->flags & I40E_FLAG_FDIR) {
                /* make queue allocated first, let FDIR use queue pair 0*/
                ret = i40e_res_pool_alloc(&pf->qp_pool, I40E_DEFAULT_QP_NUM_FDIR);
@@ -5648,7 +6521,8 @@ void
 i40e_pf_disable_irq0(struct i40e_hw *hw)
 {
        /* Disable all interrupt types */
-       I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, 0);
+       I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
+                      I40E_PFINT_DYN_CTL0_ITR_INDX_MASK);
        I40E_WRITE_FLUSH(hw);
 }
 
@@ -5698,16 +6572,16 @@ i40e_dev_handle_vfr_event(struct rte_eth_dev *dev)
                index = abs_vf_id / I40E_UINT32_BIT_SIZE;
                offset = abs_vf_id % I40E_UINT32_BIT_SIZE;
                val = I40E_READ_REG(hw, I40E_GLGEN_VFLRSTAT(index));
-               /* VFR event occured */
+               /* VFR event occurred */
                if (val & (0x1 << offset)) {
                        int ret;
 
                        /* Clear the event first */
                        I40E_WRITE_REG(hw, I40E_GLGEN_VFLRSTAT(index),
                                                        (0x1 << offset));
-                       PMD_DRV_LOG(INFO, "VF %u reset occured", abs_vf_id);
+                       PMD_DRV_LOG(INFO, "VF %u reset occurred", abs_vf_id);
                        /**
-                        * Only notify a VF reset event occured,
+                        * Only notify a VF reset event occurred,
                         * don't trigger another SW reset
                         */
                        ret = i40e_pf_host_vf_reset(&pf->vfs[i], 0);
@@ -5721,18 +6595,10 @@ static void
 i40e_notify_all_vfs_link_status(struct rte_eth_dev *dev)
 {
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-       struct i40e_virtchnl_pf_event event;
        int i;
 
-       event.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE;
-       event.event_data.link_event.link_status =
-               dev->data->dev_link.link_status;
-       event.event_data.link_event.link_speed =
-               (enum i40e_aq_link_speed)dev->data->dev_link.link_speed;
-
        for (i = 0; i < pf->vf_num; i++)
-               i40e_pf_host_send_msg_to_vf(&pf->vfs[i], I40E_VIRTCHNL_OP_EVENT,
-                               I40E_SUCCESS, (uint8_t *)&event, sizeof(event));
+               i40e_notify_vf_link_status(dev, &pf->vfs[i]);
 }
 
 static void
@@ -5774,14 +6640,12 @@ i40e_dev_handle_aq_msg(struct rte_eth_dev *dev)
                        break;
                case i40e_aqc_opc_get_link_status:
                        ret = i40e_dev_link_update(dev, 0);
-                       if (!ret) {
-                               i40e_notify_all_vfs_link_status(dev);
+                       if (!ret)
                                _rte_eth_dev_callback_process(dev,
                                        RTE_ETH_EVENT_INTR_LSC, NULL);
-                       }
                        break;
                default:
-                       PMD_DRV_LOG(ERR, "Request %u is not supported yet",
+                       PMD_DRV_LOG(DEBUG, "Request %u is not supported yet",
                                    opcode);
                        break;
                }
@@ -5802,8 +6666,7 @@ i40e_dev_handle_aq_msg(struct rte_eth_dev *dev)
  *  void
  */
 static void
-i40e_dev_interrupt_handler(struct rte_intr_handle *intr_handle,
-                          void *param)
+i40e_dev_interrupt_handler(void *param)
 {
        struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
@@ -5820,7 +6683,6 @@ i40e_dev_interrupt_handler(struct rte_intr_handle *intr_handle,
                PMD_DRV_LOG(INFO, "No interrupt event");
                goto done;
        }
-#ifdef RTE_LIBRTE_I40E_DEBUG_DRIVER
        if (icr0 & I40E_PFINT_ICR0_ECC_ERR_MASK)
                PMD_DRV_LOG(ERR, "ICR0: unrecoverable ECC error");
        if (icr0 & I40E_PFINT_ICR0_MAL_DETECT_MASK)
@@ -5835,7 +6697,6 @@ i40e_dev_interrupt_handler(struct rte_intr_handle *intr_handle,
                PMD_DRV_LOG(ERR, "ICR0: HMC error");
        if (icr0 & I40E_PFINT_ICR0_PE_CRITERR_MASK)
                PMD_DRV_LOG(ERR, "ICR0: protocol engine critical error");
-#endif /* RTE_LIBRTE_I40E_DEBUG_DRIVER */
 
        if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) {
                PMD_DRV_LOG(INFO, "ICR0: VF reset detected");
@@ -5849,10 +6710,56 @@ i40e_dev_interrupt_handler(struct rte_intr_handle *intr_handle,
 done:
        /* Enable interrupt */
        i40e_pf_enable_irq0(hw);
-       rte_intr_enable(intr_handle);
 }
 
-static int
+static void
+i40e_dev_alarm_handler(void *param)
+{
+       struct rte_eth_dev *dev = (struct rte_eth_dev *)param;
+       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t icr0;
+
+       /* Disable interrupt */
+       i40e_pf_disable_irq0(hw);
+
+       /* read out interrupt causes */
+       icr0 = I40E_READ_REG(hw, I40E_PFINT_ICR0);
+
+       /* No interrupt event indicated */
+       if (!(icr0 & I40E_PFINT_ICR0_INTEVENT_MASK))
+               goto done;
+       if (icr0 & I40E_PFINT_ICR0_ECC_ERR_MASK)
+               PMD_DRV_LOG(ERR, "ICR0: unrecoverable ECC error");
+       if (icr0 & I40E_PFINT_ICR0_MAL_DETECT_MASK)
+               PMD_DRV_LOG(ERR, "ICR0: malicious programming detected");
+       if (icr0 & I40E_PFINT_ICR0_GRST_MASK)
+               PMD_DRV_LOG(INFO, "ICR0: global reset requested");
+       if (icr0 & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK)
+               PMD_DRV_LOG(INFO, "ICR0: PCI exception activated");
+       if (icr0 & I40E_PFINT_ICR0_STORM_DETECT_MASK)
+               PMD_DRV_LOG(INFO, "ICR0: a change in the storm control state");
+       if (icr0 & I40E_PFINT_ICR0_HMC_ERR_MASK)
+               PMD_DRV_LOG(ERR, "ICR0: HMC error");
+       if (icr0 & I40E_PFINT_ICR0_PE_CRITERR_MASK)
+               PMD_DRV_LOG(ERR, "ICR0: protocol engine critical error");
+
+       if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) {
+               PMD_DRV_LOG(INFO, "ICR0: VF reset detected");
+               i40e_dev_handle_vfr_event(dev);
+       }
+       if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
+               PMD_DRV_LOG(INFO, "ICR0: adminq event");
+               i40e_dev_handle_aq_msg(dev);
+       }
+
+done:
+       /* Enable interrupt */
+       i40e_pf_enable_irq0(hw);
+       rte_eal_alarm_set(I40E_ALARM_INTERVAL,
+                         i40e_dev_alarm_handler, dev);
+}
+
+int
 i40e_add_macvlan_filters(struct i40e_vsi *vsi,
                         struct i40e_macvlan_filter *filter,
                         int total)
@@ -5881,7 +6788,7 @@ i40e_add_macvlan_filters(struct i40e_vsi *vsi,
                memset(req_list, 0, ele_buff_size);
 
                for (i = 0; i < actual_num; i++) {
-                       (void)rte_memcpy(req_list[i].mac_addr,
+                       rte_memcpy(req_list[i].mac_addr,
                                &filter[num + i].macaddr, ETH_ADDR_LEN);
                        req_list[i].vlan_tag =
                                rte_cpu_to_le_16(filter[num + i].vlan_id);
@@ -5926,7 +6833,7 @@ DONE:
        return ret;
 }
 
-static int
+int
 i40e_remove_macvlan_filters(struct i40e_vsi *vsi,
                            struct i40e_macvlan_filter *filter,
                            int total)
@@ -5956,7 +6863,7 @@ i40e_remove_macvlan_filters(struct i40e_vsi *vsi,
                memset(req_list, 0, ele_buff_size);
 
                for (i = 0; i < actual_num; i++) {
-                       (void)rte_memcpy(req_list[i].mac_addr,
+                       rte_memcpy(req_list[i].mac_addr,
                                &filter[num + i].macaddr, ETH_ADDR_LEN);
                        req_list[i].vlan_tag =
                                rte_cpu_to_le_16(filter[num + i].vlan_id);
@@ -6001,7 +6908,7 @@ DONE:
 /* Find out specific MAC filter */
 static struct i40e_mac_filter *
 i40e_find_mac_filter(struct i40e_vsi *vsi,
-                        struct ether_addr *macaddr)
+                        struct rte_ether_addr *macaddr)
 {
        struct i40e_mac_filter *f;
 
@@ -6046,7 +6953,7 @@ i40e_store_vlan_filter(struct i40e_vsi *vsi,
                vsi->vfta[vid_idx] &= ~vid_bit;
 }
 
-static void
+void
 i40e_set_vlan_filter(struct i40e_vsi *vsi,
                     uint16_t vlan_id, bool on)
 {
@@ -6082,10 +6989,10 @@ i40e_set_vlan_filter(struct i40e_vsi *vsi,
  * Find all vlan options for specific mac addr,
  * return with actual vlan found.
  */
-static inline int
+int
 i40e_find_all_vlan_for_mac(struct i40e_vsi *vsi,
                           struct i40e_macvlan_filter *mv_f,
-                          int num, struct ether_addr *addr)
+                          int num, struct rte_ether_addr *addr)
 {
        int i;
        uint32_t j, k;
@@ -6107,7 +7014,7 @@ i40e_find_all_vlan_for_mac(struct i40e_vsi *vsi,
                                                        "vlan number doesn't match");
                                                return I40E_ERR_PARAM;
                                        }
-                                       (void)rte_memcpy(&mv_f[i].macaddr,
+                                       rte_memcpy(&mv_f[i].macaddr,
                                                        addr, ETH_ADDR_LEN);
                                        mv_f[i].vlan_id =
                                                j * I40E_UINT32_BIT_SIZE + k;
@@ -6136,7 +7043,7 @@ i40e_find_all_mac_for_vlan(struct i40e_vsi *vsi,
                        PMD_DRV_LOG(ERR, "buffer number not match");
                        return I40E_ERR_PARAM;
                }
-               (void)rte_memcpy(&mv_f[i].macaddr, &f->mac_info.mac_addr,
+               rte_memcpy(&mv_f[i].macaddr, &f->mac_info.mac_addr,
                                ETH_ADDR_LEN);
                mv_f[i].vlan_id = vlan;
                mv_f[i].filter_type = f->mac_info.filter_type;
@@ -6172,7 +7079,7 @@ i40e_vsi_remove_all_macvlan_filter(struct i40e_vsi *vsi)
        i = 0;
        if (vsi->vlan_num == 0) {
                TAILQ_FOREACH(f, &vsi->mac_list, next) {
-                       (void)rte_memcpy(&mv_f[i].macaddr,
+                       rte_memcpy(&mv_f[i].macaddr,
                                &f->mac_info.mac_addr, ETH_ADDR_LEN);
                        mv_f[i].filter_type = f->mac_info.filter_type;
                        mv_f[i].vlan_id = 0;
@@ -6342,7 +7249,7 @@ i40e_vsi_add_mac(struct i40e_vsi *vsi, struct i40e_mac_filter_info *mac_filter)
 
        for (i = 0; i < vlan_num; i++) {
                mv_f[i].filter_type = mac_filter->filter_type;
-               (void)rte_memcpy(&mv_f[i].macaddr, &mac_filter->mac_addr,
+               rte_memcpy(&mv_f[i].macaddr, &mac_filter->mac_addr,
                                ETH_ADDR_LEN);
        }
 
@@ -6365,7 +7272,7 @@ i40e_vsi_add_mac(struct i40e_vsi *vsi, struct i40e_mac_filter_info *mac_filter)
                ret = I40E_ERR_NO_MEMORY;
                goto DONE;
        }
-       (void)rte_memcpy(&f->mac_info.mac_addr, &mac_filter->mac_addr,
+       rte_memcpy(&f->mac_info.mac_addr, &mac_filter->mac_addr,
                        ETH_ADDR_LEN);
        f->mac_info.filter_type = mac_filter->filter_type;
        TAILQ_INSERT_TAIL(&vsi->mac_list, f, next);
@@ -6379,7 +7286,7 @@ DONE:
 }
 
 int
-i40e_vsi_delete_mac(struct i40e_vsi *vsi, struct ether_addr *addr)
+i40e_vsi_delete_mac(struct i40e_vsi *vsi, struct rte_ether_addr *addr)
 {
        struct i40e_mac_filter *f;
        struct i40e_macvlan_filter *mv_f;
@@ -6412,7 +7319,7 @@ i40e_vsi_delete_mac(struct i40e_vsi *vsi, struct ether_addr *addr)
 
        for (i = 0; i < vlan_num; i++) {
                mv_f[i].filter_type = filter_type;
-               (void)rte_memcpy(&mv_f[i].macaddr, &f->mac_info.mac_addr,
+               rte_memcpy(&mv_f[i].macaddr, &f->mac_info.mac_addr,
                                ETH_ADDR_LEN);
        }
        if (filter_type == RTE_MACVLAN_PERFECT_MATCH ||
@@ -6439,104 +7346,36 @@ DONE:
 
 /* Configure hash enable flags for RSS */
 uint64_t
-i40e_config_hena(uint64_t flags, enum i40e_mac_type type)
+i40e_config_hena(const struct i40e_adapter *adapter, uint64_t flags)
 {
        uint64_t hena = 0;
+       int i;
 
        if (!flags)
                return hena;
 
-       if (flags & ETH_RSS_FRAG_IPV4)
-               hena |= 1ULL << I40E_FILTER_PCTYPE_FRAG_IPV4;
-       if (flags & ETH_RSS_NONFRAG_IPV4_TCP) {
-               if (type == I40E_MAC_X722) {
-                       hena |= (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) |
-                        (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK);
-               } else
-                       hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
-       }
-       if (flags & ETH_RSS_NONFRAG_IPV4_UDP) {
-               if (type == I40E_MAC_X722) {
-                       hena |= (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
-                        (1ULL << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) |
-                        (1ULL << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP);
-               } else
-                       hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
-       }
-       if (flags & ETH_RSS_NONFRAG_IPV4_SCTP)
-               hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP;
-       if (flags & ETH_RSS_NONFRAG_IPV4_OTHER)
-               hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
-       if (flags & ETH_RSS_FRAG_IPV6)
-               hena |= 1ULL << I40E_FILTER_PCTYPE_FRAG_IPV6;
-       if (flags & ETH_RSS_NONFRAG_IPV6_TCP) {
-               if (type == I40E_MAC_X722) {
-                       hena |= (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) |
-                        (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK);
-               } else
-                       hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP;
-       }
-       if (flags & ETH_RSS_NONFRAG_IPV6_UDP) {
-               if (type == I40E_MAC_X722) {
-                       hena |= (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
-                        (1ULL << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) |
-                        (1ULL << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP);
-               } else
-                       hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_UDP;
+       for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < I40E_FLOW_TYPE_MAX; i++) {
+               if (flags & (1ULL << i))
+                       hena |= adapter->pctypes_tbl[i];
        }
-       if (flags & ETH_RSS_NONFRAG_IPV6_SCTP)
-               hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP;
-       if (flags & ETH_RSS_NONFRAG_IPV6_OTHER)
-               hena |= 1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER;
-       if (flags & ETH_RSS_L2_PAYLOAD)
-               hena |= 1ULL << I40E_FILTER_PCTYPE_L2_PAYLOAD;
 
        return hena;
 }
 
 /* Parse the hash enable flags */
 uint64_t
-i40e_parse_hena(uint64_t flags)
+i40e_parse_hena(const struct i40e_adapter *adapter, uint64_t flags)
 {
        uint64_t rss_hf = 0;
 
        if (!flags)
                return rss_hf;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_FRAG_IPV4))
-               rss_hf |= ETH_RSS_FRAG_IPV4;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP))
-               rss_hf |= ETH_RSS_NONFRAG_IPV4_TCP;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK))
-               rss_hf |= ETH_RSS_NONFRAG_IPV4_TCP;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_UDP))
-               rss_hf |= ETH_RSS_NONFRAG_IPV4_UDP;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP))
-               rss_hf |= ETH_RSS_NONFRAG_IPV4_UDP;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP))
-               rss_hf |= ETH_RSS_NONFRAG_IPV4_UDP;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP))
-               rss_hf |= ETH_RSS_NONFRAG_IPV4_SCTP;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER))
-               rss_hf |= ETH_RSS_NONFRAG_IPV4_OTHER;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_FRAG_IPV6))
-               rss_hf |= ETH_RSS_FRAG_IPV6;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP))
-               rss_hf |= ETH_RSS_NONFRAG_IPV6_TCP;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK))
-               rss_hf |= ETH_RSS_NONFRAG_IPV6_TCP;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_UDP))
-               rss_hf |= ETH_RSS_NONFRAG_IPV6_UDP;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP))
-               rss_hf |= ETH_RSS_NONFRAG_IPV6_UDP;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP))
-               rss_hf |= ETH_RSS_NONFRAG_IPV6_UDP;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP))
-               rss_hf |= ETH_RSS_NONFRAG_IPV6_SCTP;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER))
-               rss_hf |= ETH_RSS_NONFRAG_IPV6_OTHER;
-       if (flags & (1ULL << I40E_FILTER_PCTYPE_L2_PAYLOAD))
-               rss_hf |= ETH_RSS_L2_PAYLOAD;
+       int i;
 
+       for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < I40E_FLOW_TYPE_MAX; i++) {
+               if (flags & adapter->pctypes_tbl[i])
+                       rss_hf |= (1ULL << i);
+       }
        return rss_hf;
 }
 
@@ -6545,30 +7384,26 @@ static void
 i40e_pf_disable_rss(struct i40e_pf *pf)
 {
        struct i40e_hw *hw = I40E_PF_TO_HW(pf);
-       uint64_t hena;
 
-       hena = (uint64_t)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0));
-       hena |= ((uint64_t)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1))) << 32;
-       if (hw->mac.type == I40E_MAC_X722)
-               hena &= ~I40E_RSS_HENA_ALL_X722;
-       else
-               hena &= ~I40E_RSS_HENA_ALL;
-       i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (uint32_t)hena);
-       i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (uint32_t)(hena >> 32));
+       i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), 0);
+       i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), 0);
        I40E_WRITE_FLUSH(hw);
 }
 
-static int
+int
 i40e_set_rss_key(struct i40e_vsi *vsi, uint8_t *key, uint8_t key_len)
 {
        struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
        struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+       uint16_t key_idx = (vsi->type == I40E_VSI_SRIOV) ?
+                          I40E_VFQF_HKEY_MAX_INDEX :
+                          I40E_PFQF_HKEY_MAX_INDEX;
        int ret = 0;
 
        if (!key || key_len == 0) {
                PMD_DRV_LOG(DEBUG, "No key to be configured");
                return 0;
-       } else if (key_len != (I40E_PFQF_HKEY_MAX_INDEX + 1) *
+       } else if (key_len != (key_idx + 1) *
                sizeof(uint32_t)) {
                PMD_DRV_LOG(ERR, "Invalid key length %u", key_len);
                return -EINVAL;
@@ -6585,8 +7420,18 @@ i40e_set_rss_key(struct i40e_vsi *vsi, uint8_t *key, uint8_t key_len)
                uint32_t *hash_key = (uint32_t *)key;
                uint16_t i;
 
-               for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-                       i40e_write_rx_ctl(hw, I40E_PFQF_HKEY(i), hash_key[i]);
+               if (vsi->type == I40E_VSI_SRIOV) {
+                       for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++)
+                               I40E_WRITE_REG(
+                                       hw,
+                                       I40E_VFQF_HKEY1(i, vsi->user_param),
+                                       hash_key[i]);
+
+               } else {
+                       for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
+                               I40E_WRITE_REG(hw, I40E_PFQF_HKEY(i),
+                                              hash_key[i]);
+               }
                I40E_WRITE_FLUSH(hw);
        }
 
@@ -6598,10 +7443,11 @@ i40e_get_rss_key(struct i40e_vsi *vsi, uint8_t *key, uint8_t *key_len)
 {
        struct i40e_pf *pf = I40E_VSI_TO_PF(vsi);
        struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
+       uint32_t reg;
        int ret;
 
        if (!key || !key_len)
-               return -EINVAL;
+               return 0;
 
        if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) {
                ret = i40e_aq_get_rss_key(hw, vsi->vsi_id,
@@ -6614,11 +7460,22 @@ i40e_get_rss_key(struct i40e_vsi *vsi, uint8_t *key, uint8_t *key_len)
                uint32_t *key_dw = (uint32_t *)key;
                uint16_t i;
 
-               for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-                       key_dw[i] = i40e_read_rx_ctl(hw, I40E_PFQF_HKEY(i));
+               if (vsi->type == I40E_VSI_SRIOV) {
+                       for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++) {
+                               reg = I40E_VFQF_HKEY1(i, vsi->user_param);
+                               key_dw[i] = i40e_read_rx_ctl(hw, reg);
+                       }
+                       *key_len = (I40E_VFQF_HKEY_MAX_INDEX + 1) *
+                                  sizeof(uint32_t);
+               } else {
+                       for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++) {
+                               reg = I40E_PFQF_HKEY(i);
+                               key_dw[i] = i40e_read_rx_ctl(hw, reg);
+                       }
+                       *key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
+                                  sizeof(uint32_t);
+               }
        }
-       *key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t);
-
        return 0;
 }
 
@@ -6626,7 +7483,6 @@ static int
 i40e_hw_rss_hash_set(struct i40e_pf *pf, struct rte_eth_rss_conf *rss_conf)
 {
        struct i40e_hw *hw = I40E_PF_TO_HW(pf);
-       uint64_t rss_hf;
        uint64_t hena;
        int ret;
 
@@ -6635,14 +7491,7 @@ i40e_hw_rss_hash_set(struct i40e_pf *pf, struct rte_eth_rss_conf *rss_conf)
        if (ret)
                return ret;
 
-       rss_hf = rss_conf->rss_hf;
-       hena = (uint64_t)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0));
-       hena |= ((uint64_t)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1))) << 32;
-       if (hw->mac.type == I40E_MAC_X722)
-               hena &= ~I40E_RSS_HENA_ALL_X722;
-       else
-               hena &= ~I40E_RSS_HENA_ALL;
-       hena |= i40e_config_hena(rss_hf, hw->mac.type);
+       hena = i40e_config_hena(pf->adapter, rss_conf->rss_hf);
        i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (uint32_t)hena);
        i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (uint32_t)(hena >> 32));
        I40E_WRITE_FLUSH(hw);
@@ -6656,14 +7505,13 @@ i40e_dev_rss_hash_update(struct rte_eth_dev *dev,
 {
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       uint64_t rss_hf = rss_conf->rss_hf & I40E_RSS_OFFLOAD_ALL;
+       uint64_t rss_hf = rss_conf->rss_hf & pf->adapter->flow_types_mask;
        uint64_t hena;
 
        hena = (uint64_t)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0));
        hena |= ((uint64_t)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1))) << 32;
-       if (!(hena & ((hw->mac.type == I40E_MAC_X722)
-                ? I40E_RSS_HENA_ALL_X722
-                : I40E_RSS_HENA_ALL))) { /* RSS disabled */
+
+       if (!(hena & pf->adapter->pctypes_mask)) { /* RSS disabled */
                if (rss_hf != 0) /* Enable RSS */
                        return -EINVAL;
                return 0; /* Nothing to do */
@@ -6682,13 +7530,19 @@ i40e_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        uint64_t hena;
+       int ret;
+
+       if (!rss_conf)
+               return -EINVAL;
 
-       i40e_get_rss_key(pf->main_vsi, rss_conf->rss_key,
+       ret = i40e_get_rss_key(pf->main_vsi, rss_conf->rss_key,
                         &rss_conf->rss_key_len);
+       if (ret)
+               return ret;
 
        hena = (uint64_t)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0));
        hena |= ((uint64_t)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1))) << 32;
-       rss_conf->rss_hf = i40e_parse_hena(hena);
+       rss_conf->rss_hf = i40e_parse_hena(pf->adapter, hena);
 
        return 0;
 }
@@ -6729,13 +7583,13 @@ i40e_dev_get_filter_type(uint16_t filter_type, uint16_t *flag)
 /* Convert tunnel filter structure */
 static int
 i40e_tunnel_filter_convert(
-       struct i40e_aqc_add_rm_cloud_filt_elem_ext *cld_filter,
+       struct i40e_aqc_cloud_filters_element_bb *cld_filter,
        struct i40e_tunnel_filter *tunnel_filter)
 {
-       ether_addr_copy((struct ether_addr *)&cld_filter->element.outer_mac,
-                       (struct ether_addr *)&tunnel_filter->input.outer_mac);
-       ether_addr_copy((struct ether_addr *)&cld_filter->element.inner_mac,
-                       (struct ether_addr *)&tunnel_filter->input.inner_mac);
+       ether_addr_copy((struct rte_ether_addr *)&cld_filter->element.outer_mac,
+               (struct rte_ether_addr *)&tunnel_filter->input.outer_mac);
+       ether_addr_copy((struct rte_ether_addr *)&cld_filter->element.inner_mac,
+               (struct rte_ether_addr *)&tunnel_filter->input.inner_mac);
        tunnel_filter->input.inner_vlan = cld_filter->element.inner_vlan;
        if ((rte_le_to_cpu_16(cld_filter->element.flags) &
             I40E_AQC_ADD_CLOUD_FLAGS_IPV6) ==
@@ -6820,15 +7674,15 @@ i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
                        uint8_t add)
 {
        uint16_t ip_type;
-       uint32_t ipv4_addr;
+       uint32_t ipv4_addr, ipv4_addr_le;
        uint8_t i, tun_type = 0;
        /* internal varialbe to convert ipv6 byte order */
        uint32_t convert_ipv6[4];
        int val, ret = 0;
        struct i40e_hw *hw = I40E_PF_TO_HW(pf);
        struct i40e_vsi *vsi = pf->main_vsi;
-       struct i40e_aqc_add_rm_cloud_filt_elem_ext *cld_filter;
-       struct i40e_aqc_add_rm_cloud_filt_elem_ext *pfilter;
+       struct i40e_aqc_cloud_filters_element_bb *cld_filter;
+       struct i40e_aqc_cloud_filters_element_bb *pfilter;
        struct i40e_tunnel_rule *tunnel_rule = &pf->tunnel;
        struct i40e_tunnel_filter *tunnel, *node;
        struct i40e_tunnel_filter check_filter; /* Check if filter exists */
@@ -6844,17 +7698,18 @@ i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
        pfilter = cld_filter;
 
        ether_addr_copy(&tunnel_filter->outer_mac,
-                       (struct ether_addr *)&pfilter->element.outer_mac);
+                       (struct rte_ether_addr *)&pfilter->element.outer_mac);
        ether_addr_copy(&tunnel_filter->inner_mac,
-                       (struct ether_addr *)&pfilter->element.inner_mac);
+                       (struct rte_ether_addr *)&pfilter->element.inner_mac);
 
        pfilter->element.inner_vlan =
                rte_cpu_to_le_16(tunnel_filter->inner_vlan);
        if (tunnel_filter->ip_type == RTE_TUNNEL_IPTYPE_IPV4) {
                ip_type = I40E_AQC_ADD_CLOUD_FLAGS_IPV4;
                ipv4_addr = rte_be_to_cpu_32(tunnel_filter->ip_addr.ipv4_addr);
+               ipv4_addr_le = rte_cpu_to_le_32(ipv4_addr);
                rte_memcpy(&pfilter->element.ipaddr.v4.data,
-                               &rte_cpu_to_le_32(ipv4_addr),
+                               &ipv4_addr_le,
                                sizeof(pfilter->element.ipaddr.v4.data));
        } else {
                ip_type = I40E_AQC_ADD_CLOUD_FLAGS_IPV6;
@@ -6878,6 +7733,9 @@ i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
        case RTE_TUNNEL_TYPE_IP_IN_GRE:
                tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_IP;
                break;
+       case RTE_TUNNEL_TYPE_VXLAN_GPE:
+               tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN_GPE;
+               break;
        default:
                /* Other tunnel types is not supported. */
                PMD_DRV_LOG(ERR, "tunnel type is not supported.");
@@ -6905,11 +7763,13 @@ i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
        node = i40e_sw_tunnel_filter_lookup(tunnel_rule, &check_filter.input);
        if (add && node) {
                PMD_DRV_LOG(ERR, "Conflict with existing tunnel rules!");
+               rte_free(cld_filter);
                return -EINVAL;
        }
 
        if (!add && !node) {
                PMD_DRV_LOG(ERR, "There's no corresponding tunnel filter!");
+               rte_free(cld_filter);
                return -EINVAL;
        }
 
@@ -6918,16 +7778,26 @@ i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
                                        vsi->seid, &cld_filter->element, 1);
                if (ret < 0) {
                        PMD_DRV_LOG(ERR, "Failed to add a tunnel filter.");
+                       rte_free(cld_filter);
                        return -ENOTSUP;
                }
                tunnel = rte_zmalloc("tunnel_filter", sizeof(*tunnel), 0);
+               if (tunnel == NULL) {
+                       PMD_DRV_LOG(ERR, "Failed to alloc memory.");
+                       rte_free(cld_filter);
+                       return -ENOMEM;
+               }
+
                rte_memcpy(tunnel, &check_filter, sizeof(check_filter));
                ret = i40e_sw_tunnel_filter_insert(pf, tunnel);
+               if (ret < 0)
+                       rte_free(tunnel);
        } else {
-               ret = i40e_aq_remove_cloud_filters(hw, vsi->seid,
+               ret = i40e_aq_rem_cloud_filters(hw, vsi->seid,
                                                   &cld_filter->element, 1);
                if (ret < 0) {
                        PMD_DRV_LOG(ERR, "Failed to delete a tunnel filter.");
+                       rte_free(cld_filter);
                        return -ENOTSUP;
                }
                ret = i40e_sw_tunnel_filter_del(pf, &node->input);
@@ -6951,8 +7821,14 @@ i40e_status_code i40e_replace_mpls_l1_filter(struct i40e_pf *pf)
        struct i40e_aqc_replace_cloud_filters_cmd  filter_replace;
        struct i40e_aqc_replace_cloud_filters_cmd_buf  filter_replace_buf;
        struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+       struct rte_eth_dev *dev = ((struct i40e_adapter *)hw->back)->eth_dev;
        enum i40e_status_code status = I40E_SUCCESS;
 
+       if (pf->support_multi_driver) {
+               PMD_DRV_LOG(ERR, "Replace l1 filter is not supported.");
+               return I40E_NOT_SUPPORTED;
+       }
+
        memset(&filter_replace, 0,
               sizeof(struct i40e_aqc_replace_cloud_filters_cmd));
        memset(&filter_replace_buf, 0,
@@ -6961,7 +7837,7 @@ i40e_status_code i40e_replace_mpls_l1_filter(struct i40e_pf *pf)
        /* create L1 filter */
        filter_replace.old_filter_type =
                I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IMAC;
-       filter_replace.new_filter_type = I40E_AQC_ADD_L1_FILTER_TEID_MPLS;
+       filter_replace.new_filter_type = I40E_AQC_ADD_L1_FILTER_0X11;
        filter_replace.tr_bit = 0;
 
        /* Prepare the buffer, 3 entries */
@@ -6989,6 +7865,14 @@ i40e_status_code i40e_replace_mpls_l1_filter(struct i40e_pf *pf)
 
        status = i40e_aq_replace_cloud_filters(hw, &filter_replace,
                                               &filter_replace_buf);
+       if (!status && (filter_replace.old_filter_type !=
+                       filter_replace.new_filter_type))
+               PMD_DRV_LOG(WARNING, "i40e device %s changed cloud l1 type."
+                           " original: 0x%x, new: 0x%x",
+                           dev->device->name,
+                           filter_replace.old_filter_type,
+                           filter_replace.new_filter_type);
+
        return status;
 }
 
@@ -6998,8 +7882,14 @@ i40e_status_code i40e_replace_mpls_cloud_filter(struct i40e_pf *pf)
        struct i40e_aqc_replace_cloud_filters_cmd  filter_replace;
        struct i40e_aqc_replace_cloud_filters_cmd_buf  filter_replace_buf;
        struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+       struct rte_eth_dev *dev = ((struct i40e_adapter *)hw->back)->eth_dev;
        enum i40e_status_code status = I40E_SUCCESS;
 
+       if (pf->support_multi_driver) {
+               PMD_DRV_LOG(ERR, "Replace cloud filter is not supported.");
+               return I40E_NOT_SUPPORTED;
+       }
+
        /* For MPLSoUDP */
        memset(&filter_replace, 0,
               sizeof(struct i40e_aqc_replace_cloud_filters_cmd));
@@ -7009,18 +7899,25 @@ i40e_status_code i40e_replace_mpls_cloud_filter(struct i40e_pf *pf)
                I40E_AQC_MIRROR_CLOUD_FILTER;
        filter_replace.old_filter_type = I40E_AQC_ADD_CLOUD_FILTER_IIP;
        filter_replace.new_filter_type =
-               I40E_AQC_ADD_CLOUD_FILTER_TEID_MPLSoUDP;
+               I40E_AQC_ADD_CLOUD_FILTER_0X11;
        /* Prepare the buffer, 2 entries */
        filter_replace_buf.data[0] = I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG;
        filter_replace_buf.data[0] |=
                I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
-       filter_replace_buf.data[4] = I40E_AQC_ADD_L1_FILTER_TEID_MPLS;
+       filter_replace_buf.data[4] = I40E_AQC_ADD_L1_FILTER_0X11;
        filter_replace_buf.data[4] |=
                I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
        status = i40e_aq_replace_cloud_filters(hw, &filter_replace,
                                               &filter_replace_buf);
        if (status < 0)
                return status;
+       if (filter_replace.old_filter_type !=
+           filter_replace.new_filter_type)
+               PMD_DRV_LOG(WARNING, "i40e device %s changed cloud filter type."
+                           " original: 0x%x, new: 0x%x",
+                           dev->device->name,
+                           filter_replace.old_filter_type,
+                           filter_replace.new_filter_type);
 
        /* For MPLSoGRE */
        memset(&filter_replace, 0,
@@ -7032,92 +7929,262 @@ i40e_status_code i40e_replace_mpls_cloud_filter(struct i40e_pf *pf)
                I40E_AQC_MIRROR_CLOUD_FILTER;
        filter_replace.old_filter_type = I40E_AQC_ADD_CLOUD_FILTER_IMAC;
        filter_replace.new_filter_type =
-               I40E_AQC_ADD_CLOUD_FILTER_TEID_MPLSoGRE;
+               I40E_AQC_ADD_CLOUD_FILTER_0X12;
        /* Prepare the buffer, 2 entries */
        filter_replace_buf.data[0] = I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG;
        filter_replace_buf.data[0] |=
                I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
-       filter_replace_buf.data[4] = I40E_AQC_ADD_L1_FILTER_TEID_MPLS;
+       filter_replace_buf.data[4] = I40E_AQC_ADD_L1_FILTER_0X11;
        filter_replace_buf.data[4] |=
                I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
 
        status = i40e_aq_replace_cloud_filters(hw, &filter_replace,
                                               &filter_replace_buf);
+       if (!status && (filter_replace.old_filter_type !=
+                       filter_replace.new_filter_type))
+               PMD_DRV_LOG(WARNING, "i40e device %s changed cloud filter type."
+                           " original: 0x%x, new: 0x%x",
+                           dev->device->name,
+                           filter_replace.old_filter_type,
+                           filter_replace.new_filter_type);
+
        return status;
 }
 
-int
-i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf,
-                     struct i40e_tunnel_filter_conf *tunnel_filter,
-                     uint8_t add)
+static enum i40e_status_code
+i40e_replace_gtp_l1_filter(struct i40e_pf *pf)
 {
-       uint16_t ip_type;
-       uint32_t ipv4_addr;
-       uint8_t i, tun_type = 0;
-       /* internal variable to convert ipv6 byte order */
-       uint32_t convert_ipv6[4];
-       int val, ret = 0;
-       struct i40e_pf_vf *vf = NULL;
+       struct i40e_aqc_replace_cloud_filters_cmd  filter_replace;
+       struct i40e_aqc_replace_cloud_filters_cmd_buf  filter_replace_buf;
        struct i40e_hw *hw = I40E_PF_TO_HW(pf);
-       struct i40e_vsi *vsi;
-       struct i40e_aqc_add_rm_cloud_filt_elem_ext *cld_filter;
-       struct i40e_aqc_add_rm_cloud_filt_elem_ext *pfilter;
-       struct i40e_tunnel_rule *tunnel_rule = &pf->tunnel;
-       struct i40e_tunnel_filter *tunnel, *node;
-       struct i40e_tunnel_filter check_filter; /* Check if filter exists */
-       uint32_t teid_le;
-       bool big_buffer = 0;
-
-       cld_filter = rte_zmalloc("tunnel_filter",
-                        sizeof(struct i40e_aqc_add_rm_cloud_filt_elem_ext),
-                        0);
-
-       if (cld_filter == NULL) {
-               PMD_DRV_LOG(ERR, "Failed to alloc memory.");
-               return -ENOMEM;
-       }
-       pfilter = cld_filter;
-
-       ether_addr_copy(&tunnel_filter->outer_mac,
-                       (struct ether_addr *)&pfilter->element.outer_mac);
-       ether_addr_copy(&tunnel_filter->inner_mac,
-                       (struct ether_addr *)&pfilter->element.inner_mac);
+       struct rte_eth_dev *dev = ((struct i40e_adapter *)hw->back)->eth_dev;
+       enum i40e_status_code status = I40E_SUCCESS;
 
-       pfilter->element.inner_vlan =
-               rte_cpu_to_le_16(tunnel_filter->inner_vlan);
-       if (tunnel_filter->ip_type == I40E_TUNNEL_IPTYPE_IPV4) {
-               ip_type = I40E_AQC_ADD_CLOUD_FLAGS_IPV4;
-               ipv4_addr = rte_be_to_cpu_32(tunnel_filter->ip_addr.ipv4_addr);
-               rte_memcpy(&pfilter->element.ipaddr.v4.data,
-                               &rte_cpu_to_le_32(ipv4_addr),
-                               sizeof(pfilter->element.ipaddr.v4.data));
-       } else {
-               ip_type = I40E_AQC_ADD_CLOUD_FLAGS_IPV6;
-               for (i = 0; i < 4; i++) {
-                       convert_ipv6[i] =
-                       rte_cpu_to_le_32(rte_be_to_cpu_32(
-                                        tunnel_filter->ip_addr.ipv6_addr[i]));
-               }
-               rte_memcpy(&pfilter->element.ipaddr.v6.data,
-                          &convert_ipv6,
-                          sizeof(pfilter->element.ipaddr.v6.data));
+       if (pf->support_multi_driver) {
+               PMD_DRV_LOG(ERR, "Replace l1 filter is not supported.");
+               return I40E_NOT_SUPPORTED;
        }
 
-       /* check tunneled type */
-       switch (tunnel_filter->tunnel_type) {
-       case I40E_TUNNEL_TYPE_VXLAN:
-               tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN;
-               break;
-       case I40E_TUNNEL_TYPE_NVGRE:
-               tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC;
-               break;
-       case I40E_TUNNEL_TYPE_IP_IN_GRE:
-               tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_IP;
-               break;
-       case I40E_TUNNEL_TYPE_MPLSoUDP:
-               if (!pf->mpls_replace_flag) {
-                       i40e_replace_mpls_l1_filter(pf);
-                       i40e_replace_mpls_cloud_filter(pf);
+       /* For GTP-C */
+       memset(&filter_replace, 0,
+              sizeof(struct i40e_aqc_replace_cloud_filters_cmd));
+       memset(&filter_replace_buf, 0,
+              sizeof(struct i40e_aqc_replace_cloud_filters_cmd_buf));
+       /* create L1 filter */
+       filter_replace.old_filter_type =
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_IMAC;
+       filter_replace.new_filter_type = I40E_AQC_ADD_L1_FILTER_0X12;
+       filter_replace.tr_bit = I40E_AQC_NEW_TR_22 |
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+       /* Prepare the buffer, 2 entries */
+       filter_replace_buf.data[0] =
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD0;
+       filter_replace_buf.data[0] |=
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+       filter_replace_buf.data[2] = 0xFF;
+       filter_replace_buf.data[3] = 0xFF;
+       filter_replace_buf.data[4] =
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD1;
+       filter_replace_buf.data[4] |=
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+       filter_replace_buf.data[6] = 0xFF;
+       filter_replace_buf.data[7] = 0xFF;
+       status = i40e_aq_replace_cloud_filters(hw, &filter_replace,
+                                              &filter_replace_buf);
+       if (status < 0)
+               return status;
+       if (filter_replace.old_filter_type !=
+           filter_replace.new_filter_type)
+               PMD_DRV_LOG(WARNING, "i40e device %s changed cloud l1 type."
+                           " original: 0x%x, new: 0x%x",
+                           dev->device->name,
+                           filter_replace.old_filter_type,
+                           filter_replace.new_filter_type);
+
+       /* for GTP-U */
+       memset(&filter_replace, 0,
+              sizeof(struct i40e_aqc_replace_cloud_filters_cmd));
+       memset(&filter_replace_buf, 0,
+              sizeof(struct i40e_aqc_replace_cloud_filters_cmd_buf));
+       /* create L1 filter */
+       filter_replace.old_filter_type =
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TUNNLE_KEY;
+       filter_replace.new_filter_type = I40E_AQC_ADD_L1_FILTER_0X13;
+       filter_replace.tr_bit = I40E_AQC_NEW_TR_21 |
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+       /* Prepare the buffer, 2 entries */
+       filter_replace_buf.data[0] =
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD0;
+       filter_replace_buf.data[0] |=
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+       filter_replace_buf.data[2] = 0xFF;
+       filter_replace_buf.data[3] = 0xFF;
+       filter_replace_buf.data[4] =
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_TEID_WORD1;
+       filter_replace_buf.data[4] |=
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+       filter_replace_buf.data[6] = 0xFF;
+       filter_replace_buf.data[7] = 0xFF;
+
+       status = i40e_aq_replace_cloud_filters(hw, &filter_replace,
+                                              &filter_replace_buf);
+       if (!status && (filter_replace.old_filter_type !=
+                       filter_replace.new_filter_type))
+               PMD_DRV_LOG(WARNING, "i40e device %s changed cloud l1 type."
+                           " original: 0x%x, new: 0x%x",
+                           dev->device->name,
+                           filter_replace.old_filter_type,
+                           filter_replace.new_filter_type);
+
+       return status;
+}
+
+static enum
+i40e_status_code i40e_replace_gtp_cloud_filter(struct i40e_pf *pf)
+{
+       struct i40e_aqc_replace_cloud_filters_cmd  filter_replace;
+       struct i40e_aqc_replace_cloud_filters_cmd_buf  filter_replace_buf;
+       struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+       struct rte_eth_dev *dev = ((struct i40e_adapter *)hw->back)->eth_dev;
+       enum i40e_status_code status = I40E_SUCCESS;
+
+       if (pf->support_multi_driver) {
+               PMD_DRV_LOG(ERR, "Replace cloud filter is not supported.");
+               return I40E_NOT_SUPPORTED;
+       }
+
+       /* for GTP-C */
+       memset(&filter_replace, 0,
+              sizeof(struct i40e_aqc_replace_cloud_filters_cmd));
+       memset(&filter_replace_buf, 0,
+              sizeof(struct i40e_aqc_replace_cloud_filters_cmd_buf));
+       filter_replace.valid_flags = I40E_AQC_REPLACE_CLOUD_FILTER;
+       filter_replace.old_filter_type = I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN;
+       filter_replace.new_filter_type =
+               I40E_AQC_ADD_CLOUD_FILTER_0X11;
+       /* Prepare the buffer, 2 entries */
+       filter_replace_buf.data[0] = I40E_AQC_ADD_L1_FILTER_0X12;
+       filter_replace_buf.data[0] |=
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+       filter_replace_buf.data[4] = I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG;
+       filter_replace_buf.data[4] |=
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+       status = i40e_aq_replace_cloud_filters(hw, &filter_replace,
+                                              &filter_replace_buf);
+       if (status < 0)
+               return status;
+       if (filter_replace.old_filter_type !=
+           filter_replace.new_filter_type)
+               PMD_DRV_LOG(WARNING, "i40e device %s changed cloud filter type."
+                           " original: 0x%x, new: 0x%x",
+                           dev->device->name,
+                           filter_replace.old_filter_type,
+                           filter_replace.new_filter_type);
+
+       /* for GTP-U */
+       memset(&filter_replace, 0,
+              sizeof(struct i40e_aqc_replace_cloud_filters_cmd));
+       memset(&filter_replace_buf, 0,
+              sizeof(struct i40e_aqc_replace_cloud_filters_cmd_buf));
+       filter_replace.valid_flags = I40E_AQC_REPLACE_CLOUD_FILTER;
+       filter_replace.old_filter_type =
+               I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID;
+       filter_replace.new_filter_type =
+               I40E_AQC_ADD_CLOUD_FILTER_0X12;
+       /* Prepare the buffer, 2 entries */
+       filter_replace_buf.data[0] = I40E_AQC_ADD_L1_FILTER_0X13;
+       filter_replace_buf.data[0] |=
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+       filter_replace_buf.data[4] = I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG;
+       filter_replace_buf.data[4] |=
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+
+       status = i40e_aq_replace_cloud_filters(hw, &filter_replace,
+                                              &filter_replace_buf);
+       if (!status && (filter_replace.old_filter_type !=
+                       filter_replace.new_filter_type))
+               PMD_DRV_LOG(WARNING, "i40e device %s changed cloud filter type."
+                           " original: 0x%x, new: 0x%x",
+                           dev->device->name,
+                           filter_replace.old_filter_type,
+                           filter_replace.new_filter_type);
+
+       return status;
+}
+
+int
+i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf,
+                     struct i40e_tunnel_filter_conf *tunnel_filter,
+                     uint8_t add)
+{
+       uint16_t ip_type;
+       uint32_t ipv4_addr, ipv4_addr_le;
+       uint8_t i, tun_type = 0;
+       /* internal variable to convert ipv6 byte order */
+       uint32_t convert_ipv6[4];
+       int val, ret = 0;
+       struct i40e_pf_vf *vf = NULL;
+       struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+       struct i40e_vsi *vsi;
+       struct i40e_aqc_cloud_filters_element_bb *cld_filter;
+       struct i40e_aqc_cloud_filters_element_bb *pfilter;
+       struct i40e_tunnel_rule *tunnel_rule = &pf->tunnel;
+       struct i40e_tunnel_filter *tunnel, *node;
+       struct i40e_tunnel_filter check_filter; /* Check if filter exists */
+       uint32_t teid_le;
+       bool big_buffer = 0;
+
+       cld_filter = rte_zmalloc("tunnel_filter",
+                        sizeof(struct i40e_aqc_add_rm_cloud_filt_elem_ext),
+                        0);
+
+       if (cld_filter == NULL) {
+               PMD_DRV_LOG(ERR, "Failed to alloc memory.");
+               return -ENOMEM;
+       }
+       pfilter = cld_filter;
+
+       ether_addr_copy(&tunnel_filter->outer_mac,
+                       (struct rte_ether_addr *)&pfilter->element.outer_mac);
+       ether_addr_copy(&tunnel_filter->inner_mac,
+                       (struct rte_ether_addr *)&pfilter->element.inner_mac);
+
+       pfilter->element.inner_vlan =
+               rte_cpu_to_le_16(tunnel_filter->inner_vlan);
+       if (tunnel_filter->ip_type == I40E_TUNNEL_IPTYPE_IPV4) {
+               ip_type = I40E_AQC_ADD_CLOUD_FLAGS_IPV4;
+               ipv4_addr = rte_be_to_cpu_32(tunnel_filter->ip_addr.ipv4_addr);
+               ipv4_addr_le = rte_cpu_to_le_32(ipv4_addr);
+               rte_memcpy(&pfilter->element.ipaddr.v4.data,
+                               &ipv4_addr_le,
+                               sizeof(pfilter->element.ipaddr.v4.data));
+       } else {
+               ip_type = I40E_AQC_ADD_CLOUD_FLAGS_IPV6;
+               for (i = 0; i < 4; i++) {
+                       convert_ipv6[i] =
+                       rte_cpu_to_le_32(rte_be_to_cpu_32(
+                                        tunnel_filter->ip_addr.ipv6_addr[i]));
+               }
+               rte_memcpy(&pfilter->element.ipaddr.v6.data,
+                          &convert_ipv6,
+                          sizeof(pfilter->element.ipaddr.v6.data));
+       }
+
+       /* check tunneled type */
+       switch (tunnel_filter->tunnel_type) {
+       case I40E_TUNNEL_TYPE_VXLAN:
+               tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_VXLAN;
+               break;
+       case I40E_TUNNEL_TYPE_NVGRE:
+               tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC;
+               break;
+       case I40E_TUNNEL_TYPE_IP_IN_GRE:
+               tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_IP;
+               break;
+       case I40E_TUNNEL_TYPE_MPLSoUDP:
+               if (!pf->mpls_replace_flag) {
+                       i40e_replace_mpls_l1_filter(pf);
+                       i40e_replace_mpls_cloud_filter(pf);
                        pf->mpls_replace_flag = 1;
                }
                teid_le = rte_cpu_to_le_32(tunnel_filter->tenant_id);
@@ -7128,7 +8195,7 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf,
                pfilter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2] =
                        0x40;
                big_buffer = 1;
-               tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_MPLSoUDP;
+               tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_MPLSOUDP;
                break;
        case I40E_TUNNEL_TYPE_MPLSoGRE:
                if (!pf->mpls_replace_flag) {
@@ -7144,7 +8211,54 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf,
                pfilter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2] =
                        0x0;
                big_buffer = 1;
-               tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_MPLSoGRE;
+               tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_MPLSOGRE;
+               break;
+       case I40E_TUNNEL_TYPE_GTPC:
+               if (!pf->gtp_replace_flag) {
+                       i40e_replace_gtp_l1_filter(pf);
+                       i40e_replace_gtp_cloud_filter(pf);
+                       pf->gtp_replace_flag = 1;
+               }
+               teid_le = rte_cpu_to_le_32(tunnel_filter->tenant_id);
+               pfilter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD0] =
+                       (teid_le >> 16) & 0xFFFF;
+               pfilter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD1] =
+                       teid_le & 0xFFFF;
+               pfilter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD2] =
+                       0x0;
+               big_buffer = 1;
+               break;
+       case I40E_TUNNEL_TYPE_GTPU:
+               if (!pf->gtp_replace_flag) {
+                       i40e_replace_gtp_l1_filter(pf);
+                       i40e_replace_gtp_cloud_filter(pf);
+                       pf->gtp_replace_flag = 1;
+               }
+               teid_le = rte_cpu_to_le_32(tunnel_filter->tenant_id);
+               pfilter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD0] =
+                       (teid_le >> 16) & 0xFFFF;
+               pfilter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD1] =
+                       teid_le & 0xFFFF;
+               pfilter->general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD2] =
+                       0x0;
+               big_buffer = 1;
+               break;
+       case I40E_TUNNEL_TYPE_QINQ:
+               if (!pf->qinq_replace_flag) {
+                       ret = i40e_cloud_filter_qinq_create(pf);
+                       if (ret < 0)
+                               PMD_DRV_LOG(DEBUG,
+                                           "QinQ tunnel filter already created.");
+                       pf->qinq_replace_flag = 1;
+               }
+               /*      Add in the General fields the values of
+                *      the Outer and Inner VLAN
+                *      Big Buffer should be set, see changes in
+                *      i40e_aq_add_cloud_filters
+                */
+               pfilter->general_fields[0] = tunnel_filter->inner_vlan;
+               pfilter->general_fields[1] = tunnel_filter->outer_vlan;
+               big_buffer = 1;
                break;
        default:
                /* Other tunnel types is not supported. */
@@ -7155,10 +8269,19 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf,
 
        if (tunnel_filter->tunnel_type == I40E_TUNNEL_TYPE_MPLSoUDP)
                pfilter->element.flags =
-                       I40E_AQC_ADD_CLOUD_FILTER_TEID_MPLSoUDP;
+                       I40E_AQC_ADD_CLOUD_FILTER_0X11;
        else if (tunnel_filter->tunnel_type == I40E_TUNNEL_TYPE_MPLSoGRE)
                pfilter->element.flags =
-                       I40E_AQC_ADD_CLOUD_FILTER_TEID_MPLSoGRE;
+                       I40E_AQC_ADD_CLOUD_FILTER_0X12;
+       else if (tunnel_filter->tunnel_type == I40E_TUNNEL_TYPE_GTPC)
+               pfilter->element.flags =
+                       I40E_AQC_ADD_CLOUD_FILTER_0X11;
+       else if (tunnel_filter->tunnel_type == I40E_TUNNEL_TYPE_GTPU)
+               pfilter->element.flags =
+                       I40E_AQC_ADD_CLOUD_FILTER_0X12;
+       else if (tunnel_filter->tunnel_type == I40E_TUNNEL_TYPE_QINQ)
+               pfilter->element.flags |=
+                       I40E_AQC_ADD_CLOUD_FILTER_0X10;
        else {
                val = i40e_dev_get_filter_type(tunnel_filter->filter_type,
                                                &pfilter->element.flags);
@@ -7180,6 +8303,7 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf,
        else {
                if (tunnel_filter->vf_id >= pf->vf_num) {
                        PMD_DRV_LOG(ERR, "Invalid argument.");
+                       rte_free(cld_filter);
                        return -EINVAL;
                }
                vf = &pf->vfs[tunnel_filter->vf_id];
@@ -7189,40 +8313,54 @@ i40e_dev_consistent_tunnel_filter_set(struct i40e_pf *pf,
        /* Check if there is the filter in SW list */
        memset(&check_filter, 0, sizeof(check_filter));
        i40e_tunnel_filter_convert(cld_filter, &check_filter);
+       check_filter.is_to_vf = tunnel_filter->is_to_vf;
+       check_filter.vf_id = tunnel_filter->vf_id;
        node = i40e_sw_tunnel_filter_lookup(tunnel_rule, &check_filter.input);
        if (add && node) {
                PMD_DRV_LOG(ERR, "Conflict with existing tunnel rules!");
+               rte_free(cld_filter);
                return -EINVAL;
        }
 
        if (!add && !node) {
                PMD_DRV_LOG(ERR, "There's no corresponding tunnel filter!");
+               rte_free(cld_filter);
                return -EINVAL;
        }
 
        if (add) {
                if (big_buffer)
-                       ret = i40e_aq_add_cloud_filters_big_buffer(hw,
+                       ret = i40e_aq_add_cloud_filters_bb(hw,
                                                   vsi->seid, cld_filter, 1);
                else
                        ret = i40e_aq_add_cloud_filters(hw,
                                        vsi->seid, &cld_filter->element, 1);
                if (ret < 0) {
                        PMD_DRV_LOG(ERR, "Failed to add a tunnel filter.");
+                       rte_free(cld_filter);
                        return -ENOTSUP;
                }
                tunnel = rte_zmalloc("tunnel_filter", sizeof(*tunnel), 0);
+               if (tunnel == NULL) {
+                       PMD_DRV_LOG(ERR, "Failed to alloc memory.");
+                       rte_free(cld_filter);
+                       return -ENOMEM;
+               }
+
                rte_memcpy(tunnel, &check_filter, sizeof(check_filter));
                ret = i40e_sw_tunnel_filter_insert(pf, tunnel);
+               if (ret < 0)
+                       rte_free(tunnel);
        } else {
                if (big_buffer)
-                       ret = i40e_aq_remove_cloud_filters_big_buffer(
+                       ret = i40e_aq_rem_cloud_filters_bb(
                                hw, vsi->seid, cld_filter, 1);
                else
-                       ret = i40e_aq_remove_cloud_filters(hw, vsi->seid,
-                                                  &cld_filter->element, 1);
+                       ret = i40e_aq_rem_cloud_filters(hw, vsi->seid,
+                                               &cld_filter->element, 1);
                if (ret < 0) {
                        PMD_DRV_LOG(ERR, "Failed to delete a tunnel filter.");
+                       rte_free(cld_filter);
                        return -ENOTSUP;
                }
                ret = i40e_sw_tunnel_filter_del(pf, &node->input);
@@ -7246,7 +8384,7 @@ i40e_get_vxlan_port_idx(struct i40e_pf *pf, uint16_t port)
 }
 
 static int
-i40e_add_vxlan_port(struct i40e_pf *pf, uint16_t port)
+i40e_add_vxlan_port(struct i40e_pf *pf, uint16_t port, int udp_type)
 {
        int  idx, ret;
        uint8_t filter_idx;
@@ -7269,7 +8407,7 @@ i40e_add_vxlan_port(struct i40e_pf *pf, uint16_t port)
                return -ENOSPC;
        }
 
-       ret =  i40e_aq_add_udp_tunnel(hw, port, I40E_AQC_TUNNEL_TYPE_VXLAN,
+       ret =  i40e_aq_add_udp_tunnel(hw, port, udp_type,
                                        &filter_idx, NULL);
        if (ret < 0) {
                PMD_DRV_LOG(ERR, "Failed to add VXLAN UDP port %d", port);
@@ -7337,9 +8475,13 @@ i40e_dev_udp_tunnel_port_add(struct rte_eth_dev *dev,
 
        switch (udp_tunnel->prot_type) {
        case RTE_TUNNEL_TYPE_VXLAN:
-               ret = i40e_add_vxlan_port(pf, udp_tunnel->udp_port);
+               ret = i40e_add_vxlan_port(pf, udp_tunnel->udp_port,
+                                         I40E_AQC_TUNNEL_TYPE_VXLAN);
+               break;
+       case RTE_TUNNEL_TYPE_VXLAN_GPE:
+               ret = i40e_add_vxlan_port(pf, udp_tunnel->udp_port,
+                                         I40E_AQC_TUNNEL_TYPE_VXLAN_GPE);
                break;
-
        case RTE_TUNNEL_TYPE_GENEVE:
        case RTE_TUNNEL_TYPE_TEREDO:
                PMD_DRV_LOG(ERR, "Tunnel type is not supported now.");
@@ -7368,6 +8510,7 @@ i40e_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
 
        switch (udp_tunnel->prot_type) {
        case RTE_TUNNEL_TYPE_VXLAN:
+       case RTE_TUNNEL_TYPE_VXLAN_GPE:
                ret = i40e_del_vxlan_port(pf, udp_tunnel->udp_port);
                break;
        case RTE_TUNNEL_TYPE_GENEVE:
@@ -7415,7 +8558,7 @@ i40e_pf_config_rss(struct i40e_pf *pf)
 
        /*
         * If both VMDQ and RSS enabled, not all of PF queues are configured.
-        * It's necessary to calulate the actual PF queues that are configured.
+        * It's necessary to calculate the actual PF queues that are configured.
         */
        if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG)
                num = i40e_pf_calc_configured_queues_num(pf);
@@ -7431,17 +8574,20 @@ i40e_pf_config_rss(struct i40e_pf *pf)
                return -ENOTSUP;
        }
 
-       for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) {
-               if (j == num)
-                       j = 0;
-               lut = (lut << 8) | (j & ((0x1 <<
-                       hw->func_caps.rss_table_entry_width) - 1));
-               if ((i & 3) == 3)
-                       I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut);
+       if (pf->adapter->rss_reta_updated == 0) {
+               for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) {
+                       if (j == num)
+                               j = 0;
+                       lut = (lut << 8) | (j & ((0x1 <<
+                               hw->func_caps.rss_table_entry_width) - 1));
+                       if ((i & 3) == 3)
+                               I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2),
+                                              rte_bswap32(lut));
+               }
        }
 
        rss_conf = pf->dev_data->dev_conf.rx_adv_conf.rss_conf;
-       if ((rss_conf.rss_hf & I40E_RSS_OFFLOAD_ALL) == 0) {
+       if ((rss_conf.rss_hf & pf->adapter->flow_types_mask) == 0) {
                i40e_pf_disable_rss(pf);
                return 0;
        }
@@ -7500,9 +8646,15 @@ i40e_tunnel_filter_param_check(struct i40e_pf *pf,
 static int
 i40e_dev_set_gre_key_len(struct i40e_hw *hw, uint8_t len)
 {
+       struct i40e_pf *pf = &((struct i40e_adapter *)hw->back)->pf;
        uint32_t val, reg;
        int ret = -EINVAL;
 
+       if (pf->support_multi_driver) {
+               PMD_DRV_LOG(ERR, "GRE key length configuration is unsupported");
+               return -ENOTSUP;
+       }
+
        val = I40E_READ_REG(hw, I40E_GL_PRS_FVBM(2));
        PMD_DRV_LOG(DEBUG, "Read original GL_PRS_FVBM with 0x%08x", val);
 
@@ -7516,10 +8668,14 @@ i40e_dev_set_gre_key_len(struct i40e_hw *hw, uint8_t len)
        }
 
        if (reg != val) {
-               ret = i40e_aq_debug_write_register(hw, I40E_GL_PRS_FVBM(2),
+               ret = i40e_aq_debug_write_global_register(hw,
+                                                  I40E_GL_PRS_FVBM(2),
                                                   reg, NULL);
                if (ret != 0)
                        return ret;
+               PMD_DRV_LOG(DEBUG, "Global register 0x%08x is changed "
+                           "with value 0x%08x",
+                           I40E_GL_PRS_FVBM(2), reg);
        } else {
                ret = 0;
        }
@@ -7662,9 +8818,9 @@ static int
 i40e_get_hash_filter_global_config(struct i40e_hw *hw,
                                   struct rte_eth_hash_global_conf *g_cfg)
 {
-       uint32_t reg, mask = I40E_FLOW_TYPES;
-       uint16_t i;
-       enum i40e_filter_pctype pctype;
+       struct i40e_adapter *adapter = (struct i40e_adapter *)hw->back;
+       uint32_t reg;
+       uint16_t i, j;
 
        memset(g_cfg, 0, sizeof(*g_cfg));
        reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL);
@@ -7675,29 +8831,41 @@ i40e_get_hash_filter_global_config(struct i40e_hw *hw,
        PMD_DRV_LOG(DEBUG, "Hash function is %s",
                (reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
 
-       for (i = 0; mask && i < RTE_ETH_FLOW_MAX; i++) {
-               if (!(mask & (1UL << i)))
-                       continue;
-               mask &= ~(1UL << i);
-               /* Bit set indicats the coresponding flow type is supported */
-               g_cfg->valid_bit_mask[0] |= (1UL << i);
-               /* if flowtype is invalid, continue */
-               if (!I40E_VALID_FLOW(i))
+       /*
+        * As i40e supports less than 64 flow types, only first 64 bits need to
+        * be checked.
+        */
+       for (i = 1; i < RTE_SYM_HASH_MASK_ARRAY_SIZE; i++) {
+               g_cfg->valid_bit_mask[i] = 0ULL;
+               g_cfg->sym_hash_enable_mask[i] = 0ULL;
+       }
+
+       g_cfg->valid_bit_mask[0] = adapter->flow_types_mask;
+
+       for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < UINT64_BIT; i++) {
+               if (!adapter->pctypes_tbl[i])
                        continue;
-               pctype = i40e_flowtype_to_pctype(i);
-               reg = i40e_read_rx_ctl(hw, I40E_GLQF_HSYM(pctype));
-               if (reg & I40E_GLQF_HSYM_SYMH_ENA_MASK)
-                       g_cfg->sym_hash_enable_mask[0] |= (1UL << i);
+               for (j = I40E_FILTER_PCTYPE_INVALID + 1;
+                    j < I40E_FILTER_PCTYPE_MAX; j++) {
+                       if (adapter->pctypes_tbl[i] & (1ULL << j)) {
+                               reg = i40e_read_rx_ctl(hw, I40E_GLQF_HSYM(j));
+                               if (reg & I40E_GLQF_HSYM_SYMH_ENA_MASK) {
+                                       g_cfg->sym_hash_enable_mask[0] |=
+                                                               (1ULL << i);
+                               }
+                       }
+               }
        }
 
        return 0;
 }
 
 static int
-i40e_hash_global_config_check(struct rte_eth_hash_global_conf *g_cfg)
+i40e_hash_global_config_check(const struct i40e_adapter *adapter,
+                             const struct rte_eth_hash_global_conf *g_cfg)
 {
        uint32_t i;
-       uint32_t mask0, i40e_mask = I40E_FLOW_TYPES;
+       uint64_t mask0, i40e_mask = adapter->flow_types_mask;
 
        if (g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_TOEPLITZ &&
                g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_SIMPLE_XOR &&
@@ -7708,7 +8876,7 @@ i40e_hash_global_config_check(struct rte_eth_hash_global_conf *g_cfg)
        }
 
        /*
-        * As i40e supports less than 32 flow types, only first 32 bits need to
+        * As i40e supports less than 64 flow types, only first 64 bits need to
         * be checked.
         */
        mask0 = g_cfg->valid_bit_mask[0];
@@ -7740,28 +8908,40 @@ static int
 i40e_set_hash_filter_global_config(struct i40e_hw *hw,
                                   struct rte_eth_hash_global_conf *g_cfg)
 {
+       struct i40e_adapter *adapter = (struct i40e_adapter *)hw->back;
+       struct i40e_pf *pf = &((struct i40e_adapter *)hw->back)->pf;
        int ret;
-       uint16_t i;
+       uint16_t i, j;
        uint32_t reg;
-       uint32_t mask0 = g_cfg->valid_bit_mask[0];
-       enum i40e_filter_pctype pctype;
+       uint64_t mask0 = g_cfg->valid_bit_mask[0] & adapter->flow_types_mask;
+
+       if (pf->support_multi_driver) {
+               PMD_DRV_LOG(ERR, "Hash global configuration is not supported.");
+               return -ENOTSUP;
+       }
 
        /* Check the input parameters */
-       ret = i40e_hash_global_config_check(g_cfg);
+       ret = i40e_hash_global_config_check(adapter, g_cfg);
        if (ret < 0)
                return ret;
 
-       for (i = 0; mask0 && i < UINT32_BIT; i++) {
-               if (!(mask0 & (1UL << i)))
-                       continue;
-               mask0 &= ~(1UL << i);
-               /* if flowtype is invalid, continue */
-               if (!I40E_VALID_FLOW(i))
-                       continue;
-               pctype = i40e_flowtype_to_pctype(i);
-               reg = (g_cfg->sym_hash_enable_mask[0] & (1UL << i)) ?
-                               I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
-               i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(pctype), reg);
+       /*
+        * As i40e supports less than 64 flow types, only first 64 bits need to
+        * be configured.
+        */
+       for (i = RTE_ETH_FLOW_UNKNOWN + 1; mask0 && i < UINT64_BIT; i++) {
+               if (mask0 & (1UL << i)) {
+                       reg = (g_cfg->sym_hash_enable_mask[0] & (1ULL << i)) ?
+                                       I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
+
+                       for (j = I40E_FILTER_PCTYPE_INVALID + 1;
+                            j < I40E_FILTER_PCTYPE_MAX; j++) {
+                               if (adapter->pctypes_tbl[i] & (1ULL << j))
+                                       i40e_write_global_rx_ctl(hw,
+                                                         I40E_GLQF_HSYM(j),
+                                                         reg);
+                       }
+               }
        }
 
        reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL);
@@ -7785,7 +8965,7 @@ i40e_set_hash_filter_global_config(struct i40e_hw *hw,
                /* Use the default, and keep it as it is */
                goto out;
 
-       i40e_write_rx_ctl(hw, I40E_GLQF_CTL, reg);
+       i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg);
 
 out:
        I40E_WRITE_FLUSH(hw);
@@ -8054,7 +9234,7 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
 /**
  * Validate if the input set is allowed for a specific PCTYPE
  */
-static int
+int
 i40e_validate_input_set(enum i40e_filter_pctype pctype,
                enum rte_filter_type filter, uint64_t inset)
 {
@@ -8229,7 +9409,7 @@ i40e_parse_input_set(uint64_t *inset,
  * Translate the input set from bit masks to register aware bit masks
  * and vice versa
  */
-static uint64_t
+uint64_t
 i40e_translate_input_set_reg(enum i40e_mac_type type, uint64_t input)
 {
        uint64_t val = 0;
@@ -8314,7 +9494,7 @@ i40e_translate_input_set_reg(enum i40e_mac_type type, uint64_t input)
        return val;
 }
 
-static int
+int
 i40e_generate_inset_mask_reg(uint64_t inset, uint32_t *mask, uint8_t nb_elem)
 {
        uint8_t i, idx = 0;
@@ -8362,7 +9542,7 @@ i40e_generate_inset_mask_reg(uint64_t inset, uint32_t *mask, uint8_t nb_elem)
        return idx;
 }
 
-static void
+void
 i40e_check_write_reg(struct i40e_hw *hw, uint32_t addr, uint32_t val)
 {
        uint32_t reg = i40e_read_rx_ctl(hw, addr);
@@ -8374,6 +9554,23 @@ i40e_check_write_reg(struct i40e_hw *hw, uint32_t addr, uint32_t val)
                    (uint32_t)i40e_read_rx_ctl(hw, addr));
 }
 
+void
+i40e_check_write_global_reg(struct i40e_hw *hw, uint32_t addr, uint32_t val)
+{
+       uint32_t reg = i40e_read_rx_ctl(hw, addr);
+       struct rte_eth_dev *dev;
+
+       dev = ((struct i40e_adapter *)hw->back)->eth_dev;
+       if (reg != val) {
+               i40e_write_rx_ctl(hw, addr, val);
+               PMD_DRV_LOG(WARNING,
+                           "i40e device %s changed global register [0x%08x]."
+                           " original: 0x%08x, new: 0x%08x",
+                           dev->device->name, addr, reg,
+                           (uint32_t)i40e_read_rx_ctl(hw, addr));
+       }
+}
+
 static void
 i40e_filter_input_set_init(struct i40e_pf *pf)
 {
@@ -8382,16 +9579,14 @@ i40e_filter_input_set_init(struct i40e_pf *pf)
        uint64_t input_set, inset_reg;
        uint32_t mask_reg[I40E_INSET_MASK_NUM_REG] = {0};
        int num, i;
+       uint16_t flow_type;
 
        for (pctype = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
             pctype <= I40E_FILTER_PCTYPE_L2_PAYLOAD; pctype++) {
-               if (hw->mac.type == I40E_MAC_X722) {
-                       if (!I40E_VALID_PCTYPE_X722(pctype))
-                               continue;
-               } else {
-                       if (!I40E_VALID_PCTYPE(pctype))
-                               continue;
-               }
+               flow_type = i40e_pctype_to_flowtype(pf->adapter, pctype);
+
+               if (flow_type == RTE_ETH_FLOW_UNKNOWN)
+                       continue;
 
                input_set = i40e_get_default_input_set(pctype);
 
@@ -8399,6 +9594,10 @@ i40e_filter_input_set_init(struct i40e_pf *pf)
                                                   I40E_INSET_MASK_NUM_REG);
                if (num < 0)
                        return;
+               if (pf->support_multi_driver && num > 0) {
+                       PMD_DRV_LOG(ERR, "Input set setting is not supported.");
+                       return;
+               }
                inset_reg = i40e_translate_input_set_reg(hw->mac.type,
                                        input_set);
 
@@ -8407,29 +9606,40 @@ i40e_filter_input_set_init(struct i40e_pf *pf)
                i40e_check_write_reg(hw, I40E_PRTQF_FD_INSET(pctype, 1),
                                     (uint32_t)((inset_reg >>
                                     I40E_32_BIT_WIDTH) & UINT32_MAX));
-               i40e_check_write_reg(hw, I40E_GLQF_HASH_INSET(0, pctype),
-                                     (uint32_t)(inset_reg & UINT32_MAX));
-               i40e_check_write_reg(hw, I40E_GLQF_HASH_INSET(1, pctype),
-                                    (uint32_t)((inset_reg >>
-                                    I40E_32_BIT_WIDTH) & UINT32_MAX));
-
-               for (i = 0; i < num; i++) {
-                       i40e_check_write_reg(hw, I40E_GLQF_FD_MSK(i, pctype),
-                                            mask_reg[i]);
-                       i40e_check_write_reg(hw, I40E_GLQF_HASH_MSK(i, pctype),
-                                            mask_reg[i]);
-               }
-               /*clear unused mask registers of the pctype */
-               for (i = num; i < I40E_INSET_MASK_NUM_REG; i++) {
-                       i40e_check_write_reg(hw, I40E_GLQF_FD_MSK(i, pctype),
-                                            0);
-                       i40e_check_write_reg(hw, I40E_GLQF_HASH_MSK(i, pctype),
-                                            0);
+               if (!pf->support_multi_driver) {
+                       i40e_check_write_global_reg(hw,
+                                           I40E_GLQF_HASH_INSET(0, pctype),
+                                           (uint32_t)(inset_reg & UINT32_MAX));
+                       i40e_check_write_global_reg(hw,
+                                            I40E_GLQF_HASH_INSET(1, pctype),
+                                            (uint32_t)((inset_reg >>
+                                             I40E_32_BIT_WIDTH) & UINT32_MAX));
+
+                       for (i = 0; i < num; i++) {
+                               i40e_check_write_global_reg(hw,
+                                                   I40E_GLQF_FD_MSK(i, pctype),
+                                                   mask_reg[i]);
+                               i40e_check_write_global_reg(hw,
+                                                 I40E_GLQF_HASH_MSK(i, pctype),
+                                                 mask_reg[i]);
+                       }
+                       /*clear unused mask registers of the pctype */
+                       for (i = num; i < I40E_INSET_MASK_NUM_REG; i++) {
+                               i40e_check_write_global_reg(hw,
+                                                   I40E_GLQF_FD_MSK(i, pctype),
+                                                   0);
+                               i40e_check_write_global_reg(hw,
+                                                 I40E_GLQF_HASH_MSK(i, pctype),
+                                                 0);
+                       }
+               } else {
+                       PMD_DRV_LOG(ERR, "Input set setting is not supported.");
                }
                I40E_WRITE_FLUSH(hw);
 
                /* store the default input set */
-               pf->hash_input_set[pctype] = input_set;
+               if (!pf->support_multi_driver)
+                       pf->hash_input_set[pctype] = input_set;
                pf->fdir.input_set[pctype] = input_set;
        }
 }
@@ -8454,7 +9664,13 @@ i40e_hash_filter_inset_select(struct i40e_hw *hw,
                return -EINVAL;
        }
 
-       if (!I40E_VALID_FLOW(conf->flow_type)) {
+       if (pf->support_multi_driver) {
+               PMD_DRV_LOG(ERR, "Hash input set setting is not supported.");
+               return -ENOTSUP;
+       }
+
+       pctype = i40e_flowtype_to_pctype(pf->adapter, conf->flow_type);
+       if (pctype == I40E_FILTER_PCTYPE_INVALID) {
                PMD_DRV_LOG(ERR, "invalid flow_type input.");
                return -EINVAL;
        }
@@ -8462,10 +9678,8 @@ i40e_hash_filter_inset_select(struct i40e_hw *hw,
        if (hw->mac.type == I40E_MAC_X722) {
                /* get translated pctype value in fd pctype register */
                pctype = (enum i40e_filter_pctype)i40e_read_rx_ctl(hw,
-                       I40E_GLQF_FD_PCTYPES((int)i40e_flowtype_to_pctype(
-                       conf->flow_type)));
-       } else
-               pctype = i40e_flowtype_to_pctype(conf->flow_type);
+                       I40E_GLQF_FD_PCTYPES((int)pctype));
+       }
 
        ret = i40e_parse_input_set(&input_set, pctype, conf->field,
                                   conf->inset_size);
@@ -8473,11 +9687,7 @@ i40e_hash_filter_inset_select(struct i40e_hw *hw,
                PMD_DRV_LOG(ERR, "Failed to parse input set");
                return -EINVAL;
        }
-       if (i40e_validate_input_set(pctype, RTE_ETH_FILTER_HASH,
-                                   input_set) != 0) {
-               PMD_DRV_LOG(ERR, "Invalid input set");
-               return -EINVAL;
-       }
+
        if (conf->op == RTE_ETH_INPUT_SET_ADD) {
                /* get inset value in register */
                inset_reg = i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, pctype));
@@ -8492,19 +9702,19 @@ i40e_hash_filter_inset_select(struct i40e_hw *hw,
 
        inset_reg |= i40e_translate_input_set_reg(hw->mac.type, input_set);
 
-       i40e_check_write_reg(hw, I40E_GLQF_HASH_INSET(0, pctype),
-                             (uint32_t)(inset_reg & UINT32_MAX));
-       i40e_check_write_reg(hw, I40E_GLQF_HASH_INSET(1, pctype),
-                            (uint32_t)((inset_reg >>
-                            I40E_32_BIT_WIDTH) & UINT32_MAX));
+       i40e_check_write_global_reg(hw, I40E_GLQF_HASH_INSET(0, pctype),
+                                   (uint32_t)(inset_reg & UINT32_MAX));
+       i40e_check_write_global_reg(hw, I40E_GLQF_HASH_INSET(1, pctype),
+                                   (uint32_t)((inset_reg >>
+                                   I40E_32_BIT_WIDTH) & UINT32_MAX));
 
        for (i = 0; i < num; i++)
-               i40e_check_write_reg(hw, I40E_GLQF_HASH_MSK(i, pctype),
-                                    mask_reg[i]);
+               i40e_check_write_global_reg(hw, I40E_GLQF_HASH_MSK(i, pctype),
+                                           mask_reg[i]);
        /*clear unused mask registers of the pctype */
        for (i = num; i < I40E_INSET_MASK_NUM_REG; i++)
-               i40e_check_write_reg(hw, I40E_GLQF_HASH_MSK(i, pctype),
-                                    0);
+               i40e_check_write_global_reg(hw, I40E_GLQF_HASH_MSK(i, pctype),
+                                           0);
        I40E_WRITE_FLUSH(hw);
 
        pf->hash_input_set[pctype] = input_set;
@@ -8531,24 +9741,19 @@ i40e_fdir_filter_inset_select(struct i40e_pf *pf,
                return -EINVAL;
        }
 
-       if (!I40E_VALID_FLOW(conf->flow_type)) {
+       pctype = i40e_flowtype_to_pctype(pf->adapter, conf->flow_type);
+
+       if (pctype == I40E_FILTER_PCTYPE_INVALID) {
                PMD_DRV_LOG(ERR, "invalid flow_type input.");
                return -EINVAL;
        }
 
-       pctype = i40e_flowtype_to_pctype(conf->flow_type);
-
        ret = i40e_parse_input_set(&input_set, pctype, conf->field,
                                   conf->inset_size);
        if (ret) {
                PMD_DRV_LOG(ERR, "Failed to parse input set");
                return -EINVAL;
        }
-       if (i40e_validate_input_set(pctype, RTE_ETH_FILTER_FDIR,
-                                   input_set) != 0) {
-               PMD_DRV_LOG(ERR, "Invalid input set");
-               return -EINVAL;
-       }
 
        /* get inset value in register */
        inset_reg = i40e_read_rx_ctl(hw, I40E_PRTQF_FD_INSET(pctype, 1));
@@ -8567,6 +9772,10 @@ i40e_fdir_filter_inset_select(struct i40e_pf *pf,
                                           I40E_INSET_MASK_NUM_REG);
        if (num < 0)
                return -EINVAL;
+       if (pf->support_multi_driver && num > 0) {
+               PMD_DRV_LOG(ERR, "FDIR bit mask is not supported.");
+               return -ENOTSUP;
+       }
 
        inset_reg |= i40e_translate_input_set_reg(hw->mac.type, input_set);
 
@@ -8576,13 +9785,19 @@ i40e_fdir_filter_inset_select(struct i40e_pf *pf,
                             (uint32_t)((inset_reg >>
                             I40E_32_BIT_WIDTH) & UINT32_MAX));
 
-       for (i = 0; i < num; i++)
-               i40e_check_write_reg(hw, I40E_GLQF_FD_MSK(i, pctype),
-                                    mask_reg[i]);
-       /*clear unused mask registers of the pctype */
-       for (i = num; i < I40E_INSET_MASK_NUM_REG; i++)
-               i40e_check_write_reg(hw, I40E_GLQF_FD_MSK(i, pctype),
-                                    0);
+       if (!pf->support_multi_driver) {
+               for (i = 0; i < num; i++)
+                       i40e_check_write_global_reg(hw,
+                                                   I40E_GLQF_FD_MSK(i, pctype),
+                                                   mask_reg[i]);
+               /*clear unused mask registers of the pctype */
+               for (i = num; i < I40E_INSET_MASK_NUM_REG; i++)
+                       i40e_check_write_global_reg(hw,
+                                                   I40E_GLQF_FD_MSK(i, pctype),
+                                                   0);
+       } else {
+               PMD_DRV_LOG(ERR, "FDIR bit mask is not supported.");
+       }
        I40E_WRITE_FLUSH(hw);
 
        pf->fdir.input_set[pctype] = input_set;
@@ -8828,9 +10043,16 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
        if (add) {
                ethertype_filter = rte_zmalloc("ethertype_filter",
                                       sizeof(*ethertype_filter), 0);
+               if (ethertype_filter == NULL) {
+                       PMD_DRV_LOG(ERR, "Failed to alloc memory.");
+                       return -ENOMEM;
+               }
+
                rte_memcpy(ethertype_filter, &check_filter,
                           sizeof(check_filter));
                ret = i40e_sw_ethertype_filter_insert(pf, ethertype_filter);
+               if (ret < 0)
+                       rte_free(ethertype_filter);
        } else {
                ret = i40e_sw_ethertype_filter_del(pf, &node->input);
        }
@@ -8930,11 +10152,11 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 static void
 i40e_enable_extended_tag(struct rte_eth_dev *dev)
 {
-       struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        uint32_t buf = 0;
        int ret;
 
-       ret = rte_eal_pci_read_config(pci_dev, &buf, sizeof(buf),
+       ret = rte_pci_read_config(pci_dev, &buf, sizeof(buf),
                                      PCI_DEV_CAP_REG);
        if (ret < 0) {
                PMD_DRV_LOG(ERR, "Failed to read PCI offset 0x%x",
@@ -8947,7 +10169,7 @@ i40e_enable_extended_tag(struct rte_eth_dev *dev)
        }
 
        buf = 0;
-       ret = rte_eal_pci_read_config(pci_dev, &buf, sizeof(buf),
+       ret = rte_pci_read_config(pci_dev, &buf, sizeof(buf),
                                      PCI_DEV_CTRL_REG);
        if (ret < 0) {
                PMD_DRV_LOG(ERR, "Failed to read PCI offset 0x%x",
@@ -8959,7 +10181,7 @@ i40e_enable_extended_tag(struct rte_eth_dev *dev)
                return;
        }
        buf |= PCI_DEV_CTRL_EXT_TAG_MASK;
-       ret = rte_eal_pci_write_config(pci_dev, &buf, sizeof(buf),
+       ret = rte_pci_write_config(pci_dev, &buf, sizeof(buf),
                                       PCI_DEV_CTRL_REG);
        if (ret < 0) {
                PMD_DRV_LOG(ERR, "Failed to write PCI offset 0x%x",
@@ -8987,72 +10209,42 @@ i40e_hw_init(struct rte_eth_dev *dev)
        i40e_set_symmetric_hash_enable_per_port(hw, 0);
 }
 
+/*
+ * For X722 it is possible to have multiple pctypes mapped to the same flowtype
+ * however this function will return only one highest pctype index,
+ * which is not quite correct. This is known problem of i40e driver
+ * and needs to be fixed later.
+ */
 enum i40e_filter_pctype
-i40e_flowtype_to_pctype(uint16_t flow_type)
-{
-       static const enum i40e_filter_pctype pctype_table[] = {
-               [RTE_ETH_FLOW_FRAG_IPV4] = I40E_FILTER_PCTYPE_FRAG_IPV4,
-               [RTE_ETH_FLOW_NONFRAG_IPV4_UDP] =
-                       I40E_FILTER_PCTYPE_NONF_IPV4_UDP,
-               [RTE_ETH_FLOW_NONFRAG_IPV4_TCP] =
-                       I40E_FILTER_PCTYPE_NONF_IPV4_TCP,
-               [RTE_ETH_FLOW_NONFRAG_IPV4_SCTP] =
-                       I40E_FILTER_PCTYPE_NONF_IPV4_SCTP,
-               [RTE_ETH_FLOW_NONFRAG_IPV4_OTHER] =
-                       I40E_FILTER_PCTYPE_NONF_IPV4_OTHER,
-               [RTE_ETH_FLOW_FRAG_IPV6] = I40E_FILTER_PCTYPE_FRAG_IPV6,
-               [RTE_ETH_FLOW_NONFRAG_IPV6_UDP] =
-                       I40E_FILTER_PCTYPE_NONF_IPV6_UDP,
-               [RTE_ETH_FLOW_NONFRAG_IPV6_TCP] =
-                       I40E_FILTER_PCTYPE_NONF_IPV6_TCP,
-               [RTE_ETH_FLOW_NONFRAG_IPV6_SCTP] =
-                       I40E_FILTER_PCTYPE_NONF_IPV6_SCTP,
-               [RTE_ETH_FLOW_NONFRAG_IPV6_OTHER] =
-                       I40E_FILTER_PCTYPE_NONF_IPV6_OTHER,
-               [RTE_ETH_FLOW_L2_PAYLOAD] = I40E_FILTER_PCTYPE_L2_PAYLOAD,
-       };
+i40e_flowtype_to_pctype(const struct i40e_adapter *adapter, uint16_t flow_type)
+{
+       int i;
+       uint64_t pctype_mask;
 
-       return pctype_table[flow_type];
+       if (flow_type < I40E_FLOW_TYPE_MAX) {
+               pctype_mask = adapter->pctypes_tbl[flow_type];
+               for (i = I40E_FILTER_PCTYPE_MAX - 1; i > 0; i--) {
+                       if (pctype_mask & (1ULL << i))
+                               return (enum i40e_filter_pctype)i;
+               }
+       }
+       return I40E_FILTER_PCTYPE_INVALID;
 }
 
 uint16_t
-i40e_pctype_to_flowtype(enum i40e_filter_pctype pctype)
+i40e_pctype_to_flowtype(const struct i40e_adapter *adapter,
+                       enum i40e_filter_pctype pctype)
 {
-       static const uint16_t flowtype_table[] = {
-               [I40E_FILTER_PCTYPE_FRAG_IPV4] = RTE_ETH_FLOW_FRAG_IPV4,
-               [I40E_FILTER_PCTYPE_NONF_IPV4_UDP] =
-                       RTE_ETH_FLOW_NONFRAG_IPV4_UDP,
-               [I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP] =
-                       RTE_ETH_FLOW_NONFRAG_IPV4_UDP,
-               [I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP] =
-                       RTE_ETH_FLOW_NONFRAG_IPV4_UDP,
-               [I40E_FILTER_PCTYPE_NONF_IPV4_TCP] =
-                       RTE_ETH_FLOW_NONFRAG_IPV4_TCP,
-               [I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK] =
-                       RTE_ETH_FLOW_NONFRAG_IPV4_TCP,
-               [I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] =
-                       RTE_ETH_FLOW_NONFRAG_IPV4_SCTP,
-               [I40E_FILTER_PCTYPE_NONF_IPV4_OTHER] =
-                       RTE_ETH_FLOW_NONFRAG_IPV4_OTHER,
-               [I40E_FILTER_PCTYPE_FRAG_IPV6] = RTE_ETH_FLOW_FRAG_IPV6,
-               [I40E_FILTER_PCTYPE_NONF_IPV6_UDP] =
-                       RTE_ETH_FLOW_NONFRAG_IPV6_UDP,
-               [I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP] =
-                       RTE_ETH_FLOW_NONFRAG_IPV6_UDP,
-               [I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP] =
-                       RTE_ETH_FLOW_NONFRAG_IPV6_UDP,
-               [I40E_FILTER_PCTYPE_NONF_IPV6_TCP] =
-                       RTE_ETH_FLOW_NONFRAG_IPV6_TCP,
-               [I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK] =
-                       RTE_ETH_FLOW_NONFRAG_IPV6_TCP,
-               [I40E_FILTER_PCTYPE_NONF_IPV6_SCTP] =
-                       RTE_ETH_FLOW_NONFRAG_IPV6_SCTP,
-               [I40E_FILTER_PCTYPE_NONF_IPV6_OTHER] =
-                       RTE_ETH_FLOW_NONFRAG_IPV6_OTHER,
-               [I40E_FILTER_PCTYPE_L2_PAYLOAD] = RTE_ETH_FLOW_L2_PAYLOAD,
-       };
+       uint16_t flowtype;
+       uint64_t pctype_mask = 1ULL << pctype;
 
-       return flowtype_table[pctype];
+       for (flowtype = RTE_ETH_FLOW_UNKNOWN + 1; flowtype < I40E_FLOW_TYPE_MAX;
+            flowtype++) {
+               if (adapter->pctypes_tbl[flowtype] & pctype_mask)
+                       return flowtype;
+       }
+
+       return RTE_ETH_FLOW_UNKNOWN;
 }
 
 /*
@@ -9068,8 +10260,9 @@ i40e_pctype_to_flowtype(enum i40e_filter_pctype pctype)
  */
 
 /* For both X710 and XL710 */
-#define I40E_GL_SWR_PRI_JOIN_MAP_0_VALUE 0x10000200
-#define I40E_GL_SWR_PRI_JOIN_MAP_0       0x26CE00
+#define I40E_GL_SWR_PRI_JOIN_MAP_0_VALUE_1     0x10000200
+#define I40E_GL_SWR_PRI_JOIN_MAP_0_VALUE_2     0x203F0200
+#define I40E_GL_SWR_PRI_JOIN_MAP_0             0x26CE00
 
 #define I40E_GL_SWR_PRI_JOIN_MAP_2_VALUE 0x011f0200
 #define I40E_GL_SWR_PRI_JOIN_MAP_2       0x26CE08
@@ -9084,19 +10277,82 @@ i40e_pctype_to_flowtype(enum i40e_filter_pctype pctype)
 #define I40E_GL_SWR_PM_UP_THR_SF_VALUE   0x06060606
 #define I40E_GL_SWR_PM_UP_THR            0x269FBC
 
+/*
+ * GL_SWR_PM_UP_THR:
+ * The value is not impacted from the link speed, its value is set according
+ * to the total number of ports for a better pipe-monitor configuration.
+ */
+static bool
+i40e_get_swr_pm_cfg(struct i40e_hw *hw, uint32_t *value)
+{
+#define I40E_GL_SWR_PM_EF_DEVICE(dev) \
+               .device_id = (dev),   \
+               .val = I40E_GL_SWR_PM_UP_THR_EF_VALUE
+
+#define I40E_GL_SWR_PM_SF_DEVICE(dev) \
+               .device_id = (dev),   \
+               .val = I40E_GL_SWR_PM_UP_THR_SF_VALUE
+
+       static const struct {
+               uint16_t device_id;
+               uint32_t val;
+       } swr_pm_table[] = {
+               { I40E_GL_SWR_PM_EF_DEVICE(I40E_DEV_ID_SFP_XL710) },
+               { I40E_GL_SWR_PM_EF_DEVICE(I40E_DEV_ID_KX_C) },
+               { I40E_GL_SWR_PM_EF_DEVICE(I40E_DEV_ID_10G_BASE_T) },
+               { I40E_GL_SWR_PM_EF_DEVICE(I40E_DEV_ID_10G_BASE_T4) },
+
+               { I40E_GL_SWR_PM_SF_DEVICE(I40E_DEV_ID_KX_B) },
+               { I40E_GL_SWR_PM_SF_DEVICE(I40E_DEV_ID_QSFP_A) },
+               { I40E_GL_SWR_PM_SF_DEVICE(I40E_DEV_ID_QSFP_B) },
+               { I40E_GL_SWR_PM_SF_DEVICE(I40E_DEV_ID_20G_KR2) },
+               { I40E_GL_SWR_PM_SF_DEVICE(I40E_DEV_ID_20G_KR2_A) },
+               { I40E_GL_SWR_PM_SF_DEVICE(I40E_DEV_ID_25G_B) },
+               { I40E_GL_SWR_PM_SF_DEVICE(I40E_DEV_ID_25G_SFP28) },
+       };
+       uint32_t i;
+
+       if (value == NULL) {
+               PMD_DRV_LOG(ERR, "value is NULL");
+               return false;
+       }
+
+       for (i = 0; i < RTE_DIM(swr_pm_table); i++) {
+               if (hw->device_id == swr_pm_table[i].device_id) {
+                       *value = swr_pm_table[i].val;
+
+                       PMD_DRV_LOG(DEBUG, "Device 0x%x with GL_SWR_PM_UP_THR "
+                                   "value - 0x%08x",
+                                   hw->device_id, *value);
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 static int
 i40e_dev_sync_phy_type(struct i40e_hw *hw)
 {
        enum i40e_status_code status;
        struct i40e_aq_get_phy_abilities_resp phy_ab;
        int ret = -ENOTSUP;
+       int retries = 0;
 
        status = i40e_aq_get_phy_capabilities(hw, false, true, &phy_ab,
                                              NULL);
 
-       if (status)
-               return ret;
-
+       while (status) {
+               PMD_INIT_LOG(WARNING, "Failed to sync phy type: status=%d",
+                       status);
+               retries++;
+               rte_delay_us(100000);
+               if  (retries < 5)
+                       status = i40e_aq_get_phy_capabilities(hw, false,
+                                       true, &phy_ab, NULL);
+               else
+                       return ret;
+       }
        return 0;
 }
 
@@ -9121,8 +10377,12 @@ i40e_configure_registers(struct i40e_hw *hw)
                                reg_table[i].val =
                                        I40E_X722_GL_SWR_PRI_JOIN_MAP_0_VALUE;
                        else /* For X710/XL710/XXV710 */
-                               reg_table[i].val =
-                                       I40E_GL_SWR_PRI_JOIN_MAP_0_VALUE;
+                               if (hw->aq.fw_maj_ver < 6)
+                                       reg_table[i].val =
+                                            I40E_GL_SWR_PRI_JOIN_MAP_0_VALUE_1;
+                               else
+                                       reg_table[i].val =
+                                            I40E_GL_SWR_PRI_JOIN_MAP_0_VALUE_2;
                }
 
                if (reg_table[i].addr == I40E_GL_SWR_PRI_JOIN_MAP_2) {
@@ -9135,13 +10395,16 @@ i40e_configure_registers(struct i40e_hw *hw)
                }
 
                if (reg_table[i].addr == I40E_GL_SWR_PM_UP_THR) {
-                       if (I40E_PHY_TYPE_SUPPORT_40G(hw->phy.phy_types) || /* For XL710 */
-                           I40E_PHY_TYPE_SUPPORT_25G(hw->phy.phy_types)) /* For XXV710 */
-                               reg_table[i].val =
-                                       I40E_GL_SWR_PM_UP_THR_SF_VALUE;
-                       else /* For X710 */
-                               reg_table[i].val =
-                                       I40E_GL_SWR_PM_UP_THR_EF_VALUE;
+                       uint32_t cfg_val;
+
+                       if (!i40e_get_swr_pm_cfg(hw, &cfg_val)) {
+                               PMD_DRV_LOG(DEBUG, "Device 0x%x skips "
+                                           "GL_SWR_PM_UP_THR value fixup",
+                                           hw->device_id);
+                               continue;
+                       }
+
+                       reg_table[i].val = cfg_val;
                }
 
                ret = i40e_aq_debug_read_register(hw, reg_table[i].addr,
@@ -9583,12 +10846,12 @@ i40e_start_timecounters(struct rte_eth_dev *dev)
        uint32_t tsync_inc_h;
 
        /* Get current link speed. */
-       memset(&link, 0, sizeof(link));
        i40e_dev_link_update(dev, 1);
-       rte_i40e_dev_atomic_read_link_status(dev, &link);
+       rte_eth_linkstatus_get(dev, &link);
 
        switch (link.link_speed) {
        case ETH_SPEED_NUM_40G:
+       case ETH_SPEED_NUM_25G:
                tsync_inc_l = I40E_PTP_40GB_INCVAL & 0xFFFFFFFF;
                tsync_inc_h = I40E_PTP_40GB_INCVAL >> 32;
                break;
@@ -10065,9 +11328,9 @@ i40e_vsi_config_tc(struct i40e_vsi *vsi, uint8_t tc_map)
                goto out;
        }
        /* update the local VSI info with updated queue map */
-       (void)rte_memcpy(&vsi->info.tc_mapping, &ctxt.info.tc_mapping,
+       rte_memcpy(&vsi->info.tc_mapping, &ctxt.info.tc_mapping,
                                        sizeof(vsi->info.tc_mapping));
-       (void)rte_memcpy(&vsi->info.queue_mapping,
+       rte_memcpy(&vsi->info.queue_mapping,
                        &ctxt.info.queue_mapping,
                sizeof(vsi->info.queue_mapping));
        vsi->info.mapping_flags = ctxt.info.mapping_flags;
@@ -10194,7 +11457,7 @@ i40e_dcb_hw_configure(struct i40e_pf *pf,
  *
  * Returns 0 on success, negative value on failure
  */
-static int
+int
 i40e_dcb_init_configure(struct rte_eth_dev *dev, bool sw_dcb)
 {
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
@@ -10211,6 +11474,12 @@ i40e_dcb_init_configure(struct rte_eth_dev *dev, bool sw_dcb)
         * LLDP MIB change event.
         */
        if (sw_dcb == TRUE) {
+               if (i40e_need_stop_lldp(dev)) {
+                       ret = i40e_aq_stop_lldp(hw, TRUE, NULL);
+                       if (ret != I40E_SUCCESS)
+                               PMD_INIT_LOG(DEBUG, "Failed to stop lldp");
+               }
+
                ret = i40e_init_dcb(hw);
                /* If lldp agent is stopped, the return value from
                 * i40e_init_dcb we expect is failure with I40E_AQ_RC_EPERM
@@ -10234,8 +11503,6 @@ i40e_dcb_init_configure(struct rte_eth_dev *dev, bool sw_dcb)
                        hw->local_dcbx_config.pfc.willing = 0;
                        hw->local_dcbx_config.pfc.pfccap =
                                                I40E_MAX_TRAFFIC_CLASS;
-                       hw->local_dcbx_config.pfc.pfcenable =
-                                               I40E_DEFAULT_TCMAP;
                        /* FW needs one App to configure HW */
                        hw->local_dcbx_config.numapps = 1;
                        hw->local_dcbx_config.app[0].selector =
@@ -10380,30 +11647,24 @@ i40e_dev_get_dcb_info(struct rte_eth_dev *dev,
 static int
 i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
-       struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       uint16_t interval =
-               i40e_calc_itr_interval(RTE_LIBRTE_I40E_ITR_INTERVAL);
        uint16_t msix_intr;
 
        msix_intr = intr_handle->intr_vec[queue_id];
        if (msix_intr == I40E_MISC_VEC_ID)
                I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
-                              I40E_PFINT_DYN_CTLN_INTENA_MASK |
-                              I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
-                              (0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
-                              (interval <<
-                               I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+                              I40E_PFINT_DYN_CTL0_INTENA_MASK |
+                              I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
+                              I40E_PFINT_DYN_CTL0_ITR_INDX_MASK);
        else
                I40E_WRITE_REG(hw,
                               I40E_PFINT_DYN_CTLN(msix_intr -
                                                   I40E_RX_VEC_START),
                               I40E_PFINT_DYN_CTLN_INTENA_MASK |
                               I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
-                              (0 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) |
-                              (interval <<
-                               I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT));
+                              I40E_PFINT_DYN_CTLN_ITR_INDX_MASK);
 
        I40E_WRITE_FLUSH(hw);
        rte_intr_enable(&pci_dev->intr_handle);
@@ -10414,24 +11675,51 @@ i40e_dev_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id)
 static int
 i40e_dev_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id)
 {
-       struct rte_pci_device *pci_dev = I40E_DEV_TO_PCI(dev);
+       struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
        struct rte_intr_handle *intr_handle = &pci_dev->intr_handle;
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        uint16_t msix_intr;
 
        msix_intr = intr_handle->intr_vec[queue_id];
        if (msix_intr == I40E_MISC_VEC_ID)
-               I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, 0);
+               I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0,
+                              I40E_PFINT_DYN_CTL0_ITR_INDX_MASK);
        else
                I40E_WRITE_REG(hw,
                               I40E_PFINT_DYN_CTLN(msix_intr -
                                                   I40E_RX_VEC_START),
-                              0);
+                              I40E_PFINT_DYN_CTLN_ITR_INDX_MASK);
        I40E_WRITE_FLUSH(hw);
 
        return 0;
 }
 
+/**
+ * This function is used to check if the register is valid.
+ * Below is the valid registers list for X722 only:
+ * 0x2b800--0x2bb00
+ * 0x38700--0x38a00
+ * 0x3d800--0x3db00
+ * 0x208e00--0x209000
+ * 0x20be00--0x20c000
+ * 0x263c00--0x264000
+ * 0x265c00--0x266000
+ */
+static inline int i40e_valid_regs(enum i40e_mac_type type, uint32_t reg_offset)
+{
+       if ((type != I40E_MAC_X722) &&
+           ((reg_offset >= 0x2b800 && reg_offset <= 0x2bb00) ||
+            (reg_offset >= 0x38700 && reg_offset <= 0x38a00) ||
+            (reg_offset >= 0x3d800 && reg_offset <= 0x3db00) ||
+            (reg_offset >= 0x208e00 && reg_offset <= 0x209000) ||
+            (reg_offset >= 0x20be00 && reg_offset <= 0x20c000) ||
+            (reg_offset >= 0x263c00 && reg_offset <= 0x264000) ||
+            (reg_offset >= 0x265c00 && reg_offset <= 0x266000)))
+               return 0;
+       else
+               return 1;
+}
+
 static int i40e_get_regs(struct rte_eth_dev *dev,
                         struct rte_dev_reg_info *regs)
 {
@@ -10473,8 +11761,11 @@ static int i40e_get_regs(struct rte_eth_dev *dev,
                                reg_offset = arr_idx * reg_info->stride1 +
                                        arr_idx2 * reg_info->stride2;
                                reg_offset += reg_info->base_addr;
-                               ptr_data[reg_offset >> 2] =
-                                       I40E_READ_REG(hw, reg_offset);
+                               if (!i40e_valid_regs(hw->mac.type, reg_offset))
+                                       ptr_data[reg_offset >> 2] = 0;
+                               else
+                                       ptr_data[reg_offset >> 2] =
+                                               I40E_READ_REG(hw, reg_offset);
                        }
        }
 
@@ -10518,18 +11809,194 @@ static int i40e_get_eeprom(struct rte_eth_dev *dev,
        return 0;
 }
 
-static void i40e_set_default_mac_addr(struct rte_eth_dev *dev,
-                                     struct ether_addr *mac_addr)
+static int i40e_get_module_info(struct rte_eth_dev *dev,
+                               struct rte_eth_dev_module_info *modinfo)
+{
+       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t sff8472_comp = 0;
+       uint32_t sff8472_swap = 0;
+       uint32_t sff8636_rev = 0;
+       i40e_status status;
+       uint32_t type = 0;
+
+       /* Check if firmware supports reading module EEPROM. */
+       if (!(hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE)) {
+               PMD_DRV_LOG(ERR,
+                           "Module EEPROM memory read not supported. "
+                           "Please update the NVM image.\n");
+               return -EINVAL;
+       }
+
+       status = i40e_update_link_info(hw);
+       if (status)
+               return -EIO;
+
+       if (hw->phy.link_info.phy_type == I40E_PHY_TYPE_EMPTY) {
+               PMD_DRV_LOG(ERR,
+                           "Cannot read module EEPROM memory. "
+                           "No module connected.\n");
+               return -EINVAL;
+       }
+
+       type = hw->phy.link_info.module_type[0];
+
+       switch (type) {
+       case I40E_MODULE_TYPE_SFP:
+               status = i40e_aq_get_phy_register(hw,
+                               I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
+                               I40E_I2C_EEPROM_DEV_ADDR, 1,
+                               I40E_MODULE_SFF_8472_COMP,
+                               &sff8472_comp, NULL);
+               if (status)
+                       return -EIO;
+
+               status = i40e_aq_get_phy_register(hw,
+                               I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
+                               I40E_I2C_EEPROM_DEV_ADDR, 1,
+                               I40E_MODULE_SFF_8472_SWAP,
+                               &sff8472_swap, NULL);
+               if (status)
+                       return -EIO;
+
+               /* Check if the module requires address swap to access
+                * the other EEPROM memory page.
+                */
+               if (sff8472_swap & I40E_MODULE_SFF_ADDR_MODE) {
+                       PMD_DRV_LOG(WARNING,
+                                   "Module address swap to access "
+                                   "page 0xA2 is not supported.\n");
+                       modinfo->type = RTE_ETH_MODULE_SFF_8079;
+                       modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8079_LEN;
+               } else if (sff8472_comp == 0x00) {
+                       /* Module is not SFF-8472 compliant */
+                       modinfo->type = RTE_ETH_MODULE_SFF_8079;
+                       modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8079_LEN;
+               } else {
+                       modinfo->type = RTE_ETH_MODULE_SFF_8472;
+                       modinfo->eeprom_len = RTE_ETH_MODULE_SFF_8472_LEN;
+               }
+               break;
+       case I40E_MODULE_TYPE_QSFP_PLUS:
+               /* Read from memory page 0. */
+               status = i40e_aq_get_phy_register(hw,
+                               I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
+                               0, 1,
+                               I40E_MODULE_REVISION_ADDR,
+                               &sff8636_rev, NULL);
+               if (status)
+                       return -EIO;
+               /* Determine revision compliance byte */
+               if (sff8636_rev > 0x02) {
+                       /* Module is SFF-8636 compliant */
+                       modinfo->type = RTE_ETH_MODULE_SFF_8636;
+                       modinfo->eeprom_len = I40E_MODULE_QSFP_MAX_LEN;
+               } else {
+                       modinfo->type = RTE_ETH_MODULE_SFF_8436;
+                       modinfo->eeprom_len = I40E_MODULE_QSFP_MAX_LEN;
+               }
+               break;
+       case I40E_MODULE_TYPE_QSFP28:
+               modinfo->type = RTE_ETH_MODULE_SFF_8636;
+               modinfo->eeprom_len = I40E_MODULE_QSFP_MAX_LEN;
+               break;
+       default:
+               PMD_DRV_LOG(ERR, "Module type unrecognized\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int i40e_get_module_eeprom(struct rte_eth_dev *dev,
+                                 struct rte_dev_eeprom_info *info)
+{
+       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       bool is_sfp = false;
+       i40e_status status;
+       uint8_t *data;
+       uint32_t value = 0;
+       uint32_t i;
+
+       if (!info || !info->length || !info->data)
+               return -EINVAL;
+
+       if (hw->phy.link_info.module_type[0] == I40E_MODULE_TYPE_SFP)
+               is_sfp = true;
+
+       data = info->data;
+       for (i = 0; i < info->length; i++) {
+               u32 offset = i + info->offset;
+               u32 addr = is_sfp ? I40E_I2C_EEPROM_DEV_ADDR : 0;
+
+               /* Check if we need to access the other memory page */
+               if (is_sfp) {
+                       if (offset >= RTE_ETH_MODULE_SFF_8079_LEN) {
+                               offset -= RTE_ETH_MODULE_SFF_8079_LEN;
+                               addr = I40E_I2C_EEPROM_DEV_ADDR2;
+                       }
+               } else {
+                       while (offset >= RTE_ETH_MODULE_SFF_8436_LEN) {
+                               /* Compute memory page number and offset. */
+                               offset -= RTE_ETH_MODULE_SFF_8436_LEN / 2;
+                               addr++;
+                       }
+               }
+               status = i40e_aq_get_phy_register(hw,
+                               I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
+                               addr, offset, 1, &value, NULL);
+               if (status)
+                       return -EIO;
+               data[i] = (uint8_t)value;
+       }
+       return 0;
+}
+
+static int i40e_set_default_mac_addr(struct rte_eth_dev *dev,
+                                    struct rte_ether_addr *mac_addr)
 {
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct i40e_vsi *vsi = pf->main_vsi;
+       struct i40e_mac_filter_info mac_filter;
+       struct i40e_mac_filter *f;
+       int ret;
 
        if (!is_valid_assigned_ether_addr(mac_addr)) {
                PMD_DRV_LOG(ERR, "Tried to set invalid MAC address.");
-               return;
+               return -EINVAL;
+       }
+
+       TAILQ_FOREACH(f, &vsi->mac_list, next) {
+               if (is_same_ether_addr(&pf->dev_addr, &f->mac_info.mac_addr))
+                       break;
+       }
+
+       if (f == NULL) {
+               PMD_DRV_LOG(ERR, "Failed to find filter for default mac");
+               return -EIO;
+       }
+
+       mac_filter = f->mac_info;
+       ret = i40e_vsi_delete_mac(vsi, &mac_filter.mac_addr);
+       if (ret != I40E_SUCCESS) {
+               PMD_DRV_LOG(ERR, "Failed to delete mac filter");
+               return -EIO;
+       }
+       memcpy(&mac_filter.mac_addr, mac_addr, ETH_ADDR_LEN);
+       ret = i40e_vsi_add_mac(vsi, &mac_filter);
+       if (ret != I40E_SUCCESS) {
+               PMD_DRV_LOG(ERR, "Failed to add mac filter");
+               return -EIO;
+       }
+       memcpy(&pf->dev_addr, mac_addr, ETH_ADDR_LEN);
+
+       ret = i40e_aq_mac_address_write(hw, I40E_AQC_WRITE_TYPE_LAA_WOL,
+                                       mac_addr->addr_bytes, NULL);
+       if (ret != I40E_SUCCESS) {
+               PMD_DRV_LOG(ERR, "Failed to change mac");
+               return -EIO;
        }
 
-       /* Flags: 0x3 updates port address */
-       i40e_aq_mac_address_write(hw, 0x3, mac_addr->addr_bytes, NULL);
+       return 0;
 }
 
 static int
@@ -10537,8 +12004,7 @@ i40e_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct rte_eth_dev_data *dev_data = pf->dev_data;
-       uint32_t frame_size = mtu + ETHER_HDR_LEN
-                             + ETHER_CRC_LEN + I40E_VLAN_TAG_SIZE;
+       uint32_t frame_size = mtu + I40E_ETH_OVERHEAD;
        int ret = 0;
 
        /* check if mtu is within the allowed range */
@@ -10553,9 +12019,11 @@ i40e_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
        }
 
        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;
        else
-               dev_data->dev_conf.rxmode.jumbo_frame = 0;
+               dev_data->dev_conf.rxmode.offloads &=
+                       ~DEV_RX_OFFLOAD_JUMBO_FRAME;
 
        dev_data->dev_conf.rxmode.max_rx_pkt_len = frame_size;
 
@@ -10600,19 +12068,26 @@ static void
 i40e_tunnel_filter_restore(struct i40e_pf *pf)
 {
        struct i40e_hw *hw = I40E_PF_TO_HW(pf);
-       struct i40e_vsi *vsi = pf->main_vsi;
+       struct i40e_vsi *vsi;
+       struct i40e_pf_vf *vf;
        struct i40e_tunnel_filter_list
                *tunnel_list = &pf->tunnel.tunnel_list;
        struct i40e_tunnel_filter *f;
-       struct i40e_aqc_add_rm_cloud_filt_elem_ext cld_filter;
+       struct i40e_aqc_cloud_filters_element_bb cld_filter;
        bool big_buffer = 0;
 
        TAILQ_FOREACH(f, tunnel_list, rules) {
+               if (!f->is_to_vf)
+                       vsi = pf->main_vsi;
+               else {
+                       vf = &pf->vfs[f->vf_id];
+                       vsi = vf->vsi;
+               }
                memset(&cld_filter, 0, sizeof(cld_filter));
-               ether_addr_copy((struct ether_addr *)&f->input.outer_mac,
-                       (struct ether_addr *)&cld_filter.element.outer_mac);
-               ether_addr_copy((struct ether_addr *)&f->input.inner_mac,
-                       (struct ether_addr *)&cld_filter.element.inner_mac);
+               ether_addr_copy((struct rte_ether_addr *)&f->input.outer_mac,
+                       (struct rte_ether_addr *)&cld_filter.element.outer_mac);
+               ether_addr_copy((struct rte_ether_addr *)&f->input.inner_mac,
+                       (struct rte_ether_addr *)&cld_filter.element.inner_mac);
                cld_filter.element.inner_vlan = f->input.inner_vlan;
                cld_filter.element.flags = f->input.flags;
                cld_filter.element.tenant_id = f->input.tenant_id;
@@ -10622,1654 +12097,698 @@ i40e_tunnel_filter_restore(struct i40e_pf *pf)
                           sizeof(f->input.general_fields));
 
                if (((f->input.flags &
-                    I40E_AQC_ADD_CLOUD_FILTER_TEID_MPLSoUDP) ==
-                    I40E_AQC_ADD_CLOUD_FILTER_TEID_MPLSoUDP) ||
+                    I40E_AQC_ADD_CLOUD_FILTER_0X11) ==
+                    I40E_AQC_ADD_CLOUD_FILTER_0X11) ||
                    ((f->input.flags &
-                    I40E_AQC_ADD_CLOUD_FILTER_TEID_MPLSoGRE) ==
-                    I40E_AQC_ADD_CLOUD_FILTER_TEID_MPLSoGRE))
+                    I40E_AQC_ADD_CLOUD_FILTER_0X12) ==
+                    I40E_AQC_ADD_CLOUD_FILTER_0X12) ||
+                   ((f->input.flags &
+                    I40E_AQC_ADD_CLOUD_FILTER_0X10) ==
+                    I40E_AQC_ADD_CLOUD_FILTER_0X10))
                        big_buffer = 1;
 
                if (big_buffer)
-                       i40e_aq_add_cloud_filters_big_buffer(hw,
-                                            vsi->seid, &cld_filter, 1);
+                       i40e_aq_add_cloud_filters_bb(hw,
+                                       vsi->seid, &cld_filter, 1);
                else
                        i40e_aq_add_cloud_filters(hw, vsi->seid,
                                                  &cld_filter.element, 1);
        }
 }
 
+/* Restore rss filter */
+static inline void
+i40e_rss_filter_restore(struct i40e_pf *pf)
+{
+       struct i40e_rte_flow_rss_conf *conf =
+                                       &pf->rss_info;
+       if (conf->conf.queue_num)
+               i40e_config_rss_filter(pf, conf, TRUE);
+}
+
 static void
 i40e_filter_restore(struct i40e_pf *pf)
 {
        i40e_ethertype_filter_restore(pf);
        i40e_tunnel_filter_restore(pf);
        i40e_fdir_filter_restore(pf);
+       i40e_rss_filter_restore(pf);
 }
 
 static bool
-is_device_supported(struct rte_eth_dev *dev, struct eth_driver *drv)
+is_device_supported(struct rte_eth_dev *dev, struct rte_pci_driver *drv)
 {
-       if (strcmp(dev->driver->pci_drv.driver.name,
-                  drv->pci_drv.driver.name))
+       if (strcmp(dev->device->driver->name, drv->driver.name))
                return false;
 
        return true;
 }
 
-int
-rte_pmd_i40e_ping_vfs(uint8_t port, uint16_t vf)
+bool
+is_i40e_supported(struct rte_eth_dev *dev)
 {
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
+       return is_device_supported(dev, &rte_i40e_pmd);
+}
 
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
+struct i40e_customized_pctype*
+i40e_find_customized_pctype(struct i40e_pf *pf, uint8_t index)
+{
+       int i;
 
-       dev = &rte_eth_devices[port];
+       for (i = 0; i < I40E_CUSTOMIZED_MAX; i++) {
+               if (pf->customized_pctype[i].index == index)
+                       return &pf->customized_pctype[i];
+       }
+       return NULL;
+}
 
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
+static int
+i40e_update_customized_pctype(struct rte_eth_dev *dev, uint8_t *pkg,
+                             uint32_t pkg_size, uint32_t proto_num,
+                             struct rte_pmd_i40e_proto_info *proto,
+                             enum rte_pmd_i40e_package_op op)
+{
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       uint32_t pctype_num;
+       struct rte_pmd_i40e_ptype_info *pctype;
+       uint32_t buff_size;
+       struct i40e_customized_pctype *new_pctype = NULL;
+       uint8_t proto_id;
+       uint8_t pctype_value;
+       char name[64];
+       uint32_t i, j, n;
+       int ret;
 
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       if (op != RTE_PMD_I40E_PKG_OP_WR_ADD &&
+           op != RTE_PMD_I40E_PKG_OP_WR_DEL) {
+               PMD_DRV_LOG(ERR, "Unsupported operation.");
+               return -1;
+       }
 
-       if (vf >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid argument.");
-               return -EINVAL;
+       ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+                               (uint8_t *)&pctype_num, sizeof(pctype_num),
+                               RTE_PMD_I40E_PKG_INFO_PCTYPE_NUM);
+       if (ret) {
+               PMD_DRV_LOG(ERR, "Failed to get pctype number");
+               return -1;
+       }
+       if (!pctype_num) {
+               PMD_DRV_LOG(INFO, "No new pctype added");
+               return -1;
        }
 
-       i40e_notify_vf_link_status(dev, &pf->vfs[vf]);
+       buff_size = pctype_num * sizeof(struct rte_pmd_i40e_proto_info);
+       pctype = rte_zmalloc("new_pctype", buff_size, 0);
+       if (!pctype) {
+               PMD_DRV_LOG(ERR, "Failed to allocate memory");
+               return -1;
+       }
+       /* get information about new pctype list */
+       ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+                                       (uint8_t *)pctype, buff_size,
+                                       RTE_PMD_I40E_PKG_INFO_PCTYPE_LIST);
+       if (ret) {
+               PMD_DRV_LOG(ERR, "Failed to get pctype list");
+               rte_free(pctype);
+               return -1;
+       }
+
+       /* Update customized pctype. */
+       for (i = 0; i < pctype_num; i++) {
+               pctype_value = pctype[i].ptype_id;
+               memset(name, 0, sizeof(name));
+               for (j = 0; j < RTE_PMD_I40E_PROTO_NUM; j++) {
+                       proto_id = pctype[i].protocols[j];
+                       if (proto_id == RTE_PMD_I40E_PROTO_UNUSED)
+                               continue;
+                       for (n = 0; n < proto_num; n++) {
+                               if (proto[n].proto_id != proto_id)
+                                       continue;
+                               strlcat(name, proto[n].name, sizeof(name));
+                               strlcat(name, "_", sizeof(name));
+                               break;
+                       }
+               }
+               name[strlen(name) - 1] = '\0';
+               if (!strcmp(name, "GTPC"))
+                       new_pctype =
+                               i40e_find_customized_pctype(pf,
+                                                     I40E_CUSTOMIZED_GTPC);
+               else if (!strcmp(name, "GTPU_IPV4"))
+                       new_pctype =
+                               i40e_find_customized_pctype(pf,
+                                                  I40E_CUSTOMIZED_GTPU_IPV4);
+               else if (!strcmp(name, "GTPU_IPV6"))
+                       new_pctype =
+                               i40e_find_customized_pctype(pf,
+                                                  I40E_CUSTOMIZED_GTPU_IPV6);
+               else if (!strcmp(name, "GTPU"))
+                       new_pctype =
+                               i40e_find_customized_pctype(pf,
+                                                     I40E_CUSTOMIZED_GTPU);
+               if (new_pctype) {
+                       if (op == RTE_PMD_I40E_PKG_OP_WR_ADD) {
+                               new_pctype->pctype = pctype_value;
+                               new_pctype->valid = true;
+                       } else {
+                               new_pctype->pctype = I40E_FILTER_PCTYPE_INVALID;
+                               new_pctype->valid = false;
+                       }
+               }
+       }
 
+       rte_free(pctype);
        return 0;
 }
 
-int
-rte_pmd_i40e_set_vf_mac_anti_spoof(uint8_t port, uint16_t vf_id, uint8_t on)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_vsi *vsi;
-       struct i40e_hw *hw;
-       struct i40e_vsi_context ctxt;
+static int
+i40e_update_customized_ptype(struct rte_eth_dev *dev, uint8_t *pkg,
+                            uint32_t pkg_size, uint32_t proto_num,
+                            struct rte_pmd_i40e_proto_info *proto,
+                            enum rte_pmd_i40e_package_op op)
+{
+       struct rte_pmd_i40e_ptype_mapping *ptype_mapping;
+       uint16_t port_id = dev->data->port_id;
+       uint32_t ptype_num;
+       struct rte_pmd_i40e_ptype_info *ptype;
+       uint32_t buff_size;
+       uint8_t proto_id;
+       char name[RTE_PMD_I40E_DDP_NAME_SIZE];
+       uint32_t i, j, n;
+       bool in_tunnel;
        int ret;
 
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       if (op != RTE_PMD_I40E_PKG_OP_WR_ADD &&
+           op != RTE_PMD_I40E_PKG_OP_WR_DEL) {
+               PMD_DRV_LOG(ERR, "Unsupported operation.");
+               return -1;
+       }
 
-       if (vf_id >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid argument.");
-               return -EINVAL;
+       if (op == RTE_PMD_I40E_PKG_OP_WR_DEL) {
+               rte_pmd_i40e_ptype_mapping_reset(port_id);
+               return 0;
        }
 
-       vsi = pf->vfs[vf_id].vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
+       /* get information about new ptype num */
+       ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+                               (uint8_t *)&ptype_num, sizeof(ptype_num),
+                               RTE_PMD_I40E_PKG_INFO_PTYPE_NUM);
+       if (ret) {
+               PMD_DRV_LOG(ERR, "Failed to get ptype number");
+               return ret;
+       }
+       if (!ptype_num) {
+               PMD_DRV_LOG(INFO, "No new ptype added");
+               return -1;
        }
 
-       /* Check if it has been already on or off */
-       if (vsi->info.valid_sections &
-               rte_cpu_to_le_16(I40E_AQ_VSI_PROP_SECURITY_VALID)) {
-               if (on) {
-                       if ((vsi->info.sec_flags &
-                            I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK) ==
-                           I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK)
-                               return 0; /* already on */
-               } else {
-                       if ((vsi->info.sec_flags &
-                            I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK) == 0)
-                               return 0; /* already off */
-               }
-       }
-
-       vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SECURITY_VALID);
-       if (on)
-               vsi->info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
-       else
-               vsi->info.sec_flags &= ~I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
-
-       memset(&ctxt, 0, sizeof(ctxt));
-       (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
-       ctxt.seid = vsi->seid;
-
-       hw = I40E_VSI_TO_HW(vsi);
-       ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
-       if (ret != I40E_SUCCESS) {
-               ret = -ENOTSUP;
-               PMD_DRV_LOG(ERR, "Failed to update VSI params");
-       }
-
-       return ret;
-}
-
-static int
-i40e_add_rm_all_vlan_filter(struct i40e_vsi *vsi, uint8_t add)
-{
-       uint32_t j, k;
-       uint16_t vlan_id;
-       struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
-       struct i40e_aqc_add_remove_vlan_element_data vlan_data = {0};
-       int ret;
-
-       for (j = 0; j < I40E_VFTA_SIZE; j++) {
-               if (!vsi->vfta[j])
-                       continue;
-
-               for (k = 0; k < I40E_UINT32_BIT_SIZE; k++) {
-                       if (!(vsi->vfta[j] & (1 << k)))
-                               continue;
-
-                       vlan_id = j * I40E_UINT32_BIT_SIZE + k;
-                       if (!vlan_id)
-                               continue;
-
-                       vlan_data.vlan_tag = rte_cpu_to_le_16(vlan_id);
-                       if (add)
-                               ret = i40e_aq_add_vlan(hw, vsi->seid,
-                                                      &vlan_data, 1, NULL);
-                       else
-                               ret = i40e_aq_remove_vlan(hw, vsi->seid,
-                                                         &vlan_data, 1, NULL);
-                       if (ret != I40E_SUCCESS) {
-                               PMD_DRV_LOG(ERR,
-                                           "Failed to add/rm vlan filter");
-                               return ret;
-                       }
-               }
-       }
-
-       return I40E_SUCCESS;
-}
-
-int
-rte_pmd_i40e_set_vf_vlan_anti_spoof(uint8_t port, uint16_t vf_id, uint8_t on)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_vsi *vsi;
-       struct i40e_hw *hw;
-       struct i40e_vsi_context ctxt;
-       int ret;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-
-       if (vf_id >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid argument.");
-               return -EINVAL;
-       }
-
-       vsi = pf->vfs[vf_id].vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
-       }
-
-       /* Check if it has been already on or off */
-       if (vsi->vlan_anti_spoof_on == on)
-               return 0; /* already on or off */
-
-       vsi->vlan_anti_spoof_on = on;
-       if (!vsi->vlan_filter_on) {
-               ret = i40e_add_rm_all_vlan_filter(vsi, on);
-               if (ret) {
-                       PMD_DRV_LOG(ERR, "Failed to add/remove VLAN filters.");
-                       return -ENOTSUP;
-               }
-       }
-
-       vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SECURITY_VALID);
-       if (on)
-               vsi->info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK;
-       else
-               vsi->info.sec_flags &= ~I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK;
-
-       memset(&ctxt, 0, sizeof(ctxt));
-       (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
-       ctxt.seid = vsi->seid;
-
-       hw = I40E_VSI_TO_HW(vsi);
-       ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
-       if (ret != I40E_SUCCESS) {
-               ret = -ENOTSUP;
-               PMD_DRV_LOG(ERR, "Failed to update VSI params");
-       }
-
-       return ret;
-}
-
-static int
-i40e_vsi_rm_mac_filter(struct i40e_vsi *vsi)
-{
-       struct i40e_mac_filter *f;
-       struct i40e_macvlan_filter *mv_f;
-       int i, vlan_num;
-       enum rte_mac_filter_type filter_type;
-       int ret = I40E_SUCCESS;
-       void *temp;
-
-       /* remove all the MACs */
-       TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
-               vlan_num = vsi->vlan_num;
-               filter_type = f->mac_info.filter_type;
-               if (filter_type == RTE_MACVLAN_PERFECT_MATCH ||
-                   filter_type == RTE_MACVLAN_HASH_MATCH) {
-                       if (vlan_num == 0) {
-                               PMD_DRV_LOG(ERR, "VLAN number shouldn't be 0");
-                               return I40E_ERR_PARAM;
-                       }
-               } else if (filter_type == RTE_MAC_PERFECT_MATCH ||
-                          filter_type == RTE_MAC_HASH_MATCH)
-                       vlan_num = 1;
-
-               mv_f = rte_zmalloc("macvlan_data", vlan_num * sizeof(*mv_f), 0);
-               if (!mv_f) {
-                       PMD_DRV_LOG(ERR, "failed to allocate memory");
-                       return I40E_ERR_NO_MEMORY;
-               }
-
-               for (i = 0; i < vlan_num; i++) {
-                       mv_f[i].filter_type = filter_type;
-                       (void)rte_memcpy(&mv_f[i].macaddr,
-                                        &f->mac_info.mac_addr,
-                                        ETH_ADDR_LEN);
-               }
-               if (filter_type == RTE_MACVLAN_PERFECT_MATCH ||
-                   filter_type == RTE_MACVLAN_HASH_MATCH) {
-                       ret = i40e_find_all_vlan_for_mac(vsi, mv_f, vlan_num,
-                                                        &f->mac_info.mac_addr);
-                       if (ret != I40E_SUCCESS) {
-                               rte_free(mv_f);
-                               return ret;
-                       }
-               }
-
-               ret = i40e_remove_macvlan_filters(vsi, mv_f, vlan_num);
-               if (ret != I40E_SUCCESS) {
-                       rte_free(mv_f);
-                       return ret;
-               }
-
-               rte_free(mv_f);
-               ret = I40E_SUCCESS;
-       }
-
-       return ret;
-}
-
-static int
-i40e_vsi_restore_mac_filter(struct i40e_vsi *vsi)
-{
-       struct i40e_mac_filter *f;
-       struct i40e_macvlan_filter *mv_f;
-       int i, vlan_num = 0;
-       int ret = I40E_SUCCESS;
-       void *temp;
-
-       /* restore all the MACs */
-       TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
-               if ((f->mac_info.filter_type == RTE_MACVLAN_PERFECT_MATCH) ||
-                   (f->mac_info.filter_type == RTE_MACVLAN_HASH_MATCH)) {
-                       /**
-                        * If vlan_num is 0, that's the first time to add mac,
-                        * set mask for vlan_id 0.
-                        */
-                       if (vsi->vlan_num == 0) {
-                               i40e_set_vlan_filter(vsi, 0, 1);
-                               vsi->vlan_num = 1;
-                       }
-                       vlan_num = vsi->vlan_num;
-               } else if ((f->mac_info.filter_type == RTE_MAC_PERFECT_MATCH) ||
-                          (f->mac_info.filter_type == RTE_MAC_HASH_MATCH))
-                       vlan_num = 1;
-
-               mv_f = rte_zmalloc("macvlan_data", vlan_num * sizeof(*mv_f), 0);
-               if (!mv_f) {
-                       PMD_DRV_LOG(ERR, "failed to allocate memory");
-                       return I40E_ERR_NO_MEMORY;
-               }
-
-               for (i = 0; i < vlan_num; i++) {
-                       mv_f[i].filter_type = f->mac_info.filter_type;
-                       (void)rte_memcpy(&mv_f[i].macaddr,
-                                        &f->mac_info.mac_addr,
-                                        ETH_ADDR_LEN);
-               }
-
-               if (f->mac_info.filter_type == RTE_MACVLAN_PERFECT_MATCH ||
-                   f->mac_info.filter_type == RTE_MACVLAN_HASH_MATCH) {
-                       ret = i40e_find_all_vlan_for_mac(vsi, mv_f, vlan_num,
-                                                        &f->mac_info.mac_addr);
-                       if (ret != I40E_SUCCESS) {
-                               rte_free(mv_f);
-                               return ret;
-                       }
-               }
-
-               ret = i40e_add_macvlan_filters(vsi, mv_f, vlan_num);
-               if (ret != I40E_SUCCESS) {
-                       rte_free(mv_f);
-                       return ret;
-               }
-
-               rte_free(mv_f);
-               ret = I40E_SUCCESS;
-       }
-
-       return ret;
-}
-
-static int
-i40e_vsi_set_tx_loopback(struct i40e_vsi *vsi, uint8_t on)
-{
-       struct i40e_vsi_context ctxt;
-       struct i40e_hw *hw;
-       int ret;
-
-       if (!vsi)
-               return -EINVAL;
-
-       hw = I40E_VSI_TO_HW(vsi);
-
-       /* Use the FW API if FW >= v5.0 */
-       if (hw->aq.fw_maj_ver < 5) {
-               PMD_INIT_LOG(ERR, "FW < v5.0, cannot enable loopback");
-               return -ENOTSUP;
-       }
-
-       /* Check if it has been already on or off */
-       if (vsi->info.valid_sections &
-               rte_cpu_to_le_16(I40E_AQ_VSI_PROP_SWITCH_VALID)) {
-               if (on) {
-                       if ((vsi->info.switch_id &
-                            I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB) ==
-                           I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB)
-                               return 0; /* already on */
-               } else {
-                       if ((vsi->info.switch_id &
-                            I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB) == 0)
-                               return 0; /* already off */
-               }
-       }
-
-       /* remove all the MAC and VLAN first */
-       ret = i40e_vsi_rm_mac_filter(vsi);
-       if (ret) {
-               PMD_INIT_LOG(ERR, "Failed to remove MAC filters.");
-               return ret;
-       }
-       if (vsi->vlan_anti_spoof_on || vsi->vlan_filter_on) {
-               ret = i40e_add_rm_all_vlan_filter(vsi, 0);
-               if (ret) {
-                       PMD_INIT_LOG(ERR, "Failed to remove VLAN filters.");
-                       return ret;
-               }
-       }
-
-       vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
-       if (on)
-               vsi->info.switch_id |= I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB;
-       else
-               vsi->info.switch_id &= ~I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB;
-
-       memset(&ctxt, 0, sizeof(ctxt));
-       (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
-       ctxt.seid = vsi->seid;
-
-       ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
-       if (ret != I40E_SUCCESS) {
-               PMD_DRV_LOG(ERR, "Failed to update VSI params");
-               return ret;
-       }
-
-       /* add all the MAC and VLAN back */
-       ret = i40e_vsi_restore_mac_filter(vsi);
-       if (ret)
-               return ret;
-       if (vsi->vlan_anti_spoof_on || vsi->vlan_filter_on) {
-               ret = i40e_add_rm_all_vlan_filter(vsi, 1);
-               if (ret)
-                       return ret;
-       }
-
-       return ret;
-}
-
-int
-rte_pmd_i40e_set_tx_loopback(uint8_t port, uint8_t on)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_pf_vf *vf;
-       struct i40e_vsi *vsi;
-       uint16_t vf_id;
-       int ret;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-
-       /* setup PF TX loopback */
-       vsi = pf->main_vsi;
-       ret = i40e_vsi_set_tx_loopback(vsi, on);
-       if (ret)
-               return -ENOTSUP;
-
-       /* setup TX loopback for all the VFs */
-       if (!pf->vfs) {
-               /* if no VF, do nothing. */
-               return 0;
-       }
-
-       for (vf_id = 0; vf_id < pf->vf_num; vf_id++) {
-               vf = &pf->vfs[vf_id];
-               vsi = vf->vsi;
-
-               ret = i40e_vsi_set_tx_loopback(vsi, on);
-               if (ret)
-                       return -ENOTSUP;
-       }
-
-       return ret;
-}
-
-int
-rte_pmd_i40e_set_vf_unicast_promisc(uint8_t port, uint16_t vf_id, uint8_t on)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_vsi *vsi;
-       struct i40e_hw *hw;
-       int ret;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-
-       if (vf_id >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid argument.");
-               return -EINVAL;
-       }
-
-       vsi = pf->vfs[vf_id].vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
-       }
-
-       hw = I40E_VSI_TO_HW(vsi);
-
-       ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid,
-                                                 on, NULL, true);
-       if (ret != I40E_SUCCESS) {
-               ret = -ENOTSUP;
-               PMD_DRV_LOG(ERR, "Failed to set unicast promiscuous mode");
-       }
-
-       return ret;
-}
-
-int
-rte_pmd_i40e_set_vf_multicast_promisc(uint8_t port, uint16_t vf_id, uint8_t on)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_vsi *vsi;
-       struct i40e_hw *hw;
-       int ret;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-
-       if (vf_id >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid argument.");
-               return -EINVAL;
-       }
-
-       vsi = pf->vfs[vf_id].vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
-       }
-
-       hw = I40E_VSI_TO_HW(vsi);
-
-       ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid,
-                                                   on, NULL);
-       if (ret != I40E_SUCCESS) {
-               ret = -ENOTSUP;
-               PMD_DRV_LOG(ERR, "Failed to set multicast promiscuous mode");
-       }
-
-       return ret;
-}
-
-int
-rte_pmd_i40e_set_vf_mac_addr(uint8_t port, uint16_t vf_id,
-                            struct ether_addr *mac_addr)
-{
-       struct i40e_mac_filter *f;
-       struct rte_eth_dev *dev;
-       struct i40e_pf_vf *vf;
-       struct i40e_vsi *vsi;
-       struct i40e_pf *pf;
-       void *temp;
-
-       if (i40e_validate_mac_addr((u8 *)mac_addr) != I40E_SUCCESS)
-               return -EINVAL;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-
-       if (vf_id >= pf->vf_num || !pf->vfs)
-               return -EINVAL;
-
-       vf = &pf->vfs[vf_id];
-       vsi = vf->vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
-       }
-
-       ether_addr_copy(mac_addr, &vf->mac_addr);
-
-       /* Remove all existing mac */
-       TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp)
-               i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr);
-
-       return 0;
-}
-
-/* Set vlan strip on/off for specific VF from host */
-int
-rte_pmd_i40e_set_vf_vlan_stripq(uint8_t port, uint16_t vf_id, uint8_t on)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_vsi *vsi;
-       int ret;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-
-       if (vf_id >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid argument.");
-               return -EINVAL;
-       }
-
-       vsi = pf->vfs[vf_id].vsi;
-
-       if (!vsi)
-               return -EINVAL;
-
-       ret = i40e_vsi_config_vlan_stripping(vsi, !!on);
-       if (ret != I40E_SUCCESS) {
-               ret = -ENOTSUP;
-               PMD_DRV_LOG(ERR, "Failed to set VLAN stripping!");
-       }
-
-       return ret;
-}
-
-int rte_pmd_i40e_set_vf_vlan_insert(uint8_t port, uint16_t vf_id,
-                                   uint16_t vlan_id)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_hw *hw;
-       struct i40e_vsi *vsi;
-       struct i40e_vsi_context ctxt;
-       int ret;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       if (vlan_id > ETHER_MAX_VLAN_ID) {
-               PMD_DRV_LOG(ERR, "Invalid VLAN ID.");
-               return -EINVAL;
-       }
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-       hw = I40E_PF_TO_HW(pf);
-
-       /**
-        * return -ENODEV if SRIOV not enabled, VF number not configured
-        * or no queue assigned.
-        */
-       if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 ||
-           pf->vf_nb_qps == 0)
-               return -ENODEV;
-
-       if (vf_id >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid VF ID.");
-               return -EINVAL;
-       }
-
-       vsi = pf->vfs[vf_id].vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
-       }
-
-       vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID);
-       vsi->info.pvid = vlan_id;
-       if (vlan_id > 0)
-               vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_INSERT_PVID;
-       else
-               vsi->info.port_vlan_flags &= ~I40E_AQ_VSI_PVLAN_INSERT_PVID;
-
-       memset(&ctxt, 0, sizeof(ctxt));
-       (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
-       ctxt.seid = vsi->seid;
-
-       hw = I40E_VSI_TO_HW(vsi);
-       ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
-       if (ret != I40E_SUCCESS) {
-               ret = -ENOTSUP;
-               PMD_DRV_LOG(ERR, "Failed to update VSI params");
-       }
-
-       return ret;
-}
-
-int rte_pmd_i40e_set_vf_broadcast(uint8_t port, uint16_t vf_id,
-                                 uint8_t on)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_vsi *vsi;
-       struct i40e_hw *hw;
-       struct i40e_mac_filter_info filter;
-       struct ether_addr broadcast = {
-               .addr_bytes = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} };
-       int ret;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       if (on > 1) {
-               PMD_DRV_LOG(ERR, "on should be 0 or 1.");
-               return -EINVAL;
-       }
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-       hw = I40E_PF_TO_HW(pf);
-
-       if (vf_id >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid VF ID.");
-               return -EINVAL;
-       }
-
-       /**
-        * return -ENODEV if SRIOV not enabled, VF number not configured
-        * or no queue assigned.
-        */
-       if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 ||
-           pf->vf_nb_qps == 0) {
-               PMD_DRV_LOG(ERR, "SRIOV is not enabled or no queue.");
-               return -ENODEV;
-       }
-
-       vsi = pf->vfs[vf_id].vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
-       }
-
-       if (on) {
-               (void)rte_memcpy(&filter.mac_addr, &broadcast, ETHER_ADDR_LEN);
-               filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
-               ret = i40e_vsi_add_mac(vsi, &filter);
-       } else {
-               ret = i40e_vsi_delete_mac(vsi, &broadcast);
-       }
-
-       if (ret != I40E_SUCCESS && ret != I40E_ERR_PARAM) {
-               ret = -ENOTSUP;
-               PMD_DRV_LOG(ERR, "Failed to set VSI broadcast");
-       } else {
-               ret = 0;
-       }
-
-       return ret;
-}
-
-int rte_pmd_i40e_set_vf_vlan_tag(uint8_t port, uint16_t vf_id, uint8_t on)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_hw *hw;
-       struct i40e_vsi *vsi;
-       struct i40e_vsi_context ctxt;
-       int ret;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       if (on > 1) {
-               PMD_DRV_LOG(ERR, "on should be 0 or 1.");
-               return -EINVAL;
-       }
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-       hw = I40E_PF_TO_HW(pf);
-
-       /**
-        * return -ENODEV if SRIOV not enabled, VF number not configured
-        * or no queue assigned.
-        */
-       if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 ||
-           pf->vf_nb_qps == 0) {
-               PMD_DRV_LOG(ERR, "SRIOV is not enabled or no queue.");
-               return -ENODEV;
-       }
-
-       if (vf_id >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid VF ID.");
-               return -EINVAL;
-       }
-
-       vsi = pf->vfs[vf_id].vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
-       }
-
-       vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID);
-       if (on) {
-               vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_TAGGED;
-               vsi->info.port_vlan_flags &= ~I40E_AQ_VSI_PVLAN_MODE_UNTAGGED;
-       } else {
-               vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_UNTAGGED;
-               vsi->info.port_vlan_flags &= ~I40E_AQ_VSI_PVLAN_MODE_TAGGED;
-       }
-
-       memset(&ctxt, 0, sizeof(ctxt));
-       (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
-       ctxt.seid = vsi->seid;
-
-       hw = I40E_VSI_TO_HW(vsi);
-       ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
-       if (ret != I40E_SUCCESS) {
-               ret = -ENOTSUP;
-               PMD_DRV_LOG(ERR, "Failed to update VSI params");
-       }
-
-       return ret;
-}
-
-int rte_pmd_i40e_set_vf_vlan_filter(uint8_t port, uint16_t vlan_id,
-                                   uint64_t vf_mask, uint8_t on)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_hw *hw;
-       struct i40e_vsi *vsi;
-       uint16_t vf_idx;
-       int ret = I40E_SUCCESS;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       if (vlan_id > ETHER_MAX_VLAN_ID) {
-               PMD_DRV_LOG(ERR, "Invalid VLAN ID.");
-               return -EINVAL;
-       }
-
-       if (vf_mask == 0) {
-               PMD_DRV_LOG(ERR, "No VF.");
-               return -EINVAL;
-       }
-
-       if (on > 1) {
-               PMD_DRV_LOG(ERR, "on is should be 0 or 1.");
-               return -EINVAL;
-       }
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-       hw = I40E_PF_TO_HW(pf);
-
-       /**
-        * return -ENODEV if SRIOV not enabled, VF number not configured
-        * or no queue assigned.
-        */
-       if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 ||
-           pf->vf_nb_qps == 0) {
-               PMD_DRV_LOG(ERR, "SRIOV is not enabled or no queue.");
-               return -ENODEV;
-       }
-
-       for (vf_idx = 0; vf_idx < pf->vf_num && ret == I40E_SUCCESS; vf_idx++) {
-               if (vf_mask & ((uint64_t)(1ULL << vf_idx))) {
-                       vsi = pf->vfs[vf_idx].vsi;
-                       if (on) {
-                               if (!vsi->vlan_filter_on) {
-                                       vsi->vlan_filter_on = true;
-                                       if (!vsi->vlan_anti_spoof_on)
-                                               i40e_add_rm_all_vlan_filter(
-                                                       vsi, true);
-                               }
-                               i40e_aq_set_vsi_vlan_promisc(hw, vsi->seid,
-                                                            false, NULL);
-                               ret = i40e_vsi_add_vlan(vsi, vlan_id);
-                       } else {
-                               ret = i40e_vsi_delete_vlan(vsi, vlan_id);
-                       }
-               }
-       }
-
-       if (ret != I40E_SUCCESS) {
-               ret = -ENOTSUP;
-               PMD_DRV_LOG(ERR, "Failed to set VF VLAN filter, on = %d", on);
-       }
-
-       return ret;
-}
-
-int
-rte_pmd_i40e_get_vf_stats(uint8_t port,
-                         uint16_t vf_id,
-                         struct rte_eth_stats *stats)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_vsi *vsi;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-
-       if (vf_id >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid VF ID.");
-               return -EINVAL;
-       }
-
-       vsi = pf->vfs[vf_id].vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
-       }
-
-       i40e_update_vsi_stats(vsi);
-
-       stats->ipackets = vsi->eth_stats.rx_unicast +
-                       vsi->eth_stats.rx_multicast +
-                       vsi->eth_stats.rx_broadcast;
-       stats->opackets = vsi->eth_stats.tx_unicast +
-                       vsi->eth_stats.tx_multicast +
-                       vsi->eth_stats.tx_broadcast;
-       stats->ibytes   = vsi->eth_stats.rx_bytes;
-       stats->obytes   = vsi->eth_stats.tx_bytes;
-       stats->ierrors  = vsi->eth_stats.rx_discards;
-       stats->oerrors  = vsi->eth_stats.tx_errors + vsi->eth_stats.tx_discards;
-
-       return 0;
-}
-
-int
-rte_pmd_i40e_reset_vf_stats(uint8_t port,
-                           uint16_t vf_id)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_vsi *vsi;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-
-       if (vf_id >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid VF ID.");
-               return -EINVAL;
-       }
-
-       vsi = pf->vfs[vf_id].vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
-       }
-
-       vsi->offset_loaded = false;
-       i40e_update_vsi_stats(vsi);
-
-       return 0;
-}
-
-int
-rte_pmd_i40e_set_vf_max_bw(uint8_t port, uint16_t vf_id, uint32_t bw)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_vsi *vsi;
-       struct i40e_hw *hw;
-       int ret = 0;
-       int i;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-
-       if (vf_id >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid VF ID.");
-               return -EINVAL;
-       }
-
-       vsi = pf->vfs[vf_id].vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
-       }
-
-       if (bw > I40E_QOS_BW_MAX) {
-               PMD_DRV_LOG(ERR, "Bandwidth should not be larger than %dMbps.",
-                           I40E_QOS_BW_MAX);
-               return -EINVAL;
-       }
-
-       if (bw % I40E_QOS_BW_GRANULARITY) {
-               PMD_DRV_LOG(ERR, "Bandwidth should be the multiple of %dMbps.",
-                           I40E_QOS_BW_GRANULARITY);
-               return -EINVAL;
-       }
-
-       bw /= I40E_QOS_BW_GRANULARITY;
-
-       hw = I40E_VSI_TO_HW(vsi);
-
-       /* No change. */
-       if (bw == vsi->bw_info.bw_limit) {
-               PMD_DRV_LOG(INFO,
-                           "No change for VF max bandwidth. Nothing to do.");
-               return 0;
-       }
-
-       /**
-        * VF bandwidth limitation and TC bandwidth limitation cannot be
-        * enabled in parallel, quit if TC bandwidth limitation is enabled.
-        *
-        * If bw is 0, means disable bandwidth limitation. Then no need to
-        * check TC bandwidth limitation.
-        */
-       if (bw) {
-               for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-                       if ((vsi->enabled_tc & BIT_ULL(i)) &&
-                           vsi->bw_info.bw_ets_credits[i])
-                               break;
-               }
-               if (i != I40E_MAX_TRAFFIC_CLASS) {
-                       PMD_DRV_LOG(ERR,
-                                   "TC max bandwidth has been set on this VF,"
-                                   " please disable it first.");
-                       return -EINVAL;
-               }
-       }
-
-       ret = i40e_aq_config_vsi_bw_limit(hw, vsi->seid, (uint16_t)bw, 0, NULL);
-       if (ret) {
-               PMD_DRV_LOG(ERR,
-                           "Failed to set VF %d bandwidth, err(%d).",
-                           vf_id, ret);
-               return -EINVAL;
-       }
-
-       /* Store the configuration. */
-       vsi->bw_info.bw_limit = (uint16_t)bw;
-       vsi->bw_info.bw_max = 0;
-
-       return 0;
-}
-
-int
-rte_pmd_i40e_set_vf_tc_bw_alloc(uint8_t port, uint16_t vf_id,
-                               uint8_t tc_num, uint8_t *bw_weight)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_vsi *vsi;
-       struct i40e_hw *hw;
-       struct i40e_aqc_configure_vsi_tc_bw_data tc_bw;
-       int ret = 0;
-       int i, j;
-       uint16_t sum;
-       bool b_change = false;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-
-       if (vf_id >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid VF ID.");
-               return -EINVAL;
-       }
-
-       vsi = pf->vfs[vf_id].vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
-       }
-
-       if (tc_num > I40E_MAX_TRAFFIC_CLASS) {
-               PMD_DRV_LOG(ERR, "TCs should be no more than %d.",
-                           I40E_MAX_TRAFFIC_CLASS);
-               return -EINVAL;
-       }
-
-       sum = 0;
-       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-               if (vsi->enabled_tc & BIT_ULL(i))
-                       sum++;
-       }
-       if (sum != tc_num) {
-               PMD_DRV_LOG(ERR,
-                           "Weight should be set for all %d enabled TCs.",
-                           sum);
-               return -EINVAL;
-       }
-
-       sum = 0;
-       for (i = 0; i < tc_num; i++) {
-               if (!bw_weight[i]) {
-                       PMD_DRV_LOG(ERR,
-                                   "The weight should be 1 at least.");
-                       return -EINVAL;
-               }
-               sum += bw_weight[i];
-       }
-       if (sum != 100) {
-               PMD_DRV_LOG(ERR,
-                           "The summary of the TC weight should be 100.");
-               return -EINVAL;
-       }
-
-       /**
-        * Create the configuration for all the TCs.
-        */
-       memset(&tc_bw, 0, sizeof(tc_bw));
-       tc_bw.tc_valid_bits = vsi->enabled_tc;
-       j = 0;
-       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-               if (vsi->enabled_tc & BIT_ULL(i)) {
-                       if (bw_weight[j] !=
-                               vsi->bw_info.bw_ets_share_credits[i])
-                               b_change = true;
-
-                       tc_bw.tc_bw_credits[i] = bw_weight[j];
-                       j++;
-               }
-       }
-
-       /* No change. */
-       if (!b_change) {
-               PMD_DRV_LOG(INFO,
-                           "No change for TC allocated bandwidth."
-                           " Nothing to do.");
-               return 0;
-       }
-
-       hw = I40E_VSI_TO_HW(vsi);
-
-       ret = i40e_aq_config_vsi_tc_bw(hw, vsi->seid, &tc_bw, NULL);
-       if (ret) {
-               PMD_DRV_LOG(ERR,
-                           "Failed to set VF %d TC bandwidth weight, err(%d).",
-                           vf_id, ret);
-               return -EINVAL;
-       }
-
-       /* Store the configuration. */
-       j = 0;
-       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-               if (vsi->enabled_tc & BIT_ULL(i)) {
-                       vsi->bw_info.bw_ets_share_credits[i] = bw_weight[j];
-                       j++;
-               }
-       }
-
-       return 0;
-}
-
-int
-rte_pmd_i40e_set_vf_tc_max_bw(uint8_t port, uint16_t vf_id,
-                             uint8_t tc_no, uint32_t bw)
-{
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_vsi *vsi;
-       struct i40e_hw *hw;
-       struct i40e_aqc_configure_vsi_ets_sla_bw_data tc_bw;
-       int ret = 0;
-       int i;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-
-       if (vf_id >= pf->vf_num || !pf->vfs) {
-               PMD_DRV_LOG(ERR, "Invalid VF ID.");
-               return -EINVAL;
-       }
-
-       vsi = pf->vfs[vf_id].vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
-       }
-
-       if (bw > I40E_QOS_BW_MAX) {
-               PMD_DRV_LOG(ERR, "Bandwidth should not be larger than %dMbps.",
-                           I40E_QOS_BW_MAX);
-               return -EINVAL;
-       }
-
-       if (bw % I40E_QOS_BW_GRANULARITY) {
-               PMD_DRV_LOG(ERR, "Bandwidth should be the multiple of %dMbps.",
-                           I40E_QOS_BW_GRANULARITY);
-               return -EINVAL;
-       }
-
-       bw /= I40E_QOS_BW_GRANULARITY;
-
-       if (tc_no >= I40E_MAX_TRAFFIC_CLASS) {
-               PMD_DRV_LOG(ERR, "TC No. should be less than %d.",
-                           I40E_MAX_TRAFFIC_CLASS);
-               return -EINVAL;
+       buff_size = ptype_num * sizeof(struct rte_pmd_i40e_ptype_info);
+       ptype = rte_zmalloc("new_ptype", buff_size, 0);
+       if (!ptype) {
+               PMD_DRV_LOG(ERR, "Failed to allocate memory");
+               return -1;
        }
 
-       hw = I40E_VSI_TO_HW(vsi);
-
-       if (!(vsi->enabled_tc & BIT_ULL(tc_no))) {
-               PMD_DRV_LOG(ERR, "VF %d TC %d isn't enabled.",
-                           vf_id, tc_no);
-               return -EINVAL;
+       /* get information about new ptype list */
+       ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+                                       (uint8_t *)ptype, buff_size,
+                                       RTE_PMD_I40E_PKG_INFO_PTYPE_LIST);
+       if (ret) {
+               PMD_DRV_LOG(ERR, "Failed to get ptype list");
+               rte_free(ptype);
+               return ret;
        }
 
-       /* No change. */
-       if (bw == vsi->bw_info.bw_ets_credits[tc_no]) {
-               PMD_DRV_LOG(INFO,
-                           "No change for TC max bandwidth. Nothing to do.");
-               return 0;
+       buff_size = ptype_num * sizeof(struct rte_pmd_i40e_ptype_mapping);
+       ptype_mapping = rte_zmalloc("ptype_mapping", buff_size, 0);
+       if (!ptype_mapping) {
+               PMD_DRV_LOG(ERR, "Failed to allocate memory");
+               rte_free(ptype);
+               return -1;
        }
 
-       /**
-        * VF bandwidth limitation and TC bandwidth limitation cannot be
-        * enabled in parallel, disable VF bandwidth limitation if it's
-        * enabled.
-        * If bw is 0, means disable bandwidth limitation. Then no need to
-        * care about VF bandwidth limitation configuration.
-        */
-       if (bw && vsi->bw_info.bw_limit) {
-               ret = i40e_aq_config_vsi_bw_limit(hw, vsi->seid, 0, 0, NULL);
-               if (ret) {
-                       PMD_DRV_LOG(ERR,
-                                   "Failed to disable VF(%d)"
-                                   " bandwidth limitation, err(%d).",
-                                   vf_id, ret);
-                       return -EINVAL;
-               }
-
-               PMD_DRV_LOG(INFO,
-                           "VF max bandwidth is disabled according"
-                           " to TC max bandwidth setting.");
-       }
+       /* Update ptype mapping table. */
+       for (i = 0; i < ptype_num; i++) {
+               ptype_mapping[i].hw_ptype = ptype[i].ptype_id;
+               ptype_mapping[i].sw_ptype = 0;
+               in_tunnel = false;
+               for (j = 0; j < RTE_PMD_I40E_PROTO_NUM; j++) {
+                       proto_id = ptype[i].protocols[j];
+                       if (proto_id == RTE_PMD_I40E_PROTO_UNUSED)
+                               continue;
+                       for (n = 0; n < proto_num; n++) {
+                               if (proto[n].proto_id != proto_id)
+                                       continue;
+                               memset(name, 0, sizeof(name));
+                               strcpy(name, proto[n].name);
+                               if (!strncasecmp(name, "PPPOE", 5))
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_L2_ETHER_PPPOE;
+                               else if (!strncasecmp(name, "IPV4FRAG", 8) &&
+                                        !in_tunnel) {
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_L4_FRAG;
+                               } else if (!strncasecmp(name, "IPV4FRAG", 8) &&
+                                          in_tunnel) {
+                                       ptype_mapping[i].sw_ptype |=
+                                           RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN;
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_INNER_L4_FRAG;
+                               } else if (!strncasecmp(name, "OIPV4", 5)) {
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+                                       in_tunnel = true;
+                               } else if (!strncasecmp(name, "IPV4", 4) &&
+                                          !in_tunnel)
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+                               else if (!strncasecmp(name, "IPV4", 4) &&
+                                        in_tunnel)
+                                       ptype_mapping[i].sw_ptype |=
+                                           RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN;
+                               else if (!strncasecmp(name, "IPV6FRAG", 8) &&
+                                        !in_tunnel) {
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_L4_FRAG;
+                               } else if (!strncasecmp(name, "IPV6FRAG", 8) &&
+                                          in_tunnel) {
+                                       ptype_mapping[i].sw_ptype |=
+                                           RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN;
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_INNER_L4_FRAG;
+                               } else if (!strncasecmp(name, "OIPV6", 5)) {
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
+                                       in_tunnel = true;
+                               } else if (!strncasecmp(name, "IPV6", 4) &&
+                                          !in_tunnel)
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
+                               else if (!strncasecmp(name, "IPV6", 4) &&
+                                        in_tunnel)
+                                       ptype_mapping[i].sw_ptype |=
+                                           RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN;
+                               else if (!strncasecmp(name, "UDP", 3) &&
+                                        !in_tunnel)
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_L4_UDP;
+                               else if (!strncasecmp(name, "UDP", 3) &&
+                                        in_tunnel)
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_INNER_L4_UDP;
+                               else if (!strncasecmp(name, "TCP", 3) &&
+                                        !in_tunnel)
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_L4_TCP;
+                               else if (!strncasecmp(name, "TCP", 3) &&
+                                        in_tunnel)
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_INNER_L4_TCP;
+                               else if (!strncasecmp(name, "SCTP", 4) &&
+                                        !in_tunnel)
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_L4_SCTP;
+                               else if (!strncasecmp(name, "SCTP", 4) &&
+                                        in_tunnel)
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_INNER_L4_SCTP;
+                               else if ((!strncasecmp(name, "ICMP", 4) ||
+                                         !strncasecmp(name, "ICMPV6", 6)) &&
+                                        !in_tunnel)
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_L4_ICMP;
+                               else if ((!strncasecmp(name, "ICMP", 4) ||
+                                         !strncasecmp(name, "ICMPV6", 6)) &&
+                                        in_tunnel)
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_INNER_L4_ICMP;
+                               else if (!strncasecmp(name, "GTPC", 4)) {
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_TUNNEL_GTPC;
+                                       in_tunnel = true;
+                               } else if (!strncasecmp(name, "GTPU", 4)) {
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_TUNNEL_GTPU;
+                                       in_tunnel = true;
+                               } else if (!strncasecmp(name, "GRENAT", 6)) {
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_TUNNEL_GRENAT;
+                                       in_tunnel = true;
+                               } else if (!strncasecmp(name, "L2TPV2CTL", 9) ||
+                                          !strncasecmp(name, "L2TPV2", 6)) {
+                                       ptype_mapping[i].sw_ptype |=
+                                               RTE_PTYPE_TUNNEL_L2TP;
+                                       in_tunnel = true;
+                               }
 
-       /**
-        * Get all the TCs' info to create a whole picture.
-        * Because the incremental change isn't permitted.
-        */
-       memset(&tc_bw, 0, sizeof(tc_bw));
-       tc_bw.tc_valid_bits = vsi->enabled_tc;
-       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-               if (vsi->enabled_tc & BIT_ULL(i)) {
-                       tc_bw.tc_bw_credits[i] =
-                               rte_cpu_to_le_16(
-                                       vsi->bw_info.bw_ets_credits[i]);
+                               break;
+                       }
                }
        }
-       tc_bw.tc_bw_credits[tc_no] = rte_cpu_to_le_16((uint16_t)bw);
-
-       ret = i40e_aq_config_vsi_ets_sla_bw_limit(hw, vsi->seid, &tc_bw, NULL);
-       if (ret) {
-               PMD_DRV_LOG(ERR,
-                           "Failed to set VF %d TC %d max bandwidth, err(%d).",
-                           vf_id, tc_no, ret);
-               return -EINVAL;
-       }
 
-       /* Store the configuration. */
-       vsi->bw_info.bw_ets_credits[tc_no] = (uint16_t)bw;
+       ret = rte_pmd_i40e_ptype_mapping_update(port_id, ptype_mapping,
+                                               ptype_num, 0);
+       if (ret)
+               PMD_DRV_LOG(ERR, "Failed to update mapping table.");
 
-       return 0;
+       rte_free(ptype_mapping);
+       rte_free(ptype);
+       return ret;
 }
 
-int
-rte_pmd_i40e_set_tc_strict_prio(uint8_t port, uint8_t tc_map)
+void
+i40e_update_customized_info(struct rte_eth_dev *dev, uint8_t *pkg,
+                           uint32_t pkg_size, enum rte_pmd_i40e_package_op op)
 {
-       struct rte_eth_dev *dev;
-       struct i40e_pf *pf;
-       struct i40e_vsi *vsi;
-       struct i40e_veb *veb;
-       struct i40e_hw *hw;
-       struct i40e_aqc_configure_switching_comp_ets_data ets_data;
-       int i;
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       uint32_t proto_num;
+       struct rte_pmd_i40e_proto_info *proto;
+       uint32_t buff_size;
+       uint32_t i;
        int ret;
 
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-
-       vsi = pf->main_vsi;
-       if (!vsi) {
-               PMD_DRV_LOG(ERR, "Invalid VSI.");
-               return -EINVAL;
+       if (op != RTE_PMD_I40E_PKG_OP_WR_ADD &&
+           op != RTE_PMD_I40E_PKG_OP_WR_DEL) {
+               PMD_DRV_LOG(ERR, "Unsupported operation.");
+               return;
        }
 
-       veb = vsi->veb;
-       if (!veb) {
-               PMD_DRV_LOG(ERR, "Invalid VEB.");
-               return -EINVAL;
+       /* get information about protocol number */
+       ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+                                      (uint8_t *)&proto_num, sizeof(proto_num),
+                                      RTE_PMD_I40E_PKG_INFO_PROTOCOL_NUM);
+       if (ret) {
+               PMD_DRV_LOG(ERR, "Failed to get protocol number");
+               return;
        }
-
-       if ((tc_map & veb->enabled_tc) != tc_map) {
-               PMD_DRV_LOG(ERR,
-                           "TC bitmap isn't the subset of enabled TCs 0x%x.",
-                           veb->enabled_tc);
-               return -EINVAL;
+       if (!proto_num) {
+               PMD_DRV_LOG(INFO, "No new protocol added");
+               return;
        }
 
-       if (tc_map == veb->strict_prio_tc) {
-               PMD_DRV_LOG(INFO, "No change for TC bitmap. Nothing to do.");
-               return 0;
+       buff_size = proto_num * sizeof(struct rte_pmd_i40e_proto_info);
+       proto = rte_zmalloc("new_proto", buff_size, 0);
+       if (!proto) {
+               PMD_DRV_LOG(ERR, "Failed to allocate memory");
+               return;
        }
 
-       hw = I40E_VSI_TO_HW(vsi);
-
-       /* Disable DCBx if it's the first time to set strict priority. */
-       if (!veb->strict_prio_tc) {
-               ret = i40e_aq_stop_lldp(hw, true, NULL);
-               if (ret)
-                       PMD_DRV_LOG(INFO,
-                                   "Failed to disable DCBx as it's already"
-                                   " disabled.");
-               else
-                       PMD_DRV_LOG(INFO,
-                                   "DCBx is disabled according to strict"
-                                   " priority setting.");
+       /* get information about protocol list */
+       ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+                                       (uint8_t *)proto, buff_size,
+                                       RTE_PMD_I40E_PKG_INFO_PROTOCOL_LIST);
+       if (ret) {
+               PMD_DRV_LOG(ERR, "Failed to get protocol list");
+               rte_free(proto);
+               return;
        }
 
-       memset(&ets_data, 0, sizeof(ets_data));
-       ets_data.tc_valid_bits = veb->enabled_tc;
-       ets_data.seepage = I40E_AQ_ETS_SEEPAGE_EN_MASK;
-       ets_data.tc_strict_priority_flags = tc_map;
-       /* Get all TCs' bandwidth. */
-       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-               if (veb->enabled_tc & BIT_ULL(i)) {
-                       /* For rubust, if bandwidth is 0, use 1 instead. */
-                       if (veb->bw_info.bw_ets_share_credits[i])
-                               ets_data.tc_bw_share_credits[i] =
-                                       veb->bw_info.bw_ets_share_credits[i];
+       /* Check if GTP is supported. */
+       for (i = 0; i < proto_num; i++) {
+               if (!strncmp(proto[i].name, "GTP", 3)) {
+                       if (op == RTE_PMD_I40E_PKG_OP_WR_ADD)
+                               pf->gtp_support = true;
                        else
-                               ets_data.tc_bw_share_credits[i] =
-                                       I40E_QOS_BW_WEIGHT_MIN;
+                               pf->gtp_support = false;
+                       break;
                }
        }
 
-       if (!veb->strict_prio_tc)
-               ret = i40e_aq_config_switch_comp_ets(
-                       hw, veb->uplink_seid,
-                       &ets_data, i40e_aqc_opc_enable_switching_comp_ets,
-                       NULL);
-       else if (tc_map)
-               ret = i40e_aq_config_switch_comp_ets(
-                       hw, veb->uplink_seid,
-                       &ets_data, i40e_aqc_opc_modify_switching_comp_ets,
-                       NULL);
-       else
-               ret = i40e_aq_config_switch_comp_ets(
-                       hw, veb->uplink_seid,
-                       &ets_data, i40e_aqc_opc_disable_switching_comp_ets,
-                       NULL);
-
-       if (ret) {
-               PMD_DRV_LOG(ERR,
-                           "Failed to set TCs' strict priority mode."
-                           " err (%d)", ret);
-               return -EINVAL;
-       }
-
-       veb->strict_prio_tc = tc_map;
-
-       /* Enable DCBx again, if all the TCs' strict priority disabled. */
-       if (!tc_map) {
-               ret = i40e_aq_start_lldp(hw, NULL);
-               if (ret) {
-                       PMD_DRV_LOG(ERR,
-                                   "Failed to enable DCBx, err(%d).", ret);
-                       return -EINVAL;
-               }
+       /* Update customized pctype info */
+       ret = i40e_update_customized_pctype(dev, pkg, pkg_size,
+                                           proto_num, proto, op);
+       if (ret)
+               PMD_DRV_LOG(INFO, "No pctype is updated.");
 
-               PMD_DRV_LOG(INFO,
-                           "DCBx is enabled again according to strict"
-                           " priority setting.");
-       }
+       /* Update customized ptype info */
+       ret = i40e_update_customized_ptype(dev, pkg, pkg_size,
+                                          proto_num, proto, op);
+       if (ret)
+               PMD_DRV_LOG(INFO, "No ptype is updated.");
 
-       return ret;
+       rte_free(proto);
 }
 
-#define I40E_PROFILE_INFO_SIZE 48
-#define I40E_MAX_PROFILE_NUM 16
+/* Create a QinQ cloud filter
+ *
+ * The Fortville NIC has limited resources for tunnel filters,
+ * so we can only reuse existing filters.
+ *
+ * In step 1 we define which Field Vector fields can be used for
+ * filter types.
+ * As we do not have the inner tag defined as a field,
+ * we have to define it first, by reusing one of L1 entries.
+ *
+ * In step 2 we are replacing one of existing filter types with
+ * a new one for QinQ.
+ * As we reusing L1 and replacing L2, some of the default filter
+ * types will disappear,which depends on L1 and L2 entries we reuse.
+ *
+ * Step 1: Create L1 filter of outer vlan (12b) + inner vlan (12b)
+ *
+ * 1.  Create L1 filter of outer vlan (12b) which will be in use
+ *             later when we define the cloud filter.
+ *     a.      Valid_flags.replace_cloud = 0
+ *     b.      Old_filter = 10 (Stag_Inner_Vlan)
+ *     c.      New_filter = 0x10
+ *     d.      TR bit = 0xff (optional, not used here)
+ *     e.      Buffer – 2 entries:
+ *             i.      Byte 0 = 8 (outer vlan FV index).
+ *                     Byte 1 = 0 (rsv)
+ *                     Byte 2-3 = 0x0fff
+ *             ii.     Byte 0 = 37 (inner vlan FV index).
+ *                     Byte 1 =0 (rsv)
+ *                     Byte 2-3 = 0x0fff
+ *
+ * Step 2:
+ * 2.  Create cloud filter using two L1 filters entries: stag and
+ *             new filter(outer vlan+ inner vlan)
+ *     a.      Valid_flags.replace_cloud = 1
+ *     b.      Old_filter = 1 (instead of outer IP)
+ *     c.      New_filter = 0x10
+ *     d.      Buffer – 2 entries:
+ *             i.      Byte 0 = 0x80 | 7 (valid | Stag).
+ *                     Byte 1-3 = 0 (rsv)
+ *             ii.     Byte 8 = 0x80 | 0x10 (valid | new l1 filter step1)
+ *                     Byte 9-11 = 0 (rsv)
+ */
+static int
+i40e_cloud_filter_qinq_create(struct i40e_pf *pf)
+{
+       int ret = -ENOTSUP;
+       struct i40e_aqc_replace_cloud_filters_cmd  filter_replace;
+       struct i40e_aqc_replace_cloud_filters_cmd_buf  filter_replace_buf;
+       struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+       struct rte_eth_dev *dev = ((struct i40e_adapter *)hw->back)->eth_dev;
 
-static void
-i40e_generate_profile_info_sec(char *name, struct i40e_ddp_version *version,
-                              uint32_t track_id, uint8_t *profile_info_sec,
-                              bool add)
-{
-       struct i40e_profile_section_header *sec = NULL;
-       struct i40e_profile_info *pinfo;
-
-       sec = (struct i40e_profile_section_header *)profile_info_sec;
-       sec->tbl_size = 1;
-       sec->data_end = sizeof(struct i40e_profile_section_header) +
-               sizeof(struct i40e_profile_info);
-       sec->section.type = SECTION_TYPE_INFO;
-       sec->section.offset = sizeof(struct i40e_profile_section_header);
-       sec->section.size = sizeof(struct i40e_profile_info);
-       pinfo = (struct i40e_profile_info *)(profile_info_sec +
-                                            sec->section.offset);
-       pinfo->track_id = track_id;
-       memcpy(pinfo->name, name, I40E_DDP_NAME_SIZE);
-       memcpy(&pinfo->version, version, sizeof(struct i40e_ddp_version));
-       if (add)
-               pinfo->op = I40E_DDP_ADD_TRACKID;
-       else
-               pinfo->op = I40E_DDP_REMOVE_TRACKID;
-}
+       if (pf->support_multi_driver) {
+               PMD_DRV_LOG(ERR, "Replace cloud filter is not supported.");
+               return ret;
+       }
 
-static enum i40e_status_code
-i40e_add_rm_profile_info(struct i40e_hw *hw, uint8_t *profile_info_sec)
-{
-       enum i40e_status_code status = I40E_SUCCESS;
-       struct i40e_profile_section_header *sec;
-       uint32_t track_id;
-       uint32_t offset = 0;
-       uint32_t info = 0;
+       /* Init */
+       memset(&filter_replace, 0,
+              sizeof(struct i40e_aqc_replace_cloud_filters_cmd));
+       memset(&filter_replace_buf, 0,
+              sizeof(struct i40e_aqc_replace_cloud_filters_cmd_buf));
 
-       sec = (struct i40e_profile_section_header *)profile_info_sec;
-       track_id = ((struct i40e_profile_info *)(profile_info_sec +
-                                        sec->section.offset))->track_id;
+       /* create L1 filter */
+       filter_replace.old_filter_type =
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_IVLAN;
+       filter_replace.new_filter_type = I40E_AQC_ADD_CLOUD_FILTER_0X10;
+       filter_replace.tr_bit = 0;
 
-       status = i40e_aq_write_ddp(hw, (void *)sec, sec->data_end,
-                                  track_id, &offset, &info, NULL);
-       if (status)
-               PMD_DRV_LOG(ERR, "Failed to add/remove profile info: "
-                           "offset %d, info %d",
-                           offset, info);
+       /* Prepare the buffer, 2 entries */
+       filter_replace_buf.data[0] = I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_VLAN;
+       filter_replace_buf.data[0] |=
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+       /* Field Vector 12b mask */
+       filter_replace_buf.data[2] = 0xff;
+       filter_replace_buf.data[3] = 0x0f;
+       filter_replace_buf.data[4] =
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_INNER_VLAN;
+       filter_replace_buf.data[4] |=
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+       /* Field Vector 12b mask */
+       filter_replace_buf.data[6] = 0xff;
+       filter_replace_buf.data[7] = 0x0f;
+       ret = i40e_aq_replace_cloud_filters(hw, &filter_replace,
+                       &filter_replace_buf);
+       if (ret != I40E_SUCCESS)
+               return ret;
 
-       return status;
-}
+       if (filter_replace.old_filter_type !=
+           filter_replace.new_filter_type)
+               PMD_DRV_LOG(WARNING, "i40e device %s changed cloud l1 type."
+                           " original: 0x%x, new: 0x%x",
+                           dev->device->name,
+                           filter_replace.old_filter_type,
+                           filter_replace.new_filter_type);
 
-#define I40E_PROFILE_INFO_SIZE 48
-#define I40E_MAX_PROFILE_NUM 16
+       /* Apply the second L2 cloud filter */
+       memset(&filter_replace, 0,
+              sizeof(struct i40e_aqc_replace_cloud_filters_cmd));
+       memset(&filter_replace_buf, 0,
+              sizeof(struct i40e_aqc_replace_cloud_filters_cmd_buf));
 
-/* Check if the profile info exists */
-static int
-i40e_check_profile_info(uint8_t port, uint8_t *profile_info_sec)
-{
-       struct rte_eth_dev *dev = &rte_eth_devices[port];
-       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       uint8_t *buff;
-       struct rte_pmd_i40e_profile_list *p_list;
-       struct rte_pmd_i40e_profile_info *pinfo, *p;
-       uint32_t i;
-       int ret;
+       /* create L2 filter, input for L2 filter will be L1 filter  */
+       filter_replace.valid_flags = I40E_AQC_REPLACE_CLOUD_FILTER;
+       filter_replace.old_filter_type = I40E_AQC_ADD_CLOUD_FILTER_OIP;
+       filter_replace.new_filter_type = I40E_AQC_ADD_CLOUD_FILTER_0X10;
 
-       buff = rte_zmalloc("pinfo_list",
-                          (I40E_PROFILE_INFO_SIZE * I40E_MAX_PROFILE_NUM + 4),
-                          0);
-       if (!buff) {
-               PMD_DRV_LOG(ERR, "failed to allocate memory");
-               return -1;
-       }
+       /* Prepare the buffer, 2 entries */
+       filter_replace_buf.data[0] = I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG;
+       filter_replace_buf.data[0] |=
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+       filter_replace_buf.data[4] = I40E_AQC_ADD_CLOUD_FILTER_0X10;
+       filter_replace_buf.data[4] |=
+               I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+       ret = i40e_aq_replace_cloud_filters(hw, &filter_replace,
+                       &filter_replace_buf);
+       if (!ret && (filter_replace.old_filter_type !=
+                    filter_replace.new_filter_type))
+               PMD_DRV_LOG(WARNING, "i40e device %s changed cloud filter type."
+                           " original: 0x%x, new: 0x%x",
+                           dev->device->name,
+                           filter_replace.old_filter_type,
+                           filter_replace.new_filter_type);
 
-       ret = i40e_aq_get_ddp_list(hw, (void *)buff,
-                     (I40E_PROFILE_INFO_SIZE * I40E_MAX_PROFILE_NUM + 4),
-                     0, NULL);
-       if (ret) {
-               PMD_DRV_LOG(ERR, "Failed to get profile info list.");
-               rte_free(buff);
-               return -1;
-       }
-       p_list = (struct rte_pmd_i40e_profile_list *)buff;
-       pinfo = (struct rte_pmd_i40e_profile_info *)(profile_info_sec +
-                            sizeof(struct i40e_profile_section_header));
-       for (i = 0; i < p_list->p_count; i++) {
-               p = &p_list->p_info[i];
-               if ((pinfo->track_id == p->track_id) &&
-                   !memcmp(&pinfo->version, &p->version,
-                           sizeof(struct i40e_ddp_version)) &&
-                   !memcmp(&pinfo->name, &p->name,
-                           I40E_DDP_NAME_SIZE)) {
-                       PMD_DRV_LOG(INFO, "Profile exists.");
-                       rte_free(buff);
-                       return 1;
-               }
-       }
+       return ret;
+}
 
-       rte_free(buff);
+int
+i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out,
+                  const struct rte_flow_action_rss *in)
+{
+       if (in->key_len > RTE_DIM(out->key) ||
+           in->queue_num > RTE_DIM(out->queue))
+               return -EINVAL;
+       if (!in->key && in->key_len)
+               return -EINVAL;
+       out->conf = (struct rte_flow_action_rss){
+               .func = in->func,
+               .level = in->level,
+               .types = in->types,
+               .key_len = in->key_len,
+               .queue_num = in->queue_num,
+               .queue = memcpy(out->queue, in->queue,
+                               sizeof(*in->queue) * in->queue_num),
+       };
+       if (in->key)
+               out->conf.key = memcpy(out->key, in->key, in->key_len);
        return 0;
 }
 
 int
-rte_pmd_i40e_process_ddp_package(uint8_t port, uint8_t *buff,
-                                uint32_t size,
-                                enum rte_pmd_i40e_package_op op)
+i40e_action_rss_same(const struct rte_flow_action_rss *comp,
+                    const struct rte_flow_action_rss *with)
 {
-       struct rte_eth_dev *dev;
-       struct i40e_hw *hw;
-       struct i40e_package_header *pkg_hdr;
-       struct i40e_generic_seg_header *profile_seg_hdr;
-       struct i40e_generic_seg_header *metadata_seg_hdr;
-       uint32_t track_id;
-       uint8_t *profile_info_sec;
-       int is_exist;
-       enum i40e_status_code status = I40E_SUCCESS;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
+       return (comp->func == with->func &&
+               comp->level == with->level &&
+               comp->types == with->types &&
+               comp->key_len == with->key_len &&
+               comp->queue_num == with->queue_num &&
+               !memcmp(comp->key, with->key, with->key_len) &&
+               !memcmp(comp->queue, with->queue,
+                       sizeof(*with->queue) * with->queue_num));
+}
 
-       hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+int
+i40e_config_rss_filter(struct i40e_pf *pf,
+               struct i40e_rte_flow_rss_conf *conf, bool add)
+{
+       struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+       uint32_t i, lut = 0;
+       uint16_t j, num;
+       struct rte_eth_rss_conf rss_conf = {
+               .rss_key = conf->conf.key_len ?
+                       (void *)(uintptr_t)conf->conf.key : NULL,
+               .rss_key_len = conf->conf.key_len,
+               .rss_hf = conf->conf.types,
+       };
+       struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
 
-       if (size < (sizeof(struct i40e_package_header) +
-                   sizeof(struct i40e_metadata_segment) +
-                   sizeof(uint32_t) * 2)) {
-               PMD_DRV_LOG(ERR, "Buff is invalid.");
+       if (!add) {
+               if (i40e_action_rss_same(&rss_info->conf, &conf->conf)) {
+                       i40e_pf_disable_rss(pf);
+                       memset(rss_info, 0,
+                               sizeof(struct i40e_rte_flow_rss_conf));
+                       return 0;
+               }
                return -EINVAL;
        }
 
-       pkg_hdr = (struct i40e_package_header *)buff;
+       /* If both VMDQ and RSS enabled, not all of PF queues are configured.
+        * It's necessary to calculate the actual PF queues that are configured.
+        */
+       if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG)
+               num = i40e_pf_calc_configured_queues_num(pf);
+       else
+               num = pf->dev_data->nb_rx_queues;
 
-       if (!pkg_hdr) {
-               PMD_DRV_LOG(ERR, "Failed to fill the package structure");
-               return -EINVAL;
-       }
+       num = RTE_MIN(num, conf->conf.queue_num);
+       PMD_DRV_LOG(INFO, "Max of contiguous %u PF queues are configured",
+                       num);
 
-       if (pkg_hdr->segment_count < 2) {
-               PMD_DRV_LOG(ERR, "Segment_count should be 2 at least.");
-               return -EINVAL;
+       if (num == 0) {
+               PMD_DRV_LOG(ERR, "No PF queues are configured to enable RSS");
+               return -ENOTSUP;
        }
 
-       /* Find metadata segment */
-       metadata_seg_hdr = i40e_find_segment_in_package(SEGMENT_TYPE_METADATA,
-                                                       pkg_hdr);
-       if (!metadata_seg_hdr) {
-               PMD_DRV_LOG(ERR, "Failed to find metadata segment header");
-               return -EINVAL;
+       /* Fill in redirection table */
+       for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) {
+               if (j == num)
+                       j = 0;
+               lut = (lut << 8) | (conf->conf.queue[j] & ((0x1 <<
+                       hw->func_caps.rss_table_entry_width) - 1));
+               if ((i & 3) == 3)
+                       I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut);
        }
-       track_id = ((struct i40e_metadata_segment *)metadata_seg_hdr)->track_id;
 
-       /* Find profile segment */
-       profile_seg_hdr = i40e_find_segment_in_package(SEGMENT_TYPE_I40E,
-                                                      pkg_hdr);
-       if (!profile_seg_hdr) {
-               PMD_DRV_LOG(ERR, "Failed to find profile segment header");
-               return -EINVAL;
+       if ((rss_conf.rss_hf & pf->adapter->flow_types_mask) == 0) {
+               i40e_pf_disable_rss(pf);
+               return 0;
        }
+       if (rss_conf.rss_key == NULL || rss_conf.rss_key_len <
+               (I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
+               /* Random default keys */
+               static uint32_t rss_key_default[] = {0x6b793944,
+                       0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8,
+                       0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605,
+                       0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581};
 
-       profile_info_sec = rte_zmalloc("i40e_profile_info",
-                              sizeof(struct i40e_profile_section_header) +
-                              sizeof(struct i40e_profile_info),
-                              0);
-       if (!profile_info_sec) {
-               PMD_DRV_LOG(ERR, "Failed to allocate memory");
-               return -EINVAL;
+               rss_conf.rss_key = (uint8_t *)rss_key_default;
+               rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
+                                                       sizeof(uint32_t);
+               PMD_DRV_LOG(INFO,
+                       "No valid RSS key config for i40e, using default\n");
        }
 
-       if (op == RTE_PMD_I40E_PKG_OP_WR_ADD) {
-               /* Check if the profile exists */
-               i40e_generate_profile_info_sec(
-                    ((struct i40e_profile_segment *)profile_seg_hdr)->name,
-                    &((struct i40e_profile_segment *)profile_seg_hdr)->version,
-                    track_id, profile_info_sec, 1);
-               is_exist = i40e_check_profile_info(port, profile_info_sec);
-               if (is_exist > 0) {
-                       PMD_DRV_LOG(ERR, "Profile already exists.");
-                       rte_free(profile_info_sec);
-                       return 1;
-               } else if (is_exist < 0) {
-                       PMD_DRV_LOG(ERR, "Failed to check profile.");
-                       rte_free(profile_info_sec);
-                       return -EINVAL;
-               }
-
-               /* Write profile to HW */
-               status = i40e_write_profile(hw,
-                                (struct i40e_profile_segment *)profile_seg_hdr,
-                                track_id);
-               if (status) {
-                       PMD_DRV_LOG(ERR, "Failed to write profile.");
-                       rte_free(profile_info_sec);
-                       return status;
-               }
+       i40e_hw_rss_hash_set(pf, &rss_conf);
 
-               /* Add profile info to info list */
-               status = i40e_add_rm_profile_info(hw, profile_info_sec);
-               if (status)
-                       PMD_DRV_LOG(ERR, "Failed to add profile info.");
-       } else
-               PMD_DRV_LOG(ERR, "Operation not supported.");
+       if (i40e_rss_conf_init(rss_info, &conf->conf))
+               return -EINVAL;
 
-       rte_free(profile_info_sec);
-       return status;
+       return 0;
 }
 
-int
-rte_pmd_i40e_get_ddp_list(uint8_t port, uint8_t *buff, uint32_t size)
+RTE_INIT(i40e_init_log)
 {
-       struct rte_eth_dev *dev;
-       struct i40e_hw *hw;
-       enum i40e_status_code status = I40E_SUCCESS;
-
-       RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
-
-       dev = &rte_eth_devices[port];
-
-       if (!is_device_supported(dev, &rte_i40e_pmd))
-               return -ENOTSUP;
-
-       if (size < (I40E_PROFILE_INFO_SIZE * I40E_MAX_PROFILE_NUM + 4))
-               return -EINVAL;
-
-       hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-
-       status = i40e_aq_get_ddp_list(hw, (void *)buff,
-                                     size, 0, NULL);
-
-       return status;
+       i40e_logtype_init = rte_log_register("pmd.net.i40e.init");
+       if (i40e_logtype_init >= 0)
+               rte_log_set_level(i40e_logtype_init, RTE_LOG_NOTICE);
+       i40e_logtype_driver = rte_log_register("pmd.net.i40e.driver");
+       if (i40e_logtype_driver >= 0)
+               rte_log_set_level(i40e_logtype_driver, RTE_LOG_NOTICE);
 }
+
+RTE_PMD_REGISTER_PARAM_STRING(net_i40e,
+                             ETH_I40E_FLOATING_VEB_ARG "=1"
+                             ETH_I40E_FLOATING_VEB_LIST_ARG "=<string>"
+                             ETH_I40E_QUEUE_NUM_PER_VF_ARG "=1|2|4|8|16"
+                             ETH_I40E_SUPPORT_MULTI_DRIVER "=1"
+                             ETH_I40E_USE_LATEST_VEC "=0|1");