blob: 8d5c92bad4fb487a1ee09ad97eaf66524d9d7a68 [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
19#define SUSPEND_TIME_1_SEC 1000
20
21static volatile int wakeup_irq_received[PLATFORM_CORE_COUNT];
22
23/* Dummy timer handler that sets a flag to check it has been called. */
24static int suspend_wakeup_handler(void *data)
25{
26 u_register_t core_mpid = read_mpidr_el1() & MPID_MASK;
27 unsigned int core_pos = platform_get_core_pos(core_mpid);
28
29 assert(wakeup_irq_received[core_pos] == 0);
30
31 wakeup_irq_received[core_pos] = 1;
32
33 return 0;
34}
35
36/*
37 * Helper function to suspend a CPU to power level 0 and wake it up with
38 * a timer.
39 */
40static test_result_t suspend_and_resume_this_cpu(void)
41{
42 uint32_t stateid;
43 int psci_ret;
44 test_result_t result = TEST_RESULT_SUCCESS;
45
46 u_register_t core_mpid = read_mpidr_el1() & MPID_MASK;
47 unsigned int core_pos = platform_get_core_pos(core_mpid);
48
49 /* Prepare wakeup timer. IRQs need to be enabled. */
50 wakeup_irq_received[core_pos] = 0;
51
52 tftf_timer_register_handler(suspend_wakeup_handler);
53
54 /* Program timer to fire interrupt after timer expires */
55 tftf_program_timer(SUSPEND_TIME_1_SEC);
56
57 /*
58 * Suspend the calling CPU to power level 0 and power
59 * state.
60 */
61 psci_ret = tftf_psci_make_composite_state_id(PSTATE_AFF_LVL_0,
62 PSTATE_TYPE_POWERDOWN,
63 &stateid);
64 if (psci_ret != PSCI_E_SUCCESS) {
65 mp_printf("Failed to make composite state ID @ CPU %d. rc = %x\n",
66 core_pos, psci_ret);
67 result = TEST_RESULT_FAIL;
68 } else {
69 unsigned int power_state = tftf_make_psci_pstate(PSTATE_AFF_LVL_0,
70 PSTATE_TYPE_POWERDOWN, stateid);
71 psci_ret = tftf_cpu_suspend(power_state);
72
73 if (!wakeup_irq_received[core_pos]) {
74 mp_printf("Didn't receive wakeup IRQ in CPU %d.\n",
75 core_pos);
76 result = TEST_RESULT_FAIL;
77 }
78
79 if (psci_ret != PSCI_E_SUCCESS) {
80 mp_printf("Failed to suspend from CPU %d. ret: %x\n",
81 core_pos, psci_ret);
82 result = TEST_RESULT_FAIL;
83 }
84 }
85
86 /* Wake up. Remove timer after waking up.*/
87 tftf_cancel_timer();
88 tftf_timer_unregister_handler();
89
90 return result;
91}
92
93/*
John Tsichritziscae91ca2019-05-12 16:06:09 +010094 * Helper function that checks whether the value of a group0 counter is valid
95 * or not. The first 3 counters (0,1,2) cannot have values of zero but the last
96 * counter that counts "memory stall cycles" can have a value of zero, under
97 * certain circumstances.
98 *
99 * Return values:
100 * 0 = valid counter value
101 * -1 = invalid counter value
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200102 */
John Tsichritziscae91ca2019-05-12 16:06:09 +0100103static int amu_group0_cnt_valid(unsigned int idx, uint64_t value)
104{
105 int answer = 0;
106
johpow01b7d752a2020-10-08 17:29:11 -0500107 if ((idx <= 2) && (value == 0)) {
John Tsichritziscae91ca2019-05-12 16:06:09 +0100108 answer = -1;
johpow01b7d752a2020-10-08 17:29:11 -0500109 }
John Tsichritziscae91ca2019-05-12 16:06:09 +0100110
111 return answer;
112}
113
114/*
115 * Check that group0 counters are valid. As EL3 has enabled the counters before
116 * the first entry to NS world, the counters should have increased by the time
117 * we reach this test case.
118 */
119test_result_t test_amu_valid_ctr(void)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200120{
johpow01b7d752a2020-10-08 17:29:11 -0500121 unsigned int i;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200122
johpow01b7d752a2020-10-08 17:29:11 -0500123 if (amu_get_version() == 0U) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200124 return TEST_RESULT_SKIPPED;
johpow01b7d752a2020-10-08 17:29:11 -0500125 }
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200126
127 /* If counters are not enabled, then skip the test */
johpow01b7d752a2020-10-08 17:29:11 -0500128 if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200129 return TEST_RESULT_SKIPPED;
johpow01b7d752a2020-10-08 17:29:11 -0500130 }
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200131
johpow01b7d752a2020-10-08 17:29:11 -0500132 for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
John Tsichritziscae91ca2019-05-12 16:06:09 +0100133 uint64_t value;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200134
John Tsichritziscae91ca2019-05-12 16:06:09 +0100135 value = amu_group0_cnt_read(i);
136 if (amu_group0_cnt_valid(i, value)) {
137 tftf_testcase_printf("Group0 counter %d has invalid value %lld\n", i, value);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200138 return TEST_RESULT_FAIL;
139 }
140 }
141
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200142 return TEST_RESULT_SUCCESS;
143}
144
145/*
146 * Check that the counters are non-decreasing during
147 * a suspend/resume cycle.
148 */
149test_result_t test_amu_suspend_resume(void)
150{
johpow01b7d752a2020-10-08 17:29:11 -0500151 uint64_t group0_ctrs[AMU_GROUP0_NR_COUNTERS];
152 unsigned int i;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200153
johpow01b7d752a2020-10-08 17:29:11 -0500154 if (amu_get_version() == 0U) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200155 return TEST_RESULT_SKIPPED;
johpow01b7d752a2020-10-08 17:29:11 -0500156 }
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200157
158 /* If counters are not enabled, then skip the test */
John Tsichritzis68759a82019-05-12 15:10:27 +0100159 if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200160 return TEST_RESULT_SKIPPED;
161
162 /* Save counters values before suspend */
johpow01b7d752a2020-10-08 17:29:11 -0500163 for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200164 group0_ctrs[i] = amu_group0_cnt_read(i);
johpow01b7d752a2020-10-08 17:29:11 -0500165 }
166
167 /*
168 * If FEAT_AMUv1p1 supported then make sure the save/restore works for
169 * virtual counter values. Write known values into the virtual offsets
170 * and then make sure they are still there after resume. The virtual
171 * offset registers are only accessible in AARCH64 mode in EL2 or EL3.
172 */
173#if __aarch64__
174 if (amu_get_version() >= ID_AA64PFR0_AMU_V1P1) {
175 /* Enabling voffsets in HCR_EL2. */
176 write_hcr_el2(read_hcr_el2() | HCR_AMVOFFEN_BIT);
177
178 /* Writing known values into voffset registers. */
179 amu_group0_voffset_write(0U, 0xDEADBEEF);
180 amu_group0_voffset_write(2U, 0xDEADBEEF);
181 amu_group0_voffset_write(3U, 0xDEADBEEF);
182
183#if AMU_GROUP1_NR_COUNTERS
184 u_register_t amcg1idr = read_amcg1idr_el0() >> 16;
185
186 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
187 if (((amcg1idr >> i) & 1U) != 0U) {
188 amu_group1_voffset_write(i, 0xDEADBEEF);
189 }
190 }
191#endif
192 }
193#endif
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200194
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200195 /* Suspend/resume current core */
196 suspend_and_resume_this_cpu();
197
198 /*
199 * Check if counter values are >= than the stored values.
200 * If they are not, the AMU context save/restore in EL3 is buggy.
201 */
202 for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) {
John Tsichritziscae91ca2019-05-12 16:06:09 +0100203 uint64_t value;
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200204
John Tsichritziscae91ca2019-05-12 16:06:09 +0100205 value = amu_group0_cnt_read(i);
206 if (value < group0_ctrs[i]) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200207 tftf_testcase_printf("Invalid counter value: before: %llx, after: %llx\n",
208 (unsigned long long)group0_ctrs[i],
John Tsichritziscae91ca2019-05-12 16:06:09 +0100209 (unsigned long long)value);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200210 return TEST_RESULT_FAIL;
211 }
212 }
213
johpow01b7d752a2020-10-08 17:29:11 -0500214#if __aarch64__
215 if (amu_get_version() >= ID_AA64PFR0_AMU_V1P1) {
216 for (i = 0U; i < AMU_GROUP0_NR_COUNTERS; i++) {
217 if ((i != 1U) &&
218 (amu_group0_voffset_read(i) != 0xDEADBEEF)) {
219 tftf_testcase_printf(
220 "Invalid G0 voffset %u: 0x%llx\n", i,
221 amu_group0_voffset_read(i));
222 return TEST_RESULT_FAIL;
223 }
224 }
225
226#if AMU_GROUP1_NR_COUNTERS
227 u_register_t amcg1idr = read_amcg1idr_el0() >> 16;
228
229 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) {
230 if (((amcg1idr >> i) & 1U) != 0U) {
231 if (amu_group1_voffset_read(i) != 0xDEADBEEF) {
232 tftf_testcase_printf("Invalid G1 " \
233 "voffset %u: 0x%llx\n", i,
234 amu_group1_voffset_read(i));
235 return TEST_RESULT_FAIL;
236 }
237 }
238 }
239#endif
240 }
241#endif
242
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200243 return TEST_RESULT_SUCCESS;
244}