public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 00/17] VKMS: Add configfs support
@ 2024-08-13 10:44 José Expósito
  2024-08-13 10:44 ` [RFC PATCH 01/17] drm/vkms: Extract vkms_config header José Expósito
                   ` (18 more replies)
  0 siblings, 19 replies; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Hi everyone,

This RFC implements support to configure VKMS using configfs.
It allows to:

 - Create multiple devices
 - Configure multiple overlay planes, CRTCs, encoders and
   connectors
 - Enable or disable cursor plane and writeback connector for
   each CRTC
 - Hot-plug/unplug connectors after device creation
 - Disable the creation of the default VKMS instance to be
   able to use only the configfs ones

This work is based on a previous attempt to implement configfs
support by Jim Shargo and Brandon Pollack [1].
I tried to keep the changes as minimal and simple as possible
and addressed Sima's comments on [1].

Currently, there is another RFC by Louis Chauvet [2]. As I
mentioned on his RFC, I'm not trying to push my implementation.
Instead, I think that having 2 implementations will make code
review way easier and I don't mind which implementation is used
as long as we get the feature implemented :)

I'm looking forward to analyzing Louis's implementation, seeing
what the differences are and finding a common solution.

What's missing?

 - DebugFS only works for the default VKMS instance.
   If we want to support it on instances created with configfs
   I'll need to implement it.

Known bugs:

 - When a CRTC is added and removed before device creation, there
   is a vblank warning.
   The issue is caused because vblanks are referenced using the
   CRTC index but, because one of the CRTCs is removed, the
   indices are not consecutives and drm_crtc_vblank_crtc() tries to
   access and invalid index
   I'm not sure if CRTC's indices *must* start at 0 and be
   consecutives or if this is a bug in the drm_crtc_vblank_crtc()
   implementation.

Best wishes,
José Expósito

[1] https://patchwork.kernel.org/project/dri-devel/list/?series=780110&archive=both
[2] https://lore.kernel.org/dri-devel/ZrZZFQW5RiG12ApN@louis-chauvet-laptop/T/#u

José Expósito (17):
  drm/vkms: Extract vkms_config header
  drm/vkms: Move default_config creation to its own function
  drm/vkms: Set device name from vkms_config
  drm/vkms: Allow to configure multiple CRTCs
  drm/vkms: Use managed memory to create encoders
  drm/vkms: Allow to configure multiple encoders
  drm/vkms: Use managed memory to create connectors
  drm/vkms: Allow to configure multiple connectors
  drm/vkms: Allow to configure multiple overlay planes
  drm/vkms: Allow to change connector status
  drm/vkms: Add and remove VKMS instances via configfs
  drm/vkms: Allow to configure multiple CRTCs via configfs
  drm/vkms: Allow to configure multiple encoders via configfs
  drm/vkms: Allow to configure multiple encoders
  drm/vkms: Allow to configure multiple planes via configfs
  drm/vkms: Allow to configure the default device creation
  drm/vkms: Remove completed task from the TODO list

 Documentation/gpu/vkms.rst            | 102 +++-
 drivers/gpu/drm/vkms/Kconfig          |   1 +
 drivers/gpu/drm/vkms/Makefile         |   4 +-
 drivers/gpu/drm/vkms/vkms_composer.c  |  30 +-
 drivers/gpu/drm/vkms/vkms_config.c    | 265 ++++++++++
 drivers/gpu/drm/vkms/vkms_config.h    | 101 ++++
 drivers/gpu/drm/vkms/vkms_configfs.c  | 721 ++++++++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_configfs.h  |   9 +
 drivers/gpu/drm/vkms/vkms_crtc.c      |  99 ++--
 drivers/gpu/drm/vkms/vkms_drv.c       |  75 ++-
 drivers/gpu/drm/vkms/vkms_drv.h       |  52 +-
 drivers/gpu/drm/vkms/vkms_output.c    | 187 ++++---
 drivers/gpu/drm/vkms/vkms_plane.c     |   6 +-
 drivers/gpu/drm/vkms/vkms_writeback.c |  27 +-
 14 files changed, 1464 insertions(+), 215 deletions(-)
 create mode 100644 drivers/gpu/drm/vkms/vkms_config.c
 create mode 100644 drivers/gpu/drm/vkms/vkms_config.h
 create mode 100644 drivers/gpu/drm/vkms/vkms_configfs.c
 create mode 100644 drivers/gpu/drm/vkms/vkms_configfs.h

-- 
2.46.0


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC PATCH 01/17] drm/vkms: Extract vkms_config header
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 10:44 ` [RFC PATCH 02/17] drm/vkms: Move default_config creation to its own function José Expósito
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Creating a new vkms_config structure will be more complex once we
start adding more options.

Extract the vkms_config structure to its own header and source files
and add functions to create and delete a vkms_config and to initialize
debugfs.

Refactor, no functional changes.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 drivers/gpu/drm/vkms/Makefile      |  3 +-
 drivers/gpu/drm/vkms/vkms_config.c | 48 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_config.h | 25 ++++++++++++++++
 drivers/gpu/drm/vkms/vkms_drv.c    | 34 +++++----------------
 drivers/gpu/drm/vkms/vkms_drv.h    | 10 +------
 drivers/gpu/drm/vkms/vkms_output.c |  1 +
 6 files changed, 84 insertions(+), 37 deletions(-)
 create mode 100644 drivers/gpu/drm/vkms/vkms_config.c
 create mode 100644 drivers/gpu/drm/vkms/vkms_config.h

diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile
index 1b28a6a32948..b371b5d70ee3 100644
--- a/drivers/gpu/drm/vkms/Makefile
+++ b/drivers/gpu/drm/vkms/Makefile
@@ -6,6 +6,7 @@ vkms-y := \
 	vkms_formats.o \
 	vkms_crtc.o \
 	vkms_composer.o \
-	vkms_writeback.o
+	vkms_writeback.o \
+	vkms_config.o
 
 obj-$(CONFIG_DRM_VKMS) += vkms.o
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
new file mode 100644
index 000000000000..c58eda76c238
--- /dev/null
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/slab.h>
+
+#include <drm/drm_print.h>
+#include <drm/drm_debugfs.h>
+
+#include "vkms_config.h"
+#include "vkms_drv.h"
+
+struct vkms_config *vkms_config_create(void)
+{
+	struct vkms_config *config;
+
+	config = kzalloc(sizeof(*config), GFP_KERNEL);
+	if (!config)
+		return ERR_PTR(-ENOMEM);
+
+	return config;
+}
+
+void vkms_config_destroy(struct vkms_config *config)
+{
+	kfree(config);
+}
+
+static int vkms_config_show(struct seq_file *m, void *data)
+{
+	struct drm_debugfs_entry *entry = m->private;
+	struct drm_device *dev = entry->dev;
+	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
+
+	seq_printf(m, "writeback=%d\n", vkmsdev->config->writeback);
+	seq_printf(m, "cursor=%d\n", vkmsdev->config->cursor);
+	seq_printf(m, "overlay=%d\n", vkmsdev->config->overlay);
+
+	return 0;
+}
+
+static const struct drm_debugfs_info vkms_config_debugfs_list[] = {
+	{ "vkms_config", vkms_config_show, 0 },
+};
+
+void vkms_config_debugfs_init(struct vkms_device *vkms_device)
+{
+	drm_debugfs_add_files(&vkms_device->drm, vkms_config_debugfs_list,
+			      ARRAY_SIZE(vkms_config_debugfs_list));
+}
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
new file mode 100644
index 000000000000..65da8cd6ff96
--- /dev/null
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef _VKMS_CONFIG_H_
+#define _VKMS_CONFIG_H_
+
+#include <linux/types.h>
+
+struct vkms_device;
+
+struct vkms_config {
+	bool writeback;
+	bool cursor;
+	bool overlay;
+	/* only set when instantiated */
+	struct vkms_device *dev;
+};
+
+/* VKMS Config */
+struct vkms_config *vkms_config_create(void);
+void vkms_config_destroy(struct vkms_config *config);
+
+/* DebugFS */
+void vkms_config_debugfs_init(struct vkms_device *vkms_device);
+
+#endif /* _VKMS_CONFIG_H_ */
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 8dc9dc13896e..6bf462985731 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -26,11 +26,9 @@
 #include <drm/drm_gem_shmem_helper.h>
 #include <drm/drm_vblank.h>
 
+#include "vkms_config.h"
 #include "vkms_drv.h"
 
-#include <drm/drm_print.h>
-#include <drm/drm_debugfs.h>
-
 #define DRIVER_NAME	"vkms"
 #define DRIVER_DESC	"Virtual Kernel Mode Setting"
 #define DRIVER_DATE	"20180514"
@@ -90,23 +88,6 @@ static void vkms_atomic_commit_tail(struct drm_atomic_state *old_state)
 	drm_atomic_helper_cleanup_planes(dev, old_state);
 }
 
-static int vkms_config_show(struct seq_file *m, void *data)
-{
-	struct drm_debugfs_entry *entry = m->private;
-	struct drm_device *dev = entry->dev;
-	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
-
-	seq_printf(m, "writeback=%d\n", vkmsdev->config->writeback);
-	seq_printf(m, "cursor=%d\n", vkmsdev->config->cursor);
-	seq_printf(m, "overlay=%d\n", vkmsdev->config->overlay);
-
-	return 0;
-}
-
-static const struct drm_debugfs_info vkms_config_debugfs_list[] = {
-	{ "vkms_config", vkms_config_show, 0 },
-};
-
 static const struct drm_driver vkms_driver = {
 	.driver_features	= DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM,
 	.release		= vkms_release,
@@ -216,8 +197,7 @@ static int vkms_create(struct vkms_config *config)
 	if (ret)
 		goto out_devres;
 
-	drm_debugfs_add_files(&vkms_device->drm, vkms_config_debugfs_list,
-			      ARRAY_SIZE(vkms_config_debugfs_list));
+	vkms_config_debugfs_init(vkms_device);
 
 	ret = drm_dev_register(&vkms_device->drm, 0);
 	if (ret)
@@ -239,9 +219,9 @@ static int __init vkms_init(void)
 	int ret;
 	struct vkms_config *config;
 
-	config = kmalloc(sizeof(*config), GFP_KERNEL);
-	if (!config)
-		return -ENOMEM;
+	config = vkms_config_create();
+	if (IS_ERR(config))
+		return PTR_ERR(config);
 
 	default_config = config;
 
@@ -251,7 +231,7 @@ static int __init vkms_init(void)
 
 	ret = vkms_create(config);
 	if (ret)
-		kfree(config);
+		vkms_config_destroy(config);
 
 	return ret;
 }
@@ -280,7 +260,7 @@ static void __exit vkms_exit(void)
 	if (default_config->dev)
 		vkms_destroy(default_config);
 
-	kfree(default_config);
+	vkms_config_destroy(default_config);
 }
 
 module_init(vkms_init);
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 5e46ea5b96dc..5c523ca27f22 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -115,15 +115,7 @@ struct vkms_output {
 	spinlock_t composer_lock;
 };
 
-struct vkms_device;
-
-struct vkms_config {
-	bool writeback;
-	bool cursor;
-	bool overlay;
-	/* only set when instantiated */
-	struct vkms_device *dev;
-};
+struct vkms_config;
 
 struct vkms_device {
 	struct drm_device drm;
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 5ce70dd946aa..afe3945c1962 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0+
 
+#include "vkms_config.h"
 #include "vkms_drv.h"
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 02/17] drm/vkms: Move default_config creation to its own function
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
  2024-08-13 10:44 ` [RFC PATCH 01/17] drm/vkms: Extract vkms_config header José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 10:44 ` [RFC PATCH 03/17] drm/vkms: Set device name from vkms_config José Expósito
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Extract the initialization of the default configuration to a function.
Refactor, no functional changes.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 17 +++++++++++++++++
 drivers/gpu/drm/vkms/vkms_config.h |  3 +++
 drivers/gpu/drm/vkms/vkms_drv.c    |  6 +-----
 3 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index c58eda76c238..4c7cda16dfd8 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -19,6 +19,23 @@ struct vkms_config *vkms_config_create(void)
 	return config;
 }
 
+struct vkms_config *vkms_config_default_create(bool enable_cursor,
+					       bool enable_writeback,
+					       bool enable_overlay)
+{
+	struct vkms_config *config;
+
+	config = vkms_config_create();
+	if (IS_ERR(config))
+		return config;
+
+	config->cursor = enable_cursor;
+	config->writeback = enable_writeback;
+	config->overlay = enable_overlay;
+
+	return config;
+}
+
 void vkms_config_destroy(struct vkms_config *config)
 {
 	kfree(config);
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 65da8cd6ff96..83181760b02b 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -17,6 +17,9 @@ struct vkms_config {
 
 /* VKMS Config */
 struct vkms_config *vkms_config_create(void);
+struct vkms_config *vkms_config_default_create(bool enable_cursor,
+					       bool enable_writeback,
+					       bool enable_overlay);
 void vkms_config_destroy(struct vkms_config *config);
 
 /* DebugFS */
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 6bf462985731..4e36989589f9 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -219,16 +219,12 @@ static int __init vkms_init(void)
 	int ret;
 	struct vkms_config *config;
 
-	config = vkms_config_create();
+	config = vkms_config_default_create(enable_cursor, enable_writeback, enable_overlay);
 	if (IS_ERR(config))
 		return PTR_ERR(config);
 
 	default_config = config;
 
-	config->cursor = enable_cursor;
-	config->writeback = enable_writeback;
-	config->overlay = enable_overlay;
-
 	ret = vkms_create(config);
 	if (ret)
 		vkms_config_destroy(config);
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 03/17] drm/vkms: Set device name from vkms_config
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
  2024-08-13 10:44 ` [RFC PATCH 01/17] drm/vkms: Extract vkms_config header José Expósito
  2024-08-13 10:44 ` [RFC PATCH 02/17] drm/vkms: Move default_config creation to its own function José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:58   ` Louis Chauvet
  2024-08-13 10:44 ` [RFC PATCH 04/17] drm/vkms: Allow to configure multiple CRTCs José Expósito
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

In order to be able to create multiple devices, the device name needs to
be unique.

Allow to set it in the VKMS configuration.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 7 +++++--
 drivers/gpu/drm/vkms/vkms_config.h | 3 ++-
 drivers/gpu/drm/vkms/vkms_drv.c    | 2 +-
 drivers/gpu/drm/vkms/vkms_drv.h    | 2 ++
 4 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 4c7cda16dfd8..6ab8091bf72f 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -8,7 +8,7 @@
 #include "vkms_config.h"
 #include "vkms_drv.h"
 
-struct vkms_config *vkms_config_create(void)
+struct vkms_config *vkms_config_create(char *dev_name)
 {
 	struct vkms_config *config;
 
@@ -16,6 +16,8 @@ struct vkms_config *vkms_config_create(void)
 	if (!config)
 		return ERR_PTR(-ENOMEM);
 
+	config->dev_name = dev_name;
+
 	return config;
 }
 
@@ -25,7 +27,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
 {
 	struct vkms_config *config;
 
-	config = vkms_config_create();
+	config = vkms_config_create(DEFAULT_DEVICE_NAME);
 	if (IS_ERR(config))
 		return config;
 
@@ -47,6 +49,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);
 
+	seq_printf(m, "dev_name=%s\n", vkmsdev->config->dev_name);
 	seq_printf(m, "writeback=%d\n", vkmsdev->config->writeback);
 	seq_printf(m, "cursor=%d\n", vkmsdev->config->cursor);
 	seq_printf(m, "overlay=%d\n", vkmsdev->config->overlay);
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 83181760b02b..ba06aad32799 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -8,6 +8,7 @@
 struct vkms_device;
 
 struct vkms_config {
+	char *dev_name;
 	bool writeback;
 	bool cursor;
 	bool overlay;
@@ -16,7 +17,7 @@ struct vkms_config {
 };
 
 /* VKMS Config */
-struct vkms_config *vkms_config_create(void);
+struct vkms_config *vkms_config_create(char *dev_name);
 struct vkms_config *vkms_config_default_create(bool enable_cursor,
 					       bool enable_writeback,
 					       bool enable_overlay);
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 4e36989589f9..2f9d1db0cfae 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -160,7 +160,7 @@ static int vkms_create(struct vkms_config *config)
 	struct platform_device *pdev;
 	struct vkms_device *vkms_device;
 
-	pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
+	pdev = platform_device_register_simple(config->dev_name, -1, NULL, 0);
 	if (IS_ERR(pdev))
 		return PTR_ERR(pdev);
 
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 5c523ca27f22..87e44b51a03f 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -12,6 +12,8 @@
 #include <drm/drm_encoder.h>
 #include <drm/drm_writeback.h>
 
+#define DEFAULT_DEVICE_NAME "vkms"
+
 #define XRES_MIN    10
 #define YRES_MIN    10
 
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 04/17] drm/vkms: Allow to configure multiple CRTCs
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (2 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 03/17] drm/vkms: Set device name from vkms_config José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:58   ` Louis Chauvet
  2024-08-13 10:44 ` [RFC PATCH 05/17] drm/vkms: Use managed memory to create encoders José Expósito
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Add a list of CRTC configurations to vkms_config and add as many CRTCs
as configured during output initialization.

For backwards compatibility, create a single CRTC in the default
configuration.

Since writeback support, vblank and composer states are now per CRTC,
extract all the fields to the vkms_crtc structure and allow each
vkms_device to have a list of CRTCs.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 drivers/gpu/drm/vkms/vkms_composer.c  | 30 ++++----
 drivers/gpu/drm/vkms/vkms_config.c    | 54 ++++++++++++++-
 drivers/gpu/drm/vkms/vkms_config.h    | 15 +++-
 drivers/gpu/drm/vkms/vkms_crtc.c      | 99 ++++++++++++++-------------
 drivers/gpu/drm/vkms/vkms_drv.c       | 10 ++-
 drivers/gpu/drm/vkms/vkms_drv.h       | 35 +++++++---
 drivers/gpu/drm/vkms/vkms_output.c    | 38 +++++-----
 drivers/gpu/drm/vkms/vkms_writeback.c | 27 ++++----
 8 files changed, 197 insertions(+), 111 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c
index e7441b227b3c..b1723cf02ed3 100644
--- a/drivers/gpu/drm/vkms/vkms_composer.c
+++ b/drivers/gpu/drm/vkms/vkms_composer.c
@@ -306,13 +306,13 @@ void vkms_composer_worker(struct work_struct *work)
 						composer_work);
 	struct drm_crtc *crtc = crtc_state->base.crtc;
 	struct vkms_writeback_job *active_wb = crtc_state->active_writeback;
-	struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
+	struct vkms_crtc *vkms_crtc = drm_crtc_to_vkms_crtc(crtc);
 	bool crc_pending, wb_pending;
 	u64 frame_start, frame_end;
 	u32 crc32 = 0;
 	int ret;
 
-	spin_lock_irq(&out->composer_lock);
+	spin_lock_irq(&vkms_crtc->composer_lock);
 	frame_start = crtc_state->frame_start;
 	frame_end = crtc_state->frame_end;
 	crc_pending = crtc_state->crc_pending;
@@ -336,7 +336,7 @@ void vkms_composer_worker(struct work_struct *work)
 		crtc_state->gamma_lut.base = NULL;
 	}
 
-	spin_unlock_irq(&out->composer_lock);
+	spin_unlock_irq(&vkms_crtc->composer_lock);
 
 	/*
 	 * We raced with the vblank hrtimer and previous work already computed
@@ -354,10 +354,10 @@ void vkms_composer_worker(struct work_struct *work)
 		return;
 
 	if (wb_pending) {
-		drm_writeback_signal_completion(&out->wb_connector, 0);
-		spin_lock_irq(&out->composer_lock);
+		drm_writeback_signal_completion(&vkms_crtc->wb_connector, 0);
+		spin_lock_irq(&vkms_crtc->composer_lock);
 		crtc_state->wb_pending = false;
-		spin_unlock_irq(&out->composer_lock);
+		spin_unlock_irq(&vkms_crtc->composer_lock);
 	}
 
 	/*
@@ -407,31 +407,31 @@ int vkms_verify_crc_source(struct drm_crtc *crtc, const char *src_name,
 	return 0;
 }
 
-void vkms_set_composer(struct vkms_output *out, bool enabled)
+void vkms_set_composer(struct vkms_crtc *vkms_crtc, bool enabled)
 {
 	bool old_enabled;
 
 	if (enabled)
-		drm_crtc_vblank_get(&out->crtc);
+		drm_crtc_vblank_get(&vkms_crtc->base);
 
-	spin_lock_irq(&out->lock);
-	old_enabled = out->composer_enabled;
-	out->composer_enabled = enabled;
-	spin_unlock_irq(&out->lock);
+	spin_lock_irq(&vkms_crtc->lock);
+	old_enabled = vkms_crtc->composer_enabled;
+	vkms_crtc->composer_enabled = enabled;
+	spin_unlock_irq(&vkms_crtc->lock);
 
 	if (old_enabled)
-		drm_crtc_vblank_put(&out->crtc);
+		drm_crtc_vblank_put(&vkms_crtc->base);
 }
 
 int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name)
 {
-	struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
+	struct vkms_crtc *vkms_crtc = drm_crtc_to_vkms_crtc(crtc);
 	bool enabled = false;
 	int ret = 0;
 
 	ret = vkms_crc_parse_source(src_name, &enabled);
 
-	vkms_set_composer(out, enabled);
+	vkms_set_composer(vkms_crtc, enabled);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 6ab8091bf72f..3af750071f04 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -17,6 +17,7 @@ struct vkms_config *vkms_config_create(char *dev_name)
 		return ERR_PTR(-ENOMEM);
 
 	config->dev_name = dev_name;
+	config->crtcs = (struct list_head)LIST_HEAD_INIT(config->crtcs);
 
 	return config;
 }
@@ -26,20 +27,29 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
 					       bool enable_overlay)
 {
 	struct vkms_config *config;
+	struct vkms_config_crtc *crtc_cfg;
 
 	config = vkms_config_create(DEFAULT_DEVICE_NAME);
 	if (IS_ERR(config))
 		return config;
 
 	config->cursor = enable_cursor;
-	config->writeback = enable_writeback;
 	config->overlay = enable_overlay;
 
+	crtc_cfg = vkms_config_add_crtc(config, enable_writeback);
+	if (IS_ERR(crtc_cfg))
+		return ERR_CAST(crtc_cfg);
+
 	return config;
 }
 
 void vkms_config_destroy(struct vkms_config *config)
 {
+	struct vkms_config_crtc *crtc_cfg, *crtc_tmp;
+
+	list_for_each_entry_safe(crtc_cfg, crtc_tmp, &config->crtcs, list)
+		vkms_config_destroy_crtc(config, crtc_cfg);
+
 	kfree(config);
 }
 
@@ -48,12 +58,20 @@ static int vkms_config_show(struct seq_file *m, void *data)
 	struct drm_debugfs_entry *entry = m->private;
 	struct drm_device *dev = entry->dev;
 	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
+	struct vkms_config_crtc *crtc_cfg;
+	int n;
 
 	seq_printf(m, "dev_name=%s\n", vkmsdev->config->dev_name);
-	seq_printf(m, "writeback=%d\n", vkmsdev->config->writeback);
 	seq_printf(m, "cursor=%d\n", vkmsdev->config->cursor);
 	seq_printf(m, "overlay=%d\n", vkmsdev->config->overlay);
 
+	n = 0;
+	list_for_each_entry(crtc_cfg, &vkmsdev->config->crtcs, list) {
+		seq_printf(m, "crtc(%d).writeback=%d\n", n,
+			   crtc_cfg->writeback);
+		n++;
+	}
+
 	return 0;
 }
 
@@ -66,3 +84,35 @@ void vkms_config_debugfs_init(struct vkms_device *vkms_device)
 	drm_debugfs_add_files(&vkms_device->drm, vkms_config_debugfs_list,
 			      ARRAY_SIZE(vkms_config_debugfs_list));
 }
+
+struct vkms_config_crtc *vkms_config_add_crtc(struct vkms_config *config,
+					      bool enable_writeback)
+{
+	struct vkms_config_crtc *crtc_cfg;
+
+	crtc_cfg = kzalloc(sizeof(*crtc_cfg), GFP_KERNEL);
+	if (!crtc_cfg)
+		return ERR_PTR(-ENOMEM);
+
+	crtc_cfg->writeback = enable_writeback;
+
+	crtc_cfg->index = 0;
+	if (!list_empty(&config->crtcs)) {
+		struct vkms_config_crtc *last;
+
+		last = list_last_entry(&config->crtcs, struct vkms_config_crtc,
+				       list);
+		crtc_cfg->index = last->index + 1;
+	}
+
+	list_add_tail(&crtc_cfg->list, &config->crtcs);
+
+	return crtc_cfg;
+}
+
+void vkms_config_destroy_crtc(struct vkms_config *config,
+			      struct vkms_config_crtc *crtc_cfg)
+{
+	list_del(&crtc_cfg->list);
+	kfree(crtc_cfg);
+}
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index ba06aad32799..bc40a0e3859a 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -3,15 +3,22 @@
 #ifndef _VKMS_CONFIG_H_
 #define _VKMS_CONFIG_H_
 
+#include <linux/list.h>
 #include <linux/types.h>
 
 struct vkms_device;
 
+struct vkms_config_crtc {
+	struct list_head list;
+	unsigned int index;
+	bool writeback;
+};
+
 struct vkms_config {
 	char *dev_name;
-	bool writeback;
 	bool cursor;
 	bool overlay;
+	struct list_head crtcs;
 	/* only set when instantiated */
 	struct vkms_device *dev;
 };
@@ -26,4 +33,10 @@ void vkms_config_destroy(struct vkms_config *config);
 /* DebugFS */
 void vkms_config_debugfs_init(struct vkms_device *vkms_device);
 
+/* CRTCs */
+struct vkms_config_crtc *vkms_config_add_crtc(struct vkms_config *config,
+					      bool enable_writeback);
+void vkms_config_destroy_crtc(struct vkms_config *config,
+			      struct vkms_config_crtc *crtc_cfg);
+
 #endif /* _VKMS_CONFIG_H_ */
diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index 40b4d084e3ce..41ab8f47331c 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -11,35 +11,34 @@
 
 static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
 {
-	struct vkms_output *output = container_of(timer, struct vkms_output,
-						  vblank_hrtimer);
-	struct drm_crtc *crtc = &output->crtc;
+	struct vkms_crtc *vkms_crtc = timer_to_vkms_crtc(timer);
+	struct drm_crtc *crtc = &vkms_crtc->base;
 	struct vkms_crtc_state *state;
 	u64 ret_overrun;
 	bool ret, fence_cookie;
 
 	fence_cookie = dma_fence_begin_signalling();
 
-	ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer,
-					  output->period_ns);
+	ret_overrun = hrtimer_forward_now(&vkms_crtc->vblank_hrtimer,
+					  vkms_crtc->period_ns);
 	if (ret_overrun != 1)
 		pr_warn("%s: vblank timer overrun\n", __func__);
 
-	spin_lock(&output->lock);
+	spin_lock(&vkms_crtc->lock);
 	ret = drm_crtc_handle_vblank(crtc);
 	if (!ret)
 		DRM_ERROR("vkms failure on handling vblank");
 
-	state = output->composer_state;
-	spin_unlock(&output->lock);
+	state = vkms_crtc->composer_state;
+	spin_unlock(&vkms_crtc->lock);
 
-	if (state && output->composer_enabled) {
+	if (state && vkms_crtc->composer_enabled) {
 		u64 frame = drm_crtc_accurate_vblank_count(crtc);
 
 		/* update frame_start only if a queued vkms_composer_worker()
 		 * has read the data
 		 */
-		spin_lock(&output->composer_lock);
+		spin_lock(&vkms_crtc->composer_lock);
 		if (!state->crc_pending)
 			state->frame_start = frame;
 		else
@@ -47,9 +46,9 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
 					 state->frame_start, frame);
 		state->frame_end = frame;
 		state->crc_pending = true;
-		spin_unlock(&output->composer_lock);
+		spin_unlock(&vkms_crtc->composer_lock);
 
-		ret = queue_work(output->composer_workq, &state->composer_work);
+		ret = queue_work(vkms_crtc->composer_workq, &state->composer_work);
 		if (!ret)
 			DRM_DEBUG_DRIVER("Composer worker already queued\n");
 	}
@@ -62,32 +61,30 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
 static int vkms_enable_vblank(struct drm_crtc *crtc)
 {
 	struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
-	struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
+	struct vkms_crtc *vkms_crtc = drm_crtc_to_vkms_crtc(crtc);
 
 	drm_calc_timestamping_constants(crtc, &crtc->mode);
 
-	hrtimer_init(&out->vblank_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-	out->vblank_hrtimer.function = &vkms_vblank_simulate;
-	out->period_ns = ktime_set(0, vblank->framedur_ns);
-	hrtimer_start(&out->vblank_hrtimer, out->period_ns, HRTIMER_MODE_REL);
+	hrtimer_init(&vkms_crtc->vblank_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	vkms_crtc->vblank_hrtimer.function = &vkms_vblank_simulate;
+	vkms_crtc->period_ns = ktime_set(0, vblank->framedur_ns);
+	hrtimer_start(&vkms_crtc->vblank_hrtimer, vkms_crtc->period_ns, HRTIMER_MODE_REL);
 
 	return 0;
 }
 
 static void vkms_disable_vblank(struct drm_crtc *crtc)
 {
-	struct vkms_output *out = drm_crtc_to_vkms_output(crtc);
+	struct vkms_crtc *vkms_crtc = drm_crtc_to_vkms_crtc(crtc);
 
-	hrtimer_cancel(&out->vblank_hrtimer);
+	hrtimer_cancel(&vkms_crtc->vblank_hrtimer);
 }
 
 static bool vkms_get_vblank_timestamp(struct drm_crtc *crtc,
 				      int *max_error, ktime_t *vblank_time,
 				      bool in_vblank_irq)
 {
-	struct drm_device *dev = crtc->dev;
-	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
-	struct vkms_output *output = &vkmsdev->output;
+	struct vkms_crtc *vkms_crtc = drm_crtc_to_vkms_crtc(crtc);
 	struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
 
 	if (!READ_ONCE(vblank->enabled)) {
@@ -95,7 +92,7 @@ static bool vkms_get_vblank_timestamp(struct drm_crtc *crtc,
 		return true;
 	}
 
-	*vblank_time = READ_ONCE(output->vblank_hrtimer.node.expires);
+	*vblank_time = READ_ONCE(vkms_crtc->vblank_hrtimer.node.expires);
 
 	if (WARN_ON(*vblank_time == vblank->time))
 		return true;
@@ -107,7 +104,7 @@ static bool vkms_get_vblank_timestamp(struct drm_crtc *crtc,
 	 * the vblank core expects. Therefore we need to always correct the
 	 * timestampe by one frame.
 	 */
-	*vblank_time -= output->period_ns;
+	*vblank_time -= vkms_crtc->period_ns;
 
 	return true;
 }
@@ -233,18 +230,18 @@ static void vkms_crtc_atomic_disable(struct drm_crtc *crtc,
 static void vkms_crtc_atomic_begin(struct drm_crtc *crtc,
 				   struct drm_atomic_state *state)
 {
-	struct vkms_output *vkms_output = drm_crtc_to_vkms_output(crtc);
+	struct vkms_crtc *vkms_crtc = drm_crtc_to_vkms_crtc(crtc);
 
 	/* This lock is held across the atomic commit to block vblank timer
 	 * from scheduling vkms_composer_worker until the composer is updated
 	 */
-	spin_lock_irq(&vkms_output->lock);
+	spin_lock_irq(&vkms_crtc->lock);
 }
 
 static void vkms_crtc_atomic_flush(struct drm_crtc *crtc,
 				   struct drm_atomic_state *state)
 {
-	struct vkms_output *vkms_output = drm_crtc_to_vkms_output(crtc);
+	struct vkms_crtc *vkms_crtc = drm_crtc_to_vkms_crtc(crtc);
 
 	if (crtc->state->event) {
 		spin_lock(&crtc->dev->event_lock);
@@ -259,9 +256,9 @@ static void vkms_crtc_atomic_flush(struct drm_crtc *crtc,
 		crtc->state->event = NULL;
 	}
 
-	vkms_output->composer_state = to_vkms_crtc_state(crtc->state);
+	vkms_crtc->composer_state = to_vkms_crtc_state(crtc->state);
 
-	spin_unlock_irq(&vkms_output->lock);
+	spin_unlock_irq(&vkms_crtc->lock);
 }
 
 static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = {
@@ -272,30 +269,38 @@ static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs = {
 	.atomic_disable	= vkms_crtc_atomic_disable,
 };
 
-int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
-		   struct drm_plane *primary, struct drm_plane *cursor)
+struct vkms_crtc *vkms_crtc_init(struct drm_device *dev,
+				 struct drm_plane *primary,
+				 struct drm_plane *cursor,
+				 unsigned int index)
 {
-	struct vkms_output *vkms_out = drm_crtc_to_vkms_output(crtc);
-	int ret;
+	struct vkms_crtc *crtc;
 
-	ret = drmm_crtc_init_with_planes(dev, crtc, primary, cursor,
-					 &vkms_crtc_funcs, NULL);
-	if (ret) {
-		DRM_ERROR("Failed to init CRTC\n");
-		return ret;
+	crtc = drmm_crtc_alloc_with_planes(dev, struct vkms_crtc, base, primary,
+					   cursor, &vkms_crtc_funcs, NULL);
+	if (IS_ERR(crtc)) {
+		DRM_ERROR("Failed to alloc CRTC\n");
+		return crtc;
 	}
 
-	drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs);
+	crtc->base.index = index;
+	primary->possible_crtcs = drm_crtc_mask(&crtc->base);
+	if (cursor)
+		cursor->possible_crtcs = drm_crtc_mask(&crtc->base);
 
-	drm_mode_crtc_set_gamma_size(crtc, VKMS_LUT_SIZE);
-	drm_crtc_enable_color_mgmt(crtc, 0, false, VKMS_LUT_SIZE);
+	INIT_LIST_HEAD(&crtc->list);
 
-	spin_lock_init(&vkms_out->lock);
-	spin_lock_init(&vkms_out->composer_lock);
+	drm_crtc_helper_add(&crtc->base, &vkms_crtc_helper_funcs);
 
-	vkms_out->composer_workq = alloc_ordered_workqueue("vkms_composer", 0);
-	if (!vkms_out->composer_workq)
-		return -ENOMEM;
+	drm_mode_crtc_set_gamma_size(&crtc->base, VKMS_LUT_SIZE);
+	drm_crtc_enable_color_mgmt(&crtc->base, 0, false, VKMS_LUT_SIZE);
+
+	spin_lock_init(&crtc->lock);
+	spin_lock_init(&crtc->composer_lock);
+
+	crtc->composer_workq = alloc_ordered_workqueue("vkms_composer", 0);
+	if (!crtc->composer_workq)
+		return ERR_PTR(-ENOMEM);
 
-	return ret;
+	return crtc;
 }
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 2f9d1db0cfae..15a2ba26d190 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -54,9 +54,12 @@ DEFINE_DRM_GEM_FOPS(vkms_driver_fops);
 static void vkms_release(struct drm_device *dev)
 {
 	struct vkms_device *vkms = drm_device_to_vkms_device(dev);
+	struct vkms_crtc *vkms_crtc;
 
-	if (vkms->output.composer_workq)
-		destroy_workqueue(vkms->output.composer_workq);
+	list_for_each_entry(vkms_crtc, &vkms->crtcs, list) {
+		if (vkms_crtc->composer_workq)
+			destroy_workqueue(vkms_crtc->composer_workq);
+	}
 }
 
 static void vkms_atomic_commit_tail(struct drm_atomic_state *old_state)
@@ -177,6 +180,7 @@ static int vkms_create(struct vkms_config *config)
 	}
 	vkms_device->platform = pdev;
 	vkms_device->config = config;
+	vkms_device->crtcs = (struct list_head)LIST_HEAD_INIT(vkms_device->crtcs);
 	config->dev = vkms_device;
 
 	ret = dma_coerce_mask_and_coherent(vkms_device->drm.dev,
@@ -187,7 +191,7 @@ static int vkms_create(struct vkms_config *config)
 		goto out_devres;
 	}
 
-	ret = drm_vblank_init(&vkms_device->drm, 1);
+	ret = drm_vblank_init(&vkms_device->drm, list_count_nodes(&config->crtcs));
 	if (ret) {
 		DRM_ERROR("Failed to vblank\n");
 		goto out_devres;
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 87e44b51a03f..3156ff896c33 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -4,6 +4,7 @@
 #define _VKMS_DRV_H_
 
 #include <linux/hrtimer.h>
+#include <linux/list.h>
 
 #include <drm/drm.h>
 #include <drm/drm_framebuffer.h>
@@ -98,10 +99,11 @@ struct vkms_crtc_state {
 	u64 frame_end;
 };
 
-struct vkms_output {
-	struct drm_crtc crtc;
-	struct drm_encoder encoder;
-	struct drm_connector connector;
+struct vkms_crtc {
+	struct list_head list;
+
+	struct drm_crtc base;
+
 	struct drm_writeback_connector wb_connector;
 	struct hrtimer vblank_hrtimer;
 	ktime_t period_ns;
@@ -119,19 +121,28 @@ struct vkms_output {
 
 struct vkms_config;
 
+struct vkms_output {
+	struct drm_encoder encoder;
+	struct drm_connector connector;
+};
+
 struct vkms_device {
 	struct drm_device drm;
 	struct platform_device *platform;
 	struct vkms_output output;
+	struct list_head crtcs;
 	const struct vkms_config *config;
 };
 
-#define drm_crtc_to_vkms_output(target) \
-	container_of(target, struct vkms_output, crtc)
-
 #define drm_device_to_vkms_device(target) \
 	container_of(target, struct vkms_device, drm)
 
+#define drm_crtc_to_vkms_crtc(crtc) \
+	container_of(crtc, struct vkms_crtc, base)
+
+#define timer_to_vkms_crtc(timer) \
+	container_of(timer, struct vkms_crtc, vblank_hrtimer)
+
 #define to_vkms_crtc_state(target)\
 	container_of(target, struct vkms_crtc_state, base)
 
@@ -139,8 +150,10 @@ struct vkms_device {
 	container_of(target, struct vkms_plane_state, base.base)
 
 /* CRTC */
-int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
-		   struct drm_plane *primary, struct drm_plane *cursor);
+struct vkms_crtc *vkms_crtc_init(struct drm_device *dev,
+				 struct drm_plane *primary,
+				 struct drm_plane *cursor,
+				 unsigned int index);
 
 int vkms_output_init(struct vkms_device *vkmsdev, int index);
 
@@ -156,11 +169,11 @@ int vkms_verify_crc_source(struct drm_crtc *crtc, const char *source_name,
 
 /* Composer Support */
 void vkms_composer_worker(struct work_struct *work);
-void vkms_set_composer(struct vkms_output *out, bool enabled);
+void vkms_set_composer(struct vkms_crtc *vkms_crtc, bool enabled);
 void vkms_compose_row(struct line_buffer *stage_buffer, struct vkms_plane_state *plane, int y);
 void vkms_writeback_row(struct vkms_writeback_job *wb, const struct line_buffer *src_buffer, int y);
 
 /* Writeback */
-int vkms_enable_writeback_connector(struct vkms_device *vkmsdev);
+int vkms_enable_writeback_connector(struct vkms_crtc *vkms_crtc);
 
 #endif /* _VKMS_DRV_H_ */
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index afe3945c1962..dcd32bc30e17 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -32,8 +32,7 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
 	.get_modes    = vkms_conn_get_modes,
 };
 
-static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index,
-				  struct drm_crtc *crtc)
+static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index)
 {
 	struct vkms_plane *overlay;
 
@@ -42,7 +41,7 @@ static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index,
 		return PTR_ERR(overlay);
 
 	if (!overlay->base.possible_crtcs)
-		overlay->base.possible_crtcs = drm_crtc_mask(crtc);
+		overlay->base.possible_crtcs = BIT(index);
 
 	return 0;
 }
@@ -53,7 +52,8 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 	struct drm_device *dev = &vkmsdev->drm;
 	struct drm_connector *connector = &output->connector;
 	struct drm_encoder *encoder = &output->encoder;
-	struct drm_crtc *crtc = &output->crtc;
+	struct vkms_crtc *vkms_crtc;
+	struct vkms_config_crtc *crtc_cfg;
 	struct vkms_plane *primary, *cursor = NULL;
 	int ret;
 	int writeback;
@@ -65,7 +65,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 
 	if (vkmsdev->config->overlay) {
 		for (n = 0; n < NUM_OVERLAY_PLANES; n++) {
-			ret = vkms_add_overlay_plane(vkmsdev, index, crtc);
+			ret = vkms_add_overlay_plane(vkmsdev, index);
 			if (ret)
 				return ret;
 		}
@@ -77,15 +77,26 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 			return PTR_ERR(cursor);
 	}
 
-	ret = vkms_crtc_init(dev, crtc, &primary->base, &cursor->base);
-	if (ret)
-		return ret;
+	list_for_each_entry(crtc_cfg, &vkmsdev->config->crtcs, list) {
+		vkms_crtc = vkms_crtc_init(dev, &primary->base, &cursor->base,
+					   crtc_cfg->index);
+		if (IS_ERR(vkms_crtc))
+			return PTR_ERR(vkms_crtc);
+
+		list_add_tail(&vkms_crtc->list, &vkmsdev->crtcs);
+
+		if (crtc_cfg->writeback) {
+			writeback = vkms_enable_writeback_connector(vkms_crtc);
+			if (writeback)
+				DRM_ERROR("Failed to init writeback connector\n");
+		}
+	}
 
 	ret = drm_connector_init(dev, connector, &vkms_connector_funcs,
 				 DRM_MODE_CONNECTOR_VIRTUAL);
 	if (ret) {
 		DRM_ERROR("Failed to init connector\n");
-		goto err_connector;
+		return ret;
 	}
 
 	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
@@ -104,12 +115,6 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 		goto err_attach;
 	}
 
-	if (vkmsdev->config->writeback) {
-		writeback = vkms_enable_writeback_connector(vkmsdev);
-		if (writeback)
-			DRM_ERROR("Failed to init writeback connector\n");
-	}
-
 	drm_mode_config_reset(dev);
 
 	return 0;
@@ -120,8 +125,5 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 err_encoder:
 	drm_connector_cleanup(connector);
 
-err_connector:
-	drm_crtc_cleanup(crtc);
-
 	return ret;
 }
diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c
index bc724cbd5e3a..b317cb291586 100644
--- a/drivers/gpu/drm/vkms/vkms_writeback.c
+++ b/drivers/gpu/drm/vkms/vkms_writeback.c
@@ -106,7 +106,7 @@ static void vkms_wb_cleanup_job(struct drm_writeback_connector *connector,
 				struct drm_writeback_job *job)
 {
 	struct vkms_writeback_job *vkmsjob = job->priv;
-	struct vkms_device *vkmsdev;
+	struct vkms_crtc *vkms_crtc;
 
 	if (!job->fb)
 		return;
@@ -115,8 +115,8 @@ static void vkms_wb_cleanup_job(struct drm_writeback_connector *connector,
 
 	drm_framebuffer_put(vkmsjob->wb_frame_info.fb);
 
-	vkmsdev = drm_device_to_vkms_device(job->fb->dev);
-	vkms_set_composer(&vkmsdev->output, false);
+	vkms_crtc = container_of(connector, struct vkms_crtc, wb_connector);
+	vkms_set_composer(vkms_crtc, false);
 	kfree(vkmsjob);
 }
 
@@ -125,11 +125,10 @@ static void vkms_wb_atomic_commit(struct drm_connector *conn,
 {
 	struct drm_connector_state *connector_state = drm_atomic_get_new_connector_state(state,
 											 conn);
-	struct vkms_device *vkmsdev = drm_device_to_vkms_device(conn->dev);
-	struct vkms_output *output = &vkmsdev->output;
-	struct drm_writeback_connector *wb_conn = &output->wb_connector;
+	struct vkms_crtc *vkms_crtc = drm_crtc_to_vkms_crtc(connector_state->crtc);
+	struct drm_writeback_connector *wb_conn = &vkms_crtc->wb_connector;
 	struct drm_connector_state *conn_state = wb_conn->base.state;
-	struct vkms_crtc_state *crtc_state = output->composer_state;
+	struct vkms_crtc_state *crtc_state = vkms_crtc->composer_state;
 	struct drm_framebuffer *fb = connector_state->writeback_job->fb;
 	u16 crtc_height = crtc_state->base.crtc->mode.vdisplay;
 	u16 crtc_width = crtc_state->base.crtc->mode.hdisplay;
@@ -140,15 +139,15 @@ static void vkms_wb_atomic_commit(struct drm_connector *conn,
 	if (!conn_state)
 		return;
 
-	vkms_set_composer(&vkmsdev->output, true);
+	vkms_set_composer(vkms_crtc, true);
 
 	active_wb = conn_state->writeback_job->priv;
 	wb_frame_info = &active_wb->wb_frame_info;
 
-	spin_lock_irq(&output->composer_lock);
+	spin_lock_irq(&vkms_crtc->composer_lock);
 	crtc_state->active_writeback = active_wb;
 	crtc_state->wb_pending = true;
-	spin_unlock_irq(&output->composer_lock);
+	spin_unlock_irq(&vkms_crtc->composer_lock);
 
 	wb_frame_info->offset = fb->offsets[0];
 	wb_frame_info->pitch = fb->pitches[0];
@@ -168,16 +167,16 @@ static const struct drm_connector_helper_funcs vkms_wb_conn_helper_funcs = {
 	.atomic_check = vkms_wb_atomic_check,
 };
 
-int vkms_enable_writeback_connector(struct vkms_device *vkmsdev)
+int vkms_enable_writeback_connector(struct vkms_crtc *vkms_crtc)
 {
-	struct drm_writeback_connector *wb = &vkmsdev->output.wb_connector;
+	struct drm_writeback_connector *wb = &vkms_crtc->wb_connector;
 
 	drm_connector_helper_add(&wb->base, &vkms_wb_conn_helper_funcs);
 
-	return drm_writeback_connector_init(&vkmsdev->drm, wb,
+	return drm_writeback_connector_init(vkms_crtc->base.dev, wb,
 					    &vkms_wb_connector_funcs,
 					    NULL,
 					    vkms_wb_formats,
 					    ARRAY_SIZE(vkms_wb_formats),
-					    1);
+					    drm_crtc_mask(&vkms_crtc->base));
 }
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 05/17] drm/vkms: Use managed memory to create encoders
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (3 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 04/17] drm/vkms: Allow to configure multiple CRTCs José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:58   ` Louis Chauvet
  2024-08-13 10:44 ` [RFC PATCH 06/17] drm/vkms: Allow to configure multiple encoders José Expósito
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

A future patch will allow to create multiple encoders. Use managed
memory to simplify the code.

Refactor, no functional changes.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 drivers/gpu/drm/vkms/vkms_drv.h    |  1 -
 drivers/gpu/drm/vkms/vkms_output.c | 45 ++++++++++++++++++++----------
 2 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 3156ff896c33..2466e8b0231f 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -122,7 +122,6 @@ struct vkms_crtc {
 struct vkms_config;
 
 struct vkms_output {
-	struct drm_encoder encoder;
 	struct drm_connector connector;
 };
 
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index dcd32bc30e17..15f0b72af325 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -4,6 +4,7 @@
 #include "vkms_drv.h"
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
+#include <drm/drm_managed.h>
 #include <drm/drm_probe_helper.h>
 
 static const struct drm_connector_funcs vkms_connector_funcs = {
@@ -14,10 +15,6 @@ static const struct drm_connector_funcs vkms_connector_funcs = {
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 };
 
-static const struct drm_encoder_funcs vkms_encoder_funcs = {
-	.destroy = drm_encoder_cleanup,
-};
-
 static int vkms_conn_get_modes(struct drm_connector *connector)
 {
 	int count;
@@ -32,6 +29,31 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
 	.get_modes    = vkms_conn_get_modes,
 };
 
+static struct drm_encoder *vkms_encoder_init(struct vkms_device *vkms_device,
+					     uint32_t possible_crtcs)
+{
+	struct drm_encoder *encoder;
+	int ret;
+
+	encoder = drmm_kzalloc(&vkms_device->drm, sizeof(*encoder), GFP_KERNEL);
+	if (!encoder) {
+		DRM_ERROR("Failed to allocate encoder\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	ret = drmm_encoder_init(&vkms_device->drm, encoder, NULL,
+				DRM_MODE_ENCODER_VIRTUAL, NULL);
+	if (ret) {
+		DRM_ERROR("Failed to init encoder\n");
+		kfree(encoder);
+		return ERR_PTR(ret);
+	}
+
+	encoder->possible_crtcs = possible_crtcs;
+
+	return encoder;
+}
+
 static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index)
 {
 	struct vkms_plane *overlay;
@@ -51,7 +73,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 	struct vkms_output *output = &vkmsdev->output;
 	struct drm_device *dev = &vkmsdev->drm;
 	struct drm_connector *connector = &output->connector;
-	struct drm_encoder *encoder = &output->encoder;
+	struct drm_encoder *encoder;
 	struct vkms_crtc *vkms_crtc;
 	struct vkms_config_crtc *crtc_cfg;
 	struct vkms_plane *primary, *cursor = NULL;
@@ -101,13 +123,9 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 
 	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
 
-	ret = drm_encoder_init(dev, encoder, &vkms_encoder_funcs,
-			       DRM_MODE_ENCODER_VIRTUAL, NULL);
-	if (ret) {
-		DRM_ERROR("Failed to init encoder\n");
-		goto err_encoder;
-	}
-	encoder->possible_crtcs = 1;
+	encoder = vkms_encoder_init(vkmsdev, BIT(0));
+	if (IS_ERR(encoder))
+		return PTR_ERR(encoder);
 
 	ret = drm_connector_attach_encoder(connector, encoder);
 	if (ret) {
@@ -120,9 +138,6 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 	return 0;
 
 err_attach:
-	drm_encoder_cleanup(encoder);
-
-err_encoder:
 	drm_connector_cleanup(connector);
 
 	return ret;
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 06/17] drm/vkms: Allow to configure multiple encoders
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (4 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 05/17] drm/vkms: Use managed memory to create encoders José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:58   ` Louis Chauvet
  2024-08-13 10:44 ` [RFC PATCH 07/17] drm/vkms: Use managed memory to create connectors José Expósito
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Add a list of encoder configurations to vkms_config and add as many
encoders as configured during output initialization.

For backwards compatibility, create a single encoder in the default
configuration.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 50 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_config.h | 13 ++++++++
 drivers/gpu/drm/vkms/vkms_output.c | 14 ++++++---
 3 files changed, 73 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 3af750071f04..6a8dfebee24e 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -18,6 +18,7 @@ struct vkms_config *vkms_config_create(char *dev_name)
 
 	config->dev_name = dev_name;
 	config->crtcs = (struct list_head)LIST_HEAD_INIT(config->crtcs);
+	config->encoders = (struct list_head)LIST_HEAD_INIT(config->encoders);
 
 	return config;
 }
@@ -28,6 +29,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
 {
 	struct vkms_config *config;
 	struct vkms_config_crtc *crtc_cfg;
+	struct vkms_config_encoder *encoder_cfg;
 
 	config = vkms_config_create(DEFAULT_DEVICE_NAME);
 	if (IS_ERR(config))
@@ -40,16 +42,24 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
 	if (IS_ERR(crtc_cfg))
 		return ERR_CAST(crtc_cfg);
 
+	encoder_cfg = vkms_config_add_encoder(config, BIT(0));
+	if (IS_ERR(encoder_cfg))
+		return ERR_CAST(encoder_cfg);
+
 	return config;
 }
 
 void vkms_config_destroy(struct vkms_config *config)
 {
 	struct vkms_config_crtc *crtc_cfg, *crtc_tmp;
+	struct vkms_config_encoder *encoder_cfg, *encoder_tmp;
 
 	list_for_each_entry_safe(crtc_cfg, crtc_tmp, &config->crtcs, list)
 		vkms_config_destroy_crtc(config, crtc_cfg);
 
+	list_for_each_entry_safe(encoder_cfg, encoder_tmp, &config->encoders, list)
+		vkms_config_destroy_encoder(config, encoder_cfg);
+
 	kfree(config);
 }
 
@@ -59,6 +69,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);
 	struct vkms_config_crtc *crtc_cfg;
+	struct vkms_config_encoder *encoder_cfg;
 	int n;
 
 	seq_printf(m, "dev_name=%s\n", vkmsdev->config->dev_name);
@@ -72,6 +83,13 @@ static int vkms_config_show(struct seq_file *m, void *data)
 		n++;
 	}
 
+	n = 0;
+	list_for_each_entry(encoder_cfg, &vkmsdev->config->encoders, list) {
+		seq_printf(m, "encoder(%d).possible_crtcs=%d\n", n,
+			   encoder_cfg->possible_crtcs);
+		n++;
+	}
+
 	return 0;
 }
 
@@ -116,3 +134,35 @@ void vkms_config_destroy_crtc(struct vkms_config *config,
 	list_del(&crtc_cfg->list);
 	kfree(crtc_cfg);
 }
+
+struct vkms_config_encoder *vkms_config_add_encoder(struct vkms_config *config,
+						    uint32_t possible_crtcs)
+{
+	struct vkms_config_encoder *encoder_cfg;
+
+	encoder_cfg = kzalloc(sizeof(*encoder_cfg), GFP_KERNEL);
+	if (!encoder_cfg)
+		return ERR_PTR(-ENOMEM);
+
+	encoder_cfg->possible_crtcs = possible_crtcs;
+
+	encoder_cfg->index = 0;
+	if (!list_empty(&config->encoders)) {
+		struct vkms_config_encoder *last;
+
+		last = list_last_entry(&config->encoders,
+				       struct vkms_config_encoder, list);
+		encoder_cfg->index = last->index + 1;
+	}
+
+	list_add_tail(&encoder_cfg->list, &config->encoders);
+
+	return encoder_cfg;
+}
+
+void vkms_config_destroy_encoder(struct vkms_config *config,
+				 struct vkms_config_encoder *encoder_cfg)
+{
+	list_del(&encoder_cfg->list);
+	kfree(encoder_cfg);
+}
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index bc40a0e3859a..b717b5c0d3d9 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -14,11 +14,18 @@ struct vkms_config_crtc {
 	bool writeback;
 };
 
+struct vkms_config_encoder {
+	struct list_head list;
+	unsigned int index;
+	uint32_t possible_crtcs;
+};
+
 struct vkms_config {
 	char *dev_name;
 	bool cursor;
 	bool overlay;
 	struct list_head crtcs;
+	struct list_head encoders;
 	/* only set when instantiated */
 	struct vkms_device *dev;
 };
@@ -39,4 +46,10 @@ struct vkms_config_crtc *vkms_config_add_crtc(struct vkms_config *config,
 void vkms_config_destroy_crtc(struct vkms_config *config,
 			      struct vkms_config_crtc *crtc_cfg);
 
+/* Encoders */
+struct vkms_config_encoder *vkms_config_add_encoder(struct vkms_config *config,
+						    uint32_t possible_crtcs);
+void vkms_config_destroy_encoder(struct vkms_config *config,
+				 struct vkms_config_encoder *encoder_cfg);
+
 #endif /* _VKMS_CONFIG_H_ */
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 15f0b72af325..7afe37aea52d 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -30,7 +30,8 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
 };
 
 static struct drm_encoder *vkms_encoder_init(struct vkms_device *vkms_device,
-					     uint32_t possible_crtcs)
+					     uint32_t possible_crtcs,
+					     unsigned int index)
 {
 	struct drm_encoder *encoder;
 	int ret;
@@ -49,6 +50,7 @@ static struct drm_encoder *vkms_encoder_init(struct vkms_device *vkms_device,
 		return ERR_PTR(ret);
 	}
 
+	encoder->index = index;
 	encoder->possible_crtcs = possible_crtcs;
 
 	return encoder;
@@ -74,6 +76,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 	struct drm_device *dev = &vkmsdev->drm;
 	struct drm_connector *connector = &output->connector;
 	struct drm_encoder *encoder;
+	struct vkms_config_encoder *encoder_cfg;
 	struct vkms_crtc *vkms_crtc;
 	struct vkms_config_crtc *crtc_cfg;
 	struct vkms_plane *primary, *cursor = NULL;
@@ -123,9 +126,12 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 
 	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
 
-	encoder = vkms_encoder_init(vkmsdev, BIT(0));
-	if (IS_ERR(encoder))
-		return PTR_ERR(encoder);
+	list_for_each_entry(encoder_cfg, &vkmsdev->config->encoders, list) {
+		encoder = vkms_encoder_init(vkmsdev, encoder_cfg->possible_crtcs,
+					    encoder_cfg->index);
+		if (IS_ERR(encoder))
+			return PTR_ERR(encoder);
+	}
 
 	ret = drm_connector_attach_encoder(connector, encoder);
 	if (ret) {
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 07/17] drm/vkms: Use managed memory to create connectors
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (5 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 06/17] drm/vkms: Allow to configure multiple encoders José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:58   ` Louis Chauvet
  2024-08-13 10:44 ` [RFC PATCH 08/17] drm/vkms: Allow to configure multiple connectors José Expósito
                   ` (11 subsequent siblings)
  18 siblings, 1 reply; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

A future patch will allow to create multiple connectors. Use managed
memory to simplify the code.

Refactor, no functional changes.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 drivers/gpu/drm/vkms/vkms_drv.h    |  5 ---
 drivers/gpu/drm/vkms/vkms_output.c | 53 +++++++++++++++++-------------
 2 files changed, 31 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 2466e8b0231f..cac37d21654a 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -121,14 +121,9 @@ struct vkms_crtc {
 
 struct vkms_config;
 
-struct vkms_output {
-	struct drm_connector connector;
-};
-
 struct vkms_device {
 	struct drm_device drm;
 	struct platform_device *platform;
-	struct vkms_output output;
 	struct list_head crtcs;
 	const struct vkms_config *config;
 };
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 7afe37aea52d..4413cf88afc7 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -9,7 +9,6 @@
 
 static const struct drm_connector_funcs vkms_connector_funcs = {
 	.fill_modes = drm_helper_probe_single_connector_modes,
-	.destroy = drm_connector_cleanup,
 	.reset = drm_atomic_helper_connector_reset,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
@@ -29,6 +28,33 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
 	.get_modes    = vkms_conn_get_modes,
 };
 
+static struct drm_connector *vkms_connector_init(struct vkms_device *vkms_device,
+						 uint32_t possible_encoders)
+{
+	struct drm_connector *connector;
+	int ret;
+
+	connector = drmm_kzalloc(&vkms_device->drm, sizeof(*connector), GFP_KERNEL);
+	if (!connector) {
+		DRM_ERROR("Failed to allocate connector\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	ret = drmm_connector_init(&vkms_device->drm, connector,
+				  &vkms_connector_funcs,
+				  DRM_MODE_CONNECTOR_VIRTUAL, NULL);
+	if (ret) {
+		DRM_ERROR("Failed to init connector\n");
+		kfree(connector);
+		return ERR_PTR(ret);
+	}
+
+	connector->possible_encoders = possible_encoders;
+	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
+
+	return connector;
+}
+
 static struct drm_encoder *vkms_encoder_init(struct vkms_device *vkms_device,
 					     uint32_t possible_crtcs,
 					     unsigned int index)
@@ -72,9 +98,8 @@ static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index)
 
 int vkms_output_init(struct vkms_device *vkmsdev, int index)
 {
-	struct vkms_output *output = &vkmsdev->output;
 	struct drm_device *dev = &vkmsdev->drm;
-	struct drm_connector *connector = &output->connector;
+	struct drm_connector *connector;
 	struct drm_encoder *encoder;
 	struct vkms_config_encoder *encoder_cfg;
 	struct vkms_crtc *vkms_crtc;
@@ -117,14 +142,9 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 		}
 	}
 
-	ret = drm_connector_init(dev, connector, &vkms_connector_funcs,
-				 DRM_MODE_CONNECTOR_VIRTUAL);
-	if (ret) {
-		DRM_ERROR("Failed to init connector\n");
-		return ret;
-	}
-
-	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
+	connector = vkms_connector_init(vkmsdev, BIT(index));
+	if (IS_ERR(connector))
+		return PTR_ERR(connector);
 
 	list_for_each_entry(encoder_cfg, &vkmsdev->config->encoders, list) {
 		encoder = vkms_encoder_init(vkmsdev, encoder_cfg->possible_crtcs,
@@ -133,18 +153,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 			return PTR_ERR(encoder);
 	}
 
-	ret = drm_connector_attach_encoder(connector, encoder);
-	if (ret) {
-		DRM_ERROR("Failed to attach connector to encoder\n");
-		goto err_attach;
-	}
-
 	drm_mode_config_reset(dev);
 
 	return 0;
-
-err_attach:
-	drm_connector_cleanup(connector);
-
-	return ret;
 }
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 08/17] drm/vkms: Allow to configure multiple connectors
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (6 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 07/17] drm/vkms: Use managed memory to create connectors José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:58   ` Louis Chauvet
  2024-08-13 10:44 ` [RFC PATCH 09/17] drm/vkms: Allow to configure multiple overlay planes José Expósito
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Add a list of connector configurations to vkms_config and add as many
connector as configured during output initialization.

For backwards compatibility, create a single connector in the default
configuration.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 40 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_config.h | 12 +++++++++
 drivers/gpu/drm/vkms/vkms_output.c | 11 +++++---
 3 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index 6a8dfebee24e..a456f9db3c66 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -19,6 +19,7 @@ struct vkms_config *vkms_config_create(char *dev_name)
 	config->dev_name = dev_name;
 	config->crtcs = (struct list_head)LIST_HEAD_INIT(config->crtcs);
 	config->encoders = (struct list_head)LIST_HEAD_INIT(config->encoders);
+	config->connectors = (struct list_head)LIST_HEAD_INIT(config->connectors);
 
 	return config;
 }
@@ -30,6 +31,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
 	struct vkms_config *config;
 	struct vkms_config_crtc *crtc_cfg;
 	struct vkms_config_encoder *encoder_cfg;
+	struct vkms_config_connector *connector_cfg;
 
 	config = vkms_config_create(DEFAULT_DEVICE_NAME);
 	if (IS_ERR(config))
@@ -46,6 +48,10 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
 	if (IS_ERR(encoder_cfg))
 		return ERR_CAST(encoder_cfg);
 
+	connector_cfg = vkms_config_add_connector(config, BIT(0));
+	if (IS_ERR(connector_cfg))
+		return ERR_CAST(connector_cfg);
+
 	return config;
 }
 
@@ -53,6 +59,7 @@ void vkms_config_destroy(struct vkms_config *config)
 {
 	struct vkms_config_crtc *crtc_cfg, *crtc_tmp;
 	struct vkms_config_encoder *encoder_cfg, *encoder_tmp;
+	struct vkms_config_connector *connector_cfg, *connector_tmp;
 
 	list_for_each_entry_safe(crtc_cfg, crtc_tmp, &config->crtcs, list)
 		vkms_config_destroy_crtc(config, crtc_cfg);
@@ -60,6 +67,9 @@ void vkms_config_destroy(struct vkms_config *config)
 	list_for_each_entry_safe(encoder_cfg, encoder_tmp, &config->encoders, list)
 		vkms_config_destroy_encoder(config, encoder_cfg);
 
+	list_for_each_entry_safe(connector_cfg, connector_tmp, &config->connectors, list)
+		vkms_config_destroy_connector(config, connector_cfg);
+
 	kfree(config);
 }
 
@@ -70,6 +80,7 @@ static int vkms_config_show(struct seq_file *m, void *data)
 	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
 	struct vkms_config_crtc *crtc_cfg;
 	struct vkms_config_encoder *encoder_cfg;
+	struct vkms_config_connector *connector_cfg;
 	int n;
 
 	seq_printf(m, "dev_name=%s\n", vkmsdev->config->dev_name);
@@ -90,6 +101,13 @@ static int vkms_config_show(struct seq_file *m, void *data)
 		n++;
 	}
 
+	n = 0;
+	list_for_each_entry(connector_cfg, &vkmsdev->config->connectors, list) {
+		seq_printf(m, "connector(%d).possible_encoders=%d\n", n,
+			   connector_cfg->possible_encoders);
+		n++;
+	}
+
 	return 0;
 }
 
@@ -166,3 +184,25 @@ void vkms_config_destroy_encoder(struct vkms_config *config,
 	list_del(&encoder_cfg->list);
 	kfree(encoder_cfg);
 }
+
+struct vkms_config_connector *vkms_config_add_connector(struct vkms_config *config,
+							uint32_t possible_encoders)
+{
+	struct vkms_config_connector *connector_cfg;
+
+	connector_cfg = kzalloc(sizeof(*connector_cfg), GFP_KERNEL);
+	if (!connector_cfg)
+		return ERR_PTR(-ENOMEM);
+
+	connector_cfg->possible_encoders = possible_encoders;
+	list_add_tail(&connector_cfg->list, &config->connectors);
+
+	return connector_cfg;
+}
+
+void vkms_config_destroy_connector(struct vkms_config *config,
+				   struct vkms_config_connector *connector_cfg)
+{
+	list_del(&connector_cfg->list);
+	kfree(connector_cfg);
+}
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index b717b5c0d3d9..f1dd59fc6300 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -20,12 +20,18 @@ struct vkms_config_encoder {
 	uint32_t possible_crtcs;
 };
 
+struct vkms_config_connector {
+	struct list_head list;
+	uint32_t possible_encoders;
+};
+
 struct vkms_config {
 	char *dev_name;
 	bool cursor;
 	bool overlay;
 	struct list_head crtcs;
 	struct list_head encoders;
+	struct list_head connectors;
 	/* only set when instantiated */
 	struct vkms_device *dev;
 };
@@ -52,4 +58,10 @@ struct vkms_config_encoder *vkms_config_add_encoder(struct vkms_config *config,
 void vkms_config_destroy_encoder(struct vkms_config *config,
 				 struct vkms_config_encoder *encoder_cfg);
 
+/* Connectors */
+struct vkms_config_connector *vkms_config_add_connector(struct vkms_config *config,
+							uint32_t possible_encoders);
+void vkms_config_destroy_connector(struct vkms_config *config,
+				   struct vkms_config_connector *connector_cfg);
+
 #endif /* _VKMS_CONFIG_H_ */
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 4413cf88afc7..021a491de817 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -100,6 +100,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 {
 	struct drm_device *dev = &vkmsdev->drm;
 	struct drm_connector *connector;
+	struct vkms_config_connector *connector_cfg;
 	struct drm_encoder *encoder;
 	struct vkms_config_encoder *encoder_cfg;
 	struct vkms_crtc *vkms_crtc;
@@ -142,10 +143,6 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 		}
 	}
 
-	connector = vkms_connector_init(vkmsdev, BIT(index));
-	if (IS_ERR(connector))
-		return PTR_ERR(connector);
-
 	list_for_each_entry(encoder_cfg, &vkmsdev->config->encoders, list) {
 		encoder = vkms_encoder_init(vkmsdev, encoder_cfg->possible_crtcs,
 					    encoder_cfg->index);
@@ -153,6 +150,12 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 			return PTR_ERR(encoder);
 	}
 
+	list_for_each_entry(connector_cfg, &vkmsdev->config->connectors, list) {
+		connector = vkms_connector_init(vkmsdev, connector_cfg->possible_encoders);
+		if (IS_ERR(connector))
+			return PTR_ERR(connector);
+	}
+
 	drm_mode_config_reset(dev);
 
 	return 0;
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 09/17] drm/vkms: Allow to configure multiple overlay planes
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (7 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 08/17] drm/vkms: Allow to configure multiple connectors José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:58   ` Louis Chauvet
  2024-08-13 10:44 ` [RFC PATCH 10/17] drm/vkms: Allow to change connector status José Expósito
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Add a list of overlay planes to vkms_config and add as many overlay
planes as configured during output initialization.

For backwards compatibility, add NUM_OVERLAY_PLANES to the default
configuration.

Note that a primary plane is created for each CRTC and it is not
possible to configure it.
A cursor plane is added conditionally if it is enabled in the CRTC
configuration.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 53 +++++++++++++++++++++++++++---
 drivers/gpu/drm/vkms/vkms_config.h | 16 +++++++--
 drivers/gpu/drm/vkms/vkms_drv.c    |  2 +-
 drivers/gpu/drm/vkms/vkms_drv.h    |  5 +--
 drivers/gpu/drm/vkms/vkms_output.c | 43 ++++++++++++------------
 drivers/gpu/drm/vkms/vkms_plane.c  |  6 ++--
 6 files changed, 91 insertions(+), 34 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index a456f9db3c66..d95a42a6745a 100644
--- a/drivers/gpu/drm/vkms/vkms_config.c
+++ b/drivers/gpu/drm/vkms/vkms_config.c
@@ -17,6 +17,7 @@ struct vkms_config *vkms_config_create(char *dev_name)
 		return ERR_PTR(-ENOMEM);
 
 	config->dev_name = dev_name;
+	config->planes = (struct list_head)LIST_HEAD_INIT(config->planes);
 	config->crtcs = (struct list_head)LIST_HEAD_INIT(config->crtcs);
 	config->encoders = (struct list_head)LIST_HEAD_INIT(config->encoders);
 	config->connectors = (struct list_head)LIST_HEAD_INIT(config->connectors);
@@ -32,15 +33,22 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
 	struct vkms_config_crtc *crtc_cfg;
 	struct vkms_config_encoder *encoder_cfg;
 	struct vkms_config_connector *connector_cfg;
+	struct vkms_config_plane *plane_cfg;
+	int n;
 
 	config = vkms_config_create(DEFAULT_DEVICE_NAME);
 	if (IS_ERR(config))
 		return config;
 
-	config->cursor = enable_cursor;
-	config->overlay = enable_overlay;
+	if (enable_overlay) {
+		for (n = 0; n < NUM_OVERLAY_PLANES; n++) {
+			plane_cfg = vkms_config_add_overlay_plane(config, BIT(0));
+			if (IS_ERR(plane_cfg))
+				return ERR_CAST(plane_cfg);
+		}
+	}
 
-	crtc_cfg = vkms_config_add_crtc(config, enable_writeback);
+	crtc_cfg = vkms_config_add_crtc(config, enable_cursor, enable_writeback);
 	if (IS_ERR(crtc_cfg))
 		return ERR_CAST(crtc_cfg);
 
@@ -57,10 +65,14 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
 
 void vkms_config_destroy(struct vkms_config *config)
 {
+	struct vkms_config_plane *plane_cfg, *plane_tmp;
 	struct vkms_config_crtc *crtc_cfg, *crtc_tmp;
 	struct vkms_config_encoder *encoder_cfg, *encoder_tmp;
 	struct vkms_config_connector *connector_cfg, *connector_tmp;
 
+	list_for_each_entry_safe(plane_cfg, plane_tmp, &config->planes, list)
+		vkms_config_destroy_overlay_plane(config, plane_cfg);
+
 	list_for_each_entry_safe(crtc_cfg, crtc_tmp, &config->crtcs, list)
 		vkms_config_destroy_crtc(config, crtc_cfg);
 
@@ -78,17 +90,24 @@ static int vkms_config_show(struct seq_file *m, void *data)
 	struct drm_debugfs_entry *entry = m->private;
 	struct drm_device *dev = entry->dev;
 	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
+	struct vkms_config_plane *plane_cfg;
 	struct vkms_config_crtc *crtc_cfg;
 	struct vkms_config_encoder *encoder_cfg;
 	struct vkms_config_connector *connector_cfg;
 	int n;
 
 	seq_printf(m, "dev_name=%s\n", vkmsdev->config->dev_name);
-	seq_printf(m, "cursor=%d\n", vkmsdev->config->cursor);
-	seq_printf(m, "overlay=%d\n", vkmsdev->config->overlay);
+
+	n = 0;
+	list_for_each_entry(plane_cfg, &vkmsdev->config->planes, list) {
+		seq_printf(m, "plane(%d).possible_crtcs=%d\n", n,
+			   plane_cfg->possible_crtcs);
+		n++;
+	}
 
 	n = 0;
 	list_for_each_entry(crtc_cfg, &vkmsdev->config->crtcs, list) {
+		seq_printf(m, "crtc(%d).cursor=%d\n", n, crtc_cfg->cursor);
 		seq_printf(m, "crtc(%d).writeback=%d\n", n,
 			   crtc_cfg->writeback);
 		n++;
@@ -121,7 +140,30 @@ void vkms_config_debugfs_init(struct vkms_device *vkms_device)
 			      ARRAY_SIZE(vkms_config_debugfs_list));
 }
 
