xref: /aosp_15_r20/external/mesa3d/src/intel/vulkan/i915/anv_kmd_backend.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 
24 #include <sys/mman.h>
25 
26 #include "anv_private.h"
27 
28 #include "i915/anv_batch_chain.h"
29 
30 #include "drm-uapi/i915_drm.h"
31 #include "intel/common/i915/intel_gem.h"
32 
33 static int
i915_gem_set_caching(struct anv_device * device,uint32_t gem_handle,uint32_t caching)34 i915_gem_set_caching(struct anv_device *device,
35                      uint32_t gem_handle, uint32_t caching)
36 {
37    struct drm_i915_gem_caching gem_caching = {
38       .handle = gem_handle,
39       .caching = caching,
40    };
41 
42    return intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_SET_CACHING, &gem_caching);
43 }
44 
45 static uint32_t
i915_gem_create(struct anv_device * device,const struct intel_memory_class_instance ** regions,uint16_t num_regions,uint64_t size,enum anv_bo_alloc_flags alloc_flags,uint64_t * actual_size)46 i915_gem_create(struct anv_device *device,
47                 const struct intel_memory_class_instance **regions,
48                 uint16_t num_regions, uint64_t size,
49                 enum anv_bo_alloc_flags alloc_flags,
50                 uint64_t *actual_size)
51 {
52    if (unlikely(!device->info->mem.use_class_instance)) {
53       assert(num_regions == 1 &&
54              device->physical->sys.region == regions[0]);
55 
56       struct drm_i915_gem_create gem_create = {
57             .size = size,
58       };
59       if (intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_CREATE, &gem_create))
60          return 0;
61 
62       if ((alloc_flags & ANV_BO_ALLOC_HOST_CACHED_COHERENT) == ANV_BO_ALLOC_HOST_CACHED_COHERENT) {
63          /* We don't want to change these defaults if it's going to be shared
64           * with another process.
65           */
66          assert(!(alloc_flags & ANV_BO_ALLOC_EXTERNAL));
67 
68          /* Regular objects are created I915_CACHING_CACHED on LLC platforms and
69           * I915_CACHING_NONE on non-LLC platforms.  For many internal state
70           * objects, we'd rather take the snooping overhead than risk forgetting
71           * a CLFLUSH somewhere.  Userptr objects are always created as
72           * I915_CACHING_CACHED, which on non-LLC means snooped so there's no
73           * need to do this there.
74           */
75          if (device->info->has_caching_uapi && !device->info->has_llc)
76             i915_gem_set_caching(device, gem_create.handle, I915_CACHING_CACHED);
77       }
78 
79       *actual_size = gem_create.size;
80       return gem_create.handle;
81    }
82 
83    struct drm_i915_gem_memory_class_instance i915_regions[2];
84    assert(num_regions <= ARRAY_SIZE(i915_regions));
85 
86    for (uint16_t i = 0; i < num_regions; i++) {
87       i915_regions[i].memory_class = regions[i]->klass;
88       i915_regions[i].memory_instance = regions[i]->instance;
89    }
90 
91    uint32_t flags = 0;
92    if (alloc_flags & (ANV_BO_ALLOC_MAPPED | ANV_BO_ALLOC_LOCAL_MEM_CPU_VISIBLE) &&
93        !(alloc_flags & ANV_BO_ALLOC_NO_LOCAL_MEM))
94       if (device->physical->vram_non_mappable.size > 0)
95          flags |= I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS;
96 
97    struct drm_i915_gem_create_ext_memory_regions ext_regions = {
98       .num_regions = num_regions,
99       .regions = (uintptr_t)i915_regions,
100    };
101    struct drm_i915_gem_create_ext gem_create = {
102       .size = size,
103       .flags = flags,
104    };
105 
106    intel_i915_gem_add_ext(&gem_create.extensions,
107                           I915_GEM_CREATE_EXT_MEMORY_REGIONS,
108                           &ext_regions.base);
109 
110    struct drm_i915_gem_create_ext_set_pat set_pat_param = { 0 };
111    if (device->info->has_set_pat_uapi) {
112       /* Set PAT param */
113       set_pat_param.pat_index = anv_device_get_pat_entry(device, alloc_flags)->index;
114       intel_i915_gem_add_ext(&gem_create.extensions,
115                              I915_GEM_CREATE_EXT_SET_PAT,
116                              &set_pat_param.base);
117    }
118 
119    struct drm_i915_gem_create_ext_protected_content protected_param = { 0 };
120    if (alloc_flags & ANV_BO_ALLOC_PROTECTED) {
121       intel_i915_gem_add_ext(&gem_create.extensions,
122                              I915_GEM_CREATE_EXT_PROTECTED_CONTENT,
123                              &protected_param.base);
124    }
125 
126    if (intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &gem_create))
127       return 0;
128 
129    *actual_size = gem_create.size;
130 
131    if ((alloc_flags & ANV_BO_ALLOC_HOST_CACHED_COHERENT) == ANV_BO_ALLOC_HOST_CACHED_COHERENT) {
132       /* We don't want to change these defaults if it's going to be shared
133        * with another process.
134        */
135       assert(!(alloc_flags & ANV_BO_ALLOC_EXTERNAL));
136 
137       /* Regular objects are created I915_CACHING_CACHED on LLC platforms and
138        * I915_CACHING_NONE on non-LLC platforms.  For many internal state
139        * objects, we'd rather take the snooping overhead than risk forgetting
140        * a CLFLUSH somewhere.  Userptr objects are always created as
141        * I915_CACHING_CACHED, which on non-LLC means snooped so there's no
142        * need to do this there.
143        */
144       if (device->info->has_caching_uapi && !device->info->has_llc)
145          i915_gem_set_caching(device, gem_create.handle, I915_CACHING_CACHED);
146    }
147 
148    return gem_create.handle;
149 }
150 
151 static void
i915_gem_close(struct anv_device * device,struct anv_bo * bo)152 i915_gem_close(struct anv_device *device, struct anv_bo *bo)
153 {
154    struct drm_gem_close close = {
155       .handle = bo->gem_handle,
156    };
157 
158    intel_ioctl(device->fd, DRM_IOCTL_GEM_CLOSE, &close);
159 }
160 
161 static void *
i915_gem_mmap_offset(struct anv_device * device,struct anv_bo * bo,uint64_t size,uint32_t flags,void * placed_addr)162 i915_gem_mmap_offset(struct anv_device *device, struct anv_bo *bo,
163                      uint64_t size, uint32_t flags,
164                      void *placed_addr)
165 {
166    struct drm_i915_gem_mmap_offset gem_mmap = {
167       .handle = bo->gem_handle,
168       .flags = flags,
169    };
170    if (intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_MMAP_OFFSET, &gem_mmap))
171       return MAP_FAILED;
172 
173    return mmap(placed_addr, size, PROT_READ | PROT_WRITE,
174                (placed_addr != NULL ? MAP_FIXED : 0) | MAP_SHARED,
175                device->fd, gem_mmap.offset);
176 }
177 
178 static void *
i915_gem_mmap_legacy(struct anv_device * device,struct anv_bo * bo,uint64_t offset,uint64_t size,uint32_t flags)179 i915_gem_mmap_legacy(struct anv_device *device, struct anv_bo *bo, uint64_t offset,
180                       uint64_t size, uint32_t flags)
181 {
182    struct drm_i915_gem_mmap gem_mmap = {
183       .handle = bo->gem_handle,
184       .offset = offset,
185       .size = size,
186       .flags = flags,
187    };
188    if (intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_MMAP, &gem_mmap))
189       return MAP_FAILED;
190 
191    return (void *)(uintptr_t) gem_mmap.addr_ptr;
192 }
193 
194 static uint32_t
mmap_calc_flags(struct anv_device * device,struct anv_bo * bo)195 mmap_calc_flags(struct anv_device *device, struct anv_bo *bo)
196 {
197    if (device->info->has_local_mem)
198       return I915_MMAP_OFFSET_FIXED;
199 
200    uint32_t flags;
201    switch (anv_bo_get_mmap_mode(device, bo)) {
202    case INTEL_DEVICE_INFO_MMAP_MODE_WC:
203       flags = I915_MMAP_WC;
204       break;
205    case INTEL_DEVICE_INFO_MMAP_MODE_UC:
206       unreachable("Missing");
207    default:
208       /* no flags == WB */
209       flags = 0;
210    }
211 
212    if (likely(device->physical->info.has_mmap_offset))
213       flags = (flags & I915_MMAP_WC) ? I915_MMAP_OFFSET_WC : I915_MMAP_OFFSET_WB;
214    return flags;
215 }
216 
217 static void *
i915_gem_mmap(struct anv_device * device,struct anv_bo * bo,uint64_t offset,uint64_t size,void * placed_addr)218 i915_gem_mmap(struct anv_device *device, struct anv_bo *bo, uint64_t offset,
219               uint64_t size, void *placed_addr)
220 {
221    const uint32_t flags = mmap_calc_flags(device, bo);
222 
223    if (likely(device->physical->info.has_mmap_offset))
224       return i915_gem_mmap_offset(device, bo, size, flags, placed_addr);
225    assert(placed_addr == NULL);
226    return i915_gem_mmap_legacy(device, bo, offset, size, flags);
227 }
228 
229 static VkResult
i915_vm_bind(struct anv_device * device,struct anv_sparse_submission * submit,enum anv_vm_bind_flags flags)230 i915_vm_bind(struct anv_device *device, struct anv_sparse_submission *submit,
231              enum anv_vm_bind_flags flags)
232 {
233    return VK_SUCCESS;
234 }
235 
236 static VkResult
i915_vm_bind_bo(struct anv_device * device,struct anv_bo * bo)237 i915_vm_bind_bo(struct anv_device *device, struct anv_bo *bo)
238 {
239    return VK_SUCCESS;
240 }
241 
242 static uint32_t
i915_gem_create_userptr(struct anv_device * device,void * mem,uint64_t size)243 i915_gem_create_userptr(struct anv_device *device, void *mem, uint64_t size)
244 {
245    struct drm_i915_gem_userptr userptr = {
246       .user_ptr = (__u64)((unsigned long) mem),
247       .user_size = size,
248       .flags = 0,
249    };
250 
251    if (device->physical->info.has_userptr_probe)
252       userptr.flags |= I915_USERPTR_PROBE;
253 
254    int ret = intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_USERPTR, &userptr);
255    if (ret == -1)
256       return 0;
257 
258    return userptr.handle;
259 }
260 
261 static uint32_t
i915_bo_alloc_flags_to_bo_flags(struct anv_device * device,enum anv_bo_alloc_flags alloc_flags)262 i915_bo_alloc_flags_to_bo_flags(struct anv_device *device,
263                                 enum anv_bo_alloc_flags alloc_flags)
264 {
265    struct anv_physical_device *pdevice = device->physical;
266 
267    uint64_t bo_flags = EXEC_OBJECT_PINNED;
268 
269    if (!(alloc_flags & ANV_BO_ALLOC_32BIT_ADDRESS))
270       bo_flags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
271 
272    if (((alloc_flags & ANV_BO_ALLOC_CAPTURE) ||
273         INTEL_DEBUG(DEBUG_CAPTURE_ALL)) &&
274        pdevice->has_exec_capture)
275       bo_flags |= EXEC_OBJECT_CAPTURE;
276 
277    if (alloc_flags & ANV_BO_ALLOC_IMPLICIT_WRITE) {
278       assert(alloc_flags & ANV_BO_ALLOC_IMPLICIT_SYNC);
279       bo_flags |= EXEC_OBJECT_WRITE;
280    }
281 
282    if (!(alloc_flags & ANV_BO_ALLOC_IMPLICIT_SYNC) && pdevice->has_exec_async)
283       bo_flags |= EXEC_OBJECT_ASYNC;
284 
285    return bo_flags;
286 }
287 
288 const struct anv_kmd_backend *
anv_i915_kmd_backend_get(void)289 anv_i915_kmd_backend_get(void)
290 {
291    static const struct anv_kmd_backend i915_backend = {
292       .gem_create = i915_gem_create,
293       .gem_create_userptr = i915_gem_create_userptr,
294       .gem_close = i915_gem_close,
295       .gem_mmap = i915_gem_mmap,
296       .vm_bind = i915_vm_bind,
297       .vm_bind_bo = i915_vm_bind_bo,
298       .vm_unbind_bo = i915_vm_bind_bo,
299       .queue_exec_locked = i915_queue_exec_locked,
300       .queue_exec_async = i915_queue_exec_async,
301       .bo_alloc_flags_to_bo_flags = i915_bo_alloc_flags_to_bo_flags,
302    };
303    return &i915_backend;
304 }
305