net/i40e: return errno when interrupt setup fails
[dpdk.git] / drivers / net / i40e / i40e_ethdev.c
index c9ba789..6d09bba 100644 (file)
@@ -51,6 +51,7 @@
 #include <rte_dev.h>
 #include <rte_eth_ctrl.h>
 #include <rte_tailq.h>
+#include <rte_hash_crc.h>
 
 #include "i40e_logs.h"
 #include "base/i40e_prototype.h"
 #define I40E_DEFAULT_DCB_APP_NUM    1
 #define I40E_DEFAULT_DCB_APP_PRIO   3
 
-#define I40E_INSET_NONE            0x00000000000000000ULL
-
-/* bit0 ~ bit 7 */
-#define I40E_INSET_DMAC            0x0000000000000001ULL
-#define I40E_INSET_SMAC            0x0000000000000002ULL
-#define I40E_INSET_VLAN_OUTER      0x0000000000000004ULL
-#define I40E_INSET_VLAN_INNER      0x0000000000000008ULL
-#define I40E_INSET_VLAN_TUNNEL     0x0000000000000010ULL
-
-/* bit 8 ~ bit 15 */
-#define I40E_INSET_IPV4_SRC        0x0000000000000100ULL
-#define I40E_INSET_IPV4_DST        0x0000000000000200ULL
-#define I40E_INSET_IPV6_SRC        0x0000000000000400ULL
-#define I40E_INSET_IPV6_DST        0x0000000000000800ULL
-#define I40E_INSET_SRC_PORT        0x0000000000001000ULL
-#define I40E_INSET_DST_PORT        0x0000000000002000ULL
-#define I40E_INSET_SCTP_VT         0x0000000000004000ULL
-
-/* bit 16 ~ bit 31 */
-#define I40E_INSET_IPV4_TOS        0x0000000000010000ULL
-#define I40E_INSET_IPV4_PROTO      0x0000000000020000ULL
-#define I40E_INSET_IPV4_TTL        0x0000000000040000ULL
-#define I40E_INSET_IPV6_TC         0x0000000000080000ULL
-#define I40E_INSET_IPV6_FLOW       0x0000000000100000ULL
-#define I40E_INSET_IPV6_NEXT_HDR   0x0000000000200000ULL
-#define I40E_INSET_IPV6_HOP_LIMIT  0x0000000000400000ULL
-#define I40E_INSET_TCP_FLAGS       0x0000000000800000ULL
-
-/* bit 32 ~ bit 47, tunnel fields */
-#define I40E_INSET_TUNNEL_IPV4_DST       0x0000000100000000ULL
-#define I40E_INSET_TUNNEL_IPV6_DST       0x0000000200000000ULL
-#define I40E_INSET_TUNNEL_DMAC           0x0000000400000000ULL
-#define I40E_INSET_TUNNEL_SRC_PORT       0x0000000800000000ULL
-#define I40E_INSET_TUNNEL_DST_PORT       0x0000001000000000ULL
-#define I40E_INSET_TUNNEL_ID             0x0000002000000000ULL
-
-/* bit 48 ~ bit 55 */
-#define I40E_INSET_LAST_ETHER_TYPE 0x0001000000000000ULL
-
-/* bit 56 ~ bit 63, Flex Payload */
-#define I40E_INSET_FLEX_PAYLOAD_W1 0x0100000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W2 0x0200000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W3 0x0400000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W4 0x0800000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W5 0x1000000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W6 0x2000000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W7 0x4000000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD_W8 0x8000000000000000ULL
-#define I40E_INSET_FLEX_PAYLOAD \
-       (I40E_INSET_FLEX_PAYLOAD_W1 | I40E_INSET_FLEX_PAYLOAD_W2 | \
-       I40E_INSET_FLEX_PAYLOAD_W3 | I40E_INSET_FLEX_PAYLOAD_W4 | \
-       I40E_INSET_FLEX_PAYLOAD_W5 | I40E_INSET_FLEX_PAYLOAD_W6 | \
-       I40E_INSET_FLEX_PAYLOAD_W7 | I40E_INSET_FLEX_PAYLOAD_W8)
-
 /**
  * Below are values for writing un-exposed registers suggested
  * by silicon experts
 #define I40E_INSET_IPV6_HOP_LIMIT_MASK  0x000CFF00UL
 #define I40E_INSET_IPV6_NEXT_HDR_MASK   0x000C00FFUL
 
-#define I40E_GL_SWT_L2TAGCTRL(_i)             (0x001C0A70 + ((_i) * 4))
-#define I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_SHIFT 16
-#define I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_MASK  \
-       I40E_MASK(0xFFFF, I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_SHIFT)
-
 /* PCI offset for querying capability */
 #define PCI_DEV_CAP_REG            0xA4
 /* PCI offset for enabling/disabling Extended Tag */
@@ -324,6 +266,8 @@ static int i40e_dev_queue_stats_mapping_set(struct rte_eth_dev *dev,
                                            uint16_t queue_id,
                                            uint8_t stat_idx,
                                            uint8_t is_rx);
