blob: 6d248428e48536ac7cc7dfec7d5d84ef8d4f20bd [file] [log] [blame]
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <cactus_def.h>
#include <debug.h>
#include <events.h>
#include <ivy_def.h>
#include <plat_topology.h>
#include <platform.h>
#include <power_management.h>
#include <smccc.h>
#include <spci_helpers.h>
#include <spci_svc.h>
#include <test_helpers.h>
#include <tftf_lib.h>
#define TEST_NUM_ITERATIONS 1000U
static event_t cpu_has_entered_test[PLATFORM_CORE_COUNT];
static test_result_t test_spci_blocking_multicore_fn(void)
{
int ret;
uint16_t handle_cactus, handle_ivy;
u_register_t rx1, rx2, rx3;
test_result_t result = TEST_RESULT_SUCCESS;
u_register_t cpu_mpid = read_mpidr_el1() & MPID_MASK;
unsigned int core_pos = platform_get_core_pos(cpu_mpid);
tftf_send_event(&cpu_has_entered_test[core_pos]);
/* Open handles. */
ret = spci_service_handle_open(TFTF_SPCI_CLIENT_ID, &handle_cactus,
CACTUS_SERVICE1_UUID);
if (ret != SPCI_SUCCESS) {
tftf_testcase_printf("%d: SPM failed to return a valid handle. Returned: 0x%x\n",
__LINE__, (uint32_t)ret);
result = TEST_RESULT_FAIL;
goto exit_none;
}
ret = spci_service_handle_open(TFTF_SPCI_CLIENT_ID, &handle_ivy,
IVY_SERVICE1_UUID);
if (ret != SPCI_SUCCESS) {
tftf_testcase_printf("%d: SPM failed to return a valid handle. Returned: 0x%x\n",
__LINE__, (uint32_t)ret);
result = TEST_RESULT_FAIL;
goto exit_cactus;
}
/* Request services. */
for (unsigned int i = 0U; i < TEST_NUM_ITERATIONS; i++) {
/* Send request to Cactus */
ret = spci_service_request_blocking(CACTUS_GET_MAGIC,
0, 0, 0, 0, 0,
TFTF_SPCI_CLIENT_ID,
handle_cactus,
&rx1, &rx2, &rx3);
if (ret == SPCI_BUSY) {
/*
* Another CPU is already using Cactus, this is not a
* failure.
*/
} else if (ret == SPCI_SUCCESS) {
if (rx1 != CACTUS_MAGIC_NUMBER) {
tftf_testcase_printf("%d: Cactus returned 0x%x 0x%lx 0x%lx 0x%lx\n",
__LINE__, (uint32_t)ret, rx1, rx2, rx3);
result = TEST_RESULT_FAIL;
break;
}
} else {
tftf_testcase_printf("%d: SPM should have returned SPCI_SUCCESS. Returned: 0x%x\n",
__LINE__, (uint32_t)ret);
result = TEST_RESULT_FAIL;
break;
}
/* Send request to Ivy */
ret = spci_service_request_blocking(IVY_GET_MAGIC,
0, 0, 0, 0, 0,
TFTF_SPCI_CLIENT_ID,
handle_ivy,
&rx1, &rx2, &rx3);
if (ret == SPCI_BUSY) {
/*
* Another CPU is already using Ivy, this is not a
* failure.
*/
} else if (ret == SPCI_SUCCESS) {
if (rx1 != IVY_MAGIC_NUMBER) {
tftf_testcase_printf("%d: Ivy returned 0x%x 0x%lx 0x%lx 0x%lx\n",
__LINE__, (uint32_t)ret, rx1, rx2, rx3);
result = TEST_RESULT_FAIL;
break;
}
} else {
tftf_testcase_printf("%d: SPM should have returned SPCI_SUCCESS. Returned: 0x%x\n",
__LINE__, (uint32_t)ret);
result = TEST_RESULT_FAIL;
break;
}
}
/* Close handles. */
ret = spci_service_handle_close(TFTF_SPCI_CLIENT_ID, handle_ivy);
if (ret != SPCI_SUCCESS) {
tftf_testcase_printf("%d: SPM failed to close the handle. Returned: 0x%x\n",
__LINE__, (uint32_t)ret);
result = TEST_RESULT_FAIL;
}
exit_cactus:
ret = spci_service_handle_close(TFTF_SPCI_CLIENT_ID, handle_cactus);
if (ret != SPCI_SUCCESS) {
tftf_testcase_printf("%d: SPM failed to close the handle. Returned: 0x%x\n",
__LINE__, (uint32_t)ret);
result = TEST_RESULT_FAIL;
}
/* All tests finished. */
exit_none:
return result;
}
/*
* @Test_Aim@ This tests opens a Secure Service handle and performs many simple
* blocking requests to Cactus and Ivy from multiple cores
*/
test_result_t test_spci_blocking_request_multicore(void)
{
unsigned int cpu_node, core_pos;
int psci_ret;
u_register_t cpu_mpid;
u_register_t lead_mpid = read_mpidr_el1() & MPID_MASK;
SKIP_TEST_IF_SPCI_VERSION_LESS_THAN(0, 1);
for (int i = 0; i < PLATFORM_CORE_COUNT; i++) {
tftf_init_event(&cpu_has_entered_test[i]);
}
/* 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_mpid) {
continue;
}
psci_ret = tftf_cpu_on(cpu_mpid,
(uintptr_t)test_spci_blocking_multicore_fn, 0);
if (psci_ret != PSCI_E_SUCCESS) {
core_pos = platform_get_core_pos(cpu_mpid);
tftf_testcase_printf(
"Failed to power on CPU %d (rc = %d)\n",
core_pos, psci_ret);
return TEST_RESULT_FAIL;
}
}
/* Wait until all CPUs have started the test. */
for_each_cpu(cpu_node) {
cpu_mpid = tftf_get_mpidr_from_node(cpu_node);
/* Skip lead CPU */
if (cpu_mpid == lead_mpid) {
continue;
}
core_pos = platform_get_core_pos(cpu_mpid);
tftf_wait_for_event(&cpu_has_entered_test[core_pos]);
}
/* Enter the test on lead CPU and return the result. */
return test_spci_blocking_multicore_fn();
}