Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 1 | /* |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 2 | * Copyright (c) 2021-2023, Arm Limited. All rights reserved. |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 3 | * |
| 4 | * SPDX-License-Identifier: BSD-3-Clause |
| 5 | */ |
| 6 | |
| 7 | #include <stdint.h> |
| 8 | |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 9 | #include <assert.h> |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 10 | #include "cactus.h" |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 11 | #include <arch_helpers.h> |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 12 | #include "cactus_message_loop.h" |
Daniel Boulby | f3da591 | 2022-04-01 12:31:52 +0100 | [diff] [blame] | 13 | #include <sp_platform_def.h> |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 14 | #include "cactus_test_cmds.h" |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 15 | #include <debug.h> |
| 16 | #include <ffa_helpers.h> |
| 17 | #include <mmio.h> |
| 18 | #include "smmuv3_test_engine.h" |
| 19 | #include <sp_helpers.h> |
Daniel Boulby | f3da591 | 2022-04-01 12:31:52 +0100 | [diff] [blame] | 20 | #include "sp_tests.h" |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 21 | #include <spm_common.h> |
| 22 | |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 23 | /* Miscellaneous */ |
| 24 | #define NO_SUBSTREAMID (0xFFFFFFFFU) |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 25 | #define LOOP_COUNT (5000U) |
| 26 | |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 27 | static bool run_testengine(uint32_t operation, uintptr_t source_addr, |
| 28 | uintptr_t target_addr, size_t transfer_size, |
| 29 | uint32_t attributes) |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 30 | { |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 31 | const uint32_t streamID_list[] = { 0U, 1U }; |
| 32 | uintptr_t begin_addr; |
| 33 | uintptr_t end_addr; |
| 34 | uintptr_t dest_addr; |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 35 | uint32_t status; |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 36 | uint32_t f; |
| 37 | uint32_t attempts; |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 38 | |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 39 | assert(operation == ENGINE_MEMCPY || operation == ENGINE_RAND48); |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 40 | |
| 41 | for (f = 0U; f < FRAME_COUNT; f++) { |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 42 | begin_addr = source_addr + (transfer_size * f); |
| 43 | end_addr = begin_addr + transfer_size - 1U; |
| 44 | |
| 45 | if (operation == ENGINE_MEMCPY) { |
| 46 | dest_addr = target_addr + (transfer_size * f); |
| 47 | } else { |
| 48 | dest_addr = 0; |
| 49 | } |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 50 | |
| 51 | /* Initiate DMA sequence */ |
| 52 | mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), PCTRL_OFF, 0); |
| 53 | mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), DOWNSTREAM_PORT_OFF, 0); |
| 54 | mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), STREAM_ID_OFF, streamID_list[f%2]); |
| 55 | mmio_write32_offset(PRIV_BASE_FRAME + F_IDX(f), SUBSTREAM_ID_OFF, NO_SUBSTREAMID); |
| 56 | |
| 57 | mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), UCTRL_OFF, 0); |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 58 | mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), ATTR_OFF, attributes); |
| 59 | |
| 60 | if (operation == ENGINE_RAND48) { |
| 61 | mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), SEED_OFF, (f + 1) * 42); |
| 62 | } |
| 63 | |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 64 | mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), BEGIN_OFF, begin_addr); |
| 65 | mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), END_CTRL_OFF, end_addr); |
| 66 | |
| 67 | /* Legal values for stride: 1 and any multiples of 8 */ |
| 68 | mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), STRIDE_OFF, 1); |
| 69 | mmio_write64_offset(USR_BASE_FRAME + F_IDX(f), UDATA_OFF, dest_addr); |
| 70 | |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 71 | mmio_write32_offset(USR_BASE_FRAME + F_IDX(f), CMD_OFF, operation); |
| 72 | VERBOSE("SMMUv3TestEngine: waiting completion for frame: %u\n", f); |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 73 | |
| 74 | /* |
| 75 | * It is guaranteed that a read of "cmd" fields after writing to it will |
| 76 | * immediately return ENGINE_FRAME_MISCONFIGURED if the command was |
| 77 | * invalid. |
| 78 | */ |
| 79 | if (mmio_read32_offset(USR_BASE_FRAME + F_IDX(f), CMD_OFF) == ENGINE_MIS_CFG) { |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 80 | ERROR("SMMUv3TestEngine: misconfigured for frame: %u\n", f); |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 81 | return false; |
| 82 | } |
| 83 | |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 84 | /* Wait for operation to be complete */ |
| 85 | attempts = 0U; |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 86 | while (attempts++ < LOOP_COUNT) { |
| 87 | status = mmio_read32_offset(USR_BASE_FRAME + F_IDX(f), CMD_OFF); |
| 88 | if (status == ENGINE_HALTED) { |
| 89 | break; |
| 90 | } else if (status == ENGINE_ERROR) { |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 91 | ERROR("SMMUv3: test failed, engine error.\n"); |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 92 | return false; |
| 93 | } |
| 94 | |
| 95 | /* |
| 96 | * TODO: Introduce a small delay here to make sure the |
| 97 | * CPU memory accesses do not starve the interconnect |
| 98 | * due to continuous polling. |
| 99 | */ |
| 100 | } |
| 101 | |
| 102 | if (attempts == LOOP_COUNT) { |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 103 | ERROR("SMMUv3: test failed, exceeded max. wait loop.\n"); |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 104 | return false; |
| 105 | } |
| 106 | |
| 107 | dsbsy(); |
| 108 | } |
| 109 | |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 110 | return true; |
| 111 | } |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 112 | |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 113 | static bool run_smmuv3_memcpy(uintptr_t start_address, size_t size, uint32_t attributes) |
| 114 | { |
| 115 | uintptr_t target_address; |
| 116 | size_t cpy_range = size >> 1; |
| 117 | bool ret; |
| 118 | |
| 119 | /* |
| 120 | * The test engine's MEMCPY command copies data from the region in |
| 121 | * range [begin, end_incl] to the region with base address as udata. |
| 122 | * In this test, we configure the test engine to initiate memcpy from |
| 123 | * scratch page located at MEMCPY_SOURCE_BASE to the page located at |
| 124 | * address MEMCPY_TARGET_BASE |
| 125 | */ |
| 126 | |
| 127 | target_address = start_address + cpy_range; |
| 128 | ret = run_testengine(ENGINE_MEMCPY, start_address, target_address, |
| 129 | cpy_range / FRAME_COUNT, attributes); |
| 130 | |
| 131 | if (ret) { |
| 132 | /* |
| 133 | * Invalidate cached entries to force the CPU to fetch the data from |
| 134 | * Main memory |
| 135 | */ |
| 136 | inv_dcache_range(start_address, cpy_range); |
| 137 | inv_dcache_range(target_address, cpy_range); |
| 138 | |
| 139 | /* Compare source and destination memory locations for data */ |
| 140 | for (size_t i = 0U; i < (cpy_range / 8U); i++) { |
| 141 | if (mmio_read_64(start_address + 8 * i) != |
| 142 | mmio_read_64(target_address + 8 * i)) { |
| 143 | ERROR("SMMUv3: Mem copy failed: %lx\n", target_address + 8 * i); |
| 144 | return false; |
| 145 | } |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 146 | } |
| 147 | } |
| 148 | |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 149 | return ret; |
| 150 | } |
| 151 | |
| 152 | static bool run_smmuv3_rand48(uintptr_t start_address, size_t size, uint32_t attributes) |
| 153 | { |
| 154 | return run_testengine(ENGINE_RAND48, start_address, 0, size / FRAME_COUNT, attributes); |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 155 | } |
| 156 | |
| 157 | CACTUS_CMD_HANDLER(smmuv3_cmd, CACTUS_DMA_SMMUv3_CMD) |
| 158 | { |
Daniel Boulby | e79d207 | 2021-03-03 11:34:53 +0000 | [diff] [blame] | 159 | ffa_id_t vm_id = ffa_dir_msg_dest(*args); |
| 160 | ffa_id_t source = ffa_dir_msg_source(*args); |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 161 | uint32_t operation = args->arg4; |
| 162 | uintptr_t start_address = args->arg5; |
| 163 | size_t size = args->arg6; |
| 164 | uint32_t attributes = args->arg7; |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 165 | |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 166 | VERBOSE("Received request through direct message for DMA service.\n"); |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 167 | |
| 168 | /* |
| 169 | * At present, the test cannot be run concurrently on multiple SPs as |
| 170 | * there is only one SMMUv3TestEngine IP in the FVP model. Hence, run |
| 171 | * the test only on the first SP. |
| 172 | */ |
| 173 | if (vm_id != SPM_VM_ID_FIRST) { |
| 174 | return cactus_error_resp(vm_id, source, 0); |
| 175 | } |
| 176 | |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 177 | switch (operation) { |
| 178 | case ENGINE_MEMCPY: |
| 179 | if (run_smmuv3_memcpy(start_address, size, attributes)) { |
| 180 | return cactus_success_resp(vm_id, source, 0); |
| 181 | } |
| 182 | break; |
| 183 | case ENGINE_RAND48: |
| 184 | if (run_smmuv3_rand48(start_address, size, attributes)) { |
| 185 | return cactus_success_resp(vm_id, source, 0); |
| 186 | } |
| 187 | break; |
| 188 | default: |
| 189 | ERROR("SMMUv3TestEngine: unsupported operation (%u).\n", operation); |
| 190 | break; |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 191 | } |
| 192 | |
Olivier Deprez | e71ec9c | 2022-02-28 18:57:26 +0100 | [diff] [blame] | 193 | return cactus_error_resp(vm_id, source, 0); |
Madhukar Pappireddy | 172523b | 2020-12-31 19:25:33 -0600 | [diff] [blame] | 194 | } |