i40e: fix VLAN filtering
[dpdk.git] / drivers / net / i40e / i40e_ethdev.c
index 6cf99dc..87d8f4b 100644 (file)
 #define I40E_PTP_1GB_INCVAL      0x2000000000ULL
 #define I40E_PRTTSYN_TSYNENA     0x80000000
 #define I40E_PRTTSYN_TSYNTYPE    0x0e000000
-#define I40E_CYCLECOUNTER_MASK   0xffffffffffffffff
+#define I40E_CYCLECOUNTER_MASK   0xffffffffffffffffULL
 
 #define I40E_MAX_PERCENT            100
 #define I40E_DEFAULT_DCB_APP_NUM    1
 #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_W3 | \
+       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)
 
 /* Source MAC address */
 #define I40E_REG_INSET_L2_SMAC                   0x1C00000000000000ULL
 /* VLAN tag in the outer L2 header */
-#define I40E_REG_INSET_L2_OUTER_VLAN             0x0000000000800000ULL
+#define I40E_REG_INSET_L2_OUTER_VLAN             0x0080000000000000ULL
 /* VLAN tag in the inner L2 header */
-#define I40E_REG_INSET_L2_INNER_VLAN             0x0000000001000000ULL
+#define I40E_REG_INSET_L2_INNER_VLAN             0x0100000000000000ULL
 /* Source IPv4 address */
 #define I40E_REG_INSET_L3_SRC_IP4                0x0001800000000000ULL
 /* Destination IPv4 address */
 #define I40E_INSET_IPV6_TC_MASK       0x0009F00FUL
 #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 */
+#define PCI_DEV_CTRL_REG           0xA8
+/* Bit mask of Extended Tag capability */
+#define PCI_DEV_CAP_EXT_TAG_MASK   0x20
+/* Bit shift of Extended Tag enable/disable */
+#define PCI_DEV_CTRL_EXT_TAG_SHIFT 8
+/* Bit mask of Extended Tag enable/disable */
+#define PCI_DEV_CTRL_EXT_TAG_MASK  (1 << PCI_DEV_CTRL_EXT_TAG_SHIFT)
+
 static int eth_i40e_dev_init(struct rte_eth_dev *eth_dev);
 static int eth_i40e_dev_uninit(struct rte_eth_dev *eth_dev);
 static int i40e_dev_configure(struct rte_eth_dev *dev);
@@ -299,7 +315,9 @@ static void i40e_dev_info_get(struct rte_eth_dev *dev,
 static int i40e_vlan_filter_set(struct rte_eth_dev *dev,
                                uint16_t vlan_id,
                                int on);
-static void i40e_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid);
+static 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 void i40e_vlan_strip_queue_set(struct rte_eth_dev *dev,
                                      uint16_t queue,
@@ -369,10 +387,10 @@ static int i40e_dev_rss_hash_update(struct rte_eth_dev *dev,
                                    struct rte_eth_rss_conf *rss_conf);
 static int i40e_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
                                      struct rte_eth_rss_conf *rss_conf);
-static int i40e_dev_udp_tunnel_add(struct rte_eth_dev *dev,
-                               struct rte_eth_udp_tunnel *udp_tunnel);
-static int i40e_dev_udp_tunnel_del(struct rte_eth_dev *dev,
-                               struct rte_eth_udp_tunnel *udp_tunnel);
+static int i40e_dev_udp_tunnel_port_add(struct rte_eth_dev *dev,
+                                       struct rte_eth_udp_tunnel *udp_tunnel);
+static int i40e_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
+                                       struct rte_eth_udp_tunnel *udp_tunnel);
 static int i40e_ethertype_filter_set(struct i40e_pf *pf,
                        struct rte_eth_ethertype_filter *filter,
                        bool add);
@@ -386,7 +404,7 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 static int i40e_dev_get_dcb_info(struct rte_eth_dev *dev,
                                  struct rte_eth_dcb_info *dcb_info);
 static void i40e_configure_registers(struct i40e_hw *hw);
