blob: 7a10e190df5901aa38a4fe79c16fc695fd68f4b7 [file] [log] [blame]
/*
* Copyright (c) 2018, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <debug.h>
#include <events.h>
#include <nvm.h>
#include <plat_topology.h>
#include <platform.h>
#include <platform_def.h>
#include <power_management.h>
#include <psci.h>
#include <tftf_lib.h>
#define PER_CPU_BUFFER_OFFSET 0x08
/* Events to specify activity to lead cpu */
static event_t cpu_ready[PLATFORM_CORE_COUNT];
static event_t test_done[PLATFORM_CORE_COUNT];
/* Used to make concurrent access to flash by all the cores */
static volatile int cpu_concurrent_write;
/*
* @Test_Aim@ Test Non-Volatile Memory support
*
* Try reading/writing data from/to NVM to check that basic NVM support is
* working as expected.
*/
test_result_t test_validation_nvm(void)
{
STATUS status;
unsigned test_value1 = 0x12345678;
unsigned test_value2 = 0;
/* Write a value in NVM */
status = tftf_nvm_write(TFTF_STATE_OFFSET(testcase_buffer),
&test_value1, sizeof(test_value1));
if (status != STATUS_SUCCESS) {
tftf_testcase_printf("tftf_nvm_write: error %d\n", status);
return TEST_RESULT_FAIL;
}
/* Read it back from NVM */
status = tftf_nvm_read(TFTF_STATE_OFFSET(testcase_buffer),
&test_value2, sizeof(test_value2));
if (status != STATUS_SUCCESS) {
tftf_testcase_printf("tftf_nvm_read: error (%d)\n", status);
return TEST_RESULT_FAIL;
}
/* Check that the 2 values match */
if (test_value1 != test_value2) {
tftf_testcase_printf("Values mismatch: %u != %u\n",
test_value1, test_value2);
return TEST_RESULT_FAIL;
}
return TEST_RESULT_SUCCESS;
}
/* Odd CPU's write to flash and even CPU's read the flash */
static unsigned int access_flash_concurrent(unsigned int core_pos)
{
unsigned int ret;
unsigned int test_value;
if (core_pos % 2) {
ret = tftf_nvm_write(TFTF_STATE_OFFSET(testcase_buffer)
+ core_pos * PER_CPU_BUFFER_OFFSET,
&core_pos, sizeof(core_pos));
if (ret != STATUS_SUCCESS) {
tftf_testcase_printf("Write failed\n");
return TEST_RESULT_FAIL;
}
} else {
/* Dummy read */
ret = tftf_nvm_read(TFTF_STATE_OFFSET(testcase_buffer),
&test_value, sizeof(test_value));
if (ret != STATUS_SUCCESS) {
tftf_testcase_printf("Read failed\n");
return TEST_RESULT_FAIL;
}
}
return TEST_RESULT_SUCCESS;
}
/*
* @Test_Aim@ Test concurrent memory access to Non-Volatile Memory
*
* Try reading/writing data from multiple cores to NVM and verify the operations are
* serialised and also the device does not crash.
*
*/
static test_result_t test_validate_nvm_secondary(void)
{
unsigned int mpid = read_mpidr_el1();
unsigned int core_pos = platform_get_core_pos(mpid);
unsigned int ret;
tftf_send_event(&cpu_ready[core_pos]);
/* Wait until all cores are ready to access simultaneously */
while (!cpu_concurrent_write)
;
ret = access_flash_concurrent(core_pos);
tftf_send_event(&test_done[core_pos]);
return ret;
}
/*
* @Test_Aim@ Test serialisation of access by multiple CPU's
*
* Try reading/writing data to flash from all the CPU's with as much
* concurrency as possible. Check the device does not hang and also
* the update to flash happened as expected
*/
test_result_t test_validate_nvm_serialisation(void)
{
unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
unsigned int target_mpid, target_node;
unsigned int core_pos;
unsigned int lead_core_pos;
unsigned int test_value;
unsigned int ret;
int rc;
char init_buffer[TEST_BUFFER_SIZE] = {0};
/* Initialise the scratch flash */
ret = tftf_nvm_write(TFTF_STATE_OFFSET(testcase_buffer),
&init_buffer,
sizeof(init_buffer));
if (ret != STATUS_SUCCESS) {
tftf_testcase_printf("Write failed\n");
return TEST_RESULT_FAIL;
}
/* Power on all the cores */
for_each_cpu(target_node) {
target_mpid = tftf_get_mpidr_from_node(target_node);
/* Skip lead CPU as it is already on */
if (target_mpid == lead_mpid)
continue;
rc = tftf_cpu_on(target_mpid,
(uintptr_t) test_validate_nvm_secondary,
0);
if (rc != PSCI_E_SUCCESS) {
tftf_testcase_printf("Failed to power on CPU 0x%x (%d)\n",
target_mpid, rc);
return TEST_RESULT_SKIPPED;
}
}
/* Wait for all non-lead CPU's to be ready */
for_each_cpu(target_node) {
target_mpid = tftf_get_mpidr_from_node(target_node);
/* Skip lead CPU */
if (target_mpid == lead_mpid)
continue;
core_pos = platform_get_core_pos(target_mpid);
tftf_wait_for_event(&cpu_ready[core_pos]);
}
lead_core_pos = platform_get_core_pos(read_mpidr_el1());
/*
* Send event to all CPU's so that we can have as much concurrent
* access to flash as possible
*/
cpu_concurrent_write = 1;
ret = access_flash_concurrent(lead_core_pos);
if (ret != TEST_RESULT_SUCCESS)
return ret;
/* Wait for all non-lead CPU's to complete the test */
for_each_cpu(target_node) {
target_mpid = tftf_get_mpidr_from_node(target_node);
/* Skip lead CPU */
if (target_mpid == lead_mpid)
continue;
core_pos = platform_get_core_pos(target_mpid);
tftf_wait_for_event(&test_done[core_pos]);
}
/* Validate the results */
for_each_cpu(target_node) {
target_mpid = tftf_get_mpidr_from_node(target_node);
core_pos = platform_get_core_pos(target_mpid);
tftf_nvm_read(TFTF_STATE_OFFSET(testcase_buffer) +
core_pos * PER_CPU_BUFFER_OFFSET,
&test_value,
sizeof(test_value));
if ((core_pos % 2) && (test_value != core_pos)) {
tftf_testcase_printf("Concurrent flash access test "
"failed on cpu index: %d test_value:%d \n",
core_pos, test_value);
return TEST_RESULT_FAIL;
} else if (((core_pos % 2) == 0) && (test_value != 0)) {
tftf_testcase_printf("Concurrent flash access test "
"failed on cpu index: %d test_value:%d \n",
core_pos, test_value);
return TEST_RESULT_FAIL;
}
}
return TEST_RESULT_SUCCESS;
}