Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PM: runtime: Add basic kunit tests for API contracts

In exploring the various return codes and failure modes of runtime PM
APIs, I found it helpful to verify and codify many of them in unit
tests, especially given that even the kerneldoc can be rather complex to
reason through, and it also has had subtle errors of its own.

Notably, I avoid testing the return codes for pm_runtime_put() and
pm_runtime_put_autosuspend(), since code that checks them is probably
wrong, and we're considering making them return 'void' altogether. I
still test the sync() variants, since those have a bit more meaning to
them.

Signed-off-by: Brian Norris <briannorris@chromium.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Brian Norris and committed by
Rafael J. Wysocki
7f7acd19 927f3e85

+260
+6
drivers/base/Kconfig
··· 167 167 depends on KUNIT=y 168 168 default KUNIT_ALL_TESTS 169 169 170 + config PM_RUNTIME_KUNIT_TEST 171 + tristate "KUnit Tests for runtime PM" if !KUNIT_ALL_TESTS 172 + depends on KUNIT 173 + depends on PM 174 + default KUNIT_ALL_TESTS 175 + 170 176 config HMEM_REPORTING 171 177 bool 172 178 default n
+1
drivers/base/power/Makefile
··· 4 4 obj-$(CONFIG_PM_TRACE_RTC) += trace.o 5 5 obj-$(CONFIG_HAVE_CLK) += clock_ops.o 6 6 obj-$(CONFIG_PM_QOS_KUNIT_TEST) += qos-test.o 7 + obj-$(CONFIG_PM_RUNTIME_KUNIT_TEST) += runtime-test.o 7 8 8 9 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
+253
drivers/base/power/runtime-test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright 2025 Google, Inc. 4 + */ 5 + 6 + #include <linux/cleanup.h> 7 + #include <linux/pm_runtime.h> 8 + #include <kunit/device.h> 9 + #include <kunit/test.h> 10 + 11 + #define DEVICE_NAME "pm_runtime_test_device" 12 + 13 + static void pm_runtime_depth_test(struct kunit *test) 14 + { 15 + struct device *dev = kunit_device_register(test, DEVICE_NAME); 16 + 17 + KUNIT_ASSERT_PTR_NE(test, NULL, dev); 18 + 19 + pm_runtime_enable(dev); 20 + 21 + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); 22 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev)); 23 + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); 24 + KUNIT_EXPECT_EQ(test, 1, pm_runtime_get_sync(dev)); /* "already active" */ 25 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev)); 26 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev)); 27 + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); 28 + } 29 + 30 + /* Test pm_runtime_put() and friends when already suspended. */ 31 + static void pm_runtime_already_suspended_test(struct kunit *test) 32 + { 33 + struct device *dev = kunit_device_register(test, DEVICE_NAME); 34 + 35 + KUNIT_ASSERT_PTR_NE(test, NULL, dev); 36 + 37 + pm_runtime_enable(dev); 38 + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); 39 + 40 + pm_runtime_get_noresume(dev); 41 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_barrier(dev)); /* no wakeup needed */ 42 + pm_runtime_put(dev); 43 + 44 + pm_runtime_get_noresume(dev); 45 + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_put_sync(dev)); 46 + 47 + KUNIT_EXPECT_EQ(test, 1, pm_runtime_suspend(dev)); 48 + KUNIT_EXPECT_EQ(test, 1, pm_runtime_autosuspend(dev)); 49 + KUNIT_EXPECT_EQ(test, 1, pm_request_autosuspend(dev)); 50 + 51 + pm_runtime_get_noresume(dev); 52 + KUNIT_EXPECT_EQ(test, 1, pm_runtime_put_sync_autosuspend(dev)); 53 + 54 + pm_runtime_get_noresume(dev); 55 + pm_runtime_put_autosuspend(dev); 56 + 57 + /* Grab 2 refcounts */ 58 + pm_runtime_get_noresume(dev); 59 + pm_runtime_get_noresume(dev); 60 + /* The first put() sees usage_count 1 */ 61 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync_autosuspend(dev)); 62 + /* The second put() sees usage_count 0 but tells us "already suspended". */ 63 + KUNIT_EXPECT_EQ(test, 1, pm_runtime_put_sync_autosuspend(dev)); 64 + 65 + /* Should have remained suspended the whole time. */ 66 + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); 67 + } 68 + 69 + static void pm_runtime_idle_test(struct kunit *test) 70 + { 71 + struct device *dev = kunit_device_register(test, DEVICE_NAME); 72 + 73 + KUNIT_ASSERT_PTR_NE(test, NULL, dev); 74 + 75 + pm_runtime_enable(dev); 76 + 77 + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); 78 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev)); 79 + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); 80 + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_idle(dev)); 81 + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); 82 + pm_runtime_put_noidle(dev); 83 + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); 84 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_idle(dev)); 85 + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); 86 + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_idle(dev)); 87 + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_request_idle(dev)); 88 + } 89 + 90 + static void pm_runtime_disabled_test(struct kunit *test) 91 + { 92 + struct device *dev = kunit_device_register(test, DEVICE_NAME); 93 + 94 + KUNIT_ASSERT_PTR_NE(test, NULL, dev); 95 + 96 + /* Never called pm_runtime_enable() */ 97 + KUNIT_EXPECT_FALSE(test, pm_runtime_enabled(dev)); 98 + 99 + /* "disabled" is treated as "active" */ 100 + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); 101 + KUNIT_EXPECT_FALSE(test, pm_runtime_suspended(dev)); 102 + 103 + /* 104 + * Note: these "fail", but they still acquire/release refcounts, so 105 + * keep them balanced. 106 + */ 107 + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_get(dev)); 108 + pm_runtime_put(dev); 109 + 110 + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_get_sync(dev)); 111 + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_put_sync(dev)); 112 + 113 + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_get(dev)); 114 + pm_runtime_put_autosuspend(dev); 115 + 116 + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_resume_and_get(dev)); 117 + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_idle(dev)); 118 + KUNIT_EXPECT_EQ(test, -EACCES, pm_request_idle(dev)); 119 + KUNIT_EXPECT_EQ(test, -EACCES, pm_request_resume(dev)); 120 + KUNIT_EXPECT_EQ(test, -EACCES, pm_request_autosuspend(dev)); 121 + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_suspend(dev)); 122 + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_resume(dev)); 123 + KUNIT_EXPECT_EQ(test, -EACCES, pm_runtime_autosuspend(dev)); 124 + 125 + /* Still disabled */ 126 + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); 127 + KUNIT_EXPECT_FALSE(test, pm_runtime_enabled(dev)); 128 + } 129 + 130 + static void pm_runtime_error_test(struct kunit *test) 131 + { 132 + struct device *dev = kunit_device_register(test, DEVICE_NAME); 133 + 134 + KUNIT_ASSERT_PTR_NE(test, NULL, dev); 135 + 136 + pm_runtime_enable(dev); 137 + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); 138 + 139 + /* Fake a .runtime_resume() error */ 140 + dev->power.runtime_error = -EIO; 141 + 142 + /* 143 + * Note: these "fail", but they still acquire/release refcounts, so 144 + * keep them balanced. 145 + */ 146 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get(dev)); 147 + pm_runtime_put(dev); 148 + 149 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get_sync(dev)); 150 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_put_sync(dev)); 151 + 152 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get(dev)); 153 + pm_runtime_put_autosuspend(dev); 154 + 155 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_get(dev)); 156 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_put_sync_autosuspend(dev)); 157 + 158 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_resume_and_get(dev)); 159 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_idle(dev)); 160 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_request_idle(dev)); 161 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_request_resume(dev)); 162 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_request_autosuspend(dev)); 163 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_suspend(dev)); 164 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_resume(dev)); 165 + KUNIT_EXPECT_EQ(test, -EINVAL, pm_runtime_autosuspend(dev)); 166 + 167 + /* Error is still pending */ 168 + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); 169 + KUNIT_EXPECT_EQ(test, -EIO, dev->power.runtime_error); 170 + /* Clear error */ 171 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_set_suspended(dev)); 172 + KUNIT_EXPECT_EQ(test, 0, dev->power.runtime_error); 173 + /* Still suspended */ 174 + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); 175 + 176 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_get(dev)); 177 + KUNIT_EXPECT_EQ(test, 1, pm_runtime_barrier(dev)); /* resume was pending */ 178 + pm_runtime_put(dev); 179 + pm_runtime_suspend(dev); /* flush the put(), to suspend */ 180 + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); 181 + 182 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev)); 183 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev)); 184 + 185 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_get_sync(dev)); 186 + pm_runtime_put_autosuspend(dev); 187 + 188 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_resume_and_get(dev)); 189 + 190 + /* 191 + * The following should all return -EAGAIN (usage is non-zero) or 1 192 + * (already resumed). 193 + */ 194 + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_idle(dev)); 195 + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_request_idle(dev)); 196 + KUNIT_EXPECT_EQ(test, 1, pm_request_resume(dev)); 197 + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_request_autosuspend(dev)); 198 + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_suspend(dev)); 199 + KUNIT_EXPECT_EQ(test, 1, pm_runtime_resume(dev)); 200 + KUNIT_EXPECT_EQ(test, -EAGAIN, pm_runtime_autosuspend(dev)); 201 + 202 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_put_sync(dev)); 203 + 204 + /* Suspended again */ 205 + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); 206 + } 207 + 208 + /* 209 + * Explore a typical probe() sequence in which a device marks itself powered, 210 + * but doesn't hold any runtime PM reference, so it suspends as soon as it goes 211 + * idle. 212 + */ 213 + static void pm_runtime_probe_active_test(struct kunit *test) 214 + { 215 + struct device *dev = kunit_device_register(test, DEVICE_NAME); 216 + 217 + KUNIT_ASSERT_PTR_NE(test, NULL, dev); 218 + 219 + KUNIT_EXPECT_TRUE(test, pm_runtime_status_suspended(dev)); 220 + 221 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_set_active(dev)); 222 + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); 223 + 224 + pm_runtime_enable(dev); 225 + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); 226 + 227 + /* Nothing to flush. We stay active. */ 228 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_barrier(dev)); 229 + KUNIT_EXPECT_TRUE(test, pm_runtime_active(dev)); 230 + 231 + /* Ask for idle? Now we suspend. */ 232 + KUNIT_EXPECT_EQ(test, 0, pm_runtime_idle(dev)); 233 + KUNIT_EXPECT_TRUE(test, pm_runtime_suspended(dev)); 234 + } 235 + 236 + static struct kunit_case pm_runtime_test_cases[] = { 237 + KUNIT_CASE(pm_runtime_depth_test), 238 + KUNIT_CASE(pm_runtime_already_suspended_test), 239 + KUNIT_CASE(pm_runtime_idle_test), 240 + KUNIT_CASE(pm_runtime_disabled_test), 241 + KUNIT_CASE(pm_runtime_error_test), 242 + KUNIT_CASE(pm_runtime_probe_active_test), 243 + {} 244 + }; 245 + 246 + static struct kunit_suite pm_runtime_test_suite = { 247 + .name = "pm_runtime_test_cases", 248 + .test_cases = pm_runtime_test_cases, 249 + }; 250 + 251 + kunit_test_suite(pm_runtime_test_suite); 252 + MODULE_DESCRIPTION("Runtime power management unit test suite"); 253 + MODULE_LICENSE("GPL");