Linux Kernel Selftest development
 help / color / mirror / Atom feed
* [PATCH net v2 0/6] net: stmmac: Fix double VLAN 802.1ad tag handling
@ 2026-08-21 17:09 Ovidiu Panait
  2026-08-21 17:09 ` [PATCH net v2 1/6] net: stmmac: Remove VLAN perfect matching dead code Ovidiu Panait
                   ` (5 more replies)
  0 siblings, 6 replies; 15+ messages in thread
From: Ovidiu Panait @ 2026-08-21 17:09 UTC (permalink / raw)
  To: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	mcoquelin.stm32, alexandre.torgue, shuah, joabreu, yi.fang.gan,
	jun.ann.lai
  Cc: linux-kernel, netdev, linux-stm32, linux-arm-kernel,
	linux-kselftest, Ovidiu Panait

Currently, hardware VLAN stripping is broken for 802.1ad tags. vlan_rx_hw()
hardcodes ETH_P_8021Q when putting the hardware tag into the skb, rather
than using the actual protocol from the packet. Because of this, packets
that contain an 802.1ad outer tag are incorrectly passed up the stack as
having an 802.1Q tag.

This issue was observed on the Renesas RZ/V2H platform (which has a dwmac4
IP), when testing QinQ ping:

  # DUT
  ip link add link end0 name end0.100 type vlan proto 802.1ad id 100
  ip link add link end0.100 name end0.100.200 type vlan proto 802.1q id 200
  ip addr add 172.16.3.2/24 dev end0.100.200
  ip link set end0 up
  ip link set end0.100 up
  ip link set end0.100.200 up

  # Peer
  ip link add link eth0 name eth0.100 type vlan proto 802.1ad id 100
  ip link add link eth0.100 name eth0.100.200 type vlan proto 802.1q id 200
  ip addr add 172.16.3.1/24 dev eth0.100.200
  ip link set eth0 up
  ip link set eth0.100 up
  ip link set eth0.100.200 up
  ping 172.16.3.2
    -- FAIL --

Note that this series only fixes the issue on dwmac4. dwxgmac2 has the same
issue but I do not have access to hw to test on.

Since dwmac4 does not expose the tag type in the RDES3 descriptor, it
cannot support hardware double VLAN stripping correctly. This series
disables double VLAN stripping for it, so the 802.1ad tags are left in
place and are handled by the software VLAN path.

v2 changes:
- Added a net selftest for VLAN.
- Dropped patch "net: stmmac: Fix double VLAN stripping on dwxgmac2" from
  this series, as it was compile tested only and Nazim reported that it
  doesn't actually fix the issue on his board. More investigation is
  needed on dwxgmac2, but it should not block this series.
- Addressed some issues reported by Sashiko, to fix the advertised STAG
  offload features mismatch.

v1: https://lore.kernel.org/all/20260729095110.164157-1-ovidiu.panait.rb@renesas.com/

Ovidiu Panait (6):
  net: stmmac: Remove VLAN perfect matching dead code
  net: stmmac: Enable double VLAN processing only when supported
  net: stmmac: Move double VLAN handling to a dedicated op
  net: stmmac: Disable double VLAN handling on dwmac4
  selftests: drv-net: Move _set_ethtool_feat() into lib
  selftests: drv-net: Add VLAN test

 drivers/net/ethernet/stmicro/stmmac/hwif.h    |   6 +-
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  26 +++--
 .../net/ethernet/stmicro/stmmac/stmmac_vlan.c |  81 +++-----------
 tools/testing/selftests/drivers/net/Makefile  |   1 +
 tools/testing/selftests/drivers/net/gro.py    |  65 ++++--------
 .../selftests/drivers/net/lib/py/__init__.py  |   3 +-
 .../selftests/drivers/net/lib/py/feat.py      |  37 +++++++
 tools/testing/selftests/drivers/net/vlan.py   | 100 ++++++++++++++++++
 8 files changed, 193 insertions(+), 126 deletions(-)
 create mode 100644 tools/testing/selftests/drivers/net/lib/py/feat.py
 create mode 100755 tools/testing/selftests/drivers/net/vlan.py

-- 
2.34.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH net v2 1/6] net: stmmac: Remove VLAN perfect matching dead code
  2026-08-21 17:09 [PATCH net v2 0/6] net: stmmac: Fix double VLAN 802.1ad tag handling Ovidiu Panait
@ 2026-08-21 17:09 ` Ovidiu Panait
  2026-08-23  7:48   ` Maxime Chevallier
  2026-08-21 17:09 ` [PATCH net v2 2/6] net: stmmac: Enable double VLAN processing only when supported Ovidiu Panait
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 15+ messages in thread
From: Ovidiu Panait @ 2026-08-21 17:09 UTC (permalink / raw)
  To: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	mcoquelin.stm32, alexandre.torgue, shuah, joabreu, yi.fang.gan,
	jun.ann.lai
  Cc: linux-kernel, netdev, linux-stm32, linux-arm-kernel,
	linux-kselftest, Ovidiu Panait

stmmac_vlan_update() falls back to "perfect matching" when the VLAN hash
filter is unavailable (!priv->dma_cap.vlhash). This fallback has been
unreachable in normal operation since its introduction in
commit c7ab0b8088d7 ("net: stmmac: Fallback to VLAN Perfect filtering if
HASH is not available") because the NETIF_F_HW_VLAN_{CTAG,STAG}_FILTER
features are advertised only when priv->dma_cap.vlhash is true.

The fallback is also duplicating the code in vlan_add_hw_rx_fltr(), which
is always available since stmmac_get_num_vlan() returns at least 1.

Therefore, remove it.

Fixes: c7ab0b8088d7 ("net: stmmac: Fallback to VLAN Perfect filtering if HASH is not available")
Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
---
v2 changes: None.

 drivers/net/ethernet/stmicro/stmmac/hwif.h    |  2 +-
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 13 +-----
 .../net/ethernet/stmicro/stmmac/stmmac_vlan.c | 41 +------------------
 3 files changed, 4 insertions(+), 52 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 04dafec021b4..6f26dbf95ce1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -633,7 +633,7 @@ struct stmmac_est_ops {
 struct stmmac_vlan_ops {
 	/* VLAN */
 	void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash,
-				 u16 perfect_match, bool is_double);
+				 bool is_double);
 	void (*enable_vlan)(struct mac_device_info *hw, u32 type);
 	void (*rx_hw_vlan)(struct mac_device_info *hw, struct dma_desc *rx_desc,
 			   struct sk_buff *skb);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index b2b7d0242dd3..16fe56a1f617 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -6809,29 +6809,18 @@ static u32 stmmac_vid_crc32_le(__le16 vid_le)
 static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double)
 {
 	u32 crc, hash = 0;
-	u16 pmatch = 0;
-	int count = 0;
 	u16 vid = 0;
 
 	for_each_set_bit(vid, priv->active_vlans, VLAN_N_VID) {
 		__le16 vid_le = cpu_to_le16(vid);
 		crc = bitrev32(~stmmac_vid_crc32_le(vid_le)) >> 28;
 		hash |= (1 << crc);
-		count++;
-	}
-
-	if (!priv->dma_cap.vlhash) {
-		if (count > 2) /* VID = 0 always passes filter */
-			return -EOPNOTSUPP;
-
-		pmatch = vid;
-		hash = 0;
 	}
 
 	if (!netif_running(priv->dev))
 		return 0;
 
-	return stmmac_update_vlan_hash(priv, priv->hw, hash, pmatch, is_double);
+	return stmmac_update_vlan_hash(priv, priv->hw, hash, is_double);
 }
 
 /* FIXME: This may need RXC to be running, but it may be called with BH
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
index e24efe3bfedb..983a90cb9767 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
@@ -162,7 +162,7 @@ static void vlan_restore_hw_rx_fltr(struct net_device *dev,
 }
 
 static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
-			     u16 perfect_match, bool is_double)
+			     bool is_double)
 {
 	void __iomem *ioaddr = hw->pcsr;
 	u32 value;
@@ -184,20 +184,6 @@ static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
 		}
 
 		writel(value, ioaddr + VLAN_TAG);
-	} else if (perfect_match) {
-		u32 value = VLAN_ETV;
-
-		if (is_double) {
-			value |= VLAN_EDVLP;
-			value |= VLAN_ESVL;
-			value |= VLAN_DOVLTC;
-		} else {
-			value &= ~VLAN_EDVLP;
-			value &= ~VLAN_ESVL;
-			value &= ~VLAN_DOVLTC;
-		}
-
-		writel(value | perfect_match, ioaddr + VLAN_TAG);
 	} else {
 		value &= ~(VLAN_VTHM | VLAN_ETV);
 		value &= ~(VLAN_EDVLP | VLAN_ESVL);
@@ -251,7 +237,7 @@ static void vlan_set_hw_mode(struct mac_device_info *hw)
 }
 
 static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
-				      u16 perfect_match, bool is_double)
+				      bool is_double)
 {
 	void __iomem *ioaddr = hw->pcsr;
 
@@ -279,29 +265,6 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
 
 		value &= ~VLAN_VID;
 		writel(value, ioaddr + VLAN_TAG);
-	} else if (perfect_match) {
-		u32 value = readl(ioaddr + XGMAC_PACKET_FILTER);
-
-		value |= XGMAC_FILTER_VTFE;
-
-		writel(value, ioaddr + XGMAC_PACKET_FILTER);
-
-		value = readl(ioaddr + VLAN_TAG);
-
-		value &= ~VLAN_VTHM;
-		value |= VLAN_ETV;
-		if (is_double) {
-			value |= VLAN_EDVLP;
-			value |= VLAN_ESVL;
-			value |= VLAN_DOVLTC;
-		} else {
-			value &= ~VLAN_EDVLP;
-			value &= ~VLAN_ESVL;
-			value &= ~VLAN_DOVLTC;
-		}
-
-		value &= ~VLAN_VID;
-		writel(value | perfect_match, ioaddr + VLAN_TAG);
 	} else {
 		u32 value = readl(ioaddr + XGMAC_PACKET_FILTER);
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net v2 2/6] net: stmmac: Enable double VLAN processing only when supported
  2026-08-21 17:09 [PATCH net v2 0/6] net: stmmac: Fix double VLAN 802.1ad tag handling Ovidiu Panait
  2026-08-21 17:09 ` [PATCH net v2 1/6] net: stmmac: Remove VLAN perfect matching dead code Ovidiu Panait
