]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: stmmac: dwxgmac2: Add support for HW-accelerated VLAN stripping
authorBoon Khai Ng <boon.khai.ng@altera.com>
Wed, 7 May 2025 06:38:12 +0000 (14:38 +0800)
committerJakub Kicinski <kuba@kernel.org>
Sat, 10 May 2025 00:29:43 +0000 (17:29 -0700)
This patch adds support for MAC level VLAN tag stripping for the
dwxgmac2 IP. This feature can be configured through ethtool.
If the rx-vlan-offload is off, then the VLAN tag will be stripped
by the driver. If the rx-vlan-offload is on then the VLAN tag
will be stripped by the MAC.

Signed-off-by: Boon Khai Ng <boon.khai.ng@altera.com>
Reviewed-by: Matthew Gerlach <matthew.gerlach@altera.com>
Link: https://patch.msgid.link/20250507063812.34000-4-boon.khai.ng@altera.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c

index 5e369a9a25959a5c45400cc437c5db7848c1bc5b..0d408ee17f337851502cbcba8e82d2b839b9db02 100644 (file)
 #define XGMAC_RDES3_RSV                        BIT(26)
 #define XGMAC_RDES3_L34T               GENMASK(23, 20)
 #define XGMAC_RDES3_L34T_SHIFT         20
+#define XGMAC_RDES3_ET_LT              GENMASK(19, 16)
 #define XGMAC_L34T_IP4TCP              0x1
 #define XGMAC_L34T_IP4UDP              0x2
 #define XGMAC_L34T_IP6TCP              0x9
 #define XGMAC_RDES3_TSD                        BIT(6)
 #define XGMAC_RDES3_TSA                        BIT(4)
 
+/* RDES0 (write back format) */
+#define XGMAC_RDES0_VLAN_TAG_MASK      GENMASK(15, 0)
+
+/* Error Type or L2 Type(ET/LT) Field Number */
+#define XGMAC_ET_LT_VLAN_STAG          8
+#define XGMAC_ET_LT_VLAN_CTAG          9
+#define XGMAC_ET_LT_DVLAN_CTAG_CTAG    10
+#define XGMAC_ET_LT_DVLAN_STAG_STAG    11
+#define XGMAC_ET_LT_DVLAN_CTAG_STAG    12
+#define XGMAC_ET_LT_DVLAN_STAG_CTAG    13
+
 extern const struct stmmac_ops dwxgmac210_ops;
 extern const struct stmmac_ops dwxlgmac2_ops;
 extern const struct stmmac_dma_ops dwxgmac210_dma_ops;
index d9f41c047e5e157d20779e7024a072b9ebec2e34..6cadf8de4fdfdb18af1a112b883b3d33a53da638 100644 (file)
@@ -10,6 +10,7 @@
 #include "stmmac.h"
 #include "stmmac_fpe.h"
 #include "stmmac_ptp.h"
+#include "stmmac_vlan.h"
 #include "dwxlgmac2.h"
 #include "dwxgmac2.h"
 
@@ -1551,6 +1552,7 @@ int dwxgmac2_setup(struct stmmac_priv *priv)
        mac->mii.reg_mask = GENMASK(15, 0);
        mac->mii.clk_csr_shift = 19;
        mac->mii.clk_csr_mask = GENMASK(21, 19);
+       mac->num_vlan = stmmac_get_num_vlan(priv->ioaddr);
 
        return 0;
 }
index 389aad7b5c1ee3ae8e9365d88f3df8ab1b77668d..a2980482fccea99f955f476e23d31a083c67dde7 100644 (file)
@@ -4,6 +4,7 @@
  * stmmac XGMAC support.
  */
 
+#include <linux/bitfield.h>
 #include <linux/stmmac.h>
 #include "common.h"
 #include "dwxgmac2.h"
@@ -69,6 +70,21 @@ static int dwxgmac2_get_tx_ls(struct dma_desc *p)
        return (le32_to_cpu(p->des3) & XGMAC_RDES3_LD) > 0;
 }
 
+static u16 dwxgmac2_wrback_get_rx_vlan_tci(struct dma_desc *p)
+{
+       return le32_to_cpu(p->des0) & XGMAC_RDES0_VLAN_TAG_MASK;
+}
+
+static bool dwxgmac2_wrback_get_rx_vlan_valid(struct dma_desc *p)
+{
+       u32 et_lt;
+
+       et_lt = FIELD_GET(XGMAC_RDES3_ET_LT, le32_to_cpu(p->des3));
+
+       return et_lt >= XGMAC_ET_LT_VLAN_STAG &&
+              et_lt <= XGMAC_ET_LT_DVLAN_STAG_CTAG;
+}
+
 static int dwxgmac2_get_rx_frame_len(struct dma_desc *p, int rx_coe)
 {
        return (le32_to_cpu(p->des3) & XGMAC_RDES3_PL);
@@ -351,6 +367,8 @@ const struct stmmac_desc_ops dwxgmac210_desc_ops = {
        .set_tx_owner = dwxgmac2_set_tx_owner,
        .set_rx_owner = dwxgmac2_set_rx_owner,
        .get_tx_ls = dwxgmac2_get_tx_ls,
+       .get_rx_vlan_tci = dwxgmac2_wrback_get_rx_vlan_tci,
+       .get_rx_vlan_valid = dwxgmac2_wrback_get_rx_vlan_valid,
        .get_rx_frame_len = dwxgmac2_get_rx_frame_len,
        .enable_tx_timestamp = dwxgmac2_enable_tx_timestamp,
        .get_tx_timestamp_status = dwxgmac2_get_tx_timestamp_status,
index 28b62bd73e2312cefb4b33cd95051ed37be0af52..a19b6f940bf340eef07580e366a2546dcb2d19ef 100644 (file)
@@ -7653,7 +7653,7 @@ 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 (priv->plat->has_gmac4) {
+       if (priv->plat->has_gmac4 || priv->plat->has_xgmac) {
                ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
                priv->hw->hw_vlan_en = true;
        }
index c66233f2c697a934fcc787ccaf216d7bb9e42967..0b6f6228ae35db3d855d8d386c3806a007a9d176 100644 (file)
@@ -335,6 +335,11 @@ const struct stmmac_vlan_ops dwxlgmac2_vlan_ops = {
 const struct stmmac_vlan_ops dwxgmac210_vlan_ops = {
        .update_vlan_hash = dwxgmac2_update_vlan_hash,
        .enable_vlan = vlan_enable,
+       .add_hw_vlan_rx_fltr = vlan_add_hw_rx_fltr,
+       .del_hw_vlan_rx_fltr = vlan_del_hw_rx_fltr,
+       .restore_hw_vlan_rx_fltr = vlan_restore_hw_rx_fltr,
+       .rx_hw_vlan = vlan_rx_hw,
+       .set_hw_vlan_mode = vlan_set_hw_mode,
 };
 
 u32 stmmac_get_num_vlan(void __iomem *ioaddr)