]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
PM: runtime: Fix unpaired parent child_count for force_resume
authorTony Lindgren <tony@atomide.com>
Wed, 5 May 2021 11:09:15 +0000 (14:09 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 May 2021 08:29:26 +0000 (10:29 +0200)
commit c745253e2a691a40c66790defe85c104a887e14a upstream.

As pm_runtime_need_not_resume() relies also on usage_count, it can return
a different value in pm_runtime_force_suspend() compared to when called in
pm_runtime_force_resume(). Different return values can happen if anything
calls PM runtime functions in between, and causes the parent child_count
to increase on every resume.

So far I've seen the issue only for omapdrm that does complicated things
with PM runtime calls during system suspend for legacy reasons:

omap_atomic_commit_tail() for omapdrm.0
 dispc_runtime_get()
  wakes up 58000000.dss as it's the dispc parent
   dispc_runtime_resume()
    rpm_resume() increases parent child_count
 dispc_runtime_put() won't idle, PM runtime suspend blocked
pm_runtime_force_suspend() for 58000000.dss, !pm_runtime_need_not_resume()
 __update_runtime_status()
system suspended
pm_runtime_force_resume() for 58000000.dss, pm_runtime_need_not_resume()
 pm_runtime_enable() only called because of pm_runtime_need_not_resume()
omap_atomic_commit_tail() for omapdrm.0
 dispc_runtime_get()
  wakes up 58000000.dss as it's the dispc parent
   dispc_runtime_resume()
    rpm_resume() increases parent child_count
 dispc_runtime_put() won't idle, PM runtime suspend blocked
...
rpm_suspend for 58000000.dss but parent child_count is now unbalanced

Let's fix the issue by adding a flag for needs_force_resume and use it in
pm_runtime_force_resume() instead of pm_runtime_need_not_resume().

Additionally omapdrm system suspend could be simplified later on to avoid
lots of unnecessary PM runtime calls and the complexity it adds. The
driver can just use internal functions that are shared between the PM
runtime and system suspend related functions.

Fixes: 4918e1f87c5f ("PM / runtime: Rework pm_runtime_force_suspend/resume()")
Signed-off-by: Tony Lindgren <tony@atomide.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Tested-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Cc: 4.16+ <stable@vger.kernel.org> # 4.16+
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/base/power/runtime.c
include/linux/pm.h

index d6d73ff94e88f96be2c6af6cffb47ecaa175bd1f..bc649da4899a0b873884226c40af571c6cfed8a2 100644 (file)
@@ -1637,6 +1637,7 @@ void pm_runtime_init(struct device *dev)
        dev->power.request_pending = false;
        dev->power.request = RPM_REQ_NONE;
        dev->power.deferred_resume = false;
+       dev->power.needs_force_resume = 0;
        INIT_WORK(&dev->power.work, pm_runtime_work);
 
        dev->power.timer_expires = 0;
@@ -1804,10 +1805,12 @@ int pm_runtime_force_suspend(struct device *dev)
         * its parent, but set its status to RPM_SUSPENDED anyway in case this
         * function will be called again for it in the meantime.
         */
-       if (pm_runtime_need_not_resume(dev))
+       if (pm_runtime_need_not_resume(dev)) {
                pm_runtime_set_suspended(dev);
-       else
+       } else {
                __update_runtime_status(dev, RPM_SUSPENDED);
+               dev->power.needs_force_resume = 1;
+       }
 
        return 0;
 
@@ -1834,7 +1837,7 @@ int pm_runtime_force_resume(struct device *dev)
        int (*callback)(struct device *);
        int ret = 0;
 
-       if (!pm_runtime_status_suspended(dev) || pm_runtime_need_not_resume(dev))
+       if (!pm_runtime_status_suspended(dev) || !dev->power.needs_force_resume)
                goto out;
 
        /*
@@ -1853,6 +1856,7 @@ int pm_runtime_force_resume(struct device *dev)
 
        pm_runtime_mark_last_busy(dev);
 out:
+       dev->power.needs_force_resume = 0;
        pm_runtime_enable(dev);
        return ret;
 }
index 47aca6bac1d6a285bda9724b4f5d9e1d071d0f7c..52d9724db9dc61c9183279cff0adf51d1b6f7de2 100644 (file)
@@ -600,6 +600,7 @@ struct dev_pm_info {
        unsigned int            idle_notification:1;
        unsigned int            request_pending:1;
        unsigned int            deferred_resume:1;
+       unsigned int            needs_force_resume:1;
        unsigned int            runtime_auto:1;
        bool                    ignore_children:1;
        unsigned int            no_callbacks:1;