<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>