On 2018-12-11 5:37 a.m., Chunming Zhou wrote:
> v2: adapt to new transfer ioctl
> 
> Signed-off-by: Chunming Zhou <david1.z...@amd.com>

+igt-dev

I think intel-gfx still works for IGT development but most of the IGT work 
happens on igt-...@lists.freedesktop.org now.

Harry

> ---
>  include/drm-uapi/drm.h   |   33 ++
>  lib/igt_syncobj.c        |  206 ++++++++
>  lib/igt_syncobj.h        |   19 +
>  tests/meson.build        |    1 +
>  tests/syncobj_timeline.c | 1032 ++++++++++++++++++++++++++++++++++++++
>  5 files changed, 1291 insertions(+)
>  create mode 100644 tests/syncobj_timeline.c
> 
> diff --git a/include/drm-uapi/drm.h b/include/drm-uapi/drm.h
> index 85c685a2..dcd245d9 100644
> --- a/include/drm-uapi/drm.h
> +++ b/include/drm-uapi/drm.h
> @@ -731,6 +731,8 @@ struct drm_syncobj_handle {
>  
>  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
>  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
> +/* wait for time point to become available */
> +#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
>  struct drm_syncobj_wait {
>       __u64 handles;
>       /* absolute timeout */
> @@ -741,11 +743,38 @@ struct drm_syncobj_wait {
>       __u32 pad;
>  };
>  
> +struct drm_syncobj_timeline_wait {
> +        __u64 handles;
> +        /* wait on specific timeline point for every handles*/
> +        __u64 points;
> +        /* absolute timeout */
> +        __s64 timeout_nsec;
> +        __u32 count_handles;
> +        __u32 flags;
> +        __u32 first_signaled; /* only valid when not waiting all */
> +        __u32 pad;
> +};
> +
>  struct drm_syncobj_array {
>       __u64 handles;
>       __u32 count_handles;
>       __u32 pad;
>  };
> +struct drm_syncobj_timeline_array {
> +       __u64 handles;
> +       __u64 points;
> +       __u32 count_handles;
> +       __u32 pad;
> +};
> +
> +struct drm_syncobj_transfer {
> +        __u32 src_handle;
> +        __u32 dst_handle;
> +        __u64 src_point;
> +        __u64 dst_point;
> +        __u32 flags;
> +        __u32 pad;
> +};
>  
>  /* Query current scanout sequence number */
>  struct drm_crtc_get_sequence {
> @@ -902,6 +931,10 @@ extern "C" {
>  #define DRM_IOCTL_MODE_LIST_LESSEES  DRM_IOWR(0xC7, struct 
> drm_mode_list_lessees)
>  #define DRM_IOCTL_MODE_GET_LEASE     DRM_IOWR(0xC8, struct 
> drm_mode_get_lease)
>  #define DRM_IOCTL_MODE_REVOKE_LEASE  DRM_IOWR(0xC9, struct 
> drm_mode_revoke_lease)
> +#define DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT DRM_IOWR(0xCA, struct 
> drm_syncobj_timeline_wait)
> +#define DRM_IOCTL_SYNCOBJ_QUERY         DRM_IOWR(0xCB, struct 
> drm_syncobj_timeline_array)
> +#define DRM_IOCTL_SYNCOBJ_TRANSFER    DRM_IOWR(0xCC, struct 
> drm_syncobj_transfer)
> +#define DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL    DRM_IOWR(0xCD, struct 
> drm_syncobj_timeline_array)
>  
>  /**
>   * Device specific ioctls should only be in their respective headers
> diff --git a/lib/igt_syncobj.c b/lib/igt_syncobj.c
> index d9114ca8..efa2adc4 100644
> --- a/lib/igt_syncobj.c
> +++ b/lib/igt_syncobj.c
> @@ -286,3 +286,209 @@ syncobj_signal(int fd, uint32_t *handles, uint32_t 
> count)
>  {
>       igt_assert_eq(__syncobj_signal(fd, handles, count), 0);
>  }
> +
> +static int
> +__syncobj_timeline_signal(int fd, uint32_t *handles, uint64_t *points, 
> uint32_t count)
> +{
> +     struct drm_syncobj_timeline_array array = { 0 };
> +     int err = 0;
> +
> +     array.handles = to_user_pointer(handles);
> +     array.points = to_user_pointer(points);
> +     array.count_handles = count;
> +     if (drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &array))
> +             err = -errno;
> +     return err;
> +}
> +
> +/**
> + * syncobj_signal:
> + * @fd: The DRM file descriptor.
> + * @handles: Array of syncobj handles to signal
> + * @points: List of point of handles to signal.
> + * @count: Count of syncobj handles.
> + *
> + * Signal a set of syncobjs.
> + */
> +void
> +syncobj_timeline_signal(int fd, uint32_t *handles, uint64_t *points, 
> uint32_t count)
> +{
> +     igt_assert_eq(__syncobj_timeline_signal(fd, handles, points, count), 0);
> +}
> +int
> +__syncobj_timeline_wait_ioctl(int fd, struct drm_syncobj_timeline_wait *args)
> +{
> +     int err = 0;
> +     if (drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, args))
> +             err = -errno;
> +     return err;
> +}
> +static int
> +__syncobj_timeline_wait(int fd, uint32_t *handles, uint64_t *points,
> +                     unsigned num_handles,
> +                     int64_t timeout_nsec, unsigned flags,
> +                     uint32_t *first_signaled)
> +{
> +     struct drm_syncobj_timeline_wait args;
> +     int ret;
> +
> +     args.handles = to_user_pointer(handles);
> +     args.points = (uint64_t)to_user_pointer(points);
> +     args.timeout_nsec = timeout_nsec;
> +     args.count_handles = num_handles;
> +     args.flags = flags;
> +     args.first_signaled = 0;
> +     args.pad = 0;
> +
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args);
> +     if (ret < 0)
> +             return -errno;
> +
> +     if (first_signaled)
> +             *first_signaled = args.first_signaled;
> +
> +     return ret;
> +}
> +int
> +syncobj_timeline_wait_err(int fd, uint32_t *handles, uint64_t *points,
> +                       unsigned num_handles,
> +                       int64_t timeout_nsec, unsigned flags)
> +{
> +     return __syncobj_timeline_wait(fd, handles, points, num_handles,
> +                                    timeout_nsec, flags, NULL);
> +}
> +
> +/**
> + * syncobj_timeline_wait:
> + * @fd: The DRM file descriptor
> + * @handles: List of syncobj handles to wait for.
> + * @points: List of point of handles to wait for.
> + * @num_handles: Count of handles
> + * @timeout_nsec: Absolute wait timeout in nanoseconds.
> + * @flags: Wait ioctl flags.
> + * @first_signaled: Returned handle for first signaled syncobj.
> + *
> + * Waits in the kernel for any/all the requested syncobjs timeline point
> + * using the timeout and flags.
> + * Returns: bool value - false = timedout, true = signaled
> + */
> +bool
> +syncobj_timeline_wait(int fd, uint32_t *handles, uint64_t *points,
> +                   unsigned num_handles,
> +                   int64_t timeout_nsec, unsigned flags,
> +                   uint32_t *first_signaled)
> +{
> +     int ret;
> +
> +     ret = __syncobj_timeline_wait(fd, handles, points, num_handles,
> +                                   timeout_nsec, flags, first_signaled);
> +     if (ret == -ETIME)
> +             return false;
> +     igt_assert_eq(ret, 0);
> +
> +     return true;
> +
> +}
> +
> +static int
> +__syncobj_timeline_query(int fd, uint32_t *handles, uint64_t **points,
> +                      uint32_t handle_count)
> +{
> +     struct drm_syncobj_timeline_array args;
> +     int ret;
> +
> +     args.handles = to_user_pointer(handles);
> +     args.points = (uint64_t)to_user_pointer(points);
> +     args.count_handles = handle_count;
> +     args.pad = 0;
> +
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
> +     if (ret)
> +             return ret;
> +     return 0;
> +}
> +
> +/**
> + * syncobj_timeline_query:
> + * @fd: The DRM file descriptor.
> + * @handles: Array of syncobj handles.
> + * @points: Array of syncobj points queried.
> + * @count: Count of syncobj handles.
> + *
> + * query a set of syncobjs.
> + */
> +void
> +syncobj_timeline_query(int fd, uint32_t *handles, uint64_t **points,
> +                    uint32_t count)
> +{
> +     igt_assert_eq(__syncobj_timeline_query(fd, handles, points, count), 0);
> +}
> +
> +static int
> +__syncobj_binary_to_timeline(int fd, uint32_t timeline_handle,
> +                          uint64_t point, uint32_t binary_handle)
> +{
> +     struct drm_syncobj_transfer args;
> +
> +     args.src_handle = binary_handle;
> +     args.dst_handle = timeline_handle;
> +     args.src_point = 0;
> +     args.dst_point = point;
> +     args.flags = 0;
> +     args.pad = 0;
> +     return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args);
> +}
> +
> +/**
> + * syncobj_binary_to_timeline:
> + * @fd: The DRM file descriptor.
> + * @timeline_handles: Array of timeline syncobj handles.
> + * @point: syncobj point.
> + * @binary_handle: Array of binary syncobj handles.
> + *
> + * query a set of syncobjs.
> + */
> +void
> +syncobj_binary_to_timeline(int fd, uint32_t timeline_handle,
> +                        uint64_t point, uint32_t binary_handle)
> +{
> +     igt_assert_eq(__syncobj_binary_to_timeline(fd, timeline_handle, point,
> +                                                binary_handle), 0);
> +}
> +
> +static int
> +__syncobj_timeline_to_binary(int fd, uint32_t binary_handle,
> +                          uint32_t timeline_handle,
> +                          uint64_t point,
> +                          uint32_t flags)
> +{
> +     struct drm_syncobj_transfer args;
> +
> +     args.dst_handle = binary_handle;
> +     args.src_handle = timeline_handle;
> +     args.dst_point = 0;
> +     args.src_point = point;
> +     args.flags = flags;
> +     args.pad = 0;
> +     return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args);
> +}
> +
> +/**
> + * syncobj_binary_to_timeline:
> + * @fd: The DRM file descriptor.
> + * @timeline_handles: Array of timeline syncobj handles.
> + * @point: syncobj point.
> + * @binary_handle: Array of binary syncobj handles.
> + *
> + * query a set of syncobjs.
> + */
> +void
> +syncobj_timeline_to_binary(int fd, uint32_t binary_handle,
> +                        uint32_t timeline_handle,
> +                        uint64_t point,
> +                        uint32_t flags)
> +{
> +     igt_assert_eq(__syncobj_timeline_to_binary(fd, binary_handle,
> +                                                timeline_handle, point,
> +                                                flags), 0);
> +}
> diff --git a/lib/igt_syncobj.h b/lib/igt_syncobj.h
> index 44d1378d..175e5027 100644
> --- a/lib/igt_syncobj.h
> +++ b/lib/igt_syncobj.h
> @@ -65,7 +65,26 @@ int syncobj_wait_err(int fd, uint32_t *handles, uint32_t 
> count,
>  bool syncobj_wait(int fd, uint32_t *handles, uint32_t count,
>                 uint64_t abs_timeout_nsec, uint32_t flags,
>                 uint32_t *first_signaled);
> +int __syncobj_timeline_wait_ioctl(int fd,
> +                               struct drm_syncobj_timeline_wait *args);
> +bool syncobj_timeline_wait(int fd, uint32_t *handles, uint64_t *points,
> +                        unsigned num_handles,
> +                        int64_t timeout_nsec, unsigned flags,
> +                        uint32_t *first_signaled);
> +int syncobj_timeline_wait_err(int fd, uint32_t *handles, uint64_t *points,
> +                           unsigned num_handles,
> +                           int64_t timeout_nsec, unsigned flags);
>  void syncobj_reset(int fd, uint32_t *handles, uint32_t count);
>  void syncobj_signal(int fd, uint32_t *handles, uint32_t count);
> +void syncobj_timeline_query(int fd, uint32_t *handles, uint64_t **points,
> +                         uint32_t count);
> +void syncobj_binary_to_timeline(int fd, uint32_t timeline_handle,
> +                             uint64_t point, uint32_t binary_handle);
> +void syncobj_timeline_to_binary(int fd, uint32_t binary_handle,
> +                             uint32_t timeline_handle,
> +                             uint64_t point,
> +                             uint32_t flags);
> +void syncobj_timeline_signal(int fd, uint32_t *handles, uint64_t *points,
> +                          uint32_t count);
>  
>  #endif /* IGT_SYNCOBJ_H */
> diff --git a/tests/meson.build b/tests/meson.build
> index b8a6e61b..bddc223c 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -77,6 +77,7 @@ test_progs = [
>       'sw_sync',
>       'syncobj_basic',
>       'syncobj_wait',
> +     'syncobj_timeline',
>       'template',
>       'tools_test',
>       'v3d_get_bo_offset',
> diff --git a/tests/syncobj_timeline.c b/tests/syncobj_timeline.c
> new file mode 100644
> index 00000000..505fd9ed
> --- /dev/null
> +++ b/tests/syncobj_timeline.c
> @@ -0,0 +1,1032 @@
> +/*
> + * Copyright © 2018 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
> DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +#include "igt.h"
> +#include "sw_sync.h"
> +#include "igt_syncobj.h"
> +#include <unistd.h>
> +#include <time.h>
> +#include <sys/ioctl.h>
> +#include <pthread.h>
> +#include <signal.h>
> +#include "drm.h"
> +
> +IGT_TEST_DESCRIPTION("Tests for the drm timeline sync object API");
> +
> +/* One tenth of a second */
> +#define SHORT_TIME_NSEC 100000000ull
> +
> +#define NSECS_PER_SEC 1000000000ull
> +
> +static uint64_t
> +gettime_ns(void)
> +{
> +     struct timespec current;
> +     clock_gettime(CLOCK_MONOTONIC, &current);
> +     return (uint64_t)current.tv_sec * NSECS_PER_SEC + current.tv_nsec;
> +}
> +
> +static void
> +sleep_nsec(uint64_t time_nsec)
> +{
> +     struct timespec t;
> +     t.tv_sec = time_nsec / NSECS_PER_SEC;
> +     t.tv_nsec = time_nsec % NSECS_PER_SEC;
> +     igt_assert_eq(nanosleep(&t, NULL), 0);
> +}
> +
> +static uint64_t
> +short_timeout(void)
> +{
> +     return gettime_ns() + SHORT_TIME_NSEC;
> +}
> +
> +static int
> +syncobj_attach_sw_sync(int fd, uint32_t handle, uint64_t point)
> +{
> +     struct drm_syncobj_handle;
> +     uint32_t syncobj = syncobj_create(fd, 0);
> +     int timeline, fence;
> +
> +     timeline = sw_sync_timeline_create();
> +     fence = sw_sync_timeline_create_fence(timeline, 1);
> +     syncobj_import_sync_file(fd, syncobj, fence);
> +     syncobj_binary_to_timeline(fd, handle, point, syncobj);
> +     close(fence);
> +
> +     syncobj_destroy(fd, syncobj);
> +     return timeline;
> +}
> +
> +static void
> +syncobj_trigger(int fd, uint32_t handle, uint64_t point)
> +{
> +     int timeline = syncobj_attach_sw_sync(fd, handle, point);
> +     sw_sync_timeline_inc(timeline, 1);
> +     close(timeline);
> +}
> +
> +static timer_t
> +set_timer(void (*cb)(union sigval), void *ptr, int i, uint64_t nsec)
> +{
> +        timer_t timer;
> +        struct sigevent sev;
> +        struct itimerspec its;
> +
> +        memset(&sev, 0, sizeof(sev));
> +        sev.sigev_notify = SIGEV_THREAD;
> +     if (ptr)
> +             sev.sigev_value.sival_ptr = ptr;
> +     else
> +             sev.sigev_value.sival_int = i;
> +        sev.sigev_notify_function = cb;
> +        igt_assert(timer_create(CLOCK_MONOTONIC, &sev, &timer) == 0);
> +
> +        memset(&its, 0, sizeof(its));
> +        its.it_value.tv_sec = nsec / NSEC_PER_SEC;
> +        its.it_value.tv_nsec = nsec % NSEC_PER_SEC;
> +        igt_assert(timer_settime(timer, 0, &its, NULL) == 0);
> +
> +     return timer;
> +}
> +
> +struct fd_handle_pair {
> +     int fd;
> +     uint32_t handle;
> +     uint64_t point;
> +};
> +
> +static void
> +timeline_inc_func(union sigval sigval)
> +{
> +     sw_sync_timeline_inc(sigval.sival_int, 1);
> +}
> +
> +static void
> +syncobj_trigger_free_pair_func(union sigval sigval)
> +{
> +     struct fd_handle_pair *pair = sigval.sival_ptr;
> +     syncobj_trigger(pair->fd, pair->handle, pair->point);
> +     free(pair);
> +}
> +
> +static timer_t
> +syncobj_trigger_delayed(int fd, uint32_t syncobj, uint64_t point, uint64_t 
> nsec)
> +{
> +     struct fd_handle_pair *pair = malloc(sizeof(*pair));
> +
> +     pair->fd = fd;
> +     pair->handle = syncobj;
> +     pair->point = syncobj;
> +
> +     return set_timer(syncobj_trigger_free_pair_func, pair, 0, nsec);
> +}
> +
> +static void
> +test_wait_bad_flags(int fd)
> +{
> +     struct drm_syncobj_timeline_wait wait = { 0 };
> +     wait.flags = 0xdeadbeef;
> +     igt_assert_eq(__syncobj_timeline_wait_ioctl(fd, &wait), -EINVAL);
> +}
> +
> +static void
> +test_wait_zero_handles(int fd)
> +{
> +     struct drm_syncobj_timeline_wait wait = { 0 };
> +     igt_assert_eq(__syncobj_timeline_wait_ioctl(fd, &wait), -EINVAL);
> +}
> +
> +static void
> +test_wait_illegal_handle(int fd)
> +{
> +     struct drm_syncobj_timeline_wait wait = { 0 };
> +     uint32_t handle = 0;
> +
> +     wait.count_handles = 1;
> +     wait.handles = to_user_pointer(&handle);
> +     igt_assert_eq(__syncobj_timeline_wait_ioctl(fd, &wait), -ENOENT);
> +}
> +
> +static void
> +test_query_zero_handles(int fd)
> +{
> +     struct drm_syncobj_timeline_array args = { 0 };
> +     int ret;
> +
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
> +     igt_assert(ret == -1 && errno ==  EINVAL);
> +}
> +
> +static void
> +test_query_illegal_handle(int fd)
> +{
> +     struct drm_syncobj_timeline_array args = { 0 };
> +     uint32_t handle = 0;
> +     int ret;
> +
> +     args.count_handles = 1;
> +     args.handles = to_user_pointer(&handle);
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
> +     igt_assert(ret == -1 && errno == ENOENT);
> +}
> +
> +static void
> +test_query_one_illegal_handle(int fd)
> +{
> +     struct drm_syncobj_timeline_array array = { 0 };
> +     uint32_t syncobjs[3];
> +     uint64_t initial_point = 1;
> +     int ret;
> +
> +     syncobjs[0] = syncobj_create(fd, 0);
> +     syncobjs[1] = 0;
> +     syncobjs[2] = syncobj_create(fd, 0);
> +
> +     syncobj_timeline_signal(fd, &syncobjs[0], &initial_point, 1);
> +     syncobj_timeline_signal(fd, &syncobjs[2], &initial_point, 1);
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobjs[0],
> +                                             &initial_point, 1, 0, 0), 0);
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobjs[2],
> +                                             &initial_point, 1, 0, 0), 0);
> +
> +     array.count_handles = 3;
> +     array.handles = to_user_pointer(syncobjs);
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &array);
> +     igt_assert(ret == -1 && errno == ENOENT);
> +
> +     syncobj_destroy(fd, syncobjs[0]);
> +     syncobj_destroy(fd, syncobjs[2]);
> +}
> +
> +static void
> +test_query_bad_pad(int fd)
> +{
> +     struct drm_syncobj_timeline_array array = { 0 };
> +     uint32_t handle = 0;
> +     int ret;
> +
> +     array.pad = 0xdeadbeef;
> +     array.count_handles = 1;
> +     array.handles = to_user_pointer(&handle);
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &array);
> +     igt_assert(ret == -1 && errno == EINVAL);
> +}
> +
> +static void
> +test_signal_zero_handles(int fd)
> +{
> +     struct drm_syncobj_timeline_array args = { 0 };
> +     int ret;
> +
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args);
> +     igt_assert(ret == -1 && errno ==  EINVAL);
> +}
> +
> +static void
> +test_signal_illegal_handle(int fd)
> +{
> +     struct drm_syncobj_timeline_array args = { 0 };
> +     uint32_t handle = 0;
> +     int ret;
> +
> +     args.count_handles = 1;
> +     args.handles = to_user_pointer(&handle);
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args);
> +     igt_assert(ret == -1 && errno == ENOENT);
> +}
> +
> +static void
> +test_signal_illegal_point(int fd)
> +{
> +     struct drm_syncobj_timeline_array args = { 0 };
> +     uint32_t handle = 1;
> +     uint64_t point = 0;
> +     int ret;
> +
> +     args.count_handles = 1;
> +     args.handles = to_user_pointer(&handle);
> +     args.points = to_user_pointer(&point);
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args);
> +     igt_assert(ret == -1 && errno == ENOENT);
> +}
> +static void
> +test_signal_one_illegal_handle(int fd)
> +{
> +     struct drm_syncobj_timeline_array array = { 0 };
> +     uint32_t syncobjs[3];
> +     uint64_t initial_point = 1;
> +     int ret;
> +
> +     syncobjs[0] = syncobj_create(fd, 0);
> +     syncobjs[1] = 0;
> +     syncobjs[2] = syncobj_create(fd, 0);
> +
> +     syncobj_timeline_signal(fd, &syncobjs[0], &initial_point, 1);
> +     syncobj_timeline_signal(fd, &syncobjs[2], &initial_point, 1);
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobjs[0],
> +                                             &initial_point, 1, 0, 0), 0);
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobjs[2],
> +                                             &initial_point, 1, 0, 0), 0);
> +
> +     array.count_handles = 3;
> +     array.handles = to_user_pointer(syncobjs);
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &array);
> +     igt_assert(ret == -1 && errno == ENOENT);
> +
> +     syncobj_destroy(fd, syncobjs[0]);
> +     syncobj_destroy(fd, syncobjs[2]);
> +}
> +
> +static void
> +test_signal_bad_pad(int fd)
> +{
> +     struct drm_syncobj_timeline_array array = { 0 };
> +     uint32_t handle = 0;
> +     int ret;
> +
> +     array.pad = 0xdeadbeef;
> +     array.count_handles = 1;
> +     array.handles = to_user_pointer(&handle);
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &array);
> +     igt_assert(ret == -1 && errno == EINVAL);
> +}
> +
> +static void
> +test_signal_array(int fd)
> +{
> +     uint32_t syncobjs[4];
> +     uint64_t points[4] = {1, 1, 1, 0};
> +
> +     syncobjs[0] = syncobj_create(fd, 0);
> +     syncobjs[1] = syncobj_create(fd, 0);
> +     syncobjs[2] = syncobj_create(fd, 0);
> +     syncobjs[3] = syncobj_create(fd, 0);
> +
> +     syncobj_timeline_signal(fd, syncobjs, points, 4);
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, syncobjs,
> +                                             points, 3, 0, 0), 0);
> +     igt_assert_eq(syncobj_wait_err(fd, &syncobjs[3], 1, 0, 0), 0);
> +
> +     syncobj_destroy(fd, syncobjs[0]);
> +     syncobj_destroy(fd, syncobjs[1]);
> +     syncobj_destroy(fd, syncobjs[2]);
> +     syncobj_destroy(fd, syncobjs[3]);
> +}
> +
> +static void
> +test_transfer_illegal_handle(int fd)
> +{
> +     struct drm_syncobj_transfer args = { 0 };
> +     uint32_t handle = 0;
> +     int ret;
> +
> +     args.src_handle = to_user_pointer(&handle);
> +     args.dst_handle = to_user_pointer(&handle);
> +     args.src_point = 1;
> +     args.dst_point = 0;
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args);
> +     igt_assert(ret == -1 && errno == ENOENT);
> +}
> +
> +static void
> +test_transfer_bad_pad(int fd)
> +{
> +     struct drm_syncobj_transfer arg = { 0 };
> +     uint32_t handle = 0;
> +     int ret;
> +
> +     arg.pad = 0xdeadbeef;
> +     arg.src_handle = to_user_pointer(&handle);
> +     arg.dst_handle = to_user_pointer(&handle);
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &arg);
> +     igt_assert(ret == -1 && errno == EINVAL);
> +}
> +
> +#define WAIT_FOR_SUBMIT              (1 << 0)
> +#define WAIT_ALL             (1 << 1)
> +#define WAIT_AVAILABLE               (1 << 2)
> +#define WAIT_UNSUBMITTED     (1 << 3)
> +#define WAIT_SUBMITTED               (1 << 4)
> +#define WAIT_SIGNALED                (1 << 5)
> +#define WAIT_FLAGS_MAX               (1 << 6) - 1
> +
> +static uint32_t
> +flags_for_test_flags(uint32_t test_flags)
> +{
> +     uint32_t flags = 0;
> +
> +     if (test_flags & WAIT_FOR_SUBMIT)
> +             flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT;
> +
> +     if (test_flags & WAIT_AVAILABLE)
> +             flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE;
> +
> +     if (test_flags & WAIT_ALL)
> +             flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL;
> +
> +     return flags;
> +}
> +
> +static void
> +test_single_wait(int fd, uint32_t test_flags, int expect)
> +{
> +     uint32_t syncobj = syncobj_create(fd, 0);
> +     uint32_t flags = flags_for_test_flags(test_flags);
> +     uint64_t point = 1;
> +     int timeline = -1;
> +
> +     if (test_flags & (WAIT_SUBMITTED | WAIT_SIGNALED))
> +             timeline = syncobj_attach_sw_sync(fd, syncobj, point);
> +
> +     if (test_flags & WAIT_SIGNALED)
> +             sw_sync_timeline_inc(timeline, 1);
> +
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobj, &point, 1,
> +                                             0, flags), expect);
> +
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobj, &point, 1,
> +                                             short_timeout(), flags), 
> expect);
> +
> +     if (expect != -ETIME) {
> +             igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobj, &point, 1,
> +                                                     UINT64_MAX, flags), 
> expect);
> +     }
> +
> +     syncobj_destroy(fd, syncobj);
> +     if (timeline != -1)
> +             close(timeline);
> +}
> +
> +static void
> +test_wait_delayed_signal(int fd, uint32_t test_flags)
> +{
> +     uint32_t syncobj = syncobj_create(fd, 0);
> +     uint32_t flags = flags_for_test_flags(test_flags);
> +     uint64_t point = 1;
> +     int timeline = -1;
> +     timer_t timer;
> +
> +     if (test_flags & WAIT_FOR_SUBMIT) {
> +             timer = syncobj_trigger_delayed(fd, syncobj, point, 
> SHORT_TIME_NSEC);
> +     } else {
> +             timeline = syncobj_attach_sw_sync(fd, syncobj, point);
> +             timer = set_timer(timeline_inc_func, NULL,
> +                               timeline, SHORT_TIME_NSEC);
> +     }
> +
> +     igt_assert(syncobj_timeline_wait(fd, &syncobj, &point, 1,
> +                             gettime_ns() + SHORT_TIME_NSEC * 2,
> +                             flags, NULL));
> +
> +     timer_delete(timer);
> +
> +     if (timeline != -1)
> +             close(timeline);
> +
> +     syncobj_destroy(fd, syncobj);
> +}
> +
> +static void
> +test_reset_unsignaled(int fd)
> +{
> +     uint32_t syncobj = syncobj_create(fd, 0);
> +     uint64_t point = 1;
> +
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobj, &point,
> +                                             1, 0, 0), -EINVAL);
> +
> +     syncobj_reset(fd, &syncobj, 1);
> +
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobj, &point,
> +                                             1, 0, 0), -EINVAL);
> +
> +     syncobj_destroy(fd, syncobj);
> +}
> +
> +static void
> +test_reset_signaled(int fd)
> +{
> +     uint32_t syncobj = syncobj_create(fd, 0);
> +     uint64_t point = 1;
> +
> +     syncobj_trigger(fd, syncobj, point);
> +
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobj, &point,
> +                                             1, 0, 0), 0);
> +
> +     syncobj_reset(fd, &syncobj, 1);
> +
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobj, &point,
> +                                             1, 0, 0), -EINVAL);
> +
> +     syncobj_destroy(fd, syncobj);
> +}
> +
> +static void
> +test_reset_multiple_signaled(int fd)
> +{
> +     uint64_t points[3] = {1, 1, 1};
> +     uint32_t syncobjs[3];
> +     int i;
> +
> +     for (i = 0; i < 3; i++) {
> +             syncobjs[i] = syncobj_create(fd, 0);
> +             syncobj_trigger(fd, syncobjs[i], points[i]);
> +     }
> +
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, syncobjs, points, 3, 0, 0), 
> 0);
> +
> +     syncobj_reset(fd, syncobjs, 3);
> +
> +     for (i = 0; i < 3; i++) {
> +             igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobjs[i],
> +                                                     &points[i], 1,
> +                                                     0, 0), -EINVAL);
> +             syncobj_destroy(fd, syncobjs[i]);
> +     }
> +}
> +
> +static void
> +reset_and_trigger_func(union sigval sigval)
> +{
> +     struct fd_handle_pair *pair = sigval.sival_ptr;
> +     syncobj_reset(pair->fd, &pair->handle, 1);
> +     syncobj_trigger(pair->fd, pair->handle, pair->point);
> +}
> +
> +static void
> +test_reset_during_wait_for_submit(int fd)
> +{
> +     uint32_t syncobj = syncobj_create(fd, 0);
> +     uint32_t flags = LOCAL_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT;
> +     struct fd_handle_pair pair;
> +     uint64_t point = 1;
> +     timer_t timer;
> +
> +     pair.fd = fd;
> +     pair.handle = syncobj;
> +     timer = set_timer(reset_and_trigger_func, &pair, 0, SHORT_TIME_NSEC);
> +
> +     /* A reset should be a no-op even if we're in the middle of a wait */
> +     igt_assert(syncobj_timeline_wait(fd, &syncobj, &point, 1,
> +                             gettime_ns() + SHORT_TIME_NSEC * 2,
> +                             flags, NULL));
> +
> +     timer_delete(timer);
> +
> +     syncobj_destroy(fd, syncobj);
> +}
> +
> +static void
> +test_signal(int fd)
> +{
> +     uint32_t syncobj = syncobj_create(fd, 0);
> +     uint32_t flags = LOCAL_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT;
> +     uint64_t point = 1;
> +
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobj, &point,
> +                                             1, 0, 0), -EINVAL);
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, &syncobj, &point,
> +                                             1, 0, flags), -ETIME);
> +
> +     syncobj_timeline_signal(fd, &syncobj, &point, 1);
> +
> +     igt_assert(syncobj_timeline_wait(fd, &syncobj, &point, 1, 0, 0, NULL));
> +     igt_assert(syncobj_timeline_wait(fd, &syncobj, &point, 1, 0, flags, 
> NULL));
> +
> +     syncobj_destroy(fd, syncobj);
> +}
> +
> +static void
> +test_multi_wait(int fd, uint32_t test_flags, int expect)
> +{
> +     uint32_t syncobjs[3];
> +     uint32_t tflag, flags;
> +     int i, fidx, timeline;
> +     uint64_t points[3] = {1, 1, 1};
> +
> +     syncobjs[0] = syncobj_create(fd, 0);
> +     syncobjs[1] = syncobj_create(fd, 0);
> +     syncobjs[2] = syncobj_create(fd, 0);
> +
> +     flags = flags_for_test_flags(test_flags);
> +     test_flags &= ~(WAIT_ALL | WAIT_FOR_SUBMIT | WAIT_AVAILABLE);
> +
> +     for (i = 0; i < 3; i++) {
> +             fidx = ffs(test_flags) - 1;
> +             tflag = (1 << fidx);
> +
> +             if (test_flags & ~tflag)
> +                     test_flags &= ~tflag;
> +
> +             if (tflag & (WAIT_SUBMITTED | WAIT_SIGNALED))
> +                     timeline = syncobj_attach_sw_sync(fd, syncobjs[i],
> +                                                       points[i]);
> +             if (tflag & WAIT_SIGNALED)
> +                     sw_sync_timeline_inc(timeline, 1);
> +     }
> +
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, syncobjs, points, 3, 0, 
> flags), expect);
> +
> +     igt_assert_eq(syncobj_timeline_wait_err(fd, syncobjs, points, 3, 
> short_timeout(),
> +                                    flags), expect);
> +
> +     if (expect != -ETIME) {
> +             igt_assert_eq(syncobj_timeline_wait_err(fd, syncobjs, points, 
> 3, UINT64_MAX,
> +                                            flags), expect);
> +     }
> +
> +     syncobj_destroy(fd, syncobjs[0]);
> +     syncobj_destroy(fd, syncobjs[1]);
> +     syncobj_destroy(fd, syncobjs[2]);
> +}
> +
> +struct wait_thread_data {
> +     int fd;
> +     struct drm_syncobj_timeline_wait wait;
> +};
> +
> +static void *
> +wait_thread_func(void *data)
> +{
> +     struct wait_thread_data *wait = data;
> +     igt_assert_eq(__syncobj_timeline_wait_ioctl(wait->fd, &wait->wait), 0);
> +     return NULL;
> +}
> +
> +static void
> +test_wait_snapshot(int fd, uint32_t test_flags)
> +{
> +     struct wait_thread_data wait = { 0 };
> +     uint32_t syncobjs[2];
> +     uint64_t points[2] = {1, 1};
> +     int timelines[3] = { -1, -1, -1 };
> +     pthread_t thread;
> +
> +     syncobjs[0] = syncobj_create(fd, 0);
> +     syncobjs[1] = syncobj_create(fd, 0);
> +
> +     if (!(test_flags & WAIT_FOR_SUBMIT)) {
> +             timelines[0] = syncobj_attach_sw_sync(fd, syncobjs[0], 
> points[0]);
> +             timelines[1] = syncobj_attach_sw_sync(fd, syncobjs[1], 
> points[1]);
> +     }
> +
> +     wait.fd = fd;
> +     wait.wait.handles = to_user_pointer(syncobjs);
> +     wait.wait.count_handles = 2;
> +     wait.wait.points = to_user_pointer(points);
> +     wait.wait.timeout_nsec = short_timeout();
> +     wait.wait.flags = flags_for_test_flags(test_flags);
> +
> +     igt_assert_eq(pthread_create(&thread, NULL, wait_thread_func, &wait), 
> 0);
> +
> +     sleep_nsec(SHORT_TIME_NSEC / 5);
> +
> +     /* Try to fake the kernel out by triggering or partially triggering
> +      * the first fence.
> +      */
> +     if (test_flags & WAIT_ALL) {
> +             /* If it's WAIT_ALL, actually trigger it */
> +             if (timelines[0] == -1)
> +                     syncobj_trigger(fd, syncobjs[0], points[0]);
> +             else
> +                     sw_sync_timeline_inc(timelines[0], 1);
> +     } else if (test_flags & WAIT_FOR_SUBMIT) {
> +             timelines[0] = syncobj_attach_sw_sync(fd, syncobjs[0], 
> points[0]);
> +     }
> +
> +     sleep_nsec(SHORT_TIME_NSEC / 5);
> +
> +     /* Then reset it */
> +     syncobj_reset(fd, &syncobjs[0], 1);
> +
> +     sleep_nsec(SHORT_TIME_NSEC / 5);
> +
> +     /* Then "submit" it in a way that will never trigger.  This way, if
> +      * the kernel picks up on the new fence (it shouldn't), we'll get a
> +      * timeout.
> +      */
> +     timelines[2] = syncobj_attach_sw_sync(fd, syncobjs[0], points[0]);
> +
> +     sleep_nsec(SHORT_TIME_NSEC / 5);
> +
> +     /* Now trigger the second fence to complete the wait */
> +
> +     if (timelines[1] == -1)
> +             syncobj_trigger(fd, syncobjs[1], points[1]);
> +     else
> +             sw_sync_timeline_inc(timelines[1], 1);
> +
> +     pthread_join(thread, NULL);
> +
> +     if (!(test_flags & WAIT_ALL))
> +             igt_assert_eq(wait.wait.first_signaled, 1);
> +
> +     close(timelines[0]);
> +     close(timelines[1]);
> +     close(timelines[2]);
> +     syncobj_destroy(fd, syncobjs[0]);
> +     syncobj_destroy(fd, syncobjs[1]);
> +}
> +
> +/* The numbers 0-7, each repeated 5x and shuffled. */
> +static const unsigned shuffled_0_7_x4[] = {
> +     2, 0, 6, 1, 1, 4, 5, 2, 0, 7, 1, 7, 6, 3, 4, 5,
> +     0, 2, 7, 3, 5, 4, 0, 6, 7, 3, 2, 5, 6, 1, 4, 3,
> +};
> +
> +enum syncobj_stage {
> +     STAGE_UNSUBMITTED,
> +     STAGE_SUBMITTED,
> +     STAGE_SIGNALED,
> +     STAGE_RESET,
> +     STAGE_RESUBMITTED,
> +};
> +
> +static void
> +test_wait_complex(int fd, uint32_t test_flags)
> +{
> +     struct wait_thread_data wait = { 0 };
> +     uint32_t syncobjs[8];
> +     uint64_t points[8] = {1, 1, 1, 1, 1, 1, 1, 1};
> +     enum syncobj_stage stage[8];
> +     int i, j, timelines[8];
> +     uint32_t first_signaled = -1, num_signaled = 0;
> +     pthread_t thread;
> +
> +     for (i = 0; i < 8; i++) {
> +             stage[i] = STAGE_UNSUBMITTED;
> +             syncobjs[i] = syncobj_create(fd, 0);
> +     }
> +
> +     if (test_flags & WAIT_FOR_SUBMIT) {
> +             for (i = 0; i < 8; i++)
> +                     timelines[i] = -1;
> +     } else {
> +             for (i = 0; i < 8; i++)
> +                     timelines[i] = syncobj_attach_sw_sync(fd, syncobjs[i],
> +                                                           points[i]);
> +     }
> +
> +     wait.fd = fd;
> +     wait.wait.handles = to_user_pointer(syncobjs);
> +     wait.wait.count_handles = 2;
> +     wait.wait.points = to_user_pointer(points);
> +     wait.wait.timeout_nsec = gettime_ns() + NSECS_PER_SEC;
> +     wait.wait.flags = flags_for_test_flags(test_flags);
> +
> +     igt_assert_eq(pthread_create(&thread, NULL, wait_thread_func, &wait), 
> 0);
> +
> +     sleep_nsec(NSECS_PER_SEC / 50);
> +
> +     num_signaled = 0;
> +     for (j = 0; j < ARRAY_SIZE(shuffled_0_7_x4); j++) {
> +             i = shuffled_0_7_x4[j];
> +             igt_assert_lt(i, ARRAY_SIZE(syncobjs));
> +
> +             switch (stage[i]++) {
> +             case STAGE_UNSUBMITTED:
> +                     /* We need to submit attach a fence */
> +                     if (!(test_flags & WAIT_FOR_SUBMIT)) {
> +                             /* We had to attach one up-front */
> +                             igt_assert_neq(timelines[i], -1);
> +                             break;
> +                     }
> +                     timelines[i] = syncobj_attach_sw_sync(fd, syncobjs[i],
> +                                                           points[i]);
> +                     break;
> +
> +             case STAGE_SUBMITTED:
> +                     /* We have a fence, trigger it */
> +                     igt_assert_neq(timelines[i], -1);
> +                     sw_sync_timeline_inc(timelines[i], 1);
> +                     close(timelines[i]);
> +                     timelines[i] = -1;
> +                     if (num_signaled == 0)
> +                             first_signaled = i;
> +                     num_signaled++;
> +                     break;
> +
> +             case STAGE_SIGNALED:
> +                     /* We're already signaled, reset */
> +                     syncobj_reset(fd, &syncobjs[i], 1);
> +                     break;
> +
> +             case STAGE_RESET:
> +                     /* We're reset, submit and don't signal */
> +                     timelines[i] = syncobj_attach_sw_sync(fd, syncobjs[i],
> +                                                           points[i]);
> +                     break;
> +
> +             case STAGE_RESUBMITTED:
> +                     igt_assert(!"Should not reach this stage");
> +                     break;
> +             }
> +
> +             if (test_flags & WAIT_ALL) {
> +                     if (num_signaled == ARRAY_SIZE(syncobjs))
> +                             break;
> +             } else {
> +                     if (num_signaled > 0)
> +                             break;
> +             }
> +
> +             sleep_nsec(NSECS_PER_SEC / 100);
> +     }
> +
> +     pthread_join(thread, NULL);
> +
> +     if (test_flags & WAIT_ALL) {
> +             igt_assert_eq(num_signaled, ARRAY_SIZE(syncobjs));
> +     } else {
> +             igt_assert_eq(num_signaled, 1);
> +             igt_assert_eq(wait.wait.first_signaled, first_signaled);
> +     }
> +
> +     for (i = 0; i < 8; i++) {
> +             close(timelines[i]);
> +             syncobj_destroy(fd, syncobjs[i]);
> +     }
> +}
> +
> +static void
> +test_wait_interrupted(int fd, uint32_t test_flags)
> +{
> +     struct drm_syncobj_timeline_wait wait = { 0 };
> +     uint32_t syncobj = syncobj_create(fd, 0);
> +     uint64_t point = 1;
> +     int timeline;
> +
> +     wait.handles = to_user_pointer(&syncobj);
> +     wait.points = to_user_pointer(&point);
> +     wait.count_handles = 1;
> +     wait.flags = flags_for_test_flags(test_flags);
> +
> +     if (test_flags & WAIT_FOR_SUBMIT) {
> +             wait.timeout_nsec = short_timeout();
> +             igt_while_interruptible(true)
> +                     igt_assert_eq(__syncobj_timeline_wait_ioctl(fd, &wait), 
> -ETIME);
> +     }
> +
> +     timeline = syncobj_attach_sw_sync(fd, syncobj, point);
> +
> +     wait.timeout_nsec = short_timeout();
> +     igt_while_interruptible(true)
> +             igt_assert_eq(__syncobj_timeline_wait_ioctl(fd, &wait), -ETIME);
> +
> +     syncobj_destroy(fd, syncobj);
> +     close(timeline);
> +}
> +
> +static bool
> +has_syncobj_timeline_wait(int fd)
> +{
> +     struct drm_syncobj_timeline_wait wait = { 0 };
> +     uint32_t handle = 0;
> +     uint64_t value;
> +     int ret;
> +
> +     if (drmGetCap(fd, DRM_CAP_SYNCOBJ, &value))
> +             return false;
> +     if (!value)
> +             return false;
> +
> +     /* Try waiting for zero sync objects should fail with EINVAL */
> +     wait.count_handles = 1;
> +     wait.handles = to_user_pointer(&handle);
> +     ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &wait);
> +     return ret == -1 && errno == ENOENT;
> +}
> +
> +igt_main
> +{
> +     int fd = -1;
> +
> +     igt_fixture {
> +             fd = drm_open_driver(DRIVER_ANY);
> +             igt_require(has_syncobj_timeline_wait(fd));
> +             igt_require_sw_sync();
> +     }
> +
> +     igt_subtest("invalid-wait-bad-flags")
> +             test_wait_bad_flags(fd);
> +
> +     igt_subtest("invalid-wait-zero-handles")
> +             test_wait_zero_handles(fd);
> +
> +     igt_subtest("invalid-wait-illegal-handle")
> +             test_wait_illegal_handle(fd);
> +
> +     igt_subtest("invalid-query-zero-handles")
> +             test_query_zero_handles(fd);
> +
> +     igt_subtest("invalid-query-illegal-handle")
> +             test_query_illegal_handle(fd);
> +
> +     igt_subtest("invalid-query-one-illegal-handle")
> +             test_query_one_illegal_handle(fd);
> +
> +     igt_subtest("invalid-query-bad-pad")
> +             test_query_bad_pad(fd);
> +
> +     igt_subtest("invalid-signal-zero-handles")
> +             test_signal_zero_handles(fd);
> +
> +     igt_subtest("invalid-signal-illegal-handle")
> +             test_signal_illegal_handle(fd);
> +
> +     igt_subtest("invalid-signal-illegal-point")
> +             test_signal_illegal_point(fd);
> +
> +     igt_subtest("invalid-signal-one-illegal-handle")
> +             test_signal_one_illegal_handle(fd);
> +
> +     igt_subtest("invalid-signal-bad-pad")
> +             test_signal_bad_pad(fd);
> +
> +     igt_subtest("invalid-signal-array")
> +             test_signal_array(fd);
> +
> +     igt_subtest("invalid-transfer-illegal-handle")
> +             test_transfer_illegal_handle(fd);
> +
> +     igt_subtest("invalid-transfer-bad-pad")
> +             test_transfer_bad_pad(fd);
> +
> +     for (unsigned flags = 0; flags < WAIT_FLAGS_MAX; flags++) {
> +             int err;
> +
> +             /* Only one wait mode for single-wait tests */
> +             if (__builtin_popcount(flags & (WAIT_UNSUBMITTED |
> +                                             WAIT_SUBMITTED |
> +                                             WAIT_SIGNALED)) != 1)
> +                     continue;
> +
> +             if ((flags & WAIT_UNSUBMITTED) && !(flags & WAIT_FOR_SUBMIT))
> +                     err = -EINVAL;
> +             else if (!(flags & WAIT_SIGNALED) && !((flags & WAIT_SUBMITTED) 
> && (flags & WAIT_AVAILABLE)))
> +                     err = -ETIME;
> +             else
> +                     err = 0;
> +
> +             igt_subtest_f("%ssingle-wait%s%s%s%s%s%s",
> +                           err == -EINVAL ? "invalid-" : err == -ETIME ? 
> "etime-" : "",
> +                           (flags & WAIT_ALL) ? "-all" : "",
> +                           (flags & WAIT_FOR_SUBMIT) ? "-for-submit" : "",
> +                           (flags & WAIT_AVAILABLE) ? "-available" : "",
> +                           (flags & WAIT_UNSUBMITTED) ? "-unsubmitted" : "",
> +                           (flags & WAIT_SUBMITTED) ? "-submitted" : "",
> +                           (flags & WAIT_SIGNALED) ? "-signaled" : "")
> +                     test_single_wait(fd, flags, err);
> +     }
> +
> +     igt_subtest("wait-delayed-signal")
> +             test_wait_delayed_signal(fd, 0);
> +
> +     igt_subtest("wait-for-submit-delayed-submit")
> +             test_wait_delayed_signal(fd, WAIT_FOR_SUBMIT);
> +
> +     igt_subtest("wait-all-delayed-signal")
> +             test_wait_delayed_signal(fd, WAIT_ALL);
> +
> +     igt_subtest("wait-all-for-submit-delayed-submit")
> +             test_wait_delayed_signal(fd, WAIT_ALL | WAIT_FOR_SUBMIT);
> +
> +     igt_subtest("reset-unsignaled")
> +             test_reset_unsignaled(fd);
> +
> +     igt_subtest("reset-signaled")
> +             test_reset_signaled(fd);
> +
> +     igt_subtest("reset-multiple-signaled")
> +             test_reset_multiple_signaled(fd);
> +
> +     igt_subtest("reset-during-wait-for-submit")
> +             test_reset_during_wait_for_submit(fd);
> +
> +     igt_subtest("signal")
> +             test_signal(fd);
> +
> +     for (unsigned flags = 0; flags < WAIT_FLAGS_MAX; flags++) {
> +             int err;
> +
> +             /* At least one wait mode for multi-wait tests */
> +             if (!(flags & (WAIT_UNSUBMITTED |
> +                            WAIT_SUBMITTED |
> +                            WAIT_SIGNALED)))
> +                     continue;
> +
> +             err = 0;
> +             if ((flags & WAIT_UNSUBMITTED) && !(flags & WAIT_FOR_SUBMIT)) {
> +                     err = -EINVAL;
> +             } else if (flags & WAIT_ALL) {
> +                     if (flags & (WAIT_UNSUBMITTED | WAIT_SUBMITTED))
> +                             err = -ETIME;
> +                     if (!(flags & WAIT_UNSUBMITTED) && (flags & 
> WAIT_SUBMITTED) && (flags & WAIT_AVAILABLE))
> +                             err = 0;
> +             } else {
> +                     if (!(flags & WAIT_SIGNALED) && !((flags & 
> WAIT_SUBMITTED) && (flags & WAIT_AVAILABLE)))
> +                             err = -ETIME;
> +             }
> +
> +             igt_subtest_f("%smulti-wait%s%s%s%s%s%s",
> +                           err == -EINVAL ? "invalid-" : err == -ETIME ? 
> "etime-" : "",
> +                           (flags & WAIT_ALL) ? "-all" : "",
> +                           (flags & WAIT_FOR_SUBMIT) ? "-for-submit" : "",
> +                           (flags & WAIT_AVAILABLE) ? "-available" : "",
> +                           (flags & WAIT_UNSUBMITTED) ? "-unsubmitted" : "",
> +                           (flags & WAIT_SUBMITTED) ? "-submitted" : "",
> +                           (flags & WAIT_SIGNALED) ? "-signaled" : "")
> +                     test_multi_wait(fd, flags, err);
> +     }
> +     igt_subtest("wait-any-snapshot")
> +             test_wait_snapshot(fd, 0);
> +
> +     igt_subtest("wait-all-snapshot")
> +             test_wait_snapshot(fd, WAIT_ALL);
> +
> +     igt_subtest("wait-for-submit-snapshot")
> +             test_wait_snapshot(fd, WAIT_FOR_SUBMIT);
> +
> +     igt_subtest("wait-all-for-submit-snapshot")
> +             test_wait_snapshot(fd, WAIT_ALL | WAIT_FOR_SUBMIT);
> +
> +     igt_subtest("wait-any-complex")
> +             test_wait_complex(fd, 0);
> +
> +     igt_subtest("wait-all-complex")
> +             test_wait_complex(fd, WAIT_ALL);
> +
> +     igt_subtest("wait-for-submit-complex")
> +             test_wait_complex(fd, WAIT_FOR_SUBMIT);
> +
> +     igt_subtest("wait-all-for-submit-complex")
> +             test_wait_complex(fd, WAIT_ALL | WAIT_FOR_SUBMIT);
> +
> +     igt_subtest("wait-any-interrupted")
> +             test_wait_interrupted(fd, 0);
> +
> +     igt_subtest("wait-all-interrupted")
> +             test_wait_interrupted(fd, WAIT_ALL);
> +}
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to