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