<div dir="ltr">I'm trying to understand if this change is at all related to an issue we are experiencing with newer firmwares (<a href="https://mails.dpdk.org/archives/dev/2022-April/238621.html" target="_blank">https://mails.dpdk.org/archives/dev/2022-April/238621.html</a>) that happened to start with 8.4 and affected qinq offload processing.  I can say loading this patch and running testpmd does not seem to have any effect on the issue we are experiencing.<div><br></div><div>Side note, there is also a minor typo in the comment block "i40e_vlan_tpie_set" vs "i40e_vlan_tpid_set".</div><div><br></div><div>Thanks</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Jun 10, 2022 at 4:30 AM Kevin Liu <<a href="mailto:kevinx.liu@intel.com" target="_blank">kevinx.liu@intel.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">From: Robin Zhang <<a href="mailto:robinx.zhang@intel.com" target="_blank">robinx.zhang@intel.com</a>><br>
<br>
Outer VLAN processing is supported after firmware v8.4, kernel driver<br>
also change the default behavior to support this feature. To align with<br>
kernel driver, add support for outer VLAN processing in DPDK.<br>
<br>
But it is forbidden for firmware to change the Inner/Outer VLAN<br>
configuration while there are MAC/VLAN filters in the switch table.<br>
Therefore, we need to clear the MAC table before setting config,<br>
and then restore the MAC table after setting.<br>
<br>
This will not impact on an old firmware.<br>
<br>
Signed-off-by: Robin Zhang <<a href="mailto:robinx.zhang@intel.com" target="_blank">robinx.zhang@intel.com</a>><br>
Signed-off-by: Kevin Liu <<a href="mailto:kevinx.liu@intel.com" target="_blank">kevinx.liu@intel.com</a>><br>
---<br>
 drivers/net/i40e/i40e_ethdev.c | 94 ++++++++++++++++++++++++++++++++--<br>
 drivers/net/i40e/i40e_ethdev.h |  3 ++<br>
 2 files changed, 92 insertions(+), 5 deletions(-)<br>
<br>
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c<br>
index 755786dc10..4cae163cb9 100644<br>
--- a/drivers/net/i40e/i40e_ethdev.c<br>
+++ b/drivers/net/i40e/i40e_ethdev.c<br>
@@ -2575,6 +2575,7 @@ i40e_dev_close(struct rte_eth_dev *dev)<br>
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);<br>
        struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);<br>
        struct rte_intr_handle *intr_handle = pci_dev->intr_handle;<br>
+       struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;<br>
        struct i40e_filter_control_settings settings;<br>
        struct rte_flow *p_flow;<br>
        uint32_t reg;<br>
@@ -2587,6 +2588,18 @@ i40e_dev_close(struct rte_eth_dev *dev)<br>
        if (rte_eal_process_type() != RTE_PROC_PRIMARY)<br>
                return 0;<br>
<br>
+       /*<br>
+        * It is a workaround, if the double VLAN is disabled when<br>
+        * the program exits, an abnormal error will occur on the<br>
+        * NIC. Need to enable double VLAN when dev is closed.<br>
+        */<br>
+       if (pf->fw8_3gt) {<br>
+               if (!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND)) {<br>
+                       rxmode->offloads |= RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;<br>
+                       i40e_vlan_offload_set(dev, RTE_ETH_VLAN_EXTEND_MASK);<br>
+               }<br>
+       }<br>
+<br>
        ret = rte_eth_switch_domain_free(pf->switch_domain_id);<br>
        if (ret)<br>
                PMD_INIT_LOG(WARNING, "failed to free switch domain: %d", ret);<br>
@@ -3909,6 +3922,7 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,<br>
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);<br>
        int qinq = dev->data->dev_conf.rxmode.offloads &<br>
                   RTE_ETH_RX_OFFLOAD_VLAN_EXTEND;<br>
+       u16 sw_flags = 0, valid_flags = 0;<br>
        int ret = 0;<br>