+static int i40e_fw_version_get(struct rte_eth_dev *dev,
+                               char *fw_version, size_t fw_size);
 static void i40e_dev_info_get(struct rte_eth_dev *dev,
                              struct rte_eth_dev_info *dev_info);
 static int i40e_vlan_filter_set(struct rte_eth_dev *dev,
@@ -406,9 +350,6 @@ static int i40e_dev_udp_tunnel_port_add(struct rte_eth_dev *dev,
 static int i40e_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
                                        struct rte_eth_udp_tunnel *udp_tunnel);
 static void i40e_filter_input_set_init(struct i40e_pf *pf);
-static int i40e_ethertype_filter_set(struct i40e_pf *pf,
-                       struct rte_eth_ethertype_filter *filter,
-                       bool add);
 static int i40e_ethertype_filter_handle(struct rte_eth_dev *dev,
                                enum rte_filter_op filter_op,
                                void *arg);
@@ -461,6 +402,22 @@ static void i40e_set_default_mac_addr(struct rte_eth_dev *dev,
 
 static int i40e_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
 
+static int i40e_ethertype_filter_convert(
+       const struct rte_eth_ethertype_filter *input,
+       struct i40e_ethertype_filter *filter);
+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_remove_cloud_filters_element_data *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 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 const struct rte_pci_id pci_id_i40e_map[] = {
        { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710) },
        { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QEMU) },
@@ -503,6 +460,7 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
        .stats_reset                  = i40e_dev_stats_reset,
        .xstats_reset                 = i40e_dev_stats_reset,
        .queue_stats_mapping_set      = i40e_dev_queue_stats_mapping_set,
+       .fw_version_get               = i40e_fw_version_get,
        .dev_infos_get                = i40e_dev_info_get,
        .dev_supported_ptypes_get     = i40e_dev_supported_ptypes_get,
        .vlan_filter_set              = i40e_vlan_filter_set,
@@ -671,8 +629,7 @@ static const struct rte_i40e_xstats_name_off rte_i40e_txq_prio_strings[] = {
 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 |
-                       RTE_PCI_DRV_DETACHABLE,
+               .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
                .probe = rte_eth_dev_pci_probe,
                .remove = rte_eth_dev_pci_remove,
        },
@@ -928,6 +885,134 @@ config_floating_veb(struct rte_eth_dev *dev)
 #define I40E_L2_TAGS_S_TAG_SHIFT 1
 #define I40E_L2_TAGS_S_TAG_MASK I40E_MASK(0x1, I40E_L2_TAGS_S_TAG_SHIFT)
 
+static int
+i40e_init_ethtype_filter_list(struct rte_eth_dev *dev)
+{
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
+       char ethertype_hash_name[RTE_HASH_NAMESIZE];
+       int ret;
+
+       struct rte_hash_parameters ethertype_hash_params = {
+               .name = ethertype_hash_name,
+               .entries = I40E_MAX_ETHERTYPE_FILTER_NUM,
+               .key_len = sizeof(struct i40e_ethertype_filter_input),
+               .hash_func = rte_hash_crc,
+       };
+
+       /* 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_rule->hash_table = rte_hash_create(&ethertype_hash_params);
+       if (!ethertype_rule->hash_table) {
+               PMD_INIT_LOG(ERR, "Failed to create ethertype hash table!");
+               return -EINVAL;
+       }
+       ethertype_rule->hash_map = rte_zmalloc("i40e_ethertype_hash_map",
+                                      sizeof(struct i40e_ethertype_filter *) *
+                                      I40E_MAX_ETHERTYPE_FILTER_NUM,
+                                      0);
+       if (!ethertype_rule->hash_map) {
+               PMD_INIT_LOG(ERR,
+                            "Failed to allocate memory for ethertype hash map!");
+               ret = -ENOMEM;
+               goto err_ethertype_hash_map_alloc;
+       }
+
+       return 0;
+
+err_ethertype_hash_map_alloc:
+       rte_hash_free(ethertype_rule->hash_table);
+
+       return ret;
+}
+
+static int
+i40e_init_tunnel_filter_list(struct rte_eth_dev *dev)
+{
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct i40e_tunnel_rule *tunnel_rule = &pf->tunnel;
+       char tunnel_hash_name[RTE_HASH_NAMESIZE];
+       int ret;
+
+       struct rte_hash_parameters tunnel_hash_params = {
+               .name = tunnel_hash_name,
+               .entries = I40E_MAX_TUNNEL_FILTER_NUM,
+               .key_len = sizeof(struct i40e_tunnel_filter_input),
+               .hash_func = rte_hash_crc,
+       };
+
+       /* 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_rule->hash_table = rte_hash_create(&tunnel_hash_params);
+       if (!tunnel_rule->hash_table) {
+               PMD_INIT_LOG(ERR, "Failed to create tunnel hash table!");
+               return -EINVAL;
+       }
+       tunnel_rule->hash_map = rte_zmalloc("i40e_tunnel_hash_map",
+                                   sizeof(struct i40e_tunnel_filter *) *
+                                   I40E_MAX_TUNNEL_FILTER_NUM,
+                                   0);
+       if (!tunnel_rule->hash_map) {
+               PMD_INIT_LOG(ERR,
+                            "Failed to allocate memory for tunnel hash map!");
+               ret = -ENOMEM;
+               goto err_tunnel_hash_map_alloc;
+       }
+
+       return 0;
+
+err_tunnel_hash_map_alloc:
+       rte_hash_free(tunnel_rule->hash_table);
+
+       return ret;
+}
+
+static int
+i40e_init_fdir_filter_list(struct rte_eth_dev *dev)
+{
+       struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+       struct i40e_fdir_info *fdir_info = &pf->fdir;
+       char fdir_hash_name[RTE_HASH_NAMESIZE];
+       int ret;
+
+       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),
+               .hash_func = rte_hash_crc,
+       };
+
+       /* 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_info->hash_table = rte_hash_create(&fdir_hash_params);
+       if (!fdir_info->hash_table) {
+               PMD_INIT_LOG(ERR, "Failed to create fdir hash table!");
+               return -EINVAL;
+       }
+       fdir_info->hash_map = rte_zmalloc("i40e_fdir_hash_map",
+                                         sizeof(struct i40e_fdir_filter *) *
+                                         I40E_MAX_FDIR_FILTER_NUM,
+                                         0);
+       if (!fdir_info->hash_map) {
+               PMD_INIT_LOG(ERR,
+                            "Failed to allocate memory for fdir hash map!");
+               ret = -ENOMEM;
+               goto err_fdir_hash_map_alloc;
+       }
+       return 0;
+
+err_fdir_hash_map_alloc:
+       rte_hash_free(fdir_info->hash_table);
+
+       return ret;
+}
+
 static int
 eth_i40e_dev_init(struct rte_eth_dev *dev)
 {
@@ -945,6 +1030,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
        dev->dev_ops = &i40e_eth_dev_ops;
        dev->rx_pkt_burst = i40e_recv_pkts;
        dev->tx_pkt_burst = i40e_xmit_pkts;
+       dev->tx_pkt_prepare = i40e_prep_pkts;
 
        /* for secondary processes, we don't initialise any further as primary
         * has already done this work. Only check we don't need a different
@@ -958,6 +1044,7 @@ eth_i40e_dev_init(struct rte_eth_dev *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;
@@ -1182,8 +1269,26 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
                pf->flags &= ~I40E_FLAG_DCB;
        }
 
+       ret = i40e_init_ethtype_filter_list(dev);
+       if (ret < 0)
+               goto err_init_ethtype_filter_list;
+       ret = i40e_init_tunnel_filter_list(dev);
+       if (ret < 0)
+               goto err_init_tunnel_filter_list;
+       ret = i40e_init_fdir_filter_list(dev);
+       if (ret < 0)
+               goto err_init_fdir_filter_list;
+
        return 0;
 
+err_init_fdir_filter_list:
+       rte_free(pf->tunnel.hash_table);
+       rte_free(pf->tunnel.hash_map);
+err_init_tunnel_filter_list:
+       rte_free(pf->ethertype.hash_table);
+       rte_free(pf->ethertype.hash_map);
+err_init_ethtype_filter_list:
+       rte_free(dev->data->mac_addrs);
 err_mac_alloc:
        i40e_vsi_release(pf->main_vsi);
 err_setup_pf_switch:
@@ -1203,13 +1308,73 @@ err_sync_phy_type:
        return ret;
 }
 
+static void
+i40e_rm_ethtype_filter_list(struct i40e_pf *pf)
+{
+       struct i40e_ethertype_filter *p_ethertype;
+       struct i40e_ethertype_rule *ethertype_rule;
+
+       ethertype_rule = &pf->ethertype;
+       /* Remove all ethertype filter rules and hash */
+       if (ethertype_rule->hash_map)
+               rte_free(ethertype_rule->hash_map);
+       if (ethertype_rule->hash_table)
+               rte_hash_free(ethertype_rule->hash_table);
+
+       while ((p_ethertype = TAILQ_FIRST(&ethertype_rule->ethertype_list))) {
+               TAILQ_REMOVE(&ethertype_rule->ethertype_list,
+                            p_ethertype, rules);
+               rte_free(p_ethertype);
+       }
+}
+
+static void
+i40e_rm_tunnel_filter_list(struct i40e_pf *pf)
+{
+       struct i40e_tunnel_filter *p_tunnel;
+       struct i40e_tunnel_rule *tunnel_rule;
+
+       tunnel_rule = &pf->tunnel;
+       /* Remove all tunnel director rules and hash */
+       if (tunnel_rule->hash_map)
+               rte_free(tunnel_rule->hash_map);
+       if (tunnel_rule->hash_table)
+               rte_hash_free(tunnel_rule->hash_table);
+
+       while ((p_tunnel = TAILQ_FIRST(&tunnel_rule->tunnel_list))) {
+               TAILQ_REMOVE(&tunnel_rule->tunnel_list, p_tunnel, rules);
+               rte_free(p_tunnel);
+       }
+}
+
+static void
+i40e_rm_fdir_filter_list(struct i40e_pf *pf)
+{
+       struct i40e_fdir_filter *p_fdir;
+       struct i40e_fdir_info *fdir_info;
+
+       fdir_info = &pf->fdir;
+       /* Remove all flow director rules and hash */
+       if (fdir_info->hash_map)
+               rte_free(fdir_info->hash_map);
+       if (fdir_info->hash_table)
+               rte_hash_free(fdir_info->hash_table);
+
+       while ((p_fdir = TAILQ_FIRST(&fdir_info->fdir_list))) {
+               TAILQ_REMOVE(&fdir_info->fdir_list, p_fdir, rules);
+               rte_free(p_fdir);
+       }
+}
+
 static int
 eth_i40e_dev_uninit(struct rte_eth_dev *dev)
 {
+       struct i40e_pf *pf;
        struct rte_pci_device *pci_dev;
        struct rte_intr_handle *intr_handle;
        struct i40e_hw *hw;
        struct i40e_filter_control_settings settings;
+       struct rte_flow *p_flow;
        int ret;
        uint8_t aq_fail = 0;
 
@@ -1218,6 +1383,7 @@ eth_i40e_dev_uninit(struct rte_eth_dev *dev)
        if (rte_eal_process_type() != RTE_PROC_PRIMARY)
                return 0;
 
+       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);
        intr_handle = &pci_dev->intr_handle;
@@ -1256,6 +1422,16 @@ eth_i40e_dev_uninit(struct rte_eth_dev *dev)
        rte_intr_callback_unregister(intr_handle,
                                     i40e_dev_interrupt_handler, dev);
 
+       i40e_rm_ethtype_filter_list(pf);
+       i40e_rm_tunnel_filter_list(pf);
+       i40e_rm_fdir_filter_list(pf);
+
+       /* Remove all flows */
+       while ((p_flow = TAILQ_FIRST(&pf->flow_list))) {
+               TAILQ_REMOVE(&pf->flow_list, p_flow, node);
+               rte_free(p_flow);
+       }
+
        return 0;
 }
 
