Merge branches 'pm-core' and 'pm-runtime'

Merge runtime PM framework updates and a core power management code fix
for 6.18-rc1:

 - Make pm_runtime_put*() family of functions return 1 when the
   given device is already suspended which is consistent with the
   documentation (Brian Norris)

 - Add basic kunit tests for runtime PM API contracts and update return
   values in kerneldoc coments for the runtime PM API (Brian Norris,
   Dan Carpenter)

 - Add auto-cleanup macros for runtime PM "resume and get" and "get
   without resume" operations, use one of them in the PCI core and
   drop the existing "free" macro introduced for similar purpose, but
   somewhat cumbersome to use (Rafael Wysocki)

 - Make the core power management code avoid waiting on device links
   marked as SYNC_STATE_ONLY which is consistent with the handling of
   those device links elsewhere (Pin-yen Lin)

* pm-core:
  PM: sleep: Do not wait on SYNC_STATE_ONLY device links

* pm-runtime:
  PM: runtime: Fix error checking for kunit_device_register()
  PM: runtime: Introduce one more usage counter guard
  PM: runtime: Drop DEFINE_FREE() for pm_runtime_put()
  PCI/sysfs: Use runtime PM guard macro for auto-cleanup
  PM: runtime: Add auto-cleanup macros for "resume and get" operations
  PM: runtime: Update kerneldoc return codes
  PM: runtime: Make put{,_sync}() return 1 when already suspended
  PM: runtime: Add basic kunit tests for API contracts
This commit is contained in:
Rafael J. Wysocki 2025-10-07 12:20:36 +02:00
commit 05f084d24e
9 changed files with 343 additions and 41 deletions

View file

@ -167,6 +167,12 @@ config PM_QOS_KUNIT_TEST
depends on KUNIT=y
default KUNIT_ALL_TESTS
config PM_RUNTIME_KUNIT_TEST
tristate "KUnit Tests for runtime PM" if !KUNIT_ALL_TESTS
depends on KUNIT
depends on PM
default KUNIT_ALL_TESTS
config HMEM_REPORTING
bool
default n

View file

@ -248,6 +248,7 @@ void device_links_driver_cleanup(struct device *dev);
void device_links_no_driver(struct device *dev);
bool device_links_busy(struct device *dev);
void device_links_unbind_consumers(struct device *dev);
bool device_link_flag_is_sync_state_only(u32 flags);
void fw_devlink_drivers_done(void);
void fw_devlink_probing_done(void);

View file

@ -287,7 +287,7 @@ static bool device_is_ancestor(struct device *dev, struct device *target)
#define DL_MARKER_FLAGS (DL_FLAG_INFERRED | \
DL_FLAG_CYCLE | \
DL_FLAG_MANAGED)
static inline bool device_link_flag_is_sync_state_only(u32 flags)
bool device_link_flag_is_sync_state_only(u32 flags)
{
return (flags & ~DL_MARKER_FLAGS) == DL_FLAG_SYNC_STATE_ONLY;
}

View file

@ -4,5 +4,6 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o wakeup_stats.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
obj-$(CONFIG_HAVE_CLK) += clock_ops.o
obj-$(CONFIG_PM_QOS_KUNIT_TEST) += qos-test.o
obj-$(CONFIG_PM_RUNTIME_KUNIT_TEST) += runtime-test.o
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG

View file

@ -278,7 +278,8 @@ static void dpm_wait_for_suppliers(struct device *dev, bool async)
* walking.
*/
dev_for_each_link_to_supplier(link, dev)
if (READ_ONCE(link->status) != DL_STATE_DORMANT)
if (READ_ONCE(link->status) != DL_STATE_DORMANT &&
!device_link_flag_is_sync_state_only(link->flags))
dpm_wait(link->supplier, async);
device_links_read_unlock(idx);
@ -335,7 +336,8 @@ static void dpm_wait_for_consumers(struct device *dev, bool async)
* unregistration).
*/
dev_for_each_link_to_consumer(link, dev)
if (READ_ONCE(link->status) != DL_STATE_DORMANT)
if (READ_ONCE(link->status) != DL_STATE_DORMANT &&
!device_link_flag_is_sync_state_only(link->flags))
dpm_wait(link->consumer, async);
device_links_read_unlock(idx);

View file

@ -0,0 +1,253 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2025 Google, Inc.
*/
#include <linux/cleanup.h>
#include <linux/pm_runtime.h>
#include <kunit/device.h>
#include <kunit/test.h>
#define DEVICE_NAME "pm_runtime_test_device"
static void pm_runtime_depth_test(struct kunit *test)
{
struct device *dev = kunit_device_register(test, DEVICE_NAME);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
pm_runtime_enable(dev);
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev));
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
KUNIT_EXPECT_EQ(test, 1, pm_runtime_get_sync(dev)); /* "already active" */
KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev));
KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev));
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
}
/* Test pm_runtime_put() and friends when already suspended. */
static void pm_runtime_already_suspended_test(struct kunit *test)
{
struct device *dev = kunit_device_register(test, DEVICE_NAME);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
pm_runtime_enable(dev);
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
pm_runtime_get_noresume(dev);
KUNIT_EXPECT_EQ(test, 0, pm_runtime_barrier(dev)); /* no wakeup needed */
pm_runtime_put(dev);
pm_runtime_get_noresume(dev);
KUNIT_EXPECT_EQ(test, 1, pm_runtime_put_sync(dev));
KUNIT_EXPECT_EQ(test, 1, pm_runtime_suspend(dev));
KUNIT_EXPECT_EQ(test, 1, pm_runtime_autosuspend(dev));
KUNIT_EXPECT_EQ(test, 1, pm_request_autosuspend(dev));
pm_runtime_get_noresume(dev);
KUNIT_EXPECT_EQ(test, 1, pm_runtime_put_sync_autosuspend(dev));
pm_runtime_get_noresume(dev);
pm_runtime_put_autosuspend(dev);
/* Grab 2 refcounts */
pm_runtime_get_noresume(dev);
pm_runtime_get_noresume(dev);
/* The first put() sees usage_count 1 */
KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync_autosuspend(dev));
/* The second put() sees usage_count 0 but tells us "already suspended". */
KUNIT_EXPECT_EQ(test, 1, pm_runtime_put_sync_autosuspend(dev));
/* Should have remained suspended the whole time. */
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
}
static void pm_runtime_idle_test(struct kunit *test)
{
struct device *dev = kunit_device_register(test, DEVICE_NAME);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
pm_runtime_enable(dev);
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev));
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_idle(dev));
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
pm_runtime_put_noidle(dev);
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
KUNIT_EXPECT_EQ(test, 0, pm_runtime_idle(dev));
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_idle(dev));
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_request_idle(dev));
}
static void pm_runtime_disabled_test(struct kunit *test)
{
struct device *dev = kunit_device_register(test, DEVICE_NAME);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
/* Never called pm_runtime_enable() */
KUNIT_EXPECT_FALSE(test, pm_runtime_enabled(dev));
/* "disabled" is treated as "active" */
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
KUNIT_EXPECT_FALSE(test, pm_runtime_suspended(dev));
/*
* Note: these "fail", but they still acquire/release refcounts, so
* keep them balanced.
*/
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_get(dev));
pm_runtime_put(dev);
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_get_sync(dev));
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_put_sync(dev));
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_get(dev));
pm_runtime_put_autosuspend(dev);
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_resume_and_get(dev));
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_idle(dev));
KUNIT_EXPECT_EQ(test, -EACCES, pm_request_idle(dev));
KUNIT_EXPECT_EQ(test, -EACCES, pm_request_resume(dev));
KUNIT_EXPECT_EQ(test, -EACCES, pm_request_autosuspend(dev));
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_suspend(dev));
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_resume(dev));
KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_autosuspend(dev));
/* Still disabled */
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
KUNIT_EXPECT_FALSE(test, pm_runtime_enabled(dev));
}
static void pm_runtime_error_test(struct kunit *test)
{
struct device *dev = kunit_device_register(test, DEVICE_NAME);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
pm_runtime_enable(dev);
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
/* Fake a .runtime_resume() error */
dev->power.runtime_error = -EIO;
/*
* Note: these "fail", but they still acquire/release refcounts, so
* keep them balanced.
*/
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get(dev));
pm_runtime_put(dev);
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get_sync(dev));
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_put_sync(dev));
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get(dev));
pm_runtime_put_autosuspend(dev);
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get(dev));
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_put_sync_autosuspend(dev));
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_resume_and_get(dev));
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_idle(dev));
KUNIT_EXPECT_EQ(test, -EINVAL, pm_request_idle(dev));
KUNIT_EXPECT_EQ(test, -EINVAL, pm_request_resume(dev));
KUNIT_EXPECT_EQ(test, -EINVAL, pm_request_autosuspend(dev));
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_suspend(dev));
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_resume(dev));
KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_autosuspend(dev));
/* Error is still pending */
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
KUNIT_EXPECT_EQ(test, -EIO, dev->power.runtime_error);
/* Clear error */
KUNIT_EXPECT_EQ(test, 0, pm_runtime_set_suspended(dev));
KUNIT_EXPECT_EQ(test, 0, dev->power.runtime_error);
/* Still suspended */
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
KUNIT_EXPECT_EQ(test, 0, pm_runtime_get(dev));
KUNIT_EXPECT_EQ(test, 1, pm_runtime_barrier(dev)); /* resume was pending */
pm_runtime_put(dev);
pm_runtime_suspend(dev); /* flush the put(), to suspend */
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev));
KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev));
KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev));
pm_runtime_put_autosuspend(dev);
KUNIT_EXPECT_EQ(test, 0, pm_runtime_resume_and_get(dev));
/*
* The following should all return -EAGAIN (usage is non-zero) or 1
* (already resumed).
*/
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_idle(dev));
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_request_idle(dev));
KUNIT_EXPECT_EQ(test, 1, pm_request_resume(dev));
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_request_autosuspend(dev));
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_suspend(dev));
KUNIT_EXPECT_EQ(test, 1, pm_runtime_resume(dev));
KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_autosuspend(dev));
KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev));
/* Suspended again */
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
}
/*
* Explore a typical probe() sequence in which a device marks itself powered,
* but doesn't hold any runtime PM reference, so it suspends as soon as it goes
* idle.
*/
static void pm_runtime_probe_active_test(struct kunit *test)
{
struct device *dev = kunit_device_register(test, DEVICE_NAME);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
KUNIT_EXPECT_TRUE(test, pm_runtime_status_suspended(dev));
KUNIT_EXPECT_EQ(test, 0, pm_runtime_set_active(dev));
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
pm_runtime_enable(dev);
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
/* Nothing to flush. We stay active. */
KUNIT_EXPECT_EQ(test, 0, pm_runtime_barrier(dev));
KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev));
/* Ask for idle? Now we suspend. */
KUNIT_EXPECT_EQ(test, 0, pm_runtime_idle(dev));
KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev));
}
static struct kunit_case pm_runtime_test_cases[] = {
KUNIT_CASE(pm_runtime_depth_test),
KUNIT_CASE(pm_runtime_already_suspended_test),
KUNIT_CASE(pm_runtime_idle_test),
KUNIT_CASE(pm_runtime_disabled_test),
KUNIT_CASE(pm_runtime_error_test),
KUNIT_CASE(pm_runtime_probe_active_test),
{}
};
static struct kunit_suite pm_runtime_test_suite = {
.name = "pm_runtime_test_cases",
.test_cases = pm_runtime_test_cases,
};
kunit_test_suite(pm_runtime_test_suite);
MODULE_DESCRIPTION("Runtime power management unit test suite");
MODULE_LICENSE("GPL");

View file

@ -498,6 +498,9 @@ static int rpm_idle(struct device *dev, int rpmflags)
if (retval < 0)
; /* Conditions are wrong. */
else if ((rpmflags & RPM_GET_PUT) && retval == 1)
; /* put() is allowed in RPM_SUSPENDED */
/* Idle notifications are allowed only in the RPM_ACTIVE state. */
else if (dev->power.runtime_status != RPM_ACTIVE)
retval = -EAGAIN;
@ -796,6 +799,8 @@ static int rpm_resume(struct device *dev, int rpmflags)
if (dev->power.runtime_status == RPM_ACTIVE &&
dev->power.last_status == RPM_ACTIVE)
retval = 1;
else if (rpmflags & RPM_TRANSPARENT)
goto out;
else
retval = -EACCES;
}

View file

@ -1475,8 +1475,9 @@ static ssize_t reset_method_store(struct device *dev,
return count;
}
pm_runtime_get_sync(dev);
struct device *pmdev __free(pm_runtime_put) = dev;
ACQUIRE(pm_runtime_active_try, pm)(dev);
if (ACQUIRE_ERR(pm_runtime_active_try, &pm))
return -ENXIO;
if (sysfs_streq(buf, "default")) {
pci_init_reset_methods(pdev);

View file

@ -21,6 +21,7 @@
#define RPM_GET_PUT 0x04 /* Increment/decrement the
usage_count */
#define RPM_AUTO 0x08 /* Use autosuspend_delay */
#define RPM_TRANSPARENT 0x10 /* Succeed if runtime PM is disabled */
/*
* Use this for defining a set of PM operations to be used in all situations
@ -350,13 +351,12 @@ static inline int pm_runtime_force_resume(struct device *dev) { return -ENXIO; }
* * 0: Success.
* * -EINVAL: Runtime PM error.
* * -EACCES: Runtime PM disabled.
* * -EAGAIN: Runtime PM usage_count non-zero, Runtime PM status change ongoing
* or device not in %RPM_ACTIVE state.
* * -EAGAIN: Runtime PM usage counter non-zero, Runtime PM status change
* ongoing or device not in %RPM_ACTIVE state.
* * -EBUSY: Runtime PM child_count non-zero.
* * -EPERM: Device PM QoS resume latency 0.
* * -EINPROGRESS: Suspend already in progress.
* * -ENOSYS: CONFIG_PM not enabled.
* * 1: Device already suspended.
* Other values and conditions for the above values are possible as returned by
* Runtime PM idle and suspend callbacks.
*/
@ -370,14 +370,15 @@ static inline int pm_runtime_idle(struct device *dev)
* @dev: Target device.
*
* Return:
* * 1: Success; device was already suspended.
* * 0: Success.
* * -EINVAL: Runtime PM error.
* * -EACCES: Runtime PM disabled.
* * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing.
* * -EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change
* ongoing.
* * -EBUSY: Runtime PM child_count non-zero.
* * -EPERM: Device PM QoS resume latency 0.
* * -ENOSYS: CONFIG_PM not enabled.
* * 1: Device already suspended.
* Other values and conditions for the above values are possible as returned by
* Runtime PM suspend callbacks.
*/
@ -396,14 +397,15 @@ static inline int pm_runtime_suspend(struct device *dev)
* engaging its "idle check" callback.
*
* Return:
* * 1: Success; device was already suspended.
* * 0: Success.
* * -EINVAL: Runtime PM error.
* * -EACCES: Runtime PM disabled.
* * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing.
* * -EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change
* ongoing.
* * -EBUSY: Runtime PM child_count non-zero.
* * -EPERM: Device PM QoS resume latency 0.
* * -ENOSYS: CONFIG_PM not enabled.
* * 1: Device already suspended.
* Other values and conditions for the above values are possible as returned by
* Runtime PM suspend callbacks.
*/
@ -433,13 +435,12 @@ static inline int pm_runtime_resume(struct device *dev)
* * 0: Success.
* * -EINVAL: Runtime PM error.
* * -EACCES: Runtime PM disabled.
* * -EAGAIN: Runtime PM usage_count non-zero, Runtime PM status change ongoing
* or device not in %RPM_ACTIVE state.
* * -EAGAIN: Runtime PM usage counter non-zero, Runtime PM status change
* ongoing or device not in %RPM_ACTIVE state.
* * -EBUSY: Runtime PM child_count non-zero.
* * -EPERM: Device PM QoS resume latency 0.
* * -EINPROGRESS: Suspend already in progress.
* * -ENOSYS: CONFIG_PM not enabled.
* * 1: Device already suspended.
*/
static inline int pm_request_idle(struct device *dev)
{
@ -464,15 +465,16 @@ static inline int pm_request_resume(struct device *dev)
* equivalent pm_runtime_autosuspend() for @dev asynchronously.
*
* Return:
* * 1: Success; device was already suspended.
* * 0: Success.
* * -EINVAL: Runtime PM error.
* * -EACCES: Runtime PM disabled.
* * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing.
* * -EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change
* ongoing.
* * -EBUSY: Runtime PM child_count non-zero.
* * -EPERM: Device PM QoS resume latency 0.
* * -EINPROGRESS: Suspend already in progress.
* * -ENOSYS: CONFIG_PM not enabled.
* * 1: Device already suspended.
*/
static inline int pm_request_autosuspend(struct device *dev)
{
@ -511,6 +513,19 @@ static inline int pm_runtime_get_sync(struct device *dev)
return __pm_runtime_resume(dev, RPM_GET_PUT);
}
static inline int pm_runtime_get_active(struct device *dev, int rpmflags)
{
int ret;
ret = __pm_runtime_resume(dev, RPM_GET_PUT | rpmflags);
if (ret < 0) {
pm_runtime_put_noidle(dev);
return ret;
}
return 0;
}
/**
* pm_runtime_resume_and_get - Bump up usage counter of a device and resume it.
* @dev: Target device.
@ -521,15 +536,7 @@ static inline int pm_runtime_get_sync(struct device *dev)
*/
static inline int pm_runtime_resume_and_get(struct device *dev)
{
int ret;
ret = __pm_runtime_resume(dev, RPM_GET_PUT);
if (ret < 0) {
pm_runtime_put_noidle(dev);
return ret;
}
return 0;
return pm_runtime_get_active(dev, 0);
}
/**
@ -540,23 +547,22 @@ static inline int pm_runtime_resume_and_get(struct device *dev)
* equal to 0, queue up a work item for @dev like in pm_request_idle().
*
* Return:
* * 1: Success. Usage counter dropped to zero, but device was already suspended.
* * 0: Success.
* * -EINVAL: Runtime PM error.
* * -EACCES: Runtime PM disabled.
* * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing.
* * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
* change ongoing.
* * -EBUSY: Runtime PM child_count non-zero.
* * -EPERM: Device PM QoS resume latency 0.
* * -EINPROGRESS: Suspend already in progress.
* * -ENOSYS: CONFIG_PM not enabled.
* * 1: Device already suspended.
*/
static inline int pm_runtime_put(struct device *dev)
{
return __pm_runtime_idle(dev, RPM_GET_PUT | RPM_ASYNC);
}
DEFINE_FREE(pm_runtime_put, struct device *, if (_T) pm_runtime_put(_T))
/**
* __pm_runtime_put_autosuspend - Drop device usage counter and queue autosuspend if 0.
* @dev: Target device.
@ -565,15 +571,16 @@ DEFINE_FREE(pm_runtime_put, struct device *, if (_T) pm_runtime_put(_T))
* equal to 0, queue up a work item for @dev like in pm_request_autosuspend().
*
* Return:
* * 1: Success. Usage counter dropped to zero, but device was already suspended.
* * 0: Success.
* * -EINVAL: Runtime PM error.
* * -EACCES: Runtime PM disabled.
* * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing.
* * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
* change ongoing.
* * -EBUSY: Runtime PM child_count non-zero.
* * -EPERM: Device PM QoS resume latency 0.
* * -EINPROGRESS: Suspend already in progress.
* * -ENOSYS: CONFIG_PM not enabled.
* * 1: Device already suspended.
*/
static inline int __pm_runtime_put_autosuspend(struct device *dev)
{
@ -590,15 +597,16 @@ static inline int __pm_runtime_put_autosuspend(struct device *dev)
* in pm_request_autosuspend().
*
* Return:
* * 1: Success. Usage counter dropped to zero, but device was already suspended.
* * 0: Success.
* * -EINVAL: Runtime PM error.
* * -EACCES: Runtime PM disabled.
* * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing.
* * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
* change ongoing.
* * -EBUSY: Runtime PM child_count non-zero.
* * -EPERM: Device PM QoS resume latency 0.
* * -EINPROGRESS: Suspend already in progress.
* * -ENOSYS: CONFIG_PM not enabled.
* * 1: Device already suspended.
*/
static inline int pm_runtime_put_autosuspend(struct device *dev)
{
@ -606,6 +614,29 @@ static inline int pm_runtime_put_autosuspend(struct device *dev)
return __pm_runtime_put_autosuspend(dev);
}
DEFINE_GUARD(pm_runtime_noresume, struct device *,
pm_runtime_get_noresume(_T), pm_runtime_put_noidle(_T));
DEFINE_GUARD(pm_runtime_active, struct device *,
pm_runtime_get_sync(_T), pm_runtime_put(_T));
DEFINE_GUARD(pm_runtime_active_auto, struct device *,
pm_runtime_get_sync(_T), pm_runtime_put_autosuspend(_T));
/*
* Use the following guards with ACQUIRE()/ACQUIRE_ERR().
*
* The difference between the "_try" and "_try_enabled" variants is that the
* former do not produce an error when runtime PM is disabled for the given
* device.
*/
DEFINE_GUARD_COND(pm_runtime_active, _try,
pm_runtime_get_active(_T, RPM_TRANSPARENT))
DEFINE_GUARD_COND(pm_runtime_active, _try_enabled,
pm_runtime_resume_and_get(_T))
DEFINE_GUARD_COND(pm_runtime_active_auto, _try,
pm_runtime_get_active(_T, RPM_TRANSPARENT))
DEFINE_GUARD_COND(pm_runtime_active_auto, _try_enabled,
pm_runtime_resume_and_get(_T))
/**
* pm_runtime_put_sync - Drop device usage counter and run "idle check" if 0.
* @dev: Target device.
@ -619,14 +650,15 @@ static inline int pm_runtime_put_autosuspend(struct device *dev)
* if it returns an error code.
*
* Return:
* * 1: Success. Usage counter dropped to zero, but device was already suspended.
* * 0: Success.
* * -EINVAL: Runtime PM error.
* * -EACCES: Runtime PM disabled.
* * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing.
* * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
* change ongoing.
* * -EBUSY: Runtime PM child_count non-zero.
* * -EPERM: Device PM QoS resume latency 0.
* * -ENOSYS: CONFIG_PM not enabled.
* * 1: Device already suspended.
* Other values and conditions for the above values are possible as returned by
* Runtime PM suspend callbacks.
*/
@ -646,15 +678,15 @@ static inline int pm_runtime_put_sync(struct device *dev)
* if it returns an error code.
*
* Return:
* * 1: Success. Usage counter dropped to zero, but device was already suspended.
* * 0: Success.
* * -EINVAL: Runtime PM error.
* * -EACCES: Runtime PM disabled.
* * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing.
* * -EAGAIN: usage_count non-zero or Runtime PM status change ongoing.
* * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
* change ongoing.
* * -EBUSY: Runtime PM child_count non-zero.
* * -EPERM: Device PM QoS resume latency 0.
* * -ENOSYS: CONFIG_PM not enabled.
* * 1: Device already suspended.
* Other values and conditions for the above values are possible as returned by
* Runtime PM suspend callbacks.
*/
@ -677,15 +709,16 @@ static inline int pm_runtime_put_sync_suspend(struct device *dev)
* if it returns an error code.
*
* Return:
* * 1: Success. Usage counter dropped to zero, but device was already suspended.
* * 0: Success.
* * -EINVAL: Runtime PM error.
* * -EACCES: Runtime PM disabled.
* * -EAGAIN: Runtime PM usage_count non-zero or Runtime PM status change ongoing.
* * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status
* change ongoing.
* * -EBUSY: Runtime PM child_count non-zero.
* * -EPERM: Device PM QoS resume latency 0.
* * -EINPROGRESS: Suspend already in progress.
* * -ENOSYS: CONFIG_PM not enabled.
* * 1: Device already suspended.
* Other values and conditions for the above values are possible as returned by
* Runtime PM suspend callbacks.
*/