blob: 58c05f07414bc23bf795a2b40eee7d91462766bc [file] [log] [blame]
AlexeiFedorov2f30f102023-03-13 19:37:46 +00001/*
2 * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch_helpers.h>
8#include <arm_arch_svc.h>
9#include <debug.h>
10#include <drivers/arm/gic_v3.h>
11
12#include <host_realm_pmu.h>
13#include <realm_rsi.h>
14
15/* PMUv3 events */
16#define PMU_EVT_SW_INCR 0x0
17#define PMU_EVT_INST_RETIRED 0x8
18#define PMU_EVT_CPU_CYCLES 0x11
19#define PMU_EVT_MEM_ACCESS 0x13
20
21#define NOP_REPETITIONS 50
22#define MAX_COUNTERS 32
23
24#define PRE_OVERFLOW ~(0xF)
25
26#define DELAY_MS 3000ULL
27
28static inline void read_all_counters(u_register_t *array, int impl_ev_ctrs)
29{
30 array[0] = read_pmccntr_el0();
31 for (unsigned int i = 0U; i < impl_ev_ctrs; i++) {
32 array[i + 1] = read_pmevcntrn_el0(i);
33 }
34}
35
36static inline void read_all_counter_configs(u_register_t *array, int impl_ev_ctrs)
37{
38 array[0] = read_pmccfiltr_el0();
39 for (unsigned int i = 0U; i < impl_ev_ctrs; i++) {
40 array[i + 1] = read_pmevtypern_el0(i);
41 }
42}
43
44static inline void read_all_pmu_configs(u_register_t *array)
45{
46 array[0] = read_pmcntenset_el0();
47 array[1] = read_pmcr_el0();
48 array[2] = read_pmselr_el0();
49}
50
51static inline void enable_counting(void)
52{
53 write_pmcr_el0(read_pmcr_el0() | PMCR_EL0_E_BIT);
54 /* This function means we are about to use the PMU, synchronize */
55 isb();
56}
57
58static inline void disable_counting(void)
59{
60 write_pmcr_el0(read_pmcr_el0() & ~PMCR_EL0_E_BIT);
61 /* We also rely that disabling really did work */
62 isb();
63}
64
65static inline void clear_counters(void)
66{
67 write_pmcr_el0(read_pmcr_el0() | PMCR_EL0_C_BIT | PMCR_EL0_P_BIT);
68 isb();
69}
70
71static void pmu_reset(void)
72{
73 /* Reset all counters */
74 write_pmcr_el0(read_pmcr_el0() |
75 PMCR_EL0_DP_BIT | PMCR_EL0_C_BIT | PMCR_EL0_P_BIT);
76
77 /* Disable all counters */
78 write_pmcntenclr_el0(PMU_CLEAR_ALL);
79
80 /* Clear overflow status */
81 write_pmovsclr_el0(PMU_CLEAR_ALL);
82
83 /* Disable overflow interrupts on all counters */
84 write_pmintenclr_el1(PMU_CLEAR_ALL);
85 isb();
86}
87
88/*
89 * This test runs in Realm EL1, don't bother enabling counting at lower ELs
90 * and secure world. TF-A has other controls for them and counting there
91 * doesn't impact us.
92 */
93static inline void enable_cycle_counter(void)
94{
95 /*
96 * Set PMCCFILTR_EL0.U != PMCCFILTR_EL0.RLU
97 * to disable counting in Realm EL0.
98 * Set PMCCFILTR_EL0.P = PMCCFILTR_EL0.RLK
99 * to enable counting in Realm EL1.
100 * Set PMCCFILTR_EL0.NSH = PMCCFILTR_EL0_EL0.RLH
101 * to disable event counting in Realm EL2.
102 */
103 write_pmccfiltr_el0(PMCCFILTR_EL0_U_BIT |
104 PMCCFILTR_EL0_P_BIT | PMCCFILTR_EL0_RLK_BIT |
105 PMCCFILTR_EL0_NSH_BIT | PMCCFILTR_EL0_RLH_BIT);
106 write_pmcntenset_el0(read_pmcntenset_el0() | PMCNTENSET_EL0_C_BIT);
107 isb();
108}
109
110static inline void enable_event_counter(int ctr_num)
111{
112 /*
113 * Set PMEVTYPER_EL0.U != PMEVTYPER_EL0.RLU
114 * to disable event counting in Realm EL0.
115 * Set PMEVTYPER_EL0.P = PMEVTYPER_EL0.RLK
116 * to enable counting in Realm EL1.
117 * Set PMEVTYPER_EL0.NSH = PMEVTYPER_EL0.RLH
118 * to disable event counting in Realm EL2.
119 */
120 write_pmevtypern_el0(ctr_num,
121 PMEVTYPER_EL0_U_BIT |
122 PMEVTYPER_EL0_P_BIT | PMEVTYPER_EL0_RLK_BIT |
123 PMEVTYPER_EL0_NSH_BIT | PMEVTYPER_EL0_RLH_BIT |
124 (PMU_EVT_INST_RETIRED & PMEVTYPER_EL0_EVTCOUNT_BITS));
125 write_pmcntenset_el0(read_pmcntenset_el0() |
126 PMCNTENSET_EL0_P_BIT(ctr_num));
127 isb();
128}
129
130/* Doesn't really matter what happens, as long as it happens a lot */
131static inline void execute_nops(void)
132{
133 for (unsigned int i = 0U; i < NOP_REPETITIONS; i++) {
134 __asm__ ("orr x0, x0, x0\n");
135 }
136}
137
138/*
139 * Try the cycle counter with some NOPs to see if it works
140 */
141bool test_pmuv3_cycle_works_realm(void)
142{
143 u_register_t ccounter_start;
144 u_register_t ccounter_end;
145
146 pmu_reset();
147
148 enable_cycle_counter();
149 enable_counting();
150
151 ccounter_start = read_pmccntr_el0();
152 execute_nops();
153 ccounter_end = read_pmccntr_el0();
154 disable_counting();
155 clear_counters();
156
157 realm_printf("Realm: counted from %lu to %lu\n",
158 ccounter_start, ccounter_end);
159 if (ccounter_start != ccounter_end) {
160 return true;
161 }
162 return false;
163}
164
165/*
166 * Try an event counter with some NOPs to see if it works.
167 */
168bool test_pmuv3_event_works_realm(void)
169{
170 u_register_t evcounter_start;
171 u_register_t evcounter_end;
172
173 if (GET_CNT_NUM == 0) {
174 realm_printf("Realm: no event counters implemented\n");
175 return false;
176 }
177
178 pmu_reset();
179
180 enable_event_counter(0);
181 enable_counting();
182
183 /*
184 * If any is enabled it will be in the first range.
185 */
186 evcounter_start = read_pmevcntrn_el0(0);
187 execute_nops();
188 disable_counting();
189 evcounter_end = read_pmevcntrn_el0(0);
190 clear_counters();
191
192 realm_printf("Realm: counted from %lu to %lu\n",
193 evcounter_start, evcounter_end);
194 if (evcounter_start != evcounter_end) {
195 return true;
196 }
197 return false;
198}
199
200/*
201 * Check if entering/exiting RMM (with a NOP) preserves all PMU registers.
202 */
203bool test_pmuv3_rmm_preserves(void)
204{
205 u_register_t ctr_start[MAX_COUNTERS] = {0};
206 u_register_t ctr_cfg_start[MAX_COUNTERS] = {0};
207 u_register_t pmu_cfg_start[3];
208 u_register_t ctr_end[MAX_COUNTERS] = {0};
209 u_register_t ctr_cfg_end[MAX_COUNTERS] = {0};
210 u_register_t pmu_cfg_end[3];
211 unsigned int impl_ev_ctrs = GET_CNT_NUM;
212
213 realm_printf("Realm: testing %u event counters\n", impl_ev_ctrs);
214
215 pmu_reset();
216
217 /* Pretend counters have just been used */
218 enable_cycle_counter();
219 enable_event_counter(0);
220 enable_counting();
221 execute_nops();
222 disable_counting();
223
224 /* Get before reading */
225 read_all_counters(ctr_start, impl_ev_ctrs);
226 read_all_counter_configs(ctr_cfg_start, impl_ev_ctrs);
227 read_all_pmu_configs(pmu_cfg_start);
228
229 /* Give RMM a chance to scramble everything */
Shruti Gupta40de8ec2023-10-12 21:45:12 +0100230 (void)rsi_get_version(RSI_ABI_VERSION_VAL);
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000231
232 /* Get after reading */
233 read_all_counters(ctr_end, impl_ev_ctrs);
234 read_all_counter_configs(ctr_cfg_end, impl_ev_ctrs);
235 read_all_pmu_configs(pmu_cfg_end);
236
237 if (memcmp(ctr_start, ctr_end, sizeof(ctr_start)) != 0) {
238 realm_printf("Realm: SMC call did not preserve %s\n",
239 "counters");
240 return false;
241 }
242
243 if (memcmp(ctr_cfg_start, ctr_cfg_end, sizeof(ctr_cfg_start)) != 0) {
244 realm_printf("Realm: SMC call did not preserve %s\n",
245 "counter config");
246 return false;
247 }
248
249 if (memcmp(pmu_cfg_start, pmu_cfg_end, sizeof(pmu_cfg_start)) != 0) {
250 realm_printf("Realm: SMC call did not preserve %s\n",
251 "PMU registers");
252 return false;
253 }
254
255 return true;
256}
257
258bool test_pmuv3_overflow_interrupt(void)
259{
260 unsigned long priority_bits, priority;
261 uint64_t delay_time = DELAY_MS;
262
263 pmu_reset();
264
265 /* Get the number of priority bits implemented */
266 priority_bits = ((read_icv_ctrl_el1() >> ICV_CTLR_EL1_PRIbits_SHIFT) &
267 ICV_CTLR_EL1_PRIbits_MASK) + 1UL;
268
269 /* Unimplemented bits are RES0 and start from LSB */
270 priority = (0xFFUL << (8UL - priority_bits)) & 0xFFUL;
271
272 /* Set the priority mask register to allow all interrupts */
273 write_icv_pmr_el1(priority);
274
275 /* Enable Virtual Group 1 interrupts */
276 write_icv_igrpen1_el1(ICV_IGRPEN1_EL1_Enable);
277
278 /* Enable IRQ */
279 enable_irq();
280
281 write_pmevcntrn_el0(0, PRE_OVERFLOW);
282 enable_event_counter(0);
283
284 /* Enable interrupt on event counter #0 */
285 write_pmintenset_el1((1UL << 0));
286
287 realm_printf("Realm: waiting for PMU vIRQ...\n");
288
289 enable_counting();
290 execute_nops();
291
292 /*
293 * Interrupt handler will clear
294 * Performance Monitors Interrupt Enable Set register
295 * as part of handling the overflow interrupt.
296 */
297 while ((read_pmintenset_el1() != 0UL) && (delay_time != 0ULL)) {
298 --delay_time;
299 }
300
301 /* Disable IRQ */
302 disable_irq();
303
304 pmu_reset();
305
306 if (delay_time == 0ULL) {
307 realm_printf("Realm: PMU vIRQ %sreceived in %llums\n", "not ",
308 DELAY_MS);
309 return false;
310 }
311
312 realm_printf("Realm: PMU vIRQ %sreceived in %llums\n", "",
313 DELAY_MS - delay_time);
314
315 return true;
316}