@@ -1320,6 +1496,8 @@ i40e_dev_configure(struct rte_eth_dev *dev)
                }
        }
 
+       TAILQ_INIT(&pf->flow_list);
+
        return 0;
 
 err_dcb:
@@ -1637,6 +1815,8 @@ i40e_phy_conf_link(struct i40e_hw *hw,
 
        /* 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.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;
        phy_conf.low_power_ctrl = phy_ab.d3_lpan;
@@ -1662,8 +1842,7 @@ i40e_apply_link_speed(struct rte_eth_dev *dev)
        struct rte_eth_conf *conf = &dev->data->dev_conf;
 
        speed = i40e_parse_link_speeds(conf->link_speeds);
-       if (!I40E_PHY_TYPE_SUPPORT_25G(hw->phy.phy_types))
-               abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
+       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;
@@ -1702,8 +1881,9 @@ i40e_dev_start(struct rte_eth_dev *dev)
             !RTE_ETH_DEV_SRIOV(dev).active) &&
            dev->data->dev_conf.intr_conf.rxq != 0) {
                intr_vector = dev->data->nb_rx_queues;
-               if (rte_intr_efd_enable(intr_handle, intr_vector))
-                       return -1;
+               ret = rte_intr_efd_enable(intr_handle, intr_vector);
+               if (ret)
+                       return ret;
        }
 
        if (rte_intr_dp_is_en(intr_handle) && !intr_handle->intr_vec) {
@@ -1803,6 +1983,8 @@ i40e_dev_start(struct rte_eth_dev *dev)
        /* enable uio intr after callback register */
        rte_intr_enable(intr_handle);
 
+       i40e_filter_restore(pf);
+
        return I40E_SUCCESS;
 
 err_up:
@@ -2003,8 +2185,7 @@ i40e_dev_set_link_down(struct rte_eth_dev *dev)
        uint8_t abilities = 0;
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-       if (!I40E_PHY_TYPE_SUPPORT_25G(hw->phy.phy_types))
-               abilities = I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
+       abilities = I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
        return i40e_phy_conf_link(hw, abilities, speed);
 }
 
