mirror of
https://github.com/torvalds/linux.git
synced 2025-11-01 17:18:25 +02:00
The kunit_device_register() function never returns NULL, it returns
error pointers. Update the assertions to use
KUNIT_ASSERT_NOT_ERR_OR_NULL() instead of checking for NULL.
Fixes: 7f7acd193b ("PM: runtime: Add basic kunit tests for API contracts")
Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
Reviewed-by: Brian Norris <briannorris@chromium.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
253 lines
8.3 KiB
C
253 lines
8.3 KiB
C
// 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");
|