1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <zephyr/pm/device.h>
9 #include <zephyr/pm/device_runtime.h>
10
11 #include "test_driver.h"
12 #include "zephyr/sys/util_macro.h"
13
14
15 static const struct device *test_dev;
16
17 #ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
18 static struct k_thread get_runner_td;
19 K_THREAD_STACK_DEFINE(get_runner_stack, 1024);
20
get_runner(void * arg1,void * arg2,void * arg3)21 static void get_runner(void *arg1, void *arg2, void *arg3)
22 {
23 int ret;
24 bool ongoing;
25
26 ARG_UNUSED(arg1);
27 ARG_UNUSED(arg2);
28 ARG_UNUSED(arg3);
29
30 /* make sure we test blocking path (suspend is ongoing) */
31 ongoing = test_driver_pm_ongoing(test_dev);
32 zassert_equal(ongoing, true);
33
34 /* usage: 0, +1, resume: yes */
35 ret = pm_device_runtime_get(test_dev);
36 zassert_equal(ret, 0);
37 }
38 #endif /* CONFIG_PM_DEVICE_RUNTIME_ASYNC */
39
test_api_setup(void * data)40 void test_api_setup(void *data)
41 {
42 int ret;
43 enum pm_device_state state;
44
45 test_driver_pm_retval(test_dev, 0);
46
47 /* check API always returns 0 when runtime PM is disabled */
48 ret = pm_device_runtime_get(test_dev);
49 zassert_equal(ret, 0);
50 ret = pm_device_runtime_put(test_dev);
51 zassert_equal(ret, 0);
52 ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT);
53 #ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
54 zassert_equal(ret, 0);
55 #else
56 zassert_equal(ret, -ENOSYS);
57 #endif
58
59 /* enable runtime PM */
60 ret = pm_device_runtime_enable(test_dev);
61 zassert_equal(ret, 0);
62
63 (void)pm_device_state_get(test_dev, &state);
64 zassert_equal(state, PM_DEVICE_STATE_SUSPENDED);
65
66 /* enabling again should succeed (no-op) */
67 ret = pm_device_runtime_enable(test_dev);
68 zassert_equal(ret, 0);
69 }
70
test_api_teardown(void * data)71 static void test_api_teardown(void *data)
72 {
73 int ret;
74 enum pm_device_state state;
75
76 /* let test driver finish async PM (in case it was left pending due to
77 * a failure)
78 */
79 if (test_driver_pm_ongoing(test_dev)) {
80 test_driver_pm_done(test_dev);
81 }
82
83 /* disable runtime PM, make sure device is left into active state */
84 ret = pm_device_runtime_disable(test_dev);
85 zassert_equal(ret, 0);
86
87 (void)pm_device_state_get(test_dev, &state);
88 zassert_equal(state, PM_DEVICE_STATE_ACTIVE);
89 }
90
91 /**
92 * @brief Test the behavior of the device runtime PM API.
93 *
94 * Scenarios tested:
95 *
96 * - get + put
97 * - get + asynchronous put until suspended
98 * - get + asynchronous put + get (while suspend still ongoing)
99 */
ZTEST(device_runtime_api,test_api)100 ZTEST(device_runtime_api, test_api)
101 {
102 int ret;
103 enum pm_device_state state;
104
105 /* device is initially suspended */
106 (void)pm_device_state_get(test_dev, &state);
107 zassert_equal(state, PM_DEVICE_STATE_SUSPENDED);
108 zassert_equal(pm_device_runtime_usage(test_dev), 0);
109
110 /*** get + put ***/
111
112 /* usage: 0, 0, resume: no */
113 test_driver_pm_retval(test_dev, -EIO);
114 ret = pm_device_runtime_get(test_dev);
115 zassert_equal(ret, -EIO);
116 test_driver_pm_retval(test_dev, 0);
117
118 /* usage: 0, +1, resume: yes */
119 ret = pm_device_runtime_get(test_dev);
120 zassert_equal(ret, 0);
121
122 (void)pm_device_state_get(test_dev, &state);
123 zassert_equal(state, PM_DEVICE_STATE_ACTIVE);
124
125 /* usage: 1, +1, resume: no */
126 ret = pm_device_runtime_get(test_dev);
127 zassert_equal(ret, 0);
128 zassert_equal(pm_device_runtime_usage(test_dev), 2);
129
130 /* usage: 2, -1, suspend: no */
131 ret = pm_device_runtime_put(test_dev);
132 zassert_equal(ret, 0);
133
134 (void)pm_device_state_get(test_dev, &state);
135 zassert_equal(state, PM_DEVICE_STATE_ACTIVE);
136
137 /* usage: 1, 0, suspend: no */
138 test_driver_pm_retval(test_dev, -EIO);
139 ret = pm_device_runtime_put(test_dev);
140 zassert_equal(ret, -EIO);
141 test_driver_pm_retval(test_dev, 0);
142
143 /* usage: 1, -1, suspend: yes */
144 ret = pm_device_runtime_put(test_dev);
145 zassert_equal(ret, 0);
146 zassert_equal(pm_device_runtime_usage(test_dev), 0);
147
148 (void)pm_device_state_get(test_dev, &state);
149 zassert_equal(state, PM_DEVICE_STATE_SUSPENDED);
150
151 /* usage: 0, -1, suspend: no (unbalanced call) */
152 ret = pm_device_runtime_put(test_dev);
153 zassert_equal(ret, -EALREADY);
154 zassert_equal(pm_device_runtime_usage(test_dev), 0);
155
156 #ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
157 /*** get + asynchronous put until suspended ***/
158
159 /* usage: 0, +1, resume: yes */
160 ret = pm_device_runtime_get(test_dev);
161 zassert_equal(ret, 0);
162 zassert_equal(pm_device_runtime_usage(test_dev), 1);
163
164 (void)pm_device_state_get(test_dev, &state);
165 zassert_equal(state, PM_DEVICE_STATE_ACTIVE);
166
167 test_driver_pm_async(test_dev);
168
169 /* usage: 1, -1, suspend: yes (queued) */
170 ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT);
171 zassert_equal(ret, 0);
172 zassert_equal(pm_device_runtime_usage(test_dev), 0);
173
174 if (IS_ENABLED(CONFIG_TEST_PM_DEVICE_ISR_SAFE)) {
175 /* In sync mode async put is equivalent as normal put. */
176 (void)pm_device_state_get(test_dev, &state);
177 zassert_equal(state, PM_DEVICE_STATE_SUSPENDED);
178 zassert_equal(pm_device_runtime_usage(test_dev), 0);
179 } else {
180 (void)pm_device_state_get(test_dev, &state);
181 zassert_equal(state, PM_DEVICE_STATE_SUSPENDING);
182
183 /* usage: 0, -1, suspend: no (unbalanced call) */
184 ret = pm_device_runtime_put(test_dev);
185 zassert_equal(ret, -EALREADY);
186
187 /* usage: 0, -1, suspend: no (unbalanced call) */
188 ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT);
189 zassert_equal(ret, -EALREADY);
190 zassert_equal(pm_device_runtime_usage(test_dev), 0);
191
192 /* unblock test driver and let it finish */
193 test_driver_pm_done(test_dev);
194 k_yield();
195
196 (void)pm_device_state_get(test_dev, &state);
197 zassert_equal(state, PM_DEVICE_STATE_SUSPENDED);
198
199 /*** get + asynchronous put + get (while suspend still ongoing) ***/
200
201 /* usage: 0, +1, resume: yes */
202 ret = pm_device_runtime_get(test_dev);
203 zassert_equal(ret, 0);
204
205 (void)pm_device_state_get(test_dev, &state);
206 zassert_equal(state, PM_DEVICE_STATE_ACTIVE);
207
208 test_driver_pm_async(test_dev);
209
210 /* usage: 1, -1, suspend: yes (queued) */
211 ret = pm_device_runtime_put_async(test_dev, K_NO_WAIT);
212 zassert_equal(ret, 0);
213
214 (void)pm_device_state_get(test_dev, &state);
215 zassert_equal(state, PM_DEVICE_STATE_SUSPENDING);
216
217 /* let suspension start */
218 k_yield();
219
220 /* create and start get_runner thread
221 * get_runner thread is used to test synchronous path while asynchronous
222 * is ongoing. It is important to set its priority >= to the system work
223 * queue to make sure sync path run by the thread is forced to wait.
224 */
225 k_thread_create(&get_runner_td, get_runner_stack,
226 K_THREAD_STACK_SIZEOF(get_runner_stack), get_runner,
227 NULL, NULL, NULL,
228 COND_CODE_1(CONFIG_PM_DEVICE_RUNTIME_USE_DEDICATED_WQ,
229 (CONFIG_PM_DEVICE_RUNTIME_DEDICATED_WQ_PRIO),
230 (CONFIG_SYSTEM_WORKQUEUE_PRIORITY)), 0, K_NO_WAIT);
231 k_yield();
232
233 /* let driver suspend to finish and wait until get_runner finishes
234 * resuming the driver
235 */
236 test_driver_pm_done(test_dev);
237 k_thread_join(&get_runner_td, K_FOREVER);
238
239 (void)pm_device_state_get(test_dev, &state);
240 zassert_equal(state, PM_DEVICE_STATE_ACTIVE);
241
242 /* Test if getting a device before an async operation starts does
243 * not trigger any device pm action.
244 */
245 size_t count = test_driver_pm_count(test_dev);
246
247 ret = pm_device_runtime_put_async(test_dev, K_MSEC(10));
248 zassert_equal(ret, 0);
249
250 (void)pm_device_state_get(test_dev, &state);
251 zassert_equal(state, PM_DEVICE_STATE_SUSPENDING);
252
253 ret = pm_device_runtime_get(test_dev);
254 zassert_equal(ret, 0);
255
256 /* Now lets check if the calls above have triggered a device
257 * pm action
258 */
259 zassert_equal(count, test_driver_pm_count(test_dev));
260
261 /*
262 * test if async put with a delay respects the given time.
263 */
264 ret = pm_device_runtime_put_async(test_dev, K_MSEC(100));
265
266 (void)pm_device_state_get(test_dev, &state);
267 zassert_equal(state, PM_DEVICE_STATE_SUSPENDING);
268
269 k_sleep(K_MSEC(80));
270
271 /* It should still be suspending since we have waited less than
272 * the delay we've set.
273 */
274 (void)pm_device_state_get(test_dev, &state);
275 zassert_equal(state, PM_DEVICE_STATE_SUSPENDING);
276
277 k_sleep(K_MSEC(30));
278
279 /* Now it should be already suspended */
280 (void)pm_device_state_get(test_dev, &state);
281 zassert_equal(state, PM_DEVICE_STATE_SUSPENDED);
282 }
283
284 /* Put operation should fail due the state be locked. */
285 ret = pm_device_runtime_disable(test_dev);
286 zassert_equal(ret, 0);
287 zassert_equal(pm_device_runtime_usage(test_dev), -ENOTSUP);
288 #endif /* CONFIG_PM_DEVICE_RUNTIME_ASYNC */
289 }
290
291 DEVICE_DEFINE(pm_unsupported_device, "PM Unsupported", NULL, NULL, NULL, NULL,
292 POST_KERNEL, 0, NULL);
293
ZTEST(device_runtime_api,test_unsupported)294 ZTEST(device_runtime_api, test_unsupported)
295 {
296 const struct device *const dev = DEVICE_GET(pm_unsupported_device);
297
298 zassert_false(pm_device_runtime_is_enabled(dev), "");
299 zassert_equal(pm_device_runtime_enable(dev), -ENOTSUP, "");
300 zassert_equal(pm_device_runtime_disable(dev), -ENOTSUP, "");
301 zassert_equal(pm_device_runtime_get(dev), 0, "");
302 zassert_equal(pm_device_runtime_put(dev), 0, "");
303 #ifdef CONFIG_PM_DEVICE_RUNTIME_ASYNC
304 zassert_equal(pm_device_runtime_put_async(dev, K_NO_WAIT), 0, "");
305 #else
306 zassert_equal(pm_device_runtime_put_async(dev, K_NO_WAIT), -ENOSYS, "");
307 #endif
308 }
309
dev_pm_control(const struct device * dev,enum pm_device_action action)310 int dev_pm_control(const struct device *dev, enum pm_device_action action)
311 {
312 ARG_UNUSED(dev);
313 ARG_UNUSED(action);
314
315 return 0;
316 }
317
318 PM_DEVICE_DT_DEFINE(DT_NODELABEL(test_dev), dev_pm_control);
319 DEVICE_DT_DEFINE(DT_NODELABEL(test_dev), NULL, PM_DEVICE_DT_GET(DT_NODELABEL(test_dev)),
320 NULL, NULL, POST_KERNEL, 80, NULL);
321
ZTEST(device_runtime_api,test_pm_device_runtime_auto)322 ZTEST(device_runtime_api, test_pm_device_runtime_auto)
323 {
324 const struct device *const dev = DEVICE_DT_GET(DT_NODELABEL(test_dev));
325
326 zassert_true(pm_device_runtime_is_enabled(dev), "");
327 zassert_equal(pm_device_runtime_get(dev), 0, "");
328 zassert_equal(pm_device_runtime_put(dev), 0, "");
329 }
330
device_runtime_api_setup(void)331 void *device_runtime_api_setup(void)
332 {
333 test_dev = device_get_binding("test_driver");
334 zassert_not_null(test_dev);
335 return NULL;
336 }
337
338 ZTEST_SUITE(device_runtime_api, NULL, device_runtime_api_setup,
339 test_api_setup, test_api_teardown, NULL);
340