xref: /aosp_15_r20/external/mesa3d/src/intel/vulkan/i915/anv_device.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2022 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 shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "i915/anv_device.h"
24 #include "anv_private.h"
25 
26 #include "common/i915/intel_defines.h"
27 #include "common/i915/intel_gem.h"
28 
29 #include "drm-uapi/i915_drm.h"
30 
31 static int
vk_priority_to_i915(VkQueueGlobalPriorityKHR priority)32 vk_priority_to_i915(VkQueueGlobalPriorityKHR priority)
33 {
34    switch (priority) {
35    case VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR:
36       return INTEL_CONTEXT_LOW_PRIORITY;
37    case VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR:
38       return INTEL_CONTEXT_MEDIUM_PRIORITY;
39    case VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR:
40       return INTEL_CONTEXT_HIGH_PRIORITY;
41    case VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR:
42       return INTEL_CONTEXT_REALTIME_PRIORITY;
43    default:
44       unreachable("Invalid priority");
45    }
46 }
47 
48 int
anv_gem_set_context_param(int fd,uint32_t context,uint32_t param,uint64_t value)49 anv_gem_set_context_param(int fd, uint32_t context, uint32_t param, uint64_t value)
50 {
51    if (param == I915_CONTEXT_PARAM_PRIORITY)
52       value = vk_priority_to_i915(value);
53 
54    int err = 0;
55    if (!intel_gem_set_context_param(fd, context, param, value))
56       err = -errno;
57    return err;
58 }
59 
60 static bool
anv_gem_has_context_priority(int fd,VkQueueGlobalPriorityKHR priority)61 anv_gem_has_context_priority(int fd, VkQueueGlobalPriorityKHR priority)
62 {
63    return !anv_gem_set_context_param(fd, 0, I915_CONTEXT_PARAM_PRIORITY,
64                                      priority);
65 }
66 
67 VkResult
anv_i915_physical_device_get_parameters(struct anv_physical_device * device)68 anv_i915_physical_device_get_parameters(struct anv_physical_device *device)
69 {
70    VkResult result = VK_SUCCESS;
71    int val, fd = device->local_fd;
72    uint64_t value;
73 
74    if (!intel_gem_get_param(fd, I915_PARAM_HAS_WAIT_TIMEOUT, &val) || !val) {
75        result = vk_errorf(device, VK_ERROR_INITIALIZATION_FAILED,
76                           "kernel missing gem wait");
77        return result;
78    }
79 
80    if (!intel_gem_get_param(fd, I915_PARAM_HAS_EXECBUF2, &val) || !val) {
81       result = vk_errorf(device, VK_ERROR_INITIALIZATION_FAILED,
82                          "kernel missing execbuf2");
83       return result;
84    }
85 
86    if (!device->info.has_llc &&
87        (!intel_gem_get_param(fd, I915_PARAM_MMAP_VERSION, &val) || val < 1)) {
88        result = vk_errorf(device, VK_ERROR_INITIALIZATION_FAILED,
89                           "kernel missing wc mmap");
90        return result;
91    }
92 
93    if (!intel_gem_get_param(fd, I915_PARAM_HAS_EXEC_SOFTPIN, &val) || !val) {
94       result = vk_errorf(device, VK_ERROR_INITIALIZATION_FAILED,
95                          "kernel missing softpin");
96       return result;
97    }
98 
99    if (!intel_gem_get_param(fd, I915_PARAM_HAS_EXEC_FENCE_ARRAY, &val) || !val) {
100       result = vk_errorf(device, VK_ERROR_INITIALIZATION_FAILED,
101                          "kernel missing syncobj support");
102       return result;
103    }
104 
105    if (intel_gem_get_param(fd, I915_PARAM_HAS_EXEC_ASYNC, &val))
106       device->has_exec_async = val;
107    if (intel_gem_get_param(fd, I915_PARAM_HAS_EXEC_CAPTURE, &val))
108       device->has_exec_capture = val;
109 
110    /* Start with medium; sorted low to high */
111    const VkQueueGlobalPriorityKHR priorities[] = {
112          VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR,
113          VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR,
114          VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR,
115          VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR,
116    };
117    device->max_context_priority = VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR;
118    for (unsigned i = 0; i < ARRAY_SIZE(priorities); i++) {
119       if (!anv_gem_has_context_priority(fd, priorities[i]))
120          break;
121       device->max_context_priority = priorities[i];
122    }
123 
124    if (intel_gem_get_param(fd, I915_PARAM_HAS_EXEC_TIMELINE_FENCES, &val))
125       device->has_exec_timeline = val;
126 
127    if (intel_gem_get_context_param(fd, 0, I915_CONTEXT_PARAM_VM, &value))
128       device->has_vm_control = value;
129 
130    return result;
131 }
132 
133 VkResult
anv_i915_physical_device_init_memory_types(struct anv_physical_device * device)134 anv_i915_physical_device_init_memory_types(struct anv_physical_device *device)
135 {
136    if (anv_physical_device_has_vram(device)) {
137       device->memory.type_count = 3;
138       device->memory.types[0] = (struct anv_memory_type) {
139          .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
140          .heapIndex = 0,
141       };
142       device->memory.types[1] = (struct anv_memory_type) {
143          .propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
144                           VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
145                           VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
146          .heapIndex = 1,
147       };
148       device->memory.types[2] = (struct anv_memory_type) {
149          .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
150                           VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
151                           VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
152          /* This memory type either comes from heaps[0] if there is only
153           * mappable vram region, or from heaps[2] if there is both mappable &
154           * non-mappable vram regions.
155           */
156          .heapIndex = device->vram_non_mappable.size > 0 ? 2 : 0,
157       };
158    } else if (device->info.has_llc) {
159       /* Big core GPUs share LLC with the CPU and thus one memory type can be
160        * both cached and coherent at the same time.
161        *
162        * But some game engines can't handle single type well
163        * https://gitlab.freedesktop.org/mesa/mesa/-/issues/7360#note_1719438
164        *
165        * The second memory type w/out HOST_CACHED_BIT will get write-combining.
166        * See anv_AllocateMemory()).
167        *
168        * The Intel Vulkan driver for Windows also advertises these memory types.
169        */
170       device->memory.type_count = 3;
171       device->memory.types[0] = (struct anv_memory_type) {
172          .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
173          .heapIndex = 0,
174       };
175       device->memory.types[1] = (struct anv_memory_type) {
176          .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
177                           VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
178                           VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
179          .heapIndex = 0,
180       };
181       device->memory.types[2] = (struct anv_memory_type) {
182          .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
183                           VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
184                           VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
185                           VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
186          .heapIndex = 0,
187       };
188    } else {
189       /* The spec requires that we expose a host-visible, coherent memory
190        * type, but Atom GPUs don't share LLC. Thus we offer two memory types
191        * to give the application a choice between cached, but not coherent and
192        * coherent but uncached (WC though).
193        */
194       device->memory.type_count = 2;
195       device->memory.types[0] = (struct anv_memory_type) {
196          .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
197                           VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
198                           VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
199          .heapIndex = 0,
200       };
201       device->memory.types[1] = (struct anv_memory_type) {
202          .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
203                           VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
204                           VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
205          .heapIndex = 0,
206       };
207    }
208 
209    if (device->has_protected_contexts) {
210       /* Add a memory type for protected buffers, local and not host
211        * visible.
212        */
213       device->memory.types[device->memory.type_count++] =
214          (struct anv_memory_type) {
215             .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
216                              VK_MEMORY_PROPERTY_PROTECTED_BIT,
217             .heapIndex = 0,
218       };
219    }
220 
221    return VK_SUCCESS;
222 }
223 
224 VkResult
anv_i915_set_queue_parameters(struct anv_device * device,uint32_t context_id,const VkDeviceQueueGlobalPriorityCreateInfoKHR * queue_priority)225 anv_i915_set_queue_parameters(
226       struct anv_device *device,
227       uint32_t context_id,
228       const VkDeviceQueueGlobalPriorityCreateInfoKHR *queue_priority)
229 {
230    struct anv_physical_device *physical_device = device->physical;
231 
232    /* Here we tell the kernel not to attempt to recover our context but
233     * immediately (on the next batchbuffer submission) report that the
234     * context is lost, and we will do the recovery ourselves.  In the case
235     * of Vulkan, recovery means throwing VK_ERROR_DEVICE_LOST and letting
236     * the client clean up the pieces.
237     */
238    anv_gem_set_context_param(device->fd, context_id,
239                              I915_CONTEXT_PARAM_RECOVERABLE, false);
240 
241    VkQueueGlobalPriorityKHR priority =
242       queue_priority ? queue_priority->globalPriority :
243          VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR;
244 
245    /* As per spec, the driver implementation may deny requests to acquire
246     * a priority above the default priority (MEDIUM) if the caller does not
247     * have sufficient privileges. In this scenario VK_ERROR_NOT_PERMITTED_KHR
248     * is returned.
249     */
250    if (physical_device->max_context_priority >= VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR) {
251       int err = anv_gem_set_context_param(device->fd, context_id,
252                                           I915_CONTEXT_PARAM_PRIORITY,
253                                           priority);
254       if (err != 0 && priority > VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR) {
255          return vk_error(device, VK_ERROR_NOT_PERMITTED_KHR);
256       }
257    }
258 
259    return VK_SUCCESS;
260 }
261 
262 VkResult
anv_i915_device_setup_context(struct anv_device * device,const VkDeviceCreateInfo * pCreateInfo,const uint32_t num_queues)263 anv_i915_device_setup_context(struct anv_device *device,
264                               const VkDeviceCreateInfo *pCreateInfo,
265                               const uint32_t num_queues)
266 {
267    device->protected_session_id = I915_PROTECTED_CONTENT_DEFAULT_SESSION;
268 
269    if (device->physical->has_vm_control)
270       return anv_i915_device_setup_vm(device);
271 
272    struct anv_physical_device *physical_device = device->physical;
273    VkResult result = VK_SUCCESS;
274 
275    if (device->physical->engine_info) {
276       /* The kernel API supports at most 64 engines */
277       assert(num_queues <= 64);
278       enum intel_engine_class engine_classes[64];
279       int engine_count = 0;
280       enum intel_gem_create_context_flags flags = 0;
281       for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
282          const VkDeviceQueueCreateInfo *queueCreateInfo =
283             &pCreateInfo->pQueueCreateInfos[i];
284 
285          assert(queueCreateInfo->queueFamilyIndex <
286                 physical_device->queue.family_count);
287          struct anv_queue_family *queue_family =
288             &physical_device->queue.families[queueCreateInfo->queueFamilyIndex];
289 
290          for (uint32_t j = 0; j < queueCreateInfo->queueCount; j++)
291             engine_classes[engine_count++] = queue_family->engine_class;
292 
293          if (pCreateInfo->pQueueCreateInfos[i].flags &
294              VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT)
295             flags |= INTEL_GEM_CREATE_CONTEXT_EXT_PROTECTED_FLAG;
296       }
297       if (!intel_gem_create_context_engines(device->fd, flags,
298                                             physical_device->engine_info,
299                                             engine_count, engine_classes,
300                                             device->vm_id,
301                                             (uint32_t *)&device->context_id))
302          result = vk_errorf(device, VK_ERROR_INITIALIZATION_FAILED,
303                             "kernel context creation failed");
304    } else {
305       assert(num_queues == 1);
306       if (!intel_gem_create_context(device->fd, &device->context_id))
307          result = vk_error(device, VK_ERROR_INITIALIZATION_FAILED);
308    }
309 
310    if (result != VK_SUCCESS)
311       return result;
312 
313    /* Check if client specified queue priority. */
314    const VkDeviceQueueGlobalPriorityCreateInfoKHR *queue_priority =
315       vk_find_struct_const(pCreateInfo->pQueueCreateInfos[0].pNext,
316                            DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR);
317 
318    result = anv_i915_set_queue_parameters(device, device->context_id,
319                                           queue_priority);
320    if (result != VK_SUCCESS)
321       goto fail_context;
322 
323    return result;
324 
325 fail_context:
326    intel_gem_destroy_context(device->fd, device->context_id);
327    return result;
328 }
329 
330 static VkResult
anv_gem_context_get_reset_stats(struct anv_device * device,int context)331 anv_gem_context_get_reset_stats(struct anv_device *device, int context)
332 {
333    struct drm_i915_reset_stats stats = {
334       .ctx_id = context,
335    };
336 
337    int ret = intel_ioctl(device->fd, DRM_IOCTL_I915_GET_RESET_STATS, &stats);
338    if (ret == -1) {
339       /* We don't know the real error. */
340       return vk_device_set_lost(&device->vk, "get_reset_stats failed: %m");
341    }
342 
343    if (stats.batch_active) {
344       return vk_device_set_lost(&device->vk, "GPU hung on one of our command buffers");
345    } else if (stats.batch_pending) {
346       return vk_device_set_lost(&device->vk, "GPU hung with commands in-flight");
347    }
348 
349    return VK_SUCCESS;
350 }
351 
352 VkResult
anv_i915_device_check_status(struct vk_device * vk_device)353 anv_i915_device_check_status(struct vk_device *vk_device)
354 {
355    struct anv_device *device = container_of(vk_device, struct anv_device, vk);
356    VkResult result;
357 
358    if (device->physical->has_vm_control) {
359       for (uint32_t i = 0; i < device->queue_count; i++) {
360          result = anv_gem_context_get_reset_stats(device,
361                                                   device->queues[i].context_id);
362          if (result != VK_SUCCESS)
363             return result;
364 
365          if (device->queues[i].companion_rcs_id != 0) {
366             uint32_t context_id = device->queues[i].companion_rcs_id;
367             result = anv_gem_context_get_reset_stats(device, context_id);
368             if (result != VK_SUCCESS) {
369                return result;
370             }
371          }
372       }
373    } else {
374       result = anv_gem_context_get_reset_stats(device, device->context_id);
375    }
376 
377    return result;
378 }
379 
380 bool
anv_i915_device_destroy_vm(struct anv_device * device)381 anv_i915_device_destroy_vm(struct anv_device *device)
382 {
383    struct drm_i915_gem_vm_control destroy = {
384       .vm_id = device->vm_id,
385    };
386 
387    return intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_VM_DESTROY, &destroy) == 0;
388 }
389 
390 VkResult
anv_i915_device_setup_vm(struct anv_device * device)391 anv_i915_device_setup_vm(struct anv_device *device)
392 {
393    struct drm_i915_gem_vm_control create = {};
394    if (intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_VM_CREATE, &create))
395       return vk_errorf(device, VK_ERROR_INITIALIZATION_FAILED,
396                        "vm creation failed");
397 
398    device->vm_id = create.vm_id;
399    return VK_SUCCESS;
400 }
401