1 /*
2 * Copyright © 2014 Intel Corporation
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 (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 * Mika Kuoppala <[email protected]>
25 * Oscar Mateo <[email protected]>
26 *
27 */
28
29 #include "igt.h"
30 #include <limits.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34
35 #include "igt_sysfs.h"
36 #include "igt_debugfs.h"
37
38 #ifndef I915_PARAM_CMD_PARSER_VERSION
39 #define I915_PARAM_CMD_PARSER_VERSION 28
40 #endif
41
42 static int device = -1;
43 static int sysfs = -1;
44
has_error_state(int dir)45 static bool has_error_state(int dir)
46 {
47 bool result;
48 int fd;
49
50 fd = openat(dir, "error", O_RDONLY);
51 if (fd < 0)
52 return false;
53
54 if (read(fd, &result, sizeof(result)) < 0)
55 result = false;
56 else
57 result = true;
58
59 close(fd);
60 return result;
61 }
62
assert_entry(const char * s,bool expect)63 static void assert_entry(const char *s, bool expect)
64 {
65 char *error;
66
67 error = igt_sysfs_get(sysfs, "error");
68 igt_assert(error);
69
70 igt_assert_f(!!strcasecmp(error, s) != expect,
71 "contents of error: '%s' (expected %s '%s')\n",
72 error, expect ? "": "not", s);
73
74 free(error);
75 }
76
assert_error_state_clear(void)77 static void assert_error_state_clear(void)
78 {
79 assert_entry("no error state collected", true);
80 }
81
assert_error_state_collected(void)82 static void assert_error_state_collected(void)
83 {
84 assert_entry("no error state collected", false);
85 }
86
clear_error_state(void)87 static void clear_error_state(void)
88 {
89 igt_sysfs_write(sysfs, "error", "", 1);
90 }
91
test_error_state_basic(void)92 static void test_error_state_basic(void)
93 {
94 int fd;
95
96 clear_error_state();
97 assert_error_state_clear();
98
99 /* Manually trigger a hang by request a reset */
100 fd = igt_debugfs_open(device, "i915_wedged", O_WRONLY);
101 igt_ignore_warn(write(fd, "1\n", 2));
102 close(fd);
103
104 assert_error_state_collected();
105
106 clear_error_state();
107 assert_error_state_clear();
108 }
109
open_error(void)110 static FILE *open_error(void)
111 {
112 int fd;
113
114 fd = openat(sysfs, "error", O_RDONLY);
115 if (fd < 0)
116 return NULL;
117
118 return fdopen(fd, "r");
119 }
120
uses_cmd_parser(void)121 static bool uses_cmd_parser(void)
122 {
123 int parser_version = 0;
124 drm_i915_getparam_t gp;
125
126 gp.param = I915_PARAM_CMD_PARSER_VERSION;
127 gp.value = &parser_version;
128 drmIoctl(device, DRM_IOCTL_I915_GETPARAM, &gp);
129
130 return parser_version > 0;
131 }
132
check_error_state(const char * expected_ring_name,uint64_t expected_offset,const uint32_t * batch)133 static void check_error_state(const char *expected_ring_name,
134 uint64_t expected_offset,
135 const uint32_t *batch)
136 {
137 bool cmd_parser = uses_cmd_parser();
138 FILE *file = open_error();
139 char *line = NULL;
140 size_t line_size = 0;
141 bool found = false;
142
143 igt_debug("%s(expected ring name=%s, expected offset=%"PRIx64")\n",
144 __func__, expected_ring_name, expected_offset);
145 igt_debugfs_dump(device, "i915_error_state");
146
147 igt_assert(getline(&line, &line_size, file) != -1);
148 igt_assert(strcasecmp(line, "No error state collected"));
149
150 while (getline(&line, &line_size, file) > 0) {
151 char *dashes;
152 uint32_t gtt_offset_upper, gtt_offset_lower;
153 int matched;
154
155 dashes = strstr(line, "---");
156 if (!dashes)
157 continue;
158
159 matched = sscanf(dashes, "--- gtt_offset = 0x%08x %08x\n",
160 >t_offset_upper, >t_offset_lower);
161 if (matched) {
162 char expected_line[128];
163 uint64_t gtt_offset;
164 int i;
165
166 strncpy(expected_line, line, dashes - line);
167 expected_line[dashes - line - 1] = '\0';
168 igt_assert(strstr(expected_line, expected_ring_name));
169
170 gtt_offset = gtt_offset_upper;
171 if (matched == 2) {
172 gtt_offset <<= 32;
173 gtt_offset |= gtt_offset_lower;
174 }
175 if (!cmd_parser)
176 igt_assert_eq_u64(gtt_offset, expected_offset);
177
178 for (i = 0; i < 1024; i++) {
179 igt_assert(getline(&line, &line_size, file) > 0);
180 if (line[0] == ':' || line[0] == '~')
181 break;
182
183 snprintf(expected_line, sizeof(expected_line),
184 "%08x : %08x",
185 4*i, batch[i]);
186 igt_assert(strstr(line, expected_line));
187 }
188
189 found = true;
190 break;
191 }
192 }
193
194 free(line);
195 fclose(file);
196
197 clear_error_state();
198
199 igt_assert(found);
200 }
201
test_error_state_capture(unsigned ring_id,const char * ring_name)202 static void test_error_state_capture(unsigned ring_id,
203 const char *ring_name)
204 {
205 uint32_t *batch;
206 igt_hang_t hang;
207 uint64_t offset;
208
209 clear_error_state();
210
211 hang = igt_hang_ctx(device, 0, ring_id, HANG_ALLOW_CAPTURE);
212 offset = hang.spin->obj[IGT_SPIN_BATCH].offset;
213
214 batch = gem_mmap__cpu(device, hang.spin->handle, 0, 4096, PROT_READ);
215 gem_set_domain(device, hang.spin->handle, I915_GEM_DOMAIN_CPU, 0);
216
217 igt_post_hang_ring(device, hang);
218
219 check_error_state(ring_name, offset, batch);
220 munmap(batch, 4096);
221 }
222
223 /* This test covers the case where we end up in an uninitialised area of the
224 * ppgtt and keep executing through it. This is particularly relevant if 48b
225 * ppgtt is enabled because the ppgtt is massively bigger compared to the 32b
226 * case and it takes a lot more time to wrap, so the acthd can potentially keep
227 * increasing for a long time
228 */
hangcheck_unterminated(void)229 static void hangcheck_unterminated(void)
230 {
231 /* timeout needs to be greater than ~5*hangcheck */
232 int64_t timeout_ns = 100ull * NSEC_PER_SEC; /* 100 seconds */
233 struct drm_i915_gem_execbuffer2 execbuf;
234 struct drm_i915_gem_exec_object2 gem_exec;
235 uint32_t handle;
236
237 igt_require(gem_uses_full_ppgtt(device));
238 igt_require_hang_ring(device, 0);
239
240 handle = gem_create(device, 4096);
241
242 memset(&gem_exec, 0, sizeof(gem_exec));
243 gem_exec.handle = handle;
244
245 memset(&execbuf, 0, sizeof(execbuf));
246 execbuf.buffers_ptr = (uintptr_t)&gem_exec;
247 execbuf.buffer_count = 1;
248
249 gem_execbuf(device, &execbuf);
250 if (gem_wait(device, handle, &timeout_ns) != 0) {
251 /* need to manually trigger an hang to clean before failing */
252 igt_force_gpu_reset(device);
253 igt_assert_f(0, "unterminated batch did not trigger an hang!");
254 }
255 }
256
257 igt_main
258 {
259 const struct intel_execution_engine2 *e;
260 igt_hang_t hang = {};
261
262 igt_skip_on_simulation();
263
264 igt_fixture {
265 device = drm_open_driver(DRIVER_INTEL);
266 igt_require_gem(device);
267
268 hang = igt_allow_hang(device, 0, HANG_ALLOW_CAPTURE);
269
270 sysfs = igt_sysfs_open(device);
271 igt_assert(sysfs != -1);
272
273 igt_require(has_error_state(sysfs));
274 }
275
276 igt_subtest("error-state-basic")
277 test_error_state_basic();
278
279 __for_each_physical_engine(device, e)
280 igt_subtest_f("error-state-capture-%s", e->name)
281 test_error_state_capture(e->flags, e->name);
282
283 igt_subtest("hangcheck-unterminated")
284 hangcheck_unterminated();
285
286 igt_fixture {
287 igt_disallow_hang(device, hang);
288 }
289 }
290