Igt-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [igt-dev] [PATCH i-g-t 0/4] Add vkms configfs testing
@ 2023-09-01  9:28 Marius Vlad
  2023-09-01  9:28 ` [igt-dev] [PATCH i-g-t 1/5] lib/drmtest: Add VKMS as a known driver type Marius Vlad
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Marius Vlad @ 2023-09-01  9:28 UTC (permalink / raw)
  To: igt-dev; +Cc: tzimmermann, yixie, seanpaul, daniel, brpol, igormtorrente

With this series we add some basic tests for sanity checking the
ConfigFS functionality into the vkms driver. This would allow to create
and to customize dynamically the entire DRM pipeline.

This small series adds a new library (igt_vkms) for creating the entire
pipeline, as well as enabling the device and set the connectors as
connected or disconnected. Further more it adds some helpers
(igt_configfs) to create the proper ConfigFS mount point.

The sub-tests in this series added are:

- a basic device test, that creates an entire pipeline with a primary
  plane
- an empty test, that doesn't create a primary plane and which should
  fail
- a test that creates multiple overlay and cursor planes
- a test that creates multiple pipelines
- a test similar to basic device test but that also disables the vkms
  device at the end

These kernel changes were written initially by Jim Shargo, and then were
picked up by Brandon Pollack. As of today the latest version is at 
https://patchwork.kernel.org/project/dri-devel/list/?series=780110

The i-g-t changes were also developed by Jim Shargo, and I've massaged
them a bit doing some minor changes since their inception. These changes
are:

- replaced all string strcat/strcpy with snprintfs
- renamed all _permit_ functions to _attach_
- added documentation for all public functions
- vkms_crtc_no_primary_test was fixed such that should it now fails
  as expected
- split the changes one more time, and group one of the patches 
  with the introduction of igt_configfs
- fixed skipping the (sub)tests if vkms wasn't found loaded

I've kept the original author as Jim was the original person
working on them.

For history purposes I've picked these up from 
https://gitlab.freedesktop.org/jshargo/igt-gpu-tools/-/merge_requests/1.

Jim Shargo (4):
  lib/drmtest: Add VKMS as a known driver type
  lib/confifs: Add helpers for mounting/unmounting configfs
  tests/vkms: Add a small library for VKMS testing
  tests/vkms: Add more tests for VKMS

 lib/drmtest.c              |  26 ++
 lib/drmtest.h              |   9 +-
 lib/igt.h                  |   3 +-
 lib/igt_aux.c              |  25 ++
 lib/igt_aux.h              |   2 +
 lib/igt_configfs.c         | 106 ++++++++
 lib/igt_configfs.h         |  36 +++
 lib/igt_debugfs.c          |  29 +--
 lib/igt_vkms.c             | 514 +++++++++++++++++++++++++++++++++++++
 lib/igt_vkms.h             |  66 +++++
 lib/meson.build            |   2 +
 tests/meson.build          |  13 +
 tests/vkms/vkms_configfs.c | 194 ++++++++++++++
 13 files changed, 995 insertions(+), 30 deletions(-)
 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

-- 
2.40.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [igt-dev] [PATCH i-g-t 1/5] lib/drmtest: Add VKMS as a known driver type
  2023-09-01  9:28 [igt-dev] [PATCH i-g-t 0/4] Add vkms configfs testing Marius Vlad
@ 2023-09-01  9:28 ` Marius Vlad
  2023-09-01  9:28 ` [igt-dev] [PATCH i-g-t 2/5] lib/confifs: Add helpers for mounting/unmounting configfs Marius Vlad
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Marius Vlad @ 2023-09-01  9:28 UTC (permalink / raw)
  To: igt-dev; +Cc: tzimmermann, yixie, seanpaul, daniel, brpol, igormtorrente

From: Jim Shargo <jshargo@chromium.org>

Signed-off-by: Jim Shargo <jshargo@chromium.org>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
---
 lib/drmtest.c | 26 ++++++++++++++++++++++++++
 lib/drmtest.h |  9 +++++++--
 2 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/lib/drmtest.c b/lib/drmtest.c
index e1da66c87..8cb22ce39 100644
--- a/lib/drmtest.c
+++ b/lib/drmtest.c
@@ -161,6 +161,16 @@ enum intel_driver get_intel_driver(int fd)
 	igt_assert_f(0, "Device is not handled by Intel driver\n");
 }
 
+bool is_vkms_device(int fd)
+{
+	char name[64] = "";
+
+	if (__get_drm_device_name(fd, name, sizeof(name) - 1))
+		return false;
+
+	return strncmp("vkms", name, strlen("vkms")) == 0;
+}
+
 static char _forced_driver[16] = "";
 
 /**
@@ -806,3 +816,19 @@ void igt_require_xe(int fd)
 {
 	igt_require(is_xe_device(fd));
 }
+
+void igt_require_vkms(void)
+{
+	/* Since VKMS can create and destroy virtual drivers at will, instead
+	 * look to make sure the driver is installed.  */
+	struct stat s = {};
+	int ret;
+	const char *vkms_module_dir = "/sys/module/vkms";
+
+	ret = stat(vkms_module_dir, &s);
+
+	igt_require_f(ret == 0, "VKMS stat of %s returned %d (%s)\n",
+		      vkms_module_dir, ret, strerror(ret));
+	igt_require_f(S_ISDIR(s.st_mode),
+		      "VKMS stat of %s was not a directory\n", vkms_module_dir);
+}
diff --git a/lib/drmtest.h b/lib/drmtest.h
index 97ab6e759..2d8f74771 100644
--- a/lib/drmtest.h
+++ b/lib/drmtest.h
@@ -52,15 +52,18 @@
 #define DRIVER_PANFROST	(1 << 5)
 #define DRIVER_MSM	(1 << 6)
 #define DRIVER_XE	(1 << 7)
-#define DRIVER_VMWGFX   (1 << 8)
+#define DRIVER_VMWGFX	(1 << 8)
+#define DRIVER_VKMS	(1 << 9)
 
 /*
  * Exclude DRVER_VGEM from DRIVER_ANY since if you run on a system
  * with vgem as well as a supported driver, you can end up with a
  * near-100% skip rate if you don't explicitly specify the device,
  * depending on device-load ordering.
+ *
+ * Exclude VKMS to prefer hardware drivers.
  */
-#define DRIVER_ANY 	~(DRIVER_VGEM)
+#define DRIVER_ANY ~(DRIVER_VGEM | DRIVER_VKMS)
 
 /*
  * Compile friendly enum for i915/xe.
@@ -115,6 +118,7 @@ void igt_require_i915(int fd);
 void igt_require_nouveau(int fd);
 void igt_require_vc4(int fd);
 void igt_require_xe(int fd);
+void igt_require_vkms(void);
 
 bool is_amdgpu_device(int fd);
 bool is_i915_device(int fd);
@@ -125,6 +129,7 @@ bool is_vc4_device(int fd);
 bool is_xe_device(int fd);
 bool is_intel_device(int fd);
 enum intel_driver get_intel_driver(int fd);
+bool is_vkms_device(int fd);
 
 /**
  * do_or_die:
-- 
2.40.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [igt-dev] [PATCH i-g-t 2/5] lib/confifs: Add helpers for mounting/unmounting configfs
  2023-09-01  9:28 [igt-dev] [PATCH i-g-t 0/4] Add vkms configfs testing Marius Vlad
  2023-09-01  9:28 ` [igt-dev] [PATCH i-g-t 1/5] lib/drmtest: Add VKMS as a known driver type Marius Vlad
