| From 762479cd26f46045ae75ad7b30f5076b17f7ffe8 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 13 Dec 2023 19:31:10 +0530 |
| Subject: watchdog: rti_wdt: Drop runtime pm reference count when watchdog is |
| unused |
| |
| From: Vignesh Raghavendra <vigneshr@ti.com> |
| |
| [ Upstream commit c1a6edf3b541e44e78f10bc6024df779715723f1 ] |
| |
| 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 <vigneshr@ti.com> |
| Tested-by: Manorit Chawdhry <m-chawdhry@ti.com> |
| Reviewed-by: Guenter Roeck <linux@roeck-us.net> |
| Link: https://lore.kernel.org/r/20231213140110.938129-1-vigneshr@ti.com |
| Signed-off-by: Guenter Roeck <linux@roeck-us.net> |
| Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| 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 6e9253761fc1..ea617c0f9747 100644 |
| --- a/drivers/watchdog/rti_wdt.c |
| +++ b/drivers/watchdog/rti_wdt.c |
| @@ -70,6 +70,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; |
| @@ -295,6 +300,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: |
| @@ -309,7 +317,10 @@ static int 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); |
| |
| return 0; |
| -- |
| 2.43.0 |
| |