blob: fbf46c8063ac57966a36bb96f2680fcce6743d4c [file] [log] [blame]
Madhukar Pappireddy172523b2020-12-31 19:25:33 -06001/*
2 * Copyright (c) 2021, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <stdint.h>
8
9#include <arch_helpers.h>
10#include "cactus.h"
11#include "cactus_message_loop.h"
12#include <cactus_platform_def.h>
13#include "cactus_test_cmds.h"
14#include "cactus_tests.h"
15#include <debug.h>
16#include <ffa_helpers.h>
17#include <mmio.h>
18#include "smmuv3_test_engine.h"
19#include <sp_helpers.h>
20#include <spm_common.h>
21
22/* Source and target address for memcopy operation */
23#define MEMCPY_SOURCE_BASE PLAT_CACTUS_MEMCPY_BASE
24#define MEMPCY_TOTAL_SIZE (PLAT_CACTUS_MEMCPY_RANGE / 2)
25#define MEMCPY_TARGET_BASE (MEMCPY_SOURCE_BASE + MEMPCY_TOTAL_SIZE)
26
27/* Miscellaneous */
28#define NO_SUBSTREAMID (0xFFFFFFFFU)
29#define TRANSFER_SIZE (MEMPCY_TOTAL_SIZE / FRAME_COUNT)
30#define LOOP_COUNT (5000U)
31
32static bool run_smmuv3_test(void)
33{
34 uint64_t source_addr, cpy_range, target_addr;
35 uint64_t begin_addr, end_addr, dest_addr;
36 uint32_t status;
37 unsigned int i, f, attempts;
38
39 /*
40 * The test engine's MEMCPY command copies data from the region in
41 * range [begin, end_incl] to the region with base address as udata.
42 * In this test, we configure the test engine to initiate memcpy from
43 * scratch page located at MEMCPY_SOURCE_BASE to the page located at
44 * address MEMCPY_TARGET_BASE
45 */
46
47 VERBOSE("CACTUS: Running SMMUv3 test\n");
48
49 source_addr = MEMCPY_SOURCE_BASE;
50 cpy_range = MEMPCY_TOTAL_SIZE;
51 target_addr = MEMCPY_TARGET_BASE;
52 uint32_t streamID_list[] = { 0U, 1U };
53
54 uint64_t data[] = {
55 ULL(0xBAADFEEDCEEBDAAF),
56 ULL(0x0123456776543210)
57 };
58
59 /* Write pre-determined content to source pages */
60 for (i = 0U; i < (cpy_range / 8U); i++) {
61 mmio_write64_offset(source_addr, i * 8, data[i%2]);
62 }
63
64 /* Clean the data caches */
65 clean_dcache_range(source_addr, cpy_range);
66
67 /*
68 * Make sure above load, store and cache maintenance instructions
69 * complete before we start writing to TestEngine frame configuration
70 * fields
71 */
72 dsbsy();
73
74 for (f = 0U; f < FRAME_COUNT; f++) {
75 attempts = 0U;
76 begin_addr = source_addr + (TRANSFER_SIZE * f);
77 end_addr = begin_addr + TRANSFER_SIZE - 1U;
78 dest_addr = target_addr + (TRANSFER_SIZE * f);
79
80 /* Initiate DMA sequence */
81 mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), PCTRL_OFF, 0);
82 mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), DOWNSTREAM_PORT_OFF, 0);
83 mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), STREAM_ID_OFF, streamID_list[f%2]);
84 mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), SUBSTREAM_ID_OFF, NO_SUBSTREAMID);
85
86 mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), UCTRL_OFF, 0);
87 mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), SEED_OFF, 0);
88 mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), BEGIN_OFF, begin_addr);
89 mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), END_CTRL_OFF, end_addr);
90
91 /* Legal values for stride: 1 and any multiples of 8 */
92 mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), STRIDE_OFF, 1);
93 mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), UDATA_OFF, dest_addr);
94
95 mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), CMD_OFF, ENGINE_MEMCPY);
96 VERBOSE("SMMUv3TestEngine: Waiting for MEMCPY completion for frame: %u\n", f);
97
98 /*
99 * It is guaranteed that a read of "cmd" fields after writing to it will
100 * immediately return ENGINE_FRAME_MISCONFIGURED if the command was
101 * invalid.
102 */
103 if (mmio_read32_offset(USR_BASE_FRAME + F_IDX(f), CMD_OFF) == ENGINE_MIS_CFG) {
104 ERROR("SMMUv3TestEngine: Misconfigured for frame: %u\n", f);
105 return false;
106 }
107
108 /* Wait for mem copy to be complete */
109 while (attempts++ < LOOP_COUNT) {
110 status = mmio_read32_offset(USR_BASE_FRAME + F_IDX(f), CMD_OFF);
111 if (status == ENGINE_HALTED) {
112 break;
113 } else if (status == ENGINE_ERROR) {
114 ERROR("SMMUv3: Test failed\n");
115 return false;
116 }
117
118 /*
119 * TODO: Introduce a small delay here to make sure the
120 * CPU memory accesses do not starve the interconnect
121 * due to continuous polling.
122 */
123 }
124
125 if (attempts == LOOP_COUNT) {
126 ERROR("SMMUv3: Test failed\n");
127 return false;
128 }
129
130 dsbsy();
131 }
132
133 /*
134 * Invalidate cached entries to force the CPU to fetch the data from
135 * Main memory
136 */
137 inv_dcache_range(source_addr, cpy_range);
138 inv_dcache_range(target_addr, cpy_range);
139
140 /* Compare source and destination memory locations for data */
141 for (i = 0U; i < (cpy_range / 8U); i++) {
142 if (mmio_read_64(source_addr + 8 * i) != mmio_read_64(target_addr + 8 * i)) {
143 ERROR("SMMUv3: Mem copy failed: %llx\n", target_addr + 8 * i);
144 return false;
145 }
146 }
147
148 return true;
149}
150
151CACTUS_CMD_HANDLER(smmuv3_cmd, CACTUS_DMA_SMMUv3_CMD)
152{
153 smc_ret_values ffa_ret;
Daniel Boulbye79d2072021-03-03 11:34:53 +0000154 ffa_id_t vm_id = ffa_dir_msg_dest(*args);
155 ffa_id_t source = ffa_dir_msg_source(*args);
Madhukar Pappireddy172523b2020-12-31 19:25:33 -0600156
157 VERBOSE("Received request through direct message for DMA service\n");
158
159 /*
160 * At present, the test cannot be run concurrently on multiple SPs as
161 * there is only one SMMUv3TestEngine IP in the FVP model. Hence, run
162 * the test only on the first SP.
163 */
164 if (vm_id != SPM_VM_ID_FIRST) {
165 return cactus_error_resp(vm_id, source, 0);
166 }
167
168 if (run_smmuv3_test()) {
169 ffa_ret = cactus_success_resp(vm_id, source, 0);
170 } else {
171 ffa_ret = cactus_error_resp(vm_id, source, 0);
172 }
173
174 return ffa_ret;
175}