[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251029-vkms-all-config-v2-17-a49a2d4cba26@bootlin.com>
Date: Wed, 29 Oct 2025 15:36:54 +0100
From: Louis Chauvet <louis.chauvet@...tlin.com>
To: Haneen Mohammed <hamohammed.sa@...il.com>, 
 Simona Vetter <simona@...ll.ch>, Melissa Wen <melissa.srw@...il.com>, 
 Maarten Lankhorst <maarten.lankhorst@...ux.intel.com>, 
 Maxime Ripard <mripard@...nel.org>, Thomas Zimmermann <tzimmermann@...e.de>, 
 David Airlie <airlied@...il.com>, jose.exposito89@...il.com, 
 Jonathan Corbet <corbet@....net>
Cc: victoria@...tem76.com, sebastian.wick@...hat.com, victoria@...tem76.com, 
 airlied@...il.com, thomas.petazzoni@...tlin.com, 
 dri-devel@...ts.freedesktop.org, linux-kernel@...r.kernel.org, 
 linux-doc@...r.kernel.org, Louis Chauvet <louis.chauvet@...tlin.com>
Subject: [PATCH RESEND v2 17/32] drm/vkms: Introduce configfs for plane
 format
To allow the userspace to test many hardware configuration, introduce a
new interface to configure the available formats per planes. VKMS supports
multiple formats, so the userspace can choose any combination.
The supported formats are configured by writing the fourcc code in
supported_formats:
 # enable AR24 format
  echo '+AR24' > /config/vkms/DEVICE_1/planes/PLANE_1/supported_formats
 # disable AR24 format
  echo '-AR24' > /config/vkms/DEVICE_1/planes/PLANE_1/supported_formats
 # enable all format supported by VKMS
  echo '+*' > /config/vkms/DEVICE_1/planes/PLANE_1/supported_formats
 # disable all formats
  echo '-*' > /config/vkms/DEVICE_1/planes/PLANE_1/supported_formats
Signed-off-by: Louis Chauvet <louis.chauvet@...tlin.com>
---
 Documentation/gpu/vkms.rst                      |   7 +-
 drivers/gpu/drm/vkms/tests/Makefile             |   1 +
 drivers/gpu/drm/vkms/tests/vkms_configfs_test.c | 102 ++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_configfs.c            | 119 ++++++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_configfs.h            |   6 ++
 5 files changed, 234 insertions(+), 1 deletion(-)
diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index 8383e1b94668..779ae363110d 100644
--- a/Documentation/gpu/vkms.rst
+++ b/Documentation/gpu/vkms.rst
@@ -87,7 +87,7 @@ Start by creating one or more planes::
 
   sudo mkdir /config/vkms/my-vkms/planes/plane0
 
-Planes have 8 configurable attributes:
+Planes have 9 configurable attributes:
 
 - type: Plane type: 0 overlay, 1 primary, 2 cursor (same values as those
   exposed by the "type" property of a plane)
@@ -109,6 +109,11 @@ Planes have 8 configurable attributes:
   must be set too.
 - default_color_range: Default color range presented to the userspace, same
   values as supported_color_range
+- supported_formats: List of supported formats for this plane. To add a new item in the
+  list, write it using a plus its fourcc code: +XR24
+  To remove a format, use a minus and its fourcc: -XR24
+  To add all formats use +*
+  To remove all formats, use -*
 
 Continue by creating one or more CRTCs::
 
diff --git a/drivers/gpu/drm/vkms/tests/Makefile b/drivers/gpu/drm/vkms/tests/Makefile
index 5750f0bd9d40..a2dc4008d27e 100644
--- a/drivers/gpu/drm/vkms/tests/Makefile
+++ b/drivers/gpu/drm/vkms/tests/Makefile
@@ -2,6 +2,7 @@
 
 vkms-kunit-tests-y := \
 	vkms_config_test.o \
+	vkms_configfs_test.o \
 	vkms_format_test.o
 
 obj-$(CONFIG_DRM_VKMS_KUNIT_TEST) += vkms-kunit-tests.o
diff --git a/drivers/gpu/drm/vkms/tests/vkms_configfs_test.c b/drivers/gpu/drm/vkms/tests/vkms_configfs_test.c
new file mode 100644
index 000000000000..0963a8e8a585
--- /dev/null
+++ b/drivers/gpu/drm/vkms/tests/vkms_configfs_test.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include "linux/printk.h"
+#include <kunit/test.h>
+
+#include "../vkms_configfs.h"
+
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+
+/**
+ * struct vkms_configfs_parse_format_case - Store test case for format parsing
+ * @data: Contains the string to parse
+ * @data_len: data len
+ * @expected_len: expected len of the matched format
+ * @expected_offset: expected offset in the string for the parsed format
+ */
+struct vkms_configfs_parse_format_case {
+	const char *data;
+	int data_len;
+	int expected_len;
+	int expected_offset;
+};
+
+struct vkms_configfs_parse_format_case vkms_configfs_parse_format_test_cases[] = {
+	{
+		.data = "+RG24",
+		.data_len = 6,
+		.expected_len = 5,
+		.expected_offset = 0,
+	}, {
+		.data = "-RG24",
+		.data_len = 6,
+		.expected_len = 5,
+		.expected_offset = 0
+	}, {
+		.data = "  -RG24",
+		.data_len = 8,
+		.expected_len = 5,
+		.expected_offset = 2
+	}, {
+		.data = "+*",
+		.data_len = 3,
+		.expected_len = 2,
+		.expected_offset = 0
+	}, {
+		.data = "-RG24+RG24",
+		.data_len = 11,
+		.expected_len = 5,
+		.expected_offset = 0
+	}, {
+		.data = "-R1+RG24",
+		.data_len = 9,
+		.expected_len = 3,
+		.expected_offset = 0
+	}, {
+		.data = "\n-R1",
+		.data_len = 5,
+		.expected_len = 3,
+		.expected_offset = 1
+	}, {
+		.data = "-R1111",
+		.data_len = 3,
+		.expected_len = 3,
+		.expected_offset = 0
+	}
+};
+
+static void vkms_configfs_test_parse_format(struct kunit *test)
+{
+	const struct vkms_configfs_parse_format_case *param = test->param_value;
+	char *out;
+	int len = vkms_configfs_parse_next_format(param->data, param->data + param->data_len, &out);
+
+	KUNIT_EXPECT_EQ(test, len, param->expected_len);
+	KUNIT_EXPECT_PTR_EQ(test, out, param->data + param->expected_offset);
+}
+
+static void vkms_configfs_test_parse_format_get_desc(struct vkms_configfs_parse_format_case *t,
+						     char *desc)
+{
+	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s", t->data);
+}
+
+KUNIT_ARRAY_PARAM(vkms_configfs_test_parse_format, vkms_configfs_parse_format_test_cases,
+		  vkms_configfs_test_parse_format_get_desc
+);
+
+static struct kunit_case vkms_configfs_test_cases[] = {
+	KUNIT_CASE_PARAM(vkms_configfs_test_parse_format,
+			 vkms_configfs_test_parse_format_gen_params),
+	{}
+};
+
+static struct kunit_suite vkms_configfs_test_suite = {
+	.name = "vkms-configfs",
+	.test_cases = vkms_configfs_test_cases,
+};
+
+kunit_test_suite(vkms_configfs_test_suite);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Kunit test for vkms configfs utility");
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index 3f658dd41272..b0a26c4dbebe 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -1,8 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0+
+
 #include <linux/cleanup.h>
 #include <linux/configfs.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/string.h>
+#include <kunit/visibility.h>
 
 #include "vkms_drv.h"
 #include "vkms_config.h"
@@ -618,6 +621,120 @@ static ssize_t plane_default_color_encoding_store(struct config_item *item,
 	return count;
 }
 
+static ssize_t plane_supported_formats_show(struct config_item *item, char *page)
+{
+	struct vkms_configfs_plane *plane;
+
+	plane = plane_item_to_vkms_configfs_plane(item);
+
+	page[0] = '\0';
+
+	scoped_guard(mutex, &plane->dev->lock) {
+		u32 *formats = vkms_config_plane_get_supported_formats(plane->config);
+
+		for (int i = 0;
+		     i < vkms_config_plane_get_supported_formats_count(plane->config);
+		     i++) {
+			char tmp[6] = { 0 };
+			const ssize_t ret = snprintf(tmp, ARRAY_SIZE(tmp), "%.*s\n",
+					       (int)sizeof(*formats),
+					       (char *)&formats[i]);
+			if (ret < 0)
+				return ret;
+			/*
+			 * Limitation of ConfigFS attributes, an attribute can't be bigger
+			 * than PAGE_SIZE. This will crop the result if this plane support
+			 * more than ≈1000 formats.
+			 */
+			if (ret + strlen(page) > PAGE_SIZE - 1)
+				return -ENOMEM;
+			strncat(page, tmp, ARRAY_SIZE(tmp));
+		}
+	}
+
+	return strlen(page);
+}
+
+/**
+ * parse_next_format() - Parse the next format in page, skipping all non fourcc-related characters
+ * @page: page to search into
+ * @page_end: last charater of the page
+ * @out: Output pointer, will point inside page
+ *
+ * Returns: size of the matched format, @out will point to the + or -
+ */
+VISIBLE_IF_KUNIT
+int vkms_configfs_parse_next_format(const char *page, const char *page_end, char **out)
+{
+	int count = page - page_end;
+	char *tmp_plus = strnchr(page, count, '+');
+	char *tmp_minus = strnchr(page, count, '-');
+
+	if (!tmp_plus && !tmp_minus)
+		return 0;
+	if (!tmp_plus)
+		*out = tmp_minus;
+	else if (!tmp_minus)
+		*out = tmp_plus;
+	else
+		*out = min(tmp_plus, tmp_minus);
+
+	char *end = *out + 1;
+
+	while (end < page_end) {
+		if (!isalnum(*end) && *end != '*')
+			break;
+		end++;
+	}
+
+	return end - *out;
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_configfs_parse_next_format);
+
+static ssize_t plane_supported_formats_store(struct config_item *item,
+					     const char *page, size_t count)
+{
+	struct vkms_configfs_plane *plane;
+
+	plane = plane_item_to_vkms_configfs_plane(item);
+	int ret = 0;
+	const char *end_page = page + count;
+
+	scoped_guard(mutex, &plane->dev->lock) {
+		while (1) {
+			char *tmp;
+			char fmt[4] = {' ', ' ', ' ', ' '};
+			int len = vkms_configfs_parse_next_format(page, end_page, &tmp);
+
+			// No fourcc code found
+			if (len <= 1)
+				break;
+
+			page = tmp + len;
+			memcpy(tmp, &fmt[1], min(len - 1, 4));
+			if (tmp[0] == '+') {
+				if (fmt[0] == '*') {
+					ret = vkms_config_plane_add_all_formats(plane->config);
+					if (ret)
+						return ret;
+				} else {
+					ret = vkms_config_plane_add_format(plane->config,
+									   *(int *)fmt);
+					if (ret)
+						return ret;
+				}
+			} else if (tmp[0] == '-') {
+				if (fmt[0] == '*')
+					vkms_config_plane_remove_all_formats(plane->config);
+				else
+					vkms_config_plane_remove_format(plane->config, *(int *)fmt);
+			}
+		}
+	}
+
+	return count;
+}
+
 CONFIGFS_ATTR(plane_, type);
 CONFIGFS_ATTR(plane_, name);
 CONFIGFS_ATTR(plane_, supported_rotations);
@@ -626,6 +743,7 @@ CONFIGFS_ATTR(plane_, supported_color_ranges);
 CONFIGFS_ATTR(plane_, default_color_range);
 CONFIGFS_ATTR(plane_, supported_color_encodings);
 CONFIGFS_ATTR(plane_, default_color_encoding);
+CONFIGFS_ATTR(plane_, supported_formats);
 
 static struct configfs_attribute *plane_item_attrs[] = {
 	&plane_attr_type,
@@ -636,6 +754,7 @@ static struct configfs_attribute *plane_item_attrs[] = {
 	&plane_attr_default_color_range,
 	&plane_attr_supported_color_encodings,
 	&plane_attr_default_color_encoding,
+	&plane_attr_supported_formats,
 	NULL,
 };
 
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.h b/drivers/gpu/drm/vkms/vkms_configfs.h
index e9020b0043db..2774655bfcc5 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.h
+++ b/drivers/gpu/drm/vkms/vkms_configfs.h
@@ -2,7 +2,13 @@
 #ifndef _VKMS_CONFIGFS_H_
 #define _VKMS_CONFIGFS_H_
 
+#include <linux/types.h>
+
 int vkms_configfs_register(void);
 void vkms_configfs_unregister(void);
 
+#if IS_ENABLED(CONFIG_KUNIT)
+int vkms_configfs_parse_next_format(const char *page, const char *end_page, char **out);
+#endif
+
 #endif /* _VKMS_CONFIGFS_H_ */
-- 
2.51.0
Powered by blists - more mailing lists
 
