To allows the userspace to test many hardware configuration, introduce a new interface to create and configure connectors. The connectors are created by creating a directory in the `connectors` directory. Connectors and encoders can be linked by creating a symlink in the possible_encoders directory. The current interface is: /config/vkms DEVICE_1 ┣━ enable ┣━ planes ┃ ┗━ [...] ┣━ connectors ┃ ┗━ CONNECTOR_1 ┃ ┗━ possible_encoders ┃ ┗━ >> DEVICE_1/encoders/ENCODER_1 ┗━ encoders ┗━ ENCODER_1 Signed-off-by: Louis Chauvet <louis.chauvet@xxxxxxxxxxx> --- drivers/gpu/drm/vkms/vkms_config.c | 13 ++++ drivers/gpu/drm/vkms/vkms_config.h | 3 + drivers/gpu/drm/vkms/vkms_configfs.c | 138 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/vkms/vkms_configfs.h | 23 ++++++ 4 files changed, 177 insertions(+) diff --git a/drivers/gpu/drm/vkms/vkms_config.c b/drivers/gpu/drm/vkms/vkms_config.c index 8ac9cd52cc00f7c317f2514a73c3d2f3908b085b..cb97bf292b72e9faf0050338fe845a254f691987 100644 --- a/drivers/gpu/drm/vkms/vkms_config.c +++ b/drivers/gpu/drm/vkms/vkms_config.c @@ -479,6 +479,19 @@ vkms_config_connector_attach_encoder(struct vkms_config_connector *vkms_config_c return ret; } +void vkms_config_connector_detach_encoder(struct vkms_config_connector *vkms_config_connector, + struct vkms_config_encoder *vkms_config_encoder) +{ + struct vkms_config_encoder *encoder_entry; + unsigned long encoder_idx; + + xa_for_each(&vkms_config_connector->possible_encoders, encoder_idx, encoder_entry) { + if (encoder_entry == vkms_config_encoder) + break; + } + xa_erase(&vkms_config_connector->possible_encoders, encoder_idx); +} + bool vkms_config_is_valid(struct vkms_config *config) { struct vkms_config_plane *config_plane; diff --git a/drivers/gpu/drm/vkms/vkms_config.h b/drivers/gpu/drm/vkms/vkms_config.h index 2e5d2aa34a4f039c738cb9ac5642f3c75df36ba7..57cdf5fc2df1a62f57b4588c36ad0a99f63bee2a 100644 --- a/drivers/gpu/drm/vkms/vkms_config.h +++ b/drivers/gpu/drm/vkms/vkms_config.h @@ -189,6 +189,9 @@ int __must_check vkms_config_encoder_attach_crtc(struct vkms_config_encoder *vkm int __must_check vkms_config_connector_attach_encoder(struct vkms_config_connector *vkms_config_connector, struct vkms_config_encoder *vkms_config_encoder); +void vkms_config_connector_detach_encoder(struct vkms_config_connector *vkms_config_connector, + struct vkms_config_encoder *vkms_config_encoder); + /** * vkms_config_delete_plane() - Remove a plane configuration and frees its memory * diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vkms_configfs.c index 9f41506849552960970aa08b9329b4f88d0aa8e7..8bb3223c810dddb7d713ad4b01cece825f9939f6 100644 --- a/drivers/gpu/drm/vkms/vkms_configfs.c +++ b/drivers/gpu/drm/vkms/vkms_configfs.c @@ -536,6 +536,7 @@ static struct config_group *encoder_make_group(struct config_group *config_group } strscpy(vkms_configfs_encoder->vkms_config_encoder->name, name, strlen(name) + 1); + config_group_init_type_name(&vkms_configfs_encoder->group, name, &encoder_item_type); @@ -559,6 +560,139 @@ static const struct config_item_type encoders_item_type = { .ct_owner = THIS_MODULE, }; +static int connector_possible_encoders_allow_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_config_encoder *vkms_config_encoder; + struct vkms_configfs_device *vkms_configfs = + connector_possible_encoder_src_item_to_vkms_configfs_device + (src); + + mutex_lock(&vkms_configfs->lock); + + if (target->ci_type != &encoder_item_type) { + DRM_ERROR("Unable to link non-CRTCs.\n"); + mutex_unlock(&vkms_configfs->lock); + return -EINVAL; + } + + vkms_config_encoder = encoder_item_to_vkms_configfs_encoder(target) + ->vkms_config_encoder; + struct vkms_config_connector *vkms_config_connector = + connector_possible_encoder_src_item_to_vkms_configfs_connector + (src) + ->vkms_config_connector; + + if (vkms_config_connector_attach_encoder(vkms_config_connector, + vkms_config_encoder)) + return -EINVAL; + + mutex_unlock(&vkms_configfs->lock); + + return 0; +} + +static void connector_possible_encoders_drop_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_config_encoder *vkms_config_encoder; + struct vkms_configfs_device *vkms_configfs = + connector_possible_encoder_src_item_to_vkms_configfs_device(src); + + mutex_lock(&vkms_configfs->lock); + + vkms_config_encoder = encoder_item_to_vkms_configfs_encoder(target)->vkms_config_encoder; + struct vkms_config_connector *vkms_config_connector = + connector_possible_encoder_src_item_to_vkms_configfs_connector(src) + ->vkms_config_connector; + + vkms_config_connector_detach_encoder(vkms_config_connector, vkms_config_encoder); + + mutex_unlock(&vkms_configfs->lock); +} + +static struct configfs_item_operations connector_possible_encoders_item_operations = { + .allow_link = &connector_possible_encoders_allow_link, + .drop_link = &connector_possible_encoders_drop_link, +}; + +static struct config_item_type connector_possible_encoders_item_type = { + .ct_item_ops = &connector_possible_encoders_item_operations, + .ct_owner = THIS_MODULE, +}; + +static void connector_release(struct config_item *item) +{ + struct vkms_configfs_connector *vkms_configfs_connector = + connector_item_to_vkms_configfs_connector(item); + + mutex_lock(&vkms_configfs_connector->vkms_configfs_device->lock); + vkms_config_delete_connector(vkms_configfs_connector->vkms_config_connector); + mutex_unlock(&vkms_configfs_connector->vkms_configfs_device->lock); + + kfree(vkms_configfs_connector); +} + +static struct configfs_item_operations connector_item_operations = { + .release = connector_release, +}; + +static const struct config_item_type connector_item_type = { + .ct_item_ops = &connector_item_operations, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *connector_make_group(struct config_group *config_group, + const char *name) +{ + struct vkms_configfs_device *vkms_configfs = + connector_item_to_vkms_configfs_device(&config_group->cg_item); + struct vkms_configfs_connector *vkms_configfs_connector; + + vkms_configfs_connector = kzalloc(sizeof(*vkms_configfs_connector), GFP_KERNEL); + + if (!vkms_configfs_connector) + return ERR_PTR(-ENOMEM); + + mutex_lock(&vkms_configfs->lock); + + if (vkms_configfs->enabled) { + kfree(vkms_configfs_connector); + mutex_unlock(&vkms_configfs->lock); + return ERR_PTR(-EINVAL); + } + + vkms_configfs_connector->vkms_config_connector = + vkms_config_create_connector(vkms_configfs->vkms_config); + + if (!vkms_configfs_connector->vkms_config_connector) { + kfree(vkms_configfs_connector); + mutex_unlock(&vkms_configfs->lock); + return ERR_PTR(-ENOMEM); + } + + config_group_init_type_name(&vkms_configfs_connector->group, name, &connector_item_type); + + config_group_init_type_name(&vkms_configfs_connector->possible_encoder_group, + "possible_encoders", &connector_possible_encoders_item_type); + configfs_add_default_group(&vkms_configfs_connector->possible_encoder_group, + &vkms_configfs_connector->group); + vkms_configfs_connector->vkms_configfs_device = vkms_configfs; + + mutex_unlock(&vkms_configfs->lock); + + return &vkms_configfs_connector->group; +} + +static struct configfs_group_operations connector_group_operations = { + .make_group = &connector_make_group, +}; + +static const struct config_item_type connectors_item_type = { + .ct_group_ops = &connector_group_operations, + .ct_owner = THIS_MODULE, +}; + /** * configfs_lock_dependencies() - In order to forbid the userspace to delete items when the * device is enabled, mark all configfs items as dependent @@ -705,6 +839,10 @@ static struct config_group *root_make_group(struct config_group *group, config_group_init_type_name(&configfs->encoder_group, "encoders", &encoders_item_type); configfs_add_default_group(&configfs->encoder_group, &configfs->group); + config_group_init_type_name(&configfs->connector_group, "connectors", + &connectors_item_type); + configfs_add_default_group(&configfs->connector_group, &configfs->group); + return &configfs->group; } diff --git a/drivers/gpu/drm/vkms/vkms_configfs.h b/drivers/gpu/drm/vkms/vkms_configfs.h index c033810f86ce467f564a14f74165198f12ea044c..5e13941df3382ed30770e79a0432bf37764d7c59 100644 --- a/drivers/gpu/drm/vkms/vkms_configfs.h +++ b/drivers/gpu/drm/vkms/vkms_configfs.h @@ -22,6 +22,7 @@ struct vkms_configfs_device { struct config_group plane_group; struct config_group crtc_group; struct config_group encoder_group; + struct config_group connector_group; struct mutex lock; bool enabled; @@ -53,6 +54,14 @@ struct vkms_configfs_encoder { struct vkms_config_encoder *vkms_config_encoder; }; +struct vkms_configfs_connector { + struct config_group group; + + struct config_group possible_encoder_group; + struct vkms_configfs_device *vkms_configfs_device; + struct vkms_config_connector *vkms_config_connector; +}; + #define config_item_to_vkms_configfs_device(item) \ container_of(to_config_group((item)), struct vkms_configfs_device, group) @@ -68,6 +77,9 @@ struct vkms_configfs_encoder { #define encoder_item_to_vkms_configfs_encoder(item) \ container_of(to_config_group((item)), struct vkms_configfs_encoder, group) +#define connector_item_to_vkms_configfs_connector(item) \ + container_of(to_config_group((item)), struct vkms_configfs_connector, group) + #define plane_item_to_vkms_configfs_device(item) \ planes_item_to_vkms_configfs_device((item)->ci_parent) @@ -89,14 +101,25 @@ struct vkms_configfs_encoder { #define encoder_item_to_vkms_configfs_device(item) \ config_item_to_vkms_configfs_device((item)->ci_parent) +#define connector_item_to_vkms_configfs_device(item) \ + config_item_to_vkms_configfs_device((item)->ci_parent) + #define encoder_child_item_to_vkms_configfs_device(item) \ encoder_item_to_vkms_configfs_device((item)->ci_parent) #define encoder_possible_crtc_src_item_to_vkms_configfs_device(item) \ encoder_child_item_to_vkms_configfs_device((item)->ci_parent) +#define connector_child_item_to_vkms_configfs_device(item) \ + connector_item_to_vkms_configfs_device((item)->ci_parent) + +#define connector_possible_encoder_src_item_to_vkms_configfs_device(item) \ + connector_child_item_to_vkms_configfs_device((item)->ci_parent) + #define encoder_possible_crtc_src_item_to_vkms_configfs_encoder(item) \ encoder_item_to_vkms_configfs_encoder((item)->ci_parent) +#define connector_possible_encoder_src_item_to_vkms_configfs_connector(item) \ + connector_item_to_vkms_configfs_connector((item)->ci_parent) /* ConfigFS Support */ int vkms_init_configfs(void); -- 2.47.1