@@ -2593,6 +2774,34 @@ i40e_dev_queue_stats_mapping_set(__rte_unused struct rte_eth_dev *dev,
        return -ENOSYS;
 }
 
+static int
+i40e_fw_version_get(struct rte_eth_dev *dev, char *fw_version, size_t fw_size)
+{
+       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       u32 full_ver;
+       u8 ver, patch;
+       u16 build;
+       int ret;
+
+       full_ver = hw->nvm.oem_ver;
+       ver = (u8)(full_ver >> 24);
+       build = (u16)((full_ver >> 8) & 0xffff);
+       patch = (u8)(full_ver & 0xff);
+
+       ret = snprintf(fw_version, fw_size,
+                "%d.%d%d 0x%08x %d.%d.%d",
+                ((hw->nvm.version >> 12) & 0xf),
+                ((hw->nvm.version >> 4) & 0xff),
+                (hw->nvm.version & 0xf), hw->nvm.eetrack,
+                ver, build, patch);
+
+       ret += 1; /* add the size of '\0' */
+       if (fw_size < (u32)ret)
+               return ret;
+       else
+               return 0;
+}
+
 static void
 i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
@@ -2664,6 +2873,8 @@ i40e_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                .nb_max = I40E_MAX_RING_DESC,
                .nb_min = I40E_MIN_RING_DESC,
                .nb_align = I40E_ALIGN_RING_DESC,
+               .nb_seg_max = I40E_TX_MAX_SEG,
+               .nb_mtu_seg_max = I40E_TX_MAX_MTU_SEG,
        };
 
        if (pf->flags & I40E_FLAG_VMDQ) {
@@ -4127,7 +4338,7 @@ i40e_veb_setup(struct i40e_pf *pf, struct i40e_vsi *vsi)
        ret = i40e_aq_get_veb_parameters(hw, veb->seid, NULL, NULL,
                                &veb->stats_idx, NULL, NULL, NULL);
        if (ret != I40E_SUCCESS) {
-               PMD_DRV_LOG(ERR, "Get veb statics index failed, aq_err: %d",
+               PMD_DRV_LOG(ERR, "Get veb statistics index failed, aq_err: %d",
                            hw->aq.asq_last_status);
                goto fail;
        }
@@ -6218,18 +6429,14 @@ i40e_parse_hena(uint64_t flags)
                rss_hf |= ETH_RSS_FRAG_IPV4;
        if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP))
                rss_hf |= ETH_RSS_NONFRAG_IPV4_TCP;
