summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoia Prant <coiaprant@gmail.com>2026-10-23 15:52:12 +0800
committerJakub Kicinski <kuba@kernel.org>2026-10-28 17:29:38 -0700
commit49d8bbc21244f0c2d2ebf5ee03fb7352ff019ecc (patch)
treeb61b110f9ff9d15e5a7ef1e45d8244d5147cc5a3
parent8146be04908d3efbe3c6e130f551edbfd7a9dab8 (diff)
net: pcs: xpcs-plat: fix runtime PM initialization
The driver calls pm_runtime_set_active() before runtime PM is enabled and before the CSR clock is prepared and enabled. If the device is later suspended (e.g. during unbind), the runtime suspend callback tries to disable a clock that was never enabled, producing: clk_csr already disabled clk_csr already unprepared Set the initial runtime PM status to suspended instead, and register a devm action that force-suspends the device on teardown. Without that action the CSR clock would stay enabled if the driver is removed while runtime-active, since nothing triggers a runtime suspend on unbind. pm_runtime_force_suspend() is not checked because the runtime suspend callback cannot fail. The clock is enabled on the first runtime resume (e.g. during MDIO access). No upstream platform currently enables this driver with a real CSR clock dependency, so the issue is not reachable in mainline today. It was found while using this driver as a reference for the Rockchip XPCS glue driver. Signed-off-by: Coia Prant <coiaprant@gmail.com> Link: https://patch.msgid.link/20261023075214.1793922-3-coiaprant@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--drivers/net/pcs/pcs-xpcs-plat.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/drivers/net/pcs/pcs-xpcs-plat.c b/drivers/net/pcs/pcs-xpcs-plat.c
index e669a7b248ac..11c4239bfd74 100644
--- a/drivers/net/pcs/pcs-xpcs-plat.c
+++ b/drivers/net/pcs/pcs-xpcs-plat.c
@@ -275,6 +275,14 @@ static int xpcs_plat_init_res(struct dw_xpcs_plat *pxpcs)
return 0;
}
+static void xpcs_plat_exit_clk(void *data)
+{
+ struct dw_xpcs_plat *pxpcs = data;
+ struct device *dev = &pxpcs->pdev->dev;
+
+ pm_runtime_force_suspend(dev);
+}
+
static int xpcs_plat_init_clk(struct dw_xpcs_plat *pxpcs)
{
struct device *dev = &pxpcs->pdev->dev;
@@ -285,10 +293,12 @@ static int xpcs_plat_init_clk(struct dw_xpcs_plat *pxpcs)
return dev_err_probe(dev, PTR_ERR(pxpcs->cclk),
"Failed to get CSR clock\n");
- pm_runtime_set_active(dev);
- ret = devm_pm_runtime_enable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_enable(dev);
+
+ ret = devm_add_action_or_reset(dev, xpcs_plat_exit_clk, pxpcs);
if (ret) {
- dev_err(dev, "Failed to enable runtime-PM\n");
+ dev_err(dev, "Failed to register devm for xpcs_plat_exit_clk: %d\n", ret);
return ret;
}