blob: 0cc43950d07ffa2cb8628ab6efb6c001706a8b05 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
Boyan Karatotev4e282422024-10-25 14:34:13 +01002 * Copyright (c) 2018-2024, Arm Limited. All rights reserved.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <amu.h>
8#include <arch.h>
Boyan Karatotev4e282422024-10-25 14:34:13 +01009#include <arch_features.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020010#include <arch_helpers.h>
11#include <assert.h>
12#include <debug.h>
13#include <irq.h>
14#include <plat_topology.h>
15#include <platform.h>
16#include <power_management.h>
17#include <tftf_lib.h>
18#include <timer.h>
19
Juan Pablo Condec3cf2da2024-04-01 13:57:19 -050020#define SUSPEND_TIME_1_SEC 1000
21#define MAX_MPMM_TEST_ITERATIONS 100000U
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020022
23static volatile int wakeup_irq_received[PLATFORM_CORE_COUNT];
24
25/* Dummy timer handler that sets a flag to check it has been called. */
26static int suspend_wakeup_handler(void *data)
27{
28 u_register_t core_mpid = read_mpidr_el1() & MPID_MASK;
29 unsigned int core_pos = platform_get_core_pos(core_mpid);
30
31 assert(wakeup_irq_received[core_pos] == 0);
32
33 wakeup_irq_received[core_pos] = 1;
34
35 return 0;
36}
37
38/*
39 * Helper function to suspend a CPU to power level 0 and wake it up with
40 * a timer.
41 */
42static test_result_t suspend_and_resume_this_cpu(void)
43{
44 uint32_t stateid;
45 int psci_ret;
46 test_result_t result = TEST_RESULT_SUCCESS;
47
48 u_register_t core_mpid = read_mpidr_el1() & MPID_MASK;
49 unsigned int core_pos = platform_get_core_pos(core_mpid);
50
51 /* Prepare wakeup timer. IRQs need to be enabled. */
52 wakeup_irq_received[core_pos] = 0;
53
54 tftf_timer_register_handler(suspend_wakeup_handler);
55
56 /* Program timer to fire interrupt after timer expires */
57 tftf_program_timer(SUSPEND_TIME_1_SEC);
58
59 /*
60 * Suspend the calling CPU to power level 0 and power
61 * state.
62 */
63 psci_ret = tftf_psci_make_composite_state_id(PSTATE_AFF_LVL_0,
64 PSTATE_TYPE_POWERDOWN,
65 &stateid);
66 if (psci_ret != PSCI_E_SUCCESS) {
67 mp_printf("Failed to make composite state ID @ CPU %d. rc = %x\n",
68 core_pos, psci_ret);
69 result = TEST_RESULT_FAIL;
70 } else {
71 unsigned int power_state = tftf_make_psci_pstate(PSTATE_AFF_LVL_0,
72 PSTATE_TYPE_POWERDOWN, stateid);
73 psci_ret = tftf_cpu_suspend(power_state);
74
75 if (!wakeup_irq_received[core_pos]) {
76 mp_printf("Didn't receive wakeup IRQ in CPU %d.\n",
77 core_pos);
78 result = TEST_RESULT_FAIL;
79 }
80
81 if (psci_ret != PSCI_E_SUCCESS) {
82 mp_printf("Failed to suspend from CPU %d. ret: %x\n",
83 core_pos, psci_ret);
84 result = TEST_RESULT_FAIL;
85 }
86 }
87
88 /* Wake up. Remove timer after waking up.*/
89 tftf_cancel_timer();
90 tftf_timer_unregister_handler();
91
92 return result;
93}
94
95/*
John Tsichritziscae91ca2019-05-12 16:06:09 +010096 * Helper function that checks whether the value of a group0 counter is valid
97 * or not. The first 3 counters (0,1,2) cannot have values of zero but the last
98 * counter that counts "memory stall cycles" can have a value of zero, under
99 * certain circumstances.
100 *
101 * Return values:
102 * 0 = valid counter value
103 * -1 = invalid counter value
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200104 */
John Tsichritziscae91ca2019-05-12 16:06:09 +0100105static int amu_group0_cnt_valid(unsigned int idx, uint64_t value)
106{
107 int answer = 0;
108
johpow01b7d752a2020-10-08 17:29:11 -0500109 if ((idx <= 2) && (value == 0)) {
John Tsichritziscae91ca2019-05-12 16:06:09 +0100110 answer = -1;
johpow01b7d752a2020-10-08 17:29:11 -0500111 }
John Tsichritziscae91ca2019-05-12 16:06:09 +0100112
113 return answer;
114}
115
116/*
117 * Check that group0 counters are valid. As EL3 has enabled the counters before
118 * the first entry to NS world, the counters should have increased by the time
119 * we reach this test case.
120 */
121test_result_t test_amu_valid_ctr(void)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200122{
johpow01b7d752a2020-10-08 17:29:11 -0500123 unsigned int i;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200124
johpow01b7d752a2020-10-08 17:29:11 -0500125 if (amu_get_version() == 0U) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200126 return TEST_RESULT_SKIPPED;
johpow01b7d752a2020-10-08 17:29:11 -0500127 }
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200128
129 /* If counters are not enabled, then skip the test */
johpow01b7d752a2020-10-08 17:29:11 -0500130 if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200131 return TEST_RESULT_SKIPPED;
johpow01b7d752a2020-10-08 17:29:11 -0500132 }
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200133
johpow01b7d752a2020-10-08 17:29:11 -0500134 for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
John Tsichritziscae91ca2019-05-12 16:06:09 +0100135 uint64_t value;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200136
John Tsichritziscae91ca2019-05-12 16:06:09 +0100137 value = amu_group0_cnt_read(i);
138 if (amu_group0_cnt_valid(i, value)) {
139 tftf_testcase_printf("Group0 counter %d has invalid value %lld\n", i, value);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200140 return TEST_RESULT_FAIL;
141 }
142 }
143
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200144 return TEST_RESULT_SUCCESS;
145}
146
147/*
148 * Check that the counters are non-decreasing during
149 * a suspend/resume cycle.
150 */
151test_result_t test_amu_suspend_resume(void)
152{
johpow01b7d752a2020-10-08 17:29:11 -0500153 uint64_t group0_ctrs[AMU_GROUP0_NR_COUNTERS];
154 unsigned int i;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200155
johpow01b7d752a2020-10-08 17:29:11 -0500156 if (amu_get_version() == 0U) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200157 return TEST_RESULT_SKIPPED;
johpow01b7d752a2020-10-08 17:29:11 -0500158 }
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200159
160 /* If counters are not enabled, then skip the test */
John Tsichritzis68759a82019-05-12 15:10:27 +0100161 if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200162 return TEST_RESULT_SKIPPED;
163
164 /* Save counters values before suspend */
johpow01b7d752a2020-10-08 17:29:11 -0500165 for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200166 group0_ctrs[i] = amu_group0_cnt_read(i);
johpow01b7d752a2020-10-08 17:29:11 -0500167 }
168
169 /*
170 * If FEAT_AMUv1p1 supported then make sure the save/restore works for
171 * virtual counter values. Write known values into the virtual offsets
172 * and then make sure they are still there after resume. The virtual
173 * offset registers are only accessible in AARCH64 mode in EL2 or EL3.
174 */
175#if __aarch64__
176 if (amu_get_version() >= ID_AA64PFR0_AMU_V1P1) {
177 /* Enabling voffsets in HCR_EL2. */
178 write_hcr_el2(read_hcr_el2() | HCR_AMVOFFEN_BIT);
179
180 /* Writing known values into voffset registers. */
181 amu_group0_voffset_write(0U, 0xDEADBEEF);
182 amu_group0_voffset_write(2U, 0xDEADBEEF);
183 amu_group0_voffset_write(3U, 0xDEADBEEF);
184
185#if AMU_GROUP1_NR_COUNTERS
186 u_register_t amcg1idr = read_amcg1idr_el0() >> 16;
187
188 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
189 if (((amcg1idr >> i) & 1U) != 0U) {
190 amu_group1_voffset_write(i, 0xDEADBEEF);
191 }
192 }
193#endif
194 }
195#endif
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200196
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200197 /* Suspend/resume current core */
198 suspend_and_resume_this_cpu();
199
200 /*
201 * Check if counter values are >= than the stored values.
202 * If they are not, the AMU context save/restore in EL3 is buggy.
203 */
204 for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) {
John Tsichritziscae91ca2019-05-12 16:06:09 +0100205 uint64_t value;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200206
John Tsichritziscae91ca2019-05-12 16:06:09 +0100207 value = amu_group0_cnt_read(i);
208 if (value < group0_ctrs[i]) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200209 tftf_testcase_printf("Invalid counter value: before: %llx, after: %llx\n",
210 (unsigned long long)group0_ctrs[i],
John Tsichritziscae91ca2019-05-12 16:06:09 +0100211 (unsigned long long)value);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200212 return TEST_RESULT_FAIL;
213 }
214 }
215
johpow01b7d752a2020-10-08 17:29:11 -0500216#if __aarch64__
217 if (amu_get_version() >= ID_AA64PFR0_AMU_V1P1) {
218 for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
219 if ((i != 1U) &&
220 (amu_group0_voffset_read(i) != 0xDEADBEEF)) {
221 tftf_testcase_printf(
222 "Invalid G0 voffset %u: 0x%llx\n", i,
223 amu_group0_voffset_read(i));
224 return TEST_RESULT_FAIL;
225 }
226 }
227
228#if AMU_GROUP1_NR_COUNTERS
229 u_register_t amcg1idr = read_amcg1idr_el0() >> 16;
230
231 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
232 if (((amcg1idr >> i) & 1U) != 0U) {
233 if (amu_group1_voffset_read(i) != 0xDEADBEEF) {
234 tftf_testcase_printf("Invalid G1 " \
235 "voffset %u: 0x%llx\n", i,
236 amu_group1_voffset_read(i));
237 return TEST_RESULT_FAIL;
238 }
239 }
240 }
241#endif
242 }
243#endif
244
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200245 return TEST_RESULT_SUCCESS;
246}
Juan Pablo Condec3cf2da2024-04-01 13:57:19 -0500247
248/*
249 * Check that group 1 counters read as 0 at ELs lower than EL3 when
250 * AMCR.CG1RZ is set.
251 */
252test_result_t test_amu_group1_raz(void)
253{
254/* Test on TC2 only, as MPMM not implemented in other platforms yet */
255#if PLAT_tc && (TARGET_PLATFORM == 2)
256 uint64_t counters_initial[AMU_GROUP1_NR_COUNTERS] = {0};
257 uint64_t counters_final[AMU_GROUP1_NR_COUNTERS] = {0};
258
259 for (unsigned int i = 0; i < amu_group1_num_counters(); i++) {
260 INFO("AMUEVTYPER1%x: 0x%llx\n", i, amu_group1_evtype_read(i));
261 counters_initial[i] = amu_group1_cnt_read(i);
262 }
263
264 for (int i = 0; i < MAX_MPMM_TEST_ITERATIONS; i++) {
265 // Instruction with activity count 1
266 __asm__ volatile("fmov d0,xzr");
267 __asm__ volatile("fmov d1,xzr");
268 __asm__ volatile("fmul d2,d0,d1");
269 __asm__ volatile("fmov d2,xzr");
270
271 __asm__ volatile("fmov d0,xzr");
272 __asm__ volatile("fmov d1,xzr");
273 __asm__ volatile("fmov d2,xzr");
274 __asm__ volatile("fmadd d3,d2,d1,d0");
275
276 // Instruction with activity count 2
277 __asm__ volatile("ptrue p0.s, ALL");
278 __asm__ volatile("index z10.s, #10,13");
279 __asm__ volatile("index z11.s, #12,7");
280 __asm__ volatile("ucvtf v10.4s, v10.4s");
281 __asm__ volatile("ucvtf v11.4s, v11.4s");
282 __asm__ volatile("fadd v0.4s, v10.4s, v11.4s");
283 }
284
285 for (unsigned int i = 0; i < amu_group1_num_counters(); i++) {
286 counters_final[i] = amu_group1_cnt_read(i);
287 if (counters_final[i] == counters_initial[i]) {
288 return TEST_RESULT_FAIL;
289 }
290 }
291
292 return TEST_RESULT_SUCCESS;
293#else
294 return TEST_RESULT_SKIPPED;
295#endif /* PLAT_tc && (TARGET_PLATFORM == 2) */
296}