diff options
author | Madhukar Pappireddy <madhukar.pappireddy@arm.com> | 2020-12-31 19:25:33 -0600 |
---|---|---|
committer | Madhukar Pappireddy <madhukar.pappireddy@arm.com> | 2021-04-30 09:31:53 -0500 |
commit | 172523b9ceadd0af9f6e8e4fb899cc7f354ff002 (patch) | |
tree | ef3d02c2953b208aa5e1c84a23bc58a117f27e9a /spm/cactus/cactus_tests | |
parent | c5b60fce76bd56739c909fa0d5ac53d482171c88 (diff) |
Cactus test for exercising SMMUv3 driver to perform stage2 translation
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
Change-Id: I498cb63aed497ab469a38e486a7943dd634e5b36
Diffstat (limited to 'spm/cactus/cactus_tests')
-rw-r--r-- | spm/cactus/cactus_tests/cactus_tests_smmuv3.c | 175 | ||||
-rw-r--r-- | spm/cactus/cactus_tests/smmuv3_test_engine.h | 45 |
2 files changed, 220 insertions, 0 deletions
diff --git a/spm/cactus/cactus_tests/cactus_tests_smmuv3.c b/spm/cactus/cactus_tests/cactus_tests_smmuv3.c new file mode 100644 index 0000000..ce53dc6 --- /dev/null +++ b/spm/cactus/cactus_tests/cactus_tests_smmuv3.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> + +#include <arch_helpers.h> +#include "cactus.h" +#include "cactus_message_loop.h" +#include <cactus_platform_def.h> +#include "cactus_test_cmds.h" +#include "cactus_tests.h" +#include <debug.h> +#include <ffa_helpers.h> +#include <mmio.h> +#include "smmuv3_test_engine.h" +#include <sp_helpers.h> +#include <spm_common.h> + +/* Source and target address for memcopy operation */ +#define MEMCPY_SOURCE_BASE PLAT_CACTUS_MEMCPY_BASE +#define MEMPCY_TOTAL_SIZE (PLAT_CACTUS_MEMCPY_RANGE / 2) +#define MEMCPY_TARGET_BASE (MEMCPY_SOURCE_BASE + MEMPCY_TOTAL_SIZE) + +/* Miscellaneous */ +#define NO_SUBSTREAMID (0xFFFFFFFFU) +#define TRANSFER_SIZE (MEMPCY_TOTAL_SIZE / FRAME_COUNT) +#define LOOP_COUNT (5000U) + +static bool run_smmuv3_test(void) +{ + uint64_t source_addr, cpy_range, target_addr; + uint64_t begin_addr, end_addr, dest_addr; + uint32_t status; + unsigned int i, f, attempts; + + /* + * The test engine's MEMCPY command copies data from the region in + * range [begin, end_incl] to the region with base address as udata. + * In this test, we configure the test engine to initiate memcpy from + * scratch page located at MEMCPY_SOURCE_BASE to the page located at + * address MEMCPY_TARGET_BASE + */ + + VERBOSE("CACTUS: Running SMMUv3 test\n"); + + source_addr = MEMCPY_SOURCE_BASE; + cpy_range = MEMPCY_TOTAL_SIZE; + target_addr = MEMCPY_TARGET_BASE; + uint32_t streamID_list[] = { 0U, 1U }; + + uint64_t data[] = { + ULL(0xBAADFEEDCEEBDAAF), + ULL(0x0123456776543210) + }; + + /* Write pre-determined content to source pages */ + for (i = 0U; i < (cpy_range / 8U); i++) { + mmio_write64_offset(source_addr, i * 8, data[i%2]); + } + + /* Clean the data caches */ + clean_dcache_range(source_addr, cpy_range); + + /* + * Make sure above load, store and cache maintenance instructions + * complete before we start writing to TestEngine frame configuration + * fields + */ + dsbsy(); + + for (f = 0U; f < FRAME_COUNT; f++) { + attempts = 0U; + begin_addr = source_addr + (TRANSFER_SIZE * f); + end_addr = begin_addr + TRANSFER_SIZE - 1U; + dest_addr = target_addr + (TRANSFER_SIZE * f); + + /* Initiate DMA sequence */ + mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), PCTRL_OFF, 0); + mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), DOWNSTREAM_PORT_OFF, 0); + mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), STREAM_ID_OFF, streamID_list[f%2]); + mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), SUBSTREAM_ID_OFF, NO_SUBSTREAMID); + + mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), UCTRL_OFF, 0); + mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), SEED_OFF, 0); + mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), BEGIN_OFF, begin_addr); + mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), END_CTRL_OFF, end_addr); + + /* Legal values for stride: 1 and any multiples of 8 */ + mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), STRIDE_OFF, 1); + mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), UDATA_OFF, dest_addr); + + mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), CMD_OFF, ENGINE_MEMCPY); + VERBOSE("SMMUv3TestEngine: Waiting for MEMCPY completion for frame: %u\n", f); + + /* + * It is guaranteed that a read of "cmd" fields after writing to it will + * immediately return ENGINE_FRAME_MISCONFIGURED if the command was + * invalid. + */ + if (mmio_read32_offset(USR_BASE_FRAME + F_IDX(f), CMD_OFF) == ENGINE_MIS_CFG) { + ERROR("SMMUv3TestEngine: Misconfigured for frame: %u\n", f); + return false; + } + + /* Wait for mem copy to be complete */ + while (attempts++ < LOOP_COUNT) { + status = mmio_read32_offset(USR_BASE_FRAME + F_IDX(f), CMD_OFF); + if (status == ENGINE_HALTED) { + break; + } else if (status == ENGINE_ERROR) { + ERROR("SMMUv3: Test failed\n"); + return false; + } + + /* + * TODO: Introduce a small delay here to make sure the + * CPU memory accesses do not starve the interconnect + * due to continuous polling. + */ + } + + if (attempts == LOOP_COUNT) { + ERROR("SMMUv3: Test failed\n"); + return false; + } + + dsbsy(); + } + + /* + * Invalidate cached entries to force the CPU to fetch the data from + * Main memory + */ + inv_dcache_range(source_addr, cpy_range); + inv_dcache_range(target_addr, cpy_range); + + /* Compare source and destination memory locations for data */ + for (i = 0U; i < (cpy_range / 8U); i++) { + if (mmio_read_64(source_addr + 8 * i) != mmio_read_64(target_addr + 8 * i)) { + ERROR("SMMUv3: Mem copy failed: %llx\n", target_addr + 8 * i); + return false; + } + } + + return true; +} + +CACTUS_CMD_HANDLER(smmuv3_cmd, CACTUS_DMA_SMMUv3_CMD) +{ + smc_ret_values ffa_ret; + ffa_vm_id_t vm_id = ffa_dir_msg_dest(*args); + ffa_vm_id_t source = ffa_dir_msg_source(*args); + + VERBOSE("Received request through direct message for DMA service\n"); + + /* + * At present, the test cannot be run concurrently on multiple SPs as + * there is only one SMMUv3TestEngine IP in the FVP model. Hence, run + * the test only on the first SP. + */ + if (vm_id != SPM_VM_ID_FIRST) { + return cactus_error_resp(vm_id, source, 0); + } + + if (run_smmuv3_test()) { + ffa_ret = cactus_success_resp(vm_id, source, 0); + } else { + ffa_ret = cactus_error_resp(vm_id, source, 0); + } + + return ffa_ret; +} diff --git a/spm/cactus/cactus_tests/smmuv3_test_engine.h b/spm/cactus/cactus_tests/smmuv3_test_engine.h new file mode 100644 index 0000000..32d86ac --- /dev/null +++ b/spm/cactus/cactus_tests/smmuv3_test_engine.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* The test engine supports numerous frames but we only use a few */ +#define FRAME_COUNT (2U) +#define FRAME_SIZE (0x80U) /* 128 bytes */ +#define F_IDX(n) (n * FRAME_SIZE) + +/* Commands supported by SMMUv3TestEngine built into the AEM */ +#define ENGINE_NO_FRAME (0U) +#define ENGINE_HALTED (1U) + +/* + * ENGINE_MEMCPY: Read and Write transactions + * ENGINE_RAND48: Only Write transactions: Source address not required + * ENGINE_SUM64: Only read transactions: Target address not required + */ +#define ENGINE_MEMCPY (2U) +#define ENGINE_RAND48 (3U) +#define ENGINE_SUM64 (4U) +#define ENGINE_ERROR (0xFFFFFFFFU) +#define ENGINE_MIS_CFG (ENGINE_ERROR - 1) + +/* + * Refer to: + * https://developer.arm.com/documentation/100964/1111-00/Trace-components/SMMUv3TestEngine---trace + */ + +/* Offset of various control fields belonging to User Frame */ +#define CMD_OFF (0x0U) +#define UCTRL_OFF (0x4U) +#define SEED_OFF (0x24U) +#define BEGIN_OFF (0x28U) +#define END_CTRL_OFF (0x30U) +#define STRIDE_OFF (0x38U) +#define UDATA_OFF (0x40U) + +/* Offset of various control fields belonging to PRIV Frame */ +#define PCTRL_OFF (0x0U) +#define DOWNSTREAM_PORT_OFF (0x4U) +#define STREAM_ID_OFF (0x8U) +#define SUBSTREAM_ID_OFF (0xCU) |