From nobody Mon Feb 9 06:34:33 2026 Received: from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net [217.70.183.198]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 692A81DE2BD for ; Fri, 22 Nov 2024 17:39:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.183.198 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732297149; cv=none; b=TE75aALeEWAn0kptBRdrACm61p8hnHjVIM5mfYCZRXjoe4c2IRRwcsTzHY+J0pNuvYzvigKYJG/x6NKO9XPjAcV3TC64n2O9LyHuptN/dCNlEEIHppQETgVcoxwNOwPhg2TcspQtREv1pSxEQYzGAk4uLZ5ex7esj6wpTq5vZpY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732297149; c=relaxed/simple; bh=gndkOG5m3vc2al8lf41sf/N19K1uU2teEn3f/2c0XLA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mczZzC6lDdEuKjJWM5ScDpUO3sG4vmOVcjGsOa4OJ8/r4UesSppXK0OlBqbr/HmoagDjKK6A82Dv/5zA5GgrjuBLp+326N32ppq0QdiWUbuOegJ1lRrVuX3yi5+dVGy256WBnT0uC9WEwog4CSkSLBUB+DvQxXyPHsUfZAFAYWk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=cTd+yms5; arc=none smtp.client-ip=217.70.183.198 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="cTd+yms5" Received: by mail.gandi.net (Postfix) with ESMTPSA id D2B97C000B; Fri, 22 Nov 2024 17:39:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1732297144; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=RiHV4kTKs+4HZbVoCDeGNcEDP2FhnDWM5/2UYTHeIhA=; b=cTd+yms53lU7DPAk9LIt/dj+nz2yHT/HgoVAC6lEh8gS7fSJS56glc/FexImHqhyVOrciK 9L/TBzfs+SMiohz4oI1KWErSl6i+hsgZHT2ZkptttYuGPoD4uTY5IZvHHuMIYPATQjgy1e 68pfM+Psx2GKIBmpuy752BDne0zqX+a5TUk9sz89lpX68/BD6OrhIXqFUKpONUNWS56pBS gReHETFiX+JW49rnyITYz6wmE4q3EMCNNj5MtqT7gz7f8us9dtByIqEs7xs/GyE1e+nuYs XMgdZOmxJ/bqX62TMf3OaeQ/pdOXfUw1H4uGx+zakX2JbwtH1BCpCGP7gIG4cA== From: Louis Chauvet Date: Fri, 22 Nov 2024 18:38:34 +0100 Subject: [PATCH RFC v2 08/16] drm/vkms: Introduce configfs for crtc and encoder Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20241122-google-config-fs-v2-8-4b7e6f183320@bootlin.com> References: <20241122-google-config-fs-v2-0-4b7e6f183320@bootlin.com> In-Reply-To: <20241122-google-config-fs-v2-0-4b7e6f183320@bootlin.com> To: Rodrigo Siqueira , Melissa Wen , =?utf-8?q?Ma=C3=ADra_Canal?= , Haneen Mohammed , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Simona Vetter Cc: jose.exposito89@gmail.com, dri-devel@lists.freedesktop.org, arthurgrillo@riseup.net, linux-kernel@vger.kernel.org, jeremie.dautheribes@bootlin.com, miquel.raynal@bootlin.com, thomas.petazzoni@bootlin.com, seanpaul@google.com, nicolejadeyee@google.com, Louis Chauvet X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=20793; i=louis.chauvet@bootlin.com; h=from:subject:message-id; bh=gndkOG5m3vc2al8lf41sf/N19K1uU2teEn3f/2c0XLA=; b=kA0DAAgBIK0uxlsQLOIByyZiAGdAwauhW9GXc+VgMJcWeEyVtrK3f4d0fVGCWazJvjI8b0cka YkCMwQAAQgAHRYhBE+PuD++eDwxDFBZBCCtLsZbECziBQJnQMGrAAoJECCtLsZbECziH74P/jrB rCfYxiGHlp32cXrEii22DsE9zdMXG3o9EFq3fv+Cb7a0FqU4CU7k5DIPhUUb1qkuhQ6V3pmrJyA ZEBvhNepel+Yc+hGlTL0CwPXsS7sPXq0jH+yiyYiqt0hVRXNnWg+2mEy1QfPOLZUuxsWefPTZ6m HFA9kiL6A8gQw+qIV1dUhrHhQmj5F+3I9mnTBkTo+eelj3NrRs9fomw5qOnxB9Ixd1uBmzCvide jgLb0n70Ou+Pw7i1szXnHeZHtsjXLaT7tuhFbutHKPhnRxGIHI7kJfPHpDh6DVEPCU6a2U/jFpe jsbFbuGp9IEz6aLILRfqdJ+kqbYuFedCe26VfXXz+qIXRHSpOibPdLYtieA69TT/kQXBQIPLsU0 cZM2ixl0gPOeYrC87/5FEi4+Ec+ff04yhJiEYrEzxhWjoysAONeYe8ybkPi4/L5CJ88SxhtBtO/ ENj8VsUpWxkMsq+oJSVvnUtKbB0tebloy9bFKsyzmbRsvZhGe4cWBc10nXTGnfS9D/XSwjfeFWi M5v7nIyC7cgcyjB6RB89cx0LV4KISzPmkt025FYw9SvS7yV37PByjgc1jo06snW2AkXy5V0fMBA bun4W3BzJI3gmSBPBftpLW2+eViXic8Po53blcWFRwFdGfC1ldtflTN3cZ52xMBAujCvcHqmc8T tciVJ X-Developer-Key: i=louis.chauvet@bootlin.com; a=openpgp; fpr=8B7104AE9A272D6693F527F2EC1883F55E0B40A5 X-GND-Sasl: louis.chauvet@bootlin.com To allows the userspace to test many hardware configuration, introduce a new interface to configure CRTCs and encoders. The CRTCs and encoders are created in their own directory. To link the CRTC, symlinks are used in the `possible_crtcs` folders. The current interface is: /config/vkms DEVICE_1 =E2=94=A3=E2=94=81 enable =E2=94=A3=E2=94=81 planes =E2=94=83 =E2=94=97=E2=94=81 PLANE_1 =E2=94=83 =E2=94=A3=E2=94=81 type =E2=94=83 =E2=94=A3=E2=94=81 supported_rotations =E2=94=83 =E2=94=A3=E2=94=81 supported_color_encoding =E2=94=83 =E2=94=A3=E2=94=81 supported_color_ranges =E2=94=83 =E2=94=A3=E2=94=81 default_rotation =E2=94=83 =E2=94=A3=E2=94=81 default_color_encoding =E2=94=83 =E2=94=A3=E2=94=81 default_color_range =E2=94=83 =E2=94=97=E2=94=81 possible_crtcs =E2=94=83 =E2=94=97=E2=94=81 >> /config/vkms/DEVICE_1/crtcs/CRTC_1 =E2=94=A3=E2=94=81 encoders =E2=94=83 =E2=94=97=E2=94=81 ENCODER_1 =E2=94=83 =E2=94=97=E2=94=81 possible_crtcs =E2=94=83 =E2=94=97=E2=94=81 >> /config/vkms/DEVICE_1/crtcs/CRTC_1 =E2=94=A3=E2=94=81 crtcs =E2=94=83 =E2=94=97=E2=94=81 CRTC_1 DEVICE_2 =E2=94=97=E2=94=81 ditto Signed-off-by: Louis Chauvet --- drivers/gpu/drm/vkms/vkms_configfs.c | 401 +++++++++++++++++++++++++++++++= ++-- drivers/gpu/drm/vkms/vkms_configfs.h | 54 ++++- 2 files changed, 434 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vk= ms_configfs.c index aabc832836266668c8adc60d7d5284ee1f385f31..a410c9be4f2bbf7b2651245747e= b357fcf32d1f2 100644 --- a/drivers/gpu/drm/vkms/vkms_configfs.c +++ b/drivers/gpu/drm/vkms/vkms_configfs.c @@ -5,6 +5,7 @@ #include #include #include +#include =20 #include "vkms_configfs.h" #include "vkms_drv.h" @@ -395,6 +396,84 @@ static const struct config_item_type subgroup_plane = =3D { .ct_owner =3D THIS_MODULE, }; =20 +static const struct config_item_type crtc_item_type; +static const struct config_item_type planes_item_type; + +static int possible_crtcs_allow_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_configfs_device *vkms_configfs =3D plane_possible_crtc_src_it= em_to_vkms_configfs_device(src); + struct vkms_config_crtc *crtc; + + mutex_lock(&vkms_configfs->lock); + + if (target->ci_type !=3D &crtc_item_type) { + mutex_unlock(&vkms_configfs->lock); + return -EINVAL; + } + + crtc =3D crtc_item_to_vkms_configfs_crtc(target)->vkms_config_crtc; + struct vkms_config_plane *plane =3D plane_possible_crtc_src_item_to_vkms_= configfs_plane(src)->vkms_config_plane; + + struct vkms_config_crtc *crtc_entry; + unsigned long idx =3D 0; + + xa_for_each(&plane->possible_crtcs, idx, crtc_entry) { + if (crtc_entry =3D=3D crtc) { + mutex_unlock(&vkms_configfs->lock); + return -EINVAL; + } + } + + if (vkms_config_plane_attach_crtc(plane, crtc)) + return -EINVAL; + + mutex_unlock(&vkms_configfs->lock); + + return 0; +} + +static void possible_crtcs_drop_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_config_crtc *crtc; + struct vkms_configfs_device *vkms_configfs =3D plane_possible_crtc_src_it= em_to_vkms_configfs_device(src); + + mutex_lock(&vkms_configfs->lock); + + crtc =3D crtc_item_to_vkms_configfs_crtc(target)->vkms_config_crtc; + struct vkms_config_plane *plane =3D plane_possible_crtc_src_item_to_vkms_= configfs_plane(src)->vkms_config_plane; + + struct vkms_config_crtc *crtc_entry; + struct vkms_config_plane *plane_entry; + unsigned long crtc_idx =3D -1; + + xa_for_each(&plane->possible_crtcs, crtc_idx, crtc_entry) { + if (crtc_entry =3D=3D crtc) + break; + } + unsigned long plane_idx =3D -1; + + xa_erase(&plane->possible_crtcs, crtc_idx); + xa_for_each(&crtc->possible_planes, plane_idx, plane_entry) { + if (plane_entry =3D=3D plane) + break; + } + xa_erase(&crtc->possible_planes, plane_idx); + + mutex_unlock(&vkms_configfs->lock); +} + +static struct configfs_item_operations plane_possible_crtcs_item_ops =3D { + .allow_link =3D &possible_crtcs_allow_link, + .drop_link =3D &possible_crtcs_drop_link, +}; + +static struct config_item_type plane_possible_crtcs_group_type =3D { + .ct_item_ops =3D &plane_possible_crtcs_item_ops, + .ct_owner =3D THIS_MODULE, +}; + static struct config_group *planes_make_group(struct config_group *config_= group, const char *name) { @@ -419,10 +498,7 @@ static struct config_group *planes_make_group(struct c= onfig_group *config_group, =20 if (list_count_nodes(&vkms_configfs->vkms_config->planes) =3D=3D 1) vkms_configfs_plane->vkms_config_plane->type =3D DRM_PLANE_TYPE_PRIMARY; - - if (!vkms_configfs_plane->vkms_config_plane || - vkms_config_plane_attach_crtc(vkms_configfs_plane->vkms_config_plane, - vkms_configfs->vkms_config_crtc)) { + if (!vkms_configfs_plane->vkms_config_plane) { kfree(vkms_configfs_plane); mutex_unlock(&vkms_configfs->lock); return ERR_PTR(-ENOMEM); @@ -439,7 +515,12 @@ static struct config_group *planes_make_group(struct c= onfig_group *config_group, =20 config_group_init_type_name(&vkms_configfs_plane->group, name, &subgroup_= plane); =20 + config_group_init_type_name(&vkms_configfs_plane->possible_crtc_group, "p= ossible_crtcs", + &plane_possible_crtcs_group_type); + configfs_add_default_group(&vkms_configfs_plane->possible_crtc_group, + &vkms_configfs_plane->group); vkms_configfs_plane->vkms_configfs_device =3D vkms_configfs; + mutex_unlock(&vkms_configfs->lock); =20 return &vkms_configfs_plane->group; @@ -454,6 +535,283 @@ static const struct config_item_type planes_item_type= =3D { .ct_owner =3D THIS_MODULE, }; =20 +static void crtc_release(struct config_item *item) +{ + struct vkms_configfs_crtc *vkms_configfs_crtc =3D crtc_item_to_vkms_confi= gfs_crtc(item); + + mutex_lock(&vkms_configfs_crtc->vkms_configfs_device->lock); + vkms_config_delete_crtc(vkms_configfs_crtc->vkms_config_crtc, + vkms_configfs_crtc->vkms_configfs_device->vkms_config); + mutex_unlock(&vkms_configfs_crtc->vkms_configfs_device->lock); + + kfree(vkms_configfs_crtc); +} + +static struct configfs_item_operations crtc_item_operations =3D { + .release =3D crtc_release, +}; + +static const struct config_item_type crtc_item_type =3D { + .ct_owner =3D THIS_MODULE, + .ct_item_ops =3D &crtc_item_operations, +}; + +static struct config_group *crtcs_make_group(struct config_group *config_g= roup, + const char *name) +{ + struct config_item *root_item =3D config_group->cg_item.ci_parent; + struct vkms_configfs_device *vkms_configfs =3D config_item_to_vkms_config= fs_device(root_item); + struct vkms_configfs_crtc *vkms_configfs_crtc; + + vkms_configfs_crtc =3D kzalloc(sizeof(*vkms_configfs_crtc), GFP_KERNEL); + + if (!vkms_configfs_crtc) + return ERR_PTR(-ENOMEM); + + mutex_lock(&vkms_configfs->lock); + vkms_configfs_crtc->vkms_configfs_device =3D vkms_configfs; + + if (vkms_configfs->enabled) { + kfree(vkms_configfs_crtc); + mutex_unlock(&vkms_configfs->lock); + return ERR_PTR(-EINVAL); + } + + vkms_configfs_crtc->vkms_config_crtc =3D vkms_config_create_crtc(vkms_con= figfs->vkms_config); + + if (!vkms_configfs_crtc->vkms_config_crtc) { + kfree(vkms_configfs_crtc); + mutex_unlock(&vkms_configfs->lock); + return ERR_PTR(-ENOMEM); + } + + vkms_configfs_crtc->vkms_config_crtc->name =3D kzalloc(strlen(name) + 1, = GFP_KERNEL); + if (!vkms_configfs_crtc->vkms_config_crtc->name) { + kfree(vkms_configfs_crtc->vkms_config_crtc); + kfree(vkms_configfs_crtc); + mutex_unlock(&vkms_configfs->lock); + return ERR_PTR(-ENOMEM); + } + + vkms_configfs_crtc->vkms_configfs_device =3D vkms_configfs; + + strscpy(vkms_configfs_crtc->vkms_config_crtc->name, name, strlen(name) + = 1); + config_group_init_type_name(&vkms_configfs_crtc->group, name, + &crtc_item_type); + + mutex_unlock(&vkms_configfs->lock); + + return &vkms_configfs_crtc->group; +} + +static struct configfs_group_operations crtcs_group_operations =3D { + .make_group =3D &crtcs_make_group, +}; + +static const struct config_item_type crtcs_item_type =3D { + .ct_group_ops =3D &crtcs_group_operations, + .ct_owner =3D THIS_MODULE, +}; + +static int encoder_possible_crtcs_allow_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_config_crtc *crtc; + struct vkms_configfs_device *vkms_configfs =3D encoder_possible_crtc_src_= item_to_vkms_configfs_device(src); + + mutex_lock(&vkms_configfs->lock); + + if (target->ci_type !=3D &crtc_item_type) { + DRM_ERROR("Unable to link non-CRTCs.\n"); + mutex_unlock(&vkms_configfs->lock); + return -EINVAL; + } + + crtc =3D crtc_item_to_vkms_configfs_crtc(target)->vkms_config_crtc; + struct vkms_config_encoder *encoder =3D encoder_possible_crtc_src_item_to= _vkms_configfs_encoder(src)->vkms_config_encoder; + + struct vkms_config_crtc *crtc_entry; + unsigned long idx =3D 0; + + xa_for_each(&encoder->possible_crtcs, idx, crtc_entry) { + if (crtc_entry =3D=3D crtc) { + pr_err("Tried to add two symlinks to the same CRTC from the same object= .\n"); + mutex_unlock(&vkms_configfs->lock); + return -EINVAL; + } + } + + if (vkms_config_encoder_attach_crtc(encoder, crtc)) + return -EINVAL; + + mutex_unlock(&vkms_configfs->lock); + + return 0; +} + +static void encoder_possible_crtcs_drop_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_config_crtc *crtc; + struct vkms_configfs_device *vkms_configfs =3D encoder_possible_crtc_src_= item_to_vkms_configfs_device(src); + + mutex_lock(&vkms_configfs->lock); + + crtc =3D crtc_item_to_vkms_configfs_crtc(target)->vkms_config_crtc; + struct vkms_config_encoder *encoder =3D encoder_possible_crtc_src_item_to= _vkms_configfs_encoder(src)->vkms_config_encoder; + + struct vkms_config_encoder *encoder_entry; + struct vkms_config_crtc *crtc_entry; + unsigned long encoder_idx =3D -1; + unsigned long crtc_idx =3D -1; + + xa_for_each(&encoder->possible_crtcs, crtc_idx, crtc_entry) { + if (crtc_entry =3D=3D crtc) + break; + } + xa_erase(&encoder->possible_crtcs, crtc_idx); + xa_for_each(&crtc->possible_encoders, encoder_idx, encoder_entry) { + if (encoder_entry =3D=3D encoder) + break; + } + xa_erase(&crtc->possible_encoders, encoder_idx); + + mutex_unlock(&vkms_configfs->lock); +} + +static struct configfs_item_operations encoder_possible_crtcs_item_operati= ons =3D { + .allow_link =3D &encoder_possible_crtcs_allow_link, + .drop_link =3D &encoder_possible_crtcs_drop_link, +}; + +static struct config_item_type encoder_possible_crtcs_item_type =3D { + .ct_item_ops =3D &encoder_possible_crtcs_item_operations, + .ct_owner =3D THIS_MODULE, +}; + +static void encoder_release(struct config_item *item) +{ + struct vkms_configfs_encoder *vkms_configfs_encoder =3D encoder_item_to_v= kms_configfs_encoder(item); + + mutex_lock(&vkms_configfs_encoder->vkms_configfs_device->lock); + vkms_config_delete_encoder(vkms_configfs_encoder->vkms_config_encoder, + vkms_configfs_encoder->vkms_configfs_device->vkms_config); + mutex_unlock(&vkms_configfs_encoder->vkms_configfs_device->lock); + + kfree(vkms_configfs_encoder); +} + +static struct configfs_item_operations encoder_item_operations =3D { + .release =3D encoder_release, +}; + +static const struct config_item_type encoder_item_type =3D { + .ct_item_ops =3D &encoder_item_operations, + .ct_owner =3D THIS_MODULE, +}; + +static struct config_group *encoder_make_group(struct config_group *config= _group, + const char *name) +{ + struct vkms_configfs_device *vkms_configfs =3D encoder_item_to_vkms_confi= gfs_device(&config_group->cg_item); + struct vkms_configfs_encoder *vkms_configfs_encoder; + + vkms_configfs_encoder =3D kzalloc(sizeof(*vkms_configfs_encoder), GFP_KER= NEL); + + if (!vkms_configfs_encoder) + return ERR_PTR(-ENOMEM); + + mutex_lock(&vkms_configfs->lock); + + if (vkms_configfs->enabled) { + kfree(vkms_configfs_encoder); + mutex_unlock(&vkms_configfs->lock); + return ERR_PTR(-EINVAL); + } + + vkms_configfs_encoder->vkms_config_encoder =3D vkms_config_create_encoder= (vkms_configfs->vkms_config); + + if (!vkms_configfs_encoder->vkms_config_encoder) { + kfree(vkms_configfs_encoder); + mutex_unlock(&vkms_configfs->lock); + return ERR_PTR(-ENOMEM); + } + + vkms_configfs_encoder->vkms_config_encoder->name =3D kzalloc(strlen(name)= + 1, GFP_KERNEL); + if (!vkms_configfs_encoder->vkms_config_encoder->name) { + kfree(vkms_configfs_encoder->vkms_config_encoder); + kfree(vkms_configfs_encoder); + mutex_unlock(&vkms_configfs->lock); + return ERR_PTR(-ENOMEM); + } + + strscpy(vkms_configfs_encoder->vkms_config_encoder->name, name, strlen(na= me) + 1); + config_group_init_type_name(&vkms_configfs_encoder->group, name, + &encoder_item_type); + + config_group_init_type_name(&vkms_configfs_encoder->possible_crtc_group, = "possible_crtcs", + &encoder_possible_crtcs_item_type); + configfs_add_default_group(&vkms_configfs_encoder->possible_crtc_group, + &vkms_configfs_encoder->group); + vkms_configfs_encoder->vkms_configfs_device =3D vkms_configfs; + + mutex_unlock(&vkms_configfs->lock); + + return &vkms_configfs_encoder->group; +} + +static struct configfs_group_operations encoder_group_operations =3D { + .make_group =3D &encoder_make_group, +}; + +static const struct config_item_type encoders_item_type =3D { + .ct_group_ops =3D &encoder_group_operations, + .ct_owner =3D THIS_MODULE, +}; + +/** + * configfs_lock_dependencies() - In order to forbid the userspace to dele= te items when the + * device is enabled, mark all configfs items as dependent + * + * @vkms_configfs_device: Device to lock + */ +static void configfs_lock_dependencies(struct vkms_configfs_device *vkms_c= onfigfs_device) +{ + /* Lock the group itself */ + configfs_depend_item_unlocked(vkms_configfs_device->group.cg_subsys, + &vkms_configfs_device->group.cg_item); + /* Lock the planes elements */ + struct config_item *item; + + list_for_each_entry(item, &vkms_configfs_device->plane_group.cg_children,= ci_entry) { + configfs_depend_item_unlocked(vkms_configfs_device->plane_group.cg_subsy= s, + item); + } + list_for_each_entry(item, &vkms_configfs_device->crtc_group.cg_children, = ci_entry) { + configfs_depend_item_unlocked(vkms_configfs_device->crtc_group.cg_subsys, + item); + } +} + +/** + * configfs_unlock_dependencies() - Once the device is disable, its config= uration can be modified. + * + * @vkms_configfs_device: Device to unlock + */ +static void configfs_unlock_dependencies(struct vkms_configfs_device *vkms= _configfs_device) +{ + struct config_item *item; + + configfs_undepend_item_unlocked(&vkms_configfs_device->group.cg_item); + + list_for_each_entry(item, &vkms_configfs_device->plane_group.cg_children,= ci_entry) { + configfs_undepend_item_unlocked(item); + } + list_for_each_entry(item, &vkms_configfs_device->crtc_group.cg_children, = ci_entry) { + configfs_undepend_item_unlocked(item); + } +} + static ssize_t device_enable_show(struct config_item *item, char *page) { return sprintf(page, "%d\n", @@ -474,13 +832,25 @@ static ssize_t device_enable_store(struct config_item= *item, return -EINVAL; =20 mutex_lock(&vkms_configfs_device->lock); + if (vkms_configfs_device->enabled =3D=3D value) { + mutex_unlock(&vkms_configfs_device->lock); + return (ssize_t)count; + } + + if (value && !vkms_config_is_valid(vkms_configfs_device->vkms_config)) { + mutex_unlock(&vkms_configfs_device->lock); + return -EINVAL; + } =20 vkms_configfs_device->enabled =3D value; =20 - if (value) + if (value) { + configfs_lock_dependencies(vkms_configfs_device); vkms_create(vkms_configfs_device->vkms_config); - else + } else { + configfs_unlock_dependencies(vkms_configfs_device); vkms_destroy(vkms_configfs_device->vkms_config); + } =20 mutex_unlock(&vkms_configfs_device->lock); =20 @@ -519,9 +889,6 @@ static const struct config_item_type device_item_type = =3D { static struct config_group *root_make_group(struct config_group *group, const char *name) { - struct vkms_config_plane *plane; - struct vkms_config_crtc *crtc; - struct vkms_config_encoder *encoder; struct vkms_configfs_device *configfs =3D kzalloc(sizeof(*configfs), GFP_= KERNEL); =20 if (!configfs) @@ -536,22 +903,18 @@ static struct config_group *root_make_group(struct co= nfig_group *group, return ERR_PTR(-ENOMEM); } =20 - configfs->vkms_config_crtc =3D vkms_config_create_crtc(configfs->vkms_con= fig); - configfs->vkms_config_encoder =3D vkms_config_create_encoder(configfs->vk= ms_config); - if (!configfs->vkms_config_crtc || !configfs->vkms_config_encoder || - vkms_config_encoder_attach_crtc(configfs->vkms_config_encoder, - configfs->vkms_config_crtc)) { - vkms_config_destroy(configfs->vkms_config); - kfree(configfs); - return ERR_PTR(-ENOMEM); - } - config_group_init_type_name(&configfs->group, name, &device_item_type); =20 config_group_init_type_name(&configfs->plane_group, "planes", &planes_ite= m_type); configfs_add_default_group(&configfs->plane_group, &configfs->group); =20 + config_group_init_type_name(&configfs->crtc_group, "crtcs", &crtcs_item_t= ype); + configfs_add_default_group(&configfs->crtc_group, &configfs->group); + + config_group_init_type_name(&configfs->encoder_group, "encoders", &encode= rs_item_type); + configfs_add_default_group(&configfs->encoder_group, &configfs->group); + return &configfs->group; } =20 diff --git a/drivers/gpu/drm/vkms/vkms_configfs.h b/drivers/gpu/drm/vkms/vk= ms_configfs.h index 6dc4d34a9e44ed4beb115ad3c86b759e28f5d0ef..df743e0107f40cd10433bdb6381= 08d266f9c83a6 100644 --- a/drivers/gpu/drm/vkms/vkms_configfs.h +++ b/drivers/gpu/drm/vkms/vkms_configfs.h @@ -20,34 +20,84 @@ struct vkms_configfs_device { struct config_group group; =20 struct config_group plane_group; + struct config_group crtc_group; + struct config_group encoder_group; =20 struct mutex lock; bool enabled; =20 struct vkms_config *vkms_config; - struct vkms_config_crtc *vkms_config_crtc; - struct vkms_config_encoder *vkms_config_encoder; }; =20 struct vkms_configfs_plane { struct config_group group; + struct config_group possible_crtc_group; =20 struct vkms_configfs_device *vkms_configfs_device; struct vkms_config_plane *vkms_config_plane; }; =20 +struct vkms_configfs_crtc { + struct config_group group; + + struct vkms_configfs_device *vkms_configfs_device; + struct vkms_config_crtc *vkms_config_crtc; +}; + +struct vkms_configfs_encoder { + /* must be first because it is a krefcounted stuff */ + struct config_group group; + + struct config_group possible_crtc_group; + struct vkms_configfs_device *vkms_configfs_device; + struct vkms_config_encoder *vkms_config_encoder; +}; + #define config_item_to_vkms_configfs_device(item) \ container_of(to_config_group((item)), struct vkms_configfs_device, group) =20 #define planes_item_to_vkms_configfs_device(item) \ config_item_to_vkms_configfs_device((item)->ci_parent) =20 +#define encoders_item_to_vkms_configfs_device(item) \ + config_item_to_vkms_configfs_device((item)->ci_parent) + +#define crtc_item_to_vkms_configfs_crtc(item) \ + container_of(to_config_group((item)), struct vkms_configfs_crtc, group) + +#define encoder_item_to_vkms_configfs_encoder(item) \ + container_of(to_config_group((item)), struct vkms_configfs_encoder, group) + #define plane_item_to_vkms_configfs_device(item) \ planes_item_to_vkms_configfs_device((item)->ci_parent) =20 #define plane_item_to_vkms_configfs_plane(item) \ container_of(to_config_group((item)), struct vkms_configfs_plane, group) =20 +#define plane_possible_crtc_src_item_to_vkms_configfs_device(item) \ + plane_item_to_vkms_configfs_device((item)->ci_parent) + +#define plane_possible_crtc_src_item_to_vkms_configfs_plane(item) \ + plane_item_to_vkms_configfs_plane((item)->ci_parent) + +#define crtc_item_to_vkms_configfs_device(item) \ + config_item_to_vkms_configfs_device((item)->ci_parent) + +#define crtc_child_item_to_vkms_configfs_device(item) \ + crtc_item_to_vkms_configfs_device((item)->ci_parent) + +#define encoder_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 encoder_possible_crtc_src_item_to_vkms_configfs_encoder(item) \ + encoder_item_to_vkms_configfs_encoder((item)->ci_parent) + /* ConfigFS Support */ int vkms_init_configfs(void); void vkms_unregister_configfs(void); --=20 2.47.0