Previously, a single VLAN header is treated as inner VLAN,
but generally, a single VLAN header is treated as the outer
VLAN header.
The patch fixes the ether type of a single VLAN type, and
enables configuring inner and outer TPID for double VLAN.

Fixes: 19b16e2f6442 ("ethdev: add vlan type when setting ether type")

Signed-off-by: Beilei Xing <beilei.xing at intel.com>
---
v4 changes:
 Update commit log.
v3 changes:
 Fix inserting vlan tpid issue for Tx.

 drivers/net/ixgbe/ixgbe_ethdev.c | 41 +++++++++++++++++++++++++++++++++++++---
 lib/librte_ether/rte_ethdev.h    |  4 ++--
 2 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index e11a431..a5427b4 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -157,6 +157,9 @@ enum ixgbevf_xcast_modes {
        IXGBEVF_XCAST_MODE_ALLMULTI,
 };

+#define IXGBE_EXVET_VET_EXT_SHIFT              16
+#define IXGBE_DMATXCTL_VT_MASK                 0xFFFF0000
+
 static int eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev);
 static int eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev);
 static int  ixgbe_dev_configure(struct rte_eth_dev *dev);
@@ -1584,15 +1587,47 @@ ixgbe_vlan_tpid_set(struct rte_eth_dev *dev,
        struct ixgbe_hw *hw =
                IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        int ret = 0;
+       uint32_t reg;
+       uint32_t qinq;
+
+       qinq = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
+       qinq &= IXGBE_DMATXCTL_GDV;

        switch (vlan_type) {
        case ETH_VLAN_TYPE_INNER:
-               /* Only the high 16-bits is valid */
-               IXGBE_WRITE_REG(hw, IXGBE_EXVET, tpid << 16);
+               if (qinq) {
+                       reg = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+                       reg = (reg & (~IXGBE_VLNCTRL_VET)) | (uint32_t)tpid;
+                       IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, reg);
+                       reg = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
+                       reg = (reg & (~IXGBE_DMATXCTL_VT_MASK))
+                               | ((uint32_t)tpid << IXGBE_DMATXCTL_VT_SHIFT);
+                       IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg);
+               } else {
+                       ret = -ENOTSUP;
+                       PMD_DRV_LOG(ERR, "Inner type is not supported"
+                                   " by single VLAN");
+               }
+               break;
+       case ETH_VLAN_TYPE_OUTER:
+               if (qinq) {
+                       /* Only the high 16-bits is valid */
+                       IXGBE_WRITE_REG(hw, IXGBE_EXVET, (uint32_t)tpid <<
+                                       IXGBE_EXVET_VET_EXT_SHIFT);
+               } else {
+                       reg = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+                       reg = (reg & (~IXGBE_VLNCTRL_VET)) | (uint32_t)tpid;
+                       IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, reg);
+                       reg = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
+                       reg = (reg & (~IXGBE_DMATXCTL_VT_MASK))
+                               | ((uint32_t)tpid << IXGBE_DMATXCTL_VT_SHIFT);
+                       IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg);
+               }
+
                break;
        default:
                ret = -EINVAL;
-               PMD_DRV_LOG(ERR, "Unsupported vlan type %d\n", vlan_type);
+               PMD_DRV_LOG(ERR, "Unsupported VLAN type %d", vlan_type);
                break;
        }

diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 45482f1..d04ddec 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -1157,7 +1157,7 @@ typedef int (*vlan_filter_set_t)(struct rte_eth_dev *dev,

 typedef int (*vlan_tpid_set_t)(struct rte_eth_dev *dev,
                               enum rte_vlan_type type, uint16_t tpid);
-/**< @internal set the outer VLAN-TPID by an Ethernet device. */
+/**< @internal set the outer/inner VLAN-TPID by an Ethernet device. */

 typedef void (*vlan_offload_set_t)(struct rte_eth_dev *dev, int mask);
 /**< @internal set VLAN offload function by an Ethernet device. */
@@ -1443,7 +1443,7 @@ struct eth_dev_ops {
        /**< Get packet types supported and identified by device*/
        mtu_set_t                  mtu_set; /**< Set MTU. */
        vlan_filter_set_t          vlan_filter_set;  /**< Filter VLAN Setup. */
-       vlan_tpid_set_t            vlan_tpid_set;      /**< Outer VLAN TPID 
Setup. */
+       vlan_tpid_set_t            vlan_tpid_set;      /**< Outer/Inner VLAN 
TPID Setup. */
        vlan_strip_queue_set_t     vlan_strip_queue_set; /**< VLAN Stripping on 
queue. */
        vlan_offload_set_t         vlan_offload_set; /**< Set VLAN Offload. */
        vlan_pvid_set_t            vlan_pvid_set; /**< Set port based TX VLAN 
insertion */
-- 
2.5.0

Reply via email to