@@ -51,6 +51,29 @@ To disable the driver, use ::
sudo modprobe -r vkms
+Configuration With ConfigFS
+===========================
+
+VKMS is instrumented with support for configuration via `ConfigFS`. With VKMS
+installed, you can mount ConfigFS at /config/ like so::
+
+ mkdir -p /config/
+ sudo mount -t configfs none /config
+
+This will create a directory tree that looks something like this::
+
+ - /config/vkms/
+ - connectors/ -- a list of all the planes available in the VKMS driver
+ - N/ -- the connector with ID=N
+ - crtc/ -- a list of all the crtcs available in the VKMS driver
+ - N/ -- the crtc with ID=N
+ - encoders/ -- a list of all the encoders available in the VKMS driver
+ - N/ -- the encoder with ID=N
+ - planes/ -- a list of all the planes available in the VKMS driver
+ - N/ -- the plane with ID=N.
+
+Settings for each object will appear in the ``/config/vkms/<type>/<N>/`` directory.
+
Testing With IGT
================
@@ -307,6 +307,7 @@ config DRM_VKMS
depends on DRM && MMU
select DRM_KMS_HELPER
select DRM_GEM_SHMEM_HELPER
+ select CONFIGFS_FS
select CRC32
default n
help
@@ -3,6 +3,7 @@ vkms-y := \
vkms_drv.o \
vkms_plane.o \
vkms_output.o \
+ vkms_configfs.o \
vkms_crtc.o \
vkms_composer.o \
vkms_writeback.o
new file mode 100644
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/configfs.h>
+#include <linux/export.h>
+#include <linux/mutex.h>
+
+#include "vkms_drv.h"
+
+static void setup_configfs_object(uint32_t id, struct config_group *object,
+ struct config_group *parent,
+ struct config_item_type *type)
+{
+ char name[CONFIGFS_ITEM_NAME_LEN];
+
+ snprintf(name, CONFIGFS_ITEM_NAME_LEN, "%d", id);
+ config_group_init_type_name(object, name, type);
+ configfs_add_default_group(object, parent);
+}
+
+/* connector item, e.g. /config/vkms/connectors/ID */
+
+static struct config_item_type connector_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+/* crtc item, e.g. /config/vkms/crtc/ID */
+
+static struct config_item_type crtc_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+/* encoder item, e.g. /config/vkms/encoder/ID */
+
+static struct config_item_type encoder_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+void vkms_init_output_configfs(struct vkms_device *vkmsdev,
+ struct vkms_output *output)
+{
+ setup_configfs_object(output->connector.base.id,
+ &output->connector_config_group,
+ &vkmsdev->configfs.connectors_group,
+ &connector_type);
+
+ setup_configfs_object(output->crtc.base.id, &output->crtc_config_group,
+ &vkmsdev->configfs.crtcs_group, &crtc_type);
+
+ setup_configfs_object(output->encoder.base.id,
+ &output->encoder_config_group,
+ &vkmsdev->configfs.encoders_group, &encoder_type);
+}
+
+/* Plane item, e.g. /config/vkms/planes/ID */
+
+static struct config_item_type plane_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+void vkms_init_plane_configfs(struct vkms_device *vkmsdev,
+ struct vkms_plane *plane)
+{
+ setup_configfs_object(plane->base.base.id, &plane->config_group,
+ &vkmsdev->configfs.planes_group, &plane_type);
+}
+
+/* Directory groups, e.g. /config/vkms/planes */
+
+static struct config_item_type connectors_group_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type crtcs_group_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type encoders_group_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type planes_group_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+/* Root directory group, e.g. /config/vkms/ */
+
+static struct config_item_type vkms_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+static struct configfs_subsystem vkms_subsys = {
+ .su_group = {
+ .cg_item = {
+ .ci_name = "vkms",
+ .ci_type = &vkms_type,
+ },
+ },
+};
+
+void vkms_init_configfs(struct vkms_device *vkmsdev)
+{
+ config_group_init(&vkms_subsys.su_group);
+ mutex_init(&vkms_subsys.su_mutex);
+
+ config_group_init_type_name(&vkmsdev->configfs.connectors_group,
+ "connectors", &connectors_group_type);
+ configfs_add_default_group(&vkmsdev->configfs.connectors_group,
+ &vkms_subsys.su_group);
+
+ config_group_init_type_name(&vkmsdev->configfs.crtcs_group, "crtcs",
+ &crtcs_group_type);
+ configfs_add_default_group(&vkmsdev->configfs.crtcs_group,
+ &vkms_subsys.su_group);
+
+ config_group_init_type_name(&vkmsdev->configfs.encoders_group,
+ "encoders", &encoders_group_type);
+ configfs_add_default_group(&vkmsdev->configfs.encoders_group,
+ &vkms_subsys.su_group);
+
+ config_group_init_type_name(&vkmsdev->configfs.planes_group, "planes",
+ &planes_group_type);
+ configfs_add_default_group(&vkmsdev->configfs.planes_group,
+ &vkms_subsys.su_group);
+}
+
+int vkms_register_configfs(void)
+{
+ return configfs_register_subsystem(&vkms_subsys);
+}
@@ -9,6 +9,7 @@
* the GPU in DRM API tests.
*/
+#include <linux/configfs.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
@@ -191,6 +192,8 @@ static int vkms_create(struct vkms_config *config)
goto out_devres;
}
+ vkms_init_configfs(vkms_device);
+
ret = drm_vblank_init(&vkms_device->drm, 1);
if (ret) {
DRM_ERROR("Failed to vblank\n");
@@ -207,8 +210,15 @@ static int vkms_create(struct vkms_config *config)
drm_fbdev_generic_setup(&vkms_device->drm, 0);
+ ret = vkms_register_configfs();
+ if (ret)
+ goto out_drmres;
+
+
return 0;
+out_drmres:
+ drm_dev_unregister(&vkms_device->drm);
out_devres:
devres_release_group(&pdev->dev, NULL);
out_unregister:
@@ -3,6 +3,7 @@
#ifndef _VKMS_DRV_H_
#define _VKMS_DRV_H_
+#include <linux/configfs.h>
#include <linux/hrtimer.h>
#include <drm/drm.h>
@@ -48,6 +49,7 @@ struct vkms_plane_state {
struct vkms_plane {
struct drm_plane base;
+ struct config_group config_group;
};
/**
@@ -86,6 +88,10 @@ struct vkms_output {
/* protects concurrent access to composer */
spinlock_t lock;
+ struct config_group crtc_config_group;
+ struct config_group encoder_config_group;
+ struct config_group connector_config_group;
+
/* protected by @lock */
bool composer_enabled;
struct vkms_crtc_state *composer_state;
@@ -103,10 +109,22 @@ struct vkms_config {
struct vkms_device *dev;
};
+struct vkms_configfs {
+ /* Directory group containing connector configs, e.g. /config/vkms/connectors/ */
+ struct config_group connectors_group;
+ /* Directory group containing CRTC configs, e.g. /config/vkms/crtcs/ */
+ struct config_group crtcs_group;
+ /* Directory group containing encoder configs, e.g. /config/vkms/encoders/ */
+ struct config_group encoders_group;
+ /* Directory group containing plane configs, e.g. /config/vkms/planes/ */
+ struct config_group planes_group;
+};
+
struct vkms_device {
struct drm_device drm;
struct platform_device *platform;
struct vkms_output output;
+ struct vkms_configfs configfs;
const struct vkms_config *config;
};
@@ -145,4 +163,11 @@ void vkms_set_composer(struct vkms_output *out, bool enabled);
/* Writeback */
int vkms_enable_writeback_connector(struct vkms_device *vkmsdev);
+/* ConfigFS Support */
+void vkms_init_configfs(struct vkms_device *vkmsdev);
+int vkms_register_configfs(void);
+
+void vkms_init_plane_configfs(struct vkms_device *vkmsdev, struct vkms_plane *plane);
+void vkms_init_output_configfs(struct vkms_device *vkmsdev, struct vkms_output *output);
+
#endif /* _VKMS_DRV_H_ */
@@ -111,6 +111,8 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index)
drm_mode_config_reset(dev);
+ vkms_init_output_configfs(vkmsdev, output);
+
return 0;
err_attach:
@@ -195,5 +195,7 @@ struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev,
drm_plane_helper_add(&plane->base, funcs);
+ vkms_init_plane_configfs(vkmsdev, plane);
+
return plane;
}