From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from NAM11-BN8-obe.outbound.protection.outlook.com (mail-bn8nam11on2040.outbound.protection.outlook.com [40.107.236.40]) by gabe.freedesktop.org (Postfix) with ESMTPS id E856910E045 for ; Wed, 26 Jul 2023 17:57:09 +0000 (UTC) Message-ID: <26f9a6a1-abd3-eff0-893c-2cbb214154c1@nvidia.com> Date: Wed, 26 Jul 2023 10:56:58 -0700 Content-Language: en-US To: igt-dev@lists.freedesktop.org From: Erik Kurzinger Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MIME-Version: 1.0 Subject: [igt-dev] [PATCH v2] tests/syncobj_sync_file: new test List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Simon Ser , Austin Shafer , James Jones Errors-To: igt-dev-bounces@lists.freedesktop.org Sender: "igt-dev" List-ID: This test suite exercises the new DRM_IOCTL_IMPORT/EXPORT_SYNC_FILE ioctl introduced in [1]. [1] https://lore.kernel.org/dri-devel/5e687ad8-78ad-0350-6052-a698b278cc8c@nvidia.com/ V1 -> V2: * added "v2" to new libigt functions to differentiate them from existing ones * added convenience functions to wrap the raw import/export ioctls * fixed error codes in invalid handle tests, ENOENT instead of EINVAL * used 0 instead of 0xffffffff as invalid handle in requirement check Signed-off-by: Erik Kurzinger --- include/drm-uapi/drm.h | 11 ++ lib/igt_syncobj.c | 64 ++++++++++ lib/igt_syncobj.h | 5 + tests/meson.build | 1 + tests/syncobj_sync_file.c | 242 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 323 insertions(+) create mode 100644 tests/syncobj_sync_file.c diff --git a/include/drm-uapi/drm.h b/include/drm-uapi/drm.h index 5e54c3aa4..389dc138a 100644 --- a/include/drm-uapi/drm.h +++ b/include/drm-uapi/drm.h @@ -878,6 +878,12 @@ struct drm_syncobj_transfer { __u32 pad; }; +struct drm_syncobj_sync_file { + __u32 handle; + __u32 fd; + __u64 point; +}; + #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0) #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1) #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2) /* wait for time point to become available */ @@ -1090,8 +1096,13 @@ extern "C" { #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) + + #define DRM_IOCTL_MODE_GETFB2 DRM_IOWR(0xCE, struct drm_mode_fb_cmd2) +#define DRM_IOCTL_SYNCOBJ_IMPORT_SYNC_FILE DRM_IOWR(0xD0, struct drm_syncobj_sync_file) +#define DRM_IOCTL_SYNCOBJ_EXPORT_SYNC_FILE DRM_IOWR(0xD1, struct drm_syncobj_sync_file) + /* * Device specific ioctls should only be in their respective headers * The device specific ioctl range is from 0x40 to 0x9f. diff --git a/lib/igt_syncobj.c b/lib/igt_syncobj.c index a24ed10b7..ee7d01ad0 100644 --- a/lib/igt_syncobj.c +++ b/lib/igt_syncobj.c @@ -181,6 +181,70 @@ syncobj_import_sync_file(int fd, uint32_t handle, int sync_file) igt_assert_eq(__syncobj_fd_to_handle(fd, &args), 0); } +int +__syncobj_import_sync_file_v2(int fd, struct drm_syncobj_sync_file *args) +{ + int err = 0; + if (igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_IMPORT_SYNC_FILE, args)) { + err = -errno; + igt_assume(err); + errno = 0; + } + return err; +} + +/** + * syncobj_import_sync_file_v2: + * @fd: The DRM file descriptor + * @handle: The handle of the syncobj to import into + * @sync_file: The sync_file FD to import + * @point: The timeline point to import into + * + * Import a sync_file fd into a syncobj at a given timeline point + */ +void +syncobj_import_sync_file_v2(int fd, uint32_t handle, + int sync_file, uint64_t point) +{ + struct drm_syncobj_sync_file args = { 0 }; + args.handle = handle; + args.point = point; + args.fd = sync_file; + igt_assert_eq(__syncobj_import_sync_file_v2(fd, &args), 0); +} + +int +__syncobj_export_sync_file_v2(int fd, struct drm_syncobj_sync_file *args) +{ + int err = 0; + if (igt_ioctl(fd, DRM_IOCTL_SYNCOBJ_EXPORT_SYNC_FILE, args)) { + err = -errno; + igt_assume(err); + errno = 0; + } + return err; +} + +/** + * syncobj_export_sync_file_v2: + * @fd: The DRM file descriptor + * @handle: The handle to the syncobj to export from + * @point: The timeline point to export from + * + * Export a sync_file FD from a syncobj at a given timeline point + * Returns: The exported sync_file FD + */ +int +syncobj_export_sync_file_v2(int fd, uint32_t handle, uint64_t point) +{ + struct drm_syncobj_sync_file args = { 0 }; + args.handle = handle; + args.point = point; + args.fd = -1; + igt_assert_eq(__syncobj_export_sync_file_v2(fd, &args), 0); + return args.fd; +} + int __syncobj_wait(int fd, struct drm_syncobj_wait *args) { diff --git a/lib/igt_syncobj.h b/lib/igt_syncobj.h index e6725671d..207fd2142 100644 --- a/lib/igt_syncobj.h +++ b/lib/igt_syncobj.h @@ -35,6 +35,11 @@ int __syncobj_fd_to_handle(int fd, struct drm_syncobj_handle *args); int syncobj_handle_to_fd(int fd, uint32_t handle, uint32_t flags); uint32_t syncobj_fd_to_handle(int fd, int syncobj_fd, uint32_t flags); void syncobj_import_sync_file(int fd, uint32_t handle, int sync_file); +int __syncobj_import_sync_file_v2(int fd, struct drm_syncobj_sync_file *args); +void syncobj_import_sync_file_v2(int fd, uint32_t handle, + int sync_file, uint64_t point); +int __syncobj_export_sync_file_v2(int fd, struct drm_syncobj_sync_file *args); +int syncobj_export_sync_file_v2(int fd, uint32_t handle, uint64_t point); int __syncobj_wait(int fd, struct drm_syncobj_wait *args); int syncobj_wait_err(int fd, uint32_t *handles, uint32_t count, uint64_t abs_timeout_nsec, uint32_t flags); diff --git a/tests/meson.build b/tests/meson.build index 944a0941f..1712c31ca 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -80,6 +80,7 @@ test_progs = [ 'syncobj_basic', 'syncobj_wait', 'syncobj_timeline', + 'syncobj_sync_file', 'sw_sync', 'template', 'testdisplay', diff --git a/tests/syncobj_sync_file.c b/tests/syncobj_sync_file.c new file mode 100644 index 000000000..3a6a8f8a1 --- /dev/null +++ b/tests/syncobj_sync_file.c @@ -0,0 +1,242 @@ +/* + * Copyright © 2023 NVIDIA + * + * 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 "igt_syncobj.h" +#include "sw_sync.h" +#include +#include +#include "drm.h" + +/** + * TEST: syncobj sync file + * Category: Infrastructure + * Description: Tests for DRM syncobj sync file import and export + * Feature: synchronization + * Functionality: semaphore + * Run type: FULL + * Sub-category: DRM + * Test category: GEM_Legacy + * + * SUBTEST: binary-import-export + * Description: Verifies importing and exporting sync files with a binary syncobj. + * + * SUBTEST: timeline-import-export + * Description: Verifies importing and exporting sync files with a timeline syncobj. + * + * SUBTEST: invalid-handle-import + * Description: Verifies that importing a sync file to an invalid syncobj fails. + * + * SUBTEST: invalid-handle-export + * Description: Verifies that exporting a sync file from an invalid syncobj fails. + * + * SUBTEST: invalid-fd-import + * Description: Verifies that importing an invalid sync file fails. + * + * SUBTEST: unsubmitted-export + * Description: Verifies that exporting a sync file for an unsubmitted point fails. + * + */ + +IGT_TEST_DESCRIPTION("Tests for DRM syncobj sync file import and export"); + +const char *test_binary_import_export_desc = + "Verifies importing and exporting a sync file with a binary syncobj."; +static void +test_binary_import_export(int fd) +{ + uint32_t syncobj = syncobj_create(fd, 0); + int timeline = sw_sync_timeline_create(); + int sync_file = sw_sync_timeline_create_fence(timeline, 1); + int exported_sync_file; + + syncobj_import_sync_file_v2(fd, syncobj, sync_file, 0); + close(sync_file); + exported_sync_file = syncobj_export_sync_file_v2(fd, syncobj, 0); + + igt_assert(!syncobj_wait(fd, &syncobj, 1, 0, 0, NULL)); + igt_assert_eq(sync_fence_status(exported_sync_file), 0); + + sw_sync_timeline_inc(timeline, 1); + igt_assert(syncobj_wait(fd, &syncobj, 1, 0, 0, NULL)); + igt_assert_eq(sync_fence_status(exported_sync_file), 1); + + close(exported_sync_file); + close(timeline); + syncobj_destroy(fd, syncobj); +} + +const char *test_timeline_import_export_desc = + "Verifies importing and exporting sync files with a timeline syncobj."; +static void +test_timeline_import_export(int fd) +{ + uint32_t syncobj = syncobj_create(fd, 0); + int timeline = sw_sync_timeline_create(); + int sync_file1 = sw_sync_timeline_create_fence(timeline, 1); + int sync_file2 = sw_sync_timeline_create_fence(timeline, 2); + int exported_sync_file1, exported_sync_file2; + uint64_t point1 = 1, point2 = 2; + + syncobj_import_sync_file_v2(fd, syncobj, sync_file1, point1); + close(sync_file1); + exported_sync_file1 = syncobj_export_sync_file_v2(fd, syncobj, point1); + + syncobj_import_sync_file_v2(fd, syncobj, sync_file2, point2); + close(sync_file2); + exported_sync_file2 = syncobj_export_sync_file_v2(fd, syncobj, point2); + + igt_assert(!syncobj_timeline_wait(fd, &syncobj, &point1, 1, 0, 0, NULL)); + igt_assert_eq(sync_fence_status(exported_sync_file1), 0); + igt_assert(!syncobj_timeline_wait(fd, &syncobj, &point2, 1, 0, 0, NULL)); + igt_assert_eq(sync_fence_status(exported_sync_file2), 0); + + sw_sync_timeline_inc(timeline, 1); + igt_assert(syncobj_timeline_wait(fd, &syncobj, &point1, 1, 0, 0, NULL)); + igt_assert_eq(sync_fence_status(exported_sync_file1), 1); + igt_assert(!syncobj_timeline_wait(fd, &syncobj, &point2, 1, 0, 0, NULL)); + igt_assert_eq(sync_fence_status(exported_sync_file2), 0); + + sw_sync_timeline_inc(timeline, 1); + igt_assert(syncobj_timeline_wait(fd, &syncobj, &point1, 1, 0, 0, NULL)); + igt_assert_eq(sync_fence_status(exported_sync_file1), 1); + igt_assert(syncobj_timeline_wait(fd, &syncobj, &point2, 1, 0, 0, NULL)); + igt_assert_eq(sync_fence_status(exported_sync_file2), 1); + + close(exported_sync_file1); + close(exported_sync_file2); + close(timeline); + syncobj_destroy(fd, syncobj); +} + +const char *test_invalid_handle_import_desc = + "Verifies that importing a sync file to an invalid syncobj fails."; +static void +test_invalid_handle_import(int fd) +{ + struct drm_syncobj_sync_file args = { 0 }; + int timeline = sw_sync_timeline_create(); + + args.fd = sw_sync_timeline_create_fence(timeline, 1); + igt_assert_eq(__syncobj_import_sync_file_v2(fd, &args), -ENOENT); + + close(args.fd); + close(timeline); +} + +const char *test_invalid_handle_export_desc = + "Verifies that exporting a sync file from an invalid syncobj fails."; +static void +test_invalid_handle_export(int fd) +{ + struct drm_syncobj_sync_file args = { 0 }; + + args.fd = -1; + igt_assert_eq(__syncobj_export_sync_file_v2(fd, &args), -ENOENT); +} + +const char *test_invalid_fd_import_desc = + "Verifies that importing an invalid sync file fails."; +static void +test_invalid_fd_import(int fd) +{ + struct drm_syncobj_sync_file args = { 0 }; + + args.handle = syncobj_create(fd, 0); + args.point = 0; + args.fd = -1; + igt_assert_eq(__syncobj_import_sync_file_v2(fd, &args), -EINVAL); + + syncobj_destroy(fd, args.handle); +} + +const char *test_unsubmitted_export_desc = + "Verifies that exporting a sync file for an unsubmitted point fails."; +static void +test_unsubmitted_export(int fd) +{ + struct drm_syncobj_sync_file args = { 0 }; + + args.handle = syncobj_create(fd, 0); + args.point = 0; + args.fd = -1; + igt_assert_eq(__syncobj_export_sync_file_v2(fd, &args), -EINVAL); + + syncobj_destroy(fd, args.handle); +} + +static bool has_syncobj_timeline(int fd) +{ + uint64_t value; + return drmGetCap(fd, DRM_CAP_SYNCOBJ_TIMELINE, + &value) == 0 && value; +} + +static bool has_syncobj_sync_file_import_export(int fd) +{ + struct drm_syncobj_sync_file args = { 0 }; + /* if sync file import/export is supported this will fail with ENOENT, + * otherwise it will fail with EINVAL */ + return __syncobj_export_sync_file_v2(fd, &args) == -ENOENT; +} + +igt_main +{ + int fd = -1; + + igt_fixture { + fd = drm_open_driver(DRIVER_ANY); + igt_require(has_syncobj_timeline(fd)); + igt_require(has_syncobj_sync_file_import_export(fd)); + igt_require_sw_sync(); + } + + igt_describe(test_binary_import_export_desc); + igt_subtest("binary-import-export") + test_binary_import_export(fd); + + igt_describe(test_timeline_import_export_desc); + igt_subtest("timeline-import-export") + test_timeline_import_export(fd); + + igt_describe(test_invalid_handle_import_desc); + igt_subtest("invalid-handle-import") + test_invalid_handle_import(fd); + + igt_describe(test_invalid_handle_export_desc); + igt_subtest("invalid-handle-export") + test_invalid_handle_export(fd); + + igt_describe(test_invalid_fd_import_desc); + igt_subtest("invalid-fd-import") + test_invalid_fd_import(fd); + + igt_describe(test_unsubmitted_export_desc); + igt_subtest("unsubmitted-export") + test_unsubmitted_export(fd); + + igt_fixture { + drm_close_driver(fd); + } + +} -- 2.41.0