blob: ba67ab1b5c392b75e03fd4d1207d7cff15920feb [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
Charlie Barehamaf8934c2024-07-26 14:51:14 +01002 * Copyright (c) 2018-2025, Arm Limited. All rights reserved.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch.h>
8#include <arch_helpers.h>
9#include <assert.h>
10#include <debug.h>
11#include <events.h>
12#include <irq.h>
13#include <plat_topology.h>
14#include <platform.h>
15#include <platform_def.h>
16#include <power_management.h>
17#include <psci.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020018#include <tftf_lib.h>
19#include <timer.h>
20
21/*
Wing Licb88add2022-10-29 02:32:06 +010022 * Desired affinity level, state type (standby or powerdown), and entry time for
Charlie Barehamaf8934c2024-07-26 14:51:14 +010023 * each CPU in the next CPU_SUSPEND operation. There are suspend flags so
24 * some CPUs can be left running. We need these shared variables because there
25 * is no way to pass arguments to non-lead CPUs.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020026 */
Wing Licb88add2022-10-29 02:32:06 +010027static unsigned int test_aff_level[PLATFORM_CORE_COUNT];
28static unsigned int test_suspend_type[PLATFORM_CORE_COUNT];
29static unsigned int test_suspend_entry_time[PLATFORM_CORE_COUNT];
Charlie Barehamaf8934c2024-07-26 14:51:14 +010030static bool test_should_suspend[PLATFORM_CORE_COUNT];
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020031
Wing Licb88add2022-10-29 02:32:06 +010032static event_t cpu_booted[PLATFORM_CORE_COUNT];
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020033static event_t cpu_ready[PLATFORM_CORE_COUNT];
Charlie Barehamaf8934c2024-07-26 14:51:14 +010034static event_t cpu_finished[PLATFORM_CORE_COUNT];
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020035
36/*
37 * Variable used by the non-lead CPUs to tell the lead CPU they
38 * were woken up by IRQ_WAKE_SGI
39 */
40static event_t event_received_wake_irq[PLATFORM_CORE_COUNT];
41
42/* Variable used to confirm the CPU is woken up by IRQ_WAKE_SGI or Timer IRQ */
43static volatile int requested_irq_received[PLATFORM_CORE_COUNT];
44
45static int requested_irq_handler(void *data)
46{
47 unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
48#if ENABLE_ASSERTIONS
49 unsigned int irq_id = *(unsigned int *) data;
50#endif
51
Boyan Karatotev6d144db2025-06-23 15:04:53 +010052 assert(irq_id == tftf_irq_get_my_sgi_num(IRQ_WAKE_SGI) || irq_id == tftf_get_timer_irq());
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020053 assert(requested_irq_received[core_pos] == 0);
54
55 requested_irq_received[core_pos] = 1;
56
57 return 0;
58}
59
Wing Licb88add2022-10-29 02:32:06 +010060static test_result_t test_init(unsigned int aff_level,
61 unsigned int suspend_type)
62{
63 if (aff_level > MPIDR_MAX_AFFLVL)
64 return TEST_RESULT_SKIPPED;
65
66 assert((suspend_type == PSTATE_TYPE_POWERDOWN) ||
67 (suspend_type == PSTATE_TYPE_STANDBY));
68
69 for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; ++i) {
70 /* Export these variables for the non-lead CPUs */
71 test_aff_level[i] = aff_level;
72 test_suspend_type[i] = suspend_type;
73 test_suspend_entry_time[i] =
74 PLAT_SUSPEND_ENTRY_TIME * PLATFORM_CORE_COUNT;
Charlie Barehamaf8934c2024-07-26 14:51:14 +010075 test_should_suspend[i] = true;
Wing Licb88add2022-10-29 02:32:06 +010076
77 /*
78 * All testcases in this file use the same arrays so it needs to
79 * be re-initialised each time.
80 */
81 tftf_init_event(&cpu_booted[i]);
82 tftf_init_event(&cpu_ready[i]);
Charlie Barehamaf8934c2024-07-26 14:51:14 +010083 tftf_init_event(&cpu_finished[i]);
Wing Licb88add2022-10-29 02:32:06 +010084 tftf_init_event(&event_received_wake_irq[i]);
85 requested_irq_received[i] = 0;
86 }
87
88 /* Ensure the above writes are seen before any read */
89 dmbsy();
90
91 return TEST_RESULT_SUCCESS;
92}
93
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020094/*
95 * Suspend the calling (non-lead) CPU.
96 * 1) Program a wake-up event to come out of suspend state
97 * 2) Suspend the CPU to the desired affinity level and power state (standby or
98 * powerdown)
99 * 3) Report success/failure of the suspend operation
100 */
101static test_result_t suspend_non_lead_cpu(void)
102{
103 unsigned int mpid = read_mpidr_el1();
104 unsigned int core_pos = platform_get_core_pos(mpid);
Wing Licb88add2022-10-29 02:32:06 +0100105 unsigned int aff_level = test_aff_level[core_pos];
106 unsigned int suspend_type = test_suspend_type[core_pos];
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200107 uint32_t power_state, stateid;
108 int rc, expected_return_val;
109 u_register_t flags;
110
111 tftf_timer_register_handler(requested_irq_handler);
112
Wing Licb88add2022-10-29 02:32:06 +0100113 /* Signal to the lead CPU that the calling CPU has entered the test */
114 tftf_send_event(&cpu_booted[core_pos]);
115
116 /* Wait for signal from the lead CPU before suspending itself */
117 tftf_wait_for_event(&cpu_ready[core_pos]);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200118
119 /* IRQs need to be disabled prior to programming the timer */
120 /* Preserve DAIF flags*/
121 flags = read_daif();
122 disable_irq();
123
Wing Licb88add2022-10-29 02:32:06 +0100124 rc = tftf_program_timer(test_suspend_entry_time[core_pos]);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200125 if (rc != 0) {
126 /* Restore previous DAIF flags */
127 write_daif(flags);
128 isb();
129 ERROR("Timer programming failed with error %d\n", rc);
130 return TEST_RESULT_FAIL;
131 }
132
Wing Licb88add2022-10-29 02:32:06 +0100133 expected_return_val = tftf_psci_make_composite_state_id(aff_level,
134 suspend_type,
135 &stateid);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200136
137 /*
138 * Suspend the calling CPU to the desired affinity level and power state
139 */
Wing Licb88add2022-10-29 02:32:06 +0100140 power_state = tftf_make_psci_pstate(aff_level, suspend_type, stateid);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200141 rc = tftf_cpu_suspend(power_state);
142
143 /* Restore previous DAIF flags */
144 write_daif(flags);
145 isb();
146
147 /* Wait until the IRQ wake interrupt is received */
148 while (!requested_irq_received[core_pos])
149 ;
150
151 tftf_send_event(&event_received_wake_irq[core_pos]);
152 tftf_timer_unregister_handler();
153
154 if (rc == expected_return_val)
155 return TEST_RESULT_SUCCESS;
156
157 tftf_testcase_printf("Wrong value: expected %i, got %i\n",
158 expected_return_val, rc);
159 return TEST_RESULT_FAIL;
160}
161
162/*
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100163 * Leave a non-load CPU running until the cpu_finished event is triggered.
164 */
165static test_result_t run_non_lead_cpu(void)
166{
167 unsigned int mpid = read_mpidr_el1();
168 unsigned int core_pos = platform_get_core_pos(mpid);
169
170 /* Signal to the lead CPU that the calling CPU has entered the test */
171 tftf_send_event(&cpu_booted[core_pos]);
172
173 /* Wait for signal from the lead CPU before suspending itself */
174 tftf_wait_for_event(&cpu_finished[core_pos]);
175
176 return TEST_RESULT_SUCCESS;
177}
178
179/*
180 * @brief: CPU suspend test to the desired affinity level and power state
181 * @param: Boolean flag to indicate when a suspend request should be denied.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200182 *
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100183 * Test do:
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200184 * 1) Power on all cores
185 * 2) Each core registers a wake-up event to come out of suspend state
186 * 3) Each core tries to enter suspend state
187 *
188 * The test is skipped if an error occurs during the bring-up of non-lead CPUs.
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100189 * Some cores can be left running be setting the test_should_suspend array.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200190 */
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100191static test_result_t test_psci_suspend(bool test_should_deny)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200192{
193 unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
194 unsigned int target_mpid, target_node;
195 unsigned int core_pos;
Wing Licb88add2022-10-29 02:32:06 +0100196 unsigned int aff_level, suspend_type;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200197 uint32_t power_state, stateid;
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100198 int rc, composite_state_rc, expected_return_val;
Wing Licb88add2022-10-29 02:32:06 +0100199 int aff_info;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200200 u_register_t flags;
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100201 test_result_t (*entry_point)(void);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200202
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200203 /*
204 * Preparation step: Power on all cores.
205 */
206 for_each_cpu(target_node) {
207 target_mpid = tftf_get_mpidr_from_node(target_node);
208 /* Skip lead CPU as it is already on */
209 if (target_mpid == lead_mpid)
210 continue;
211
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100212 core_pos = platform_get_core_pos(target_mpid);
213 if (test_should_suspend[core_pos]) {
214 entry_point = suspend_non_lead_cpu;
215 } else {
216 entry_point = run_non_lead_cpu;
217 }
218
219 rc = tftf_cpu_on(target_mpid, (uintptr_t) entry_point, 0);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200220 if (rc != PSCI_E_SUCCESS) {
221 tftf_testcase_printf(
222 "Failed to power on CPU 0x%x (%d)\n",
223 target_mpid, rc);
224 return TEST_RESULT_SKIPPED;
225 }
226 }
227
Wing Licb88add2022-10-29 02:32:06 +0100228 /* Wait for all non-lead CPUs to enter the test */
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200229 for_each_cpu(target_node) {
230 target_mpid = tftf_get_mpidr_from_node(target_node);
231 /* Skip lead CPU */
232 if (target_mpid == lead_mpid)
233 continue;
234
235 core_pos = platform_get_core_pos(target_mpid);
Wing Licb88add2022-10-29 02:32:06 +0100236 tftf_wait_for_event(&cpu_booted[core_pos]);
237 }
238
239 /* Signal to each non-lead CPU to suspend itself */
240 for_each_cpu(target_node) {
241 target_mpid = tftf_get_mpidr_from_node(target_node);
242 /* Skip lead CPU */
243 if (target_mpid == lead_mpid)
244 continue;
245
246 core_pos = platform_get_core_pos(target_mpid);
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100247 if (test_should_suspend[core_pos]) {
248 tftf_send_event(&cpu_ready[core_pos]);
249 waitms(PLAT_SUSPEND_ENTRY_TIME);
250 }
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200251 }
252
253 /* IRQs need to be disabled prior to programming the timer */
254 /* Preserve DAIF flags*/
255 flags = read_daif();
256 disable_irq();
257
258 /*
259 * Program the timer, this will serve as the
260 * wake-up event to come out of suspend state.
261 */
Wing Licb88add2022-10-29 02:32:06 +0100262 rc = tftf_program_timer(PLAT_SUSPEND_ENTRY_TIME * PLATFORM_CORE_COUNT);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200263 if (rc) {
264 /* Restore previous DAIF flags */
265 write_daif(flags);
266 isb();
267 ERROR("Timer programming failed with error %d\n", rc);
268 return TEST_RESULT_FAIL;
269 }
270
Wing Licb88add2022-10-29 02:32:06 +0100271 core_pos = platform_get_core_pos(lead_mpid);
272 aff_level = test_aff_level[core_pos];
273 suspend_type = test_suspend_type[core_pos];
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100274 composite_state_rc = tftf_psci_make_composite_state_id(aff_level,
Wing Licb88add2022-10-29 02:32:06 +0100275 suspend_type,
276 &stateid);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200277
278 /*
279 * Suspend the calling CPU to the desired affinity level and power state
280 */
Wing Licb88add2022-10-29 02:32:06 +0100281 power_state = tftf_make_psci_pstate(aff_level, suspend_type, stateid);
282 if (aff_level >= PSTATE_AFF_LVL_2)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200283 rc = tftf_cpu_suspend_save_sys_ctx(power_state);
284 else
285 rc = tftf_cpu_suspend(power_state);
286
287 /* Restore previous DAIF flags */
288 write_daif(flags);
289 isb();
290
291 /*
292 * Cancel the timer set up by lead CPU in case we have returned early
293 * due to invalid parameters or it will lead to spurious wake-up later.
294 */
295 tftf_cancel_timer();
296
297 /*
298 * Wait for all non-lead CPUs to receive IRQ_WAKE_SGI. This will also
299 * ensure that the lead CPU has received the system timer IRQ
300 * because SGI #IRQ_WAKE_SGI is sent only after that.
301 */
302 for_each_cpu(target_node) {
303 target_mpid = tftf_get_mpidr_from_node(target_node);
304 /* Skip lead CPU */
305 if (target_mpid == lead_mpid)
306 continue;
307
308 core_pos = platform_get_core_pos(target_mpid);
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100309 if (test_should_suspend[core_pos]) {
310 tftf_wait_for_event(&event_received_wake_irq[core_pos]);
311 }
312 }
313
314 if (test_should_deny) {
315 /*
316 * Signal to all non-lead CPUs that the test has finished.
317 */
318 for_each_cpu(target_node) {
319 target_mpid = tftf_get_mpidr_from_node(target_node);
320 /* Skip lead CPU */
321 if (target_mpid == lead_mpid)
322 continue;
323
324 core_pos = platform_get_core_pos(target_mpid);
325 tftf_send_event(&cpu_finished[core_pos]);
326 }
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200327 }
328
Wing Licb88add2022-10-29 02:32:06 +0100329 /* Wait for all non-lead CPUs to power down */
330 for_each_cpu(target_node) {
331 target_mpid = tftf_get_mpidr_from_node(target_node);
332 /* Skip lead CPU */
333 if (target_mpid == lead_mpid)
334 continue;
335
336 do {
337 aff_info = tftf_psci_affinity_info(target_mpid,
338 MPIDR_AFFLVL0);
339 } while (aff_info != PSCI_STATE_OFF);
340 }
341
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100342 expected_return_val = test_should_deny ? PSCI_E_DENIED : composite_state_rc;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200343 if (rc == expected_return_val)
344 return TEST_RESULT_SUCCESS;
345
346 tftf_testcase_printf("Wrong value: expected %i, got %i\n",
347 expected_return_val, rc);
348 return TEST_RESULT_FAIL;
349}
350
351/*
Wing Licb88add2022-10-29 02:32:06 +0100352 * @Test_Aim@ Suspend to the specified suspend type targeted at the specified
353 * affinity level
354 */
355static test_result_t test_psci_suspend_level(unsigned int aff_level,
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100356 unsigned int suspend_type,
357 bool should_deny)
Wing Licb88add2022-10-29 02:32:06 +0100358{
359 int rc;
360
361 rc = test_init(aff_level, suspend_type);
362 if (rc != TEST_RESULT_SUCCESS)
363 return rc;
364
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100365 return test_psci_suspend(should_deny);
Wing Licb88add2022-10-29 02:32:06 +0100366}
367
368/*
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200369 * @Test_Aim@ Suspend to powerdown state targeted at affinity level 0
370 */
371test_result_t test_psci_suspend_powerdown_level0(void)
372{
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100373 return test_psci_suspend_level(PSTATE_AFF_LVL_0,
374 PSTATE_TYPE_POWERDOWN,
375 false);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200376}
377
378/*
379 * @Test_Aim@ Suspend to standby state targeted at affinity level 0
380 */
381test_result_t test_psci_suspend_standby_level0(void)
382{
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100383 return test_psci_suspend_level(PSTATE_AFF_LVL_0,
384 PSTATE_TYPE_STANDBY,
385 false);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200386}
387
388/*
389 * @Test_Aim@ Suspend to powerdown state targeted at affinity level 1
390 */
391test_result_t test_psci_suspend_powerdown_level1(void)
392{
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100393 return test_psci_suspend_level(PSTATE_AFF_LVL_1,
394 PSTATE_TYPE_POWERDOWN,
395 false);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200396}
397
398/*
399 * @Test_Aim@ Suspend to standby state targeted at affinity level 1
400 */
401test_result_t test_psci_suspend_standby_level1(void)
402{
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100403 return test_psci_suspend_level(PSTATE_AFF_LVL_1,
404 PSTATE_TYPE_STANDBY,
405 false);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200406}
407
408/*
409 * @Test_Aim@ Suspend to powerdown state targeted at affinity level 2
410 */
411test_result_t test_psci_suspend_powerdown_level2(void)
412{
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100413 return test_psci_suspend_level(PSTATE_AFF_LVL_2,
414 PSTATE_TYPE_POWERDOWN,
415 false);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200416}
417
418/*
419 * @Test_Aim@ Suspend to standby state targeted at affinity level 2
420 */
421test_result_t test_psci_suspend_standby_level2(void)
422{
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100423 return test_psci_suspend_level(PSTATE_AFF_LVL_2,
424 PSTATE_TYPE_STANDBY,
425 false);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200426}
427
428/*
429 * @Test_Aim@ Suspend to powerdown state targeted at affinity level 3
430 */
431test_result_t test_psci_suspend_powerdown_level3(void)
432{
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100433 return test_psci_suspend_level(PSTATE_AFF_LVL_3,
434 PSTATE_TYPE_POWERDOWN,
435 false);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200436}
437
438/*
439 * @Test_Aim@ Suspend to standby state targeted at affinity level 3
440 */
441test_result_t test_psci_suspend_standby_level3(void)
442{
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100443 return test_psci_suspend_level(PSTATE_AFF_LVL_3,
444 PSTATE_TYPE_STANDBY,
445 false);
Wing Licb88add2022-10-29 02:32:06 +0100446}
447
Imre Kis6e191232025-08-06 16:28:57 +0200448static test_result_t check_osi_mode_support(void) {
449 int feat;
450
451 feat = tftf_get_psci_feature_info(SMC_PSCI_CPU_SUSPEND);
452 if (feat < 0)
453 return TEST_RESULT_FAIL;
454 if ((feat & (1 << CPU_SUSPEND_FEAT_OS_INIT_MODE_SHIFT)) == 0)
455 return TEST_RESULT_SKIPPED;
456
457 return TEST_RESULT_SUCCESS;
458}
459
Wing Licb88add2022-10-29 02:32:06 +0100460/*
461 * @Test_Aim@ Suspend to the specified suspend type targeted at affinity level 0
462 * in OS-initiated mode
463 */
464static test_result_t test_psci_suspend_level0_osi(unsigned int suspend_type)
465{
466 int err, rc;
467
Imre Kis6e191232025-08-06 16:28:57 +0200468 err = check_osi_mode_support();
469 if (err != TEST_RESULT_SUCCESS)
470 return err;
471
Wing Licb88add2022-10-29 02:32:06 +0100472 err = tftf_psci_set_suspend_mode(PSCI_OS_INIT);
473 if (err != PSCI_E_SUCCESS)
474 return TEST_RESULT_FAIL;
475
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100476 rc = test_psci_suspend_level(PSTATE_AFF_LVL_0, suspend_type, false);
Wing Licb88add2022-10-29 02:32:06 +0100477
478 err = tftf_psci_set_suspend_mode(PSCI_PLAT_COORD);
479 if (err != PSCI_E_SUCCESS)
480 return TEST_RESULT_FAIL;
481
482 return rc;
483}
484
485/*
486 * @Test_Aim@ Suspend to powerdown state targeted at affinity level 0 in
487 * OS-initiated mode
488 */
489test_result_t test_psci_suspend_powerdown_level0_osi(void)
490{
491 return test_psci_suspend_level0_osi(PSTATE_TYPE_POWERDOWN);
492}
493
494/*
495 * @Test_Aim@ Suspend to standby state targeted at affinity level 0 in
496 * OS-initiated mode
497 */
498test_result_t test_psci_suspend_standby_level0_osi(void)
499{
500 return test_psci_suspend_level0_osi(PSTATE_TYPE_STANDBY);
501}
502
503/*
504 * @Test_Aim@ Suspend to the specified suspend type targeted at affinity level 1
505 * in OS-initiated mode
506 */
507static test_result_t test_psci_suspend_level1_osi(unsigned int suspend_type)
508{
509 unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
510 unsigned int lead_lvl_1_node =
511 tftf_get_parent_node_from_mpidr(lead_mpid, PSTATE_AFF_LVL_1);
512 unsigned int target_mpid, target_node, lvl_1_node, lvl_1_end_node;
513 unsigned int core_pos;
514 tftf_pwr_domain_node_t pd_node;
515 int err, rc;
516
Imre Kis6e191232025-08-06 16:28:57 +0200517 err = check_osi_mode_support();
518 if (err != TEST_RESULT_SUCCESS)
519 return err;
520
Wing Licb88add2022-10-29 02:32:06 +0100521 err = test_init(PSTATE_AFF_LVL_1, suspend_type);
522 if (err != TEST_RESULT_SUCCESS)
523 return err;
524
525 err = tftf_psci_set_suspend_mode(PSCI_OS_INIT);
526 if (err != PSCI_E_SUCCESS)
527 return TEST_RESULT_FAIL;
528
529 for_each_power_domain_idx(lvl_1_node, PSTATE_AFF_LVL_1) {
530 pd_node = tftf_pd_nodes[lvl_1_node];
531 lvl_1_end_node = pd_node.cpu_start_node + pd_node.ncpus - 1;
532
533 for_each_cpu_in_power_domain(target_node, lvl_1_node) {
534 target_mpid = tftf_get_mpidr_from_node(target_node);
535 /* Skip lead CPU as it is already on */
536 if (target_mpid == lead_mpid)
537 continue;
538
539 core_pos = platform_get_core_pos(target_mpid);
540 if (target_node == lvl_1_end_node &&
541 lvl_1_node != lead_lvl_1_node) {
542 test_aff_level[core_pos] = PSTATE_AFF_LVL_1;
543 } else {
544 test_aff_level[core_pos] = PSTATE_AFF_LVL_0;
545 }
546 }
547 }
548
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100549 rc = test_psci_suspend(false);
Wing Licb88add2022-10-29 02:32:06 +0100550
551 err = tftf_psci_set_suspend_mode(PSCI_PLAT_COORD);
552 if (err != PSCI_E_SUCCESS)
553 return TEST_RESULT_FAIL;
554
555 return rc;
556}
557
558/*
559 * @Test_Aim@ Suspend to powerdown state targeted at affinity level 1 in
560 * OS-initiated mode
561 */
562test_result_t test_psci_suspend_powerdown_level1_osi(void)
563{
564 return test_psci_suspend_level1_osi(PSTATE_TYPE_POWERDOWN);
565}
566
567/*
568 * @Test_Aim@ Suspend to standby state targeted at affinity level 1 in
569 * OS-initiated mode
570 */
571test_result_t test_psci_suspend_standby_level1_osi(void)
572{
573 return test_psci_suspend_level1_osi(PSTATE_TYPE_STANDBY);
574}
575
576/*
577 * @Test_Aim@ Suspend to the specified suspend type targeted at affinity level 2
578 * in OS-initiated mode
579 */
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100580static test_result_t test_psci_suspend_level2_osi(unsigned int suspend_type,
581 bool should_deny)
Wing Licb88add2022-10-29 02:32:06 +0100582{
583 unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
584 unsigned int lead_lvl_1_node =
585 tftf_get_parent_node_from_mpidr(lead_mpid, PSTATE_AFF_LVL_1);
586 unsigned int lead_lvl_2_node =
587 tftf_get_parent_node_from_mpidr(lead_mpid, PSTATE_AFF_LVL_2);
588 unsigned int target_mpid, target_node;
589 unsigned int lvl_1_node, lvl_2_node;
590 unsigned int lvl_1_end_node, lvl_2_end_node;
591 unsigned int core_pos;
592 tftf_pwr_domain_node_t lvl_1_pd_node, lvl_2_pd_node;
593 int err, rc;
594
Imre Kis6e191232025-08-06 16:28:57 +0200595 err = check_osi_mode_support();
596 if (err != TEST_RESULT_SUCCESS)
597 return err;
598
Wing Licb88add2022-10-29 02:32:06 +0100599 err = test_init(PSTATE_AFF_LVL_2, suspend_type);
600 if (err != TEST_RESULT_SUCCESS)
601 return err;
602
603 err = tftf_psci_set_suspend_mode(PSCI_OS_INIT);
604 if (err != PSCI_E_SUCCESS)
605 return TEST_RESULT_FAIL;
606
607 for_each_power_domain_idx(lvl_2_node, PSTATE_AFF_LVL_2) {
608 lvl_2_pd_node = tftf_pd_nodes[lvl_2_node];
609 lvl_2_end_node =
610 lvl_2_pd_node.cpu_start_node + lvl_2_pd_node.ncpus - 1;
611
612 for_each_power_domain_idx(lvl_1_node, PSTATE_AFF_LVL_1) {
613 lvl_1_pd_node = tftf_pd_nodes[lvl_1_node];
614 if (lvl_1_pd_node.parent_node != lvl_2_node)
615 continue;
616
617 lvl_1_end_node =
618 lvl_1_pd_node.cpu_start_node +
619 lvl_1_pd_node.ncpus - 1;
620
621 for_each_cpu_in_power_domain(target_node, lvl_1_node) {
622 target_mpid =
623 tftf_get_mpidr_from_node(target_node);
624 /* Skip lead CPU as it is already on */
625 if (target_mpid == lead_mpid)
626 continue;
627
628 core_pos = platform_get_core_pos(target_mpid);
629 if (target_node == lvl_1_end_node &&
630 target_node == lvl_2_end_node &&
631 lvl_2_node != lead_lvl_2_node) {
632 test_aff_level[core_pos] =
633 PSTATE_AFF_LVL_2;
634 } else if (target_node == lvl_1_end_node &&
635 lvl_1_node != lead_lvl_1_node) {
636 test_aff_level[core_pos] =
637 PSTATE_AFF_LVL_1;
638 } else {
639 test_aff_level[core_pos] =
640 PSTATE_AFF_LVL_0;
641 }
642 }
643 }
644
645 }
646
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100647 rc = test_psci_suspend(should_deny);
648
649 err = tftf_psci_set_suspend_mode(PSCI_PLAT_COORD);
650 if (err != PSCI_E_SUCCESS)
651 return TEST_RESULT_FAIL;
652
653 return rc;
654}
655
656/*
657 * @Test_Aim@ Suspend to powerdown state targeted at affinity level 2, in
658 * OS-Initiated mode, with two CPUs left running, so the suspend call should be
659 * denied.
660 *
661 * This test was added to catch a specific bug. The bug made it so that the
662 * function only checked one power domain when suspending to affinity level 2.
663 * This meant that if there was a cpu running outside the power domain of the
664 * calling CPU, the suspend request would be allowed. But in this case, the
665 * request should be denied.
666 */
667test_result_t test_psci_suspend_invalid(void)
668{
669 unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
670 unsigned int lead_core_pos = platform_get_core_pos(lead_mpid);
671 unsigned int running_mpid, running_core_pos;
672 int32_t err;
673 test_result_t rc;
674
675 /*
676 * This test requires at least two clusters.
677 */
678 if (tftf_get_total_aff_count(MPIDR_AFFLVL1) < 2) {
679 return TEST_RESULT_SKIPPED;
680 }
681
Imre Kis6e191232025-08-06 16:28:57 +0200682 err = check_osi_mode_support();
683 if (err != TEST_RESULT_SUCCESS)
684 return err;
685
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100686 /*
687 * Non-lead CPUs should be suspended, and the lead CPU should
688 * attempt to supend to level 2. As there is a cpu running in another
689 * cluster, in this case the request from the lead CPU will be denied.
690 */
691
692 rc = test_init(MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN);
693 if (rc != TEST_RESULT_SUCCESS)
694 return rc;
695
696 test_aff_level[lead_core_pos] = MPIDR_AFFLVL2;
697
698 running_mpid = tftf_find_any_cpu_in_other_cluster(lead_mpid);
699 assert(running_mpid != INVALID_MPID);
700 running_core_pos = platform_get_core_pos(running_mpid);
701 test_should_suspend[running_core_pos] = false;
702
703 err = tftf_psci_set_suspend_mode(PSCI_OS_INIT);
704 if (err != PSCI_E_SUCCESS)
705 return TEST_RESULT_FAIL;
706
707 rc = test_psci_suspend(true);
Wing Licb88add2022-10-29 02:32:06 +0100708
709 err = tftf_psci_set_suspend_mode(PSCI_PLAT_COORD);
710 if (err != PSCI_E_SUCCESS)
711 return TEST_RESULT_FAIL;
712
713 return rc;
714}
715
716/*
717 * @Test_Aim@ Suspend to powerdown state targeted at affinity level 2 in
718 * OS-initiated mode
719 */
720test_result_t test_psci_suspend_powerdown_level2_osi(void)
721{
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100722 return test_psci_suspend_level2_osi(PSTATE_TYPE_POWERDOWN, false);
Wing Licb88add2022-10-29 02:32:06 +0100723}
724
725/*
726 * @Test_Aim@ Suspend to standby state targeted at affinity level 2 in
727 * OS-initiated mode
728 */
729test_result_t test_psci_suspend_standby_level2_osi(void)
730{
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100731 return test_psci_suspend_level2_osi(PSTATE_TYPE_STANDBY, false);
Wing Licb88add2022-10-29 02:32:06 +0100732}
733
734/*
735 * @Test_Aim@ Suspend to the specified suspend type targeted at affinity level 3
736 * in OS-initiated mode
737 */
738static test_result_t test_psci_suspend_level3_osi(unsigned int suspend_type)
739{
740 unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
741 unsigned int lead_lvl_1_node =
742 tftf_get_parent_node_from_mpidr(lead_mpid, PSTATE_AFF_LVL_1);
743 unsigned int lead_lvl_2_node =
744 tftf_get_parent_node_from_mpidr(lead_mpid, PSTATE_AFF_LVL_2);
745 unsigned int lead_lvl_3_node =
746 tftf_get_parent_node_from_mpidr(lead_mpid, PSTATE_AFF_LVL_3);
747 unsigned int target_mpid, target_node;
748 unsigned int lvl_1_node, lvl_2_node, lvl_3_node;
749 unsigned int lvl_1_end_node, lvl_2_end_node, lvl_3_end_node;
750 unsigned int core_pos;
751 tftf_pwr_domain_node_t lvl_1_pd_node, lvl_2_pd_node, lvl_3_pd_node;
752 int err, rc;
753
Imre Kis6e191232025-08-06 16:28:57 +0200754 err = check_osi_mode_support();
755 if (err != TEST_RESULT_SUCCESS)
756 return err;
757
Wing Licb88add2022-10-29 02:32:06 +0100758 err = test_init(PSTATE_AFF_LVL_3, PSTATE_TYPE_POWERDOWN);
759 if (err != TEST_RESULT_SUCCESS)
760 return err;
761
762 err = tftf_psci_set_suspend_mode(PSCI_OS_INIT);
763 if (err != PSCI_E_SUCCESS)
764 return TEST_RESULT_FAIL;
765
766 for_each_power_domain_idx(lvl_3_node, PSTATE_AFF_LVL_3) {
767 lvl_3_pd_node = tftf_pd_nodes[lvl_3_node];
768 lvl_3_end_node =
769 lvl_3_pd_node.cpu_start_node + lvl_3_pd_node.ncpus - 1;
770
771 for_each_power_domain_idx(lvl_2_node, PSTATE_AFF_LVL_2) {
772 lvl_2_pd_node = tftf_pd_nodes[lvl_2_node];
773 if (lvl_2_pd_node.parent_node != lvl_3_node)
774 continue;
775
776 lvl_2_end_node =
777 lvl_2_pd_node.cpu_start_node + lvl_2_pd_node.ncpus - 1;
778
779 for_each_power_domain_idx(lvl_1_node, PSTATE_AFF_LVL_1) {
780 lvl_1_pd_node = tftf_pd_nodes[lvl_1_node];
781 if (lvl_1_pd_node.parent_node != lvl_2_node)
782 continue;
783
784 lvl_1_end_node =
785 lvl_1_pd_node.cpu_start_node +
786 lvl_1_pd_node.ncpus - 1;
787
788 for_each_cpu_in_power_domain(target_node, lvl_1_node) {
789 target_mpid =
790 tftf_get_mpidr_from_node(target_node);
791 /* Skip lead CPU as it is already on */
792 if (target_mpid == lead_mpid)
793 continue;
794
795 core_pos = platform_get_core_pos(target_mpid);
796 if (target_node == lvl_1_end_node &&
797 target_node == lvl_2_end_node &&
798 target_node == lvl_3_end_node &&
799 lvl_3_node != lead_lvl_3_node) {
800 test_aff_level[core_pos] =
801 PSTATE_AFF_LVL_3;
802 }
803 if (target_node == lvl_1_end_node &&
804 target_node == lvl_2_end_node &&
805 lvl_2_node != lead_lvl_2_node) {
806 test_aff_level[core_pos] =
807 PSTATE_AFF_LVL_2;
808 } else if (target_node == lvl_1_end_node &&
809 lvl_1_node != lead_lvl_1_node) {
810 test_aff_level[core_pos] =
811 PSTATE_AFF_LVL_1;
812 } else {
813 test_aff_level[core_pos] =
814 PSTATE_AFF_LVL_0;
815 }
816 }
817 }
818
819 }
820 }
821
Charlie Barehamaf8934c2024-07-26 14:51:14 +0100822 rc = test_psci_suspend(false);
Wing Licb88add2022-10-29 02:32:06 +0100823
824 err = tftf_psci_set_suspend_mode(PSCI_PLAT_COORD);
825 if (err != PSCI_E_SUCCESS)
826 return TEST_RESULT_FAIL;
827
828 return rc;
829}
830
831/*
832 * @Test_Aim@ Suspend to powerdown state targeted at affinity level 3 in
833 * OS-initiated mode
834 */
835test_result_t test_psci_suspend_powerdown_level3_osi(void)
836{
837 return test_psci_suspend_level3_osi(PSTATE_TYPE_POWERDOWN);
838}
839
840/*
841 * @Test_Aim@ Suspend to standby state targeted at affinity level 3 in
842 * OS-initiated mode
843 */
844test_result_t test_psci_suspend_standby_level3_osi(void)
845{
846 return test_psci_suspend_level3_osi(PSTATE_TYPE_STANDBY);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200847}