blob: 2e2ea6fba13ad55e43b03f9936151a9d8cec68a5 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
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/*
94 * Check that group0/group1 counters are non-zero. As EL3
95 * has enabled the counters before the first entry to NS world,
96 * the counters should have increased by the time we reach this
97 * test case.
98 */
99test_result_t test_amu_nonzero_ctr(void)
100{
101 int i;
102
103 if (!amu_supported())
104 return TEST_RESULT_SKIPPED;
105
106 /* If counters are not enabled, then skip the test */
107 if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK ||
108 read_amcntenset1_el0() != AMU_GROUP1_COUNTERS_MASK)
109 return TEST_RESULT_SKIPPED;
110
111 for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) {
112 uint64_t v;
113
114 v = amu_group0_cnt_read(i);
115 if (v == 0) {
116 tftf_testcase_printf("Group0 counter cannot be 0\n");
117 return TEST_RESULT_FAIL;
118 }
119 }
120
121 for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++) {
122 uint64_t v;
123
124 v = amu_group1_cnt_read(i);
125 if (v == 0) {
126 tftf_testcase_printf("Group1 counter cannot be 0\n");
127 return TEST_RESULT_FAIL;
128 }
129 }
130
131 return TEST_RESULT_SUCCESS;
132}
133
134/*
135 * Check that the counters are non-decreasing during
136 * a suspend/resume cycle.
137 */
138test_result_t test_amu_suspend_resume(void)
139{
140 uint64_t group0_ctrs[AMU_GROUP0_MAX_NR_COUNTERS];
141 uint64_t group1_ctrs[AMU_GROUP1_MAX_NR_COUNTERS];
142 int i;
143
144 if (!amu_supported())
145 return TEST_RESULT_SKIPPED;
146
147 /* If counters are not enabled, then skip the test */
148 if (read_amcntenset0_el0() != AMU_GROUP0_COUNTERS_MASK ||
149 read_amcntenset1_el0() != AMU_GROUP1_COUNTERS_MASK)
150 return TEST_RESULT_SKIPPED;
151
152 /* Save counters values before suspend */
153 for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++)
154 group0_ctrs[i] = amu_group0_cnt_read(i);
155
156 for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++)
157 group1_ctrs[i] = amu_group1_cnt_read(i);
158
159 /* Suspend/resume current core */
160 suspend_and_resume_this_cpu();
161
162 /*
163 * Check if counter values are >= than the stored values.
164 * If they are not, the AMU context save/restore in EL3 is buggy.
165 */
166 for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) {
167 uint64_t v;
168
169 v = amu_group0_cnt_read(i);
170 if (v < group0_ctrs[i]) {
171 tftf_testcase_printf("Invalid counter value: before: %llx, after: %llx\n",
172 (unsigned long long)group0_ctrs[i],
173 (unsigned long long)v);
174 return TEST_RESULT_FAIL;
175 }
176 }
177
178 for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++) {
179 uint64_t v;
180
181 v = amu_group1_cnt_read(i);
182 if (v < group1_ctrs[i]) {
183 tftf_testcase_printf("Invalid counter value: before: %llx, after: %llx\n",
184 (unsigned long long)group1_ctrs[i],
185 (unsigned long long)v);
186 return TEST_RESULT_FAIL;
187 }
188 }
189
190 return TEST_RESULT_SUCCESS;
191}