diff options
| author | Serge Semin <fancer.lancer@gmail.com> | 2025-04-08 23:52:37 +0300 |
|---|---|---|
| committer | Serge Semin <fancer.lancer@gmail.com> | 2026-08-13 20:34:38 +0300 |
| commit | 523a423a3ec0ad5725f1fa881e6986339f3e7a38 (patch) | |
| tree | fe3f30d4f9a4d6c0e02dbd4a841c8fd8078a28f9 | |
| parent | 58cf7d6e3073700c2c34186a2fec3afcac332411 (diff) | |
| download | linux-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.h | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/hwif.h | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 58 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c | 5 |
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 |