-#ifdef X722_SUPPORT
        if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK))
                rss_hf |= ETH_RSS_NONFRAG_IPV4_TCP;
-#endif
        if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV4_UDP))
                rss_hf |= ETH_RSS_NONFRAG_IPV4_UDP;
-#ifdef X722_SUPPORT
        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;
-#endif
        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))
@@ -6238,18 +6445,14 @@ i40e_parse_hena(uint64_t flags)
                rss_hf |= ETH_RSS_FRAG_IPV6;
        if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP))
                rss_hf |= ETH_RSS_NONFRAG_IPV6_TCP;
-#ifdef X722_SUPPORT
        if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK))
                rss_hf |= ETH_RSS_NONFRAG_IPV6_TCP;
-#endif
        if (flags & (1ULL << I40E_FILTER_PCTYPE_NONF_IPV6_UDP))
                rss_hf |= ETH_RSS_NONFRAG_IPV6_UDP;
-#ifdef X722_SUPPORT
        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;
-#endif
        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))
@@ -6447,7 +6650,86 @@ i40e_dev_get_filter_type(uint16_t filter_type, uint16_t *flag)
        return 0;
 }
 
+/* Convert tunnel filter structure */
+static int
+i40e_tunnel_filter_convert(struct i40e_aqc_add_remove_cloud_filters_element_data
+                          *cld_filter,
+                          struct i40e_tunnel_filter *tunnel_filter)
+{
+       ether_addr_copy((struct ether_addr *)&cld_filter->outer_mac,
+                       (struct ether_addr *)&tunnel_filter->input.outer_mac);
+       ether_addr_copy((struct ether_addr *)&cld_filter->inner_mac,
+                       (struct ether_addr *)&tunnel_filter->input.inner_mac);
+       tunnel_filter->input.inner_vlan = cld_filter->inner_vlan;
+       tunnel_filter->input.flags = cld_filter->flags;
+       tunnel_filter->input.tenant_id = cld_filter->tenant_id;
+       tunnel_filter->queue = cld_filter->queue_number;
+
+       return 0;
+}
+
+/* Check if there exists the tunnel filter */
+struct i40e_tunnel_filter *
+i40e_sw_tunnel_filter_lookup(struct i40e_tunnel_rule *tunnel_rule,
+                            const struct i40e_tunnel_filter_input *input)
+{
+       int ret;
+
+       ret = rte_hash_lookup(tunnel_rule->hash_table, (const void *)input);
+       if (ret < 0)
+               return NULL;
+
+       return tunnel_rule->hash_map[ret];
+}
+
+/* Add a tunnel filter into the SW list */
 static int
+i40e_sw_tunnel_filter_insert(struct i40e_pf *pf,
+                            struct i40e_tunnel_filter *tunnel_filter)
+{
+       struct i40e_tunnel_rule *rule = &pf->tunnel;
+       int ret;
+
+       ret = rte_hash_add_key(rule->hash_table, &tunnel_filter->input);
+       if (ret < 0) {
+               PMD_DRV_LOG(ERR,
+                           "Failed to insert tunnel filter to hash table %d!",
+                           ret);
+               return ret;
+       }
+       rule->hash_map[ret] = tunnel_filter;
+
+       TAILQ_INSERT_TAIL(&rule->tunnel_list, tunnel_filter, rules);
+
+       return 0;
+}
+
+/* Delete a tunnel filter from the SW list */
+int
+i40e_sw_tunnel_filter_del(struct i40e_pf *pf,
+                         struct i40e_tunnel_filter_input *input)
+{
+       struct i40e_tunnel_rule *rule = &pf->tunnel;
+       struct i40e_tunnel_filter *tunnel_filter;
+       int ret;
+
+       ret = rte_hash_del_key(rule->hash_table, input);
+       if (ret < 0) {
+               PMD_DRV_LOG(ERR,
+                           "Failed to delete tunnel filter to hash table %d!",
+                           ret);
+               return ret;
+       }
+       tunnel_filter = rule->hash_map[ret];
+       rule->hash_map[ret] = NULL;
+
+       TAILQ_REMOVE(&rule->tunnel_list, tunnel_filter, rules);
+       rte_free(tunnel_filter);
+
+       return 0;
+}
+
+int
 i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
                        struct rte_eth_tunnel_filter_conf *tunnel_filter,
                        uint8_t add)
