]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: stmmac: Fix VLAN HW state restore
authorOvidiu Panait <ovidiu.panait.rb@renesas.com>
Tue, 3 Mar 2026 14:58:27 +0000 (14:58 +0000)
committerJakub Kicinski <kuba@kernel.org>
Thu, 5 Mar 2026 02:48:49 +0000 (18:48 -0800)
When the network interface is opened or resumed, a DMA reset is performed,
which resets all hardware state, including VLAN state. Currently, only
the resume path is restoring the VLAN state via
stmmac_restore_hw_vlan_rx_fltr(), but that is incomplete: the VLAN hash
table and the VLAN_TAG control bits are not restored.

Therefore, add stmmac_vlan_restore(), which restores the full VLAN
state by updating both the HW filter entries and the hash table, and
call it from both the open and resume paths.

The VLAN restore is moved outside of phylink_rx_clk_stop_block/unblock
in the resume path because receive clock stop is already disabled when
stmmac supports VLAN.

Also, remove the hash readback code in vlan_restore_hw_rx_fltr() that
attempts to restore VTHM by reading VLAN_HASH_TABLE, as it always reads
zero after DMA reset, making it dead code.

Fixes: 3cd1cfcba26e ("net: stmmac: Implement VLAN Hash Filtering in XGMAC")
Fixes: ed64639bc1e0 ("net: stmmac: Add support for VLAN Rx filtering")
Signed-off-by: Ovidiu Panait <ovidiu.panait.rb@renesas.com>
Link: https://patch.msgid.link/20260303145828.7845-4-ovidiu.panait.rb@renesas.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c

index 01d181c2c68eae688a1c3e057d59d2ccc93271b7..6d4ce35e990f2e0dbcdc3edb5489aa354ae84431 100644 (file)
@@ -156,6 +156,7 @@ static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue);
 static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue);
 static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
                                          u32 rxmode, u32 chan);
+static int stmmac_vlan_restore(struct stmmac_priv *priv);
 
 #ifdef CONFIG_DEBUG_FS
 static const struct net_device_ops stmmac_netdev_ops;
@@ -4107,6 +4108,8 @@ static int __stmmac_open(struct net_device *dev,
 
        phylink_start(priv->phylink);
 
+       stmmac_vlan_restore(priv);
+
        ret = stmmac_request_irq(dev);
        if (ret)
                goto irq_error;
@@ -6853,6 +6856,23 @@ del_vlan_error:
        return ret;
 }
 
+static int stmmac_vlan_restore(struct stmmac_priv *priv)
+{
+       int ret;
+
+       if (!(priv->dev->features & NETIF_F_VLAN_FEATURES))
+               return 0;
+
+       if (priv->hw->num_vlan)
+               stmmac_restore_hw_vlan_rx_fltr(priv, priv->dev, priv->hw);
+
+       ret = stmmac_vlan_update(priv, priv->num_double_vlans);
+       if (ret)
+               netdev_err(priv->dev, "Failed to restore VLANs\n");
+
+       return ret;
+}
+
 static int stmmac_bpf(struct net_device *dev, struct netdev_bpf *bpf)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
@@ -8277,10 +8297,10 @@ int stmmac_resume(struct device *dev)
        stmmac_init_coalesce(priv);
        phylink_rx_clk_stop_block(priv->phylink);
        stmmac_set_rx_mode(ndev);
-
-       stmmac_restore_hw_vlan_rx_fltr(priv, ndev, priv->hw);
        phylink_rx_clk_stop_unblock(priv->phylink);
 
+       stmmac_vlan_restore(priv);
+
        stmmac_enable_all_queues(priv);
        stmmac_enable_all_dma_irq(priv);
 
index de1a70e1c86ef5f9c84a42c91c3c4595967bc616..fcc34867405ed823521048da13351859b6142efd 100644 (file)
@@ -139,9 +139,6 @@ static int vlan_del_hw_rx_fltr(struct net_device *dev,
 static void vlan_restore_hw_rx_fltr(struct net_device *dev,
                                    struct mac_device_info *hw)
 {
-       void __iomem *ioaddr = hw->pcsr;
-       u32 value;
-       u32 hash;
        u32 val;
        int i;
 
@@ -158,13 +155,6 @@ static void vlan_restore_hw_rx_fltr(struct net_device *dev,
                        vlan_write_filter(dev, hw, i, val);
                }
        }
-
-       hash = readl(ioaddr + VLAN_HASH_TABLE);
-       if (hash & VLAN_VLHT) {
-               value = readl(ioaddr + VLAN_TAG);
-               value |= VLAN_VTHM;
-               writel(value, ioaddr + VLAN_TAG);
-       }
 }
 
 static void vlan_update_hash(struct mac_device_info *hw, u32 hash,