@ 2023-09-01  9:28 ` Marius Vlad
  2023-09-01  9:28 ` [igt-dev] [PATCH i-g-t 3/5] tests/vkms: Add a small library for VKMS testing Marius Vlad
  2023-09-01  9:28 ` [igt-dev] [PATCH i-g-t 4/5] tests/vkms: Add more tests for VKMS Marius Vlad
  3 siblings, 0 replies; 5+ messages in thread
From: Marius Vlad @ 2023-09-01  9:28 UTC (permalink / raw)
  To: igt-dev; +Cc: tzimmermann, yixie, seanpaul, daniel, brpol, igormtorrente

From: Jim Shargo <jshargo@chromium.org>

This change supports the subsequent testing of ConfigFS-based VKMS
features, which require their own mounting.

With this change, we also make is_mountpoint public renamaning to
igt_is_mountpoint and we make use of it.

Signed-off-by: Jim Shargo <jshargo@chromium.org>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
---
 lib/igt.h          |   2 +-
 lib/igt_aux.c      |  25 +++++++++++
 lib/igt_aux.h      |   2 +
 lib/igt_configfs.c | 105 +++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_configfs.h |  36 ++++++++++++++++
 lib/igt_debugfs.c  |  29 +------------
 lib/meson.build    |   1 +
 7 files changed, 172 insertions(+), 28 deletions(-)
 create mode 100644 lib/igt_configfs.c
 create mode 100644 lib/igt_configfs.h

diff --git a/lib/igt.h b/lib/igt.h
index 73b6f7727..6108d9615 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -28,7 +28,7 @@
 #include "i915_3d.h"
 #include "igt_aux.h"
 #include "igt_core.h"
-#include "igt_core.h"
+#include "igt_configfs.h"
 #include "igt_debugfs.h"
 #include "igt_draw.h"
 #include "igt_dummyload.h"
diff --git a/lib/igt_aux.c b/lib/igt_aux.c
index 18edc5ef9..8b38b5a3e 100644
--- a/lib/igt_aux.c
+++ b/lib/igt_aux.c
@@ -2035,6 +2035,31 @@ bool igt_allow_unlimited_files(void)
 	return setrlimit(RLIMIT_NOFILE, &rlim) == 0;
 }
 
+bool igt_is_mountpoint(const char *path)
+{
+	char buf[strlen(path) + 4];
+	struct stat st;
+	dev_t dev;
+
+	igt_assert_lt(snprintf(buf, sizeof(buf), "%s/.", path), sizeof(buf));
+	if (stat(buf, &st))
+		return false;
+
+	if (!S_ISDIR(st.st_mode))
+		return false;
+
+	dev = st.st_dev;
+
+	igt_assert_lt(snprintf(buf, sizeof(buf), "%s/..", path), sizeof(buf));
+	if (stat(buf, &st))
+		return false;
+
+	if (!S_ISDIR(st.st_mode))
+		return false;
+
+	return dev != st.st_dev;
+}
+
 /**
  * vfs_file_max: report maximum number of files
  *
diff --git a/lib/igt_aux.h b/lib/igt_aux.h
index fb76b0313..298c610f2 100644
--- a/lib/igt_aux.h
+++ b/lib/igt_aux.h
@@ -311,6 +311,8 @@ double igt_stop_siglatency(struct igt_mean *result);
 
 bool igt_allow_unlimited_files(void);
 
+bool igt_is_mountpoint(const char *path);
+
 int igt_is_process_running(const char *comm);
 int igt_terminate_process(int sig, const char *comm);
 void igt_lsof(const char *dpath);
diff --git a/lib/igt_configfs.c b/lib/igt_configfs.c
new file mode 100644
index 000000000..89acab315
--- /dev/null
+++ b/lib/igt_configfs.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2023 Google LLC.
+ * Copyright 2023 Collabora, Ltd.
+ *
+ * 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_configfs.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];
+	const char *path = igt_configfs_mount();
+
+	if (!path)
+		return NULL;
+
+	snprintf(vkms_path, sizeof(vkms_path), "%s/%s", path, "vkms");
+
+	igt_debug("VKMS path: %s\n", vkms_path);
+	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..238007ab7
--- /dev/null
+++ b/lib/igt_configfs.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2023 Google LLC.
+ * Copyright 2023 Collabora, Ltd.
+ *
+ * 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_debugfs.c b/lib/igt_debugfs.c
index a7b54bae5..63fc6b9e7 100644
--- a/lib/igt_debugfs.c
+++ b/lib/igt_debugfs.c
@@ -67,37 +67,12 @@
  * General debugfs helpers
  */
 
-static bool is_mountpoint(const char *path)
-{
-	char buf[strlen(path) + 4];
-	struct stat st;
-	dev_t dev;
-
-	igt_assert_lt(snprintf(buf, sizeof(buf), "%s/.", path), sizeof(buf));
-	if (stat(buf, &st))
-		return false;
-
-	if (!S_ISDIR(st.st_mode))
-		return false;
-
-	dev = st.st_dev;
-
-	igt_assert_lt(snprintf(buf, sizeof(buf), "%s/..", path), sizeof(buf));
-	if (stat(buf, &st))
-		return false;
-
-	if (!S_ISDIR(st.st_mode))
-		return false;
-
-	return dev != st.st_dev;
-}
-
 static const char *__igt_debugfs_mount(void)
 {
-	if (is_mountpoint("/sys/kernel/debug"))
+	if (igt_is_mountpoint("/sys/kernel/debug"))
 		return "/sys/kernel/debug";
 
-	if (is_mountpoint("/debug"))
+	if (igt_is_mountpoint("/debug"))
 		return "/debug";
 
 	if (mount("debug", "/sys/kernel/debug", "debugfs", 0, 0))
diff --git a/lib/meson.build b/lib/meson.build
index 21ea9d5ac..d727529f0 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -19,6 +19,7 @@ lib_sources = [
 	'igt_collection.c',
 	'igt_color_encoding.c',
 	'igt_crc.c',
+	'igt_configfs.c',
 	'igt_debugfs.c',
 	'igt_device.c',
 	'igt_device_scan.c',
-- 
2.40.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [igt-dev] [PATCH i-g-t 3/5] tests/vkms: Add a small library for VKMS testing
  2023-09-01  9:28 [igt-dev] [PATCH i-g-t 0/4] Add vkms configfs testing Marius Vlad
  2023-09-01  9:28 ` [igt-dev] [PATCH i-g-t 1/5] lib/drmtest: Add VKMS as a known driver type Marius Vlad
  2023-09-01  9:28 ` [igt-dev] [PATCH i-g-t 2/5] lib/confifs: Add helpers for mounting/unmounting configfs Marius Vlad
@ 2023-09-01  9:28 ` Marius Vlad
  2023-09-01  9:28 ` [igt-dev] [PATCH i-g-t 4/5] tests/vkms: Add more tests for VKMS Marius Vlad
  3 siblings, 0 replies; 5+ messages in thread
From: Marius Vlad @ 2023-09-01  9:28 UTC (permalink / raw)
  To: igt-dev; +Cc: tzimmermann, yixie, seanpaul, daniel, brpol, igormtorrente

From: Jim Shargo <jshargo@chromium.org>

And with it, this adds a basic test that makes use of it,
creating a device and with it a pipeline.

One should create a vkms device, add pipeline elements, like encoders,
crtc, and connectors, compose the pipeline by attaching each element
using the _attach_ functions, set the connector as connected and
finally, enable the vkms device.

This works in-tandem with the vkms driver which requires to enable the
device and set the connector as connected.

Signed-off-by: Jim Shargo <jshargo@chromium.org>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
---
 lib/igt.h                  |   1 +
 lib/igt_vkms.c             | 532 +++++++++++++++++++++++++++++++++++++
 lib/igt_vkms.h             |  66 +++++
 lib/meson.build            |   1 +
 tests/meson.build          |  13 +
 tests/vkms/vkms_configfs.c |  83 ++++++
 6 files changed, 696 insertions(+)
 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 6108d9615..d3771c1f1 100644
--- a/lib/igt.h
+++ b/lib/igt.h
@@ -41,6 +41,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_vkms.c b/lib/igt_vkms.c
new file mode 100644
index 000000000..7ae8dde55
--- /dev/null
+++ b/lib/igt_vkms.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright 2023 Google LLC.
+ * Copyright 2023 Collabora, Ltd.
+ *
+ * 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"
+
+/**
+ * SECTION:igt_vkms
+ * @short_description: Library with creating and dynamically configure a vkms device
+ * @title: vkms
+ * @include: igt_vkms.h
+ *
+ * This library contains helpers for creating a vkms device and configuring it
+ * dynamically.
+ *
+ * One should create a vkms device, add pipeline elements, like encoders, crtc,
+ * and connectors, compose the pipeline by attaching each element using the
+ * _attach_ functions, set the connector as connected and finally, enable the
+ * vkms device.
+ */
+
+
+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));
+
+	snprintf(device->name, sizeof(device->name), "%s", name);
+	snprintf(device->device_dir, sizeof(device->device_dir), "%s/%s", vkms_root, name);
+}
+
+/**
+ * igt_vkms_destroy_all_devices:
+ *
+ * Iterates over all directories found in the ConfigFS mountpoint and calls
+ * igt_vkms_device_destroy, which cleans up any previous directories,
+ * symlinks and objects.
+ */
+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);
+}
+
+/**
+ * igt_vkms_device_create:
+ * @device: a statically allocated object that denotes a vkms device
+ * @name: a string that signifies the vkms device to be created
+ *
+ * This creates a directory in the ConfigFS root mountpoint directory, where
+ * the entire pipeline will be configured.
+ */
+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);
+
+	create_device_from_directory(device, 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));
+}
+
+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;
+	char path_buf[VKMS_CARD_OBJECT_DIR_SIZE];
+
+	memset(path_buf, 0x0, sizeof(path_buf));
+	snprintf(path_buf, sizeof(path_buf), "%s", fpath);
+	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;
+}
+
+/**
+ * igt_vkms_device_destroy:
+ * @device: the vkms device in question
+ *
+ * Removes any possible symlinks, objects and directories, and clears the
+ * device for later usage.
+ *
+ * Users can then create a new vkms device with igt_vkms_device_create().
+ */
+void igt_vkms_device_destroy(igt_vkms_t *device)
+{
+	int ret = 0;
+
+	igt_debug("Destroying device %s\n", device->device_dir);
+
+	/* 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));
+}
+
+/**
+ * igt_vkms_device_add_plane:
+ * @device: the device in question
+ * @name: the name of the plane, as a string
+ * @type: the type of the HW plane, as an integer, one of DRM_PLANE_TYPE_PRIMARY,
+ * DRM_PLANE_TYPE_OVERLAY or DRM_PLANE_TYPE_CURSOR.
+ *
+ * mkdirs and creates a plane using the provided name and the type.
+ */
+void igt_vkms_device_add_plane(igt_vkms_t *device, const char *name, int type)
+{
+	char path[VKMS_CARD_OBJECT_DIR_SIZE];
+	char writebuf[2];
+	int fd, ret;
+
+	memset(path, 0x0, sizeof(path));
+	snprintf(path, sizeof(path), "%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);
+}
+
+/**
+ * igt_vkms_device_add_connector:
+ * @device: the device in question
+ * @name: the name of the connector, as a string
+ *
+ * mkdirs and creates a connector using the provided name.
+ *
+ */
+void igt_vkms_device_add_connector(igt_vkms_t *device, const char *name)
+{
+	char path[VKMS_CARD_OBJECT_DIR_SIZE];
+	int ret;
+
+	memset(path, 0x0, sizeof(path));
+	snprintf(path, sizeof(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));
+}
+
+/**
+ * igt_vkms_device_add_encoder:
+ * @device: the device in question
+ * @name: the name of the encoder, as a string
+ *
+ * mkdirs and creates an encoder using the provided name.
+ */
+void igt_vkms_device_add_encoder(igt_vkms_t *device, const char *name)
+{
+	char path[VKMS_CARD_OBJECT_DIR_SIZE];
+	int ret;
+
+	memset(path, 0x0, sizeof(path));
+	snprintf(path, sizeof(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));
+}
+
+/**
+ * igt_vkms_device_add_crtc:
+ * @device: the device in question
+ * @name: the name of the crtc, as a string
+ *
+ * mkdirs and creates a crtc using the provided name.
+ */
+void igt_vkms_device_add_crtc(igt_vkms_t *device, const char *name)
+{
+	char path[VKMS_CARD_OBJECT_DIR_SIZE];
+	int ret;
+
+	memset(path, 0x0, sizeof(path));
+	snprintf(path, sizeof(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));
+}
+
+/**
+ * igt_vkms_device_attach_plane_to_crtc:
+ * @device: the vkms device in question
+ * @plane_name: the plane name, as a string
+ * @crtc_name: the crtc name, as a string
+ *
+ * This function symlinks the crtc, as pointed by crtc_name to the planes
+ * possible_crtcs directory.
+ */
+void igt_vkms_device_attach_plane_to_crtc(igt_vkms_t *device, const char *plane_name,
+					  const char *crtc_name)
+{
+	char plane_crtcs_path[VKMS_CARD_OBJECT_DIR_SIZE];
+	char crtc_path[VKMS_CARD_OBJECT_DIR_SIZE];
+	int ret;
+
+	memset(crtc_path, 0x0, sizeof(crtc_path));
+	memset(plane_crtcs_path, 0x0, sizeof(plane_crtcs_path));
+
+	snprintf(plane_crtcs_path, sizeof(plane_crtcs_path),
+		 "%s/planes/%s/possible_crtcs/%s",
+		 device->device_dir, plane_name, crtc_name);
+	snprintf(crtc_path, sizeof(crtc_path), "%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));
+}
+
+/**
+ * igt_vkms_device_attach_crtc_to_encoder:
+ * @device: the vkms device in question
+ * @encoder_name: the encoder name, as a string
+ * @crtc_name: the crtc name, as a string
+ *
+ * This function symlinks the crtc, as pointed by crtc_name to the encoders
+ * possible_crtcs directory.
+ */
+void igt_vkms_device_attach_crtc_to_encoder(igt_vkms_t *device, const char *encoder_name,
+					    const char *crtc_name)
+{
+	char encoder_crtcs_path[VKMS_CARD_OBJECT_DIR_SIZE];
+	char crtc_path[VKMS_CARD_OBJECT_DIR_SIZE];
+	int ret;
+
+	memset(crtc_path, 0x0, sizeof(crtc_path));
+	memset(encoder_crtcs_path, 0x0, sizeof(encoder_crtcs_path));
+
+	snprintf(encoder_crtcs_path, sizeof(encoder_crtcs_path),
+		 "%s/encoders/%s/possible_crtcs/%s", device->device_dir,
+		 encoder_name, crtc_name);
+	snprintf(crtc_path, sizeof(crtc_path), "%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));
+}
+
+/**
+ * igt_vkms_device_attach_encoder_to_connector:
+ * @device: the vkms device in question
+ * @connector_name: the connector name, as a string
+ * @encoder_name: the encoder name, as a string
+ *
+ * This function symlinks the encoder, pointed by encoder_name to the
+ * connectors possible_encoders directory.
+ */
+void igt_vkms_device_attach_encoder_to_connector(igt_vkms_t *device,
+						 const char *connector_name,
+						 const char *encoder_name)
+{
+	char connector_encoders_path[VKMS_CARD_OBJECT_DIR_SIZE];
+	char encoder_path[VKMS_CARD_OBJECT_DIR_SIZE];
+	int ret;
+
+	memset(encoder_path, 0x0, sizeof(encoder_path));
+	memset(connector_encoders_path, 0x0, sizeof(connector_encoders_path));
+
+	snprintf(connector_encoders_path, sizeof(connector_encoders_path),
+		 "%s/connectors/%s/possible_encoders/%s", device->device_dir,
+		 connector_name, encoder_name);
+	snprintf(encoder_path, sizeof(encoder_path), "%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));
+}
+
+/**
+ * igt_vkms_enable:
+ * @device: the vkms device in question
+ *
+ * This would enable the vkms device after setting up the pipeline. Use this
+ * function after you've set up the entire pipeline to probe and add the vkms
+ * device.
+ *
+ */
+void igt_vkms_enable(igt_vkms_t *device)
+{
+	char enabled_file[VKMS_CARD_OBJECT_DIR_SIZE];
+	int fd, ret;
+
+	memset(enabled_file, 0x0, sizeof(enabled_file));
+	snprintf(enabled_file, sizeof(enabled_file),
+		 "%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);
+}
+
+/**
+ * igt_vkms_connector_connect:
+ * @device: the vkms device in question
+ * @connector_name: the connector name, as a string
+ *
+ * By default the connector will be created as disconnected so you'd need to
+ * mark the connector as connected. This will generate connected hot-plug
+ * event.
+ *
+ * You can either call this before enabling the vkms device, or after.
+ */
+void igt_vkms_connector_connect(igt_vkms_t *device, const char *connector_name)
+{
+	char connector_path[VKMS_CARD_OBJECT_DIR_SIZE];
+	int fd, ret;
+
+	memset(connector_path, 0x0, sizeof(connector_path));
+	snprintf(connector_path, sizeof(connector_path),
+		 "%s/connectors/%s/connected", device->device_dir, connector_name);
+
+	fd = open(connector_path, O_WRONLY);
+	igt_assert_f(fd > 0, "Unable to open '%s'\n", connector_path);
+
+	ret = write(fd, "1", 1);
+	igt_assert_f(ret >= 0, "Unable to write '%s'. Got errno=%d (%s)\n",
+		     connector_path, errno, strerror(errno));
+
+	ret = close(fd);
+	igt_assert_eq(ret, 0);
+}
+
+/**
+ * igt_vkms_connector_disconnect:
+ * @device: the vkms device in question
+ * @connector_name: the connector name as a string
+ *
+ * Mark the connector, pointed by @connector_name as disconnected.
+ * This will generate a disconnected hot-plug event.
+ */
+void igt_vkms_connector_disconnect(igt_vkms_t *device, const char *connector_name)
+{
+	char connector_path[VKMS_CARD_OBJECT_DIR_SIZE];
+	int fd, ret;
+
+	memset(connector_path, 0x0, sizeof(connector_path));
+	snprintf(connector_path, sizeof(connector_path),
+		 "%s/connectors/%s/connected", device->device_dir, connector_name);
+
+	fd = open(connector_path, O_WRONLY);
+	igt_assert_f(fd > 0, "Unable to open '%s'\n", connector_path);
+
+	ret = write(fd, "1", 1);
+	igt_assert_f(ret >= 0, "Unable to write '%s'. Got errno=%d (%s)\n",
+		     connector_path, errno, strerror(errno));
+
+	ret = close(fd);
+	igt_assert_eq(ret, 0);
+}
+
+/**
+ * igt_vkms_is_enabled:
+ * @device:
+ *
+ * This checks out if the device has been indeed enabled by checking that
+ * underlying file has the value of '1'.
+ *
+ * Returns true if the device has been enabled, or false otherwise.
+ */
+bool igt_vkms_is_enabled(igt_vkms_t *device)
+{
+	char registration_file[VKMS_CARD_OBJECT_DIR_SIZE];
+	char is_enabled[2];
+	int fd, ret = 0;
+
+	memset(registration_file, 0x0, sizeof(registration_file));
+	snprintf(registration_file, sizeof(registration_file),
+		 "%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, sizeof(is_enabled));
+	igt_assert_eq(0, close(fd));
+	if (ret < 0) {
+		return false;
+	}
+
+	return strncmp("1", is_enabled, sizeof(char)) == 0;
+}
diff --git a/lib/igt_vkms.h b/lib/igt_vkms.h
new file mode 100644
index 000000000..174039ca0
--- /dev/null
+++ b/lib/igt_vkms.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2023 Google LLC.
+ * Copyright 2023 Collabora, Ltd.
+ *
+ * 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__
+
+#include <stdbool.h>
+#include <limits.h>
+
+#define VKMS_CARD_NAME_SIZE		(PATH_MAX / 4)
+#define VKMS_CARD_DIR_SIZE 		(PATH_MAX / 2)
+#define VKMS_CARD_OBJECT_DIR_SIZE	PATH_MAX
+
+
+void igt_vkms_destroy_all_devices(void);
+
+typedef struct igt_vkms {
+	char name[VKMS_CARD_NAME_SIZE];
+	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_attach_plane_to_crtc(igt_vkms_t *device, const char *plane_name,
+					  const char *crtc_name);
+void igt_vkms_device_attach_crtc_to_encoder(igt_vkms_t *device,
+					    const char *encoder_name,
+					    const char *crtc_name);
+void igt_vkms_device_attach_encoder_to_connector(igt_vkms_t *device,
+						 const char *connector_name,
+						 const char *encoder_name);
+
+void igt_vkms_enable(igt_vkms_t *device);
+void igt_vkms_connector_connect(igt_vkms_t *device, const char *connector_name);
+void igt_vkms_connector_disconnect(igt_vkms_t *device, const char *connector_name);
+bool igt_vkms_is_enabled(igt_vkms_t *device);
+
+#endif /* __IGT_VKMS_H__ */
diff --git a/lib/meson.build b/lib/meson.build
index d727529f0..600bbcc0c 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -20,6 +20,7 @@ lib_sources = [
 	'igt_color_encoding.c',
 	'igt_crc.c',
 	'igt_configfs.c',
+	'igt_vkms.c',
 	'igt_debugfs.c',
 	'igt_device.c',
 	'igt_device_scan.c',
diff --git a/tests/meson.build b/tests/meson.build
index c683e468d..db1545fe0 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -316,6 +316,10 @@ chamelium_progs = [
 	'kms_chamelium_hpd',
 ]
 
+vkms_progs = [
+  'vkms_configfs',
+]
+
 test_deps = [ igt_deps ]
 
 if libdrm_nouveau.found()
@@ -459,6 +463,15 @@ if chamelium.found()
 		     output : name + '.testlist')
 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
+
 subdir('amdgpu')
 
 subdir('v3d')
diff --git a/tests/vkms/vkms_configfs.c b/tests/vkms/vkms_configfs.c
new file mode 100644
index 000000000..974753318
--- /dev/null
+++ b/tests/vkms/vkms_configfs.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2023 Google LLC.
+ * Copyright 2023 Collabora, Ltd.
+ *
+ * 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_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_connector_connect(device, "connector");
+
+	igt_vkms_device_attach_plane_to_crtc(device, "primary", "crtc");
+	igt_vkms_device_attach_encoder_to_connector(device, "connector", "encoder");
+	igt_vkms_device_attach_crtc_to_encoder(device, "encoder", "crtc");
+
+	igt_vkms_enable(device);
+	igt_assert(igt_vkms_is_enabled(device));
+}
+
+
+igt_main
+{
+	igt_vkms_t device;
+
+	/* By clearing out all existing devices, we don't end up with confusing
+	 * name collision errors. */
+	igt_fixture
+	{
+		igt_require_vkms();
+		igt_vkms_destroy_all_devices();
+	}
+
+	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_fixture
+	{
+		igt_require_vkms();
+		/* avoid potential dangling directories/objects if some of the
+		 * tests failed */
+		if (strcmp(device.name, ""))
+			igt_vkms_device_destroy(&device);
+	}
+}
-- 
2.40.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [igt-dev] [PATCH i-g-t 4/5] tests/vkms: Add more tests for VKMS
  2023-09-01  9:28 [igt-dev] [PATCH i-g-t 0/4] Add vkms configfs testing Marius Vlad
                   ` (2 preceding siblings ...)
  2023-09-01  9:28 ` [igt-dev] [PATCH i-g-t 3/5] tests/vkms: Add a small library for VKMS testing Marius Vlad
@ 2023-09-01  9:28 ` Marius Vlad
  3 siblings, 0 replies; 5+ messages in thread