@@ -6462,6 +6744,9 @@ i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
        struct i40e_vsi *vsi = pf->main_vsi;
        struct i40e_aqc_add_remove_cloud_filters_element_data  *cld_filter;
        struct i40e_aqc_add_remove_cloud_filters_element_data  *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 */
 
        cld_filter = rte_zmalloc("tunnel_filter",
                sizeof(struct i40e_aqc_add_remove_cloud_filters_element_data),
@@ -6524,11 +6809,38 @@ i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
        pfilter->tenant_id = rte_cpu_to_le_32(tunnel_filter->tenant_id);
        pfilter->queue_number = rte_cpu_to_le_16(tunnel_filter->queue_id);
 
-       if (add)
+       /* Check if there is the filter in SW list */
+       memset(&check_filter, 0, sizeof(check_filter));
+       i40e_tunnel_filter_convert(cld_filter, &check_filter);
+       node = i40e_sw_tunnel_filter_lookup(tunnel_rule, &check_filter.input);
+       if (add && node) {
+               PMD_DRV_LOG(ERR, "Conflict with existing tunnel rules!");
+               return -EINVAL;
+       }
+
+       if (!add && !node) {
+               PMD_DRV_LOG(ERR, "There's no corresponding tunnel filter!");
+               return -EINVAL;
+       }
+
+       if (add) {
                ret = i40e_aq_add_cloud_filters(hw, vsi->seid, cld_filter, 1);
-       else
+               if (ret < 0) {
+                       PMD_DRV_LOG(ERR, "Failed to add a tunnel filter.");
+                       return ret;
+               }
+               tunnel = rte_zmalloc("tunnel_filter", sizeof(*tunnel), 0);
+               rte_memcpy(tunnel, &check_filter, sizeof(check_filter));
+               ret = i40e_sw_tunnel_filter_insert(pf, tunnel);
+       } else {
                ret = i40e_aq_remove_cloud_filters(hw, vsi->seid,
-                                               cld_filter, 1);
+                                                  cld_filter, 1);
+               if (ret < 0) {
+                       PMD_DRV_LOG(ERR, "Failed to delete a tunnel filter.");
+                       return ret;
+               }
+               ret = i40e_sw_tunnel_filter_del(pf, &node->input);
+       }
 
        rte_free(cld_filter);
        return ret;
@@ -7121,7 +7433,6 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                        I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
                        I40E_INSET_FLEX_PAYLOAD,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP] =
                        I40E_INSET_DMAC | I40E_INSET_SMAC |
                        I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
@@ -7140,7 +7451,6 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                        I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
                        I40E_INSET_FLEX_PAYLOAD,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV4_TCP] =
                        I40E_INSET_DMAC | I40E_INSET_SMAC |
                        I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
@@ -7150,7 +7460,6 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                        I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
                        I40E_INSET_TCP_FLAGS | I40E_INSET_FLEX_PAYLOAD,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK] =
                        I40E_INSET_DMAC | I40E_INSET_SMAC |
                        I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
@@ -7160,7 +7469,6 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                        I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
                        I40E_INSET_TCP_FLAGS | I40E_INSET_FLEX_PAYLOAD,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] =
                        I40E_INSET_DMAC | I40E_INSET_SMAC |
                        I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
@@ -7194,7 +7502,6 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                        I40E_INSET_IPV6_HOP_LIMIT | I40E_INSET_IPV6_SRC |
                        I40E_INSET_IPV6_DST | I40E_INSET_SRC_PORT |
                        I40E_INSET_DST_PORT | I40E_INSET_FLEX_PAYLOAD,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP] =
                        I40E_INSET_DMAC | I40E_INSET_SMAC |
                        I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
@@ -7213,7 +7520,6 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                        I40E_INSET_IPV6_DST | I40E_INSET_SRC_PORT |
                        I40E_INSET_DST_PORT | I40E_INSET_TCP_FLAGS |
                        I40E_INSET_FLEX_PAYLOAD,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV6_TCP] =
                        I40E_INSET_DMAC | I40E_INSET_SMAC |
                        I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
@@ -7223,7 +7529,6 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                        I40E_INSET_IPV6_DST | I40E_INSET_SRC_PORT |
                        I40E_INSET_DST_PORT | I40E_INSET_TCP_FLAGS |
                        I40E_INSET_FLEX_PAYLOAD,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK] =
                        I40E_INSET_DMAC | I40E_INSET_SMAC |
                        I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
@@ -7233,7 +7538,6 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                        I40E_INSET_IPV6_DST | I40E_INSET_SRC_PORT |
                        I40E_INSET_DST_PORT | I40E_INSET_TCP_FLAGS |
                        I40E_INSET_FLEX_PAYLOAD,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV6_SCTP] =
                        I40E_INSET_DMAC | I40E_INSET_SMAC |
                        I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
@@ -7273,7 +7577,6 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                I40E_INSET_IPV4_TOS | I40E_INSET_IPV4_TTL |
                I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP] =
                I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
                I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
@@ -7284,19 +7587,16 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                I40E_INSET_IPV4_TOS | I40E_INSET_IPV4_TTL |
                I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV4_TCP] =
                I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
                I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                I40E_INSET_IPV4_TOS | I40E_INSET_IPV4_TTL |
                I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK] =
                I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
                I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                I40E_INSET_IPV4_TOS | I40E_INSET_IPV4_TTL |
                I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] =
                I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
                I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
@@ -7318,7 +7618,6 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
                I40E_INSET_IPV6_TC | I40E_INSET_IPV6_HOP_LIMIT |
                I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP] =
                I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
                I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
@@ -7329,19 +7628,16 @@ i40e_get_valid_input_set(enum i40e_filter_pctype pctype,
                I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
                I40E_INSET_IPV6_TC | I40E_INSET_IPV6_HOP_LIMIT |
                I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV6_TCP] =
                I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
                I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
                I40E_INSET_IPV6_TC | I40E_INSET_IPV6_HOP_LIMIT |
                I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK] =
                I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
                I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
                I40E_INSET_IPV6_TC | I40E_INSET_IPV6_HOP_LIMIT |
                I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV6_SCTP] =
                I40E_INSET_VLAN_OUTER | I40E_INSET_VLAN_INNER |
                I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
