blob: 6e7f3f70fd8f4df2bebc1255ecb29bc8db2ea745 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
Boyan Karatotev794b0ac2025-06-20 13:13:29 +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>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02009#include <assert.h>
Antonio Nino Diaz09a00ef2019-01-11 13:12:58 +000010#include <drivers/arm/arm_gic.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020011#include <events.h>
12#include <irq.h>
13#include <plat_topology.h>
14#include <platform.h>
15#include <power_management.h>
16#include <psci.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020017#include <test_helpers.h>
18#include <tftf_lib.h>
19
20/* Special value used to terminate the array of expected return values */
21#define END_OF_EXPECTED_VALUE 0xDEADBEEF
Antonio Nino Diaz855b0b22018-11-23 13:19:33 +000022
23/* TODO: Remove assumption that affinity levels always map to power levels. */
24#define MPIDR_CLUSTER_ID(mpid) MPIDR_AFF_ID(mpid, 1)
25#define MPIDR_CPU_ID(mpid) MPIDR_AFF_ID(mpid, 0)
26
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020027/*
28 * Event used by test test_affinity_info_level0_powerdown() to synchronise
29 * CPUs
30 */
31static event_t cpu_about_to_suspend;
32static unsigned int psci_version;
33
34/*
35 * `expected_values` should contain an array of expected return values
36 * terminated by `END_OF_EXPECTED_VALUE`. If 'actual_value' exists in
37 * one of 'expected_values' then return a test success.
38 * Otherwise, print an error message in the test report and report a test
39 * failure.
40 */
41static test_result_t get_test_result(const int *expected_values, int actual_value)
42{
43 const int *expected_val_list;
44
45 expected_val_list = expected_values;
46 while (*expected_val_list != END_OF_EXPECTED_VALUE) {
47 if (*expected_val_list == actual_value)
48 return TEST_RESULT_SUCCESS;
49 expected_val_list++;
50 }
51
52 expected_val_list = expected_values;
53 tftf_testcase_printf("Unexpected return value: %i Expected values are:",
54 actual_value);
55 while (*expected_val_list != END_OF_EXPECTED_VALUE) {
56 tftf_testcase_printf("%i ", *expected_val_list);
57 expected_val_list++;
58 }
59 tftf_testcase_printf("\n");
60
61 return TEST_RESULT_FAIL;
62}
63
64/*
65 * @Test_Aim@ Test PSCI AFFINITY_INFO targeted at affinity level 0 on online CPU
66 *
67 * Call PSCI AFFINITY_INFO targeted at affinity level 0 on lead CPU.
68 * Expect the PSCI implementation to report that the affinity instance is on.
69 */
70test_result_t test_affinity_info_level0_on(void)
71{
72 unsigned int mpid = read_mpidr_el1() & MPID_MASK;
73 int32_t aff_info;
74 int expected_values[] = {PSCI_STATE_ON, END_OF_EXPECTED_VALUE};
75
76 aff_info = tftf_psci_affinity_info(mpid, MPIDR_AFFLVL0);
77 return get_test_result(expected_values, aff_info);
78}
79
80/*
81 * @Test_Aim@ Test PSCI AFFINITY_INFO targeted at affinity level 0 on offline CPU
82 *
83 * Call PSCI AFFINITY_INFO targeted at affinity level 0 on all non-lead CPUs.
84 * Expect the PSCI implementation to report that the affinity instances are off.
85 *
86 * This test needs 2 CPUs to run. It will be skipped on a single core platform.
87 */
88test_result_t test_affinity_info_level0_off(void)
89{
90 unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
91 unsigned int target_mpid, target_node;
92 int32_t aff_info;
93 test_result_t ret = TEST_RESULT_SUCCESS;
94 int expected_values[] = {PSCI_STATE_OFF, END_OF_EXPECTED_VALUE};
95
96 SKIP_TEST_IF_LESS_THAN_N_CPUS(2);
97
98 for_each_cpu(target_node) {
99 target_mpid = tftf_get_mpidr_from_node(target_node);
100 /* Skip lead CPU, as it is powered on */
101 if (target_mpid == lead_mpid)
102 continue;
103
104 aff_info = tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0);
105 if (get_test_result(expected_values, aff_info)
106 == TEST_RESULT_FAIL) {
107 ret = TEST_RESULT_FAIL;
108 }
109 }
110
111 return ret;
112}
113
114/*
115 * @Test_Aim@ Test PSCI AFFINITY_INFO targeted at affinity level 1 on online cluster
116 *
117 * Call PSCI AFFINITY_INFO targeted at affinity level 1 on the lead cluster
118 * (i.e. the cluster to which the lead CPU belongs to).
119 * PSCI implementation prior to PSCI 1.0 needs to report that the cluster is on
120 * and others can also return INVALID_PARAMETERS.
121 */
122test_result_t test_affinity_info_level1_on(void)
123{
124 unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
125 unsigned int target_mpid;
126 int32_t aff_info;
127 int expected_values[3];
128
129 /*
130 * Minimum version of PSCI is 0.2, uses this info to decide if
131 * tftf_get_psci_version() needs to be called or not.
132 */
133 if (!psci_version)
134 psci_version = tftf_get_psci_version();
135
136 /*
137 * From PSCI version 1.0 onwards, Trusted Firmware-A may or may not
138 * track affinity levels greater than zero.
139 */
140 if (!(psci_version & PSCI_MAJOR_VER_MASK)) {
141 expected_values[0] = PSCI_STATE_ON;
142 expected_values[1] = END_OF_EXPECTED_VALUE;
143 } else {
144 expected_values[0] = PSCI_STATE_ON;
145 expected_values[1] = PSCI_E_INVALID_PARAMS;
146 expected_values[2] = END_OF_EXPECTED_VALUE;
147 }
148
149 /*
150 * Build an MPID corresponding to the lead cluster. Set the affinity
151 * level0 bits to some arbitrary value that doesn't correspond to any
152 * CPU on the platform. The PSCI implementation should ignore the
153 * affinity 0 field.
154 */
155 target_mpid = (lead_mpid & MPIDR_CLUSTER_MASK) | 0xE1;
156 aff_info = tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL1);
157 return get_test_result(expected_values, aff_info);
158}
159
160/*
161 * @Test_Aim@ Test PSCI AFFINITY_INFO targeted at affinity level 1 on offline cluster
162 *
163 * Call PSCI AFFINITY_INFO targeted at affinity level 1 on a non-lead cluster
164 * (i.e. another cluster than the one to which the lead CPU belongs to).
165 * PSCI implementation prior to PSCI 1.0 needs to report that the cluster is OFF
166 * and others can also return INVALID_PARAMETERS.
167 *
168 * This test needs 2 clusters to run. It will be skipped on a single cluster
169 * platform.
170 */
171test_result_t test_affinity_info_level1_off(void)
172{
173 unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
174 unsigned int target_mpid;
175 int32_t aff_info;
176 unsigned int cluster_id;
177 int expected_values[3];
178
179 SKIP_TEST_IF_LESS_THAN_N_CLUSTERS(2);
180
181 for (cluster_id = 0;
182 cluster_id < tftf_get_total_clusters_count();
183 ++cluster_id) {
184 if (cluster_id != MPIDR_CLUSTER_ID(lead_mpid))
185 break;
186 }
187 assert(cluster_id != tftf_get_total_clusters_count());
188
189
190 /*
191 * Minimum version of PSCI is 0.2, uses this info to decide if
192 * tftf_get_psci_version() needs to be called or not.
193 */
194 if (!psci_version)
195 psci_version = tftf_get_psci_version();
196
197 /*
198 * From PSCI version 1.0 onwards, Trusted Firmware-A may or may not
199 * track affinity levels greater than zero.
200 */
201 if (!(psci_version & PSCI_MAJOR_VER_MASK)) {
202 expected_values[0] = PSCI_STATE_OFF;
203 expected_values[1] = END_OF_EXPECTED_VALUE;
204 } else {
205 expected_values[0] = PSCI_STATE_OFF;
206 expected_values[1] = PSCI_E_INVALID_PARAMS;
207 expected_values[2] = END_OF_EXPECTED_VALUE;
208 }
209
210 /*
211 * Build an MPID corresponding to a non-lead cluster. Set the affinity
212 * level0 bits to some arbitrary value that doesn't correspond to any
213 * CPU on the platform. The PSCI implementation should ignore the
214 * affinity 0 field.
215 */
Javier Almansa Sobrino109d5c12020-09-04 12:52:23 +0100216#if PLAT_MAX_PE_PER_CPU > 1
Alexei Fedorov0f305472019-10-29 14:06:54 +0000217 target_mpid = make_mpid(cluster_id, 0, 0xE1);
218#else
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200219 target_mpid = make_mpid(cluster_id, 0xE1);
Alexei Fedorov0f305472019-10-29 14:06:54 +0000220#endif
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200221 aff_info = tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL1);
222 return get_test_result(expected_values, aff_info);
223}
224
225/*
226 * @Test_Aim@ Test PSCI AFFINITY_INFO targeted at affinity level 2
227 *
228 * For PSCI implementations prior to PSCI 1.0 , the expected return value
229 * depends on the the maximum affinity level that the power management
230 * operations can apply to on this platform.
231 * - If the platform doesn't have an affinity level 2 then expect the PSCI
232 * implementation to report that it received invalid parameters.
233 * - If affinity level 2 exists then expect the PSCI implementation to report
234 * that the affinity instance is on.
235 *
236 * From PSCI 1.0 onwards, it can also return either INVALID_PARMETERS
237 */
238test_result_t test_affinity_info_level2(void)
239{
240 int expected_values[3];
241 unsigned int target_mpid;
242 int32_t aff_info;
243
244 /*
245 * Minimum version of PSCI is 0.2, uses this info to decide if
246 * tftf_get_psci_version() needs to be called or not.
247 */
248 if (!psci_version)
249 psci_version = tftf_get_psci_version();
250
251 expected_values[0] = (PLATFORM_MAX_AFFLVL >= 2)
252 ? PSCI_STATE_ON
253 : PSCI_E_INVALID_PARAMS;
254
255 /*
256 * From PSCI version 1.0 onwards, Trusted Firmware-A may or may not
257 * track affinity levels greater than zero.
258 */
259 if (!(psci_version & PSCI_MAJOR_VER_MASK)) {
260 expected_values[1] = END_OF_EXPECTED_VALUE;
261 } else {
262 expected_values[1] = PSCI_E_INVALID_PARAMS;
263 expected_values[2] = END_OF_EXPECTED_VALUE;
264 }
265
266 /*
267 * Build an MPID corresponding to the lead affinity instance at level 2.
268 * Set the affinity level0 & level1 bits to some arbitrary values that
269 * don't correspond to any affinity instance on the platform. The PSCI
270 * implementation should ignore the affinity 0 & 1 fields.
271 */
272 target_mpid = read_mpidr_el1() & (MPIDR_AFFLVL_MASK << MPIDR_AFF_SHIFT(2));
273 target_mpid |= 0xAB << MPIDR_AFF1_SHIFT;
274 target_mpid |= 0xE1 << MPIDR_AFF0_SHIFT;
275
276 aff_info = tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL2);
277 return get_test_result(expected_values, aff_info);
278}
279
280/*
281 * @Test_Aim@ Test PSCI AFFINITY_INFO targeted at affinity level 3
282 *
283 * For PSCI implementations prior to PSCI 1.0 , the expected return value
284 * depends on the maximum affinity level that the power management
285 * operations can apply to on this platform.
286 * - If the platform doesn't have an affinity level 3 then expect the PSCI
287 * implementation to report that it received invalid parameters.
288 * - If affinity level 3 exists then expect the PSCI implementation to report
289 * that the affinity instance is on.
290 *
291 * From PSCI 1.0 onwards, it can also return INVALID_PARMETERS
292 */
293test_result_t test_affinity_info_level3(void)
294{
Deepika Bhavnanic249d5e2020-02-06 16:29:45 -0600295#ifdef __aarch64__
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200296 int expected_values[3];
297 uint64_t target_mpid;
298 int32_t aff_info;
299
300 /*
301 * Minimum version of PSCI is 0.2, uses this info to decide if
302 * tftf_get_psci_version() needs to be called or not.
303 */
304 if (!psci_version)
305 psci_version = tftf_get_psci_version();
306
307 expected_values[0] = (PLATFORM_MAX_AFFLVL == 3)
308 ? PSCI_STATE_ON
309 : PSCI_E_INVALID_PARAMS;
310
311 /*
312 * From PSCI version 1.0 onwards, Trusted Firmware-A may or may not
313 * track affinity levels greater than zero.
314 */
315 if (!(psci_version & PSCI_MAJOR_VER_MASK)) {
316 expected_values[1] = END_OF_EXPECTED_VALUE;
317 } else {
318 expected_values[1] = PSCI_E_INVALID_PARAMS;
319 expected_values[2] = END_OF_EXPECTED_VALUE;
320 }
321
322 /*
323 * Build an MPID corresponding to the lead affinity instance at level 3.
324 * Set the affinity level0/level1/level2 bits to some arbitrary values
325 * that don't correspond to any affinity instance on the platform. The
326 * PSCI implementation should ignore the affinity 0, 1 & 2 fields.
327 */
328 target_mpid = read_mpidr_el1();
329 target_mpid &= ((uint64_t) MPIDR_AFFLVL_MASK) << MPIDR_AFF_SHIFT(3);
330 target_mpid |= 0xD2 << MPIDR_AFF2_SHIFT;
331 target_mpid |= 0xAB << MPIDR_AFF1_SHIFT;
332 target_mpid |= 0xE1 << MPIDR_AFF0_SHIFT;
333
334 aff_info = tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL3);
335 return get_test_result(expected_values, aff_info);
336#else
337 return TEST_RESULT_SKIPPED;
338#endif
339}
340
341/*
342 * Suspend to powerdown the calling CPU.
343 *
344 * 1) Enable SGI #0. This SGI will be sent by the lead CPU to wake this CPU.
345 * 2) Suspend the CPU.
346 * 3) Report success/failure of the suspend operation.
347 */
348static test_result_t suspend_to_powerdown(void)
349{
350 uint32_t power_state, stateid;
351 int psci_ret, expected_return_val;
352
353 /*
354 * Enable reception of SGI 0 on the calling CPU.
355 * SGI 0 will serve as the wake-up event to come out of suspend.
356 */
Boyan Karatotev6d144db2025-06-23 15:04:53 +0100357 tftf_irq_enable_sgi(IRQ_NS_SGI_0, GIC_HIGHEST_NS_PRIORITY);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200358
359 expected_return_val = tftf_psci_make_composite_state_id(
360 PSTATE_AFF_LVL_0, PSTATE_TYPE_POWERDOWN, &stateid);
361
362 /* Need at least 1 power down state defined at level 0 */
363 if (expected_return_val != PSCI_E_SUCCESS)
364 return TEST_RESULT_SKIPPED;
365
366 /*
367 * Suspend the calling CPU to the desired affinity level and power state
368 */
369 power_state = tftf_make_psci_pstate(PSTATE_AFF_LVL_0,
370 PSTATE_TYPE_POWERDOWN,
371 stateid);
372
373 /*
374 * Notify the lead CPU that the calling CPU is about to suspend itself
375 */
376 tftf_send_event(&cpu_about_to_suspend);
377
378 psci_ret = tftf_cpu_suspend(power_state);
379
Boyan Karatotev6d144db2025-06-23 15:04:53 +0100380 tftf_irq_disable_sgi(IRQ_NS_SGI_0);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200381
382 if (psci_ret != PSCI_E_SUCCESS) {
383 tftf_testcase_printf("Failed to suspend (%i)\n", psci_ret);
384 return TEST_RESULT_FAIL;
385 }
386
387 return TEST_RESULT_SUCCESS;
388}
389
390/*
391 * @Test_Aim@ Test PSCI AFFINITY_INFO targeted at affinity level 0 on a
392 * suspended CPU
393 *
394 * A CPU that has been physically powered down as a result of a call to
395 * CPU_SUSPEND must be reported as ON by the AFFINITY_INFO call. This test
396 * aims at verifying this behaviour.
397 *
398 * This test needs 2 CPUs to run. It will be skipped on a single core platform.
399 * It will also be skipped if an error is encountered during the bring-up of the
400 * non-lead CPU.
401 */
402test_result_t test_affinity_info_level0_powerdown(void)
403{
404 unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
405 unsigned int target_mpid, target_core_pos;
406 int psci_ret;
407 int32_t aff_info;
408 test_result_t ret;
409 int expected_values[] = {PSCI_STATE_ON, END_OF_EXPECTED_VALUE};
410
411 SKIP_TEST_IF_LESS_THAN_N_CPUS(2);
412
413 /*
414 * Preparation step:
415 * Find another CPU than the lead CPU and power it on.
416 */
417 target_mpid = tftf_find_any_cpu_other_than(lead_mpid);
418 assert(target_mpid != INVALID_MPID);
419 target_core_pos = platform_get_core_pos(target_mpid);
420
421 psci_ret = tftf_cpu_on(target_mpid, (uintptr_t) suspend_to_powerdown, 0);
422 if (psci_ret != PSCI_E_SUCCESS) {
423 tftf_testcase_printf("Failed to power on CPU 0x%x (%d)\n",
424 target_mpid, psci_ret);
425 return TEST_RESULT_SKIPPED;
426 }
427
428 /* Wait for the other CPU to initiate the suspend operation */
429 tftf_wait_for_event(&cpu_about_to_suspend);
430
431 /* Wait a bit for the CPU to really enter suspend state */
432 waitms(PLAT_SUSPEND_ENTRY_TIME);
433
434 /* Request status of the non-lead CPU while it is suspended */
435 aff_info = tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0);
436 ret = get_test_result(expected_values, aff_info);
437
438 /* Wake up non-lead CPU */
439 tftf_send_sgi(IRQ_NS_SGI_0, target_core_pos);
440
441 return ret;
442}