blob: 21305a73217ee6e90ead97d244f3421f45b263e3 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
johpow01b7d752a2020-10-08 17:29:11 -05002 * Copyright (c) 2018-2021, 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>
9#include <arch_helpers.h>
10#include <assert.h>
11#include <debug.h>
12#include <irq.h>
13#include <plat_topology.h>
14#include <platform.h>
15#include <power_management.h>
16#include <tftf_lib.h>
17#include <timer.h>
18
Juan Pablo Condec3cf2da2024-04-01 13:57:19 -050019#define SUSPEND_TIME_1_SEC 1000
20#define MAX_MPMM_TEST_ITERATIONS 100000U
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020021
22static volatile int wakeup_irq_received[PLATFORM_CORE_COUNT];
23
24/* Dummy timer handler that sets a flag to check it has been called. */
25static int suspend_wakeup_handler(void *data)
26{
27 u_register_t core_mpid = read_mpidr_el1() & MPID_MASK;
28 unsigned int core_pos = platform_get_core_pos(core_mpid);
29
30 assert(wakeup_irq_received[core_pos] == 0);
31
32 wakeup_irq_received[core_pos] = 1;
33
34 return 0;
35}
36
37/*
38 * Helper function to suspend a CPU to power level 0 and wake it up with
39 * a timer.
40 */
41static test_result_t suspend_and_resume_this_cpu(void)
42{
43 uint32_t stateid;
44 int psci_ret;
45 test_result_t result = TEST_RESULT_SUCCESS;
46
47 u_register_t core_mpid = read_mpidr_el1() & MPID_MASK;
48 unsigned int core_pos = platform_get_core_pos(core_mpid);
49
50 /* Prepare wakeup timer. IRQs need to be enabled. */
51 wakeup_irq_received[core_pos] = 0;
52
53 tftf_timer_register_handler(suspend_wakeup_handler);
54
55 /* Program timer to fire interrupt after timer expires */
56 tftf_program_timer(SUSPEND_TIME_1_SEC);
57
58 /*
59 * Suspend the calling CPU to power level 0 and power
60 * state.
61 */
62 psci_ret = tftf_psci_make_composite_state_id(PSTATE_AFF_LVL_0,
63 PSTATE_TYPE_POWERDOWN,
64 &stateid);
65 if (psci_ret != PSCI_E_SUCCESS) {
66 mp_printf("Failed to make composite state ID @ CPU %d. rc = %x\n",
67 core_pos, psci_ret);
68 result = TEST_RESULT_FAIL;
69 } else {
70 unsigned int power_state = tftf_make_psci_pstate(PSTATE_AFF_LVL_0,
71 PSTATE_TYPE_POWERDOWN, stateid);
72 psci_ret = tftf_cpu_suspend(power_state);
73
74 if (!wakeup_irq_received[core_pos]) {
75 mp_printf("Didn't receive wakeup IRQ in CPU %d.\n",
76 core_pos);
77 result = TEST_RESULT_FAIL;
78 }
79
80 if (psci_ret != PSCI_E_SUCCESS) {
81 mp_printf("Failed to suspend from CPU %d. ret: %x\n",
82 core_pos, psci_ret);
83 result = TEST_RESULT_FAIL;
84 }
85 }
86
87 /* Wake up. Remove timer after waking up.*/
88 tftf_cancel_timer();
89 tftf_timer_unregister_handler();
90
91 return result;
92}
93
94/*
John Tsichritziscae91ca2019-05-12 16:06:09 +010095 * Helper function that checks whether the value of a group0 counter is valid
96 * or not. The first 3 counters (0,1,2) cannot have values of zero but the last
97 * counter that counts "memory stall cycles" can have a value of zero, under
98 * certain circumstances.
99 *
100 * Return values:
101 * 0 = valid counter value
102 * -1 = invalid counter value
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200103 */
John Tsichritziscae91ca2019-05-12 16:06:09 +0100104static int amu_group0_cnt_valid(unsigned int idx, uint64_t value)
105{
106 int answer = 0;
107
johpow01b7d752a2020-10-08 17:29:11 -0500108 if ((idx <= 2) && (value == 0)) {
John Tsichritziscae91ca2019-05-12 16:06:09 +0100109 answer = -1;
johpow01b7d752a2020-10-08 17:29:11 -0500110 }
John Tsichritziscae91ca2019-05-12 16:06:09 +0100111
112 return answer;
113}
114
115/*
116 * Check that group0 counters are valid. As EL3 has enabled the counters before
117 * the first entry to NS world, the counters should have increased by the time
118 * we reach this test case.
119 */
120test_result_t test_amu_valid_ctr(void)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200121{
johpow01b7d752a2020-10-08 17:29:11 -0500122 unsigned int i;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200123
johpow01b7d752a2020-10-08 17:29:11 -0500124 if (amu_get_version() == 0U) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200125 return TEST_RESULT_SKIPPED;
johpow01b7d752a2020-10-08 17:29:11 -0500126 }
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200127
128 /* If counters are not enabled, then skip the test */
johpow01b7d752a2020-10-08 17:29:11 -0500129 if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200130 return TEST_RESULT_SKIPPED;
johpow01b7d752a2020-10-08 17:29:11 -0500131 }
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200132
johpow01b7d752a2020-10-08 17:29:11 -0500133 for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
John Tsichritziscae91ca2019-05-12 16:06:09 +0100134 uint64_t value;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200135
John Tsichritziscae91ca2019-05-12 16:06:09 +0100136 value = amu_group0_cnt_read(i);
137 if (amu_group0_cnt_valid(i, value)) {
138 tftf_testcase_printf("Group0 counter %d has invalid value %lld\n", i, value);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200139 return TEST_RESULT_FAIL;
140 }
141 }
142
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200143 return TEST_RESULT_SUCCESS;
144}
145
146/*
147 * Check that the counters are non-decreasing during
148 * a suspend/resume cycle.
149 */
150test_result_t test_amu_suspend_resume(void)
151{
johpow01b7d752a2020-10-08 17:29:11 -0500152 uint64_t group0_ctrs[AMU_GROUP0_NR_COUNTERS];
153 unsigned int i;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200154
johpow01b7d752a2020-10-08 17:29:11 -0500155 if (amu_get_version() == 0U) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200156 return TEST_RESULT_SKIPPED;
johpow01b7d752a2020-10-08 17:29:11 -0500157 }
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200158
159 /* If counters are not enabled, then skip the test */
John Tsichritzis68759a82019-05-12 15:10:27 +0100160 if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200161 return TEST_RESULT_SKIPPED;
162
163 /* Save counters values before suspend */
johpow01b7d752a2020-10-08 17:29:11 -0500164 for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200165 group0_ctrs[i] = amu_group0_cnt_read(i);
johpow01b7d752a2020-10-08 17:29:11 -0500166 }
167
168 /*
169 * If FEAT_AMUv1p1 supported then make sure the save/restore works for
170 * virtual counter values. Write known values into the virtual offsets
171 * and then make sure they are still there after resume. The virtual
172 * offset registers are only accessible in AARCH64 mode in EL2 or EL3.
173 */
174#if __aarch64__
175 if (amu_get_version() >= ID_AA64PFR0_AMU_V1P1) {
176 /* Enabling voffsets in HCR_EL2. */
177 write_hcr_el2(read_hcr_el2() | HCR_AMVOFFEN_BIT);
178
179 /* Writing known values into voffset registers. */
180 amu_group0_voffset_write(0U, 0xDEADBEEF);
181 amu_group0_voffset_write(2U, 0xDEADBEEF);
182 amu_group0_voffset_write(3U, 0xDEADBEEF);
183
184#if AMU_GROUP1_NR_COUNTERS
185 u_register_t amcg1idr = read_amcg1idr_el0() >> 16;
186
187 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
188 if (((amcg1idr >> i) & 1U) != 0U) {
189 amu_group1_voffset_write(i, 0xDEADBEEF);
190 }
191 }
192#endif
193 }
194#endif
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200195
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200196 /* Suspend/resume current core */
197 suspend_and_resume_this_cpu();
198
199 /*
200 * Check if counter values are >= than the stored values.
201 * If they are not, the AMU context save/restore in EL3 is buggy.
202 */
203 for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) {
John Tsichritziscae91ca2019-05-12 16:06:09 +0100204 uint64_t value;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200205
John Tsichritziscae91ca2019-05-12 16:06:09 +0100206 value = amu_group0_cnt_read(i);
207 if (value < group0_ctrs[i]) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200208 tftf_testcase_printf("Invalid counter value: before: %llx, after: %llx\n",
209 (unsigned long long)group0_ctrs[i],
John Tsichritziscae91ca2019-05-12 16:06:09 +0100210 (unsigned long long)value);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200211 return TEST_RESULT_FAIL;
212 }
213 }
214
johpow01b7d752a2020-10-08 17:29:11 -0500215#if __aarch64__
216 if (amu_get_version() >= ID_AA64PFR0_AMU_V1P1) {
217 for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
218 if ((i != 1U) &&
219 (amu_group0_voffset_read(i) != 0xDEADBEEF)) {
220 tftf_testcase_printf(
221 "Invalid G0 voffset %u: 0x%llx\n", i,
222 amu_group0_voffset_read(i));
223 return TEST_RESULT_FAIL;
224 }
225 }
226
227#if AMU_GROUP1_NR_COUNTERS
228 u_register_t amcg1idr = read_amcg1idr_el0() >> 16;
229
230 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
231 if (((amcg1idr >> i) & 1U) != 0U) {
232 if (amu_group1_voffset_read(i) != 0xDEADBEEF) {
233 tftf_testcase_printf("Invalid G1 " \
234 "voffset %u: 0x%llx\n", i,
235 amu_group1_voffset_read(i));
236 return TEST_RESULT_FAIL;
237 }
238 }
239 }
240#endif
241 }
242#endif
243
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200244 return TEST_RESULT_SUCCESS;
245}
Juan Pablo Condec3cf2da2024-04-01 13:57:19 -0500246
247/*
248 * Check that group 1 counters read as 0 at ELs lower than EL3 when
249 * AMCR.CG1RZ is set.
250 */
251test_result_t test_amu_group1_raz(void)
252{
253/* Test on TC2 only, as MPMM not implemented in other platforms yet */
254#if PLAT_tc && (TARGET_PLATFORM == 2)
255 uint64_t counters_initial[AMU_GROUP1_NR_COUNTERS] = {0};
256 uint64_t counters_final[AMU_GROUP1_NR_COUNTERS] = {0};
257
258 for (unsigned int i = 0; i < amu_group1_num_counters(); i++) {
259 INFO("AMUEVTYPER1%x: 0x%llx\n", i, amu_group1_evtype_read(i));
260 counters_initial[i] = amu_group1_cnt_read(i);
261 }
262
263 for (int i = 0; i < MAX_MPMM_TEST_ITERATIONS; i++) {
264 // Instruction with activity count 1
265 __asm__ volatile("fmov d0,xzr");
266 __asm__ volatile("fmov d1,xzr");
267 __asm__ volatile("fmul d2,d0,d1");
268 __asm__ volatile("fmov d2,xzr");
269
270 __asm__ volatile("fmov d0,xzr");
271 __asm__ volatile("fmov d1,xzr");
272 __asm__ volatile("fmov d2,xzr");
273 __asm__ volatile("fmadd d3,d2,d1,d0");
274
275 // Instruction with activity count 2
276 __asm__ volatile("ptrue p0.s, ALL");
277 __asm__ volatile("index z10.s, #10,13");
278 __asm__ volatile("index z11.s, #12,7");
279 __asm__ volatile("ucvtf v10.4s, v10.4s");
280 __asm__ volatile("ucvtf v11.4s, v11.4s");
281 __asm__ volatile("fadd v0.4s, v10.4s, v11.4s");
282 }
283
284 for (unsigned int i = 0; i < amu_group1_num_counters(); i++) {
285 counters_final[i] = amu_group1_cnt_read(i);
286 if (counters_final[i] == counters_initial[i]) {
287 return TEST_RESULT_FAIL;
288 }
289 }
290
291 return TEST_RESULT_SUCCESS;
292#else
293 return TEST_RESULT_SKIPPED;
294#endif /* PLAT_tc && (TARGET_PLATFORM == 2) */
295}