@@ -7385,7 +7681,7 @@ i40e_validate_input_set(enum i40e_filter_pctype pctype,
 }
 
 /* default input set fields combination per pctype */
-static uint64_t
+uint64_t
 i40e_get_default_input_set(uint16_t pctype)
 {
        static const uint64_t default_inset_table[] = {
@@ -7394,22 +7690,18 @@ i40e_get_default_input_set(uint16_t pctype)
                [I40E_FILTER_PCTYPE_NONF_IPV4_UDP] =
                        I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP] =
                        I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
                [I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP] =
                        I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV4_TCP] =
                        I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK] =
                        I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] =
                        I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
@@ -7421,22 +7713,18 @@ i40e_get_default_input_set(uint16_t pctype)
                [I40E_FILTER_PCTYPE_NONF_IPV6_UDP] =
                        I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP] =
                        I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
                [I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP] =
                        I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV6_TCP] =
                        I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK] =
                        I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV6_SCTP] =
                        I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
                        I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT |
@@ -8006,16 +8294,95 @@ i40e_hash_filter_ctrl(struct rte_eth_dev *dev,
        return ret;
 }
 
+/* Convert ethertype filter structure */
+static int
+i40e_ethertype_filter_convert(const struct rte_eth_ethertype_filter *input,
+                             struct i40e_ethertype_filter *filter)
+{
+       rte_memcpy(&filter->input.mac_addr, &input->mac_addr, ETHER_ADDR_LEN);
+       filter->input.ether_type = input->ether_type;
+       filter->flags = input->flags;
+       filter->queue = input->queue;
+
+       return 0;
+}
+
+/* Check if there exists the ehtertype filter */
+struct i40e_ethertype_filter *
+i40e_sw_ethertype_filter_lookup(struct i40e_ethertype_rule *ethertype_rule,
+                               const struct i40e_ethertype_filter_input *input)
+{
+       int ret;
+
+       ret = rte_hash_lookup(ethertype_rule->hash_table, (const void *)input);
+       if (ret < 0)
+               return NULL;
+
+       return ethertype_rule->hash_map[ret];
+}
+
+/* Add ethertype filter in SW list */
+static int
+i40e_sw_ethertype_filter_insert(struct i40e_pf *pf,
+                               struct i40e_ethertype_filter *filter)
+{
+       struct i40e_ethertype_rule *rule = &pf->ethertype;
+       int ret;
+
+       ret = rte_hash_add_key(rule->hash_table, &filter->input);
+       if (ret < 0) {
+               PMD_DRV_LOG(ERR,
+                           "Failed to insert ethertype filter"
+                           " to hash table %d!",
+                           ret);
+               return ret;
+       }
+       rule->hash_map[ret] = filter;
+
+       TAILQ_INSERT_TAIL(&rule->ethertype_list, filter, rules);
+
+       return 0;
+}
+
+/* Delete ethertype filter in SW list */
+int
+i40e_sw_ethertype_filter_del(struct i40e_pf *pf,
+                            struct i40e_ethertype_filter_input *input)
+{
+       struct i40e_ethertype_rule *rule = &pf->ethertype;
+       struct i40e_ethertype_filter *filter;
+       int ret;
+
+       ret = rte_hash_del_key(rule->hash_table, input);
+       if (ret < 0) {
+               PMD_DRV_LOG(ERR,
+                           "Failed to delete ethertype filter"
+                           " to hash table %d!",
+                           ret);
+               return ret;
+       }
+       filter = rule->hash_map[ret];
+       rule->hash_map[ret] = NULL;
+
+       TAILQ_REMOVE(&rule->ethertype_list, filter, rules);
+       rte_free(filter);
+
+       return 0;
+}
+
 /*
  * Configure ethertype filter, which can director packet by filtering
  * with mac address and ether_type or only ether_type
  */