@ 2026-08-21 17:09 ` Ovidiu Panait
  2026-08-23  7:49   ` Maxime Chevallier
  2026-08-24  6:47   ` Joseph Steel
  2026-08-21 17:09 ` [PATCH net v2 3/6] net: stmmac: Move double VLAN handling to a dedicated op Ovidiu Panait
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 15+ messages in thread
From: Ovidiu Panait @ 2026-08-21 17:09 UTC (permalink / raw)
  To: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	mcoquelin.stm32, alexandre.torgue, shuah, joabreu, yi.fang.gan,
	jun.ann.lai
  Cc: linux-kernel, netdev, linux-stm32, linux-arm-kernel,
	linux-kselftest, Ovidiu Panait

stmmac_vlan_update() turns on double/S-VLAN processing whenever an
802.1ad VLAN is registered, without checking whether the MAC actually
supports double VLAN processing. That capability is reported in
dma_cap.dvlan.

This was found while investigating a separate bug in the double VLAN RX
stripping path. The outer 802.1ad tags were unexpectedly stripped by the
MAC (because the ESVL bit was set).

Check dma_cap.dvlan before enabling EDVLP/ESVL/DOVLTC bits, so that double
VLAN processing is enabled only on supported hardware. Also, advertise
NETIF_F_HW_VLAN_STAG_RX and NETIF_F_HW_VLAN_STAG_FILTER only when
dma_cap.dvlan is set.

Fixes: 3cd1cfcba26e ("net: stmmac: Implement VLAN Hash Filtering in XGMAC")
Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
---
v2 changes:
- Advertised NETIF_F_HW_VLAN_STAG_RX and NETIF_F_HW_VLAN_STAG_FILTER only
  when dma_cap.dvlan is set (reported by Sashiko).

 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 16fe56a1f617..880cf3fab913 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -6820,6 +6820,9 @@ static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double)
 	if (!netif_running(priv->dev))
 		return 0;
 
+	if (!priv->dma_cap.dvlan)
+		is_double = false;
+
 	return stmmac_update_vlan_hash(priv, priv->hw, hash, is_double);
 }
 
@@ -7954,14 +7957,18 @@ static int __stmmac_dvr_probe(struct device *device,
 	ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
 #ifdef STMMAC_VLAN_TAG_USED
 	/* Both mac100 and gmac support receive VLAN tag detection */
-	ndev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX;
+	ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+	if (priv->dma_cap.dvlan)
+		ndev->features |= NETIF_F_HW_VLAN_STAG_RX;
+
 	if (dwmac_is_xmac(priv->plat->core_type)) {
 		ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
 		priv->hw->hw_vlan_en = true;
 	}
 	if (priv->dma_cap.vlhash) {
 		ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
-		ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER;
+		if (priv->dma_cap.dvlan)
+			ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER;
 	}
 	if (priv->dma_cap.vlins)
 		ndev->features |= NETIF_F_HW_VLAN_CTAG_TX;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net v2 3/6] net: stmmac: Move double VLAN handling to a dedicated op
  2026-08-21 17:09 [PATCH net v2 0/6] net: stmmac: Fix double VLAN 802.1ad tag handling Ovidiu Panait
  2026-08-21 17:09 ` [PATCH net v2 1/6] net: stmmac: Remove VLAN perfect matching dead code Ovidiu Panait
  2026-08-21 17:09 ` [PATCH net v2 2/6] net: stmmac: Enable double VLAN processing only when supported Ovidiu Panait
@ 2026-08-21 17:09 ` Ovidiu Panait
  2026-08-23  7:52   ` Maxime Chevallier
  2026-08-21 17:09 ` [PATCH net v2 4/6] net: stmmac: Disable double VLAN handling on dwmac4 Ovidiu Panait
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 15+ messages in thread
From: Ovidiu Panait @ 2026-08-21 17:09 UTC (permalink / raw)
  To: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	mcoquelin.stm32, alexandre.torgue, shuah, joabreu, yi.fang.gan,
	jun.ann.lai
  Cc: linux-kernel, netdev, linux-stm32, linux-arm-kernel,
	linux-kselftest, Ovidiu Panait

The double VLAN bits (EDVLP, ESVL, DOVLTC) are currently handled inside
update_vlan_hash(). This ties the double VLAN state to the hash filter
update, even though the two features are independent: hash filtering is
controlled by dma_cap.vlhash and double vlan by dma_cap.dvlan.

In preparation for removing double vlan support from dwmac4, move the
double vlan logic into a separate update_dvlan_state() VLAN operation.

Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
---
v2 changes: None.

 drivers/net/ethernet/stmicro/stmmac/hwif.h    |  6 ++-
 .../net/ethernet/stmicro/stmmac/stmmac_main.c |  6 +--
 .../net/ethernet/stmicro/stmmac/stmmac_vlan.c | 45 ++++++++-----------
 3 files changed, 25 insertions(+), 32 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 6f26dbf95ce1..66837caafa84 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -632,8 +632,8 @@ struct stmmac_est_ops {
 
 struct stmmac_vlan_ops {
 	/* VLAN */
-	void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash,
-				 bool is_double);
+	void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash);
+	void (*update_dvlan_state)(struct mac_device_info *hw, bool enable);
 	void (*enable_vlan)(struct mac_device_info *hw, u32 type);
 	void (*rx_hw_vlan)(struct mac_device_info *hw, struct dma_desc *rx_desc,
 			   struct sk_buff *skb);
@@ -650,6 +650,8 @@ struct stmmac_vlan_ops {
 
 #define stmmac_update_vlan_hash(__priv, __args...) \
 	stmmac_do_void_callback(__priv, vlan, update_vlan_hash, __args)
+#define stmmac_update_dvlan_state(__priv, __args...) \
+	stmmac_do_void_callback(__priv, vlan, update_dvlan_state, __args)
 #define stmmac_enable_vlan(__priv, __args...) \
 	stmmac_do_void_callback(__priv, vlan, enable_vlan, __args)
 #define stmmac_rx_hw_vlan(__priv, __args...) \
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 880cf3fab913..802f9e67a4bc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -6820,10 +6820,10 @@ static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double)
 	if (!netif_running(priv->dev))
 		return 0;
 
-	if (!priv->dma_cap.dvlan)
-		is_double = false;
+	if (priv->dma_cap.dvlan)
+		stmmac_update_dvlan_state(priv, priv->hw, is_double);
 
-	return stmmac_update_vlan_hash(priv, priv->hw, hash, is_double);
+	return stmmac_update_vlan_hash(priv, priv->hw, hash);
 }
 
 /* FIXME: This may need RXC to be running, but it may be called with BH
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
index 983a90cb9767..1e47ae62093e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
@@ -161,8 +161,20 @@ static void vlan_restore_hw_rx_fltr(struct net_device *dev,
 		vlan_write_filter(dev, hw, i, hw->vlan_filter[i]);
 }
 
-static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
-			     bool is_double)
+static void vlan_update_dvlan_state(struct mac_device_info *hw, bool enable)
+{
+	void __iomem *ioaddr = hw->pcsr;
+	u32 value;
+
+	value = readl(ioaddr + VLAN_TAG);
+	if (enable)
+		value |= VLAN_EDVLP | VLAN_ESVL | VLAN_DOVLTC;
+	else
+		value &= ~(VLAN_EDVLP | VLAN_ESVL | VLAN_DOVLTC);
+	writel(value, ioaddr + VLAN_TAG);
+}
+
+static void vlan_update_hash(struct mac_device_info *hw, u32 hash)
 {
 	void __iomem *ioaddr = hw->pcsr;
 	u32 value;
@@ -173,21 +185,9 @@ static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
 
 	if (hash) {
 		value |= VLAN_VTHM | VLAN_ETV;
-		if (is_double) {
-			value |= VLAN_EDVLP;
-			value |= VLAN_ESVL;
-			value |= VLAN_DOVLTC;
-		} else {
-			value &= ~VLAN_EDVLP;
-			value &= ~VLAN_ESVL;
-			value &= ~VLAN_DOVLTC;
-		}
-
 		writel(value, ioaddr + VLAN_TAG);
 	} else {
 		value &= ~(VLAN_VTHM | VLAN_ETV);
-		value &= ~(VLAN_EDVLP | VLAN_ESVL);
-		value &= ~VLAN_DOVLTC;
 		value &= ~VLAN_VID;
 
 		writel(value, ioaddr + VLAN_TAG);
@@ -236,8 +236,7 @@ static void vlan_set_hw_mode(struct mac_device_info *hw)
 	writel(value, ioaddr + VLAN_TAG);
 }
 
-static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
-				      bool is_double)
+static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash)
 {
 	void __iomem *ioaddr = hw->pcsr;
 
@@ -253,15 +252,6 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
 		value = readl(ioaddr + VLAN_TAG);
 
 		value |= VLAN_VTHM | VLAN_ETV;
-		if (is_double) {
-			value |= VLAN_EDVLP;
-			value |= VLAN_ESVL;
-			value |= VLAN_DOVLTC;
-		} else {
-			value &= ~VLAN_EDVLP;
-			value &= ~VLAN_ESVL;
-			value &= ~VLAN_DOVLTC;
-		}
 
 		value &= ~VLAN_VID;
 		writel(value, ioaddr + VLAN_TAG);
@@ -275,8 +265,6 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
 		value = readl(ioaddr + VLAN_TAG);
 
 		value &= ~(VLAN_VTHM | VLAN_ETV);
-		value &= ~(VLAN_EDVLP | VLAN_ESVL);
-		value &= ~VLAN_DOVLTC;
 		value &= ~VLAN_VID;
 
 		writel(value, ioaddr + VLAN_TAG);
@@ -285,6 +273,7 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
 
 const struct stmmac_vlan_ops dwmac_vlan_ops = {
 	.update_vlan_hash = vlan_update_hash,
+	.update_dvlan_state = vlan_update_dvlan_state,
 	.enable_vlan = vlan_enable,
 	.add_hw_vlan_rx_fltr = vlan_add_hw_rx_fltr,
 	.del_hw_vlan_rx_fltr = vlan_del_hw_rx_fltr,
@@ -295,11 +284,13 @@ const struct stmmac_vlan_ops dwmac_vlan_ops = {
 
 const struct stmmac_vlan_ops dwxlgmac2_vlan_ops = {
 	.update_vlan_hash = dwxgmac2_update_vlan_hash,
+	.update_dvlan_state = vlan_update_dvlan_state,
 	.enable_vlan = vlan_enable,
 };
 
 const struct stmmac_vlan_ops dwxgmac210_vlan_ops = {
 	.update_vlan_hash = dwxgmac2_update_vlan_hash,
+	.update_dvlan_state = vlan_update_dvlan_state,
 	.enable_vlan = vlan_enable,
 	.add_hw_vlan_rx_fltr = vlan_add_hw_rx_fltr,
 	.del_hw_vlan_rx_fltr = vlan_del_hw_rx_fltr,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net v2 4/6] net: stmmac: Disable double VLAN handling on dwmac4
  2026-08-21 17:09 [PATCH net v2 0/6] net: stmmac: Fix double VLAN 802.1ad tag handling Ovidiu Panait
                   ` (2 preceding siblings ...)
  2026-08-21 17:09 ` [PATCH net v2 3/6] net: stmmac: Move double VLAN handling to a dedicated op Ovidiu Panait
@ 2026-08-21 17:09 ` Ovidiu Panait
  2026-08-21 17:09 ` [PATCH net v2 5/6] selftests: drv-net: Move _set_ethtool_feat() into lib Ovidiu Panait
  2026-08-21 17:09 ` [PATCH net v2 6/6] selftests: drv-net: Add VLAN test Ovidiu Panait
  5 siblings, 0 replies; 15+ messages in thread
