// 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, 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)); pm_runtime_barrier(dev); 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. */ 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");
// 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, 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));
pm_runtime_barrier(dev);
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. */
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");