-static int
+int
 i40e_ethertype_filter_set(struct i40e_pf *pf,
                        struct rte_eth_ethertype_filter *filter,
                        bool add)
 {
        struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+       struct i40e_ethertype_rule *ethertype_rule = &pf->ethertype;
+       struct i40e_ethertype_filter *ethertype_filter, *node;
+       struct i40e_ethertype_filter check_filter;
        struct i40e_control_filter_stats stats;
        uint16_t flags = 0;
        int ret;
@@ -8034,6 +8401,21 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
                PMD_DRV_LOG(WARNING, "filter vlan ether_type in first tag is"
                        " not supported.");
 
+       /* Check if there is the filter in SW list */
+       memset(&check_filter, 0, sizeof(check_filter));
+       i40e_ethertype_filter_convert(filter, &check_filter);
+       node = i40e_sw_ethertype_filter_lookup(ethertype_rule,
+                                              &check_filter.input);
+       if (add && node) {
+               PMD_DRV_LOG(ERR, "Conflict with existing ethertype rules!");
+               return -EINVAL;
+       }
+
+       if (!add && !node) {
+               PMD_DRV_LOG(ERR, "There's no corresponding ethertype filter!");
+               return -EINVAL;
+       }
+
        if (!(filter->flags & RTE_ETHTYPE_FLAGS_MAC))
                flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC;
        if (filter->flags & RTE_ETHTYPE_FLAGS_DROP)
@@ -8054,7 +8436,19 @@ i40e_ethertype_filter_set(struct i40e_pf *pf,
                         stats.mac_etype_free, stats.etype_free);
        if (ret < 0)
                return -ENOSYS;
-       return 0;
+
+       /* Add or delete a filter in SW list */
+       if (add) {
+               ethertype_filter = rte_zmalloc("ethertype_filter",
+                                      sizeof(*ethertype_filter), 0);
+               rte_memcpy(ethertype_filter, &check_filter,
+                          sizeof(check_filter));
+               ret = i40e_sw_ethertype_filter_insert(pf, ethertype_filter);
+       } else {
+               ret = i40e_sw_ethertype_filter_del(pf, &node->input);
+       }
+
+       return ret;
 }
 
 /*
@@ -8127,6 +8521,11 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
        case RTE_ETH_FILTER_FDIR:
                ret = i40e_fdir_ctrl_func(dev, filter_op, arg);
                break;
+       case RTE_ETH_FILTER_GENERIC:
+               if (filter_op != RTE_ETH_FILTER_GET)
+                       return -EINVAL;
+               *(const void **)arg = &i40e_flow_ops;
+               break;
        default:
                PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
                                                        filter_type);
@@ -8236,18 +8635,14 @@ i40e_pctype_to_flowtype(enum i40e_filter_pctype pctype)
                [I40E_FILTER_PCTYPE_FRAG_IPV4] = RTE_ETH_FLOW_FRAG_IPV4,
                [I40E_FILTER_PCTYPE_NONF_IPV4_UDP] =
                        RTE_ETH_FLOW_NONFRAG_IPV4_UDP,
-#ifdef X722_SUPPORT
                [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,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV4_TCP] =
                        RTE_ETH_FLOW_NONFRAG_IPV4_TCP,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK] =
                        RTE_ETH_FLOW_NONFRAG_IPV4_TCP,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] =
                        RTE_ETH_FLOW_NONFRAG_IPV4_SCTP,
                [I40E_FILTER_PCTYPE_NONF_IPV4_OTHER] =
@@ -8255,18 +8650,14 @@ i40e_pctype_to_flowtype(enum i40e_filter_pctype pctype)
                [I40E_FILTER_PCTYPE_FRAG_IPV6] = RTE_ETH_FLOW_FRAG_IPV6,
                [I40E_FILTER_PCTYPE_NONF_IPV6_UDP] =
                        RTE_ETH_FLOW_NONFRAG_IPV6_UDP,
-#ifdef X722_SUPPORT
                [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,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV6_TCP] =
                        RTE_ETH_FLOW_NONFRAG_IPV6_TCP,
-#ifdef X722_SUPPORT
                [I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK] =
                        RTE_ETH_FLOW_NONFRAG_IPV6_TCP,
-#endif
                [I40E_FILTER_PCTYPE_NONF_IPV6_SCTP] =
                        RTE_ETH_FLOW_NONFRAG_IPV6_SCTP,
                [I40E_FILTER_PCTYPE_NONF_IPV6_OTHER] =
@@ -9758,3 +10149,63 @@ i40e_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 
        return ret;
 }
+
+/* Restore ethertype filter */
+static void
+i40e_ethertype_filter_restore(struct i40e_pf *pf)
+{
+       struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+       struct i40e_ethertype_filter_list
+               *ethertype_list = &pf->ethertype.ethertype_list;
+       struct i40e_ethertype_filter *f;
+       struct i40e_control_filter_stats stats;
+       uint16_t flags;
+
+       TAILQ_FOREACH(f, ethertype_list, rules) {
+               flags = 0;
+               if (!(f->flags & RTE_ETHTYPE_FLAGS_MAC))
+                       flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC;
+               if (f->flags & RTE_ETHTYPE_FLAGS_DROP)
+                       flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP;
+               flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TO_QUEUE;
+
+               memset(&stats, 0, sizeof(stats));
+               i40e_aq_add_rem_control_packet_filter(hw,
+                                           f->input.mac_addr.addr_bytes,
+                                           f->input.ether_type,
+                                           flags, pf->main_vsi->seid,
+                                           f->queue, 1, &stats, NULL);
+       }
+       PMD_DRV_LOG(INFO, "Ethertype filter:"
+                   " mac_etype_used = %u, etype_used = %u,"
+                   " mac_etype_free = %u, etype_free = %u\n",
+                   stats.mac_etype_used, stats.etype_used,
+                   stats.mac_etype_free, stats.etype_free);
+}
+
+/* Restore tunnel filter */
+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_tunnel_filter_list
+               *tunnel_list = &pf->tunnel.tunnel_list;
+       struct i40e_tunnel_filter *f;
+       struct i40e_aqc_add_remove_cloud_filters_element_data cld_filter;
+
+       TAILQ_FOREACH(f, tunnel_list, rules) {
+               memset(&cld_filter, 0, sizeof(cld_filter));
+               rte_memcpy(&cld_filter, &f->input, sizeof(f->input));
+               cld_filter.queue_number = f->queue;
+               i40e_aq_add_cloud_filters(hw, vsi->seid, &cld_filter, 1);
+       }
+}
+
+static void
+i40e_filter_restore(struct i40e_pf *pf)
+{
+       i40e_ethertype_filter_restore(pf);
+       i40e_tunnel_filter_restore(pf);
+       i40e_fdir_filter_restore(pf);
+}