xref: /aosp_15_r20/external/igt-gpu-tools/tests/i915/i915_hangman.c (revision d83cc019efdc2edc6c4b16e9034a3ceb8d35d77c)
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 				 &gtt_offset_upper, &gtt_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