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