]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
PM: sleep: Add strict_midlayer flag to struct dev_pm_info
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Fri, 27 Jun 2025 19:23:42 +0000 (21:23 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 3 Jul 2025 15:10:40 +0000 (17:10 +0200)
Add a new flag, called strict_midlayer, to struct dev_pm_info, along
with helper functions for updating and reading 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@intel.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Link: https://patch.msgid.link/24017035.6Emhk5qWAg@rjwysocki.net
drivers/base/power/runtime.c
include/linux/device.h
include/linux/pm.h

index 8cd1a4db5e8465b1cd992fdcab3ba4fafcae010e..05ff3d2209e6ddaaf62260614d0e8c332a8bae13 100644 (file)
@@ -1958,6 +1958,23 @@ void pm_runtime_drop_link(struct device_link *link)
        pm_request_idle(link->supplier);
 }
 
+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_pm_strict_midlayer_is_set(dev))
+               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.
@@ -1984,7 +2001,7 @@ int pm_runtime_force_suspend(struct device *dev)
        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;
@@ -2046,7 +2063,7 @@ int pm_runtime_force_resume(struct device *dev)
            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;
index 4940db137fffff4ceacf819b32433a0f4898b125..5137f9d213ec54d441985a39573a799f3c6e5b19 100644 (file)
@@ -879,6 +879,33 @@ static inline bool dev_pm_smart_suspend(struct device *dev)
 #endif
 }
 
+/*
+ * dev_pm_set_strict_midlayer - Update the device's power.strict_midlayer flag
+ * @dev: Target device.
+ * @val: New flag value.
+ *
+ * When set, power.strict_midlayer means that the middle layer power management
+ * code (typically, a bus type or a PM domain) does not expect its runtime PM
+ * suspend callback to be invoked at all during system-wide PM transitions and
+ * it does not expect its runtime PM resume callback to be invoked at any point
+ * when runtime PM is disabled for the device during system-wide PM transitions.
+ */
+static inline void dev_pm_set_strict_midlayer(struct device *dev, bool val)
+{
+#ifdef CONFIG_PM_SLEEP
+       dev->power.strict_midlayer = val;
+#endif
+}
+
+static inline bool dev_pm_strict_midlayer_is_set(struct device *dev)
+{
+#ifdef CONFIG_PM_SLEEP
+       return dev->power.strict_midlayer;
+#else
+       return false;
+#endif
+}
+
 static inline void device_lock(struct device *dev)
 {
        mutex_lock(&dev->mutex);
index f0bd8fbae4f2c09c63d780bb2528693acf2d2da1..4149d45f6f76221efbdca0582408efddf4eb85a0 100644 (file)
@@ -683,6 +683,7 @@ struct dev_pm_info {
        bool                    smart_suspend:1;        /* Owned by the PM core */
        bool                    must_resume:1;          /* Owned by the PM core */
        bool                    may_skip_resume:1;      /* Set by subsystems */
+       bool                    strict_midlayer:1;
 #else
        bool                    should_wakeup:1;
 #endif