From 2e93726d0b11cafeb3b600a79cb296d3967c2b97 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 22 Sep 2022 08:43:53 -0700 Subject: [PATCH 5/6] PM: runtime: Add pm_runtime_try_put_sync() and pm_runtime_try_get_sync() In some cases, a caller may wish to synchronously get or put the PM Runtime state of a device but the caller may also be holding a resource that the runtime suspend or runtime resume of the device needs. Obviously this can lead to deadlock. A case in point is the clock framework. While running clk_disable_unused() the clock framework holds the global clock "prepare" lock. The clock framework then goes through and does PM Runtime actions. It should be no surprise to anyone that some devices need to prepare or unprepare clocks are part of their PM Runtime actions. Things generally work OK because of the "recursive" nature of the global clock "prepare" lock, but if we get unlucky and the PM Runtime action is happening in another task then we can end up deadlocking. Let's add a "try" version of the synchronous PM Runtime routines. This version will return -EINPROGRESS rather than waiting. To implement this we'll add a new flag: RPM_TRY. Signed-off-by: Douglas Anderson --- include/linux/pm_runtime.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 7efb10518313..5236695b2fae 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -395,6 +395,19 @@ static inline int pm_runtime_get_sync(struct device *dev) return __pm_runtime_resume(dev, RPM_GET_PUT); } +/** + * pm_runtime_try_get_sync - Like pm_runtime_get_sync() but err if blocking + * @dev: Target device. + * + * This function works just like pm_runtime_get_sync() except that if the + * device in question is currently in the process of suspending or resuming + * that it will return with -EINPROGRESS instead of blocking. + */ +static inline int pm_runtime_try_get_sync(struct device *dev) +{ + return __pm_runtime_resume(dev, RPM_GET_PUT | RPM_NOWAIT); +} + /** * pm_runtime_resume_and_get - Bump up usage counter of a device and resume it. * @dev: Target device. @@ -459,6 +472,19 @@ static inline int pm_runtime_put_sync(struct device *dev) return __pm_runtime_idle(dev, RPM_GET_PUT); } +/** + * pm_runtime_try_put_sync - Like pm_runtime_put_sync() but err if blocking + * @dev: Target device. + * + * This function works just like pm_runtime_put_sync() except that if the + * device in question is currently in the process of suspending that it will + * return with -EINPROGRESS instead of blocking. + */ +static inline int pm_runtime_try_put_sync(struct device *dev) +{ + return __pm_runtime_idle(dev, RPM_GET_PUT | RPM_NOWAIT); +} + /** * pm_runtime_put_sync_suspend - Drop device usage counter and suspend if 0. * @dev: Target device. -- 2.44.0.rc1.240.g4c46232300-goog