summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Semin <fancer.lancer@gmail.com>2025-04-08 23:52:37 +0300
committerSerge Semin <fancer.lancer@gmail.com>2026-08-13 20:34:38 +0300
commit523a423a3ec0ad5725f1fa881e6986339f3e7a38 (patch)
treefe3f30d4f9a4d6c0e02dbd4a841c8fd8078a28f9
parent58cf7d6e3073700c2c34186a2fec3afcac332411 (diff)
downloadlinux-gmac/ext1/vlan.tar.gz
linux-gmac/ext1/vlan.zip
net: stmmac: vlan: Drop redundant mac_device_info::hw_vlan_en flaggmac/ext1/vlan
The flag has been introduced in the commit 750011e239a5 ("net: stmmac: Add support for HW-accelerated VLAN stripping") in order to logically split up the HW-offloaded VLAN tag stripping and the stripping implemented in the driver. As the commit log says it's supposed to be in sync with the NETIF_F_HW_VLAN_CTAG_RX feature-flag, otherwise the software-based VLAN tag stripping will be performed. First of all the denoted semantics is incorrect, since the MAC and driver-based VLAN tag stripping are mutually exclusive features and are supposed to be enabled/disabled by the NETIF_F_HW_VLAN_CTAG_RX/NETIF_F_HW_VLAN_STAG_RX feature flags. Secondly the flags can be directly retrieved from the net_device::features field anytime in the driver. So introducing another mirror-flag for that was unnecessary. Finally the MAC-based VLAN tag stripping is always persistent in the DW *MAC IP-cores supporting VLANs (at least DW Ether QoS and DW XGMAC). Thus as long as the HW-offloaded VLAN tag stripping is implemented in the respective VLAN driver it can be utilized instead of the software-based tag stripping code. So to speak let's drop the mac_device_info::hw_vlan_en flag and just switch on/off the VLAN tags stripping feature based on the respective flags set in the net_device::features field. Please note that since the VLAN-based features are available on the kernel with the CONFIG_VLAN_8021Q config enabled it is pointless to parse VLAN Ethernet-header if the config is disable. In that case the entire stmmac_get_rx_vlan() body can be compiled off thus speeding up the Rx fast-path of the driver. Note as a nice side effect of this change the VLAN tag stripping feature is now capable to be switched on/off by the system administrator irrespective whether it's HW-offloaded or not. Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/hwif.h3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c58
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c5
4 files changed, 40 insertions, 27 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 8403a3e17211..dff7a12047a2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -661,7 +661,6 @@ struct mac_device_info {
u32 vlan_filter[32];
bool vlan_fail_q_en;
u8 vlan_fail_q;
- bool hw_vlan_en;
bool reverse_sgmii_enable;
/* This spinlock protects read-modify-write of the interrupt
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index 45111ec4902f..6996fe2e1336 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -632,7 +632,8 @@ struct stmmac_vlan_ops {
bool is_svlan);
void (*rx_hw_vlan)(struct mac_device_info *hw, struct dma_desc *rx_desc,
struct sk_buff *skb);
- void (*set_hw_vlan_mode)(struct mac_device_info *hw, bool tx_stag);
+ void (*set_hw_vlan_mode)(struct mac_device_info *hw, bool rx_strip,
+ bool tx_stag);
int (*add_hw_vlan_rx_fltr)(struct net_device *dev,
struct mac_device_info *hw,
__be16 proto, u16 vid);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index ae2dea6b3d3c..47de06bbde2f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -3893,6 +3893,8 @@ static int stmmac_hw_setup(struct net_device *dev)
phylink_rx_clk_stop_block(priv->phylink);
stmmac_set_hw_vlan_mode(priv, priv->hw,
+ dev->features & (NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_STAG_RX),
dev->features & NETIF_F_HW_VLAN_STAG_TX);
phylink_rx_clk_stop_unblock(priv->phylink);
@@ -5158,22 +5160,43 @@ static int stmmac_get_rx_status(struct stmmac_priv *priv, struct dma_desc *p)
return ret | discard_frame;
}
-static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb)
+/**
+ * stmmac_get_rx_vlan - Extract VLAN ID from the frame
+ * @priv: driver private structure
+ * @p : descriptor pointer
+ * @skb : the socket buffer
+ * Description :
+ * This function will either read the VLAN ID and TCI from the DMA-descriptor
+ * (if it's supported the VLAN stripping has been enabled) or just perform
+ * the VLAN header stripping directly from the payload.
+ */
+static void stmmac_get_rx_vlan(struct stmmac_priv *priv, struct dma_desc *p,
+ struct sk_buff *skb)
{
+#ifdef STMMAC_VLAN_TAG_USED
struct vlan_ethhdr *veth = skb_vlan_eth_hdr(skb);
- __be16 vlan_proto = veth->h_vlan_proto;
+ __be16 vlan_proto;
u16 vlanid;
+ int ret;
+
+ /* MAC level stripping */
+ ret = stmmac_rx_hw_vlan(priv, priv->hw, p, skb);
+ if (!ret)
+ return;
+ /* Driver level stripping */
+ vlan_proto = veth->h_vlan_proto;
if ((vlan_proto == htons(ETH_P_8021Q) &&
- dev->features & NETIF_F_HW_VLAN_CTAG_RX) ||
+ priv->dev->features & NETIF_F_HW_VLAN_CTAG_RX) ||
(vlan_proto == htons(ETH_P_8021AD) &&
- dev->features & NETIF_F_HW_VLAN_STAG_RX)) {
+ priv->dev->features & NETIF_F_HW_VLAN_STAG_RX)) {
/* pop the vlan tag */
vlanid = ntohs(veth->h_vlan_TCI);
memmove(skb->data + VLAN_HLEN, veth, ETH_ALEN * 2);
skb_pull(skb, VLAN_HLEN);
__vlan_hwaccel_put_tag(skb, vlan_proto, vlanid);
}
+#endif
}
/**
@@ -5639,12 +5662,9 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
}
stmmac_get_rx_hwtstamp(priv, p, np, skb);
- if (priv->hw->hw_vlan_en)
- /* MAC level stripping. */
- stmmac_rx_hw_vlan(priv, priv->hw, p, skb);
- else
- /* Driver level stripping. */
- stmmac_rx_vlan(priv->dev, skb);
+
+ stmmac_get_rx_vlan(priv, p, skb);
+
skb->protocol = eth_type_trans(skb, priv->dev);
stmmac_get_rx_csum(priv, status, skb);
@@ -6133,12 +6153,7 @@ drain_data:
stmmac_get_rx_hwtstamp(priv, p, np, skb);
- if (priv->hw->hw_vlan_en)
- /* MAC level stripping. */
- stmmac_rx_hw_vlan(priv, priv->hw, p, skb);
- else
- /* Driver level stripping. */
- stmmac_rx_vlan(priv->dev, skb);
+ stmmac_get_rx_vlan(priv, p, skb);
skb->protocol = eth_type_trans(skb, priv->dev);
@@ -6502,11 +6517,10 @@ static int stmmac_set_features(struct net_device *netdev,
features & NETIF_F_RXHASH,
priv->plat->rx_queues_to_use);
- if (netdev->hw_features & NETIF_F_HW_VLAN_CTAG_RX)
- priv->hw->hw_vlan_en = !!(features & NETIF_F_HW_VLAN_CTAG_RX);
-
phylink_rx_clk_stop_block(priv->phylink);
stmmac_set_hw_vlan_mode(priv, priv->hw,
+ features & (NETIF_F_HW_VLAN_CTAG_RX |
+ NETIF_F_HW_VLAN_STAG_RX),
features & NETIF_F_HW_VLAN_STAG_TX);
phylink_rx_clk_stop_unblock(priv->phylink);
@@ -8753,10 +8767,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 | NETIF_F_HW_VLAN_STAG_RX;
- if (dwmac_is_xmac(priv->plat->core_type)) {
- ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX;
- priv->hw->hw_vlan_en = true;
- }
+ ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX;
+
if (priv->dma_cap.vlhash) {
ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
index 77fe0ea31c33..bb0521978453 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
@@ -239,14 +239,15 @@ static void vlan_rx_hw(struct mac_device_info *hw,
}
}
-static void vlan_set_hw_mode(struct mac_device_info *hw, bool tx_stag)
+static void vlan_set_hw_mode(struct mac_device_info *hw, bool rx_strip,
+ bool tx_stag)
{
void __iomem *ioaddr = hw->pcsr;
u32 value = readl(ioaddr + VLAN_TAG);
value &= ~VLAN_TAG_CTRL_EVLS_MASK;
- if (hw->hw_vlan_en)
+ if (rx_strip)
/* Always strip VLAN on Receive */
value |= VLAN_TAG_STRIP_ALL;
else