* [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes
@ 2026-06-27 3:30 Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 01/38] drm/drm_mode_config: Add helper to get plane type name Louis Chauvet
` (37 more replies)
0 siblings, 38 replies; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm, José Expósito
VKMS have a wide range of options. The aim of this series is to introduce
many configfs attribute so VKMS can be used to test a wide range of
configurations.
PATCH 1-5 are to expose human readable strings from drm core
PATCH 6 is a fix for rotation value
PATCH 7 is ABI documentation
PATCH 8 added some error checks in plane configuration
PATCH 9 cleanup in plane_release
PATCH 10-12 change the display in configfs to be more readable
PATCH 13,14 plane name
PATCH 15,16 plane rotation
PATCH 17,18 plane color encoding
PATCH 19,20 plane color range
PATCH 21,22 plane format
PATCH 23 properly use zpos
PATCH 24,25 plane zpos
PATCH 26,27 connector type
PATCH 28 preparation in connector initialization
PATCH 29,30 connector supported colorspace
PATCH 31,32 connector EDID
PATCH 33-35 dynamic connectors
PATCH 36-37 PATH property
PS: Each pair of config/configfs patch are independant. I could
technically create ≈10 different series, but there will be a lot of
(trivial) conflicts between them. I will be happy to reordoer, split and
partially apply this series to help the review process.
PS2: I am currently cleaning the IGT test series to validate all that,
it should come on Monday/Tuesday
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
Changes in v5:
- Fixed missing property creation for PATH
- Use the folder name instead of a new attribute for plane
- Rebased on drm-misc-next
- Link to v4: https://patch.msgid.link/20260422-vkms-all-config-v4-0-dbb52e9aadc3@bootlin.com
Changes in v4:
- Introduced a way to change the PATH property
- Reordered drm-only patches to the front of the series.
- Fixed a bug when dynamic connector are allocated/freed (drmm instead of
kzalloc)
- Properly handle errors in vkms_connector_init
- Only parse formats one by one (no more complex algorithm, you will have
to write multiple times for multiple formats)
- Use sysfs_emit instead of sprintf
- Fix rotate property default value
- Link to v3: https://lore.kernel.org/r/20251222-vkms-all-config-v3-0-ba42dc3fb9ff@bootlin.com
Changes in v3:
- Added Documentation/ABI (Thomas Petazzoni)
- PATCH 2: Clarify return value
- PATCH 6,7: Avoid passing null to printf
- PATCH 7: Restrict plane name to A-Za-z0-9
- PATCH 12: Fix missing s
- PATCH 13: Add macro to avoid repetition, fix missing s, make code
consistent, remove wrong comment, properly check bit values
- PATCH 15: Fix missing s
- PATCH 16: Fix missing s, make code consistent, remove wrong comments,
properly check value and fix default_color_range value
- PATCH 17: Create function to reduce code complexity, fix missing s
- PATCH 18: Fix parsing, rename data, reject strings > 4 chars
- PATCH 20: Remove duplicated lines, fix test comments simplify conditions,
remove useless documentation,
- PATCH 21: {Min,Max}imal -> {Min,Max}imum, simplify commit log
- PATCH 25: Fix wrong comment
- PATCH 26: Rename type to colorspaces
- PATCH 27: Improve comment, avoid useless iterations
- PATCH 28: Fix typo in commit log
- PATCH 29: Fix typo in commit log
- PATCH 30: Remove useless include and move it to proper commit
- PATCH 32: Clarify documentation
- PATCH 33: Simplify code and use better variable names
- PATCH *: Fix EINVAL/EBUSY
- Link to v2: https://lore.kernel.org/r/20251029-vkms-all-config-v2-0-be20b9bf146e@bootlin.com
Changes in v2:
- PATCH 1: reorder includes (José)
- PATCH 2: use name property instead of folder name (José)
- PATCH 3: Fix default rotations (José)
- PATCH 3,5,7,12: Add tests and extract validation for planes (José)
- PATCH 3,5: Do not create color range/encoding properties if not set
- PATCH 5,6,7,8: Set plural form for vkms_config_plane fields (José)
- PATCH 4,6,8,13: Remove checking for default in supported (José)
- PATCH 9: Add break in vkms_config_plane_add_format (José)
- PATCH 12: fix zpos_enabled typo (José)
- PATCH 13: fix documentation (José)
- Add debug display (José)
- PATCH 20: use drmm_kzalloc instead of kzalloc (José)
- PATCH 22: simplify the code (José)
- Link to v1: https://lore.kernel.org/r/20251018-vkms-all-config-v1-0-a7760755d92d@bootlin.com
To: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
To: Maxime Ripard <mripard@kernel.org>
To: Thomas Zimmermann <tzimmermann@suse.de>
To: David Airlie <airlied@gmail.com>
To: Simona Vetter <simona@ffwll.ch>
To: Louis Chauvet <louis.chauvet@bootlin.com>
To: Haneen Mohammed <hamohammed.sa@gmail.com>
To: Melissa Wen <melissa.srw@gmail.com>
To: Jonathan Corbet <corbet@lwn.net>
To: Shuah Khan <skhan@linuxfoundation.org>
To: Miguel Ojeda <ojeda@kernel.org>
To: Nathan Chancellor <nathan@kernel.org>
To: Nick Desaulniers <nick.desaulniers+lkml@gmail.com>
To: Bill Wendling <morbo@google.com>
To: Justin Stitt <justinstitt@google.com>
Cc: thomas.petazzoni@bootlin.com
Cc: dri-devel@lists.freedesktop.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: llvm@lists.linux.dev
---
Louis Chauvet (38):
drm/drm_mode_config: Add helper to get plane type name
drm/blend: Get a rotation name from it's bitfield
drm/drm_color_mgmt: Expose drm_get_color_encoding_name
drm/drm_color_mgmt: Expose drm_get_color_range_name
drm/connector: Export drm_get_colorspace_name
drm/drm_atomic_state_helper: Properly load default value for rotation
Documentation: ABI: vkms: Add current VKMS ABI documentation
drm/vkms: Add error handling in plane config creation
drm/vkms: Simplify plane_release code
drm/vkms: Explicitly display plane type
drm/vkms: Use enabled/disabled instead of 1/0 for debug
drm/vkms: Explicitly display connector status
drm/vkms: Introduce config for plane name
drm/vkms: Use plane folder name as plane name
drm/vkms: Introduce config for plane rotation
drm/vkms: Use DRM_ROTATION_FMT macros for rotation display
drm/vkms: Introduce configfs for plane rotation
drm/vkms: Introduce config for plane color encoding
drm/vkms: Introduce configfs for plane color encoding
drm/vkms: Introduce config for plane color range
drm/vkms: Introduce configfs for plane color range
drm/vkms: Introduce config for plane format
drm/vkms: Introduce configfs for plane format
drm/vkms: Properly render plane using their zpos
drm/vkms: Introduce config for plane zpos property
drm/vkms: Introduce configfs for plane zpos property
drm/vkms: Introduce config for connector type
drm/vkms: Introduce configfs for connector type
drm/vkms: Rename vkms_connector_init to vkms_connector_init_static
drm/vkms: Introduce config for connector supported colorspace
drm/vkms: Introduce configfs for connector supported colorspace
drm/vkms: Introduce config for connector EDID
drm/vkms: Introduce configfs for connector EDID
drm/vkms: Store the enabled/disabled status for connector
drm/vkms: Allow to hot-add connectors
drm/vkms: Introduce configfs for dynamic connector creation
drm/vkms: Add connector parent configuration in vkms_config
drm/vkms: Add ConfigFS interface for connector parent and port_id
.clang-format | 2 +
Documentation/ABI/testing/configfs-vkms | 250 ++++
Documentation/gpu/vkms.rst | 44 +-
drivers/gpu/drm/drm_atomic_state_helper.c | 6 +
drivers/gpu/drm/drm_blend.c | 35 +-
drivers/gpu/drm/drm_color_mgmt.c | 4 +-
drivers/gpu/drm/drm_connector.c | 1 +
drivers/gpu/drm/drm_crtc_internal.h | 6 -
drivers/gpu/drm/drm_mode_config.c | 16 +
drivers/gpu/drm/vkms/tests/Makefile | 3 +-
drivers/gpu/drm/vkms/tests/vkms_config_test.c | 513 ++++++++-
drivers/gpu/drm/vkms/tests/vkms_configfs_test.c | 102 ++
drivers/gpu/drm/vkms/vkms_config.c | 421 ++++++-
drivers/gpu/drm/vkms/vkms_config.h | 641 ++++++++++-
drivers/gpu/drm/vkms/vkms_configfs.c | 1402 +++++++++++++++++++----
drivers/gpu/drm/vkms/vkms_configfs.h | 4 +
drivers/gpu/drm/vkms/vkms_connector.c | 268 ++++-
drivers/gpu/drm/vkms/vkms_connector.h | 48 +-
drivers/gpu/drm/vkms/vkms_crtc.c | 10 +-
drivers/gpu/drm/vkms/vkms_output.c | 15 +-
drivers/gpu/drm/vkms/vkms_plane.c | 73 +-
include/drm/drm_blend.h | 17 +
include/drm/drm_color_mgmt.h | 3 +
include/drm/drm_mode_config.h | 3 +
24 files changed, 3581 insertions(+), 306 deletions(-)
---
base-commit: 6648301c5bb2ef23f0fb15bcb01d21ff66f36799
change-id: 20251017-vkms-all-config-bd0c2a01846f
Best regards,
--
Louis Chauvet <louis.chauvet@bootlin.com>
^ permalink raw reply [flat|nested] 65+ messages in thread
* [PATCH v5 01/38] drm/drm_mode_config: Add helper to get plane type name
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 02/38] drm/blend: Get a rotation name from it's bitfield Louis Chauvet
` (36 subsequent siblings)
37 siblings, 0 replies; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm, José Expósito
Create and export an helper to display plane type using the
property string. This could be used to display debug
information in VKMS.
Reviewed-by: José Expósito <jose.exposito@redhat.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/drm_mode_config.c | 16 ++++++++++++++++
include/drm/drm_mode_config.h | 3 +++
2 files changed, 19 insertions(+)
diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
index f432f485a914..6f8a363ec6a1 100644
--- a/drivers/gpu/drm/drm_mode_config.c
+++ b/drivers/gpu/drm/drm_mode_config.c
@@ -414,6 +414,22 @@ static const struct drm_prop_enum_list drm_plane_type_enum_list[] = {
{ DRM_PLANE_TYPE_CURSOR, "Cursor" },
};
+/**
+ * drm_get_plane_type_name - return a string for plane name
+ * @type: plane type to compute name of
+ *
+ * Returns: The name of the plane type. "(unknown)" if type is not a known
+ * plane type.
+ */
+const char *drm_get_plane_type_name(enum drm_plane_type type)
+{
+ if (type >= 0 && type < ARRAY_SIZE(drm_plane_type_enum_list))
+ return drm_plane_type_enum_list[type].name;
+ else
+ return "(unknown)";
+}
+EXPORT_SYMBOL(drm_get_plane_type_name);
+
static int drm_mode_create_standard_properties(struct drm_device *dev)
{
struct drm_property *prop;
diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
index d8f5b7e9673e..20aed1ae2985 100644
--- a/include/drm/drm_mode_config.h
+++ b/include/drm/drm_mode_config.h
@@ -30,6 +30,7 @@
#include <linux/llist.h>
#include <drm/drm_modeset_lock.h>
+#include <drm/drm_plane.h>
struct drm_file;
struct drm_device;
@@ -1011,4 +1012,6 @@ int drm_mode_config_create_initial_state(struct drm_device *dev);
void drm_mode_config_reset(struct drm_device *dev);
void drm_mode_config_cleanup(struct drm_device *dev);
+const char *drm_get_plane_type_name(enum drm_plane_type type);
+
#endif
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 02/38] drm/blend: Get a rotation name from it's bitfield
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 01/38] drm/drm_mode_config: Add helper to get plane type name Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:41 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 03/38] drm/drm_color_mgmt: Expose drm_get_color_encoding_name Louis Chauvet
` (35 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
Having the rotation/reflection name from its value can be useful for
debugging purpose. Extract the rotation property table and implement
drm_get_rotation_name.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/drm_blend.c | 35 ++++++++++++++++++++++++++---------
include/drm/drm_blend.h | 17 +++++++++++++++++
2 files changed, 43 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c
index 2f0d1ba285be..eecdaf623c1e 100644
--- a/drivers/gpu/drm/drm_blend.c
+++ b/drivers/gpu/drm/drm_blend.c
@@ -256,6 +256,31 @@ int drm_plane_create_alpha_property(struct drm_plane *plane)
}
EXPORT_SYMBOL(drm_plane_create_alpha_property);
+static const struct drm_prop_enum_list rotation_props[] = {
+ { __builtin_ffs(DRM_MODE_ROTATE_0) - 1, "rotate-0" },
+ { __builtin_ffs(DRM_MODE_ROTATE_90) - 1, "rotate-90" },
+ { __builtin_ffs(DRM_MODE_ROTATE_180) - 1, "rotate-180" },
+ { __builtin_ffs(DRM_MODE_ROTATE_270) - 1, "rotate-270" },
+ { __builtin_ffs(DRM_MODE_REFLECT_X) - 1, "reflect-x" },
+ { __builtin_ffs(DRM_MODE_REFLECT_Y) - 1, "reflect-y" },
+};
+
+/**
+ * drm_get_rotation_name - Return the name of a rotation
+ * @rotation: The rotation mask (DRM_MODE_ROTATE_* | DRM_MODE_REFLECT_*)
+ *
+ * Returns: the name of the rotation type (unknown) if rotation is not
+ * a known rotation/reflection
+ */
+const char *drm_get_rotation_name(unsigned int rotation)
+{
+ if (rotation < ARRAY_SIZE(rotation_props))
+ return rotation_props[rotation].name;
+
+ return "(unknown)";
+}
+EXPORT_SYMBOL(drm_get_rotation_name);
+
/**
* drm_plane_create_rotation_property - create a new rotation property
* @plane: drm plane
@@ -294,14 +319,6 @@ int drm_plane_create_rotation_property(struct drm_plane *plane,
unsigned int rotation,
unsigned int supported_rotations)
{
- static const struct drm_prop_enum_list props[] = {
- { __builtin_ffs(DRM_MODE_ROTATE_0) - 1, "rotate-0" },
- { __builtin_ffs(DRM_MODE_ROTATE_90) - 1, "rotate-90" },
- { __builtin_ffs(DRM_MODE_ROTATE_180) - 1, "rotate-180" },
- { __builtin_ffs(DRM_MODE_ROTATE_270) - 1, "rotate-270" },
- { __builtin_ffs(DRM_MODE_REFLECT_X) - 1, "reflect-x" },
- { __builtin_ffs(DRM_MODE_REFLECT_Y) - 1, "reflect-y" },
- };
struct drm_property *prop;
WARN_ON((supported_rotations & DRM_MODE_ROTATE_MASK) == 0);
@@ -309,7 +326,7 @@ int drm_plane_create_rotation_property(struct drm_plane *plane,
WARN_ON(rotation & ~supported_rotations);
prop = drm_property_create_bitmask(plane->dev, 0, "rotation",
- props, ARRAY_SIZE(props),
+ rotation_props, ARRAY_SIZE(rotation_props),
supported_rotations);
if (!prop)
return -ENOMEM;
diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h
index bebbb77a8f21..33329170aafe 100644
--- a/include/drm/drm_blend.h
+++ b/include/drm/drm_blend.h
@@ -43,6 +43,23 @@ static inline bool drm_rotation_90_or_270(unsigned int rotation)
#define DRM_BLEND_ALPHA_OPAQUE 0xffff
+const char *drm_get_rotation_name(unsigned int rotation);
+
+#define DRM_ROTATION_FMT "%s%s%s%s%s%s%s%s%s%s%s%s"
+#define DRM_ROTATION_FMT_ARGS(rot) \
+ (rot) & DRM_MODE_ROTATE_0 ? drm_get_rotation_name(0) : "", \
+ (rot) & DRM_MODE_ROTATE_0 ? " " : "", \
+ (rot) & DRM_MODE_ROTATE_90 ? drm_get_rotation_name(1) : "", \
+ (rot) & DRM_MODE_ROTATE_90 ? " " : "", \
+ (rot) & DRM_MODE_ROTATE_180 ? drm_get_rotation_name(2) : "", \
+ (rot) & DRM_MODE_ROTATE_180 ? " " : "", \
+ (rot) & DRM_MODE_ROTATE_270 ? drm_get_rotation_name(3) : "", \
+ (rot) & DRM_MODE_ROTATE_270 ? " " : "", \
+ (rot) & DRM_MODE_REFLECT_X ? drm_get_rotation_name(4) : "", \
+ (rot) & DRM_MODE_REFLECT_X ? " " : "", \
+ (rot) & DRM_MODE_REFLECT_Y ? drm_get_rotation_name(5) : "", \
+ (rot) & DRM_MODE_REFLECT_Y ? " " : ""
+
int drm_plane_create_alpha_property(struct drm_plane *plane);
int drm_plane_create_rotation_property(struct drm_plane *plane,
unsigned int rotation,
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 03/38] drm/drm_color_mgmt: Expose drm_get_color_encoding_name
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 01/38] drm/drm_mode_config: Add helper to get plane type name Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 02/38] drm/blend: Get a rotation name from it's bitfield Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 04/38] drm/drm_color_mgmt: Expose drm_get_color_range_name Louis Chauvet
` (34 subsequent siblings)
37 siblings, 0 replies; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
drm_get_color_encoding_name can be useful to display debug information
outside drm core. Export it so it could be used for VKMS
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/drm_color_mgmt.c | 2 +-
drivers/gpu/drm/drm_crtc_internal.h | 2 --
include/drm/drm_color_mgmt.h | 2 ++
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c
index 3bcf82cf61a7..b5635862dc91 100644
--- a/drivers/gpu/drm/drm_color_mgmt.c
+++ b/drivers/gpu/drm/drm_color_mgmt.c
@@ -496,7 +496,7 @@ const char *drm_get_color_encoding_name(enum drm_color_encoding encoding)
return color_encoding_name[encoding];
}
-EXPORT_SYMBOL_IF_KUNIT(drm_get_color_encoding_name);
+EXPORT_SYMBOL(drm_get_color_encoding_name);
/**
* drm_get_color_range_name - return a string for color range
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index 83146ffef00c..bcd23eb0e531 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -38,7 +38,6 @@
#include <linux/err.h>
#include <linux/types.h>
-enum drm_color_encoding;
enum drm_color_range;
enum drm_connector_force;
enum drm_mode_status;
@@ -121,7 +120,6 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
/* drm_color_mgmt.c */
-const char *drm_get_color_encoding_name(enum drm_color_encoding encoding);
const char *drm_get_color_range_name(enum drm_color_range range);
/* IOCTLs */
diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h
index 5140691f476a..133ca77d91c7 100644
--- a/include/drm/drm_color_mgmt.h
+++ b/include/drm/drm_color_mgmt.h
@@ -113,6 +113,8 @@ enum drm_color_range {
DRM_COLOR_RANGE_MAX,
};
+const char *drm_get_color_encoding_name(enum drm_color_encoding encoding);
+
int drm_plane_create_color_properties(struct drm_plane *plane,
u32 supported_encodings,
u32 supported_ranges,
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 04/38] drm/drm_color_mgmt: Expose drm_get_color_range_name
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (2 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 03/38] drm/drm_color_mgmt: Expose drm_get_color_encoding_name Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 05/38] drm/connector: Export drm_get_colorspace_name Louis Chauvet
` (33 subsequent siblings)
37 siblings, 0 replies; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
drm_get_color_range_name can be useful to print debugging information.
Export it so it could be used from VKMS.
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/drm_color_mgmt.c | 2 +-
drivers/gpu/drm/drm_crtc_internal.h | 4 ----
include/drm/drm_color_mgmt.h | 1 +
3 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/drm_color_mgmt.c b/drivers/gpu/drm/drm_color_mgmt.c
index b5635862dc91..8ec87d1c7433 100644
--- a/drivers/gpu/drm/drm_color_mgmt.c
+++ b/drivers/gpu/drm/drm_color_mgmt.c
@@ -512,7 +512,7 @@ const char *drm_get_color_range_name(enum drm_color_range range)
return color_range_name[range];
}
-EXPORT_SYMBOL_IF_KUNIT(drm_get_color_range_name);
+EXPORT_SYMBOL(drm_get_color_range_name);
/**
* drm_plane_create_color_properties - color encoding related plane properties
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index bcd23eb0e531..4bf6bc0bcb5a 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -38,7 +38,6 @@
#include <linux/err.h>
#include <linux/types.h>
-enum drm_color_range;
enum drm_connector_force;
enum drm_mode_status;
@@ -119,9 +118,6 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
-/* drm_color_mgmt.c */
-const char *drm_get_color_range_name(enum drm_color_range range);
-
/* IOCTLs */
int drm_mode_gamma_get_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
diff --git a/include/drm/drm_color_mgmt.h b/include/drm/drm_color_mgmt.h
index 133ca77d91c7..e91f494e5a63 100644
--- a/include/drm/drm_color_mgmt.h
+++ b/include/drm/drm_color_mgmt.h
@@ -114,6 +114,7 @@ enum drm_color_range {
};
const char *drm_get_color_encoding_name(enum drm_color_encoding encoding);
+const char *drm_get_color_range_name(enum drm_color_range range);
int drm_plane_create_color_properties(struct drm_plane *plane,
u32 supported_encodings,
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 05/38] drm/connector: Export drm_get_colorspace_name
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (3 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 04/38] drm/drm_color_mgmt: Expose drm_get_color_range_name Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 06/38] drm/drm_atomic_state_helper: Properly load default value for rotation Louis Chauvet
` (32 subsequent siblings)
37 siblings, 0 replies; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
Export drm_get_colorspace_name so it could be used by VKMS
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/drm_connector.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index cbb067d02cb9..4b2c7c09ba69 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1386,6 +1386,7 @@ const char *drm_get_colorspace_name(enum drm_colorspace colorspace)
else
return "(null)";
}
+EXPORT_SYMBOL(drm_get_colorspace_name);
static const u32 hdmi_colorspaces =
BIT(DRM_MODE_COLORIMETRY_SMPTE_170M_YCC) |
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 06/38] drm/drm_atomic_state_helper: Properly load default value for rotation
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (4 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 05/38] drm/connector: Export drm_get_colorspace_name Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 07/38] Documentation: ABI: vkms: Add current VKMS ABI documentation Louis Chauvet
` (31 subsequent siblings)
37 siblings, 0 replies; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
Currently, the default rotation is always DRM_MODE_ROTATE_0 for all planes.
Some planes may have a rotation property, and the property may specify a
different default value and supported values.
This is not an issue for "fixed" configurations, but with the introduction
of VKMS configuration, some plane may only support 90° and 180°
rotations, so the reset state of the plane was wrong (forced to 0°).
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/drm_atomic_state_helper.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index d90d1d7c9cf9..7fe612c4da83 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -32,6 +32,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_framebuffer.h>
+#include <drm/drm_mode_object.h>
#include <drm/drm_plane.h>
#include <drm/drm_print.h>
#include <drm/drm_vblank.h>
@@ -276,6 +277,11 @@ void __drm_atomic_helper_plane_state_init(struct drm_plane_state *plane_state,
plane_state->plane = plane;
plane_state->rotation = DRM_MODE_ROTATE_0;
+ if (plane->rotation_property &&
+ !drm_object_property_get_default_value(&plane->base,
+ plane->rotation_property,
+ &val))
+ plane_state->rotation = val;
plane_state->alpha = DRM_BLEND_ALPHA_OPAQUE;
plane_state->pixel_blend_mode = DRM_MODE_BLEND_PREMULTI;
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 07/38] Documentation: ABI: vkms: Add current VKMS ABI documentation
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (5 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 06/38] drm/drm_atomic_state_helper: Properly load default value for rotation Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 08/38] drm/vkms: Add error handling in plane config creation Louis Chauvet
` (30 subsequent siblings)
37 siblings, 0 replies; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
VKMS recently introduced a ConfigFS API to configure new devices.
Add proper ABI documentation.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
Documentation/ABI/testing/configfs-vkms | 118 ++++++++++++++++++++++++++++++++
1 file changed, 118 insertions(+)
diff --git a/Documentation/ABI/testing/configfs-vkms b/Documentation/ABI/testing/configfs-vkms
new file mode 100644
index 000000000000..a1a3e186e50a
--- /dev/null
+++ b/Documentation/ABI/testing/configfs-vkms
@@ -0,0 +1,118 @@
+What: /sys/kernel/config/vkms/
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ This group contains sub-groups corresponding to created
+ VKMS devices.
+
+What: /sys/kernel/config/vkms/<device>
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ This group contains sub-groups corresponding to the VKMS
+ device <device>.
+
+What: /sys/kernel/config/vkms/<device>/connectors
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ This group contains sub-groups corresponding to the
+ connectors of the VKMS device <device>.
+
+What: /sys/kernel/config/vkms/<device>/connectors/<connector>
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ This group contains attributes corresponding to the
+ connector <connector> of the VKMS device <device>.
+
+What: /sys/kernel/config/vkms/<device>/connectors/<connector>/status
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Connection status of the connector. Possible values:
+ 1 - connected, 2 - disconnected, 3 - unknown.
+
+What: /sys/kernel/config/vkms/<device>/connectors/<connector>/possible_encoders
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ This group contains symbolic links to possible encoders
+ for this connector.
+
+What: /sys/kernel/config/vkms/<device>/crtcs
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ This group contains sub-groups corresponding to the
+ CRTCs of the VKMS device <device>.
+
+What: /sys/kernel/config/vkms/<device>/crtcs/<crtc>
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ This group contains attributes corresponding to the
+ CRTC <crtc> of the VKMS device <device>.
+
+What: /sys/kernel/config/vkms/<device>/crtcs/<crtc>/writeback
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Enable or disable writeback connector support for this
+ CRTC. Value: 1 - enabled, 0 - disabled.
+
+What: /sys/kernel/config/vkms/<device>/encoders
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ This group contains sub-groups corresponding to the
+ encoders of the VKMS device <device>.
+
+What: /sys/kernel/config/vkms/<device>/encoders/<encoder>
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ This group contains attributes corresponding to the
+ encoder <encoder> of the VKMS device <device>.
+
+What: /sys/kernel/config/vkms/<device>/encoders/<encoder>/possible_crtcs
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ This group contains symbolic links to possible CRTCs
+ for this encoder.
+
+What: /sys/kernel/config/vkms/<device>/planes
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ This group contains sub-groups corresponding to the
+ planes of the VKMS device <device>.
+
+What: /sys/kernel/config/vkms/<device>/planes/<plane>
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ This group contains attributes corresponding to the
+ plane <plane> of the VKMS device <device>.
+
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/type
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Plane type. Possible values: 0 - overlay, 1 - primary,
+ 2 - cursor.
+
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/possible_crtcs
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ This group contains symbolic links to possible CRTCs
+ for this plane.
+
+What: /sys/kernel/config/vkms/<device>/enabled
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Enable or disable the VKMS device. Value: 1 - enabled,
+ 0 - disabled.
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 08/38] drm/vkms: Add error handling in plane config creation
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (6 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 07/38] Documentation: ABI: vkms: Add current VKMS ABI documentation Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:41 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 09/38] drm/vkms: Simplify plane_release code Louis Chauvet
` (29 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
For future patches, it is useful to properly handle errors in
vkms_config_create_plane.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/vkms_config.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 5a654d6dead8..1fd2ed1167c5 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -384,13 +384,16 @@ void vkms_config_register_debugfs(struct vkms_device *vkms_device)
ARRAY_SIZE(vkms_config_debugfs_list));
}
-struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *config)
+struct vkms_config_plane __must_check *vkms_config_create_plane(struct vkms_config *config)
{
struct vkms_config_plane *plane_cfg;
+ int ret;
plane_cfg = kzalloc_obj(*plane_cfg);
- if (!plane_cfg)
- return ERR_PTR(-ENOMEM);
+ if (!plane_cfg) {
+ ret = -ENOMEM;
+ goto fail;
+ }
plane_cfg->config = config;
plane_cfg->default_pipeline = false;
@@ -400,6 +403,9 @@ struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *config)
list_add_tail(&plane_cfg->link, &config->planes);
return plane_cfg;
+
+fail:
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_plane);
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 09/38] drm/vkms: Simplify plane_release code
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (7 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 08/38] drm/vkms: Add error handling in plane config creation Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 10/38] drm/vkms: Explicitly display plane type Louis Chauvet
` (28 subsequent siblings)
37 siblings, 0 replies; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
plane_release code used multiple intermediate variable, remove those in
favor of direct access.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/vkms_configfs.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index 7551b8c7766d..97f87a53d202 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -333,13 +333,9 @@ static struct configfs_attribute *plane_item_attrs[] = {
static void plane_release(struct config_item *item)
{
- struct vkms_configfs_plane *plane;
- struct mutex *lock;
-
- plane = plane_item_to_vkms_configfs_plane(item);
- lock = &plane->dev->lock;
+ struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
- scoped_guard(mutex, lock) {
+ scoped_guard(mutex, &plane->dev->lock) {
vkms_config_destroy_plane(plane->config);
kfree(plane);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 10/38] drm/vkms: Explicitly display plane type
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (8 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 09/38] drm/vkms: Simplify plane_release code Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 11/38] drm/vkms: Use enabled/disabled instead of 1/0 for debug Louis Chauvet
` (27 subsequent siblings)
37 siblings, 0 replies; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm, José Expósito
Debug information are mainly read by human, so use full name instead
of values.
Reviewed-by: José Expósito <jose.exposito@redhat.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/vkms_config.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 1fd2ed1167c5..469c57c6d1e8 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -352,8 +352,8 @@ static int vkms_config_show(struct seq_file *m, void *data)
vkms_config_for_each_plane(vkmsdev->config, plane_cfg) {
seq_puts(m, "plane:\n");
- seq_printf(m, "\ttype=%d\n",
- vkms_config_plane_get_type(plane_cfg));
+ seq_printf(m, "\ttype=%s\n",
+ drm_get_plane_type_name(vkms_config_plane_get_type(plane_cfg)));
}
vkms_config_for_each_crtc(vkmsdev->config, crtc_cfg) {
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 11/38] drm/vkms: Use enabled/disabled instead of 1/0 for debug
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (9 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 10/38] drm/vkms: Explicitly display plane type Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 12/38] drm/vkms: Explicitly display connector status Louis Chauvet
` (26 subsequent siblings)
37 siblings, 0 replies; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm, José Expósito
Debug information are mainly read by human, so display human
readable values.
Reviewed-by: José Expósito <jose.exposito@redhat.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/vkms_config.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 469c57c6d1e8..4c6f3ead51d7 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
#include <linux/slab.h>
+#include <linux/string_choices.h>
#include <drm/drm_print.h>
#include <drm/drm_debugfs.h>
@@ -358,8 +359,8 @@ static int vkms_config_show(struct seq_file *m, void *data)
vkms_config_for_each_crtc(vkmsdev->config, crtc_cfg) {
seq_puts(m, "crtc:\n");
- seq_printf(m, "\twriteback=%d\n",
- vkms_config_crtc_get_writeback(crtc_cfg));
+ seq_printf(m, "\twriteback=%s\n",
+ str_enabled_disabled(vkms_config_crtc_get_writeback(crtc_cfg)));
}
vkms_config_for_each_encoder(vkmsdev->config, encoder_cfg)
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 12/38] drm/vkms: Explicitly display connector status
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (10 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 11/38] drm/vkms: Use enabled/disabled instead of 1/0 for debug Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 13/38] drm/vkms: Introduce config for plane name Louis Chauvet
` (25 subsequent siblings)
37 siblings, 0 replies; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm, José Expósito
Debug information are mainly read by human, so use full name instead
of raw values for connector status.
Reviewed-by: José Expósito <jose.exposito@redhat.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/vkms_config.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 4c6f3ead51d7..9071d6864d52 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -3,6 +3,7 @@
#include <linux/slab.h>
#include <linux/string_choices.h>
+#include <drm/drm_connector.h>
#include <drm/drm_print.h>
#include <drm/drm_debugfs.h>
#include <kunit/visibility.h>
@@ -368,8 +369,8 @@ static int vkms_config_show(struct seq_file *m, void *data)
vkms_config_for_each_connector(vkmsdev->config, connector_cfg) {
seq_puts(m, "connector:\n");
- seq_printf(m, "\tstatus=%d\n",
- vkms_config_connector_get_status(connector_cfg));
+ seq_printf(m, "\tstatus=%s\n",
+ drm_get_connector_status_name(vkms_config_connector_get_status(connector_cfg)));
}
return 0;
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 13/38] drm/vkms: Introduce config for plane name
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (11 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 12/38] drm/vkms: Explicitly display connector status Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:46 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 14/38] drm/vkms: Use plane folder name as " Louis Chauvet
` (24 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
As planes can have a name in DRM, prepare VKMS to configure it using
ConfigFS.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/vkms_config.c | 11 +++++++++++
drivers/gpu/drm/vkms/vkms_config.h | 34 ++++++++++++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_plane.c | 3 ++-
3 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 9071d6864d52..54994f3c8e14 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -356,6 +356,9 @@ static int vkms_config_show(struct seq_file *m, void *data)
seq_puts(m, "plane:\n");
seq_printf(m, "\ttype=%s\n",
drm_get_plane_type_name(vkms_config_plane_get_type(plane_cfg)));
+ seq_printf(m, "\tname=%s\n",
+ vkms_config_plane_get_name(plane_cfg) ?
+ vkms_config_plane_get_name(plane_cfg) : "(null)");
}
vkms_config_for_each_crtc(vkmsdev->config, crtc_cfg) {
@@ -400,12 +403,19 @@ struct vkms_config_plane __must_check *vkms_config_create_plane(struct vkms_conf
plane_cfg->config = config;
plane_cfg->default_pipeline = false;
vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_OVERLAY);
+
+ ret = vkms_config_plane_set_name(plane_cfg, NULL, 0);
+ if (ret)
+ goto cleanup_plane_cfg;
+
xa_init_flags(&plane_cfg->possible_crtcs, XA_FLAGS_ALLOC);
list_add_tail(&plane_cfg->link, &config->planes);
return plane_cfg;
+cleanup_plane_cfg:
+ kfree(plane_cfg);
fail:
return ERR_PTR(ret);
}
@@ -415,6 +425,7 @@ void vkms_config_destroy_plane(struct vkms_config_plane *plane_cfg)
{
xa_destroy(&plane_cfg->possible_crtcs);
list_del(&plane_cfg->link);
+ kfree(plane_cfg->name);
kfree(plane_cfg);
}
EXPORT_SYMBOL_IF_KUNIT(vkms_config_destroy_plane);
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 8f7f286a4bdd..e34f4cbfe8b8 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -3,6 +3,7 @@
#ifndef _VKMS_CONFIG_H_
#define _VKMS_CONFIG_H_
+#include <linux/string.h>
#include <linux/list.h>
#include <linux/types.h>
#include <linux/xarray.h>
@@ -35,6 +36,7 @@ struct vkms_config {
*
* @link: Link to the others planes in vkms_config
* @config: The vkms_config this plane belongs to
+ * @name: Name of the plane
* @type: Type of the plane. The creator of configuration needs to ensures that
* at least one primary plane is present.
* @possible_crtcs: Array of CRTCs that can be used with this plane
@@ -47,6 +49,7 @@ struct vkms_config_plane {
struct list_head link;
struct vkms_config *config;
+ const char *name;
enum drm_plane_type type;
struct xarray possible_crtcs;
bool default_pipeline;
@@ -314,6 +317,37 @@ vkms_config_plane_set_default_pipeline(struct vkms_config_plane *plane_cfg,
plane_cfg->default_pipeline = default_pipeline;
}
+/**
+ * vkms_config_plane_set_name() - Set the plane name
+ * @plane_cfg: Plane to set the name to
+ * @name: New plane name. The name is copied.
+ *
+ * Returns: -ENOMEM if the memory allocation failed, 0 in case of success
+ */
+static inline int __must_check
+vkms_config_plane_set_name(struct vkms_config_plane *plane_cfg,
+ const char *name, size_t name_len)
+{
+ kfree(plane_cfg->name);
+
+ plane_cfg->name = kmemdup_nul(name, name_len, GFP_KERNEL);
+
+ if (name && !plane_cfg->name)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * vkms_config_plane_get_name - Get the plane name
+ * @plane_cfg: Plane to get the name from
+ */
+static inline const char *
+vkms_config_plane_get_name(const struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->name;
+}
+
/**
* vkms_config_plane_attach_crtc - Attach a plane to a CRTC
* @plane_cfg: Plane to attach
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index 68cb2a3335e6..f35120203124 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -11,6 +11,7 @@
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_print.h>
+#include "vkms_config.h"
#include "vkms_drv.h"
#include "vkms_formats.h"
@@ -228,7 +229,7 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
&vkms_plane_funcs,
vkms_formats, ARRAY_SIZE(vkms_formats),
NULL, vkms_config_plane_get_type(plane_cfg),
- NULL);
+ vkms_config_plane_get_name(plane_cfg));
if (IS_ERR(plane))
return plane;
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 14/38] drm/vkms: Use plane folder name as plane name
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (12 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 13/38] drm/vkms: Introduce config for plane name Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:43 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 15/38] drm/vkms: Introduce config for plane rotation Louis Chauvet
` (23 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
The plane name is now directly derived from the configfs folder
name. When a plane directory is created under
/config/vkms/<device>/planes/, the folder name is used as the
plane name via vkms_config_plane_set_name.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/vkms_configfs.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index 97f87a53d202..0744ac40814d 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -377,6 +377,12 @@ static struct config_group *make_plane_group(struct config_group *group,
return ERR_PTR(ret);
}
+ ret = vkms_config_plane_set_name(plane->config, name, strlen(name));
+ if (ret) {
+ kfree(plane);
+ return ERR_PTR(ret);
+ }
+
config_group_init_type_name(&plane->group, name, &plane_item_type);
config_group_init_type_name(&plane->possible_crtcs_group,
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 15/38] drm/vkms: Introduce config for plane rotation
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (13 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 14/38] drm/vkms: Use plane folder name as " Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:42 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 16/38] drm/vkms: Use DRM_ROTATION_FMT macros for rotation display Louis Chauvet
` (22 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
VKMS driver supports all the rotation on planes, but for testing it can be
useful to only advertise few of them. This new configuration interface
will allow configuring the rotation per planes.
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/tests/vkms_config_test.c | 46 +++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_config.c | 38 +++++++++++++++++
drivers/gpu/drm/vkms/vkms_config.h | 59 +++++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_plane.c | 5 ++-
4 files changed, 146 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
index 1e4ea1863420..c33fe737678f 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_config_test.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
+#include <drm/drm_mode.h>
#include <kunit/test.h>
#include "../vkms_config.h"
@@ -185,6 +186,12 @@ static void vkms_config_test_default_config(struct kunit *test)
n_possible_crtcs++;
}
KUNIT_EXPECT_EQ(test, n_possible_crtcs, 1);
+ KUNIT_EXPECT_EQ(test,
+ vkms_config_plane_get_supported_rotations(plane_cfg),
+ DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK);
+ KUNIT_EXPECT_EQ(test,
+ vkms_config_plane_get_default_rotation(plane_cfg),
+ DRM_MODE_ROTATE_0);
}
/* Encoders */
@@ -481,6 +488,44 @@ static void vkms_config_test_valid_plane_type(struct kunit *test)
vkms_config_destroy(config);
}
+static void vkms_config_test_valid_plane_rotations(struct kunit *test)
+{
+ struct vkms_config *config;
+ struct vkms_config_plane *plane_cfg;
+
+ config = vkms_config_default_create(false, false, false, false);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
+
+ plane_cfg = get_first_plane(config);
+
+ /* Valid, no rotation, no reflection */
+ vkms_config_plane_set_supported_rotations(plane_cfg, DRM_MODE_ROTATE_0);
+ vkms_config_plane_set_default_rotation(plane_cfg, DRM_MODE_ROTATE_0);
+ KUNIT_EXPECT_TRUE(test, vkms_config_valid_plane_rotation(config, plane_cfg));
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Invalid, default rotation is not supported */
+ vkms_config_plane_set_supported_rotations(plane_cfg, DRM_MODE_ROTATE_0);
+ vkms_config_plane_set_default_rotation(plane_cfg, DRM_MODE_ROTATE_90);
+ KUNIT_EXPECT_FALSE(test, vkms_config_valid_plane_rotation(config, plane_cfg));
+ KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
+
+ /* Invalid, supported rotations must contains at least one rotation */
+ vkms_config_plane_set_supported_rotations(plane_cfg, DRM_MODE_REFLECT_MASK);
+ vkms_config_plane_set_default_rotation(plane_cfg, DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_0);
+ KUNIT_EXPECT_FALSE(test, vkms_config_valid_plane_rotation(config, plane_cfg));
+ KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
+
+ /* Invalid, default rotation must contains at least one rotation */
+ vkms_config_plane_set_supported_rotations(plane_cfg,
+ DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0);
+ vkms_config_plane_set_default_rotation(plane_cfg, DRM_MODE_REFLECT_X);
+ KUNIT_EXPECT_FALSE(test, vkms_config_valid_plane_rotation(config, plane_cfg));
+ KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
+
+ vkms_config_destroy(config);
+}
+
static void vkms_config_test_valid_plane_possible_crtcs(struct kunit *test)
{
struct vkms_config *config;
@@ -1003,6 +1048,7 @@ static struct kunit_case vkms_config_test_cases[] = {
KUNIT_CASE(vkms_config_test_get_connectors),
KUNIT_CASE(vkms_config_test_invalid_plane_number),
KUNIT_CASE(vkms_config_test_valid_plane_type),
+ KUNIT_CASE(vkms_config_test_valid_plane_rotations),
KUNIT_CASE(vkms_config_test_valid_plane_possible_crtcs),
KUNIT_CASE(vkms_config_test_invalid_crtc_number),
KUNIT_CASE(vkms_config_test_invalid_encoder_number),
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 54994f3c8e14..5c86eb24fedf 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -4,6 +4,7 @@
#include <linux/string_choices.h>
#include <drm/drm_connector.h>
+#include <drm/drm_mode.h>
#include <drm/drm_print.h>
#include <drm/drm_debugfs.h>
#include <kunit/visibility.h>
@@ -150,6 +151,33 @@ static bool valid_plane_number(const struct vkms_config *config)
return true;
}
+VISIBLE_IF_KUNIT
+bool vkms_config_valid_plane_rotation(const struct vkms_config *config,
+ const struct vkms_config_plane *plane_cfg)
+{
+ struct drm_device *dev = config->dev ? &config->dev->drm : NULL;
+
+ if ((vkms_config_plane_get_default_rotation(plane_cfg) &
+ vkms_config_plane_get_supported_rotations(plane_cfg)) !=
+ vkms_config_plane_get_default_rotation(plane_cfg)) {
+ drm_info(dev, "Configured default rotation is not supported by the plane\n");
+ return false;
+ }
+
+ if ((vkms_config_plane_get_default_rotation(plane_cfg) & DRM_MODE_ROTATE_MASK) == 0) {
+ drm_info(dev, "Configured default rotation must contains at least one possible rotation\n");
+ return false;
+ }
+
+ if ((vkms_config_plane_get_supported_rotations(plane_cfg) & DRM_MODE_ROTATE_MASK) == 0) {
+ drm_info(dev, "Configured supported rotations must contains at least one possible rotation\n");
+ return false;
+ }
+
+ return true;
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_valid_plane_rotation);
+
static bool valid_planes_for_crtc(const struct vkms_config *config,
struct vkms_config_crtc *crtc_cfg)
{
@@ -307,6 +335,12 @@ static bool valid_connector_possible_encoders(const struct vkms_config *config)
bool vkms_config_is_valid(const struct vkms_config *config)
{
struct vkms_config_crtc *crtc_cfg;
+ struct vkms_config_plane *plane_cfg;
+
+ vkms_config_for_each_plane(config, plane_cfg) {
+ if (!vkms_config_valid_plane_rotation(config, plane_cfg))
+ return false;
+ }
if (!valid_plane_number(config))
return false;
@@ -408,6 +442,10 @@ struct vkms_config_plane __must_check *vkms_config_create_plane(struct vkms_conf
if (ret)
goto cleanup_plane_cfg;
+ vkms_config_plane_set_supported_rotations(plane_cfg,
+ DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK);
+ vkms_config_plane_set_default_rotation(plane_cfg, DRM_MODE_ROTATE_0);
+
xa_init_flags(&plane_cfg->possible_crtcs, XA_FLAGS_ALLOC);
list_add_tail(&plane_cfg->link, &config->planes);
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index e34f4cbfe8b8..b5884ac0f42f 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -40,6 +40,8 @@ struct vkms_config {
* @type: Type of the plane. The creator of configuration needs to ensures that
* at least one primary plane is present.
* @possible_crtcs: Array of CRTCs that can be used with this plane
+ * @default_rotation: Default rotation that should be used by this plane
+ * @supported_rotation: Rotation that this plane will support
* @plane: Internal usage. This pointer should never be considered as valid.
* It can be used to store a temporary reference to a VKMS plane during
* device creation. This pointer is not managed by the configuration and
@@ -51,6 +53,8 @@ struct vkms_config_plane {
const char *name;
enum drm_plane_type type;
+ unsigned int default_rotation;
+ unsigned int supported_rotations;
struct xarray possible_crtcs;
bool default_pipeline;
@@ -317,6 +321,61 @@ vkms_config_plane_set_default_pipeline(struct vkms_config_plane *plane_cfg,
plane_cfg->default_pipeline = default_pipeline;
}
+/**
+ * vkms_config_plane_get_default_rotation() - Get the default rotation for a plane
+ * @plane_cfg: Plane to get the default rotation from
+ *
+ * Returns:
+ * The default rotation for the plane.
+ */
+static inline unsigned int
+vkms_config_plane_get_default_rotation(const struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->default_rotation;
+}
+
+/**
+ * vkms_config_plane_set_default_rotation() - Set the default rotation for a plane
+ * @plane_cfg: Plane to set the default rotation to
+ * @default_rotation: New default rotation for the plane
+ */
+static inline void
+vkms_config_plane_set_default_rotation(struct vkms_config_plane *plane_cfg,
+ unsigned int default_rotation)
+{
+ plane_cfg->default_rotation = default_rotation;
+}
+
+/**
+ * vkms_config_plane_get_supported_rotations() - Get the supported rotations for a plane
+ * @plane_cfg: Plane to get the supported rotations from
+ *
+ * Returns:
+ * The supported rotations for the plane.
+ */
+static inline unsigned int
+vkms_config_plane_get_supported_rotations(const struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->supported_rotations;
+}
+
+/**
+ * vkms_config_plane_set_supported_rotations() - Set the supported rotations for a plane
+ * @plane_cfg: Plane to set the supported rotations to
+ * @supported_rotations: New supported rotations for the plane
+ */
+static inline void
+vkms_config_plane_set_supported_rotations(struct vkms_config_plane *plane_cfg,
+ unsigned int supported_rotations)
+{
+ plane_cfg->supported_rotations = supported_rotations;
+}
+
+#if IS_ENABLED(CONFIG_KUNIT)
+bool vkms_config_valid_plane_rotation(const struct vkms_config *config,
+ const struct vkms_config_plane *plane_cfg);
+#endif
+
/**
* vkms_config_plane_set_name() - Set the plane name
* @plane_cfg: Plane to set the name to
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index f35120203124..8a64ea41734b 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -235,8 +235,9 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
drm_plane_helper_add(&plane->base, &vkms_plane_helper_funcs);
- drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0,
- DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK);
+ drm_plane_create_rotation_property(&plane->base,
+ vkms_config_plane_get_default_rotation(plane_cfg),
+ vkms_config_plane_get_supported_rotations(plane_cfg));
drm_plane_create_color_properties(&plane->base,
BIT(DRM_COLOR_YCBCR_BT601) |
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 16/38] drm/vkms: Use DRM_ROTATION_FMT macros for rotation display
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (14 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 15/38] drm/vkms: Introduce config for plane rotation Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:39 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 17/38] drm/vkms: Introduce configfs for plane rotation Louis Chauvet
` (21 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
Replace show_bitfield calls for rotation/reflection with the new
DRM_ROTATION_FMT / DRM_ROTATION_FMT_ARGS macros for cleaner code.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/vkms_config.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 5c86eb24fedf..ca3ee3aa2c41 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -3,6 +3,7 @@
#include <linux/slab.h>
#include <linux/string_choices.h>
+#include <drm/drm_blend.h>
#include <drm/drm_connector.h>
#include <drm/drm_mode.h>
#include <drm/drm_print.h>
@@ -393,6 +394,10 @@ static int vkms_config_show(struct seq_file *m, void *data)
seq_printf(m, "\tname=%s\n",
vkms_config_plane_get_name(plane_cfg) ?
vkms_config_plane_get_name(plane_cfg) : "(null)");
+ seq_printf(m, "\tsupported rotations=" DRM_ROTATION_FMT "\n",
+ DRM_ROTATION_FMT_ARGS(vkms_config_plane_get_supported_rotations(plane_cfg)));
+ seq_printf(m, "\tdefault rotation=" DRM_ROTATION_FMT "\n",
+ DRM_ROTATION_FMT_ARGS(vkms_config_plane_get_default_rotation(plane_cfg)));
}
vkms_config_for_each_crtc(vkmsdev->config, crtc_cfg) {
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 17/38] drm/vkms: Introduce configfs for plane rotation
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (15 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 16/38] drm/vkms: Use DRM_ROTATION_FMT macros for rotation display Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:46 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 18/38] drm/vkms: Introduce config for plane color encoding Louis Chauvet
` (20 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
To allows the userspace to test many hardware configurations, introduce a
new interface to configure the available rotation per planes. VKMS
supports any rotation and reflection, so the userspace can choose any
combination.
The supported rotations are configured by writing a rotation bitmask to
the file `supported_rotations` and the default rotation is chosen by
writing a rotation bitmask to `default_rotation`.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
Documentation/ABI/testing/configfs-vkms | 15 ++++++
Documentation/gpu/vkms.rst | 7 ++-
drivers/gpu/drm/vkms/vkms_configfs.c | 82 +++++++++++++++++++++++++++++++++
3 files changed, 103 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/configfs-vkms b/Documentation/ABI/testing/configfs-vkms
index a1a3e186e50a..7820da8505ef 100644
--- a/Documentation/ABI/testing/configfs-vkms
+++ b/Documentation/ABI/testing/configfs-vkms
@@ -103,6 +103,21 @@ Description:
Plane type. Possible values: 0 - overlay, 1 - primary,
2 - cursor.
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/supported_rotations
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Available rotations for the plane, as a bitmask:
+ 0x01 - no rotation, 0x02 - rotate 90°, 0x04 - rotate 180°,
+ 0x08 - rotate 270°, 0x10 - reflect x, 0x20 - reflect y.
+
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/default_rotation
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Default rotation presented to userspace, same values as
+ possible_rotations.
+
What: /sys/kernel/config/vkms/<device>/planes/<plane>/possible_crtcs
Date: Nov 2025
Contact: dri-devel@lists.freedesktop.org
diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index 1e79e62a6bc4..610305483716 100644
--- a/Documentation/gpu/vkms.rst
+++ b/Documentation/gpu/vkms.rst
@@ -87,10 +87,15 @@ Start by creating one or more planes::
sudo mkdir /config/vkms/my-vkms/planes/plane0
-Planes have 1 configurable attribute:
+Planes have 3 configurable attributes:
- type: Plane type: 0 overlay, 1 primary, 2 cursor (same values as those
exposed by the "type" property of a plane)
+- supported_rotations: Available rotation for a plane, as a bitmask: 0x01 no rotation,
+ 0x02 rotate 90°, 0x04 rotate 180°, 0x08 rotate 270°, 0x10 reflect x, 0x20 reflect y
+ (same values as those exposed by the "rotation" property of a plane)
+- default_rotation: Default rotation presented to the userspace, same values as
+ supported_rotations.
Continue by creating one or more CRTCs::
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index 0744ac40814d..47b3a4aeee8d 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -324,10 +324,92 @@ static ssize_t plane_type_store(struct config_item *item, const char *page,
return (ssize_t)count;
}
+static ssize_t plane_supported_rotations_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
+ unsigned int plane_supported_rotations;
+
+ scoped_guard(mutex, &plane->dev->lock)
+ plane_supported_rotations = vkms_config_plane_get_supported_rotations(plane->config);
+
+ return sprintf(page, "%u", plane_supported_rotations);
+}
+
+static ssize_t plane_supported_rotations_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
+ int ret, val = 0;
+
+ ret = kstrtouint(page, 0, &val);
+ if (ret)
+ return ret;
+
+ /* Should be a supported value */
+ if (val & ~(DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK))
+ return -EINVAL;
+ /* Should at least provide one rotation */
+ if (!(val & DRM_MODE_ROTATE_MASK))
+ return -EINVAL;
+
+ scoped_guard(mutex, &plane->dev->lock) {
+ if (plane->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_plane_set_supported_rotations(plane->config, val);
+ }
+
+ return count;
+}
+
+static ssize_t plane_default_rotation_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
+ unsigned int plane_default_rotation;
+
+ scoped_guard(mutex, &plane->dev->lock) {
+ plane_default_rotation = vkms_config_plane_get_default_rotation(plane->config);
+ }
+
+ return sprintf(page, "%u", plane_default_rotation);
+}
+
+static ssize_t plane_default_rotation_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
+ int ret, val = 0;
+
+ ret = kstrtouint(page, 10, &val);
+ if (ret)
+ return ret;
+
+ /* Should be a supported value */
+ if (val & ~(DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK))
+ return -EINVAL;
+
+ /* Should contain exactly one rotation */
+ if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK))
+ return -EINVAL;
+
+ scoped_guard(mutex, &plane->dev->lock) {
+ if (plane->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_plane_set_default_rotation(plane->config, val);
+ }
+
+ return count;
+}
+
CONFIGFS_ATTR(plane_, type);
+CONFIGFS_ATTR(plane_, supported_rotations);
+CONFIGFS_ATTR(plane_, default_rotation);
static struct configfs_attribute *plane_item_attrs[] = {
&plane_attr_type,
+ &plane_attr_supported_rotations,
+ &plane_attr_default_rotation,
NULL,
};
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 18/38] drm/vkms: Introduce config for plane color encoding
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (16 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 17/38] drm/vkms: Introduce configfs for plane rotation Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:43 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 19/38] drm/vkms: Introduce configfs " Louis Chauvet
` (19 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
VKMS driver supports all the color encoding on planes, but for testing it
can be useful to only advertise few of them. This new configuration
interface will allow configuring the color encoding per planes.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/tests/vkms_config_test.c | 51 +++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_config.c | 48 ++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_config.h | 64 +++++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_plane.c | 15 +++----
4 files changed, 170 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
index c33fe737678f..a2a3f1a106a3 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_config_test.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
@@ -192,6 +192,14 @@ static void vkms_config_test_default_config(struct kunit *test)
KUNIT_EXPECT_EQ(test,
vkms_config_plane_get_default_rotation(plane_cfg),
DRM_MODE_ROTATE_0);
+ KUNIT_EXPECT_EQ(test,
+ vkms_config_plane_get_supported_color_encodings(plane_cfg),
+ BIT(DRM_COLOR_YCBCR_BT601) |
+ BIT(DRM_COLOR_YCBCR_BT709) |
+ BIT(DRM_COLOR_YCBCR_BT2020));
+ KUNIT_EXPECT_EQ(test,
+ vkms_config_plane_get_default_color_encoding(plane_cfg),
+ DRM_COLOR_YCBCR_BT601);
}
/* Encoders */
@@ -526,6 +534,48 @@ static void vkms_config_test_valid_plane_rotations(struct kunit *test)
vkms_config_destroy(config);
}
+static void vkms_config_test_valid_plane_color_encoding(struct kunit *test)
+{
+ struct vkms_config *config;
+ struct vkms_config_plane *plane_cfg;
+
+ config = vkms_config_default_create(false, false, false, false);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
+
+ plane_cfg = get_first_plane(config);
+
+ /* Valid, all color encoding supported */
+ vkms_config_plane_set_supported_color_encodings(plane_cfg,
+ BIT(DRM_COLOR_YCBCR_BT601) |
+ BIT(DRM_COLOR_YCBCR_BT709) |
+ BIT(DRM_COLOR_YCBCR_BT2020));
+ vkms_config_plane_set_default_color_encoding(plane_cfg, DRM_COLOR_YCBCR_BT601);
+ KUNIT_EXPECT_TRUE(test, vkms_config_valid_plane_color_encoding(config, plane_cfg));
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Invalid, default color encoding is not supported */
+ vkms_config_plane_set_supported_color_encodings(plane_cfg,
+ BIT(DRM_COLOR_YCBCR_BT601) |
+ BIT(DRM_COLOR_YCBCR_BT2020));
+ vkms_config_plane_set_default_color_encoding(plane_cfg, DRM_COLOR_YCBCR_BT709);
+ KUNIT_EXPECT_FALSE(test, vkms_config_valid_plane_color_encoding(config, plane_cfg));
+ KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
+
+ /* Valid, no supported or color encoding */
+ vkms_config_plane_set_supported_color_encodings(plane_cfg, 0);
+ vkms_config_plane_set_default_color_encoding(plane_cfg, 0);
+ KUNIT_EXPECT_TRUE(test, vkms_config_valid_plane_color_encoding(config, plane_cfg));
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Valid, if no supported color encoding, default is ignored */
+ vkms_config_plane_set_supported_color_encodings(plane_cfg, 0);
+ vkms_config_plane_set_default_color_encoding(plane_cfg, DRM_COLOR_YCBCR_BT601);
+ KUNIT_EXPECT_TRUE(test, vkms_config_valid_plane_color_encoding(config, plane_cfg));
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ vkms_config_destroy(config);
+}
+
static void vkms_config_test_valid_plane_possible_crtcs(struct kunit *test)
{
struct vkms_config *config;
@@ -1049,6 +1099,7 @@ static struct kunit_case vkms_config_test_cases[] = {
KUNIT_CASE(vkms_config_test_invalid_plane_number),
KUNIT_CASE(vkms_config_test_valid_plane_type),
KUNIT_CASE(vkms_config_test_valid_plane_rotations),
+ KUNIT_CASE(vkms_config_test_valid_plane_color_encoding),
KUNIT_CASE(vkms_config_test_valid_plane_possible_crtcs),
KUNIT_CASE(vkms_config_test_invalid_crtc_number),
KUNIT_CASE(vkms_config_test_invalid_encoder_number),
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index ca3ee3aa2c41..2fa467f5e17e 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -179,6 +179,25 @@ bool vkms_config_valid_plane_rotation(const struct vkms_config *config,
}
EXPORT_SYMBOL_IF_KUNIT(vkms_config_valid_plane_rotation);
+VISIBLE_IF_KUNIT
+bool vkms_config_valid_plane_color_encoding(const struct vkms_config *config,
+ const struct vkms_config_plane *plane_cfg)
+{
+ struct drm_device *dev = config->dev ? &config->dev->drm : NULL;
+
+ if (vkms_config_plane_get_supported_color_encodings(plane_cfg)) {
+ if ((BIT(vkms_config_plane_get_default_color_encoding(plane_cfg)) &
+ vkms_config_plane_get_supported_color_encodings(plane_cfg)) !=
+ BIT(vkms_config_plane_get_default_color_encoding(plane_cfg))) {
+ drm_info(dev, "Configured default color encoding is not supported by the plane\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_valid_plane_color_encoding);
+
static bool valid_planes_for_crtc(const struct vkms_config *config,
struct vkms_config_crtc *crtc_cfg)
{
@@ -341,6 +360,9 @@ bool vkms_config_is_valid(const struct vkms_config *config)
vkms_config_for_each_plane(config, plane_cfg) {
if (!vkms_config_valid_plane_rotation(config, plane_cfg))
return false;
+
+ if (!vkms_config_valid_plane_color_encoding(config, plane_cfg))
+ return false;
}
if (!valid_plane_number(config))
@@ -373,6 +395,22 @@ bool vkms_config_is_valid(const struct vkms_config *config)
}
EXPORT_SYMBOL_IF_KUNIT(vkms_config_is_valid);
+static void show_bitfield(struct seq_file *m, uint32_t value, const char *callback(unsigned int))
+{
+ u32 offset = 0;
+ bool first = true;
+
+ while (value >= BIT(offset) && offset < 32) {
+ if (value & BIT(offset)) {
+ if (!first)
+ seq_puts(m, ",");
+ seq_printf(m, callback(offset));
+ first = false;
+ }
+ offset += 1;
+ }
+}
+
static int vkms_config_show(struct seq_file *m, void *data)
{
struct drm_debugfs_entry *entry = m->private;
@@ -398,6 +436,12 @@ static int vkms_config_show(struct seq_file *m, void *data)
DRM_ROTATION_FMT_ARGS(vkms_config_plane_get_supported_rotations(plane_cfg)));
seq_printf(m, "\tdefault rotation=" DRM_ROTATION_FMT "\n",
DRM_ROTATION_FMT_ARGS(vkms_config_plane_get_default_rotation(plane_cfg)));
+ seq_puts(m, "\tsupported color encoding=");
+ show_bitfield(m, vkms_config_plane_get_supported_color_encodings(plane_cfg),
+ drm_get_color_encoding_name);
+ seq_puts(m, "\n");
+ seq_printf(m, "\tdefault color encoding=%s\n",
+ drm_get_color_encoding_name(vkms_config_plane_get_default_color_encoding(plane_cfg)));
}
vkms_config_for_each_crtc(vkmsdev->config, crtc_cfg) {
@@ -450,6 +494,10 @@ struct vkms_config_plane __must_check *vkms_config_create_plane(struct vkms_conf
vkms_config_plane_set_supported_rotations(plane_cfg,
DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK);
vkms_config_plane_set_default_rotation(plane_cfg, DRM_MODE_ROTATE_0);
+ vkms_config_plane_set_supported_color_encodings(plane_cfg, BIT(DRM_COLOR_YCBCR_BT601) |
+ BIT(DRM_COLOR_YCBCR_BT709) |
+ BIT(DRM_COLOR_YCBCR_BT2020));
+ vkms_config_plane_set_default_color_encoding(plane_cfg, DRM_COLOR_YCBCR_BT601);
xa_init_flags(&plane_cfg->possible_crtcs, XA_FLAGS_ALLOC);
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index b5884ac0f42f..31c1598ff866 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -46,6 +46,8 @@ struct vkms_config {
* It can be used to store a temporary reference to a VKMS plane during
* device creation. This pointer is not managed by the configuration and
* must be managed by other means.
+ * @default_color_encoding: Default color encoding that should be used by this plane
+ * @supported_color_encodings: Color encodings that this plane will support
*/
struct vkms_config_plane {
struct list_head link;
@@ -55,6 +57,8 @@ struct vkms_config_plane {
enum drm_plane_type type;
unsigned int default_rotation;
unsigned int supported_rotations;
+ enum drm_color_encoding default_color_encoding;
+ unsigned int supported_color_encodings;
struct xarray possible_crtcs;
bool default_pipeline;
@@ -376,6 +380,66 @@ bool vkms_config_valid_plane_rotation(const struct vkms_config *config,
const struct vkms_config_plane *plane_cfg);
#endif
+/**
+ * vkms_config_plane_get_default_color_encoding() - Get the default color encoding for a plane
+ * @plane_cfg: Plane to get the default color encoding from
+ *
+ * Returns:
+ * The default color encoding for the plane
+ */
+static inline enum drm_color_encoding
+vkms_config_plane_get_default_color_encoding(const struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->default_color_encoding;
+}
+
+/**
+ * vkms_config_plane_set_default_color_encoding() - Set the default color encoding for a plane
+ * @plane_cfg: Plane to set the default color encoding to
+ * @default_color_encoding: New default color encoding for the plane
+ */
+static inline void
+vkms_config_plane_set_default_color_encoding(struct vkms_config_plane *plane_cfg,
+ enum drm_color_encoding default_color_encoding)
+{
+ plane_cfg->default_color_encoding = default_color_encoding;
+}
+
+/**
+ * vkms_config_plane_get_supported_color_encodings() - Get the supported color encodings for a plane
+ * @plane_cfg: Plane to get the supported color encodings from
+ *
+ * Returns:
+ * The supported color encodings for the plane. Each set bit correspond to a value of enum
+ * drm_color_encoding: BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709) means that
+ * DRM_COLOR_YCBCR_BT601 and DRM_COLOR_YCBCR_BT709 are supported.
+ */
+static inline unsigned int
+vkms_config_plane_get_supported_color_encodings(const struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->supported_color_encodings;
+}
+
+/**
+ * vkms_config_plane_set_supported_color_encodings() - Set the supported color encodings for a plane
+ * @plane_cfg: Plane to set the supported color encodings to
+ * @supported_color_encodings: New supported color encodings for the plane. Each set bit corresponds
+ * to a value of enum drm_color_encoding:
+ * BIT(DRM_COLOR_YCBCR_BT601) | BIT(DRM_COLOR_YCBCR_BT709) means that
+ * DRM_COLOR_YCBCR_BT601 and DRM_COLOR_YCBCR_BT709 are supported.
+ */
+static inline void
+vkms_config_plane_set_supported_color_encodings(struct vkms_config_plane *plane_cfg,
+ unsigned int supported_color_encodings)
+{
+ plane_cfg->supported_color_encodings = supported_color_encodings;
+}
+
+#if IS_ENABLED(CONFIG_KUNIT)
+bool vkms_config_valid_plane_color_encoding(const struct vkms_config *config,
+ const struct vkms_config_plane *plane_cfg);
+#endif
+
/**
* vkms_config_plane_set_name() - Set the plane name
* @plane_cfg: Plane to set the name to
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index 8a64ea41734b..8d3953667f21 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -239,14 +239,13 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
vkms_config_plane_get_default_rotation(plane_cfg),
vkms_config_plane_get_supported_rotations(plane_cfg));
- drm_plane_create_color_properties(&plane->base,
- BIT(DRM_COLOR_YCBCR_BT601) |
- BIT(DRM_COLOR_YCBCR_BT709) |
- BIT(DRM_COLOR_YCBCR_BT2020),
- BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
- BIT(DRM_COLOR_YCBCR_FULL_RANGE),
- DRM_COLOR_YCBCR_BT601,
- DRM_COLOR_YCBCR_FULL_RANGE);
+ if (vkms_config_plane_get_supported_color_encodings(plane_cfg) != 0)
+ drm_plane_create_color_properties(&plane->base,
+ vkms_config_plane_get_supported_color_encodings(plane_cfg),
+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
+ BIT(DRM_COLOR_YCBCR_FULL_RANGE),
+ vkms_config_plane_get_default_color_encoding(plane_cfg),
+ DRM_COLOR_YCBCR_FULL_RANGE);
if (vkms_config_plane_get_default_pipeline(plane_cfg))
vkms_initialize_colorops(&plane->base);
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 19/38] drm/vkms: Introduce configfs for plane color encoding
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (17 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 18/38] drm/vkms: Introduce config for plane color encoding Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:49 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 20/38] drm/vkms: Introduce config for plane color range Louis Chauvet
` (18 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
To allows the userspace to test many hardware configuration, introduce a
new interface to configure the available color encoding per planes. VKMS
supports multiple color encoding, so the userspace can choose any
combination.
The supported color encoding are configured by writing a color encoding
bitmask to the file `supported_color_encoding` and the default color
encoding is chosen by writing a color encoding bitmask to
`default_color_encoding`.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
Documentation/ABI/testing/configfs-vkms | 14 +++++
Documentation/gpu/vkms.rst | 8 ++-
drivers/gpu/drm/vkms/vkms_configfs.c | 92 +++++++++++++++++++++++++++++++++
3 files changed, 113 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/configfs-vkms b/Documentation/ABI/testing/configfs-vkms
index 7820da8505ef..a9ee05fe0c66 100644
--- a/Documentation/ABI/testing/configfs-vkms
+++ b/Documentation/ABI/testing/configfs-vkms
@@ -118,6 +118,20 @@ Description:
Default rotation presented to userspace, same values as
possible_rotations.
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/supported_color_encodings
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Available color encodings for the plane, as a bitmask:
+ 0x01 - YCBCR_BT601, 0x02 - YCBCR_BT709, 0x04 - YCBCR_BT2020.
+
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/default_color_encoding
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Default color encoding presented to userspace, same
+ values as supported_color_encoding.
+
What: /sys/kernel/config/vkms/<device>/planes/<plane>/possible_crtcs
Date: Nov 2025
Contact: dri-devel@lists.freedesktop.org
diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index 610305483716..7206cd2b231a 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 3 configurable attributes:
+Planes have 5 configurable attributes:
- type: Plane type: 0 overlay, 1 primary, 2 cursor (same values as those
exposed by the "type" property of a plane)
@@ -96,6 +96,12 @@ Planes have 3 configurable attributes:
(same values as those exposed by the "rotation" property of a plane)
- default_rotation: Default rotation presented to the userspace, same values as
supported_rotations.
+- supported_color_encodings: Available encodings for a plane, as a bitmask:
+ 0x01 YCBCR_BT601, 0x02 YCBCR_BT709, 0x04 YCBCR_BT2020 (same values as those exposed
+ by the COLOR_ENCODING property of a plane). If set, supported_color_range
+ must be set too.
+- default_color_encoding: Default color encoding presented to the userspace, same
+ values as supported_color_encodings
Continue by creating one or more CRTCs::
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index 47b3a4aeee8d..c1d1841b2c5a 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -9,6 +9,14 @@
#include "vkms_configfs.h"
#include "vkms_connector.h"
+/**
+ * VKMS_SUPPORTED_COLOR_ENCODINGS - Bitmask of all supported color encodings in VKMS
+ */
+#define VKMS_SUPPORTED_COLOR_ENCODINGS ( \
+ BIT(DRM_COLOR_YCBCR_BT601) | \
+ BIT(DRM_COLOR_YCBCR_BT709) | \
+ BIT(DRM_COLOR_YCBCR_BT2020))
+
/* To avoid registering configfs more than once or unregistering on error */
static bool is_configfs_registered;
@@ -402,14 +410,98 @@ static ssize_t plane_default_rotation_store(struct config_item *item,
return count;
}
+static ssize_t plane_supported_color_encodings_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
+ unsigned int supported_color_encodings;
+
+ scoped_guard(mutex, &plane->dev->lock)
+ supported_color_encodings = vkms_config_plane_get_supported_color_encodings(plane->config);
+
+ return sprintf(page, "%u", supported_color_encodings);
+}
+
+static ssize_t plane_supported_color_encodings_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
+ int ret, val = 0;
+
+ ret = kstrtouint(page, 10, &val);
+ if (ret)
+ return ret;
+
+ /* Should be a supported value */
+ if (val & ~(VKMS_SUPPORTED_COLOR_ENCODINGS))
+ return -EINVAL;
+ /* Should at least provide one color encoding */
+ if ((val & (VKMS_SUPPORTED_COLOR_ENCODINGS)) == 0)
+ return -EINVAL;
+
+ scoped_guard(mutex, &plane->dev->lock) {
+ if (plane->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_plane_set_supported_color_encodings(plane->config, val);
+ }
+
+ return count;
+}
+
+static ssize_t plane_default_color_encoding_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_plane *plane = plane = plane_item_to_vkms_configfs_plane(item);
+ unsigned int default_color_encoding;
+
+ scoped_guard(mutex, &plane->dev->lock)
+ default_color_encoding = BIT(vkms_config_plane_get_default_color_encoding(plane->config));
+
+ return sprintf(page, "%u", default_color_encoding);
+}
+
+static ssize_t plane_default_color_encoding_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
+ int ret, val = 0;
+
+ ret = kstrtouint(page, 10, &val);
+ if (ret)
+ return ret;
+
+ /* Should be a supported value */
+ if (val & ~VKMS_SUPPORTED_COLOR_ENCODINGS)
+ return -EINVAL;
+
+ /* Ensure val is a single bit set */
+ if (!is_power_of_2(val))
+ return -EINVAL;
+
+ /* Convert bit position to the proper enum value */
+ val = __ffs(val) + DRM_COLOR_YCBCR_BT601;
+
+ scoped_guard(mutex, &plane->dev->lock) {
+ if (plane->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_plane_set_default_color_encoding(plane->config, val);
+ }
+
+ return count;
+}
+
CONFIGFS_ATTR(plane_, type);
CONFIGFS_ATTR(plane_, supported_rotations);
CONFIGFS_ATTR(plane_, default_rotation);
+CONFIGFS_ATTR(plane_, supported_color_encodings);
+CONFIGFS_ATTR(plane_, default_color_encoding);
static struct configfs_attribute *plane_item_attrs[] = {
&plane_attr_type,
&plane_attr_supported_rotations,
&plane_attr_default_rotation,
+ &plane_attr_supported_color_encodings,
+ &plane_attr_default_color_encoding,
NULL,
};
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 20/38] drm/vkms: Introduce config for plane color range
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (18 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 19/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 21/38] drm/vkms: Introduce configfs " Louis Chauvet
` (17 subsequent siblings)
37 siblings, 0 replies; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
VKMS driver supports all the color range on planes, but for testing it can
be useful to only advertise few of them. This new configuration interface
will allow configuring the color range per planes.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/tests/vkms_config_test.c | 44 +++++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_config.c | 39 ++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_config.h | 35 +++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_plane.c | 8 ++---
4 files changed, 122 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
index a2a3f1a106a3..a88d8b4a969e 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_config_test.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
+#include <drm/drm_color_mgmt.h>
#include <drm/drm_mode.h>
#include <kunit/test.h>
@@ -562,6 +563,7 @@ static void vkms_config_test_valid_plane_color_encoding(struct kunit *test)
KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
/* Valid, no supported or color encoding */
+ vkms_config_plane_set_supported_color_ranges(plane_cfg, 0);
vkms_config_plane_set_supported_color_encodings(plane_cfg, 0);
vkms_config_plane_set_default_color_encoding(plane_cfg, 0);
KUNIT_EXPECT_TRUE(test, vkms_config_valid_plane_color_encoding(config, plane_cfg));
@@ -576,6 +578,47 @@ static void vkms_config_test_valid_plane_color_encoding(struct kunit *test)
vkms_config_destroy(config);
}
+static void vkms_config_test_valid_plane_color_range(struct kunit *test)
+{
+ struct vkms_config *config;
+ struct vkms_config_plane *plane_cfg;
+
+ config = vkms_config_default_create(false, false, false, false);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
+
+ plane_cfg = get_first_plane(config);
+
+ /* Valid, all color range supported */
+ vkms_config_plane_set_supported_color_ranges(plane_cfg,
+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
+ BIT(DRM_COLOR_YCBCR_FULL_RANGE));
+ vkms_config_plane_set_default_color_range(plane_cfg, DRM_COLOR_YCBCR_FULL_RANGE);
+ KUNIT_EXPECT_TRUE(test, vkms_config_valid_plane_color_range(config, plane_cfg));
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Invalid, default color range is not supported */
+ vkms_config_plane_set_supported_color_ranges(plane_cfg,
+ BIT(DRM_COLOR_YCBCR_FULL_RANGE));
+ vkms_config_plane_set_default_color_range(plane_cfg, DRM_COLOR_YCBCR_LIMITED_RANGE);
+ KUNIT_EXPECT_FALSE(test, vkms_config_valid_plane_color_range(config, plane_cfg));
+ KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
+
+ /* Valid, no supported or color range */
+ vkms_config_plane_set_supported_color_encodings(plane_cfg, 0);
+ vkms_config_plane_set_supported_color_ranges(plane_cfg, 0);
+ vkms_config_plane_set_default_color_range(plane_cfg, 0);
+ KUNIT_EXPECT_TRUE(test, vkms_config_valid_plane_color_range(config, plane_cfg));
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Valid, if no supported color range, default is ignored */
+ vkms_config_plane_set_supported_color_ranges(plane_cfg, 0);
+ vkms_config_plane_set_default_color_range(plane_cfg, DRM_COLOR_YCBCR_LIMITED_RANGE);
+ KUNIT_EXPECT_TRUE(test, vkms_config_valid_plane_color_range(config, plane_cfg));
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ vkms_config_destroy(config);
+}
+
static void vkms_config_test_valid_plane_possible_crtcs(struct kunit *test)
{
struct vkms_config *config;
@@ -1100,6 +1143,7 @@ static struct kunit_case vkms_config_test_cases[] = {
KUNIT_CASE(vkms_config_test_valid_plane_type),
KUNIT_CASE(vkms_config_test_valid_plane_rotations),
KUNIT_CASE(vkms_config_test_valid_plane_color_encoding),
+ KUNIT_CASE(vkms_config_test_valid_plane_color_range),
KUNIT_CASE(vkms_config_test_valid_plane_possible_crtcs),
KUNIT_CASE(vkms_config_test_invalid_crtc_number),
KUNIT_CASE(vkms_config_test_invalid_encoder_number),
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 2fa467f5e17e..553871646761 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -198,6 +198,25 @@ bool vkms_config_valid_plane_color_encoding(const struct vkms_config *config,
}
EXPORT_SYMBOL_IF_KUNIT(vkms_config_valid_plane_color_encoding);
+VISIBLE_IF_KUNIT
+bool vkms_config_valid_plane_color_range(const struct vkms_config *config,
+ const struct vkms_config_plane *plane_cfg)
+{
+ struct drm_device *dev = config->dev ? &config->dev->drm : NULL;
+
+ if (vkms_config_plane_get_supported_color_ranges(plane_cfg)) {
+ if ((BIT(vkms_config_plane_get_default_color_range(plane_cfg)) &
+ vkms_config_plane_get_supported_color_ranges(plane_cfg)) !=
+ BIT(vkms_config_plane_get_default_color_range(plane_cfg))) {
+ drm_info(dev, "Configured default color range is not supported by the plane\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+EXPORT_SYMBOL_IF_KUNIT(vkms_config_valid_plane_color_range);
+
static bool valid_planes_for_crtc(const struct vkms_config *config,
struct vkms_config_crtc *crtc_cfg)
{
@@ -354,6 +373,7 @@ static bool valid_connector_possible_encoders(const struct vkms_config *config)
bool vkms_config_is_valid(const struct vkms_config *config)
{
+ struct drm_device *dev = config->dev ? &config->dev->drm : NULL;
struct vkms_config_crtc *crtc_cfg;
struct vkms_config_plane *plane_cfg;
@@ -363,6 +383,16 @@ bool vkms_config_is_valid(const struct vkms_config *config)
if (!vkms_config_valid_plane_color_encoding(config, plane_cfg))
return false;
+
+ if (!vkms_config_valid_plane_color_range(config, plane_cfg))
+ return false;
+
+ if ((vkms_config_plane_get_supported_color_encodings(plane_cfg) == 0) !=
+ (vkms_config_plane_get_supported_color_ranges(plane_cfg) == 0)) {
+ drm_info(dev,
+ "Both supported color encodings and color ranges must be set, or none\n");
+ return false;
+ }
}
if (!valid_plane_number(config))
@@ -442,6 +472,12 @@ static int vkms_config_show(struct seq_file *m, void *data)
seq_puts(m, "\n");
seq_printf(m, "\tdefault color encoding=%s\n",
drm_get_color_encoding_name(vkms_config_plane_get_default_color_encoding(plane_cfg)));
+ seq_puts(m, "\tsupported color ranges=");
+ show_bitfield(m, vkms_config_plane_get_supported_color_ranges(plane_cfg),
+ drm_get_color_range_name);
+ seq_puts(m, "\n");
+ seq_printf(m, "\tdefault color range=%s\n",
+ drm_get_color_range_name(vkms_config_plane_get_default_color_range(plane_cfg)));
}
vkms_config_for_each_crtc(vkmsdev->config, crtc_cfg) {
@@ -498,6 +534,9 @@ struct vkms_config_plane __must_check *vkms_config_create_plane(struct vkms_conf
BIT(DRM_COLOR_YCBCR_BT709) |
BIT(DRM_COLOR_YCBCR_BT2020));
vkms_config_plane_set_default_color_encoding(plane_cfg, DRM_COLOR_YCBCR_BT601);
+ vkms_config_plane_set_supported_color_ranges(plane_cfg, BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
+ BIT(DRM_COLOR_YCBCR_FULL_RANGE));
+ vkms_config_plane_set_default_color_range(plane_cfg, DRM_COLOR_YCBCR_FULL_RANGE);
xa_init_flags(&plane_cfg->possible_crtcs, XA_FLAGS_ALLOC);
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 31c1598ff866..60cadb7bea5b 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -48,6 +48,8 @@ struct vkms_config {
* must be managed by other means.
* @default_color_encoding: Default color encoding that should be used by this plane
* @supported_color_encodings: Color encodings that this plane will support
+ * @default_color_range: Default color range that should be used by this plane
+ * @supported_color_ranges: Color ranges that this plane will support
*/
struct vkms_config_plane {
struct list_head link;
@@ -59,6 +61,8 @@ struct vkms_config_plane {
unsigned int supported_rotations;
enum drm_color_encoding default_color_encoding;
unsigned int supported_color_encodings;
+ enum drm_color_range default_color_range;
+ unsigned int supported_color_ranges;
struct xarray possible_crtcs;
bool default_pipeline;
@@ -440,6 +444,37 @@ bool vkms_config_valid_plane_color_encoding(const struct vkms_config *config,
const struct vkms_config_plane *plane_cfg);
#endif
+static inline enum drm_color_range
+vkms_config_plane_get_default_color_range(const struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->default_color_range;
+}
+
+static inline void
+vkms_config_plane_set_default_color_range(struct vkms_config_plane *plane_cfg,
+ enum drm_color_range default_color_range)
+{
+ plane_cfg->default_color_range = default_color_range;
+}
+
+static inline unsigned int
+vkms_config_plane_get_supported_color_ranges(const struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->supported_color_ranges;
+}
+
+static inline void
+vkms_config_plane_set_supported_color_ranges(struct vkms_config_plane *plane_cfg,
+ unsigned int supported_color_ranges)
+{
+ plane_cfg->supported_color_ranges = supported_color_ranges;
+}
+
+#if IS_ENABLED(CONFIG_KUNIT)
+bool vkms_config_valid_plane_color_range(const struct vkms_config *config,
+ const struct vkms_config_plane *plane_cfg);
+#endif
+
/**
* vkms_config_plane_set_name() - Set the plane name
* @plane_cfg: Plane to set the name to
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index 8d3953667f21..d4ccf418198e 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -239,13 +239,13 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
vkms_config_plane_get_default_rotation(plane_cfg),
vkms_config_plane_get_supported_rotations(plane_cfg));
- if (vkms_config_plane_get_supported_color_encodings(plane_cfg) != 0)
+ if (vkms_config_plane_get_supported_color_encodings(plane_cfg) != 0 &&
+ vkms_config_plane_get_supported_color_ranges(plane_cfg) != 0)
drm_plane_create_color_properties(&plane->base,
vkms_config_plane_get_supported_color_encodings(plane_cfg),
- BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
- BIT(DRM_COLOR_YCBCR_FULL_RANGE),
+ vkms_config_plane_get_supported_color_ranges(plane_cfg),
vkms_config_plane_get_default_color_encoding(plane_cfg),
- DRM_COLOR_YCBCR_FULL_RANGE);
+ vkms_config_plane_get_default_color_range(plane_cfg));
if (vkms_config_plane_get_default_pipeline(plane_cfg))
vkms_initialize_colorops(&plane->base);
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 21/38] drm/vkms: Introduce configfs for plane color range
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (19 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 20/38] drm/vkms: Introduce config for plane color range Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:45 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 22/38] drm/vkms: Introduce config for plane format Louis Chauvet
` (16 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
To allows the userspace to test many hardware configuration, introduce a
new interface to configure the available color ranges per planes. VKMS
supports multiple color ranges, so the userspace can choose any
combination.
The supported color ranges are configured by writing a color range bitmask
to the file `supported_color_ranges` and the default color range is
chosen by writing a color encoding bitmask to `default_color_range`.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
Documentation/ABI/testing/configfs-vkms | 15 ++++++
Documentation/gpu/vkms.rst | 10 +++-
drivers/gpu/drm/vkms/vkms_configfs.c | 90 +++++++++++++++++++++++++++++++++
3 files changed, 113 insertions(+), 2 deletions(-)
diff --git a/Documentation/ABI/testing/configfs-vkms b/Documentation/ABI/testing/configfs-vkms
index a9ee05fe0c66..ef0c3da6b3ca 100644
--- a/Documentation/ABI/testing/configfs-vkms
+++ b/Documentation/ABI/testing/configfs-vkms
@@ -132,6 +132,21 @@ Description:
Default color encoding presented to userspace, same
values as supported_color_encoding.
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/supported_color_ranges
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Available color ranges for the plane, as a bitmask:
+ 0x1 - DRM_COLOR_YCBCR_LIMITED_RANGE,
+ 0x2 - DRM_COLOR_YCBCR_FULL_RANGE.
+
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/default_color_range
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Default color range presented to userspace, same
+ values as supported_color_ranges.
+
What: /sys/kernel/config/vkms/<device>/planes/<plane>/possible_crtcs
Date: Nov 2025
Contact: dri-devel@lists.freedesktop.org
diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index 7206cd2b231a..7e8f4fe3b392 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 5 configurable attributes:
+Planes have 7 configurable attributes:
- type: Plane type: 0 overlay, 1 primary, 2 cursor (same values as those
exposed by the "type" property of a plane)
@@ -98,10 +98,16 @@ Planes have 5 configurable attributes:
supported_rotations.
- supported_color_encodings: Available encodings for a plane, as a bitmask:
0x01 YCBCR_BT601, 0x02 YCBCR_BT709, 0x04 YCBCR_BT2020 (same values as those exposed
- by the COLOR_ENCODING property of a plane). If set, supported_color_range
+ by the COLOR_ENCODING property of a plane). If set, supported_color_ranges
must be set too.
- default_color_encoding: Default color encoding presented to the userspace, same
values as supported_color_encodings
+- supported_color_ranges: Available color range for a plane, as a bitmask:
+ 0x1 DRM_COLOR_YCBCR_LIMITED_RANGE, 0x2 DRM_COLOR_YCBCR_FULL_RANGE (same values as
+ those exposed by the COLOR_RANGE property of a plane). If set, supported_color_encoding
+ must be set too.
+- default_color_range: Default color range presented to the userspace, same
+ values as supported_color_ranges
Continue by creating one or more CRTCs::
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index c1d1841b2c5a..56a0c542a143 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -17,6 +17,13 @@
BIT(DRM_COLOR_YCBCR_BT709) | \
BIT(DRM_COLOR_YCBCR_BT2020))
+/**
+ * VKMS_SUPPORTED_COLOR_RANGES - Bitmask of all supported color ranges in VKMS
+ */
+#define VKMS_SUPPORTED_COLOR_RANGES ( \
+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | \
+ BIT(DRM_COLOR_YCBCR_FULL_RANGE))
+
/* To avoid registering configfs more than once or unregistering on error */
static bool is_configfs_registered;
@@ -410,6 +417,85 @@ static ssize_t plane_default_rotation_store(struct config_item *item,
return count;
}
+static ssize_t plane_supported_color_ranges_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
+ unsigned int supported_color_ranges;
+
+ scoped_guard(mutex, &plane->dev->lock)
+ supported_color_ranges = vkms_config_plane_get_supported_color_ranges(plane->config);
+
+ return sprintf(page, "%u", supported_color_ranges);
+}
+
+static ssize_t plane_supported_color_ranges_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
+ int ret, val = 0;
+
+ ret = kstrtouint(page, 10, &val);
+ if (ret)
+ return ret;
+
+ /* Should be a supported value */
+ if (val & ~VKMS_SUPPORTED_COLOR_RANGES)
+ return -EINVAL;
+ /* Should at least provide one color range */
+ if ((val & VKMS_SUPPORTED_COLOR_RANGES) == 0)
+ return -EINVAL;
+
+ scoped_guard(mutex, &plane->dev->lock) {
+ if (plane->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_plane_set_supported_color_ranges(plane->config, val);
+ }
+
+ return count;
+}
+
+static ssize_t plane_default_color_range_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
+ unsigned int default_color_range;
+
+ scoped_guard(mutex, &plane->dev->lock)
+ default_color_range = vkms_config_plane_get_default_color_range(plane->config);
+
+ return sprintf(page, "%lu", BIT(default_color_range));
+}
+
+static ssize_t plane_default_color_range_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
+ int ret, val = 0;
+
+ ret = kstrtouint(page, 10, &val);
+ if (ret)
+ return ret;
+
+ /* Should be a supported value */
+ if (val & ~VKMS_SUPPORTED_COLOR_RANGES)
+ return -EINVAL;
+
+ if (!is_power_of_2(val))
+ return -EINVAL;
+
+ /* Convert bit position to the proper enum value */
+ val = ffs(val) + DRM_COLOR_YCBCR_LIMITED_RANGE - 1;
+
+ scoped_guard(mutex, &plane->dev->lock) {
+ if (plane->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_plane_set_default_color_range(plane->config, val);
+ }
+
+ return count;
+}
+
static ssize_t plane_supported_color_encodings_show(struct config_item *item, char *page)
{
struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
@@ -493,6 +579,8 @@ static ssize_t plane_default_color_encoding_store(struct config_item *item,
CONFIGFS_ATTR(plane_, type);
CONFIGFS_ATTR(plane_, supported_rotations);
CONFIGFS_ATTR(plane_, default_rotation);
+CONFIGFS_ATTR(plane_, supported_color_ranges);
+CONFIGFS_ATTR(plane_, default_color_range);
CONFIGFS_ATTR(plane_, supported_color_encodings);
CONFIGFS_ATTR(plane_, default_color_encoding);
@@ -500,6 +588,8 @@ static struct configfs_attribute *plane_item_attrs[] = {
&plane_attr_type,
&plane_attr_supported_rotations,
&plane_attr_default_rotation,
+ &plane_attr_supported_color_ranges,
+ &plane_attr_default_color_range,
&plane_attr_supported_color_encodings,
&plane_attr_default_color_encoding,
NULL,
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 22/38] drm/vkms: Introduce config for plane format
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (20 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 21/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:46 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 23/38] drm/vkms: Introduce configfs " Louis Chauvet
` (15 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
VKMS driver supports all the pixel formats for planes, but for testing it
can be useful to only advertise few of them. This new configuration
interface will allow configuring the pixel format per planes.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/vkms_config.c | 128 +++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_config.h | 51 +++++++++++++++
drivers/gpu/drm/vkms/vkms_plane.c | 39 +----------
3 files changed, 181 insertions(+), 37 deletions(-)
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 553871646761..c7de3e307367 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -12,6 +12,42 @@
#include "vkms_config.h"
+static const u32 vkms_supported_plane_formats[] = {
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_BGRA8888,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_BGR888,
+ DRM_FORMAT_XRGB16161616,
+ DRM_FORMAT_XBGR16161616,
+ DRM_FORMAT_ARGB16161616,
+ DRM_FORMAT_ABGR16161616,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_BGR565,
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV16,
+ DRM_FORMAT_NV24,
+ DRM_FORMAT_NV21,
+ DRM_FORMAT_NV61,
+ DRM_FORMAT_NV42,
+ DRM_FORMAT_YUV420,
+ DRM_FORMAT_YUV422,
+ DRM_FORMAT_YUV444,
+ DRM_FORMAT_YVU420,
+ DRM_FORMAT_YVU422,
+ DRM_FORMAT_YVU444,
+ DRM_FORMAT_P010,
+ DRM_FORMAT_P012,
+ DRM_FORMAT_P016,
+ DRM_FORMAT_R1,
+ DRM_FORMAT_R2,
+ DRM_FORMAT_R4,
+ DRM_FORMAT_R8,
+};
+
struct vkms_config *vkms_config_create(const char *dev_name)
{
struct vkms_config *config;
@@ -441,6 +477,15 @@ static void show_bitfield(struct seq_file *m, uint32_t value, const char *callba
}
}
+static void show_formats(struct seq_file *m, u32 *formats, size_t formats_count)
+{
+ for (int i = 0; i < formats_count; i++) {
+ seq_printf(m, "%p4cc", &formats[i]);
+ if (i != formats_count - 1)
+ seq_puts(m, ", ");
+ }
+}
+
static int vkms_config_show(struct seq_file *m, void *data)
{
struct drm_debugfs_entry *entry = m->private;
@@ -478,6 +523,10 @@ static int vkms_config_show(struct seq_file *m, void *data)
seq_puts(m, "\n");
seq_printf(m, "\tdefault color range=%s\n",
drm_get_color_range_name(vkms_config_plane_get_default_color_range(plane_cfg)));
+ seq_puts(m, "\tsupported formats=");
+ show_formats(m, vkms_config_plane_get_supported_formats(plane_cfg),
+ vkms_config_plane_get_supported_formats_count(plane_cfg));
+ seq_puts(m, "\n");
}
vkms_config_for_each_crtc(vkmsdev->config, crtc_cfg) {
@@ -527,6 +576,10 @@ struct vkms_config_plane __must_check *vkms_config_create_plane(struct vkms_conf
if (ret)
goto cleanup_plane_cfg;
+ ret = vkms_config_plane_add_all_formats(plane_cfg);
+ if (ret)
+ goto cleanup_plane_cfg;
+
vkms_config_plane_set_supported_rotations(plane_cfg,
DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK);
vkms_config_plane_set_default_rotation(plane_cfg, DRM_MODE_ROTATE_0);
@@ -554,6 +607,7 @@ EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_plane);
void vkms_config_destroy_plane(struct vkms_config_plane *plane_cfg)
{
xa_destroy(&plane_cfg->possible_crtcs);
+ kfree(plane_cfg->supported_formats);
list_del(&plane_cfg->link);
kfree(plane_cfg->name);
kfree(plane_cfg);
@@ -658,6 +712,80 @@ static struct vkms_config_plane *vkms_config_crtc_get_plane(const struct vkms_co
return NULL;
}
+int __must_check vkms_config_plane_add_all_formats(struct vkms_config_plane *plane_cfg)
+{
+ u32 *ret = krealloc_array(plane_cfg->supported_formats,
+ ARRAY_SIZE(vkms_supported_plane_formats),
+ sizeof(uint32_t), GFP_KERNEL);
+ if (!ret)
+ return -ENOMEM;
+ plane_cfg->supported_formats = ret;
+
+ memcpy(plane_cfg->supported_formats, vkms_supported_plane_formats,
+ sizeof(vkms_supported_plane_formats));
+ plane_cfg->supported_formats_count = ARRAY_SIZE(vkms_supported_plane_formats);
+ return 0;
+}
+
+static bool is_supported_format(u32 drm_format)
+{
+ for (int i = 0; i < ARRAY_SIZE(vkms_supported_plane_formats); i++) {
+ if (vkms_supported_plane_formats[i] == drm_format)
+ return true;
+ }
+
+ return false;
+}
+
+static bool vkms_config_plane_has_format(struct vkms_config_plane *plane_cfg, u32 drm_format)
+{
+ for (unsigned int i = 0; i < plane_cfg->supported_formats_count; i++) {
+ if (plane_cfg->supported_formats[i] == drm_format)
+ return true;
+ }
+ return false;
+}
+
+int __must_check vkms_config_plane_add_format(struct vkms_config_plane *plane_cfg, u32 drm_format)
+{
+ if (!is_supported_format(drm_format))
+ return -EINVAL;
+
+ if (vkms_config_plane_has_format(plane_cfg, drm_format))
+ return 0;
+
+ u32 *new_ptr = krealloc_array(plane_cfg->supported_formats,
+ plane_cfg->supported_formats_count + 1,
+ sizeof(*plane_cfg->supported_formats), GFP_KERNEL);
+ if (!new_ptr)
+ return -ENOMEM;
+
+ plane_cfg->supported_formats = new_ptr;
+ plane_cfg->supported_formats[plane_cfg->supported_formats_count] = drm_format;
+ plane_cfg->supported_formats_count++;
+
+ return 0;
+}
+
+void vkms_config_plane_remove_all_formats(struct vkms_config_plane *plane_cfg)
+{
+ plane_cfg->supported_formats_count = 0;
+ kfree(plane_cfg->supported_formats);
+ plane_cfg->supported_formats = NULL;
+}
+
+void vkms_config_plane_remove_format(struct vkms_config_plane *plane_cfg, u32 drm_format)
+{
+ for (unsigned int i = 0; i < plane_cfg->supported_formats_count; i++) {
+ if (plane_cfg->supported_formats[i] == drm_format) {
+ plane_cfg->supported_formats[i] =
+ plane_cfg->supported_formats[plane_cfg->supported_formats_count -
+ 1];
+ plane_cfg->supported_formats_count--;
+ }
+ }
+}
+
struct vkms_config_plane *vkms_config_crtc_primary_plane(const struct vkms_config *config,
struct vkms_config_crtc *crtc_cfg)
{
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 60cadb7bea5b..3de4a92af9c5 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -50,6 +50,8 @@ struct vkms_config {
* @supported_color_encodings: Color encodings that this plane will support
* @default_color_range: Default color range that should be used by this plane
* @supported_color_ranges: Color ranges that this plane will support
+ * @supported_formats: List of supported formats
+ * @supported_formats_count: Length of @supported_formats
*/
struct vkms_config_plane {
struct list_head link;
@@ -63,6 +65,8 @@ struct vkms_config_plane {
unsigned int supported_color_encodings;
enum drm_color_range default_color_range;
unsigned int supported_color_ranges;
+ u32 *supported_formats;
+ unsigned int supported_formats_count;
struct xarray possible_crtcs;
bool default_pipeline;
@@ -475,6 +479,53 @@ bool vkms_config_valid_plane_color_range(const struct vkms_config *config,
const struct vkms_config_plane *plane_cfg);
#endif
+static inline u32 *
+vkms_config_plane_get_supported_formats(const struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->supported_formats;
+}
+
+static inline unsigned int
+vkms_config_plane_get_supported_formats_count(struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->supported_formats_count;
+}
+
+/** vkms_config_plane_add_format - Add a format to the list of supported format of a plane
+ *
+ * The passed drm_format can already be present in the list. This may fail if the allocation of a
+ * bigger array fails.
+ *
+ * @plane_cfg: Plane to add the format to
+ * @drm_format: Format to add to this plane
+ *
+ * Returns: 0 on success, -ENOMEM if array allocation fails, -EINVAL if the format is not supported
+ * by VKMS
+ */
+int __must_check vkms_config_plane_add_format(struct vkms_config_plane *plane_cfg, u32 drm_format);
+
+/**
+ * vkms_config_plane_add_all_formats - Helper to quickly add all the supported formats
+ * @plane_cfg: Plane to add the formats to
+ *
+ * Returns: 0 on success, -ENOMEM if array allocation fails
+ * by VKMS
+ */
+int __must_check vkms_config_plane_add_all_formats(struct vkms_config_plane *plane_cfg);
+
+/**
+ * vkms_config_plane_remove_format - Remove a specific format from a plane
+ * @plane_cfg: Plane to remove the format from
+ * @drm_format: Format to remove
+ */
+void vkms_config_plane_remove_format(struct vkms_config_plane *plane_cfg, u32 drm_format);
+
+/**
+ * vkms_config_plane_remove_all_formats - Remove all formats from a plane
+ * @plane_cfg: Plane to remove the formats from
+ */
+void vkms_config_plane_remove_all_formats(struct vkms_config_plane *plane_cfg);
+
/**
* vkms_config_plane_set_name() - Set the plane name
* @plane_cfg: Plane to set the name to
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index d4ccf418198e..6e767cdf8194 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -15,42 +15,6 @@
#include "vkms_drv.h"
#include "vkms_formats.h"
-static const u32 vkms_formats[] = {
- DRM_FORMAT_ARGB8888,
- DRM_FORMAT_ABGR8888,
- DRM_FORMAT_BGRA8888,
- DRM_FORMAT_RGBA8888,
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_XBGR8888,
- DRM_FORMAT_RGB888,
- DRM_FORMAT_BGR888,
- DRM_FORMAT_XRGB16161616,
- DRM_FORMAT_XBGR16161616,
- DRM_FORMAT_ARGB16161616,
- DRM_FORMAT_ABGR16161616,
- DRM_FORMAT_RGB565,
- DRM_FORMAT_BGR565,
- DRM_FORMAT_NV12,
- DRM_FORMAT_NV16,
- DRM_FORMAT_NV24,
- DRM_FORMAT_NV21,
- DRM_FORMAT_NV61,
- DRM_FORMAT_NV42,
- DRM_FORMAT_YUV420,
- DRM_FORMAT_YUV422,
- DRM_FORMAT_YUV444,
- DRM_FORMAT_YVU420,
- DRM_FORMAT_YVU422,
- DRM_FORMAT_YVU444,
- DRM_FORMAT_P010,
- DRM_FORMAT_P012,
- DRM_FORMAT_P016,
- DRM_FORMAT_R1,
- DRM_FORMAT_R2,
- DRM_FORMAT_R4,
- DRM_FORMAT_R8,
-};
-
static struct drm_plane_state *
vkms_plane_duplicate_state(struct drm_plane *plane)
{
@@ -227,7 +191,8 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 0,
&vkms_plane_funcs,
- vkms_formats, ARRAY_SIZE(vkms_formats),
+ vkms_config_plane_get_supported_formats(plane_cfg),
+ vkms_config_plane_get_supported_formats_count(plane_cfg),
NULL, vkms_config_plane_get_type(plane_cfg),
vkms_config_plane_get_name(plane_cfg));
if (IS_ERR(plane))
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 23/38] drm/vkms: Introduce configfs for plane format
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (21 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 22/38] drm/vkms: Introduce config for plane format Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:45 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 24/38] drm/vkms: Properly render plane using their zpos Louis Chauvet
` (14 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
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@bootlin.com>
---
Documentation/ABI/testing/configfs-vkms | 9 ++
Documentation/gpu/vkms.rst | 7 +-
drivers/gpu/drm/vkms/tests/Makefile | 3 +-
drivers/gpu/drm/vkms/tests/vkms_configfs_test.c | 102 +++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_configfs.c | 113 ++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_configfs.h | 4 +
6 files changed, 236 insertions(+), 2 deletions(-)
diff --git a/Documentation/ABI/testing/configfs-vkms b/Documentation/ABI/testing/configfs-vkms
index ef0c3da6b3ca..de901ce36b2e 100644
--- a/Documentation/ABI/testing/configfs-vkms
+++ b/Documentation/ABI/testing/configfs-vkms
@@ -147,6 +147,15 @@ Description:
Default color range presented to userspace, same
values as supported_color_ranges.
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/supported_formats
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ List of supported formats for this plane. To add a new
+ item, write its fourcc code prefixed with '+'. To remove,
+ use '-' prefix. Use '+*' to add all formats, '-*' to
+ remove all.
+
What: /sys/kernel/config/vkms/<device>/planes/<plane>/possible_crtcs
Date: Nov 2025
Contact: dri-devel@lists.freedesktop.org
diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index 7e8f4fe3b392..e5280a99eee8 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 7 configurable attributes:
+Planes have 8 configurable attributes:
- type: Plane type: 0 overlay, 1 primary, 2 cursor (same values as those
exposed by the "type" property of a plane)
@@ -108,6 +108,11 @@ Planes have 7 configurable attributes:
must be set too.
- default_color_range: Default color range presented to the userspace, same
values as supported_color_ranges
+- supported_formats: List of supported formats for this plane. To add a new item in the
+ list, write it using a plus and 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 d4d9ba8d4c54..92cfa7262ba4 100644
--- a/drivers/gpu/drm/vkms/tests/Makefile
+++ b/drivers/gpu/drm/vkms/tests/Makefile
@@ -3,6 +3,7 @@
vkms-kunit-tests-y := \
vkms_config_test.o \
vkms_format_test.o \
- vkms_color_test.o
+ vkms_color_test.o \
+ vkms_configfs_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..8d02c2c459d9
--- /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
+ * @str: Contains the string to parse
+ * @str_len: str 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 *str;
+ int str_len;
+ int expected_len;
+ int expected_offset;
+};
+
+struct vkms_configfs_parse_format_case vkms_configfs_parse_format_test_cases[] = {
+ {
+ .str = "+RG24",
+ .str_len = 6,
+ .expected_len = 5,
+ .expected_offset = 0,
+ }, {
+ .str = "-RG24",
+ .str_len = 6,
+ .expected_len = 5,
+ .expected_offset = 0
+ }, {
+ .str = " -RG24",
+ .str_len = 8,
+ .expected_len = 5,
+ .expected_offset = 2
+ }, {
+ .str = "+*",
+ .str_len = 3,
+ .expected_len = 2,
+ .expected_offset = 0
+ }, {
+ .str = "-RG24+RG24",
+ .str_len = 11,
+ .expected_len = 5,
+ .expected_offset = 0
+ }, {
+ .str = "-R1+RG24",
+ .str_len = 9,
+ .expected_len = 3,
+ .expected_offset = 0
+ }, {
+ .str = "\n-R1",
+ .str_len = 5,
+ .expected_len = 3,
+ .expected_offset = 1
+ }, {
+ .str = "-R1111",
+ .str_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->str, param->str + param->str_len, &out);
+
+ KUNIT_EXPECT_EQ(test, len, param->expected_len);
+ KUNIT_EXPECT_PTR_EQ(test, out, param->str + 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->str);
+}
+
+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 56a0c542a143..e6cb245b8582 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -3,6 +3,8 @@
#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"
@@ -576,6 +578,115 @@ 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);
+}
+
+/**
+ * vkms_configfs_parse_next_format() - Parse the next format in page,
+ * skipping all non fourcc-related characters
+ * @page: page to search into
+ * @page_end: last character 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;
+
+ if (count < 2 || count > 5)
+ return -EINVAL;
+
+ if (page[0] != '+' && page[0] != '-')
+ return -EINVAL;
+
+ if (page[1] == '*' && count != 2)
+ return -EINVAL;
+
+ scoped_guard(mutex, &plane->dev->lock) {
+ char fmt[4] = {' ', ' ', ' ', ' '};
+
+ memcpy(fmt, &page[1], min(count - 1, 4));
+
+ if (page[0] == '+' && page[1] == '*')
+ ret = vkms_config_plane_add_all_formats(plane->config);
+ else if (page[0] == '-' && page[1] == '*')
+ vkms_config_plane_remove_all_formats(plane->config);
+ else if (page[0] == '+')
+ ret = vkms_config_plane_add_format(plane->config, *(int *)fmt);
+ else if (page[0] == '-')
+ vkms_config_plane_remove_format(plane->config, *(int *)fmt);
+
+ if (ret)
+ return ret;
+ }
+
+ return count;
+}
+
CONFIGFS_ATTR(plane_, type);
CONFIGFS_ATTR(plane_, supported_rotations);
CONFIGFS_ATTR(plane_, default_rotation);
@@ -583,6 +694,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,
@@ -592,6 +704,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..73be660412ca 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.h
+++ b/drivers/gpu/drm/vkms/vkms_configfs.h
@@ -5,4 +5,8 @@
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.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 24/38] drm/vkms: Properly render plane using their zpos
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (22 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 23/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:44 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 25/38] drm/vkms: Introduce config for plane zpos property Louis Chauvet
` (13 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
Currently planes are rendered in creation order. This is not an issue, but
with the introduction of new zpos configuration, it is required to
properly render planes.
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/vkms_crtc.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index 079abfba427d..b9428de2d4aa 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -142,14 +142,20 @@ static int vkms_crtc_atomic_check(struct drm_crtc *crtc,
return -ENOMEM;
vkms_state->num_active_planes = i;
- i = 0;
+ ret = drm_atomic_normalize_zpos(crtc->dev, state);
+ if (ret)
+ return ret;
+
drm_for_each_plane_mask(plane, crtc->dev, crtc_state->plane_mask) {
plane_state = drm_atomic_get_new_plane_state(crtc_state->state, plane);
if (!plane_state->visible)
continue;
- vkms_state->active_planes[i++] =
+ // Order planes according to their normalized_zpos
+ // After drm_atomic_normalize_zpos, the possible values are 0..n_planes-1
+ // so store them using this index
+ vkms_state->active_planes[plane_state->normalized_zpos] =
to_vkms_plane_state(plane_state);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 25/38] drm/vkms: Introduce config for plane zpos property
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (23 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 24/38] drm/vkms: Properly render plane using their zpos Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:41 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 26/38] drm/vkms: Introduce configfs " Louis Chauvet
` (12 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
VKMS can render plane in any order. Introduce the appropriate
configuration.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/tests/vkms_config_test.c | 89 ++++++++++++++++
drivers/gpu/drm/vkms/vkms_config.c | 56 ++++++++++
drivers/gpu/drm/vkms/vkms_config.h | 143 ++++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_plane.c | 11 ++
4 files changed, 299 insertions(+)
diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
index a88d8b4a969e..4a5899b8ccfd 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_config_test.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
@@ -201,6 +201,9 @@ static void vkms_config_test_default_config(struct kunit *test)
KUNIT_EXPECT_EQ(test,
vkms_config_plane_get_default_color_encoding(plane_cfg),
DRM_COLOR_YCBCR_BT601);
+ KUNIT_EXPECT_EQ(test, vkms_config_plane_get_zpos_enabled(plane_cfg), false);
+ // No need to test the other zpos configurations as they are discarded if
+ // the zpos property is not created.
}
/* Encoders */
@@ -619,6 +622,91 @@ static void vkms_config_test_valid_plane_color_range(struct kunit *test)
vkms_config_destroy(config);
}
+static void vkms_config_test_valid_plane_zpos(struct kunit *test)
+{
+ struct vkms_config *config;
+ struct vkms_config_plane *plane_cfg;
+
+ config = vkms_config_default_create(false, false, false, false);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
+
+ plane_cfg = get_first_plane(config);
+
+ /* Valid, zpos disabled */
+ vkms_config_plane_set_zpos_enabled(plane_cfg, false);
+ vkms_config_plane_set_zpos_mutable(plane_cfg, false);
+ vkms_config_plane_set_zpos_initial(plane_cfg, 0);
+ vkms_config_plane_set_zpos_min(plane_cfg, 0);
+ vkms_config_plane_set_zpos_max(plane_cfg, 0);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Valid, zpos disabled, min/max are ignored */
+ vkms_config_plane_set_zpos_enabled(plane_cfg, false);
+ vkms_config_plane_set_zpos_mutable(plane_cfg, false);
+ vkms_config_plane_set_zpos_initial(plane_cfg, 8);
+ vkms_config_plane_set_zpos_min(plane_cfg, 3);
+ vkms_config_plane_set_zpos_max(plane_cfg, 2);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Valid, zpos enabled but mutable disabled */
+ vkms_config_plane_set_zpos_enabled(plane_cfg, true);
+ vkms_config_plane_set_zpos_mutable(plane_cfg, false);
+ vkms_config_plane_set_zpos_initial(plane_cfg, 1);
+ vkms_config_plane_set_zpos_min(plane_cfg, 0);
+ vkms_config_plane_set_zpos_max(plane_cfg, 0);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Valid, zpos enabled but mutable disabled */
+ vkms_config_plane_set_zpos_enabled(plane_cfg, true);
+ vkms_config_plane_set_zpos_mutable(plane_cfg, false);
+ vkms_config_plane_set_zpos_initial(plane_cfg, 0);
+ vkms_config_plane_set_zpos_min(plane_cfg, 0);
+ vkms_config_plane_set_zpos_max(plane_cfg, 0);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Invalid, zpos enabled with min > max */
+ vkms_config_plane_set_zpos_enabled(plane_cfg, true);
+ vkms_config_plane_set_zpos_mutable(plane_cfg, true);
+ vkms_config_plane_set_zpos_initial(plane_cfg, 0);
+ vkms_config_plane_set_zpos_min(plane_cfg, 1);
+ vkms_config_plane_set_zpos_max(plane_cfg, 0);
+ KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
+
+ /* Valid, zpos enabled with min <= max */
+ vkms_config_plane_set_zpos_enabled(plane_cfg, true);
+ vkms_config_plane_set_zpos_mutable(plane_cfg, true);
+ vkms_config_plane_set_zpos_initial(plane_cfg, 0);
+ vkms_config_plane_set_zpos_min(plane_cfg, 0);
+ vkms_config_plane_set_zpos_max(plane_cfg, 1);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Invalid, zpos enabled with initial < min */
+ vkms_config_plane_set_zpos_enabled(plane_cfg, true);
+ vkms_config_plane_set_zpos_mutable(plane_cfg, true);
+ vkms_config_plane_set_zpos_initial(plane_cfg, 0);
+ vkms_config_plane_set_zpos_min(plane_cfg, 1);
+ vkms_config_plane_set_zpos_max(plane_cfg, 2);
+ KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
+
+ /* Invalid, zpos enabled with initial > max */
+ vkms_config_plane_set_zpos_enabled(plane_cfg, true);
+ vkms_config_plane_set_zpos_mutable(plane_cfg, true);
+ vkms_config_plane_set_zpos_initial(plane_cfg, 3);
+ vkms_config_plane_set_zpos_min(plane_cfg, 1);
+ vkms_config_plane_set_zpos_max(plane_cfg, 2);
+ KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
+
+ /* Valid, zpos enabled with initial between min and max */
+ vkms_config_plane_set_zpos_enabled(plane_cfg, true);
+ vkms_config_plane_set_zpos_mutable(plane_cfg, true);
+ vkms_config_plane_set_zpos_initial(plane_cfg, 1);
+ vkms_config_plane_set_zpos_min(plane_cfg, 0);
+ vkms_config_plane_set_zpos_max(plane_cfg, 2);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ vkms_config_destroy(config);
+}
+
static void vkms_config_test_valid_plane_possible_crtcs(struct kunit *test)
{
struct vkms_config *config;
@@ -1144,6 +1232,7 @@ static struct kunit_case vkms_config_test_cases[] = {
KUNIT_CASE(vkms_config_test_valid_plane_rotations),
KUNIT_CASE(vkms_config_test_valid_plane_color_encoding),
KUNIT_CASE(vkms_config_test_valid_plane_color_range),
+ KUNIT_CASE(vkms_config_test_valid_plane_zpos),
KUNIT_CASE(vkms_config_test_valid_plane_possible_crtcs),
KUNIT_CASE(vkms_config_test_invalid_crtc_number),
KUNIT_CASE(vkms_config_test_invalid_encoder_number),
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index c7de3e307367..5bc8248f9935 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -91,6 +91,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
if (IS_ERR(plane_cfg))
goto err_alloc;
vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_PRIMARY);
+ vkms_config_plane_set_zpos_enabled(plane_cfg, false);
crtc_cfg = vkms_config_create_crtc(config);
if (IS_ERR(crtc_cfg))
@@ -110,6 +111,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
vkms_config_plane_set_type(plane_cfg,
DRM_PLANE_TYPE_OVERLAY);
vkms_config_plane_set_default_pipeline(plane_cfg, enable_plane_pipeline);
+ vkms_config_plane_set_zpos_enabled(plane_cfg, false);
if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg))
goto err_alloc;
@@ -123,6 +125,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_CURSOR);
vkms_config_plane_set_default_pipeline(plane_cfg, enable_plane_pipeline);
+ vkms_config_plane_set_zpos_enabled(plane_cfg, false);
if (vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg))
goto err_alloc;
@@ -253,6 +256,33 @@ bool vkms_config_valid_plane_color_range(const struct vkms_config *config,
}
EXPORT_SYMBOL_IF_KUNIT(vkms_config_valid_plane_color_range);
+VISIBLE_IF_KUNIT
+bool vkms_config_valid_plane_zpos(const struct vkms_config *config,
+ const struct vkms_config_plane *plane_cfg)
+{
+ struct drm_device *dev = config->dev ? &config->dev->drm : NULL;
+
+ if (!vkms_config_plane_get_zpos_enabled(plane_cfg) ||
+ !vkms_config_plane_get_zpos_mutable(plane_cfg))
+ return true;
+
+ if (vkms_config_plane_get_zpos_initial(plane_cfg) >
+ vkms_config_plane_get_zpos_max(plane_cfg)) {
+ drm_info(dev, "Configured initial zpos value bigger than zpos max\n");
+ return false;
+ }
+
+ if (vkms_config_plane_get_zpos_max(plane_cfg) <
+ vkms_config_plane_get_zpos_min(plane_cfg) ||
+ vkms_config_plane_get_zpos_initial(plane_cfg) <
+ vkms_config_plane_get_zpos_min(plane_cfg)) {
+ drm_info(dev, "Configured zpos value outside (zpos min; zpos max)\n");
+ return false;
+ }
+
+ return true;
+}
+
static bool valid_planes_for_crtc(const struct vkms_config *config,
struct vkms_config_crtc *crtc_cfg)
{
@@ -413,6 +443,9 @@ bool vkms_config_is_valid(const struct vkms_config *config)
struct vkms_config_crtc *crtc_cfg;
struct vkms_config_plane *plane_cfg;
+ bool has_zpos_enabled = false;
+ bool has_zpos_disabled = false;
+
vkms_config_for_each_plane(config, plane_cfg) {
if (!vkms_config_valid_plane_rotation(config, plane_cfg))
return false;
@@ -429,6 +462,19 @@ bool vkms_config_is_valid(const struct vkms_config *config)
"Both supported color encodings and color ranges must be set, or none\n");
return false;
}
+
+ if (!vkms_config_valid_plane_zpos(config, plane_cfg))
+ return false;
+
+ if (vkms_config_plane_get_zpos_enabled(plane_cfg))
+ has_zpos_enabled = true;
+ else
+ has_zpos_disabled = true;
+ }
+
+ if (has_zpos_enabled && has_zpos_disabled) {
+ drm_info(dev, "In the same device, all planes must have zpos enabled or none of them");
+ return false;
}
if (!valid_plane_number(config))
@@ -527,6 +573,16 @@ static int vkms_config_show(struct seq_file *m, void *data)
show_formats(m, vkms_config_plane_get_supported_formats(plane_cfg),
vkms_config_plane_get_supported_formats_count(plane_cfg));
seq_puts(m, "\n");
+ seq_printf(m, "\tzpos_enabled=%s\n",
+ str_true_false(vkms_config_plane_get_zpos_enabled(plane_cfg)));
+ seq_printf(m, "\tzpos_mutable=%s\n",
+ str_true_false(vkms_config_plane_get_zpos_mutable(plane_cfg)));
+ seq_printf(m, "\tzpos_min=%d\n",
+ vkms_config_plane_get_zpos_min(plane_cfg));
+ seq_printf(m, "\tzpos_initial=%d\n",
+ vkms_config_plane_get_zpos_initial(plane_cfg));
+ seq_printf(m, "\tzpos_max=%d\n",
+ vkms_config_plane_get_zpos_max(plane_cfg));
}
vkms_config_for_each_crtc(vkmsdev->config, crtc_cfg) {
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 3de4a92af9c5..7c0c24939a96 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -52,6 +52,11 @@ struct vkms_config {
* @supported_color_ranges: Color ranges that this plane will support
* @supported_formats: List of supported formats
* @supported_formats_count: Length of @supported_formats
+ * @zpos_enabled: Enable or disable the zpos property
+ * @zpos_mutable: Make the zpos property mutable or not (ignored if @zpos_enabled is false)
+ * @zpos_initial: Initial value for zpos property (ignored if @zpos_enabled is false)
+ * @zpos_min: Minimal value for zpos property (ignored if @zpos_enabled is false)
+ * @zpos_max: Maximal value for zpos property (ignored if @zpos_enabled is false)
*/
struct vkms_config_plane {
struct list_head link;
@@ -69,6 +74,11 @@ struct vkms_config_plane {
unsigned int supported_formats_count;
struct xarray possible_crtcs;
bool default_pipeline;
+ bool zpos_enabled;
+ bool zpos_mutable;
+ unsigned int zpos_initial;
+ unsigned int zpos_min;
+ unsigned int zpos_max;
/* Internal usage */
struct vkms_plane *plane;
@@ -557,6 +567,139 @@ vkms_config_plane_get_name(const struct vkms_config_plane *plane_cfg)
return plane_cfg->name;
}
+/**
+ * vkms_config_plane_set_zpos_enabled() - Enable or disable zpos property for a plane
+ * @plane_cfg: Plane configuration to modify
+ * @zpos_enabled: Whether to enable the zpos property
+ */
+static inline
+void vkms_config_plane_set_zpos_enabled(struct vkms_config_plane *plane_cfg,
+ bool zpos_enabled)
+{
+ plane_cfg->zpos_enabled = zpos_enabled;
+}
+
+/**
+ * vkms_config_plane_set_zpos_mutable() - Set whether zpos property is mutable
+ * @plane_cfg: Plane configuration to modify
+ * @zpos_mutable: Whether the zpos property should be mutable
+ */
+static inline
+void vkms_config_plane_set_zpos_mutable(struct vkms_config_plane *plane_cfg,
+ bool zpos_mutable)
+{
+ plane_cfg->zpos_mutable = zpos_mutable;
+}
+
+/**
+ * vkms_config_plane_set_zpos_initial() - Set the initial zpos value
+ * @plane_cfg: Plane configuration to modify
+ * @zpos_initial: Initial zpos value
+ */
+static inline
+void vkms_config_plane_set_zpos_initial(struct vkms_config_plane *plane_cfg,
+ unsigned int zpos_initial)
+{
+ plane_cfg->zpos_initial = zpos_initial;
+}
+
+/**
+ * vkms_config_plane_set_zpos_min() - Set the minimum zpos value
+ * @plane_cfg: Plane configuration to modify
+ * @zpos_min: Minimum zpos value
+ */
+static inline
+void vkms_config_plane_set_zpos_min(struct vkms_config_plane *plane_cfg,
+ unsigned int zpos_min)
+{
+ plane_cfg->zpos_min = zpos_min;
+}
+
+/**
+ * vkms_config_plane_set_zpos_max() - Set the maximum zpos value
+ * @plane_cfg: Plane configuration to modify
+ * @zpos_max: Maximum zpos value
+ */
+static inline
+void vkms_config_plane_set_zpos_max(struct vkms_config_plane *plane_cfg,
+ unsigned int zpos_max)
+{
+ plane_cfg->zpos_max = zpos_max;
+}
+
+/**
+ * vkms_config_plane_get_zpos_enabled() - Check if zpos property is enabled
+ * @plane_cfg: Plane configuration to check
+ *
+ * Returns:
+ * True if the zpos property is enabled for this plane, false otherwise.
+ */
+static inline
+bool vkms_config_plane_get_zpos_enabled(const struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->zpos_enabled;
+}
+
+/**
+ * vkms_config_plane_get_zpos_mutable() - Check if zpos property is mutable
+ * @plane_cfg: Plane configuration to check
+ *
+ * Returns:
+ * True if the zpos property is mutable for this plane, false otherwise.
+ */
+static inline
+bool vkms_config_plane_get_zpos_mutable(const struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->zpos_mutable;
+}
+
+/**
+ * vkms_config_plane_get_zpos_initial() - Get the initial zpos value
+ * @plane_cfg: Plane configuration to check
+ *
+ * Returns:
+ * The initial zpos value for this plane. The return value is undefined if
+ * zpos is disabled.
+ */
+static inline
+unsigned int vkms_config_plane_get_zpos_initial(const struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->zpos_initial;
+}
+
+/**
+ * vkms_config_plane_get_zpos_min() - Get the minimum zpos value
+ * @plane_cfg: Plane configuration to check
+ *
+ * Returns:
+ * The minimum allowed zpos value for this plane. The return value is undefined
+ * if zpos is disabled.
+ */
+static inline
+unsigned int vkms_config_plane_get_zpos_min(const struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->zpos_min;
+}
+
+/**
+ * vkms_config_plane_get_zpos_max() - Get the maximum zpos value
+ * @plane_cfg: Plane configuration to check
+ *
+ * Returns:
+ * The maximum allowed zpos value for this plane. The return value is undefined
+ * if zpos is disabled.
+ */
+static inline
+unsigned int vkms_config_plane_get_zpos_max(const struct vkms_config_plane *plane_cfg)
+{
+ return plane_cfg->zpos_max;
+}
+
+#if IS_ENABLED(CONFIG_KUNIT)
+bool vkms_config_valid_plane_zpos(const struct vkms_config *config,
+ const struct vkms_config_plane *plane_cfg);
+#endif
+
/**
* vkms_config_plane_attach_crtc - Attach a plane to a CRTC
* @plane_cfg: Plane to attach
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index 6e767cdf8194..d600a6167042 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -214,6 +214,17 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
if (vkms_config_plane_get_default_pipeline(plane_cfg))
vkms_initialize_colorops(&plane->base);
+ if (vkms_config_plane_get_zpos_enabled(plane_cfg)) {
+ if (vkms_config_plane_get_zpos_mutable(plane_cfg)) {
+ drm_plane_create_zpos_property(&plane->base,
+ vkms_config_plane_get_zpos_initial(plane_cfg),
+ vkms_config_plane_get_zpos_min(plane_cfg),
+ vkms_config_plane_get_zpos_max(plane_cfg));
+ } else {
+ drm_plane_create_zpos_immutable_property(&plane->base,
+ vkms_config_plane_get_zpos_initial(plane_cfg));
+ }
+ }
return plane;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 26/38] drm/vkms: Introduce configfs for plane zpos property
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (24 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 25/38] drm/vkms: Introduce config for plane zpos property Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:46 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 27/38] drm/vkms: Introduce config for connector type Louis Chauvet
` (11 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
Modern compositor rely on zpos management to offload some processing to
deticated hardware. In order to test multiple configurations, add zpos
configuration to configFS.
Introduce multiple attributes to configure zpos:
- zpos_enabled - Create or not the zpos property. If not created, the zpos
is undefined.
- zpos_mutable - If the zpos property is created, allow or not the
userspace to modify it
- zpos_initial - Initial value for zpos property. Must be between zpos_min
and zpos_max
- zpos_min - Minimum zpos value for this plane. Must be <= zpos_max
- zpos_max - Maximum zpos value for this plane. Must be >= zpos_min
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
Documentation/ABI/testing/configfs-vkms | 36 +++++++
Documentation/gpu/vkms.rst | 9 +-
drivers/gpu/drm/vkms/vkms_configfs.c | 180 ++++++++++++++++++++++++++++++++
3 files changed, 224 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/configfs-vkms b/Documentation/ABI/testing/configfs-vkms
index de901ce36b2e..9bc51b1e682a 100644
--- a/Documentation/ABI/testing/configfs-vkms
+++ b/Documentation/ABI/testing/configfs-vkms
@@ -156,6 +156,42 @@ Description:
use '-' prefix. Use '+*' to add all formats, '-*' to
remove all.
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/zpos_enabled
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Enable or disable the zpos property. Value: 1 - enabled,
+ 0 - disabled.
+
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/zpos_mutable
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Create the zpos property as mutable or immutable.
+ Value: 1 - mutable, 0 - immutable. No effect if
+ zpos_enabled is not set.
+
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/zpos_initial
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Set the initial zpos value. Must be between zpos_min
+ and zpos_max. No effect if zpos_enabled is not set.
+
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/zpos_min
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Set the minimal zpos value. No effect if zpos_enabled
+ is not set.
+
+What: /sys/kernel/config/vkms/<device>/planes/<plane>/zpos_max
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Set the maximal zpos value. No effect if zpos_enabled
+ is not set.
+
What: /sys/kernel/config/vkms/<device>/planes/<plane>/possible_crtcs
Date: Nov 2025
Contact: dri-devel@lists.freedesktop.org
diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index e5280a99eee8..b58e96a3c273 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 13 configurable attributes:
- type: Plane type: 0 overlay, 1 primary, 2 cursor (same values as those
exposed by the "type" property of a plane)
@@ -113,6 +113,13 @@ Planes have 8 configurable attributes:
To remove a format, use a minus and its fourcc: -XR24
To add all formats use +*
To remove all formats, use -*
+- zpos_enabled: Enable or not the zpos property: 1 enable, 0 disable
+- zpos_mutable: Create the zpos property as a mutable or imutable property: 1 mutable,
+ 0 immutable. No effect if zpos_enabled is not set.
+- zpos_initial: Set the initial zpos value. Must be between zpos_min and zpos_max. No
+ effect if zpos_enabled is not set.
+- zpos_min: Set the minimum zpos value. No effect if zpos_enabled is not set.
+- zpos_max: Set the maximum zpos value. No effect if zpos_enabled is not set.
Continue by creating one or more CRTCs::
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index e6cb245b8582..95f4594fb683 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -687,6 +687,176 @@ static ssize_t plane_supported_formats_store(struct config_item *item,
return count;
}
+static ssize_t plane_zpos_enabled_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_plane *plane;
+ bool enabled;
+
+ plane = plane_item_to_vkms_configfs_plane(item);
+
+ scoped_guard(mutex, &plane->dev->lock)
+ enabled = vkms_config_plane_get_zpos_enabled(plane->config);
+
+ return sprintf(page, "%d\n", enabled);
+}
+
+static ssize_t plane_zpos_enabled_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct vkms_configfs_plane *plane;
+ bool enabled;
+
+ plane = plane_item_to_vkms_configfs_plane(item);
+
+ if (kstrtobool(page, &enabled))
+ return -EINVAL;
+
+ scoped_guard(mutex, &plane->dev->lock) {
+ if (plane->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_plane_set_zpos_enabled(plane->config, enabled);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t plane_zpos_mutable_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_plane *plane;
+ bool mutable;
+
+ plane = plane_item_to_vkms_configfs_plane(item);
+
+ scoped_guard(mutex, &plane->dev->lock)
+ mutable = vkms_config_plane_get_zpos_mutable(plane->config);
+
+ return sprintf(page, "%d\n", mutable);
+}
+
+static ssize_t plane_zpos_mutable_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct vkms_configfs_plane *plane;
+ bool mutable;
+
+ plane = plane_item_to_vkms_configfs_plane(item);
+
+ if (kstrtobool(page, &mutable))
+ return -EINVAL;
+
+ scoped_guard(mutex, &plane->dev->lock) {
+ if (plane->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_plane_set_zpos_mutable(plane->config, mutable);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t plane_zpos_initial_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_plane *plane;
+ unsigned int initial;
+
+ plane = plane_item_to_vkms_configfs_plane(item);
+
+ scoped_guard(mutex, &plane->dev->lock)
+ initial = vkms_config_plane_get_zpos_initial(plane->config);
+
+ return sprintf(page, "%u\n", initial);
+}
+
+static ssize_t plane_zpos_initial_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct vkms_configfs_plane *plane;
+ unsigned int initial;
+
+ plane = plane_item_to_vkms_configfs_plane(item);
+
+ if (kstrtouint(page, 10, &initial))
+ return -EINVAL;
+
+ scoped_guard(mutex, &plane->dev->lock) {
+ if (plane->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_plane_set_zpos_initial(plane->config, initial);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t plane_zpos_min_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_plane *plane;
+ unsigned int min;
+
+ plane = plane_item_to_vkms_configfs_plane(item);
+
+ scoped_guard(mutex, &plane->dev->lock)
+ min = vkms_config_plane_get_zpos_min(plane->config);
+
+ return sprintf(page, "%u\n", min);
+}
+
+static ssize_t plane_zpos_min_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct vkms_configfs_plane *plane;
+ unsigned int min;
+
+ plane = plane_item_to_vkms_configfs_plane(item);
+
+ if (kstrtouint(page, 10, &min))
+ return -EINVAL;
+
+ scoped_guard(mutex, &plane->dev->lock) {
+ if (plane->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_plane_set_zpos_min(plane->config, min);
+ }
+
+ return (ssize_t)count;
+}
+
+static ssize_t plane_zpos_max_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_plane *plane;
+ unsigned int max;
+
+ plane = plane_item_to_vkms_configfs_plane(item);
+
+ scoped_guard(mutex, &plane->dev->lock)
+ max = vkms_config_plane_get_zpos_max(plane->config);
+
+ return sprintf(page, "%u\n", max);
+}
+
+static ssize_t plane_zpos_max_store(struct config_item *item, const char *page,
+ size_t count)
+{
+ struct vkms_configfs_plane *plane;
+ unsigned int max;
+
+ plane = plane_item_to_vkms_configfs_plane(item);
+
+ if (kstrtouint(page, 10, &max))
+ return -EINVAL;
+
+ scoped_guard(mutex, &plane->dev->lock) {
+ if (plane->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_plane_set_zpos_max(plane->config, max);
+ }
+
+ return (ssize_t)count;
+}
+
CONFIGFS_ATTR(plane_, type);
CONFIGFS_ATTR(plane_, supported_rotations);
CONFIGFS_ATTR(plane_, default_rotation);
@@ -695,6 +865,11 @@ CONFIGFS_ATTR(plane_, default_color_range);
CONFIGFS_ATTR(plane_, supported_color_encodings);
CONFIGFS_ATTR(plane_, default_color_encoding);
CONFIGFS_ATTR(plane_, supported_formats);
+CONFIGFS_ATTR(plane_, zpos_enabled);
+CONFIGFS_ATTR(plane_, zpos_mutable);
+CONFIGFS_ATTR(plane_, zpos_initial);
+CONFIGFS_ATTR(plane_, zpos_min);
+CONFIGFS_ATTR(plane_, zpos_max);
static struct configfs_attribute *plane_item_attrs[] = {
&plane_attr_type,
@@ -705,6 +880,11 @@ static struct configfs_attribute *plane_item_attrs[] = {
&plane_attr_supported_color_encodings,
&plane_attr_default_color_encoding,
&plane_attr_supported_formats,
+ &plane_attr_zpos_enabled,
+ &plane_attr_zpos_mutable,
+ &plane_attr_zpos_initial,
+ &plane_attr_zpos_min,
+ &plane_attr_zpos_max,
NULL,
};
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 27/38] drm/vkms: Introduce config for connector type
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (25 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 26/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:45 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 28/38] drm/vkms: Introduce configfs " Louis Chauvet
` (10 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
In order to emulate connector-specific behavior, add connector type
configuration.
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/tests/vkms_config_test.c | 5 +++++
drivers/gpu/drm/vkms/vkms_config.c | 3 +++
drivers/gpu/drm/vkms/vkms_config.h | 24 ++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_connector.c | 5 +++--
drivers/gpu/drm/vkms/vkms_connector.h | 4 +++-
drivers/gpu/drm/vkms/vkms_output.c | 2 +-
6 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
index 4a5899b8ccfd..1900cc79db2b 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_config_test.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
@@ -137,6 +137,7 @@ static void vkms_config_test_default_config(struct kunit *test)
struct vkms_config *config;
struct vkms_config_plane *plane_cfg;
struct vkms_config_crtc *crtc_cfg;
+ struct vkms_config_connector *connector_cfg;
int n_primaries = 0;
int n_cursors = 0;
int n_overlays = 0;
@@ -211,6 +212,10 @@ static void vkms_config_test_default_config(struct kunit *test)
/* Connectors */
KUNIT_EXPECT_EQ(test, vkms_config_get_num_connectors(config), 1);
+ vkms_config_for_each_connector(config, connector_cfg) {
+ KUNIT_EXPECT_EQ(test, vkms_config_connector_get_type(connector_cfg),
+ DRM_MODE_CONNECTOR_VIRTUAL);
+ }
KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 5bc8248f9935..c407aea0bc6a 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -598,6 +598,8 @@ static int vkms_config_show(struct seq_file *m, void *data)
seq_puts(m, "connector:\n");
seq_printf(m, "\tstatus=%s\n",
drm_get_connector_status_name(vkms_config_connector_get_status(connector_cfg)));
+ seq_printf(m, "\ttype=%s\n",
+ drm_get_connector_type_name(vkms_config_connector_get_type(connector_cfg)));
}
return 0;
@@ -930,6 +932,7 @@ struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *c
connector_cfg->config = config;
connector_cfg->status = connector_status_connected;
+ vkms_config_connector_set_type(connector_cfg, DRM_MODE_CONNECTOR_VIRTUAL);
xa_init_flags(&connector_cfg->possible_encoders, XA_FLAGS_ALLOC);
list_add_tail(&connector_cfg->link, &config->connectors);
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 7c0c24939a96..d6d185b2ccc0 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -130,6 +130,7 @@ struct vkms_config_encoder {
* struct vkms_config_connector
*
* @link: Link to the others connector in vkms_config
+ * @type: Store the type of connector using DRM_MODE_CONNECTOR_* values
* @config: The vkms_config this connector belongs to
* @status: Status (connected, disconnected...) of the connector
* @possible_encoders: Array of encoders that can be used with this connector
@@ -142,6 +143,7 @@ struct vkms_config_connector {
struct list_head link;
struct vkms_config *config;
+ int type;
enum drm_connector_status status;
struct xarray possible_encoders;
@@ -344,6 +346,28 @@ vkms_config_plane_set_default_pipeline(struct vkms_config_plane *plane_cfg,
}
/**
+ * vkms_config_connector_get_type() - Return the connector type
+ * @connector_cfg: Connector to get the type from
+ */
+static inline int
+vkms_config_connector_get_type(const struct vkms_config_connector *connector_cfg)
+{
+ return connector_cfg->type;
+}
+
+/**
+ * vkms_config_connector_set_type() - Set the connector type
+ * @connector_cfg: Connector to set the type to
+ * @type: New connector type
+ */
+static inline void
+vkms_config_connector_set_type(struct vkms_config_connector *connector_cfg,
+ int type)
+{
+ connector_cfg->type = type;
+}
+
+/*
* vkms_config_plane_get_default_rotation() - Get the default rotation for a plane
* @plane_cfg: Plane to get the default rotation from
*
diff --git a/drivers/gpu/drm/vkms/vkms_connector.c b/drivers/gpu/drm/vkms/vkms_connector.c
index b0a6b212d3f4..5a87dc2d4c63 100644
--- a/drivers/gpu/drm/vkms/vkms_connector.c
+++ b/drivers/gpu/drm/vkms/vkms_connector.c
@@ -68,7 +68,8 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
.best_encoder = vkms_conn_best_encoder,
};
-struct vkms_connector *vkms_connector_init(struct vkms_device *vkmsdev)
+struct vkms_connector *vkms_connector_init(struct vkms_device *vkmsdev,
+ struct vkms_config_connector *connector_cfg)
{
struct drm_device *dev = &vkmsdev->drm;
struct vkms_connector *connector;
@@ -79,7 +80,7 @@ struct vkms_connector *vkms_connector_init(struct vkms_device *vkmsdev)
return ERR_PTR(-ENOMEM);
ret = drmm_connector_init(dev, &connector->base, &vkms_connector_funcs,
- DRM_MODE_CONNECTOR_VIRTUAL, NULL);
+ vkms_config_connector_get_type(connector_cfg), NULL);
if (ret)
return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/vkms/vkms_connector.h b/drivers/gpu/drm/vkms/vkms_connector.h
index ed312f4eff3a..33253d29b1cc 100644
--- a/drivers/gpu/drm/vkms/vkms_connector.h
+++ b/drivers/gpu/drm/vkms/vkms_connector.h
@@ -4,6 +4,7 @@
#define _VKMS_CONNECTOR_H_
#include "vkms_drv.h"
+#include "vkms_config.h"
#define drm_connector_to_vkms_connector(target) \
container_of(target, struct vkms_connector, base)
@@ -24,7 +25,8 @@ struct vkms_connector {
* Returns:
* The connector or an error on failure.
*/
-struct vkms_connector *vkms_connector_init(struct vkms_device *vkmsdev);
+struct vkms_connector *vkms_connector_init(struct vkms_device *vkmsdev,
+ struct vkms_config_connector *connector_cfg);
/**
* vkms_trigger_connector_hotplug() - Update the device's connectors status
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 86ce07a617f5..1288c8551bc8 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -97,7 +97,7 @@ int vkms_output_init(struct vkms_device *vkmsdev)
struct vkms_config_encoder *possible_encoder;
unsigned long idx = 0;
- connector_cfg->connector = vkms_connector_init(vkmsdev);
+ connector_cfg->connector = vkms_connector_init(vkmsdev, connector_cfg);
if (IS_ERR(connector_cfg->connector)) {
DRM_ERROR("Failed to init connector\n");
return PTR_ERR(connector_cfg->connector);
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 28/38] drm/vkms: Introduce configfs for connector type
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (26 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 27/38] drm/vkms: Introduce config for connector type Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:45 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 29/38] drm/vkms: Rename vkms_connector_init to vkms_connector_init_static Louis Chauvet
` (9 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
Add a new attribute to connector to change its type. This is mostly
cosmetic and don't have direct effect in VKMS behavior.
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
Documentation/ABI/testing/configfs-vkms | 7 ++++
Documentation/gpu/vkms.rst | 3 +-
drivers/gpu/drm/vkms/vkms_configfs.c | 65 +++++++++++++++++++++++++++++++++
3 files changed, 74 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/configfs-vkms b/Documentation/ABI/testing/configfs-vkms
index 9bc51b1e682a..0e588a1145ff 100644
--- a/Documentation/ABI/testing/configfs-vkms
+++ b/Documentation/ABI/testing/configfs-vkms
@@ -33,6 +33,13 @@ Description:
Connection status of the connector. Possible values:
1 - connected, 2 - disconnected, 3 - unknown.
+What: /sys/kernel/config/vkms/<device>/connectors/<connector>/type
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Type of the connector. Possible values match those
+ exposed by the "type" field in drm_connector.
+
What: /sys/kernel/config/vkms/<device>/connectors/<connector>/possible_encoders
Date: Nov 2025
Contact: dri-devel@lists.freedesktop.org
diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index b58e96a3c273..f2622b3fd8af 100644
--- a/Documentation/gpu/vkms.rst
+++ b/Documentation/gpu/vkms.rst
@@ -137,10 +137,11 @@ Last but not least, create one or more connectors::
sudo mkdir /config/vkms/my-vkms/connectors/connector0
-Connectors have 1 configurable attribute:
+Connectors have 2 configurable attribute:
- status: Connection status: 1 connected, 2 disconnected, 3 unknown (same values
as those exposed by the "status" property of a connector)
+- type: Type of connector. Same values as exposed by the "type" field in drm_connector.
To finish the configuration, link the different pipeline items::
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index 95f4594fb683..8b414f1950e8 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -1117,10 +1117,75 @@ static ssize_t connector_status_store(struct config_item *item,
return (ssize_t)count;
}
+static ssize_t connector_type_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_connector *connector;
+ int type;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+
+ scoped_guard(mutex, &connector->dev->lock) {
+ type = vkms_config_connector_get_type(connector->config);
+ }
+
+ return sprintf(page, "%u", type);
+}
+
+static ssize_t connector_type_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct vkms_configfs_connector *connector;
+ int val, ret;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+
+ ret = kstrtouint(page, 10, &val);
+
+ if (ret)
+ return ret;
+
+ switch (val) {
+ case DRM_MODE_CONNECTOR_Unknown:
+ case DRM_MODE_CONNECTOR_VGA:
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_DVID:
+ case DRM_MODE_CONNECTOR_DVIA:
+ case DRM_MODE_CONNECTOR_Composite:
+ case DRM_MODE_CONNECTOR_SVIDEO:
+ case DRM_MODE_CONNECTOR_LVDS:
+ case DRM_MODE_CONNECTOR_Component:
+ case DRM_MODE_CONNECTOR_9PinDIN:
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ case DRM_MODE_CONNECTOR_HDMIA:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ case DRM_MODE_CONNECTOR_TV:
+ case DRM_MODE_CONNECTOR_eDP:
+ case DRM_MODE_CONNECTOR_VIRTUAL:
+ case DRM_MODE_CONNECTOR_DSI:
+ case DRM_MODE_CONNECTOR_DPI:
+ case DRM_MODE_CONNECTOR_SPI:
+ case DRM_MODE_CONNECTOR_USB:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ scoped_guard(mutex, &connector->dev->lock) {
+ if (connector->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_connector_set_type(connector->config, val);
+ }
+
+ return count;
+}
+
CONFIGFS_ATTR(connector_, status);
+CONFIGFS_ATTR(connector_, type);
static struct configfs_attribute *connector_item_attrs[] = {
&connector_attr_status,
+ &connector_attr_type,
NULL,
};
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 29/38] drm/vkms: Rename vkms_connector_init to vkms_connector_init_static
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (27 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 28/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 30/38] drm/vkms: Introduce config for connector supported colorspace Louis Chauvet
` (8 subsequent siblings)
37 siblings, 0 replies; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
With the introduction of dynamic connectors we will have two way of
initializing a VKMS connector. Rename the current function to clarify
the case.
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/vkms_connector.c | 4 ++--
drivers/gpu/drm/vkms/vkms_connector.h | 6 +++---
drivers/gpu/drm/vkms/vkms_output.c | 2 +-
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/vkms/vkms_connector.c b/drivers/gpu/drm/vkms/vkms_connector.c
index 5a87dc2d4c63..5b29dcade7e1 100644
--- a/drivers/gpu/drm/vkms/vkms_connector.c
+++ b/drivers/gpu/drm/vkms/vkms_connector.c
@@ -68,8 +68,8 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
.best_encoder = vkms_conn_best_encoder,
};
-struct vkms_connector *vkms_connector_init(struct vkms_device *vkmsdev,
- struct vkms_config_connector *connector_cfg)
+struct vkms_connector *vkms_connector_init_static(struct vkms_device *vkmsdev,
+ struct vkms_config_connector *connector_cfg)
{
struct drm_device *dev = &vkmsdev->drm;
struct vkms_connector *connector;
diff --git a/drivers/gpu/drm/vkms/vkms_connector.h b/drivers/gpu/drm/vkms/vkms_connector.h
index 33253d29b1cc..85f9082c710e 100644
--- a/drivers/gpu/drm/vkms/vkms_connector.h
+++ b/drivers/gpu/drm/vkms/vkms_connector.h
@@ -19,14 +19,14 @@ struct vkms_connector {
};
/**
- * vkms_connector_init() - Initialize a connector
+ * vkms_connector_init_static() - Initialize a connector
* @vkmsdev: VKMS device containing the connector
*
* Returns:
* The connector or an error on failure.
*/
-struct vkms_connector *vkms_connector_init(struct vkms_device *vkmsdev,
- struct vkms_config_connector *connector_cfg);
+struct vkms_connector *vkms_connector_init_static(struct vkms_device *vkmsdev,
+ struct vkms_config_connector *connector_cfg);
/**
* vkms_trigger_connector_hotplug() - Update the device's connectors status
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 1288c8551bc8..406a22f1b963 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -97,7 +97,7 @@ int vkms_output_init(struct vkms_device *vkmsdev)
struct vkms_config_encoder *possible_encoder;
unsigned long idx = 0;
- connector_cfg->connector = vkms_connector_init(vkmsdev, connector_cfg);
+ connector_cfg->connector = vkms_connector_init_static(vkmsdev, connector_cfg);
if (IS_ERR(connector_cfg->connector)) {
DRM_ERROR("Failed to init connector\n");
return PTR_ERR(connector_cfg->connector);
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 30/38] drm/vkms: Introduce config for connector supported colorspace
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (28 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 29/38] drm/vkms: Rename vkms_connector_init to vkms_connector_init_static Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:58 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 31/38] drm/vkms: Introduce configfs " Louis Chauvet
` (7 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
To emulate some HDR features of displays, it is required to expose some
properties on HDMI, eDP and DP connectors.
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/tests/vkms_config_test.c | 3 ++
drivers/gpu/drm/vkms/vkms_config.c | 5 +++
drivers/gpu/drm/vkms/vkms_config.h | 30 +++++++++++++++++
drivers/gpu/drm/vkms/vkms_connector.c | 47 +++++++++++++++++++++++++++
4 files changed, 85 insertions(+)
diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
index 1900cc79db2b..a31fd230c1d4 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_config_test.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
@@ -215,6 +215,9 @@ static void vkms_config_test_default_config(struct kunit *test)
vkms_config_for_each_connector(config, connector_cfg) {
KUNIT_EXPECT_EQ(test, vkms_config_connector_get_type(connector_cfg),
DRM_MODE_CONNECTOR_VIRTUAL);
+ KUNIT_EXPECT_EQ(test,
+ vkms_config_connector_get_supported_colorspaces(connector_cfg),
+ 0);
}
KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index c407aea0bc6a..ea9bc5d06be6 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -600,6 +600,10 @@ static int vkms_config_show(struct seq_file *m, void *data)
drm_get_connector_status_name(vkms_config_connector_get_status(connector_cfg)));
seq_printf(m, "\ttype=%s\n",
drm_get_connector_type_name(vkms_config_connector_get_type(connector_cfg)));
+ seq_puts(m, "\tsupported colorspaces=");
+ show_bitfield(m, vkms_config_connector_get_supported_colorspaces(connector_cfg),
+ drm_get_colorspace_name);
+ seq_puts(m, "\n");
}
return 0;
@@ -933,6 +937,7 @@ struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *c
connector_cfg->config = config;
connector_cfg->status = connector_status_connected;
vkms_config_connector_set_type(connector_cfg, DRM_MODE_CONNECTOR_VIRTUAL);
+ vkms_config_connector_set_supported_colorspaces(connector_cfg, 0);
xa_init_flags(&connector_cfg->possible_encoders, XA_FLAGS_ALLOC);
list_add_tail(&connector_cfg->link, &config->connectors);
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index d6d185b2ccc0..80bbc13aad79 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -133,6 +133,10 @@ struct vkms_config_encoder {
* @type: Store the type of connector using DRM_MODE_CONNECTOR_* values
* @config: The vkms_config this connector belongs to
* @status: Status (connected, disconnected...) of the connector
+ * @supported_colorspaces: Bitmask of all the supported colorspaces. Values
+ * are the sames as ones accepted by
+ * drm_mode_create_hdmi_colorspace_property() and
+ * drm_mode_create_dp_colorspace_property()
* @possible_encoders: Array of encoders that can be used with this connector
* @connector: Internal usage. This pointer should never be considered as valid.
* It can be used to store a temporary reference to a VKMS connector
@@ -145,6 +149,7 @@ struct vkms_config_connector {
int type;
enum drm_connector_status status;
+ u32 supported_colorspaces;
struct xarray possible_encoders;
/* Internal usage */
@@ -244,6 +249,31 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
*/
void vkms_config_destroy(struct vkms_config *config);
+/**
+ * vkms_config_connector_set_supported_colorspaces() - Set the supported colorspaces for a connector
+ * @connector_cfg: Connector configuration to modify
+ * @supported_colorspaces: Bitmask of supported colorspaces (DRM_MODE_COLORIMETRY_*)
+ */
+static inline void
+vkms_config_connector_set_supported_colorspaces(struct vkms_config_connector *connector_cfg,
+ u32 supported_colorspaces)
+{
+ connector_cfg->supported_colorspaces = supported_colorspaces;
+}
+
+/**
+ * vkms_config_connector_get_supported_colorspaces() - Get the supported colorspaces for a connector
+ * @connector_cfg: Connector configuration to query
+ *
+ * Returns:
+ * Bitmask of supported colorspaces (DRM_MODE_COLORIMETRY_*)
+ */
+static inline u32
+vkms_config_connector_get_supported_colorspaces(const struct vkms_config_connector *connector_cfg)
+{
+ return connector_cfg->supported_colorspaces;
+}
+
/**
* vkms_config_get_device_name() - Return the name of the device
* @config: Configuration to get the device name from
diff --git a/drivers/gpu/drm/vkms/vkms_connector.c b/drivers/gpu/drm/vkms/vkms_connector.c
index 5b29dcade7e1..a1f08167def1 100644
--- a/drivers/gpu/drm/vkms/vkms_connector.c
+++ b/drivers/gpu/drm/vkms/vkms_connector.c
@@ -68,6 +68,49 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
.best_encoder = vkms_conn_best_encoder,
};
+
+/**
+ * vkms_connector_init - Common initialization for all vkms connectors
+ *
+ * @connector - Already allocated connector
+ * @connector_cfg - Configuration to apply
+ *
+ * Returns: 0 on success, errno on error;
+ */
+static int __must_check vkms_connector_init(struct vkms_connector *connector,
+ struct vkms_config_connector *connector_cfg)
+{
+ int ret = 0;
+
+ if (vkms_config_connector_get_supported_colorspaces(connector_cfg)) {
+ if (connector_cfg->type == DRM_MODE_CONNECTOR_HDMIA) {
+ ret = drm_mode_create_hdmi_colorspace_property(&connector->base,
+ vkms_config_connector_get_supported_colorspaces(connector_cfg));
+ if (ret)
+ return ret;
+ } else if (connector_cfg->type == DRM_MODE_CONNECTOR_DisplayPort ||
+ connector_cfg->type == DRM_MODE_CONNECTOR_eDP) {
+ ret = drm_mode_create_dp_colorspace_property(&connector->base,
+ vkms_config_connector_get_supported_colorspaces(connector_cfg));
+ if (ret)
+ return ret;
+ }
+
+ if (connector_cfg->type == DRM_MODE_CONNECTOR_HDMIA ||
+ connector_cfg->type == DRM_MODE_CONNECTOR_DisplayPort ||
+ connector_cfg->type == DRM_MODE_CONNECTOR_eDP) {
+ ret = drm_connector_attach_colorspace_property(&connector->base);
+ if (ret) {
+ drm_property_destroy(connector->base.dev, connector->base.colorspace_property);
+ return ret;
+ }
+ drm_connector_attach_hdr_output_metadata_property(&connector->base);
+ }
+ }
+
+ return 0;
+}
+
struct vkms_connector *vkms_connector_init_static(struct vkms_device *vkmsdev,
struct vkms_config_connector *connector_cfg)
{
@@ -84,6 +127,10 @@ struct vkms_connector *vkms_connector_init_static(struct vkms_device *vkmsdev,
if (ret)
return ERR_PTR(ret);
+ ret = vkms_connector_init(connector, connector_cfg);
+ if (ret)
+ return ERR_PTR(ret);
+
drm_connector_helper_add(&connector->base, &vkms_conn_helper_funcs);
return connector;
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 31/38] drm/vkms: Introduce configfs for connector supported colorspace
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (29 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 30/38] drm/vkms: Introduce config for connector supported colorspace Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:48 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 32/38] drm/vkms: Introduce config for connector EDID Louis Chauvet
` (6 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
Add the attribute supported_colorspaces to configure the supported
colorspace of a connector. It will allows emulating some HDR features of
displays. This feature is only supported for HDMI, DP and eDP connectors.
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
Documentation/ABI/testing/configfs-vkms | 8 +++++++
Documentation/gpu/vkms.rst | 7 +++++-
drivers/gpu/drm/vkms/vkms_configfs.c | 40 +++++++++++++++++++++++++++++++++
3 files changed, 54 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/configfs-vkms b/Documentation/ABI/testing/configfs-vkms
index 0e588a1145ff..86f5f0beec8d 100644
--- a/Documentation/ABI/testing/configfs-vkms
+++ b/Documentation/ABI/testing/configfs-vkms
@@ -40,6 +40,14 @@ Description:
Type of the connector. Possible values match those
exposed by the "type" field in drm_connector.
+What: /sys/kernel/config/vkms/<device>/connectors/<connector>/supported_colorspaces
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Supported colorspaces for HDMI, DP, and eDP connectors.
+ Value is a bitfield, where 0x1 = NO_DATA, 0x2 = SMPTE_170M_YCC,
+ etc. See enum drm_colorspace for full list.
+
What: /sys/kernel/config/vkms/<device>/connectors/<connector>/possible_encoders
Date: Nov 2025
Contact: dri-devel@lists.freedesktop.org
diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index f2622b3fd8af..11058b6e6250 100644
--- a/Documentation/gpu/vkms.rst
+++ b/Documentation/gpu/vkms.rst
@@ -137,11 +137,16 @@ Last but not least, create one or more connectors::
sudo mkdir /config/vkms/my-vkms/connectors/connector0
-Connectors have 2 configurable attribute:
+Connectors have 3 configurable attribute:
- status: Connection status: 1 connected, 2 disconnected, 3 unknown (same values
as those exposed by the "status" property of a connector)
- type: Type of connector. Same values as exposed by the "type" field in drm_connector.
+- supported_colorspaces: Supported colorspaces values for HDMI, DP and eDP connectors.
+ If supported_colorspaces is not 0, the HDR_OUTPUT_METADATA will also be created.
+ Value is a bitfield, 0x1 = NO_DATA, 0x2 = SMPTE_170M_YCC... see enum drm_colorspace
+ for full list.
+
To finish the configuration, link the different pipeline items::
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index 8b414f1950e8..e1f6e7817f97 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -1180,12 +1180,52 @@ static ssize_t connector_type_store(struct config_item *item,
return count;
}
+static ssize_t connector_supported_colorspaces_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_connector *connector;
+ int colorspaces;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+
+ scoped_guard(mutex, &connector->dev->lock)
+ colorspaces = vkms_config_connector_get_supported_colorspaces(connector->config);
+
+ return sprintf(page, "%u", colorspaces);
+}
+
+static ssize_t connector_supported_colorspaces_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct vkms_configfs_connector *connector;
+ int val, ret;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+
+ ret = kstrtouint(page, 10, &val);
+ if (ret)
+ return ret;
+
+ if ((val & -BIT(DRM_MODE_COLORIMETRY_COUNT)) != 0)
+ return -EINVAL;
+
+ scoped_guard(mutex, &connector->dev->lock) {
+ if (connector->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_connector_set_supported_colorspaces(connector->config, val);
+ }
+
+ return count;
+}
+
CONFIGFS_ATTR(connector_, status);
CONFIGFS_ATTR(connector_, type);
+CONFIGFS_ATTR(connector_, supported_colorspaces);
static struct configfs_attribute *connector_item_attrs[] = {
&connector_attr_status,
&connector_attr_type,
+ &connector_attr_supported_colorspaces,
NULL,
};
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 32/38] drm/vkms: Introduce config for connector EDID
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (30 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 31/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:48 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 33/38] drm/vkms: Introduce configfs " Louis Chauvet
` (5 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
Allows configuration of EDID for each connector.
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/tests/vkms_config_test.c | 2 +
drivers/gpu/drm/vkms/vkms_config.c | 6 +++
drivers/gpu/drm/vkms/vkms_config.h | 75 +++++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_connector.c | 50 ++++++++++++++++--
4 files changed, 129 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
index a31fd230c1d4..2b49745ee026 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_config_test.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
@@ -218,6 +218,8 @@ static void vkms_config_test_default_config(struct kunit *test)
KUNIT_EXPECT_EQ(test,
vkms_config_connector_get_supported_colorspaces(connector_cfg),
0);
+ KUNIT_EXPECT_EQ(test, vkms_config_connector_get_edid_enabled(connector_cfg),
+ false);
}
KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index ea9bc5d06be6..1a110b8aa114 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -538,6 +538,7 @@ static int vkms_config_show(struct seq_file *m, void *data)
struct drm_device *dev = entry->dev;
struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
const char *dev_name;
+ int edid_len;
struct vkms_config_plane *plane_cfg;
struct vkms_config_crtc *crtc_cfg;
struct vkms_config_encoder *encoder_cfg;
@@ -604,6 +605,11 @@ static int vkms_config_show(struct seq_file *m, void *data)
show_bitfield(m, vkms_config_connector_get_supported_colorspaces(connector_cfg),
drm_get_colorspace_name);
seq_puts(m, "\n");
+ vkms_config_connector_get_edid(connector_cfg, &edid_len);
+ seq_printf(m, "\tEDID=%s (len=%d)\n",
+ str_enabled_disabled(vkms_config_connector_get_edid_enabled(connector_cfg)),
+ edid_len
+ );
}
return 0;
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 80bbc13aad79..7e361b6e45b0 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -137,6 +137,9 @@ struct vkms_config_encoder {
* are the sames as ones accepted by
* drm_mode_create_hdmi_colorspace_property() and
* drm_mode_create_dp_colorspace_property()
+ * @edid_enabled: If true, create the EDID property
+ * @edid: Stores the current EDID. The value will be ignored if @edid_enabled is false
+ * @edid_len: Current EDID length. The value will be ignored if @edid_enabled is false
* @possible_encoders: Array of encoders that can be used with this connector
* @connector: Internal usage. This pointer should never be considered as valid.
* It can be used to store a temporary reference to a VKMS connector
@@ -150,6 +153,9 @@ struct vkms_config_connector {
int type;
enum drm_connector_status status;
u32 supported_colorspaces;
+ bool edid_enabled;
+ u8 *edid;
+ unsigned int edid_len;
struct xarray possible_encoders;
/* Internal usage */
@@ -274,6 +280,75 @@ vkms_config_connector_get_supported_colorspaces(const struct vkms_config_connect
return connector_cfg->supported_colorspaces;
}
+/**
+ * vkms_config_connector_get_edid_enabled() - Check if EDID is enabled for a connector
+ * @connector_cfg: Connector configuration to check
+ *
+ * Returns:
+ * True if EDID is enabled for this connector, false otherwise.
+ */
+static inline bool
+vkms_config_connector_get_edid_enabled(const struct vkms_config_connector *connector_cfg)
+{
+ return connector_cfg->edid_enabled;
+}
+
+/**
+ * vkms_config_connector_set_edid_enabled() - Enable or disable EDID for a connector
+ * @connector_cfg: Connector configuration to modify
+ * @enabled: Whether to enable EDID for this connector
+ */
+static inline void
+vkms_config_connector_set_edid_enabled(struct vkms_config_connector *connector_cfg,
+ bool enabled)
+{
+ connector_cfg->edid_enabled = enabled;
+}
+
+/**
+ * vkms_config_connector_get_edid() - Get the EDID data for a connector
+ * @connector_cfg: Connector configuration to get the EDID from
+ * @len: Pointer to store the length of the EDID data
+ *
+ * Returns:
+ * Pointer to the EDID data buffer, or NULL if no EDID is set.
+ * The length of the EDID data is stored in @len.
+ */
+static inline const u8 *
+vkms_config_connector_get_edid(const struct vkms_config_connector *connector_cfg, int *len)
+{
+ *len = connector_cfg->edid_len;
+ return connector_cfg->edid;
+}
+
+/**
+ * vkms_config_connector_set_edid() - Set the EDID data for a connector
+ * @connector_cfg: Connector configuration to modify
+ * @edid: Pointer to the EDID data buffer
+ * @len: Length of the EDID data
+ *
+ * If @len is 0, the EDID data will be cleared and @edid ignored. If
+ * memory allocation fails, the existing EDID data will be preserved.
+ */
+static inline void
+vkms_config_connector_set_edid(struct vkms_config_connector *connector_cfg,
+ const u8 *edid, unsigned int len)
+{
+ if (len) {
+ void *edid_tmp = krealloc(connector_cfg->edid, len, GFP_KERNEL);
+
+ if (edid_tmp) {
+ connector_cfg->edid = edid_tmp;
+ memcpy(connector_cfg->edid, edid, len);
+ connector_cfg->edid_len = len;
+ }
+ } else {
+ kfree(connector_cfg->edid);
+ connector_cfg->edid = NULL;
+ connector_cfg->edid_len = len;
+ }
+}
+
/**
* vkms_config_get_device_name() - Return the name of the device
* @config: Configuration to get the device name from
diff --git a/drivers/gpu/drm/vkms/vkms_connector.c b/drivers/gpu/drm/vkms/vkms_connector.c
index a1f08167def1..fe42ab2ba7b1 100644
--- a/drivers/gpu/drm/vkms/vkms_connector.c
+++ b/drivers/gpu/drm/vkms/vkms_connector.c
@@ -42,13 +42,55 @@ static const struct drm_connector_funcs vkms_connector_funcs = {
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
+static int vkms_connector_read_block(void *context, u8 *buf, unsigned int block, size_t len)
+{
+ struct vkms_config_connector *config = context;
+ unsigned int edid_len;
+ const u8 *edid = vkms_config_connector_get_edid(config, &edid_len);
+
+ if (block * len + len > edid_len)
+ return 1;
+ memcpy(buf, &edid[block * len], len);
+ return 0;
+}
+
static int vkms_conn_get_modes(struct drm_connector *connector)
{
- int count;
+ struct vkms_connector *vkms_connector = drm_connector_to_vkms_connector(connector);
+ const struct drm_edid *drm_edid = NULL;
+ int count = 0;
+ struct vkms_config_connector *context = NULL;
+ struct drm_device *dev = connector->dev;
+ struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
+ struct vkms_config_connector *connector_cfg;
- /* Use the default modes list from DRM */
- count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX);
- drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);
+ vkms_config_for_each_connector(vkmsdev->config, connector_cfg) {
+ if (connector_cfg->connector == vkms_connector) {
+ context = connector_cfg;
+ break;
+ }
+ }
+ if (context) {
+ if (vkms_config_connector_get_edid_enabled(context)) {
+ drm_edid = drm_edid_read_custom(connector,
+ vkms_connector_read_block, context);
+
+ /*
+ * Unconditionally update the connector. If the EDID was read
+ * successfully, fill in the connector information derived from the
+ * EDID. Otherwise, if the EDID is NULL, clear the connector
+ * information.
+ */
+ drm_edid_connector_update(connector, drm_edid);
+
+ count = drm_edid_connector_add_modes(connector);
+
+ drm_edid_free(drm_edid);
+ } else {
+ count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX);
+ drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);
+ }
+ }
return count;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 33/38] drm/vkms: Introduce configfs for connector EDID
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (31 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 32/38] drm/vkms: Introduce config for connector EDID Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:50 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 34/38] drm/vkms: Store the enabled/disabled status for connector Louis Chauvet
` (4 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
Introduce new attributes to configure EDID of a connector:
- edid_enable - chose if the connector will have an EDID or not
- edid - raw edid content
Due to limitation of ConfigFS, the max len of EDID is PAGE_SIZE (4kB on
x86), it should be sufficient for many tests. One possible evolution is
using a ConfigFS blob to allow bigger EDID.
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
Documentation/ABI/testing/configfs-vkms | 14 ++++++
Documentation/gpu/vkms.rst | 5 ++-
drivers/gpu/drm/vkms/vkms_configfs.c | 80 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_connector.c | 3 ++
4 files changed, 101 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/configfs-vkms b/Documentation/ABI/testing/configfs-vkms
index 86f5f0beec8d..04e2f89e3129 100644
--- a/Documentation/ABI/testing/configfs-vkms
+++ b/Documentation/ABI/testing/configfs-vkms
@@ -48,6 +48,20 @@ Description:
Value is a bitfield, where 0x1 = NO_DATA, 0x2 = SMPTE_170M_YCC,
etc. See enum drm_colorspace for full list.
+What: /sys/kernel/config/vkms/<device>/connectors/<connector>/edid_enabled
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Enable or disable EDID for this connector. Value:
+ 1 - enabled, 0 - disabled.
+
+What: /sys/kernel/config/vkms/<device>/connectors/<connector>/edid
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Content of the EDID for this connector. Ignored if
+ edid_enabled is not set.
+
What: /sys/kernel/config/vkms/<device>/connectors/<connector>/possible_encoders
Date: Nov 2025
Contact: dri-devel@lists.freedesktop.org
diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index 11058b6e6250..2a3e175bf67b 100644
--- a/Documentation/gpu/vkms.rst
+++ b/Documentation/gpu/vkms.rst
@@ -137,7 +137,7 @@ Last but not least, create one or more connectors::
sudo mkdir /config/vkms/my-vkms/connectors/connector0
-Connectors have 3 configurable attribute:
+Connectors have 5 configurable attribute:
- status: Connection status: 1 connected, 2 disconnected, 3 unknown (same values
as those exposed by the "status" property of a connector)
@@ -146,6 +146,9 @@ Connectors have 3 configurable attribute:
If supported_colorspaces is not 0, the HDR_OUTPUT_METADATA will also be created.
Value is a bitfield, 0x1 = NO_DATA, 0x2 = SMPTE_170M_YCC... see enum drm_colorspace
for full list.
+- edid_enabled: Enable or not EDID for this connector. Some connectors may not have an
+ EDID but just a list of modes, this attribute allows to disable EDID property.
+- edid: Content of the EDID. Ignored if edid_enabled is not set
To finish the configuration, link the different pipeline items::
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index e1f6e7817f97..f79a796c2017 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -1218,14 +1218,94 @@ static ssize_t connector_supported_colorspaces_store(struct config_item *item,
return count;
}
+static ssize_t connector_edid_enabled_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_connector *connector;
+ bool enabled;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+
+ scoped_guard(mutex, &connector->dev->lock)
+ enabled = vkms_config_connector_get_edid_enabled(connector->config);
+
+ return sprintf(page, "%d\n", enabled);
+}
+
+static ssize_t connector_edid_enabled_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct vkms_configfs_connector *connector;
+ struct vkms_config_connector *connector_cfg;
+ bool enabled;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+ connector_cfg = connector->config;
+
+ if (kstrtobool(page, &enabled))
+ return -EINVAL;
+
+ scoped_guard(mutex, &connector->dev->lock)
+ {
+ vkms_config_connector_set_edid_enabled(connector_cfg, enabled);
+
+ if (connector->dev->enabled &&
+ vkms_config_connector_get_status(connector_cfg) !=
+ connector_status_disconnected)
+ vkms_trigger_connector_hotplug(connector->dev->config->dev);
+ }
+ return count;
+}
+
+static ssize_t connector_edid_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_connector *connector;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+
+ scoped_guard(mutex, &connector->dev->lock)
+ {
+ unsigned int len = 0;
+ const u8 *edid = vkms_config_connector_get_edid(connector->config, &len);
+
+ memcpy(page, edid, min(len, PAGE_SIZE));
+ return min(len, PAGE_SIZE);
+ }
+
+ return -EINVAL;
+}
+
+static ssize_t connector_edid_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct vkms_configfs_connector *connector;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+
+ scoped_guard(mutex, &connector->dev->lock)
+ {
+ vkms_config_connector_set_edid(connector->config, page, count);
+
+ if (connector->dev->enabled &&
+ vkms_config_connector_get_status(connector->config) !=
+ connector_status_disconnected)
+ vkms_trigger_connector_hotplug(connector->dev->config->dev);
+ }
+
+ return count;
+}
+
CONFIGFS_ATTR(connector_, status);
CONFIGFS_ATTR(connector_, type);
CONFIGFS_ATTR(connector_, supported_colorspaces);
+CONFIGFS_ATTR(connector_, edid_enabled);
+CONFIGFS_ATTR(connector_, edid);
static struct configfs_attribute *connector_item_attrs[] = {
&connector_attr_status,
&connector_attr_type,
&connector_attr_supported_colorspaces,
+ &connector_attr_edid_enabled,
+ &connector_attr_edid,
NULL,
};
diff --git a/drivers/gpu/drm/vkms/vkms_connector.c b/drivers/gpu/drm/vkms/vkms_connector.c
index fe42ab2ba7b1..f726c7995524 100644
--- a/drivers/gpu/drm/vkms/vkms_connector.c
+++ b/drivers/gpu/drm/vkms/vkms_connector.c
@@ -175,6 +175,9 @@ struct vkms_connector *vkms_connector_init_static(struct vkms_device *vkmsdev,
drm_connector_helper_add(&connector->base, &vkms_conn_helper_funcs);
+ if (vkms_config_connector_get_edid_enabled(connector_cfg))
+ drm_connector_attach_edid_property(&connector->base);
+
return connector;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 34/38] drm/vkms: Store the enabled/disabled status for connector
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (32 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 33/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:48 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 35/38] drm/vkms: Allow to hot-add connectors Louis Chauvet
` (3 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
In order to prepare for dynamic connector configuration, we need to store
if a connector is dynamic and if it is enabled.
The two new vkms_config_connector fields will helps for that.
Co-developed-by: José Expósito <jose.exposito89@gmail.com>
Signed-off-by: José Expósito <jose.exposito89@gmail.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
.clang-format | 2 +
drivers/gpu/drm/vkms/tests/vkms_config_test.c | 4 ++
drivers/gpu/drm/vkms/vkms_config.c | 6 +++
drivers/gpu/drm/vkms/vkms_config.h | 66 +++++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_output.c | 2 +-
5 files changed, 79 insertions(+), 1 deletion(-)
diff --git a/.clang-format b/.clang-format
index 1cc151e2adcc..0d985d30efb2 100644
--- a/.clang-format
+++ b/.clang-format
@@ -724,6 +724,8 @@ ForEachMacros:
- 'v4l2_m2m_for_each_src_buf_safe'
- 'virtio_device_for_each_vq'
- 'vkms_config_for_each_connector'
+ - 'vkms_config_for_each_connector_static'
+ - 'vkms_config_for_each_connector_dynamic'
- 'vkms_config_for_each_crtc'
- 'vkms_config_for_each_encoder'
- 'vkms_config_for_each_plane'
diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
index 2b49745ee026..fda23f05a0a5 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_config_test.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
@@ -220,6 +220,10 @@ static void vkms_config_test_default_config(struct kunit *test)
0);
KUNIT_EXPECT_EQ(test, vkms_config_connector_get_edid_enabled(connector_cfg),
false);
+ KUNIT_EXPECT_EQ(test, vkms_config_connector_is_enabled(connector_cfg),
+ true);
+ KUNIT_EXPECT_EQ(test, vkms_config_connector_is_dynamic(connector_cfg),
+ false);
}
KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 1a110b8aa114..98e40c6a2c5b 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -597,6 +597,8 @@ static int vkms_config_show(struct seq_file *m, void *data)
vkms_config_for_each_connector(vkmsdev->config, connector_cfg) {
seq_puts(m, "connector:\n");
+ seq_printf(m, "\t%s\n",
+ str_enabled_disabled(vkms_config_connector_is_enabled(connector_cfg)));
seq_printf(m, "\tstatus=%s\n",
drm_get_connector_status_name(vkms_config_connector_get_status(connector_cfg)));
seq_printf(m, "\ttype=%s\n",
@@ -610,6 +612,8 @@ static int vkms_config_show(struct seq_file *m, void *data)
str_enabled_disabled(vkms_config_connector_get_edid_enabled(connector_cfg)),
edid_len
);
+ seq_printf(m, "\tdynamic=%s\n",
+ str_true_false(vkms_config_connector_is_dynamic(connector_cfg)));
}
return 0;
@@ -944,6 +948,8 @@ struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *c
connector_cfg->status = connector_status_connected;
vkms_config_connector_set_type(connector_cfg, DRM_MODE_CONNECTOR_VIRTUAL);
vkms_config_connector_set_supported_colorspaces(connector_cfg, 0);
+ vkms_config_connector_set_dynamic(connector_cfg, false);
+ vkms_config_connector_set_enabled(connector_cfg, true);
xa_init_flags(&connector_cfg->possible_encoders, XA_FLAGS_ALLOC);
list_add_tail(&connector_cfg->link, &config->connectors);
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 7e361b6e45b0..071887a65380 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -132,6 +132,8 @@ struct vkms_config_encoder {
* @link: Link to the others connector in vkms_config
* @type: Store the type of connector using DRM_MODE_CONNECTOR_* values
* @config: The vkms_config this connector belongs to
+ * @dynamic: Store if a connector should be created with drm_connector_dynamic_init
+ * @enabled: If @dynamic, this means that the connector is currently registered in drm
* @status: Status (connected, disconnected...) of the connector
* @supported_colorspaces: Bitmask of all the supported colorspaces. Values
* are the sames as ones accepted by
@@ -151,6 +153,8 @@ struct vkms_config_connector {
struct vkms_config *config;
int type;
+ bool enabled;
+ bool dynamic;
enum drm_connector_status status;
u32 supported_colorspaces;
bool edid_enabled;
@@ -194,6 +198,24 @@ struct vkms_config_connector {
#define vkms_config_for_each_connector(config, connector_cfg) \
list_for_each_entry((connector_cfg), &(config)->connectors, link)
+/**
+ * vkms_config_for_each_connector_static - Iterate over the static vkms_config connectors
+ * @config: &struct vkms_config pointer
+ * @connector_cfg: &struct vkms_config_connector pointer used as cursor
+ */
+#define vkms_config_for_each_connector_static(config, connector_cfg) \
+ vkms_config_for_each_connector((config), (connector_cfg)) \
+ if (!(connector_cfg)->dynamic)
+
+/**
+ * vkms_config_for_each_connector_dynamic - Iterate over the dynamic vkms_config connectors
+ * @config: &struct vkms_config pointer
+ * @connector_cfg: &struct vkms_config_connector pointer used as cursor
+ */
+#define vkms_config_for_each_connector_dynamic(config, connector_cfg) \
+ vkms_config_for_each_connector((config), (connector_cfg)) \
+ if ((connector_cfg)->dynamic)
+
/**
* vkms_config_plane_for_each_possible_crtc - Iterate over the vkms_config_plane
* possible CRTCs
@@ -472,6 +494,50 @@ vkms_config_connector_set_type(struct vkms_config_connector *connector_cfg,
connector_cfg->type = type;
}
+/**
+ * vkms_config_connector_set_enabled() - If the connector is part of the device
+ * @crtc_cfg: Target connector
+ * @enabled: Add or remove the connector
+ */
+static inline void
+vkms_config_connector_set_enabled(struct vkms_config_connector *connector_cfg,
+ bool enabled)
+{
+ connector_cfg->enabled = enabled;
+}
+
+/**
+ * vkms_config_connector_is_enabled() - If the connector is part of the device
+ * @connector_cfg: The connector
+ */
+static inline bool
+vkms_config_connector_is_enabled(const struct vkms_config_connector *connector_cfg)
+{
+ return connector_cfg->enabled;
+}
+
+/**
+ * vkms_config_connector_set_dynamic() - If the connector is dynamic
+ * @crtc_cfg: Target connector
+ * @enabled: Enable or disable the dynamic status
+ */
+static inline void
+vkms_config_connector_set_dynamic(struct vkms_config_connector *connector_cfg,
+ bool dynamic)
+{
+ connector_cfg->dynamic = dynamic;
+}
+
+/**
+ * vkms_config_connector_is_enabled() - If the connector is dynamic
+ * @connector_cfg: The connector
+ */
+static inline bool
+vkms_config_connector_is_dynamic(struct vkms_config_connector *connector_cfg)
+{
+ return connector_cfg->dynamic;
+}
+
/*
* vkms_config_plane_get_default_rotation() - Get the default rotation for a plane
* @plane_cfg: Plane to get the default rotation from
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 406a22f1b963..13c4ca5fd39d 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -93,7 +93,7 @@ int vkms_output_init(struct vkms_device *vkmsdev)
}
}
- vkms_config_for_each_connector(vkmsdev->config, connector_cfg) {
+ vkms_config_for_each_connector_static(vkmsdev->config, connector_cfg) {
struct vkms_config_encoder *possible_encoder;
unsigned long idx = 0;
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 35/38] drm/vkms: Allow to hot-add connectors
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (33 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 34/38] drm/vkms: Store the enabled/disabled status for connector Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:50 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 36/38] drm/vkms: Introduce configfs for dynamic connector creation Louis Chauvet
` (2 subsequent siblings)
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
In order to allow creating dynamic connector, add the required
infrastructure in vkms_connector.
[Louis Chauvet: use drm_atomic_helper_connector_reset instead of
drm_mode_config_reset because connector is not yet registered]
Co-developed-by: José Expósito <jose.exposito89@gmail.com>
Signed-off-by: José Expósito <jose.exposito89@gmail.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/vkms_connector.c | 89 +++++++++++++++++++++++++++++++++++
drivers/gpu/drm/vkms/vkms_connector.h | 33 +++++++++++++
drivers/gpu/drm/vkms/vkms_output.c | 9 ++++
3 files changed, 131 insertions(+)
diff --git a/drivers/gpu/drm/vkms/vkms_connector.c b/drivers/gpu/drm/vkms/vkms_connector.c
index f726c7995524..a013b53bd915 100644
--- a/drivers/gpu/drm/vkms/vkms_connector.c
+++ b/drivers/gpu/drm/vkms/vkms_connector.c
@@ -181,9 +181,98 @@ struct vkms_connector *vkms_connector_init_static(struct vkms_device *vkmsdev,
return connector;
}
+static void vkms_connector_dynamic_destroy(struct drm_connector *connector)
+{
+ struct vkms_connector *vkms_connector;
+
+ drm_connector_cleanup(connector);
+
+ vkms_connector = drm_connector_to_vkms_connector(connector);
+ kfree(vkms_connector);
+}
+
+static const struct drm_connector_funcs vkms_dynamic_connector_funcs = {
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .destroy = vkms_connector_dynamic_destroy,
+ .detect = vkms_connector_detect,
+};
+
void vkms_trigger_connector_hotplug(struct vkms_device *vkmsdev)
{
struct drm_device *dev = &vkmsdev->drm;
drm_kms_helper_hotplug_event(dev);
}
+
+struct vkms_connector *vkms_connector_hot_add(struct vkms_device *vkmsdev,
+ struct vkms_config_connector *connector_cfg)
+{
+ struct vkms_config_encoder *encoder_cfg;
+ struct vkms_connector __free(kfree) * connector = NULL;
+ int ret;
+ unsigned long idx = 0;
+
+ connector = kzalloc_obj(*connector, GFP_KERNEL);
+ if (IS_ERR(connector))
+ return connector;
+ ret = drm_connector_dynamic_init(&vkmsdev->drm,
+ &connector->base,
+ &vkms_dynamic_connector_funcs,
+ connector_cfg->type,
+ NULL);
+ if (ret)
+ return ERR_PTR(ret);
+ drm_connector_helper_add(&connector->base, &vkms_conn_helper_funcs);
+
+ vkms_config_connector_for_each_possible_encoder(connector_cfg, idx, encoder_cfg) {
+ ret = drm_connector_attach_encoder(&connector->base,
+ encoder_cfg->encoder);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+
+ drm_atomic_helper_connector_reset(&connector->base);
+
+ ret = vkms_connector_init(connector, connector_cfg);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = drm_connector_dynamic_register(&connector->base);
+ if (ret) {
+ if (connector_cfg->type == DRM_MODE_CONNECTOR_HDMIA ||
+ connector_cfg->type == DRM_MODE_CONNECTOR_DisplayPort ||
+ connector_cfg->type == DRM_MODE_CONNECTOR_eDP) {
+ drm_property_destroy(connector->base.dev,
+ connector->base.colorspace_property);
+ }
+ return ERR_PTR(ret);
+ }
+
+ return_ptr(connector);
+}
+
+void vkms_connector_hot_remove(struct vkms_device *vkmsdev,
+ struct vkms_connector *connector)
+{
+ drm_connector_unregister(&connector->base);
+ drm_mode_config_reset(&vkmsdev->drm);
+ drm_connector_put(&connector->base);
+}
+
+int vkms_connector_hot_attach_encoder(struct vkms_device *vkmsdev,
+ struct vkms_connector *connector,
+ struct drm_encoder *encoder)
+{
+ int ret;
+
+ ret = drm_connector_attach_encoder(&connector->base, encoder);
+ if (ret)
+ return ret;
+
+ drm_mode_config_reset(&vkmsdev->drm);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/vkms/vkms_connector.h b/drivers/gpu/drm/vkms/vkms_connector.h
index 85f9082c710e..a235a518d5a0 100644
--- a/drivers/gpu/drm/vkms/vkms_connector.h
+++ b/drivers/gpu/drm/vkms/vkms_connector.h
@@ -34,4 +34,37 @@ struct vkms_connector *vkms_connector_init_static(struct vkms_device *vkmsdev,
*/
void vkms_trigger_connector_hotplug(struct vkms_device *vkmsdev);
+/**
+ * vkms_connector_hot_add() - Create a connector after the device is created
+ * @vkmsdev: Device to hot-add the connector to
+ * @connector_cfg: Connector's configuration
+ *
+ * Returns:
+ * A pointer to the newly created connector or a PTR_ERR on failure.
+ */
+struct vkms_connector *vkms_connector_hot_add(struct vkms_device *vkmsdev,
+ struct vkms_config_connector *connector_cfg);
+
+/**
+ * vkms_connector_hot_remove() - Remove a connector after a device is created
+ * @vkmsdev: Device to containing the connector to be removed
+ * @connector: The connector to hot-remove
+ */
+void vkms_connector_hot_remove(struct vkms_device *vkmsdev,
+ struct vkms_connector *connector);
+
+/**
+ * vkms_connector_hot_attach_encoder() - Attach a connector to a encoder after
+ * the device is created.
+ * @vkmsdev: Device containing the connector and the encoder
+ * @connector: Connector to attach to @encoder
+ * @encoder: Target encoder
+ *
+ * Returns:
+ * 0 on success or an error on failure.
+ */
+int vkms_connector_hot_attach_encoder(struct vkms_device *vkmsdev,
+ struct vkms_connector *connector,
+ struct drm_encoder *encoder);
+
#endif /* _VKMS_CONNECTOR_H_ */
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 13c4ca5fd39d..50f7d88dee8b 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -117,5 +117,14 @@ int vkms_output_init(struct vkms_device *vkmsdev)
drm_mode_config_reset(dev);
+ vkms_config_for_each_connector_dynamic(vkmsdev->config, connector_cfg) {
+ if (connector_cfg->enabled) {
+ connector_cfg->connector = vkms_connector_hot_add(vkmsdev, connector_cfg);
+
+ if (IS_ERR(connector_cfg->connector))
+ return PTR_ERR(connector_cfg->connector);
+ }
+ }
+
return 0;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 36/38] drm/vkms: Introduce configfs for dynamic connector creation
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (34 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 35/38] drm/vkms: Allow to hot-add connectors Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:55 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 37/38] drm/vkms: Add connector parent configuration in vkms_config Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 38/38] drm/vkms: Add ConfigFS interface for connector parent and port_id Louis Chauvet
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
DRM allows the connector to be created after the device. To allows
emulating this, add two configfs attributes to connector to allows this.
Using the dynamic attribute you can set if a connector will be dynamic or
not.
Using the enabled attribute, you can set at runtime if a dynamic connector
is present or not.
Co-developed-by: José Expósito <jose.exposito89@gmail.com>
Signed-off-by: José Expósito <jose.exposito89@gmail.com>
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
Documentation/ABI/testing/configfs-vkms | 14 ++++
Documentation/gpu/vkms.rst | 6 +-
drivers/gpu/drm/vkms/vkms_configfs.c | 144 ++++++++++++++++++++++++++++++--
3 files changed, 155 insertions(+), 9 deletions(-)
diff --git a/Documentation/ABI/testing/configfs-vkms b/Documentation/ABI/testing/configfs-vkms
index 04e2f89e3129..8a5899c52e78 100644
--- a/Documentation/ABI/testing/configfs-vkms
+++ b/Documentation/ABI/testing/configfs-vkms
@@ -62,6 +62,20 @@ Description:
Content of the EDID for this connector. Ignored if
edid_enabled is not set.
+What: /sys/kernel/config/vkms/<device>/connectors/<connector>/dynamic
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ Set to 1 to create a dynamic connector (emulates DP MST).
+ Value: 1 - dynamic, 0 - static.
+
+What: /sys/kernel/config/vkms/<device>/connectors/<connector>/enabled
+Date: Nov 2025
+Contact: dri-devel@lists.freedesktop.org
+Description:
+ For dynamic connectors, set to 1 to create the connector,
+ 0 to remove it. Value: 1 - enabled, 0 - disabled.
+
What: /sys/kernel/config/vkms/<device>/connectors/<connector>/possible_encoders
Date: Nov 2025
Contact: dri-devel@lists.freedesktop.org
diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index 2a3e175bf67b..31569421d8f5 100644
--- a/Documentation/gpu/vkms.rst
+++ b/Documentation/gpu/vkms.rst
@@ -137,7 +137,7 @@ Last but not least, create one or more connectors::
sudo mkdir /config/vkms/my-vkms/connectors/connector0
-Connectors have 5 configurable attribute:
+Connectors have 7 configurable attribute:
- status: Connection status: 1 connected, 2 disconnected, 3 unknown (same values
as those exposed by the "status" property of a connector)
@@ -149,7 +149,9 @@ Connectors have 5 configurable attribute:
- edid_enabled: Enable or not EDID for this connector. Some connectors may not have an
EDID but just a list of modes, this attribute allows to disable EDID property.
- edid: Content of the EDID. Ignored if edid_enabled is not set
-
+- dynamic: Set to 1 while configuring the device to create a dynamic connector. A dynamic
+ connector can be used to emulate DP MST connectors.
+- enabled: For dynamic connector, set it to 1 to create the connector, 0 to remove it.
To finish the configuration, link the different pipeline items::
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index f79a796c2017..f92b172e75cf 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -1091,6 +1091,12 @@ static ssize_t connector_status_show(struct config_item *item, char *page)
return sprintf(page, "%u", status);
}
+static bool connector_is_enabled(struct vkms_config_connector *connector_cfg)
+{
+ return !connector_cfg->dynamic ||
+ (connector_cfg->dynamic && connector_cfg->enabled);
+}
+
static ssize_t connector_status_store(struct config_item *item,
const char *page, size_t count)
{
@@ -1110,7 +1116,7 @@ static ssize_t connector_status_store(struct config_item *item,
scoped_guard(mutex, &connector->dev->lock) {
vkms_config_connector_set_status(connector->config, status);
- if (connector->dev->enabled)
+ if (connector->dev->enabled && connector_is_enabled(connector->config))
vkms_trigger_connector_hotplug(connector->dev->config->dev);
}
@@ -1171,7 +1177,7 @@ static ssize_t connector_type_store(struct config_item *item,
}
scoped_guard(mutex, &connector->dev->lock) {
- if (connector->dev->enabled)
+ if (connector->dev->enabled && connector_is_enabled(connector->config))
return -EBUSY;
vkms_config_connector_set_type(connector->config, val);
@@ -1290,6 +1296,107 @@ static ssize_t connector_edid_store(struct config_item *item,
connector_status_disconnected)
vkms_trigger_connector_hotplug(connector->dev->config->dev);
}
+ return count;
+}
+
+static ssize_t connector_enabled_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_connector *connector;
+ bool enabled;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+
+ scoped_guard(mutex, &connector->dev->lock)
+ enabled = vkms_config_connector_is_enabled(connector->config);
+
+ return sprintf(page, "%d\n", enabled);
+}
+
+static ssize_t connector_enabled_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct vkms_configfs_connector *connector;
+ struct vkms_config_connector *connector_cfg;
+ bool enabled, was_enabled;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+ connector_cfg = connector->config;
+
+ if (kstrtobool(page, &enabled))
+ return -EINVAL;
+ scoped_guard(mutex, &connector->dev->lock) {
+ if (!connector->dev->enabled) {
+ vkms_config_connector_set_enabled(connector_cfg, enabled);
+ } else {
+ // Only dynamic connector can be enabled/disabled at runtime
+ if (!connector_cfg->dynamic)
+ return -EBUSY;
+
+ was_enabled = vkms_config_connector_is_enabled(connector_cfg);
+ vkms_config_connector_set_enabled(connector_cfg, enabled);
+
+ // Resulting configuration is invalid (missing encoder for example)
+ // Early return to avoid drm core issue
+ if (!vkms_config_is_valid(connector->dev->config)) {
+ count = -EINVAL;
+ goto rollback;
+ }
+
+ if (!was_enabled && enabled) {
+ // Adding the connector
+ connector_cfg->connector = vkms_connector_hot_add(connector->dev->config->dev,
+ connector_cfg);
+ if (IS_ERR(connector_cfg->connector)) {
+ count = PTR_ERR(connector_cfg->connector);
+ goto rollback;
+ }
+ } else if (was_enabled && !enabled) {
+ vkms_connector_hot_remove(connector->dev->config->dev,
+ connector_cfg->connector);
+ }
+ }
+ }
+ return count;
+
+rollback:
+ vkms_config_connector_set_enabled(connector_cfg, was_enabled);
+ return count;
+}
+
+static ssize_t connector_dynamic_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_connector *connector;
+ bool enabled;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+
+ scoped_guard(mutex, &connector->dev->lock) {
+ enabled = vkms_config_connector_is_dynamic(connector->config);
+ }
+
+ return sprintf(page, "%d\n", enabled);
+}
+
+static ssize_t connector_dynamic_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct vkms_configfs_connector *connector;
+ struct vkms_config_connector *connector_cfg;
+ bool dynamic;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+ connector_cfg = connector->config;
+
+ if (kstrtobool(page, &dynamic))
+ return -EINVAL;
+
+ scoped_guard(mutex, &connector->dev->lock) {
+ // Can't change the dynamic status when the device is activated
+ if (connector->dev->enabled)
+ return -EBUSY;
+
+ vkms_config_connector_set_dynamic(connector_cfg, dynamic);
+ }
return count;
}
@@ -1299,6 +1406,8 @@ CONFIGFS_ATTR(connector_, type);
CONFIGFS_ATTR(connector_, supported_colorspaces);
CONFIGFS_ATTR(connector_, edid_enabled);
CONFIGFS_ATTR(connector_, edid);
+CONFIGFS_ATTR(connector_, dynamic);
+CONFIGFS_ATTR(connector_, enabled);
static struct configfs_attribute *connector_item_attrs[] = {
&connector_attr_status,
@@ -1306,19 +1415,28 @@ static struct configfs_attribute *connector_item_attrs[] = {
&connector_attr_supported_colorspaces,
&connector_attr_edid_enabled,
&connector_attr_edid,
+ &connector_attr_dynamic,
+ &connector_attr_enabled,
NULL,
};
static void connector_release(struct config_item *item)
{
struct vkms_configfs_connector *connector;
+ struct vkms_config_connector *connector_cfg;
struct mutex *lock;
connector = connector_item_to_vkms_configfs_connector(item);
+ connector_cfg = connector->config;
lock = &connector->dev->lock;
scoped_guard(mutex, lock) {
+ if (connector->dev->enabled && connector_cfg->dynamic && connector_cfg->enabled)
+ vkms_connector_hot_remove(connector->dev->config->dev,
+ connector_cfg->connector);
+
vkms_config_destroy_connector(connector->config);
+
kfree(connector);
}
}
@@ -1337,6 +1455,7 @@ static int connector_possible_encoders_allow_link(struct config_item *src,
struct config_item *target)
{
struct vkms_configfs_connector *connector;
+ struct vkms_config_connector *connector_cfg;
struct vkms_configfs_encoder *encoder;
int ret;
@@ -1344,14 +1463,25 @@ static int connector_possible_encoders_allow_link(struct config_item *src,
return -EINVAL;
connector = connector_possible_encoders_item_to_vkms_configfs_connector(src);
+ connector_cfg = connector->config;
encoder = encoder_item_to_vkms_configfs_encoder(target);
scoped_guard(mutex, &connector->dev->lock) {
- if (connector->dev->enabled)
- return -EBUSY;
+ if (connector->dev->enabled && connector_cfg->enabled) {
+ if (!connector_cfg->dynamic)
+ return -EBUSY;
+
+ ret = vkms_connector_hot_attach_encoder(connector->dev->config->dev,
+ connector->config->connector,
+ encoder->config->encoder);
+ if (ret)
+ return ret;
+ }
ret = vkms_config_connector_attach_encoder(connector->config,
encoder->config);
+ if (ret)
+ return ret;
}
return ret;
@@ -1392,9 +1522,6 @@ static struct config_group *make_connector_group(struct config_group *group,
dev = child_group_to_vkms_configfs_device(group);
scoped_guard(mutex, &dev->lock) {
- if (dev->enabled)
- return ERR_PTR(-EBUSY);
-
connector = kzalloc(sizeof(*connector), GFP_KERNEL);
if (!connector)
return ERR_PTR(-ENOMEM);
@@ -1408,6 +1535,9 @@ static struct config_group *make_connector_group(struct config_group *group,
return ERR_PTR(ret);
}
+ vkms_config_connector_set_dynamic(connector->config, connector->dev->enabled);
+ vkms_config_connector_set_enabled(connector->config, !connector->dev->enabled);
+
config_group_init_type_name(&connector->group, name,
&connector_item_type);
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 37/38] drm/vkms: Add connector parent configuration in vkms_config
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (35 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 36/38] drm/vkms: Introduce configfs for dynamic connector creation Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:57 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 38/38] drm/vkms: Add ConfigFS interface for connector parent and port_id Louis Chauvet
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
In order to fully emulate MST connector from the userspace point of view,
add a way to configure the PATH property.
Add two things:
- port_id, to configure the MST port id (used to generate the last
-<port-id> in the PATH property)
- parent, to configure the parent connector (used to
generate <connector-id>- or -<port-id>- in the PATH property)
In order to properly populate the PATH property, it should be done after
all the connector initialization to ensure that the <connector-id> is
known.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/tests/vkms_config_test.c | 269 +++++++++++++++++++++++++-
drivers/gpu/drm/vkms/vkms_config.c | 50 ++++-
drivers/gpu/drm/vkms/vkms_config.h | 60 +++++-
drivers/gpu/drm/vkms/vkms_configfs.c | 2 +-
drivers/gpu/drm/vkms/vkms_connector.c | 74 +++++++
drivers/gpu/drm/vkms/vkms_connector.h | 9 +
drivers/gpu/drm/vkms/vkms_output.c | 2 +
7 files changed, 460 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
index fda23f05a0a5..a9700e265d42 100644
--- a/drivers/gpu/drm/vkms/tests/vkms_config_test.c
+++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
@@ -396,7 +396,7 @@ static void vkms_config_test_get_connectors(struct kunit *test)
KUNIT_ASSERT_EQ(test, n_connectors, 2);
n_connectors = 0;
- vkms_config_destroy_connector(connector_cfg2);
+ vkms_config_destroy_connector(config, connector_cfg2);
vkms_config_for_each_connector(config, connector_cfg) {
n_connectors++;
if (connector_cfg != connector_cfg1)
@@ -845,7 +845,7 @@ static void vkms_config_test_invalid_connector_number(struct kunit *test)
/* Invalid: No connectors */
connector_cfg = get_first_connector(config);
- vkms_config_destroy_connector(connector_cfg);
+ vkms_config_destroy_connector(config, connector_cfg);
KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
/* Invalid: Too many connectors */
@@ -1233,6 +1233,267 @@ static void vkms_config_test_connector_status(struct kunit *test)
vkms_config_destroy(config);
}
+static void vkms_config_test_connector_dynamic_status(struct kunit *test)
+{
+ struct vkms_config *config;
+ struct vkms_config_connector *connector_cfg;
+ struct vkms_config_encoder *encoder_cfg;
+ struct vkms_config_crtc *crtc_cfg;
+ struct vkms_config_plane *plane_cfg;
+ enum drm_connector_status status;
+ int err;
+
+ config = vkms_config_create("test");
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
+
+ /* Create a complete pipeline */
+ crtc_cfg = vkms_config_create_crtc(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg);
+
+ encoder_cfg = vkms_config_create_encoder(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg);
+
+ connector_cfg = vkms_config_create_connector(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg);
+
+ plane_cfg = vkms_config_create_plane(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg);
+
+ vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_PRIMARY);
+ err = vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
+ err = vkms_config_encoder_attach_crtc(encoder_cfg, crtc_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
+ err = vkms_config_connector_attach_encoder(connector_cfg, encoder_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
+ /* Test dynamic status changes */
+ status = vkms_config_connector_get_status(connector_cfg);
+ KUNIT_EXPECT_EQ(test, status, connector_status_connected);
+
+ vkms_config_connector_set_status(connector_cfg, connector_status_disconnected);
+ status = vkms_config_connector_get_status(connector_cfg);
+ KUNIT_EXPECT_EQ(test, status, connector_status_disconnected);
+
+ /* Configuration should still be valid regardless of connector status */
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ vkms_config_connector_set_status(connector_cfg, connector_status_connected);
+ status = vkms_config_connector_get_status(connector_cfg);
+ KUNIT_EXPECT_EQ(test, status, connector_status_connected);
+
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Test with unknown status */
+ vkms_config_connector_set_status(connector_cfg, connector_status_unknown);
+ status = vkms_config_connector_get_status(connector_cfg);
+ KUNIT_EXPECT_EQ(test, status, connector_status_unknown);
+
+ /* Configuration should still be valid */
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ vkms_config_destroy(config);
+}
+
+static void vkms_config_test_dynamic_connector_validity(struct kunit *test)
+{
+ struct vkms_config *config;
+ struct vkms_config_connector *connector_cfg1, *connector_cfg2;
+ struct vkms_config_encoder *encoder_cfg;
+ struct vkms_config_crtc *crtc_cfg;
+ struct vkms_config_plane *plane_cfg;
+ int err;
+
+ config = vkms_config_create("test");
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
+
+ /* Create a complete pipeline */
+ crtc_cfg = vkms_config_create_crtc(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg);
+
+ encoder_cfg = vkms_config_create_encoder(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg);
+
+ connector_cfg1 = vkms_config_create_connector(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg1);
+
+ plane_cfg = vkms_config_create_plane(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg);
+
+ vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_PRIMARY);
+ err = vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
+ err = vkms_config_encoder_attach_crtc(encoder_cfg, crtc_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
+ err = vkms_config_connector_attach_encoder(connector_cfg1, encoder_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
+ /* Valid: Non-dynamic connector */
+ vkms_config_connector_set_dynamic(connector_cfg1, false);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Valid: Dynamic connector */
+ vkms_config_connector_set_dynamic(connector_cfg1, true);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Valid: Multiple dynamic connectors */
+ connector_cfg2 = vkms_config_create_connector(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg2);
+ vkms_config_connector_set_dynamic(connector_cfg2, true);
+ err = vkms_config_connector_attach_encoder(connector_cfg2, encoder_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ vkms_config_destroy(config);
+}
+
+static void vkms_config_test_dynamic_connector_parent_validity(struct kunit *test)
+{
+ struct vkms_config *config;
+ struct vkms_config_connector *connector_cfg1, *connector_cfg2, *connector_cfg3;
+ struct vkms_config_encoder *encoder_cfg;
+ struct vkms_config_crtc *crtc_cfg;
+ struct vkms_config_plane *plane_cfg;
+ int err;
+
+ config = vkms_config_create("test");
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
+
+ /* Create a complete pipeline */
+ crtc_cfg = vkms_config_create_crtc(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg);
+
+ encoder_cfg = vkms_config_create_encoder(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg);
+
+ connector_cfg1 = vkms_config_create_connector(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg1);
+
+ plane_cfg = vkms_config_create_plane(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg);
+
+ vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_PRIMARY);
+ err = vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
+ err = vkms_config_encoder_attach_crtc(encoder_cfg, crtc_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
+ err = vkms_config_connector_attach_encoder(connector_cfg1, encoder_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
+ /* Valid: Non-dynamic connector with no parent */
+ vkms_config_connector_set_dynamic(connector_cfg1, false);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Valid: Dynamic connector with no parent */
+ vkms_config_connector_set_dynamic(connector_cfg1, true);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Valid: Dynamic connector with dynamic parent */
+ connector_cfg2 = vkms_config_create_connector(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg2);
+ vkms_config_connector_set_dynamic(connector_cfg2, true);
+ err = vkms_config_connector_attach_encoder(connector_cfg2, encoder_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+ vkms_config_connector_attach_parent(connector_cfg2, connector_cfg1);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Valid: Dynamic connector with non-dynamic parent */
+ vkms_config_connector_set_dynamic(connector_cfg1, false);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Valid: Non-dynamic connector with no parent */
+ vkms_config_connector_attach_parent(connector_cfg2, NULL);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Valid: Multiple levels of dynamic parent-child relationships */
+ vkms_config_connector_set_dynamic(connector_cfg1, true);
+ vkms_config_connector_attach_parent(connector_cfg2, connector_cfg1);
+ connector_cfg3 = vkms_config_create_connector(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg3);
+ vkms_config_connector_set_dynamic(connector_cfg3, true);
+ err = vkms_config_connector_attach_encoder(connector_cfg3, encoder_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+ vkms_config_connector_attach_parent(connector_cfg3, connector_cfg2);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ vkms_config_destroy(config);
+}
+
+static void vkms_config_test_dynamic_connector_parent_loop(struct kunit *test)
+{
+ struct vkms_config *config;
+ struct vkms_config_connector *connector_cfg1, *connector_cfg2, *connector_cfg3;
+ struct vkms_config_encoder *encoder_cfg;
+ struct vkms_config_crtc *crtc_cfg;
+ struct vkms_config_plane *plane_cfg;
+ int err;
+
+ config = vkms_config_create("test");
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, config);
+
+ /* Create a complete pipeline */
+ crtc_cfg = vkms_config_create_crtc(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_cfg);
+
+ encoder_cfg = vkms_config_create_encoder(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder_cfg);
+
+ connector_cfg1 = vkms_config_create_connector(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg1);
+
+ plane_cfg = vkms_config_create_plane(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_cfg);
+
+ vkms_config_plane_set_type(plane_cfg, DRM_PLANE_TYPE_PRIMARY);
+ err = vkms_config_plane_attach_crtc(plane_cfg, crtc_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
+ err = vkms_config_encoder_attach_crtc(encoder_cfg, crtc_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
+ err = vkms_config_connector_attach_encoder(connector_cfg1, encoder_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
+ /* Valid: Single dynamic connector with no parent */
+ vkms_config_connector_set_dynamic(connector_cfg1, true);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Valid: Two dynamic connectors in a chain */
+ connector_cfg2 = vkms_config_create_connector(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg2);
+ vkms_config_connector_set_dynamic(connector_cfg2, true);
+ err = vkms_config_connector_attach_encoder(connector_cfg2, encoder_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+ vkms_config_connector_attach_parent(connector_cfg2, connector_cfg1);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Invalid: Create a loop - connector2 -> connector1 -> connector2 */
+ vkms_config_connector_attach_parent(connector_cfg1, connector_cfg2);
+ KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
+
+ /* Fix the loop */
+ vkms_config_connector_attach_parent(connector_cfg1, NULL);
+ KUNIT_EXPECT_TRUE(test, vkms_config_is_valid(config));
+
+ /* Invalid: Create a longer loop - connector1 -> connector2 -> connector3 -> connector1 */
+ connector_cfg3 = vkms_config_create_connector(config);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector_cfg3);
+ vkms_config_connector_set_dynamic(connector_cfg3, true);
+ err = vkms_config_connector_attach_encoder(connector_cfg3, encoder_cfg);
+ KUNIT_EXPECT_EQ(test, err, 0);
+ vkms_config_connector_attach_parent(connector_cfg3, connector_cfg2);
+ vkms_config_connector_attach_parent(connector_cfg1, connector_cfg3);
+ KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
+
+ vkms_config_destroy(config);
+}
+
static struct kunit_case vkms_config_test_cases[] = {
KUNIT_CASE(vkms_config_test_empty_config),
KUNIT_CASE_PARAM(vkms_config_test_default_config,
@@ -1259,6 +1520,10 @@ static struct kunit_case vkms_config_test_cases[] = {
KUNIT_CASE(vkms_config_test_encoder_get_possible_crtcs),
KUNIT_CASE(vkms_config_test_connector_get_possible_encoders),
KUNIT_CASE(vkms_config_test_connector_status),
+ KUNIT_CASE(vkms_config_test_connector_dynamic_status),
+ KUNIT_CASE(vkms_config_test_dynamic_connector_validity),
+ KUNIT_CASE(vkms_config_test_dynamic_connector_parent_validity),
+ KUNIT_CASE(vkms_config_test_dynamic_connector_parent_loop),
{}
};
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 98e40c6a2c5b..b9d5a2e44fd9 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -170,7 +170,7 @@ void vkms_config_destroy(struct vkms_config *config)
vkms_config_destroy_encoder(config, encoder_cfg);
list_for_each_entry_safe(connector_cfg, connector_tmp, &config->connectors, link)
- vkms_config_destroy_connector(connector_cfg);
+ vkms_config_destroy_connector(config, connector_cfg);
kfree_const(config->dev_name);
kfree(config);
@@ -437,6 +437,41 @@ static bool valid_connector_possible_encoders(const struct vkms_config *config)
return true;
}
+static bool valid_connector_parents(const struct vkms_config *config)
+{
+ struct drm_device *dev = config->dev ? &config->dev->drm : NULL;
+
+ struct vkms_config_connector *connector_cfg;
+ struct vkms_config_connector *connector_cfg_parent;
+
+ vkms_config_for_each_connector(config, connector_cfg) {
+ bool expected_status = connector_cfg->enabled;
+
+ vkms_config_for_each_connector(config, connector_cfg_parent)
+ connector_cfg_parent->visited = false;
+
+ connector_cfg_parent = connector_cfg;
+ while (connector_cfg_parent) {
+ if (connector_cfg_parent->visited) {
+ drm_info(dev, "Parents of connector should not form a loop\n");
+ return false;
+ }
+
+ if (expected_status && connector_cfg_parent->enabled != expected_status) {
+ drm_info(dev, "All parents of an enabled connector must be enabled\n");
+ return false;
+ }
+
+
+
+ connector_cfg_parent->visited = true;
+ connector_cfg_parent = connector_cfg_parent->parent;
+ }
+ }
+
+ return true;
+}
+
bool vkms_config_is_valid(const struct vkms_config *config)
{
struct drm_device *dev = config->dev ? &config->dev->drm : NULL;
@@ -503,6 +538,9 @@ bool vkms_config_is_valid(const struct vkms_config *config)
if (!valid_connector_possible_encoders(config))
return false;
+ if (!valid_connector_parents(config))
+ return false;
+
return true;
}
EXPORT_SYMBOL_IF_KUNIT(vkms_config_is_valid);
@@ -958,8 +996,16 @@ struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *c
}
EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_connector);
-void vkms_config_destroy_connector(struct vkms_config_connector *connector_cfg)
+void vkms_config_destroy_connector(struct vkms_config *config,
+ struct vkms_config_connector *connector_cfg)
{
+ struct vkms_config_connector *connector_cfg_tmp;
+
+ vkms_config_for_each_connector(config, connector_cfg_tmp) {
+ if (connector_cfg_tmp->parent == connector_cfg)
+ connector_cfg_tmp->parent = NULL;
+ }
+
xa_destroy(&connector_cfg->possible_encoders);
list_del(&connector_cfg->link);
kfree(connector_cfg);
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 071887a65380..2e6ddd2922c2 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -143,10 +143,14 @@ struct vkms_config_encoder {
* @edid: Stores the current EDID. The value will be ignored if @edid_enabled is false
* @edid_len: Current EDID length. The value will be ignored if @edid_enabled is false
* @possible_encoders: Array of encoders that can be used with this connector
+ * @parent: To emulate MST connector, this will contains a pointer to the parent
+ * @port_id: To emulate MST connector, this contains the physical port id. Used to
+ * generate the PATH property.
* @connector: Internal usage. This pointer should never be considered as valid.
* It can be used to store a temporary reference to a VKMS connector
* during device creation. This pointer is not managed by the
* configuration and must be managed by other means.
+ * @visited: Internal usage. This boolean is used to do some verification on the connectors.
*/
struct vkms_config_connector {
struct list_head link;
@@ -161,9 +165,12 @@ struct vkms_config_connector {
u8 *edid;
unsigned int edid_len;
struct xarray possible_encoders;
+ struct vkms_config_connector *parent;
+ u8 port_id;
/* Internal usage */
struct vkms_connector *connector;
+ bool visited;
};
/**
@@ -370,6 +377,56 @@ vkms_config_connector_set_edid(struct vkms_config_connector *connector_cfg,
connector_cfg->edid_len = len;
}
}
+/**
+ * vkms_config_connector_attach_parent - Attach a connector to a parent connector
+ * @connector_cfg: Connector to attach
+ * @parent: Parent connector to attach @connector_cfg to. Can be NULL to detach the parent.
+ */
+static inline void
+vkms_config_connector_attach_parent(struct vkms_config_connector *connector_cfg,
+ struct vkms_config_connector *parent)
+{
+ connector_cfg->parent = parent;
+}
+
+/**
+ * vkms_config_connector_get_parent - Get the parent connector of a connector
+ * @connector_cfg: Connector to get the parent from
+ *
+ * Returns:
+ * The parent connector of @connector_cfg or NULL if none is assigned yet.
+ */
+static inline struct vkms_config_connector*
+vkms_config_connector_get_parent(const struct vkms_config_connector *connector_cfg)
+{
+ return connector_cfg->parent;
+}
+
+/**
+ * vkms_config_connector_get_port_id() - Get the port ID for a connector
+ * @connector_cfg: Connector configuration to query
+ *
+ * Returns:
+ * The port ID for this connector.
+ */
+static inline u8
+vkms_config_connector_get_port_id(const struct vkms_config_connector *connector_cfg)
+{
+ return connector_cfg->port_id;
+}
+
+/**
+ * vkms_config_connector_set_port_id() - Set the port ID for a connector
+ * @connector_cfg: Connector configuration to modify
+ * @port_id: New port ID for this connector
+ */
+static inline void
+vkms_config_connector_set_port_id(struct vkms_config_connector *connector_cfg,
+ u8 port_id)
+{
+ connector_cfg->port_id = port_id;
+}
+
/**
* vkms_config_get_device_name() - Return the name of the device
@@ -1027,7 +1084,8 @@ struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *c
* vkms_config_destroy_connector() - Remove and free a connector configuration
* @connector_cfg: Connector configuration to destroy
*/
-void vkms_config_destroy_connector(struct vkms_config_connector *connector_cfg);
+void vkms_config_destroy_connector(struct vkms_config *config,
+ struct vkms_config_connector *connector_cfg);
/**
* vkms_config_connector_attach_encoder - Attach a connector to an encoder
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index f92b172e75cf..dd2a9e450150 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -1435,7 +1435,7 @@ static void connector_release(struct config_item *item)
vkms_connector_hot_remove(connector->dev->config->dev,
connector_cfg->connector);
- vkms_config_destroy_connector(connector->config);
+ vkms_config_destroy_connector(connector->dev->config, connector->config);
kfree(connector);
}
diff --git a/drivers/gpu/drm/vkms/vkms_connector.c b/drivers/gpu/drm/vkms/vkms_connector.c
index a013b53bd915..08e1828a0fb0 100644
--- a/drivers/gpu/drm/vkms/vkms_connector.c
+++ b/drivers/gpu/drm/vkms/vkms_connector.c
@@ -8,6 +8,76 @@
#include "vkms_config.h"
#include "vkms_connector.h"
+/**
+ * vkms_connector_build_path_property() - Build the PATH property string for MST connectors
+ * @connector: The connector to build the PATH property for
+ * @connector_cfg: The connector configuration
+ *
+ * The PATH property format is:
+ * mst:<drm object ID of root connector>-<dash-separated list of port_id>
+ * For nested MST connectors, this builds the full path like mst:45-2-3-4-2
+ */
+static void vkms_connector_build_path_property(struct vkms_connector *connector,
+ const struct vkms_config_connector *connector_cfg)
+{
+ const struct vkms_config_connector *current_cfg = connector_cfg;
+ const struct vkms_config_connector *root_cfg = NULL;
+ struct vkms_connector *root_connector = NULL;
+ char path[128]; /* Increased size for nested MST paths */
+ int len = 0;
+ u8 port_ids[16]; /* Max 16 levels of nesting */
+ int port_count = 0;
+ int i;
+
+ if (!vkms_config_connector_get_parent(connector_cfg))
+ return;
+
+ while (current_cfg) {
+ if (port_count < ARRAY_SIZE(port_ids))
+ port_ids[port_count++] = current_cfg->port_id;
+
+ if (!vkms_config_connector_get_parent(current_cfg)) {
+ root_cfg = current_cfg;
+ break;
+ }
+
+ current_cfg = vkms_config_connector_get_parent(current_cfg);
+ }
+
+ if (!root_cfg || !root_cfg->connector)
+ return;
+
+ root_connector = root_cfg->connector;
+
+ len = snprintf(path, sizeof(path), "mst:%d", root_connector->base.base.id);
+
+ for (i = port_count - 2; i >= 0; i--) {
+ int added = snprintf(path + len, sizeof(path) - len,
+ "-%u", port_ids[i]);
+ if (added < 0 || len + added >= sizeof(path))
+ return;
+ len += added;
+ }
+
+ drm_connector_set_path_property(&connector->base, path);
+}
+
+/**
+ * vkms_connector_update_path_properties() - Update PATH properties for all connectors
+ * @vkmsdev: VKMS device
+ *
+ * This should be called after all connectors are created to ensure parent connectors
+ * have valid DRM object IDs.
+ */
+void vkms_connector_update_path_properties(struct vkms_device *vkmsdev)
+{
+ struct vkms_config_connector *connector_cfg;
+
+ vkms_config_for_each_connector(vkmsdev->config, connector_cfg)
+ if (connector_cfg->connector)
+ vkms_connector_build_path_property(connector_cfg->connector, connector_cfg);
+}
+
static enum drm_connector_status vkms_connector_detect(struct drm_connector *connector,
bool force)
{
@@ -150,6 +220,8 @@ static int __must_check vkms_connector_init(struct vkms_connector *connector,
}
}
+ drm_object_attach_property(&connector->base.base, connector->base.dev->mode_config.path_property, 0);
+
return 0;
}
@@ -240,6 +312,8 @@ struct vkms_connector *vkms_connector_hot_add(struct vkms_device *vkmsdev,
if (ret)
return ERR_PTR(ret);
+ vkms_connector_build_path_property(connector, connector_cfg);
+
ret = drm_connector_dynamic_register(&connector->base);
if (ret) {
if (connector_cfg->type == DRM_MODE_CONNECTOR_HDMIA ||
diff --git a/drivers/gpu/drm/vkms/vkms_connector.h b/drivers/gpu/drm/vkms/vkms_connector.h
index a235a518d5a0..f8219830aaa5 100644
--- a/drivers/gpu/drm/vkms/vkms_connector.h
+++ b/drivers/gpu/drm/vkms/vkms_connector.h
@@ -67,4 +67,13 @@ int vkms_connector_hot_attach_encoder(struct vkms_device *vkmsdev,
struct vkms_connector *connector,
struct drm_encoder *encoder);
+/**
+ * vkms_connector_update_path_properties() - Update PATH properties for all connectors
+ * @vkmsdev: VKMS device
+ *
+ * This should be called after all connectors are created to ensure parent connectors
+ * have valid DRM object IDs.
+ */
+void vkms_connector_update_path_properties(struct vkms_device *vkmsdev);
+
#endif /* _VKMS_CONNECTOR_H_ */
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 50f7d88dee8b..ad901340ba7c 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -126,5 +126,7 @@ int vkms_output_init(struct vkms_device *vkmsdev)
}
}
+ vkms_connector_update_path_properties(vkmsdev);
+
return 0;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* [PATCH v5 38/38] drm/vkms: Add ConfigFS interface for connector parent and port_id
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
` (36 preceding siblings ...)
2026-06-27 3:30 ` [PATCH v5 37/38] drm/vkms: Add connector parent configuration in vkms_config Louis Chauvet
@ 2026-06-27 3:30 ` Louis Chauvet
2026-06-27 3:45 ` sashiko-bot
37 siblings, 1 reply; 65+ messages in thread
From: Louis Chauvet @ 2026-06-27 3:30 UTC (permalink / raw)
To: Haneen Mohammed, Simona Vetter, Melissa Wen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, jose.exposito89,
Jonathan Corbet, Shuah Khan, Miguel Ojeda, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt
Cc: Luca Ceresoli, Kory Maincent, victoria, sebastian.wick, victoria,
airlied, thomas.petazzoni, dri-devel, linux-kernel, linux-doc,
Louis Chauvet, llvm
Add the parent and port_id configuration for a connector.
- port_id can contains any u8 value
- parent can contain at most one symlink to an other connector.
Signed-off-by: Louis Chauvet <louis.chauvet@bootlin.com>
---
drivers/gpu/drm/vkms/vkms_configfs.c | 104 +++++++++++++++++++++++++++++++++++
1 file changed, 104 insertions(+)
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index dd2a9e450150..4f4ec9944804 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -114,6 +114,7 @@ struct vkms_configfs_encoder {
struct vkms_configfs_connector {
struct config_group group;
struct config_group possible_encoders_group;
+ struct config_group parent_group;
struct vkms_configfs_device *dev;
struct vkms_config_connector *config;
};
@@ -151,6 +152,10 @@ struct vkms_configfs_connector {
container_of(to_config_group((item)), struct vkms_configfs_connector, \
possible_encoders_group)
+#define connector_parent_item_to_vkms_configfs_connector(item) \
+ container_of(to_config_group((item)), struct vkms_configfs_connector, \
+ parent_group)
+
static ssize_t crtc_writeback_show(struct config_item *item, char *page)
{
struct vkms_configfs_crtc *crtc;
@@ -1401,6 +1406,42 @@ static ssize_t connector_dynamic_store(struct config_item *item,
return count;
}
+static ssize_t connector_port_id_show(struct config_item *item, char *page)
+{
+ struct vkms_configfs_connector *connector;
+ u8 port_id;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+
+ scoped_guard(mutex, &connector->dev->lock)
+ port_id = vkms_config_connector_get_port_id(connector->config);
+
+ return sprintf(page, "%u\n", port_id);
+}
+
+static ssize_t connector_port_id_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct vkms_configfs_connector *connector;
+ u8 port_id;
+ int ret;
+
+ connector = connector_item_to_vkms_configfs_connector(item);
+
+ ret = kstrtou8(page, 10, &port_id);
+ if (ret)
+ return ret;
+
+ scoped_guard(mutex, &connector->dev->lock) {
+ if (connector->dev->enabled && connector_is_enabled(connector->config))
+ return -EBUSY;
+
+ vkms_config_connector_set_port_id(connector->config, port_id);
+ }
+
+ return count;
+}
+
CONFIGFS_ATTR(connector_, status);
CONFIGFS_ATTR(connector_, type);
CONFIGFS_ATTR(connector_, supported_colorspaces);
@@ -1408,6 +1449,7 @@ CONFIGFS_ATTR(connector_, edid_enabled);
CONFIGFS_ATTR(connector_, edid);
CONFIGFS_ATTR(connector_, dynamic);
CONFIGFS_ATTR(connector_, enabled);
+CONFIGFS_ATTR(connector_, port_id);
static struct configfs_attribute *connector_item_attrs[] = {
&connector_attr_status,
@@ -1417,6 +1459,7 @@ static struct configfs_attribute *connector_item_attrs[] = {
&connector_attr_edid,
&connector_attr_dynamic,
&connector_attr_enabled,
+ &connector_attr_port_id,
NULL,
};
@@ -1512,6 +1555,63 @@ static const struct config_item_type connector_possible_encoders_group_type = {
.ct_owner = THIS_MODULE,
};
+static int connector_parent_connector_allow_link(struct config_item *src,
+ struct config_item *target)
+{
+ struct vkms_configfs_connector *connector;
+ struct vkms_config_connector *connector_cfg;
+ struct vkms_configfs_connector *parent;
+ struct vkms_config_connector *parent_cfg;
+ int ret;
+
+ if (target->ci_type != &connector_item_type)
+ return -EINVAL;
+
+ connector = connector_parent_item_to_vkms_configfs_connector(src);
+ connector_cfg = connector->config;
+ parent = connector_item_to_vkms_configfs_connector(target);
+ parent_cfg = parent->config;
+
+ if (connector->dev != parent->dev)
+ return -EINVAL;
+
+ scoped_guard(mutex, &connector->dev->lock) {
+ if (vkms_config_connector_get_parent(connector_cfg))
+ return -EMLINK;
+
+ if (connector->dev->enabled && connector_cfg->enabled)
+ return -EBUSY;
+
+ vkms_config_connector_attach_parent(connector_cfg,
+ parent_cfg);
+ }
+
+ return ret;
+}
+
+static void connector_parent_connector_drop_link(struct config_item *src,
+ struct config_item *target)
+{
+ struct vkms_configfs_connector *connector;
+ struct vkms_config_connector *connector_cfg;
+
+ connector = connector_parent_item_to_vkms_configfs_connector(src);
+ connector_cfg = connector->config;
+
+ scoped_guard(mutex, &connector->dev->lock)
+ vkms_config_connector_attach_parent(connector_cfg, NULL);
+}
+
+static struct configfs_item_operations connector_parent_item_operations = {
+ .allow_link = connector_parent_connector_allow_link,
+ .drop_link = connector_parent_connector_drop_link,
+};
+
+static const struct config_item_type connector_parent_group_type = {
+ .ct_item_ops = &connector_parent_item_operations,
+ .ct_owner = THIS_MODULE,
+};
+
static struct config_group *make_connector_group(struct config_group *group,
const char *name)
{
@@ -1544,6 +1644,10 @@ static struct config_group *make_connector_group(struct config_group *group,
config_group_init_type_name(&connector->possible_encoders_group,
"possible_encoders",
&connector_possible_encoders_group_type);
+ config_group_init_type_name(&connector->parent_group,
+ "parent",
+ &connector_parent_group_type);
+ configfs_add_default_group(&connector->parent_group, &connector->group);
configfs_add_default_group(&connector->possible_encoders_group,
&connector->group);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 65+ messages in thread
* Re: [PATCH v5 16/38] drm/vkms: Use DRM_ROTATION_FMT macros for rotation display
2026-06-27 3:30 ` [PATCH v5 16/38] drm/vkms: Use DRM_ROTATION_FMT macros for rotation display Louis Chauvet
@ 2026-06-27 3:39 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:39 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The commit message claims to replace 'show_bitfield' calls, but the patch only adds new code.
--
commit f7f78813e63d666fa8947019e26ece97d4eb3583
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Use DRM_ROTATION_FMT macros for rotation display
This commit updates the vkms configuration debugfs output to include supported
and default rotation configurations. It uses the DRM_ROTATION_FMT macro for
formatting.
> Replace show_bitfield calls for rotation/reflection with the new
> DRM_ROTATION_FMT / DRM_ROTATION_FMT_ARGS macros for cleaner code.
[Severity: Medium]
Is this description accurate?
The commit message claims to replace show_bitfield calls, but the patch only
adds new seq_printf calls for supported and default rotations in
vkms_config_show() (in drivers/gpu/drm/vkms/vkms_config.c) without removing
any existing code.
A search of the tree before this commit confirms show_bitfield was never used
in the vkms subsystem.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=16
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 02/38] drm/blend: Get a rotation name from it's bitfield
2026-06-27 3:30 ` [PATCH v5 02/38] drm/blend: Get a rotation name from it's bitfield Louis Chauvet
@ 2026-06-27 3:41 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:41 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] drm_get_rotation_name() incorrectly treats a rotation bitmask argument as a direct array index, returning wrong strings for valid rotation masks.
--
commit b39dab0752eb4becf3196f5e38118e4db280556f
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/blend: Get a rotation name from it's bitfield
This commit extracts the rotation property table and implements
drm_get_rotation_name() to return the name from a rotation value. It
also introduces a macro for formatting multiple rotation masks.
> diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c
> index 2f0d1ba285be8..eecdaf623c1e2 100644
> --- a/drivers/gpu/drm/drm_blend.c
> +++ b/drivers/gpu/drm/drm_blend.c
[ ... ]
> +/**
> + * drm_get_rotation_name - Return the name of a rotation
> + * @rotation: The rotation mask (DRM_MODE_ROTATE_* | DRM_MODE_REFLECT_*)
> + *
> + * Returns: the name of the rotation type (unknown) if rotation is not
> + * a known rotation/reflection
> + */
> +const char *drm_get_rotation_name(unsigned int rotation)
> +{
> + if (rotation < ARRAY_SIZE(rotation_props))
> + return rotation_props[rotation].name;
[Severity: Medium]
Since the kernel-doc states the rotation parameter is a mask, won't this
return incorrect strings?
DRM_MODE_ROTATE_90 is 2, so this would index rotation_props[2].name and
return "rotate-180" instead of "rotate-90". For higher masks like
DRM_MODE_REFLECT_X which evaluates to 16, this fails the bounds check
and returns "(unknown)".
Should this extract the bit index using __builtin_ffs before indexing the
array?
> +
> + return "(unknown)";
> +}
> +EXPORT_SYMBOL(drm_get_rotation_name);
[ ... ]
> diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h
> index bebbb77a8f214..33329170aafe8 100644
> --- a/include/drm/drm_blend.h
> +++ b/include/drm/drm_blend.h
[ ... ]
> +#define DRM_ROTATION_FMT "%s%s%s%s%s%s%s%s%s%s%s%s"
> +#define DRM_ROTATION_FMT_ARGS(rot) \
> + (rot) & DRM_MODE_ROTATE_0 ? drm_get_rotation_name(0) : "", \
> + (rot) & DRM_MODE_ROTATE_0 ? " " : "", \
> + (rot) & DRM_MODE_ROTATE_90 ? drm_get_rotation_name(1) : "", \
[Severity: Medium]
Does passing array indices like 0, 1, 2 directly to drm_get_rotation_name()
contradict the documented API contract?
The function's documentation states it expects rotation masks. Passing
literal indices works around the indexing bug in the function implementation
but leaves the exported API broken for other callers passing standard masks.
> + (rot) & DRM_MODE_ROTATE_90 ? " " : "", \
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=2
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 25/38] drm/vkms: Introduce config for plane zpos property
2026-06-27 3:30 ` [PATCH v5 25/38] drm/vkms: Introduce config for plane zpos property Louis Chauvet
@ 2026-06-27 3:41 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:41 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] The return values of `drm_plane_create_zpos_property()` and `drm_plane_create_zpos_immutable_property()` are ignored.
- [Low] Missing newline character `\n` at the end of the `drm_info` format string.
- [Low] Using signed format specifiers (`%d`) for unsigned integer variables in debugfs output.
--
commit 332270a595e6e9b34ad7075f21dc26e1c7579078
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce config for plane zpos property
VKMS can render plane in any order. Introduce the appropriate
configuration.
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index c7de3e3073674..5bc8248f99353 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
[ ... ]
> @@ -429,6 +462,19 @@ bool vkms_config_is_valid(const struct vkms_config *config)
> "Both supported color encodings and color ranges must be set, or none\n");
> return false;
> }
> +
> + if (!vkms_config_valid_plane_zpos(config, plane_cfg))
> + return false;
> +
> + if (vkms_config_plane_get_zpos_enabled(plane_cfg))
> + has_zpos_enabled = true;
> + else
> + has_zpos_disabled = true;
> + }
> +
> + if (has_zpos_enabled && has_zpos_disabled) {
> + drm_info(dev, "In the same device, all planes must have zpos enabled or none of them");
[Severity: Low]
Is this missing a newline character? Log messages without a trailing \n
can cause formatting issues by buffering and attaching to the next message.
> + return false;
> }
>
> if (!valid_plane_number(config))
[ ... ]
> @@ -527,6 +573,16 @@ static int vkms_config_show(struct seq_file *m, void *data)
> show_formats(m, vkms_config_plane_get_supported_formats(plane_cfg),
> vkms_config_plane_get_supported_formats_count(plane_cfg));
> seq_puts(m, "\n");
> + seq_printf(m, "\tzpos_enabled=%s\n",
> + str_true_false(vkms_config_plane_get_zpos_enabled(plane_cfg)));
> + seq_printf(m, "\tzpos_mutable=%s\n",
> + str_true_false(vkms_config_plane_get_zpos_mutable(plane_cfg)));
> + seq_printf(m, "\tzpos_min=%d\n",
> + vkms_config_plane_get_zpos_min(plane_cfg));
> + seq_printf(m, "\tzpos_initial=%d\n",
> + vkms_config_plane_get_zpos_initial(plane_cfg));
> + seq_printf(m, "\tzpos_max=%d\n",
> + vkms_config_plane_get_zpos_max(plane_cfg));
[Severity: Low]
Should these use the %u format specifier instead of %d? The getter
functions (like vkms_config_plane_get_zpos_min) return unsigned int,
so %d might display large values as negative numbers.
> }
>
> vkms_config_for_each_crtc(vkmsdev->config, crtc_cfg) {
[ ... ]
> diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
> index 6e767cdf81942..d600a6167042b 100644
> --- a/drivers/gpu/drm/vkms/vkms_plane.c
> +++ b/drivers/gpu/drm/vkms/vkms_plane.c
[ ... ]
> @@ -214,6 +214,17 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
>
> if (vkms_config_plane_get_default_pipeline(plane_cfg))
> vkms_initialize_colorops(&plane->base);
> + if (vkms_config_plane_get_zpos_enabled(plane_cfg)) {
> + if (vkms_config_plane_get_zpos_mutable(plane_cfg)) {
> + drm_plane_create_zpos_property(&plane->base,
> + vkms_config_plane_get_zpos_initial(plane_cfg),
> + vkms_config_plane_get_zpos_min(plane_cfg),
> + vkms_config_plane_get_zpos_max(plane_cfg));
> + } else {
> + drm_plane_create_zpos_immutable_property(&plane->base,
> + vkms_config_plane_get_zpos_initial(plane_cfg));
> + }
> + }
[Severity: Medium]
Is it safe to ignore the return values of drm_plane_create_zpos_property()
and drm_plane_create_zpos_immutable_property() here?
These functions can return -ENOMEM on allocation failure. If that happens,
the plane is partially initialized without the expected zpos property,
which might confuse userspace applications. Should we propagate the error
up through vkms_plane_init()?
>
> return plane;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=25
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 08/38] drm/vkms: Add error handling in plane config creation
2026-06-27 3:30 ` [PATCH v5 08/38] drm/vkms: Add error handling in plane config creation Louis Chauvet
@ 2026-06-27 3:41 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:41 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The `__must_check` attribute was added to the function definition but omitted from the function declaration in the header file.
--
commit b58f544faddd7341ba3d5a39105fac34d6c709cf
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Add error handling in plane config creation
This commit updates vkms_config_create_plane() to return proper error codes
using ERR_PTR instead of returning NULL on failure. It also adds the
__must_check attribute to the function definition.
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index 5a654d6dead84..1fd2ed1167c54 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
[ ... ]
> @@ -384,13 +384,16 @@ void vkms_config_register_debugfs(struct vkms_device *vkms_device)
> ARRAY_SIZE(vkms_config_debugfs_list));
> }
>
> -struct vkms_config_plane *vkms_config_create_plane(struct vkms_config *config)
> +struct vkms_config_plane __must_check *vkms_config_create_plane(struct vkms_config *config)
[Severity: Low]
Does the __must_check attribute also need to be added to the function
declaration in drivers/gpu/drm/vkms/vkms_config.h?
Since the attribute is only present on the definition here in vkms_config.c,
callers in other translation units won't see it. The compiler will not emit
a warning if the return value is ignored by external callers.
> {
> struct vkms_config_plane *plane_cfg;
> + int ret;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=8
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 15/38] drm/vkms: Introduce config for plane rotation
2026-06-27 3:30 ` [PATCH v5 15/38] drm/vkms: Introduce config for plane rotation Louis Chauvet
@ 2026-06-27 3:42 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:42 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] vkms_config_valid_plane_rotation() incorrectly allows multiple base rotation bits to be set in default_rotation, which will trigger a kernel WARNING.
- [Low] The validation check ensuring that supported_rotations contains at least one rotation is mathematically unreachable dead code.
--
commit f25358e4a8dbe82dcc32cb1193229da2bf2b59f3
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce config for plane rotation
This commit introduces a new configuration interface that allows customizing
the supported rotations for each plane. This is useful for testing specific
rotation setups without advertising all possible plane rotations.
> diff --git a/drivers/gpu/drm/vkms/tests/vkms_config_test.c b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
> index 1e4ea1863420f..c33fe737678ff 100644
> --- a/drivers/gpu/drm/vkms/tests/vkms_config_test.c
> +++ b/drivers/gpu/drm/vkms/tests/vkms_config_test.c
[ ... ]
> @@ -481,6 +488,44 @@ static void vkms_config_test_valid_plane_type(struct kunit *test)
[ ... ]
> + /* Invalid, supported rotations must contains at least one rotation */
> + vkms_config_plane_set_supported_rotations(plane_cfg, DRM_MODE_REFLECT_MASK);
> + vkms_config_plane_set_default_rotation(plane_cfg, DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_0);
> + KUNIT_EXPECT_FALSE(test, vkms_config_valid_plane_rotation(config, plane_cfg));
[Severity: Low]
Does this test actually verify the intended check?
Since default_rotation is not a subset of supported_rotations here, this test
fails the earlier subset check in vkms_config_valid_plane_rotation(),
meaning it never actually reaches the supported_rotations validation check.
> + KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
> +
> + /* Invalid, default rotation must contains at least one rotation */
> + vkms_config_plane_set_supported_rotations(plane_cfg,
> + DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0);
> + vkms_config_plane_set_default_rotation(plane_cfg, DRM_MODE_REFLECT_X);
> + KUNIT_EXPECT_FALSE(test, vkms_config_valid_plane_rotation(config, plane_cfg));
> + KUNIT_EXPECT_FALSE(test, vkms_config_is_valid(config));
> +
> + vkms_config_destroy(config);
> +}
> +
> static void vkms_config_test_valid_plane_possible_crtcs(struct kunit *test)
> {
> struct vkms_config *config;
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index 54994f3c8e144..5c86eb24fedf3 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
[ ... ]
> @@ -150,6 +151,33 @@ static bool valid_plane_number(const struct vkms_config *config)
> return true;
> }
>
> +VISIBLE_IF_KUNIT
> +bool vkms_config_valid_plane_rotation(const struct vkms_config *config,
> + const struct vkms_config_plane *plane_cfg)
> +{
> + struct drm_device *dev = config->dev ? &config->dev->drm : NULL;
> +
> + if ((vkms_config_plane_get_default_rotation(plane_cfg) &
> + vkms_config_plane_get_supported_rotations(plane_cfg)) !=
> + vkms_config_plane_get_default_rotation(plane_cfg)) {
> + drm_info(dev, "Configured default rotation is not supported by the plane\n");
> + return false;
> + }
> +
> + if ((vkms_config_plane_get_default_rotation(plane_cfg) & DRM_MODE_ROTATE_MASK) == 0) {
> + drm_info(dev, "Configured default rotation must contains at least one possible rotation\n");
> + return false;
> + }
[Severity: Medium]
Will this allow multiple base rotation bits (e.g., DRM_MODE_ROTATE_0 |
DRM_MODE_ROTATE_90) to be set simultaneously?
The API invariant in drm_plane_create_rotation_property() requires exactly one
base rotation angle and uses is_power_of_2() to check this. If multiple bits
pass this validation here, it could trigger a kernel WARNING stack trace later
when creating the property.
Should this check use is_power_of_2() instead?
> +
> + if ((vkms_config_plane_get_supported_rotations(plane_cfg) & DRM_MODE_ROTATE_MASK) == 0) {
[Severity: Low]
Is this block mathematically unreachable dead code?
If default_rotation contains at least one rotation bit (from the previous check)
and default_rotation is a bitwise subset of supported_rotations (from the first
check), then supported_rotations is mathematically guaranteed to contain at least
one rotation bit.
> + drm_info(dev, "Configured supported rotations must contains at least one possible rotation\n");
> + return false;
> + }
> +
> + return true;
> +}
> +EXPORT_SYMBOL_IF_KUNIT(vkms_config_valid_plane_rotation);
> +
[ ... ]
> diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
> index f351202031244..8a64ea41734b8 100644
> --- a/drivers/gpu/drm/vkms/vkms_plane.c
> +++ b/drivers/gpu/drm/vkms/vkms_plane.c
> @@ -235,8 +235,9 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
>
> drm_plane_helper_add(&plane->base, &vkms_plane_helper_funcs);
>
> - drm_plane_create_rotation_property(&plane->base, DRM_MODE_ROTATE_0,
> - DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK);
> + drm_plane_create_rotation_property(&plane->base,
> + vkms_config_plane_get_default_rotation(plane_cfg),
> + vkms_config_plane_get_supported_rotations(plane_cfg));
[Severity: Medium]
This is where the invalid configuration could be passed to the DRM core.
If vkms_config_valid_plane_rotation() allows a default_rotation mask with
multiple rotation bits, calling drm_plane_create_rotation_property() here will
trigger its WARN_ON() invariant check.
>
> drm_plane_create_color_properties(&plane->base,
> BIT(DRM_COLOR_YCBCR_BT601) |
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=15
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 18/38] drm/vkms: Introduce config for plane color encoding
2026-06-27 3:30 ` [PATCH v5 18/38] drm/vkms: Introduce config for plane color encoding Louis Chauvet
@ 2026-06-27 3:43 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:43 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Type mismatch and format string vulnerabilities in show_bitfield causing build failures and KCFI panics
--
commit 2751d72859c546f6b3eb551641e51316a31f2b9f
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce config for plane color encoding
VKMS driver supports all the color encoding on planes, but for testing it
can be useful to only advertise few of them. This new configuration
interface will allow configuring the color encoding per planes.
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index ca3ee3aa2c41f..2fa467f5e17ed 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
[ ... ]
> @@ -373,6 +395,22 @@ bool vkms_config_is_valid(const struct vkms_config *config)
> }
> EXPORT_SYMBOL_IF_KUNIT(vkms_config_is_valid);
>
> +static void show_bitfield(struct seq_file *m, uint32_t value, const char *callback(unsigned int))
> +{
> + u32 offset = 0;
> + bool first = true;
> +
> + while (value >= BIT(offset) && offset < 32) {
> + if (value & BIT(offset)) {
> + if (!first)
> + seq_puts(m, ",");
> + seq_printf(m, callback(offset));
[Severity: High]
Does this trigger a format-security build error?
Passing the result of callback() directly to seq_printf() without a format
string literal can cause format string vulnerabilities and typically breaks
the build under -Werror=format-security.
Should this use seq_printf(m, "%s", callback(offset)) instead?
> + first = false;
> + }
> + offset += 1;
> + }
> +}
> +
> static int vkms_config_show(struct seq_file *m, void *data)
> {
[ ... ]
> @@ -398,6 +436,12 @@ static int vkms_config_show(struct seq_file *m, void *data)
> DRM_ROTATION_FMT_ARGS(vkms_config_plane_get_supported_rotations(plane_cfg)));
> seq_printf(m, "\tdefault rotation=" DRM_ROTATION_FMT "\n",
> DRM_ROTATION_FMT_ARGS(vkms_config_plane_get_default_rotation(plane_cfg)));
> + seq_puts(m, "\tsupported color encoding=");
> + show_bitfield(m, vkms_config_plane_get_supported_color_encodings(plane_cfg),
> + drm_get_color_encoding_name);
[Severity: High]
Can this mismatch cause a KCFI kernel panic and compiler warnings?
The show_bitfield() function expects a callback taking an unsigned int, but
drm_get_color_encoding_name() takes an enum drm_color_encoding. Because C
treats enums and unsigned ints as distinct types for function signatures,
this mismatch triggers a -Wincompatible-pointer-types warning.
If executed on a kernel with Kernel Control-Flow Integrity (KCFI) enabled,
this indirect call mismatch will result in a kernel panic when a user reads
the debugfs endpoint.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=18
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 14/38] drm/vkms: Use plane folder name as plane name
2026-06-27 3:30 ` [PATCH v5 14/38] drm/vkms: Use plane folder name as " Louis Chauvet
@ 2026-06-27 3:43 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:43 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] User-provided plane name from configfs is used directly as a format string in `drmm_universal_plane_alloc()`.
- [Medium] Missing cleanup of `plane->config` on the `vkms_config_plane_set_name()` error path in `make_plane_group()`.
- [Medium] `drm_get_rotation_name` incorrectly uses a rotation mask as an array index, contrary to its documentation.
--
commit 71fdf3bbf310c477150a383e21a3c104a2d6795c
Author: Louis Chauvet <louis.chauvet@bootlin.com>
Subject: drm/vkms: Use plane folder name as plane name
The plane name is now directly derived from the configfs folder name. When a
plane directory is created under /config/vkms/<device>/planes/, the folder
name is used as the plane name via vkms_config_plane_set_name.
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index 97f87a53d202a..0744ac40814d8 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
> @@ -377,6 +377,12 @@ static struct config_group *make_plane_group(struct config_group *group,
> return ERR_PTR(ret);
> }
>
> + ret = vkms_config_plane_set_name(plane->config, name, strlen(name));
[Severity: High]
Could this introduce a format string regression?
Since this user-provided configfs folder name is stored as the plane name,
it appears it gets passed directly as the format string parameter to
drmm_universal_plane_alloc() later during initialization:
drivers/gpu/drm/vkms/vkms_plane.c:vkms_plane_init()
plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 0,
&vkms_plane_funcs,
vkms_config_plane_get_supported_formats(plane_cfg),
vkms_config_plane_get_supported_formats_count(plane_cfg),
NULL, vkms_config_plane_get_type(plane_cfg),
vkms_config_plane_get_name(plane_cfg));
If a user creates a configfs directory with a name containing printf-style
format specifiers (e.g., "%s%n"), can it lead to a kernel crash or memory
corruption?
> + if (ret) {
> + kfree(plane);
[Severity: Medium]
Is there a regression in this error path where it leaves a dangling plane
configuration?
If vkms_config_plane_set_name() fails (e.g., due to memory allocation
failure), this calls kfree(plane). However, it seems plane->config was
already appended to dev->config->planes prior to this, but we don't call
vkms_config_destroy_plane(plane->config) here.
Can this leave a ghost plane in the device configuration that lacks a
corresponding configfs directory?
> + return ERR_PTR(ret);
> + }
> +
> config_group_init_type_name(&plane->group, name, &plane_item_type);
>
> config_group_init_type_name(&plane->possible_crtcs_group,
[Severity: Medium]
Will the following logic in drm_get_rotation_name() cause a regression by
incorrectly using a rotation mask as an array index?
In drivers/gpu/drm/drm_blend.c:drm_get_rotation_name():
const char *drm_get_rotation_name(unsigned int rotation)
{
if (rotation < ARRAY_SIZE(rotation_props))
return rotation_props[rotation].name;
return "(unknown)";
}
The documentation for this function explicitly states the rotation parameter
expects a rotation mask (DRM_MODE_ROTATE_* | DRM_MODE_REFLECT_*). However,
the implementation expects an array index (0-5) and incorrectly uses the
mask as an index.
For example, passing the mask DRM_MODE_ROTATE_90 (which is 2) returns
"rotate-180" (the value at index 2).
Can this cause incorrect strings to be returned to new drivers or core code
using this exported function?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=14
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 24/38] drm/vkms: Properly render plane using their zpos
2026-06-27 3:30 ` [PATCH v5 24/38] drm/vkms: Properly render plane using their zpos Louis Chauvet
@ 2026-06-27 3:44 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:44 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Heap Out-of-bounds Write / NULL Pointer Dereference in vkms_crtc_atomic_check and blend.
- [High] Validation Bypass / Incorrect API Usage via calling drm_atomic_normalize_zpos in CRTC atomic check.
--
commit ba6a2ee7af0fa7f9537a297540c84e807c85f3f7
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Properly render plane using their zpos
Currently planes are rendered in creation order. This is not an issue, but
with the introduction of new zpos configuration, it is required to
properly render planes.
> diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
> index 079abfba427d0..b9428de2d4aa8 100644
> --- a/drivers/gpu/drm/vkms/vkms_crtc.c
> +++ b/drivers/gpu/drm/vkms/vkms_crtc.c
> @@ -142,14 +142,20 @@ static int vkms_crtc_atomic_check(struct drm_crtc *crtc,
> return -ENOMEM;
> vkms_state->num_active_planes = i;
>
> - i = 0;
> + ret = drm_atomic_normalize_zpos(crtc->dev, state);
> + if (ret)
> + return ret;
[Severity: High]
Does calling drm_atomic_normalize_zpos() inside a per-CRTC atomic check bypass
plane validation?
In the DRM atomic framework, drm_atomic_helper_check_planes() calls plane
atomic_check() callbacks before CRTC atomic_check() callbacks. By calling
drm_atomic_normalize_zpos() here and adding affected planes to the state, any
planes pulled into the state at this stage will completely miss their
plane-level validation.
Also, since drm_atomic_normalize_zpos() operates on the global atomic state, it
will be executed redundantly for every modified CRTC.
Could this be handled by setting dev->mode_config.normalize_zpos = true during
driver initialization instead, letting the core run the helper before the plane
validation phase?
> +
> drm_for_each_plane_mask(plane, crtc->dev, crtc_state->plane_mask) {
> plane_state = drm_atomic_get_new_plane_state(crtc_state->state, plane);
>
> if (!plane_state->visible)
> continue;
>
> - vkms_state->active_planes[i++] =
> + // Order planes according to their normalized_zpos
> + // After drm_atomic_normalize_zpos, the possible values are 0..n_planes-1
> + // so store them using this index
> + vkms_state->active_planes[plane_state->normalized_zpos] =
> to_vkms_plane_state(plane_state);
[Severity: High]
Can this cause an out-of-bounds write if there are invisible planes?
Earlier in this function, vkms_state->active_planes is allocated based on the
number of visible planes (the variable i).
However, drm_atomic_normalize_zpos() computes a sequential normalized_zpos for
all planes attached to the CRTC, not just visible ones. If a userspace client
configures planes such that some are invisible (e.g., clipped or scaled to 0),
the maximum normalized_zpos will exceed the allocated size (i - 1), resulting
in a heap out-of-bounds write.
Additionally, this sparse assignment leaves holes in the array. During
composition, blend() in drivers/gpu/drm/vkms/vkms_composer.c iterates up to
num_active_planes and blindly dereferences the plane array elements. Will this
cause a NULL pointer dereference for the skipped indices?
> }
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=24
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 23/38] drm/vkms: Introduce configfs for plane format
2026-06-27 3:30 ` [PATCH v5 23/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:45 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:45 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Strict length validation in `plane_supported_formats_store` rejects valid shell inputs containing trailing newlines.
- [High] Type punning between a `char` array and `int *` causes unaligned memory accesses and produces corrupted FourCC codes on big-endian architectures.
- [High] Missing `plane->dev->enabled` check in `plane_supported_formats_store` allows userspace to modify formats while the device is active, causing a Use-After-Free.
- [Medium] Incorrect pointer arithmetic in `vkms_configfs_parse_next_format` results in a negative length, defeating bounds checking for `strnchr`.
- [Low] `vkms_configfs_parse_next_format` is completely unused in the operational driver and causes a build failure when KUnit is disabled.
--
commit a7abf4a30e4c9317197078c2d2f5f96c79800929
Author: Louis Chauvet <louis.chauvet@bootlin.com>
Subject: drm/vkms: Introduce configfs for plane format
This commit introduces a configfs interface to configure the available
formats per planes in VKMS. It adds parsing logic and test cases to
allow userspace to test multiple hardware configurations.
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
[ ... ]
> +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]);
[Severity: High]
Does this cast to a char pointer cause endianness issues on big-endian
architectures?
Since DRM FourCC codes are strictly little-endian, interpreting the integer
directly as a character array might reverse the format string on big-endian
machines.
> + if (ret < 0)
> + return ret;
[ ... ]
> +VISIBLE_IF_KUNIT
> +int vkms_configfs_parse_next_format(const char *page, const char *page_end, char **out)
[Severity: Low]
Since this function isn't called anywhere in the operational driver paths, does
it cause a -Wunused-function build failure when CONFIG_KUNIT is disabled and
VISIBLE_IF_KUNIT evaluates to static?
> +{
> + int count = page - page_end;
[Severity: Medium]
Since page comes before page_end in memory, won't this calculation result in a
negative count?
When passed to strnchr() which takes a size_t, won't this negative value
become a massive positive integer and bypass the bounds check?
> + char *tmp_plus = strnchr(page, count, '+');
> + char *tmp_minus = strnchr(page, count, '-');
[ ... ]
> +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;
> +
> + if (count < 2 || count > 5)
> + return -EINVAL;
> +
> + if (page[0] != '+' && page[0] != '-')
> + return -EINVAL;
> +
> + if (page[1] == '*' && count != 2)
> + return -EINVAL;
[Severity: High]
Does this rigid length validation reject standard shell inputs?
When users configure the format using standard commands like
echo "+AR24" > supported_formats, the shell appends a trailing newline,
making the count 6 instead of 5. For echo "+*", the count becomes 3 instead
of 2.
Will this prevent userspace from using the interface as documented?
> +
> + scoped_guard(mutex, &plane->dev->lock) {
[Severity: High]
Should there be a check here to ensure the device is not enabled, similar to
other configfs store functions like plane_zpos_enabled_store()?
If userspace modifies or clears the supported formats while the virtual DRM
device is active, vkms_config_plane_remove_all_formats() frees the formats
array. Could this lead to a use-after-free if the rendering pipeline is
concurrently accessing it?
For example, shouldn't we have:
if (plane->dev->enabled)
return -EBUSY;
> + char fmt[4] = {' ', ' ', ' ', ' '};
> +
> + memcpy(fmt, &page[1], min(count - 1, 4));
> +
> + if (page[0] == '+' && page[1] == '*')
> + ret = vkms_config_plane_add_all_formats(plane->config);
> + else if (page[0] == '-' && page[1] == '*')
> + vkms_config_plane_remove_all_formats(plane->config);
> + else if (page[0] == '+')
> + ret = vkms_config_plane_add_format(plane->config, *(int *)fmt);
[Severity: High]
Does casting this 4-byte character array to an int pointer risk alignment
faults?
If the character array on the stack is not 4-byte aligned, won't this cause
a panic on architectures that enforce strict alignment?
Additionally, similar to the show() function, does this type punning create
endianness issues on big-endian systems?
> + else if (page[0] == '-')
> + vkms_config_plane_remove_format(plane->config, *(int *)fmt);
> +
> + if (ret)
> + return ret;
> + }
> +
> + return count;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=23
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 27/38] drm/vkms: Introduce config for connector type
2026-06-27 3:30 ` [PATCH v5 27/38] drm/vkms: Introduce config for connector type Louis Chauvet
@ 2026-06-27 3:45 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:45 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Missing parameter documentation for @connector_cfg in vkms_connector_init().
--
commit 7b78b90cde59a7b9192c3c5358636914942ee62e
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce config for connector type
This commit introduces a connector type configuration for VKMS to emulate
connector-specific behavior. It adds the configuration structure, updates
the connector initialization to use the specified type, and provides tests
for the new functionality.
> diff --git a/drivers/gpu/drm/vkms/vkms_connector.h b/drivers/gpu/drm/vkms/vkms_connector.h
> index ed312f4eff3a7..33253d29b1ccd 100644
> --- a/drivers/gpu/drm/vkms/vkms_connector.h
> +++ b/drivers/gpu/drm/vkms/vkms_connector.h
[ ... ]
> @@ -24,7 +25,8 @@ struct vkms_connector {
> * Returns:
> * The connector or an error on failure.
> */
> -struct vkms_connector *vkms_connector_init(struct vkms_device *vkmsdev);
> +struct vkms_connector *vkms_connector_init(struct vkms_device *vkmsdev,
> + struct vkms_config_connector *connector_cfg);
[Severity: Low]
This isn't a bug, but the kernel-doc comment above vkms_connector_init() in
drivers/gpu/drm/vkms/vkms_connector.h is missing the description for the newly
added connector_cfg parameter.
It appears this remains undocumented even in the subsequent patch that
renames the function to vkms_connector_init_static().
Should an @connector_cfg: entry be added to the kernel-doc to prevent build
warnings when compiling with W=1?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=27
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 28/38] drm/vkms: Introduce configfs for connector type
2026-06-27 3:30 ` [PATCH v5 28/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:45 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:45 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The configfs show method `connector_type_show` does not append a newline character to its output.
--
commit fa7352c404d21d848225a9615b7a1039d2636d9c
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce configfs for connector type
This commit adds a new configfs attribute to allow configuring the connector
type in VKMS. It updates both the configfs interface and the corresponding
documentation.
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index 95f4594fb683d..8b414f1950e8e 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
[ ... ]
> @@ -1117,10 +1117,75 @@ static ssize_t connector_status_store(struct config_item *item,
> return (ssize_t)count;
> }
>
> +static ssize_t connector_type_show(struct config_item *item, char *page)
> +{
> + struct vkms_configfs_connector *connector;
> + int type;
> +
> + connector = connector_item_to_vkms_configfs_connector(item);
> +
> + scoped_guard(mutex, &connector->dev->lock) {
> + type = vkms_config_connector_get_type(connector->config);
> + }
> +
> + return sprintf(page, "%u", type);
[Severity: Low]
Does this output need a trailing newline? Configfs attributes typically
include a newline (e.g., "%u\n") to ensure the output is formatted properly
when read from userspace using command-line tools like cat.
> +}
> +
> +static ssize_t connector_type_store(struct config_item *item,
> + const char *page, size_t count)
> +{
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=28
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 21/38] drm/vkms: Introduce configfs for plane color range
2026-06-27 3:30 ` [PATCH v5 21/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:45 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:45 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] ConfigFS store callbacks enforce base 10 parsing, which rejects documented hexadecimal bitmask inputs.
- [Low] kstrtouint() is called with an 'int *' instead of 'unsigned int *', generating an incompatible pointer type warning.
- [Low] ConfigFS 'show' callbacks omit a trailing newline.
--
commit 75e6ca29907842441c00bd1bce2c7956d8a33c79
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce configfs for plane color range
To allows the userspace to test many hardware configuration, introduce a
new interface to configure the available color ranges per planes. VKMS
supports multiple color ranges, so the userspace can choose any
combination.
> diff --git a/Documentation/ABI/testing/configfs-vkms b/Documentation/ABI/testing/configfs-vkms
> index a9ee05fe0c66a..ef0c3da6b3ca1 100644
> --- a/Documentation/ABI/testing/configfs-vkms
> +++ b/Documentation/ABI/testing/configfs-vkms
[ ... ]
> @@ -132,6 +132,21 @@ Description:
> Default color encoding presented to userspace, same
> values as supported_color_encoding.
>
> +What: /sys/kernel/config/vkms/<device>/planes/<plane>/supported_color_ranges
> +Date: Nov 2025
> +Contact: dri-devel@lists.freedesktop.org
> +Description:
> + Available color ranges for the plane, as a bitmask:
> + 0x1 - DRM_COLOR_YCBCR_LIMITED_RANGE,
> + 0x2 - DRM_COLOR_YCBCR_FULL_RANGE.
> +
> +What: /sys/kernel/config/vkms/<device>/planes/<plane>/default_color_range
> +Date: Nov 2025
> +Contact: dri-devel@lists.freedesktop.org
> +Description:
> + Default color range presented to userspace, same
> + values as supported_color_ranges.
> +
[ ... ]
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index c1d1841b2c5a5..56a0c542a143f 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
[ ... ]
> @@ -410,6 +417,85 @@ static ssize_t plane_default_rotation_store(struct config_item *item,
> return count;
> }
>
> +static ssize_t plane_supported_color_ranges_show(struct config_item *item, char *page)
> +{
> + struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
> + unsigned int supported_color_ranges;
> +
> + scoped_guard(mutex, &plane->dev->lock)
> + supported_color_ranges = vkms_config_plane_get_supported_color_ranges(plane->config);
> +
> + return sprintf(page, "%u", supported_color_ranges);
[Severity: Low]
Does this configfs show callback omit a trailing newline? Usually, configfs
attributes include a newline in their format string for better readability
with standard userspace tools.
> +}
> +
> +static ssize_t plane_supported_color_ranges_store(struct config_item *item,
> + const char *page, size_t count)
> +{
> + struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
> + int ret, val = 0;
> +
> + ret = kstrtouint(page, 10, &val);
[Severity: Low]
Is this passing an int pointer to kstrtouint() instead of an unsigned int
pointer? Will this mismatch generate a compiler warning about incompatible
pointer types in plane_supported_color_ranges_store()?
[Severity: Medium]
Will this base 10 parsing reject the hexadecimal values documented in the ABI?
The documentation above suggests inputs like 0x1 and 0x2, but using base 10
here will cause kstrtouint() to reject strings prefixed with 0x. Should this
use base 0 instead?
> + if (ret)
> + return ret;
> +
> + /* Should be a supported value */
> + if (val & ~VKMS_SUPPORTED_COLOR_RANGES)
> + return -EINVAL;
> + /* Should at least provide one color range */
> + if ((val & VKMS_SUPPORTED_COLOR_RANGES) == 0)
> + return -EINVAL;
> +
> + scoped_guard(mutex, &plane->dev->lock) {
> + if (plane->dev->enabled)
> + return -EBUSY;
> +
> + vkms_config_plane_set_supported_color_ranges(plane->config, val);
> + }
> +
> + return count;
> +}
> +
> +static ssize_t plane_default_color_range_show(struct config_item *item, char *page)
> +{
> + struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
> + unsigned int default_color_range;
> +
> + scoped_guard(mutex, &plane->dev->lock)
> + default_color_range = vkms_config_plane_get_default_color_range(plane->config);
> +
> + return sprintf(page, "%lu", BIT(default_color_range));
[Severity: Low]
Is it missing a newline character here as well?
> +}
> +
> +static ssize_t plane_default_color_range_store(struct config_item *item,
> + const char *page, size_t count)
> +{
> + struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
> + int ret, val = 0;
> +
> + ret = kstrtouint(page, 10, &val);
[Severity: Low]
Does this code have the same pointer type mismatch issue as above in
plane_default_color_range_store(), passing an int pointer to a function
expecting an unsigned int pointer?
[Severity: Medium]
Also, does this base 10 parsing conflict with the hexadecimal inputs shown in
the ABI documentation?
> + if (ret)
> + return ret;
> +
> + /* Should be a supported value */
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=21
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 38/38] drm/vkms: Add ConfigFS interface for connector parent and port_id
2026-06-27 3:30 ` [PATCH v5 38/38] drm/vkms: Add ConfigFS interface for connector parent and port_id Louis Chauvet
@ 2026-06-27 3:45 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:45 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The function `connector_parent_connector_allow_link` returns an uninitialized variable `ret` on success, which can cause state desynchronization and a Use-After-Free vulnerability.
--
commit bf8b7f51f1321ae67ea645909d25e75e04da5354
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Add ConfigFS interface for connector parent and port_id
This commit adds configuration interfaces for a connector's parent and port_id
using configfs. It allows port_id to hold any u8 value and permits the parent
to contain at most one symlink to another connector.
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index dd2a9e450150b..4f4ec99448042 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
[ ... ]
> @@ -1512,6 +1555,63 @@ static const struct config_item_type connector_possible_encoders_group_type = {
> .ct_owner = THIS_MODULE,
> };
>
> +static int connector_parent_connector_allow_link(struct config_item *src,
> + struct config_item *target)
> +{
> + struct vkms_configfs_connector *connector;
> + struct vkms_config_connector *connector_cfg;
> + struct vkms_configfs_connector *parent;
> + struct vkms_config_connector *parent_cfg;
> + int ret;
> +
> + if (target->ci_type != &connector_item_type)
> + return -EINVAL;
> +
> + connector = connector_parent_item_to_vkms_configfs_connector(src);
> + connector_cfg = connector->config;
> + parent = connector_item_to_vkms_configfs_connector(target);
> + parent_cfg = parent->config;
> +
> + if (connector->dev != parent->dev)
> + return -EINVAL;
> +
> + scoped_guard(mutex, &connector->dev->lock) {
> + if (vkms_config_connector_get_parent(connector_cfg))
> + return -EMLINK;
> +
> + if (connector->dev->enabled && connector_cfg->enabled)
> + return -EBUSY;
> +
> + vkms_config_connector_attach_parent(connector_cfg,
> + parent_cfg);
> + }
> +
> + return ret;
[Severity: High]
Could this return an uninitialized value on the success path?
In connector_parent_connector_allow_link(), ret is declared but never
initialized before being returned at the end of the function.
If ret happens to contain a non-zero value from the stack, configfs will
treat the link creation as a failure and abort creating the symlink.
However, the internal VKMS state has already been modified to point to the
target connector via vkms_config_connector_attach_parent().
If the user subsequently removes the target connector using rmdir, does
this leave a dangling pointer in the VKMS configuration that could result
in a use-after-free later on?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=38
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 22/38] drm/vkms: Introduce config for plane format
2026-06-27 3:30 ` [PATCH v5 22/38] drm/vkms: Introduce config for plane format Louis Chauvet
@ 2026-06-27 3:46 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:46 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Format string vulnerability when initializing planes due to user-controlled plane name.
- [Medium] vkms_config_is_valid() does not verify that a plane has at least one supported format.
- [Medium] Leaked plane configuration on configfs directory creation failure causes permanent device validation failure.
--
commit c410d8e3fb25dbafdefe89a122662119e6e4c5a1
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce config for plane format
VKMS driver supports all the pixel formats for planes, but for testing it
can be useful to only advertise few of them. This new configuration
interface will allow configuring the pixel format per planes.
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index 5538716467617..c7de3e3073674 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
[ ... ]
> @@ -658,6 +712,80 @@ static struct vkms_config_plane *vkms_config_crtc_get_plane(const struct vkms_co
> return NULL;
> }
>
> +int __must_check vkms_config_plane_add_all_formats(struct vkms_config_plane *plane_cfg)
> +{
[ ... ]
> +void vkms_config_plane_remove_all_formats(struct vkms_config_plane *plane_cfg)
> +{
> + plane_cfg->supported_formats_count = 0;
> + kfree(plane_cfg->supported_formats);
> + plane_cfg->supported_formats = NULL;
> +}
[Severity: Medium]
Since we can now remove all formats, shouldn't vkms_config_is_valid() verify
that a plane has at least one supported format?
If a plane has 0 supported formats, drm_universal_plane_init() will trigger a
WARN_ON and fail the initialization when the device is enabled.
> diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
> index d4ccf418198e8..6e767cdf81942 100644
> --- a/drivers/gpu/drm/vkms/vkms_plane.c
> +++ b/drivers/gpu/drm/vkms/vkms_plane.c
[ ... ]
> @@ -227,7 +191,8 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
>
> plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 0,
> &vkms_plane_funcs,
> - vkms_formats, ARRAY_SIZE(vkms_formats),
> + vkms_config_plane_get_supported_formats(plane_cfg),
> + vkms_config_plane_get_supported_formats_count(plane_cfg),
> NULL, vkms_config_plane_get_type(plane_cfg),
> vkms_config_plane_get_name(plane_cfg));
[Severity: High]
Does this code introduce a format string vulnerability?
The user-controlled plane name is passed directly as the format string
argument to drmm_universal_plane_alloc() without a "%s" format specifier.
If userspace passes a name containing format specifiers (e.g. "%s%x"),
this could cause an out-of-bounds memory read or kernel crash when
kvasprintf() is called.
While reviewing these changes, I noticed a related issue in make_plane_group()
in drivers/gpu/drm/vkms/vkms_configfs.c:
drivers/gpu/drm/vkms/vkms_configfs.c:make_plane_group()
[ ... ]
ret = vkms_config_plane_set_name(plane->config, name, strlen(name));
if (ret) {
kfree(plane);
return ERR_PTR(ret);
}
[ ... ]
[Severity: Medium]
Does this error path leak the plane configuration?
If setting the plane name fails, the configfs object plane is freed but it
fails to call vkms_config_destroy_plane(plane->config). This leaves the
unusable configuration object permanently attached to the device list,
causing vkms_config_is_valid() to unconditionally fail later.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=22
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 13/38] drm/vkms: Introduce config for plane name
2026-06-27 3:30 ` [PATCH v5 13/38] drm/vkms: Introduce config for plane name Louis Chauvet
@ 2026-06-27 3:46 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:46 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The user-configurable plane name is passed directly as a format string to `drmm_universal_plane_alloc()`, leading to a format string injection vulnerability.
- [Medium] `drm_get_rotation_name` incorrectly expects an array index rather than a rotation bitmask, causing it to return wrong strings for valid rotation masks.
--
commit ecb2a628cbf8a89c520eb57344c9fb30aaf1876c
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce config for plane name
This commit introduces a configuration option for setting a plane's name in
the VKMS driver using ConfigFS.
> diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
> index 68cb2a3335e64..f351202031244 100644
> --- a/drivers/gpu/drm/vkms/vkms_plane.c
> +++ b/drivers/gpu/drm/vkms/vkms_plane.c
[ ... ]
> @@ -228,7 +229,7 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
> &vkms_plane_funcs,
> vkms_formats, ARRAY_SIZE(vkms_formats),
> NULL, vkms_config_plane_get_type(plane_cfg),
> - NULL);
> + vkms_config_plane_get_name(plane_cfg));
[Severity: High]
Can this cause a format string injection vulnerability?
Since the plane name is user-configurable via ConfigFS, a user could provide a
name containing format specifiers like "plane-%px". When this is passed directly
as the format string argument to drmm_universal_plane_alloc(), it could lead to
out-of-bounds memory reads or a kernel panic.
Should this be passed as "%s", vkms_config_plane_get_name(plane_cfg) instead?
> if (IS_ERR(plane))
> return plane;
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=13
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 17/38] drm/vkms: Introduce configfs for plane rotation
2026-06-27 3:30 ` [PATCH v5 17/38] drm/vkms: Introduce configfs for plane rotation Louis Chauvet
@ 2026-06-27 3:46 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:46 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] `plane_default_rotation_store()` uses base 10 for string parsing, incorrectly rejecting documented hexadecimal values.
--
commit 5edae796c7d28ebd799b4c01972a95ad90e32c05
Author: Louis Chauvet <louis.chauvet@bootlin.com>
Subject: drm/vkms: Introduce configfs for plane rotation
This commit introduces a new configfs interface to configure available and
default rotations per plane in VKMS. It adds supported_rotations and
default_rotation attributes, allowing userspace to select any combination of
rotations and reflections.
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index 0744ac40814d8..47b3a4aeee8dd 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
[ ... ]
> +static ssize_t plane_default_rotation_store(struct config_item *item,
> + const char *page, size_t count)
> +{
> + struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
> + int ret, val = 0;
> +
> + ret = kstrtouint(page, 10, &val);
[Severity: Medium]
Does this code incorrectly reject the documented hexadecimal values?
The ABI documentation specifies the rotation values as hex bitmasks (e.g.,
0x01, 0x10). While plane_supported_rotations_store() correctly uses base 0
for kstrtouint(), using base 10 here forces it to reject hexadecimal strings.
This breaks userspace tools or scripts attempting to write the documented
hexadecimal values to default_rotation, forcing them to use base-10 instead.
> + if (ret)
> + return ret;
> +
> + /* Should be a supported value */
> + if (val & ~(DRM_MODE_ROTATE_MASK | DRM_MODE_REFLECT_MASK))
> + return -EINVAL;
> +
> + /* Should contain exactly one rotation */
> + if (!is_power_of_2(val & DRM_MODE_ROTATE_MASK))
> + return -EINVAL;
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=17
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 26/38] drm/vkms: Introduce configfs for plane zpos property
2026-06-27 3:30 ` [PATCH v5 26/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:46 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:46 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [Critical] Heap buffer overflow in `vkms_crtc_atomic_check` due to array indexing with `normalized_zpos` exceeding allocated size based on visible planes.
- [High] Memory leak and ghost object creation in `make_plane_group` if `vkms_config_plane_set_name` fails.
- [High] Unaligned memory access when parsing fourcc formats in `plane_supported_formats_store`.
--
commit 05c48fc3bf3ce414a2c90cff7116e67058f16eb1
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce configfs for plane zpos property
This commit introduces configfs attributes for managing the zpos property
of VKMS planes. It adds attributes to configure whether zpos is enabled,
mutable, its initial value, and its min/max boundaries.
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index e6cb245b8582d..95f4594fb683d 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
> @@ -687,6 +687,176 @@ static ssize_t plane_supported_formats_store(struct config_item *item,
> return count;
> }
>
[Severity: High]
This isn't a bug introduced by this patch, but can this unaligned memory
access in plane_supported_formats_store() cause a kernel panic on strict
alignment architectures?
When userspace writes a new format string, the input is copied into a
4-byte char array on the stack, which is then cast to an int pointer and
dereferenced:
drivers/gpu/drm/vkms/vkms_configfs.c:plane_supported_formats_store() {
...
scoped_guard(mutex, &plane->dev->lock) {
char fmt[4] = {' ', ' ', ' ', ' '};
memcpy(fmt, &page[1], min(count - 1, 4));
...
else if (page[0] == '+')
ret = vkms_config_plane_add_format(plane->config, *(int *)fmt);
...
}
Since a char array only guarantees 1-byte alignment, the 32-bit dereference
can trigger an unaligned access exception.
[Severity: Critical]
This is a pre-existing issue, but does this array indexing overflow the
active_planes array in vkms_crtc_atomic_check()?
The active_planes array is allocated with a size equal to the number of
strictly visible planes:
drivers/gpu/drm/vkms/vkms_crtc.c:vkms_crtc_atomic_check() {
...
drm_for_each_plane_mask(plane, crtc->dev, crtc_state->plane_mask) {
plane_state = drm_atomic_get_new_plane_state(crtc_state->state, plane);
WARN_ON(!plane_state);
if (!plane_state->visible)
continue;
i++;
}
vkms_state->active_planes = kzalloc_objs(*vkms_state->active_planes, i);
...
However, the array is populated using normalized_zpos as the index:
...
drm_for_each_plane_mask(plane, crtc->dev, crtc_state->plane_mask) {
plane_state = drm_atomic_get_new_plane_state(crtc_state->state, plane);
if (!plane_state->visible)
continue;
// Order planes according to their normalized_zpos
// After drm_atomic_normalize_zpos, the possible values are 0..n_planes-1
// so store them using this index
vkms_state->active_planes[plane_state->normalized_zpos] =
to_vkms_plane_state(plane_state);
}
...
}
If a user configures some planes as invisible but gives a visible plane a
higher zpos than the invisible ones, drm_atomic_normalize_zpos() will assign
the visible plane a normalized_zpos value greater than or equal to the total
number of strictly visible planes, resulting in an out-of-bounds write.
[Severity: High]
This is a pre-existing issue, but does make_plane_group() leak the
internal vkms_config_plane object and create a ghost plane if setting
the name fails?
drivers/gpu/drm/vkms/vkms_configfs.c:make_plane_group() {
...
plane->config = vkms_config_create_plane(dev->config);
if (IS_ERR(plane->config)) {
ret = PTR_ERR(plane->config);
kfree(plane);
return ERR_PTR(ret);
}
ret = vkms_config_plane_set_name(plane->config, name, strlen(name));
if (ret) {
kfree(plane);
return ERR_PTR(ret);
}
...
}
If vkms_config_plane_set_name() returns an error, the configfs wrapper
is freed, but vkms_config_destroy_plane(plane->config) is not called.
The internal object remains in dev->config->planes. Because it will never
have a CRTC attached, vkms_config_is_valid() will always fail, permanently
preventing the device from being enabled.
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=26
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 34/38] drm/vkms: Store the enabled/disabled status for connector
2026-06-27 3:30 ` [PATCH v5 34/38] drm/vkms: Store the enabled/disabled status for connector Louis Chauvet
@ 2026-06-27 3:48 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:48 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] The iterator macros vkms_config_for_each_connector_static and vkms_config_for_each_connector_dynamic introduce a dangling else vulnerability.
- [Low] Kernel-doc comments for the new connector configuration functions contain copy-paste errors, and vkms_config_connector_is_dynamic lacks a const qualifier.
- [Low] The connector's enabled status is printed without a key in `vkms_config_show`, breaking the `key=value` format used for other properties.
--
commit 5e65d90ba630f2831298af2bffa8fd17ac0163ce
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Store the enabled/disabled status for connector
In order to prepare for dynamic connector configuration, we need to store
if a connector is dynamic and if it is enabled.
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index 1a110b8aa114d..98e40c6a2c5b6 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
[ ... ]
> @@ -597,6 +597,8 @@ static int vkms_config_show(struct seq_file *m, void *data)
>
> vkms_config_for_each_connector(vkmsdev->config, connector_cfg) {
> seq_puts(m, "connector:\n");
> + seq_printf(m, "\t%s\n",
> + str_enabled_disabled(vkms_config_connector_is_enabled(connector_cfg)));
[Severity: Low]
Does this break the key=value format used for other properties in debugfs?
Surrounding lines output a key, like "\tstatus=%s" or "\ttype=%s", but this
prints the status on a line by itself. Should this be "\tenabled=%s\n" to
maintain consistent formatting for programmatic parsing?
> seq_printf(m, "\tstatus=%s\n",
> drm_get_connector_status_name(vkms_config_connector_get_status(connector_cfg)));
[ ... ]
> diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
> index 7e361b6e45b0e..071887a65380a 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.h
> +++ b/drivers/gpu/drm/vkms/vkms_config.h
[ ... ]
> @@ -194,6 +198,24 @@ struct vkms_config_connector {
> #define vkms_config_for_each_connector(config, connector_cfg) \
> list_for_each_entry((connector_cfg), &(config)->connectors, link)
>
> +/**
> + * vkms_config_for_each_connector_static - Iterate over the static vkms_config connectors
> + * @config: &struct vkms_config pointer
> + * @connector_cfg: &struct vkms_config_connector pointer used as cursor
> + */
> +#define vkms_config_for_each_connector_static(config, connector_cfg) \
> + vkms_config_for_each_connector((config), (connector_cfg)) \
> + if (!(connector_cfg)->dynamic)
[Severity: Medium]
Could this macro definition lead to a dangling else vulnerability?
Because the trailing if statement is unbraced, any caller wrapping this
macro in an unbraced if/else block could have their else branch unexpectedly
hijacked by this macro's internal if condition.
> +
> +/**
> + * vkms_config_for_each_connector_dynamic - Iterate over the dynamic vkms_config connectors
> + * @config: &struct vkms_config pointer
> + * @connector_cfg: &struct vkms_config_connector pointer used as cursor
> + */
> +#define vkms_config_for_each_connector_dynamic(config, connector_cfg) \
> + vkms_config_for_each_connector((config), (connector_cfg)) \
> + if ((connector_cfg)->dynamic)
[Severity: Medium]
Similarly, this macro also ends in an unbraced if statement. Could this cause
the same latent control flow issue if used in an unbraced conditional block?
[ ... ]
> @@ -472,6 +494,50 @@ vkms_config_connector_set_type(struct vkms_config_connector *connector_cfg,
> connector_cfg->type = type;
> }
>
> +/**
> + * vkms_config_connector_set_enabled() - If the connector is part of the device
> + * @crtc_cfg: Target connector
> + * @enabled: Add or remove the connector
> + */
[Severity: Low]
This isn't a bug, but there's a typo in the parameter name. Should @crtc_cfg
be @connector_cfg to match the function signature?
> +static inline void
> +vkms_config_connector_set_enabled(struct vkms_config_connector *connector_cfg,
> + bool enabled)
> +{
> + connector_cfg->enabled = enabled;
> +}
[ ... ]
> +/**
> + * vkms_config_connector_set_dynamic() - If the connector is dynamic
> + * @crtc_cfg: Target connector
> + * @enabled: Enable or disable the dynamic status
> + */
[Severity: Low]
Are these parameter names correct? It looks like @crtc_cfg should be
@connector_cfg, and @enabled should be @dynamic.
> +static inline void
> +vkms_config_connector_set_dynamic(struct vkms_config_connector *connector_cfg,
> + bool dynamic)
> +{
> + connector_cfg->dynamic = dynamic;
> +}
> +
> +/**
> + * vkms_config_connector_is_enabled() - If the connector is dynamic
> + * @connector_cfg: The connector
> + */
[Severity: Low]
There's a typo in the function name documented here. Should it be
vkms_config_connector_is_dynamic()?
> +static inline bool
> +vkms_config_connector_is_dynamic(struct vkms_config_connector *connector_cfg)
[Severity: Low]
Is there a reason connector_cfg isn't const here, unlike in the similar
vkms_config_connector_is_enabled() function?
> +{
> + return connector_cfg->dynamic;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=34
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 32/38] drm/vkms: Introduce config for connector EDID
2026-06-27 3:30 ` [PATCH v5 32/38] drm/vkms: Introduce config for connector EDID Louis Chauvet
@ 2026-06-27 3:48 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:48 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Medium] The custom EDID buffer allocated in `vkms_config_connector_set_edid()` is never freed when the connector configuration is destroyed, leading to a memory leak.
- [Medium] Disabling EDID on a connector fails to clear the previously set EDID property from the DRM connector object.
- [Low] Pointer type mismatch when passing `&edid_len` to `vkms_config_connector_get_edid()`, which causes an incompatible-pointer-types warning.
- [Low] `vkms_config_connector_set_edid()` fails silently if memory allocation fails, providing no way for callers to handle the error.
--
commit 496ec62fb3c1660fbef4e163900774284133adaa
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce config for connector EDID
Allows configuration of EDID for each connector.
> diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
> index 80bbc13aad79b..7e361b6e45b0e 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.h
> +++ b/drivers/gpu/drm/vkms/vkms_config.h
[ ... ]
> @@ -274,6 +280,75 @@ vkms_config_connector_get_supported_colorspaces(const struct vkms_config_connect
[ ... ]
> +static inline void
> +vkms_config_connector_set_edid(struct vkms_config_connector *connector_cfg,
> + const u8 *edid, unsigned int len)
> +{
> + if (len) {
> + void *edid_tmp = krealloc(connector_cfg->edid, len, GFP_KERNEL);
[Severity: Medium]
Does this code leak the memory allocated for the EDID buffer?
The buffer is dynamically allocated here, but it doesn't appear to be freed
when the connector configuration is torn down in
vkms_config_destroy_connector(). This could cause a leak when userspace
creates and destroys dynamic connectors with EDID data via configfs.
[Severity: Low]
Should this function return an error code rather than void?
If the krealloc() allocation fails, it fails silently. Callers (like
userspace writing to the configfs attribute) will assume the operation
succeeded, leaving the connector with an inconsistent or outdated EDID.
> +
> + if (edid_tmp) {
> + connector_cfg->edid = edid_tmp;
> + memcpy(connector_cfg->edid, edid, len);
> + connector_cfg->edid_len = len;
> + }
> + } else {
> + kfree(connector_cfg->edid);
> + connector_cfg->edid = NULL;
> + connector_cfg->edid_len = len;
> + }
> +}
> +
[ ... ]
> diff --git a/drivers/gpu/drm/vkms/vkms_connector.c b/drivers/gpu/drm/vkms/vkms_connector.c
> index a1f08167def1d..fe42ab2ba7b10 100644
> --- a/drivers/gpu/drm/vkms/vkms_connector.c
> +++ b/drivers/gpu/drm/vkms/vkms_connector.c
> @@ -42,13 +42,55 @@ static const struct drm_connector_funcs vkms_connector_funcs = {
> .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> };
>
> +static int vkms_connector_read_block(void *context, u8 *buf, unsigned int block, size_t len)
> +{
> + struct vkms_config_connector *config = context;
> + unsigned int edid_len;
> + const u8 *edid = vkms_config_connector_get_edid(config, &edid_len);
[Severity: Low]
Does this cause a compiler warning about incompatible pointer types?
The variable edid_len is declared as unsigned int, but its address is passed
to vkms_config_connector_get_edid(), which expects an int pointer for its
length parameter.
> +
> + if (block * len + len > edid_len)
> + return 1;
> + memcpy(buf, &edid[block * len], len);
> + return 0;
> +}
> +
> static int vkms_conn_get_modes(struct drm_connector *connector)
> {
[ ... ]
> + /*
> + * Unconditionally update the connector. If the EDID was read
> + * successfully, fill in the connector information derived from the
> + * EDID. Otherwise, if the EDID is NULL, clear the connector
> + * information.
> + */
> + drm_edid_connector_update(connector, drm_edid);
> +
> + count = drm_edid_connector_add_modes(connector);
> +
> + drm_edid_free(drm_edid);
> + } else {
> + count = drm_add_modes_noedid(connector, XRES_MAX, YRES_MAX);
> + drm_set_preferred_mode(connector, XRES_DEF, YRES_DEF);
[Severity: Medium]
Should we call drm_edid_connector_update(connector, NULL) in this else branch?
If a connector is configured with EDID enabled, drm_edid_connector_update()
is called above to attach the property. If it is later dynamically changed
to disable EDID, this branch fails to clear the DRM connector object's EDID
property, which could leave stale EDID data exposed to userspace.
> + }
> + }
>
> return count;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=32
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 31/38] drm/vkms: Introduce configfs for connector supported colorspace
2026-06-27 3:30 ` [PATCH v5 31/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:48 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:48 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Missing validation for `supported_colorspaces` against connector types, leading to silent configuration failure.
- [Low] Passing an `int *` to `kstrtouint()` instead of an `unsigned int *`, and mismatched variable types for colorspaces.
--
commit 2994a2a64dd308b728cfd70f48204aeb77b66762
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce configfs for connector supported colorspace
Add the attribute supported_colorspaces to configure the supported
colorspace of a connector. It will allows emulating some HDR features of
displays. This feature is only supported for HDMI, DP and eDP connectors.
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index 8b414f1950e8e..e1f6e7817f972 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
[ ... ]
> @@ -1180,12 +1180,52 @@ static ssize_t connector_type_store(struct config_item *item,
> return count;
> }
>
> +static ssize_t connector_supported_colorspaces_show(struct config_item *item, char *page)
> +{
> + struct vkms_configfs_connector *connector;
> + int colorspaces;
> +
> + connector = connector_item_to_vkms_configfs_connector(item);
> +
> + scoped_guard(mutex, &connector->dev->lock)
> + colorspaces = vkms_config_connector_get_supported_colorspaces(connector->config);
[Severity: Low]
Does this code assign a u32 value to a signed int?
vkms_config_connector_get_supported_colorspaces() returns a u32, but
colorspaces is declared as an int.
> +
> + return sprintf(page, "%u", colorspaces);
> +}
> +
> +static ssize_t connector_supported_colorspaces_store(struct config_item *item,
> + const char *page, size_t count)
> +{
> + struct vkms_configfs_connector *connector;
> + int val, ret;
> +
> + connector = connector_item_to_vkms_configfs_connector(item);
> +
> + ret = kstrtouint(page, 10, &val);
[Severity: Low]
Does this code pass an int pointer to an API expecting an unsigned int pointer?
kstrtouint() expects an unsigned int * for its third argument, but val is
declared as an int.
> + if (ret)
> + return ret;
> +
> + if ((val & -BIT(DRM_MODE_COLORIMETRY_COUNT)) != 0)
> + return -EINVAL;
> +
> + scoped_guard(mutex, &connector->dev->lock) {
> + if (connector->dev->enabled)
> + return -EBUSY;
> +
> + vkms_config_connector_set_supported_colorspaces(connector->config, val);
[Severity: Medium]
Since this feature is only supported for HDMI, DP, and eDP connectors, is
there any validation that prevents users from configuring this on unsupported
connector types?
If users configure this attribute on an unsupported connector (like the default
VIRTUAL type), it appears it will be accepted here but silently ignored later
when the device is initialized.
Would it make sense to reject unsupported configurations in
vkms_config_is_valid() or similar validation logic to prevent misleading
userspace?
> + }
> +
> + return count;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=31
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 19/38] drm/vkms: Introduce configfs for plane color encoding
2026-06-27 3:30 ` [PATCH v5 19/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:49 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:49 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] Rejecting a value of 0 prevents testing planes without color encodings.
- [Low] Passing an `int *` to a function expecting `unsigned int *` causes an incompatible-pointer-types compiler warning.
- [Low] Double assignment typo in variable declaration.
--
commit 14a18de4798714722e237eb41b51bd75e7c7cd56
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce configfs for plane color encoding
This patch introduces a configfs interface to configure the supported and
default color encodings for VKMS planes. It allows userspace to test different
hardware configurations regarding color encoding bitmasks.
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index 47b3a4aeee8dd..c1d1841b2c5a5 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
[ ... ]
> @@ -402,14 +410,98 @@ static ssize_t plane_default_rotation_store(struct config_item *item,
> return count;
> }
>
> +static ssize_t plane_supported_color_encodings_show(struct config_item *item, char *page)
> +{
> + struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
> + unsigned int supported_color_encodings;
> +
> + scoped_guard(mutex, &plane->dev->lock)
> + supported_color_encodings = vkms_config_plane_get_supported_color_encodings(plane->config);
> +
> + return sprintf(page, "%u", supported_color_encodings);
> +}
> +
> +static ssize_t plane_supported_color_encodings_store(struct config_item *item,
> + const char *page, size_t count)
> +{
> + struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
> + int ret, val = 0;
> +
> + ret = kstrtouint(page, 10, &val);
[Severity: Low]
Does this pass an int pointer to kstrtouint() instead of an unsigned int
pointer? This might trigger an incompatible-pointer-types compiler warning.
> + if (ret)
> + return ret;
> +
> + /* Should be a supported value */
> + if (val & ~(VKMS_SUPPORTED_COLOR_ENCODINGS))
> + return -EINVAL;
> + /* Should at least provide one color encoding */
> + if ((val & (VKMS_SUPPORTED_COLOR_ENCODINGS)) == 0)
> + return -EINVAL;
[Severity: Medium]
Does rejecting 0 here prevent userspace from configuring a VKMS plane without
color encodings?
It looks like the VKMS configuration API and kunit tests support a value of 0 to
emulate an RGB-only plane. Blocking 0 here might unnecessarily limit the hardware
configurations that can be tested.
> +
> + scoped_guard(mutex, &plane->dev->lock) {
> + if (plane->dev->enabled)
> + return -EBUSY;
> +
> + vkms_config_plane_set_supported_color_encodings(plane->config, val);
> + }
> +
> + return count;
> +}
> +
> +static ssize_t plane_default_color_encoding_show(struct config_item *item, char *page)
> +{
> + struct vkms_configfs_plane *plane = plane = plane_item_to_vkms_configfs_plane(item);
[Severity: Low]
This isn't a bug, but there is an accidental double assignment to the plane
variable here.
> + unsigned int default_color_encoding;
> +
> + scoped_guard(mutex, &plane->dev->lock)
> + default_color_encoding = BIT(vkms_config_plane_get_default_color_encoding(plane->config));
> +
> + return sprintf(page, "%u", default_color_encoding);
> +}
> +
> +static ssize_t plane_default_color_encoding_store(struct config_item *item,
> + const char *page, size_t count)
> +{
> + struct vkms_configfs_plane *plane = plane_item_to_vkms_configfs_plane(item);
> + int ret, val = 0;
> +
> + ret = kstrtouint(page, 10, &val);
[Severity: Low]
Similar to plane_supported_color_encodings_store(), does this pass an int
pointer to kstrtouint() instead of an unsigned int pointer?
> + if (ret)
> + return ret;
> +
> + /* Should be a supported value */
> + if (val & ~VKMS_SUPPORTED_COLOR_ENCODINGS)
> + return -EINVAL;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=19
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 33/38] drm/vkms: Introduce configfs for connector EDID
2026-06-27 3:30 ` [PATCH v5 33/38] drm/vkms: Introduce configfs " Louis Chauvet
@ 2026-06-27 3:50 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:50 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] Concurrent update of the EDID blob via ConfigFS and reading via DRM ioctls leads to a Use-After-Free.
- [Medium] The dynamically allocated `connector_cfg->edid` buffer is never freed when a connector configuration is destroyed, leading to a memory leak.
- [Medium] Memory allocation failure when storing an EDID is silently ignored, returning success to userspace and falsely triggering a hotplug event.
- [Medium] Toggling `edid_enabled` at runtime via ConfigFS is broken in both directions and fails to correctly synchronize with the KMS EDID property.
- [Medium] Using a standard ConfigFS string attribute for binary EDID data causes valid 4096-byte EDIDs to be truncated.
- [Medium] Calling `memcpy` with a potentially `NULL` source pointer in `connector_edid_show` triggers undefined behavior.
- [Low] Passing `unsigned int *` to a function expecting `int *` causes an incompatible pointer type compiler warning/error.
--
commit e55896ded21ff0567eff633eae34bfa27b5899cf
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce configfs for connector EDID
This commit introduces new attributes in configfs to configure the EDID
of a vkms connector. It adds edid_enable and edid attributes.
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index e1f6e7817f972..f79a796c2017f 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
[ ... ]
> @@ -1218,14 +1218,94 @@ static ssize_t connector_supported_colorspaces_store(struct config_item *item,
[ ... ]
> +static ssize_t connector_edid_show(struct config_item *item, char *page)
> +{
> + struct vkms_configfs_connector *connector;
> +
> + connector = connector_item_to_vkms_configfs_connector(item);
> +
> + scoped_guard(mutex, &connector->dev->lock)
> + {
> + unsigned int len = 0;
> + const u8 *edid = vkms_config_connector_get_edid(connector->config, &len);
[Severity: Low]
Does this trigger an incompatible-pointer-types warning during the build?
The vkms_config_connector_get_edid() function expects an int pointer for
the length, but we are passing an unsigned int pointer here.
> +
> + memcpy(page, edid, min(len, PAGE_SIZE));
[Severity: Medium]
Could this trigger undefined behavior and a UBSAN warning if edid is not set?
If len is 0, vkms_config_connector_get_edid() returns a NULL pointer, causing
us to call memcpy(page, NULL, 0) unconditionally.
> + return min(len, PAGE_SIZE);
> + }
> +
> + return -EINVAL;
> +}
> +
> +static ssize_t connector_edid_store(struct config_item *item,
> + const char *page, size_t count)
> +{
> + struct vkms_configfs_connector *connector;
> +
> + connector = connector_item_to_vkms_configfs_connector(item);
> +
> + scoped_guard(mutex, &connector->dev->lock)
> + {
> + vkms_config_connector_set_edid(connector->config, page, count);
[Severity: Medium]
Does this code assume the set operation always succeeds?
Looking at vkms_config_connector_set_edid() in vkms_config.h, it uses
krealloc() to allocate memory for the EDID but returns void. If the
allocation fails, the old EDID remains unmodified and no error is returned.
This caller then assumes success, returns the written count to userspace,
and falsely triggers a hotplug event below even if the system was out of
memory.
[Severity: High]
Can writing to this attribute cause a use-after-free during concurrent DRM
ioctl reads?
When vkms_config_connector_set_edid() is called here, it holds the
connector->dev->lock. Inside that function, krealloc() frees the old
edid pointer.
However, the DRM read path in vkms_connector_read_block() accesses the EDID
locklessly. If thread A writes a new EDID to configfs, thread B executing
a DRM_IOCTL_MODE_GETCONNECTOR ioctl might dereference the freed pointer while
copying.
> +
> + if (connector->dev->enabled &&
> + vkms_config_connector_get_status(connector->config) !=
> + connector_status_disconnected)
> + vkms_trigger_connector_hotplug(connector->dev->config->dev);
> + }
> +
> + return count;
> +}
> +
> CONFIGFS_ATTR(connector_, status);
> CONFIGFS_ATTR(connector_, type);
> CONFIGFS_ATTR(connector_, supported_colorspaces);
> +CONFIGFS_ATTR(connector_, edid_enabled);
> +CONFIGFS_ATTR(connector_, edid);
[Severity: Medium]
Will this string attribute truncate valid 4096-byte EDID payloads?
Since this is defined as a standard CONFIGFS_ATTR rather than a binary
attribute (CONFIGFS_BIN_ATTR), configfs reserves one byte for the null
terminator. A user writing exactly 4096 bytes (a valid 32-block EDID)
would have their write truncated to 4095 bytes.
> diff --git a/drivers/gpu/drm/vkms/vkms_connector.c b/drivers/gpu/drm/vkms/vkms_connector.c
> index fe42ab2ba7b10..f726c79955240 100644
> --- a/drivers/gpu/drm/vkms/vkms_connector.c
> +++ b/drivers/gpu/drm/vkms/vkms_connector.c
> @@ -175,6 +175,9 @@ struct vkms_connector *vkms_connector_init_static(struct vkms_device *vkmsdev,
>
> drm_connector_helper_add(&connector->base, &vkms_conn_helper_funcs);
>
> + if (vkms_config_connector_get_edid_enabled(connector_cfg))
> + drm_connector_attach_edid_property(&connector->base);
> +
[Severity: Medium]
Is toggling the edid_enabled attribute at runtime broken?
This code only conditionally attaches the property at initialization. If
edid_enabled is false at init, the property is never attached, so changing
it to true later via configfs will fail to expose the EDID.
Conversely, if it is toggled to false at runtime, vkms_conn_get_modes()
fails to call drm_edid_connector_update(connector, NULL). This results in
the DRM core continuing to serve the stale EDID data to userspace.
One additional question about the EDID memory lifecycle:
[Severity: Medium]
Does this change introduce a memory leak when a connector is destroyed?
The dynamically allocated connector_cfg->edid buffer does not appear to be
freed when a connector configuration directory is removed. When configfs
tears down the item, vkms_config_destroy_connector() in vkms_config.c
frees the connector_cfg struct, but it doesn't free the edid field.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=33
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 35/38] drm/vkms: Allow to hot-add connectors
2026-06-27 3:30 ` [PATCH v5 35/38] drm/vkms: Allow to hot-add connectors Louis Chauvet
@ 2026-06-27 3:50 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:50 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Incorrect error check for kzalloc_obj() return value causes NULL pointer dereference.
- [High] Using __free(kfree) on a dynamically initialized DRM connector bypasses necessary DRM core cleanup on error paths, causing UAF.
- [High] Calling drm_mode_config_reset() during dynamic hot-remove and attach blindly destroys the active atomic state of all display objects on the device.
- [High] Unconditional destruction of a potentially NULL colorspace property in the error path of vkms_connector_hot_add().
- [Medium] The dynamically allocated colorspace_property is permanently leaked when a connector is destroyed.
--
commit 5cfc3cee3faffdbe590e3944a8bf682376206e74
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Allow to hot-add connectors
This commit adds the necessary infrastructure in vkms_connector to allow
creating dynamic connectors. It implements hot-add, hot-remove, and
hot-attach functionality for the vkms device.
> diff --git a/drivers/gpu/drm/vkms/vkms_connector.c b/drivers/gpu/drm/vkms/vkms_connector.c
> --- a/drivers/gpu/drm/vkms/vkms_connector.c
> +++ b/drivers/gpu/drm/vkms/vkms_connector.c
[ ... ]
> @@ -181,9 +181,98 @@ struct vkms_connector *vkms_connector_init_static(struct vkms_device *vkmsdev,
> return connector;
> }
>
> +static void vkms_connector_dynamic_destroy(struct drm_connector *connector)
> +{
> + struct vkms_connector *vkms_connector;
> +
> + drm_connector_cleanup(connector);
> +
> + vkms_connector = drm_connector_to_vkms_connector(connector);
> + kfree(vkms_connector);
> +}
[Severity: Medium]
Is the dynamically allocated colorspace property leaked here?
vkms_connector_init() creates this property via
drm_mode_create_hdmi_colorspace_property(), but it doesn't seem to be
destroyed with drm_property_destroy() before kfree() is called on the
connector.
[ ... ]
> +struct vkms_connector *vkms_connector_hot_add(struct vkms_device *vkmsdev,
> + struct vkms_config_connector *connector_cfg)
> +{
> + struct vkms_config_encoder *encoder_cfg;
> + struct vkms_connector __free(kfree) * connector = NULL;
[Severity: High]
Will this __free(kfree) cleanup create a use-after-free if the function
returns early after drm_connector_dynamic_init() succeeds?
If drm_connector_dynamic_init() partially registers the connector, returning
early and triggering just kfree() bypasses drm_connector_cleanup() and leaves
a dangling pointer in the DRM core.
> + int ret;
> + unsigned long idx = 0;
> +
> + connector = kzalloc_obj(*connector, GFP_KERNEL);
> + if (IS_ERR(connector))
[Severity: High]
Since kzalloc_obj() returns NULL on memory allocation failure, will this
IS_ERR() check fail to catch an allocation failure?
This looks like it would pass a NULL pointer to drm_connector_dynamic_init().
> + return connector;
> + ret = drm_connector_dynamic_init(&vkmsdev->drm,
[ ... ]
> + ret = drm_connector_dynamic_register(&connector->base);
> + if (ret) {
> + if (connector_cfg->type == DRM_MODE_CONNECTOR_HDMIA ||
> + connector_cfg->type == DRM_MODE_CONNECTOR_DisplayPort ||
> + connector_cfg->type == DRM_MODE_CONNECTOR_eDP) {
> + drm_property_destroy(connector->base.dev,
> + connector->base.colorspace_property);
> + }
[Severity: High]
Could this unconditionally dereference a NULL property pointer?
If vkms_config_connector_get_supported_colorspaces() returns zero in
vkms_connector_init(), the colorspace_property pointer remains NULL.
Calling drm_property_destroy() on a NULL property leads to a dereference when
it accesses the enum_list.
> + return ERR_PTR(ret);
> + }
> +
> + return_ptr(connector);
> +}
> +
> +void vkms_connector_hot_remove(struct vkms_device *vkmsdev,
> + struct vkms_connector *connector)
> +{
> + drm_connector_unregister(&connector->base);
> + drm_mode_config_reset(&vkmsdev->drm);
> + drm_connector_put(&connector->base);
> +}
> +
> +int vkms_connector_hot_attach_encoder(struct vkms_device *vkmsdev,
> + struct vkms_connector *connector,
> + struct drm_encoder *encoder)
> +{
> + int ret;
> +
> + ret = drm_connector_attach_encoder(&connector->base, encoder);
> + if (ret)
> + return ret;
> +
> + drm_mode_config_reset(&vkmsdev->drm);
[Severity: High]
Is it safe to call drm_mode_config_reset() during runtime hotplug events?
This iterates over every display object and unconditionally frees and
reallocates their active atomic state without holding modeset locks. Doing
this while the system is actively driving displays looks like it would corrupt
the global KMS state machine.
> +
> + return ret;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=35
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 36/38] drm/vkms: Introduce configfs for dynamic connector creation
2026-06-27 3:30 ` [PATCH v5 36/38] drm/vkms: Introduce configfs for dynamic connector creation Louis Chauvet
@ 2026-06-27 3:55 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:55 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 10 potential issue(s) to consider:
New issues:
- [Critical] Calling drm_mode_config_reset() dynamically at runtime destroys active atomic states, leading to Use-After-Free.
- [High] Mixing goto-based error handling with scoped_guard causes a data race on rollback.
- [High] Removing a connector via rmdir bypasses validation checks, leaving the device in an invalid state.
- [High] Uncaught NULL pointer dereference due to incorrect IS_ERR() check on memory allocations.
- [High] Using __free(kfree) on a dynamically initialized DRM connector causes memory leaks and list corruption.
- [High] Dangling pointer in connector_cfg->connector causes state corruption via aliasing.
- [Medium] Missing rollback when configfs internal allocation fails after hot-attaching an encoder.
- [Medium] Dropping a symlink for an active dynamic connector removes the encoder from ConfigFS but fails to detach it from the live DRM connector.
Pre-existing issues:
- [High] Userspace can rmdir static connectors while the DRM device is activated, causing use-after-free.
- [High] Lockless iteration over vkmsdev->config->connectors races with configfs item removal.
--
commit fa75c62308f0301b4607b37a03a00f5ce157f6a0
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce configfs for dynamic connector creation
This commit adds two configfs attributes to connectors to allow emulating
dynamic connector creation after the device. The dynamic attribute marks a
connector as dynamic, and the enabled attribute can set it as present or not
at runtime.
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index f79a796c2017f..f92b172e75cf3 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
[ ... ]
> @@ -1290,6 +1296,107 @@ static ssize_t connector_edid_store(struct config_item *item,
[ ... ]
> + if (!was_enabled && enabled) {
> + // Adding the connector
> + connector_cfg->connector = vkms_connector_hot_add(connector->dev->config->dev,
> + connector_cfg);
[Severity: High]
Is it possible for vkms_connector_hot_add() to return a NULL pointer that gets
missed?
Looking at vkms_connector_hot_add() in drivers/gpu/drm/vkms/vkms_connector.c:
drivers/gpu/drm/vkms/vkms_connector.c:vkms_connector_hot_add() {
...
connector = kzalloc_obj(*connector, GFP_KERNEL);
if (IS_ERR(connector))
return connector;
...
}
kzalloc_obj() returns NULL on failure, but the IS_ERR() check evaluates to
false for NULL. The NULL pointer would then be immediately passed to
drm_connector_dynamic_init(), resulting in a kernel panic.
[Severity: High]
Does vkms_connector_hot_add() leak memory or corrupt lists on error?
In the same function:
drivers/gpu/drm/vkms/vkms_connector.c:vkms_connector_hot_add() {
struct vkms_connector __free(kfree) * connector = NULL;
...
}
If drm_connector_dynamic_init() succeeds, it registers the connector in core
DRM structures. If a subsequent initialization step fails, the function
returns an error, triggering the __free(kfree) cleanup.
The raw kfree() frees the memory without invoking drm_connector_cleanup() or
dropping references, leaving dangling pointers in the DRM core lists and
leaking internal property allocations.
> + if (IS_ERR(connector_cfg->connector)) {
> + count = PTR_ERR(connector_cfg->connector);
> + goto rollback;
> + }
> + } else if (was_enabled && !enabled) {
> + vkms_connector_hot_remove(connector->dev->config->dev,
> + connector_cfg->connector);
[Severity: High]
Does this leave a dangling pointer in connector_cfg->connector?
When a dynamic connector is disabled, vkms_connector_hot_remove() unregisters
and frees the DRM connector. However, connector_cfg->connector is not cleared.
Reusing memory for a new dynamic connector may result in the same pointer
address, and iteration logic that matches against it will match the dangling
pointer, corrupting connector configuration states.
[Severity: Critical]
Is it safe to call drm_mode_config_reset() dynamically at runtime?
Looking at vkms_connector_hot_remove() and vkms_connector_hot_attach_encoder():
drivers/gpu/drm/vkms/vkms_connector.c:vkms_connector_hot_remove() {
...
drm_mode_config_reset(&vkmsdev->drm);
...
}
This helper loops over all CRTCs, planes, and connectors, unconditionally
freeing their current active atomic states and allocating fresh empty states.
Executing this while userspace has an active modeset destroys the structures
currently in use without proper teardown or synchronization, leading to
use-after-free regressions.
> + }
> + }
> + }
> + return count;
> +
> +rollback:
> + vkms_config_connector_set_enabled(connector_cfg, was_enabled);
[Severity: High]
Can this modification on rollback race with concurrent accesses?
A goto rollback jumps out of the scoped_guard block, releasing the lock
implicitly:
drivers/gpu/drm/vkms/vkms_configfs.c:connector_enabled_store() {
scoped_guard(mutex, &connector->dev->lock) {
...
if (IS_ERR(connector_cfg->connector)) {
count = PTR_ERR(connector_cfg->connector);
goto rollback;
}
...
}
...
rollback:
vkms_config_connector_set_enabled(connector_cfg, was_enabled);
The rollback executes without the lock held. This violates the subsystem rule
against mixing goto and scope-based cleanup helpers.
[ ... ]
> @@ -1306,19 +1415,28 @@ static struct configfs_attribute *connector_item_attrs[] = {
[ ... ]
> static void connector_release(struct config_item *item)
> {
> struct vkms_configfs_connector *connector;
> + struct vkms_config_connector *connector_cfg;
> struct mutex *lock;
>
> connector = connector_item_to_vkms_configfs_connector(item);
> + connector_cfg = connector->config;
> lock = &connector->dev->lock;
>
> scoped_guard(mutex, lock) {
> + if (connector->dev->enabled && connector_cfg->dynamic && connector_cfg->enabled)
> + vkms_connector_hot_remove(connector->dev->config->dev,
> + connector_cfg->connector);
> +
[Severity: High]
Does this allow userspace to bypass topological validation?
Disabling a connector via the enabled sysfs attribute correctly checks
vkms_config_is_valid(). However, removing a dynamic connector entirely via
rmdir calls connector_release(), which performs vkms_connector_hot_remove()
unconditionally.
This bypasses validation checks (e.g., removing the only connected connector),
breaking the internal DRM configuration rules while the device is running.
> vkms_config_destroy_connector(connector->config);
> +
[Severity: High]
This is a pre-existing issue, but can userspace remove static connectors while
the DRM device is activated, causing a use-after-free?
Userspace can remove a static connector via rmdir while the DRM device is
fully enabled. connector_release() bypasses vkms_connector_hot_remove() for
static connectors and immediately destroys the configuration structure.
The active DRM device retains pointers to the destroyed configuration and will
dereference it.
[Severity: High]
This is a pre-existing issue, but does lockless iteration over connectors race
with configfs item removal?
When userspace invokes rmdir on a connector, connector_release() frees the
connector_cfg structure. Concurrently, functions like vkms_connector_detect()
and vkms_conn_get_modes() iterate over vkmsdev->config->connectors locklessly:
drivers/gpu/drm/vkms/vkms_connector.c:vkms_connector_detect() {
...
vkms_config_for_each_connector(vkmsdev->config, connector_cfg) {
if (connector_cfg->connector == vkms_connector)
status = vkms_config_connector_get_status(connector_cfg);
}
...
}
This lockless iteration traverses freed memory, causing a use-after-free
regression.
> kfree(connector);
> }
> }
> @@ -1337,6 +1455,7 @@ static int connector_possible_encoders_allow_link(struct config_item *src,
[ ... ]
> scoped_guard(mutex, &connector->dev->lock) {
> - if (connector->dev->enabled)
> - return -EBUSY;
> + if (connector->dev->enabled && connector_cfg->enabled) {
> + if (!connector_cfg->dynamic)
> + return -EBUSY;
> +
> + ret = vkms_connector_hot_attach_encoder(connector->dev->config->dev,
> + connector->config->connector,
> + encoder->config->encoder);
> + if (ret)
> + return ret;
> + }
>
> ret = vkms_config_connector_attach_encoder(connector->config,
> encoder->config);
> + if (ret)
> + return ret;
[Severity: Medium]
Is there a missing rollback if the internal configfs allocation fails?
vkms_connector_hot_attach_encoder() updates the live hardware state.
Immediately after, vkms_config_connector_attach_encoder() performs a memory
allocation to update the configfs state.
If this allocation fails, the error is returned without undoing the hardware
attachment, leaving the active DRM device out of sync with the configfs
representation.
[Severity: Medium]
Does dropping a symlink for an active dynamic connector fail to detach the
encoder from the live DRM connector?
Looking at the corresponding drop function:
drivers/gpu/drm/vkms/vkms_configfs.c:connector_possible_encoders_drop_link() {
...
scoped_guard(mutex, &connector->dev->lock) {
vkms_config_connector_detach_encoder(connector->config,
encoder->config);
}
}
It successfully removes the encoder from the internal configfs state, but if
the device is enabled, it fails to interact with the DRM core to actually
detach the encoder from the hardware state.
This creates a state divergence where configfs thinks the encoder is unlinked,
but DRM continues to use it.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=36
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 37/38] drm/vkms: Add connector parent configuration in vkms_config
2026-06-27 3:30 ` [PATCH v5 37/38] drm/vkms: Add connector parent configuration in vkms_config Louis Chauvet
@ 2026-06-27 3:57 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:57 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Error paths in `vkms_connector_hot_add()` free the connector via `__free(kfree)` without tearing down the DRM connector, causing a Use-After-Free and IDA leak.
- [Medium] The MST PATH property generation creates a malformed string and silently drops a valid port ID when the connector hierarchy depth exceeds 16.
- [Medium] Dynamic configuration of connector parent relationships results in inconsistent or stale DRM PATH properties.
--
commit 3d7cb6751094b4d573bbf296f74ba57a8170fe00
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Add connector parent configuration in vkms_config
This patch adds support for configuring the parent connector and port_id
in vkms_config to emulate MST connectors. It updates the PATH property
strings for nested MST configurations and manages dynamic connector
lifecycles.
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
> @@ -996,8 +996,16 @@ struct vkms_config_connector *vkms_config_create_connector(struct vkms_config *c
> }
> EXPORT_SYMBOL_IF_KUNIT(vkms_config_create_connector);
>
> -void vkms_config_destroy_connector(struct vkms_config_connector *connector_cfg)
> +void vkms_config_destroy_connector(struct vkms_config *config,
> + struct vkms_config_connector *connector_cfg)
> {
> + struct vkms_config_connector *connector_cfg_tmp;
> +
> + vkms_config_for_each_connector(config, connector_cfg_tmp) {
> + if (connector_cfg_tmp->parent == connector_cfg)
> + connector_cfg_tmp->parent = NULL;
> + }
> +
[Severity: Medium]
When dynamically destroying a parent connector, this unlinks it from the
child connectors, but doesn't it leave the active children with stale
DRM PATH properties pointing to destroyed DRM object IDs?
Also, if a child is dynamically added before its parent, the child's PATH
property is silently skipped in vkms_connector_build_path_property() due to
the missing root, and it appears it is never retroactively updated.
[ ... ]
> diff --git a/drivers/gpu/drm/vkms/vkms_connector.c b/drivers/gpu/drm/vkms/vkms_connector.c
> --- a/drivers/gpu/drm/vkms/vkms_connector.c
> +++ b/drivers/gpu/drm/vkms/vkms_connector.c
> @@ -8,6 +8,76 @@
> #include "vkms_config.h"
> #include "vkms_connector.h"
>
> +/**
> + * vkms_connector_build_path_property() - Build the PATH property string for MST connectors
[ ... ]
> + if (!root_cfg || !root_cfg->connector)
> + return;
> +
> + root_connector = root_cfg->connector;
> +
> + len = snprintf(path, sizeof(path), "mst:%d", root_connector->base.base.id);
> +
> + for (i = port_count - 2; i >= 0; i--) {
[Severity: Medium]
If the connector hierarchy exceeds 16 nodes, port_count will hit the
ARRAY_SIZE(port_ids) limit of 16. Does starting the loop at port_count - 2
(which evaluates to 14) accidentally skip the last recorded array element at
port_ids[15]?
Since the root node is not stored in the array when truncation occurs, it
seems this drops a valid intermediate node from the PATH property string.
> + int added = snprintf(path + len, sizeof(path) - len,
> + "-%u", port_ids[i]);
> + if (added < 0 || len + added >= sizeof(path))
> + return;
> + len += added;
> + }
> +
> + drm_connector_set_path_property(&connector->base, path);
> +}
[ ... ]
> @@ -240,6 +312,8 @@ struct vkms_connector *vkms_connector_hot_add(struct vkms_device *vkmsdev,
> if (ret)
> return ERR_PTR(ret);
[Severity: High]
Can this error path lead to a Use-After-Free and IDA leak?
The connector struct is allocated with __free(kfree). Earlier in this
function, drm_connector_dynamic_init() registers the connector base object
into the DRM mode object IDR and allocates IDAs.
If a subsequent step fails and we return ERR_PTR(ret) here, the __free(kfree)
attribute will directly free the connector memory without calling
drm_connector_cleanup(), leaving dangling pointers in the DRM IDR.
>
> + vkms_connector_build_path_property(connector, connector_cfg);
> +
> ret = drm_connector_dynamic_register(&connector->base);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=37
^ permalink raw reply [flat|nested] 65+ messages in thread
* Re: [PATCH v5 30/38] drm/vkms: Introduce config for connector supported colorspace
2026-06-27 3:30 ` [PATCH v5 30/38] drm/vkms: Introduce config for connector supported colorspace Louis Chauvet
@ 2026-06-27 3:58 ` sashiko-bot
0 siblings, 0 replies; 65+ messages in thread
From: sashiko-bot @ 2026-06-27 3:58 UTC (permalink / raw)
To: Louis Chauvet; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [Medium] Missing support for DRM_MODE_CONNECTOR_HDMIB in VKMS connector initialization.
Pre-existing issues:
- [High] Lockless iteration over configuration lists in debugfs allows concurrent Use-After-Free if configfs items are removed.
--
commit adab925d90477ebe9d202328861dc983f52ebccf
Author: Louis Chauvet <louis.chauvet@bootlin.com>
drm/vkms: Introduce config for connector supported colorspace
This commit introduces the ability to configure supported colorspaces
for HDMI, eDP, and DP connectors in VKMS to emulate HDR features.
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index c407aea0bc6a9..ea9bc5d06be67 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
[ ... ]
> @@ -600,6 +600,10 @@ static int vkms_config_show(struct seq_file *m, void *data)
> drm_get_connector_status_name(vkms_config_connector_get_status(connector_cfg)));
> seq_printf(m, "\ttype=%s\n",
> drm_get_connector_type_name(vkms_config_connector_get_type(connector_cfg)));
> + seq_puts(m, "\tsupported colorspaces=");
> + show_bitfield(m, vkms_config_connector_get_supported_colorspaces(connector_cfg),
> + drm_get_colorspace_name);
[Severity: High]
This is a pre-existing issue, but does this lockless iteration over the
connectors list in vkms_config_show() expose us to a use-after-free?
If userspace removes a connector via configfs concurrently,
vkms_config_destroy_connector() will free the connector_cfg without any locks
synchronizing with this debugfs read path. This patch adds additional reads
of the connector_cfg during this iteration.
> + seq_puts(m, "\n");
> }
>
> return 0;
[ ... ]
> diff --git a/drivers/gpu/drm/vkms/vkms_connector.c b/drivers/gpu/drm/vkms/vkms_connector.c
> index 5b29dcade7e19..a1f08167def1d 100644
> --- a/drivers/gpu/drm/vkms/vkms_connector.c
> +++ b/drivers/gpu/drm/vkms/vkms_connector.c
[ ... ]
> +static int __must_check vkms_connector_init(struct vkms_connector *connector,
> + struct vkms_config_connector *connector_cfg)
> +{
> + int ret = 0;
> +
> + if (vkms_config_connector_get_supported_colorspaces(connector_cfg)) {
> + if (connector_cfg->type == DRM_MODE_CONNECTOR_HDMIA) {
> + ret = drm_mode_create_hdmi_colorspace_property(&connector->base,
> + vkms_config_connector_get_supported_colorspaces(connector_cfg));
[Severity: Medium]
Does this logic inadvertently omit DRM_MODE_CONNECTOR_HDMIB?
If a user configures a connector as HDMIB with supported colorspaces via
configfs, it looks like the colorspace property will not be created or
attached since only HDMIA is checked during this initialization.
> + if (ret)
> + return ret;
> + } else if (connector_cfg->type == DRM_MODE_CONNECTOR_DisplayPort ||
> + connector_cfg->type == DRM_MODE_CONNECTOR_eDP) {
> + ret = drm_mode_create_dp_colorspace_property(&connector->base,
> + vkms_config_connector_get_supported_colorspaces(connector_cfg));
> + if (ret)
> + return ret;
> + }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260627-vkms-all-config-v5-0-854aa0840926@bootlin.com?part=30
^ permalink raw reply [flat|nested] 65+ messages in thread
end of thread, other threads:[~2026-06-27 3:58 UTC | newest]
Thread overview: 65+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-27 3:30 [PATCH v5 00/38] VKMS: Introduce multiple configFS attributes Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 01/38] drm/drm_mode_config: Add helper to get plane type name Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 02/38] drm/blend: Get a rotation name from it's bitfield Louis Chauvet
2026-06-27 3:41 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 03/38] drm/drm_color_mgmt: Expose drm_get_color_encoding_name Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 04/38] drm/drm_color_mgmt: Expose drm_get_color_range_name Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 05/38] drm/connector: Export drm_get_colorspace_name Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 06/38] drm/drm_atomic_state_helper: Properly load default value for rotation Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 07/38] Documentation: ABI: vkms: Add current VKMS ABI documentation Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 08/38] drm/vkms: Add error handling in plane config creation Louis Chauvet
2026-06-27 3:41 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 09/38] drm/vkms: Simplify plane_release code Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 10/38] drm/vkms: Explicitly display plane type Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 11/38] drm/vkms: Use enabled/disabled instead of 1/0 for debug Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 12/38] drm/vkms: Explicitly display connector status Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 13/38] drm/vkms: Introduce config for plane name Louis Chauvet
2026-06-27 3:46 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 14/38] drm/vkms: Use plane folder name as " Louis Chauvet
2026-06-27 3:43 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 15/38] drm/vkms: Introduce config for plane rotation Louis Chauvet
2026-06-27 3:42 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 16/38] drm/vkms: Use DRM_ROTATION_FMT macros for rotation display Louis Chauvet
2026-06-27 3:39 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 17/38] drm/vkms: Introduce configfs for plane rotation Louis Chauvet
2026-06-27 3:46 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 18/38] drm/vkms: Introduce config for plane color encoding Louis Chauvet
2026-06-27 3:43 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 19/38] drm/vkms: Introduce configfs " Louis Chauvet
2026-06-27 3:49 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 20/38] drm/vkms: Introduce config for plane color range Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 21/38] drm/vkms: Introduce configfs " Louis Chauvet
2026-06-27 3:45 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 22/38] drm/vkms: Introduce config for plane format Louis Chauvet
2026-06-27 3:46 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 23/38] drm/vkms: Introduce configfs " Louis Chauvet
2026-06-27 3:45 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 24/38] drm/vkms: Properly render plane using their zpos Louis Chauvet
2026-06-27 3:44 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 25/38] drm/vkms: Introduce config for plane zpos property Louis Chauvet
2026-06-27 3:41 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 26/38] drm/vkms: Introduce configfs " Louis Chauvet
2026-06-27 3:46 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 27/38] drm/vkms: Introduce config for connector type Louis Chauvet
2026-06-27 3:45 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 28/38] drm/vkms: Introduce configfs " Louis Chauvet
2026-06-27 3:45 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 29/38] drm/vkms: Rename vkms_connector_init to vkms_connector_init_static Louis Chauvet
2026-06-27 3:30 ` [PATCH v5 30/38] drm/vkms: Introduce config for connector supported colorspace Louis Chauvet
2026-06-27 3:58 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 31/38] drm/vkms: Introduce configfs " Louis Chauvet
2026-06-27 3:48 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 32/38] drm/vkms: Introduce config for connector EDID Louis Chauvet
2026-06-27 3:48 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 33/38] drm/vkms: Introduce configfs " Louis Chauvet
2026-06-27 3:50 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 34/38] drm/vkms: Store the enabled/disabled status for connector Louis Chauvet
2026-06-27 3:48 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 35/38] drm/vkms: Allow to hot-add connectors Louis Chauvet
2026-06-27 3:50 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 36/38] drm/vkms: Introduce configfs for dynamic connector creation Louis Chauvet
2026-06-27 3:55 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 37/38] drm/vkms: Add connector parent configuration in vkms_config Louis Chauvet
2026-06-27 3:57 ` sashiko-bot
2026-06-27 3:30 ` [PATCH v5 38/38] drm/vkms: Add ConfigFS interface for connector parent and port_id Louis Chauvet
2026-06-27 3:45 ` sashiko-bot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.