-static void i40e_hw_init(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 int i40e_mirror_rule_set(struct rte_eth_dev *dev,
                        struct rte_eth_mirror_conf *mirror_conf,
@@ -467,8 +485,8 @@ static const struct eth_dev_ops i40e_eth_dev_ops = {
        .reta_query                   = i40e_dev_rss_reta_query,
        .rss_hash_update              = i40e_dev_rss_hash_update,
        .rss_hash_conf_get            = i40e_dev_rss_hash_conf_get,
-       .udp_tunnel_add               = i40e_dev_udp_tunnel_add,
-       .udp_tunnel_del               = i40e_dev_udp_tunnel_del,
+       .udp_tunnel_port_add          = i40e_dev_udp_tunnel_port_add,
+       .udp_tunnel_port_del          = i40e_dev_udp_tunnel_port_del,
        .filter_ctrl                  = i40e_dev_filter_ctrl,
        .rxq_info_get                 = i40e_rxq_info_get,
        .txq_info_get                 = i40e_txq_info_get,
@@ -765,7 +783,7 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
        i40e_clear_hw(hw);
 
        /* Initialize the hardware */
-       i40e_hw_init(hw);
+       i40e_hw_init(dev);
 
        /* Reset here to make sure all is clean for each PF */
        ret = i40e_pf_reset(hw);
@@ -872,6 +890,20 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
        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;
+       }
+       ret = i40e_vlan_tpid_set(dev, ETH_VLAN_TYPE_INNER, 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 */
        ret = i40e_pf_setup(pf);
        if (ret) {
@@ -919,6 +951,11 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
         */
        i40e_add_tx_flow_control_drop_filter(pf);
 
+       /* Set the max frame size to 0x2600 by default,
+        * in case other drivers changed the default value.
+        */
+       i40e_aq_set_mac_config(hw, I40E_FRAME_SIZE_MAX, TRUE, 0, NULL);
+
        /* initialize mirror rule list */
        TAILQ_INIT(&pf->mirror_list);
 
@@ -1347,58 +1384,15 @@ i40e_parse_link_speed(uint16_t eth_link_speed)
 }
 
 static int
-i40e_phy_conf_link(struct i40e_hw *hw, uint8_t abilities, uint8_t force_speed)
-{
-       enum i40e_status_code status;
-       struct i40e_aq_get_phy_abilities_resp phy_ab;
-       struct i40e_aq_set_phy_config phy_conf;
-       const uint8_t mask = I40E_AQ_PHY_FLAG_PAUSE_TX |
-                       I40E_AQ_PHY_FLAG_PAUSE_RX |
-                       I40E_AQ_PHY_FLAG_LOW_POWER;
-       const uint8_t advt = I40E_LINK_SPEED_40GB |
-                       I40E_LINK_SPEED_10GB |
-                       I40E_LINK_SPEED_1GB |
-                       I40E_LINK_SPEED_100MB;
-       int ret = -ENOTSUP;
-
-       /* Skip it on 40G interfaces, as a workaround for the link issue */
-       if (i40e_is_40G_device(hw->device_id))
-               return I40E_SUCCESS;
-
-       status = i40e_aq_get_phy_capabilities(hw, false, false, &phy_ab,
-                                             NULL);
-       if (status)
-               return ret;
-
-       memset(&phy_conf, 0, sizeof(phy_conf));
-
-       /* bits 0-2 use the values from get_phy_abilities_resp */
-       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;
-
-       /* use get_phy_abilities_resp value for the rest */
-       phy_conf.phy_type = phy_ab.phy_type;
-       phy_conf.eee_capability = phy_ab.eee_capability;
-       phy_conf.eeer = phy_ab.eeer_val;
-       phy_conf.low_power_ctrl = phy_ab.d3_lpan;
-
-       PMD_DRV_LOG(DEBUG, "\tCurrent: abilities %x, link_speed %x",
-                   phy_ab.abilities, phy_ab.link_speed);
-       PMD_DRV_LOG(DEBUG, "\tConfig:  abilities %x, link_speed %x",
-                   phy_conf.abilities, phy_conf.link_speed);
-
-       status = i40e_aq_set_phy_config(hw, &phy_conf, NULL);
-       if (status)
-               return ret;
-
+i40e_phy_conf_link(__rte_unused struct i40e_hw *hw,
+                  __rte_unused uint8_t abilities,
+                  __rte_unused uint8_t force_speed)
+{
+       /* Skip any phy config on both 10G and 40G interfaces, as a workaround
+        * for the link control limitation of that all link control should be
+        * handled by firmware. It should follow up if link control will be
+        * opened to software driver in future firmware versions.
+        */
        return I40E_SUCCESS;
 }
 
@@ -2357,11 +2351,59 @@ i40e_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
                return i40e_vsi_delete_vlan(vsi, vlan_id);
 }
 
-static void
-i40e_vlan_tpid_set(__rte_unused struct rte_eth_dev *dev,
-                  __rte_unused uint16_t tpid)
+static int
+i40e_vlan_tpid_set(struct rte_eth_dev *dev,
+                  enum rte_vlan_type vlan_type,
+                  uint16_t tpid)
 {
-       PMD_INIT_FUNC_TRACE();
+       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;
+
+       switch (vlan_type) {
+       case ETH_VLAN_TYPE_OUTER:
+               reg_id = 2;
+               break;
+       case ETH_VLAN_TYPE_INNER:
+               reg_id = 3;
+               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;
+       }
+       PMD_DRV_LOG(DEBUG, "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;
+       }
+
+       ret = i40e_aq_debug_write_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;
+       }
+       PMD_DRV_LOG(DEBUG, "Debug write 0x%08"PRIx64" to "
+                   "I40E_GL_SWT_L2TAGCTRL[%d]", reg_w, reg_id);
+
+       return ret;
 }
 
 static void
@@ -2370,6 +2412,13 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
        struct i40e_vsi *vsi = pf->main_vsi;
 
+       if (mask & ETH_VLAN_FILTER_MASK) {
+               if (dev->data->dev_conf.rxmode.hw_vlan_filter)
+                       i40e_vsi_config_vlan_filter(vsi, TRUE);
+               else
+                       i40e_vsi_config_vlan_filter(vsi, FALSE);
+       }
+
        if (mask & ETH_VLAN_STRIP_MASK) {
                /* Enable or disable VLAN stripping */
                if (dev->data->dev_conf.rxmode.hw_vlan_strip)
@@ -2621,7 +2670,10 @@ i40e_macaddr_add(struct rte_eth_dev *dev,
        }
 
        (void)rte_memcpy(&mac_filter.mac_addr, mac_addr, ETHER_ADDR_LEN);
-       mac_filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
+       if (dev->data->dev_conf.rxmode.hw_vlan_filter)
+               mac_filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
+       else
+               mac_filter.filter_type = RTE_MAC_PERFECT_MATCH;
 
        if (pool == 0)
                vsi = pf->main_vsi;
@@ -3451,7 +3503,7 @@ i40e_res_pool_alloc(struct i40e_res_pool_info *pool,
        pool->num_free -= valid_entry->len;
        pool->num_alloc += valid_entry->len;
 
-       return (valid_entry->base + pool->base);
+       return valid_entry->base + pool->base;
 }
 
 /**
@@ -3798,14 +3850,22 @@ i40e_update_default_filter_setting(struct i40e_vsi *vsi)
        return i40e_vsi_add_mac(vsi, &filter);
 }
 
-static int
-i40e_vsi_dump_bw_config(struct i40e_vsi *vsi)
+#define I40E_3_BIT_MASK     0x7
+/*
+ * i40e_vsi_get_bw_config - Query VSI BW Information
+ * @vsi: the VSI to be queried
+ *
+ * Returns 0 on success, negative value on failure
+ */
+static enum i40e_status_code
+i40e_vsi_get_bw_config(struct i40e_vsi *vsi)
 {
        struct i40e_aqc_query_vsi_bw_config_resp bw_config;
        struct i40e_aqc_query_vsi_ets_sla_config_resp ets_sla_config;
        struct i40e_hw *hw = &vsi->adapter->hw;
        i40e_status ret;
        int i;
+       uint32_t bw_max;
 
        memset(&bw_config, 0, sizeof(bw_config));
        ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL);
@@ -3824,20 +3884,32 @@ i40e_vsi_dump_bw_config(struct i40e_vsi *vsi)
                return ret;
        }
 
-       /* Not store the info yet, just print out */
-       PMD_DRV_LOG(INFO, "VSI bw limit:%u", bw_config.port_bw_limit);
-       PMD_DRV_LOG(INFO, "VSI max_bw:%u", bw_config.max_bw);
+       /* store and print out BW info */
+       vsi->bw_info.bw_limit = rte_le_to_cpu_16(bw_config.port_bw_limit);
+       vsi->bw_info.bw_max = bw_config.max_bw;
+       PMD_DRV_LOG(DEBUG, "VSI bw limit:%u", vsi->bw_info.bw_limit);
+       PMD_DRV_LOG(DEBUG, "VSI max_bw:%u", vsi->bw_info.bw_max);
+       bw_max = rte_le_to_cpu_16(ets_sla_config.tc_bw_max[0]) |
+                   (rte_le_to_cpu_16(ets_sla_config.tc_bw_max[1]) <<
+                    I40E_16_BIT_WIDTH);
        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-               PMD_DRV_LOG(INFO, "\tVSI TC%u:share credits %u", i,
-                           ets_sla_config.share_credits[i]);
-               PMD_DRV_LOG(INFO, "\tVSI TC%u:credits %u", i,
-                           rte_le_to_cpu_16(ets_sla_config.credits[i]));
-               PMD_DRV_LOG(INFO, "\tVSI TC%u: max credits: %u", i,
-                           rte_le_to_cpu_16(ets_sla_config.credits[i / 4]) >>
-                           (i * 4));
+               vsi->bw_info.bw_ets_share_credits[i] =
+                               ets_sla_config.share_credits[i];
+               vsi->bw_info.bw_ets_credits[i] =
+                               rte_le_to_cpu_16(ets_sla_config.credits[i]);
+               /* 4 bits per TC, 4th bit is reserved */
+               vsi->bw_info.bw_ets_max[i] =
+                       (uint8_t)((bw_max >> (i * I40E_4_BIT_WIDTH)) &
+                                 I40E_3_BIT_MASK);
+               PMD_DRV_LOG(DEBUG, "\tVSI TC%u:share credits %u", i,
+                           vsi->bw_info.bw_ets_share_credits[i]);
+               PMD_DRV_LOG(DEBUG, "\tVSI TC%u:credits %u", i,
+                           vsi->bw_info.bw_ets_credits[i]);
+               PMD_DRV_LOG(DEBUG, "\tVSI TC%u: max credits: %u", i,
+                           vsi->bw_info.bw_ets_max[i]);
        }
 
-       return 0;
+       return I40E_SUCCESS;
 }
 
 /* Setup a VSI */
@@ -4163,7 +4235,7 @@ i40e_vsi_setup(struct i40e_pf *pf,
        }
 
        /* Get VSI BW information */
-       i40e_vsi_dump_bw_config(vsi);
+       i40e_vsi_get_bw_config(vsi);
        return vsi;
 fail_msix_alloc:
        i40e_res_pool_free(&pf->msix_pool,vsi->msix_intr);
@@ -4174,6 +4246,63 @@ fail_mem:
        return NULL;
 }
 
+/* Configure vlan filter on or off */
+int
+i40e_vsi_config_vlan_filter(struct i40e_vsi *vsi, bool on)
+{
+       int i, num;
+       struct i40e_mac_filter *f;
+       struct i40e_mac_filter_info *mac_filter;
+       enum rte_mac_filter_type desired_filter;
+       int ret = I40E_SUCCESS;
+
+       if (on) {
+               /* Filter to match MAC and VLAN */
+               desired_filter = RTE_MACVLAN_PERFECT_MATCH;
+       } else {
+               /* Filter to match only MAC */
+               desired_filter = RTE_MAC_PERFECT_MATCH;
+       }
+
+       num = vsi->mac_num;
+
+       mac_filter = rte_zmalloc("mac_filter_info_data",
+                                num * sizeof(*mac_filter), 0);
+       if (mac_filter == NULL) {
+               PMD_DRV_LOG(ERR, "failed to allocate memory");
+               return I40E_ERR_NO_MEMORY;
+       }
+
+       i = 0;
+
+       /* Remove all existing mac */
+       TAILQ_FOREACH(f, &vsi->mac_list, next) {
+               mac_filter[i] = f->mac_info;
+               ret = i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr);
+               if (ret) {
+                       PMD_DRV_LOG(ERR, "Update VSI failed to %s vlan filter",
+                                   on ? "enable" : "disable");
+                       goto DONE;
+               }
+               i++;
+       }
+
+       /* Override with new filter */
+       for (i = 0; i < num; i++) {
+               mac_filter[i].filter_type = desired_filter;
+               ret = i40e_vsi_add_mac(vsi, &mac_filter[i]);
+               if (ret) {
+                       PMD_DRV_LOG(ERR, "Update VSI failed to %s vlan filter",
+                                   on ? "enable" : "disable");
+                       goto DONE;
+               }
+       }
+
+DONE:
+       rte_free(mac_filter);
+       return ret;
+}
+
 /* Configure vlan stripping on or off */
 int
 i40e_vsi_config_vlan_stripping(struct i40e_vsi *vsi, bool on)
@@ -4221,9 +4350,11 @@ i40e_dev_init_vlan(struct rte_eth_dev *dev)
 {
        struct rte_eth_dev_data *data = dev->data;
        int ret;
+       int mask = 0;
 
        /* Apply vlan offload setting */
-       i40e_vlan_offload_set(dev, ETH_VLAN_STRIP_MASK);
+       mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK;
+       i40e_vlan_offload_set(dev, mask);
 
        /* Apply double-vlan setting, not implemented yet */
 
@@ -5672,9 +5803,14 @@ i40e_set_rss_key(struct i40e_vsi *vsi, uint8_t *key, uint8_t key_len)
        struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
        int ret = 0;
 
-       if (!key || key_len != ((I40E_PFQF_HKEY_MAX_INDEX + 1) *
-               sizeof(uint32_t)))
+       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) *
+               sizeof(uint32_t)) {
+               PMD_DRV_LOG(ERR, "Invalid key length %u", key_len);
                return -EINVAL;
+       }
 
        if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) {
                struct i40e_aqc_get_set_rss_key_data *key_dw =
@@ -5810,6 +5946,12 @@ i40e_dev_get_filter_type(uint16_t filter_type, uint16_t *flag)
        case ETH_TUNNEL_FILTER_IMAC:
                *flag = I40E_AQC_ADD_CLOUD_FILTER_IMAC;
                break;
+       case ETH_TUNNEL_FILTER_OIP:
+               *flag = I40E_AQC_ADD_CLOUD_FILTER_OIP;
+               break;
+       case ETH_TUNNEL_FILTER_IIP:
+               *flag = I40E_AQC_ADD_CLOUD_FILTER_IIP;
+               break;
        default:
                PMD_DRV_LOG(ERR, "invalid tunnel filter type");
                return -EINVAL;
@@ -5824,7 +5966,9 @@ i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
                        uint8_t add)
 {
        uint16_t ip_type;
-       uint8_t tun_type = 0;
+       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;
@@ -5841,21 +5985,22 @@ i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
        }
        pfilter = cld_filter;
 
-       (void)rte_memcpy(&pfilter->outer_mac, tunnel_filter->outer_mac,
-                       sizeof(struct ether_addr));
-       (void)rte_memcpy(&pfilter->inner_mac, tunnel_filter->inner_mac,
-                       sizeof(struct ether_addr));
+       ether_addr_copy(&tunnel_filter->outer_mac, (struct ether_addr*)&pfilter->outer_mac);
+       ether_addr_copy(&tunnel_filter->inner_mac, (struct ether_addr*)&pfilter->inner_mac);
 
-       pfilter->inner_vlan = tunnel_filter->inner_vlan;
+       pfilter->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;
-               (void)rte_memcpy(&pfilter->ipaddr.v4.data,
-                               &tunnel_filter->ip_addr,
+               rte_memcpy(&pfilter->ipaddr.v4.data,
+                               &rte_cpu_to_le_32(tunnel_filter->ip_addr.ipv4_addr),
                                sizeof(pfilter->ipaddr.v4.data));
        } else {
                ip_type = I40E_AQC_ADD_CLOUD_FLAGS_IPV6;
-               (void)rte_memcpy(&pfilter->ipaddr.v6.data,
-                               &tunnel_filter->ip_addr,
+               for (i = 0; i < 4; i++) {
+                       convert_ipv6[i] =
+                       rte_cpu_to_le_32(tunnel_filter->ip_addr.ipv6_addr[i]);
+               }
+               rte_memcpy(&pfilter->ipaddr.v6.data, &convert_ipv6,
                                sizeof(pfilter->ipaddr.v6.data));
        }
 
@@ -5867,6 +6012,9 @@ i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
        case RTE_TUNNEL_TYPE_NVGRE:
                tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_NVGRE_OMAC;
                break;
+       case RTE_TUNNEL_TYPE_IP_IN_GRE:
+               tun_type = I40E_AQC_ADD_CLOUD_TNL_TYPE_IP;
+               break;
        default:
                /* Other tunnel types is not supported. */
                PMD_DRV_LOG(ERR, "tunnel type is not supported.");
@@ -5881,10 +6029,11 @@ i40e_dev_tunnel_filter_set(struct i40e_pf *pf,
                return -EINVAL;
        }
 
-       pfilter->flags |= I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE | ip_type |
-               (tun_type << I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT);
-       pfilter->tenant_id = tunnel_filter->tenant_id;
-       pfilter->queue_number = tunnel_filter->queue_id;
+       pfilter->flags |= rte_cpu_to_le_16(
+               I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE |
+               ip_type | (tun_type << I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT));
+       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)
                ret = i40e_aq_add_cloud_filters(hw, vsi->seid, cld_filter, 1);
@@ -5989,8 +6138,8 @@ i40e_del_vxlan_port(struct i40e_pf *pf, uint16_t port)
 
 /* Add UDP tunneling port */
 static int
-i40e_dev_udp_tunnel_add(struct rte_eth_dev *dev,
-                       struct rte_eth_udp_tunnel *udp_tunnel)
+i40e_dev_udp_tunnel_port_add(struct rte_eth_dev *dev,
+                            struct rte_eth_udp_tunnel *udp_tunnel)
 {
        int ret = 0;
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
@@ -6020,8 +6169,8 @@ i40e_dev_udp_tunnel_add(struct rte_eth_dev *dev,
 
 /* Remove UDP tunneling port */
 static int
-i40e_dev_udp_tunnel_del(struct rte_eth_dev *dev,
-                       struct rte_eth_udp_tunnel *udp_tunnel)
+i40e_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
+                            struct rte_eth_udp_tunnel *udp_tunnel)
 {
        int ret = 0;
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
@@ -6144,13 +6293,13 @@ i40e_tunnel_filter_param_check(struct i40e_pf *pf,
        }
 
        if ((filter->filter_type & ETH_TUNNEL_FILTER_OMAC) &&
-               (is_zero_ether_addr(filter->outer_mac))) {
+               (is_zero_ether_addr(&filter->outer_mac))) {
                PMD_DRV_LOG(ERR, "Cannot add NULL outer MAC address");
                return -EINVAL;
        }
 
        if ((filter->filter_type & ETH_TUNNEL_FILTER_IMAC) &&
-               (is_zero_ether_addr(filter->inner_mac))) {
+               (is_zero_ether_addr(&filter->inner_mac))) {
                PMD_DRV_LOG(ERR, "Cannot add NULL inner MAC address");
                return -EINVAL;
        }
@@ -7274,14 +7423,62 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
        return ret;
 }
 
+/*
+ * Check and enable Extended Tag.
+ * Enabling Extended Tag is important for 40G performance.
+ */
+static void
+i40e_enable_extended_tag(struct rte_eth_dev *dev)
+{
+       uint32_t buf = 0;
+       int ret;
+
+       ret = rte_eal_pci_read_config(dev->pci_dev, &buf, sizeof(buf),
+                                     PCI_DEV_CAP_REG);
+       if (ret < 0) {
+               PMD_DRV_LOG(ERR, "Failed to read PCI offset 0x%x",
+                           PCI_DEV_CAP_REG);
+               return;
+       }
+       if (!(buf & PCI_DEV_CAP_EXT_TAG_MASK)) {
+               PMD_DRV_LOG(ERR, "Does not support Extended Tag");
+               return;
+       }
+
+       buf = 0;
+       ret = rte_eal_pci_read_config(dev->pci_dev, &buf, sizeof(buf),
+                                     PCI_DEV_CTRL_REG);
+       if (ret < 0) {
+               PMD_DRV_LOG(ERR, "Failed to read PCI offset 0x%x",
+                           PCI_DEV_CTRL_REG);
+               return;
+       }
+       if (buf & PCI_DEV_CTRL_EXT_TAG_MASK) {
+               PMD_DRV_LOG(DEBUG, "Extended Tag has already been enabled");
+               return;
+       }
+       buf |= PCI_DEV_CTRL_EXT_TAG_MASK;
+       ret = rte_eal_pci_write_config(dev->pci_dev, &buf, sizeof(buf),
+                                      PCI_DEV_CTRL_REG);
+       if (ret < 0) {
+               PMD_DRV_LOG(ERR, "Failed to write PCI offset 0x%x",
+                           PCI_DEV_CTRL_REG);
+               return;
+       }
+}
+
 /*
  * As some registers wouldn't be reset unless a global hardware reset,
  * hardware initialization is needed to put those registers into an
  * expected initial state.
  */
 static void
-i40e_hw_init(struct i40e_hw *hw)
+i40e_hw_init(struct rte_eth_dev *dev)
 {
+       struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       i40e_enable_extended_tag(dev);
+
        /* clear the PF Queue Filter control register */
        I40E_WRITE_REG(hw, I40E_PFQF_CTL_0, 0);
 
@@ -8090,70 +8287,6 @@ i40e_parse_dcb_configure(struct rte_eth_dev *dev,
        return 0;
 }
 
-/*
- * i40e_vsi_get_bw_info - Query VSI BW Information
- * @vsi: the VSI being queried
- *
- * Returns 0 on success, negative value on failure
- */
-static enum i40e_status_code
-i40e_vsi_get_bw_info(struct i40e_vsi *vsi)
-{
-       struct i40e_aqc_query_vsi_ets_sla_config_resp bw_ets_config = {0};
-       struct i40e_aqc_query_vsi_bw_config_resp bw_config = {0};
-       struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
-       enum i40e_status_code ret;
-       int i;
-       uint32_t tc_bw_max;
-
-       /* Get the VSI level BW configuration */
-       ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL);
-       if (ret) {
-               PMD_INIT_LOG(ERR,
-                        "couldn't get PF vsi bw config, err %s aq_err %s\n",
-                        i40e_stat_str(hw, ret),
-                        i40e_aq_str(hw, hw->aq.asq_last_status));
-               return ret;
-       }
-
-       /* Get the VSI level BW configuration per TC */
-       ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid, &bw_ets_config,
-                                                 NULL);
-       if (ret) {
-               PMD_INIT_LOG(ERR,
-                        "couldn't get PF vsi ets bw config, err %s aq_err %s\n",
-                        i40e_stat_str(hw, ret),
-                        i40e_aq_str(hw, hw->aq.asq_last_status));
-               return ret;
-       }
-
-       if (bw_config.tc_valid_bits != bw_ets_config.tc_valid_bits) {
-               PMD_INIT_LOG(WARNING,
-                        "Enabled TCs mismatch from querying VSI BW info"
-                        " 0x%08x 0x%08x\n", bw_config.tc_valid_bits,
-                        bw_ets_config.tc_valid_bits);
-               /* Still continuing */
-       }
-
-       vsi->bw_info.bw_limit = rte_le_to_cpu_16(bw_config.port_bw_limit);
-       vsi->bw_info.bw_max_quanta = bw_config.max_bw;
-       tc_bw_max = rte_le_to_cpu_16(bw_ets_config.tc_bw_max[0]) |
-                   (rte_le_to_cpu_16(bw_ets_config.tc_bw_max[1]) << 16);
-       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-               vsi->bw_info.bw_ets_share_credits[i] =
-                               bw_ets_config.share_credits[i];
-               vsi->bw_info.bw_ets_limit_credits[i] =
-                               rte_le_to_cpu_16(bw_ets_config.credits[i]);
-               /* 3 bits out of 4 for each TC */
-               vsi->bw_info.bw_ets_max_quanta[i] =
-                       (uint8_t)((tc_bw_max >> (i * 4)) & 0x7);
-               PMD_INIT_LOG(DEBUG,
-                        "%s: vsi seid = %d, TC = %d, qset = 0x%x\n",
-                        __func__, vsi->seid, i, bw_config.qs_handles[i]);
-       }
-
-       return ret;
-}
 
 static enum i40e_status_code
 i40e_vsi_update_queue_mapping(struct i40e_vsi *vsi,
@@ -8287,8 +8420,8 @@ i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 tc_map)
        vsi->info.mapping_flags = ctxt.info.mapping_flags;
        vsi->info.valid_sections = 0;
 
-       /* Update current VSI BW information */
-       ret = i40e_vsi_get_bw_info(vsi);
+       /* query and update current VSI BW information */
+       ret = i40e_vsi_get_bw_config(vsi);
        if (ret) {
                PMD_INIT_LOG(ERR,
                         "Failed updating vsi bw info, err %s aq_err %s",
@@ -8325,7 +8458,8 @@ i40e_dcb_hw_configure(struct i40e_pf *pf,
        uint32_t val;
 
        /* Use the FW API if FW > v4.4*/
-       if (!((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver >= 4))) {
+       if (!(((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver >= 4)) ||
+             (hw->aq.fw_maj_ver >= 5))) {
                PMD_INIT_LOG(ERR, "FW < v4.4, can not use FW LLDP API"
                                  " to configure DCB");
                return I40E_ERR_FIRMWARE_API_VERSION;