From: Marius Vlad @ 2023-09-01  9:28 UTC (permalink / raw)
  To: igt-dev; +Cc: tzimmermann, yixie, seanpaul, daniel, brpol, igormtorrente

From: Jim Shargo <jshargo@chromium.org>

This adds four more tests, one that should fail when no primary plane
is created and added to the pipeline, one that creates a device with
multiple overlay and cursor planes, another one that create two outputs,
and tests that disable works.

Signed-off-by: Jim Shargo <jshargo@chromium.org>
Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
---
 lib/igt_vkms.c             |  27 ++++++++
 lib/igt_vkms.h             |   1 +
 tests/vkms/vkms_configfs.c | 132 +++++++++++++++++++++++++++++++++++++
 3 files changed, 160 insertions(+)

diff --git a/lib/igt_vkms.c b/lib/igt_vkms.c
index 7ae8dde55..1128a9328 100644
--- a/lib/igt_vkms.c
+++ b/lib/igt_vkms.c
@@ -440,6 +440,33 @@ void igt_vkms_enable(igt_vkms_t *device)
 	igt_assert_eq(ret, 0);
 }
 
+/**
+ * igt_vkms_disable:
+ * @device: the vkms device in question
+ *
+ * This would disable the vkms device.
+ *
+ */
+void igt_vkms_disable(igt_vkms_t *device)
+{
+	char enabled_file[VKMS_CARD_OBJECT_DIR_SIZE];
+	int fd, ret;
+
+	memset(enabled_file, 0x0, sizeof(enabled_file));
+	snprintf(enabled_file, sizeof(enabled_file),
+		 "%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, "0", 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);
+}
+
 /**
  * igt_vkms_connector_connect:
  * @device: the vkms device in question
diff --git a/lib/igt_vkms.h b/lib/igt_vkms.h
index 174039ca0..48bdb063f 100644
--- a/lib/igt_vkms.h
+++ b/lib/igt_vkms.h
@@ -59,6 +59,7 @@ void igt_vkms_device_attach_encoder_to_connector(igt_vkms_t *device,
 						 const char *encoder_name);
 
 void igt_vkms_enable(igt_vkms_t *device);
+void igt_vkms_disable(igt_vkms_t *device);
 void igt_vkms_connector_connect(igt_vkms_t *device, const char *connector_name);
 void igt_vkms_connector_disconnect(igt_vkms_t *device, const char *connector_name);
 bool igt_vkms_is_enabled(igt_vkms_t *device);
diff --git a/tests/vkms/vkms_configfs.c b/tests/vkms/vkms_configfs.c
index 974753318..1d3fa2ec1 100644
--- a/tests/vkms/vkms_configfs.c
+++ b/tests/vkms/vkms_configfs.c
@@ -51,6 +51,105 @@ static void vkms_basic_test(igt_vkms_t *device)
 	igt_assert(igt_vkms_is_enabled(device));
 }
 
+static void vkms_crtc_no_primary_test(igt_vkms_t *device)
+{
+	igt_vkms_device_add_crtc(device, "crtc");
+	igt_vkms_device_add_encoder(device, "encoder");
+	igt_vkms_device_add_connector(device, "connector");
+	igt_vkms_connector_connect(device, "connector");
+
+	igt_vkms_device_attach_encoder_to_connector(device, "connector", "encoder");
+	igt_vkms_device_attach_crtc_to_encoder(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_connector_connect(device, "connector");
+
+	igt_vkms_device_attach_plane_to_crtc(device, "primary", "crtc");
+	igt_vkms_device_attach_plane_to_crtc(device, "cursor", "crtc");
+	igt_vkms_device_attach_plane_to_crtc(device, "overlay0", "crtc");
+	igt_vkms_device_attach_plane_to_crtc(device, "overlay1", "crtc");
+	igt_vkms_device_attach_plane_to_crtc(device, "overlay2", "crtc");
+	igt_vkms_device_attach_plane_to_crtc(device, "overlay3", "crtc");
+	igt_vkms_device_attach_encoder_to_connector(device, "connector", "encoder");
+	igt_vkms_device_attach_crtc_to_encoder(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_connector_connect(device, "connector0");
+	igt_vkms_device_add_connector(device, "connector1");
+	igt_vkms_connector_connect(device, "connector1");
+
+	igt_vkms_device_attach_plane_to_crtc(device, "primary0", "crtc0");
+	igt_vkms_device_attach_plane_to_crtc(device, "cursor0", "crtc0");
+	igt_vkms_device_attach_plane_to_crtc(device, "overlay0", "crtc0");
+	igt_vkms_device_attach_plane_to_crtc(device, "overlay1", "crtc0");
+	igt_vkms_device_attach_plane_to_crtc(device, "overlay2", "crtc0");
+	igt_vkms_device_attach_plane_to_crtc(device, "overlay3", "crtc0");
+	igt_vkms_device_attach_encoder_to_connector(device, "connector0", "encoder0");
+	igt_vkms_device_attach_crtc_to_encoder(device, "encoder0", "crtc0");
+
+	igt_vkms_device_attach_plane_to_crtc(device, "primary1", "crtc1");
+	igt_vkms_device_attach_plane_to_crtc(device, "cursor1", "crtc1");
+	igt_vkms_device_attach_plane_to_crtc(device, "overlay0", "crtc1");
+	igt_vkms_device_attach_plane_to_crtc(device, "overlay1", "crtc1");
+	igt_vkms_device_attach_plane_to_crtc(device, "overlay2", "crtc1");
+	igt_vkms_device_attach_plane_to_crtc(device, "overlay3", "crtc1");
+	igt_vkms_device_attach_encoder_to_connector(device, "connector1", "encoder1");
+	igt_vkms_device_attach_crtc_to_encoder(device, "encoder1", "crtc1");
+
+	igt_vkms_enable(device);
+	igt_assert(igt_vkms_is_enabled(device));
+}
+
+static void disable_device(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_connector_connect(device, "connector");
+
+	igt_vkms_device_attach_plane_to_crtc(device, "primary", "crtc");
+	igt_vkms_device_attach_encoder_to_connector(device, "connector", "encoder");
+	igt_vkms_device_attach_crtc_to_encoder(device, "encoder", "crtc");
+
+	igt_vkms_enable(device);
+	igt_assert(igt_vkms_is_enabled(device));
+
+	igt_vkms_disable(device);
+	igt_assert(!igt_vkms_is_enabled(device));
+}
 
 igt_main
 {
@@ -72,6 +171,39 @@ igt_main
 		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 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_describe("Disable the device");
+	igt_subtest("disable_device")
+	{
+		igt_vkms_device_create(&device, "device-disable");
+		disable_device(&device);
+		igt_vkms_device_destroy(&device);
+	}
+
 	igt_fixture
 	{
 		igt_require_vkms();
-- 
2.40.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-09-01  9:28 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-09-01  9:28 [igt-dev] [PATCH i-g-t 0/4] Add vkms configfs testing Marius Vlad
2023-09-01  9:28 ` [igt-dev] [PATCH i-g-t 1/5] lib/drmtest: Add VKMS as a known driver type Marius Vlad
2023-09-01  9:28 ` [igt-dev] [PATCH i-g-t 2/5] lib/confifs: Add helpers for mounting/unmounting configfs Marius Vlad
2023-09-01  9:28 ` [igt-dev] [PATCH i-g-t 3/5] tests/vkms: Add a small library for VKMS testing Marius Vlad
2023-09-01  9:28 ` [igt-dev] [PATCH i-g-t 4/5] tests/vkms: Add more tests for VKMS Marius Vlad

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox