1 /* 2 * Copyright 2017 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 */ 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <unistd.h> 27 #ifdef HAVE_ALLOCA_H 28 # include <alloca.h> 29 #endif 30 31 #include "CUnit/Basic.h" 32 33 #include "amdgpu_test.h" 34 #include "amdgpu_drm.h" 35 #include "amdgpu_internal.h" 36 37 #include <pthread.h> 38 39 40 /* 41 * This defines the delay in MS after which memory location designated for 42 * compression against reference value is written to, unblocking command 43 * processor 44 */ 45 #define WRITE_MEM_ADDRESS_DELAY_MS 100 46 47 #define PACKET_TYPE3 3 48 49 #define PACKET3(op, n) ((PACKET_TYPE3 << 30) | \ 50 (((op) & 0xFF) << 8) | \ 51 ((n) & 0x3FFF) << 16) 52 53 #define PACKET3_WAIT_REG_MEM 0x3C 54 #define WAIT_REG_MEM_FUNCTION(x) ((x) << 0) 55 /* 0 - always 56 * 1 - < 57 * 2 - <= 58 * 3 - == 59 * 4 - != 60 * 5 - >= 61 * 6 - > 62 */ 63 #define WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4) 64 /* 0 - reg 65 * 1 - mem 66 */ 67 #define WAIT_REG_MEM_OPERATION(x) ((x) << 6) 68 /* 0 - wait_reg_mem 69 * 1 - wr_wait_wr_reg 70 */ 71 #define WAIT_REG_MEM_ENGINE(x) ((x) << 8) 72 /* 0 - me 73 * 1 - pfp 74 */ 75 76 static amdgpu_device_handle device_handle; 77 static uint32_t major_version; 78 static uint32_t minor_version; 79 80 static pthread_t stress_thread; 81 static uint32_t *ptr; 82 83 static void amdgpu_deadlock_helper(unsigned ip_type); 84 static void amdgpu_deadlock_gfx(void); 85 static void amdgpu_deadlock_compute(void); 86 87 CU_BOOL suite_deadlock_tests_enable(void) 88 { 89 CU_BOOL enable = CU_TRUE; 90 91 if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, 92 &minor_version, &device_handle)) 93 return CU_FALSE; 94 95 if (device_handle->info.family_id == AMDGPU_FAMILY_AI || 96 device_handle->info.family_id == AMDGPU_FAMILY_SI) { 97 printf("\n\nCurrently hangs the CP on this ASIC, deadlock suite disabled\n"); 98 enable = CU_FALSE; 99 } 100 101 if (amdgpu_device_deinitialize(device_handle)) 102 return CU_FALSE; 103 104 return enable; 105 } 106 107 int suite_deadlock_tests_init(void) 108 { 109 int r; 110 111 r = amdgpu_device_initialize(drm_amdgpu[0], &major_version, 112 &minor_version, &device_handle); 113 114 if (r) { 115 if ((r == -EACCES) && (errno == EACCES)) 116 printf("\n\nError:%s. " 117 "Hint:Try to run this test program as root.", 118 strerror(errno)); 119 return CUE_SINIT_FAILED; 120 } 121 122 return CUE_SUCCESS; 123 } 124 125 int suite_deadlock_tests_clean(void) 126 { 127 int r = amdgpu_device_deinitialize(device_handle); 128 129 if (r == 0) 130 return CUE_SUCCESS; 131 else 132 return CUE_SCLEAN_FAILED; 133 } 134 135 136 CU_TestInfo deadlock_tests[] = { 137 { "gfx ring block test", amdgpu_deadlock_gfx }, 138 { "compute ring block test", amdgpu_deadlock_compute }, 139 CU_TEST_INFO_NULL, 140 }; 141 142 static void *write_mem_address(void *data) 143 { 144 int i; 145 146 /* useconds_t range is [0, 1,000,000] so use loop for waits > 1s */ 147 for (i = 0; i < WRITE_MEM_ADDRESS_DELAY_MS; i++) 148 usleep(1000); 149 150 ptr[256] = 0x1; 151 152 return 0; 153 } 154 155 static void amdgpu_deadlock_gfx(void) 156 { 157 amdgpu_deadlock_helper(AMDGPU_HW_IP_GFX); 158 } 159 160 static void amdgpu_deadlock_compute(void) 161 { 162 amdgpu_deadlock_helper(AMDGPU_HW_IP_COMPUTE); 163 } 164 165 static void amdgpu_deadlock_helper(unsigned ip_type) 166 { 167 amdgpu_context_handle context_handle; 168 amdgpu_bo_handle ib_result_handle; 169 void *ib_result_cpu; 170 uint64_t ib_result_mc_address; 171 struct amdgpu_cs_request ibs_request; 172 struct amdgpu_cs_ib_info ib_info; 173 struct amdgpu_cs_fence fence_status; 174 uint32_t expired; 175 int i, r; 176 amdgpu_bo_list_handle bo_list; 177 amdgpu_va_handle va_handle; 178 179 r = pthread_create(&stress_thread, NULL, write_mem_address, NULL); 180 CU_ASSERT_EQUAL(r, 0); 181 182 r = amdgpu_cs_ctx_create(device_handle, &context_handle); 183 CU_ASSERT_EQUAL(r, 0); 184 185 r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, 186 AMDGPU_GEM_DOMAIN_GTT, 0, 187 &ib_result_handle, &ib_result_cpu, 188 &ib_result_mc_address, &va_handle); 189 CU_ASSERT_EQUAL(r, 0); 190 191 r = amdgpu_get_bo_list(device_handle, ib_result_handle, NULL, 192 &bo_list); 193 CU_ASSERT_EQUAL(r, 0); 194 195 ptr = ib_result_cpu; 196 197 ptr[0] = PACKET3(PACKET3_WAIT_REG_MEM, 5); 198 ptr[1] = (WAIT_REG_MEM_MEM_SPACE(1) | /* memory */ 199 WAIT_REG_MEM_FUNCTION(4) | /* != */ 200 WAIT_REG_MEM_ENGINE(0)); /* me */ 201 ptr[2] = (ib_result_mc_address + 256*4) & 0xfffffffc; 202 ptr[3] = ((ib_result_mc_address + 256*4) >> 32) & 0xffffffff; 203 ptr[4] = 0x00000000; /* reference value */ 204 ptr[5] = 0xffffffff; /* and mask */ 205 ptr[6] = 0x00000004; /* poll interval */ 206 207 for (i = 7; i < 16; ++i) 208 ptr[i] = 0xffff1000; 209 210 211 ptr[256] = 0x0; /* the memory we wait on to change */ 212 213 214 215 memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info)); 216 ib_info.ib_mc_address = ib_result_mc_address; 217 ib_info.size = 16; 218 219 memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request)); 220 ibs_request.ip_type = ip_type; 221 ibs_request.ring = 0; 222 ibs_request.number_of_ibs = 1; 223 ibs_request.ibs = &ib_info; 224 ibs_request.resources = bo_list; 225 ibs_request.fence_info.handle = NULL; 226 227 for (i = 0; i < 200; i++) { 228 r = amdgpu_cs_submit(context_handle, 0,&ibs_request, 1); 229 CU_ASSERT_EQUAL((r == 0 || r == -ECANCELED), 1); 230 231 } 232 233 memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence)); 234 fence_status.context = context_handle; 235 fence_status.ip_type = ip_type; 236 fence_status.ip_instance = 0; 237 fence_status.ring = 0; 238 fence_status.fence = ibs_request.seq_no; 239 240 r = amdgpu_cs_query_fence_status(&fence_status, 241 AMDGPU_TIMEOUT_INFINITE,0, &expired); 242 CU_ASSERT_EQUAL((r == 0 || r == -ECANCELED), 1); 243 244 pthread_join(stress_thread, NULL); 245 246 r = amdgpu_bo_list_destroy(bo_list); 247 CU_ASSERT_EQUAL(r, 0); 248 249 r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, 250 ib_result_mc_address, 4096); 251 CU_ASSERT_EQUAL(r, 0); 252 253 r = amdgpu_cs_ctx_free(context_handle); 254 CU_ASSERT_EQUAL(r, 0); 255 } 256