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