blob: 0d4782a3b9fbcce727bf5718db324b5f94cc8c11 [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
Shruti Guptaa276b202023-12-18 10:07:43 +0000157 realm_printf("counted from %lu to %lu\n",
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000158 ccounter_start, ccounter_end);
159 if (ccounter_start != ccounter_end) {
160 return true;
161 }
162 return false;
163}
164
Shruti Guptab1b37922024-01-13 21:49:04 +0000165/* Test if max counter available is same as that programmed by host */
166bool test_pmuv3_counter(void)
167{
168 uint64_t num_cnts, num_cnts_host;
169
170 num_cnts_host = realm_shared_data_get_my_host_val(HOST_ARG1_INDEX);
171 num_cnts = GET_PMU_CNT;
172 realm_printf("CPU=%u num_cnts=%lu num_cnts_host=%lu\n", read_mpidr_el1() & MPID_MASK,
173 num_cnts, num_cnts_host);
174 if (num_cnts == num_cnts_host) {
175 return true;
176 }
177 return false;
178}
179
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000180/*
181 * Try an event counter with some NOPs to see if it works.
182 */
183bool test_pmuv3_event_works_realm(void)
184{
185 u_register_t evcounter_start;
186 u_register_t evcounter_end;
187
Shruti Guptab1b37922024-01-13 21:49:04 +0000188 if (GET_PMU_CNT == 0) {
Shruti Guptaa276b202023-12-18 10:07:43 +0000189 realm_printf("no event counters implemented\n");
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000190 return false;
191 }
192
193 pmu_reset();
194
195 enable_event_counter(0);
196 enable_counting();
197
198 /*
199 * If any is enabled it will be in the first range.
200 */
201 evcounter_start = read_pmevcntrn_el0(0);
202 execute_nops();
203 disable_counting();
204 evcounter_end = read_pmevcntrn_el0(0);
205 clear_counters();
206
Shruti Guptaa276b202023-12-18 10:07:43 +0000207 realm_printf("counted from %lu to %lu\n",
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000208 evcounter_start, evcounter_end);
209 if (evcounter_start != evcounter_end) {
210 return true;
211 }
212 return false;
213}
214
215/*
216 * Check if entering/exiting RMM (with a NOP) preserves all PMU registers.
217 */
218bool test_pmuv3_rmm_preserves(void)
219{
220 u_register_t ctr_start[MAX_COUNTERS] = {0};
221 u_register_t ctr_cfg_start[MAX_COUNTERS] = {0};
222 u_register_t pmu_cfg_start[3];
223 u_register_t ctr_end[MAX_COUNTERS] = {0};
224 u_register_t ctr_cfg_end[MAX_COUNTERS] = {0};
225 u_register_t pmu_cfg_end[3];
Shruti Guptab1b37922024-01-13 21:49:04 +0000226 unsigned int impl_ev_ctrs = GET_PMU_CNT;
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000227
Shruti Guptaa276b202023-12-18 10:07:43 +0000228 realm_printf("testing %u event counters\n", impl_ev_ctrs);
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000229
230 pmu_reset();
231
232 /* Pretend counters have just been used */
233 enable_cycle_counter();
234 enable_event_counter(0);
235 enable_counting();
236 execute_nops();
237 disable_counting();
238
239 /* Get before reading */
240 read_all_counters(ctr_start, impl_ev_ctrs);
241 read_all_counter_configs(ctr_cfg_start, impl_ev_ctrs);
242 read_all_pmu_configs(pmu_cfg_start);
243
244 /* Give RMM a chance to scramble everything */
Shruti Gupta40de8ec2023-10-12 21:45:12 +0100245 (void)rsi_get_version(RSI_ABI_VERSION_VAL);
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000246
247 /* Get after reading */
248 read_all_counters(ctr_end, impl_ev_ctrs);
249 read_all_counter_configs(ctr_cfg_end, impl_ev_ctrs);
250 read_all_pmu_configs(pmu_cfg_end);
251
252 if (memcmp(ctr_start, ctr_end, sizeof(ctr_start)) != 0) {
Shruti Guptaa276b202023-12-18 10:07:43 +0000253 realm_printf("SMC call did not preserve %s\n",
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000254 "counters");
255 return false;
256 }
257
258 if (memcmp(ctr_cfg_start, ctr_cfg_end, sizeof(ctr_cfg_start)) != 0) {
Shruti Guptaa276b202023-12-18 10:07:43 +0000259 realm_printf("SMC call did not preserve %s\n",
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000260 "counter config");
261 return false;
262 }
263
264 if (memcmp(pmu_cfg_start, pmu_cfg_end, sizeof(pmu_cfg_start)) != 0) {
Shruti Guptaa276b202023-12-18 10:07:43 +0000265 realm_printf("SMC call did not preserve %s\n",
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000266 "PMU registers");
267 return false;
268 }
269
270 return true;
271}
272
273bool test_pmuv3_overflow_interrupt(void)
274{
275 unsigned long priority_bits, priority;
276 uint64_t delay_time = DELAY_MS;
277
278 pmu_reset();
279
280 /* Get the number of priority bits implemented */
281 priority_bits = ((read_icv_ctrl_el1() >> ICV_CTLR_EL1_PRIbits_SHIFT) &
282 ICV_CTLR_EL1_PRIbits_MASK) + 1UL;
283
284 /* Unimplemented bits are RES0 and start from LSB */
285 priority = (0xFFUL << (8UL - priority_bits)) & 0xFFUL;
286
287 /* Set the priority mask register to allow all interrupts */
288 write_icv_pmr_el1(priority);
289
290 /* Enable Virtual Group 1 interrupts */
291 write_icv_igrpen1_el1(ICV_IGRPEN1_EL1_Enable);
292
293 /* Enable IRQ */
294 enable_irq();
295
296 write_pmevcntrn_el0(0, PRE_OVERFLOW);
297 enable_event_counter(0);
298
299 /* Enable interrupt on event counter #0 */
300 write_pmintenset_el1((1UL << 0));
301
Shruti Guptaa276b202023-12-18 10:07:43 +0000302 realm_printf("waiting for PMU vIRQ...\n");
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000303
304 enable_counting();
305 execute_nops();
306
307 /*
308 * Interrupt handler will clear
309 * Performance Monitors Interrupt Enable Set register
310 * as part of handling the overflow interrupt.
311 */
312 while ((read_pmintenset_el1() != 0UL) && (delay_time != 0ULL)) {
313 --delay_time;
314 }
315
316 /* Disable IRQ */
317 disable_irq();
318
319 pmu_reset();
320
321 if (delay_time == 0ULL) {
Shruti Guptaa276b202023-12-18 10:07:43 +0000322 realm_printf("PMU vIRQ %sreceived in %llums\n", "not ",
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000323 DELAY_MS);
324 return false;
325 }
326
Shruti Guptaa276b202023-12-18 10:07:43 +0000327 realm_printf("PMU vIRQ %sreceived in %llums\n", "",
AlexeiFedorov2f30f102023-03-13 19:37:46 +0000328 DELAY_MS - delay_time);
329
330 return true;
331}