diff options
Diffstat (limited to 'tests/amdgpu/deadlock_tests.c')
-rw-r--r-- | tests/amdgpu/deadlock_tests.c | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/tests/amdgpu/deadlock_tests.c b/tests/amdgpu/deadlock_tests.c new file mode 100644 index 00000000..1eb5761a --- /dev/null +++ b/tests/amdgpu/deadlock_tests.c | |||
@@ -0,0 +1,255 @@ | |||
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 | } | ||