1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2018 Google, Inc. 3bf215546Sopenharmony_ci * Copyright © 2015 Intel Corporation 4bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT 5bf215546Sopenharmony_ci */ 6bf215546Sopenharmony_ci 7bf215546Sopenharmony_ci#include "tu_drm.h" 8bf215546Sopenharmony_ci 9bf215546Sopenharmony_ci#include <errno.h> 10bf215546Sopenharmony_ci#include <fcntl.h> 11bf215546Sopenharmony_ci#include <sys/ioctl.h> 12bf215546Sopenharmony_ci#include <sys/mman.h> 13bf215546Sopenharmony_ci#include <xf86drm.h> 14bf215546Sopenharmony_ci 15bf215546Sopenharmony_ci#ifdef MAJOR_IN_MKDEV 16bf215546Sopenharmony_ci#include <sys/mkdev.h> 17bf215546Sopenharmony_ci#endif 18bf215546Sopenharmony_ci#ifdef MAJOR_IN_SYSMACROS 19bf215546Sopenharmony_ci#include <sys/sysmacros.h> 20bf215546Sopenharmony_ci#endif 21bf215546Sopenharmony_ci 22bf215546Sopenharmony_ci#include "vk_util.h" 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "drm-uapi/msm_drm.h" 25bf215546Sopenharmony_ci#include "util/debug.h" 26bf215546Sopenharmony_ci#include "util/timespec.h" 27bf215546Sopenharmony_ci#include "util/os_time.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include "tu_cmd_buffer.h" 30bf215546Sopenharmony_ci#include "tu_cs.h" 31bf215546Sopenharmony_ci#include "tu_device.h" 32bf215546Sopenharmony_ci#include "tu_dynamic_rendering.h" 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_cistruct tu_queue_submit 35bf215546Sopenharmony_ci{ 36bf215546Sopenharmony_ci struct vk_queue_submit *vk_submit; 37bf215546Sopenharmony_ci struct tu_u_trace_submission_data *u_trace_submission_data; 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci struct tu_cmd_buffer **cmd_buffers; 40bf215546Sopenharmony_ci struct drm_msm_gem_submit_cmd *cmds; 41bf215546Sopenharmony_ci struct drm_msm_gem_submit_syncobj *in_syncobjs; 42bf215546Sopenharmony_ci struct drm_msm_gem_submit_syncobj *out_syncobjs; 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci uint32_t nr_cmd_buffers; 45bf215546Sopenharmony_ci uint32_t nr_in_syncobjs; 46bf215546Sopenharmony_ci uint32_t nr_out_syncobjs; 47bf215546Sopenharmony_ci uint32_t entry_count; 48bf215546Sopenharmony_ci uint32_t perf_pass_index; 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ci bool autotune_fence; 51bf215546Sopenharmony_ci}; 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_cistruct tu_u_trace_syncobj 54bf215546Sopenharmony_ci{ 55bf215546Sopenharmony_ci uint32_t msm_queue_id; 56bf215546Sopenharmony_ci uint32_t fence; 57bf215546Sopenharmony_ci}; 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_cistatic int 60bf215546Sopenharmony_citu_drm_get_param(const struct tu_physical_device *dev, 61bf215546Sopenharmony_ci uint32_t param, 62bf215546Sopenharmony_ci uint64_t *value) 63bf215546Sopenharmony_ci{ 64bf215546Sopenharmony_ci /* Technically this requires a pipe, but the kernel only supports one pipe 65bf215546Sopenharmony_ci * anyway at the time of writing and most of these are clearly pipe 66bf215546Sopenharmony_ci * independent. */ 67bf215546Sopenharmony_ci struct drm_msm_param req = { 68bf215546Sopenharmony_ci .pipe = MSM_PIPE_3D0, 69bf215546Sopenharmony_ci .param = param, 70bf215546Sopenharmony_ci }; 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_ci int ret = drmCommandWriteRead(dev->local_fd, DRM_MSM_GET_PARAM, &req, 73bf215546Sopenharmony_ci sizeof(req)); 74bf215546Sopenharmony_ci if (ret) 75bf215546Sopenharmony_ci return ret; 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci *value = req.value; 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci return 0; 80bf215546Sopenharmony_ci} 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_cistatic int 83bf215546Sopenharmony_citu_drm_get_gpu_id(const struct tu_physical_device *dev, uint32_t *id) 84bf215546Sopenharmony_ci{ 85bf215546Sopenharmony_ci uint64_t value; 86bf215546Sopenharmony_ci int ret = tu_drm_get_param(dev, MSM_PARAM_GPU_ID, &value); 87bf215546Sopenharmony_ci if (ret) 88bf215546Sopenharmony_ci return ret; 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci *id = value; 91bf215546Sopenharmony_ci return 0; 92bf215546Sopenharmony_ci} 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_cistatic int 95bf215546Sopenharmony_citu_drm_get_gmem_size(const struct tu_physical_device *dev, uint32_t *size) 96bf215546Sopenharmony_ci{ 97bf215546Sopenharmony_ci uint64_t value; 98bf215546Sopenharmony_ci int ret = tu_drm_get_param(dev, MSM_PARAM_GMEM_SIZE, &value); 99bf215546Sopenharmony_ci if (ret) 100bf215546Sopenharmony_ci return ret; 101bf215546Sopenharmony_ci 102bf215546Sopenharmony_ci *size = value; 103bf215546Sopenharmony_ci return 0; 104bf215546Sopenharmony_ci} 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_cistatic int 107bf215546Sopenharmony_citu_drm_get_gmem_base(const struct tu_physical_device *dev, uint64_t *base) 108bf215546Sopenharmony_ci{ 109bf215546Sopenharmony_ci return tu_drm_get_param(dev, MSM_PARAM_GMEM_BASE, base); 110bf215546Sopenharmony_ci} 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ciint 113bf215546Sopenharmony_citu_device_get_gpu_timestamp(struct tu_device *dev, uint64_t *ts) 114bf215546Sopenharmony_ci{ 115bf215546Sopenharmony_ci return tu_drm_get_param(dev->physical_device, MSM_PARAM_TIMESTAMP, ts); 116bf215546Sopenharmony_ci} 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ciint 119bf215546Sopenharmony_citu_device_get_suspend_count(struct tu_device *dev, uint64_t *suspend_count) 120bf215546Sopenharmony_ci{ 121bf215546Sopenharmony_ci int ret = tu_drm_get_param(dev->physical_device, MSM_PARAM_SUSPENDS, suspend_count); 122bf215546Sopenharmony_ci return ret; 123bf215546Sopenharmony_ci} 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ciVkResult 126bf215546Sopenharmony_citu_device_check_status(struct vk_device *vk_device) 127bf215546Sopenharmony_ci{ 128bf215546Sopenharmony_ci struct tu_device *device = container_of(vk_device, struct tu_device, vk); 129bf215546Sopenharmony_ci struct tu_physical_device *physical_device = device->physical_device; 130bf215546Sopenharmony_ci 131bf215546Sopenharmony_ci uint64_t last_fault_count = physical_device->fault_count; 132bf215546Sopenharmony_ci int ret = tu_drm_get_param(physical_device, MSM_PARAM_FAULTS, &physical_device->fault_count); 133bf215546Sopenharmony_ci if (ret != 0) 134bf215546Sopenharmony_ci return vk_device_set_lost(&device->vk, "error getting GPU fault count: %d", ret); 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci if (last_fault_count != physical_device->fault_count) 137bf215546Sopenharmony_ci return vk_device_set_lost(&device->vk, "GPU faulted or hung"); 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci return VK_SUCCESS; 140bf215546Sopenharmony_ci} 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ciint 143bf215546Sopenharmony_citu_drm_submitqueue_new(const struct tu_device *dev, 144bf215546Sopenharmony_ci int priority, 145bf215546Sopenharmony_ci uint32_t *queue_id) 146bf215546Sopenharmony_ci{ 147bf215546Sopenharmony_ci uint64_t nr_rings = 1; 148bf215546Sopenharmony_ci tu_drm_get_param(dev->physical_device, MSM_PARAM_NR_RINGS, &nr_rings); 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci struct drm_msm_submitqueue req = { 151bf215546Sopenharmony_ci .flags = 0, 152bf215546Sopenharmony_ci .prio = MIN2(priority, MAX2(nr_rings, 1) - 1), 153bf215546Sopenharmony_ci }; 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci int ret = drmCommandWriteRead(dev->fd, 156bf215546Sopenharmony_ci DRM_MSM_SUBMITQUEUE_NEW, &req, sizeof(req)); 157bf215546Sopenharmony_ci if (ret) 158bf215546Sopenharmony_ci return ret; 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci *queue_id = req.id; 161bf215546Sopenharmony_ci return 0; 162bf215546Sopenharmony_ci} 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_civoid 165bf215546Sopenharmony_citu_drm_submitqueue_close(const struct tu_device *dev, uint32_t queue_id) 166bf215546Sopenharmony_ci{ 167bf215546Sopenharmony_ci drmCommandWrite(dev->fd, DRM_MSM_SUBMITQUEUE_CLOSE, 168bf215546Sopenharmony_ci &queue_id, sizeof(uint32_t)); 169bf215546Sopenharmony_ci} 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_cistatic void 172bf215546Sopenharmony_citu_gem_close(const struct tu_device *dev, uint32_t gem_handle) 173bf215546Sopenharmony_ci{ 174bf215546Sopenharmony_ci struct drm_gem_close req = { 175bf215546Sopenharmony_ci .handle = gem_handle, 176bf215546Sopenharmony_ci }; 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req); 179bf215546Sopenharmony_ci} 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci/** Helper for DRM_MSM_GEM_INFO, returns 0 on error. */ 182bf215546Sopenharmony_cistatic uint64_t 183bf215546Sopenharmony_citu_gem_info(const struct tu_device *dev, uint32_t gem_handle, uint32_t info) 184bf215546Sopenharmony_ci{ 185bf215546Sopenharmony_ci struct drm_msm_gem_info req = { 186bf215546Sopenharmony_ci .handle = gem_handle, 187bf215546Sopenharmony_ci .info = info, 188bf215546Sopenharmony_ci }; 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci int ret = drmCommandWriteRead(dev->fd, 191bf215546Sopenharmony_ci DRM_MSM_GEM_INFO, &req, sizeof(req)); 192bf215546Sopenharmony_ci if (ret < 0) 193bf215546Sopenharmony_ci return 0; 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci return req.value; 196bf215546Sopenharmony_ci} 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_cistatic VkResult 199bf215546Sopenharmony_citu_bo_init(struct tu_device *dev, 200bf215546Sopenharmony_ci struct tu_bo *bo, 201bf215546Sopenharmony_ci uint32_t gem_handle, 202bf215546Sopenharmony_ci uint64_t size, 203bf215546Sopenharmony_ci bool dump) 204bf215546Sopenharmony_ci{ 205bf215546Sopenharmony_ci uint64_t iova = tu_gem_info(dev, gem_handle, MSM_INFO_GET_IOVA); 206bf215546Sopenharmony_ci if (!iova) { 207bf215546Sopenharmony_ci tu_gem_close(dev, gem_handle); 208bf215546Sopenharmony_ci return VK_ERROR_OUT_OF_DEVICE_MEMORY; 209bf215546Sopenharmony_ci } 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci mtx_lock(&dev->bo_mutex); 212bf215546Sopenharmony_ci uint32_t idx = dev->bo_count++; 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci /* grow the bo list if needed */ 215bf215546Sopenharmony_ci if (idx >= dev->bo_list_size) { 216bf215546Sopenharmony_ci uint32_t new_len = idx + 64; 217bf215546Sopenharmony_ci struct drm_msm_gem_submit_bo *new_ptr = 218bf215546Sopenharmony_ci vk_realloc(&dev->vk.alloc, dev->bo_list, new_len * sizeof(*dev->bo_list), 219bf215546Sopenharmony_ci 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); 220bf215546Sopenharmony_ci if (!new_ptr) 221bf215546Sopenharmony_ci goto fail_bo_list; 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci dev->bo_list = new_ptr; 224bf215546Sopenharmony_ci dev->bo_list_size = new_len; 225bf215546Sopenharmony_ci } 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci dev->bo_list[idx] = (struct drm_msm_gem_submit_bo) { 228bf215546Sopenharmony_ci .flags = MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE | 229bf215546Sopenharmony_ci COND(dump, MSM_SUBMIT_BO_DUMP), 230bf215546Sopenharmony_ci .handle = gem_handle, 231bf215546Sopenharmony_ci .presumed = iova, 232bf215546Sopenharmony_ci }; 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci *bo = (struct tu_bo) { 235bf215546Sopenharmony_ci .gem_handle = gem_handle, 236bf215546Sopenharmony_ci .size = size, 237bf215546Sopenharmony_ci .iova = iova, 238bf215546Sopenharmony_ci .refcnt = 1, 239bf215546Sopenharmony_ci .bo_list_idx = idx, 240bf215546Sopenharmony_ci }; 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci mtx_unlock(&dev->bo_mutex); 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci return VK_SUCCESS; 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_cifail_bo_list: 247bf215546Sopenharmony_ci tu_gem_close(dev, gem_handle); 248bf215546Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 249bf215546Sopenharmony_ci} 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ciVkResult 252bf215546Sopenharmony_citu_bo_init_new(struct tu_device *dev, struct tu_bo **out_bo, uint64_t size, 253bf215546Sopenharmony_ci enum tu_bo_alloc_flags flags) 254bf215546Sopenharmony_ci{ 255bf215546Sopenharmony_ci /* TODO: Choose better flags. As of 2018-11-12, freedreno/drm/msm_bo.c 256bf215546Sopenharmony_ci * always sets `flags = MSM_BO_WC`, and we copy that behavior here. 257bf215546Sopenharmony_ci */ 258bf215546Sopenharmony_ci struct drm_msm_gem_new req = { 259bf215546Sopenharmony_ci .size = size, 260bf215546Sopenharmony_ci .flags = MSM_BO_WC 261bf215546Sopenharmony_ci }; 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci if (flags & TU_BO_ALLOC_GPU_READ_ONLY) 264bf215546Sopenharmony_ci req.flags |= MSM_BO_GPU_READONLY; 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci int ret = drmCommandWriteRead(dev->fd, 267bf215546Sopenharmony_ci DRM_MSM_GEM_NEW, &req, sizeof(req)); 268bf215546Sopenharmony_ci if (ret) 269bf215546Sopenharmony_ci return vk_error(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY); 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci struct tu_bo* bo = tu_device_lookup_bo(dev, req.handle); 272bf215546Sopenharmony_ci assert(bo && bo->gem_handle == 0); 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci VkResult result = 275bf215546Sopenharmony_ci tu_bo_init(dev, bo, req.handle, size, flags & TU_BO_ALLOC_ALLOW_DUMP); 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci if (result != VK_SUCCESS) 278bf215546Sopenharmony_ci memset(bo, 0, sizeof(*bo)); 279bf215546Sopenharmony_ci else 280bf215546Sopenharmony_ci *out_bo = bo; 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci return result; 283bf215546Sopenharmony_ci} 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_ciVkResult 286bf215546Sopenharmony_citu_bo_init_dmabuf(struct tu_device *dev, 287bf215546Sopenharmony_ci struct tu_bo **out_bo, 288bf215546Sopenharmony_ci uint64_t size, 289bf215546Sopenharmony_ci int prime_fd) 290bf215546Sopenharmony_ci{ 291bf215546Sopenharmony_ci /* lseek() to get the real size */ 292bf215546Sopenharmony_ci off_t real_size = lseek(prime_fd, 0, SEEK_END); 293bf215546Sopenharmony_ci lseek(prime_fd, 0, SEEK_SET); 294bf215546Sopenharmony_ci if (real_size < 0 || (uint64_t) real_size < size) 295bf215546Sopenharmony_ci return vk_error(dev, VK_ERROR_INVALID_EXTERNAL_HANDLE); 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_ci /* Importing the same dmabuf several times would yield the same 298bf215546Sopenharmony_ci * gem_handle. Thus there could be a race when destroying 299bf215546Sopenharmony_ci * BO and importing the same dmabuf from different threads. 300bf215546Sopenharmony_ci * We must not permit the creation of dmabuf BO and its release 301bf215546Sopenharmony_ci * to happen in parallel. 302bf215546Sopenharmony_ci */ 303bf215546Sopenharmony_ci u_rwlock_wrlock(&dev->dma_bo_lock); 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci uint32_t gem_handle; 306bf215546Sopenharmony_ci int ret = drmPrimeFDToHandle(dev->fd, prime_fd, 307bf215546Sopenharmony_ci &gem_handle); 308bf215546Sopenharmony_ci if (ret) { 309bf215546Sopenharmony_ci u_rwlock_wrunlock(&dev->dma_bo_lock); 310bf215546Sopenharmony_ci return vk_error(dev, VK_ERROR_INVALID_EXTERNAL_HANDLE); 311bf215546Sopenharmony_ci } 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci struct tu_bo* bo = tu_device_lookup_bo(dev, gem_handle); 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_ci if (bo->refcnt != 0) { 316bf215546Sopenharmony_ci p_atomic_inc(&bo->refcnt); 317bf215546Sopenharmony_ci u_rwlock_wrunlock(&dev->dma_bo_lock); 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_ci *out_bo = bo; 320bf215546Sopenharmony_ci return VK_SUCCESS; 321bf215546Sopenharmony_ci } 322bf215546Sopenharmony_ci 323bf215546Sopenharmony_ci VkResult result = tu_bo_init(dev, bo, gem_handle, size, false); 324bf215546Sopenharmony_ci 325bf215546Sopenharmony_ci if (result != VK_SUCCESS) 326bf215546Sopenharmony_ci memset(bo, 0, sizeof(*bo)); 327bf215546Sopenharmony_ci else 328bf215546Sopenharmony_ci *out_bo = bo; 329bf215546Sopenharmony_ci 330bf215546Sopenharmony_ci u_rwlock_wrunlock(&dev->dma_bo_lock); 331bf215546Sopenharmony_ci 332bf215546Sopenharmony_ci return result; 333bf215546Sopenharmony_ci} 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ciint 336bf215546Sopenharmony_citu_bo_export_dmabuf(struct tu_device *dev, struct tu_bo *bo) 337bf215546Sopenharmony_ci{ 338bf215546Sopenharmony_ci int prime_fd; 339bf215546Sopenharmony_ci int ret = drmPrimeHandleToFD(dev->fd, bo->gem_handle, 340bf215546Sopenharmony_ci DRM_CLOEXEC | DRM_RDWR, &prime_fd); 341bf215546Sopenharmony_ci 342bf215546Sopenharmony_ci return ret == 0 ? prime_fd : -1; 343bf215546Sopenharmony_ci} 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ciVkResult 346bf215546Sopenharmony_citu_bo_map(struct tu_device *dev, struct tu_bo *bo) 347bf215546Sopenharmony_ci{ 348bf215546Sopenharmony_ci if (bo->map) 349bf215546Sopenharmony_ci return VK_SUCCESS; 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_ci uint64_t offset = tu_gem_info(dev, bo->gem_handle, MSM_INFO_GET_OFFSET); 352bf215546Sopenharmony_ci if (!offset) 353bf215546Sopenharmony_ci return vk_error(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY); 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_ci /* TODO: Should we use the wrapper os_mmap() like Freedreno does? */ 356bf215546Sopenharmony_ci void *map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, 357bf215546Sopenharmony_ci dev->fd, offset); 358bf215546Sopenharmony_ci if (map == MAP_FAILED) 359bf215546Sopenharmony_ci return vk_error(dev, VK_ERROR_MEMORY_MAP_FAILED); 360bf215546Sopenharmony_ci 361bf215546Sopenharmony_ci bo->map = map; 362bf215546Sopenharmony_ci return VK_SUCCESS; 363bf215546Sopenharmony_ci} 364bf215546Sopenharmony_ci 365bf215546Sopenharmony_civoid 366bf215546Sopenharmony_citu_bo_finish(struct tu_device *dev, struct tu_bo *bo) 367bf215546Sopenharmony_ci{ 368bf215546Sopenharmony_ci assert(bo->gem_handle); 369bf215546Sopenharmony_ci 370bf215546Sopenharmony_ci u_rwlock_rdlock(&dev->dma_bo_lock); 371bf215546Sopenharmony_ci 372bf215546Sopenharmony_ci if (!p_atomic_dec_zero(&bo->refcnt)) { 373bf215546Sopenharmony_ci u_rwlock_rdunlock(&dev->dma_bo_lock); 374bf215546Sopenharmony_ci return; 375bf215546Sopenharmony_ci } 376bf215546Sopenharmony_ci 377bf215546Sopenharmony_ci if (bo->map) 378bf215546Sopenharmony_ci munmap(bo->map, bo->size); 379bf215546Sopenharmony_ci 380bf215546Sopenharmony_ci mtx_lock(&dev->bo_mutex); 381bf215546Sopenharmony_ci dev->bo_count--; 382bf215546Sopenharmony_ci dev->bo_list[bo->bo_list_idx] = dev->bo_list[dev->bo_count]; 383bf215546Sopenharmony_ci 384bf215546Sopenharmony_ci struct tu_bo* exchanging_bo = tu_device_lookup_bo(dev, dev->bo_list[bo->bo_list_idx].handle); 385bf215546Sopenharmony_ci exchanging_bo->bo_list_idx = bo->bo_list_idx; 386bf215546Sopenharmony_ci 387bf215546Sopenharmony_ci if (bo->implicit_sync) 388bf215546Sopenharmony_ci dev->implicit_sync_bo_count--; 389bf215546Sopenharmony_ci 390bf215546Sopenharmony_ci mtx_unlock(&dev->bo_mutex); 391bf215546Sopenharmony_ci 392bf215546Sopenharmony_ci /* Our BO structs are stored in a sparse array in the physical device, 393bf215546Sopenharmony_ci * so we don't want to free the BO pointer, instead we want to reset it 394bf215546Sopenharmony_ci * to 0, to signal that array entry as being free. 395bf215546Sopenharmony_ci */ 396bf215546Sopenharmony_ci uint32_t gem_handle = bo->gem_handle; 397bf215546Sopenharmony_ci memset(bo, 0, sizeof(*bo)); 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_ci tu_gem_close(dev, gem_handle); 400bf215546Sopenharmony_ci 401bf215546Sopenharmony_ci u_rwlock_rdunlock(&dev->dma_bo_lock); 402bf215546Sopenharmony_ci} 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ciextern const struct vk_sync_type tu_timeline_sync_type; 405bf215546Sopenharmony_ci 406bf215546Sopenharmony_cistatic inline bool 407bf215546Sopenharmony_civk_sync_is_tu_timeline_sync(const struct vk_sync *sync) 408bf215546Sopenharmony_ci{ 409bf215546Sopenharmony_ci return sync->type == &tu_timeline_sync_type; 410bf215546Sopenharmony_ci} 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_cistatic struct tu_timeline_sync * 413bf215546Sopenharmony_cito_tu_timeline_sync(struct vk_sync *sync) 414bf215546Sopenharmony_ci{ 415bf215546Sopenharmony_ci assert(sync->type == &tu_timeline_sync_type); 416bf215546Sopenharmony_ci return container_of(sync, struct tu_timeline_sync, base); 417bf215546Sopenharmony_ci} 418bf215546Sopenharmony_ci 419bf215546Sopenharmony_cistatic uint32_t 420bf215546Sopenharmony_citu_syncobj_from_vk_sync(struct vk_sync *sync) 421bf215546Sopenharmony_ci{ 422bf215546Sopenharmony_ci uint32_t syncobj = -1; 423bf215546Sopenharmony_ci if (vk_sync_is_tu_timeline_sync(sync)) { 424bf215546Sopenharmony_ci syncobj = to_tu_timeline_sync(sync)->syncobj; 425bf215546Sopenharmony_ci } else if (vk_sync_type_is_drm_syncobj(sync->type)) { 426bf215546Sopenharmony_ci syncobj = vk_sync_as_drm_syncobj(sync)->syncobj; 427bf215546Sopenharmony_ci } 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci assert(syncobj != -1); 430bf215546Sopenharmony_ci 431bf215546Sopenharmony_ci return syncobj; 432bf215546Sopenharmony_ci} 433bf215546Sopenharmony_ci 434bf215546Sopenharmony_cistatic VkResult 435bf215546Sopenharmony_citu_timeline_sync_init(struct vk_device *vk_device, 436bf215546Sopenharmony_ci struct vk_sync *vk_sync, 437bf215546Sopenharmony_ci uint64_t initial_value) 438bf215546Sopenharmony_ci{ 439bf215546Sopenharmony_ci struct tu_device *device = container_of(vk_device, struct tu_device, vk); 440bf215546Sopenharmony_ci struct tu_timeline_sync *sync = to_tu_timeline_sync(vk_sync); 441bf215546Sopenharmony_ci uint32_t flags = 0; 442bf215546Sopenharmony_ci 443bf215546Sopenharmony_ci assert(device->fd >= 0); 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_ci int err = drmSyncobjCreate(device->fd, flags, &sync->syncobj); 446bf215546Sopenharmony_ci 447bf215546Sopenharmony_ci if (err < 0) { 448bf215546Sopenharmony_ci return vk_error(device, VK_ERROR_DEVICE_LOST); 449bf215546Sopenharmony_ci } 450bf215546Sopenharmony_ci 451bf215546Sopenharmony_ci sync->state = initial_value ? TU_TIMELINE_SYNC_STATE_SIGNALED : 452bf215546Sopenharmony_ci TU_TIMELINE_SYNC_STATE_RESET; 453bf215546Sopenharmony_ci 454bf215546Sopenharmony_ci return VK_SUCCESS; 455bf215546Sopenharmony_ci} 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_cistatic void 458bf215546Sopenharmony_citu_timeline_sync_finish(struct vk_device *vk_device, 459bf215546Sopenharmony_ci struct vk_sync *vk_sync) 460bf215546Sopenharmony_ci{ 461bf215546Sopenharmony_ci struct tu_device *dev = container_of(vk_device, struct tu_device, vk); 462bf215546Sopenharmony_ci struct tu_timeline_sync *sync = to_tu_timeline_sync(vk_sync); 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci assert(dev->fd >= 0); 465bf215546Sopenharmony_ci ASSERTED int err = drmSyncobjDestroy(dev->fd, sync->syncobj); 466bf215546Sopenharmony_ci assert(err == 0); 467bf215546Sopenharmony_ci} 468bf215546Sopenharmony_ci 469bf215546Sopenharmony_cistatic VkResult 470bf215546Sopenharmony_citu_timeline_sync_reset(struct vk_device *vk_device, 471bf215546Sopenharmony_ci struct vk_sync *vk_sync) 472bf215546Sopenharmony_ci{ 473bf215546Sopenharmony_ci struct tu_device *dev = container_of(vk_device, struct tu_device, vk); 474bf215546Sopenharmony_ci struct tu_timeline_sync *sync = to_tu_timeline_sync(vk_sync); 475bf215546Sopenharmony_ci 476bf215546Sopenharmony_ci int err = drmSyncobjReset(dev->fd, &sync->syncobj, 1); 477bf215546Sopenharmony_ci if (err) { 478bf215546Sopenharmony_ci return vk_errorf(dev, VK_ERROR_UNKNOWN, 479bf215546Sopenharmony_ci "DRM_IOCTL_SYNCOBJ_RESET failed: %m"); 480bf215546Sopenharmony_ci } else { 481bf215546Sopenharmony_ci sync->state = TU_TIMELINE_SYNC_STATE_RESET; 482bf215546Sopenharmony_ci } 483bf215546Sopenharmony_ci 484bf215546Sopenharmony_ci return VK_SUCCESS; 485bf215546Sopenharmony_ci} 486bf215546Sopenharmony_ci 487bf215546Sopenharmony_cistatic VkResult 488bf215546Sopenharmony_cidrm_syncobj_wait(struct tu_device *device, 489bf215546Sopenharmony_ci uint32_t *handles, uint32_t count_handles, 490bf215546Sopenharmony_ci uint64_t timeout_nsec, bool wait_all) 491bf215546Sopenharmony_ci{ 492bf215546Sopenharmony_ci uint32_t syncobj_wait_flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT; 493bf215546Sopenharmony_ci if (wait_all) syncobj_wait_flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL; 494bf215546Sopenharmony_ci 495bf215546Sopenharmony_ci /* syncobj absolute timeouts are signed. clamp OS_TIMEOUT_INFINITE down. */ 496bf215546Sopenharmony_ci timeout_nsec = MIN2(timeout_nsec, (uint64_t)INT64_MAX); 497bf215546Sopenharmony_ci 498bf215546Sopenharmony_ci int err = drmSyncobjWait(device->fd, handles, 499bf215546Sopenharmony_ci count_handles, timeout_nsec, 500bf215546Sopenharmony_ci syncobj_wait_flags, 501bf215546Sopenharmony_ci NULL /* first_signaled */); 502bf215546Sopenharmony_ci if (err && errno == ETIME) { 503bf215546Sopenharmony_ci return VK_TIMEOUT; 504bf215546Sopenharmony_ci } else if (err) { 505bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, 506bf215546Sopenharmony_ci "DRM_IOCTL_SYNCOBJ_WAIT failed: %m"); 507bf215546Sopenharmony_ci } 508bf215546Sopenharmony_ci 509bf215546Sopenharmony_ci return VK_SUCCESS; 510bf215546Sopenharmony_ci} 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_ci/* Based on anv_bo_sync_wait */ 513bf215546Sopenharmony_cistatic VkResult 514bf215546Sopenharmony_citu_timeline_sync_wait(struct vk_device *vk_device, 515bf215546Sopenharmony_ci uint32_t wait_count, 516bf215546Sopenharmony_ci const struct vk_sync_wait *waits, 517bf215546Sopenharmony_ci enum vk_sync_wait_flags wait_flags, 518bf215546Sopenharmony_ci uint64_t abs_timeout_ns) 519bf215546Sopenharmony_ci{ 520bf215546Sopenharmony_ci struct tu_device *dev = container_of(vk_device, struct tu_device, vk); 521bf215546Sopenharmony_ci bool wait_all = !(wait_flags & VK_SYNC_WAIT_ANY); 522bf215546Sopenharmony_ci 523bf215546Sopenharmony_ci uint32_t handles[wait_count]; 524bf215546Sopenharmony_ci uint32_t submit_count; 525bf215546Sopenharmony_ci VkResult ret = VK_SUCCESS; 526bf215546Sopenharmony_ci uint32_t pending = wait_count; 527bf215546Sopenharmony_ci struct tu_timeline_sync *submitted_syncs[wait_count]; 528bf215546Sopenharmony_ci 529bf215546Sopenharmony_ci while (pending) { 530bf215546Sopenharmony_ci pending = 0; 531bf215546Sopenharmony_ci submit_count = 0; 532bf215546Sopenharmony_ci 533bf215546Sopenharmony_ci for (unsigned i = 0; i < wait_count; ++i) { 534bf215546Sopenharmony_ci struct tu_timeline_sync *sync = to_tu_timeline_sync(waits[i].sync); 535bf215546Sopenharmony_ci 536bf215546Sopenharmony_ci if (sync->state == TU_TIMELINE_SYNC_STATE_RESET) { 537bf215546Sopenharmony_ci assert(!(wait_flags & VK_SYNC_WAIT_PENDING)); 538bf215546Sopenharmony_ci pending++; 539bf215546Sopenharmony_ci } else if (sync->state == TU_TIMELINE_SYNC_STATE_SIGNALED) { 540bf215546Sopenharmony_ci if (wait_flags & VK_SYNC_WAIT_ANY) 541bf215546Sopenharmony_ci return VK_SUCCESS; 542bf215546Sopenharmony_ci } else if (sync->state == TU_TIMELINE_SYNC_STATE_SUBMITTED) { 543bf215546Sopenharmony_ci if (!(wait_flags & VK_SYNC_WAIT_PENDING)) { 544bf215546Sopenharmony_ci handles[submit_count] = sync->syncobj; 545bf215546Sopenharmony_ci submitted_syncs[submit_count++] = sync; 546bf215546Sopenharmony_ci } 547bf215546Sopenharmony_ci } 548bf215546Sopenharmony_ci } 549bf215546Sopenharmony_ci 550bf215546Sopenharmony_ci if (submit_count > 0) { 551bf215546Sopenharmony_ci do { 552bf215546Sopenharmony_ci ret = drm_syncobj_wait(dev, handles, submit_count, abs_timeout_ns, wait_all); 553bf215546Sopenharmony_ci } while (ret == VK_TIMEOUT && os_time_get_nano() < abs_timeout_ns); 554bf215546Sopenharmony_ci 555bf215546Sopenharmony_ci if (ret == VK_SUCCESS) { 556bf215546Sopenharmony_ci for (unsigned i = 0; i < submit_count; ++i) { 557bf215546Sopenharmony_ci struct tu_timeline_sync *sync = submitted_syncs[i]; 558bf215546Sopenharmony_ci sync->state = TU_TIMELINE_SYNC_STATE_SIGNALED; 559bf215546Sopenharmony_ci } 560bf215546Sopenharmony_ci } else { 561bf215546Sopenharmony_ci /* return error covering timeout */ 562bf215546Sopenharmony_ci return ret; 563bf215546Sopenharmony_ci } 564bf215546Sopenharmony_ci } else if (pending > 0) { 565bf215546Sopenharmony_ci /* If we've hit this then someone decided to vkWaitForFences before 566bf215546Sopenharmony_ci * they've actually submitted any of them to a queue. This is a 567bf215546Sopenharmony_ci * fairly pessimal case, so it's ok to lock here and use a standard 568bf215546Sopenharmony_ci * pthreads condition variable. 569bf215546Sopenharmony_ci */ 570bf215546Sopenharmony_ci pthread_mutex_lock(&dev->submit_mutex); 571bf215546Sopenharmony_ci 572bf215546Sopenharmony_ci /* It's possible that some of the fences have changed state since the 573bf215546Sopenharmony_ci * last time we checked. Now that we have the lock, check for 574bf215546Sopenharmony_ci * pending fences again and don't wait if it's changed. 575bf215546Sopenharmony_ci */ 576bf215546Sopenharmony_ci uint32_t now_pending = 0; 577bf215546Sopenharmony_ci for (uint32_t i = 0; i < wait_count; i++) { 578bf215546Sopenharmony_ci struct tu_timeline_sync *sync = to_tu_timeline_sync(waits[i].sync); 579bf215546Sopenharmony_ci if (sync->state == TU_TIMELINE_SYNC_STATE_RESET) 580bf215546Sopenharmony_ci now_pending++; 581bf215546Sopenharmony_ci } 582bf215546Sopenharmony_ci assert(now_pending <= pending); 583bf215546Sopenharmony_ci 584bf215546Sopenharmony_ci if (now_pending == pending) { 585bf215546Sopenharmony_ci struct timespec abstime = { 586bf215546Sopenharmony_ci .tv_sec = abs_timeout_ns / NSEC_PER_SEC, 587bf215546Sopenharmony_ci .tv_nsec = abs_timeout_ns % NSEC_PER_SEC, 588bf215546Sopenharmony_ci }; 589bf215546Sopenharmony_ci 590bf215546Sopenharmony_ci ASSERTED int ret; 591bf215546Sopenharmony_ci ret = pthread_cond_timedwait(&dev->timeline_cond, 592bf215546Sopenharmony_ci &dev->submit_mutex, &abstime); 593bf215546Sopenharmony_ci assert(ret != EINVAL); 594bf215546Sopenharmony_ci if (os_time_get_nano() >= abs_timeout_ns) { 595bf215546Sopenharmony_ci pthread_mutex_unlock(&dev->submit_mutex); 596bf215546Sopenharmony_ci return VK_TIMEOUT; 597bf215546Sopenharmony_ci } 598bf215546Sopenharmony_ci } 599bf215546Sopenharmony_ci 600bf215546Sopenharmony_ci pthread_mutex_unlock(&dev->submit_mutex); 601bf215546Sopenharmony_ci } 602bf215546Sopenharmony_ci } 603bf215546Sopenharmony_ci 604bf215546Sopenharmony_ci return ret; 605bf215546Sopenharmony_ci} 606bf215546Sopenharmony_ci 607bf215546Sopenharmony_ciconst struct vk_sync_type tu_timeline_sync_type = { 608bf215546Sopenharmony_ci .size = sizeof(struct tu_timeline_sync), 609bf215546Sopenharmony_ci .features = VK_SYNC_FEATURE_BINARY | 610bf215546Sopenharmony_ci VK_SYNC_FEATURE_GPU_WAIT | 611bf215546Sopenharmony_ci VK_SYNC_FEATURE_GPU_MULTI_WAIT | 612bf215546Sopenharmony_ci VK_SYNC_FEATURE_CPU_WAIT | 613bf215546Sopenharmony_ci VK_SYNC_FEATURE_CPU_RESET | 614bf215546Sopenharmony_ci VK_SYNC_FEATURE_WAIT_ANY | 615bf215546Sopenharmony_ci VK_SYNC_FEATURE_WAIT_PENDING, 616bf215546Sopenharmony_ci .init = tu_timeline_sync_init, 617bf215546Sopenharmony_ci .finish = tu_timeline_sync_finish, 618bf215546Sopenharmony_ci .reset = tu_timeline_sync_reset, 619bf215546Sopenharmony_ci .wait_many = tu_timeline_sync_wait, 620bf215546Sopenharmony_ci}; 621bf215546Sopenharmony_ci 622bf215546Sopenharmony_cistatic VkResult 623bf215546Sopenharmony_citu_drm_device_init(struct tu_physical_device *device, 624bf215546Sopenharmony_ci struct tu_instance *instance, 625bf215546Sopenharmony_ci drmDevicePtr drm_device) 626bf215546Sopenharmony_ci{ 627bf215546Sopenharmony_ci const char *primary_path = drm_device->nodes[DRM_NODE_PRIMARY]; 628bf215546Sopenharmony_ci const char *path = drm_device->nodes[DRM_NODE_RENDER]; 629bf215546Sopenharmony_ci VkResult result = VK_SUCCESS; 630bf215546Sopenharmony_ci drmVersionPtr version; 631bf215546Sopenharmony_ci int fd; 632bf215546Sopenharmony_ci int master_fd = -1; 633bf215546Sopenharmony_ci 634bf215546Sopenharmony_ci fd = open(path, O_RDWR | O_CLOEXEC); 635bf215546Sopenharmony_ci if (fd < 0) { 636bf215546Sopenharmony_ci return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, 637bf215546Sopenharmony_ci "failed to open device %s", path); 638bf215546Sopenharmony_ci } 639bf215546Sopenharmony_ci 640bf215546Sopenharmony_ci /* Version 1.6 added SYNCOBJ support. */ 641bf215546Sopenharmony_ci const int min_version_major = 1; 642bf215546Sopenharmony_ci const int min_version_minor = 6; 643bf215546Sopenharmony_ci 644bf215546Sopenharmony_ci version = drmGetVersion(fd); 645bf215546Sopenharmony_ci if (!version) { 646bf215546Sopenharmony_ci close(fd); 647bf215546Sopenharmony_ci return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, 648bf215546Sopenharmony_ci "failed to query kernel driver version for device %s", 649bf215546Sopenharmony_ci path); 650bf215546Sopenharmony_ci } 651bf215546Sopenharmony_ci 652bf215546Sopenharmony_ci if (strcmp(version->name, "msm")) { 653bf215546Sopenharmony_ci drmFreeVersion(version); 654bf215546Sopenharmony_ci close(fd); 655bf215546Sopenharmony_ci return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, 656bf215546Sopenharmony_ci "device %s does not use the msm kernel driver", 657bf215546Sopenharmony_ci path); 658bf215546Sopenharmony_ci } 659bf215546Sopenharmony_ci 660bf215546Sopenharmony_ci if (version->version_major != min_version_major || 661bf215546Sopenharmony_ci version->version_minor < min_version_minor) { 662bf215546Sopenharmony_ci result = vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, 663bf215546Sopenharmony_ci "kernel driver for device %s has version %d.%d, " 664bf215546Sopenharmony_ci "but Vulkan requires version >= %d.%d", 665bf215546Sopenharmony_ci path, 666bf215546Sopenharmony_ci version->version_major, version->version_minor, 667bf215546Sopenharmony_ci min_version_major, min_version_minor); 668bf215546Sopenharmony_ci drmFreeVersion(version); 669bf215546Sopenharmony_ci close(fd); 670bf215546Sopenharmony_ci return result; 671bf215546Sopenharmony_ci } 672bf215546Sopenharmony_ci 673bf215546Sopenharmony_ci device->msm_major_version = version->version_major; 674bf215546Sopenharmony_ci device->msm_minor_version = version->version_minor; 675bf215546Sopenharmony_ci 676bf215546Sopenharmony_ci drmFreeVersion(version); 677bf215546Sopenharmony_ci 678bf215546Sopenharmony_ci if (instance->debug_flags & TU_DEBUG_STARTUP) 679bf215546Sopenharmony_ci mesa_logi("Found compatible device '%s'.", path); 680bf215546Sopenharmony_ci 681bf215546Sopenharmony_ci device->instance = instance; 682bf215546Sopenharmony_ci 683bf215546Sopenharmony_ci if (instance->vk.enabled_extensions.KHR_display) { 684bf215546Sopenharmony_ci master_fd = open(primary_path, O_RDWR | O_CLOEXEC); 685bf215546Sopenharmony_ci if (master_fd >= 0) { 686bf215546Sopenharmony_ci /* TODO: free master_fd is accel is not working? */ 687bf215546Sopenharmony_ci } 688bf215546Sopenharmony_ci } 689bf215546Sopenharmony_ci 690bf215546Sopenharmony_ci device->master_fd = master_fd; 691bf215546Sopenharmony_ci device->local_fd = fd; 692bf215546Sopenharmony_ci 693bf215546Sopenharmony_ci if (tu_drm_get_gpu_id(device, &device->dev_id.gpu_id)) { 694bf215546Sopenharmony_ci result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED, 695bf215546Sopenharmony_ci "could not get GPU ID"); 696bf215546Sopenharmony_ci goto fail; 697bf215546Sopenharmony_ci } 698bf215546Sopenharmony_ci 699bf215546Sopenharmony_ci if (tu_drm_get_param(device, MSM_PARAM_CHIP_ID, &device->dev_id.chip_id)) { 700bf215546Sopenharmony_ci result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED, 701bf215546Sopenharmony_ci "could not get CHIP ID"); 702bf215546Sopenharmony_ci goto fail; 703bf215546Sopenharmony_ci } 704bf215546Sopenharmony_ci 705bf215546Sopenharmony_ci if (tu_drm_get_gmem_size(device, &device->gmem_size)) { 706bf215546Sopenharmony_ci result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED, 707bf215546Sopenharmony_ci "could not get GMEM size"); 708bf215546Sopenharmony_ci goto fail; 709bf215546Sopenharmony_ci } 710bf215546Sopenharmony_ci device->gmem_size = env_var_as_unsigned("TU_GMEM", device->gmem_size); 711bf215546Sopenharmony_ci 712bf215546Sopenharmony_ci if (tu_drm_get_gmem_base(device, &device->gmem_base)) { 713bf215546Sopenharmony_ci result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED, 714bf215546Sopenharmony_ci "could not get GMEM size"); 715bf215546Sopenharmony_ci goto fail; 716bf215546Sopenharmony_ci } 717bf215546Sopenharmony_ci 718bf215546Sopenharmony_ci struct stat st; 719bf215546Sopenharmony_ci 720bf215546Sopenharmony_ci if (stat(primary_path, &st) == 0) { 721bf215546Sopenharmony_ci device->has_master = true; 722bf215546Sopenharmony_ci device->master_major = major(st.st_rdev); 723bf215546Sopenharmony_ci device->master_minor = minor(st.st_rdev); 724bf215546Sopenharmony_ci } else { 725bf215546Sopenharmony_ci device->has_master = false; 726bf215546Sopenharmony_ci device->master_major = 0; 727bf215546Sopenharmony_ci device->master_minor = 0; 728bf215546Sopenharmony_ci } 729bf215546Sopenharmony_ci 730bf215546Sopenharmony_ci if (stat(path, &st) == 0) { 731bf215546Sopenharmony_ci device->has_local = true; 732bf215546Sopenharmony_ci device->local_major = major(st.st_rdev); 733bf215546Sopenharmony_ci device->local_minor = minor(st.st_rdev); 734bf215546Sopenharmony_ci } else { 735bf215546Sopenharmony_ci result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED, 736bf215546Sopenharmony_ci "failed to stat DRM render node %s", path); 737bf215546Sopenharmony_ci goto fail; 738bf215546Sopenharmony_ci } 739bf215546Sopenharmony_ci 740bf215546Sopenharmony_ci int ret = tu_drm_get_param(device, MSM_PARAM_FAULTS, &device->fault_count); 741bf215546Sopenharmony_ci if (ret != 0) { 742bf215546Sopenharmony_ci result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED, 743bf215546Sopenharmony_ci "Failed to get initial fault count: %d", ret); 744bf215546Sopenharmony_ci goto fail; 745bf215546Sopenharmony_ci } 746bf215546Sopenharmony_ci 747bf215546Sopenharmony_ci device->syncobj_type = vk_drm_syncobj_get_type(fd); 748bf215546Sopenharmony_ci /* we don't support DRM_CAP_SYNCOBJ_TIMELINE, but drm-shim does */ 749bf215546Sopenharmony_ci if (!(device->syncobj_type.features & VK_SYNC_FEATURE_TIMELINE)) 750bf215546Sopenharmony_ci device->timeline_type = vk_sync_timeline_get_type(&tu_timeline_sync_type); 751bf215546Sopenharmony_ci 752bf215546Sopenharmony_ci device->sync_types[0] = &device->syncobj_type; 753bf215546Sopenharmony_ci device->sync_types[1] = &device->timeline_type.sync; 754bf215546Sopenharmony_ci device->sync_types[2] = NULL; 755bf215546Sopenharmony_ci 756bf215546Sopenharmony_ci device->heap.size = tu_get_system_heap_size(); 757bf215546Sopenharmony_ci device->heap.used = 0u; 758bf215546Sopenharmony_ci device->heap.flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT; 759bf215546Sopenharmony_ci 760bf215546Sopenharmony_ci result = tu_physical_device_init(device, instance); 761bf215546Sopenharmony_ci 762bf215546Sopenharmony_ci if (result == VK_SUCCESS) 763bf215546Sopenharmony_ci return result; 764bf215546Sopenharmony_ci 765bf215546Sopenharmony_cifail: 766bf215546Sopenharmony_ci close(fd); 767bf215546Sopenharmony_ci if (master_fd != -1) 768bf215546Sopenharmony_ci close(master_fd); 769bf215546Sopenharmony_ci return result; 770bf215546Sopenharmony_ci} 771bf215546Sopenharmony_ci 772bf215546Sopenharmony_ciVkResult 773bf215546Sopenharmony_citu_enumerate_devices(struct tu_instance *instance) 774bf215546Sopenharmony_ci{ 775bf215546Sopenharmony_ci /* TODO: Check for more devices ? */ 776bf215546Sopenharmony_ci drmDevicePtr devices[8]; 777bf215546Sopenharmony_ci VkResult result = VK_ERROR_INCOMPATIBLE_DRIVER; 778bf215546Sopenharmony_ci int max_devices; 779bf215546Sopenharmony_ci 780bf215546Sopenharmony_ci instance->physical_device_count = 0; 781bf215546Sopenharmony_ci 782bf215546Sopenharmony_ci max_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices)); 783bf215546Sopenharmony_ci 784bf215546Sopenharmony_ci if (instance->debug_flags & TU_DEBUG_STARTUP) { 785bf215546Sopenharmony_ci if (max_devices < 0) 786bf215546Sopenharmony_ci mesa_logi("drmGetDevices2 returned error: %s\n", strerror(max_devices)); 787bf215546Sopenharmony_ci else 788bf215546Sopenharmony_ci mesa_logi("Found %d drm nodes", max_devices); 789bf215546Sopenharmony_ci } 790bf215546Sopenharmony_ci 791bf215546Sopenharmony_ci if (max_devices < 1) 792bf215546Sopenharmony_ci return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER, 793bf215546Sopenharmony_ci "No DRM devices found"); 794bf215546Sopenharmony_ci 795bf215546Sopenharmony_ci for (unsigned i = 0; i < (unsigned) max_devices; i++) { 796bf215546Sopenharmony_ci if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER && 797bf215546Sopenharmony_ci devices[i]->bustype == DRM_BUS_PLATFORM) { 798bf215546Sopenharmony_ci 799bf215546Sopenharmony_ci result = tu_drm_device_init( 800bf215546Sopenharmony_ci instance->physical_devices + instance->physical_device_count, 801bf215546Sopenharmony_ci instance, devices[i]); 802bf215546Sopenharmony_ci if (result == VK_SUCCESS) 803bf215546Sopenharmony_ci ++instance->physical_device_count; 804bf215546Sopenharmony_ci else if (result != VK_ERROR_INCOMPATIBLE_DRIVER) 805bf215546Sopenharmony_ci break; 806bf215546Sopenharmony_ci } 807bf215546Sopenharmony_ci } 808bf215546Sopenharmony_ci drmFreeDevices(devices, max_devices); 809bf215546Sopenharmony_ci 810bf215546Sopenharmony_ci return result; 811bf215546Sopenharmony_ci} 812bf215546Sopenharmony_ci 813bf215546Sopenharmony_cistatic VkResult 814bf215546Sopenharmony_citu_queue_submit_create_locked(struct tu_queue *queue, 815bf215546Sopenharmony_ci struct vk_queue_submit *vk_submit, 816bf215546Sopenharmony_ci const uint32_t nr_in_syncobjs, 817bf215546Sopenharmony_ci const uint32_t nr_out_syncobjs, 818bf215546Sopenharmony_ci uint32_t perf_pass_index, 819bf215546Sopenharmony_ci struct tu_queue_submit *new_submit) 820bf215546Sopenharmony_ci{ 821bf215546Sopenharmony_ci VkResult result; 822bf215546Sopenharmony_ci 823bf215546Sopenharmony_ci bool u_trace_enabled = u_trace_context_actively_tracing(&queue->device->trace_context); 824bf215546Sopenharmony_ci bool has_trace_points = false; 825bf215546Sopenharmony_ci 826bf215546Sopenharmony_ci struct vk_command_buffer **vk_cmd_buffers = vk_submit->command_buffers; 827bf215546Sopenharmony_ci 828bf215546Sopenharmony_ci memset(new_submit, 0, sizeof(struct tu_queue_submit)); 829bf215546Sopenharmony_ci 830bf215546Sopenharmony_ci new_submit->cmd_buffers = (void *)vk_cmd_buffers; 831bf215546Sopenharmony_ci new_submit->nr_cmd_buffers = vk_submit->command_buffer_count; 832bf215546Sopenharmony_ci tu_insert_dynamic_cmdbufs(queue->device, &new_submit->cmd_buffers, 833bf215546Sopenharmony_ci &new_submit->nr_cmd_buffers); 834bf215546Sopenharmony_ci 835bf215546Sopenharmony_ci uint32_t entry_count = 0; 836bf215546Sopenharmony_ci for (uint32_t j = 0; j < new_submit->nr_cmd_buffers; ++j) { 837bf215546Sopenharmony_ci struct tu_cmd_buffer *cmdbuf = new_submit->cmd_buffers[j]; 838bf215546Sopenharmony_ci 839bf215546Sopenharmony_ci if (perf_pass_index != ~0) 840bf215546Sopenharmony_ci entry_count++; 841bf215546Sopenharmony_ci 842bf215546Sopenharmony_ci entry_count += cmdbuf->cs.entry_count; 843bf215546Sopenharmony_ci 844bf215546Sopenharmony_ci if (u_trace_enabled && u_trace_has_points(&cmdbuf->trace)) { 845bf215546Sopenharmony_ci if (!(cmdbuf->usage_flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT)) 846bf215546Sopenharmony_ci entry_count++; 847bf215546Sopenharmony_ci 848bf215546Sopenharmony_ci has_trace_points = true; 849bf215546Sopenharmony_ci } 850bf215546Sopenharmony_ci } 851bf215546Sopenharmony_ci 852bf215546Sopenharmony_ci new_submit->autotune_fence = 853bf215546Sopenharmony_ci tu_autotune_submit_requires_fence(new_submit->cmd_buffers, new_submit->nr_cmd_buffers); 854bf215546Sopenharmony_ci if (new_submit->autotune_fence) 855bf215546Sopenharmony_ci entry_count++; 856bf215546Sopenharmony_ci 857bf215546Sopenharmony_ci new_submit->cmds = vk_zalloc(&queue->device->vk.alloc, 858bf215546Sopenharmony_ci entry_count * sizeof(*new_submit->cmds), 8, 859bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); 860bf215546Sopenharmony_ci 861bf215546Sopenharmony_ci if (new_submit->cmds == NULL) { 862bf215546Sopenharmony_ci result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 863bf215546Sopenharmony_ci goto fail_cmds; 864bf215546Sopenharmony_ci } 865bf215546Sopenharmony_ci 866bf215546Sopenharmony_ci if (has_trace_points) { 867bf215546Sopenharmony_ci result = 868bf215546Sopenharmony_ci tu_u_trace_submission_data_create( 869bf215546Sopenharmony_ci queue->device, new_submit->cmd_buffers, 870bf215546Sopenharmony_ci new_submit->nr_cmd_buffers, 871bf215546Sopenharmony_ci &new_submit->u_trace_submission_data); 872bf215546Sopenharmony_ci 873bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 874bf215546Sopenharmony_ci goto fail_u_trace_submission_data; 875bf215546Sopenharmony_ci } 876bf215546Sopenharmony_ci } 877bf215546Sopenharmony_ci 878bf215546Sopenharmony_ci /* Allocate without wait timeline semaphores */ 879bf215546Sopenharmony_ci new_submit->in_syncobjs = vk_zalloc(&queue->device->vk.alloc, 880bf215546Sopenharmony_ci nr_in_syncobjs * sizeof(*new_submit->in_syncobjs), 8, 881bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); 882bf215546Sopenharmony_ci 883bf215546Sopenharmony_ci if (new_submit->in_syncobjs == NULL) { 884bf215546Sopenharmony_ci result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 885bf215546Sopenharmony_ci goto fail_in_syncobjs; 886bf215546Sopenharmony_ci } 887bf215546Sopenharmony_ci 888bf215546Sopenharmony_ci /* Allocate with signal timeline semaphores considered */ 889bf215546Sopenharmony_ci new_submit->out_syncobjs = vk_zalloc(&queue->device->vk.alloc, 890bf215546Sopenharmony_ci nr_out_syncobjs * sizeof(*new_submit->out_syncobjs), 8, 891bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); 892bf215546Sopenharmony_ci 893bf215546Sopenharmony_ci if (new_submit->out_syncobjs == NULL) { 894bf215546Sopenharmony_ci result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY); 895bf215546Sopenharmony_ci goto fail_out_syncobjs; 896bf215546Sopenharmony_ci } 897bf215546Sopenharmony_ci 898bf215546Sopenharmony_ci new_submit->entry_count = entry_count; 899bf215546Sopenharmony_ci new_submit->nr_in_syncobjs = nr_in_syncobjs; 900bf215546Sopenharmony_ci new_submit->nr_out_syncobjs = nr_out_syncobjs; 901bf215546Sopenharmony_ci new_submit->perf_pass_index = perf_pass_index; 902bf215546Sopenharmony_ci new_submit->vk_submit = vk_submit; 903bf215546Sopenharmony_ci 904bf215546Sopenharmony_ci return VK_SUCCESS; 905bf215546Sopenharmony_ci 906bf215546Sopenharmony_cifail_out_syncobjs: 907bf215546Sopenharmony_ci vk_free(&queue->device->vk.alloc, new_submit->in_syncobjs); 908bf215546Sopenharmony_cifail_in_syncobjs: 909bf215546Sopenharmony_ci if (new_submit->u_trace_submission_data) 910bf215546Sopenharmony_ci tu_u_trace_submission_data_finish(queue->device, 911bf215546Sopenharmony_ci new_submit->u_trace_submission_data); 912bf215546Sopenharmony_cifail_u_trace_submission_data: 913bf215546Sopenharmony_ci vk_free(&queue->device->vk.alloc, new_submit->cmds); 914bf215546Sopenharmony_cifail_cmds: 915bf215546Sopenharmony_ci return result; 916bf215546Sopenharmony_ci} 917bf215546Sopenharmony_ci 918bf215546Sopenharmony_cistatic void 919bf215546Sopenharmony_citu_queue_submit_finish(struct tu_queue *queue, struct tu_queue_submit *submit) 920bf215546Sopenharmony_ci{ 921bf215546Sopenharmony_ci vk_free(&queue->device->vk.alloc, submit->cmds); 922bf215546Sopenharmony_ci vk_free(&queue->device->vk.alloc, submit->in_syncobjs); 923bf215546Sopenharmony_ci vk_free(&queue->device->vk.alloc, submit->out_syncobjs); 924bf215546Sopenharmony_ci if (submit->cmd_buffers != (void *) submit->vk_submit->command_buffers) 925bf215546Sopenharmony_ci vk_free(&queue->device->vk.alloc, submit->cmd_buffers); 926bf215546Sopenharmony_ci} 927bf215546Sopenharmony_ci 928bf215546Sopenharmony_cistatic void 929bf215546Sopenharmony_citu_fill_msm_gem_submit(struct tu_device *dev, 930bf215546Sopenharmony_ci struct drm_msm_gem_submit_cmd *cmd, 931bf215546Sopenharmony_ci struct tu_cs_entry *cs_entry) 932bf215546Sopenharmony_ci{ 933bf215546Sopenharmony_ci cmd->type = MSM_SUBMIT_CMD_BUF; 934bf215546Sopenharmony_ci cmd->submit_idx = cs_entry->bo->bo_list_idx; 935bf215546Sopenharmony_ci cmd->submit_offset = cs_entry->offset; 936bf215546Sopenharmony_ci cmd->size = cs_entry->size; 937bf215546Sopenharmony_ci cmd->pad = 0; 938bf215546Sopenharmony_ci cmd->nr_relocs = 0; 939bf215546Sopenharmony_ci cmd->relocs = 0; 940bf215546Sopenharmony_ci} 941bf215546Sopenharmony_ci 942bf215546Sopenharmony_cistatic void 943bf215546Sopenharmony_citu_queue_build_msm_gem_submit_cmds(struct tu_queue *queue, 944bf215546Sopenharmony_ci struct tu_queue_submit *submit, 945bf215546Sopenharmony_ci struct tu_cs *autotune_cs) 946bf215546Sopenharmony_ci{ 947bf215546Sopenharmony_ci struct tu_device *dev = queue->device; 948bf215546Sopenharmony_ci struct drm_msm_gem_submit_cmd *cmds = submit->cmds; 949bf215546Sopenharmony_ci 950bf215546Sopenharmony_ci uint32_t entry_idx = 0; 951bf215546Sopenharmony_ci for (uint32_t j = 0; j < submit->nr_cmd_buffers; ++j) { 952bf215546Sopenharmony_ci struct tu_device *dev = queue->device; 953bf215546Sopenharmony_ci struct tu_cmd_buffer *cmdbuf = submit->cmd_buffers[j]; 954bf215546Sopenharmony_ci struct tu_cs *cs = &cmdbuf->cs; 955bf215546Sopenharmony_ci 956bf215546Sopenharmony_ci if (submit->perf_pass_index != ~0) { 957bf215546Sopenharmony_ci struct tu_cs_entry *perf_cs_entry = 958bf215546Sopenharmony_ci &dev->perfcntrs_pass_cs_entries[submit->perf_pass_index]; 959bf215546Sopenharmony_ci 960bf215546Sopenharmony_ci tu_fill_msm_gem_submit(dev, &cmds[entry_idx], perf_cs_entry); 961bf215546Sopenharmony_ci entry_idx++; 962bf215546Sopenharmony_ci } 963bf215546Sopenharmony_ci 964bf215546Sopenharmony_ci for (unsigned i = 0; i < cs->entry_count; ++i, ++entry_idx) { 965bf215546Sopenharmony_ci tu_fill_msm_gem_submit(dev, &cmds[entry_idx], &cs->entries[i]); 966bf215546Sopenharmony_ci } 967bf215546Sopenharmony_ci 968bf215546Sopenharmony_ci if (submit->u_trace_submission_data) { 969bf215546Sopenharmony_ci struct tu_cs *ts_cs = 970bf215546Sopenharmony_ci submit->u_trace_submission_data->cmd_trace_data[j].timestamp_copy_cs; 971bf215546Sopenharmony_ci if (ts_cs) { 972bf215546Sopenharmony_ci tu_fill_msm_gem_submit(dev, &cmds[entry_idx], &ts_cs->entries[0]); 973bf215546Sopenharmony_ci entry_idx++; 974bf215546Sopenharmony_ci } 975bf215546Sopenharmony_ci } 976bf215546Sopenharmony_ci } 977bf215546Sopenharmony_ci 978bf215546Sopenharmony_ci if (autotune_cs) { 979bf215546Sopenharmony_ci assert(autotune_cs->entry_count == 1); 980bf215546Sopenharmony_ci tu_fill_msm_gem_submit(dev, &cmds[entry_idx], &autotune_cs->entries[0]); 981bf215546Sopenharmony_ci entry_idx++; 982bf215546Sopenharmony_ci } 983bf215546Sopenharmony_ci} 984bf215546Sopenharmony_ci 985bf215546Sopenharmony_cistatic VkResult 986bf215546Sopenharmony_citu_queue_submit_locked(struct tu_queue *queue, struct tu_queue_submit *submit) 987bf215546Sopenharmony_ci{ 988bf215546Sopenharmony_ci queue->device->submit_count++; 989bf215546Sopenharmony_ci 990bf215546Sopenharmony_ci struct tu_cs *autotune_cs = NULL; 991bf215546Sopenharmony_ci if (submit->autotune_fence) { 992bf215546Sopenharmony_ci autotune_cs = tu_autotune_on_submit(queue->device, 993bf215546Sopenharmony_ci &queue->device->autotune, 994bf215546Sopenharmony_ci submit->cmd_buffers, 995bf215546Sopenharmony_ci submit->nr_cmd_buffers); 996bf215546Sopenharmony_ci } 997bf215546Sopenharmony_ci 998bf215546Sopenharmony_ci uint32_t flags = MSM_PIPE_3D0; 999bf215546Sopenharmony_ci 1000bf215546Sopenharmony_ci if (submit->vk_submit->wait_count) 1001bf215546Sopenharmony_ci flags |= MSM_SUBMIT_SYNCOBJ_IN; 1002bf215546Sopenharmony_ci 1003bf215546Sopenharmony_ci if (submit->vk_submit->signal_count) 1004bf215546Sopenharmony_ci flags |= MSM_SUBMIT_SYNCOBJ_OUT; 1005bf215546Sopenharmony_ci 1006bf215546Sopenharmony_ci mtx_lock(&queue->device->bo_mutex); 1007bf215546Sopenharmony_ci 1008bf215546Sopenharmony_ci if (queue->device->implicit_sync_bo_count == 0) 1009bf215546Sopenharmony_ci flags |= MSM_SUBMIT_NO_IMPLICIT; 1010bf215546Sopenharmony_ci 1011bf215546Sopenharmony_ci /* drm_msm_gem_submit_cmd requires index of bo which could change at any 1012bf215546Sopenharmony_ci * time when bo_mutex is not locked. So we build submit cmds here the real 1013bf215546Sopenharmony_ci * place to submit. 1014bf215546Sopenharmony_ci */ 1015bf215546Sopenharmony_ci tu_queue_build_msm_gem_submit_cmds(queue, submit, autotune_cs); 1016bf215546Sopenharmony_ci 1017bf215546Sopenharmony_ci struct drm_msm_gem_submit req = { 1018bf215546Sopenharmony_ci .flags = flags, 1019bf215546Sopenharmony_ci .queueid = queue->msm_queue_id, 1020bf215546Sopenharmony_ci .bos = (uint64_t)(uintptr_t) queue->device->bo_list, 1021bf215546Sopenharmony_ci .nr_bos = submit->entry_count ? queue->device->bo_count : 0, 1022bf215546Sopenharmony_ci .cmds = (uint64_t)(uintptr_t)submit->cmds, 1023bf215546Sopenharmony_ci .nr_cmds = submit->entry_count, 1024bf215546Sopenharmony_ci .in_syncobjs = (uint64_t)(uintptr_t)submit->in_syncobjs, 1025bf215546Sopenharmony_ci .out_syncobjs = (uint64_t)(uintptr_t)submit->out_syncobjs, 1026bf215546Sopenharmony_ci .nr_in_syncobjs = submit->nr_in_syncobjs, 1027bf215546Sopenharmony_ci .nr_out_syncobjs = submit->nr_out_syncobjs, 1028bf215546Sopenharmony_ci .syncobj_stride = sizeof(struct drm_msm_gem_submit_syncobj), 1029bf215546Sopenharmony_ci }; 1030bf215546Sopenharmony_ci 1031bf215546Sopenharmony_ci int ret = drmCommandWriteRead(queue->device->fd, 1032bf215546Sopenharmony_ci DRM_MSM_GEM_SUBMIT, 1033bf215546Sopenharmony_ci &req, sizeof(req)); 1034bf215546Sopenharmony_ci 1035bf215546Sopenharmony_ci mtx_unlock(&queue->device->bo_mutex); 1036bf215546Sopenharmony_ci 1037bf215546Sopenharmony_ci if (ret) 1038bf215546Sopenharmony_ci return vk_device_set_lost(&queue->device->vk, "submit failed: %m"); 1039bf215546Sopenharmony_ci 1040bf215546Sopenharmony_ci#if HAVE_PERFETTO 1041bf215546Sopenharmony_ci tu_perfetto_submit(queue->device, queue->device->submit_count); 1042bf215546Sopenharmony_ci#endif 1043bf215546Sopenharmony_ci 1044bf215546Sopenharmony_ci if (submit->u_trace_submission_data) { 1045bf215546Sopenharmony_ci struct tu_u_trace_submission_data *submission_data = 1046bf215546Sopenharmony_ci submit->u_trace_submission_data; 1047bf215546Sopenharmony_ci submission_data->submission_id = queue->device->submit_count; 1048bf215546Sopenharmony_ci /* We have to allocate it here since it is different between drm/kgsl */ 1049bf215546Sopenharmony_ci submission_data->syncobj = 1050bf215546Sopenharmony_ci vk_alloc(&queue->device->vk.alloc, sizeof(struct tu_u_trace_syncobj), 1051bf215546Sopenharmony_ci 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE); 1052bf215546Sopenharmony_ci submission_data->syncobj->fence = req.fence; 1053bf215546Sopenharmony_ci submission_data->syncobj->msm_queue_id = queue->msm_queue_id; 1054bf215546Sopenharmony_ci 1055bf215546Sopenharmony_ci submit->u_trace_submission_data = NULL; 1056bf215546Sopenharmony_ci 1057bf215546Sopenharmony_ci for (uint32_t i = 0; i < submission_data->cmd_buffer_count; i++) { 1058bf215546Sopenharmony_ci bool free_data = i == submission_data->last_buffer_with_tracepoints; 1059bf215546Sopenharmony_ci if (submission_data->cmd_trace_data[i].trace) 1060bf215546Sopenharmony_ci u_trace_flush(submission_data->cmd_trace_data[i].trace, 1061bf215546Sopenharmony_ci submission_data, free_data); 1062bf215546Sopenharmony_ci 1063bf215546Sopenharmony_ci if (!submission_data->cmd_trace_data[i].timestamp_copy_cs) { 1064bf215546Sopenharmony_ci /* u_trace is owned by cmd_buffer */ 1065bf215546Sopenharmony_ci submission_data->cmd_trace_data[i].trace = NULL; 1066bf215546Sopenharmony_ci } 1067bf215546Sopenharmony_ci } 1068bf215546Sopenharmony_ci } 1069bf215546Sopenharmony_ci 1070bf215546Sopenharmony_ci for (uint32_t i = 0; i < submit->vk_submit->wait_count; i++) { 1071bf215546Sopenharmony_ci if (!vk_sync_is_tu_timeline_sync(submit->vk_submit->waits[i].sync)) 1072bf215546Sopenharmony_ci continue; 1073bf215546Sopenharmony_ci 1074bf215546Sopenharmony_ci struct tu_timeline_sync *sync = 1075bf215546Sopenharmony_ci container_of(submit->vk_submit->waits[i].sync, struct tu_timeline_sync, base); 1076bf215546Sopenharmony_ci 1077bf215546Sopenharmony_ci assert(sync->state != TU_TIMELINE_SYNC_STATE_RESET); 1078bf215546Sopenharmony_ci 1079bf215546Sopenharmony_ci /* Set SIGNALED to the state of the wait timeline sync since this means the syncobj 1080bf215546Sopenharmony_ci * is done and ready again so this can be garbage-collectioned later. 1081bf215546Sopenharmony_ci */ 1082bf215546Sopenharmony_ci sync->state = TU_TIMELINE_SYNC_STATE_SIGNALED; 1083bf215546Sopenharmony_ci } 1084bf215546Sopenharmony_ci 1085bf215546Sopenharmony_ci for (uint32_t i = 0; i < submit->vk_submit->signal_count; i++) { 1086bf215546Sopenharmony_ci if (!vk_sync_is_tu_timeline_sync(submit->vk_submit->signals[i].sync)) 1087bf215546Sopenharmony_ci continue; 1088bf215546Sopenharmony_ci 1089bf215546Sopenharmony_ci struct tu_timeline_sync *sync = 1090bf215546Sopenharmony_ci container_of(submit->vk_submit->signals[i].sync, struct tu_timeline_sync, base); 1091bf215546Sopenharmony_ci 1092bf215546Sopenharmony_ci assert(sync->state == TU_TIMELINE_SYNC_STATE_RESET); 1093bf215546Sopenharmony_ci /* Set SUBMITTED to the state of the signal timeline sync so we could wait for 1094bf215546Sopenharmony_ci * this timeline sync until completed if necessary. 1095bf215546Sopenharmony_ci */ 1096bf215546Sopenharmony_ci sync->state = TU_TIMELINE_SYNC_STATE_SUBMITTED; 1097bf215546Sopenharmony_ci } 1098bf215546Sopenharmony_ci 1099bf215546Sopenharmony_ci pthread_cond_broadcast(&queue->device->timeline_cond); 1100bf215546Sopenharmony_ci 1101bf215546Sopenharmony_ci return VK_SUCCESS; 1102bf215546Sopenharmony_ci} 1103bf215546Sopenharmony_ci 1104bf215546Sopenharmony_cistatic inline void 1105bf215546Sopenharmony_ciget_abs_timeout(struct drm_msm_timespec *tv, uint64_t ns) 1106bf215546Sopenharmony_ci{ 1107bf215546Sopenharmony_ci struct timespec t; 1108bf215546Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &t); 1109bf215546Sopenharmony_ci tv->tv_sec = t.tv_sec + ns / 1000000000; 1110bf215546Sopenharmony_ci tv->tv_nsec = t.tv_nsec + ns % 1000000000; 1111bf215546Sopenharmony_ci} 1112bf215546Sopenharmony_ci 1113bf215546Sopenharmony_ciVkResult 1114bf215546Sopenharmony_citu_device_wait_u_trace(struct tu_device *dev, struct tu_u_trace_syncobj *syncobj) 1115bf215546Sopenharmony_ci{ 1116bf215546Sopenharmony_ci struct drm_msm_wait_fence req = { 1117bf215546Sopenharmony_ci .fence = syncobj->fence, 1118bf215546Sopenharmony_ci .queueid = syncobj->msm_queue_id, 1119bf215546Sopenharmony_ci }; 1120bf215546Sopenharmony_ci int ret; 1121bf215546Sopenharmony_ci 1122bf215546Sopenharmony_ci get_abs_timeout(&req.timeout, 1000000000); 1123bf215546Sopenharmony_ci 1124bf215546Sopenharmony_ci ret = drmCommandWrite(dev->fd, DRM_MSM_WAIT_FENCE, &req, sizeof(req)); 1125bf215546Sopenharmony_ci if (ret && (ret != -ETIMEDOUT)) { 1126bf215546Sopenharmony_ci fprintf(stderr, "wait-fence failed! %d (%s)", ret, strerror(errno)); 1127bf215546Sopenharmony_ci return VK_TIMEOUT; 1128bf215546Sopenharmony_ci } 1129bf215546Sopenharmony_ci 1130bf215546Sopenharmony_ci return VK_SUCCESS; 1131bf215546Sopenharmony_ci} 1132bf215546Sopenharmony_ci 1133bf215546Sopenharmony_ciVkResult 1134bf215546Sopenharmony_citu_queue_submit(struct vk_queue *vk_queue, struct vk_queue_submit *submit) 1135bf215546Sopenharmony_ci{ 1136bf215546Sopenharmony_ci struct tu_queue *queue = container_of(vk_queue, struct tu_queue, vk); 1137bf215546Sopenharmony_ci uint32_t perf_pass_index = queue->device->perfcntrs_pass_cs ? 1138bf215546Sopenharmony_ci submit->perf_pass_index : ~0; 1139bf215546Sopenharmony_ci struct tu_queue_submit submit_req; 1140bf215546Sopenharmony_ci 1141bf215546Sopenharmony_ci if (unlikely(queue->device->physical_device->instance->debug_flags & 1142bf215546Sopenharmony_ci TU_DEBUG_LOG_SKIP_GMEM_OPS)) { 1143bf215546Sopenharmony_ci tu_dbg_log_gmem_load_store_skips(queue->device); 1144bf215546Sopenharmony_ci } 1145bf215546Sopenharmony_ci 1146bf215546Sopenharmony_ci pthread_mutex_lock(&queue->device->submit_mutex); 1147bf215546Sopenharmony_ci 1148bf215546Sopenharmony_ci VkResult ret = tu_queue_submit_create_locked(queue, submit, 1149bf215546Sopenharmony_ci submit->wait_count, submit->signal_count, 1150bf215546Sopenharmony_ci perf_pass_index, &submit_req); 1151bf215546Sopenharmony_ci 1152bf215546Sopenharmony_ci if (ret != VK_SUCCESS) { 1153bf215546Sopenharmony_ci pthread_mutex_unlock(&queue->device->submit_mutex); 1154bf215546Sopenharmony_ci return ret; 1155bf215546Sopenharmony_ci } 1156bf215546Sopenharmony_ci 1157bf215546Sopenharmony_ci /* note: assuming there won't be any very large semaphore counts */ 1158bf215546Sopenharmony_ci struct drm_msm_gem_submit_syncobj *in_syncobjs = submit_req.in_syncobjs; 1159bf215546Sopenharmony_ci struct drm_msm_gem_submit_syncobj *out_syncobjs = submit_req.out_syncobjs; 1160bf215546Sopenharmony_ci 1161bf215546Sopenharmony_ci uint32_t nr_in_syncobjs = 0, nr_out_syncobjs = 0; 1162bf215546Sopenharmony_ci 1163bf215546Sopenharmony_ci for (uint32_t i = 0; i < submit->wait_count; i++) { 1164bf215546Sopenharmony_ci struct vk_sync *sync = submit->waits[i].sync; 1165bf215546Sopenharmony_ci 1166bf215546Sopenharmony_ci in_syncobjs[nr_in_syncobjs++] = (struct drm_msm_gem_submit_syncobj) { 1167bf215546Sopenharmony_ci .handle = tu_syncobj_from_vk_sync(sync), 1168bf215546Sopenharmony_ci .flags = 0, 1169bf215546Sopenharmony_ci }; 1170bf215546Sopenharmony_ci } 1171bf215546Sopenharmony_ci 1172bf215546Sopenharmony_ci for (uint32_t i = 0; i < submit->signal_count; i++) { 1173bf215546Sopenharmony_ci struct vk_sync *sync = submit->signals[i].sync; 1174bf215546Sopenharmony_ci 1175bf215546Sopenharmony_ci out_syncobjs[nr_out_syncobjs++] = (struct drm_msm_gem_submit_syncobj) { 1176bf215546Sopenharmony_ci .handle = tu_syncobj_from_vk_sync(sync), 1177bf215546Sopenharmony_ci .flags = 0, 1178bf215546Sopenharmony_ci }; 1179bf215546Sopenharmony_ci } 1180bf215546Sopenharmony_ci 1181bf215546Sopenharmony_ci ret = tu_queue_submit_locked(queue, &submit_req); 1182bf215546Sopenharmony_ci 1183bf215546Sopenharmony_ci pthread_mutex_unlock(&queue->device->submit_mutex); 1184bf215546Sopenharmony_ci tu_queue_submit_finish(queue, &submit_req); 1185bf215546Sopenharmony_ci 1186bf215546Sopenharmony_ci if (ret != VK_SUCCESS) 1187bf215546Sopenharmony_ci return ret; 1188bf215546Sopenharmony_ci 1189bf215546Sopenharmony_ci u_trace_context_process(&queue->device->trace_context, true); 1190bf215546Sopenharmony_ci 1191bf215546Sopenharmony_ci return VK_SUCCESS; 1192bf215546Sopenharmony_ci} 1193bf215546Sopenharmony_ci 1194bf215546Sopenharmony_ciint 1195bf215546Sopenharmony_citu_syncobj_to_fd(struct tu_device *device, struct vk_sync *sync) 1196bf215546Sopenharmony_ci{ 1197bf215546Sopenharmony_ci VkResult ret; 1198bf215546Sopenharmony_ci int fd; 1199bf215546Sopenharmony_ci ret = vk_sync_export_opaque_fd(&device->vk, sync, &fd); 1200bf215546Sopenharmony_ci return ret ? -1 : fd; 1201bf215546Sopenharmony_ci} 1202