From: Ovidiu Panait @ 2026-08-21 17:09 UTC (permalink / raw)
  To: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	mcoquelin.stm32, alexandre.torgue, shuah, joabreu, yi.fang.gan,
	jun.ann.lai
  Cc: linux-kernel, netdev, linux-stm32, linux-arm-kernel,
	linux-kselftest, Ovidiu Panait

Currently, hardware VLAN stripping is broken for 802.1ad tags. vlan_rx_hw()
hardcodes ETH_P_8021Q when putting the hardware tag into the skb, rather
than using the actual protocol from the packet. Because of this, packets
that contain a 802.1ad outer tag are incorrectly passed up the stack as
having an 802.1Q tag. This causes QinQ ping between two hosts to fail.

vlan_rx_hw() is shared by dwxgmac2 and dwmac4: on dwxgmac2 the tag type
is available in the RDES3 write-back descriptor (the ET_LT field), so the
outer tag type can be determined based on that info. However, dwmac4
doesn't seem to provide the tag type. The Length/Type field in RDES3 only
indicates whether the packet is single or double-tagged, not which tag
type was stripped.

Since dwmac4 cannot report the stripped tag type, it cannot support
hardware double VLAN stripping correctly. Disable it by dropping
update_dvlan_state from dwmac_vlan_ops. With this, 802.1ad tags are
left in place and handled by the software VLAN path.

Also, restrict the NETIF_F_HW_VLAN_STAG_RX and NETIF_F_HW_VLAN_STAG_FILTER
advertisement to dwxgmac2.

Fixes: 750011e239a5 ("net: stmmac: Add support for HW-accelerated VLAN stripping")
Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
---
v2 changes:
- Advertised NETIF_F_HW_VLAN_STAG_RX and NETIF_F_HW_VLAN_STAG_FILTER only
  for XGMAC (reported by Sashiko).

 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 6 ++++--
 drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c | 1 -
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 802f9e67a4bc..7cfd14007d60 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -7958,7 +7958,8 @@ static int __stmmac_dvr_probe(struct device *device,
 #ifdef STMMAC_VLAN_TAG_USED
 	/* Both mac100 and gmac support receive VLAN tag detection */
 	ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
-	if (priv->dma_cap.dvlan)
+	if (priv->dma_cap.dvlan &&
+	    priv->plat->core_type == DWMAC_CORE_XGMAC)
 		ndev->features |= NETIF_F_HW_VLAN_STAG_RX;
 
 	if (dwmac_is_xmac(priv->plat->core_type)) {
@@ -7967,7 +7968,8 @@ static int __stmmac_dvr_probe(struct device *device,
 	}
 	if (priv->dma_cap.vlhash) {
 		ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
-		if (priv->dma_cap.dvlan)
+		if (priv->dma_cap.dvlan &&
+		    priv->plat->core_type == DWMAC_CORE_XGMAC)
 			ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER;
 	}
 	if (priv->dma_cap.vlins)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
index 1e47ae62093e..9b5b3f11f699 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
@@ -273,7 +273,6 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash)
 
 const struct stmmac_vlan_ops dwmac_vlan_ops = {
 	.update_vlan_hash = vlan_update_hash,
-	.update_dvlan_state = vlan_update_dvlan_state,
 	.enable_vlan = vlan_enable,
 	.add_hw_vlan_rx_fltr = vlan_add_hw_rx_fltr,
 	.del_hw_vlan_rx_fltr = vlan_del_hw_rx_fltr,
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net v2 5/6] selftests: drv-net: Move _set_ethtool_feat() into lib
  2026-08-21 17:09 [PATCH net v2 0/6] net: stmmac: Fix double VLAN 802.1ad tag handling Ovidiu Panait
                   ` (3 preceding siblings ...)
  2026-08-21 17:09 ` [PATCH net v2 4/6] net: stmmac: Disable double VLAN handling on dwmac4 Ovidiu Panait
@ 2026-08-21 17:09 ` Ovidiu Panait
  2026-08-21 17:09 ` [PATCH net v2 6/6] selftests: drv-net: Add VLAN test Ovidiu Panait
  5 siblings, 0 replies; 15+ messages in thread
From: Ovidiu Panait @ 2026-08-21 17:09 UTC (permalink / raw)
  To: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	mcoquelin.stm32, alexandre.torgue, shuah, joabreu, yi.fang.gan,
	jun.ann.lai
  Cc: linux-kernel, netdev, linux-stm32, linux-arm-kernel,
	linux-kselftest, Ovidiu Panait

Move the _set_ethtool_feat() helper from gro.py into lib, so that it can
be reused by the VLAN test added in the next commit. Drop the leading
underscore, now that the helper is exported.

Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
---
v2 changes:
- New patch.

 tools/testing/selftests/drivers/net/gro.py    | 65 ++++++-------------
 .../selftests/drivers/net/lib/py/__init__.py  |  3 +-
 .../selftests/drivers/net/lib/py/feat.py      | 37 +++++++++++
 3 files changed, 59 insertions(+), 46 deletions(-)
 create mode 100644 tools/testing/selftests/drivers/net/lib/py/feat.py

diff --git a/tools/testing/selftests/drivers/net/gro.py b/tools/testing/selftests/drivers/net/gro.py
index 6ab8c97880d1..051a3b2d0ead 100755
--- a/tools/testing/selftests/drivers/net/gro.py
+++ b/tools/testing/selftests/drivers/net/gro.py
@@ -42,7 +42,7 @@ import re
 from lib.py import ksft_run, ksft_exit, ksft_pr
 from lib.py import NetDrvEpEnv, KsftFailEx, KsftXfailEx
 from lib.py import NetdevFamily, EthtoolFamily
-from lib.py import bkg, cmd, defer, ethtool, ip
+from lib.py import bkg, cmd, defer, ethtool, ip, set_ethtool_feat
 from lib.py import ksft_variants, KsftNamedVariant
 
 
@@ -96,31 +96,6 @@ def _set_mtu_restore(dev, mtu, host):
         defer(ip, f"link set dev {dev['ifname']} mtu {dev['mtu']}", host=host)
 
 
-def _set_ethtool_feat(dev, current, feats, host=None):
-    s2n = {True: "on", False: "off"}
-
-    new = ["-K", dev]
-    old = ["-K", dev]
-    no_change = True
-    for name, state in feats.items():
-        new += [name, s2n[state]]
-        old += [name, s2n[current[name]["active"]]]
-
-        if current[name]["active"] != state:
-            no_change = False
-            if current[name]["fixed"]:
-                raise KsftXfailEx(f"Device does not support {name}")
-    if no_change:
-        return
-
-    eth_cmd = ethtool(" ".join(new), host=host)
-    defer(ethtool, " ".join(old), host=host)
-
-    # If ethtool printed something kernel must have modified some features
-    if eth_cmd.stdout:
-        ksft_pr(eth_cmd)
-
-
 def _get_queue_stats(cfg, queue_id):
     """Get stats for a specific Rx queue."""
     cfg.wait_hw_stats_settle()
@@ -247,15 +222,15 @@ def _setup(cfg, mode, test_name):
         _write_defer_restore(cfg, flush_path, "200000", defer_undo=True)
         _write_defer_restore(cfg, irq_path, "10", defer_undo=True)
 
-        _set_ethtool_feat(cfg.ifname, cfg.feat,
-                          {"generic-receive-offload": True,
-                           "rx-gro-hw": False,
-                           "large-receive-offload": False})
+        set_ethtool_feat(cfg.ifname, cfg.feat,
+                         {"generic-receive-offload": True,
+                          "rx-gro-hw": False,
+                          "large-receive-offload": False})
     elif mode == "hw":
-        _set_ethtool_feat(cfg.ifname, cfg.feat,
-                          {"generic-receive-offload": False,
-                           "rx-gro-hw": True,
-                           "large-receive-offload": False})
+        set_ethtool_feat(cfg.ifname, cfg.feat,
+                         {"generic-receive-offload": False,
+                          "rx-gro-hw": True,
+                          "large-receive-offload": False})
 
         # Some NICs treat HW GRO as a GRO sub-feature so disabling GRO
         # will also clear HW GRO. Use a hack of installing XDP generic
@@ -270,27 +245,27 @@ def _setup(cfg, mode, test_name):
             # Attaching XDP may change features, fetch the latest state
             feat = ethtool(f"-k {cfg.ifname}", json=True)[0]
 
-            _set_ethtool_feat(cfg.ifname, feat,
-                              {"generic-receive-offload": True,
-                               "rx-gro-hw": True,
-                               "large-receive-offload": False})
+            set_ethtool_feat(cfg.ifname, feat,
+                             {"generic-receive-offload": True,
+                              "rx-gro-hw": True,
+                              "large-receive-offload": False})
     elif mode == "lro":
         # netdevsim advertises LRO for feature inheritance testing with
         # bonding/team tests but it doesn't actually perform the offload
         cfg.require_nsim(nsim_test=False)
 
-        _set_ethtool_feat(cfg.ifname, cfg.feat,
-                          {"generic-receive-offload": False,
-                           "rx-gro-hw": False,
-                           "large-receive-offload": True})
+        set_ethtool_feat(cfg.ifname, cfg.feat,
+                         {"generic-receive-offload": False,
+                          "rx-gro-hw": False,
+                          "large-receive-offload": True})
 
     try:
         # Disable TSO for local tests
         cfg.require_nsim()  # will raise KsftXfailEx if not running on nsim
 
-        _set_ethtool_feat(cfg.remote_ifname, cfg.remote_feat,
-                          {"tcp-segmentation-offload": False},
-                          host=cfg.remote)
+        set_ethtool_feat(cfg.remote_ifname, cfg.remote_feat,
+                         {"tcp-segmentation-offload": False},
+                         host=cfg.remote)
     except KsftXfailEx:
         pass
 
diff --git a/tools/testing/selftests/drivers/net/lib/py/__init__.py b/tools/testing/selftests/drivers/net/lib/py/__init__.py
index ee903bcf3207..c261aac2b976 100644
--- a/tools/testing/selftests/drivers/net/lib/py/__init__.py
+++ b/tools/testing/selftests/drivers/net/lib/py/__init__.py
@@ -48,11 +48,12 @@ try:
                "ksft_not_none", "ksft_not_none"]
 
     from .env import NetDrvEnv, NetDrvEpEnv, NetDrvContEnv
+    from .feat import set_ethtool_feat
     from .load import GenerateTraffic, Iperf3Runner
     from .remote import Remote
 
     __all__ += ["NetDrvEnv", "NetDrvEpEnv", "NetDrvContEnv", "GenerateTraffic",
-                "Remote", "Iperf3Runner"]
+                "Remote", "Iperf3Runner", "set_ethtool_feat"]
 except ModuleNotFoundError as e:
     print("Failed importing `net` library from kernel sources")
     print(str(e))
diff --git a/tools/testing/selftests/drivers/net/lib/py/feat.py b/tools/testing/selftests/drivers/net/lib/py/feat.py
new file mode 100644
index 000000000000..33b4895059df
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/lib/py/feat.py
@@ -0,0 +1,37 @@
+# SPDX-License-Identifier: GPL-2.0
+
+"""
+Netdev feature helper utilities for kernel selftests.
+
+Provides common operations for changing device features via ethtool,
+used by driver test files.
+"""
+
+from lib.py import KsftXfailEx
+from lib.py import ksft_pr
+from lib.py import defer, ethtool
+
+
+def set_ethtool_feat(dev, current, feats, host=None):
+    s2n = {True: "on", False: "off"}
+
+    new = ["-K", dev]
+    old = ["-K", dev]
+    no_change = True
+    for name, state in feats.items():
+        new += [name, s2n[state]]
+        old += [name, s2n[current[name]["active"]]]
+
+        if current[name]["active"] != state:
+            no_change = False
+            if current[name]["fixed"]:
+                raise KsftXfailEx(f"Device does not support {name}")
+    if no_change:
+        return
+
+    eth_cmd = ethtool(" ".join(new), host=host)
+    defer(ethtool, " ".join(old), host=host)
+
+    # If ethtool printed something kernel must have modified some features
+    if eth_cmd.stdout:
+        ksft_pr(eth_cmd)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH net v2 6/6] selftests: drv-net: Add VLAN test
  2026-08-21 17:09 [PATCH net v2 0/6] net: stmmac: Fix double VLAN 802.1ad tag handling Ovidiu Panait
                   ` (4 preceding siblings ...)
  2026-08-21 17:09 ` [PATCH net v2 5/6] selftests: drv-net: Move _set_ethtool_feat() into lib Ovidiu Panait
@ 2026-08-21 17:09 ` Ovidiu Panait
  2026-08-23  0:04   ` Andrew Lunn
  5 siblings, 1 reply; 15+ messages in thread
From: Ovidiu Panait @ 2026-08-21 17:09 UTC (permalink / raw)
  To: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	mcoquelin.stm32, alexandre.torgue, shuah, joabreu, yi.fang.gan,
	jun.ann.lai
  Cc: linux-kernel, netdev, linux-stm32, linux-arm-kernel,
	linux-kselftest, Ovidiu Panait

Add a test that validates ping traffic over VLAN interfaces. It aims
to catch drivers which mishandle hardware VLAN tag stripping, in
particular QinQ.

Three VLAN configurations are covered, each with hardware VLAN stripping
enabled and disabled:
- a single 802.1q VLAN interface
- a single 802.1ad VLAN interface
- an 802.1q VLAN stacked on top of an 802.1ad interface

NETIF=end1 LOCAL_V4=172.16.0.2 REMOTE_V4=172.16.0.3 \
REMOTE_TYPE=ssh REMOTE_ARGS=root@172.16.0.3 \
run_kselftest.sh -t drivers/net:vlan.py
  TAP version 13
  1..1
  # timeout set to 360
  # selftests: drivers/net: vlan.py
  # # Interface: end0, driver: st_gmac
  # TAP version 13
  # 1..6
  # ok 1 vlan.test.8021q_hw
  # ok 2 vlan.test.8021q_sw
  # ok 3 vlan.test.8021ad_hw
  # ok 4 vlan.test.8021ad_sw
  # ok 5 vlan.test.qinq_hw
  # ok 6 vlan.test.qinq_sw
  # # Totals: pass:6 fail:0 xfail:0 xpass:0 skip:0 error:0
  ok 1 selftests: drivers/net: vlan.py
  # Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0

Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
---
v2 changes:
- New patch.

 tools/testing/selftests/drivers/net/Makefile |   1 +
 tools/testing/selftests/drivers/net/vlan.py  | 100 +++++++++++++++++++
 2 files changed, 101 insertions(+)
 create mode 100755 tools/testing/selftests/drivers/net/vlan.py

