1/*
2 * Copyright © 2015 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24#include <sys/ioctl.h>
25#include <sys/types.h>
26#include <sys/mman.h>
27#include <string.h>
28#include <errno.h>
29#include <unistd.h>
30#include <fcntl.h>
31
32#include "anv_private.h"
33#include "common/intel_defines.h"
34#include "common/intel_gem.h"
35#include "drm-uapi/sync_file.h"
36
37/**
38 * Wrapper around DRM_IOCTL_I915_GEM_CREATE.
39 *
40 * Return gem handle, or 0 on failure. Gem handles are never 0.
41 */
42uint32_t
43anv_gem_create(struct anv_device *device, uint64_t size)
44{
45   struct drm_i915_gem_create gem_create = {
46      .size = size,
47   };
48
49   int ret = intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_CREATE, &gem_create);
50   if (ret != 0) {
51      /* FIXME: What do we do if this fails? */
52      return 0;
53   }
54
55   return gem_create.handle;
56}
57
58void
59anv_gem_close(struct anv_device *device, uint32_t gem_handle)
60{
61   struct drm_gem_close close = {
62      .handle = gem_handle,
63   };
64
65   intel_ioctl(device->fd, DRM_IOCTL_GEM_CLOSE, &close);
66}
67
68uint32_t
69anv_gem_create_regions(struct anv_device *device, uint64_t anv_bo_size,
70                       uint32_t num_regions,
71                       struct drm_i915_gem_memory_class_instance *regions)
72{
73   struct drm_i915_gem_create_ext_memory_regions ext_regions = {
74      .base = { .name = I915_GEM_CREATE_EXT_MEMORY_REGIONS },
75      .num_regions = num_regions,
76      .regions = (uintptr_t)regions,
77   };
78
79   struct drm_i915_gem_create_ext gem_create = {
80      .size = anv_bo_size,
81      .extensions = (uintptr_t) &ext_regions,
82   };
83
84   int ret = intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_CREATE_EXT,
85                         &gem_create);
86   if (ret != 0) {
87      return 0;
88   }
89
90   return gem_create.handle;
91}
92
93/**
94 * Wrapper around DRM_IOCTL_I915_GEM_MMAP. Returns MAP_FAILED on error.
95 */
96static void*
97anv_gem_mmap_offset(struct anv_device *device, uint32_t gem_handle,
98                    uint64_t offset, uint64_t size, uint32_t flags)
99{
100   struct drm_i915_gem_mmap_offset gem_mmap = {
101      .handle = gem_handle,
102      .flags = device->info.has_local_mem ? I915_MMAP_OFFSET_FIXED :
103         (flags & I915_MMAP_WC) ? I915_MMAP_OFFSET_WC : I915_MMAP_OFFSET_WB,
104   };
105   assert(offset == 0);
106
107   /* Get the fake offset back */
108   int ret = intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_MMAP_OFFSET, &gem_mmap);
109   if (ret != 0)
110      return MAP_FAILED;
111
112   /* And map it */
113   void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
114                    device->fd, gem_mmap.offset);
115   return map;
116}
117
118static void*
119anv_gem_mmap_legacy(struct anv_device *device, uint32_t gem_handle,
120                    uint64_t offset, uint64_t size, uint32_t flags)
121{
122   assert(!device->info.has_local_mem);
123
124   struct drm_i915_gem_mmap gem_mmap = {
125      .handle = gem_handle,
126      .offset = offset,
127      .size = size,
128      .flags = flags,
129   };
130
131   int ret = intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_MMAP, &gem_mmap);
132   if (ret != 0)
133      return MAP_FAILED;
134
135   return (void *)(uintptr_t) gem_mmap.addr_ptr;
136}
137
138/**
139 * Wrapper around DRM_IOCTL_I915_GEM_MMAP. Returns MAP_FAILED on error.
140 */
141void*
142anv_gem_mmap(struct anv_device *device, uint32_t gem_handle,
143             uint64_t offset, uint64_t size, uint32_t flags)
144{
145   void *map;
146   if (device->physical->has_mmap_offset)
147      map = anv_gem_mmap_offset(device, gem_handle, offset, size, flags);
148   else
149      map = anv_gem_mmap_legacy(device, gem_handle, offset, size, flags);
150
151   if (map != MAP_FAILED)
152      VG(VALGRIND_MALLOCLIKE_BLOCK(map, size, 0, 1));
153
154   return map;
155}
156
157/* This is just a wrapper around munmap, but it also notifies valgrind that
158 * this map is no longer valid.  Pair this with anv_gem_mmap().
159 */
160void
161anv_gem_munmap(struct anv_device *device, void *p, uint64_t size)
162{
163   VG(VALGRIND_FREELIKE_BLOCK(p, 0));
164   munmap(p, size);
165}
166
167uint32_t
168anv_gem_userptr(struct anv_device *device, void *mem, size_t size)
169{
170   struct drm_i915_gem_userptr userptr = {
171      .user_ptr = (__u64)((unsigned long) mem),
172      .user_size = size,
173      .flags = 0,
174   };
175
176   if (device->physical->has_userptr_probe)
177      userptr.flags |= I915_USERPTR_PROBE;
178
179   int ret = intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_USERPTR, &userptr);
180   if (ret == -1)
181      return 0;
182
183   return userptr.handle;
184}
185
186int
187anv_gem_set_caching(struct anv_device *device,
188                    uint32_t gem_handle, uint32_t caching)
189{
190   struct drm_i915_gem_caching gem_caching = {
191      .handle = gem_handle,
192      .caching = caching,
193   };
194
195   return intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_SET_CACHING, &gem_caching);
196}
197
198int
199anv_gem_set_domain(struct anv_device *device, uint32_t gem_handle,
200                   uint32_t read_domains, uint32_t write_domain)
201{
202   struct drm_i915_gem_set_domain gem_set_domain = {
203      .handle = gem_handle,
204      .read_domains = read_domains,
205      .write_domain = write_domain,
206   };
207
208   return intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &gem_set_domain);
209}
210
211/**
212 * Returns 0, 1, or negative to indicate error
213 */
214int
215anv_gem_busy(struct anv_device *device, uint32_t gem_handle)
216{
217   struct drm_i915_gem_busy busy = {
218      .handle = gem_handle,
219   };
220
221   int ret = intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
222   if (ret < 0)
223      return ret;
224
225   return busy.busy != 0;
226}
227
228/**
229 * On error, \a timeout_ns holds the remaining time.
230 */
231int
232anv_gem_wait(struct anv_device *device, uint32_t gem_handle, int64_t *timeout_ns)
233{
234   struct drm_i915_gem_wait wait = {
235      .bo_handle = gem_handle,
236      .timeout_ns = *timeout_ns,
237      .flags = 0,
238   };
239
240   int ret = intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_WAIT, &wait);
241   *timeout_ns = wait.timeout_ns;
242
243   return ret;
244}
245
246int
247anv_gem_execbuffer(struct anv_device *device,
248                   struct drm_i915_gem_execbuffer2 *execbuf)
249{
250   if (execbuf->flags & I915_EXEC_FENCE_OUT)
251      return intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2_WR, execbuf);
252   else
253      return intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf);
254}
255
256/** Return -1 on error. */
257int
258anv_gem_get_tiling(struct anv_device *device, uint32_t gem_handle)
259{
260   struct drm_i915_gem_get_tiling get_tiling = {
261      .handle = gem_handle,
262   };
263
264   /* FIXME: On discrete platforms we don't have DRM_IOCTL_I915_GEM_GET_TILING
265    * anymore, so we will need another way to get the tiling. Apparently this
266    * is only used in Android code, so we may need some other way to
267    * communicate the tiling mode.
268    */
269   if (intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling)) {
270      assert(!"Failed to get BO tiling");
271      return -1;
272   }
273
274   return get_tiling.tiling_mode;
275}
276
277int
278anv_gem_set_tiling(struct anv_device *device,
279                   uint32_t gem_handle, uint32_t stride, uint32_t tiling)
280{
281   int ret;
282
283   /* On discrete platforms we don't have DRM_IOCTL_I915_GEM_SET_TILING. So
284    * nothing needs to be done.
285    */
286   if (!device->info.has_tiling_uapi)
287      return 0;
288
289   /* set_tiling overwrites the input on the error path, so we have to open
290    * code intel_ioctl.
291    */
292   do {
293      struct drm_i915_gem_set_tiling set_tiling = {
294         .handle = gem_handle,
295         .tiling_mode = tiling,
296         .stride = stride,
297      };
298
299      ret = ioctl(device->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling);
300   } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
301
302   return ret;
303}
304
305int
306anv_gem_get_param(int fd, uint32_t param)
307{
308   int tmp;
309
310   drm_i915_getparam_t gp = {
311      .param = param,
312      .value = &tmp,
313   };
314
315   int ret = intel_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
316   if (ret == 0)
317      return tmp;
318
319   return 0;
320}
321
322uint64_t
323anv_gem_get_drm_cap(int fd, uint32_t capability)
324{
325   struct drm_get_cap cap = {
326      .capability = capability,
327   };
328
329   intel_ioctl(fd, DRM_IOCTL_GET_CAP, &cap);
330   return cap.value;
331}
332
333bool
334anv_gem_get_bit6_swizzle(int fd, uint32_t tiling)
335{
336   struct drm_gem_close close;
337   int ret;
338
339   struct drm_i915_gem_create gem_create = {
340      .size = 4096,
341   };
342
343   if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &gem_create)) {
344      assert(!"Failed to create GEM BO");
345      return false;
346   }
347
348   bool swizzled = false;
349
350   /* set_tiling overwrites the input on the error path, so we have to open
351    * code intel_ioctl.
352    */
353   do {
354      struct drm_i915_gem_set_tiling set_tiling = {
355         .handle = gem_create.handle,
356         .tiling_mode = tiling,
357         .stride = tiling == I915_TILING_X ? 512 : 128,
358      };
359
360      ret = ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling);
361   } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
362
363   if (ret != 0) {
364      assert(!"Failed to set BO tiling");
365      goto close_and_return;
366   }
367
368   struct drm_i915_gem_get_tiling get_tiling = {
369      .handle = gem_create.handle,
370   };
371
372   if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling)) {
373      assert(!"Failed to get BO tiling");
374      goto close_and_return;
375   }
376
377   swizzled = get_tiling.swizzle_mode != I915_BIT_6_SWIZZLE_NONE;
378
379close_and_return:
380
381   memset(&close, 0, sizeof(close));
382   close.handle = gem_create.handle;
383   intel_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close);
384
385   return swizzled;
386}
387
388bool
389anv_gem_has_context_priority(int fd)
390{
391   return !anv_gem_set_context_param(fd, 0, I915_CONTEXT_PARAM_PRIORITY,
392                                     INTEL_CONTEXT_MEDIUM_PRIORITY);
393}
394
395int
396anv_gem_create_context(struct anv_device *device)
397{
398   struct drm_i915_gem_context_create create = { 0 };
399
400   int ret = intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create);
401   if (ret == -1)
402      return -1;
403
404   return create.ctx_id;
405}
406
407int
408anv_gem_create_context_engines(struct anv_device *device,
409                               const struct drm_i915_query_engine_info *info,
410                               int num_engines, uint16_t *engine_classes)
411{
412   const size_t engine_inst_sz = 2 * sizeof(__u16); /* 1 class, 1 instance */
413   const size_t engines_param_size =
414      sizeof(__u64) /* extensions */ + num_engines * engine_inst_sz;
415
416   void *engines_param = malloc(engines_param_size);
417   assert(engines_param);
418   *(__u64*)engines_param = 0;
419   __u16 *class_inst_ptr = (__u16*)(((__u64*)engines_param) + 1);
420
421   /* For each type of drm_i915_gem_engine_class of interest, we keep track of
422    * the previous engine instance used.
423    */
424   int last_engine_idx[] = {
425      [I915_ENGINE_CLASS_RENDER] = -1,
426   };
427
428   int i915_engine_counts[] = {
429      [I915_ENGINE_CLASS_RENDER] =
430         anv_gem_count_engines(info, I915_ENGINE_CLASS_RENDER),
431   };
432
433   /* For each queue, we look for the next instance that matches the class we
434    * need.
435    */
436   for (int i = 0; i < num_engines; i++) {
437      uint16_t engine_class = engine_classes[i];
438      if (i915_engine_counts[engine_class] <= 0) {
439         free(engines_param);
440         return -1;
441      }
442
443      /* Run through the engines reported by the kernel looking for the next
444       * matching instance. We loop in case we want to create multiple
445       * contexts on an engine instance.
446       */
447      int engine_instance = -1;
448      for (int i = 0; i < info->num_engines; i++) {
449         int *idx = &last_engine_idx[engine_class];
450         if (++(*idx) >= info->num_engines)
451            *idx = 0;
452         if (info->engines[*idx].engine.engine_class == engine_class) {
453            engine_instance = info->engines[*idx].engine.engine_instance;
454            break;
455         }
456      }
457      if (engine_instance < 0) {
458         free(engines_param);
459         return -1;
460      }
461
462      *class_inst_ptr++ = engine_class;
463      *class_inst_ptr++ = engine_instance;
464   }
465
466   assert((uintptr_t)engines_param + engines_param_size ==
467          (uintptr_t)class_inst_ptr);
468
469   struct drm_i915_gem_context_create_ext_setparam set_engines = {
470      .base = {
471         .name = I915_CONTEXT_CREATE_EXT_SETPARAM,
472      },
473      .param = {
474	 .param = I915_CONTEXT_PARAM_ENGINES,
475         .value = (uintptr_t)engines_param,
476         .size = engines_param_size,
477      }
478   };
479   struct drm_i915_gem_context_create_ext create = {
480      .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS,
481      .extensions = (uintptr_t)&set_engines,
482   };
483   int ret = intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT, &create);
484   free(engines_param);
485   if (ret == -1)
486      return -1;
487
488   return create.ctx_id;
489}
490
491int
492anv_gem_destroy_context(struct anv_device *device, int context)
493{
494   struct drm_i915_gem_context_destroy destroy = {
495      .ctx_id = context,
496   };
497
498   return intel_ioctl(device->fd, DRM_IOCTL_I915_GEM_CONTEXT_DESTROY, &destroy);
499}
500
501int
502anv_gem_set_context_param(int fd, int context, uint32_t param, uint64_t value)
503{
504   struct drm_i915_gem_context_param p = {
505      .ctx_id = context,
506      .param = param,
507      .value = value,
508   };
509   int err = 0;
510
511   if (intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM, &p))
512      err = -errno;
513   return err;
514}
515
516int
517anv_gem_get_context_param(int fd, int context, uint32_t param, uint64_t *value)
518{
519   struct drm_i915_gem_context_param gp = {
520      .ctx_id = context,
521      .param = param,
522   };
523
524   int ret = intel_ioctl(fd, DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM, &gp);
525   if (ret == -1)
526      return -1;
527
528   *value = gp.value;
529   return 0;
530}
531
532int
533anv_gem_context_get_reset_stats(int fd, int context,
534                                uint32_t *active, uint32_t *pending)
535{
536   struct drm_i915_reset_stats stats = {
537      .ctx_id = context,
538   };
539
540   int ret = intel_ioctl(fd, DRM_IOCTL_I915_GET_RESET_STATS, &stats);
541   if (ret == 0) {
542      *active = stats.batch_active;
543      *pending = stats.batch_pending;
544   }
545
546   return ret;
547}
548
549int
550anv_gem_handle_to_fd(struct anv_device *device, uint32_t gem_handle)
551{
552   struct drm_prime_handle args = {
553      .handle = gem_handle,
554      .flags = DRM_CLOEXEC | DRM_RDWR,
555   };
556
557   int ret = intel_ioctl(device->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
558   if (ret == -1)
559      return -1;
560
561   return args.fd;
562}
563
564uint32_t
565anv_gem_fd_to_handle(struct anv_device *device, int fd)
566{
567   struct drm_prime_handle args = {
568      .fd = fd,
569   };
570
571   int ret = intel_ioctl(device->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
572   if (ret == -1)
573      return 0;
574
575   return args.handle;
576}
577
578int
579anv_gem_reg_read(int fd, uint32_t offset, uint64_t *result)
580{
581   struct drm_i915_reg_read args = {
582      .offset = offset
583   };
584
585   int ret = intel_ioctl(fd, DRM_IOCTL_I915_REG_READ, &args);
586
587   *result = args.val;
588   return ret;
589}
590
591int
592anv_gem_sync_file_merge(struct anv_device *device, int fd1, int fd2)
593{
594   struct sync_merge_data args = {
595      .name = "anv merge fence",
596      .fd2 = fd2,
597      .fence = -1,
598   };
599
600   int ret = intel_ioctl(fd1, SYNC_IOC_MERGE, &args);
601   if (ret == -1)
602      return -1;
603
604   return args.fence;
605}
606
607uint32_t
608anv_gem_syncobj_create(struct anv_device *device, uint32_t flags)
609{
610   struct drm_syncobj_create args = {
611      .flags = flags,
612   };
613
614   int ret = intel_ioctl(device->fd, DRM_IOCTL_SYNCOBJ_CREATE, &args);
615   if (ret)
616      return 0;
617
618   return args.handle;
619}
620
621void
622anv_gem_syncobj_destroy(struct anv_device *device, uint32_t handle)
623{
624   struct drm_syncobj_destroy args = {
625      .handle = handle,
626   };
627
628   intel_ioctl(device->fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args);
629}
630
631int
632anv_gem_syncobj_handle_to_fd(struct anv_device *device, uint32_t handle)
633{
634   struct drm_syncobj_handle args = {
635      .handle = handle,
636   };
637
638   int ret = intel_ioctl(device->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
639   if (ret)
640      return -1;
641
642   return args.fd;
643}
644
645uint32_t
646anv_gem_syncobj_fd_to_handle(struct anv_device *device, int fd)
647{
648   struct drm_syncobj_handle args = {
649      .fd = fd,
650   };
651
652   int ret = intel_ioctl(device->fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
653   if (ret)
654      return 0;
655
656   return args.handle;
657}
658
659int
660anv_gem_syncobj_export_sync_file(struct anv_device *device, uint32_t handle)
661{
662   struct drm_syncobj_handle args = {
663      .handle = handle,
664      .flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE,
665   };
666
667   int ret = intel_ioctl(device->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
668   if (ret)
669      return -1;
670
671   return args.fd;
672}
673
674int
675anv_gem_syncobj_import_sync_file(struct anv_device *device,
676                                 uint32_t handle, int fd)
677{
678   struct drm_syncobj_handle args = {
679      .handle = handle,
680      .fd = fd,
681      .flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE,
682   };
683
684   return intel_ioctl(device->fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
685}
686
687void
688anv_gem_syncobj_reset(struct anv_device *device, uint32_t handle)
689{
690   struct drm_syncobj_array args = {
691      .handles = (uint64_t)(uintptr_t)&handle,
692      .count_handles = 1,
693   };
694
695   intel_ioctl(device->fd, DRM_IOCTL_SYNCOBJ_RESET, &args);
696}
697
698bool
699anv_gem_supports_syncobj_wait(int fd)
700{
701   return intel_gem_supports_syncobj_wait(fd);
702}
703
704int
705anv_gem_syncobj_wait(struct anv_device *device,
706                     const uint32_t *handles, uint32_t num_handles,
707                     int64_t abs_timeout_ns, bool wait_all)
708{
709   struct drm_syncobj_wait args = {
710      .handles = (uint64_t)(uintptr_t)handles,
711      .count_handles = num_handles,
712      .timeout_nsec = abs_timeout_ns,
713      .flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT,
714   };
715
716   if (wait_all)
717      args.flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL;
718
719   return intel_ioctl(device->fd, DRM_IOCTL_SYNCOBJ_WAIT, &args);
720}
721
722int
723anv_gem_syncobj_timeline_wait(struct anv_device *device,
724                              const uint32_t *handles, const uint64_t *points,
725                              uint32_t num_items, int64_t abs_timeout_ns,
726                              bool wait_all, bool wait_materialize)
727{
728   assert(device->physical->has_syncobj_wait_available);
729
730   struct drm_syncobj_timeline_wait args = {
731      .handles = (uint64_t)(uintptr_t)handles,
732      .points = (uint64_t)(uintptr_t)points,
733      .count_handles = num_items,
734      .timeout_nsec = abs_timeout_ns,
735      .flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT,
736   };
737
738   if (wait_all)
739      args.flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL;
740   if (wait_materialize)
741      args.flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE;
742
743   return intel_ioctl(device->fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args);
744}
745
746int
747anv_gem_syncobj_timeline_signal(struct anv_device *device,
748                                const uint32_t *handles, const uint64_t *points,
749                                uint32_t num_items)
750{
751   assert(device->physical->has_syncobj_wait_available);
752
753   struct drm_syncobj_timeline_array args = {
754      .handles = (uint64_t)(uintptr_t)handles,
755      .points = (uint64_t)(uintptr_t)points,
756      .count_handles = num_items,
757   };
758
759   return intel_ioctl(device->fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args);
760}
761
762int
763anv_gem_syncobj_timeline_query(struct anv_device *device,
764                               const uint32_t *handles, uint64_t *points,
765                               uint32_t num_items)
766{
767   assert(device->physical->has_syncobj_wait_available);
768
769   struct drm_syncobj_timeline_array args = {
770      .handles = (uint64_t)(uintptr_t)handles,
771      .points = (uint64_t)(uintptr_t)points,
772      .count_handles = num_items,
773   };
774
775   return intel_ioctl(device->fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
776}
777
778struct drm_i915_query_engine_info *
779anv_gem_get_engine_info(int fd)
780{
781   return intel_i915_query_alloc(fd, DRM_I915_QUERY_ENGINE_INFO);
782}
783
784int
785anv_gem_count_engines(const struct drm_i915_query_engine_info *info,
786                      uint16_t engine_class)
787{
788   int count = 0;
789   for (int i = 0; i < info->num_engines; i++) {
790      if (info->engines[i].engine.engine_class == engine_class)
791         count++;
792   }
793   return count;
794}
795