• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2016 Red Hat.
3  * Copyright © 2016 Bas Nieuwenhuizen
4  * SPDX-License-Identifier: MIT
5  *
6  * based in part on anv driver which is:
7  * Copyright © 2015 Intel Corporation
8  */
9 
10 #include <fcntl.h>
11 
12 #ifdef MAJOR_IN_MKDEV
13 #include <sys/mkdev.h>
14 #endif
15 #ifdef MAJOR_IN_SYSMACROS
16 #include <sys/sysmacros.h>
17 #endif
18 
19 #include <sys/mman.h>
20 
21 #include "vk_debug_utils.h"
22 
23 #include "util/libdrm.h"
24 
25 #include "tu_device.h"
26 #include "tu_knl.h"
27 #include "tu_queue.h"
28 #include "tu_rmv.h"
29 
30 
31 VkResult
tu_bo_init_new_explicit_iova(struct tu_device * dev,struct vk_object_base * base,struct tu_bo ** out_bo,uint64_t size,uint64_t client_iova,VkMemoryPropertyFlags mem_property,enum tu_bo_alloc_flags flags,const char * name)32 tu_bo_init_new_explicit_iova(struct tu_device *dev,
33                              struct vk_object_base *base,
34                              struct tu_bo **out_bo,
35                              uint64_t size,
36                              uint64_t client_iova,
37                              VkMemoryPropertyFlags mem_property,
38                              enum tu_bo_alloc_flags flags, const char *name)
39 {
40    struct tu_instance *instance = dev->physical_device->instance;
41 
42    VkResult result =
43       dev->instance->knl->bo_init(dev, base, out_bo, size, client_iova,
44                                   mem_property, flags, name);
45    if (result != VK_SUCCESS)
46       return result;
47 
48    if ((mem_property & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) &&
49        !(mem_property & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
50       (*out_bo)->cached_non_coherent = true;
51 
52    vk_address_binding_report(&instance->vk, base ? base : &dev->vk.base,
53                              (*out_bo)->iova, (*out_bo)->size,
54                              VK_DEVICE_ADDRESS_BINDING_TYPE_BIND_EXT);
55 
56    (*out_bo)->dump = flags & TU_BO_ALLOC_ALLOW_DUMP;
57 
58    return VK_SUCCESS;
59 }
60 
61 VkResult
tu_bo_init_dmabuf(struct tu_device * dev,struct tu_bo ** bo,uint64_t size,int fd)62 tu_bo_init_dmabuf(struct tu_device *dev,
63                   struct tu_bo **bo,
64                   uint64_t size,
65                   int fd)
66 {
67    VkResult result = dev->instance->knl->bo_init_dmabuf(dev, bo, size, fd);
68    if (result != VK_SUCCESS)
69       return result;
70 
71    /* If we have non-coherent cached memory, then defensively assume that it
72     * may need to be invalidated/flushed. If not, then we just have to assume
73     * that whatever dma-buf producer didn't allocate it non-coherent cached
74     * because we have no way of handling that.
75     */
76    if (dev->physical_device->has_cached_non_coherent_memory)
77       (*bo)->cached_non_coherent = true;
78 
79    return VK_SUCCESS;
80 }
81 
82 int
tu_bo_export_dmabuf(struct tu_device * dev,struct tu_bo * bo)83 tu_bo_export_dmabuf(struct tu_device *dev, struct tu_bo *bo)
84 {
85    return dev->instance->knl->bo_export_dmabuf(dev, bo);
86 }
87 
88 void
tu_bo_finish(struct tu_device * dev,struct tu_bo * bo)89 tu_bo_finish(struct tu_device *dev, struct tu_bo *bo)
90 {
91    struct tu_instance *instance = dev->physical_device->instance;
92 
93    vk_address_binding_report(&instance->vk, bo->base ? bo->base : &dev->vk.base,
94                              bo->iova, bo->size,
95                              VK_DEVICE_ADDRESS_BINDING_TYPE_UNBIND_EXT);
96 
97    dev->instance->knl->bo_finish(dev, bo);
98 }
99 
100 VkResult
tu_bo_map(struct tu_device * dev,struct tu_bo * bo,void * placed_addr)101 tu_bo_map(struct tu_device *dev, struct tu_bo *bo, void *placed_addr)
102 {
103    if (bo->map && (placed_addr == NULL || placed_addr == bo->map))
104       return VK_SUCCESS;
105    else if (bo->map)
106       /* The BO is already mapped, but with a different address. */
107       return vk_errorf(dev, VK_ERROR_MEMORY_MAP_FAILED, "Cannot remap BO to a different address");
108 
109    return dev->instance->knl->bo_map(dev, bo, placed_addr);
110 }
111 
112 VkResult
tu_bo_unmap(struct tu_device * dev,struct tu_bo * bo,bool reserve)113 tu_bo_unmap(struct tu_device *dev, struct tu_bo *bo, bool reserve)
114 {
115    if (!bo->map || bo->never_unmap)
116       return VK_SUCCESS;
117 
118    TU_RMV(bo_unmap, dev, bo);
119 
120    if (reserve) {
121       void *map = mmap(bo->map, bo->size, PROT_NONE,
122                  MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
123       if (map == MAP_FAILED)
124          return vk_errorf(dev, VK_ERROR_MEMORY_MAP_FAILED,
125                           "Failed to replace mapping with reserved memory");
126    } else {
127       munmap(bo->map, bo->size);
128    }
129 
130    bo->map = NULL;
131 
132    return VK_SUCCESS;
133 }
134 
135 static inline void
tu_sync_cacheline_to_gpu(void const * p)136 tu_sync_cacheline_to_gpu(void const *p __attribute__((unused)))
137 {
138 #if DETECT_ARCH_AARCH64
139    /* Clean data cache. */
140    __asm volatile("dc cvac, %0" : : "r" (p) : "memory");
141 #elif (DETECT_ARCH_X86 || DETECT_ARCH_X86_64)
142    __builtin_ia32_clflush(p);
143 #elif DETECT_ARCH_ARM
144    /* DCCMVAC - same as DC CVAC on aarch64.
145     * Seems to be illegal to call from userspace.
146     */
147    //__asm volatile("mcr p15, 0, %0, c7, c10, 1" : : "r" (p) : "memory");
148    unreachable("Cache line clean is unsupported on ARMv7");
149 #endif
150 }
151 
152 static inline void
tu_sync_cacheline_from_gpu(void const * p)153 tu_sync_cacheline_from_gpu(void const *p __attribute__((unused)))
154 {
155 #if DETECT_ARCH_AARCH64
156    /* Clean and Invalidate data cache, there is no separate Invalidate. */
157    __asm volatile("dc civac, %0" : : "r" (p) : "memory");
158 #elif (DETECT_ARCH_X86 || DETECT_ARCH_X86_64)
159    __builtin_ia32_clflush(p);
160 #elif DETECT_ARCH_ARM
161    /* DCCIMVAC - same as DC CIVAC on aarch64.
162     * Seems to be illegal to call from userspace.
163     */
164    //__asm volatile("mcr p15, 0, %0, c7, c14, 1" : : "r" (p) : "memory");
165    unreachable("Cache line invalidate is unsupported on ARMv7");
166 #endif
167 }
168 
169 void
tu_bo_sync_cache(struct tu_device * dev,struct tu_bo * bo,VkDeviceSize offset,VkDeviceSize size,enum tu_mem_sync_op op)170 tu_bo_sync_cache(struct tu_device *dev,
171                  struct tu_bo *bo,
172                  VkDeviceSize offset,
173                  VkDeviceSize size,
174                  enum tu_mem_sync_op op)
175 {
176    uintptr_t level1_dcache_size = dev->physical_device->level1_dcache_size;
177    char *start = (char *) bo->map + offset;
178    char *end = start + (size == VK_WHOLE_SIZE ? (bo->size - offset) : size);
179 
180    start = (char *) ((uintptr_t) start & ~(level1_dcache_size - 1));
181 
182    for (; start < end; start += level1_dcache_size) {
183       if (op == TU_MEM_SYNC_CACHE_TO_GPU) {
184          tu_sync_cacheline_to_gpu(start);
185       } else {
186          tu_sync_cacheline_from_gpu(start);
187       }
188    }
189 }
190 
191 uint32_t
tu_get_l1_dcache_size()192 tu_get_l1_dcache_size()
193 {
194 if (!(DETECT_ARCH_AARCH64 || DETECT_ARCH_X86 || DETECT_ARCH_X86_64))
195    return 0;
196 
197 #if DETECT_ARCH_AARCH64 &&                                                   \
198    (!defined(_SC_LEVEL1_DCACHE_LINESIZE) || DETECT_OS_ANDROID)
199    /* Bionic does not implement _SC_LEVEL1_DCACHE_LINESIZE properly: */
200    uint64_t ctr_el0;
201    asm("mrs\t%x0, ctr_el0" : "=r"(ctr_el0));
202    return 4 << ((ctr_el0 >> 16) & 0xf);
203 #elif defined(_SC_LEVEL1_DCACHE_LINESIZE)
204    return sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
205 #else
206    return 0;
207 #endif
208 }
209 
tu_bo_allow_dump(struct tu_device * dev,struct tu_bo * bo)210 void tu_bo_allow_dump(struct tu_device *dev, struct tu_bo *bo)
211 {
212    dev->instance->knl->bo_allow_dump(dev, bo);
213 
214    p_atomic_set(&bo->dump, true);
215 }
216 
217 void
tu_bo_set_metadata(struct tu_device * dev,struct tu_bo * bo,void * metadata,uint32_t metadata_size)218 tu_bo_set_metadata(struct tu_device *dev, struct tu_bo *bo,
219                    void *metadata, uint32_t metadata_size)
220 {
221    if (!dev->instance->knl->bo_set_metadata)
222       return;
223    dev->instance->knl->bo_set_metadata(dev, bo, metadata, metadata_size);
224 }
225 
226 int
tu_bo_get_metadata(struct tu_device * dev,struct tu_bo * bo,void * metadata,uint32_t metadata_size)227 tu_bo_get_metadata(struct tu_device *dev, struct tu_bo *bo,
228                    void *metadata, uint32_t metadata_size)
229 {
230    if (!dev->instance->knl->bo_get_metadata)
231       return -ENOSYS;
232    return dev->instance->knl->bo_get_metadata(dev, bo, metadata, metadata_size);
233 }
234 
235 VkResult
tu_drm_device_init(struct tu_device * dev)236 tu_drm_device_init(struct tu_device *dev)
237 {
238    return dev->instance->knl->device_init(dev);
239 }
240 
241 void
tu_drm_device_finish(struct tu_device * dev)242 tu_drm_device_finish(struct tu_device *dev)
243 {
244    dev->instance->knl->device_finish(dev);
245 }
246 
247 int
tu_device_get_gpu_timestamp(struct tu_device * dev,uint64_t * ts)248 tu_device_get_gpu_timestamp(struct tu_device *dev,
249                             uint64_t *ts)
250 {
251    return dev->instance->knl->device_get_gpu_timestamp(dev, ts);
252 }
253 
254 int
tu_device_get_suspend_count(struct tu_device * dev,uint64_t * suspend_count)255 tu_device_get_suspend_count(struct tu_device *dev,
256                             uint64_t *suspend_count)
257 {
258    return dev->instance->knl->device_get_suspend_count(dev, suspend_count);
259 }
260 
261 VkResult
tu_queue_wait_fence(struct tu_queue * queue,uint32_t fence,uint64_t timeout_ns)262 tu_queue_wait_fence(struct tu_queue *queue, uint32_t fence,
263                     uint64_t timeout_ns)
264 {
265    return queue->device->instance->knl->queue_wait_fence(queue, fence,
266                                                          timeout_ns);
267 }
268 
269 VkResult
tu_device_check_status(struct vk_device * vk_device)270 tu_device_check_status(struct vk_device *vk_device)
271 {
272    struct tu_device *dev = container_of(vk_device, struct tu_device, vk);
273    return dev->instance->knl->device_check_status(dev);
274 }
275 
276 int
tu_drm_submitqueue_new(struct tu_device * dev,int priority,uint32_t * queue_id)277 tu_drm_submitqueue_new(struct tu_device *dev,
278                        int priority,
279                        uint32_t *queue_id)
280 {
281    return dev->instance->knl->submitqueue_new(dev, priority, queue_id);
282 }
283 
284 void
tu_drm_submitqueue_close(struct tu_device * dev,uint32_t queue_id)285 tu_drm_submitqueue_close(struct tu_device *dev, uint32_t queue_id)
286 {
287    dev->instance->knl->submitqueue_close(dev, queue_id);
288 }
289 
290 void *
tu_submit_create(struct tu_device * dev)291 tu_submit_create(struct tu_device *dev)
292 {
293    return dev->instance->knl->submit_create(dev);
294 }
295 
296 void
tu_submit_finish(struct tu_device * dev,void * submit)297 tu_submit_finish(struct tu_device *dev, void *submit)
298 {
299    return dev->instance->knl->submit_finish(dev, submit);
300 }
301 
302 void
tu_submit_add_entries(struct tu_device * dev,void * submit,struct tu_cs_entry * entries,unsigned num_entries)303 tu_submit_add_entries(struct tu_device *dev, void *submit,
304                       struct tu_cs_entry *entries,
305                       unsigned num_entries)
306 {
307    return dev->instance->knl->submit_add_entries(dev, submit, entries,
308                                                  num_entries);
309 }
310 
311 VkResult
tu_queue_submit(struct tu_queue * queue,void * submit,struct vk_sync_wait * waits,uint32_t wait_count,struct vk_sync_signal * signals,uint32_t signal_count,struct tu_u_trace_submission_data * u_trace_submission_data)312 tu_queue_submit(struct tu_queue *queue, void *submit,
313                 struct vk_sync_wait *waits, uint32_t wait_count,
314                 struct vk_sync_signal *signals, uint32_t signal_count,
315                 struct tu_u_trace_submission_data *u_trace_submission_data)
316 {
317    return queue->device->instance->knl->queue_submit(queue, submit,
318                                                      waits, wait_count,
319                                                      signals, signal_count,
320                                                      u_trace_submission_data);
321 }
322 
323 /**
324  * Enumeration entrypoint specific to non-drm devices (ie. kgsl)
325  */
326 VkResult
tu_enumerate_devices(struct vk_instance * vk_instance)327 tu_enumerate_devices(struct vk_instance *vk_instance)
328 {
329 #ifdef TU_HAS_KGSL
330    struct tu_instance *instance =
331       container_of(vk_instance, struct tu_instance, vk);
332 
333    static const char path[] = "/dev/kgsl-3d0";
334    int fd;
335 
336    fd = open(path, O_RDWR | O_CLOEXEC);
337    if (fd < 0) {
338       if (errno == ENOENT)
339          return VK_ERROR_INCOMPATIBLE_DRIVER;
340 
341       return vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
342                        "failed to open device %s", path);
343    }
344 
345    VkResult result = tu_knl_kgsl_load(instance, fd);
346    if (result != VK_SUCCESS) {
347       close(fd);
348       return result;
349    }
350 
351    if (TU_DEBUG(STARTUP))
352       mesa_logi("Found compatible device '%s'.", path);
353 
354    return result;
355 #else
356    return VK_ERROR_INCOMPATIBLE_DRIVER;
357 #endif
358 }
359 
360 /**
361  * Enumeration entrypoint for drm devices
362  */
363 VkResult
tu_physical_device_try_create(struct vk_instance * vk_instance,struct _drmDevice * drm_device,struct vk_physical_device ** out)364 tu_physical_device_try_create(struct vk_instance *vk_instance,
365                               struct _drmDevice *drm_device,
366                               struct vk_physical_device **out)
367 {
368    struct tu_instance *instance =
369       container_of(vk_instance, struct tu_instance, vk);
370 
371    /* Note that "msm" is a platform device, but "virtio_gpu" is a pci
372     * device.  In general we shouldn't care about the bus type.
373     */
374    if (!(drm_device->available_nodes & (1 << DRM_NODE_RENDER)))
375       return VK_ERROR_INCOMPATIBLE_DRIVER;
376 
377    const char *primary_path = drm_device->nodes[DRM_NODE_PRIMARY];
378    const char *path = drm_device->nodes[DRM_NODE_RENDER];
379    drmVersionPtr version;
380    int fd;
381    int master_fd = -1;
382 
383    fd = open(path, O_RDWR | O_CLOEXEC);
384    if (fd < 0) {
385       return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
386                                "failed to open device %s", path);
387    }
388 
389    version = drmGetVersion(fd);
390    if (!version) {
391       close(fd);
392       return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
393                                "failed to query kernel driver version for device %s",
394                                path);
395    }
396 
397    struct tu_physical_device *device = NULL;
398 
399    VkResult result = VK_ERROR_INCOMPATIBLE_DRIVER;
400    if (strcmp(version->name, "msm") == 0) {
401 #ifdef TU_HAS_MSM
402       result = tu_knl_drm_msm_load(instance, fd, version, &device);
403 #endif
404    } else if (strcmp(version->name, "virtio_gpu") == 0) {
405 #ifdef TU_HAS_VIRTIO
406       result = tu_knl_drm_virtio_load(instance, fd, version, &device);
407 #endif
408    } else if (TU_DEBUG(STARTUP)) {
409       result = vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
410                                  "device %s (%s) is not compatible with turnip",
411                                  path, version->name);
412    }
413 
414    if (result != VK_SUCCESS)
415       goto out;
416 
417    assert(device);
418 
419    if (instance->vk.enabled_extensions.KHR_display) {
420       master_fd = open(primary_path, O_RDWR | O_CLOEXEC);
421    }
422 
423    device->master_fd = master_fd;
424    device->kgsl_dma_fd = -1;
425 
426    assert(strlen(path) < ARRAY_SIZE(device->fd_path));
427    snprintf(device->fd_path, ARRAY_SIZE(device->fd_path), "%s", path);
428 
429    struct stat st;
430 
431    if (stat(primary_path, &st) == 0) {
432       device->has_master = true;
433       device->master_major = major(st.st_rdev);
434       device->master_minor = minor(st.st_rdev);
435    } else {
436       device->has_master = false;
437       device->master_major = 0;
438       device->master_minor = 0;
439    }
440 
441    if (stat(path, &st) == 0) {
442       device->has_local = true;
443       device->local_major = major(st.st_rdev);
444       device->local_minor = minor(st.st_rdev);
445    } else {
446       result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
447                          "failed to stat DRM render node %s", path);
448       goto out;
449    }
450 
451    result = tu_physical_device_init(device, instance);
452    if (result != VK_SUCCESS)
453       goto out;
454 
455    if (TU_DEBUG(STARTUP))
456       mesa_logi("Found compatible device '%s' (%s).", path, version->name);
457 
458    *out = &device->vk;
459 
460 out:
461    if (result != VK_SUCCESS) {
462       if (master_fd != -1)
463          close(master_fd);
464       close(fd);
465       vk_free(&instance->vk.alloc, device);
466    }
467 
468    drmFreeVersion(version);
469 
470    return result;
471 }
472