diff --git a/tools/testing/selftests/drivers/net/Makefile b/tools/testing/selftests/drivers/net/Makefile
index d5bf4cb638a8..56c1dc16f8e9 100644
--- a/tools/testing/selftests/drivers/net/Makefile
+++ b/tools/testing/selftests/drivers/net/Makefile
@@ -24,6 +24,7 @@ TEST_PROGS := \
 	shaper.py \
 	so_txtime.py \
 	stats.py \
+	vlan.py \
 	xdp.py \
 # end of TEST_PROGS
 
diff --git a/tools/testing/selftests/drivers/net/vlan.py b/tools/testing/selftests/drivers/net/vlan.py
new file mode 100755
index 000000000000..82822a4b7bb5
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/vlan.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+
+"""
+VLAN tests.
+
+Validates that ping traffic is sent and received correctly over 802.1q
+and 802.1ad VLAN interfaces, with hardware VLAN stripping enabled and
+disabled.
+
+Test cases:
+  - 8021q_hw:  Traffic over a single 802.1q VLAN, HW stripping on
+  - 8021q_sw:  Traffic over a single 802.1q VLAN, HW stripping off
+  - 8021ad_hw: Traffic over a single 802.1ad VLAN, HW stripping on
+  - 8021ad_sw: Traffic over a single 802.1ad VLAN, HW stripping off
+  - qinq_hw:   Traffic over an 802.1q VLAN stacked on an 802.1ad VLAN,
+               HW stripping on
+  - qinq_sw:   Traffic over an 802.1q VLAN stacked on an 802.1ad VLAN,
+               HW stripping off
+"""
+
+import os
+from lib.py import ksft_run, ksft_exit
+from lib.py import NetDrvEpEnv
+from lib.py import cmd, defer, ethtool, ip, set_ethtool_feat
+from lib.py import ksft_variants, KsftNamedVariant
+
+OUTER_DEV = f"vlout{os.getpid()}"
+INNER_DEV = f"vlin{os.getpid()}"
+
+OUTER_VID = 100
+INNER_VID = 200
+
+LOCAL_IP = "198.51.100.1"
+REMOTE_IP = "198.51.100.2"
+
+
+def _vlan_add(base, name, proto, vid, host=None):
+    """Create a VLAN device on top of base and bring it up."""
+
+    ip(f"link add link {base} name {name} type vlan proto {proto} id {vid}",
+       host=host)
+    defer(ip, f"link del {name}", host=host)
+    ip(f"link set {name} up", host=host)
+
+
+def _vlan_setup(base, addr, outer_proto, inner_proto, host=None):
+    """Create VLAN interfaces on base and set an IP on the innermost one."""
+
+    _vlan_add(base, OUTER_DEV, outer_proto, OUTER_VID, host=host)
+    if inner_proto:
+        _vlan_add(OUTER_DEV, INNER_DEV, inner_proto, INNER_VID, host=host)
+
+    dev = INNER_DEV if inner_proto else OUTER_DEV
+    ip(f"addr add {addr}/24 dev {dev}", host=host)
+
+
+def _setup(cfg, outer_proto, inner_proto, hw_strip):
+    """Configure VLAN stripping and create the VLAN interfaces."""
+
+    feat = ethtool(f"-k {cfg.ifname}", json=True)[0]
+    set_ethtool_feat(cfg.ifname, feat, {"rx-vlan-offload": hw_strip})
+
+    _vlan_setup(cfg.ifname, LOCAL_IP, outer_proto, inner_proto)
+    _vlan_setup(cfg.remote_ifname, REMOTE_IP, outer_proto, inner_proto,
+                host=cfg.remote)
+
+
+def _vlan_variants():
+    """Generator that yields the VLAN protocols and the stripping mode."""
+
+    yield KsftNamedVariant("8021q_hw", "802.1q", None, True)
+    yield KsftNamedVariant("8021q_sw", "802.1q", None, False)
+    yield KsftNamedVariant("8021ad_hw", "802.1ad", None, True)
+    yield KsftNamedVariant("8021ad_sw", "802.1ad", None, False)
+    yield KsftNamedVariant("qinq_hw", "802.1ad", "802.1q", True)
+    yield KsftNamedVariant("qinq_sw", "802.1ad", "802.1q", False)
+
+
+@ksft_variants(_vlan_variants())
+def test(cfg, outer_proto, inner_proto, hw_strip):
+    """Run a single VLAN test"""
+
+    cfg.require_ipver("4")
+
+    _setup(cfg, outer_proto, inner_proto, hw_strip)
+
+    cmd(f"ping -c 1 -W 5 {REMOTE_IP}")
+
+
+def main() -> None:
+    """ Ksft boiler plate main """
+
+    with NetDrvEpEnv(__file__) as cfg:
+        ksft_run(cases=[test], args=(cfg, ))
+    ksft_exit()
+
+
+if __name__ == "__main__":
+    main()
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH net v2 6/6] selftests: drv-net: Add VLAN test
  2026-08-21 17:09 ` [PATCH net v2 6/6] selftests: drv-net: Add VLAN test Ovidiu Panait
@ 2026-08-23  0:04   ` Andrew Lunn
  2026-08-24 11:50     ` Ovidiu Panait
  0 siblings, 1 reply; 15+ messages in thread
From: Andrew Lunn @ 2026-08-23  0:04 UTC (permalink / raw)
  To: Ovidiu Panait
  Cc: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	mcoquelin.stm32, alexandre.torgue, shuah, joabreu, yi.fang.gan,
	jun.ann.lai, linux-kernel, netdev, linux-stm32, linux-arm-kernel,
	linux-kselftest

On Fri, Aug 21, 2026 at 05:09:59PM +0000, Ovidiu Panait wrote:
> Add a test that validates ping traffic over VLAN interfaces. It aims
> to catch drivers which mishandle hardware VLAN tag stripping, in
> particular QinQ.
> 
> Three VLAN configurations are covered, each with hardware VLAN stripping
> enabled and disabled:
> - a single 802.1q VLAN interface
> - a single 802.1ad VLAN interface
> - an 802.1q VLAN stacked on top of an 802.1ad interface
> 
> NETIF=end1 LOCAL_V4=172.16.0.2 REMOTE_V4=172.16.0.3 \
> REMOTE_TYPE=ssh REMOTE_ARGS=root@172.16.0.3 \
> run_kselftest.sh -t drivers/net:vlan.py
>   TAP version 13
>   1..1
>   # timeout set to 360
>   # selftests: drivers/net: vlan.py
>   # # Interface: end0, driver: st_gmac
>   # TAP version 13
>   # 1..6
>   # ok 1 vlan.test.8021q_hw
>   # ok 2 vlan.test.8021q_sw
>   # ok 3 vlan.test.8021ad_hw
>   # ok 4 vlan.test.8021ad_sw
>   # ok 5 vlan.test.qinq_hw
>   # ok 6 vlan.test.qinq_sw
>   # # Totals: pass:6 fail:0 xfail:0 xpass:0 skip:0 error:0

> +def _setup(cfg, outer_proto, inner_proto, hw_strip):
> +    """Configure VLAN stripping and create the VLAN interfaces."""
> +
> +    feat = ethtool(f"-k {cfg.ifname}", json=True)[0]
> +    set_ethtool_feat(cfg.ifname, feat, {"rx-vlan-offload": hw_strip})


+        if current[name]["active"] != state:
+            no_change = False
+            if current[name]["fixed"]:
+                raise KsftXfailEx(f"Device does not support {name}")

I'm not too familiar with the self test framework, so i could have
this wrong.

It looks to me like you fail the text if it is fixed. But does not
fixed just mean the hardware does not support it? So i think it should
actually skip the test?

Now, if it does not say fixed, but ethtool -K reports EOPNOTSUPP, that
would be an error.

Having said that, thanks for spending the time to add a test. We need
more tests like this.

     Andrew

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net v2 1/6] net: stmmac: Remove VLAN perfect matching dead code
  2026-08-21 17:09 ` [PATCH net v2 1/6] net: stmmac: Remove VLAN perfect matching dead code Ovidiu Panait