+struct vkms_config_plane *vkms_config_add_overlay_plane(struct vkms_config *config,
+							uint32_t possible_crtcs)
+{
+	struct vkms_config_plane *plane_cfg;
+
+	plane_cfg = kzalloc(sizeof(*plane_cfg), GFP_KERNEL);
+	if (!plane_cfg)
+		return ERR_PTR(-ENOMEM);
+
+	plane_cfg->possible_crtcs = possible_crtcs;
+	list_add_tail(&plane_cfg->list, &config->planes);
+
+	return plane_cfg;
+}
+
+void vkms_config_destroy_overlay_plane(struct vkms_config *config,
+				       struct vkms_config_plane *plane_cfg)
+{
+	list_del(&plane_cfg->list);
+	kfree(plane_cfg);
+}
+
 struct vkms_config_crtc *vkms_config_add_crtc(struct vkms_config *config,
+					      bool enable_cursor,
 					      bool enable_writeback)
 {
 	struct vkms_config_crtc *crtc_cfg;
@@ -130,6 +172,7 @@ struct vkms_config_crtc *vkms_config_add_crtc(struct vkms_config *config,
 	if (!crtc_cfg)
 		return ERR_PTR(-ENOMEM);
 
+	crtc_cfg->cursor = enable_cursor;
 	crtc_cfg->writeback = enable_writeback;
 
 	crtc_cfg->index = 0;
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index f1dd59fc6300..25dab63e7ae7 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -8,9 +8,15 @@
 
 struct vkms_device;
 
+struct vkms_config_plane {
+	struct list_head list;
+	uint32_t possible_crtcs;
+};
+
 struct vkms_config_crtc {
 	struct list_head list;
 	unsigned int index;
+	bool cursor;
 	bool writeback;
 };
 
@@ -27,8 +33,7 @@ struct vkms_config_connector {
 
 struct vkms_config {
 	char *dev_name;
-	bool cursor;
-	bool overlay;
+	struct list_head planes;
 	struct list_head crtcs;
 	struct list_head encoders;
 	struct list_head connectors;
@@ -46,8 +51,15 @@ void vkms_config_destroy(struct vkms_config *config);
 /* DebugFS */
 void vkms_config_debugfs_init(struct vkms_device *vkms_device);
 
+/* Planes */
+struct vkms_config_plane *vkms_config_add_overlay_plane(struct vkms_config *config,
+							uint32_t possible_crtcs);
+void vkms_config_destroy_overlay_plane(struct vkms_config *config,
+				       struct vkms_config_plane *plane_cfg);
+
 /* CRTCs */
 struct vkms_config_crtc *vkms_config_add_crtc(struct vkms_config *config,
+					      bool enable_cursor,
 					      bool enable_writeback);
 void vkms_config_destroy_crtc(struct vkms_config *config,
 			      struct vkms_config_crtc *crtc_cfg);
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index 15a2ba26d190..b0a079eb4598 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -154,7 +154,7 @@ static int vkms_modeset_init(struct vkms_device *vkmsdev)
 	dev->mode_config.preferred_depth = 0;
 	dev->mode_config.helper_private = &vkms_mode_config_helpers;
 
-	return vkms_output_init(vkmsdev, 0);
+	return vkms_output_init(vkmsdev);
 }
 
 static int vkms_create(struct vkms_config *config)
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index cac37d21654a..76394285dc68 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -149,10 +149,11 @@ struct vkms_crtc *vkms_crtc_init(struct drm_device *dev,
 				 struct drm_plane *cursor,
 				 unsigned int index);
 
-int vkms_output_init(struct vkms_device *vkmsdev, int index);
+int vkms_output_init(struct vkms_device *vkmsdev);
 
 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
-				   enum drm_plane_type type, int index);
+				   enum drm_plane_type type,
+				   uint32_t possible_crtcs);
 
 /* CRC Support */
 const char *const *vkms_get_crc_sources(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index 021a491de817..a5b1ab326cdd 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -82,21 +82,22 @@ static struct drm_encoder *vkms_encoder_init(struct vkms_device *vkms_device,
 	return encoder;
 }
 
-static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index)
+static int vkms_add_overlay_plane(struct vkms_device *vkmsdev,
+				  uint32_t possible_crtcs)
 {
 	struct vkms_plane *overlay;
 
-	overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, index);
+	overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, possible_crtcs);
 	if (IS_ERR(overlay))
 		return PTR_ERR(overlay);
 
 	if (!overlay->base.possible_crtcs)
-		overlay->base.possible_crtcs = BIT(index);
+		overlay->base.possible_crtcs = possible_crtcs;
 
 	return 0;
 }
 
-int vkms_output_init(struct vkms_device *vkmsdev, int index)
+int vkms_output_init(struct vkms_device *vkmsdev)
 {
 	struct drm_device *dev = &vkmsdev->drm;
 	struct drm_connector *connector;
@@ -106,29 +107,27 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 	struct vkms_crtc *vkms_crtc;
 	struct vkms_config_crtc *crtc_cfg;
 	struct vkms_plane *primary, *cursor = NULL;
+	struct vkms_config_plane *plane_cfg;
 	int ret;
 	int writeback;
-	unsigned int n;
 
-	primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY, index);
-	if (IS_ERR(primary))
-		return PTR_ERR(primary);
-
-	if (vkmsdev->config->overlay) {
-		for (n = 0; n < NUM_OVERLAY_PLANES; n++) {
-			ret = vkms_add_overlay_plane(vkmsdev, index);
-			if (ret)
-				return ret;
-		}
-	}
-
-	if (vkmsdev->config->cursor) {
-		cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR, index);
-		if (IS_ERR(cursor))
-			return PTR_ERR(cursor);
+	list_for_each_entry(plane_cfg, &vkmsdev->config->planes, list) {
+		ret = vkms_add_overlay_plane(vkmsdev, plane_cfg->possible_crtcs);
+		if (ret)
+			return ret;
 	}
 
 	list_for_each_entry(crtc_cfg, &vkmsdev->config->crtcs, list) {
+		primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY, 0);
+		if (IS_ERR(primary))
+			return PTR_ERR(primary);
+
+		if (crtc_cfg->cursor) {
+			cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR, 0);
+			if (IS_ERR(cursor))
+				return PTR_ERR(cursor);
+		}
+
 		vkms_crtc = vkms_crtc_init(dev, &primary->base, &cursor->base,
 					   crtc_cfg->index);
 		if (IS_ERR(vkms_crtc))
@@ -141,6 +140,8 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
 			if (writeback)
 				DRM_ERROR("Failed to init writeback connector\n");
 		}
+
+		cursor = NULL;
 	}
 
 	list_for_each_entry(encoder_cfg, &vkmsdev->config->encoders, list) {
diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
index e5c625ab8e3e..eb3edf4cb928 100644
--- a/drivers/gpu/drm/vkms/vkms_plane.c
+++ b/drivers/gpu/drm/vkms/vkms_plane.c
@@ -198,13 +198,13 @@ static const struct drm_plane_helper_funcs vkms_plane_helper_funcs = {
 };
 
 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
-				   enum drm_plane_type type, int index)
+				   enum drm_plane_type type, uint32_t possible_crtcs)
 {
 	struct drm_device *dev = &vkmsdev->drm;
 	struct vkms_plane *plane;
 
-	plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 1 << index,
-					   &vkms_plane_funcs,
+	plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base,
+					   possible_crtcs, &vkms_plane_funcs,
 					   vkms_formats, ARRAY_SIZE(vkms_formats),
 					   NULL, type, NULL);
 	if (IS_ERR(plane))
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 10/17] drm/vkms: Allow to change connector status
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (8 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 09/17] drm/vkms: Allow to configure multiple overlay planes José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:58   ` Louis Chauvet
  2024-08-13 10:44 ` [RFC PATCH 11/17] drm/vkms: Add and remove VKMS instances via configfs José Expósito
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Store the connector status in vkms_config_connector and use the stored
value to update the connector status in the drm_connector_funcs.detect()
function.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 drivers/gpu/drm/vkms/vkms_config.c | 18 ++++++++++++++++--
 drivers/gpu/drm/vkms/vkms_config.h | 12 +++++++++++-
 drivers/gpu/drm/vkms/vkms_output.c | 20 ++++++++++++++++++++
 3 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
index d95a42a6745a..e8e5c02c9d43 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 <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
 #include <drm/drm_debugfs.h>
 
 #include "vkms_config.h"
@@ -56,7 +57,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
 	if (IS_ERR(encoder_cfg))
 		return ERR_CAST(encoder_cfg);
 
-	connector_cfg = vkms_config_add_connector(config, BIT(0));
+	connector_cfg = vkms_config_add_connector(config, BIT(0), connector_status_connected);
 	if (IS_ERR(connector_cfg))
 		return ERR_CAST(connector_cfg);
 
@@ -124,6 +125,8 @@ static int vkms_config_show(struct seq_file *m, void *data)
 	list_for_each_entry(connector_cfg, &vkmsdev->config->connectors, list) {
 		seq_printf(m, "connector(%d).possible_encoders=%d\n", n,
 			   connector_cfg->possible_encoders);
+		seq_printf(m, "connector(%d).status=%d\n", n,
+			   connector_cfg->status);
 		n++;
 	}
 
