xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/iris/i915/iris_batch.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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