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