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