1 /*
2 * Copyright © 2023 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 #include "i915/iris_batch.h"
24
25 #include "iris/iris_batch.h"
26 #include "iris/iris_context.h"
27
28 #include "common/i915/intel_defines.h"
29 #include "common/intel_gem.h"
30 #include "util/u_debug.h"
31
32 #define FILE_DEBUG_FLAG DEBUG_BATCH
33
34 static int
iris_context_priority_to_i915_priority(enum iris_context_priority priority)35 iris_context_priority_to_i915_priority(enum iris_context_priority priority)
36 {
37 switch (priority) {
38 case IRIS_CONTEXT_HIGH_PRIORITY:
39 return INTEL_CONTEXT_HIGH_PRIORITY;
40 case IRIS_CONTEXT_LOW_PRIORITY:
41 return INTEL_CONTEXT_LOW_PRIORITY;
42 case IRIS_CONTEXT_MEDIUM_PRIORITY:
43 FALLTHROUGH;
44 default:
45 return INTEL_CONTEXT_MEDIUM_PRIORITY;
46 }
47 }
48
49 static int
context_set_priority(struct iris_bufmgr * bufmgr,uint32_t ctx_id,enum iris_context_priority priority)50 context_set_priority(struct iris_bufmgr *bufmgr, uint32_t ctx_id,
51 enum iris_context_priority priority)
52 {
53 int err = 0;
54 int i915_priority = iris_context_priority_to_i915_priority(priority);
55 if (!intel_gem_set_context_param(iris_bufmgr_get_fd(bufmgr), ctx_id,
56 I915_CONTEXT_PARAM_PRIORITY, i915_priority))
57 err = -errno;
58
59 return err;
60 }
61
62 static void
iris_hw_context_set_unrecoverable(struct iris_bufmgr * bufmgr,uint32_t ctx_id)63 iris_hw_context_set_unrecoverable(struct iris_bufmgr *bufmgr,
64 uint32_t ctx_id)
65 {
66 /* Upon declaring a GPU hang, the kernel will zap the guilty context
67 * back to the default logical HW state and attempt to continue on to
68 * our next submitted batchbuffer. However, our render batches assume
69 * the previous GPU state is preserved, and only emit commands needed
70 * to incrementally change that state. In particular, we inherit the
71 * STATE_BASE_ADDRESS and PIPELINE_SELECT settings, which are critical.
72 * With default base addresses, our next batches will almost certainly
73 * cause more GPU hangs, leading to repeated hangs until we're banned
74 * or the machine is dead.
75 *
76 * Here we tell the kernel not to attempt to recover our context but
77 * immediately (on the next batchbuffer submission) report that the
78 * context is lost, and we will do the recovery ourselves. Ideally,
79 * we'll have two lost batches instead of a continual stream of hangs.
80 */
81 intel_gem_set_context_param(iris_bufmgr_get_fd(bufmgr), ctx_id,
82 I915_CONTEXT_PARAM_RECOVERABLE, false);
83 }
84
85 static void
iris_hw_context_set_vm_id(struct iris_bufmgr * bufmgr,uint32_t ctx_id)86 iris_hw_context_set_vm_id(struct iris_bufmgr *bufmgr, uint32_t ctx_id)
87 {
88 if (!iris_bufmgr_use_global_vm_id(bufmgr))
89 return;
90
91 if (!intel_gem_set_context_param(iris_bufmgr_get_fd(bufmgr), ctx_id,
92 I915_CONTEXT_PARAM_VM,
93 iris_bufmgr_use_global_vm_id(bufmgr)))
94 DBG("DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM failed: %s\n",
95 strerror(errno));
96 }
97
98 static uint32_t
iris_create_hw_context(struct iris_bufmgr * bufmgr,bool protected)99 iris_create_hw_context(struct iris_bufmgr *bufmgr, bool protected)
100 {
101 uint32_t ctx_id;
102
103 if (protected) {
104 /* User explicitly requested for PXP so wait for the kernel + firmware
105 * dependencies to complete to avoid a premature PXP context-create failure.
106 */
107 if (!intel_gem_wait_on_get_param(iris_bufmgr_get_fd(bufmgr),
108 I915_PARAM_PXP_STATUS, 1,
109 8000))
110 DBG("unable to wait for pxp-readiness\n");
111
112 if (!intel_gem_create_context_ext(iris_bufmgr_get_fd(bufmgr),
113 INTEL_GEM_CREATE_CONTEXT_EXT_PROTECTED_FLAG,
114 &ctx_id)) {
115 DBG("DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT failed: %s\n", strerror(errno));
116 return 0;
117 }
118 } else {
119 if (!intel_gem_create_context(iris_bufmgr_get_fd(bufmgr), &ctx_id)) {
120 DBG("intel_gem_create_context failed: %s\n", strerror(errno));
121 return 0;
122 }
123 iris_hw_context_set_unrecoverable(bufmgr, ctx_id);
124 }
125
126 iris_hw_context_set_vm_id(bufmgr, ctx_id);
127
128 return ctx_id;
129 }
130
131 static void
iris_init_non_engine_contexts(struct iris_context * ice)132 iris_init_non_engine_contexts(struct iris_context *ice)
133 {
134 struct iris_screen *screen = (void *) ice->ctx.screen;
135
136 iris_foreach_batch(ice, batch) {
137 batch->i915.ctx_id = iris_create_hw_context(screen->bufmgr, ice->protected);
138 batch->i915.exec_flags = I915_EXEC_RENDER;
139 assert(batch->i915.ctx_id);
140 context_set_priority(screen->bufmgr, batch->i915.ctx_id, ice->priority);
141 }
142
143 ice->batches[IRIS_BATCH_BLITTER].i915.exec_flags = I915_EXEC_BLT;
144 ice->has_engines_context = false;
145 }
146
147 static int
iris_create_engines_context(struct iris_context * ice)148 iris_create_engines_context(struct iris_context *ice)
149 {
150 struct iris_screen *screen = (void *) ice->ctx.screen;
151 const struct intel_device_info *devinfo = screen->devinfo;
152 int fd = iris_bufmgr_get_fd(screen->bufmgr);
153
154 struct intel_query_engine_info *engines_info;
155 engines_info = intel_engine_get_info(fd, screen->devinfo->kmd_type);
156
157 if (!engines_info)
158 return -1;
159
160 if (intel_engines_count(engines_info, INTEL_ENGINE_CLASS_RENDER) < 1) {
161 free(engines_info);
162 return -1;
163 }
164
165 STATIC_ASSERT(IRIS_BATCH_COUNT == 3);
166 enum intel_engine_class engine_classes[IRIS_BATCH_COUNT] = {
167 [IRIS_BATCH_RENDER] = INTEL_ENGINE_CLASS_RENDER,
168 [IRIS_BATCH_COMPUTE] = INTEL_ENGINE_CLASS_RENDER,
169 [IRIS_BATCH_BLITTER] = INTEL_ENGINE_CLASS_COPY,
170 };
171
172 /* Blitter is only supported on Gfx12+ */
173 unsigned num_batches = IRIS_BATCH_COUNT - (devinfo->ver >= 12 ? 0 : 1);
174
175 if (iris_bufmgr_compute_engine_supported(screen->bufmgr))
176 engine_classes[IRIS_BATCH_COMPUTE] = INTEL_ENGINE_CLASS_COMPUTE;
177
178 enum intel_gem_create_context_flags flags = 0;
179 if (ice->protected) {
180 flags |= INTEL_GEM_CREATE_CONTEXT_EXT_PROTECTED_FLAG;
181
182 /* User explicitly requested for PXP so wait for the kernel + firmware
183 * dependencies to complete to avoid a premature PXP context-create failure.
184 */
185 if (!intel_gem_wait_on_get_param(fd,
186 I915_PARAM_PXP_STATUS, 1,
187 8000))
188 DBG("unable to wait for pxp-readiness\n");
189 }
190
191 uint32_t engines_ctx;
192 if (!intel_gem_create_context_engines(fd, flags, engines_info, num_batches,
193 engine_classes, 0, &engines_ctx)) {
194 free(engines_info);
195 return -1;
196 }
197
198 iris_hw_context_set_unrecoverable(screen->bufmgr, engines_ctx);
199 iris_hw_context_set_vm_id(screen->bufmgr, engines_ctx);
200 context_set_priority(screen->bufmgr, engines_ctx, ice->priority);
201
202 free(engines_info);
203 return engines_ctx;
204 }
205
206 static bool
iris_init_engines_context(struct iris_context * ice)207 iris_init_engines_context(struct iris_context *ice)
208 {
209 int engines_ctx = iris_create_engines_context(ice);
210 if (engines_ctx < 0)
211 return false;
212
213 iris_foreach_batch(ice, batch) {
214 unsigned i = batch - &ice->batches[0];
215 batch->i915.ctx_id = engines_ctx;
216 batch->i915.exec_flags = i;
217 }
218
219 ice->has_engines_context = true;
220 return true;
221 }
222
223 static bool
iris_hw_context_get_protected(struct iris_bufmgr * bufmgr,uint32_t ctx_id)224 iris_hw_context_get_protected(struct iris_bufmgr *bufmgr, uint32_t ctx_id)
225 {
226 uint64_t protected_content = 0;
227 intel_gem_get_context_param(iris_bufmgr_get_fd(bufmgr), ctx_id,
228 I915_CONTEXT_PARAM_PROTECTED_CONTENT,
229 &protected_content);
230 return protected_content;
231 }
232
233 static uint32_t
clone_hw_context(struct iris_batch * batch)234 clone_hw_context(struct iris_batch *batch)
235 {
236 struct iris_screen *screen = batch->screen;
237 struct iris_bufmgr *bufmgr = screen->bufmgr;
238 struct iris_context *ice = batch->ice;
239 bool protected = iris_hw_context_get_protected(bufmgr, batch->i915.ctx_id);
240 uint32_t new_ctx = iris_create_hw_context(bufmgr, protected);
241
242 if (new_ctx)
243 context_set_priority(bufmgr, new_ctx, ice->priority);
244
245 return new_ctx;
246 }
247
248 static void
iris_destroy_kernel_context(struct iris_bufmgr * bufmgr,uint32_t ctx_id)249 iris_destroy_kernel_context(struct iris_bufmgr *bufmgr, uint32_t ctx_id)
250 {
251 if (ctx_id != 0 &&
252 !intel_gem_destroy_context(iris_bufmgr_get_fd(bufmgr), ctx_id)) {
253 fprintf(stderr, "DRM_IOCTL_I915_GEM_CONTEXT_DESTROY failed: %s\n",
254 strerror(errno));
255 }
256 }
257
258 bool
iris_i915_replace_batch(struct iris_batch * batch)259 iris_i915_replace_batch(struct iris_batch *batch)
260 {
261 struct iris_screen *screen = batch->screen;
262 struct iris_bufmgr *bufmgr = screen->bufmgr;
263 struct iris_context *ice = batch->ice;
264
265 if (ice->has_engines_context) {
266 uint32_t old_ctx = batch->i915.ctx_id;
267 int new_ctx = iris_create_engines_context(ice);
268 if (new_ctx < 0)
269 return false;
270 iris_foreach_batch(ice, bat) {
271 bat->i915.ctx_id = new_ctx;
272 /* Notify the context that state must be re-initialized. */
273 iris_lost_context_state(bat);
274 }
275 iris_destroy_kernel_context(bufmgr, old_ctx);
276 } else {
277 uint32_t new_ctx = clone_hw_context(batch);
278 if (!new_ctx)
279 return false;
280
281 iris_destroy_kernel_context(bufmgr, batch->i915.ctx_id);
282 batch->i915.ctx_id = new_ctx;
283
284 /* Notify the context that state must be re-initialized. */
285 iris_lost_context_state(batch);
286 }
287
288 return true;
289 }
290
iris_i915_destroy_batch(struct iris_batch * batch)291 void iris_i915_destroy_batch(struct iris_batch *batch)
292 {
293 struct iris_screen *screen = batch->screen;
294 struct iris_bufmgr *bufmgr = screen->bufmgr;
295
296 /* destroy the engines context on the first batch or destroy each batch
297 * context
298 */
299 if (batch->ice->has_engines_context && batch != &batch->ice->batches[0])
300 return;
301
302 iris_destroy_kernel_context(bufmgr, batch->i915.ctx_id);
303 }
304
iris_i915_init_batches(struct iris_context * ice)305 void iris_i915_init_batches(struct iris_context *ice)
306 {
307 if (!iris_init_engines_context(ice))
308 iris_init_non_engine_contexts(ice);
309 }
310