1 /*
2  * Copyright © 2017 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 
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <stdbool.h>
27 #include <sys/ioctl.h>
28 
29 #include <i915_drm.h>
30 
31 #include "i915/gem_engine_topology.h"
32 
33 #include "igt_core.h"
34 #include "igt_gt.h"
35 #include "igt_sysfs.h"
36 #include "intel_chipset.h"
37 #include "intel_reg.h"
38 #include "ioctl_wrappers.h"
39 
40 #include "i915/gem_submission.h"
41 
42 /**
43  * SECTION:gem_submission
44  * @short_description: Helpers for determining submission method
45  * @title: GEM Submission
46  *
47  * This helper library contains functions used for getting information on
48  * currently used hardware submission method. Different generations of hardware
49  * support different submission backends, currently we're distinguishing 3
50  * different methods: legacy ringbuffer submission, execlists, GuC submission.
51  * For legacy ringbuffer submission, there's also a variation where we're using
52  * semaphores for synchronization between engines.
53  */
54 
has_semaphores(int fd,int dir)55 static bool has_semaphores(int fd, int dir)
56 {
57 	int val = 0;
58 	struct drm_i915_getparam gp = {
59 		gp.param = I915_PARAM_HAS_SEMAPHORES,
60 		gp.value = &val,
61 	};
62 	if (ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp) < 0)
63 		val = igt_sysfs_get_boolean(dir, "semaphores");
64 	return val;
65 }
66 
67 /**
68  * gem_submission_method:
69  * @fd: open i915 drm file descriptor
70  *
71  * Returns: Submission method bitmap.
72  */
gem_submission_method(int fd)73 unsigned gem_submission_method(int fd)
74 {
75 	const int gen = intel_gen(intel_get_drm_devid(fd));
76 	unsigned flags = 0;
77 
78 	int dir;
79 
80 	dir = igt_sysfs_open_parameters(fd);
81 	if (dir < 0)
82 		return 0;
83 
84 	if (igt_sysfs_get_u32(dir, "enable_guc") & 1) {
85 		flags |= GEM_SUBMISSION_GUC | GEM_SUBMISSION_EXECLISTS;
86 		goto out;
87 	}
88 
89 	if (gen >= 8) {
90 		flags |= GEM_SUBMISSION_EXECLISTS;
91 		goto out;
92 	}
93 
94 	if (has_semaphores(fd, dir))
95 		flags |= GEM_SUBMISSION_SEMAPHORES;
96 
97 out:
98 	close(dir);
99 	return flags;
100 }
101 
102 /**
103  * gem_submission_print_method:
104  * @fd: open i915 drm file descriptor
105  *
106  * Helper for pretty-printing currently used submission method
107  */
gem_submission_print_method(int fd)108 void gem_submission_print_method(int fd)
109 {
110 	const unsigned flags = gem_submission_method(fd);
111 
112 	if (flags & GEM_SUBMISSION_GUC) {
113 		igt_info("Using GuC submission\n");
114 		return;
115 	}
116 
117 	if (flags & GEM_SUBMISSION_EXECLISTS) {
118 		igt_info("Using Execlists submission\n");
119 		return;
120 	}
121 
122 	igt_info("Using Legacy submission%s\n",
123 		 flags & GEM_SUBMISSION_SEMAPHORES ? ", with semaphores" : "");
124 }
125 
126 /**
127  * gem_has_semaphores:
128  * @fd: open i915 drm file descriptor
129  *
130  * Feature test macro to query whether the driver is using semaphores for
131  * synchronization between engines.
132  */
gem_has_semaphores(int fd)133 bool gem_has_semaphores(int fd)
134 {
135 	return gem_submission_method(fd) & GEM_SUBMISSION_SEMAPHORES;
136 }
137 
138 /**
139  * gem_has_execlists:
140  * @fd: open i915 drm file descriptor
141  *
142  * Feature test macro to query whether the driver is using execlists as a
143  * hardware submission method.
144  */
gem_has_execlists(int fd)145 bool gem_has_execlists(int fd)
146 {
147 	return gem_submission_method(fd) & GEM_SUBMISSION_EXECLISTS;
148 }
149 
150 /**
151  * gem_has_guc_submission:
152  * @fd: open i915 drm file descriptor
153  *
154  * Feature test macro to query whether the driver is using the GuC as a
155  * hardware submission method.
156  */
gem_has_guc_submission(int fd)157 bool gem_has_guc_submission(int fd)
158 {
159 	return gem_submission_method(fd) & GEM_SUBMISSION_GUC;
160 }
161 
162 /**
163  * gem_reopen_driver:
164  * @fd: re-open the i915 drm file descriptor
165  *
166  * Re-opens the drm fd which is useful in instances where a clean default
167  * context is needed.
168  */
gem_reopen_driver(int fd)169 int gem_reopen_driver(int fd)
170 {
171 	char path[256];
172 
173 	snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
174 	fd = open(path, O_RDWR);
175 	igt_assert_fd(fd);
176 
177 	return fd;
178 }
179 
is_wedged(int i915)180 static bool is_wedged(int i915)
181 {
182 	int err = 0;
183 	if (ioctl(i915, DRM_IOCTL_I915_GEM_THROTTLE))
184 		err = -errno;
185 	return err == -EIO;
186 }
187 
188 /**
189  * gem_test_engine:
190  * @i915: open i915 drm file descriptor
191  * @engine: the engine (I915_EXEC_RING id) to exercise
192  *
193  * Execute a nop batch on the engine specified, or ALL_ENGINES for all,
194  * and check it executes.
195  */
gem_test_engine(int i915,unsigned int engine)196 void gem_test_engine(int i915, unsigned int engine)
197 {
198 	const uint32_t bbe = MI_BATCH_BUFFER_END;
199 	struct drm_i915_gem_exec_object2 obj = { };
200 	struct drm_i915_gem_execbuffer2 execbuf = {
201 		.buffers_ptr = to_user_pointer(&obj),
202 		.buffer_count = 1,
203 	};
204 
205 	i915 = gem_reopen_driver(i915);
206 	igt_assert(!is_wedged(i915));
207 
208 	obj.handle = gem_create(i915, 4096);
209 	gem_write(i915, obj.handle, 0, &bbe, sizeof(bbe));
210 
211 	if (engine == ALL_ENGINES) {
212 		const struct intel_execution_engine2 *e2;
213 
214 		__for_each_physical_engine(i915, e2) {
215 			execbuf.flags = e2->flags;
216 			gem_execbuf(i915, &execbuf);
217 		}
218 	} else {
219 		execbuf.flags = engine;
220 		gem_execbuf(i915, &execbuf);
221 	}
222 	gem_sync(i915, obj.handle);
223 	gem_close(i915, obj.handle);
224 
225 	igt_assert(!is_wedged(i915));
226 	close(i915);
227 }
228