blob: 16004f448302da9a992b3f8d597b078f2a840ed1 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
Igor Podgainõib32ccfe2025-02-27 23:48:45 +01002 * Copyright (c) 2018-2025, Arm Limited. All rights reserved.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch_helpers.h>
8#include <debug.h>
Antonio Nino Diaz09a00ef2019-01-11 13:12:58 +00009#include <drivers/arm/private_timer.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020010#include <events.h>
11#include <plat_topology.h>
12#include <platform.h>
13#include <power_management.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020014#include <sdei.h>
15#include <tftf_lib.h>
16#include <timer.h>
17
18#define EV_COOKIE 0xDEADBEEF
19#define TIMER_TIMEO_MS 10
20
21extern sdei_handler_t sdei_entrypoint;
22extern sdei_handler_t sdei_entrypoint_resume;
23
24/*
25 * the bound event number as returned from sdei_interrupt_bind(), passed
26 * to the per-cpu SDEI test function
27 */
28static int bound_ev;
29/* true if the test is using a private interrupt source, false otherwise. */
30static int private_interrupt;
31
32static spinlock_t cpu_count_lock;
33static volatile int cpu_count;
34static volatile int participating_cpu_count;
35
36/* Helper function to wait for CPUs participating in the test. */
37static void wait_for_participating_cpus(void)
38{
39 assert(participating_cpu_count <= PLATFORM_CORE_COUNT);
40
41 spin_lock(&cpu_count_lock);
42 cpu_count++;
43 spin_unlock(&cpu_count_lock);
44
45 assert(cpu_count <= PLATFORM_CORE_COUNT);
46
47 while (cpu_count != participating_cpu_count)
48 continue;
49}
50
51void sdei_trigger_event(void)
52{
53 printf("%s: triggering SDEI event\n", __func__);
54 if (private_interrupt)
55 private_timer_start(TIMER_TIMEO_MS);
56 else
57 tftf_program_timer(TIMER_TIMEO_MS);
58}
59
60static test_result_t sdei_event(void)
61{
62 long long ret;
63
64 wait_for_participating_cpus();
65
66 printf("%s: mpidr = 0x%llx\n", __func__,
67 (unsigned long long)read_mpidr_el1());
68
69 ret = sdei_event_register(bound_ev, sdei_entrypoint_resume, EV_COOKIE,
70 SDEI_REGF_RM_PE, read_mpidr_el1());
71 if (ret < 0) {
72 tftf_testcase_printf("SDEI event register failed: 0x%llx\n",
73 ret);
74 return TEST_RESULT_FAIL;
75 }
76
77 ret = sdei_event_enable(bound_ev);
78 if (ret < 0) {
79 tftf_testcase_printf("SDEI event enable failed: 0x%llx\n", ret);
80 goto err0;
81 }
82
83 ret = sdei_pe_unmask();
84 if (ret < 0) {
85 tftf_testcase_printf("SDEI pe unmask failed: 0x%llx\n", ret);
86 goto err1;
87 }
88
89 sdei_trigger_event();
90
91 sdei_handler_done();
92
93 sdei_pe_mask();
94
95err1:
96 sdei_event_disable(bound_ev);
97err0:
98 sdei_event_unregister(bound_ev);
99
100 if (ret < 0)
101 return TEST_RESULT_FAIL;
102
103 return TEST_RESULT_SUCCESS;
104}
105
106int sdei_event_handler(int ev, unsigned long long arg)
107{
108 printf("%s: handler fired\n", __func__);
109 assert(arg == EV_COOKIE);
110 if (private_interrupt)
111 private_timer_stop();
112 else
113 tftf_cancel_timer();
114 return 0;
115}
116
117/* Handle an SDEI event on all cores in sequence. */
118test_result_t test_sdei_event_serial(void)
119{
120 struct sdei_intr_ctx intr_ctx;
121 u_register_t lead_mpid, target_mpid;
122 int cpu_node;
123 long long ret;
124
125 lead_mpid = read_mpidr_el1() & MPID_MASK;
126 participating_cpu_count = 1;
127 init_spinlock(&cpu_count_lock);
128 cpu_count = 0;
129
130 ret = sdei_version();
131 if (ret != MAKE_SDEI_VERSION(1, 0, 0)) {
132 tftf_testcase_printf("Unexpected SDEI version: 0x%llx\n", ret);
133 return TEST_RESULT_SKIPPED;
134 }
135
136 disable_irq();
137 bound_ev = sdei_interrupt_bind(tftf_get_timer_irq(), &intr_ctx);
138 if (bound_ev < 0) {
139 tftf_testcase_printf("SDEI interrupt bind failed: %x\n",
140 bound_ev);
141 return TEST_RESULT_FAIL;
142 }
143
144 /* use a shared interrupt source for this test-case */
145 private_interrupt = 0;
146
147 for_each_cpu(cpu_node) {
148 target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
149 if (lead_mpid == target_mpid)
150 continue;
151 ret = tftf_cpu_on(target_mpid,
152 (uintptr_t)sdei_event, 0);
153 if (ret != PSCI_E_SUCCESS) {
154 ERROR("CPU ON failed for 0x0x%llx\n",
155 (unsigned long long)target_mpid);
156 goto err0;
157 }
158 while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) !=
159 PSCI_STATE_OFF)
160 continue;
161 cpu_count--;
162 }
163
164 assert(cpu_count == 0);
165
166 if (sdei_event() != TEST_RESULT_SUCCESS)
167 goto err0;
168
169 cpu_count--;
170 assert(cpu_count == 0);
171
172 sdei_interrupt_release(bound_ev, &intr_ctx);
173 enable_irq();
174
175 return TEST_RESULT_SUCCESS;
176
177err0:
178 sdei_private_reset();
179 sdei_shared_reset();
180 sdei_interrupt_release(bound_ev, &intr_ctx);
181 enable_irq();
182 return TEST_RESULT_FAIL;
183}
184
185/* Handle an SDEI event on all cores in parallel. */
186test_result_t test_sdei_event_parallel(void)
187{
188 struct sdei_intr_ctx intr_ctx;
189 u_register_t lead_mpid, target_mpid;
190 int cpu_node;
191 long long ret;
192
193 lead_mpid = read_mpidr_el1() & MPID_MASK;
194 participating_cpu_count = tftf_get_total_cpus_count();
195 init_spinlock(&cpu_count_lock);
196 cpu_count = 0;
197
198 ret = sdei_version();
199 if (ret != MAKE_SDEI_VERSION(1, 0, 0)) {
200 tftf_testcase_printf("Unexpected SDEI version: 0x%llx\n", ret);
201 return TEST_RESULT_SKIPPED;
202 }
203
204 disable_irq();
205 bound_ev = sdei_interrupt_bind(IRQ_PCPU_HP_TIMER, &intr_ctx);
206 if (bound_ev < 0) {
207 tftf_testcase_printf("SDEI interrupt bind failed: %x\n",
208 bound_ev);
209 return TEST_RESULT_FAIL;
210 }
211
212 /* use a private interrupt source for this test-case */
213 private_interrupt = 1;
214
215 for_each_cpu(cpu_node) {
216 target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
217 if (lead_mpid == target_mpid)
218 continue;
219 ret = tftf_cpu_on(target_mpid,
220 (uintptr_t)sdei_event, 0);
221 if (ret != PSCI_E_SUCCESS) {
222 ERROR("CPU ON failed for 0x0x%llx\n",
223 (unsigned long long)target_mpid);
224 goto err0;
225 }
226 }
227
228 if (sdei_event() != TEST_RESULT_SUCCESS)
229 goto err0;
230
231 for_each_cpu(cpu_node) {
232 target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
233 if (lead_mpid == target_mpid)
234 continue;
235 while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) !=
236 PSCI_STATE_OFF)
237 continue;
238 cpu_count--;
239 }
240
241 cpu_count--;
242 assert(cpu_count == 0);
243
244 sdei_interrupt_release(bound_ev, &intr_ctx);
245 enable_irq();
246
247 return TEST_RESULT_SUCCESS;
248err0:
249 sdei_private_reset();
250 sdei_shared_reset();
251 sdei_interrupt_release(bound_ev, &intr_ctx);
252 enable_irq();
253 return TEST_RESULT_FAIL;
254}
255
Igor Podgainõib32ccfe2025-02-27 23:48:45 +0100256static test_result_t sdei_event_signal_self(bool enable, bool unmask)
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200257{
258 long long ret;
259
260 ret = sdei_event_register(0, sdei_entrypoint_resume, EV_COOKIE,
261 SDEI_REGF_RM_PE, read_mpidr_el1());
262 if (ret < 0) {
263 tftf_testcase_printf("SDEI event register failed: 0x%llx\n",
264 ret);
265 return TEST_RESULT_FAIL;
266 }
267
Igor Podgainõib32ccfe2025-02-27 23:48:45 +0100268 if (enable) {
269 ret = sdei_event_enable(0);
270 if (ret < 0) {
271 tftf_testcase_printf("SDEI event enable failed: 0x%llx\n", ret);
272 goto err0;
273 }
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200274 }
275
Igor Podgainõib32ccfe2025-02-27 23:48:45 +0100276 if (unmask) {
277 ret = sdei_pe_unmask();
278 if (ret < 0) {
279 tftf_testcase_printf("SDEI pe unmask failed: 0x%llx\n", ret);
280 goto err1;
281 }
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200282 }
283
284 ret = sdei_event_signal(read_mpidr_el1());
285 if (ret < 0) {
286 tftf_testcase_printf("SDEI event signal failed: 0x%llx\n", ret);
287 goto err2;
288 }
289
290 sdei_handler_done();
291
292err2:
293 sdei_pe_mask();
294err1:
295 sdei_event_disable(0);
296err0:
297 sdei_event_unregister(0);
298
299 if (ret < 0)
300 return TEST_RESULT_FAIL;
301
302 return TEST_RESULT_SUCCESS;
303}
304
Igor Podgainõib32ccfe2025-02-27 23:48:45 +0100305static test_result_t sdei_event_signal_self_all(void)
306{
307 return sdei_event_signal_self(true, true);
308}
309
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200310/* Each core signals itself using SDEI event signalling. */
311test_result_t test_sdei_event_signal_serial(void)
312{
313 u_register_t lead_mpid, target_mpid;
314 int cpu_node;
315 long long ret;
316
317 lead_mpid = read_mpidr_el1() & MPID_MASK;
318
319 ret = sdei_version();
320 if (ret != MAKE_SDEI_VERSION(1, 0, 0)) {
321 tftf_testcase_printf("Unexpected SDEI version: 0x%llx\n", ret);
322 return TEST_RESULT_SKIPPED;
323 }
324
325 disable_irq();
326 for_each_cpu(cpu_node) {
327 target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
328 if (lead_mpid == target_mpid)
329 continue;
330 ret = tftf_cpu_on(target_mpid,
Igor Podgainõib32ccfe2025-02-27 23:48:45 +0100331 (uintptr_t)sdei_event_signal_self_all, 0);
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200332 if (ret != PSCI_E_SUCCESS) {
Igor Podgainõib32ccfe2025-02-27 23:48:45 +0100333 ERROR("CPU ON failed for 0x%llx\n",
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200334 (unsigned long long)target_mpid);
335 ret = -1;
336 goto err0;
337 }
338 while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) !=
339 PSCI_STATE_OFF)
340 continue;
341 }
342
Igor Podgainõib32ccfe2025-02-27 23:48:45 +0100343 if (sdei_event_signal_self_all() != TEST_RESULT_SUCCESS) {
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200344 ret = -1;
345 goto err0;
346 }
347
348err0:
349 enable_irq();
350 if (ret < 0)
351 return TEST_RESULT_FAIL;
352 return TEST_RESULT_SUCCESS;
353}
354
355static event_t cpu_ready[PLATFORM_CORE_COUNT];
356
357static test_result_t sdei_wait_for_event_signal(void)
358{
359 int core_pos;
360 long long ret;
361
362 ret = sdei_event_register(0, sdei_entrypoint_resume, EV_COOKIE,
363 SDEI_REGF_RM_PE, read_mpidr_el1());
364 if (ret < 0) {
365 tftf_testcase_printf("SDEI event register failed: 0x%llx\n",
366 ret);
367 return TEST_RESULT_FAIL;
368 }
369
370 ret = sdei_event_enable(0);
371 if (ret < 0) {
372 tftf_testcase_printf("SDEI event enable failed: 0x%llx\n", ret);
373 goto err0;
374 }
375
376 ret = sdei_pe_unmask();
377 if (ret < 0) {
378 tftf_testcase_printf("SDEI pe unmask failed: 0x%llx\n", ret);
379 goto err1;
380 }
381
382 core_pos = platform_get_core_pos(read_mpidr_el1());
383 tftf_send_event(&cpu_ready[core_pos]);
384
385 sdei_handler_done();
386
387 sdei_pe_mask();
388err1:
389 sdei_event_disable(0);
390err0:
391 sdei_event_unregister(0);
392
393 if (ret < 0)
394 return TEST_RESULT_FAIL;
395
396 return TEST_RESULT_SUCCESS;
397}
398
399/*
400 * The primary core will signal all other cores
401 * use SDEI event signalling.
402 */
403test_result_t test_sdei_event_signal_all(void)
404{
405 u_register_t lead_mpid, target_mpid;
406 int cpu_node, core_pos;
407 int i;
408 long long ret;
409
410 for (i = 0; i < PLATFORM_CORE_COUNT; i++)
411 tftf_init_event(&cpu_ready[i]);
412
413 lead_mpid = read_mpidr_el1() & MPID_MASK;
414
415 ret = sdei_version();
416 if (ret != MAKE_SDEI_VERSION(1, 0, 0)) {
417 tftf_testcase_printf("Unexpected SDEI version: 0x%llx\n", ret);
418 return TEST_RESULT_SKIPPED;
419 }
420
421 disable_irq();
422 for_each_cpu(cpu_node) {
423 target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
424 if (lead_mpid == target_mpid)
425 continue;
426 ret = tftf_cpu_on(target_mpid,
427 (uintptr_t)sdei_wait_for_event_signal, 0);
428 if (ret != PSCI_E_SUCCESS) {
429 ERROR("CPU ON failed for 0x0x%llx\n",
430 (unsigned long long)target_mpid);
431 ret = -1;
432 goto err0;
433 }
434 core_pos = platform_get_core_pos(target_mpid);
435 tftf_wait_for_event(&cpu_ready[core_pos]);
436 }
437
438 for_each_cpu(cpu_node) {
439 target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
440 if (lead_mpid == target_mpid)
441 continue;
442 ret = sdei_event_signal(target_mpid);
443 if (ret < 0) {
444 tftf_testcase_printf("SDEI event signal failed: 0x%llx\n",
445 ret);
446 ret = -1;
447 goto err0;
448 }
449 }
450
451err0:
452 enable_irq();
453 if (ret < 0)
454 return TEST_RESULT_FAIL;
455 return TEST_RESULT_SUCCESS;
456}
Igor Podgainõib32ccfe2025-02-27 23:48:45 +0100457
458/* SDEI event signaling state should be: registered, enabled, unmasked */
459test_result_t test_sdei_event_signal_state(void)
460{
461 long long ret;
462
463 ret = sdei_version();
464 if (ret != MAKE_SDEI_VERSION(1, 0, 0)) {
465 tftf_testcase_printf("Unexpected SDEI version: 0x%llx\n", ret);
466 return TEST_RESULT_SKIPPED;
467 }
468
469 disable_irq();
470 if (sdei_event_signal_self(true, true) == TEST_RESULT_FAIL) {
471 tftf_testcase_printf("UNEXPECTED: SDEI event signaling failed when "
472 "enabled and unmasked\n");
473 ret = -1;
474 goto err0;
475 } else {
476 tftf_testcase_printf("EXPECTED: SDEI event signaling succeeded when "
477 "enabled and unmasked\n");
478 }
479
480 if (sdei_event_signal_self(false, true) == TEST_RESULT_SUCCESS) {
481 tftf_testcase_printf("UNEXPECTED: SDEI event signaling succeeded when "
482 "disabled and unmasked\n");
483 ret = -1;
484 goto err0;
485 } else {
486 tftf_testcase_printf("EXPECTED: SDEI event signaling failed when "
487 "disabled and unmasked\n");
488 }
489
490 if (sdei_event_signal_self(true, false) == TEST_RESULT_SUCCESS) {
491 tftf_testcase_printf("UNEXPECTED: SDEI event signaling succeeded when "
492 "enabled and masked\n");
493 ret = -1;
494 goto err0;
495 } else {
496 tftf_testcase_printf("EXPECTED: SDEI event signaling failed when "
497 "enabled and masked\n");
498 }
499
500 if (sdei_event_signal_self(false, false) == TEST_RESULT_SUCCESS) {
501 tftf_testcase_printf("UNEXPECTED: SDEI event signaling succeeded when "
502 "disabled and masked\n");
503 ret = -1;
504 goto err0;
505 } else {
506 tftf_testcase_printf("EXPECTED: SDEI event signaling failed when "
507 "disabled and masked\n");
508 }
509
510err0:
511 enable_irq();
512 if (ret < 0)
513 return TEST_RESULT_FAIL;
514 return TEST_RESULT_SUCCESS;
515}