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 "iris_kmd_backend.h"
24
25 #include <sys/mman.h>
26
27 #include "common/intel_gem.h"
28 #include "dev/intel_debug.h"
29 #include "iris/iris_bufmgr.h"
30 #include "iris/iris_batch.h"
31 #include "iris/iris_context.h"
32
33 #include "drm-uapi/xe_drm.h"
34
35 #define FILE_DEBUG_FLAG DEBUG_BUFMGR
36
37 static uint32_t
xe_gem_create(struct iris_bufmgr * bufmgr,const struct intel_memory_class_instance ** regions,uint16_t regions_count,uint64_t size,enum iris_heap heap_flags,unsigned alloc_flags)38 xe_gem_create(struct iris_bufmgr *bufmgr,
39 const struct intel_memory_class_instance **regions,
40 uint16_t regions_count, uint64_t size,
41 enum iris_heap heap_flags, unsigned alloc_flags)
42 {
43 /* Xe still don't have support for protected content */
44 if (alloc_flags & BO_ALLOC_PROTECTED)
45 return -EINVAL;
46
47 uint32_t vm_id = iris_bufmgr_get_global_vm_id(bufmgr);
48 vm_id = alloc_flags & BO_ALLOC_SHARED ? 0 : vm_id;
49
50 uint32_t flags = 0;
51 /* TODO: we might need to consider scanout for shared buffers too as we
52 * do not know what the process this is shared with will do with it
53 */
54 if (alloc_flags & BO_ALLOC_SCANOUT)
55 flags |= DRM_XE_GEM_CREATE_FLAG_SCANOUT;
56 if (!intel_vram_all_mappable(iris_bufmgr_get_device_info(bufmgr)) &&
57 heap_flags == IRIS_HEAP_DEVICE_LOCAL_PREFERRED)
58 flags |= DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM;
59
60 struct drm_xe_gem_create gem_create = {
61 .vm_id = vm_id,
62 .size = align64(size, iris_bufmgr_get_device_info(bufmgr)->mem_alignment),
63 .flags = flags,
64 };
65 for (uint16_t i = 0; i < regions_count; i++)
66 gem_create.placement |= BITFIELD_BIT(regions[i]->instance);
67
68 const struct intel_device_info *devinfo = iris_bufmgr_get_device_info(bufmgr);
69 const struct intel_device_info_pat_entry *pat_entry;
70 pat_entry = iris_heap_to_pat_entry(devinfo, heap_flags);
71 switch (pat_entry->mmap) {
72 case INTEL_DEVICE_INFO_MMAP_MODE_WC:
73 gem_create.cpu_caching = DRM_XE_GEM_CPU_CACHING_WC;
74 break;
75 case INTEL_DEVICE_INFO_MMAP_MODE_WB:
76 gem_create.cpu_caching = DRM_XE_GEM_CPU_CACHING_WB;
77 break;
78 default:
79 unreachable("missing");
80 gem_create.cpu_caching = DRM_XE_GEM_CPU_CACHING_WC;
81 }
82
83 if (intel_ioctl(iris_bufmgr_get_fd(bufmgr), DRM_IOCTL_XE_GEM_CREATE,
84 &gem_create))
85 return 0;
86
87 return gem_create.handle;
88 }
89
90 static void *
xe_gem_mmap(struct iris_bufmgr * bufmgr,struct iris_bo * bo)91 xe_gem_mmap(struct iris_bufmgr *bufmgr, struct iris_bo *bo)
92 {
93 struct drm_xe_gem_mmap_offset args = {
94 .handle = bo->gem_handle,
95 };
96 if (intel_ioctl(iris_bufmgr_get_fd(bufmgr), DRM_IOCTL_XE_GEM_MMAP_OFFSET, &args))
97 return NULL;
98
99 void *map = mmap(NULL, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
100 iris_bufmgr_get_fd(bufmgr), args.offset);
101 return map != MAP_FAILED ? map : NULL;
102 }
103
104 static inline int
xe_gem_vm_bind_op(struct iris_bo * bo,uint32_t op)105 xe_gem_vm_bind_op(struct iris_bo *bo, uint32_t op)
106 {
107 struct iris_bufmgr *bufmgr = bo->bufmgr;
108 struct intel_bind_timeline *bind_timeline = iris_bufmgr_get_bind_timeline(bufmgr);
109 const struct intel_device_info *devinfo = iris_bufmgr_get_device_info(bufmgr);
110 uint32_t handle = op == DRM_XE_VM_BIND_OP_UNMAP ? 0 : bo->gem_handle;
111 struct drm_xe_sync xe_sync = {
112 .handle = intel_bind_timeline_get_syncobj(bind_timeline),
113 .type = DRM_XE_SYNC_TYPE_TIMELINE_SYNCOBJ,
114 .flags = DRM_XE_SYNC_FLAG_SIGNAL,
115 };
116 uint64_t range, obj_offset = 0;
117 uint32_t flags = 0;
118 int ret, fd;
119
120 fd = iris_bufmgr_get_fd(bufmgr);
121
122 if (iris_bo_is_imported(bo))
123 range = bo->size;
124 else
125 range = align64(bo->size, devinfo->mem_alignment);
126
127 if (bo->real.userptr) {
128 handle = 0;
129 obj_offset = (uintptr_t)bo->real.map;
130 if (op == DRM_XE_VM_BIND_OP_MAP)
131 op = DRM_XE_VM_BIND_OP_MAP_USERPTR;
132 }
133
134 uint16_t pat_index = 0;
135 if (op != DRM_XE_VM_BIND_OP_UNMAP)
136 pat_index = iris_heap_to_pat_entry(devinfo, bo->real.heap)->index;
137
138 if (bo->real.capture)
139 flags |= DRM_XE_VM_BIND_FLAG_DUMPABLE;
140
141 struct drm_xe_vm_bind args = {
142 .vm_id = iris_bufmgr_get_global_vm_id(bufmgr),
143 .num_syncs = 1,
144 .syncs = (uintptr_t)&xe_sync,
145 .num_binds = 1,
146 .bind.obj = handle,
147 .bind.obj_offset = obj_offset,
148 .bind.range = range,
149 .bind.addr = intel_48b_address(bo->address),
150 .bind.op = op,
151 .bind.pat_index = pat_index,
152 .bind.flags = flags,
153 };
154
155 xe_sync.timeline_value = intel_bind_timeline_bind_begin(bind_timeline);
156 ret = intel_ioctl(fd, DRM_IOCTL_XE_VM_BIND, &args);
157 intel_bind_timeline_bind_end(bind_timeline);
158
159 if (ret)
160 DBG("vm_bind_op: DRM_IOCTL_XE_VM_BIND failed(%i)", ret);
161
162 return ret;
163 }
164
165 static bool
xe_gem_vm_bind(struct iris_bo * bo)166 xe_gem_vm_bind(struct iris_bo *bo)
167 {
168 return xe_gem_vm_bind_op(bo, DRM_XE_VM_BIND_OP_MAP) == 0;
169 }
170
171 static bool
xe_gem_vm_unbind(struct iris_bo * bo)172 xe_gem_vm_unbind(struct iris_bo *bo)
173 {
174 return xe_gem_vm_bind_op(bo, DRM_XE_VM_BIND_OP_UNMAP) == 0;
175 }
176
177 static bool
xe_bo_madvise(struct iris_bo * bo,enum iris_madvice state)178 xe_bo_madvise(struct iris_bo *bo, enum iris_madvice state)
179 {
180 /* Only applicable if VM was created with DRM_XE_VM_CREATE_FAULT_MODE but
181 * that is not compatible with DRM_XE_VM_CREATE_SCRATCH_PAGE
182 *
183 * So returning as retained.
184 */
185 return true;
186 }
187
188 static int
xe_bo_set_caching(struct iris_bo * bo,bool cached)189 xe_bo_set_caching(struct iris_bo *bo, bool cached)
190 {
191 /* Xe don't have caching UAPI so this function should never be called */
192 assert(0);
193 return -1;
194 }
195
196 static enum pipe_reset_status
xe_batch_check_for_reset(struct iris_batch * batch)197 xe_batch_check_for_reset(struct iris_batch *batch)
198 {
199 enum pipe_reset_status status = PIPE_NO_RESET;
200 struct drm_xe_exec_queue_get_property exec_queue_get_property = {
201 .exec_queue_id = batch->xe.exec_queue_id,
202 .property = DRM_XE_EXEC_QUEUE_GET_PROPERTY_BAN,
203 };
204 int ret = intel_ioctl(iris_bufmgr_get_fd(batch->screen->bufmgr),
205 DRM_IOCTL_XE_EXEC_QUEUE_GET_PROPERTY,
206 &exec_queue_get_property);
207
208 if (ret || exec_queue_get_property.value)
209 status = PIPE_GUILTY_CONTEXT_RESET;
210
211 return status;
212 }
213
214 static uint32_t
xe_batch_submit_external_bo_count(struct iris_batch * batch)215 xe_batch_submit_external_bo_count(struct iris_batch *batch)
216 {
217 uint32_t count = 0;
218
219 for (int i = 0; i < batch->exec_count; i++) {
220 if (iris_bo_is_external(batch->exec_bos[i]))
221 count++;
222 }
223
224 return count;
225 }
226
227 struct iris_implicit_sync {
228 struct iris_implicit_sync_entry {
229 struct iris_bo *bo;
230 struct iris_syncobj *iris_syncobj;
231 } *entries;
232 uint32_t entry_count;
233
234 struct iris_syncobj *batch_signal_syncobj;
235 };
236
237 static bool
iris_implicit_sync_add_bo(struct iris_batch * batch,struct iris_implicit_sync * sync,struct iris_bo * bo)238 iris_implicit_sync_add_bo(struct iris_batch *batch,
239 struct iris_implicit_sync *sync,
240 struct iris_bo *bo)
241 {
242 struct iris_syncobj *syncobj = iris_bo_export_sync_state(bo);
243
244 if (!syncobj)
245 return false;
246
247 sync->entries[sync->entry_count].bo = bo;
248 sync->entries[sync->entry_count].iris_syncobj = syncobj;
249 sync->entry_count++;
250
251 iris_batch_add_syncobj(batch, syncobj, IRIS_BATCH_FENCE_WAIT);
252
253 return true;
254 }
255
256 /* Cleans up the state of 'sync'. */
257 static void
iris_implicit_sync_finish(struct iris_batch * batch,struct iris_implicit_sync * sync)258 iris_implicit_sync_finish(struct iris_batch *batch,
259 struct iris_implicit_sync *sync)
260 {
261 struct iris_bufmgr *bufmgr = batch->screen->bufmgr;
262
263 for (int i = 0; i < sync->entry_count; i++)
264 iris_syncobj_reference(bufmgr, &sync->entries[i].iris_syncobj, NULL);
265
266 free(sync->entries);
267 sync->entry_count = 0;
268 }
269
270 /* Import implicit synchronization data from the batch bos that require
271 * implicit synchronization int our batch buffer so the batch will wait for
272 * these bos to be idle before starting.
273 */
274 static int
iris_implicit_sync_import(struct iris_batch * batch,struct iris_implicit_sync * sync)275 iris_implicit_sync_import(struct iris_batch *batch,
276 struct iris_implicit_sync *sync)
277 {
278 uint32_t len = xe_batch_submit_external_bo_count(batch);
279
280 if (!len)
281 return 0;
282
283 sync->entries = malloc(sizeof(*sync->entries) * len);
284 if (!sync->entries)
285 return -ENOMEM;
286
287 for (int i = 0; i < batch->exec_count; i++) {
288 struct iris_bo *bo = batch->exec_bos[i];
289
290 if (!iris_bo_is_real(bo) || !iris_bo_is_external(bo)) {
291 assert(iris_get_backing_bo(bo)->real.prime_fd == -1);
292 continue;
293 }
294
295 if (bo->real.prime_fd == -1) {
296 fprintf(stderr, "Bo(%s/%i %sported) with prime_fd unset in iris_implicit_sync_import()\n",
297 bo->name, bo->gem_handle, bo->real.imported ? "im" : "ex");
298 continue;
299 }
300
301 if (!iris_implicit_sync_add_bo(batch, sync, bo)) {
302 iris_implicit_sync_finish(batch, sync);
303 return -1;
304 }
305 }
306
307 return 0;
308 }
309
310 /* Export implicit synchronization data from our batch buffer into the bos
311 * that require implicit synchronization so other clients relying on it can do
312 * implicit synchronization with these bos, which will wait for the batch
313 * buffer we just submitted to signal its syncobj.
314 */
315 static bool
iris_implicit_sync_export(struct iris_batch * batch,struct iris_implicit_sync * sync)316 iris_implicit_sync_export(struct iris_batch *batch,
317 struct iris_implicit_sync *sync)
318 {
319 int sync_file_fd;
320
321 if (!iris_batch_syncobj_to_sync_file_fd(batch, &sync_file_fd))
322 return false;
323
324 for (int i = 0; i < sync->entry_count; i++)
325 iris_bo_import_sync_state(sync->entries[i].bo, sync_file_fd);
326
327 close(sync_file_fd);
328
329 return true;
330 }
331
332 static int
xe_batch_submit(struct iris_batch * batch)333 xe_batch_submit(struct iris_batch *batch)
334 {
335 struct iris_bufmgr *bufmgr = batch->screen->bufmgr;
336 struct intel_bind_timeline *bind_timeline = iris_bufmgr_get_bind_timeline(bufmgr);
337 simple_mtx_t *bo_deps_lock = iris_bufmgr_get_bo_deps_lock(bufmgr);
338 struct iris_implicit_sync implicit_sync = {};
339 struct drm_xe_sync *syncs = NULL;
340 unsigned long sync_len;
341 int ret, i;
342
343 iris_bo_unmap(batch->bo);
344
345 /* The decode operation may map and wait on the batch buffer, which could
346 * in theory try to grab bo_deps_lock. Let's keep it safe and decode
347 * outside the lock.
348 */
349 if (INTEL_DEBUG(DEBUG_BATCH) &&
350 intel_debug_batch_in_range(batch->ice->frame))
351 iris_batch_decode_batch(batch);
352
353 simple_mtx_lock(bo_deps_lock);
354
355 iris_batch_update_syncobjs(batch);
356
357 ret = iris_implicit_sync_import(batch, &implicit_sync);
358 if (ret)
359 goto error_implicit_sync_import;
360
361 sync_len = iris_batch_num_fences(batch) + 1 /* vm bind sync */;
362 syncs = calloc(sync_len, sizeof(*syncs));
363 if (!syncs) {
364 ret = -ENOMEM;
365 goto error_no_sync_mem;
366 }
367
368 i = 0;
369 util_dynarray_foreach(&batch->exec_fences, struct iris_batch_fence, fence) {
370 if (fence->flags & IRIS_BATCH_FENCE_SIGNAL)
371 syncs[i].flags = DRM_XE_SYNC_FLAG_SIGNAL;
372
373 syncs[i].handle = fence->handle;
374 syncs[i].type = DRM_XE_SYNC_TYPE_SYNCOBJ;
375 i++;
376 }
377
378 syncs[i].handle = intel_bind_timeline_get_syncobj(bind_timeline);
379 syncs[i].type = DRM_XE_SYNC_TYPE_TIMELINE_SYNCOBJ;
380 syncs[i].timeline_value = intel_bind_timeline_get_last_point(bind_timeline);
381
382 if ((INTEL_DEBUG(DEBUG_BATCH) &&
383 intel_debug_batch_in_range(batch->ice->frame)) ||
384 INTEL_DEBUG(DEBUG_SUBMIT)) {
385 iris_dump_fence_list(batch);
386 iris_dump_bo_list(batch);
387 }
388
389 struct drm_xe_exec exec = {
390 .exec_queue_id = batch->xe.exec_queue_id,
391 .num_batch_buffer = 1,
392 .address = batch->exec_bos[0]->address,
393 .syncs = (uintptr_t)syncs,
394 .num_syncs = sync_len,
395 };
396 if (!batch->screen->devinfo->no_hw)
397 ret = intel_ioctl(iris_bufmgr_get_fd(bufmgr), DRM_IOCTL_XE_EXEC, &exec);
398
399 if (ret) {
400 ret = -errno;
401 goto error_exec;
402 }
403
404 if (!iris_implicit_sync_export(batch, &implicit_sync))
405 ret = -1;
406
407 error_exec:
408 iris_implicit_sync_finish(batch, &implicit_sync);
409
410 simple_mtx_unlock(bo_deps_lock);
411
412 free(syncs);
413
414 for (int i = 0; i < batch->exec_count; i++) {
415 struct iris_bo *bo = batch->exec_bos[i];
416
417 bo->idle = false;
418 bo->index = -1;
419
420 iris_get_backing_bo(bo)->idle = false;
421
422 iris_bo_unreference(bo);
423 }
424
425 return ret;
426
427 error_no_sync_mem:
428 iris_implicit_sync_finish(batch, &implicit_sync);
429 error_implicit_sync_import:
430 simple_mtx_unlock(bo_deps_lock);
431 return ret;
432 }
433
434 static int
xe_gem_close(struct iris_bufmgr * bufmgr,struct iris_bo * bo)435 xe_gem_close(struct iris_bufmgr *bufmgr, struct iris_bo *bo)
436 {
437 if (bo->real.userptr)
438 return 0;
439
440 struct drm_gem_close close = {
441 .handle = bo->gem_handle,
442 };
443 return intel_ioctl(iris_bufmgr_get_fd(bufmgr), DRM_IOCTL_GEM_CLOSE, &close);
444 }
445
446 static uint32_t
xe_gem_create_userptr(struct iris_bufmgr * bufmgr,void * ptr,uint64_t size)447 xe_gem_create_userptr(struct iris_bufmgr *bufmgr, void *ptr, uint64_t size)
448 {
449 /* We return UINT32_MAX, because Xe doesn't create handles for userptrs but
450 * it needs a gem_handle different than 0 so iris_bo_is_real() returns true
451 * for userptr bos.
452 * UINT32_MAX handle here will not conflict with an actual gem handle with
453 * same id as userptr bos are not put to slab or bo cache.
454 */
455 return UINT32_MAX;
456 }
457
xe_get_backend(void)458 const struct iris_kmd_backend *xe_get_backend(void)
459 {
460 static const struct iris_kmd_backend xe_backend = {
461 .gem_create = xe_gem_create,
462 .gem_create_userptr = xe_gem_create_userptr,
463 .gem_close = xe_gem_close,
464 .gem_mmap = xe_gem_mmap,
465 .gem_vm_bind = xe_gem_vm_bind,
466 .gem_vm_unbind = xe_gem_vm_unbind,
467 .bo_madvise = xe_bo_madvise,
468 .bo_set_caching = xe_bo_set_caching,
469 .batch_check_for_reset = xe_batch_check_for_reset,
470 .batch_submit = xe_batch_submit,
471 };
472 return &xe_backend;
473 }
474