net: stmmac:fix system hang when setting up tag_8021q VLAN for DSA ports
authorYan Wang <rk.code@outlook.com>
Wed, 19 Apr 2023 14:13:46 +0000 (22:13 +0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 21 Apr 2023 10:44:35 +0000 (11:44 +0100)
The system hang because of dsa_tag_8021q_port_setup()->
stmmac_vlan_rx_add_vid().

I found in stmmac_drv_probe() that cailing pm_runtime_put()
disabled the clock.

First, when the kernel is compiled with CONFIG_PM=y,The stmmac's
resume/suspend is active.

Secondly,stmmac as DSA master,the dsa_tag_8021q_port_setup() function
will callback stmmac_vlan_rx_add_vid when DSA dirver starts. However,
The system is hanged for the stmmac_vlan_rx_add_vid() accesses its
registers after stmmac's clock is closed.

I would suggest adding the pm_runtime_resume_and_get() to the
stmmac_vlan_rx_add_vid().This guarantees that resuming clock output
while in use.

Fixes: b3dcb3127786 ("net: stmmac: correct clocks enabled in stmmac_vlan_rx_kill_vid()")
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Yan Wang <rk.code@outlook.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

index 4753431..f116e4a 100644 (file)
@@ -6377,6 +6377,10 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid
        bool is_double = false;
        int ret;
 
+       ret = pm_runtime_resume_and_get(priv->device);
+       if (ret < 0)
+               return ret;
+
        if (be16_to_cpu(proto) == ETH_P_8021AD)
                is_double = true;
 
@@ -6384,16 +6388,18 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid
        ret = stmmac_vlan_update(priv, is_double);
        if (ret) {
                clear_bit(vid, priv->active_vlans);
-               return ret;
+               goto err_pm_put;
        }
 
        if (priv->hw->num_vlan) {
                ret = stmmac_add_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid);
                if (ret)
-                       return ret;
+                       goto err_pm_put;
        }
+err_pm_put:
+       pm_runtime_put(priv->device);
 
-       return 0;
+       return ret;
 }
 
 static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid)