All of lore.kernel.org
 help / color / mirror / Atom feed
From: Petri Latvala <petri.latvala@intel.com>
To: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Cc: igt-dev@lists.freedesktop.org, Chunming Zhou <david1.zhou@amd.com>
Subject: Re: [igt-dev] [PATCH i-g-t 03/10] igt: add timeline test cases
Date: Thu, 21 Nov 2019 16:07:59 +0200	[thread overview]
Message-ID: <20191121140759.GH25209@platvala-desk.ger.corp.intel.com> (raw)
In-Reply-To: <20191120212143.364333-4-lionel.g.landwerlin@intel.com>

On Wed, Nov 20, 2019 at 11:21:36PM +0200, Lionel Landwerlin wrote:
> From: Chunming Zhou <david1.zhou@amd.com>
> 
> v2: adapt to new transfer ioctl
> 
> v3: Drop useless uint64_t casts (Lionel)
>     Fix timeline query prototypes (Lionel)
>     Test multi wait with timeline & binary syncobjs (Lionel)
> 
> v4: Switch from drmIoctl to igt_ioctl in tests/*.c (Chris)
>     Clear out errno in helper functions (Chris)
> 
> v5: Fix lib comments on transfer helpers (Lionel)
> 
> v6: Add igt_describe() (Lionel)
> 
> Signed-off-by: Chunming Zhou <david1.zhou@amd.com>
> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
> ---
>  lib/igt_syncobj.c        |  237 ++++++++
>  lib/igt_syncobj.h        |   19 +
>  tests/meson.build        |    1 +

Corresponding autotools change missing.


-- 
Petri Latvala



>  tests/syncobj_timeline.c | 1150 ++++++++++++++++++++++++++++++++++++++
>  4 files changed, 1407 insertions(+)
>  create mode 100644 tests/syncobj_timeline.c
> 
> diff --git a/lib/igt_syncobj.c b/lib/igt_syncobj.c
> index e5569ffc..632a5182 100644
> --- a/lib/igt_syncobj.c
> +++ b/lib/igt_syncobj.c
> @@ -286,3 +286,240 @@ 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;
> +		igt_assume(err);
> +	}
> +	errno = 0;
> +	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;
> +		igt_assume(err);
> +	}
> +	errno = 0;
> +	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 = 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) {
> +		ret = -errno;
> +		igt_assume(ret);
> +	}
> +	errno = 0;
> +
> +	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 = to_user_pointer(points);
> +	args.count_handles = handle_count;
> +	args.flags = 0;
> +
> +	ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
> +	if (ret) {
> +		ret = -errno;
> +		igt_assume(ret);
> +	}
> +
> +	errno = 0;
> +	return ret;
> +}
> +
> +/**
> + * syncobj_timeline_query:
> + * @fd: The DRM file descriptor.
> + * @handles: Array of syncobj handles.
> + * @points: Array of syncobj points queried.
> + * @count: Count of syncobj handles.
> + *
> + * Queries 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;
> +	int ret;
> +
> +	args.src_handle = binary_handle;
> +	args.dst_handle = timeline_handle;
> +	args.src_point = 0;
> +	args.dst_point = point;
> +	args.flags = 0;
> +	args.pad = 0;
> +	ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args);
> +	if (ret) {
> +		ret = -errno;
> +		igt_assert(ret);
> +	}
> +
> +	errno = 0;
> +	return ret;
> +}
> +
> +/**
> + * syncobj_binary_to_timeline:
> + * @fd: The DRM file descriptor.
> + * @timeline_handle: A syncobj timeline handle
> + * @point: A syncobj timeline point in the timeline handle
> + * @binary_handle: A syncobj binary handle
> + *
> + * Transfers a DMA fence from a binary syncobj into a timeline syncobj
> + * at a given point on the timeline.
> + */
> +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;
> +	int ret;
> +
> +	args.dst_handle = binary_handle;
> +	args.src_handle = timeline_handle;
> +	args.dst_point = 0;
> +	args.src_point = point;
> +	args.flags = flags;
> +	args.pad = 0;
> +	ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args);
> +	if (ret) {
> +		ret = -errno;
> +		igt_assert(ret);
> +	}
> +
> +	errno = 0;
> +	return ret;
> +}
> +
> +/**
> + * syncobj_binary_to_timeline:
> + * @fd: The DRM file descriptor.
> + * @binary_handle: A syncobj binary handle
> + * @timeline_handle: A syncobj timeline handle
> + * @point: A syncobj timeline point in the timeline handle
> + *
> + * Transfers DMA fence from a given point from timeline syncobj into a
> + * binary syncobj.
> + */
> +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 51ad2364..20f1f18f 100644
> --- a/lib/igt_syncobj.h
> +++ b/lib/igt_syncobj.h
> @@ -41,7 +41,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 755fc9e6..7ed4140b 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -82,6 +82,7 @@ test_progs = [
>  	'prime_vgem',
>  	'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..82fc08aa
> --- /dev/null
> +++ b/tests/syncobj_timeline.c
> @@ -0,0 +1,1150 @@
> +/*
> + * 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)
> +{
> +	int timeline, fence;
> +
> +	timeline = sw_sync_timeline_create();
> +	fence = sw_sync_timeline_create_fence(timeline, 1);
> +
> +	if (point == 0) {
> +		syncobj_import_sync_file(fd, handle, fence);
> +	} else {
> +		uint32_t syncobj = syncobj_create(fd, 0);
> +
> +		syncobj_import_sync_file(fd, syncobj, fence);
> +		syncobj_binary_to_timeline(fd, handle, point, syncobj);
> +		syncobj_destroy(fd, syncobj);
> +	}
> +
> +	close(fence);
> +
> +	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 = point;
> +
> +	return set_timer(syncobj_trigger_free_pair_func, pair, 0, nsec);
> +}
> +
> +static const char *test_wait_bad_flags_desc =
> +	"Verifies that an invalid value in drm_syncobj_timeline_wait::flags is"
> +	" rejected";
> +static void
> +test_wait_bad_flags(int fd)
> +{
> +	struct drm_syncobj_timeline_wait wait = {};
> +	wait.flags = 0xdeadbeef;
> +	igt_assert_eq(__syncobj_timeline_wait_ioctl(fd, &wait), -EINVAL);
> +}
> +
> +static const char *test_wait_zero_handles_desc =
> +	"Verifies that waiting on an empty list of invalid syncobj handles is"
> +	" rejected";
> +static void
> +test_wait_zero_handles(int fd)
> +{
> +	struct drm_syncobj_timeline_wait wait = {};
> +	igt_assert_eq(__syncobj_timeline_wait_ioctl(fd, &wait), -EINVAL);
> +}
> +
> +static const char *test_wait_illegal_handle_desc =
> +	"Verifies that waiting on an invalid syncobj handle is rejected";
> +static void
> +test_wait_illegal_handle(int fd)
> +{
> +	struct drm_syncobj_timeline_wait wait = {};
> +	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 const char *test_query_zero_handles_desc =
> +	"Verifies that querying an empty list of syncobj handles is rejected";
> +static void
> +test_query_zero_handles(int fd)
> +{
> +	struct drm_syncobj_timeline_array args = {};
> +	int ret;
> +
> +	ret = igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
> +	igt_assert(ret == -1 && errno ==  EINVAL);
> +}
> +
> +static const char *test_query_illegal_handle_desc =
> +	"Verifies that querying an invalid syncobj handle is rejected";
> +static void
> +test_query_illegal_handle(int fd)
> +{
> +	struct drm_syncobj_timeline_array args = {};
> +	uint32_t handle = 0;
> +	int ret;
> +
> +	args.count_handles = 1;
> +	args.handles = to_user_pointer(&handle);
> +	ret = igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
> +	igt_assert(ret == -1 && errno == ENOENT);
> +}
> +
> +static const char *test_query_one_illegal_handle_desc =
> +	"Verifies that querying a list of invalid syncobj handle including an"
> +	" invalid one is rejected";
> +static void
> +test_query_one_illegal_handle(int fd)
> +{
> +	struct drm_syncobj_timeline_array array = {};
> +	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 = igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &array);
> +	igt_assert(ret == -1 && errno == ENOENT);
> +
> +	syncobj_destroy(fd, syncobjs[0]);
> +	syncobj_destroy(fd, syncobjs[2]);
> +}
> +
> +static const char *test_query_bad_pad_desc =
> +	"Verify that querying a timeline syncobj with an invalid"
> +	" drm_syncobj_timeline_array::flags field is rejected";
> +static void
> +test_query_bad_pad(int fd)
> +{
> +	struct drm_syncobj_timeline_array array = {};
> +	uint32_t handle = 0;
> +	int ret;
> +
> +	array.flags = 0xdeadbeef;
> +	array.count_handles = 1;
> +	array.handles = to_user_pointer(&handle);
> +	ret = igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &array);
> +	igt_assert(ret == -1 && errno == EINVAL);
> +}
> +
> +static const char *test_signal_zero_handles_desc =
> +	"Verify that signaling an empty list of syncobj handles is rejected";
> +static void
> +test_signal_zero_handles(int fd)
> +{
> +	struct drm_syncobj_timeline_array args = {};
> +	int ret;
> +
> +	ret = igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args);
> +	igt_assert(ret == -1 && errno ==  EINVAL);
> +}
> +
> +static const char *test_signal_illegal_handle_desc =
> +	"Verify that signaling an invalid syncobj handle is rejected";
> +static void
> +test_signal_illegal_handle(int fd)
> +{
> +	struct drm_syncobj_timeline_array args = {};
> +	uint32_t handle = 0;
> +	int ret;
> +
> +	args.count_handles = 1;
> +	args.handles = to_user_pointer(&handle);
> +	ret = igt_ioctl(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 = {};
> +	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 = igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args);
> +	igt_assert(ret == -1 && errno == ENOENT);
> +}
> +
> +static const char *test_signal_one_illegal_handle_desc =
> +	"Verify that an invalid syncobj handle in drm_syncobj_timeline_array is"
> +	" rejected for signaling";
> +static void
> +test_signal_one_illegal_handle(int fd)
> +{
> +	struct drm_syncobj_timeline_array array = {};
> +	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 = igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &array);
> +	igt_assert(ret == -1 && errno == ENOENT);
> +
> +	syncobj_destroy(fd, syncobjs[0]);
> +	syncobj_destroy(fd, syncobjs[2]);
> +}
> +
> +static const char *test_signal_bad_pad_desc =
> +	"Verifies that an invalid value in drm_syncobj_timeline_array.flags is"
> +	" rejected";
> +static void
> +test_signal_bad_pad(int fd)
> +{
> +	struct drm_syncobj_timeline_array array = {};
> +	uint32_t handle = 0;
> +	int ret;
> +
> +	array.flags = 0xdeadbeef;
> +	array.count_handles = 1;
> +	array.handles = to_user_pointer(&handle);
> +	ret = igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &array);
> +	igt_assert(ret == -1 && errno == EINVAL);
> +}
> +
> +static const char *test_signal_array_desc =
> +	"Verifies the signaling of a list of timeline syncobj";
> +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 const char *test_transfer_illegal_handle_desc =
> +	"Verifies that an invalid syncobj handle is rejected in"
> +	" drm_syncobj_transfer";
> +static void
> +test_transfer_illegal_handle(int fd)
> +{
> +	struct drm_syncobj_transfer args = {};
> +	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 = igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args);
> +	igt_assert(ret == -1 && errno == ENOENT);
> +}
> +
> +static const char *test_transfer_bad_pad_desc =
> +	"Verifies that invalid drm_syncobj_transfer::pad field value is"
> +	" rejected";
> +static void
> +test_transfer_bad_pad(int fd)
> +{
> +	struct drm_syncobj_transfer arg = {};
> +	uint32_t handle = 0;
> +	int ret;
> +
> +	arg.pad = 0xdeadbeef;
> +	arg.src_handle = to_user_pointer(&handle);
> +	arg.dst_handle = to_user_pointer(&handle);
> +	ret = igt_ioctl(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 const char *test_signal_wait_desc =
> +	"Verifies wait behavior on a single timeline syncobj";
> +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 const char *test_wait_delayed_signal_desc =
> +	"Verifies wait behavior on a timeline syncobj with a delayed signal"
> +	" from a different thread";
> +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 const char *test_reset_unsignaled_desc =
> +	"Verifies behavior of a reset operation on an unsignaled timeline"
> +	" 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 const char *test_reset_signaled_desc =
> +	"Verifies behavior of a reset operation on a signaled timeline 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 const char *test_reset_multiple_signaled_desc =
> +	"Verifies behavior of a reset operation on a list of signaled timeline"
> +	" syncobjs";
> +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 const char *test_reset_during_wait_for_submit_desc =
> +	"Verifies behavior of a reset operation a timeline syncobj while wait"
> +	" operation is ongoing";
> +static void
> +test_reset_during_wait_for_submit(int fd)
> +{
> +	uint32_t syncobj = syncobj_create(fd, 0);
> +	uint32_t flags = DRM_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 const char *test_signal_desc =
> +	"Verifies basic signaling of a timeline syncobj";
> +static void
> +test_signal(int fd)
> +{
> +	uint32_t syncobj = syncobj_create(fd, 0);
> +	uint32_t flags = DRM_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 const char *test_multi_wait_desc =
> +	"Verifies waiting on a list of timeline syncobjs";
> +static void
> +test_multi_wait(int fd, uint32_t test_flags, int expect)
> +{
> +	uint32_t tflag, flags;
> +	int i, fidx, timeline;
> +	uint64_t points[5] = {
> +		1 + rand() % 1000,
> +		0, /* non timeline syncobj */
> +		1 + rand() % 1000,
> +		1 + rand() % 1000,
> +		0, /* non timeline syncobj */
> +	};
> +	uint32_t syncobjs[ARRAY_SIZE(points)];
> +
> +	for (i = 0; i < ARRAY_SIZE(points); i++)
> +		syncobjs[i] = syncobj_create(fd, 0);
> +
> +	flags = flags_for_test_flags(test_flags);
> +	test_flags &= ~(WAIT_ALL | WAIT_FOR_SUBMIT | WAIT_AVAILABLE);
> +
> +	for (i = 0; i < ARRAY_SIZE(points); 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, ARRAY_SIZE(points),
> +						0, flags), expect);
> +
> +	igt_assert_eq(syncobj_timeline_wait_err(fd, syncobjs,
> +						points, ARRAY_SIZE(points),
> +						short_timeout(),
> +						flags), expect);
> +
> +	if (expect != -ETIME) {
> +		igt_assert_eq(syncobj_timeline_wait_err(fd, syncobjs,
> +							points, ARRAY_SIZE(points),
> +							UINT64_MAX,
> +							flags), expect);
> +	}
> +
> +	for (i = 0; i < ARRAY_SIZE(points); i++)
> +		syncobj_destroy(fd, syncobjs[i]);
> +}
> +
> +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 const char *test_wait_snapshot_desc =
> +	"Verifies waiting on a list of timeline syncobjs with different thread"
> +	" for wait/signal";
> +static void
> +test_wait_snapshot(int fd, uint32_t test_flags)
> +{
> +	struct wait_thread_data wait = {};
> +	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 const char *test_wait_complex_desc =
> +	"Verifies timeline syncobj at different signal/operations stages &"
> +	" between different threads.";
> +static void
> +test_wait_complex(int fd, uint32_t test_flags)
> +{
> +	struct wait_thread_data wait = {};
> +	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 const char *test_wait_interrupted_desc =
> +	"Verifies timeline syncobj waits interaction with signals.";
> +static void
> +test_wait_interrupted(int fd, uint32_t test_flags)
> +{
> +	struct drm_syncobj_timeline_wait wait = {};
> +	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 = {};
> +	uint32_t handle = 0;
> +	uint64_t value;
> +	int ret;
> +
> +	if (drmGetCap(fd, DRM_CAP_SYNCOBJ_TIMELINE, &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 = igt_ioctl(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_describe(test_wait_bad_flags_desc);
> +	igt_subtest("invalid-wait-bad-flags")
> +		test_wait_bad_flags(fd);
> +
> +	igt_describe(test_wait_zero_handles_desc);
> +	igt_subtest("invalid-wait-zero-handles")
> +		test_wait_zero_handles(fd);
> +
> +	igt_describe(test_wait_illegal_handle_desc);
> +	igt_subtest("invalid-wait-illegal-handle")
> +		test_wait_illegal_handle(fd);
> +
> +	igt_describe(test_query_zero_handles_desc);
> +	igt_subtest("invalid-query-zero-handles")
> +		test_query_zero_handles(fd);
> +
> +	igt_describe(test_query_illegal_handle_desc);
> +	igt_subtest("invalid-query-illegal-handle")
> +		test_query_illegal_handle(fd);
> +
> +	igt_describe(test_query_one_illegal_handle_desc);
> +	igt_subtest("invalid-query-one-illegal-handle")
> +		test_query_one_illegal_handle(fd);
> +
> +	igt_describe(test_query_bad_pad_desc);
> +	igt_subtest("invalid-query-bad-pad")
> +		test_query_bad_pad(fd);
> +
> +	igt_describe(test_signal_zero_handles_desc);
> +	igt_subtest("invalid-signal-zero-handles")
> +		test_signal_zero_handles(fd);
> +
> +	igt_describe(test_signal_illegal_handle_desc);
> +	igt_subtest("invalid-signal-illegal-handle")
> +		test_signal_illegal_handle(fd);
> +
> +	igt_subtest("invalid-signal-illegal-point")
> +		test_signal_illegal_point(fd);
> +
> +	igt_describe(test_signal_one_illegal_handle_desc);
> +	igt_subtest("invalid-signal-one-illegal-handle")
> +		test_signal_one_illegal_handle(fd);
> +
> +	igt_describe(test_signal_bad_pad_desc);
> +	igt_subtest("invalid-signal-bad-pad")
> +		test_signal_bad_pad(fd);
> +
> +	igt_describe(test_signal_array_desc);
> +	igt_subtest("signal-array")
> +		test_signal_array(fd);
> +
> +	igt_describe(test_transfer_illegal_handle_desc);
> +	igt_subtest("invalid-transfer-illegal-handle")
> +		test_transfer_illegal_handle(fd);
> +
> +	igt_describe(test_transfer_bad_pad_desc);
> +	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_describe(test_signal_wait_desc);
> +		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_describe(test_wait_delayed_signal_desc);
> +	igt_subtest("wait-delayed-signal")
> +		test_wait_delayed_signal(fd, 0);
> +
> +	igt_describe(test_wait_delayed_signal_desc);
> +	igt_subtest("wait-for-submit-delayed-submit")
> +		test_wait_delayed_signal(fd, WAIT_FOR_SUBMIT);
> +
> +	igt_describe(test_wait_delayed_signal_desc);
> +	igt_subtest("wait-all-delayed-signal")
> +		test_wait_delayed_signal(fd, WAIT_ALL);
> +
> +	igt_describe(test_wait_delayed_signal_desc);
> +	igt_subtest("wait-all-for-submit-delayed-submit")
> +		test_wait_delayed_signal(fd, WAIT_ALL | WAIT_FOR_SUBMIT);
> +
> +	igt_describe(test_reset_unsignaled_desc);
> +	igt_subtest("reset-unsignaled")
> +		test_reset_unsignaled(fd);
> +
> +	igt_describe(test_reset_signaled_desc);
> +	igt_subtest("reset-signaled")
> +		test_reset_signaled(fd);
> +
> +	igt_describe(test_reset_multiple_signaled_desc);
> +	igt_subtest("reset-multiple-signaled")
> +		test_reset_multiple_signaled(fd);
> +
> +	igt_describe(test_reset_during_wait_for_submit_desc);
> +	igt_subtest("reset-during-wait-for-submit")
> +		test_reset_during_wait_for_submit(fd);
> +
> +	igt_describe(test_signal_desc);
> +	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_describe(test_multi_wait_desc);
> +		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_describe(test_wait_snapshot_desc);
> +	igt_subtest("wait-any-snapshot")
> +		test_wait_snapshot(fd, 0);
> +
> +	igt_describe(test_wait_snapshot_desc);
> +	igt_subtest("wait-all-snapshot")
> +		test_wait_snapshot(fd, WAIT_ALL);
> +
> +	igt_describe(test_wait_snapshot_desc);
> +	igt_subtest("wait-for-submit-snapshot")
> +		test_wait_snapshot(fd, WAIT_FOR_SUBMIT);
> +
> +	igt_describe(test_wait_snapshot_desc);
> +	igt_subtest("wait-all-for-submit-snapshot")
> +		test_wait_snapshot(fd, WAIT_ALL | WAIT_FOR_SUBMIT);
> +
> +	igt_describe(test_wait_complex_desc);
> +	igt_subtest("wait-any-complex")
> +		test_wait_complex(fd, 0);
> +
> +	igt_describe(test_wait_complex_desc);
> +	igt_subtest("wait-all-complex")
> +		test_wait_complex(fd, WAIT_ALL);
> +
> +	igt_describe(test_wait_complex_desc);
> +	igt_subtest("wait-for-submit-complex")
> +		test_wait_complex(fd, WAIT_FOR_SUBMIT);
> +
> +	igt_describe(test_wait_complex_desc);
> +	igt_subtest("wait-all-for-submit-complex")
> +		test_wait_complex(fd, WAIT_ALL | WAIT_FOR_SUBMIT);
> +
> +	igt_describe(test_wait_interrupted_desc);
> +	igt_subtest("wait-any-interrupted")
> +		test_wait_interrupted(fd, 0);
> +
> +	igt_describe(test_wait_interrupted_desc);
> +	igt_subtest("wait-all-interrupted")
> +		test_wait_interrupted(fd, WAIT_ALL);
> +}
> -- 
> 2.24.0
> 

> _______________________________________________
> igt-dev mailing list
> igt-dev@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/igt-dev

_______________________________________________
igt-dev mailing list
igt-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/igt-dev

  parent reply	other threads:[~2019-11-21 14:08 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-11-20 21:21 [igt-dev] [PATCH i-g-t 00/10] tests: Add timeline syncobj testing Lionel Landwerlin
2019-11-20 21:21 ` [igt-dev] [PATCH i-g-t 01/10] lib/syncobj: drop local declarations Lionel Landwerlin
2019-11-20 21:49   ` Chris Wilson
2019-11-20 21:21 ` [igt-dev] [PATCH i-g-t 02/10] drm-uapi: Update drm headers to 17cc51390c141662748dbbc2fe98f3ed10f2e13e Lionel Landwerlin
2019-11-20 21:50   ` Chris Wilson
2019-11-21 11:10     ` Lionel Landwerlin
2019-11-20 21:21 ` [igt-dev] [PATCH i-g-t 05/10] tests/i915/exec_fence: switch to internal headers Lionel Landwerlin
2019-11-20 21:51   ` Chris Wilson
2019-11-20 21:21 ` [igt-dev] [PATCH i-g-t 06/10] tests/i915/exec_fence: reuse syncobj helpers Lionel Landwerlin
2019-11-20 21:52   ` Chris Wilson
2019-11-20 21:21 ` [igt-dev] [PATCH i-g-t 07/10] include: bump drm headers for i915 timeline semaphores Lionel Landwerlin
2019-11-20 21:21 ` [igt-dev] [PATCH i-g-t 08/10] tests/i915/exec_fence: add timeline fence tests Lionel Landwerlin
2019-11-20 21:40   ` Chris Wilson
2019-11-20 21:21 ` [igt-dev] [PATCH i-g-t 09/10] lib/i915: add mmio base for engines Lionel Landwerlin
2019-11-20 21:42   ` Chris Wilson
2019-11-21 13:15     ` Lionel Landwerlin
2019-11-20 21:21 ` [igt-dev] [PATCH i-g-t 10/10] tests/i915/gem_exec_fence: add engine chaining tests Lionel Landwerlin
2019-11-20 22:02   ` Chris Wilson
     [not found] ` <20191120212143.364333-5-lionel.g.landwerlin@intel.com>
2019-11-20 21:33   ` [igt-dev] [PATCH i-g-t 04/10] tests/syncobj_timeline: add more timeline tests Chris Wilson
2019-11-20 23:02 ` [igt-dev] ✗ GitLab.Pipeline: warning for tests: Add timeline syncobj testing Patchwork
2019-11-20 23:42 ` [igt-dev] ✓ Fi.CI.BAT: success " Patchwork
     [not found] ` <20191120212143.364333-4-lionel.g.landwerlin@intel.com>
2019-11-21 14:07   ` Petri Latvala [this message]
2019-11-22 13:03     ` [igt-dev] [PATCH i-g-t 03/10] igt: add timeline test cases Lionel Landwerlin
2019-11-21 22:16 ` [igt-dev] ✓ Fi.CI.IGT: success for tests: Add timeline syncobj testing Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191121140759.GH25209@platvala-desk.ger.corp.intel.com \
    --to=petri.latvala@intel.com \
    --cc=david1.zhou@amd.com \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=lionel.g.landwerlin@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.