[igt-dev] [PATCH i-g-t 3/3] tests/vkms: Adds VKMS tests and library functions to support them

Kamil Konieczny kamil.konieczny at linux.intel.com
Wed Jun 28 19:27:28 UTC 2023


Hi James,

On 2023-06-23 at 19:09:54 -0400, James Shargo wrote:
> 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.

I will review lib changes but please find someone for review
from chromium or vkms dev.

> 
> 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.
> + *

Use SPDX licence instead, look at other lib files which uses
them. Also use checkpatch.pl

> + * 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"

Move this include after igt_aux.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";
---------------------- ^
You repeat this string here, why not make it const static ?

> +
> +	if (igt_is_mountpoint("/config"))
------------------------------ ^
> +		return "/config";
---------------------- ^
Same here.

> +
> +	if (mount("config", "/sys/kernel/config", "configfs", 0, 0))
> +		return NULL;
--------------- ^
Maybe print some debugs here.

> +
> +	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)

or NULL if failed

> + */
> +const char *igt_configfs_mount(void)
> +{
> +	static const char *path;
> +
> +	if (!path)
> +		path = __igt_configfs_mount();
> +
> +	return path;
> +}
> +

Add description.

> +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:

Incomplete descripton.

> + */
> +int igt_configfs_dir(void)
> +{
> +	const char *path = igt_configfs_mount();
> +
> +	if (!path)
> +		return -1;
> +
> +	igt_debug("Opening configfs directory '%s'\n", path);

Add newline.

> +	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.
> + *

Use SPDX. Note that .c and .h files have them a little different.

> + * 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
--------------------------------- ^^
Is it enough?

> +
> +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.
> + *

Use SPDX.

> + * 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"
----------- ^^
Move it after system includes, after itg_core.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();

Add newline.

> +	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);
> +}
> +

Add documentation to each new library function, here and below.

> +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)
------------------- ^^^
Where is it changing?

> +			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));

imho little better:
	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);
------------------ ^
Creating

> +
> +	ret = mkdir(device->device_dir, 0777);
> +	igt_assert_f(ret != 0,
> +		     "Unable to mkdir device directory '%s'. Got errno=%d (%s)\n",
------------------------------- ^
create

> +		     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));

imho better:
		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) {
-------------------- ^
No need for braces for single instruction.

> +		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.
> + *

Use SPDX.

> + * 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.
> + *

Add SPDX.

> + * 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();
------- ^
Move this into fixture.

> +
> +	// 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.");
--------------------- ^^^
Use "Check that we can" or "Verify that we can"

> +	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");
--------------------- ^^^
Same here.

> +	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");
--------------------- ^^^
Same here.

Please look also at GitLab compilation errors.

Regards,
Kamil

> +	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