[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <2511990.jE0xQCEvom@rjwysocki.net>
Date: Tue, 11 Feb 2025 22:25:29 +0100
From: "Rafael J. Wysocki" <rjw@...ysocki.net>
To: Linux PM <linux-pm@...r.kernel.org>
Cc: LKML <linux-kernel@...r.kernel.org>,
Alan Stern <stern@...land.harvard.edu>, Ulf Hansson <ulf.hansson@...aro.org>,
Johan Hovold <johan@...nel.org>,
Manivannan Sadhasivam <manivannan.sadhasivam@...aro.org>,
Jon Hunter <jonathanh@...dia.com>
Subject: [PATCH v1 10/10] PM: runtime: Discover the lack of runtime PM support
From: Rafael J. Wysocki <rafael.j.wysocki@...el.com>
Previous changes have updated the PM core to special-case devices that
have never had runtime PM enabled in some places, but what if a device
had had runtime PM enabled at one point, but then it was permanently
disabled? Arguably, there is not much of a difference between such
devices and the devices that have never had runtime PM enabled as far
as system-wide suspend and resume is concerned, so they should be
handled in the same way.
For this reason, add a mechanism for discovering "lost" runtime PM
support in devices with the help of the power.last_status field used
for saving the last runtime PM status of the device known at the time
when runtime PM was disabled for it.
That field is set to RPM_INVALID initially and whenever runtime PM is
enabled for a device (that is, when its power.disable_depth counter
drops down to zero) and it is set to the current runtime PM status of
the device when runtime PM is disabled (that is, the power.disable_depth
counter becomes nonzero). Therefore, if power.last_status is equal to
RPM_INVALID for a device with runtime PM disabled, it means that
runtime PM has never been enabled for that device.
The PM core will now change the power.last_status value to RPM_UNKNOWN
for devices having runtime PM disabled and power.last_status different
from RPM_INVALID during the "prepare" phase of system suspend. Then,
__pm_runtime_disable() called subsequently on the device will set
power.last_status to RPM_INVALID unless it changes from RPM_UNKNOWN
to some other value in the meantime which requires enabling runtime PM
for the device. When power.last_status becomes RPM_INVALID and runtime
PM is still disabled, the device will be handled as a "no runtime PM
support" one from that point on until runtime PM is enabled for it
again.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@...el.com>
---
drivers/base/power/main.c | 6 ++++++
drivers/base/power/runtime.c | 25 +++++++++++++++++++++++++
include/linux/pm.h | 1 +
include/linux/pm_runtime.h | 2 ++
4 files changed, 34 insertions(+)
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1817,6 +1817,12 @@
* it again during the complete phase.
*/
pm_runtime_get_noresume(dev);
+ /*
+ * Devices that have had runtime PM disabled recently may need to be
+ * handled as though they have never supported it, so arrange for
+ * detecting that situation.
+ */
+ pm_runtime_kick_last_status(dev);
if (dev->power.syscore)
return 0;
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1480,6 +1480,9 @@
if (dev->power.disable_depth > 0) {
dev->power.disable_depth++;
+ if (dev->power.last_status == RPM_UNKNOWN)
+ dev->power.last_status = RPM_INVALID;
+
goto out;
}
@@ -1568,6 +1571,28 @@
EXPORT_SYMBOL_GPL(devm_pm_runtime_enable);
/**
+ * pm_runtime_kick_last_status - Start runtime PM support verification.
+ * @dev: Target device.
+ *
+ * If runtime PM is currently disabled for @dev, but it has been enabled at one
+ * point, change power.last_status for it to RPM_UNKNOWN, and if it is still
+ * RPM_UNKNOWN when __pm_runtime_disabled() is called for @dev next time, it
+ * will be changed to RPM_INVALID indicating no runtime PM support going
+ * forward until pm_runtime_enable() is called for @dev.
+ *
+ * This function is used by the PM core.
+ */
+void pm_runtime_kick_last_status(struct device *dev)
+{
+ spin_lock_irq(&dev->power.lock);
+
+ if (dev->power.disable_depth && dev->power.last_status != RPM_INVALID)
+ dev->power.last_status = RPM_UNKNOWN;
+
+ spin_unlock_irq(&dev->power.lock);
+}
+
+/**
* pm_runtime_forbid - Block runtime PM of a device.
* @dev: Device to handle.
*
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -597,6 +597,7 @@
RPM_RESUMING,
RPM_SUSPENDED,
RPM_SUSPENDING,
+ RPM_UNKNOWN,
};
/*
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -80,6 +80,7 @@
extern int pm_runtime_barrier(struct device *dev);
extern void pm_runtime_enable(struct device *dev);
extern void __pm_runtime_disable(struct device *dev, bool check_resume);
+extern void pm_runtime_kick_last_status(struct device *dev);
extern void pm_runtime_allow(struct device *dev);
extern void pm_runtime_forbid(struct device *dev);
extern void pm_runtime_no_callbacks(struct device *dev);
@@ -288,6 +289,7 @@
static inline int pm_runtime_barrier(struct device *dev) { return 0; }
static inline void pm_runtime_enable(struct device *dev) {}
static inline void __pm_runtime_disable(struct device *dev, bool c) {}
+static inline void pm_runtime_kick_last_status(struct device *dev) {}
static inline void pm_runtime_allow(struct device *dev) {}
static inline void pm_runtime_forbid(struct device *dev) {}
Powered by blists - more mailing lists