@ 2026-08-23  7:48   ` Maxime Chevallier
  0 siblings, 0 replies; 15+ messages in thread
From: Maxime Chevallier @ 2026-08-23  7:48 UTC (permalink / raw)
  To: Ovidiu Panait, andrew+netdev, davem, edumazet, kuba, pabeni,
	mcoquelin.stm32, alexandre.torgue, shuah, joabreu, yi.fang.gan,
	jun.ann.lai
  Cc: linux-kernel, netdev, linux-stm32, linux-arm-kernel,
	linux-kselftest

Hi Ovidiu,

On 8/21/26 19:09, Ovidiu Panait wrote:
> stmmac_vlan_update() falls back to "perfect matching" when the VLAN hash
> filter is unavailable (!priv->dma_cap.vlhash). This fallback has been
> unreachable in normal operation since its introduction in
> commit c7ab0b8088d7 ("net: stmmac: Fallback to VLAN Perfect filtering if
> HASH is not available") because the NETIF_F_HW_VLAN_{CTAG,STAG}_FILTER
> features are advertised only when priv->dma_cap.vlhash is true.
> 
> The fallback is also duplicating the code in vlan_add_hw_rx_fltr(), which
> is always available since stmmac_get_num_vlan() returns at least 1.
> 
> Therefore, remove it.
> 
> Fixes: c7ab0b8088d7 ("net: stmmac: Fallback to VLAN Perfect filtering if HASH is not available")
> Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>

Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>

Maxime

> ---
> v2 changes: None.
> 
>  drivers/net/ethernet/stmicro/stmmac/hwif.h    |  2 +-
>  .../net/ethernet/stmicro/stmmac/stmmac_main.c | 13 +-----
>  .../net/ethernet/stmicro/stmmac/stmmac_vlan.c | 41 +------------------
>  3 files changed, 4 insertions(+), 52 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
> index 04dafec021b4..6f26dbf95ce1 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
> @@ -633,7 +633,7 @@ struct stmmac_est_ops {
>  struct stmmac_vlan_ops {
>  	/* VLAN */
>  	void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash,
> -				 u16 perfect_match, bool is_double);
> +				 bool is_double);
>  	void (*enable_vlan)(struct mac_device_info *hw, u32 type);
>  	void (*rx_hw_vlan)(struct mac_device_info *hw, struct dma_desc *rx_desc,
>  			   struct sk_buff *skb);
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index b2b7d0242dd3..16fe56a1f617 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -6809,29 +6809,18 @@ static u32 stmmac_vid_crc32_le(__le16 vid_le)
>  static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double)
>  {
>  	u32 crc, hash = 0;
> -	u16 pmatch = 0;
> -	int count = 0;
>  	u16 vid = 0;
>  
>  	for_each_set_bit(vid, priv->active_vlans, VLAN_N_VID) {
>  		__le16 vid_le = cpu_to_le16(vid);
>  		crc = bitrev32(~stmmac_vid_crc32_le(vid_le)) >> 28;
>  		hash |= (1 << crc);
> -		count++;
> -	}
> -
> -	if (!priv->dma_cap.vlhash) {
> -		if (count > 2) /* VID = 0 always passes filter */
> -			return -EOPNOTSUPP;
> -
> -		pmatch = vid;
> -		hash = 0;
>  	}
>  
>  	if (!netif_running(priv->dev))
>  		return 0;
>  
> -	return stmmac_update_vlan_hash(priv, priv->hw, hash, pmatch, is_double);
> +	return stmmac_update_vlan_hash(priv, priv->hw, hash, is_double);
>  }
>  
>  /* FIXME: This may need RXC to be running, but it may be called with BH
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
> index e24efe3bfedb..983a90cb9767 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
> @@ -162,7 +162,7 @@ static void vlan_restore_hw_rx_fltr(struct net_device *dev,
>  }
>  
>  static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
> -			     u16 perfect_match, bool is_double)
> +			     bool is_double)
>  {
>  	void __iomem *ioaddr = hw->pcsr;
>  	u32 value;
> @@ -184,20 +184,6 @@ static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
>  		}
>  
>  		writel(value, ioaddr + VLAN_TAG);
> -	} else if (perfect_match) {
> -		u32 value = VLAN_ETV;
> -
> -		if (is_double) {
> -			value |= VLAN_EDVLP;
> -			value |= VLAN_ESVL;
> -			value |= VLAN_DOVLTC;
> -		} else {
> -			value &= ~VLAN_EDVLP;
> -			value &= ~VLAN_ESVL;
> -			value &= ~VLAN_DOVLTC;
> -		}
> -
> -		writel(value | perfect_match, ioaddr + VLAN_TAG);
>  	} else {
>  		value &= ~(VLAN_VTHM | VLAN_ETV);
>  		value &= ~(VLAN_EDVLP | VLAN_ESVL);
> @@ -251,7 +237,7 @@ static void vlan_set_hw_mode(struct mac_device_info *hw)
>  }
>  
>  static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
> -				      u16 perfect_match, bool is_double)
> +				      bool is_double)
>  {
>  	void __iomem *ioaddr = hw->pcsr;
>  
> @@ -279,29 +265,6 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
>  
>  		value &= ~VLAN_VID;
>  		writel(value, ioaddr + VLAN_TAG);
> -	} else if (perfect_match) {
> -		u32 value = readl(ioaddr + XGMAC_PACKET_FILTER);
> -
> -		value |= XGMAC_FILTER_VTFE;
> -
> -		writel(value, ioaddr + XGMAC_PACKET_FILTER);
> -
> -		value = readl(ioaddr + VLAN_TAG);
> -
> -		value &= ~VLAN_VTHM;
> -		value |= VLAN_ETV;
> -		if (is_double) {
> -			value |= VLAN_EDVLP;
> -			value |= VLAN_ESVL;
> -			value |= VLAN_DOVLTC;
> -		} else {
> -			value &= ~VLAN_EDVLP;
> -			value &= ~VLAN_ESVL;
> -			value &= ~VLAN_DOVLTC;
> -		}
> -
> -		value &= ~VLAN_VID;
> -		writel(value | perfect_match, ioaddr + VLAN_TAG);
>  	} else {
>  		u32 value = readl(ioaddr + XGMAC_PACKET_FILTER);
>  


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net v2 2/6] net: stmmac: Enable double VLAN processing only when supported
  2026-08-21 17:09 ` [PATCH net v2 2/6] net: stmmac: Enable double VLAN processing only when supported Ovidiu Panait
@ 2026-08-23  7:49   ` Maxime Chevallier
  2026-08-24  6:47   ` Joseph Steel
  1 sibling, 0 replies; 15+ messages in thread
From: Maxime Chevallier @ 2026-08-23  7:49 UTC (permalink / raw)
  To: Ovidiu Panait, andrew+netdev, davem, edumazet, kuba, pabeni,
	mcoquelin.stm32, alexandre.torgue, shuah, joabreu, yi.fang.gan,
	jun.ann.lai
  Cc: linux-kernel, netdev, linux-stm32, linux-arm-kernel,
	linux-kselftest

Hi,

On 8/21/26 19:09, Ovidiu Panait wrote:
> stmmac_vlan_update() turns on double/S-VLAN processing whenever an
> 802.1ad VLAN is registered, without checking whether the MAC actually
> supports double VLAN processing. That capability is reported in
> dma_cap.dvlan.
> 
> This was found while investigating a separate bug in the double VLAN RX
> stripping path. The outer 802.1ad tags were unexpectedly stripped by the
> MAC (because the ESVL bit was set).
> 
> Check dma_cap.dvlan before enabling EDVLP/ESVL/DOVLTC bits, so that double
> VLAN processing is enabled only on supported hardware. Also, advertise
> NETIF_F_HW_VLAN_STAG_RX and NETIF_F_HW_VLAN_STAG_FILTER only when
> dma_cap.dvlan is set.
> 
> Fixes: 3cd1cfcba26e ("net: stmmac: Implement VLAN Hash Filtering in XGMAC")
> Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>

Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>

Maxime

> ---
> v2 changes:
> - Advertised NETIF_F_HW_VLAN_STAG_RX and NETIF_F_HW_VLAN_STAG_FILTER only
>   when dma_cap.dvlan is set (reported by Sashiko).
> 
>  drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 11 +++++++++--
>  1 file changed, 9 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 16fe56a1f617..880cf3fab913 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -6820,6 +6820,9 @@ static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double)
>  	if (!netif_running(priv->dev))
>  		return 0;
>  
> +	if (!priv->dma_cap.dvlan)
> +		is_double = false;
> +
>  	return stmmac_update_vlan_hash(priv, priv->hw, hash, is_double);
>  }
>  
> @@ -7954,14 +7957,18 @@ static int __stmmac_dvr_probe(struct device *device,
>  	ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
>  #ifdef STMMAC_VLAN_TAG_USED
>  	/* Both mac100 and gmac support receive VLAN tag detection */
> -	ndev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX;
> +	ndev->features |= NETIF_F_HW_VLAN_CTAG_RX;
> +	if (priv->dma_cap.dvlan)
> +		ndev->features |= NETIF_F_HW_VLAN_STAG_RX;
> +
>  	if (dwmac_is_xmac(priv->plat->core_type)) {
>  		ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
>  		priv->hw->hw_vlan_en = true;
>  	}
>  	if (priv->dma_cap.vlhash) {
>  		ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
> -		ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER;
> +		if (priv->dma_cap.dvlan)
> +			ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER;
>  	}
>  	if (priv->dma_cap.vlins)
>  		ndev->features |= NETIF_F_HW_VLAN_CTAG_TX;


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net v2 3/6] net: stmmac: Move double VLAN handling to a dedicated op
  2026-08-21 17:09 ` [PATCH net v2 3/6] net: stmmac: Move double VLAN handling to a dedicated op Ovidiu Panait
@ 2026-08-23  7:52   ` Maxime Chevallier
  0 siblings, 0 replies; 15+ messages in thread
From: Maxime Chevallier @ 2026-08-23  7:52 UTC (permalink / raw)
  To: Ovidiu Panait, andrew+netdev, davem, edumazet, kuba, pabeni,
	mcoquelin.stm32, alexandre.torgue, shuah, joabreu, yi.fang.gan,
	jun.ann.lai
  Cc: linux-kernel, netdev, linux-stm32, linux-arm-kernel,
	linux-kselftest

Hi,