<br>
        if ((vlan_type != RTE_ETH_VLAN_TYPE_INNER &&<br>
@@ -3927,15 +3941,32 @@ i40e_vlan_tpid_set(struct rte_eth_dev *dev,<br>
        /* 802.1ad frames ability is added in NVM API 1.7*/<br>
        if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {<br>
                if (qinq) {<br>
+                       if (pf->fw8_3gt) {<br>
+                               sw_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;<br>
+                               valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;<br>
+                       }<br>
                        if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)<br>
                                hw->first_tag = rte_cpu_to_le_16(tpid);<br>
                        else if (vlan_type == RTE_ETH_VLAN_TYPE_INNER)<br>
                                hw->second_tag = rte_cpu_to_le_16(tpid);<br>
                } else {<br>
-                       if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)<br>
-                               hw->second_tag = rte_cpu_to_le_16(tpid);<br>
+                       /*<br>
+                        * If tpid is equal to 0x88A8, indicates that the<br>
+                        * disable double VLAN operation is in progress.<br>
+                        * Need set switch configuration back to default.<br>
+                        */<br>
+                       if (pf->fw8_3gt && tpid == RTE_ETHER_TYPE_QINQ) {<br>
+                               sw_flags = 0;<br>
+                               valid_flags = I40E_AQ_SET_SWITCH_CFG_OUTER_VLAN;<br>
+                               if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)<br>
+                                       hw->first_tag = rte_cpu_to_le_16(tpid);<br>
+                       } else {<br>
+                               if (vlan_type == RTE_ETH_VLAN_TYPE_OUTER)<br>
+                                       hw->second_tag = rte_cpu_to_le_16(tpid);<br>
+                       }<br>
                }<br>
-               ret = i40e_aq_set_switch_config(hw, 0, 0, 0, NULL);<br>
+               ret = i40e_aq_set_switch_config(hw, sw_flags,<br>
+                                               valid_flags, 0, NULL);<br>
                if (ret != I40E_SUCCESS) {<br>
                        PMD_DRV_LOG(ERR,<br>
                                    "Set switch config failed aq_err: %d",<br>
@@ -3987,8 +4018,13 @@ static int<br>
 i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)<br>
 {<br>
        struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);<br>
+       struct i40e_mac_filter_info *mac_filter;<br>
        struct i40e_vsi *vsi = pf->main_vsi;<br>
        struct rte_eth_rxmode *rxmode;<br>
+       struct i40e_mac_filter *f;<br>
+       int i, num;<br>
+       void *temp;<br>
+       int ret;<br>
<br>
        rxmode = &dev->data->dev_conf.rxmode;<br>
        if (mask & RTE_ETH_VLAN_FILTER_MASK) {<br>
@@ -4007,6 +4043,33 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)<br>
        }<br>
<br>
        if (mask & RTE_ETH_VLAN_EXTEND_MASK) {<br>
+               i = 0;<br>
+               num = vsi->mac_num;<br>
+               mac_filter = rte_zmalloc("mac_filter_info_data",<br>
+                                num * sizeof(*mac_filter), 0);<br>
+               if (mac_filter == NULL) {<br>
+                       PMD_DRV_LOG(ERR, "failed to allocate memory");<br>
+                       return I40E_ERR_NO_MEMORY;<br>
+               }<br>
+<br>
+               /*<br>
+                * Outer VLAN processing is supported after firmware v8.4, kernel driver<br>
+                * also change the default behavior to support this feature. To align with<br>
+                * kernel driver, set switch config in 'i40e_vlan_tpie_set' to support for<br>
+                * outer VLAN processing. But it is forbidden for firmware to change the<br>
+                * Inner/Outer VLAN configuration while there are MAC/VLAN filters in the<br>
+                * switch table. Therefore, we need to clear the MAC table before setting<br>
+                * config, and then restore the MAC table after setting. This feature is<br>
+                * recommended to be used in firmware v8.6.<br>
+                */<br>
+               /* Remove all existing mac */<br>
+               RTE_TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {<br>
+                       mac_filter[i] = f->mac_info;<br>
+                       ret = i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr);<br>
+                       if (ret)<br>
+                               PMD_DRV_LOG(ERR, "i40e vsi delete mac fail.");<br>
+                       i++;<br>
+               }<br>
                if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND) {<br>
                        i40e_vsi_config_double_vlan(vsi, TRUE);<br>
                        /* Set global registers with default ethertype. */<br>
@@ -4014,9 +4077,19 @@ i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask)<br>
                                           RTE_ETHER_TYPE_VLAN);<br>
                        i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_INNER,<br>
                                           RTE_ETHER_TYPE_VLAN);<br>
-               }<br>
-               else<br>
+               } else {<br>
+                       if (pf->fw8_3gt)<br>
+                               i40e_vlan_tpid_set(dev, RTE_ETH_VLAN_TYPE_OUTER,<br>
+                                          RTE_ETHER_TYPE_QINQ);<br>
                        i40e_vsi_config_double_vlan(vsi, FALSE);<br>
+               }<br>
+               /* Restore all mac */<br>
+               for (i = 0; i < num; i++) {<br>
+                       ret = i40e_vsi_add_mac(vsi, &mac_filter[i]);<br>
+                       if (ret)<br>
+                               PMD_DRV_LOG(ERR, "i40e vsi add mac fail.");<br>
+               }<br>
+               rte_free(mac_filter);<br>
        }<br>
<br>
        if (mask & RTE_ETH_QINQ_STRIP_MASK) {<br>
@@ -4846,6 +4919,17 @@ i40e_pf_parameter_init(struct rte_eth_dev *dev)<br>
                return -EINVAL;<br>
        }<br>
<br>
+       /**<br>
+        * Enable outer VLAN processing if firmware version is greater<br>
+        * than v8.3<br>
+        */<br>
+       if (hw->aq.fw_maj_ver > 8 ||<br>
+           (hw->aq.fw_maj_ver == 8 && hw->aq.fw_min_ver > 3)) {<br>
+               pf->fw8_3gt = true;<br>
+       } else {<br>
+               pf->fw8_3gt = false;<br>
+       }<br>
+<br>
        return 0;<br>
 }<br>
<br>
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h<br>
index a1ebdc093c..fe943a45ff 100644<br>
--- a/drivers/net/i40e/i40e_ethdev.h<br>
+++ b/drivers/net/i40e/i40e_ethdev.h<br>
@@ -1188,6 +1188,9 @@ struct i40e_pf {<br>
        /* Switch Domain Id */<br>
        uint16_t switch_domain_id;<br>
<br>
+       /* When firmware > 8.3, the enable flag for outer VLAN processing */<br>
+       bool fw8_3gt;<br>
+<br>
        struct i40e_vf_msg_cfg vf_msg_cfg;<br>
        uint64_t prev_rx_bytes;<br>
        uint64_t prev_tx_bytes;<br>
-- <br>
2.34.1<br>
<br>
</blockquote></div>