@@ -3910,6 +3910,7 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
int qinq = dev->data->dev_conf.rxmode.offloads &
RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;
int ret = 0;
+ u16 sw_flags = 0, valid_flags = 0;
if ((vlan_type != RTE_ETH_VLAN_TYPE_INNER &&
vlan_type != RTE_ETH_VLAN_TYPE_OUTER) ||
@@ -3927,15 +3928,28 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,
/* 802.1ad frames ability is added in NVM API 1.7*/
if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
if (qinq) {
+ if (pf->is_outer_vlan_processing) {
+ sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+ valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+ }
if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
hw->first_tag = rte_cpu_to_le_16(tpid);
else if (vlan_type == RTE_ETH_VLAN_TYPE_INNER)
hw->second_tag = rte_cpu_to_le_16(tpid);
} else {
- if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)
- hw->second_tag = rte_cpu_to_le_16(tpid);
+ if (pf->is_outer_vlan_processing) {
+ sw_flags = 0;
+ valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;
+ }
+ if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER) {
+ if (pf->is_outer_vlan_processing)
+ hw->first_tag = rte_cpu_to_le_16(tpid);
+ else
+ hw->second_tag = rte_cpu_to_le_16(tpid);
+ }
}
- ret = i40e_aq_set_switch_config(hw, 0, 0, 0, NULL);
+ ret = i40e_aq_set_switch_config(hw, sw_flags,
+ valid_flags, 0, NULL);
if (ret != I40E_SUCCESS) {
PMD_DRV_LOG(ERR,
"Set switch config failed aq_err: %d",
@@ -3987,8 +4001,12 @@ 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_mac_filter_info *mac_filter;
struct i40e_vsi *vsi = pf->main_vsi;
struct rte_eth_rxmode *rxmode;
+ struct i40e_mac_filter *f;
+ int i, num, ret;
+ void *temp;
rxmode = &dev->data->dev_conf.rxmode;
if (mask & RTE_ETH_VLAN_FILTER_MASK) {
@@ -4007,6 +4025,35 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
}
if (mask & RTE_ETH_VLAN_EXTEND_MASK) {
+ i = 0;
+ 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;
+ }
+
+ /**
+ * Outer VLAN processing is supported after firmware v8.4, kernel driver
+ * also changes the default behavior to support this feature. To align with
+ * kernel driver, set switch config in 'i40e_vlan_tpie_set' to support for
+ * outer VLAN processing. But it is forbidden for firmware to change the
+ * Inner/Outer VLAN configuration while there are MAC/VLAN filters in the
+ * switch table. Therefore, we need to clear the MAC table before setting
+ * config, and then restore the MAC table after setting. This feature is
+ * recommended to be used in firmware v8.6 at least.
+ **/
+ /* Remove all existing mac */
+ RTE_TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
+ mac_filter[i] = f->mac_info;
+ ret = i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr);
+ if (ret != I40E_SUCCESS) {
+ PMD_DRV_LOG(ERR, "Failed to delete mac filter");
+ return -EIO;
+ }
+ i++;
+ }
if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND) {
i40e_vsi_config_double_vlan(vsi, TRUE);
/* Set global registers with default ethertype. */
@@ -4014,9 +4061,20 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)
RTE_ETHER_TYPE_VLAN);
i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,
RTE_ETHER_TYPE_VLAN);
- }
- else
+ } else {
+ if (pf->is_outer_vlan_processing)
+ i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,
+ RTE_ETHER_TYPE_QINQ);
i40e_vsi_config_double_vlan(vsi, FALSE);
+ }
+ /* Restore all mac */
+ for (i = 0; i < num; i++) {
+ ret = i40e_vsi_add_mac(vsi, &mac_filter[i]);
+ if (ret != I40E_SUCCESS) {
+ PMD_DRV_LOG(ERR, "Failed to add mac filter");
+ return -EIO;
+ }
+ }
}
if (mask & RTE_ETH_QINQ_STRIP_MASK) {
@@ -4846,6 +4904,17 @@ i40e_pf_parameter_init(struct rte_eth_dev *dev)
return -EINVAL;
}
+ /**
+ * Enable outer VLAN processing if firmware version is greater
+ * than v8.3
+ */
+ if (hw->aq.fw_maj_ver > 8 ||
+ (hw->aq.fw_maj_ver == 8 && hw->aq.fw_min_ver > 3)) {
+ pf->is_outer_vlan_processing = true;
+ } else {
+ pf->is_outer_vlan_processing = false;
+ }
+
return 0;
}
@@ -1188,6 +1188,9 @@ struct i40e_pf {
/* Switch Domain Id */
uint16_t switch_domain_id;
+ /* The enable flag for outer VLAN processing */
+ bool is_outer_vlan_processing;
+
struct i40e_vf_msg_cfg vf_msg_cfg;
uint64_t prev_rx_bytes;
uint64_t prev_tx_bytes;