On 8/21/26 19:09, Ovidiu Panait wrote:
> The double VLAN bits (EDVLP, ESVL, DOVLTC) are currently handled inside
> update_vlan_hash(). This ties the double VLAN state to the hash filter
> update, even though the two features are independent: hash filtering is
> controlled by dma_cap.vlhash and double vlan by dma_cap.dvlan.
> 
> In preparation for removing double vlan support from dwmac4, move the
> double vlan logic into a separate update_dvlan_state() VLAN operation.
> 
> Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>

This is some nice code simplification, no more is_double everywhere, thanks!

Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>

Maxime

> ---
> v2 changes: None.
> 
>  drivers/net/ethernet/stmicro/stmmac/hwif.h    |  6 ++-
>  .../net/ethernet/stmicro/stmmac/stmmac_main.c |  6 +--
>  .../net/ethernet/stmicro/stmmac/stmmac_vlan.c | 45 ++++++++-----------
>  3 files changed, 25 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
> index 6f26dbf95ce1..66837caafa84 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
> +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
> @@ -632,8 +632,8 @@ struct stmmac_est_ops {
>  
>  struct stmmac_vlan_ops {
>  	/* VLAN */
> -	void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash,
> -				 bool is_double);
> +	void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash);
> +	void (*update_dvlan_state)(struct mac_device_info *hw, bool enable);
>  	void (*enable_vlan)(struct mac_device_info *hw, u32 type);
>  	void (*rx_hw_vlan)(struct mac_device_info *hw, struct dma_desc *rx_desc,
>  			   struct sk_buff *skb);
> @@ -650,6 +650,8 @@ struct stmmac_vlan_ops {
>  
>  #define stmmac_update_vlan_hash(__priv, __args...) \
>  	stmmac_do_void_callback(__priv, vlan, update_vlan_hash, __args)
> +#define stmmac_update_dvlan_state(__priv, __args...) \
> +	stmmac_do_void_callback(__priv, vlan, update_dvlan_state, __args)
>  #define stmmac_enable_vlan(__priv, __args...) \
>  	stmmac_do_void_callback(__priv, vlan, enable_vlan, __args)
>  #define stmmac_rx_hw_vlan(__priv, __args...) \
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> index 880cf3fab913..802f9e67a4bc 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> @@ -6820,10 +6820,10 @@ static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double)
>  	if (!netif_running(priv->dev))
>  		return 0;
>  
> -	if (!priv->dma_cap.dvlan)
> -		is_double = false;
> +	if (priv->dma_cap.dvlan)
> +		stmmac_update_dvlan_state(priv, priv->hw, is_double);
>  
> -	return stmmac_update_vlan_hash(priv, priv->hw, hash, is_double);
> +	return stmmac_update_vlan_hash(priv, priv->hw, hash);
>  }
>  
>  /* FIXME: This may need RXC to be running, but it may be called with BH
> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
> index 983a90cb9767..1e47ae62093e 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
> @@ -161,8 +161,20 @@ static void vlan_restore_hw_rx_fltr(struct net_device *dev,
>  		vlan_write_filter(dev, hw, i, hw->vlan_filter[i]);
>  }
>  
> -static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
> -			     bool is_double)
> +static void vlan_update_dvlan_state(struct mac_device_info *hw, bool enable)
> +{
> +	void __iomem *ioaddr = hw->pcsr;
> +	u32 value;
> +
> +	value = readl(ioaddr + VLAN_TAG);
> +	if (enable)
> +		value |= VLAN_EDVLP | VLAN_ESVL | VLAN_DOVLTC;
> +	else
> +		value &= ~(VLAN_EDVLP | VLAN_ESVL | VLAN_DOVLTC);
> +	writel(value, ioaddr + VLAN_TAG);
> +}
> +
> +static void vlan_update_hash(struct mac_device_info *hw, u32 hash)
>  {
>  	void __iomem *ioaddr = hw->pcsr;
>  	u32 value;
> @@ -173,21 +185,9 @@ static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
>  
>  	if (hash) {
>  		value |= VLAN_VTHM | VLAN_ETV;
> -		if (is_double) {
> -			value |= VLAN_EDVLP;
> -			value |= VLAN_ESVL;
> -			value |= VLAN_DOVLTC;
> -		} else {
> -			value &= ~VLAN_EDVLP;
> -			value &= ~VLAN_ESVL;
> -			value &= ~VLAN_DOVLTC;
> -		}
> -
>  		writel(value, ioaddr + VLAN_TAG);
>  	} else {
>  		value &= ~(VLAN_VTHM | VLAN_ETV);
> -		value &= ~(VLAN_EDVLP | VLAN_ESVL);
> -		value &= ~VLAN_DOVLTC;
>  		value &= ~VLAN_VID;
>  
>  		writel(value, ioaddr + VLAN_TAG);
> @@ -236,8 +236,7 @@ static void vlan_set_hw_mode(struct mac_device_info *hw)
>  	writel(value, ioaddr + VLAN_TAG);
>  }
>  
> -static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
> -				      bool is_double)
> +static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash)
>  {
>  	void __iomem *ioaddr = hw->pcsr;
>  
> @@ -253,15 +252,6 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
>  		value = readl(ioaddr + VLAN_TAG);
>  
>  		value |= VLAN_VTHM | VLAN_ETV;
> -		if (is_double) {
> -			value |= VLAN_EDVLP;
> -			value |= VLAN_ESVL;
> -			value |= VLAN_DOVLTC;
> -		} else {
> -			value &= ~VLAN_EDVLP;
> -			value &= ~VLAN_ESVL;
> -			value &= ~VLAN_DOVLTC;
> -		}
>  
>  		value &= ~VLAN_VID;
>  		writel(value, ioaddr + VLAN_TAG);
> @@ -275,8 +265,6 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
>  		value = readl(ioaddr + VLAN_TAG);
>  
>  		value &= ~(VLAN_VTHM | VLAN_ETV);
> -		value &= ~(VLAN_EDVLP | VLAN_ESVL);
> -		value &= ~VLAN_DOVLTC;
>  		value &= ~VLAN_VID;
>  
>  		writel(value, ioaddr + VLAN_TAG);
> @@ -285,6 +273,7 @@ static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash,
>  
>  const struct stmmac_vlan_ops dwmac_vlan_ops = {
>  	.update_vlan_hash = vlan_update_hash,
> +	.update_dvlan_state = vlan_update_dvlan_state,
>  	.enable_vlan = vlan_enable,
>  	.add_hw_vlan_rx_fltr = vlan_add_hw_rx_fltr,
>  	.del_hw_vlan_rx_fltr = vlan_del_hw_rx_fltr,
> @@ -295,11 +284,13 @@ const struct stmmac_vlan_ops dwmac_vlan_ops = {
>  
>  const struct stmmac_vlan_ops dwxlgmac2_vlan_ops = {
>  	.update_vlan_hash = dwxgmac2_update_vlan_hash,
> +	.update_dvlan_state = vlan_update_dvlan_state,
>  	.enable_vlan = vlan_enable,
>  };
>  
>  const struct stmmac_vlan_ops dwxgmac210_vlan_ops = {
>  	.update_vlan_hash = dwxgmac2_update_vlan_hash,
> +	.update_dvlan_state = vlan_update_dvlan_state,
>  	.enable_vlan = vlan_enable,
>  	.add_hw_vlan_rx_fltr = vlan_add_hw_rx_fltr,
>  	.del_hw_vlan_rx_fltr = vlan_del_hw_rx_fltr,


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net v2 2/6] net: stmmac: Enable double VLAN processing only when supported
  2026-08-21 17:09 ` [PATCH net v2 2/6] net: stmmac: Enable double VLAN processing only when supported Ovidiu Panait
  2026-08-23  7:49   ` Maxime Chevallier
@ 2026-08-24  6:47   ` Joseph Steel
  2026-08-24 14:06     ` Ovidiu Panait
  1 sibling, 1 reply; 15+ messages in thread
From: Joseph Steel @ 2026-08-24  6:47 UTC (permalink / raw)
  To: Ovidiu Panait
  Cc: maxime.chevallier, andrew+netdev, davem, edumazet, kuba, pabeni,
	mcoquelin.stm32, alexandre.torgue, shuah, joabreu, yi.fang.gan,
	jun.ann.lai, linux-kernel, netdev, linux-stm32, linux-arm-kernel,
	linux-kselftest

On Fri, Aug 21, 2026 at 05:09:55PM +0000, Ovidiu Panait wrote:
> stmmac_vlan_update() turns on double/S-VLAN processing whenever an
> 802.1ad VLAN is registered, without checking whether the MAC actually
> supports double VLAN processing. That capability is reported in
> dma_cap.dvlan.

This is not true. S-VLAN is never reported by the dma_cap.dvlan
feature flag. Double VLAN tagging and S-Tag VLAN features are fully
independent.

-Joseph

> 
> This was found while investigating a separate bug in the double VLAN RX
> stripping path. The outer 802.1ad tags were unexpectedly stripped by the
> MAC (because the ESVL bit was set).
> 
> Check dma_cap.dvlan before enabling EDVLP/ESVL/DOVLTC bits, so that double
> VLAN processing is enabled only on supported hardware. Also, advertise
> NETIF_F_HW_VLAN_STAG_RX and NETIF_F_HW_VLAN_STAG_FILTER only when
> dma_cap.dvlan is set.
> 


^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [PATCH net v2 6/6] selftests: drv-net: Add VLAN test
  2026-08-23  0:04   ` Andrew Lunn
@ 2026-08-24 11:50     ` Ovidiu Panait
  2026-08-24 17:42       ` Jakub Kicinski
  0 siblings, 1 reply; 15+ messages in thread
From: Ovidiu Panait @ 2026-08-24 11:50 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: maxime.chevallier@bootlin.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, mcoquelin.stm32@gmail.com,
	alexandre.torgue@foss.st.com, shuah@kernel.org,
	joabreu@synopsys.com, yi.fang.gan@intel.com,
	jun.ann.lai@intel.com, linux-kernel@vger.kernel.org,
	netdev@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com,
	linux-arm-kernel@lists.infradead.org,
	linux-kselftest@vger.kernel.org

Hi Andrew,

> 
> On Fri, Aug 21, 2026 at 05:09:59PM +0000, Ovidiu Panait wrote:
> > Add a test that validates ping traffic over VLAN interfaces. It aims
> > to catch drivers which mishandle hardware VLAN tag stripping, in
> > particular QinQ.
> >
> > Three VLAN configurations are covered, each with hardware VLAN stripping
> > enabled and disabled:
> > - a single 802.1q VLAN interface
> > - a single 802.1ad VLAN interface
> > - an 802.1q VLAN stacked on top of an 802.1ad interface
> >
> > NETIF=end1 LOCAL_V4=172.16.0.2 REMOTE_V4=172.16.0.3 \
> > REMOTE_TYPE=ssh REMOTE_ARGS=root@172.16.0.3 \
> > run_kselftest.sh -t drivers/net:vlan.py
> >   TAP version 13
> >   1..1
> >   # timeout set to 360
> >   # selftests: drivers/net: vlan.py
> >   # # Interface: end0, driver: st_gmac
> >   # TAP version 13
> >   # 1..6
> >   # ok 1 vlan.test.8021q_hw
> >   # ok 2 vlan.test.8021q_sw
> >   # ok 3 vlan.test.8021ad_hw
> >   # ok 4 vlan.test.8021ad_sw
> >   # ok 5 vlan.test.qinq_hw
> >   # ok 6 vlan.test.qinq_sw
> >   # # Totals: pass:6 fail:0 xfail:0 xpass:0 skip:0 error:0
> 
> > +def _setup(cfg, outer_proto, inner_proto, hw_strip):
> > +    """Configure VLAN stripping and create the VLAN interfaces."""
> > +
> > +    feat = ethtool(f"-k {cfg.ifname}", json=True)[0]
> > +    set_ethtool_feat(cfg.ifname, feat, {"rx-vlan-offload": hw_strip})
> 
> 
> +        if current[name]["active"] != state:
> +            no_change = False
> +            if current[name]["fixed"]:
> +                raise KsftXfailEx(f"Device does not support {name}")
> 
> I'm not too familiar with the self test framework, so i could have
> this wrong.
> 
> It looks to me like you fail the text if it is fixed. But does not
> fixed just mean the hardware does not support it? So i think it should
> actually skip the test?
> 

I compared the XFAIL vs SKIP usage when a certain hw feature is not
supported and it seems that most tests use SKIP (tso.py, gro_hw.py,
hds.py, ntuple.py, etc). I will switch to SKIP in v3, which should also
allow for some reduction in code duplication across tests.

Ovidiu

> Now, if it does not say fixed, but ethtool -K reports EOPNOTSUPP, that
> would be an error.
> 
> Having said that, thanks for spending the time to add a test. We need
> more tests like this.
> 
>      Andrew

^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [PATCH net v2 2/6] net: stmmac: Enable double VLAN processing only when supported
  2026-08-24  6:47   ` Joseph Steel
@ 2026-08-24 14:06     ` Ovidiu Panait
  0 siblings, 0 replies; 15+ messages in thread
From: Ovidiu Panait @ 2026-08-24 14:06 UTC (permalink / raw)
  To: Joseph Steel
  Cc: maxime.chevallier@bootlin.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, mcoquelin.stm32@gmail.com,
	alexandre.torgue@foss.st.com, shuah@kernel.org,
	joabreu@synopsys.com, yi.fang.gan@intel.com,
	jun.ann.lai@intel.com, linux-kernel@vger.kernel.org,
	netdev@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com,
	linux-arm-kernel@lists.infradead.org,
	linux-kselftest@vger.kernel.org

Hi Joseph,

> 
> On Fri, Aug 21, 2026 at 05:09:55PM +0000, Ovidiu Panait wrote:
> > stmmac_vlan_update() turns on double/S-VLAN processing whenever an
> > 802.1ad VLAN is registered, without checking whether the MAC actually
> > supports double VLAN processing. That capability is reported in
> > dma_cap.dvlan.
> 
> This is not true. S-VLAN is never reported by the dma_cap.dvlan
> feature flag. Double VLAN tagging and S-Tag VLAN features are fully
> independent.
> 

Right, thanks for the correction.

The EDVLP bit, which is currently set unconditionally when an 802.1ad
VLAN is registered, seems to be the only one that truly depends on the
dvlan feature flag. Taking a closer look, setting EDVLP shouldn't be
needed at all, as the driver doesn't implement any feature it gates
(inner VLAN stripping/filtering). I guess removing it should be part
of a follow up cleanup series. 

For now, I will just drop this patch in v3.

Thanks,
Ovidiu

> -Joseph
> 
> >
> > This was found while investigating a separate bug in the double VLAN RX
> > stripping path. The outer 802.1ad tags were unexpectedly stripped by the
> > MAC (because the ESVL bit was set).
> >
> > Check dma_cap.dvlan before enabling EDVLP/ESVL/DOVLTC bits, so that
> double
> > VLAN processing is enabled only on supported hardware. Also, advertise
> > NETIF_F_HW_VLAN_STAG_RX and NETIF_F_HW_VLAN_STAG_FILTER only when
> > dma_cap.dvlan is set.
> >


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH net v2 6/6] selftests: drv-net: Add VLAN test
  2026-08-24 11:50     ` Ovidiu Panait
@ 2026-08-24 17:42       ` Jakub Kicinski
  0 siblings, 0 replies; 15+ messages in thread
From: Jakub Kicinski @ 2026-08-24 17:42 UTC (permalink / raw)
  To: Ovidiu Panait
  Cc: Andrew Lunn, maxime.chevallier@bootlin.com, andrew+netdev@lunn.ch,
	davem@davemloft.net, edumazet@google.com, pabeni@redhat.com,
	mcoquelin.stm32@gmail.com, alexandre.torgue@foss.st.com,
	shuah@kernel.org, joabreu@synopsys.com, yi.fang.gan@intel.com,
	jun.ann.lai@intel.com, linux-kernel@vger.kernel.org,
	netdev@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com,
	linux-arm-kernel@lists.infradead.org,
	linux-kselftest@vger.kernel.org

On Mon, 24 Aug 2026 11:50:12 +0000 Ovidiu Panait wrote:
> > +            no_change = False
> > +            if current[name]["fixed"]:
> > +                raise KsftXfailEx(f"Device does not support {name}")
> > 
> > I'm not too familiar with the self test framework, so i could have
> > this wrong.
> > 
> > It looks to me like you fail the text if it is fixed. But does not
> > fixed just mean the hardware does not support it? So i think it should
> > actually skip the test?
> 
> I compared the XFAIL vs SKIP usage when a certain hw feature is not
> supported and it seems that most tests use SKIP (tso.py, gro_hw.py,
> hds.py, ntuple.py, etc). I will switch to SKIP in v3, which should also
> allow for some reduction in code duplication across tests.

Please double check that the test passes on netdevsim (without NETIF)
We can't have skips in SW mode, all drivers/net tests are expected to 
run against netdevsim, really. If they don't they should live under hw/
(where the SKIP vs XFAIL distinction does not matter).

BTW there are ruff check and new pylint --disable=R warnings in the
python code, pls fix

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2026-08-24 17:43 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-21 17:09 [PATCH net v2 0/6] net: stmmac: Fix double VLAN 802.1ad tag handling Ovidiu Panait
2026-08-21 17:09 ` [PATCH net v2 1/6] net: stmmac: Remove VLAN perfect matching dead code Ovidiu Panait
2026-08-23  7:48   ` Maxime Chevallier
2026-08-21 17:09 ` [PATCH net v2 2/6] net: stmmac: Enable double VLAN processing only when supported Ovidiu Panait
2026-08-23  7:49   ` Maxime Chevallier
2026-08-24  6:47   ` Joseph Steel
2026-08-24 14:06     ` Ovidiu Panait
2026-08-21 17:09 ` [PATCH net v2 3/6] net: stmmac: Move double VLAN handling to a dedicated op Ovidiu Panait
2026-08-23  7:52   ` Maxime Chevallier
2026-08-21 17:09 ` [PATCH net v2 4/6] net: stmmac: Disable double VLAN handling on dwmac4 Ovidiu Panait
2026-08-21 17:09 ` [PATCH net v2 5/6] selftests: drv-net: Move _set_ethtool_feat() into lib Ovidiu Panait
2026-08-21 17:09 ` [PATCH net v2 6/6] selftests: drv-net: Add VLAN test Ovidiu Panait
2026-08-23  0:04   ` Andrew Lunn
2026-08-24 11:50     ` Ovidiu Panait
2026-08-24 17:42       ` Jakub Kicinski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox