To allows the userspace to test many hardware configuration, introduce a
new interface to create and configure planes.

The planes are created by creating a directory in the `planes` directory.
The type of plane is configured by writing 0 (Overlay), 1 (primary) or 2
(cursor) in the file `type`.

As the CRTCs and encoders can't be configured yet, the planes are all
atteched to the same CRTC and encoder.

The current interface is:
/config/vkms
        DEVICE_1
        ┣━ enable
        ┣━ planes
        ┃  ┣━ PLANE_1
        ┃  ┃  ┣━ type
        ┃  ┣━ PLANE_2
        ┃  ┃  ┗━ type
        ┃  ┗━ PLANE_3
        ┃     ┗━ type
        DEVICE_2
        ┗━ ditto

Signed-off-by: Louis Chauvet <louis.chau...@bootlin.com>
---
 drivers/gpu/drm/vkms/vkms_configfs.c | 149 ++++++++++++++++++++++++++++++++---
 drivers/gpu/drm/vkms/vkms_configfs.h |  20 +++++
 2 files changed, 160 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c 
b/drivers/gpu/drm/vkms/vkms_configfs.c
index 
6535672f008401cf1ae008ff2ef74452b2575eab..ee64243396b3e586f76ff0671441c172da022421
 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -10,6 +10,138 @@
 #include "vkms_drv.h"
 #include "vkms_config.h"
 
+static ssize_t plane_type_show(struct config_item *item, char *page)
+{
+       struct vkms_config_plane *plane;
+       enum drm_plane_type plane_type;
+       struct vkms_configfs_device *vkms_configfs = 
plane_item_to_vkms_configfs_device(item);
+
+       mutex_lock(&vkms_configfs->lock);
+       plane = plane_item_to_vkms_configfs_plane(item)->vkms_config_plane;
+       plane_type = plane->type;
+       mutex_unlock(&vkms_configfs->lock);
+
+       return sprintf(page, "%u", plane_type);
+}
+
+static ssize_t plane_type_store(struct config_item *item,
+                               const char *page, size_t count)
+{
+       struct vkms_configfs_device *vkms_configfs = 
plane_item_to_vkms_configfs_device(item);
+       enum drm_plane_type val = DRM_PLANE_TYPE_OVERLAY;
+       struct vkms_config_plane *plane;
+       int ret;
+
+       ret = kstrtouint(page, 10, &val);
+       if (ret)
+               return ret;
+
+       if (val != DRM_PLANE_TYPE_PRIMARY && val != DRM_PLANE_TYPE_CURSOR &&
+           val != DRM_PLANE_TYPE_OVERLAY)
+               return -EINVAL;
+
+       mutex_lock(&vkms_configfs->lock);
+       if (vkms_configfs->enabled) {
+               mutex_unlock(&vkms_configfs->lock);
+               return -EINVAL;
+       }
+
+       plane = plane_item_to_vkms_configfs_plane(item)->vkms_config_plane;
+       plane->type = val;
+
+       mutex_unlock(&vkms_configfs->lock);
+
+       return count;
+}
+
+CONFIGFS_ATTR(plane_, type);
+
+static struct configfs_attribute *plane_attrs[] = {
+       &plane_attr_type,
+       NULL,
+};
+
+static void plane_release(struct config_item *item)
+{
+       struct vkms_configfs_plane *vkms_configfs_plane = 
plane_item_to_vkms_configfs_plane(item);
+
+       mutex_lock(&vkms_configfs_plane->vkms_configfs_device->lock);
+       vkms_config_delete_plane(vkms_configfs_plane->vkms_config_plane,
+                                
vkms_configfs_plane->vkms_configfs_device->vkms_config);
+       mutex_unlock(&vkms_configfs_plane->vkms_configfs_device->lock);
+
+       kfree(vkms_configfs_plane);
+}
+
+static struct configfs_item_operations plane_item_operations = {
+       .release        = plane_release,
+};
+
+static const struct config_item_type subgroup_plane = {
+       .ct_attrs       = plane_attrs,
+       .ct_item_ops    = &plane_item_operations,
+       .ct_owner       = THIS_MODULE,
+};
+
+static struct config_group *planes_make_group(struct config_group 
*config_group,
+                                             const char *name)
+{
+       struct vkms_configfs_device *vkms_configfs;
+       struct vkms_configfs_plane *vkms_configfs_plane;
+
+       vkms_configfs = 
planes_item_to_vkms_configfs_device(&config_group->cg_item);
+       vkms_configfs_plane = kzalloc(sizeof(*vkms_configfs_plane), GFP_KERNEL);
+
+       if (!vkms_configfs_plane)
+               return ERR_PTR(-ENOMEM);
+
+       mutex_lock(&vkms_configfs->lock);
+
+       if (vkms_configfs->enabled) {
+               kfree(vkms_configfs_plane);
+               mutex_unlock(&vkms_configfs->lock);
+               return ERR_PTR(-EINVAL);
+       }
+
+       vkms_configfs_plane->vkms_config_plane = 
vkms_config_create_plane(vkms_configfs->vkms_config);
+
+       if (list_count_nodes(&vkms_configfs->vkms_config->planes) == 1)
+               vkms_configfs_plane->vkms_config_plane->type = 
DRM_PLANE_TYPE_PRIMARY;
+
+       if (!vkms_configfs_plane->vkms_config_plane ||
+           
vkms_config_plane_attach_crtc(vkms_configfs_plane->vkms_config_plane,
+                                         vkms_configfs->vkms_config_crtc)) {
+               kfree(vkms_configfs_plane);
+               mutex_unlock(&vkms_configfs->lock);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       vkms_configfs_plane->vkms_config_plane->name = kzalloc(strlen(name) + 
1, GFP_KERNEL);
+       if (!vkms_configfs_plane->vkms_config_plane->name) {
+               kfree(vkms_configfs_plane->vkms_config_plane);
+               kfree(vkms_configfs_plane);
+               mutex_unlock(&vkms_configfs->lock);
+               return ERR_PTR(-ENOMEM);
+       }
+       strscpy(vkms_configfs_plane->vkms_config_plane->name, name, 
strlen(name) + 1);
+
+       config_group_init_type_name(&vkms_configfs_plane->group, name, 
&subgroup_plane);
+
+       vkms_configfs_plane->vkms_configfs_device = vkms_configfs;
+       mutex_unlock(&vkms_configfs->lock);
+
+       return &vkms_configfs_plane->group;
+}
+
+static struct configfs_group_operations planes_group_operations = {
+       .make_group     = &planes_make_group,
+};
+
+static const struct config_item_type planes_item_type = {
+       .ct_group_ops   = &planes_group_operations,
+       .ct_owner       = THIS_MODULE,
+};
+
 static ssize_t device_enable_show(struct config_item *item, char *page)
 {
        return sprintf(page, "%d\n",
@@ -92,23 +224,22 @@ static struct config_group *root_make_group(struct 
config_group *group,
                return ERR_PTR(-ENOMEM);
        }
 
-       plane = vkms_config_create_plane(configfs->vkms_config);
-       crtc = vkms_config_create_crtc(configfs->vkms_config);
-       encoder = vkms_config_create_encoder(configfs->vkms_config);
-
-       if (!plane || !crtc || !encoder ||
-           vkms_config_plane_attach_crtc(plane, crtc) ||
-           vkms_config_encoder_attach_crtc(encoder, crtc)) {
+       configfs->vkms_config_crtc = 
vkms_config_create_crtc(configfs->vkms_config);
+       configfs->vkms_config_encoder = 
vkms_config_create_encoder(configfs->vkms_config);
+       if (!configfs->vkms_config_crtc || !configfs->vkms_config_encoder ||
+           vkms_config_encoder_attach_crtc(configfs->vkms_config_encoder,
+                                           configfs->vkms_config_crtc)) {
                vkms_config_destroy(configfs->vkms_config);
                kfree(configfs);
                return ERR_PTR(-ENOMEM);
        }
 
-       plane->type = DRM_PLANE_TYPE_PRIMARY;
-
        config_group_init_type_name(&configfs->group, name,
                                    &device_item_type);
 
+       config_group_init_type_name(&configfs->plane_group, "planes", 
&planes_item_type);
+       configfs_add_default_group(&configfs->plane_group, &configfs->group);
+
        return &configfs->group;
 }
 
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.h 
b/drivers/gpu/drm/vkms/vkms_configfs.h
index 
ffacba6607018de44323fb6aa05cc6da8400a9f2..0f3701442691c23e33775fdd072701076d3d9387
 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.h
+++ b/drivers/gpu/drm/vkms/vkms_configfs.h
@@ -19,15 +19,35 @@
 struct vkms_configfs_device {
        struct config_group group;
 
+       struct config_group plane_group;
+
        struct mutex lock;
        bool enabled;
 
        struct vkms_config *vkms_config;
+       struct vkms_config_crtc *vkms_config_crtc;
+       struct vkms_config_encoder *vkms_config_encoder;
+};
+
+struct vkms_configfs_plane {
+       struct config_group group;
+
+       struct vkms_configfs_device *vkms_configfs_device;
+       struct vkms_config_plane *vkms_config_plane;
 };
 
 #define config_item_to_vkms_configfs_device(item) \
        container_of(to_config_group((item)), struct vkms_configfs_device, 
group)
 
+#define planes_item_to_vkms_configfs_device(item) \
+       config_item_to_vkms_configfs_device((item)->ci_parent)
+
+#define plane_item_to_vkms_configfs_device(item) \
+       planes_item_to_vkms_configfs_device((item)->ci_parent)
+
+#define plane_item_to_vkms_configfs_plane(item) \
+       container_of(to_config_group((item)), struct vkms_configfs_plane, group)
+
 /* ConfigFS Support */
 int vkms_init_configfs(void);
 void vkms_unregister_configfs(void);

-- 
2.47.1

Reply via email to