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 9a461a0481c2a20d6d48f1aa9649843ad1b7d13d..da99785ec89f0c6a7fe1a71fd2e6f5944c844aa9 100644 --- a/drivers/gpu/drm/vkms/vkms_config.c +++ b/drivers/gpu/drm/vkms/vkms_config.c @@ -516,6 +516,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 529d9c99f3c406d49dc7f3689a84c3dd775399a9..b1d80185216798cc9fc06e7d1cd0c423b7275185 100644 --- a/drivers/gpu/drm/vkms/vkms_config.h +++ b/drivers/gpu/drm/vkms/vkms_config.h @@ -197,6 +197,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 a410c9be4f2bbf7b2651245747eb357fcf32d1f2..94c288514172b88d06c2b74e36569c6d55383782 100644 --- a/drivers/gpu/drm/vkms/vkms_configfs.c +++ b/drivers/gpu/drm/vkms/vkms_configfs.c @@ -746,6 +746,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); @@ -769,6 +770,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 @@ -915,6 +1049,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 df743e0107f40cd10433bdb638108d266f9c83a6..12c0fdefb813387515d144519479c242b7ef6728 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.0