@@ -229,7 +232,8 @@ void vkms_config_destroy_encoder(struct vkms_config *config,
 }
 
 struct vkms_config_connector *vkms_config_add_connector(struct vkms_config *config,
-							uint32_t possible_encoders)
+							uint32_t possible_encoders,
+							enum drm_connector_status status)
 {
 	struct vkms_config_connector *connector_cfg;
 
@@ -238,6 +242,7 @@ struct vkms_config_connector *vkms_config_add_connector(struct vkms_config *conf
 		return ERR_PTR(-ENOMEM);
 
 	connector_cfg->possible_encoders = possible_encoders;
+	connector_cfg->status = status;
 	list_add_tail(&connector_cfg->list, &config->connectors);
 
 	return connector_cfg;
@@ -249,3 +254,12 @@ void vkms_config_destroy_connector(struct vkms_config *config,
 	list_del(&connector_cfg->list);
 	kfree(connector_cfg);
 }
+
+void vkms_update_connector_status(struct vkms_config *config,
+				  struct vkms_config_connector *connector_cfg,
+				  enum drm_connector_status status)
+{
+	connector_cfg->status = status;
+	if (config->dev)
+		drm_kms_helper_hotplug_event(&config->dev->drm);
+}
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 25dab63e7ae7..3237406fa3a3 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -6,6 +6,8 @@
 #include <linux/list.h>
 #include <linux/types.h>
 
+#include <drm/drm_connector.h>
+
 struct vkms_device;
 
 struct vkms_config_plane {
@@ -29,6 +31,9 @@ struct vkms_config_encoder {
 struct vkms_config_connector {
 	struct list_head list;
 	uint32_t possible_encoders;
+	enum drm_connector_status status;
+	/* only set when instantiated */
+	struct drm_connector *connector;
 };
 
 struct vkms_config {
@@ -72,8 +77,13 @@ void vkms_config_destroy_encoder(struct vkms_config *config,
 
 /* Connectors */
 struct vkms_config_connector *vkms_config_add_connector(struct vkms_config *config,
-							uint32_t possible_encoders);
+							uint32_t possible_encoders,
+							enum drm_connector_status status);
 void vkms_config_destroy_connector(struct vkms_config *config,
 				   struct vkms_config_connector *connector_cfg);
 
+void vkms_update_connector_status(struct vkms_config *config,
+				  struct vkms_config_connector *connector_cfg,
+				  enum drm_connector_status status);
+
 #endif /* _VKMS_CONFIG_H_ */
diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
index a5b1ab326cdd..511cc2c14c44 100644
--- a/drivers/gpu/drm/vkms/vkms_output.c
+++ b/drivers/gpu/drm/vkms/vkms_output.c
@@ -7,7 +7,25 @@
 #include <drm/drm_managed.h>
 #include <drm/drm_probe_helper.h>
 
+static enum drm_connector_status vkms_connector_detect(struct drm_connector *connector,
+						       bool force)
+{
+	struct vkms_device *vkmsdev = drm_device_to_vkms_device(connector->dev);
+	enum drm_connector_status status = connector->status;
+	struct vkms_config_connector *connector_cfg;
+
+	list_for_each_entry(connector_cfg, &vkmsdev->config->connectors, list) {
+		if (connector_cfg->connector == connector) {
+			status = connector_cfg->status;
+			break;
+		}
+	}
+
+	return status;
+}
+
 static const struct drm_connector_funcs vkms_connector_funcs = {
+	.detect = vkms_connector_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.reset = drm_atomic_helper_connector_reset,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -155,6 +173,8 @@ int vkms_output_init(struct vkms_device *vkmsdev)
 		connector = vkms_connector_init(vkmsdev, connector_cfg->possible_encoders);
 		if (IS_ERR(connector))
 			return PTR_ERR(connector);
+
+		connector_cfg->connector = connector;
 	}
 
 	drm_mode_config_reset(dev);
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 11/17] drm/vkms: Add and remove VKMS instances via configfs
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (9 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 10/17] drm/vkms: Allow to change connector status José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:58   ` Louis Chauvet
  2024-08-13 10:44 ` [RFC PATCH 12/17] drm/vkms: Allow to configure multiple CRTCs " José Expósito
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Allow to create, enable, disable and destroy VKMS instances using
configfs.

For the moment, add one primary plane, one CRC, one encoder and one
connector until we add support to configure them via configfs.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 Documentation/gpu/vkms.rst           |  32 +++++
 drivers/gpu/drm/vkms/Kconfig         |   1 +
 drivers/gpu/drm/vkms/Makefile        |   3 +-
 drivers/gpu/drm/vkms/vkms_configfs.c | 198 +++++++++++++++++++++++++++
 drivers/gpu/drm/vkms/vkms_configfs.h |   9 ++
 drivers/gpu/drm/vkms/vkms_drv.c      |  19 ++-
 drivers/gpu/drm/vkms/vkms_drv.h      |   4 +
 7 files changed, 262 insertions(+), 4 deletions(-)
 create mode 100644 drivers/gpu/drm/vkms/vkms_configfs.c
 create mode 100644 drivers/gpu/drm/vkms/vkms_configfs.h

diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index ba04ac7c2167..9895a9ae76f4 100644
--- a/Documentation/gpu/vkms.rst
+++ b/Documentation/gpu/vkms.rst
@@ -51,6 +51,38 @@ To disable the driver, use ::
 
   sudo modprobe -r vkms
 
+Configuring With Configfs
+=========================
+
+It is possible to create and configure multiple VKMS instances via configfs.
+
+Start by mounting configfs and loading VKMS::
+
+  sudo mount -t configfs none /config
+  sudo modprobe vkms
+
+Once VKMS is loaded, ``/config/vkms`` is created automatically. Each directory
+under ``/config/vkms`` represents a VKMS instance, create a new one::
+
+  sudo mkdir /config/vkms/my-vkms
+
+By default, the instance is disabled::
+
+  cat /config/vkms/my-vkms/enabled
+  0
+
+Once you are done configuring the VKMS instance, enable it::
+
+  echo "1" | sudo tee /config/vkms/my-vkms/enabled
+
+Finally, you can remove the VKMS instance disabling it::
+
+  echo "0" | sudo tee /config/vkms/my-vkms/enabled
+
+Or removing the top level directory::
+
+  sudo rmdir /config/vkms/my-vkms
+
 Testing With IGT
 ================
 
diff --git a/drivers/gpu/drm/vkms/Kconfig b/drivers/gpu/drm/vkms/Kconfig
index b9ecdebecb0b..de218b21a579 100644
--- a/drivers/gpu/drm/vkms/Kconfig
+++ b/drivers/gpu/drm/vkms/Kconfig
@@ -6,6 +6,7 @@ config DRM_VKMS
 	select DRM_KMS_HELPER
 	select DRM_GEM_SHMEM_HELPER
 	select CRC32
+	select CONFIGFS_FS
 	default n
 	help
 	  Virtual Kernel Mode-Setting (VKMS) is used for testing or for
diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile
index b371b5d70ee3..81c257d37689 100644
--- a/drivers/gpu/drm/vkms/Makefile
+++ b/drivers/gpu/drm/vkms/Makefile
@@ -7,6 +7,7 @@ vkms-y := \
 	vkms_crtc.o \
 	vkms_composer.o \
 	vkms_writeback.o \
-	vkms_config.o
+	vkms_config.o \
+	vkms_configfs.o
 
 obj-$(CONFIG_DRM_VKMS) += vkms.o
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
new file mode 100644
index 000000000000..3f25295f7788
--- /dev/null
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/configfs.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include "vkms_drv.h"
+#include "vkms_config.h"
+#include "vkms_configfs.h"
+
+/* To avoid registering configfs more than once or unregistering on error */
+static bool is_configfs_registered;
+
+/**
+ * struct vkms_configfs - Configfs configuration for a VKMS device
+ *
+ * @vkms_config: Configuration of the VKMS device
+ * @device_group: Top level configuration group that represents a VKMS device.
+ * Initialized when a new directory is created under "/config/vkms/"
+ * @lock: Lock used to project concurrent access to the configuration attributes
+ * @enabled: Protected by @lock. The device is created or destroyed when this
+ * option changes
+ */
+struct vkms_configfs {
+	struct vkms_config *vkms_config;
+	struct config_group device_group;
+
+	/* protected by @lock */
+	struct mutex lock;
+	bool enabled;
+};
+
+#define config_item_to_vkms_configfs(item) \
+	container_of(to_config_group(item), struct vkms_configfs, device_group)
+
+static ssize_t device_enabled_show(struct config_item *item, char *page)
+{
+	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
+
+	return sprintf(page, "%d\n", configfs->enabled);
+}
+
+static ssize_t device_enabled_store(struct config_item *item, const char *page,
+				    size_t count)
+{
+	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
+	bool enabled;
+	int ret = 0;
+
+	if (kstrtobool(page, &enabled))
+		return -EINVAL;
+
+	mutex_lock(&configfs->lock);
+
+	if (!configfs->enabled && enabled)
+		ret = vkms_create(configfs->vkms_config);
+	else if (configfs->enabled && !enabled)
+		vkms_destroy(configfs->vkms_config);
+
+	if (ret)
+		goto err_unlock;
+
+	configfs->enabled = enabled;
+
+	mutex_unlock(&configfs->lock);
+
+	return (ssize_t)count;
+
+err_unlock:
+	mutex_unlock(&configfs->lock);
+	return ret;
+}
+
+CONFIGFS_ATTR(device_, enabled);
+
+static struct configfs_attribute *device_group_attrs[] = {
+	&device_attr_enabled,
+	NULL,
+};
+
+static const struct config_item_type device_group_type = {
+	.ct_attrs = device_group_attrs,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_group *make_device_group(struct config_group *group,
+					      const char *name)
+{
+	struct vkms_configfs *configfs;
+	struct vkms_config_crtc *crtc_cfg = NULL;
+	struct vkms_config_encoder *encoder_cfg = NULL;
+	struct vkms_config_connector *connector_cfg = NULL;
+	char *config_name;
+	int ret;
+
+	if (strcmp(name, DEFAULT_DEVICE_NAME) == 0)
+		return ERR_PTR(-EINVAL);
+
+	configfs = kzalloc(sizeof(*configfs), GFP_KERNEL);
+	if (!configfs)
+		return ERR_PTR(-ENOMEM);
+
+	config_group_init_type_name(&configfs->device_group, name, &device_group_type);
+	mutex_init(&configfs->lock);
+
+	config_name = config_item_name(&configfs->device_group.cg_item);
+	configfs->vkms_config = vkms_config_create(config_name);
+	if (IS_ERR(configfs->vkms_config)) {
+		ret = PTR_ERR(configfs->vkms_config);
+		goto err_kfree;
+	}
+
+	crtc_cfg = vkms_config_add_crtc(configfs->vkms_config, false, false);
+	if (IS_ERR(crtc_cfg)) {
+		ret = PTR_ERR(crtc_cfg);
+		goto err_kfree;
+	}
+
+	encoder_cfg = vkms_config_add_encoder(configfs->vkms_config, BIT(0));
+	if (IS_ERR(encoder_cfg)) {
+		ret = PTR_ERR(encoder_cfg);
+		goto err_kfree;
+	}
+
+	connector_cfg = vkms_config_add_connector(configfs->vkms_config, BIT(0),
+						  connector_status_connected);
+	if (IS_ERR(connector_cfg)) {
+		ret = PTR_ERR(connector_cfg);
+		goto err_kfree;
+	}
+
+	return &configfs->device_group;
+
+err_kfree:
+	kfree(configfs);
+	kfree(crtc_cfg);
+	kfree(encoder_cfg);
+	kfree(connector_cfg);
+	return ERR_PTR(ret);
+}
+
+static void drop_device_group(struct config_group *group,
+			      struct config_item *item)
+{
+	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
+
+	mutex_lock(&configfs->lock);
+
+	if (configfs->enabled)
+		vkms_destroy(configfs->vkms_config);
+
+	kfree(configfs->vkms_config);
+
+	mutex_unlock(&configfs->lock);
+
+	kfree(configfs);
+}
+
+static struct configfs_group_operations device_group_ops = {
+	.make_group = &make_device_group,
+	.drop_item = &drop_device_group,
+};
+
+static struct config_item_type vkms_type = {
+	.ct_group_ops = &device_group_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct configfs_subsystem vkms_subsys = {
+	.su_group = {
+		.cg_item = {
+			.ci_name = "vkms",
+			.ci_type = &vkms_type,
+		},
+	},
+	.su_mutex = __MUTEX_INITIALIZER(vkms_subsys.su_mutex),
+};
+
+int vkms_configfs_register(void)
+{
+	int ret;
+
+	if (is_configfs_registered)
+		return 0;
+
+	config_group_init(&vkms_subsys.su_group);
+	ret = configfs_register_subsystem(&vkms_subsys);
+
+	is_configfs_registered = ret == 0;
+
+	return ret;
+}
+
+void vkms_configfs_unregister(void)
+{
+	if (is_configfs_registered)
+		configfs_unregister_subsystem(&vkms_subsys);
+}
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.h b/drivers/gpu/drm/vkms/vkms_configfs.h
new file mode 100644
index 000000000000..b5d7fab877d5
--- /dev/null
+++ b/drivers/gpu/drm/vkms/vkms_configfs.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef _VKMS_CONFIGFS_H_
+#define _VKMS_CONFIGFS_H_
+
+int vkms_configfs_register(void);
+void vkms_configfs_unregister(void);
+
+#endif /* _VKMS_CONFIGFS_H_ */
diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index b0a079eb4598..f524a9550017 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -27,6 +27,7 @@
 #include <drm/drm_vblank.h>
 
 #include "vkms_config.h"
+#include "vkms_configfs.h"
 #include "vkms_drv.h"
 
 #define DRIVER_NAME	"vkms"
@@ -157,7 +158,7 @@ static int vkms_modeset_init(struct vkms_device *vkmsdev)
 	return vkms_output_init(vkmsdev);
 }
 
-static int vkms_create(struct vkms_config *config)
+int vkms_create(struct vkms_config *config)
 {
 	int ret;
 	struct platform_device *pdev;
@@ -231,12 +232,22 @@ static int __init vkms_init(void)
 
 	ret = vkms_create(config);
 	if (ret)
-		vkms_config_destroy(config);
+		goto err_kfree;
 
+	ret = vkms_configfs_register();
+	if (ret)
+		goto err_destroy;
+
+	return 0;
+
+err_destroy:
+	vkms_destroy(config);
+err_kfree:
+	vkms_config_destroy(config);
 	return ret;
 }
 
-static void vkms_destroy(struct vkms_config *config)
+void vkms_destroy(struct vkms_config *config)
 {
 	struct platform_device *pdev;
 
@@ -257,6 +268,8 @@ static void vkms_destroy(struct vkms_config *config)
 
 static void __exit vkms_exit(void)
 {
+	vkms_configfs_unregister();
+
 	if (default_config->dev)
 		vkms_destroy(default_config);
 
diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
index 76394285dc68..eb32440e9f94 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.h
+++ b/drivers/gpu/drm/vkms/vkms_drv.h
@@ -143,6 +143,10 @@ struct vkms_device {
 #define to_vkms_plane_state(target)\
 	container_of(target, struct vkms_plane_state, base.base)
 
+/* VKMS device */
+int vkms_create(struct vkms_config *config);
+void vkms_destroy(struct vkms_config *config);
+
 /* CRTC */
 struct vkms_crtc *vkms_crtc_init(struct drm_device *dev,
 				 struct drm_plane *primary,
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 12/17] drm/vkms: Allow to configure multiple CRTCs via configfs
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (10 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 11/17] drm/vkms: Add and remove VKMS instances via configfs José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:58   ` Louis Chauvet
  2024-08-13 10:44 ` [RFC PATCH 13/17] drm/vkms: Allow to configure multiple encoders " José Expósito
                   ` (6 subsequent siblings)
  18 siblings, 1 reply; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Create a default subgroup at /config/vkms/crtcs to allow to create as
many CRTCs as required. When a CRTC is created, allow to configure the
equivalent of the module parameters enable_cursor and enable_writeback.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 Documentation/gpu/vkms.rst           |  22 +++-
 drivers/gpu/drm/vkms/vkms_config.h   |   3 +
 drivers/gpu/drm/vkms/vkms_configfs.c | 149 +++++++++++++++++++++++++--
 3 files changed, 166 insertions(+), 8 deletions(-)

diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index 9895a9ae76f4..0886349ad4a0 100644
--- a/Documentation/gpu/vkms.rst
+++ b/Documentation/gpu/vkms.rst
@@ -71,6 +71,25 @@ By default, the instance is disabled::
   cat /config/vkms/my-vkms/enabled
   0
 
+And directories are created for each configurable item of the display pipeline::
+
+  tree /config/vkms/my-vkms
+    /config/vkms/my-vkms
+    ├── crtcs
+    └── enabled
+
+To add items to the display pipeline, create one or more directories under the
+available paths.
+
+Start by creating one or more CRTCs::
+
+  sudo mkdir /config/vkms/my-vkms/crtcs/crtc0
+
+CRTCs have 2 configurable attributes:
+
+- cursor: Enable or disable cursor plane support
+- writeback: Enable or disable writeback connector support
+
 Once you are done configuring the VKMS instance, enable it::
 
   echo "1" | sudo tee /config/vkms/my-vkms/enabled
@@ -79,8 +98,9 @@ Finally, you can remove the VKMS instance disabling it::
 
   echo "0" | sudo tee /config/vkms/my-vkms/enabled
 
-Or removing the top level directory::
+Or removing the top level directory and its subdirectories::
 
+  sudo rmdir /config/vkms/my-vkms/crtcs/*
   sudo rmdir /config/vkms/my-vkms
 
 Testing With IGT
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index 3237406fa3a3..f96a0456a3d7 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/configfs.h>
 #include <linux/list.h>
 #include <linux/types.h>
 
@@ -20,6 +21,8 @@ struct vkms_config_crtc {
 	unsigned int index;
 	bool cursor;
 	bool writeback;
+	/* only used if created from configfs */
+	struct config_group crtc_group;
 };
 
 struct vkms_config_encoder {
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index 3f25295f7788..04278a39cd3c 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -17,6 +17,8 @@ static bool is_configfs_registered;
  * @vkms_config: Configuration of the VKMS device
  * @device_group: Top level configuration group that represents a VKMS device.
  * Initialized when a new directory is created under "/config/vkms/"
+ * @crtcs_group: Default subgroup of @device_group at "/config/vkms/crtcs".
+ * Each of its items represent a CRTC
  * @lock: Lock used to project concurrent access to the configuration attributes
  * @enabled: Protected by @lock. The device is created or destroyed when this
  * option changes
@@ -24,6 +26,7 @@ static bool is_configfs_registered;
 struct vkms_configfs {
 	struct vkms_config *vkms_config;
 	struct config_group device_group;
+	struct config_group crtcs_group;
 
 	/* protected by @lock */
 	struct mutex lock;
@@ -33,6 +36,141 @@ struct vkms_configfs {
 #define config_item_to_vkms_configfs(item) \
 	container_of(to_config_group(item), struct vkms_configfs, device_group)
 
+#define crtcs_group_to_vkms_configfs(group) \
+	container_of(group, struct vkms_configfs, crtcs_group)
+
+#define crtcs_item_to_vkms_configfs(item) \
+	container_of(to_config_group(item), struct vkms_configfs, crtcs_group)
+
+#define crtcs_item_to_vkms_config_crtc(item) \
+	container_of(to_config_group(item), struct vkms_config_crtc, crtc_group)
+
+static ssize_t crtc_cursor_show(struct config_item *item, char *page)
+{
+	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
+
+	return sprintf(page, "%d\n", crtc_cfg->cursor);
+}
+
+static ssize_t crtc_cursor_store(struct config_item *item, const char *page,
+				 size_t count)
+{
+	struct vkms_configfs *configfs = crtcs_item_to_vkms_configfs(item->ci_parent);
+	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
+	bool cursor;
+
+	if (kstrtobool(page, &cursor))
+		return -EINVAL;
+
+	mutex_lock(&configfs->lock);
+
+	if (configfs->enabled) {
+		mutex_unlock(&configfs->lock);
+		return -EINVAL;
+	}
+
+	crtc_cfg->cursor = cursor;
+
+	mutex_unlock(&configfs->lock);
+
+	return (ssize_t)count;
+}
+
+static ssize_t crtc_writeback_show(struct config_item *item, char *page)
+{
+	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
+
+	return sprintf(page, "%d\n", crtc_cfg->writeback);
+}
+
+static ssize_t crtc_writeback_store(struct config_item *item, const char *page,
+				    size_t count)
+{
+	struct vkms_configfs *configfs = crtcs_item_to_vkms_configfs(item->ci_parent);
+	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
+	bool writeback;
+
+	if (kstrtobool(page, &writeback))
+		return -EINVAL;
+
+	mutex_lock(&configfs->lock);
+
+	if (configfs->enabled) {
+		mutex_unlock(&configfs->lock);
+		return -EINVAL;
+	}
+
+	crtc_cfg->writeback = writeback;
+
+	mutex_unlock(&configfs->lock);
+
+	return (ssize_t)count;
+}
+
+CONFIGFS_ATTR(crtc_, cursor);
+CONFIGFS_ATTR(crtc_, writeback);
+
+static struct configfs_attribute *crtc_group_attrs[] = {
+	&crtc_attr_cursor,
+	&crtc_attr_writeback,
+	NULL,
+};
+
+static const struct config_item_type crtc_group_type = {
+	.ct_attrs = crtc_group_attrs,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_group *make_crtcs_group(struct config_group *group,
+					     const char *name)
+{
+	struct vkms_configfs *configfs = crtcs_group_to_vkms_configfs(group);
+	struct vkms_config_crtc *crtc_cfg;
+	int ret;
+
+	mutex_lock(&configfs->lock);
+
+	if (configfs->enabled) {
+		ret = -EINVAL;
+		goto err_unlock;
+	}
+
+	crtc_cfg = vkms_config_add_crtc(configfs->vkms_config, false, false);
+	if (IS_ERR(crtc_cfg)) {
+		ret = PTR_ERR(crtc_cfg);
+		goto err_unlock;
+	}
+
+	config_group_init_type_name(&crtc_cfg->crtc_group, name, &crtc_group_type);
+
+	mutex_unlock(&configfs->lock);
+
+	return &crtc_cfg->crtc_group;
+
+err_unlock:
+	mutex_unlock(&configfs->lock);
+	return ERR_PTR(ret);
+}
+
+static void drop_crtcs_group(struct config_group *group,
+			     struct config_item *item)
+{
+	struct vkms_configfs *configfs = crtcs_group_to_vkms_configfs(group);
+	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
+
+	vkms_config_destroy_crtc(configfs->vkms_config, crtc_cfg);
+}
+
+static struct configfs_group_operations crtcs_group_ops = {
+	.make_group = &make_crtcs_group,
+	.drop_item = &drop_crtcs_group,
+};
+
+static struct config_item_type crtcs_group_type = {
+	.ct_group_ops = &crtcs_group_ops,
+	.ct_owner = THIS_MODULE,
+};
+
 static ssize_t device_enabled_show(struct config_item *item, char *page)
 {
 	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
@@ -87,7 +225,6 @@ static struct config_group *make_device_group(struct config_group *group,
 					      const char *name)
 {
 	struct vkms_configfs *configfs;
-	struct vkms_config_crtc *crtc_cfg = NULL;
 	struct vkms_config_encoder *encoder_cfg = NULL;
 	struct vkms_config_connector *connector_cfg = NULL;
 	char *config_name;
@@ -110,11 +247,10 @@ static struct config_group *make_device_group(struct config_group *group,
 		goto err_kfree;
 	}
 
-	crtc_cfg = vkms_config_add_crtc(configfs->vkms_config, false, false);
-	if (IS_ERR(crtc_cfg)) {
-		ret = PTR_ERR(crtc_cfg);
-		goto err_kfree;
-	}
+	config_group_init_type_name(&configfs->crtcs_group, "crtcs",
+				    &crtcs_group_type);
+	configfs_add_default_group(&configfs->crtcs_group,
+				   &configfs->device_group);
 
 	encoder_cfg = vkms_config_add_encoder(configfs->vkms_config, BIT(0));
 	if (IS_ERR(encoder_cfg)) {
@@ -133,7 +269,6 @@ static struct config_group *make_device_group(struct config_group *group,
 
 err_kfree:
 	kfree(configfs);
-	kfree(crtc_cfg);
 	kfree(encoder_cfg);
 	kfree(connector_cfg);
 	return ERR_PTR(ret);
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 13/17] drm/vkms: Allow to configure multiple encoders via configfs
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (11 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 12/17] drm/vkms: Allow to configure multiple CRTCs " José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:58   ` Louis Chauvet
  2024-08-13 10:44 ` [RFC PATCH 14/17] drm/vkms: Allow to configure multiple encoders José Expósito
                   ` (5 subsequent siblings)
  18 siblings, 1 reply; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Create a default subgroup at /config/vkms/encoders to allow to create as
many encoders as required. When the encoder is created the
possible_crtcs subgroup is created allowing to link encoders and CRTCs.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 Documentation/gpu/vkms.rst           |  14 ++-
 drivers/gpu/drm/vkms/vkms_config.h   |   3 +
 drivers/gpu/drm/vkms/vkms_configfs.c | 127 +++++++++++++++++++++++++--
 3 files changed, 136 insertions(+), 8 deletions(-)

diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index 0886349ad4a0..c69be063d3b4 100644
--- a/Documentation/gpu/vkms.rst
+++ b/Documentation/gpu/vkms.rst
@@ -76,7 +76,8 @@ And directories are created for each configurable item of the display pipeline::
   tree /config/vkms/my-vkms
     /config/vkms/my-vkms
     ├── crtcs
-    └── enabled
+    ├── enabled
+    └── encoders
 
 To add items to the display pipeline, create one or more directories under the
 available paths.
@@ -90,6 +91,15 @@ CRTCs have 2 configurable attributes:
 - cursor: Enable or disable cursor plane support
 - writeback: Enable or disable writeback connector support
 
+Continue by creating one or more encoders::
+
+  sudo mkdir /config/vkms/my-vkms/encoders/encoder0
+
+Encoders can be linked to CRTCs by creating a symbolic link under
+``possible_crtcs``::
+
+  sudo ln -s /config/vkms/my-vkms/crtcs/crtc0 /config/vkms/my-vkms/encoders/encoder0/possible_crtcs
+
 Once you are done configuring the VKMS instance, enable it::
 
   echo "1" | sudo tee /config/vkms/my-vkms/enabled
@@ -100,6 +110,8 @@ Finally, you can remove the VKMS instance disabling it::
 
 Or removing the top level directory and its subdirectories::
 
+  sudo rm /config/vkms/my-vkms/encoders/*/possible_crtcs/*
+  sudo rmdir /config/vkms/my-vkms/encoders/*
   sudo rmdir /config/vkms/my-vkms/crtcs/*
   sudo rmdir /config/vkms/my-vkms
 
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index f96a0456a3d7..f9423533a7f3 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -29,6 +29,9 @@ struct vkms_config_encoder {
 	struct list_head list;
 	unsigned int index;
 	uint32_t possible_crtcs;
+	/* only used if created from configfs */
+	struct config_group encoder_group;
+	struct config_group possible_crtcs_group;
 };
 
 struct vkms_config_connector {
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index 04278a39cd3c..c0b62fb93dc0 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -19,6 +19,8 @@ static bool is_configfs_registered;
  * Initialized when a new directory is created under "/config/vkms/"
  * @crtcs_group: Default subgroup of @device_group at "/config/vkms/crtcs".
  * Each of its items represent a CRTC
+ * @encoders_group: Default subgroup of @device_group at
+ * "/config/vkms/encoders". Each of its items represent a encoder
  * @lock: Lock used to project concurrent access to the configuration attributes
  * @enabled: Protected by @lock. The device is created or destroyed when this
  * option changes
@@ -27,6 +29,7 @@ struct vkms_configfs {
 	struct vkms_config *vkms_config;
 	struct config_group device_group;
 	struct config_group crtcs_group;
+	struct config_group encoders_group;
 
 	/* protected by @lock */
 	struct mutex lock;
@@ -45,6 +48,15 @@ struct vkms_configfs {
 #define crtcs_item_to_vkms_config_crtc(item) \
 	container_of(to_config_group(item), struct vkms_config_crtc, crtc_group)
 
+#define encoders_group_to_vkms_configfs(group) \
+	container_of(group, struct vkms_configfs, encoders_group)
+
+#define encoders_item_to_vkms_config_encoder(item) \
+	container_of(to_config_group(item), struct vkms_config_encoder, encoder_group)
+
+#define encoder_possible_crtcs_item_to_vkms_config_encoder(item) \
+	container_of(to_config_group(item), struct vkms_config_encoder, possible_crtcs_group)
+
 static ssize_t crtc_cursor_show(struct config_item *item, char *page)
 {
 	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
@@ -171,6 +183,110 @@ static struct config_item_type crtcs_group_type = {
 	.ct_owner = THIS_MODULE,
 };
 
+static int encoder_possible_crtcs_allow_link(struct config_item *src,
+					     struct config_item *target)
+{
+	struct vkms_config_encoder *encoder_cfg;
+	struct vkms_config_crtc *crtc_cfg;
+
+	if (target->ci_type != &crtc_group_type)
+		return -EINVAL;
+
+	encoder_cfg = encoder_possible_crtcs_item_to_vkms_config_encoder(src);
+	crtc_cfg = crtcs_item_to_vkms_config_crtc(target);
+
+	if (encoder_cfg->possible_crtcs & BIT(crtc_cfg->index))
+		return -EINVAL;
+
+	encoder_cfg->possible_crtcs |= BIT(crtc_cfg->index);
+
+	return 0;
+}
+
+static void encoder_possible_crtcs_drop_link(struct config_item *src,
+					     struct config_item *target)
+{
+	struct vkms_config_encoder *encoder_cfg;
+	struct vkms_config_crtc *crtc_cfg;
+
+	encoder_cfg = encoder_possible_crtcs_item_to_vkms_config_encoder(src);
+	crtc_cfg = crtcs_item_to_vkms_config_crtc(target);
+
+	encoder_cfg->possible_crtcs &= ~BIT(crtc_cfg->index);
+}
+
+static struct configfs_item_operations encoder_possible_crtcs_item_ops = {
+	.allow_link = &encoder_possible_crtcs_allow_link,
+	.drop_link = &encoder_possible_crtcs_drop_link,
+};
+
+static struct config_item_type encoder_possible_crtcs_group_type = {
+	.ct_item_ops = &encoder_possible_crtcs_item_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static const struct config_item_type encoder_group_type = {
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_group *make_encoders_group(struct config_group *group,
+						const char *name)
+{
+	struct vkms_configfs *configfs = encoders_group_to_vkms_configfs(group);
+	struct vkms_config_encoder *encoder_cfg;
+	int ret;
+
+	mutex_lock(&configfs->lock);
+
+	if (configfs->enabled) {
+		ret = -EINVAL;
+		goto err_unlock;
+	}
+
+	encoder_cfg = vkms_config_add_encoder(configfs->vkms_config, 0);
+	if (IS_ERR(encoder_cfg)) {
+		ret = PTR_ERR(encoder_cfg);
+		goto err_unlock;
+	}
+
+	config_group_init_type_name(&encoder_cfg->encoder_group, name,
+				    &encoder_group_type);
+
+	config_group_init_type_name(&encoder_cfg->possible_crtcs_group,
+				    "possible_crtcs",
+				    &encoder_possible_crtcs_group_type);
+	configfs_add_default_group(&encoder_cfg->possible_crtcs_group,
+				   &encoder_cfg->encoder_group);
+
+	mutex_unlock(&configfs->lock);
+
+	return &encoder_cfg->encoder_group;
+
+err_unlock:
+	mutex_unlock(&configfs->lock);
+	return ERR_PTR(ret);
+}
+
+static void drop_encoders_group(struct config_group *group,
+				struct config_item *item)
+{
+	struct vkms_configfs *configfs = encoders_group_to_vkms_configfs(group);
+	struct vkms_config_encoder *encoder_cfg =
+		encoders_item_to_vkms_config_encoder(item);
+
+	vkms_config_destroy_encoder(configfs->vkms_config, encoder_cfg);
+}
+
+static struct configfs_group_operations encoders_group_ops = {
+	.make_group = &make_encoders_group,
+	.drop_item = &drop_encoders_group,
+};
+
+static struct config_item_type encoders_group_type = {
+	.ct_group_ops = &encoders_group_ops,
+	.ct_owner = THIS_MODULE,
+};
+
 static ssize_t device_enabled_show(struct config_item *item, char *page)
 {
 	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
@@ -225,7 +341,6 @@ static struct config_group *make_device_group(struct config_group *group,
 					      const char *name)
 {
 	struct vkms_configfs *configfs;
-	struct vkms_config_encoder *encoder_cfg = NULL;
 	struct vkms_config_connector *connector_cfg = NULL;
 	char *config_name;
 	int ret;
@@ -252,11 +367,10 @@ static struct config_group *make_device_group(struct config_group *group,
 	configfs_add_default_group(&configfs->crtcs_group,
 				   &configfs->device_group);
 
-	encoder_cfg = vkms_config_add_encoder(configfs->vkms_config, BIT(0));
-	if (IS_ERR(encoder_cfg)) {
-		ret = PTR_ERR(encoder_cfg);
-		goto err_kfree;
-	}
+	config_group_init_type_name(&configfs->encoders_group, "encoders",
+				    &encoders_group_type);
+	configfs_add_default_group(&configfs->encoders_group,
+				   &configfs->device_group);
 
 	connector_cfg = vkms_config_add_connector(configfs->vkms_config, BIT(0),
 						  connector_status_connected);
@@ -269,7 +383,6 @@ static struct config_group *make_device_group(struct config_group *group,
 
 err_kfree:
 	kfree(configfs);
-	kfree(encoder_cfg);
 	kfree(connector_cfg);
 	return ERR_PTR(ret);
 }
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 14/17] drm/vkms: Allow to configure multiple encoders
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (12 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 13/17] drm/vkms: Allow to configure multiple encoders " José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:59   ` Louis Chauvet
  2024-08-13 10:44 ` [RFC PATCH 15/17] drm/vkms: Allow to configure multiple planes via configfs José Expósito
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Add a list of encoder configurations to vkms_config and add as many
encoders as configured during output initialization.

For backwards compatibility, create a single encoder in the default
configuration.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 Documentation/gpu/vkms.rst           |  16 +++
 drivers/gpu/drm/vkms/vkms_config.h   |   3 +
 drivers/gpu/drm/vkms/vkms_configfs.c | 184 ++++++++++++++++++++++++---
 3 files changed, 188 insertions(+), 15 deletions(-)

diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index c69be063d3b4..b6ceb8c48310 100644
--- a/Documentation/gpu/vkms.rst
+++ b/Documentation/gpu/vkms.rst
@@ -75,6 +75,7 @@ And directories are created for each configurable item of the display pipeline::
 
   tree /config/vkms/my-vkms
     /config/vkms/my-vkms
+    ├── connectors
     ├── crtcs
     ├── enabled
     └── encoders
@@ -100,16 +101,31 @@ Encoders can be linked to CRTCs by creating a symbolic link under
 
   sudo ln -s /config/vkms/my-vkms/crtcs/crtc0 /config/vkms/my-vkms/encoders/encoder0/possible_crtcs
 
+Next, create one or more connectors::
+
+  sudo mkdir /config/vkms/my-vkms/connectors/connector0
+
+The status of the connector can be changed writing ``1`` (connected), ``2``
+(disconnected) or ``3`` (unknown) to the ``status`` attribute and they can be
+linked to encoders by creating a symbolic link under ``possible_encoders``::
+
+  sudo ln -s /config/vkms/my-vkms/encoders/encoder0 /config/vkms/my-vkms/connectors/connector0/possible_encoders
+
 Once you are done configuring the VKMS instance, enable it::
 
   echo "1" | sudo tee /config/vkms/my-vkms/enabled
 
+Note that the connector ``status`` can be changed once the VKMS instance is
+enabled to emulate hot-plug/unplug.
+
 Finally, you can remove the VKMS instance disabling it::
 
   echo "0" | sudo tee /config/vkms/my-vkms/enabled
 
 Or removing the top level directory and its subdirectories::
 
+  sudo rm /config/vkms/my-vkms/connectors/*/possible_encoders/*
+  sudo rmdir /config/vkms/my-vkms/connectors/*
   sudo rm /config/vkms/my-vkms/encoders/*/possible_crtcs/*
   sudo rmdir /config/vkms/my-vkms/encoders/*
   sudo rmdir /config/vkms/my-vkms/crtcs/*
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index f9423533a7f3..cf45e3f6ae92 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -40,6 +40,9 @@ struct vkms_config_connector {
 	enum drm_connector_status status;
 	/* only set when instantiated */
 	struct drm_connector *connector;
+	/* only used if created from configfs */
+	struct config_group connector_group;
+	struct config_group possible_encoders_group;
 };
 
 struct vkms_config {
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index c0b62fb93dc0..d2369f53e2d8 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -21,6 +21,8 @@ static bool is_configfs_registered;
  * Each of its items represent a CRTC
  * @encoders_group: Default subgroup of @device_group at
  * "/config/vkms/encoders". Each of its items represent a encoder
+ * @connectors_group: Default subgroup of @device_group at
+ * "/config/vkms/connectors". Each of its items represent a connector
  * @lock: Lock used to project concurrent access to the configuration attributes
  * @enabled: Protected by @lock. The device is created or destroyed when this
  * option changes
@@ -30,6 +32,7 @@ struct vkms_configfs {
 	struct config_group device_group;
 	struct config_group crtcs_group;
 	struct config_group encoders_group;
+	struct config_group connectors_group;
 
 	/* protected by @lock */
 	struct mutex lock;
@@ -57,6 +60,18 @@ struct vkms_configfs {
 #define encoder_possible_crtcs_item_to_vkms_config_encoder(item) \
 	container_of(to_config_group(item), struct vkms_config_encoder, possible_crtcs_group)
 
+#define connectors_group_to_vkms_configfs(group) \
+	container_of(group, struct vkms_configfs, connectors_group)
+
+#define connectors_item_to_vkms_configfs(item) \
+	container_of(to_config_group(item), struct vkms_configfs, connectors_group)
+
+#define connector_item_to_vkms_config_connector(item) \
+	container_of(to_config_group(item), struct vkms_config_connector, connector_group)
+
+#define connector_possible_encoders_item_to_vkms_config_connector(item) \
+	container_of(to_config_group(item), struct vkms_config_connector, possible_encoders_group)
+
 static ssize_t crtc_cursor_show(struct config_item *item, char *page)
 {
 	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
@@ -287,6 +302,154 @@ static struct config_item_type encoders_group_type = {
 	.ct_owner = THIS_MODULE,
 };
 
+static int connector_possible_encoders_allow_link(struct config_item *src,
+						  struct config_item *target)
+{
+	struct vkms_config_connector *connector_cfg;
+	struct vkms_config_encoder *encoder_cfg;
+
+	if (target->ci_type != &encoder_group_type)
+		return -EINVAL;
+
+	connector_cfg = connector_possible_encoders_item_to_vkms_config_connector(src);
+	encoder_cfg = encoders_item_to_vkms_config_encoder(target);
+
+	if (connector_cfg->possible_encoders & BIT(encoder_cfg->index))
+		return -EINVAL;
+
+	connector_cfg->possible_encoders |= BIT(encoder_cfg->index);
+
+	return 0;
+}
+
+static void connector_possible_encoders_drop_link(struct config_item *src,
+						  struct config_item *target)
+{
+	struct vkms_config_connector *connector_cfg;
+	struct vkms_config_encoder *encoder_cfg;
+
+	connector_cfg = connector_possible_encoders_item_to_vkms_config_connector(src);
+	encoder_cfg = encoders_item_to_vkms_config_encoder(target);
+
+	connector_cfg->possible_encoders &= ~BIT(encoder_cfg->index);
+}
+
+static struct configfs_item_operations connector_possible_encoders_item_ops = {
+	.allow_link = &connector_possible_encoders_allow_link,
+	.drop_link = &connector_possible_encoders_drop_link,
+};
+
+static struct config_item_type connector_possible_encoders_group_type = {
+	.ct_item_ops = &connector_possible_encoders_item_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static ssize_t connector_status_show(struct config_item *item, char *page)
+{
+	struct vkms_config_connector *connector_cfg =
+		connector_item_to_vkms_config_connector(item);
+
+	return sprintf(page, "%d\n", connector_cfg->status);
+}
+
+static ssize_t connector_status_store(struct config_item *item, const char *page,
+				      size_t count)
+{
+	struct vkms_configfs *configfs;
+	struct vkms_config_connector *connector_cfg;
+	int status;
+
+	if (kstrtoint(page, 10, &status))
+		return -EINVAL;
+
+	switch (status) {
+	case connector_status_connected:
+	case connector_status_disconnected:
+	case connector_status_unknown:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	configfs = connectors_item_to_vkms_configfs(item->ci_parent);
+	connector_cfg = connector_item_to_vkms_config_connector(item);
+
+	vkms_update_connector_status(configfs->vkms_config, connector_cfg, status);
+
+	return (ssize_t)count;
+}
+
+CONFIGFS_ATTR(connector_, status);
+
+static struct configfs_attribute *connector_group_attrs[] = {
+	&connector_attr_status,
+	NULL,
+};
+
+static const struct config_item_type connector_group_type = {
+	.ct_attrs = connector_group_attrs,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_group *make_connectors_group(struct config_group *group,
+						  const char *name)
+{
+	struct vkms_configfs *configfs = connectors_group_to_vkms_configfs(group);
+	struct vkms_config_connector *connector_cfg;
+	int ret;
+
+	mutex_lock(&configfs->lock);
+
+	if (configfs->enabled) {
+		ret = -EINVAL;
+		goto err_unlock;
+	}
+
+	connector_cfg = vkms_config_add_connector(configfs->vkms_config, 0,
+						  connector_status_connected);
+	if (IS_ERR(connector_cfg)) {
+		ret = PTR_ERR(connector_cfg);
+		goto err_unlock;
+	}
+
+	config_group_init_type_name(&connector_cfg->connector_group, name,
+				    &connector_group_type);
+
+	config_group_init_type_name(&connector_cfg->possible_encoders_group,
+				    "possible_encoders",
+				    &connector_possible_encoders_group_type);
+	configfs_add_default_group(&connector_cfg->possible_encoders_group,
+				   &connector_cfg->connector_group);
+
+	mutex_unlock(&configfs->lock);
+
+	return &connector_cfg->connector_group;
+
+err_unlock:
+	mutex_unlock(&configfs->lock);
+	return ERR_PTR(ret);
+}
+
+static void drop_connectors_group(struct config_group *group,
+				  struct config_item *item)
+{
+	struct vkms_configfs *configfs = connectors_group_to_vkms_configfs(group);
+	struct vkms_config_connector *connector_cfg =
+		connector_item_to_vkms_config_connector(item);
+
+	vkms_config_destroy_connector(configfs->vkms_config, connector_cfg);
+}
+
+static struct configfs_group_operations connectors_group_ops = {
+	.make_group = &make_connectors_group,
+	.drop_item = &drop_connectors_group,
+};
+
+static struct config_item_type connectors_group_type = {
+	.ct_group_ops = &connectors_group_ops,
+	.ct_owner = THIS_MODULE,
+};
+
 static ssize_t device_enabled_show(struct config_item *item, char *page)
 {
 	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
@@ -341,9 +504,7 @@ static struct config_group *make_device_group(struct config_group *group,
 					      const char *name)
 {
 	struct vkms_configfs *configfs;
-	struct vkms_config_connector *connector_cfg = NULL;
 	char *config_name;
-	int ret;
 
 	if (strcmp(name, DEFAULT_DEVICE_NAME) == 0)
 		return ERR_PTR(-EINVAL);
@@ -358,8 +519,8 @@ static struct config_group *make_device_group(struct config_group *group,
 	config_name = config_item_name(&configfs->device_group.cg_item);
 	configfs->vkms_config = vkms_config_create(config_name);
 	if (IS_ERR(configfs->vkms_config)) {
-		ret = PTR_ERR(configfs->vkms_config);
-		goto err_kfree;
+		kfree(configfs);
+		return ERR_CAST(configfs->vkms_config);
 	}
 
 	config_group_init_type_name(&configfs->crtcs_group, "crtcs",
@@ -372,19 +533,12 @@ static struct config_group *make_device_group(struct config_group *group,
 	configfs_add_default_group(&configfs->encoders_group,
 				   &configfs->device_group);
 
-	connector_cfg = vkms_config_add_connector(configfs->vkms_config, BIT(0),
-						  connector_status_connected);
-	if (IS_ERR(connector_cfg)) {
-		ret = PTR_ERR(connector_cfg);
-		goto err_kfree;
-	}
+	config_group_init_type_name(&configfs->connectors_group, "connectors",
+				    &connectors_group_type);
+	configfs_add_default_group(&configfs->connectors_group,
+				   &configfs->device_group);
 
 	return &configfs->device_group;
-
-err_kfree:
-	kfree(configfs);
-	kfree(connector_cfg);
-	return ERR_PTR(ret);
 }
 
 static void drop_device_group(struct config_group *group,
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 15/17] drm/vkms: Allow to configure multiple planes via configfs
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (13 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 14/17] drm/vkms: Allow to configure multiple encoders José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:59   ` Louis Chauvet
  2024-08-13 10:44 ` [RFC PATCH 16/17] drm/vkms: Allow to configure the default device creation José Expósito
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Create a default subgroup at /config/vkms/planes to allow to create as
many overlay planes as required. When the plane is created the
possible_crtcs subgroup is created allowing to link planes and CRTCs.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 Documentation/gpu/vkms.rst           |  13 ++-
 drivers/gpu/drm/vkms/vkms_config.h   |   3 +
 drivers/gpu/drm/vkms/vkms_configfs.c | 121 +++++++++++++++++++++++++++
 3 files changed, 136 insertions(+), 1 deletion(-)

diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index b6ceb8c48310..ee71d1a569dd 100644
--- a/Documentation/gpu/vkms.rst
+++ b/Documentation/gpu/vkms.rst
@@ -78,7 +78,8 @@ And directories are created for each configurable item of the display pipeline::
     ├── connectors
     ├── crtcs
     ├── enabled
-    └── encoders
+    ├── encoders
+    └── planes
 
 To add items to the display pipeline, create one or more directories under the
 available paths.
@@ -111,6 +112,14 @@ linked to encoders by creating a symbolic link under ``possible_encoders``::
 
   sudo ln -s /config/vkms/my-vkms/encoders/encoder0 /config/vkms/my-vkms/connectors/connector0/possible_encoders
 
+Finally, create zero or more overlay planes::
+
+  sudo mkdir /config/vkms/my-vkms/planes/plane0
+
+And link them with their ``possible_crtcs``::
+
+  sudo ln -s /config/vkms/my-vkms/crtcs/crtc0 /config/vkms/my-vkms/planes/plane0/possible_crtcs
+
 Once you are done configuring the VKMS instance, enable it::
 
   echo "1" | sudo tee /config/vkms/my-vkms/enabled
@@ -128,6 +137,8 @@ Or removing the top level directory and its subdirectories::
   sudo rmdir /config/vkms/my-vkms/connectors/*
   sudo rm /config/vkms/my-vkms/encoders/*/possible_crtcs/*
   sudo rmdir /config/vkms/my-vkms/encoders/*
+  sudo rm /config/vkms/my-vkms/planes/*/possible_crtcs/*
+  sudo rmdir /config/vkms/my-vkms/planes/*
   sudo rmdir /config/vkms/my-vkms/crtcs/*
   sudo rmdir /config/vkms/my-vkms
 
diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
index cf45e3f6ae92..2ec08bb58ec4 100644
--- a/drivers/gpu/drm/vkms/vkms_config.h
+++ b/drivers/gpu/drm/vkms/vkms_config.h
@@ -14,6 +14,9 @@ struct vkms_device;
 struct vkms_config_plane {
 	struct list_head list;
 	uint32_t possible_crtcs;
+	/* only used if created from configfs */
+	struct config_group plane_group;
+	struct config_group possible_crtcs_group;
 };
 
 struct vkms_config_crtc {
diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
index d2369f53e2d8..0b5ac0767da0 100644
--- a/drivers/gpu/drm/vkms/vkms_configfs.c
+++ b/drivers/gpu/drm/vkms/vkms_configfs.c
@@ -23,6 +23,8 @@ static bool is_configfs_registered;
  * "/config/vkms/encoders". Each of its items represent a encoder
  * @connectors_group: Default subgroup of @device_group at
  * "/config/vkms/connectors". Each of its items represent a connector
+ * @planes_group: Default subgroup of @device_group at "/config/vkms/planes".
+ * Each of its items represent an overlay plane
  * @lock: Lock used to project concurrent access to the configuration attributes
  * @enabled: Protected by @lock. The device is created or destroyed when this
  * option changes
@@ -33,6 +35,7 @@ struct vkms_configfs {
 	struct config_group crtcs_group;
 	struct config_group encoders_group;
 	struct config_group connectors_group;
+	struct config_group planes_group;
 
 	/* protected by @lock */
 	struct mutex lock;
@@ -72,6 +75,15 @@ struct vkms_configfs {
 #define connector_possible_encoders_item_to_vkms_config_connector(item) \
 	container_of(to_config_group(item), struct vkms_config_connector, possible_encoders_group)
 
+#define planes_group_to_vkms_configfs(group) \
+	container_of(group, struct vkms_configfs, planes_group)
+
+#define planes_item_to_vkms_config_plane(item) \
+	container_of(to_config_group(item), struct vkms_config_plane, plane_group)
+
+#define plane_possible_crtcs_item_to_vkms_config_plane(item) \
+	container_of(to_config_group(item), struct vkms_config_plane, possible_crtcs_group)
+
 static ssize_t crtc_cursor_show(struct config_item *item, char *page)
 {
 	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
@@ -450,6 +462,110 @@ static struct config_item_type connectors_group_type = {
 	.ct_owner = THIS_MODULE,
 };
 
+static int plane_possible_crtcs_allow_link(struct config_item *src,
+					   struct config_item *target)
+{
+	struct vkms_config_plane *plane_cfg;
+	struct vkms_config_crtc *crtc_cfg;
+
+	if (target->ci_type != &crtc_group_type)
+		return -EINVAL;
+
+	plane_cfg = plane_possible_crtcs_item_to_vkms_config_plane(src);
+	crtc_cfg = crtcs_item_to_vkms_config_crtc(target);
+
+	if (plane_cfg->possible_crtcs & BIT(crtc_cfg->index))
+		return -EINVAL;
+
+	plane_cfg->possible_crtcs |= BIT(crtc_cfg->index);
+
+	return 0;
+}
+
+static void plane_possible_crtcs_drop_link(struct config_item *src,
+					   struct config_item *target)
+{
+	struct vkms_config_plane *plane_cfg;
+	struct vkms_config_crtc *crtc_cfg;
+
+	plane_cfg = plane_possible_crtcs_item_to_vkms_config_plane(src);
+	crtc_cfg = crtcs_item_to_vkms_config_crtc(target);
+
+	plane_cfg->possible_crtcs &= ~BIT(crtc_cfg->index);
+}
+
+static struct configfs_item_operations plane_possible_crtcs_item_ops = {
+	.allow_link = &plane_possible_crtcs_allow_link,
+	.drop_link = &plane_possible_crtcs_drop_link,
+};
+
+static struct config_item_type plane_possible_crtcs_group_type = {
+	.ct_item_ops = &plane_possible_crtcs_item_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static const struct config_item_type plane_group_type = {
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_group *make_planes_group(struct config_group *group,
+					      const char *name)
+{
+	struct vkms_configfs *configfs = planes_group_to_vkms_configfs(group);
+	struct vkms_config_plane *plane_cfg;
+	int ret;
+
+	mutex_lock(&configfs->lock);
+
+	if (configfs->enabled) {
+		ret = -EINVAL;
+		goto err_unlock;
+	}
+
+	plane_cfg = vkms_config_add_overlay_plane(configfs->vkms_config, 0);
+	if (IS_ERR(plane_cfg)) {
+		ret = PTR_ERR(plane_cfg);
+		goto err_unlock;
+	}
+
+	config_group_init_type_name(&plane_cfg->plane_group, name,
+				    &plane_group_type);
+
+	config_group_init_type_name(&plane_cfg->possible_crtcs_group,
+				    "possible_crtcs",
+				    &plane_possible_crtcs_group_type);
+	configfs_add_default_group(&plane_cfg->possible_crtcs_group,
+				   &plane_cfg->plane_group);
+
+	mutex_unlock(&configfs->lock);
+
+	return &plane_cfg->plane_group;
+
+err_unlock:
+	mutex_unlock(&configfs->lock);
+	return ERR_PTR(ret);
+}
+
+static void drop_planes_group(struct config_group *group,
+			      struct config_item *item)
+{
+	struct vkms_configfs *configfs = planes_group_to_vkms_configfs(group);
+	struct vkms_config_plane *plane_cfg =
+		planes_item_to_vkms_config_plane(item);
+
+	vkms_config_destroy_overlay_plane(configfs->vkms_config, plane_cfg);
+}
+
+static struct configfs_group_operations planes_group_ops = {
+	.make_group = &make_planes_group,
+	.drop_item = &drop_planes_group,
+};
+
+static struct config_item_type planes_group_type = {
+	.ct_group_ops = &planes_group_ops,
+	.ct_owner = THIS_MODULE,
+};
+
 static ssize_t device_enabled_show(struct config_item *item, char *page)
 {
 	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
@@ -538,6 +654,11 @@ static struct config_group *make_device_group(struct config_group *group,
 	configfs_add_default_group(&configfs->connectors_group,
 				   &configfs->device_group);
 
+	config_group_init_type_name(&configfs->planes_group, "planes",
+				    &planes_group_type);
+	configfs_add_default_group(&configfs->planes_group,
+				   &configfs->device_group);
+
 	return &configfs->device_group;
 }
 
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 16/17] drm/vkms: Allow to configure the default device creation
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (14 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 15/17] drm/vkms: Allow to configure multiple planes via configfs José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 10:44 ` [RFC PATCH 17/17] drm/vkms: Remove completed task from the TODO list José Expósito
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Add a new module param to allow to create or not the default VKMS
instance. Useful when combined with configfs to avoid having additional
VKMS instances.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 drivers/gpu/drm/vkms/vkms_drv.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
index f524a9550017..248cb7166256 100644
--- a/drivers/gpu/drm/vkms/vkms_drv.c
+++ b/drivers/gpu/drm/vkms/vkms_drv.c
@@ -50,6 +50,10 @@ static bool enable_overlay;
 module_param_named(enable_overlay, enable_overlay, bool, 0444);
 MODULE_PARM_DESC(enable_overlay, "Enable/Disable overlay support");
 
+static bool create_default_dev = true;
+module_param_named(create_default_dev, create_default_dev, bool, 0444);
+MODULE_PARM_DESC(create_default_dev, "Create or not the default VKMS device");
+
 DEFINE_DRM_GEM_FOPS(vkms_driver_fops);
 
 static void vkms_release(struct drm_device *dev)
@@ -230,9 +234,11 @@ static int __init vkms_init(void)
 
 	default_config = config;
 
-	ret = vkms_create(config);
-	if (ret)
-		goto err_kfree;
+	if (create_default_dev) {
+		ret = vkms_create(config);
+		if (ret)
+			goto err_kfree;
+	}
 
 	ret = vkms_configfs_register();
 	if (ret)
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC PATCH 17/17] drm/vkms: Remove completed task from the TODO list
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (15 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 16/17] drm/vkms: Allow to configure the default device creation José Expósito
@ 2024-08-13 10:44 ` José Expósito
  2024-08-13 17:58 ` [RFC PATCH 00/17] VKMS: Add configfs support Louis Chauvet
  2024-08-14  9:10 ` Daniel Stone
  18 siblings, 0 replies; 35+ messages in thread
From: José Expósito @ 2024-08-13 10:44 UTC (permalink / raw)
  To: rodrigosiqueiramelo
  Cc: melissa.srw, mairacanal, hamohammed.sa, daniel, maarten.lankhorst,
	mripard, tzimmermann, airlied, dri-devel, linux-kernel,
	louis.chauvet, José Expósito

Remove the configfs related TODO items from the "Runtime Configuration"
section.

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
---
 Documentation/gpu/vkms.rst | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
index ee71d1a569dd..a8c187f6c0af 100644
--- a/Documentation/gpu/vkms.rst
+++ b/Documentation/gpu/vkms.rst
@@ -229,19 +229,12 @@ Runtime Configuration
 We want to be able to reconfigure vkms instance without having to reload the
 module. Use/Test-cases:
 
-- Hotplug/hotremove connectors on the fly (to be able to test DP MST handling
-  of compositors).
-
-- Configure planes/crtcs/connectors (we'd need some code to have more than 1 of
-  them first).
+- Hotremove connectors on the fly (to be able to test DP MST handling of
+  compositors).
 
 - Change output configuration: Plug/unplug screens, change EDID, allow changing
   the refresh rate.
 
-The currently proposed solution is to expose vkms configuration through
-configfs. All existing module options should be supported through configfs
-too.
-
 Writeback support
 -----------------
 
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 03/17] drm/vkms: Set device name from vkms_config
  2024-08-13 10:44 ` [RFC PATCH 03/17] drm/vkms: Set device name from vkms_config José Expósito
@ 2024-08-13 17:58   ` Louis Chauvet
  0 siblings, 0 replies; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:58 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel

Le 13/08/24 - 12:44, José Expósito a écrit :
> In order to be able to create multiple devices, the device name needs to
> be unique.
> 
> Allow to set it in the VKMS configuration.
> 
> Signed-off-by: José Expósito <jose.exposito89@gmail.com>
> ---
>  drivers/gpu/drm/vkms/vkms_config.c | 7 +++++--
>  drivers/gpu/drm/vkms/vkms_config.h | 3 ++-
>  drivers/gpu/drm/vkms/vkms_drv.c    | 2 +-
>  drivers/gpu/drm/vkms/vkms_drv.h    | 2 ++
>  4 files changed, 10 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index 4c7cda16dfd8..6ab8091bf72f 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
> @@ -8,7 +8,7 @@
>  #include "vkms_config.h"
>  #include "vkms_drv.h"
>  
> -struct vkms_config *vkms_config_create(void)
> +struct vkms_config *vkms_config_create(char *dev_name)
>  {
>  	struct vkms_config *config;
>  
> @@ -16,6 +16,8 @@ struct vkms_config *vkms_config_create(void)
>  	if (!config)
>  		return ERR_PTR(-ENOMEM);
>  
> +	config->dev_name = dev_name;
> +
>  	return config;
>  }

I think it can make sense to copy the device name here. If I look at your 
ConfigFS implementation, this pointer is managed by configfs, not vkms. 

I think it could be nice to avoid mixing different lifetime and let vkms 
fully manage its own objects.
  
> @@ -25,7 +27,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
>  {
>  	struct vkms_config *config;
>  
> -	config = vkms_config_create();
> +	config = vkms_config_create(DEFAULT_DEVICE_NAME);
>  	if (IS_ERR(config))
>  		return config;
>  
> @@ -47,6 +49,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);
>  
> +	seq_printf(m, "dev_name=%s\n", vkmsdev->config->dev_name);
>  	seq_printf(m, "writeback=%d\n", vkmsdev->config->writeback);
>  	seq_printf(m, "cursor=%d\n", vkmsdev->config->cursor);
>  	seq_printf(m, "overlay=%d\n", vkmsdev->config->overlay);
> diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
> index 83181760b02b..ba06aad32799 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.h
> +++ b/drivers/gpu/drm/vkms/vkms_config.h
> @@ -8,6 +8,7 @@
>  struct vkms_device;
>  
>  struct vkms_config {
> +	char *dev_name;
>  	bool writeback;
>  	bool cursor;
>  	bool overlay;
> @@ -16,7 +17,7 @@ struct vkms_config {
>  };
>  
>  /* VKMS Config */
> -struct vkms_config *vkms_config_create(void);
> +struct vkms_config *vkms_config_create(char *dev_name);
>  struct vkms_config *vkms_config_default_create(bool enable_cursor,
>  					       bool enable_writeback,
>  					       bool enable_overlay);
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
> index 4e36989589f9..2f9d1db0cfae 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.c
> +++ b/drivers/gpu/drm/vkms/vkms_drv.c
> @@ -160,7 +160,7 @@ static int vkms_create(struct vkms_config *config)
>  	struct platform_device *pdev;
>  	struct vkms_device *vkms_device;
>  
> -	pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
> +	pdev = platform_device_register_simple(config->dev_name, -1, NULL, 0);
>  	if (IS_ERR(pdev))
>  		return PTR_ERR(pdev);
>  
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
> index 5c523ca27f22..87e44b51a03f 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.h
> +++ b/drivers/gpu/drm/vkms/vkms_drv.h
> @@ -12,6 +12,8 @@
>  #include <drm/drm_encoder.h>
>  #include <drm/drm_writeback.h>
>  
> +#define DEFAULT_DEVICE_NAME "vkms"
> +
>  #define XRES_MIN    10
>  #define YRES_MIN    10
>  
> -- 
> 2.46.0
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 00/17] VKMS: Add configfs support
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (16 preceding siblings ...)
  2024-08-13 10:44 ` [RFC PATCH 17/17] drm/vkms: Remove completed task from the TODO list José Expósito
@ 2024-08-13 17:58 ` Louis Chauvet
  2024-08-20 15:52   ` José Expósito
  2024-08-14  9:10 ` Daniel Stone
  18 siblings, 1 reply; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:58 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel, thomas

Le 13/08/24 - 12:44, José Expósito a écrit :
> Hi everyone,

Hi José,
 
> This RFC implements support to configure VKMS using configfs.
> It allows to:
> 
>  - Create multiple devices
>  - Configure multiple overlay planes, CRTCs, encoders and
>    connectors
>  - Enable or disable cursor plane and writeback connector for
>    each CRTC
>  - Hot-plug/unplug connectors after device creation
>  - Disable the creation of the default VKMS instance to be
>    able to use only the configfs ones
> 
> This work is based on a previous attempt to implement configfs
> support by Jim Shargo and Brandon Pollack [1].
> I tried to keep the changes as minimal and simple as possible
> and addressed Sima's comments on [1].
> 
> Currently, there is another RFC by Louis Chauvet [2]. As I
> mentioned on his RFC, I'm not trying to push my implementation.
> Instead, I think that having 2 implementations will make code
> review way easier and I don't mind which implementation is used
> as long as we get the feature implemented :)

I will send few series tomorrow, don't panic, there will be 9 series and a 
total of ~50 commits (I have many conflict to rebase only the configFS 
part, and even if it was easy, I plan to submit all of my work, not 
everything will be RFC).

> I'm looking forward to analyzing Louis's implementation, seeing
> what the differences are and finding a common solution.

There are four main differences:
- I complelty splitted vkms_config and vkms_configfs structures 
- I splitted my work in many different series
- I created a real platform device driver
- I did not manage index by hand, I let drm core doing it
- I used list to link crtc/planes/encoders and not bitfield (because of 
  the previous point)
- The primary and cursor planes are fully configurable

The first two points are personnal preferences, so I am open to 
discussion.

The third point was already discussed before, I don't know if it is a good 
solution or not. I think it should be easy to remove it.

But for the index managment, I really think that for our usage 
in ConfigFS, bitfields are not a good solution and as shown in this 
series, very error-prone. If you have a better solution than what I did, 
let me know, I am not very happy with mine too.

The last point is also important, we don't want to break uAPI once this 
series is merged, so having "default hidden planes" that can't be 
configured is annoying as we will have to manage them with a special case.

> What's missing?
> 
>  - DebugFS only works for the default VKMS instance.
>    If we want to support it on instances created with configfs
>    I'll need to implement it.

Same on my side, I forgot to reimplement this :-). It will not be in my 
RFC, but on the v1 for sure!

> Known bugs:
> 
>  - When a CRTC is added and removed before device creation, there
>    is a vblank warning.
>    The issue is caused because vblanks are referenced using the
>    CRTC index but, because one of the CRTCs is removed, the
>    indices are not consecutives and drm_crtc_vblank_crtc() tries to
>    access and invalid index
>    I'm not sure if CRTC's indices *must* start at 0 and be
>    consecutives or if this is a bug in the drm_crtc_vblank_crtc()
>    implementation.

Very nice work, but you hurted many issue I had too, and I attempted to 
solve them as nicely as I can. Overall there is one main issues for me:
the crtc index managment is not correct and the configfs behavior is very 
easily broken because of this.

This is an issue for two reason I think:
- We are trying to implement a new index allocation mecanism, but it is 
  not very difficult to let drm manage this part on device creation, so 
  maybe just dont store indexes in config
- The usage of a simple index++ is not suitable for configFS usecase, 
  crating 32 crtcs and deleting 1 should be possible:
	mkdir {1..32};rmdir 1;mkdir 1
  but the index of 1 is now 33, which is forbidden by drm, so you have to 
  do a "complex" algorithim "find_first_value_not_used_bellow_32".

Thanks for all your work! You were right, while reviewing your work, I 
found issues in mine :-)

Have a nice day,
Louis Chauvet

> 
> Best wishes,
> José Expósito
> 
> [1] https://patchwork.kernel.org/project/dri-devel/list/?series=780110&archive=both
> [2] https://lore.kernel.org/dri-devel/ZrZZFQW5RiG12ApN@louis-chauvet-laptop/T/#u
> 
> José Expósito (17):
>   drm/vkms: Extract vkms_config header
>   drm/vkms: Move default_config creation to its own function
>   drm/vkms: Set device name from vkms_config
>   drm/vkms: Allow to configure multiple CRTCs
>   drm/vkms: Use managed memory to create encoders
>   drm/vkms: Allow to configure multiple encoders
>   drm/vkms: Use managed memory to create connectors
>   drm/vkms: Allow to configure multiple connectors
>   drm/vkms: Allow to configure multiple overlay planes
>   drm/vkms: Allow to change connector status
>   drm/vkms: Add and remove VKMS instances via configfs
>   drm/vkms: Allow to configure multiple CRTCs via configfs
>   drm/vkms: Allow to configure multiple encoders via configfs
>   drm/vkms: Allow to configure multiple encoders
>   drm/vkms: Allow to configure multiple planes via configfs
>   drm/vkms: Allow to configure the default device creation
>   drm/vkms: Remove completed task from the TODO list
> 
>  Documentation/gpu/vkms.rst            | 102 +++-
>  drivers/gpu/drm/vkms/Kconfig          |   1 +
>  drivers/gpu/drm/vkms/Makefile         |   4 +-
>  drivers/gpu/drm/vkms/vkms_composer.c  |  30 +-
>  drivers/gpu/drm/vkms/vkms_config.c    | 265 ++++++++++
>  drivers/gpu/drm/vkms/vkms_config.h    | 101 ++++
>  drivers/gpu/drm/vkms/vkms_configfs.c  | 721 ++++++++++++++++++++++++++
>  drivers/gpu/drm/vkms/vkms_configfs.h  |   9 +
>  drivers/gpu/drm/vkms/vkms_crtc.c      |  99 ++--
>  drivers/gpu/drm/vkms/vkms_drv.c       |  75 ++-
>  drivers/gpu/drm/vkms/vkms_drv.h       |  52 +-
>  drivers/gpu/drm/vkms/vkms_output.c    | 187 ++++---
>  drivers/gpu/drm/vkms/vkms_plane.c     |   6 +-
>  drivers/gpu/drm/vkms/vkms_writeback.c |  27 +-
>  14 files changed, 1464 insertions(+), 215 deletions(-)
>  create mode 100644 drivers/gpu/drm/vkms/vkms_config.c
>  create mode 100644 drivers/gpu/drm/vkms/vkms_config.h
>  create mode 100644 drivers/gpu/drm/vkms/vkms_configfs.c
>  create mode 100644 drivers/gpu/drm/vkms/vkms_configfs.h
> 
> -- 
> 2.46.0
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 04/17] drm/vkms: Allow to configure multiple CRTCs
  2024-08-13 10:44 ` [RFC PATCH 04/17] drm/vkms: Allow to configure multiple CRTCs José Expósito
@ 2024-08-13 17:58   ` Louis Chauvet
  0 siblings, 0 replies; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:58 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel

Le 13/08/24 - 12:44, José Expósito a écrit :
> Add a list of CRTC configurations to vkms_config and add as many CRTCs
> as configured during output initialization.
> 
> For backwards compatibility, create a single CRTC in the default
> configuration.
> 
> Since writeback support, vblank and composer states are now per CRTC,
> extract all the fields to the vkms_crtc structure and allow each
> vkms_device to have a list of CRTCs.
> 
> Signed-off-by: José Expósito <jose.exposito89@gmail.com>


If we choose your implementation, can you split this commit in two? I 
think you did two interesting stuff here:
- Creating the vkms_crtc structure
- Creating the vkms_crtc_config

> ---
>  drivers/gpu/drm/vkms/vkms_composer.c  | 30 ++++----
>  drivers/gpu/drm/vkms/vkms_config.c    | 54 ++++++++++++++-
>  drivers/gpu/drm/vkms/vkms_config.h    | 15 +++-
>  drivers/gpu/drm/vkms/vkms_crtc.c      | 99 ++++++++++++++-------------
>  drivers/gpu/drm/vkms/vkms_drv.c       | 10 ++-
>  drivers/gpu/drm/vkms/vkms_drv.h       | 35 +++++++---
>  drivers/gpu/drm/vkms/vkms_output.c    | 38 +++++-----
>  drivers/gpu/drm/vkms/vkms_writeback.c | 27 ++++----
>  8 files changed, 197 insertions(+), 111 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index 6ab8091bf72f..3af750071f04 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
> @@ -26,20 +27,29 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
>  					       bool enable_overlay)
>  {
>  	struct vkms_config *config;
> +	struct vkms_config_crtc *crtc_cfg;
>  
>  	config = vkms_config_create(DEFAULT_DEVICE_NAME);
>  	if (IS_ERR(config))
>  		return config;
>  
>  	config->cursor = enable_cursor;
> -	config->writeback = enable_writeback;
>  	config->overlay = enable_overlay;
>  
> +	crtc_cfg = vkms_config_add_crtc(config, enable_writeback);
> +	if (IS_ERR(crtc_cfg))
> +		return ERR_CAST(crtc_cfg);
> +
>  	return config;
>  }
>  
>  void vkms_config_destroy(struct vkms_config *config)
>  {
> +	struct vkms_config_crtc *crtc_cfg, *crtc_tmp;
> +
> +	list_for_each_entry_safe(crtc_cfg, crtc_tmp, &config->crtcs, list)
> +		vkms_config_destroy_crtc(config, crtc_cfg);
> +
>  	kfree(config);
>  }
>  
> @@ -48,12 +58,20 @@ static int vkms_config_show(struct seq_file *m, void *data)
>  	struct drm_debugfs_entry *entry = m->private;
>  	struct drm_device *dev = entry->dev;
>  	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
> +	struct vkms_config_crtc *crtc_cfg;
> +	int n;
>  
>  	seq_printf(m, "dev_name=%s\n", vkmsdev->config->dev_name);
> -	seq_printf(m, "writeback=%d\n", vkmsdev->config->writeback);
>  	seq_printf(m, "cursor=%d\n", vkmsdev->config->cursor);
>  	seq_printf(m, "overlay=%d\n", vkmsdev->config->overlay);
>  
> +	n = 0;
> +	list_for_each_entry(crtc_cfg, &vkmsdev->config->crtcs, list) {
> +		seq_printf(m, "crtc(%d).writeback=%d\n", n,
> +			   crtc_cfg->writeback);
> +		n++;
> +	}
> +
>  	return 0;
>  }
>  
> @@ -66,3 +84,35 @@ void vkms_config_debugfs_init(struct vkms_device *vkms_device)
>  	drm_debugfs_add_files(&vkms_device->drm, vkms_config_debugfs_list,
>  			      ARRAY_SIZE(vkms_config_debugfs_list));
>  }
> +
> +struct vkms_config_crtc *vkms_config_add_crtc(struct vkms_config *config,
> +					      bool enable_writeback)
> +{
> +	struct vkms_config_crtc *crtc_cfg;
> +
> +	crtc_cfg = kzalloc(sizeof(*crtc_cfg), GFP_KERNEL);
> +	if (!crtc_cfg)
> +		return ERR_PTR(-ENOMEM);
> +
> +	crtc_cfg->writeback = enable_writeback;
> +
> +	crtc_cfg->index = 0;
> +	if (!list_empty(&config->crtcs)) {
> +		struct vkms_config_crtc *last;
> +
> +		last = list_last_entry(&config->crtcs, struct vkms_config_crtc,
> +				       list);
> +		crtc_cfg->index = last->index + 1;
> +	}

This code may break if you create 32 crtc, delete the 31 first, and then 
recreate 31 crtc. The indexes will be 31..63, which is wrong I think for 
the `possible_crtc` mask.

That why in my series I choose to use drm_crtc_mask with the created crtc 
instance, so I don't have to manage in my code this case, I just rely on 
drm core implementation to provide indexes.

> +
> +	list_add_tail(&crtc_cfg->list, &config->crtcs);
> +
> +	return crtc_cfg;
> +}
> +
> +void vkms_config_destroy_crtc(struct vkms_config *config,
> +			      struct vkms_config_crtc *crtc_cfg)
> +{
> +	list_del(&crtc_cfg->list);
> +	kfree(crtc_cfg);
> +}
> diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
> index ba06aad32799..bc40a0e3859a 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.h
> +++ b/drivers/gpu/drm/vkms/vkms_config.h
> @@ -3,15 +3,22 @@
>  #ifndef _VKMS_CONFIG_H_
>  #define _VKMS_CONFIG_H_
>  
> +#include <linux/list.h>
>  #include <linux/types.h>
>  
>  struct vkms_device;
>  
> +struct vkms_config_crtc {
> +	struct list_head list;
> +	unsigned int index;
> +	bool writeback;
> +};
> +
>  struct vkms_config {
>  	char *dev_name;
> -	bool writeback;
>  	bool cursor;
>  	bool overlay;
> +	struct list_head crtcs;
>  	/* only set when instantiated */
>  	struct vkms_device *dev;
>  };
> @@ -26,4 +33,10 @@ void vkms_config_destroy(struct vkms_config *config);
>  /* DebugFS */
>  void vkms_config_debugfs_init(struct vkms_device *vkms_device);
>  
> +/* CRTCs */
> +struct vkms_config_crtc *vkms_config_add_crtc(struct vkms_config *config,
> +					      bool enable_writeback);
> +void vkms_config_destroy_crtc(struct vkms_config *config,
> +			      struct vkms_config_crtc *crtc_cfg);
> +
>  #endif /* _VKMS_CONFIG_H_ */



> -int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
> -		   struct drm_plane *primary, struct drm_plane *cursor)
> +struct vkms_crtc *vkms_crtc_init(struct drm_device *dev,
> +				 struct drm_plane *primary,
> +				 struct drm_plane *cursor,
> +				 unsigned int index)
>  {
> -	struct vkms_output *vkms_out = drm_crtc_to_vkms_output(crtc);
> -	int ret;
> +	struct vkms_crtc *crtc;
>  
> -	ret = drmm_crtc_init_with_planes(dev, crtc, primary, cursor,
> -					 &vkms_crtc_funcs, NULL);
> -	if (ret) {
> -		DRM_ERROR("Failed to init CRTC\n");
> -		return ret;
> +	crtc = drmm_crtc_alloc_with_planes(dev, struct vkms_crtc, base, primary,
> +					   cursor, &vkms_crtc_funcs, NULL);
> +	if (IS_ERR(crtc)) {
> +		DRM_ERROR("Failed to alloc CRTC\n");
> +		return crtc;
>  	}
>  
> -	drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs);
> +	crtc->base.index = index;
> +	primary->possible_crtcs = drm_crtc_mask(&crtc->base);

It feel strange to configure the primary plane possible_crtc inside the 
vkms_crtc_init function, espicially when it is already configured in
vkms_plane_init.

The previous comment apply for allocating index to crtc, it is already 
managed by the drm core (in drmm_crtc_alloc_with_plane). I don't think 
this is an issue for the core to have it changed, but I would prefer to 
avoid duplicating this management in vkms.

> +	if (cursor)
> +		cursor->possible_crtcs = drm_crtc_mask(&crtc->base);

(same for cursor)

> -	drm_mode_crtc_set_gamma_size(crtc, VKMS_LUT_SIZE);
> -	drm_crtc_enable_color_mgmt(crtc, 0, false, VKMS_LUT_SIZE);
> +	INIT_LIST_HEAD(&crtc->list);
>  
> -	spin_lock_init(&vkms_out->lock);
> -	spin_lock_init(&vkms_out->composer_lock);
> +	drm_crtc_helper_add(&crtc->base, &vkms_crtc_helper_funcs);
>  
> -	vkms_out->composer_workq = alloc_ordered_workqueue("vkms_composer", 0);
> -	if (!vkms_out->composer_workq)
> -		return -ENOMEM;
> +	drm_mode_crtc_set_gamma_size(&crtc->base, VKMS_LUT_SIZE);
> +	drm_crtc_enable_color_mgmt(&crtc->base, 0, false, VKMS_LUT_SIZE);
> +
> +	spin_lock_init(&crtc->lock);
> +	spin_lock_init(&crtc->composer_lock);
> +
> +	crtc->composer_workq = alloc_ordered_workqueue("vkms_composer", 0);
> +	if (!crtc->composer_workq)
> +		return ERR_PTR(-ENOMEM);
>
> -	return ret;
> +	return crtc;
>  }
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
> index 2f9d1db0cfae..15a2ba26d190 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.c
> +++ b/drivers/gpu/drm/vkms/vkms_drv.c
> @@ -54,9 +54,12 @@ DEFINE_DRM_GEM_FOPS(vkms_driver_fops);
>  static void vkms_release(struct drm_device *dev)
>  {
>  	struct vkms_device *vkms = drm_device_to_vkms_device(dev);
> +	struct vkms_crtc *vkms_crtc;
>  
> -	if (vkms->output.composer_workq)
> -		destroy_workqueue(vkms->output.composer_workq);
> +	list_for_each_entry(vkms_crtc, &vkms->crtcs, list) {
> +		if (vkms_crtc->composer_workq)
> +			destroy_workqueue(vkms_crtc->composer_workq);
> +	}
>  }

To avoid managing this per-crtc, you can maybe use 
drmm_add_action_or_reset [1] and let drm core manage the call to 
destroy_workqueue.

[1]: https://github.com/Fomys/linux/commit/c4d665599798265aedd131f93cff8c7263cacff8#diff-08d2420ad9a7a48e3c7dafa0f61e0a7c860a53de2f41659d03735875cffebea5R318
  
>  static void vkms_atomic_commit_tail(struct drm_atomic_state *old_state)
> @@ -177,6 +180,7 @@ static int vkms_create(struct vkms_config *config)
>  	}
>  	vkms_device->platform = pdev;
>  	vkms_device->config = config;
> +	vkms_device->crtcs = (struct list_head)LIST_HEAD_INIT(vkms_device->crtcs);

Why do you need a cast here?

>  	config->dev = vkms_device;
>  
>  	ret = dma_coerce_mask_and_coherent(vkms_device->drm.dev,
> @@ -187,7 +191,7 @@ static int vkms_create(struct vkms_config *config)
>  		goto out_devres;
>  	}
>  
> -	ret = drm_vblank_init(&vkms_device->drm, 1);
> +	ret = drm_vblank_init(&vkms_device->drm, list_count_nodes(&config->crtcs));

Thanks, I think I forgot this change in my implementation!

>  	if (ret) {
>  		DRM_ERROR("Failed to vblank\n");
>  		goto out_devres;
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
> index 87e44b51a03f..3156ff896c33 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.h
> +++ b/drivers/gpu/drm/vkms/vkms_drv.h
> @@ -4,6 +4,7 @@
>  #define _VKMS_DRV_H_
>  
>  #include <linux/hrtimer.h>
> +#include <linux/list.h>
>  
>  #include <drm/drm.h>
>  #include <drm/drm_framebuffer.h>
> @@ -98,10 +99,11 @@ struct vkms_crtc_state {
>  	u64 frame_end;
>  };
>  
> -struct vkms_output {
> -	struct drm_crtc crtc;
> -	struct drm_encoder encoder;
> -	struct drm_connector connector;
> +struct vkms_crtc {
> +	struct list_head list;
> +
> +	struct drm_crtc base;
> +
>  	struct drm_writeback_connector wb_connector;
>  	struct hrtimer vblank_hrtimer;
>  	ktime_t period_ns;
> @@ -119,19 +121,28 @@ struct vkms_output {
>  
>  struct vkms_config;
>  
> +struct vkms_output {
> +	struct drm_encoder encoder;
> +	struct drm_connector connector;
> +};
> +
>  struct vkms_device {
>  	struct drm_device drm;
>  	struct platform_device *platform;
>  	struct vkms_output output;
> +	struct list_head crtcs;
>  	const struct vkms_config *config;
>  };

I don't think you need to store the list of crtcs. You can use 
drm_for_each_crtc and container_of macro to get the vkms_crtc structure. 

>  
> -#define drm_crtc_to_vkms_output(target) \
> -	container_of(target, struct vkms_output, crtc)
> -
>  #define drm_device_to_vkms_device(target) \
>  	container_of(target, struct vkms_device, drm)
>  
> +#define drm_crtc_to_vkms_crtc(crtc) \
> +	container_of(crtc, struct vkms_crtc, base)
> +
> +#define timer_to_vkms_crtc(timer) \
> +	container_of(timer, struct vkms_crtc, vblank_hrtimer)
> +
>  #define to_vkms_crtc_state(target)\
>  	container_of(target, struct vkms_crtc_state, base)
>  
> @@ -139,8 +150,10 @@ struct vkms_device {
>  	container_of(target, struct vkms_plane_state, base.base)
>  
>  /* CRTC */
> -int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
> -		   struct drm_plane *primary, struct drm_plane *cursor);
> +struct vkms_crtc *vkms_crtc_init(struct drm_device *dev,
> +				 struct drm_plane *primary,
> +				 struct drm_plane *cursor,
> +				 unsigned int index);
>  
>  int vkms_output_init(struct vkms_device *vkmsdev, int index);
>  
> @@ -156,11 +169,11 @@ int vkms_verify_crc_source(struct drm_crtc *crtc, const char *source_name,
>  
>  /* Composer Support */
>  void vkms_composer_worker(struct work_struct *work);
> -void vkms_set_composer(struct vkms_output *out, bool enabled);
> +void vkms_set_composer(struct vkms_crtc *vkms_crtc, bool enabled);
>  void vkms_compose_row(struct line_buffer *stage_buffer, struct vkms_plane_state *plane, int y);
>  void vkms_writeback_row(struct vkms_writeback_job *wb, const struct line_buffer *src_buffer, int y);
>  
>  /* Writeback */
> -int vkms_enable_writeback_connector(struct vkms_device *vkmsdev);
> +int vkms_enable_writeback_connector(struct vkms_crtc *vkms_crtc);
>  
>  #endif /* _VKMS_DRV_H_ */
> diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
> index afe3945c1962..dcd32bc30e17 100644
> --- a/drivers/gpu/drm/vkms/vkms_output.c
> +++ b/drivers/gpu/drm/vkms/vkms_output.c
> @@ -32,8 +32,7 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
>  	.get_modes    = vkms_conn_get_modes,
>  };
>  
> -static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index,
> -				  struct drm_crtc *crtc)
> +static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index)
>  {
>  	struct vkms_plane *overlay;
>  
> @@ -42,7 +41,7 @@ static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index,
>  		return PTR_ERR(overlay);
>  
>  	if (!overlay->base.possible_crtcs)
> -		overlay->base.possible_crtcs = drm_crtc_mask(crtc);
> +		overlay->base.possible_crtcs = BIT(index);

Again, I prefer to see `drm_crtc_mask` to compute possible_crtcs bitmask.
  
>  	return 0;
>  }
> @@ -53,7 +52,8 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  	struct drm_device *dev = &vkmsdev->drm;
>  	struct drm_connector *connector = &output->connector;
>  	struct drm_encoder *encoder = &output->encoder;
> -	struct drm_crtc *crtc = &output->crtc;
> +	struct vkms_crtc *vkms_crtc;
> +	struct vkms_config_crtc *crtc_cfg;
>  	struct vkms_plane *primary, *cursor = NULL;
>  	int ret;
>  	int writeback;
> @@ -65,7 +65,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  
>  	if (vkmsdev->config->overlay) {
>  		for (n = 0; n < NUM_OVERLAY_PLANES; n++) {
> -			ret = vkms_add_overlay_plane(vkmsdev, index, crtc);
> +			ret = vkms_add_overlay_plane(vkmsdev, index);
>  			if (ret)
>  				return ret;
>  		}
> @@ -77,15 +77,26 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  			return PTR_ERR(cursor);
>  	}
>  
> -	ret = vkms_crtc_init(dev, crtc, &primary->base, &cursor->base);
> -	if (ret)
> -		return ret;
> +	list_for_each_entry(crtc_cfg, &vkmsdev->config->crtcs, list) {
> +		vkms_crtc = vkms_crtc_init(dev, &primary->base, &cursor->base,
> +					   crtc_cfg->index);
> +		if (IS_ERR(vkms_crtc))
> +			return PTR_ERR(vkms_crtc);
> +
> +		list_add_tail(&vkms_crtc->list, &vkmsdev->crtcs);
> +
> +		if (crtc_cfg->writeback) {
> +			writeback = vkms_enable_writeback_connector(vkms_crtc);
> +			if (writeback)
> +				DRM_ERROR("Failed to init writeback connector\n");
> +		}
> +	}

You are creating multiple CRTC, but only link planes to the `index` one. 
Is this intentional? DRM is not happy if a CRTC don't have any primary 
plane.

>  
>  	ret = drm_connector_init(dev, connector, &vkms_connector_funcs,
>  				 DRM_MODE_CONNECTOR_VIRTUAL);
>  	if (ret) {
>  		DRM_ERROR("Failed to init connector\n");
> -		goto err_connector;
> +		return ret;
>  	}
>  
>  	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
> @@ -104,12 +115,6 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  		goto err_attach;
>  	}
>  
> -	if (vkmsdev->config->writeback) {
> -		writeback = vkms_enable_writeback_connector(vkmsdev);
> -		if (writeback)
> -			DRM_ERROR("Failed to init writeback connector\n");
> -	}
> -
>  	drm_mode_config_reset(dev);
>  
>  	return 0;
> @@ -120,8 +125,5 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  err_encoder:
>  	drm_connector_cleanup(connector);
>  
> -err_connector:
> -	drm_crtc_cleanup(crtc);
> -
>  	return ret;
>  }
> diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/vkms_writeback.c
> index bc724cbd5e3a..b317cb291586 100644

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 07/17] drm/vkms: Use managed memory to create connectors
  2024-08-13 10:44 ` [RFC PATCH 07/17] drm/vkms: Use managed memory to create connectors José Expósito
@ 2024-08-13 17:58   ` Louis Chauvet
  0 siblings, 0 replies; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:58 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel

Le 13/08/24 - 12:44, José Expósito a écrit :
> A future patch will allow to create multiple connectors. Use managed
> memory to simplify the code.
> 
> Refactor, no functional changes.
> 
> Signed-off-by: José Expósito <jose.exposito89@gmail.com>
> ---
>  drivers/gpu/drm/vkms/vkms_drv.h    |  5 ---
>  drivers/gpu/drm/vkms/vkms_output.c | 53 +++++++++++++++++-------------
>  2 files changed, 31 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
> index 2466e8b0231f..cac37d21654a 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.h
> +++ b/drivers/gpu/drm/vkms/vkms_drv.h
> @@ -121,14 +121,9 @@ struct vkms_crtc {
>  
>  struct vkms_config;
>  
> -struct vkms_output {
> -	struct drm_connector connector;
> -};
> -
>  struct vkms_device {
>  	struct drm_device drm;
>  	struct platform_device *platform;
> -	struct vkms_output output;
>  	struct list_head crtcs;
>  	const struct vkms_config *config;
>  };
> diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
> index 7afe37aea52d..4413cf88afc7 100644
> --- a/drivers/gpu/drm/vkms/vkms_output.c
> +++ b/drivers/gpu/drm/vkms/vkms_output.c
> @@ -9,7 +9,6 @@
>  
>  static const struct drm_connector_funcs vkms_connector_funcs = {
>  	.fill_modes = drm_helper_probe_single_connector_modes,
> -	.destroy = drm_connector_cleanup,
>  	.reset = drm_atomic_helper_connector_reset,
>  	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
>  	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> @@ -29,6 +28,33 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
>  	.get_modes    = vkms_conn_get_modes,
>  };
>  
> +static struct drm_connector *vkms_connector_init(struct vkms_device *vkms_device,
> +						 uint32_t possible_encoders)
> +{
> +	struct drm_connector *connector;
> +	int ret;
> +
> +	connector = drmm_kzalloc(&vkms_device->drm, sizeof(*connector), GFP_KERNEL);
> +	if (!connector) {
> +		DRM_ERROR("Failed to allocate connector\n");
> +		return ERR_PTR(-ENOMEM);
> +	}
> +
> +	ret = drmm_connector_init(&vkms_device->drm, connector,
> +				  &vkms_connector_funcs,
> +				  DRM_MODE_CONNECTOR_VIRTUAL, NULL);
> +	if (ret) {
> +		DRM_ERROR("Failed to init connector\n");
> +		kfree(connector);

Again, connector is allocated with drmm_kzalloc, so drmm_kfree or nothing.

> +		return ERR_PTR(ret);
> +	}
> +
> +	connector->possible_encoders = possible_encoders;
> +	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
> +
> +	return connector;
> +}
> +
>  static struct drm_encoder *vkms_encoder_init(struct vkms_device *vkms_device,
>  					     uint32_t possible_crtcs,
>  					     unsigned int index)
> @@ -72,9 +98,8 @@ static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index)
>  
>  int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  {
> -	struct vkms_output *output = &vkmsdev->output;
>  	struct drm_device *dev = &vkmsdev->drm;
> -	struct drm_connector *connector = &output->connector;
> +	struct drm_connector *connector;
>  	struct drm_encoder *encoder;
>  	struct vkms_config_encoder *encoder_cfg;
>  	struct vkms_crtc *vkms_crtc;
> @@ -117,14 +142,9 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  		}
>  	}
>  
> -	ret = drm_connector_init(dev, connector, &vkms_connector_funcs,
> -				 DRM_MODE_CONNECTOR_VIRTUAL);
> -	if (ret) {
> -		DRM_ERROR("Failed to init connector\n");
> -		return ret;
> -	}
> -
> -	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
> +	connector = vkms_connector_init(vkmsdev, BIT(index));

As for CRTC, you can create multiple encoder but connector is always 
attached to the first? I assume this is intentionnal? Maybe you can attach 
it to all the created encoders?

> +	if (IS_ERR(connector))
> +		return PTR_ERR(connector);
>
>  	list_for_each_entry(encoder_cfg, &vkmsdev->config->encoders, list) {
>  		encoder = vkms_encoder_init(vkmsdev, encoder_cfg->possible_crtcs,
> @@ -133,18 +153,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  			return PTR_ERR(encoder);
>  	}
>  
> -	ret = drm_connector_attach_encoder(connector, encoder);
> -	if (ret) {
> -		DRM_ERROR("Failed to attach connector to encoder\n");
> -		goto err_attach;
> -	}
> -

The encoder is not attached to the connector?

>  	drm_mode_config_reset(dev);
>  
>  	return 0;
> -
> -err_attach:
> -	drm_connector_cleanup(connector);
> -
> -	return ret;
>  }
> -- 
> 2.46.0
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 06/17] drm/vkms: Allow to configure multiple encoders
  2024-08-13 10:44 ` [RFC PATCH 06/17] drm/vkms: Allow to configure multiple encoders José Expósito
@ 2024-08-13 17:58   ` Louis Chauvet
  0 siblings, 0 replies; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:58 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel

Le 13/08/24 - 12:44, José Expósito a écrit :
> Add a list of encoder configurations to vkms_config and add as many
> encoders as configured during output initialization.
> 
> For backwards compatibility, create a single encoder in the default
> configuration.

You don't manage the deletion of crtc in vkms_config_destroy_crtc. As you 
use vkms_config_encoder.possible_crtc to initialize a CRTC, it may be an 
issue for DRM.

> Signed-off-by: José Expósito <jose.exposito89@gmail.com>
> ---
>  drivers/gpu/drm/vkms/vkms_config.c | 50 ++++++++++++++++++++++++++++++
>  drivers/gpu/drm/vkms/vkms_config.h | 13 ++++++++
>  drivers/gpu/drm/vkms/vkms_output.c | 14 ++++++---
>  3 files changed, 73 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index 3af750071f04..6a8dfebee24e 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
> @@ -18,6 +18,7 @@ struct vkms_config *vkms_config_create(char *dev_name)
>  
>  	config->dev_name = dev_name;
>  	config->crtcs = (struct list_head)LIST_HEAD_INIT(config->crtcs);
> +	config->encoders = (struct list_head)LIST_HEAD_INIT(config->encoders);

Again, why there is a cast? And why you don't use INIT_LIST_HEAD? I think 
LIST_HEAD_INIT is used to initialize static structure and 
INIT_LIST_HEAD for dynamic structures.
  
>  	return config;
>  }
> @@ -28,6 +29,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
>  {
>  	struct vkms_config *config;
>  	struct vkms_config_crtc *crtc_cfg;
> +	struct vkms_config_encoder *encoder_cfg;
>  
>  	config = vkms_config_create(DEFAULT_DEVICE_NAME);
>  	if (IS_ERR(config))
> @@ -40,16 +42,24 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
>  	if (IS_ERR(crtc_cfg))
>  		return ERR_CAST(crtc_cfg);
>  
> +	encoder_cfg = vkms_config_add_encoder(config, BIT(0));

Why do you use a magic value here and not what is set by 
vkms_config_add_crtc?

	encoder_cfg = vkms_config_add_encoder(config, crtc_cfg->index);

> +	if (IS_ERR(encoder_cfg))
> +		return ERR_CAST(encoder_cfg);
> +

Here the kzalloc from vkms_config_create is leaked.

>  	return config;
>  }
>  
>  void vkms_config_destroy(struct vkms_config *config)
>  {
>  	struct vkms_config_crtc *crtc_cfg, *crtc_tmp;
> +	struct vkms_config_encoder *encoder_cfg, *encoder_tmp;
>  
>  	list_for_each_entry_safe(crtc_cfg, crtc_tmp, &config->crtcs, list)
>  		vkms_config_destroy_crtc(config, crtc_cfg);
>  
> +	list_for_each_entry_safe(encoder_cfg, encoder_tmp, &config->encoders, list)
> +		vkms_config_destroy_encoder(config, encoder_cfg);
> +
>  	kfree(config);
>  }
>  
> @@ -59,6 +69,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);
>  	struct vkms_config_crtc *crtc_cfg;
> +	struct vkms_config_encoder *encoder_cfg;
>  	int n;
>  
>  	seq_printf(m, "dev_name=%s\n", vkmsdev->config->dev_name);
> @@ -72,6 +83,13 @@ static int vkms_config_show(struct seq_file *m, void *data)
>  		n++;
>  	}
>  
> +	n = 0;
> +	list_for_each_entry(encoder_cfg, &vkmsdev->config->encoders, list) {
> +		seq_printf(m, "encoder(%d).possible_crtcs=%d\n", n,
> +			   encoder_cfg->possible_crtcs);
> +		n++;
> +	}
> +
>  	return 0;
>  }
>  
> @@ -116,3 +134,35 @@ void vkms_config_destroy_crtc(struct vkms_config *config,
>  	list_del(&crtc_cfg->list);
>  	kfree(crtc_cfg);
>  }
> +
> +struct vkms_config_encoder *vkms_config_add_encoder(struct vkms_config *config,
> +						    uint32_t possible_crtcs)
> +{
> +	struct vkms_config_encoder *encoder_cfg;
> +
> +	encoder_cfg = kzalloc(sizeof(*encoder_cfg), GFP_KERNEL);
> +	if (!encoder_cfg)
> +		return ERR_PTR(-ENOMEM);
> +
> +	encoder_cfg->possible_crtcs = possible_crtcs;
> +
> +	encoder_cfg->index = 0;
> +	if (!list_empty(&config->encoders)) {
> +		struct vkms_config_encoder *last;
> +
> +		last = list_last_entry(&config->encoders,
> +				       struct vkms_config_encoder, list);
> +		encoder_cfg->index = last->index + 1;

Same here, drm core is already managing indexes, can we avoid 
reimplementing this logic?

There is the same issue as in CRTC, if you create 32 encoders, remove one 
and add one, the index will be invalid for drm.

> +	}
> +
> +	list_add_tail(&encoder_cfg->list, &config->encoders);
> +
> +	return encoder_cfg;
> +}
> +
> +void vkms_config_destroy_encoder(struct vkms_config *config,
> +				 struct vkms_config_encoder *encoder_cfg)
> +{
> +	list_del(&encoder_cfg->list);
> +	kfree(encoder_cfg);
> +}
> diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
> index bc40a0e3859a..b717b5c0d3d9 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.h
> +++ b/drivers/gpu/drm/vkms/vkms_config.h
> @@ -14,11 +14,18 @@ struct vkms_config_crtc {
>  	bool writeback;
>  };
>  
> +struct vkms_config_encoder {
> +	struct list_head list;
> +	unsigned int index;
> +	uint32_t possible_crtcs;
> +};
> +
>  struct vkms_config {
>  	char *dev_name;
>  	bool cursor;
>  	bool overlay;
>  	struct list_head crtcs;
> +	struct list_head encoders;
>  	/* only set when instantiated */
>  	struct vkms_device *dev;
>  };
> @@ -39,4 +46,10 @@ struct vkms_config_crtc *vkms_config_add_crtc(struct vkms_config *config,
>  void vkms_config_destroy_crtc(struct vkms_config *config,
>  			      struct vkms_config_crtc *crtc_cfg);
>  
> +/* Encoders */
> +struct vkms_config_encoder *vkms_config_add_encoder(struct vkms_config *config,
> +						    uint32_t possible_crtcs);
> +void vkms_config_destroy_encoder(struct vkms_config *config,
> +				 struct vkms_config_encoder *encoder_cfg);
> +
>  #endif /* _VKMS_CONFIG_H_ */
> diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
> index 15f0b72af325..7afe37aea52d 100644
> --- a/drivers/gpu/drm/vkms/vkms_output.c
> +++ b/drivers/gpu/drm/vkms/vkms_output.c
> @@ -30,7 +30,8 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
>  };
>  
>  static struct drm_encoder *vkms_encoder_init(struct vkms_device *vkms_device,
> -					     uint32_t possible_crtcs)
> +					     uint32_t possible_crtcs,
> +					     unsigned int index)
>  {
>  	struct drm_encoder *encoder;
>  	int ret;
> @@ -49,6 +50,7 @@ static struct drm_encoder *vkms_encoder_init(struct vkms_device *vkms_device,
>  		return ERR_PTR(ret);
>  	}
>  
> +	encoder->index = index;
>  	encoder->possible_crtcs = possible_crtcs;
>  
>  	return encoder;
> @@ -74,6 +76,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  	struct drm_device *dev = &vkmsdev->drm;
>  	struct drm_connector *connector = &output->connector;
>  	struct drm_encoder *encoder;
> +	struct vkms_config_encoder *encoder_cfg;
>  	struct vkms_crtc *vkms_crtc;
>  	struct vkms_config_crtc *crtc_cfg;
>  	struct vkms_plane *primary, *cursor = NULL;
> @@ -123,9 +126,12 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  
>  	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
>  
> -	encoder = vkms_encoder_init(vkmsdev, BIT(0));
> -	if (IS_ERR(encoder))
> -		return PTR_ERR(encoder);
> +	list_for_each_entry(encoder_cfg, &vkmsdev->config->encoders, list) {
> +		encoder = vkms_encoder_init(vkmsdev, encoder_cfg->possible_crtcs,
> +					    encoder_cfg->index);
> +		if (IS_ERR(encoder))
> +			return PTR_ERR(encoder);
> +	}
>  
>  	ret = drm_connector_attach_encoder(connector, encoder);
>  	if (ret) {
> -- 
> 2.46.0
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 05/17] drm/vkms: Use managed memory to create encoders
  2024-08-13 10:44 ` [RFC PATCH 05/17] drm/vkms: Use managed memory to create encoders José Expósito
@ 2024-08-13 17:58   ` Louis Chauvet
  0 siblings, 0 replies; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:58 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel

Le 13/08/24 - 12:44, José Expósito a écrit :
> A future patch will allow to create multiple encoders. Use managed
> memory to simplify the code.
> 
> Refactor, no functional changes.
> 
> Signed-off-by: José Expósito <jose.exposito89@gmail.com>
> ---
>  drivers/gpu/drm/vkms/vkms_drv.h    |  1 -
>  drivers/gpu/drm/vkms/vkms_output.c | 45 ++++++++++++++++++++----------
>  2 files changed, 30 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
> index 3156ff896c33..2466e8b0231f 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.h
> +++ b/drivers/gpu/drm/vkms/vkms_drv.h
> @@ -122,7 +122,6 @@ struct vkms_crtc {
>  struct vkms_config;
>  
>  struct vkms_output {
> -	struct drm_encoder encoder;
>  	struct drm_connector connector;
>  };
>  
> diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
> index dcd32bc30e17..15f0b72af325 100644
> --- a/drivers/gpu/drm/vkms/vkms_output.c
> +++ b/drivers/gpu/drm/vkms/vkms_output.c
> @@ -4,6 +4,7 @@
>  #include "vkms_drv.h"
>  #include <drm/drm_atomic_helper.h>
>  #include <drm/drm_edid.h>
> +#include <drm/drm_managed.h>
>  #include <drm/drm_probe_helper.h>
>  
>  static const struct drm_connector_funcs vkms_connector_funcs = {
> @@ -14,10 +15,6 @@ static const struct drm_connector_funcs vkms_connector_funcs = {
>  	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>  };
>  
> -static const struct drm_encoder_funcs vkms_encoder_funcs = {
> -	.destroy = drm_encoder_cleanup,
> -};
> -
>  static int vkms_conn_get_modes(struct drm_connector *connector)
>  {
>  	int count;
> @@ -32,6 +29,31 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = {
>  	.get_modes    = vkms_conn_get_modes,
>  };
>  
> +static struct drm_encoder *vkms_encoder_init(struct vkms_device *vkms_device,
> +					     uint32_t possible_crtcs)
> +{
> +	struct drm_encoder *encoder;
> +	int ret;
> +
> +	encoder = drmm_kzalloc(&vkms_device->drm, sizeof(*encoder), GFP_KERNEL);
> +	if (!encoder) {
> +		DRM_ERROR("Failed to allocate encoder\n");
> +		return ERR_PTR(-ENOMEM);
> +	}

Thanks, I forgot this error handling in my implementation!

And while checking, I also found the drmm_encoder_alloc macro, which do 
the kzalloc AND the _init. Maybe we should use this?

> +
> +	ret = drmm_encoder_init(&vkms_device->drm, encoder, NULL,
> +				DRM_MODE_ENCODER_VIRTUAL, NULL);
> +	if (ret) {
> +		DRM_ERROR("Failed to init encoder\n");
> +		kfree(encoder);

Are you sure about this kfree? As the encoder was initialized by 
drmm_kzalloc, it should be freed by drm?

Or at least, drmm_kfree?

> +		return ERR_PTR(ret);
> +	}
> +
> +	encoder->possible_crtcs = possible_crtcs;
> +
> +	return encoder;
> +}
> +
>  static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index)
>  {
>  	struct vkms_plane *overlay;
> @@ -51,7 +73,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  	struct vkms_output *output = &vkmsdev->output;
>  	struct drm_device *dev = &vkmsdev->drm;
>  	struct drm_connector *connector = &output->connector;
> -	struct drm_encoder *encoder = &output->encoder;
> +	struct drm_encoder *encoder;
>  	struct vkms_crtc *vkms_crtc;
>  	struct vkms_config_crtc *crtc_cfg;
>  	struct vkms_plane *primary, *cursor = NULL;
> @@ -101,13 +123,9 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  
>  	drm_connector_helper_add(connector, &vkms_conn_helper_funcs);
>  
> -	ret = drm_encoder_init(dev, encoder, &vkms_encoder_funcs,
> -			       DRM_MODE_ENCODER_VIRTUAL, NULL);
> -	if (ret) {
> -		DRM_ERROR("Failed to init encoder\n");
> -		goto err_encoder;
> -	}
> -	encoder->possible_crtcs = 1;
> +	encoder = vkms_encoder_init(vkmsdev, BIT(0));
> +	if (IS_ERR(encoder))
> +		return PTR_ERR(encoder);
>  
>  	ret = drm_connector_attach_encoder(connector, encoder);
>  	if (ret) {
> @@ -120,9 +138,6 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  	return 0;
>  
>  err_attach:
> -	drm_encoder_cleanup(encoder);
> -
> -err_encoder:
>  	drm_connector_cleanup(connector);
>  
>  	return ret;
> -- 
> 2.46.0
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 08/17] drm/vkms: Allow to configure multiple connectors
  2024-08-13 10:44 ` [RFC PATCH 08/17] drm/vkms: Allow to configure multiple connectors José Expósito
@ 2024-08-13 17:58   ` Louis Chauvet
  0 siblings, 0 replies; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:58 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel

Le 13/08/24 - 12:44, José Expósito a écrit :
> Add a list of connector configurations to vkms_config and add as many
> connector as configured during output initialization.
> 
> For backwards compatibility, create a single connector in the default
> configuration.
> 
> Signed-off-by: José Expósito <jose.exposito89@gmail.com>
> ---
>  drivers/gpu/drm/vkms/vkms_config.c | 40 ++++++++++++++++++++++++++++++
>  drivers/gpu/drm/vkms/vkms_config.h | 12 +++++++++
>  drivers/gpu/drm/vkms/vkms_output.c | 11 +++++---
>  3 files changed, 59 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index 6a8dfebee24e..a456f9db3c66 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
> @@ -19,6 +19,7 @@ struct vkms_config *vkms_config_create(char *dev_name)
>  	config->dev_name = dev_name;
>  	config->crtcs = (struct list_head)LIST_HEAD_INIT(config->crtcs);
>  	config->encoders = (struct list_head)LIST_HEAD_INIT(config->encoders);
> +	config->connectors = (struct list_head)LIST_HEAD_INIT(config->connectors);

Again, this cast seems useless
  
>  	return config;
>  }
> @@ -30,6 +31,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
>  	struct vkms_config *config;
>  	struct vkms_config_crtc *crtc_cfg;
>  	struct vkms_config_encoder *encoder_cfg;
> +	struct vkms_config_connector *connector_cfg;
>  
>  	config = vkms_config_create(DEFAULT_DEVICE_NAME);
>  	if (IS_ERR(config))
> @@ -46,6 +48,10 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
>  	if (IS_ERR(encoder_cfg))
>  		return ERR_CAST(encoder_cfg);
>  
> +	connector_cfg = vkms_config_add_connector(config, BIT(0));
> +	if (IS_ERR(connector_cfg))
> +		return ERR_CAST(connector_cfg);
> +

The config pointer is leaked here.

>  	return config;
>  }
>  
> @@ -53,6 +59,7 @@ void vkms_config_destroy(struct vkms_config *config)
>  {
>  	struct vkms_config_crtc *crtc_cfg, *crtc_tmp;
>  	struct vkms_config_encoder *encoder_cfg, *encoder_tmp;
> +	struct vkms_config_connector *connector_cfg, *connector_tmp;
>  
>  	list_for_each_entry_safe(crtc_cfg, crtc_tmp, &config->crtcs, list)
>  		vkms_config_destroy_crtc(config, crtc_cfg);
> @@ -60,6 +67,9 @@ void vkms_config_destroy(struct vkms_config *config)
>  	list_for_each_entry_safe(encoder_cfg, encoder_tmp, &config->encoders, list)
>  		vkms_config_destroy_encoder(config, encoder_cfg);
>  
> +	list_for_each_entry_safe(connector_cfg, connector_tmp, &config->connectors, list)
> +		vkms_config_destroy_connector(config, connector_cfg);
> +
>  	kfree(config);
>  }
>  
> @@ -70,6 +80,7 @@ static int vkms_config_show(struct seq_file *m, void *data)
>  	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
>  	struct vkms_config_crtc *crtc_cfg;
>  	struct vkms_config_encoder *encoder_cfg;
> +	struct vkms_config_connector *connector_cfg;
>  	int n;
>  
>  	seq_printf(m, "dev_name=%s\n", vkmsdev->config->dev_name);
> @@ -90,6 +101,13 @@ static int vkms_config_show(struct seq_file *m, void *data)
>  		n++;
>  	}
>  
> +	n = 0;
> +	list_for_each_entry(connector_cfg, &vkmsdev->config->connectors, list) {
> +		seq_printf(m, "connector(%d).possible_encoders=%d\n", n,
> +			   connector_cfg->possible_encoders);
> +		n++;
> +	}
> +
>  	return 0;
>  }
>  
> @@ -166,3 +184,25 @@ void vkms_config_destroy_encoder(struct vkms_config *config,
>  	list_del(&encoder_cfg->list);
>  	kfree(encoder_cfg);
>  }
> +
> +struct vkms_config_connector *vkms_config_add_connector(struct vkms_config *config,
> +							uint32_t possible_encoders)
> +{
> +	struct vkms_config_connector *connector_cfg;
> +
> +	connector_cfg = kzalloc(sizeof(*connector_cfg), GFP_KERNEL);
> +	if (!connector_cfg)
> +		return ERR_PTR(-ENOMEM);
> +
> +	connector_cfg->possible_encoders = possible_encoders;

For config_encoder destruction you need to remove it from this 
possible_encoders list.

> +	list_add_tail(&connector_cfg->list, &config->connectors);
> +
> +	return connector_cfg;
> +}
> +
> +void vkms_config_destroy_connector(struct vkms_config *config,
> +				   struct vkms_config_connector *connector_cfg)
> +{
> +	list_del(&connector_cfg->list);
> +	kfree(connector_cfg);
> +}
> diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
> index b717b5c0d3d9..f1dd59fc6300 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.h
> +++ b/drivers/gpu/drm/vkms/vkms_config.h
> @@ -20,12 +20,18 @@ struct vkms_config_encoder {
>  	uint32_t possible_crtcs;
>  };
>  
> +struct vkms_config_connector {
> +	struct list_head list;
> +	uint32_t possible_encoders;
> +};
> +
>  struct vkms_config {
>  	char *dev_name;
>  	bool cursor;
>  	bool overlay;
>  	struct list_head crtcs;
>  	struct list_head encoders;
> +	struct list_head connectors;
>  	/* only set when instantiated */
>  	struct vkms_device *dev;
>  };
> @@ -52,4 +58,10 @@ struct vkms_config_encoder *vkms_config_add_encoder(struct vkms_config *config,
>  void vkms_config_destroy_encoder(struct vkms_config *config,
>  				 struct vkms_config_encoder *encoder_cfg);
>  
> +/* Connectors */
> +struct vkms_config_connector *vkms_config_add_connector(struct vkms_config *config,
> +							uint32_t possible_encoders);
> +void vkms_config_destroy_connector(struct vkms_config *config,
> +				   struct vkms_config_connector *connector_cfg);
> +
>  #endif /* _VKMS_CONFIG_H_ */
> diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
> index 4413cf88afc7..021a491de817 100644
> --- a/drivers/gpu/drm/vkms/vkms_output.c
> +++ b/drivers/gpu/drm/vkms/vkms_output.c
> @@ -100,6 +100,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  {
>  	struct drm_device *dev = &vkmsdev->drm;
>  	struct drm_connector *connector;
> +	struct vkms_config_connector *connector_cfg;
>  	struct drm_encoder *encoder;
>  	struct vkms_config_encoder *encoder_cfg;
>  	struct vkms_crtc *vkms_crtc;
> @@ -142,10 +143,6 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  		}
>  	}
>  
> -	connector = vkms_connector_init(vkmsdev, BIT(index));
> -	if (IS_ERR(connector))
> -		return PTR_ERR(connector);
> -
>  	list_for_each_entry(encoder_cfg, &vkmsdev->config->encoders, list) {
>  		encoder = vkms_encoder_init(vkmsdev, encoder_cfg->possible_crtcs,
>  					    encoder_cfg->index);
> @@ -153,6 +150,12 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  			return PTR_ERR(encoder);
>  	}
>  
> +	list_for_each_entry(connector_cfg, &vkmsdev->config->connectors, list) {
> +		connector = vkms_connector_init(vkmsdev, connector_cfg->possible_encoders);
> +		if (IS_ERR(connector))
> +			return PTR_ERR(connector);
> +	}
> +
>  	drm_mode_config_reset(dev);
>  
>  	return 0;
> -- 
> 2.46.0
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 09/17] drm/vkms: Allow to configure multiple overlay planes
  2024-08-13 10:44 ` [RFC PATCH 09/17] drm/vkms: Allow to configure multiple overlay planes José Expósito
@ 2024-08-13 17:58   ` Louis Chauvet
  0 siblings, 0 replies; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:58 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel

Le 13/08/24 - 12:44, José Expósito a écrit :
> Add a list of overlay planes to vkms_config and add as many overlay
> planes as configured during output initialization.
> 
> For backwards compatibility, add NUM_OVERLAY_PLANES to the default
> configuration.
> 
> Note that a primary plane is created for each CRTC and it is not
> possible to configure it.
> A cursor plane is added conditionally if it is enabled in the CRTC
> configuration.
> 
> Signed-off-by: José Expósito <jose.exposito89@gmail.com>
> ---
>  drivers/gpu/drm/vkms/vkms_config.c | 53 +++++++++++++++++++++++++++---
>  drivers/gpu/drm/vkms/vkms_config.h | 16 +++++++--
>  drivers/gpu/drm/vkms/vkms_drv.c    |  2 +-
>  drivers/gpu/drm/vkms/vkms_drv.h    |  5 +--
>  drivers/gpu/drm/vkms/vkms_output.c | 43 ++++++++++++------------
>  drivers/gpu/drm/vkms/vkms_plane.c  |  6 ++--
>  6 files changed, 91 insertions(+), 34 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index a456f9db3c66..d95a42a6745a 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.c
> +++ b/drivers/gpu/drm/vkms/vkms_config.c
> @@ -17,6 +17,7 @@ struct vkms_config *vkms_config_create(char *dev_name)
>  		return ERR_PTR(-ENOMEM);
>  
>  	config->dev_name = dev_name;
> +	config->planes = (struct list_head)LIST_HEAD_INIT(config->planes);
>  	config->crtcs = (struct list_head)LIST_HEAD_INIT(config->crtcs);
>  	config->encoders = (struct list_head)LIST_HEAD_INIT(config->encoders);
>  	config->connectors = (struct list_head)LIST_HEAD_INIT(config->connectors);
> @@ -32,15 +33,22 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
>  	struct vkms_config_crtc *crtc_cfg;
>  	struct vkms_config_encoder *encoder_cfg;
>  	struct vkms_config_connector *connector_cfg;
> +	struct vkms_config_plane *plane_cfg;
> +	int n;
>  
>  	config = vkms_config_create(DEFAULT_DEVICE_NAME);
>  	if (IS_ERR(config))
>  		return config;
>  
> -	config->cursor = enable_cursor;
> -	config->overlay = enable_overlay;
> +	if (enable_overlay) {
> +		for (n = 0; n < NUM_OVERLAY_PLANES; n++) {
> +			plane_cfg = vkms_config_add_overlay_plane(config, BIT(0));
> +			if (IS_ERR(plane_cfg))
> +				return ERR_CAST(plane_cfg);

The config pointer is leaked here.

> +		}
> +	}
>  
> -	crtc_cfg = vkms_config_add_crtc(config, enable_writeback);
> +	crtc_cfg = vkms_config_add_crtc(config, enable_cursor, enable_writeback);
>  	if (IS_ERR(crtc_cfg))
>  		return ERR_CAST(crtc_cfg);
>  
> @@ -57,10 +65,14 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
>  
>  void vkms_config_destroy(struct vkms_config *config)
>  {
> +	struct vkms_config_plane *plane_cfg, *plane_tmp;
>  	struct vkms_config_crtc *crtc_cfg, *crtc_tmp;
>  	struct vkms_config_encoder *encoder_cfg, *encoder_tmp;
>  	struct vkms_config_connector *connector_cfg, *connector_tmp;
>  
> +	list_for_each_entry_safe(plane_cfg, plane_tmp, &config->planes, list)
> +		vkms_config_destroy_overlay_plane(config, plane_cfg);
> +
>  	list_for_each_entry_safe(crtc_cfg, crtc_tmp, &config->crtcs, list)
>  		vkms_config_destroy_crtc(config, crtc_cfg);
>  
> @@ -78,17 +90,24 @@ static int vkms_config_show(struct seq_file *m, void *data)
>  	struct drm_debugfs_entry *entry = m->private;
>  	struct drm_device *dev = entry->dev;
>  	struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
> +	struct vkms_config_plane *plane_cfg;
>  	struct vkms_config_crtc *crtc_cfg;
>  	struct vkms_config_encoder *encoder_cfg;
>  	struct vkms_config_connector *connector_cfg;
>  	int n;
>  
>  	seq_printf(m, "dev_name=%s\n", vkmsdev->config->dev_name);
> -	seq_printf(m, "cursor=%d\n", vkmsdev->config->cursor);
> -	seq_printf(m, "overlay=%d\n", vkmsdev->config->overlay);
> +
> +	n = 0;
> +	list_for_each_entry(plane_cfg, &vkmsdev->config->planes, list) {
> +		seq_printf(m, "plane(%d).possible_crtcs=%d\n", n,
> +			   plane_cfg->possible_crtcs);
> +		n++;
> +	}
>  
>  	n = 0;
>  	list_for_each_entry(crtc_cfg, &vkmsdev->config->crtcs, list) {
> +		seq_printf(m, "crtc(%d).cursor=%d\n", n, crtc_cfg->cursor);
>  		seq_printf(m, "crtc(%d).writeback=%d\n", n,
>  			   crtc_cfg->writeback);
>  		n++;
> @@ -121,7 +140,30 @@ void vkms_config_debugfs_init(struct vkms_device *vkms_device)
>  			      ARRAY_SIZE(vkms_config_debugfs_list));
>  }
>  
> +struct vkms_config_plane *vkms_config_add_overlay_plane(struct vkms_config *config,
> +							uint32_t possible_crtcs)
> +{
> +	struct vkms_config_plane *plane_cfg;
> +
> +	plane_cfg = kzalloc(sizeof(*plane_cfg), GFP_KERNEL);
> +	if (!plane_cfg)
> +		return ERR_PTR(-ENOMEM);
> +
> +	plane_cfg->possible_crtcs = possible_crtcs;
> +	list_add_tail(&plane_cfg->list, &config->planes);
> +
> +	return plane_cfg;
> +}
> +
> +void vkms_config_destroy_overlay_plane(struct vkms_config *config,
> +				       struct vkms_config_plane *plane_cfg)
> +{
> +	list_del(&plane_cfg->list);
> +	kfree(plane_cfg);
> +}
> +
>  struct vkms_config_crtc *vkms_config_add_crtc(struct vkms_config *config,
> +					      bool enable_cursor,
>  					      bool enable_writeback)
>  {
>  	struct vkms_config_crtc *crtc_cfg;
> @@ -130,6 +172,7 @@ struct vkms_config_crtc *vkms_config_add_crtc(struct vkms_config *config,
>  	if (!crtc_cfg)
>  		return ERR_PTR(-ENOMEM);
>  
> +	crtc_cfg->cursor = enable_cursor;
>  	crtc_cfg->writeback = enable_writeback;
>  
>  	crtc_cfg->index = 0;
> diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
> index f1dd59fc6300..25dab63e7ae7 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.h
> +++ b/drivers/gpu/drm/vkms/vkms_config.h
> @@ -8,9 +8,15 @@
>  
>  struct vkms_device;
>  
> +struct vkms_config_plane {
> +	struct list_head list;
> +	uint32_t possible_crtcs;

As for encoder and connector, the crtc cleanup does not change 
possible_crtcs value, so you may end up with an invalid configuration.

> +};
> +
>  struct vkms_config_crtc {
>  	struct list_head list;
>  	unsigned int index;
> +	bool cursor;
>  	bool writeback;
>  };
>  
> @@ -27,8 +33,7 @@ struct vkms_config_connector {
>  
>  struct vkms_config {
>  	char *dev_name;
> -	bool cursor;
> -	bool overlay;
> +	struct list_head planes;
>  	struct list_head crtcs;
>  	struct list_head encoders;
>  	struct list_head connectors;
> @@ -46,8 +51,15 @@ void vkms_config_destroy(struct vkms_config *config);
>  /* DebugFS */
>  void vkms_config_debugfs_init(struct vkms_device *vkms_device);
>  
> +/* Planes */
> +struct vkms_config_plane *vkms_config_add_overlay_plane(struct vkms_config *config,
> +							uint32_t possible_crtcs);
> +void vkms_config_destroy_overlay_plane(struct vkms_config *config,
> +				       struct vkms_config_plane *plane_cfg);
> +
>  /* CRTCs */
>  struct vkms_config_crtc *vkms_config_add_crtc(struct vkms_config *config,
> +					      bool enable_cursor,
>  					      bool enable_writeback);
>  void vkms_config_destroy_crtc(struct vkms_config *config,
>  			      struct vkms_config_crtc *crtc_cfg);
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
> index 15a2ba26d190..b0a079eb4598 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.c
> +++ b/drivers/gpu/drm/vkms/vkms_drv.c
> @@ -154,7 +154,7 @@ static int vkms_modeset_init(struct vkms_device *vkmsdev)
>  	dev->mode_config.preferred_depth = 0;
>  	dev->mode_config.helper_private = &vkms_mode_config_helpers;
>  
> -	return vkms_output_init(vkmsdev, 0);
> +	return vkms_output_init(vkmsdev);
>  }
>  
>  static int vkms_create(struct vkms_config *config)
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
> index cac37d21654a..76394285dc68 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.h
> +++ b/drivers/gpu/drm/vkms/vkms_drv.h
> @@ -149,10 +149,11 @@ struct vkms_crtc *vkms_crtc_init(struct drm_device *dev,
>  				 struct drm_plane *cursor,
>  				 unsigned int index);
>  
> -int vkms_output_init(struct vkms_device *vkmsdev, int index);
> +int vkms_output_init(struct vkms_device *vkmsdev);
>  
>  struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
> -				   enum drm_plane_type type, int index);
> +				   enum drm_plane_type type,
> +				   uint32_t possible_crtcs);
>  
>  /* CRC Support */
>  const char *const *vkms_get_crc_sources(struct drm_crtc *crtc,
> diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
> index 021a491de817..a5b1ab326cdd 100644
> --- a/drivers/gpu/drm/vkms/vkms_output.c
> +++ b/drivers/gpu/drm/vkms/vkms_output.c
> @@ -82,21 +82,22 @@ static struct drm_encoder *vkms_encoder_init(struct vkms_device *vkms_device,
>  	return encoder;
>  }
>  
> -static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index)
> +static int vkms_add_overlay_plane(struct vkms_device *vkmsdev,
> +				  uint32_t possible_crtcs)
>  {
>  	struct vkms_plane *overlay;
>  
> -	overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, index);
> +	overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, possible_crtcs);
>  	if (IS_ERR(overlay))
>  		return PTR_ERR(overlay);
>  
>  	if (!overlay->base.possible_crtcs)
> -		overlay->base.possible_crtcs = BIT(index);
> +		overlay->base.possible_crtcs = possible_crtcs;
>  
>  	return 0;
>  }
>  
> -int vkms_output_init(struct vkms_device *vkmsdev, int index)
> +int vkms_output_init(struct vkms_device *vkmsdev)
>  {
>  	struct drm_device *dev = &vkmsdev->drm;
>  	struct drm_connector *connector;
> @@ -106,29 +107,27 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  	struct vkms_crtc *vkms_crtc;
>  	struct vkms_config_crtc *crtc_cfg;
>  	struct vkms_plane *primary, *cursor = NULL;
> +	struct vkms_config_plane *plane_cfg;
>  	int ret;
>  	int writeback;
> -	unsigned int n;
>  
> -	primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY, index);
> -	if (IS_ERR(primary))
> -		return PTR_ERR(primary);
> -
> -	if (vkmsdev->config->overlay) {
> -		for (n = 0; n < NUM_OVERLAY_PLANES; n++) {
> -			ret = vkms_add_overlay_plane(vkmsdev, index);
> -			if (ret)
> -				return ret;
> -		}
> -	}
> -
> -	if (vkmsdev->config->cursor) {
> -		cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR, index);
> -		if (IS_ERR(cursor))
> -			return PTR_ERR(cursor);
> +	list_for_each_entry(plane_cfg, &vkmsdev->config->planes, list) {
> +		ret = vkms_add_overlay_plane(vkmsdev, plane_cfg->possible_crtcs);
> +		if (ret)
> +			return ret;
>  	}
>  
>  	list_for_each_entry(crtc_cfg, &vkmsdev->config->crtcs, list) {
> +		primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY, 0);
> +		if (IS_ERR(primary))
> +			return PTR_ERR(primary);
> +
> +		if (crtc_cfg->cursor) {
> +			cursor = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR, 0);

Why are you hardcoding the primary and cursor plane here? I think it is 
easier to manage them as "normal" planes with vkms_config_plane, and use 
the enum drm_plane_type to find the correct one here.

Otherwise we will need either to:
- duplicate all the plane configuration for those primary and cursor 
  planes
- rework this part of the code to use vkms_config_plane.

> +			if (IS_ERR(cursor))
> +				return PTR_ERR(cursor);
> +		}
> +
>  		vkms_crtc = vkms_crtc_init(dev, &primary->base, &cursor->base,
>  					   crtc_cfg->index);
>  		if (IS_ERR(vkms_crtc))
> @@ -141,6 +140,8 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
>  			if (writeback)
>  				DRM_ERROR("Failed to init writeback connector\n");
>  		}
> +
> +		cursor = NULL;
>  	}
>  
>  	list_for_each_entry(encoder_cfg, &vkmsdev->config->encoders, list) {
> diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_plane.c
> index e5c625ab8e3e..eb3edf4cb928 100644
> --- a/drivers/gpu/drm/vkms/vkms_plane.c
> +++ b/drivers/gpu/drm/vkms/vkms_plane.c
> @@ -198,13 +198,13 @@ static const struct drm_plane_helper_funcs vkms_plane_helper_funcs = {
>  };
>  
>  struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
> -				   enum drm_plane_type type, int index)
> +				   enum drm_plane_type type, uint32_t possible_crtcs)
>  {
>  	struct drm_device *dev = &vkmsdev->drm;
>  	struct vkms_plane *plane;
>  
> -	plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base, 1 << index,
> -					   &vkms_plane_funcs,
> +	plane = drmm_universal_plane_alloc(dev, struct vkms_plane, base,
> +					   possible_crtcs, &vkms_plane_funcs,
>  					   vkms_formats, ARRAY_SIZE(vkms_formats),
>  					   NULL, type, NULL);
>  	if (IS_ERR(plane))
> -- 
> 2.46.0
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 10/17] drm/vkms: Allow to change connector status
  2024-08-13 10:44 ` [RFC PATCH 10/17] drm/vkms: Allow to change connector status José Expósito
@ 2024-08-13 17:58   ` Louis Chauvet
  0 siblings, 0 replies; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:58 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel

Le 13/08/24 - 12:44, José Expósito a écrit :
> Store the connector status in vkms_config_connector and use the stored
> value to update the connector status in the drm_connector_funcs.detect()
> function.

I did not work on this part, so my comments may be not relevant.
 
> Signed-off-by: José Expósito <jose.exposito89@gmail.com>
> ---
>  drivers/gpu/drm/vkms/vkms_config.c | 18 ++++++++++++++++--
>  drivers/gpu/drm/vkms/vkms_config.h | 12 +++++++++++-
>  drivers/gpu/drm/vkms/vkms_output.c | 20 ++++++++++++++++++++
>  3 files changed, 47 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c
> index d95a42a6745a..e8e5c02c9d43 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 <drm/drm_print.h>
> +#include <drm/drm_probe_helper.h>
>  #include <drm/drm_debugfs.h>
>  
>  #include "vkms_config.h"
> @@ -56,7 +57,7 @@ struct vkms_config *vkms_config_default_create(bool enable_cursor,
>  	if (IS_ERR(encoder_cfg))
>  		return ERR_CAST(encoder_cfg);
>  
> -	connector_cfg = vkms_config_add_connector(config, BIT(0));
> +	connector_cfg = vkms_config_add_connector(config, BIT(0), connector_status_connected);
>  	if (IS_ERR(connector_cfg))
>  		return ERR_CAST(connector_cfg);
>  
> @@ -124,6 +125,8 @@ static int vkms_config_show(struct seq_file *m, void *data)
>  	list_for_each_entry(connector_cfg, &vkmsdev->config->connectors, list) {
>  		seq_printf(m, "connector(%d).possible_encoders=%d\n", n,
>  			   connector_cfg->possible_encoders);
> +		seq_printf(m, "connector(%d).status=%d\n", n,
> +			   connector_cfg->status);
>  		n++;
>  	}
>  
> @@ -229,7 +232,8 @@ void vkms_config_destroy_encoder(struct vkms_config *config,
>  }
>  
>  struct vkms_config_connector *vkms_config_add_connector(struct vkms_config *config,
> -							uint32_t possible_encoders)
> +							uint32_t possible_encoders,
> +							enum drm_connector_status status)
>  {
>  	struct vkms_config_connector *connector_cfg;
>  
> @@ -238,6 +242,7 @@ struct vkms_config_connector *vkms_config_add_connector(struct vkms_config *conf
>  		return ERR_PTR(-ENOMEM);
>  
>  	connector_cfg->possible_encoders = possible_encoders;
> +	connector_cfg->status = status;
>  	list_add_tail(&connector_cfg->list, &config->connectors);
>  
>  	return connector_cfg;
> @@ -249,3 +254,12 @@ void vkms_config_destroy_connector(struct vkms_config *config,
>  	list_del(&connector_cfg->list);
>  	kfree(connector_cfg);
>  }
> +
> +void vkms_update_connector_status(struct vkms_config *config,
> +				  struct vkms_config_connector *connector_cfg,
> +				  enum drm_connector_status status)
> +{
> +	connector_cfg->status = status;
> +	if (config->dev)
> +		drm_kms_helper_hotplug_event(&config->dev->drm);
> +}
> diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
> index 25dab63e7ae7..3237406fa3a3 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.h
> +++ b/drivers/gpu/drm/vkms/vkms_config.h
> @@ -6,6 +6,8 @@
>  #include <linux/list.h>
>  #include <linux/types.h>
>  
> +#include <drm/drm_connector.h>
> +
>  struct vkms_device;
>  
>  struct vkms_config_plane {
> @@ -29,6 +31,9 @@ struct vkms_config_encoder {
>  struct vkms_config_connector {
>  	struct list_head list;
>  	uint32_t possible_encoders;
> +	enum drm_connector_status status;
> +	/* only set when instantiated */
> +	struct drm_connector *connector;

It seems very strange to have a "dynamic" field (status) in a 
configuration structure.

>  };
>  
>  struct vkms_config {
> @@ -72,8 +77,13 @@ void vkms_config_destroy_encoder(struct vkms_config *config,
>  
>  /* Connectors */
>  struct vkms_config_connector *vkms_config_add_connector(struct vkms_config *config,
> -							uint32_t possible_encoders);
> +							uint32_t possible_encoders,
> +							enum drm_connector_status status);
>  void vkms_config_destroy_connector(struct vkms_config *config,
>  				   struct vkms_config_connector *connector_cfg);
>  
> +void vkms_update_connector_status(struct vkms_config *config,
> +				  struct vkms_config_connector *connector_cfg,
> +				  enum drm_connector_status status);
> +
>  #endif /* _VKMS_CONFIG_H_ */
> diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c
> index a5b1ab326cdd..511cc2c14c44 100644
> --- a/drivers/gpu/drm/vkms/vkms_output.c
> +++ b/drivers/gpu/drm/vkms/vkms_output.c
> @@ -7,7 +7,25 @@
>  #include <drm/drm_managed.h>
>  #include <drm/drm_probe_helper.h>
>  
> +static enum drm_connector_status vkms_connector_detect(struct drm_connector *connector,
> +						       bool force)
> +{
> +	struct vkms_device *vkmsdev = drm_device_to_vkms_device(connector->dev);
> +	enum drm_connector_status status = connector->status;
> +	struct vkms_config_connector *connector_cfg;
> +
> +	list_for_each_entry(connector_cfg, &vkmsdev->config->connectors, list) {
> +		if (connector_cfg->connector == connector) {
> +			status = connector_cfg->status;
> +			break;
> +		}
> +	}

To avoid this, maybe we can create a vkms_connector:

	struct vkms_connector {
		int status;
		struct drm_connector base;
	};

and use container_of?

> +
> +	return status;
> +}
> +
>  static const struct drm_connector_funcs vkms_connector_funcs = {
> +	.detect = vkms_connector_detect,
>  	.fill_modes = drm_helper_probe_single_connector_modes,
>  	.reset = drm_atomic_helper_connector_reset,
>  	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> @@ -155,6 +173,8 @@ int vkms_output_init(struct vkms_device *vkmsdev)
>  		connector = vkms_connector_init(vkmsdev, connector_cfg->possible_encoders);
>  		if (IS_ERR(connector))
>  			return PTR_ERR(connector);
> +
> +		connector_cfg->connector = connector;
>  	}
>  
>  	drm_mode_config_reset(dev);
> -- 
> 2.46.0
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 11/17] drm/vkms: Add and remove VKMS instances via configfs
  2024-08-13 10:44 ` [RFC PATCH 11/17] drm/vkms: Add and remove VKMS instances via configfs José Expósito
@ 2024-08-13 17:58   ` Louis Chauvet
  0 siblings, 0 replies; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:58 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel

Le 13/08/24 - 12:44, José Expósito a écrit :
> Allow to create, enable, disable and destroy VKMS instances using
> configfs.
> 
> For the moment, add one primary plane, one CRC, one encoder and one
> connector until we add support to configure them via configfs.
> 
> Signed-off-by: José Expósito <jose.exposito89@gmail.com>
> ---
>  Documentation/gpu/vkms.rst           |  32 +++++
>  drivers/gpu/drm/vkms/Kconfig         |   1 +
>  drivers/gpu/drm/vkms/Makefile        |   3 +-
>  drivers/gpu/drm/vkms/vkms_configfs.c | 198 +++++++++++++++++++++++++++
>  drivers/gpu/drm/vkms/vkms_configfs.h |   9 ++
>  drivers/gpu/drm/vkms/vkms_drv.c      |  19 ++-
>  drivers/gpu/drm/vkms/vkms_drv.h      |   4 +
>  7 files changed, 262 insertions(+), 4 deletions(-)
>  create mode 100644 drivers/gpu/drm/vkms/vkms_configfs.c
>  create mode 100644 drivers/gpu/drm/vkms/vkms_configfs.h
> 
> diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
> index ba04ac7c2167..9895a9ae76f4 100644
> --- a/Documentation/gpu/vkms.rst
> +++ b/Documentation/gpu/vkms.rst
> @@ -51,6 +51,38 @@ To disable the driver, use ::
>  
>    sudo modprobe -r vkms
>  
> +Configuring With Configfs
> +=========================
> +
> +It is possible to create and configure multiple VKMS instances via configfs.
> +
> +Start by mounting configfs and loading VKMS::
> +
> +  sudo mount -t configfs none /config
> +  sudo modprobe vkms
> +
> +Once VKMS is loaded, ``/config/vkms`` is created automatically. Each directory
> +under ``/config/vkms`` represents a VKMS instance, create a new one::
> +
> +  sudo mkdir /config/vkms/my-vkms
> +
> +By default, the instance is disabled::
> +
> +  cat /config/vkms/my-vkms/enabled
> +  0
> +
> +Once you are done configuring the VKMS instance, enable it::
> +
> +  echo "1" | sudo tee /config/vkms/my-vkms/enabled
> +
> +Finally, you can remove the VKMS instance disabling it::
> +
> +  echo "0" | sudo tee /config/vkms/my-vkms/enabled
> +
> +Or removing the top level directory::
> +
> +  sudo rmdir /config/vkms/my-vkms
> +

I will explain more in the next commit, but you must not be able to delete 
the device directory without disabling it first.

>  Testing With IGT
>  ================
>  
> diff --git a/drivers/gpu/drm/vkms/Kconfig b/drivers/gpu/drm/vkms/Kconfig
> index b9ecdebecb0b..de218b21a579 100644
> --- a/drivers/gpu/drm/vkms/Kconfig
> +++ b/drivers/gpu/drm/vkms/Kconfig
> @@ -6,6 +6,7 @@ config DRM_VKMS
>  	select DRM_KMS_HELPER
>  	select DRM_GEM_SHMEM_HELPER
>  	select CRC32
> +	select CONFIGFS_FS
>  	default n
>  	help
>  	  Virtual Kernel Mode-Setting (VKMS) is used for testing or for
> diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile
> index b371b5d70ee3..81c257d37689 100644
> --- a/drivers/gpu/drm/vkms/Makefile
> +++ b/drivers/gpu/drm/vkms/Makefile
> @@ -7,6 +7,7 @@ vkms-y := \
>  	vkms_crtc.o \
>  	vkms_composer.o \
>  	vkms_writeback.o \
> -	vkms_config.o
> +	vkms_config.o \
> +	vkms_configfs.o
>  
>  obj-$(CONFIG_DRM_VKMS) += vkms.o
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> new file mode 100644
> index 000000000000..3f25295f7788
> --- /dev/null
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
> @@ -0,0 +1,198 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +#include <linux/configfs.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +
> +#include "vkms_drv.h"
> +#include "vkms_config.h"
> +#include "vkms_configfs.h"
> +
> +/* To avoid registering configfs more than once or unregistering on error */
> +static bool is_configfs_registered;
> +
> +/**
> + * struct vkms_configfs - Configfs configuration for a VKMS device
> + *
> + * @vkms_config: Configuration of the VKMS device
> + * @device_group: Top level configuration group that represents a VKMS device.
> + * Initialized when a new directory is created under "/config/vkms/"
> + * @lock: Lock used to project concurrent access to the configuration attributes
> + * @enabled: Protected by @lock. The device is created or destroyed when this
> + * option changes
> + */
> +struct vkms_configfs {
> +	struct vkms_config *vkms_config;
> +	struct config_group device_group;
> +
> +	/* protected by @lock */
> +	struct mutex lock;
> +	bool enabled;
> +};
> +
> +#define config_item_to_vkms_configfs(item) \
> +	container_of(to_config_group(item), struct vkms_configfs, device_group)
> +
> +static ssize_t device_enabled_show(struct config_item *item, char *page)
> +{
> +	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
> +
> +	return sprintf(page, "%d\n", configfs->enabled);
> +}
> +
> +static ssize_t device_enabled_store(struct config_item *item, const char *page,
> +				    size_t count)
> +{
> +	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
> +	bool enabled;
> +	int ret = 0;
> +
> +	if (kstrtobool(page, &enabled))
> +		return -EINVAL;
> +
> +	mutex_lock(&configfs->lock);
> +
> +	if (!configfs->enabled && enabled)
> +		ret = vkms_create(configfs->vkms_config);
> +	else if (configfs->enabled && !enabled)
> +		vkms_destroy(configfs->vkms_config);
> +
> +	if (ret)
> +		goto err_unlock;
> +
> +	configfs->enabled = enabled;
> +
> +	mutex_unlock(&configfs->lock);
> +
> +	return (ssize_t)count;
> +
> +err_unlock:
> +	mutex_unlock(&configfs->lock);
> +	return ret;
> +}
> +
> +CONFIGFS_ATTR(device_, enabled);
> +
> +static struct configfs_attribute *device_group_attrs[] = {
> +	&device_attr_enabled,
> +	NULL,
> +};
> +
> +static const struct config_item_type device_group_type = {
> +	.ct_attrs = device_group_attrs,
> +	.ct_owner = THIS_MODULE,
> +};
> +
> +static struct config_group *make_device_group(struct config_group *group,
> +					      const char *name)
> +{
> +	struct vkms_configfs *configfs;
> +	struct vkms_config_crtc *crtc_cfg = NULL;
> +	struct vkms_config_encoder *encoder_cfg = NULL;
> +	struct vkms_config_connector *connector_cfg = NULL;
> +	char *config_name;
> +	int ret;
> +
> +	if (strcmp(name, DEFAULT_DEVICE_NAME) == 0)
> +		return ERR_PTR(-EINVAL);
> +
> +	configfs = kzalloc(sizeof(*configfs), GFP_KERNEL);
> +	if (!configfs)
> +		return ERR_PTR(-ENOMEM);
> +
> +	config_group_init_type_name(&configfs->device_group, name, &device_group_type);
> +	mutex_init(&configfs->lock);
> +
> +	config_name = config_item_name(&configfs->device_group.cg_item);
> +	configfs->vkms_config = vkms_config_create(config_name);

Here, config_name is managed by configfs, but you use it in a vkms_config 
structure. I don't think this is a good idea, I would prefer to avoid 
mixing lifetimes.

> +	if (IS_ERR(configfs->vkms_config)) {
> +		ret = PTR_ERR(configfs->vkms_config);
> +		goto err_kfree;
> +	}
> +
> +	crtc_cfg = vkms_config_add_crtc(configfs->vkms_config, false, false);
> +	if (IS_ERR(crtc_cfg)) {
> +		ret = PTR_ERR(crtc_cfg);
> +		goto err_kfree;
> +	}
> +
> +	encoder_cfg = vkms_config_add_encoder(configfs->vkms_config, BIT(0));
> +	if (IS_ERR(encoder_cfg)) {
> +		ret = PTR_ERR(encoder_cfg);
> +		goto err_kfree;
> +	}
> +
> +	connector_cfg = vkms_config_add_connector(configfs->vkms_config, BIT(0),
> +						  connector_status_connected);
> +	if (IS_ERR(connector_cfg)) {
> +		ret = PTR_ERR(connector_cfg);
> +		goto err_kfree;
> +	}
> +
> +	return &configfs->device_group;
> +
> +err_kfree:
> +	kfree(configfs);
> +	kfree(crtc_cfg);
> +	kfree(encoder_cfg);
> +	kfree(connector_cfg);

You are not freeing configfs->vkms_config. And it will automatically free 
*_cfg for you ;)

> +	return ERR_PTR(ret);
> +}
> +
> +static void drop_device_group(struct config_group *group,
> +			      struct config_item *item)
> +{
> +	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
> +
> +	mutex_lock(&configfs->lock);
> +
> +	if (configfs->enabled)
> +		vkms_destroy(configfs->vkms_config);
> +
> +	kfree(configfs->vkms_config);

You are not freeing stuff added with vkms_config_add_*

> +
> +	mutex_unlock(&configfs->lock);
> +
> +	kfree(configfs);
> +}

If I understood well the configfs documentation, the free of memory should 
not occur in drop, but in release.

Drop should only call configfs_group_put (default behavior) and configfs 
will manage the call to release for you. The same will apply for all the 
next commits.

> +static struct configfs_group_operations device_group_ops = {
> +	.make_group = &make_device_group,
> +	.drop_item = &drop_device_group,
> +};
> +
> +static struct config_item_type vkms_type = {
> +	.ct_group_ops = &device_group_ops,
> +	.ct_owner = THIS_MODULE,
> +};
> +
> +static struct configfs_subsystem vkms_subsys = {
> +	.su_group = {
> +		.cg_item = {
> +			.ci_name = "vkms",
> +			.ci_type = &vkms_type,
> +		},
> +	},
> +	.su_mutex = __MUTEX_INITIALIZER(vkms_subsys.su_mutex),
> +};
> +
> +int vkms_configfs_register(void)
> +{
> +	int ret;
> +
> +	if (is_configfs_registered)
> +		return 0;
> +
> +	config_group_init(&vkms_subsys.su_group);
> +	ret = configfs_register_subsystem(&vkms_subsys);
> +
> +	is_configfs_registered = ret == 0;
> +
> +	return ret;
> +}
> +
> +void vkms_configfs_unregister(void)
> +{
> +	if (is_configfs_registered)
> +		configfs_unregister_subsystem(&vkms_subsys);

I don't see any other users of configfs_unregister_subsystem protecting 
the call. Is it really needed to have is_configfs_registered?

> +}
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.h b/drivers/gpu/drm/vkms/vkms_configfs.h
> new file mode 100644
> index 000000000000..b5d7fab877d5
> --- /dev/null
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.h
> @@ -0,0 +1,9 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +#ifndef _VKMS_CONFIGFS_H_
> +#define _VKMS_CONFIGFS_H_
> +
> +int vkms_configfs_register(void);
> +void vkms_configfs_unregister(void);
> +
> +#endif /* _VKMS_CONFIGFS_H_ */
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_drv.c
> index b0a079eb4598..f524a9550017 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.c
> +++ b/drivers/gpu/drm/vkms/vkms_drv.c
> @@ -27,6 +27,7 @@
>  #include <drm/drm_vblank.h>
>  
>  #include "vkms_config.h"
> +#include "vkms_configfs.h"
>  #include "vkms_drv.h"
>  
>  #define DRIVER_NAME	"vkms"
> @@ -157,7 +158,7 @@ static int vkms_modeset_init(struct vkms_device *vkmsdev)
>  	return vkms_output_init(vkmsdev);
>  }
>  
> -static int vkms_create(struct vkms_config *config)
> +int vkms_create(struct vkms_config *config)
>  {
>  	int ret;
>  	struct platform_device *pdev;
> @@ -231,12 +232,22 @@ static int __init vkms_init(void)
>  
>  	ret = vkms_create(config);
>  	if (ret)
> -		vkms_config_destroy(config);
> +		goto err_kfree;
>  
> +	ret = vkms_configfs_register();
> +	if (ret)
> +		goto err_destroy;
> +
> +	return 0;
> +
> +err_destroy:
> +	vkms_destroy(config);
> +err_kfree:
> +	vkms_config_destroy(config);
>  	return ret;
>  }
>  
> -static void vkms_destroy(struct vkms_config *config)
> +void vkms_destroy(struct vkms_config *config)
>  {
>  	struct platform_device *pdev;
>  
> @@ -257,6 +268,8 @@ static void vkms_destroy(struct vkms_config *config)
>  
>  static void __exit vkms_exit(void)
>  {
> +	vkms_configfs_unregister();
> +
>  	if (default_config->dev)
>  		vkms_destroy(default_config);
>  
> diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h
> index 76394285dc68..eb32440e9f94 100644
> --- a/drivers/gpu/drm/vkms/vkms_drv.h
> +++ b/drivers/gpu/drm/vkms/vkms_drv.h
> @@ -143,6 +143,10 @@ struct vkms_device {
>  #define to_vkms_plane_state(target)\
>  	container_of(target, struct vkms_plane_state, base.base)
>  
> +/* VKMS device */
> +int vkms_create(struct vkms_config *config);
> +void vkms_destroy(struct vkms_config *config);
>
>  /* CRTC */
>  struct vkms_crtc *vkms_crtc_init(struct drm_device *dev,
>  				 struct drm_plane *primary,
> -- 
> 2.46.0
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 12/17] drm/vkms: Allow to configure multiple CRTCs via configfs
  2024-08-13 10:44 ` [RFC PATCH 12/17] drm/vkms: Allow to configure multiple CRTCs " José Expósito
@ 2024-08-13 17:58   ` Louis Chauvet
  0 siblings, 0 replies; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:58 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel

Le 13/08/24 - 12:44, José Expósito a écrit :
> Create a default subgroup at /config/vkms/crtcs to allow to create as
> many CRTCs as required. When a CRTC is created, allow to configure the
> equivalent of the module parameters enable_cursor and enable_writeback.

I think this commit is not bissectable, you have issue with:

	mkdir /config/vkms/my-vkms
	mkdir /config/vkms/my-vkms/crtcs/1
	rmdir /config/vkms/my-vkms/crtcs/1
	mkdir /config/vkms/my-vkms/crtcs/1
	echo 1 > /config/vkms/my-vkms/enabled
	# Not a crash, but drm is complaining
	
and also when creating many crtcs:

	mkdir /config/vkms/my-vkms
	mkdir /config/vkms/my-vkms/crtcs/{1..32}
	mkdir /config/vkms/my-vkms/crtcs/33 # Should be forbidden (I also 
					forgot to manage this case)
	echo 1 > /config/vkms/my-vkms/enabled
	# DRM is complaining

or

	mkdir /config/vkms/my-vkms
	mkdir /config/vkms/my-vkms/crtcs/{1..32}
	rmdir /config/vkms/my-vkms/crtcs/31 # not 32 because the index 
						will works "by chance"
	mkdir /config/vkms/my-vkms/crtcs/31
	echo 1 > /config/vkms/my-vkms/enabled
       	# DRM is complaining

> Signed-off-by: José Expósito <jose.exposito89@gmail.com>
> ---
>  Documentation/gpu/vkms.rst           |  22 +++-
>  drivers/gpu/drm/vkms/vkms_config.h   |   3 +
>  drivers/gpu/drm/vkms/vkms_configfs.c | 149 +++++++++++++++++++++++++--
>  3 files changed, 166 insertions(+), 8 deletions(-)
> 
> diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
> index 9895a9ae76f4..0886349ad4a0 100644
> --- a/Documentation/gpu/vkms.rst
> +++ b/Documentation/gpu/vkms.rst
> @@ -71,6 +71,25 @@ By default, the instance is disabled::
>    cat /config/vkms/my-vkms/enabled
>    0
>  
> +And directories are created for each configurable item of the display pipeline::
> +
> +  tree /config/vkms/my-vkms
> +    /config/vkms/my-vkms
> +    ├── crtcs
> +    └── enabled
> +
> +To add items to the display pipeline, create one or more directories under the
> +available paths.
> +
> +Start by creating one or more CRTCs::
> +
> +  sudo mkdir /config/vkms/my-vkms/crtcs/crtc0
> +
> +CRTCs have 2 configurable attributes:
> +
> +- cursor: Enable or disable cursor plane support
> +- writeback: Enable or disable writeback connector support
> +
>  Once you are done configuring the VKMS instance, enable it::
>  
>    echo "1" | sudo tee /config/vkms/my-vkms/enabled
> @@ -79,8 +98,9 @@ Finally, you can remove the VKMS instance disabling it::
>  
>    echo "0" | sudo tee /config/vkms/my-vkms/enabled
>  
> -Or removing the top level directory::
> +Or removing the top level directory and its subdirectories::
>  
> +  sudo rmdir /config/vkms/my-vkms/crtcs/*
>    sudo rmdir /config/vkms/my-vkms

Here, I really don't like this way to delete a device, because you may 
lost objects later.

For example, if we take a connector, we want the let the userspace 
connecting and disconnecting it, so something like

	echo 1 > /config/vkms/my-vkms/connectors/my_conn/connected
	echo 0 > /config/vkms/my-vkms/connectors/my_conn/connected
  
But in the same time, we allows the userspace to delete directory, so you 
may "loose" your connector

	echo 1 > /config/vkms/my-vkms/connectors/my_conn/connected
	rmdir /config/vkms/my-vkms/connectors/my_conn/
	# no way to disconnect it now! you must completly delete the 
	# device and create a new one

So I think we should totally forbid the deletion of anything if 
the device is enabled. So to delete one device, you have to:

	echo 0 > /config/vkms/my-vkms/enabled
	rmdir /config/vkms/my_vkms/{everything}

>  Testing With IGT
> diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
> index 3237406fa3a3..f96a0456a3d7 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/configfs.h>
>  #include <linux/list.h>
>  #include <linux/types.h>
>  
> @@ -20,6 +21,8 @@ struct vkms_config_crtc {
>  	unsigned int index;
>  	bool cursor;
>  	bool writeback;
> +	/* only used if created from configfs */
> +	struct config_group crtc_group;

I don't really like the idea of mixing configfs structure and vkms 
configuration. Both can have different lifetime and are created in 
different places.

You already created a vkms_configfs_device structure, why not for a 
vkms_configfs_crtc?

>  };
>  
>  struct vkms_config_encoder {
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index 3f25295f7788..04278a39cd3c 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
> @@ -17,6 +17,8 @@ static bool is_configfs_registered;
>   * @vkms_config: Configuration of the VKMS device
>   * @device_group: Top level configuration group that represents a VKMS device.
>   * Initialized when a new directory is created under "/config/vkms/"
> + * @crtcs_group: Default subgroup of @device_group at "/config/vkms/crtcs".
> + * Each of its items represent a CRTC
>   * @lock: Lock used to project concurrent access to the configuration attributes
>   * @enabled: Protected by @lock. The device is created or destroyed when this
>   * option changes
> @@ -24,6 +26,7 @@ static bool is_configfs_registered;
>  struct vkms_configfs {
>  	struct vkms_config *vkms_config;
>  	struct config_group device_group;
> +	struct config_group crtcs_group;
>  
>  	/* protected by @lock */
>  	struct mutex lock;
> @@ -33,6 +36,141 @@ struct vkms_configfs {
>  #define config_item_to_vkms_configfs(item) \
>  	container_of(to_config_group(item), struct vkms_configfs, device_group)
>  
> +#define crtcs_group_to_vkms_configfs(group) \
> +	container_of(group, struct vkms_configfs, crtcs_group)
> +
> +#define crtcs_item_to_vkms_configfs(item) \
> +	container_of(to_config_group(item), struct vkms_configfs, crtcs_group)
> +
> +#define crtcs_item_to_vkms_config_crtc(item) \
> +	container_of(to_config_group(item), struct vkms_config_crtc, crtc_group)
> +
> +static ssize_t crtc_cursor_show(struct config_item *item, char *page)
> +{
> +	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
> +
> +	return sprintf(page, "%d\n", crtc_cfg->cursor);
> +}
> +
> +static ssize_t crtc_cursor_store(struct config_item *item, const char *page,
> +				 size_t count)
> +{
> +	struct vkms_configfs *configfs = crtcs_item_to_vkms_configfs(item->ci_parent);
> +	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
> +	bool cursor;
> +
> +	if (kstrtobool(page, &cursor))
> +		return -EINVAL;
> +
> +	mutex_lock(&configfs->lock);
> +
> +	if (configfs->enabled) {
> +		mutex_unlock(&configfs->lock);
> +		return -EINVAL;
> +	}
> +
> +	crtc_cfg->cursor = cursor;
> +
> +	mutex_unlock(&configfs->lock);
> +
> +	return (ssize_t)count;

Same comment as for vkms_config, why cursor is hardcoded here? It should 
be as configurable as other planes (size, color formats...).

> +
> +static ssize_t crtc_writeback_show(struct config_item *item, char *page)
> +{
> +	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
> +
> +	return sprintf(page, "%d\n", crtc_cfg->writeback);
> +}
>
> +static ssize_t crtc_writeback_store(struct config_item *item, const char *page,
> +				    size_t count)
> +{
> +	struct vkms_configfs *configfs = crtcs_item_to_vkms_configfs(item->ci_parent);
> +	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
> +	bool writeback;
> +
> +	if (kstrtobool(page, &writeback))
> +		return -EINVAL;
> +
> +	mutex_lock(&configfs->lock);
> +
> +	if (configfs->enabled) {
> +		mutex_unlock(&configfs->lock);
> +		return -EINVAL;
> +	}
> +
> +	crtc_cfg->writeback = writeback;
> +
> +	mutex_unlock(&configfs->lock);
> +
> +	return (ssize_t)count;
> +}
> +
> +CONFIGFS_ATTR(crtc_, cursor);
> +CONFIGFS_ATTR(crtc_, writeback);
> +
> +static struct configfs_attribute *crtc_group_attrs[] = {
> +	&crtc_attr_cursor,
> +	&crtc_attr_writeback,
> +	NULL,
> +};
> +
> +static const struct config_item_type crtc_group_type = {
> +	.ct_attrs = crtc_group_attrs,
> +	.ct_owner = THIS_MODULE,
> +};
> +
> +static struct config_group *make_crtcs_group(struct config_group *group,
> +					     const char *name)
> +{
> +	struct vkms_configfs *configfs = crtcs_group_to_vkms_configfs(group);
> +	struct vkms_config_crtc *crtc_cfg;
> +	int ret;
> +
> +	mutex_lock(&configfs->lock);
> +
> +	if (configfs->enabled) {
> +		ret = -EINVAL;
> +		goto err_unlock;
> +	}
> +
> +	crtc_cfg = vkms_config_add_crtc(configfs->vkms_config, false, false);
> +	if (IS_ERR(crtc_cfg)) {
> +		ret = PTR_ERR(crtc_cfg);
> +		goto err_unlock;
> +	}
> +
> +	config_group_init_type_name(&crtc_cfg->crtc_group, name, &crtc_group_type);
> +
> +	mutex_unlock(&configfs->lock);
> +
> +	return &crtc_cfg->crtc_group;
> +
> +err_unlock:
> +	mutex_unlock(&configfs->lock);
> +	return ERR_PTR(ret);
> +}
> +
> +static void drop_crtcs_group(struct config_group *group,
> +			     struct config_item *item)
> +{
> +	struct vkms_configfs *configfs = crtcs_group_to_vkms_configfs(group);
> +	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
> +
> +	vkms_config_destroy_crtc(configfs->vkms_config, crtc_cfg);
> +}

Again, free should be in release, not in drop.

And by the way, here you will have the problem I described before: the 
vkms_config_destroy_crtc does not update possible_crtcs fields, so they 
became complelty invalids.

And you also have the issue of invalid index, you can create 32 crtcs, 
delete 32 and recreate 32, the userspace expect it to works (only 32 
crtcs, wich is the maximum allowed by drm), but the index used in 
vkms_config are 32..64, which are invalid.

> +
> +static struct configfs_group_operations crtcs_group_ops = {
> +	.make_group = &make_crtcs_group,
> +	.drop_item = &drop_crtcs_group,
> +};
> +
> +static struct config_item_type crtcs_group_type = {
> +	.ct_group_ops = &crtcs_group_ops,
> +	.ct_owner = THIS_MODULE,
> +};
> +
>  static ssize_t device_enabled_show(struct config_item *item, char *page)
>  {
>  	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
> @@ -87,7 +225,6 @@ static struct config_group *make_device_group(struct config_group *group,
>  					      const char *name)
>  {
>  	struct vkms_configfs *configfs;
> -	struct vkms_config_crtc *crtc_cfg = NULL;
>  	struct vkms_config_encoder *encoder_cfg = NULL;
>  	struct vkms_config_connector *connector_cfg = NULL;
>  	char *config_name;
> @@ -110,11 +247,10 @@ static struct config_group *make_device_group(struct config_group *group,
>  		goto err_kfree;
>  	}
>  
> -	crtc_cfg = vkms_config_add_crtc(configfs->vkms_config, false, false);
> -	if (IS_ERR(crtc_cfg)) {
> -		ret = PTR_ERR(crtc_cfg);
> -		goto err_kfree;
> -	}
> +	config_group_init_type_name(&configfs->crtcs_group, "crtcs",
> +				    &crtcs_group_type);
> +	configfs_add_default_group(&configfs->crtcs_group,
> +				   &configfs->device_group);
>
>  	encoder_cfg = vkms_config_add_encoder(configfs->vkms_config, BIT(0));
>  	if (IS_ERR(encoder_cfg)) {
> @@ -133,7 +269,6 @@ static struct config_group *make_device_group(struct config_group *group,
>  
>  err_kfree:
>  	kfree(configfs);
> -	kfree(crtc_cfg);
>  	kfree(encoder_cfg);
>  	kfree(connector_cfg);
>  	return ERR_PTR(ret);
> -- 
> 2.46.0
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 13/17] drm/vkms: Allow to configure multiple encoders via configfs
  2024-08-13 10:44 ` [RFC PATCH 13/17] drm/vkms: Allow to configure multiple encoders " José Expósito
@ 2024-08-13 17:58   ` Louis Chauvet
  0 siblings, 0 replies; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:58 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel

Le 13/08/24 - 12:44, José Expósito a écrit :
> Create a default subgroup at /config/vkms/encoders to allow to create as
> many encoders as required. When the encoder is created the
> possible_crtcs subgroup is created allowing to link encoders and CRTCs.

I did not test, but the issue about index for crtc are maybe the same for 
encoders.
 
> Signed-off-by: José Expósito <jose.exposito89@gmail.com>
> ---
>  Documentation/gpu/vkms.rst           |  14 ++-
>  drivers/gpu/drm/vkms/vkms_config.h   |   3 +
>  drivers/gpu/drm/vkms/vkms_configfs.c | 127 +++++++++++++++++++++++++--
>  3 files changed, 136 insertions(+), 8 deletions(-)
> 
> diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
> index 0886349ad4a0..c69be063d3b4 100644
> --- a/Documentation/gpu/vkms.rst
> +++ b/Documentation/gpu/vkms.rst
> @@ -76,7 +76,8 @@ And directories are created for each configurable item of the display pipeline::
>    tree /config/vkms/my-vkms
>      /config/vkms/my-vkms
>      ├── crtcs
> -    └── enabled
> +    ├── enabled
> +    └── encoders
>  
>  To add items to the display pipeline, create one or more directories under the
>  available paths.
> @@ -90,6 +91,15 @@ CRTCs have 2 configurable attributes:
>  - cursor: Enable or disable cursor plane support
>  - writeback: Enable or disable writeback connector support
>  
> +Continue by creating one or more encoders::
> +
> +  sudo mkdir /config/vkms/my-vkms/encoders/encoder0
> +
> +Encoders can be linked to CRTCs by creating a symbolic link under
> +``possible_crtcs``::
> +
> +  sudo ln -s /config/vkms/my-vkms/crtcs/crtc0 /config/vkms/my-vkms/encoders/encoder0/possible_crtcs
> +
>  Once you are done configuring the VKMS instance, enable it::
>  
>    echo "1" | sudo tee /config/vkms/my-vkms/enabled
> @@ -100,6 +110,8 @@ Finally, you can remove the VKMS instance disabling it::
>  
>  Or removing the top level directory and its subdirectories::
>  
> +  sudo rm /config/vkms/my-vkms/encoders/*/possible_crtcs/*
> +  sudo rmdir /config/vkms/my-vkms/encoders/*
>    sudo rmdir /config/vkms/my-vkms/crtcs/*
>    sudo rmdir /config/vkms/my-vkms

Same comment as previously, I think we should forbid this way to delete an 
instance.

> diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
> index f96a0456a3d7..f9423533a7f3 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.h
> +++ b/drivers/gpu/drm/vkms/vkms_config.h
> @@ -29,6 +29,9 @@ struct vkms_config_encoder {
>  	struct list_head list;
>  	unsigned int index;
>  	uint32_t possible_crtcs;
> +	/* only used if created from configfs */
> +	struct config_group encoder_group;
> +	struct config_group possible_crtcs_group;

Again, I don't like mixing configfs and vkms_config. Can we keep both 
stuff splitted?

>  };
>  
>  struct vkms_config_connector {
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index 04278a39cd3c..c0b62fb93dc0 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
> @@ -19,6 +19,8 @@ static bool is_configfs_registered;
>   * Initialized when a new directory is created under "/config/vkms/"
>   * @crtcs_group: Default subgroup of @device_group at "/config/vkms/crtcs".
>   * Each of its items represent a CRTC
> + * @encoders_group: Default subgroup of @device_group at
> + * "/config/vkms/encoders". Each of its items represent a encoder
>   * @lock: Lock used to project concurrent access to the configuration attributes
>   * @enabled: Protected by @lock. The device is created or destroyed when this
>   * option changes
> @@ -27,6 +29,7 @@ struct vkms_configfs {
>  	struct vkms_config *vkms_config;
>  	struct config_group device_group;
>  	struct config_group crtcs_group;
> +	struct config_group encoders_group;
>  
>  	/* protected by @lock */
>  	struct mutex lock;
> @@ -45,6 +48,15 @@ struct vkms_configfs {
>  #define crtcs_item_to_vkms_config_crtc(item) \
>  	container_of(to_config_group(item), struct vkms_config_crtc, crtc_group)
>  
> +#define encoders_group_to_vkms_configfs(group) \
> +	container_of(group, struct vkms_configfs, encoders_group)
> +
> +#define encoders_item_to_vkms_config_encoder(item) \
> +	container_of(to_config_group(item), struct vkms_config_encoder, encoder_group)
> +
> +#define encoder_possible_crtcs_item_to_vkms_config_encoder(item) \
> +	container_of(to_config_group(item), struct vkms_config_encoder, possible_crtcs_group)
> +
>  static ssize_t crtc_cursor_show(struct config_item *item, char *page)
>  {
>  	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
> @@ -171,6 +183,110 @@ static struct config_item_type crtcs_group_type = {
>  	.ct_owner = THIS_MODULE,
>  };
>  
> +static int encoder_possible_crtcs_allow_link(struct config_item *src,
> +					     struct config_item *target)
> +{
> +	struct vkms_config_encoder *encoder_cfg;
> +	struct vkms_config_crtc *crtc_cfg;
> +
> +	if (target->ci_type != &crtc_group_type)
> +		return -EINVAL;

I also need to check on my implementation, be we also need to check if the 
target is in the correct device, not only the correct type :)

> +
> +	encoder_cfg = encoder_possible_crtcs_item_to_vkms_config_encoder(src);
> +	crtc_cfg = crtcs_item_to_vkms_config_crtc(target);
> +
> +	if (encoder_cfg->possible_crtcs & BIT(crtc_cfg->index))
> +		return -EINVAL;
> +
> +	encoder_cfg->possible_crtcs |= BIT(crtc_cfg->index);
> +
> +	return 0;
> +}
> +
> +static void encoder_possible_crtcs_drop_link(struct config_item *src,
> +					     struct config_item *target)
> +{
> +	struct vkms_config_encoder *encoder_cfg;
> +	struct vkms_config_crtc *crtc_cfg;
> +
> +	encoder_cfg = encoder_possible_crtcs_item_to_vkms_config_encoder(src);
> +	crtc_cfg = crtcs_item_to_vkms_config_crtc(target);
> +
> +	encoder_cfg->possible_crtcs &= ~BIT(crtc_cfg->index);
> +}
> +
> +static struct configfs_item_operations encoder_possible_crtcs_item_ops = {
> +	.allow_link = &encoder_possible_crtcs_allow_link,
> +	.drop_link = &encoder_possible_crtcs_drop_link,
> +};
> +
> +static struct config_item_type encoder_possible_crtcs_group_type = {
> +	.ct_item_ops = &encoder_possible_crtcs_item_ops,
> +	.ct_owner = THIS_MODULE,
> +};
> +
> +static const struct config_item_type encoder_group_type = {
> +	.ct_owner = THIS_MODULE,
> +};
> +
> +static struct config_group *make_encoders_group(struct config_group *group,
> +						const char *name)
> +{
> +	struct vkms_configfs *configfs = encoders_group_to_vkms_configfs(group);
> +	struct vkms_config_encoder *encoder_cfg;
> +	int ret;
> +
> +	mutex_lock(&configfs->lock);
> +
> +	if (configfs->enabled) {
> +		ret = -EINVAL;
> +		goto err_unlock;
> +	}
> +
> +	encoder_cfg = vkms_config_add_encoder(configfs->vkms_config, 0);
> +	if (IS_ERR(encoder_cfg)) {
> +		ret = PTR_ERR(encoder_cfg);
> +		goto err_unlock;
> +	}
> +
> +	config_group_init_type_name(&encoder_cfg->encoder_group, name,
> +				    &encoder_group_type);
> +
> +	config_group_init_type_name(&encoder_cfg->possible_crtcs_group,
> +				    "possible_crtcs",
> +				    &encoder_possible_crtcs_group_type);
> +	configfs_add_default_group(&encoder_cfg->possible_crtcs_group,
> +				   &encoder_cfg->encoder_group);
> +
> +	mutex_unlock(&configfs->lock);
> +
> +	return &encoder_cfg->encoder_group;
> +
> +err_unlock:
> +	mutex_unlock(&configfs->lock);
> +	return ERR_PTR(ret);
> +}
> +
> +static void drop_encoders_group(struct config_group *group,
> +				struct config_item *item)
> +{
> +	struct vkms_configfs *configfs = encoders_group_to_vkms_configfs(group);
> +	struct vkms_config_encoder *encoder_cfg =
> +		encoders_item_to_vkms_config_encoder(item);
> +
> +	vkms_config_destroy_encoder(configfs->vkms_config, encoder_cfg);
> +}

Same, I think there should not be any free in drop.

> +
> +static struct configfs_group_operations encoders_group_ops = {
> +	.make_group = &make_encoders_group,
> +	.drop_item = &drop_encoders_group,
> +};
> +
> +static struct config_item_type encoders_group_type = {
> +	.ct_group_ops = &encoders_group_ops,
> +	.ct_owner = THIS_MODULE,
> +};
> +
>  static ssize_t device_enabled_show(struct config_item *item, char *page)
>  {
>  	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
> @@ -225,7 +341,6 @@ static struct config_group *make_device_group(struct config_group *group,
>  					      const char *name)
>  {
>  	struct vkms_configfs *configfs;
> -	struct vkms_config_encoder *encoder_cfg = NULL;
>  	struct vkms_config_connector *connector_cfg = NULL;
>  	char *config_name;
>  	int ret;
> @@ -252,11 +367,10 @@ static struct config_group *make_device_group(struct config_group *group,
>  	configfs_add_default_group(&configfs->crtcs_group,
>  				   &configfs->device_group);
>  
> -	encoder_cfg = vkms_config_add_encoder(configfs->vkms_config, BIT(0));
> -	if (IS_ERR(encoder_cfg)) {
> -		ret = PTR_ERR(encoder_cfg);
> -		goto err_kfree;
> -	}
> +	config_group_init_type_name(&configfs->encoders_group, "encoders",
> +				    &encoders_group_type);
> +	configfs_add_default_group(&configfs->encoders_group,
> +				   &configfs->device_group);
>  
>  	connector_cfg = vkms_config_add_connector(configfs->vkms_config, BIT(0),
>  						  connector_status_connected);
> @@ -269,7 +383,6 @@ static struct config_group *make_device_group(struct config_group *group,
>  
>  err_kfree:
>  	kfree(configfs);
> -	kfree(encoder_cfg);
>  	kfree(connector_cfg);
>  	return ERR_PTR(ret);
>  }
> -- 
> 2.46.0
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 15/17] drm/vkms: Allow to configure multiple planes via configfs
  2024-08-13 10:44 ` [RFC PATCH 15/17] drm/vkms: Allow to configure multiple planes via configfs José Expósito
@ 2024-08-13 17:59   ` Louis Chauvet
  0 siblings, 0 replies; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:59 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel

Le 13/08/24 - 12:44, José Expósito a écrit :
> Create a default subgroup at /config/vkms/planes to allow to create as
> many overlay planes as required. When the plane is created the
> possible_crtcs subgroup is created allowing to link planes and CRTCs.

I think my comment about updating possible_crtc and indexes is very 
important here as the userspace can create and delete crtcs. I don't have 
the time to test today, but there is probably issues again with crtc 
creation/deletion.

> Signed-off-by: José Expósito <jose.exposito89@gmail.com>
> ---
>  Documentation/gpu/vkms.rst           |  13 ++-
>  drivers/gpu/drm/vkms/vkms_config.h   |   3 +
>  drivers/gpu/drm/vkms/vkms_configfs.c | 121 +++++++++++++++++++++++++++
>  3 files changed, 136 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
> index b6ceb8c48310..ee71d1a569dd 100644
> --- a/Documentation/gpu/vkms.rst
> +++ b/Documentation/gpu/vkms.rst
> @@ -78,7 +78,8 @@ And directories are created for each configurable item of the display pipeline::
>      ├── connectors
>      ├── crtcs
>      ├── enabled
> -    └── encoders
> +    ├── encoders
> +    └── planes
>  
>  To add items to the display pipeline, create one or more directories under the
>  available paths.
> @@ -111,6 +112,14 @@ linked to encoders by creating a symbolic link under ``possible_encoders``::
>  
>    sudo ln -s /config/vkms/my-vkms/encoders/encoder0 /config/vkms/my-vkms/connectors/connector0/possible_encoders
>  
> +Finally, create zero or more overlay planes::
> +
> +  sudo mkdir /config/vkms/my-vkms/planes/plane0
> +
> +And link them with their ``possible_crtcs``::
> +
> +  sudo ln -s /config/vkms/my-vkms/crtcs/crtc0 /config/vkms/my-vkms/planes/plane0/possible_crtcs
> +
>  Once you are done configuring the VKMS instance, enable it::
>  
>    echo "1" | sudo tee /config/vkms/my-vkms/enabled
> @@ -128,6 +137,8 @@ Or removing the top level directory and its subdirectories::
>    sudo rmdir /config/vkms/my-vkms/connectors/*
>    sudo rm /config/vkms/my-vkms/encoders/*/possible_crtcs/*
>    sudo rmdir /config/vkms/my-vkms/encoders/*
> +  sudo rm /config/vkms/my-vkms/planes/*/possible_crtcs/*
> +  sudo rmdir /config/vkms/my-vkms/planes/*
>    sudo rmdir /config/vkms/my-vkms/crtcs/*
>    sudo rmdir /config/vkms/my-vkms
>  
> diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
> index cf45e3f6ae92..2ec08bb58ec4 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.h
> +++ b/drivers/gpu/drm/vkms/vkms_config.h
> @@ -14,6 +14,9 @@ struct vkms_device;
>  struct vkms_config_plane {
>  	struct list_head list;
>  	uint32_t possible_crtcs;
> +	/* only used if created from configfs */
> +	struct config_group plane_group;
> +	struct config_group possible_crtcs_group;
>  };
>  
>  struct vkms_config_crtc {
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index d2369f53e2d8..0b5ac0767da0 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
> @@ -23,6 +23,8 @@ static bool is_configfs_registered;
>   * "/config/vkms/encoders". Each of its items represent a encoder
>   * @connectors_group: Default subgroup of @device_group at
>   * "/config/vkms/connectors". Each of its items represent a connector
> + * @planes_group: Default subgroup of @device_group at "/config/vkms/planes".
> + * Each of its items represent an overlay plane
>   * @lock: Lock used to project concurrent access to the configuration attributes
>   * @enabled: Protected by @lock. The device is created or destroyed when this
>   * option changes
> @@ -33,6 +35,7 @@ struct vkms_configfs {
>  	struct config_group crtcs_group;
>  	struct config_group encoders_group;
>  	struct config_group connectors_group;
> +	struct config_group planes_group;
>  
>  	/* protected by @lock */
>  	struct mutex lock;
> @@ -72,6 +75,15 @@ struct vkms_configfs {
>  #define connector_possible_encoders_item_to_vkms_config_connector(item) \
>  	container_of(to_config_group(item), struct vkms_config_connector, possible_encoders_group)
>  
> +#define planes_group_to_vkms_configfs(group) \
> +	container_of(group, struct vkms_configfs, planes_group)
> +
> +#define planes_item_to_vkms_config_plane(item) \
> +	container_of(to_config_group(item), struct vkms_config_plane, plane_group)
> +
> +#define plane_possible_crtcs_item_to_vkms_config_plane(item) \
> +	container_of(to_config_group(item), struct vkms_config_plane, possible_crtcs_group)
> +
>  static ssize_t crtc_cursor_show(struct config_item *item, char *page)
>  {
>  	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
> @@ -450,6 +462,110 @@ static struct config_item_type connectors_group_type = {
>  	.ct_owner = THIS_MODULE,
>  };
>  
> +static int plane_possible_crtcs_allow_link(struct config_item *src,
> +					   struct config_item *target)
> +{
> +	struct vkms_config_plane *plane_cfg;
> +	struct vkms_config_crtc *crtc_cfg;
> +
> +	if (target->ci_type != &crtc_group_type)
> +		return -EINVAL;
> +
> +	plane_cfg = plane_possible_crtcs_item_to_vkms_config_plane(src);
> +	crtc_cfg = crtcs_item_to_vkms_config_crtc(target);
> +
> +	if (plane_cfg->possible_crtcs & BIT(crtc_cfg->index))
> +		return -EINVAL;
> +
> +	plane_cfg->possible_crtcs |= BIT(crtc_cfg->index);
> +
> +	return 0;
> +}
> +
> +static void plane_possible_crtcs_drop_link(struct config_item *src,
> +					   struct config_item *target)
> +{
> +	struct vkms_config_plane *plane_cfg;
> +	struct vkms_config_crtc *crtc_cfg;
> +
> +	plane_cfg = plane_possible_crtcs_item_to_vkms_config_plane(src);
> +	crtc_cfg = crtcs_item_to_vkms_config_crtc(target);
> +
> +	plane_cfg->possible_crtcs &= ~BIT(crtc_cfg->index);
> +}
> +
> +static struct configfs_item_operations plane_possible_crtcs_item_ops = {
> +	.allow_link = &plane_possible_crtcs_allow_link,
> +	.drop_link = &plane_possible_crtcs_drop_link,
> +};
> +
> +static struct config_item_type plane_possible_crtcs_group_type = {
> +	.ct_item_ops = &plane_possible_crtcs_item_ops,
> +	.ct_owner = THIS_MODULE,
> +};
> +
> +static const struct config_item_type plane_group_type = {
> +	.ct_owner = THIS_MODULE,
> +};
> +
> +static struct config_group *make_planes_group(struct config_group *group,
> +					      const char *name)
> +{
> +	struct vkms_configfs *configfs = planes_group_to_vkms_configfs(group);
> +	struct vkms_config_plane *plane_cfg;
> +	int ret;
> +
> +	mutex_lock(&configfs->lock);
> +
> +	if (configfs->enabled) {
> +		ret = -EINVAL;
> +		goto err_unlock;
> +	}
> +
> +	plane_cfg = vkms_config_add_overlay_plane(configfs->vkms_config, 0);
> +	if (IS_ERR(plane_cfg)) {
> +		ret = PTR_ERR(plane_cfg);
> +		goto err_unlock;
> +	}
> +
> +	config_group_init_type_name(&plane_cfg->plane_group, name,
> +				    &plane_group_type);
> +
> +	config_group_init_type_name(&plane_cfg->possible_crtcs_group,
> +				    "possible_crtcs",
> +				    &plane_possible_crtcs_group_type);
> +	configfs_add_default_group(&plane_cfg->possible_crtcs_group,
> +				   &plane_cfg->plane_group);
> +
> +	mutex_unlock(&configfs->lock);
> +
> +	return &plane_cfg->plane_group;
> +
> +err_unlock:
> +	mutex_unlock(&configfs->lock);
> +	return ERR_PTR(ret);
> +}

If I understand properly your code, there is no way to configure primary 
and cursor planes? If we want to introduce it later, I think we will break 
the uAPI, so it will be difficult.

> +
> +static void drop_planes_group(struct config_group *group,
> +			      struct config_item *item)
> +{
> +	struct vkms_configfs *configfs = planes_group_to_vkms_configfs(group);
> +	struct vkms_config_plane *plane_cfg =
> +		planes_item_to_vkms_config_plane(item);
> +
> +	vkms_config_destroy_overlay_plane(configfs->vkms_config, plane_cfg);
> +}
> +
> +static struct configfs_group_operations planes_group_ops = {
> +	.make_group = &make_planes_group,
> +	.drop_item = &drop_planes_group,
> +};
> +
> +static struct config_item_type planes_group_type = {
> +	.ct_group_ops = &planes_group_ops,
> +	.ct_owner = THIS_MODULE,
> +};
> +
>  static ssize_t device_enabled_show(struct config_item *item, char *page)
>  {
>  	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
> @@ -538,6 +654,11 @@ static struct config_group *make_device_group(struct config_group *group,
>  	configfs_add_default_group(&configfs->connectors_group,
>  				   &configfs->device_group);
>  
> +	config_group_init_type_name(&configfs->planes_group, "planes",
> +				    &planes_group_type);
> +	configfs_add_default_group(&configfs->planes_group,
> +				   &configfs->device_group);
> +
>  	return &configfs->device_group;
>  }
>  
> -- 
> 2.46.0
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 14/17] drm/vkms: Allow to configure multiple encoders
  2024-08-13 10:44 ` [RFC PATCH 14/17] drm/vkms: Allow to configure multiple encoders José Expósito
@ 2024-08-13 17:59   ` Louis Chauvet
  0 siblings, 0 replies; 35+ messages in thread
From: Louis Chauvet @ 2024-08-13 17:59 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel

Le 13/08/24 - 12:44, José Expósito a écrit :
> Add a list of encoder configurations to vkms_config and add as many
> encoders as configured during output initialization.

Small mistake, this commit is about connector with configfs :)

> 
> For backwards compatibility, create a single encoder in the default
> configuration.
> 
> Signed-off-by: José Expósito <jose.exposito89@gmail.com>
> ---
>  Documentation/gpu/vkms.rst           |  16 +++
>  drivers/gpu/drm/vkms/vkms_config.h   |   3 +
>  drivers/gpu/drm/vkms/vkms_configfs.c | 184 ++++++++++++++++++++++++---
>  3 files changed, 188 insertions(+), 15 deletions(-)
> 
> diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst
> index c69be063d3b4..b6ceb8c48310 100644
> --- a/Documentation/gpu/vkms.rst
> +++ b/Documentation/gpu/vkms.rst
> @@ -75,6 +75,7 @@ And directories are created for each configurable item of the display pipeline::
>  
>    tree /config/vkms/my-vkms
>      /config/vkms/my-vkms
> +    ├── connectors
>      ├── crtcs
>      ├── enabled
>      └── encoders
> @@ -100,16 +101,31 @@ Encoders can be linked to CRTCs by creating a symbolic link under
>  
>    sudo ln -s /config/vkms/my-vkms/crtcs/crtc0 /config/vkms/my-vkms/encoders/encoder0/possible_crtcs
>  
> +Next, create one or more connectors::
> +
> +  sudo mkdir /config/vkms/my-vkms/connectors/connector0
> +
> +The status of the connector can be changed writing ``1`` (connected), ``2``
> +(disconnected) or ``3`` (unknown) to the ``status`` attribute and they can be
> +linked to encoders by creating a symbolic link under ``possible_encoders``::
> +
> +  sudo ln -s /config/vkms/my-vkms/encoders/encoder0 /config/vkms/my-vkms/connectors/connector0/possible_encoders
> +
>  Once you are done configuring the VKMS instance, enable it::
>  
>    echo "1" | sudo tee /config/vkms/my-vkms/enabled
>  
> +Note that the connector ``status`` can be changed once the VKMS instance is
> +enabled to emulate hot-plug/unplug.
> +
>  Finally, you can remove the VKMS instance disabling it::
>  
>    echo "0" | sudo tee /config/vkms/my-vkms/enabled
>  
>  Or removing the top level directory and its subdirectories::
>  
> +  sudo rm /config/vkms/my-vkms/connectors/*/possible_encoders/*
> +  sudo rmdir /config/vkms/my-vkms/connectors/*
>    sudo rm /config/vkms/my-vkms/encoders/*/possible_crtcs/*
>    sudo rmdir /config/vkms/my-vkms/encoders/*
>    sudo rmdir /config/vkms/my-vkms/crtcs/*
> diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h
> index f9423533a7f3..cf45e3f6ae92 100644
> --- a/drivers/gpu/drm/vkms/vkms_config.h
> +++ b/drivers/gpu/drm/vkms/vkms_config.h
> @@ -40,6 +40,9 @@ struct vkms_config_connector {
>  	enum drm_connector_status status;
>  	/* only set when instantiated */
>  	struct drm_connector *connector;
> +	/* only used if created from configfs */
> +	struct config_group connector_group;
> +	struct config_group possible_encoders_group;
>  };
>  
>  struct vkms_config {
> diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c
> index c0b62fb93dc0..d2369f53e2d8 100644
> --- a/drivers/gpu/drm/vkms/vkms_configfs.c
> +++ b/drivers/gpu/drm/vkms/vkms_configfs.c
> @@ -21,6 +21,8 @@ static bool is_configfs_registered;
>   * Each of its items represent a CRTC
>   * @encoders_group: Default subgroup of @device_group at
>   * "/config/vkms/encoders". Each of its items represent a encoder
> + * @connectors_group: Default subgroup of @device_group at
> + * "/config/vkms/connectors". Each of its items represent a connector
>   * @lock: Lock used to project concurrent access to the configuration attributes
>   * @enabled: Protected by @lock. The device is created or destroyed when this
>   * option changes
> @@ -30,6 +32,7 @@ struct vkms_configfs {
>  	struct config_group device_group;
>  	struct config_group crtcs_group;
>  	struct config_group encoders_group;
> +	struct config_group connectors_group;
>  
>  	/* protected by @lock */
>  	struct mutex lock;
> @@ -57,6 +60,18 @@ struct vkms_configfs {
>  #define encoder_possible_crtcs_item_to_vkms_config_encoder(item) \
>  	container_of(to_config_group(item), struct vkms_config_encoder, possible_crtcs_group)
>  
> +#define connectors_group_to_vkms_configfs(group) \
> +	container_of(group, struct vkms_configfs, connectors_group)
> +
> +#define connectors_item_to_vkms_configfs(item) \
> +	container_of(to_config_group(item), struct vkms_configfs, connectors_group)
> +
> +#define connector_item_to_vkms_config_connector(item) \
> +	container_of(to_config_group(item), struct vkms_config_connector, connector_group)
> +
> +#define connector_possible_encoders_item_to_vkms_config_connector(item) \
> +	container_of(to_config_group(item), struct vkms_config_connector, possible_encoders_group)
> +
>  static ssize_t crtc_cursor_show(struct config_item *item, char *page)
>  {
>  	struct vkms_config_crtc *crtc_cfg = crtcs_item_to_vkms_config_crtc(item);
> @@ -287,6 +302,154 @@ static struct config_item_type encoders_group_type = {
>  	.ct_owner = THIS_MODULE,
>  };
>  
> +static int connector_possible_encoders_allow_link(struct config_item *src,
> +						  struct config_item *target)
> +{
> +	struct vkms_config_connector *connector_cfg;
> +	struct vkms_config_encoder *encoder_cfg;

I think I forgit it before, but once the device is enabled, no 
configuration should be possible (except connector status).

> +	if (target->ci_type != &encoder_group_type)
> +		return -EINVAL;
> +

Same as before, the type and the device must be checked.

> +	connector_cfg = connector_possible_encoders_item_to_vkms_config_connector(src);
> +	encoder_cfg = encoders_item_to_vkms_config_encoder(target);
> +
> +	if (connector_cfg->possible_encoders & BIT(encoder_cfg->index))
> +		return -EINVAL;
> +
> +	connector_cfg->possible_encoders |= BIT(encoder_cfg->index);
> +
> +	return 0;
> +}
> +
> +static void connector_possible_encoders_drop_link(struct config_item *src,
> +						  struct config_item *target)
> +{
> +	struct vkms_config_connector *connector_cfg;
> +	struct vkms_config_encoder *encoder_cfg;
> +
> +	connector_cfg = connector_possible_encoders_item_to_vkms_config_connector(src);
> +	encoder_cfg = encoders_item_to_vkms_config_encoder(target);
> +
> +	connector_cfg->possible_encoders &= ~BIT(encoder_cfg->index);
> +}
> +
> +static struct configfs_item_operations connector_possible_encoders_item_ops = {
> +	.allow_link = &connector_possible_encoders_allow_link,
> +	.drop_link = &connector_possible_encoders_drop_link,
> +};
> +
> +static struct config_item_type connector_possible_encoders_group_type = {
> +	.ct_item_ops = &connector_possible_encoders_item_ops,
> +	.ct_owner = THIS_MODULE,
> +};
> +
> +static ssize_t connector_status_show(struct config_item *item, char *page)
> +{
> +	struct vkms_config_connector *connector_cfg =
> +		connector_item_to_vkms_config_connector(item);
> +
> +	return sprintf(page, "%d\n", connector_cfg->status);
> +}
> +
> +static ssize_t connector_status_store(struct config_item *item, const char *page,
> +				      size_t count)
> +{
> +	struct vkms_configfs *configfs;
> +	struct vkms_config_connector *connector_cfg;
> +	int status;
> +
> +	if (kstrtoint(page, 10, &status))
> +		return -EINVAL;
> +
> +	switch (status) {
> +	case connector_status_connected:
> +	case connector_status_disconnected:
> +	case connector_status_unknown:
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	configfs = connectors_item_to_vkms_configfs(item->ci_parent);
> +	connector_cfg = connector_item_to_vkms_config_connector(item);
> +
> +	vkms_update_connector_status(configfs->vkms_config, connector_cfg, status);
> +
> +	return (ssize_t)count;
> +}
> +
> +CONFIGFS_ATTR(connector_, status);
> +
> +static struct configfs_attribute *connector_group_attrs[] = {
> +	&connector_attr_status,
> +	NULL,
> +};
> +
> +static const struct config_item_type connector_group_type = {
> +	.ct_attrs = connector_group_attrs,
> +	.ct_owner = THIS_MODULE,
> +};
> +
> +static struct config_group *make_connectors_group(struct config_group *group,
> +						  const char *name)
> +{
> +	struct vkms_configfs *configfs = connectors_group_to_vkms_configfs(group);
> +	struct vkms_config_connector *connector_cfg;
> +	int ret;
> +
> +	mutex_lock(&configfs->lock);
> +
> +	if (configfs->enabled) {
> +		ret = -EINVAL;
> +		goto err_unlock;
> +	}
> +
> +	connector_cfg = vkms_config_add_connector(configfs->vkms_config, 0,
> +						  connector_status_connected);
> +	if (IS_ERR(connector_cfg)) {
> +		ret = PTR_ERR(connector_cfg);
> +		goto err_unlock;
> +	}
> +
> +	config_group_init_type_name(&connector_cfg->connector_group, name,
> +				    &connector_group_type);
> +
> +	config_group_init_type_name(&connector_cfg->possible_encoders_group,
> +				    "possible_encoders",
> +				    &connector_possible_encoders_group_type);
> +	configfs_add_default_group(&connector_cfg->possible_encoders_group,
> +				   &connector_cfg->connector_group);
> +
> +	mutex_unlock(&configfs->lock);
> +
> +	return &connector_cfg->connector_group;
> +
> +err_unlock:
> +	mutex_unlock(&configfs->lock);
> +	return ERR_PTR(ret);
> +}
> +
> +static void drop_connectors_group(struct config_group *group,
> +				  struct config_item *item)
> +{
> +	struct vkms_configfs *configfs = connectors_group_to_vkms_configfs(group);
> +	struct vkms_config_connector *connector_cfg =
> +		connector_item_to_vkms_config_connector(item);
> +
> +	vkms_config_destroy_connector(configfs->vkms_config, connector_cfg);
> +}

Again, I think drop should not free memory.

> +
> +static struct configfs_group_operations connectors_group_ops = {
> +	.make_group = &make_connectors_group,
> +	.drop_item = &drop_connectors_group,
> +};
> +
> +static struct config_item_type connectors_group_type = {
> +	.ct_group_ops = &connectors_group_ops,
> +	.ct_owner = THIS_MODULE,
> +};
> +
>  static ssize_t device_enabled_show(struct config_item *item, char *page)
>  {
>  	struct vkms_configfs *configfs = config_item_to_vkms_configfs(item);
> @@ -341,9 +504,7 @@ static struct config_group *make_device_group(struct config_group *group,
>  					      const char *name)
>  {
>  	struct vkms_configfs *configfs;
> -	struct vkms_config_connector *connector_cfg = NULL;
>  	char *config_name;
> -	int ret;
>  
>  	if (strcmp(name, DEFAULT_DEVICE_NAME) == 0)
>  		return ERR_PTR(-EINVAL);
> @@ -358,8 +519,8 @@ static struct config_group *make_device_group(struct config_group *group,
>  	config_name = config_item_name(&configfs->device_group.cg_item);
>  	configfs->vkms_config = vkms_config_create(config_name);
>  	if (IS_ERR(configfs->vkms_config)) {
> -		ret = PTR_ERR(configfs->vkms_config);
> -		goto err_kfree;
> +		kfree(configfs);
> +		return ERR_CAST(configfs->vkms_config);
>  	}
>  
>  	config_group_init_type_name(&configfs->crtcs_group, "crtcs",
> @@ -372,19 +533,12 @@ static struct config_group *make_device_group(struct config_group *group,
>  	configfs_add_default_group(&configfs->encoders_group,
>  				   &configfs->device_group);
>  
> -	connector_cfg = vkms_config_add_connector(configfs->vkms_config, BIT(0),
> -						  connector_status_connected);
> -	if (IS_ERR(connector_cfg)) {
> -		ret = PTR_ERR(connector_cfg);
> -		goto err_kfree;
> -	}
> +	config_group_init_type_name(&configfs->connectors_group, "connectors",
> +				    &connectors_group_type);
> +	configfs_add_default_group(&configfs->connectors_group,
> +				   &configfs->device_group);
>  
>  	return &configfs->device_group;
> -
> -err_kfree:
> -	kfree(configfs);
> -	kfree(connector_cfg);
> -	return ERR_PTR(ret);
>  }
>  
>  static void drop_device_group(struct config_group *group,
> -- 
> 2.46.0
> 

-- 
Louis Chauvet, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 00/17] VKMS: Add configfs support
  2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
                   ` (17 preceding siblings ...)
  2024-08-13 17:58 ` [RFC PATCH 00/17] VKMS: Add configfs support Louis Chauvet
@ 2024-08-14  9:10 ` Daniel Stone
  2024-08-20 16:03   ` José Expósito
  18 siblings, 1 reply; 35+ messages in thread
From: Daniel Stone @ 2024-08-14  9:10 UTC (permalink / raw)
  To: José Expósito
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel, louis.chauvet

Hi José,

On Tue, 13 Aug 2024 at 11:51, José Expósito <jose.exposito89@gmail.com> wrote:
>  - When a CRTC is added and removed before device creation, there
>    is a vblank warning.
>    The issue is caused because vblanks are referenced using the
>    CRTC index but, because one of the CRTCs is removed, the
>    indices are not consecutives and drm_crtc_vblank_crtc() tries to
>    access and invalid index
>    I'm not sure if CRTC's indices *must* start at 0 and be
>    consecutives or if this is a bug in the drm_crtc_vblank_crtc()
>    implementation.

CRTCs and planes are not hotpluggable. I recommend you just create a
lot of each of them statically at startup, and hotplug only
connectors.

Cheers,
Daniel

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 00/17] VKMS: Add configfs support
  2024-08-13 17:58 ` [RFC PATCH 00/17] VKMS: Add configfs support Louis Chauvet
@ 2024-08-20 15:52   ` José Expósito
  0 siblings, 0 replies; 35+ messages in thread
From: José Expósito @ 2024-08-20 15:52 UTC (permalink / raw)
  To: Louis Chauvet
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel, thomas

Hi Louis,

Thanks a lot for the review and for your comments!

On Tue, Aug 13, 2024 at 07:58:55PM +0200, Louis Chauvet wrote:
> Le 13/08/24 - 12:44, José Expósito a écrit :
> > Hi everyone,
> 
> Hi José,
>  
> > This RFC implements support to configure VKMS using configfs.
> > It allows to:
> > 
> >  - Create multiple devices
> >  - Configure multiple overlay planes, CRTCs, encoders and
> >    connectors
> >  - Enable or disable cursor plane and writeback connector for
> >    each CRTC
> >  - Hot-plug/unplug connectors after device creation
> >  - Disable the creation of the default VKMS instance to be
> >    able to use only the configfs ones
> > 
> > This work is based on a previous attempt to implement configfs
> > support by Jim Shargo and Brandon Pollack [1].
> > I tried to keep the changes as minimal and simple as possible
> > and addressed Sima's comments on [1].
> > 
> > Currently, there is another RFC by Louis Chauvet [2]. As I
> > mentioned on his RFC, I'm not trying to push my implementation.
> > Instead, I think that having 2 implementations will make code
> > review way easier and I don't mind which implementation is used
> > as long as we get the feature implemented :)
> 
> I will send few series tomorrow, don't panic, there will be 9 series and a 
> total of ~50 commits (I have many conflict to rebase only the configFS 
> part, and even if it was easy, I plan to submit all of my work, not 
> everything will be RFC).

Nice work! I already reviewed "drm/vkms: Miscelanious clarifications",
"drm/vkms: Completly split headers" and "drm/vkms: Switch all vkms
object to DRM managed objects".

I'll have a look to the vkms_config and configfs as soon as possible,
but I think they'll have to wait until next week.

> > I'm looking forward to analyzing Louis's implementation, seeing
> > what the differences are and finding a common solution.
> 
> There are four main differences:
> - I complelty splitted vkms_config and vkms_configfs structures

I considered this and I didn't do it because it duplicates a lot of
fields, but your implementation does the right think. I need to
split both structures.

> - I splitted my work in many different series

Which is really nice, I think that the 3 series I reviewed can be
easily rebased on drm-misc-next and get merged. I'd be able to drop
at least 4 patches if your code is merged.

> - I created a real platform device driver
> - I did not manage index by hand, I let drm core doing it
> - I used list to link crtc/planes/encoders and not bitfield (because of 
>   the previous point)

I need to look about your solution for the indices. It is the root
cause for the problems I'm having with vblanks not being referenced
by the correct index.

> - The primary and cursor planes are fully configurable

I think this is the right approach. However, there are some restrictions
on primary planes and a user will be able to create some invalid setups.
The DRM subsystem complains if you create a CRTC without a primary plane,
but I'm not sure if we want to do the validation in VKMS as well.

There are other restrictions handled by DRM (for example, only 32 encoders
and CRTCs are allowed) and I don't know if re-implement all validation
rules in VKMS is the best idea.

> The first two points are personnal preferences, so I am open to 
> discussion.
> 
> The third point was already discussed before, I don't know if it is a good 
> solution or not. I think it should be easy to remove it.
> 
> But for the index managment, I really think that for our usage 
> in ConfigFS, bitfields are not a good solution and as shown in this 
> series, very error-prone. If you have a better solution than what I did, 
> let me know, I am not very happy with mine too.
> 
> The last point is also important, we don't want to break uAPI once this 
> series is merged, so having "default hidden planes" that can't be 
> configured is annoying as we will have to manage them with a special case.
> 
> > What's missing?
> > 
> >  - DebugFS only works for the default VKMS instance.
> >    If we want to support it on instances created with configfs
> >    I'll need to implement it.
> 
> Same on my side, I forgot to reimplement this :-). It will not be in my 
> RFC, but on the v1 for sure!
> 
> > Known bugs:
> > 
> >  - When a CRTC is added and removed before device creation, there
> >    is a vblank warning.
> >    The issue is caused because vblanks are referenced using the
> >    CRTC index but, because one of the CRTCs is removed, the
> >    indices are not consecutives and drm_crtc_vblank_crtc() tries to
> >    access and invalid index
> >    I'm not sure if CRTC's indices *must* start at 0 and be
> >    consecutives or if this is a bug in the drm_crtc_vblank_crtc()
> >    implementation.
> 
> Very nice work, but you hurted many issue I had too, and I attempted to 
> solve them as nicely as I can. Overall there is one main issues for me:
> the crtc index managment is not correct and the configfs behavior is very 
> easily broken because of this.
> 
> This is an issue for two reason I think:
> - We are trying to implement a new index allocation mecanism, but it is 
>   not very difficult to let drm manage this part on device creation, so 
>   maybe just dont store indexes in config
> - The usage of a simple index++ is not suitable for configFS usecase, 
>   crating 32 crtcs and deleting 1 should be possible:
> 	mkdir {1..32};rmdir 1;mkdir 1
>   but the index of 1 is now 33, which is forbidden by drm, so you have to 
>   do a "complex" algorithim "find_first_value_not_used_bellow_32".
> 
> Thanks for all your work! You were right, while reviewing your work, I 
> found issues in mine :-)
> 
> Have a nice day,
> Louis Chauvet

I ran out of time this week to work on VKMS, but I'll try to solve the
issues you pointed out.

Thanks again for your review,
Jose

> > 
> > Best wishes,
> > José Expósito
> > 
> > [1] https://patchwork.kernel.org/project/dri-devel/list/?series=780110&archive=both
> > [2] https://lore.kernel.org/dri-devel/ZrZZFQW5RiG12ApN@louis-chauvet-laptop/T/#u
> > 
> > José Expósito (17):
> >   drm/vkms: Extract vkms_config header
> >   drm/vkms: Move default_config creation to its own function
> >   drm/vkms: Set device name from vkms_config
> >   drm/vkms: Allow to configure multiple CRTCs
> >   drm/vkms: Use managed memory to create encoders
> >   drm/vkms: Allow to configure multiple encoders
> >   drm/vkms: Use managed memory to create connectors
> >   drm/vkms: Allow to configure multiple connectors
> >   drm/vkms: Allow to configure multiple overlay planes
> >   drm/vkms: Allow to change connector status
> >   drm/vkms: Add and remove VKMS instances via configfs
> >   drm/vkms: Allow to configure multiple CRTCs via configfs
> >   drm/vkms: Allow to configure multiple encoders via configfs
> >   drm/vkms: Allow to configure multiple encoders
> >   drm/vkms: Allow to configure multiple planes via configfs
> >   drm/vkms: Allow to configure the default device creation
> >   drm/vkms: Remove completed task from the TODO list
> > 
> >  Documentation/gpu/vkms.rst            | 102 +++-
> >  drivers/gpu/drm/vkms/Kconfig          |   1 +
> >  drivers/gpu/drm/vkms/Makefile         |   4 +-
> >  drivers/gpu/drm/vkms/vkms_composer.c  |  30 +-
> >  drivers/gpu/drm/vkms/vkms_config.c    | 265 ++++++++++
> >  drivers/gpu/drm/vkms/vkms_config.h    | 101 ++++
> >  drivers/gpu/drm/vkms/vkms_configfs.c  | 721 ++++++++++++++++++++++++++
> >  drivers/gpu/drm/vkms/vkms_configfs.h  |   9 +
> >  drivers/gpu/drm/vkms/vkms_crtc.c      |  99 ++--
> >  drivers/gpu/drm/vkms/vkms_drv.c       |  75 ++-
> >  drivers/gpu/drm/vkms/vkms_drv.h       |  52 +-
> >  drivers/gpu/drm/vkms/vkms_output.c    | 187 ++++---
> >  drivers/gpu/drm/vkms/vkms_plane.c     |   6 +-
> >  drivers/gpu/drm/vkms/vkms_writeback.c |  27 +-
> >  14 files changed, 1464 insertions(+), 215 deletions(-)
> >  create mode 100644 drivers/gpu/drm/vkms/vkms_config.c
> >  create mode 100644 drivers/gpu/drm/vkms/vkms_config.h
> >  create mode 100644 drivers/gpu/drm/vkms/vkms_configfs.c
> >  create mode 100644 drivers/gpu/drm/vkms/vkms_configfs.h
> > 
> > -- 
> > 2.46.0
> > 
> 
> -- 
> Louis Chauvet, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC PATCH 00/17] VKMS: Add configfs support
  2024-08-14  9:10 ` Daniel Stone
@ 2024-08-20 16:03   ` José Expósito
  0 siblings, 0 replies; 35+ messages in thread
From: José Expósito @ 2024-08-20 16:03 UTC (permalink / raw)
  To: Daniel Stone
  Cc: rodrigosiqueiramelo, melissa.srw, mairacanal, hamohammed.sa,
	daniel, maarten.lankhorst, mripard, tzimmermann, airlied,
	dri-devel, linux-kernel, louis.chauvet

Hi Daniel,

Thanks a lot for looking into this.
On Wed, Aug 14, 2024 at 10:10:39AM +0100, Daniel Stone wrote:
> Hi José,
> 
> On Tue, 13 Aug 2024 at 11:51, José Expósito <jose.exposito89@gmail.com> wrote:
> >  - When a CRTC is added and removed before device creation, there
> >    is a vblank warning.
> >    The issue is caused because vblanks are referenced using the
> >    CRTC index but, because one of the CRTCs is removed, the
> >    indices are not consecutives and drm_crtc_vblank_crtc() tries to
> >    access and invalid index
> >    I'm not sure if CRTC's indices *must* start at 0 and be
> >    consecutives or if this is a bug in the drm_crtc_vblank_crtc()
> >    implementation.
> 
> CRTCs and planes are not hotpluggable. I recommend you just create a
> lot of each of them statically at startup, and hotplug only
> connectors.

Yes, it is an issue creating them before the device is active. Once the VKMS
device is active, it is not possible to delete them.

Because of how the CRTC index is handled, it is possible create 3 CRTCs
(indices 0, 1 and 2), delete the second one and end up with 2 CRTCs: The
first one with index 0 and the second one with index 2.

This is handled nicelly in the possible_crtcs bitmask, but drm_crtc_vblank_crtc()
tries to access index 2 of an array of size 2.

This case is not possible with actual HW, so I need to fix it on the VKMS
side and make indices start at 0 and be consecutive.
A check on the drm_crtc_vblank_crtc() side won't hurt us though.

For extra context, see Louis message on the topic. It looks like
we are having similar issues:
https://lore.kernel.org/dri-devel/ZsS7x2y_HKgqGUFR@fedora/T/#mccf9a9748ae67a07a7e6ad694c42afc2ccd3c7f1

Best wishes,
Jose
 
> Cheers,
> Daniel

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2024-08-20 16:03 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-13 10:44 [RFC PATCH 00/17] VKMS: Add configfs support José Expósito
2024-08-13 10:44 ` [RFC PATCH 01/17] drm/vkms: Extract vkms_config header José Expósito
2024-08-13 10:44 ` [RFC PATCH 02/17] drm/vkms: Move default_config creation to its own function José Expósito
2024-08-13 10:44 ` [RFC PATCH 03/17] drm/vkms: Set device name from vkms_config José Expósito
2024-08-13 17:58   ` Louis Chauvet
2024-08-13 10:44 ` [RFC PATCH 04/17] drm/vkms: Allow to configure multiple CRTCs José Expósito
2024-08-13 17:58   ` Louis Chauvet
2024-08-13 10:44 ` [RFC PATCH 05/17] drm/vkms: Use managed memory to create encoders José Expósito
2024-08-13 17:58   ` Louis Chauvet
2024-08-13 10:44 ` [RFC PATCH 06/17] drm/vkms: Allow to configure multiple encoders José Expósito
2024-08-13 17:58   ` Louis Chauvet
2024-08-13 10:44 ` [RFC PATCH 07/17] drm/vkms: Use managed memory to create connectors José Expósito
2024-08-13 17:58   ` Louis Chauvet
2024-08-13 10:44 ` [RFC PATCH 08/17] drm/vkms: Allow to configure multiple connectors José Expósito
2024-08-13 17:58   ` Louis Chauvet
2024-08-13 10:44 ` [RFC PATCH 09/17] drm/vkms: Allow to configure multiple overlay planes José Expósito
2024-08-13 17:58   ` Louis Chauvet
2024-08-13 10:44 ` [RFC PATCH 10/17] drm/vkms: Allow to change connector status José Expósito
2024-08-13 17:58   ` Louis Chauvet
2024-08-13 10:44 ` [RFC PATCH 11/17] drm/vkms: Add and remove VKMS instances via configfs José Expósito
2024-08-13 17:58   ` Louis Chauvet
2024-08-13 10:44 ` [RFC PATCH 12/17] drm/vkms: Allow to configure multiple CRTCs " José Expósito
2024-08-13 17:58   ` Louis Chauvet
2024-08-13 10:44 ` [RFC PATCH 13/17] drm/vkms: Allow to configure multiple encoders " José Expósito
2024-08-13 17:58   ` Louis Chauvet
2024-08-13 10:44 ` [RFC PATCH 14/17] drm/vkms: Allow to configure multiple encoders José Expósito
2024-08-13 17:59   ` Louis Chauvet
2024-08-13 10:44 ` [RFC PATCH 15/17] drm/vkms: Allow to configure multiple planes via configfs José Expósito
2024-08-13 17:59   ` Louis Chauvet
2024-08-13 10:44 ` [RFC PATCH 16/17] drm/vkms: Allow to configure the default device creation José Expósito
2024-08-13 10:44 ` [RFC PATCH 17/17] drm/vkms: Remove completed task from the TODO list José Expósito
2024-08-13 17:58 ` [RFC PATCH 00/17] VKMS: Add configfs support Louis Chauvet
2024-08-20 15:52   ` José Expósito
2024-08-14  9:10 ` Daniel Stone
2024-08-20 16:03   ` José Expósito

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox