2023-12-13 14:02:16

by Vignesh Raghavendra

[permalink] [raw]
Subject: [PATCH v3] watchdog: rti_wdt: Drop runtime pm reference count when watchdog is unused

Call runtime_pm_put*() if watchdog is not already started during probe and re
enable it in watchdog start as required.

On K3 SoCs, watchdogs and their corresponding CPUs are under same
power-domain, so if the reference count of unused watchdogs aren't
dropped, it will lead to CPU hotplug failures as Device Management
firmware won't allow to turn off the power-domain due to dangling
reference count.

Fixes: 2d63908bdbfb ("watchdog: Add K3 RTI watchdog support")
Signed-off-by: Vignesh Raghavendra <[email protected]>
Reviewed-by: Guenter Roeck <[email protected]>
Tested-by: Manorit Chawdhry <[email protected]>
---
v3:
Reword commit message to expand non std acronyms
Collect Reviewed-by and Tested-by tags
No code change

v2: https://lore.kernel.org/r/[email protected]

v2:
* Drop 1/2 (will be posted along with runtime_pm callbacks)
* Use pm_runtime_resume_and_get() instead of pm_runtime_get_sync() which
takes care of err handling

v1: https://lore.kernel.org/r/[email protected]

drivers/watchdog/rti_wdt.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c
index 8e1be7ba0103..9215793a1c81 100644
--- a/drivers/watchdog/rti_wdt.c
+++ b/drivers/watchdog/rti_wdt.c
@@ -77,6 +77,11 @@ static int rti_wdt_start(struct watchdog_device *wdd)
{
u32 timer_margin;
struct rti_wdt_device *wdt = watchdog_get_drvdata(wdd);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(wdd->parent);
+ if (ret)
+ return ret;

/* set timeout period */
timer_margin = (u64)wdd->timeout * wdt->freq;
@@ -343,6 +348,9 @@ static int rti_wdt_probe(struct platform_device *pdev)
if (last_ping)
watchdog_set_last_hw_keepalive(wdd, last_ping);

+ if (!watchdog_hw_running(wdd))
+ pm_runtime_put_sync(&pdev->dev);
+
return 0;

err_iomap:
@@ -357,7 +365,10 @@ static void rti_wdt_remove(struct platform_device *pdev)
struct rti_wdt_device *wdt = platform_get_drvdata(pdev);

watchdog_unregister_device(&wdt->wdd);
- pm_runtime_put(&pdev->dev);
+
+ if (!pm_runtime_suspended(&pdev->dev))
+ pm_runtime_put(&pdev->dev);
+
pm_runtime_disable(&pdev->dev);
}

--
2.43.0