[PATCH v4 25/37] drm/vkms: Introduce configfs for plane zpos property

Louis Chauvet
2026-04-22T16:50:01Z

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 dae8b9e9d6bf..9f77a878aeef 100644
--- a/Documentation/ABI/testing/configfs-vkms
+++ b/Documentation/ABI/testing/configfs-vkms
@@ -162,6 +162,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 94f7b0d85ca7..c811290af983 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 9 configurable attributes:
+Planes have 14 configurable attributes:

- type: Plane type: 0 overlay, 1 primary, 2 cursor (same values as those
exposed by the "type" property of a plane)
@@ -114,6 +114,13 @@ Planes have 9 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 b38d724cfb94..832f73011353 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -747,6 +747,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_, name);
CONFIGFS_ATTR(plane_, supported_rotations);
@@ -756,6 +926,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,
@@ -767,6 +942,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