[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1990775.taCxCBeP46@rjwysocki.net>
Date: Wed, 25 Jun 2025 21:24:17 +0200
From: "Rafael J. Wysocki" <rjw@...ysocki.net>
To: Linux PM <linux-pm@...r.kernel.org>
Cc: LKML <linux-kernel@...r.kernel.org>,
Linux ACPI <linux-acpi@...r.kernel.org>,
Linux PCI <linux-pci@...r.kernel.org>, Ulf Hansson <ulf.hansson@...aro.org>,
Mika Westerberg <mika.westerberg@...ux.intel.com>
Subject:
[PATCH v1 7/9] PM: sleep: Add strict_midlayer flag to struct dev_pm_info
From: Rafael J. Wysocki <rafael.j.wysocki@...el.com>
Add a new flag, called strict_midlayer, to struct dev_pm_info, along
with a helper function for changing its value, to allow middle layer
code that provides proper callbacks for device suspend/resume during
system-wide PM transitions to let pm_runtime_force_suspend() and
and pm_runtime_force_resume() know that they should only invoke runtime
PM callbacks coming from the device's driver.
Namely, if this flag is set, pm_runtime_force_suspend() and
and pm_runtime_force_resume() will invoke runtime PM callbacks
provided by the device's driver directly with the assumption that
they have been called via a middle layer callback for device suspend
or resume, respectively.
For instance, acpi_general_pm_domain provides specific
callback functions for system suspend, acpi_subsys_suspend(),
acpi_subsys_suspend_late() and acpi_subsys_suspend_noirq(), and
it does not expect its runtime suspend callback function,
acpi_subsys_runtime_suspend(), to be invoked at any point during
system suspend. In particular, it does not expect that function
to be called from within any of the system suspend callback functions
mentioned above which would happen if a device driver collaborating
with acpi_general_pm_domain used pm_runtime_force_suspend() as its
callback function for any system suspend phase later than "prepare".
The new flag allows this expectation of acpi_general_pm_domain to
be formally expressed, which is going to be done subsequently.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@...el.com>
---
drivers/base/power/runtime.c | 21 +++++++++++++++++++--
include/linux/device.h | 7 +++++++
include/linux/pm.h | 1 +
3 files changed, 27 insertions(+), 2 deletions(-)
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -1962,6 +1962,23 @@
dev->power.ignore_children);
}
+static pm_callback_t get_callback(struct device *dev, size_t cb_offset)
+{
+ /*
+ * Setting power.strict_midlayer means that the middle layer
+ * code does not want its runtime PM callbacks to be invoked via
+ * pm_runtime_force_suspend() and pm_runtime_force_resume(), so
+ * return a direct pointer to the driver callback in that case.
+ */
+ if (dev->power.strict_midlayer)
+ return __rpm_get_driver_callback(dev, cb_offset);
+
+ return __rpm_get_callback(dev, cb_offset);
+}
+
+#define GET_CALLBACK(dev, callback) \
+ get_callback(dev, offsetof(struct dev_pm_ops, callback))
+
/**
* pm_runtime_force_suspend - Force a device into suspend state if needed.
* @dev: Device to suspend.
@@ -1988,7 +2005,7 @@
if (pm_runtime_status_suspended(dev) || dev->power.needs_force_resume)
return 0;
- callback = RPM_GET_CALLBACK(dev, runtime_suspend);
+ callback = GET_CALLBACK(dev, runtime_suspend);
dev_pm_enable_wake_irq_check(dev, true);
ret = callback ? callback(dev) : 0;
@@ -2048,7 +2065,7 @@
pm_runtime_status_suspended(dev)))
goto out;
- callback = RPM_GET_CALLBACK(dev, runtime_resume);
+ callback = GET_CALLBACK(dev, runtime_resume);
dev_pm_disable_wake_irq_check(dev, false);
ret = callback ? callback(dev) : 0;
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -879,6 +879,13 @@
#endif
}
+static inline void dev_pm_strict_midlayer(struct device *dev, bool val)
+{
+#ifdef CONFIG_PM_SLEEP
+ dev->power.strict_midlayer = val;
+#endif
+}
+
static inline void device_lock(struct device *dev)
{
mutex_lock(&dev->mutex);
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -684,6 +684,7 @@
bool must_resume:1; /* Owned by the PM core */
bool may_skip_resume:1; /* Set by subsystems */
bool needs_force_resume:1;
+ bool strict_midlayer:1;
#else
bool should_wakeup:1;
#endif
Powered by blists - more mailing lists