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
74 /**
75 * @brief Test the behavior of pm_policy_next_state() when
76 * states are allowed/disallowed and CONFIG_PM_POLICY_DEFAULT=y.
77 */
ZTEST(policy_api,test_pm_policy_next_state_default_allowed)78 ZTEST(policy_api, test_pm_policy_next_state_default_allowed)
79 {
80 bool active;
81 const struct pm_state_info *next;
82
83 /* initial state: PM_STATE_RUNTIME_IDLE allowed
84 * next state: PM_STATE_RUNTIME_IDLE
85 */
86 active = pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
87 zassert_false(active);
88
89 next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
90 zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
91
92 /* disallow PM_STATE_RUNTIME_IDLE
93 * next state: NULL (active)
94 */
95 pm_policy_state_lock_get(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
96
97 active = pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
98 zassert_true(active);
99
100 next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
101 zassert_is_null(next);
102
103 /* allow PM_STATE_RUNTIME_IDLE again
104 * next state: PM_STATE_RUNTIME_IDLE
105 */
106 pm_policy_state_lock_put(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
107
108 active = pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES);
109 zassert_false(active);
110
111 next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
112 zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
113
114 /* initial state: PM_STATE_RUNTIME_IDLE and substate 1 allowed
115 * next state: PM_STATE_RUNTIME_IDLE
116 */
117 pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, 1);
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 and substate 1
124 * next state: NULL (active)
125 */
126 pm_policy_state_lock_get(PM_STATE_RUNTIME_IDLE, 1);
127
128 active = pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, 1);
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 and substate 1 again
135 * next state: PM_STATE_RUNTIME_IDLE
136 */
137 pm_policy_state_lock_put(PM_STATE_RUNTIME_IDLE, 1);
138
139 active = pm_policy_state_lock_is_active(PM_STATE_RUNTIME_IDLE, 1);
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
146 /** Flag to indicate number of times callback has been called */
147 static uint8_t latency_cb_call_cnt;
148 /** Flag to indicate expected latency */
149 static int32_t expected_latency;
150
151 /**
152 * Callback to notify when state allowed status changes.
153 */
on_pm_policy_latency_changed(int32_t latency)154 static void on_pm_policy_latency_changed(int32_t latency)
155 {
156 TC_PRINT("Latency changed to %d\n", latency);
157
158 zassert_equal(latency, expected_latency);
159
160 latency_cb_call_cnt++;
161 }
162
163 /**
164 * @brief Test the behavior of pm_policy_next_state() when
165 * latency requirements are imposed and CONFIG_PM_POLICY_DEFAULT=y.
166 */
ZTEST(policy_api,test_pm_policy_next_state_default_latency)167 ZTEST(policy_api, test_pm_policy_next_state_default_latency)
168 {
169 struct pm_policy_latency_request req1, req2;
170 struct pm_policy_latency_subscription sreq1, sreq2;
171 const struct pm_state_info *next;
172
173 /* add a latency requirement with a maximum value below the
174 * latency given by any state, so we should stay active all the time
175 */
176 pm_policy_latency_request_add(&req1, 9000);
177
178 next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
179 zassert_is_null(next);
180
181 next = pm_policy_next_state(0U, k_us_to_ticks_floor32(1100000));
182 zassert_is_null(next);
183
184 /* update latency requirement to a value between latencies for
185 * PM_STATE_RUNTIME_IDLE and PM_STATE_SUSPEND_TO_RAM, so we should
186 * never enter PM_STATE_SUSPEND_TO_RAM.
187 */
188 pm_policy_latency_request_update(&req1, 50000);
189
190 next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
191 zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
192
193 next = pm_policy_next_state(0U, k_us_to_ticks_floor32(1100000));
194 zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
195
196 /* add a new latency requirement with a maximum value below the
197 * latency given by any state, so we should stay active all the time
198 * since it overrides the previous one.
199 */
200 pm_policy_latency_request_add(&req2, 8000);
201
202 next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
203 zassert_is_null(next);
204
205 next = pm_policy_next_state(0U, k_us_to_ticks_floor32(1100000));
206 zassert_is_null(next);
207
208 /* remove previous request, so we should recover behavior given by
209 * first request.
210 */
211 pm_policy_latency_request_remove(&req2);
212
213 next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
214 zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
215
216 next = pm_policy_next_state(0U, k_us_to_ticks_floor32(1100000));
217 zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
218
219 /* remove first request, so we should observe regular behavior again */
220 pm_policy_latency_request_remove(&req1);
221
222 next = pm_policy_next_state(0U, k_us_to_ticks_floor32(110000));
223 zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
224
225 next = pm_policy_next_state(0U, k_us_to_ticks_floor32(1100000));
226 zassert_equal(next->state, PM_STATE_SUSPEND_TO_RAM);
227
228 /* get notified when latency requirement changes */
229 pm_policy_latency_changed_subscribe(&sreq1, on_pm_policy_latency_changed);
230 pm_policy_latency_changed_subscribe(&sreq2, on_pm_policy_latency_changed);
231
232 /* add new request (expected notification) */
233 latency_cb_call_cnt = 0;
234 expected_latency = 10000;
235 pm_policy_latency_request_add(&req1, 10000);
236 zassert_equal(latency_cb_call_cnt, 2);
237
238 /* update request (expected notification, but only sreq1) */
239 pm_policy_latency_changed_unsubscribe(&sreq2);
240
241 latency_cb_call_cnt = 0;
242 expected_latency = 50000;
243 pm_policy_latency_request_update(&req1, 50000);
244 zassert_equal(latency_cb_call_cnt, 1);
245
246 /* add a new request, with higher value (no notification, previous
247 * prevails)
248 */
249 latency_cb_call_cnt = 0;
250 pm_policy_latency_request_add(&req2, 60000);
251 zassert_equal(latency_cb_call_cnt, 0);
252
253 pm_policy_latency_request_remove(&req2);
254 zassert_equal(latency_cb_call_cnt, 0);
255
256 /* remove first request, we no longer have latency requirements */
257 expected_latency = SYS_FOREVER_US;
258 pm_policy_latency_request_remove(&req1);
259 zassert_equal(latency_cb_call_cnt, 1);
260 }
261 #else
ZTEST(policy_api,test_pm_policy_next_state_default)262 ZTEST(policy_api, test_pm_policy_next_state_default)
263 {
264 ztest_test_skip();
265 }
266
ZTEST(policy_api,test_pm_policy_next_state_default_allowed)267 ZTEST(policy_api, test_pm_policy_next_state_default_allowed)
268 {
269 ztest_test_skip();
270 }
271
ZTEST(policy_api,test_pm_policy_next_state_default_latency)272 ZTEST(policy_api, test_pm_policy_next_state_default_latency)
273 {
274 ztest_test_skip();
275 }
276 #endif /* CONFIG_PM_POLICY_DEFAULT */
277
278 #ifdef CONFIG_PM_POLICY_CUSTOM
pm_policy_next_state(uint8_t cpu,int32_t ticks)279 const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks)
280 {
281 static const struct pm_state_info state = {.state = PM_STATE_SOFT_OFF};
282
283 ARG_UNUSED(cpu);
284 ARG_UNUSED(ticks);
285
286 return &state;
287 }
288
289 /**
290 * @brief Test that a custom policy can be implemented when
291 * CONFIG_PM_POLICY_CUSTOM=y.
292 */
ZTEST(policy_api,test_pm_policy_next_state_custom)293 ZTEST(policy_api, test_pm_policy_next_state_custom)
294 {
295 const struct pm_state_info *next;
296
297 next = pm_policy_next_state(0U, 0);
298 zassert_equal(next->state, PM_STATE_SOFT_OFF);
299 }
300 #else
ZTEST(policy_api,test_pm_policy_next_state_custom)301 ZTEST(policy_api, test_pm_policy_next_state_custom)
302 {
303 ztest_test_skip();
304 }
305 #endif /* CONFIG_PM_POLICY_CUSTOM */
306
307 #ifdef CONFIG_PM_POLICY_DEFAULT
308 /* note: we can't easily mock k_cycle_get_32(), so test is not ideal */
ZTEST(policy_api,test_pm_policy_events)309 ZTEST(policy_api, test_pm_policy_events)
310 {
311 struct pm_policy_event evt1, evt2;
312 const struct pm_state_info *next;
313 uint32_t now;
314
315 now = k_cyc_to_us_ceil32(k_cycle_get_32());
316
317 /* events:
318 * - 10ms from now (time < runtime idle latency)
319 * - 200ms from now (time > runtime idle, < suspend to ram latencies)
320 *
321 * system wakeup:
322 * - 2s from now (time > suspend to ram latency)
323 *
324 * first event wins, so we must stay active
325 */
326 pm_policy_event_register(&evt1, 10000);
327 pm_policy_event_register(&evt2, 200000);
328 next = pm_policy_next_state(0U, now + k_us_to_ticks_floor32(2000000));
329 zassert_is_null(next);
330
331 /* remove first event so second event now wins, meaning we can now enter
332 * runtime idle
333 */
334 pm_policy_event_unregister(&evt1);
335 next = pm_policy_next_state(0U, now + k_us_to_ticks_floor32(2000000));
336 zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
337
338 /* remove second event, now we can enter deepest state */
339 pm_policy_event_unregister(&evt2);
340 next = pm_policy_next_state(0U, now + k_us_to_ticks_floor32(2000000));
341 zassert_equal(next->state, PM_STATE_SUSPEND_TO_RAM);
342
343 /* events:
344 * - 2s from now (time > suspend to ram latency)
345 *
346 * system wakeup:
347 * - 200ms from now (time > runtime idle, < suspend to ram latencies)
348 *
349 * system wakeup wins, so we can go up to runtime idle.
350 */
351 pm_policy_event_register(&evt1, 2000000);
352 next = pm_policy_next_state(0U, now + k_us_to_ticks_floor32(200000));
353 zassert_equal(next->state, PM_STATE_RUNTIME_IDLE);
354
355 /* modify event to occur in 10ms, so it now wins system wakeup and
356 * requires to stay awake
357 */
358 pm_policy_event_update(&evt1, 10000);
359 next = pm_policy_next_state(0U, now + k_us_to_ticks_floor32(200000));
360 zassert_is_null(next);
361
362 pm_policy_event_unregister(&evt1);
363 }
364 #else
ZTEST(policy_api,test_pm_policy_events)365 ZTEST(policy_api, test_pm_policy_events)
366 {
367 ztest_test_skip();
368 }
369 #endif /* CONFIG_PM_POLICY_CUSTOM */
370
371 ZTEST_SUITE(policy_api, NULL, NULL, NULL, NULL, NULL);
372