| /* |
| * Copyright (c) 2018-2025, Arm Limited. All rights reserved. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| #include <arch_helpers.h> |
| #include <events.h> |
| #include <plat_topology.h> |
| #include <platform.h> |
| #include <power_management.h> |
| #include <psci.h> |
| #include <tftf_lib.h> |
| |
| /* Events structures used by this test case */ |
| static event_t lead_cpu_event; |
| static event_t cpu_has_entered_test[PLATFORM_CORE_COUNT]; |
| static event_t test_is_finished; |
| |
| volatile bool last_event_ready; |
| |
| static test_result_t non_lead_cpu_fn(void) |
| { |
| unsigned int mpid = read_mpidr_el1() & MPID_MASK; |
| unsigned int core_pos = platform_get_core_pos(mpid); |
| |
| /* Signal to the lead CPU that the calling CPU has entered the test */ |
| tftf_send_event(&cpu_has_entered_test[core_pos]); |
| |
| tftf_wait_for_event(&lead_cpu_event); |
| |
| /* |
| * Wait for lead CPU's signal before exiting the test. |
| * Wait for the lead CPU to send the event before the non-lead CPUs wait |
| * for it. |
| */ |
| while (!last_event_ready); |
| tftf_wait_for_event(&test_is_finished); |
| |
| return TEST_RESULT_SUCCESS; |
| } |
| |
| /* |
| * @Test_Aim@ Validate the events API |
| * |
| * This test exercises the events API. |
| * - It creates a sequence of events sending and receiving. The order of |
| * operations is ensured by synchronizing at strategic points. |
| * - It tests the communication in both directions (i.e. from CPUx to CPUy and |
| * vice versa). |
| * - It tests that it doesn't matter whether CPUx waits for the event first |
| * then CPUy sends the event, or that things happen in the other order. |
| * - It tests the API on a single CPU. |
| * |
| * This test is skipped if an error occurs during the bring-up of non-lead CPUs. |
| * Otherwise, this test always returns success. If something goes wrong, the |
| * test will most probably hang because the system will go into a WFE/SEV dead |
| * lock. |
| */ |
| test_result_t test_validation_events(void) |
| { |
| unsigned int lead_cpu; |
| unsigned int cpu_mpid; |
| unsigned int cpu_node; |
| unsigned int core_pos; |
| unsigned int cpus_count; |
| int psci_ret; |
| |
| /* initialise as not ready */ |
| last_event_ready = false; |
| |
| lead_cpu = read_mpidr_el1() & MPID_MASK; |
| |
| /* |
| * The events API should work on a single CPU, provided that the event |
| * is sent before we wait for it. If we do things the other way around, |
| * the CPU will end up stuck in WFE state. |
| */ |
| tftf_send_event(&lead_cpu_event); |
| tftf_wait_for_event(&lead_cpu_event); |
| |
| /* Re-init lead_cpu_event to be able to reuse it */ |
| tftf_init_event(&lead_cpu_event); |
| |
| /* Power on all CPUs */ |
| for_each_cpu(cpu_node) { |
| cpu_mpid = tftf_get_mpidr_from_node(cpu_node); |
| /* Skip lead CPU as it is already powered on */ |
| if (cpu_mpid == lead_cpu) |
| continue; |
| |
| psci_ret = tftf_cpu_on(cpu_mpid, (uintptr_t) non_lead_cpu_fn, 0); |
| if (psci_ret != PSCI_E_SUCCESS) { |
| tftf_testcase_printf( |
| "Failed to power on CPU 0x%x (%d)\n", |
| cpu_mpid, psci_ret); |
| return TEST_RESULT_SKIPPED; |
| } |
| } |
| |
| /* Wait for all CPUs to have entered the test */ |
| for_each_cpu(cpu_node) { |
| cpu_mpid = tftf_get_mpidr_from_node(cpu_node); |
| if (cpu_mpid == lead_cpu) |
| continue; |
| |
| core_pos = platform_get_core_pos(cpu_mpid); |
| tftf_wait_for_event(&cpu_has_entered_test[core_pos]); |
| } |
| |
| /* |
| * Send the event to half of the CPUs. Some should already be waiting, |
| * as they signalled entering the test. |
| */ |
| cpus_count = PLATFORM_CORE_COUNT / 2; |
| tftf_send_event_to(&lead_cpu_event, cpus_count); |
| /* Send the event to the other half of the CPUs */ |
| tftf_send_event_to(&lead_cpu_event, PLATFORM_CORE_COUNT - cpus_count); |
| |
| /* Signal termination of the test to all CPUs */ |
| tftf_send_event_to_all(&test_is_finished); |
| |
| /* Signal the last event has been sent so secondaries can wait() */ |
| last_event_ready = true; |
| |
| return TEST_RESULT_SUCCESS; |
| } |