From: Yan Wang Date: Wed, 19 Apr 2023 14:13:46 +0000 (+0800) Subject: net: stmmac:fix system hang when setting up tag_8021q VLAN for DSA ports X-Git-Tag: v6.1.37~1647 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ad5b2cf5d1356ace5c8c213034839fa0d80f9d99;p=platform%2Fkernel%2Flinux-starfive.git net: stmmac:fix system hang when setting up tag_8021q VLAN for DSA ports [ Upstream commit 35226750f7ab9d49140d95bc7d38a2a9b0f4fdfc ] 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 Signed-off-by: Yan Wang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin --- diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index fa3ce3b..4903157 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -6346,6 +6346,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; @@ -6353,16 +6357,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)