Netdev List
 help / color / mirror / Atom feed
* [RFC net-next] net: phy: realtek: track clock state across suspend and resume
@ 2026-11-12 19:24 Artemii Mashanov
  2026-11-12 19:28 ` netdev-bot+sinfo
  0 siblings, 1 reply; 2+ messages in thread
From: Artemii Mashanov @ 2026-11-12 19:24 UTC (permalink / raw)
  To: netdev; +Cc: kmehltretter, andrew, hkallweit1, linux, Artemii Mashanov

The RTL821x PHY driver obtains an enabled clock during probe and
disables it during suspend. However, phylib may invoke resume
without a preceding suspend, causing an unbalanced clock enable.

The current resume path also ignores clk_prepare_enable() errors
and fails to balance clock enables when subsequent operations fail.

Track clock state explicitly, use a managed cleanup action, and
avoid redundant clock enables. Propagate clock enable failures
and undo enables acquired during unsuccessful resume attempts.

The change was compiled for x86_64 and checked with Smatch and
checkpatch.pl

Signed-off-by: Artemii Mashanov <ralerrdirsardx@gmail.com>
---
 drivers/net/phy/realtek/realtek_main.c | 55 ++++++++++++++++++++++----
 1 file changed, 48 insertions(+), 7 deletions(-)

diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c
index 4927ee838..4adcdbe16 100644
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -351,6 +351,7 @@ struct rtl821x_priv {
 	bool enable_rxc_ssc;
 	bool enable_sysclk_ssc;
 	struct clk *clk;
+	bool clk_enabled;
 	/* rtl8211f */
 	u16 iner;
 };
@@ -732,20 +733,41 @@ static int rtl8261x_config_init(struct phy_device *phydev)
 	return 0;
 }
 
+static void rtl821x_clk_disable(void *data)
+{
+	struct rtl821x_priv *priv = data;
+
+	if (!priv->clk_enabled)
+		return;
+
+	clk_disable_unprepare(priv->clk);
+	priv->clk_enabled = false;
+}
+
 static int rtl821x_probe(struct phy_device *phydev)
 {
 	struct device *dev = &phydev->mdio.dev;
 	struct rtl821x_priv *priv;
+	int ret;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
-	priv->clk = devm_clk_get_optional_enabled(dev, NULL);
+	priv->clk = devm_clk_get_optional(dev, NULL);
 	if (IS_ERR(priv->clk))
 		return dev_err_probe(dev, PTR_ERR(priv->clk),
 				     "failed to get phy clock\n");
 
+	ret = clk_prepare_enable(priv->clk);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to enable phy clock\n");
+
+	priv->clk_enabled = true;
+	ret = devm_add_action_or_reset(dev, rtl821x_clk_disable, priv);
+	if (ret)
+		return ret;
+
 	priv->enable_aldps = of_property_read_bool(dev->of_node,
 						   "realtek,aldps-enable");
 	priv->disable_clk_out = of_property_read_bool(dev->of_node,
@@ -1333,7 +1355,7 @@ static int rtl821x_suspend(struct phy_device *phydev)
 		if (ret)
 			return ret;
 
-		clk_disable_unprepare(priv->clk);
+		rtl821x_clk_disable(priv);
 	}
 
 	return ret;
@@ -1388,23 +1410,39 @@ static int rtl8211f_suspend(struct phy_device *phydev)
 static int rtl821x_resume(struct phy_device *phydev)
 {
 	struct rtl821x_priv *priv = phydev->priv;
+	bool clk_reenabled = false;
 	int ret;
 
-	if (!phydev->wol_enabled)
-		clk_prepare_enable(priv->clk);
+	if (!priv->clk_enabled) {
+		ret = clk_prepare_enable(priv->clk);
+		if (ret)
+			return ret;
+		priv->clk_enabled = true;
+		clk_reenabled = true;
+	}
 
 	ret = genphy_resume(phydev);
 	if (ret < 0)
-		return ret;
+		goto err_disable_clk;
 
 	msleep(20);
 
-	return rtl8211f_config_rgmii_delay(phydev);
+	ret = rtl8211f_config_rgmii_delay(phydev);
+	if (ret < 0)
+		goto err_disable_clk;
+
+	return 0;
+
+err_disable_clk:
+	if (clk_reenabled)
+		rtl821x_clk_disable(priv);
+	return ret;
 }
 
 static int rtl8211f_resume(struct phy_device *phydev)
 {
 	struct rtl821x_priv *priv = phydev->priv;
+	bool clk_was_enabled = priv->clk_enabled;
 	int ret;
 
 	ret = rtl821x_resume(phydev);
@@ -1414,8 +1452,11 @@ static int rtl8211f_resume(struct phy_device *phydev)
 	/* If the device was programmed for a PME event, restore the interrupt
 	 * enable so phylib can receive link state interrupts.
 	 */
-	if (device_may_wakeup(&phydev->mdio.dev))
+	if (device_may_wakeup(&phydev->mdio.dev)) {
 		ret = phy_write_paged(phydev, 0xa42, RTL821x_INER, priv->iner);
+		if (ret < 0 && !clk_was_enabled)
+			rtl821x_clk_disable(priv);
+	}
 
 	return ret;
 }
-- 
2.56.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-11-12 19:28 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-12 19:24 [RFC net-next] net: phy: realtek: track clock state across suspend and resume Artemii Mashanov
2026-11-12 19:28 ` netdev-bot+sinfo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox