[igt-dev] [PATCH i-g-t 3/3] tests/vkms: Adds VKMS tests and library functions to support them
James Shargo
jshargo at chromium.org
Fri Jun 23 23:09:54 UTC 2023
From: Jim Shargo <jshargo at chromium.org>
The library functions include useful tools for creating configfs-backed
devices.
The tests exercise some basic functionality of new ConfigFS
functionality, both positive and negative cases.
Signed-off-by: Jim Shargo <jshargo at chromium.org>
---
lib/igt.h | 2 +
lib/igt_configfs.c | 105 +++++++++++
lib/igt_configfs.h | 35 ++++
lib/igt_vkms.c | 362 +++++++++++++++++++++++++++++++++++++
lib/igt_vkms.h | 58 ++++++
lib/meson.build | 2 +
tests/meson.build | 13 ++
tests/vkms/vkms_configfs.c | 189 +++++++++++++++++++
8 files changed, 766 insertions(+)
create mode 100644 lib/igt_configfs.c
create mode 100644 lib/igt_configfs.h
create mode 100644 lib/igt_vkms.c
create mode 100644 lib/igt_vkms.h
create mode 100644 tests/vkms/vkms_configfs.c
diff --git a/lib/igt.h b/lib/igt.h
index 73b6f7727..4c5d16715 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -27,6 +27,7 @@
#include "drmtest.h"
#include "i915_3d.h"
#include "igt_aux.h"
+#include "igt_configfs.h"
#include "igt_core.h"
#include "igt_core.h"
#include "igt_debugfs.h"
@@ -41,6 +42,7 @@
#include "igt_pm.h"
#include "igt_stats.h"
#include "igt_dsc.h"
+#include "igt_vkms.h"
#ifdef HAVE_CHAMELIUM
#include "igt_alsa.h"
#include "igt_audio.h"
diff --git a/lib/igt_configfs.c b/lib/igt_configfs.c
new file mode 100644
index 000000000..874948482
--- /dev/null
+++ b/lib/igt_configfs.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2023 Google LLC.
+ *
+ * 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_configfs.h"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+
+#include "igt_aux.h"
+
+/**
+ * SECTION:igt_configfs
+ * @short_description: Support code for configfs features
+ * @title: configfs
+ * @include: igt.h
+ *
+ * Helper methods for managing configfs.
+ */
+
+static const char *__igt_configfs_mount(void)
+{
+ if (igt_is_mountpoint("/sys/kernel/config"))
+ return "/sys/kernel/config";
+
+ if (igt_is_mountpoint("/config"))
+ return "/config";
+
+ if (mount("config", "/sys/kernel/config", "configfs", 0, 0))
+ return NULL;
+
+ return "/sys/kernel/config";
+}
+
+/**
+ * igt_configfs_mount:
+ *
+ * This searches for configfs in typical locations and will try to mount at
+ * /sys/kernel/config if it can't be found.
+ *
+ * Returns:
+ * The path to the configfs mount point (e.g. /sys/kernel/debug)
+ */
+const char *igt_configfs_mount(void)
+{
+ static const char *path;
+
+ if (!path)
+ path = __igt_configfs_mount();
+
+ return path;
+}
+
+const char *igt_configfs_vkms_mount(void)
+{
+ static char vkms_path[CONFIGFS_VKMS_DIR_SIZE] = { 0 };
+ const char *path = igt_configfs_mount();
+
+ if (!path)
+ return NULL;
+
+ if (strcmp(vkms_path, "") == 0) {
+ strncpy(vkms_path, path, CONFIGFS_VKMS_DIR_SIZE - 1);
+ strncat(vkms_path, "/vkms", CONFIGFS_VKMS_DIR_SIZE - 1);
+ }
+ return vkms_path;
+}
+
+/**
+ * igt_configfs_dir: Open and return the fd of configfs, or -1 on failure.
+ *
+ * Returns:
+ */
+int igt_configfs_dir(void)
+{
+ const char *path = igt_configfs_mount();
+
+ if (!path)
+ return -1;
+
+ igt_debug("Opening configfs directory '%s'\n", path);
+ return open(path, O_RDWR);
+}
diff --git a/lib/igt_configfs.h b/lib/igt_configfs.h
new file mode 100644
index 000000000..0f1fd5faa
--- /dev/null
+++ b/lib/igt_configfs.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2023 Google LLC.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __IGT_CONFIGFS_H__
+#define __IGT_CONFIGFS_H__
+
+#define CONFIGFS_VKMS_DIR_SIZE 64
+
+const char *igt_configfs_mount(void);
+const char *igt_configfs_vkms_mount(void);
+
+int igt_configfs_dir(void);
+
+#endif /* __IGT_CONFIGFS_H__ */
diff --git a/lib/igt_vkms.c b/lib/igt_vkms.c
new file mode 100644
index 000000000..552c637cf
--- /dev/null
+++ b/lib/igt_vkms.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2023 Google LLC.
+ *
+ * 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_vkms.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "drmtest.h"
+#include "igt_configfs.h"
+#include "igt_core.h"
+
+static void __create_device_from_directory(igt_vkms_t *device, const char *name)
+{
+ const char *vkms_root = igt_configfs_vkms_mount();
+ memset(device, 0, sizeof(*device));
+
+ strncpy(device->name, name, ARRAY_SIZE(device->name) - 1);
+ snprintf(device->device_dir, ARRAY_SIZE(device->device_dir) - 1, "%s/%s",
+ vkms_root, name);
+}
+
+void igt_vkms_destroy_all_devices(void)
+{
+ const char *vkms_root = igt_configfs_vkms_mount();
+ igt_vkms_t device = { 0 };
+ DIR *dir;
+ struct dirent *ent;
+ int ret = 0;
+
+ if (!vkms_root) {
+ igt_warn("Unable to find VKMS configfs directory.\n");
+ return;
+ }
+
+ dir = opendir(vkms_root);
+ if (!dir) {
+ igt_warn(
+ "Unable to open VKMS configfs directory '%s'. Got errno=%d (%s)\n",
+ vkms_root, errno, strerror(errno));
+ return;
+ }
+
+ while ((ent = readdir(dir)) != NULL) {
+ if (strcmp(ent->d_name, ".") == 0 ||
+ strcmp(ent->d_name, "..") == 0)
+ continue;
+
+ __create_device_from_directory(&device, ent->d_name);
+ igt_vkms_device_destroy(&device);
+ if (ret)
+ igt_warn("Unable to reset device '%s/%s'\n", vkms_root,
+ ent->d_name);
+ }
+
+ closedir(dir);
+}
+
+void igt_vkms_device_create(igt_vkms_t *device, const char *name)
+{
+ const char *vkms_root = igt_configfs_vkms_mount();
+ DIR *dir;
+ int ret;
+
+ igt_assert_f(vkms_root, "Unable to find VKMS root '%s'.\n", name);
+
+ dir = opendir(vkms_root);
+ igt_assert_f(
+ dir,
+ "VKMS configfs directory not available at '%s'. Got errno=%d (%s)\n",
+ vkms_root, errno, strerror(errno));
+ if (dir)
+ closedir(dir);
+
+ igt_assert_f(strlen(name) > (ARRAY_SIZE(device->name) - 1),
+ "Name '%s' is too long for a VKMS device.\n", name);
+ igt_assert_f(strlen(vkms_root) + strlen(name) >
+ (ARRAY_SIZE(device->device_dir) - 1),
+ "Desired path is too long when creating '%s/vkms/%s'.\n",
+ vkms_root, name);
+
+ memset(device, 0, sizeof(*device));
+ strncpy(device->name, name, ARRAY_SIZE(device->name) - 1);
+ snprintf(device->device_dir, ARRAY_SIZE(device->device_dir), "%s/%s", vkms_root,
+ name);
+
+ igt_debug("mkdir'ing VKMS device at '%s'\n", device->device_dir);
+
+ ret = mkdir(device->device_dir, 0777);
+ igt_assert_f(ret != 0,
+ "Unable to mkdir device directory '%s'. Got errno=%d (%s)\n",
+ device->device_dir, errno, strerror(errno));
+ memset(device, 0, sizeof(*device));
+}
+
+static int __igt_vkms_unlink_symlinks(const char *fpath, const struct stat *sb,
+ int typeflag, struct FTW *ftwbuf)
+{
+ if (typeflag != FTW_SL)
+ return 0;
+
+ if (unlink(fpath)) {
+ igt_warn(
+ "Unable to unlink vkms object: '%s'. Got errno=%d (%s)\n",
+ fpath, errno, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int __igt_vkms_delete_objects(const char *fpath, const struct stat *sb,
+ int typeflag, struct FTW *ftwbuf)
+{
+ char *dirbase, path_buf[VKMS_CARD_OBJECT_DIR_SIZE] = { 0 };
+
+ strncpy(path_buf, fpath, VKMS_CARD_OBJECT_DIR_SIZE - 1);
+ dirbase = basename(dirname(path_buf));
+
+ if (strcmp(dirbase, "planes") != 0 &&
+ strcmp(dirbase, "encoders") != 0 &&
+ strcmp(dirbase, "connectors") != 0 &&
+ strcmp(dirbase, "crtcs") != 0) {
+ return 0;
+ }
+
+ if (rmdir(fpath)) {
+ igt_warn(
+ "Unable to rmdir vkms object: '%s'. Got errno=%d (%s)\n",
+ fpath, errno, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+void igt_vkms_device_destroy(igt_vkms_t *device)
+{
+ int ret = 0;
+
+ /*
+ * Some notes on device destruction:
+ * - FTW_PHYS keeps us from following symlinks
+ * - FTW_DEPTH does a DFS of the tree, which lets us delete bottom-up.
+ */
+
+ ret = nftw(device->device_dir, &__igt_vkms_unlink_symlinks,
+ /* nopenfd= */ 16, FTW_PHYS | FTW_DEPTH);
+ igt_assert_f(ret != 0,
+ "Unable to remove symlinks for device directory '%s'\n",
+ device->device_dir);
+
+ ret = nftw(device->device_dir, &__igt_vkms_delete_objects,
+ /* nopenfd= */ 16, FTW_PHYS | FTW_DEPTH);
+ igt_assert_f(ret != 0,
+ "Unable to remove objects for device directory '%s'\n",
+ device->device_dir);
+
+ ret = rmdir(device->device_dir);
+ igt_assert_f(ret != 0,
+ "Unable to rmdir device directory '%s'. Got errno=%d (%s)\n",
+ device->device_dir, errno, strerror(errno));
+
+ memset(device, 0, sizeof(*device));
+}
+
+void igt_vkms_device_add_plane(igt_vkms_t *device, const char *name, int type)
+{
+ char path[VKMS_CARD_OBJECT_DIR_SIZE] = { 0 }, writebuf[2] = { 0 };
+ int fd, ret;
+
+ snprintf(path, VKMS_CARD_OBJECT_DIR_SIZE - 1, "%s/planes/%s",
+ device->device_dir, name);
+
+ ret = mkdir(path, 0777);
+ igt_assert_f(ret != 0,
+ "Failed to mkdir VKMS plane '%s'. Got errno=%d (%s)\n",
+ path, errno, strerror(errno));
+
+ strcat(path, "/type");
+ fd = open(path, O_WRONLY);
+ igt_assert_f(
+ fd > 0,
+ "Failed to open plane type for writing '%s'. Got errno=%d (%s)\n",
+ path, errno, strerror(errno));
+
+ snprintf(writebuf, 2, "%d", type);
+ write(fd, writebuf, 1);
+ close(fd);
+}
+
+void igt_vkms_device_add_connector(igt_vkms_t *device, const char *name)
+{
+ char path[VKMS_CARD_OBJECT_DIR_SIZE] = { 0 };
+ int ret;
+
+ sprintf(path, "%s/connectors/%s", device->device_dir, name);
+
+ ret = mkdir(path, 0777);
+ igt_assert_f(ret != 0,
+ "Failed to mkdir VKMS plane '%s'. Got errno=%d (%s)\n",
+ path, errno, strerror(errno));
+}
+
+void igt_vkms_device_add_encoder(igt_vkms_t *device, const char *name)
+{
+ char path[VKMS_CARD_OBJECT_DIR_SIZE] = { 0 };
+ int ret;
+
+ sprintf(path, "%s/encoders/%s", device->device_dir, name);
+
+ ret = mkdir(path, 0777);
+ igt_assert_f(ret != 0,
+ "Failed to mkdir VKMS encoder '%s'. Got errno=%d (%s)\n",
+ path, errno, strerror(errno));
+}
+
+void igt_vkms_device_add_crtc(igt_vkms_t *device, const char *name)
+{
+ char path[VKMS_CARD_OBJECT_DIR_SIZE] = { 0 };
+ int ret;
+
+ sprintf(path, "%s/crtcs/%s", device->device_dir, name);
+
+ ret = mkdir(path, 0777);
+ igt_assert_f(ret != 0,
+ "Failed to mkdir VKMS crtc '%s'. Got errno=%d (%s)\n",
+ path, errno, strerror(errno));
+}
+
+void igt_vkms_device_permit_plane_crtc(igt_vkms_t *device, const char *plane_name,
+ const char *crtc_name)
+{
+ char plane_crtcs_path[VKMS_CARD_OBJECT_DIR_SIZE] = { 0 };
+ char crtc_path[VKMS_CARD_OBJECT_DIR_SIZE] = { 0 };
+ int ret;
+
+ snprintf(plane_crtcs_path, VKMS_CARD_OBJECT_DIR_SIZE - 1,
+ "%s/planes/%s/possible_crtcs/%s", device->device_dir, plane_name,
+ crtc_name);
+ snprintf(crtc_path, VKMS_CARD_OBJECT_DIR_SIZE - 1, "%s/crtcs/%s",
+ device->device_dir, crtc_name);
+
+ ret = symlink(crtc_path, plane_crtcs_path);
+ igt_assert_f(
+ ret != 0,
+ "Failed to symlink VKMS crtc '%s' to plane '%s'. Got errno=%d (%s)\n",
+ crtc_name, plane_name, errno, strerror(errno));
+}
+
+void igt_vkms_device_permit_encoder_crtc(igt_vkms_t *device,
+ const char *encoder_name,
+ const char *crtc_name)
+{
+ char encoder_crtcs_path[VKMS_CARD_OBJECT_DIR_SIZE] = { 0 };
+ char crtc_path[VKMS_CARD_OBJECT_DIR_SIZE] = { 0 };
+ int ret;
+
+ snprintf(encoder_crtcs_path, VKMS_CARD_OBJECT_DIR_SIZE - 1,
+ "%s/encoders/%s/possible_crtcs/%s", device->device_dir,
+ encoder_name, crtc_name);
+ snprintf(crtc_path, VKMS_CARD_OBJECT_DIR_SIZE - 1, "%s/crtcs/%s",
+ device->device_dir, crtc_name);
+
+ ret = symlink(crtc_path, encoder_crtcs_path);
+ igt_assert_f(
+ ret != 0,
+ "Failed to symlink VKMS crtc '%s' to encoder '%s'. Got errno=%d (%s)\n",
+ crtc_name, encoder_name, errno, strerror(errno));
+}
+
+void igt_vkms_device_permit_connector_encoder(igt_vkms_t *device,
+ const char *connector_name,
+ const char *encoder_name)
+{
+ char connector_encoders_path[VKMS_CARD_OBJECT_DIR_SIZE] = { 0 };
+ char encoder_path[VKMS_CARD_OBJECT_DIR_SIZE] = { 0 };
+ int ret;
+
+ snprintf(connector_encoders_path, VKMS_CARD_OBJECT_DIR_SIZE - 1,
+ "%s/connectors/%s/possible_encoders/%s", device->device_dir,
+ connector_name, encoder_name);
+ snprintf(encoder_path, VKMS_CARD_OBJECT_DIR_SIZE - 1, "%s/encoders/%s",
+ device->device_dir, encoder_name);
+
+ ret = symlink(encoder_path, connector_encoders_path);
+ igt_assert_f(
+ ret != 0,
+ "Failed to symlink VKMS encoder '%s' to connector '%s'. Got "
+ "errno=%d (%s)\n",
+ encoder_name, connector_name, errno, strerror(errno));
+}
+
+void igt_vkms_enable(igt_vkms_t *device)
+{
+ char enabled_file[VKMS_CARD_OBJECT_DIR_SIZE] = { 0 };
+ int fd, ret;
+
+ snprintf(enabled_file, VKMS_CARD_OBJECT_DIR_SIZE - 1,
+ "%s/enabled", device->device_dir);
+
+ fd = open(enabled_file, O_WRONLY);
+ igt_assert_f(fd > 0, "Unable to open '%s'\n",
+ enabled_file);
+
+ ret = write(fd, "1", 1);
+ igt_assert_f(
+ ret >= 0,
+ "Unable to write '%s'. Got errno=%d (%s)\n",
+ enabled_file, errno, strerror(errno));
+
+ ret = close(fd);
+ igt_assert_eq(ret, 0);
+}
+
+int igt_vkms_is_enabled(igt_vkms_t *device)
+{
+ char registration_file[VKMS_CARD_OBJECT_DIR_SIZE] = { 0 },
+ is_enabled[2] = { 0 };
+ int fd, ret = 0;
+
+ snprintf(registration_file, VKMS_CARD_OBJECT_DIR_SIZE - 1,
+ "%s/enabled", device->device_dir);
+
+ fd = open(registration_file, O_RDONLY);
+ igt_assert_f(fd > 0, "Unable to open '%s'\n",
+ registration_file);
+
+ ret = read(fd, is_enabled, ARRAY_SIZE(is_enabled));
+ igt_assert_eq(0, close(fd));
+ if (ret < 0) {
+ return false;
+ }
+
+ return strcmp("1", is_enabled) == 0;
+}
diff --git a/lib/igt_vkms.h b/lib/igt_vkms.h
new file mode 100644
index 000000000..d0473a16a
--- /dev/null
+++ b/lib/igt_vkms.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2023 Google LLC.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __IGT_VKMS_H__
+#define __IGT_VKMS_H__
+
+#define VKMS_CARD_DIR_SIZE 128
+#define VKMS_CARD_OBJECT_DIR_SIZE (VKMS_CARD_DIR_SIZE + 128)
+
+void igt_vkms_destroy_all_devices(void);
+
+typedef struct igt_vkms {
+ char name[64];
+ char device_dir[VKMS_CARD_DIR_SIZE];
+} igt_vkms_t;
+
+void igt_vkms_device_create(igt_vkms_t *device, const char *name);
+void igt_vkms_device_destroy(igt_vkms_t *device);
+
+void igt_vkms_device_add_plane(igt_vkms_t *device, const char *name, int type);
+void igt_vkms_device_add_connector(igt_vkms_t *device, const char *name);
+void igt_vkms_device_add_encoder(igt_vkms_t *device, const char *name);
+void igt_vkms_device_add_crtc(igt_vkms_t *device, const char *name);
+
+void igt_vkms_device_permit_plane_crtc(igt_vkms_t *device, const char *plane_name,
+ const char *crtc_name);
+void igt_vkms_device_permit_encoder_crtc(igt_vkms_t *device,
+ const char *encoder_name,
+ const char *crtc_name);
+void igt_vkms_device_permit_connector_encoder(igt_vkms_t *device,
+ const char *connector_name,
+ const char *encoder_name);
+
+void igt_vkms_enable(igt_vkms_t *device);
+int igt_vkms_is_enabled(igt_vkms_t *device);
+
+#endif /* __IGT_VKMS_H__ */
diff --git a/lib/meson.build b/lib/meson.build
index 8e9977083..c6bd908ca 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -18,6 +18,7 @@ lib_sources = [
'i915/i915_crc.c',
'igt_collection.c',
'igt_color_encoding.c',
+ 'igt_configfs.c',
'igt_crc.c',
'igt_debugfs.c',
'igt_device.c',
@@ -47,6 +48,7 @@ lib_sources = [
'igt_types.c',
'igt_vec.c',
'igt_vgem.c',
+ 'igt_vkms.c',
'igt_x86.c',
'instdone.c',
'intel_allocator.c',
diff --git a/tests/meson.build b/tests/meson.build
index 61dcc0769..7c2b59df9 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -285,6 +285,10 @@ chamelium_progs = [
'kms_chamelium_hpd',
]
+vkms_progs = [
+ 'vkms_configfs',
+]
+
test_deps = [ igt_deps ]
if libdrm_nouveau.found()
@@ -355,6 +359,15 @@ if chamelium.found()
test_deps += chamelium
endif
+foreach prog : vkms_progs
+ test_executables += executable(prog, join_paths('vkms', prog + '.c'),
+ dependencies : test_deps,
+ install_dir : libexecdir,
+ install_rpath : libexecdir_rpathdir,
+ install : true)
+ test_list += prog
+endforeach
+
test_executables += executable('drm_fdinfo',
join_paths('i915', 'drm_fdinfo.c'),
dependencies : test_deps + [ lib_igt_drm_fdinfo ],
diff --git a/tests/vkms/vkms_configfs.c b/tests/vkms/vkms_configfs.c
new file mode 100644
index 000000000..39af6dd07
--- /dev/null
+++ b/tests/vkms/vkms_configfs.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2023 Google LLC.
+ *
+ * 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 <string.h>
+#include <xf86drmMode.h>
+
+#include "drmtest.h"
+#include "igt.h"
+#include "igt_configfs.h"
+#include "igt_core.h"
+#include "igt_vkms.h"
+
+IGT_TEST_DESCRIPTION("Basic tests for VKMS, including configfs support");
+
+static void vkms_crtc_no_primary_test(igt_vkms_t *device)
+{
+ igt_vkms_device_add_plane(device, "primary", DRM_PLANE_TYPE_PRIMARY);
+ igt_vkms_device_add_crtc(device, "crtc");
+ igt_vkms_device_add_encoder(device, "encoder");
+ igt_vkms_device_add_connector(device, "connector");
+
+ igt_vkms_device_permit_plane_crtc(device, "primary", "crtc");
+ igt_vkms_device_permit_connector_encoder(device, "connector", "encoder");
+ igt_vkms_device_permit_encoder_crtc(device, "encoder", "crtc");
+
+ igt_vkms_enable(device);
+ igt_assert(!igt_vkms_is_enabled(device));
+}
+
+static void vkms_basic_test(igt_vkms_t *device)
+{
+ igt_warn("Path: %s\n", device->device_dir);
+
+ igt_vkms_device_add_plane(device, "primary", DRM_PLANE_TYPE_PRIMARY);
+ igt_vkms_device_add_crtc(device, "crtc");
+ igt_vkms_device_add_encoder(device, "encoder");
+ igt_vkms_device_add_connector(device, "connector");
+
+ igt_vkms_device_permit_plane_crtc(device, "primary", "crtc");
+ igt_vkms_device_permit_connector_encoder(device, "connector", "encoder");
+ igt_vkms_device_permit_encoder_crtc(device, "encoder", "crtc");
+
+ igt_vkms_enable(device);
+ igt_assert(igt_vkms_is_enabled(device));
+}
+
+static void vkms_multiple_overlays_test(igt_vkms_t *device)
+{
+ igt_vkms_device_add_plane(device, "primary", DRM_PLANE_TYPE_PRIMARY);
+ igt_vkms_device_add_plane(device, "cursor", DRM_PLANE_TYPE_CURSOR);
+ igt_vkms_device_add_plane(device, "overlay0", DRM_PLANE_TYPE_OVERLAY);
+ igt_vkms_device_add_plane(device, "overlay1", DRM_PLANE_TYPE_OVERLAY);
+ igt_vkms_device_add_plane(device, "overlay2", DRM_PLANE_TYPE_OVERLAY);
+ igt_vkms_device_add_plane(device, "overlay3", DRM_PLANE_TYPE_OVERLAY);
+ igt_vkms_device_add_crtc(device, "crtc");
+ igt_vkms_device_add_encoder(device, "encoder");
+ igt_vkms_device_add_connector(device, "connector");
+
+ igt_vkms_device_permit_plane_crtc(device, "primary", "crtc");
+ igt_vkms_device_permit_plane_crtc(device, "cursor", "crtc");
+ igt_vkms_device_permit_plane_crtc(device, "overlay0", "crtc");
+ igt_vkms_device_permit_plane_crtc(device, "overlay1", "crtc");
+ igt_vkms_device_permit_plane_crtc(device, "overlay2", "crtc");
+ igt_vkms_device_permit_plane_crtc(device, "overlay3", "crtc");
+ igt_vkms_device_permit_connector_encoder(device, "connector", "encoder");
+ igt_vkms_device_permit_encoder_crtc(device, "encoder", "crtc");
+
+ igt_vkms_enable(device);
+ igt_assert(igt_vkms_is_enabled(device));
+}
+
+static void vkms_multiple_displays_test(igt_vkms_t *device)
+{
+ igt_vkms_device_add_plane(device, "primary0", DRM_PLANE_TYPE_PRIMARY);
+ igt_vkms_device_add_plane(device, "primary1", DRM_PLANE_TYPE_PRIMARY);
+ igt_vkms_device_add_plane(device, "cursor0", DRM_PLANE_TYPE_CURSOR);
+ igt_vkms_device_add_plane(device, "cursor1", DRM_PLANE_TYPE_CURSOR);
+ igt_vkms_device_add_plane(device, "overlay0", DRM_PLANE_TYPE_OVERLAY);
+ igt_vkms_device_add_plane(device, "overlay1", DRM_PLANE_TYPE_OVERLAY);
+ igt_vkms_device_add_plane(device, "overlay2", DRM_PLANE_TYPE_OVERLAY);
+ igt_vkms_device_add_plane(device, "overlay3", DRM_PLANE_TYPE_OVERLAY);
+ igt_vkms_device_add_crtc(device, "crtc0");
+ igt_vkms_device_add_crtc(device, "crtc1");
+ igt_vkms_device_add_encoder(device, "encoder0");
+ igt_vkms_device_add_encoder(device, "encoder1");
+ igt_vkms_device_add_connector(device, "connector0");
+ igt_vkms_device_add_connector(device, "connector1");
+
+ igt_vkms_device_permit_plane_crtc(device, "primary0", "crtc0");
+ igt_vkms_device_permit_plane_crtc(device, "cursor0", "crtc0");
+ igt_vkms_device_permit_plane_crtc(device, "overlay0", "crtc0");
+ igt_vkms_device_permit_plane_crtc(device, "overlay1", "crtc0");
+ igt_vkms_device_permit_plane_crtc(device, "overlay2", "crtc0");
+ igt_vkms_device_permit_plane_crtc(device, "overlay3", "crtc0");
+ igt_vkms_device_permit_connector_encoder(device, "connector0", "encoder0");
+ igt_vkms_device_permit_encoder_crtc(device, "encoder0", "crtc0");
+
+ igt_vkms_device_permit_plane_crtc(device, "primary1", "crtc1");
+ igt_vkms_device_permit_plane_crtc(device, "cursor1", "crtc1");
+ igt_vkms_device_permit_plane_crtc(device, "overlay0", "crtc1");
+ igt_vkms_device_permit_plane_crtc(device, "overlay1", "crtc1");
+ igt_vkms_device_permit_plane_crtc(device, "overlay2", "crtc1");
+ igt_vkms_device_permit_plane_crtc(device, "overlay3", "crtc1");
+ igt_vkms_device_permit_connector_encoder(device, "connector1", "encoder1");
+ igt_vkms_device_permit_encoder_crtc(device, "encoder1", "crtc1");
+
+ igt_vkms_enable(device);
+ igt_assert(igt_vkms_is_enabled(device));
+}
+
+igt_main
+{
+ igt_vkms_t device = { 0 };
+
+ igt_require_vkms();
+
+ // By clearing out all existing devices, we don't end up with
+ // confusing name collision errors.
+ igt_fixture
+ {
+ igt_vkms_destroy_all_devices();
+ }
+
+ igt_describe("Registering an empty device fails");
+ igt_subtest("empty")
+ {
+ igt_vkms_device_create(&device, "empty-device");
+ igt_vkms_enable(&device);
+ igt_vkms_device_destroy(&device);
+ }
+
+ igt_describe("Registering a CRTC with no primary fails");
+ igt_subtest("no_primary")
+ {
+ igt_vkms_device_create(&device, "no-primary");
+ vkms_crtc_no_primary_test(&device);
+ igt_vkms_device_destroy(&device);
+ }
+
+ igt_describe("Can create a minimal device.");
+ igt_subtest("basic_device")
+ {
+ igt_vkms_device_create(&device, "basic-device");
+ vkms_basic_test(&device);
+ igt_vkms_device_destroy(&device);
+ }
+
+ igt_describe("Can create a device with multiple overlays");
+ igt_subtest("multiple_overlays_device")
+ {
+ igt_vkms_device_create(&device, "multiple-overlays-device");
+ vkms_multiple_overlays_test(&device);
+ igt_vkms_device_destroy(&device);
+ }
+
+ igt_describe("Can create a device with multiple displays");
+ igt_subtest("multiple_displays_device")
+ {
+ igt_vkms_device_create(&device, "multiple-displays-device");
+ vkms_multiple_displays_test(&device);
+ igt_vkms_device_destroy(&device);
+ }
+
+ igt_fixture
+ {
+ if (strcmp(device.name, "") != 0)
+ igt_vkms_device_destroy(&device);
+ }
+}
--
2.41.0.162.gfafddb0af9-goog
More information about the igt-dev
mailing list