• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
24 #include <sys/mman.h>
25 
26 #include "common/xe/intel_engine.h"
27 
28 #include "anv_private.h"
29 
30 #include "xe/anv_batch_chain.h"
31 
32 #include "drm-uapi/gpu_scheduler.h"
33 #include "drm-uapi/xe_drm.h"
34 
35 static uint32_t
xe_gem_create(struct anv_device * device,const struct intel_memory_class_instance ** regions,uint16_t regions_count,uint64_t size,enum anv_bo_alloc_flags alloc_flags,uint64_t * actual_size)36 xe_gem_create(struct anv_device *device,
37               const struct intel_memory_class_instance **regions,
38               uint16_t regions_count, uint64_t size,
39               enum anv_bo_alloc_flags alloc_flags,
40               uint64_t *actual_size)
41 {
42    /* TODO: protected content */
43    assert((alloc_flags & ANV_BO_ALLOC_PROTECTED) == 0);
44    /* WB+0 way coherent not supported by Xe KMD */
45    assert(alloc_flags & ANV_BO_ALLOC_HOST_COHERENT);
46 
47    uint32_t flags = 0;
48    if (alloc_flags & ANV_BO_ALLOC_SCANOUT)
49       flags |= DRM_XE_GEM_CREATE_FLAG_SCANOUT;
50    if ((alloc_flags & (ANV_BO_ALLOC_MAPPED | ANV_BO_ALLOC_LOCAL_MEM_CPU_VISIBLE)) &&
51        !(alloc_flags & ANV_BO_ALLOC_NO_LOCAL_MEM) &&
52        device->physical->vram_non_mappable.size > 0)
53       flags |= DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM;
54 
55    struct drm_xe_gem_create gem_create = {
56      /* From xe_drm.h: If a VM is specified, this BO must:
57       * 1. Only ever be bound to that VM.
58       * 2. Cannot be exported as a PRIME fd.
59       */
60      .vm_id = alloc_flags & ANV_BO_ALLOC_EXTERNAL ? 0 : device->vm_id,
61      .size = align64(size, device->info->mem_alignment),
62      .flags = flags,
63    };
64    for (uint16_t i = 0; i < regions_count; i++)
65       gem_create.placement |= BITFIELD_BIT(regions[i]->instance);
66 
67    const struct intel_device_info_pat_entry *pat_entry =
68          anv_device_get_pat_entry(device, alloc_flags);
69    switch (pat_entry->mmap) {
70    case INTEL_DEVICE_INFO_MMAP_MODE_WC:
71       gem_create.cpu_caching = DRM_XE_GEM_CPU_CACHING_WC;
72       break;
73    case INTEL_DEVICE_INFO_MMAP_MODE_WB:
74       gem_create.cpu_caching = DRM_XE_GEM_CPU_CACHING_WB;
75       break;
76    default:
77       unreachable("missing");
78       gem_create.cpu_caching = DRM_XE_GEM_CPU_CACHING_WC;
79    }
80 
81    if (intel_ioctl(device->fd, DRM_IOCTL_XE_GEM_CREATE, &gem_create))
82       return 0;
83 
84    *actual_size = gem_create.size;
85    return gem_create.handle;
86 }
87 
88 static void
xe_gem_close(struct anv_device * device,struct anv_bo * bo)89 xe_gem_close(struct anv_device *device, struct anv_bo *bo)
90 {
91    if (bo->from_host_ptr)
92       return;
93 
94    struct drm_gem_close close = {
95       .handle = bo->gem_handle,
96    };
97    intel_ioctl(device->fd, DRM_IOCTL_GEM_CLOSE, &close);
98 }
99 
100 static void *
xe_gem_mmap(struct anv_device * device,struct anv_bo * bo,uint64_t offset,uint64_t size)101 xe_gem_mmap(struct anv_device *device, struct anv_bo *bo, uint64_t offset,
102             uint64_t size)
103 {
104    struct drm_xe_gem_mmap_offset args = {
105       .handle = bo->gem_handle,
106    };
107    if (intel_ioctl(device->fd, DRM_IOCTL_XE_GEM_MMAP_OFFSET, &args))
108       return MAP_FAILED;
109 
110    return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
111                device->fd, args.offset);
112 }
113 
114 static inline uint32_t
capture_vm_in_error_dump(struct anv_device * device,struct anv_bo * bo)115 capture_vm_in_error_dump(struct anv_device *device, struct anv_bo *bo)
116 {
117    enum anv_bo_alloc_flags alloc_flags = bo ? bo->alloc_flags : 0;
118    bool capture = INTEL_DEBUG(DEBUG_CAPTURE_ALL) ||
119                   (alloc_flags & ANV_BO_ALLOC_CAPTURE);
120 
121    return capture ? DRM_XE_VM_BIND_FLAG_DUMPABLE : 0;
122 }
123 
124 static inline int
xe_vm_bind_op(struct anv_device * device,struct anv_sparse_submission * submit)125 xe_vm_bind_op(struct anv_device *device,
126               struct anv_sparse_submission *submit)
127 {
128    struct drm_xe_sync xe_sync = {
129       .handle = intel_bind_timeline_get_syncobj(&device->bind_timeline),
130       .type = DRM_XE_SYNC_TYPE_TIMELINE_SYNCOBJ,
131       .flags = DRM_XE_SYNC_FLAG_SIGNAL,
132    };
133    struct drm_xe_vm_bind args = {
134       .vm_id = device->vm_id,
135       .num_binds = submit->binds_len,
136       .bind = {},
137       .num_syncs = 1,
138       .syncs = (uintptr_t)&xe_sync,
139    };
140    int ret;
141 
142    STACK_ARRAY(struct drm_xe_vm_bind_op, xe_binds_stackarray,
143                submit->binds_len);
144    struct drm_xe_vm_bind_op *xe_binds;
145    if (submit->binds_len > 1) {
146       if (!xe_binds_stackarray)
147          return -ENOMEM;
148 
149       xe_binds = xe_binds_stackarray;
150       args.vector_of_binds = (uintptr_t)xe_binds;
151    } else {
152       xe_binds = &args.bind;
153    }
154 
155    for (int i = 0; i < submit->binds_len; i++) {
156       struct anv_vm_bind *bind = &submit->binds[i];
157       struct anv_bo *bo = bind->bo;
158 
159       struct drm_xe_vm_bind_op *xe_bind = &xe_binds[i];
160       *xe_bind = (struct drm_xe_vm_bind_op) {
161          .obj = 0,
162          .obj_offset = bind->bo_offset,
163          .range = bind->size,
164          .addr = intel_48b_address(bind->address),
165          .op = DRM_XE_VM_BIND_OP_UNMAP,
166          .flags = capture_vm_in_error_dump(device, bo),
167          .prefetch_mem_region_instance = 0,
168       };
169 
170       if (bind->op == ANV_VM_BIND) {
171          const enum anv_bo_alloc_flags alloc_flags = bo ? bo->alloc_flags : 0;
172 
173          xe_bind->pat_index = anv_device_get_pat_entry(device, alloc_flags)->index;
174          if (!bo) {
175             xe_bind->op = DRM_XE_VM_BIND_OP_MAP;
176             xe_bind->flags |= DRM_XE_VM_BIND_FLAG_NULL;
177             assert(xe_bind->obj_offset == 0);
178          } else if (bo->from_host_ptr) {
179             xe_bind->op = DRM_XE_VM_BIND_OP_MAP_USERPTR;
180          } else {
181             xe_bind->op = DRM_XE_VM_BIND_OP_MAP;
182             xe_bind->obj = bo->gem_handle;
183          }
184       } else if (bind->op == ANV_VM_UNBIND_ALL) {
185          xe_bind->op = DRM_XE_VM_BIND_OP_UNMAP_ALL;
186          xe_bind->obj = bo->gem_handle;
187          assert(bind->address == 0);
188          assert(bind->size == 0);
189       } else {
190          assert(bind->op == ANV_VM_UNBIND);
191       }
192 
193       /* userptr and bo_offset are an union! */
194       if (bo && bo->from_host_ptr)
195          xe_bind->userptr = (uintptr_t)bo->map;
196    }
197 
198    xe_sync.timeline_value = intel_bind_timeline_bind_begin(&device->bind_timeline);
199    ret = intel_ioctl(device->fd, DRM_IOCTL_XE_VM_BIND, &args);
200    intel_bind_timeline_bind_end(&device->bind_timeline);
201 
202    if (ret)
203       goto out_stackarray;
204 
205    ANV_RMV(vm_binds, device, submit->binds, submit->binds_len);
206 
207 out_stackarray:
208    STACK_ARRAY_FINISH(xe_binds_stackarray);
209 
210    return ret;
211 }
212 
213 static int
xe_vm_bind(struct anv_device * device,struct anv_sparse_submission * submit)214 xe_vm_bind(struct anv_device *device, struct anv_sparse_submission *submit)
215 {
216    return xe_vm_bind_op(device, submit);
217 }
218 
xe_vm_bind_bo(struct anv_device * device,struct anv_bo * bo)219 static int xe_vm_bind_bo(struct anv_device *device, struct anv_bo *bo)
220 {
221    struct anv_vm_bind bind = {
222       .bo = bo,
223       .address = bo->offset,
224       .bo_offset = 0,
225       .size = bo->actual_size,
226       .op = ANV_VM_BIND,
227    };
228    struct anv_sparse_submission submit = {
229       .queue = NULL,
230       .binds = &bind,
231       .binds_len = 1,
232       .binds_capacity = 1,
233       .wait_count = 0,
234       .signal_count = 0,
235    };
236    return xe_vm_bind_op(device, &submit);
237 }
238 
xe_vm_unbind_bo(struct anv_device * device,struct anv_bo * bo)239 static int xe_vm_unbind_bo(struct anv_device *device, struct anv_bo *bo)
240 {
241    struct anv_vm_bind bind = {
242       .bo = bo,
243       .address = 0,
244       .bo_offset = 0,
245       .size = 0,
246       .op = ANV_VM_UNBIND_ALL,
247    };
248    struct anv_sparse_submission submit = {
249       .queue = NULL,
250       .binds = &bind,
251       .binds_len = 1,
252       .binds_capacity = 1,
253       .wait_count = 0,
254       .signal_count = 0,
255    };
256    return xe_vm_bind_op(device, &submit);
257 }
258 
259 static uint32_t
xe_gem_create_userptr(struct anv_device * device,void * mem,uint64_t size)260 xe_gem_create_userptr(struct anv_device *device, void *mem, uint64_t size)
261 {
262    /* We return the workaround BO gem_handle here, because Xe doesn't
263     * create handles for userptrs. But we still need to make it look
264     * to the rest of Anv that the operation succeeded.
265     */
266    return device->workaround_bo->gem_handle;
267 }
268 
269 static uint32_t
xe_bo_alloc_flags_to_bo_flags(struct anv_device * device,enum anv_bo_alloc_flags alloc_flags)270 xe_bo_alloc_flags_to_bo_flags(struct anv_device *device,
271                               enum anv_bo_alloc_flags alloc_flags)
272 {
273    return 0;
274 }
275 
276 const struct anv_kmd_backend *
anv_xe_kmd_backend_get(void)277 anv_xe_kmd_backend_get(void)
278 {
279    static const struct anv_kmd_backend xe_backend = {
280       .gem_create = xe_gem_create,
281       .gem_create_userptr = xe_gem_create_userptr,
282       .gem_close = xe_gem_close,
283       .gem_mmap = xe_gem_mmap,
284       .vm_bind = xe_vm_bind,
285       .vm_bind_bo = xe_vm_bind_bo,
286       .vm_unbind_bo = xe_vm_unbind_bo,
287       .execute_simple_batch = xe_execute_simple_batch,
288       .execute_trtt_batch = xe_execute_trtt_batch,
289       .queue_exec_locked = xe_queue_exec_locked,
290       .queue_exec_trace = xe_queue_exec_utrace_locked,
291       .bo_alloc_flags_to_bo_flags = xe_bo_alloc_flags_to_bo_flags,
292    };
293    return &xe_backend;
294 }
295