1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/pm/policy.h>
8 #include <zephyr/sys/time_units.h>
9 #include <zephyr/sys_clock.h>
10 #include <zephyr/ztest.h>
11 
pm_state_set(enum pm_state state,uint8_t substate_id)12 void pm_state_set(enum pm_state state, uint8_t substate_id)
13 {
14 	ARG_UNUSED(substate_id);
15 	ARG_UNUSED(state);
16 }
17 
pm_state_exit_post_ops(enum pm_state state,uint8_t substate_id)18 void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
19 {
20 	ARG_UNUSED(state);
21 	ARG_UNUSED(substate_id);
22 
23 	irq_unlock(0);
24 }
25 
26 #ifdef CONFIG_PM_POLICY_DEFAULT
27 /**
28  * @brief Test the behavior of pm_policy_next_state() when
29  * CONFIG_PM_POLICY_DEFAULT=y.
30  */
ZTEST(policy_api,test_pm_policy_next_state_default)31 ZTEST(policy_api, test_pm_policy_next_state_default)
32 {
33 	const struct pm_state_info *next;
34 
35 	/* cpu 0 */
36 	next = pm_policy_next_state(0U, 0);
37 	zassert_is_null(next);
38 
39 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(10999));
40 	zassert_is_null(next);
41 
42 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
43 	zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
44 	zassert_equal(next->min_residency_us, 100000);
45 	zassert_equal(next->exit_latency_us, 10000);
46 
47 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(1099999));
48 	zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
49 
50 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(1100000));
51 	zassert_equal(next->state, PM_STATE_SUSPEND_TO_RAM);
52 	zassert_equal(next->min_residency_us, 1000000);
53 	zassert_equal(next->exit_latency_us, 100000);
54 
55 	next = pm_policy_next_state(0U, K_TICKS_FOREVER);
56 	zassert_equal(next->state, PM_STATE_SUSPEND_TO_RAM);
57 
58 	/* cpu 1 */
59 	next = pm_policy_next_state(1U, 0);
60 	zassert_is_null(next);
61 
62 	next = pm_policy_next_state(1U, k_us_to_ticks_floor32(549999));
63 	zassert_is_null(next);
64 
65 	next = pm_policy_next_state(1U, k_us_to_ticks_floor32(550000));
66 	zassert_equal(next->state, PM_STATE_SUSPEND_TO_RAM);
67 	zassert_equal(next->min_residency_us, 500000);
68 	zassert_equal(next->exit_latency_us, 50000);
69 
70 	next = pm_policy_next_state(1U, K_TICKS_FOREVER);
71 	zassert_equal(next->state, PM_STATE_SUSPEND_TO_RAM);
72 }
73 
ZTEST(policy_api,test_pm_policy_state_all_lock)74 ZTEST(policy_api, test_pm_policy_state_all_lock)
75 {
76 	/* initial state: PM_STATE_RUNTIME_IDLE allowed */
77 	zassert_false(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES));
78 	zassert_true(pm_policy_state_is_available(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES));
79 	zassert_true(pm_policy_state_any_active());
80 
81 	/* Locking all states. */
82 	pm_policy_state_all_lock_get();
83 	pm_policy_state_all_lock_get();
84 
85 	/* States are locked. */
86 	zassert_true(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES));
87 	zassert_false(pm_policy_state_is_available(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES));
88 	zassert_false(pm_policy_state_any_active());
89 
90 	pm_policy_state_all_lock_put();
91 
92 	/* States are still locked due to reference counter. */
93 	zassert_true(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES));
94 	zassert_false(pm_policy_state_is_available(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES));
95 	zassert_false(pm_policy_state_any_active());
96 
97 	pm_policy_state_all_lock_put();
98 
99 	/* States are available again. */
100 	zassert_false(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES));
101 	zassert_true(pm_policy_state_is_available(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES));
102 	zassert_true(pm_policy_state_any_active());
103 }
104 
105 /**
106  * @brief Test the behavior of pm_policy_next_state() when
107  * states are allowed/disallowed and CONFIG_PM_POLICY_DEFAULT=y.
108  */
ZTEST(policy_api,test_pm_policy_next_state_default_allowed)109 ZTEST(policy_api, test_pm_policy_next_state_default_allowed)
110 {
111 	bool active;
112 	const struct pm_state_info *next;
113 
114 	/* initial state: PM_STATE_RUNTIME_IDLE allowed
115 	 * next state: PM_STATE_RUNTIME_IDLE
116 	 */
117 	active = pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
118 	zassert_false(active);
119 
120 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
121 	zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
122 
123 	/* disallow PM_STATE_RUNTIME_IDLE
124 	 * next state: NULL (active)
125 	 */
126 	pm_policy_state_lock_get(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
127 
128 	active = pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
129 	zassert_true(active);
130 
131 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
132 	zassert_is_null(next);
133 
134 	/* allow PM_STATE_RUNTIME_IDLE again
135 	 * next state: PM_STATE_RUNTIME_IDLE
136 	 */
137 	pm_policy_state_lock_put(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
138 
139 	active = pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
140 	zassert_false(active);
141 
142 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
143 	zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
144 
145 	/* initial state: PM_STATE_RUNTIME_IDLE and substate 1 allowed
146 	 * next state: PM_STATE_RUNTIME_IDLE
147 	 */
148 	pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, 1);
149 	zassert_false(active);
150 
151 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
152 	zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
153 
154 	/* disallow PM_STATE_RUNTIME_IDLE and substate 1
155 	 * next state: NULL (active)
156 	 */
157 	pm_policy_state_lock_get(PM_STATE_RUNTIME_IDLE, 1);
158 
159 	active = pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, 1);
160 	zassert_true(active);
161 
162 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
163 	zassert_is_null(next);
164 
165 	/* allow PM_STATE_RUNTIME_IDLE and substate 1 again
166 	 * next state: PM_STATE_RUNTIME_IDLE
167 	 */
168 	pm_policy_state_lock_put(PM_STATE_RUNTIME_IDLE, 1);
169 
170 	active = pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, 1);
171 	zassert_false(active);
172 
173 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
174 	zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
175 }
176 
177 /** Flag to indicate number of times callback has been called */
178 static uint8_t latency_cb_call_cnt;
179 /** Flag to indicate expected latency */
180 static int32_t expected_latency;
181 
182 /**
183  * Callback to notify when state allowed status changes.
184  */
on_pm_policy_latency_changed(int32_t latency)185 static void on_pm_policy_latency_changed(int32_t latency)
186 {
187 	TC_PRINT("Latency changed to %d\n", latency);
188 
189 	zassert_equal(latency, expected_latency);
190 
191 	latency_cb_call_cnt++;
192 }
193 
194 /**
195  * @brief Test the behavior of pm_policy_next_state() when
196  * latency requirements are imposed and CONFIG_PM_POLICY_DEFAULT=y.
197  */
ZTEST(policy_api,test_pm_policy_next_state_default_latency)198 ZTEST(policy_api, test_pm_policy_next_state_default_latency)
199 {
200 	struct pm_policy_latency_request req1, req2;
201 	struct pm_policy_latency_subscription sreq1, sreq2;
202 	const struct pm_state_info *next;
203 
204 	/* add a latency requirement with a maximum value below the
205 	 * latency given by any state, so we should stay active all the time
206 	 */
207 	pm_policy_latency_request_add(&req1, 9000);
208 
209 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
210 	zassert_is_null(next);
211 
212 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(1100000));
213 	zassert_is_null(next);
214 
215 	/* update latency requirement to a value between latencies for
216 	 * PM_STATE_RUNTIME_IDLE and PM_STATE_SUSPEND_TO_RAM, so we should
217 	 * never enter PM_STATE_SUSPEND_TO_RAM.
218 	 */
219 	pm_policy_latency_request_update(&req1, 50000);
220 
221 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
222 	zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
223 
224 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(1100000));
225 	zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
226 
227 	/* add a new latency requirement with a maximum value below the
228 	 * latency given by any state, so we should stay active all the time
229 	 * since it overrides the previous one.
230 	 */
231 	pm_policy_latency_request_add(&req2, 8000);
232 
233 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
234 	zassert_is_null(next);
235 
236 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(1100000));
237 	zassert_is_null(next);
238 
239 	/* remove previous request, so we should recover behavior given by
240 	 * first request.
241 	 */
242 	pm_policy_latency_request_remove(&req2);
243 
244 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
245 	zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
246 
247 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(1100000));
248 	zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
249 
250 	/* remove first request, so we should observe regular behavior again */
251 	pm_policy_latency_request_remove(&req1);
252 
253 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
254 	zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
255 
256 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(1100000));
257 	zassert_equal(next->state, PM_STATE_SUSPEND_TO_RAM);
258 
259 	/* get notified when latency requirement changes */
260 	pm_policy_latency_changed_subscribe(&sreq1, on_pm_policy_latency_changed);
261 	pm_policy_latency_changed_subscribe(&sreq2, on_pm_policy_latency_changed);
262 
263 	/* add new request (expected notification) */
264 	latency_cb_call_cnt = 0;
265 	expected_latency = 10000;
266 	pm_policy_latency_request_add(&req1, 10000);
267 	zassert_equal(latency_cb_call_cnt, 2);
268 
269 	/* update request (expected notification, but only sreq1) */
270 	pm_policy_latency_changed_unsubscribe(&sreq2);
271 
272 	latency_cb_call_cnt = 0;
273 	expected_latency = 50000;
274 	pm_policy_latency_request_update(&req1, 50000);
275 	zassert_equal(latency_cb_call_cnt, 1);
276 
277 	/* add a new request, with higher value (no notification, previous
278 	 * prevails)
279 	 */
280 	latency_cb_call_cnt = 0;
281 	pm_policy_latency_request_add(&req2, 60000);
282 	zassert_equal(latency_cb_call_cnt, 0);
283 
284 	pm_policy_latency_request_remove(&req2);
285 	zassert_equal(latency_cb_call_cnt, 0);
286 
287 	/* remove first request, we no longer have latency requirements */
288 	expected_latency = SYS_FOREVER_US;
289 	pm_policy_latency_request_remove(&req1);
290 	zassert_equal(latency_cb_call_cnt, 1);
291 }
292 
293 /**
294  * @brief Test pm_policy_state_constraints_get/put functions using devicetree
295  * test-states property and PM_STATE_CONSTRAINTS macros.
296  */
ZTEST(policy_api,test_pm_policy_state_constraints)297 ZTEST(policy_api, test_pm_policy_state_constraints)
298 {
299 	/* Define constraints list from the zephyr,user test-states property */
300 	PM_STATE_CONSTRAINTS_LIST_DEFINE(DT_PATH(zephyr_user), test_states);
301 
302 	/* Get the constraints structure from devicetree */
303 	struct pm_state_constraints test_constraints =
304 		PM_STATE_CONSTRAINTS_GET(DT_PATH(zephyr_user), test_states);
305 
306 	/* Verify the constraints were parsed correctly from devicetree
307 	 * test-states = <&state0 &state2> from app.overlay
308 	 */
309 	zassert_equal(test_constraints.count, 2,
310 		      "Expected 2 constraints from test-states property");
311 
312 	/* Check that the constraints contain the expected states:
313 	 * state0 (runtime-idle, substate 1) and state2 (suspend-to-ram, substate 100)
314 	 */
315 	bool found_runtime_idle = false;
316 	bool found_suspend_to_ram = false;
317 
318 	for (size_t i = 0; i < test_constraints.count; i++) {
319 		TC_PRINT("Constraint %zu: state=%d, substate_id=%d\n",
320 			 i, test_constraints.list[i].state, test_constraints.list[i].substate_id);
321 
322 		if (test_constraints.list[i].state == PM_STATE_RUNTIME_IDLE &&
323 		    test_constraints.list[i].substate_id == 1) {
324 			found_runtime_idle = true;
325 		}
326 		if (test_constraints.list[i].state == PM_STATE_SUSPEND_TO_RAM &&
327 		    test_constraints.list[i].substate_id == 100) {
328 			found_suspend_to_ram = true;
329 		}
330 	}
331 
332 	zassert_true(found_runtime_idle,
333 		     "Expected runtime-idle state with substate 1 in constraints");
334 	zassert_true(found_suspend_to_ram,
335 		     "Expected suspend-to-ram state with substate 100 in constraints");
336 
337 	/* Test that states are initially available */
338 	zassert_false(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, 1),
339 		      "runtime-idle substate 1 should be initially available");
340 	zassert_false(pm_policy_state_lock_is_active(PM_STATE_SUSPEND_TO_RAM, 100),
341 		      "suspend-to-ram substate 100 should be initially available");
342 
343 	/* Apply the constraints - this should lock the specified states */
344 	pm_policy_state_constraints_get(&test_constraints);
345 
346 	/* Verify that the constrained states are now locked */
347 	zassert_true(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, 1),
348 		     "runtime-idle substate 1 should be locked after applying constraints");
349 	zassert_true(pm_policy_state_lock_is_active(PM_STATE_SUSPEND_TO_RAM, 100),
350 		     "suspend-to-ram substate 100 should be locked after applying constraints");
351 
352 	/* Verify that non-constrained states are still available */
353 	zassert_false(pm_policy_state_lock_is_active(PM_STATE_SUSPEND_TO_RAM, 10),
354 		      "suspend-to-ram substate 10 should not be locked");
355 
356 	/* Test that policy respects the constraints */
357 	const struct pm_state_info *next;
358 
359 	/* This should not return the locked runtime-idle state,
360 	 * but should return suspend-to-ram substate 10
361 	 */
362 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(1100000));
363 	zassert_not_null(next, "Policy should return an available state");
364 	zassert_equal(next->state, PM_STATE_SUSPEND_TO_RAM);
365 	zassert_equal(next->substate_id, 10);
366 
367 	/* Remove the constraints - this should unlock the states */
368 	pm_policy_state_constraints_put(&test_constraints);
369 
370 	/* Verify that the previously constrained states are now unlocked */
371 	zassert_false(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, 1),
372 		      "runtime-idle substate 1 should be unlocked after removing constraints");
373 	zassert_false(pm_policy_state_lock_is_active(PM_STATE_SUSPEND_TO_RAM, 100),
374 		      "suspend-to-ram substate 100 should be unlocked after removing constraints");
375 
376 	/* Verify policy works normally again */
377 	next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
378 	zassert_not_null(next, "Policy should return a state after removing constraints");
379 	zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
380 
381 	/* Test multiple get/put cycles to verify reference counting */
382 	pm_policy_state_constraints_get(&test_constraints);
383 	pm_policy_state_constraints_get(&test_constraints);
384 
385 	zassert_true(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, 1),
386 		     "runtime-idle substate 1 should remain locked with multiple gets");
387 
388 	/* First put should not unlock (reference count > 1) */
389 	pm_policy_state_constraints_put(&test_constraints);
390 	zassert_true(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, 1),
391 		     "runtime-idle substate 1 should remain locked after first put");
392 
393 	/* Second put should unlock (reference count = 0) */
394 	pm_policy_state_constraints_put(&test_constraints);
395 	zassert_false(pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, 1),
396 		      "runtime-idle substate 1 should be unlocked after final put");
397 }
398 #else
ZTEST(policy_api,test_pm_policy_next_state_default)399 ZTEST(policy_api, test_pm_policy_next_state_default)
400 {
401 	ztest_test_skip();
402 }
403 
ZTEST(policy_api,test_pm_policy_next_state_default_allowed)404 ZTEST(policy_api, test_pm_policy_next_state_default_allowed)
405 {
406 	ztest_test_skip();
407 }
408 
ZTEST(policy_api,test_pm_policy_next_state_default_latency)409 ZTEST(policy_api, test_pm_policy_next_state_default_latency)
410 {
411 	ztest_test_skip();
412 }
413 
ZTEST(policy_api,test_pm_policy_state_constraints)414 ZTEST(policy_api, test_pm_policy_state_constraints)
415 {
416 	ztest_test_skip();
417 }
418 #endif /* CONFIG_PM_POLICY_DEFAULT */
419 
420 #ifdef CONFIG_PM_POLICY_CUSTOM
pm_policy_next_state(uint8_t cpu,int32_t ticks)421 const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks)
422 {
423 	static const struct pm_state_info state = {.state = PM_STATE_SOFT_OFF};
424 
425 	ARG_UNUSED(cpu);
426 	ARG_UNUSED(ticks);
427 
428 	return &state;
429 }
430 
431 /**
432  * @brief Test that a custom policy can be implemented when
433  * CONFIG_PM_POLICY_CUSTOM=y.
434  */
ZTEST(policy_api,test_pm_policy_next_state_custom)435 ZTEST(policy_api, test_pm_policy_next_state_custom)
436 {
437 	const struct pm_state_info *next;
438 
439 	next = pm_policy_next_state(0U, 0);
440 	zassert_equal(next->state, PM_STATE_SOFT_OFF);
441 }
442 #else
ZTEST(policy_api,test_pm_policy_next_state_custom)443 ZTEST(policy_api, test_pm_policy_next_state_custom)
444 {
445 	ztest_test_skip();
446 }
447 #endif /* CONFIG_PM_POLICY_CUSTOM */
448 
ZTEST(policy_api,test_pm_policy_events)449 ZTEST(policy_api, test_pm_policy_events)
450 {
451 	struct pm_policy_event evt1;
452 	struct pm_policy_event evt2;
453 	int64_t now_uptime_ticks;
454 	int64_t evt1_1_uptime_ticks;
455 	int64_t evt1_2_uptime_ticks;
456 	int64_t evt2_uptime_ticks;
457 
458 	now_uptime_ticks = k_uptime_ticks();
459 	evt1_1_uptime_ticks = now_uptime_ticks + 100;
460 	evt1_2_uptime_ticks = now_uptime_ticks + 200;
461 	evt2_uptime_ticks = now_uptime_ticks + 2000;
462 
463 	zassert_equal(pm_policy_next_event_ticks(), -1);
464 	pm_policy_event_register(&evt1, evt1_1_uptime_ticks);
465 	pm_policy_event_register(&evt2, evt2_uptime_ticks);
466 	zassert_within(pm_policy_next_event_ticks(), 100, 50);
467 	pm_policy_event_unregister(&evt1);
468 	zassert_within(pm_policy_next_event_ticks(), 2000, 50);
469 	pm_policy_event_unregister(&evt2);
470 	zassert_equal(pm_policy_next_event_ticks(), -1);
471 	pm_policy_event_register(&evt2, evt2_uptime_ticks);
472 	zassert_within(pm_policy_next_event_ticks(), 2000, 50);
473 	pm_policy_event_register(&evt1, evt1_1_uptime_ticks);
474 	zassert_within(pm_policy_next_event_ticks(), 100, 50);
475 	pm_policy_event_update(&evt1, evt1_2_uptime_ticks);
476 	zassert_within(pm_policy_next_event_ticks(), 200, 50);
477 	pm_policy_event_unregister(&evt1);
478 	pm_policy_event_unregister(&evt2);
479 }
480 
481 ZTEST_SUITE(policy_api, NULL, NULL, NULL, NULL, NULL);
482