Skip to content

Commit 4f04c74

Browse files
committed
PM: sleep: Add strict_midlayer flag to struct dev_pm_info
JIRA: https://issues.redhat.com/browse/RHEL-109251 Conflicts: include/linux/pm.h - minor context differences commit ffda4ca Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Date: Thu, 03 Jul 2025 17:10:40 +0000 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 Signed-off-by: Mark Langsdorf <mlangsdo@redhat.com>
1 parent 6f52c5b commit 4f04c74

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

drivers/base/power/runtime.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,6 +1958,23 @@ void pm_runtime_drop_link(struct device_link *link)
19581958
pm_request_idle(link->supplier);
19591959
}
19601960

1961+
static pm_callback_t get_callback(struct device *dev, size_t cb_offset)
1962+
{
1963+
/*
1964+
* Setting power.strict_midlayer means that the middle layer
1965+
* code does not want its runtime PM callbacks to be invoked via
1966+
* pm_runtime_force_suspend() and pm_runtime_force_resume(), so
1967+
* return a direct pointer to the driver callback in that case.
1968+
*/
1969+
if (dev_pm_strict_midlayer_is_set(dev))
1970+
return __rpm_get_driver_callback(dev, cb_offset);
1971+
1972+
return __rpm_get_callback(dev, cb_offset);
1973+
}
1974+
1975+
#define GET_CALLBACK(dev, callback) \
1976+
get_callback(dev, offsetof(struct dev_pm_ops, callback))
1977+
19611978
/**
19621979
* pm_runtime_force_suspend - Force a device into suspend state if needed.
19631980
* @dev: Device to suspend.
@@ -1984,7 +2001,7 @@ int pm_runtime_force_suspend(struct device *dev)
19842001
if (pm_runtime_status_suspended(dev) || dev->power.needs_force_resume)
19852002
return 0;
19862003

1987-
callback = RPM_GET_CALLBACK(dev, runtime_suspend);
2004+
callback = GET_CALLBACK(dev, runtime_suspend);
19882005

19892006
dev_pm_enable_wake_irq_check(dev, true);
19902007
ret = callback ? callback(dev) : 0;
@@ -2046,7 +2063,7 @@ int pm_runtime_force_resume(struct device *dev)
20462063
pm_runtime_status_suspended(dev)))
20472064
goto out;
20482065

2049-
callback = RPM_GET_CALLBACK(dev, runtime_resume);
2066+
callback = GET_CALLBACK(dev, runtime_resume);
20502067

20512068
dev_pm_disable_wake_irq_check(dev, false);
20522069
ret = callback ? callback(dev) : 0;

include/linux/device.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,33 @@ static inline bool dev_pm_smart_suspend(struct device *dev)
772772
#endif
773773
}
774774

775+
/*
776+
* dev_pm_set_strict_midlayer - Update the device's power.strict_midlayer flag
777+
* @dev: Target device.
778+
* @val: New flag value.
779+
*
780+
* When set, power.strict_midlayer means that the middle layer power management
781+
* code (typically, a bus type or a PM domain) does not expect its runtime PM
782+
* suspend callback to be invoked at all during system-wide PM transitions and
783+
* it does not expect its runtime PM resume callback to be invoked at any point
784+
* when runtime PM is disabled for the device during system-wide PM transitions.
785+
*/
786+
static inline void dev_pm_set_strict_midlayer(struct device *dev, bool val)
787+
{
788+
#ifdef CONFIG_PM_SLEEP
789+
dev->power.strict_midlayer = val;
790+
#endif
791+
}
792+
793+
static inline bool dev_pm_strict_midlayer_is_set(struct device *dev)
794+
{
795+
#ifdef CONFIG_PM_SLEEP
796+
return dev->power.strict_midlayer;
797+
#else
798+
return false;
799+
#endif
800+
}
801+
775802
static inline void device_lock(struct device *dev)
776803
{
777804
mutex_lock(&dev->mutex);

include/linux/pm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,7 @@ struct dev_pm_info {
669669
bool smart_suspend:1; /* Owned by the PM core */
670670
unsigned int must_resume:1; /* Owned by the PM core */
671671
unsigned int may_skip_resume:1; /* Set by subsystems */
672+
bool strict_midlayer:1;
672673
#else
673674
unsigned int should_wakeup:1;
674675
#endif

0 commit comments

Comments
 (0)