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