From nobody Thu Dec 18 01:35:38 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 59701C83F17 for ; Tue, 29 Aug 2023 05:33:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235803AbjH2Fc1 (ORCPT ); Tue, 29 Aug 2023 01:32:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54468 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235885AbjH2FcP (ORCPT ); Tue, 29 Aug 2023 01:32:15 -0400 Received: from mail-pl1-x636.google.com (mail-pl1-x636.google.com [IPv6:2607:f8b0:4864:20::636]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E97761AA for ; Mon, 28 Aug 2023 22:32:11 -0700 (PDT) Received: by mail-pl1-x636.google.com with SMTP id d9443c01a7336-1bdbf10333bso31294405ad.1 for ; Mon, 28 Aug 2023 22:32:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1693287131; x=1693891931; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=rbDza5IiePKcj9edkK1zUt6ifaFTEp3xjRfsYOaehus=; b=oeDHNiRCMTv+lSdweXO/ZvMsxk6RYBFXTz58uL1Tlb607Y5ezGi30pLq4NVY/PoYVg 7Or0SFyEf62ug56STgF4/7ogJgn541LIN3Fv+EdndcYwLmtFkvBjW52/5S+pVQjYgMpz KWoNfwVkmZY5EqYPcikytl01Bh8n+K6OI38g4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1693287131; x=1693891931; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=rbDza5IiePKcj9edkK1zUt6ifaFTEp3xjRfsYOaehus=; b=ctY7E2ia5bcO7zRbPGEjyOoW8E2zn2AH72GjKwqIj/Fkcig2YIsBk5wmxkV1rsEld5 UUH0bbCtvh9K0UVT88hAItHXnrIz/qSZKqGsmYAqoxw3RXFoDfXOTWo8IBL35ts/Arel 2qHbVAxLx1qknltZ358sxOhHND7DNqF7qT9NX6lbqyhxpajcFzO7sv4lDoYPqbEj28W/ nJBGNUYUCNVatXnBHPSDTRbZ9IEy4z+P9KS2l3pIFM1hROCqxykHC2FudzJdTx4zlstW rK9iEutEBaJg77Csz6Y5DqaGQT5fVhj+5l7fg/e0826Mhda0sEHTDWtMYh+aQkj5Xs6s w8rg== X-Gm-Message-State: AOJu0Yz65Oc1VcTPHoRBRGznlDIHwj2wJCwrLSajAN6/UsSe64XwlC/T 8zg+cCCAcJcpdWgX2m9CUicNDQ== X-Google-Smtp-Source: AGHT+IG6MLFbWE4HjvBXziHk0gW9EHyAZf8/H+nPA6ymhQnO6mZrwmDR0hdSRjmcYXB1hY8x6MXluQ== X-Received: by 2002:a17:902:7891:b0:1b8:16c7:a786 with SMTP id q17-20020a170902789100b001b816c7a786mr26208455pll.4.1693287131344; Mon, 28 Aug 2023 22:32:11 -0700 (PDT) Received: from datalore.c.googlers.com.com (148.175.199.104.bc.googleusercontent.com. [104.199.175.148]) by smtp.gmail.com with ESMTPSA id g6-20020a170902c38600b001bdccf6b8c9sm8420874plg.127.2023.08.28.22.32.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Aug 2023 22:32:11 -0700 (PDT) From: Brandon Pollack To: marius.vlad@collabora.com, mairacanal@riseup.net, jshargo@chromium.org Cc: corbet@lwn.net, dri-devel@lists.freedesktop.org, hamohammed.sa@gmail.com, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, melissa.srw@gmail.com, mripard@kernel.org, rodrigosiqueiramelo@gmail.com, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mduggan@chromium.org, hirono@chromium.org, Brandon Pollack Subject: [PATCH v6 1/7] drm/vkms: Back VKMS with DRM memory management instead of static objects Date: Tue, 29 Aug 2023 05:30:53 +0000 Message-ID: <20230829053201.423261-2-brpol@chromium.org> X-Mailer: git-send-email 2.42.0.rc2.253.gd59a3bf2b4-goog In-Reply-To: <20230829053201.423261-1-brpol@chromium.org> References: <20230829053201.423261-1-brpol@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Jim Shargo This is a small refactor to make ConfigFS support easier. Once we support ConfigFS, there can be multiple devices instantiated by the driver, and so moving everything into managed memory makes things much easier. This should be a no-op refactor. Signed-off-by: Jim Shargo Signed-off-by: Brandon Pollack --- drivers/gpu/drm/vkms/vkms_drv.c | 128 +++++++++++++++-------------- drivers/gpu/drm/vkms/vkms_drv.h | 4 +- drivers/gpu/drm/vkms/vkms_output.c | 6 +- 3 files changed, 71 insertions(+), 67 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_dr= v.c index dd0af086e7fa..387c832f5dc9 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -9,10 +9,12 @@ * the GPU in DRM API tests. */ =20 +#include #include #include #include =20 +#include #include #include #include @@ -37,8 +39,6 @@ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 =20 -static struct vkms_config *default_config; - static bool enable_cursor =3D true; module_param_named(enable_cursor, enable_cursor, bool, 0444); MODULE_PARM_DESC(enable_cursor, "Enable/Disable cursor support"); @@ -96,9 +96,9 @@ static int vkms_config_show(struct seq_file *m, void *dat= a) struct drm_device *dev =3D entry->dev; struct vkms_device *vkmsdev =3D drm_device_to_vkms_device(dev); =20 - seq_printf(m, "writeback=3D%d\n", vkmsdev->config->writeback); - seq_printf(m, "cursor=3D%d\n", vkmsdev->config->cursor); - seq_printf(m, "overlay=3D%d\n", vkmsdev->config->overlay); + seq_printf(m, "writeback=3D%d\n", vkmsdev->config.writeback); + seq_printf(m, "cursor=3D%d\n", vkmsdev->config.cursor); + seq_printf(m, "overlay=3D%d\n", vkmsdev->config.overlay); =20 return 0; } @@ -166,121 +166,127 @@ static int vkms_modeset_init(struct vkms_device *vk= msdev) dev->mode_config.cursor_height =3D 512; /* FIXME: There's a confusion between bpp and depth between this and * fbdev helpers. We have to go with 0, meaning "pick the default", - * which ix XRGB8888 in all cases. */ + * which ix XRGB8888 in all cases. + */ dev->mode_config.preferred_depth =3D 0; dev->mode_config.helper_private =3D &vkms_mode_config_helpers; =20 return vkms_output_init(vkmsdev, 0); } =20 -static int vkms_create(struct vkms_config *config) +static int vkms_platform_probe(struct platform_device *pdev) { int ret; - struct platform_device *pdev; struct vkms_device *vkms_device; + void *grp; =20 - pdev =3D platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL)) { - ret =3D -ENOMEM; - goto out_unregister; - } + grp =3D devres_open_group(&pdev->dev, NULL, GFP_KERNEL); + if (!grp) + return -ENOMEM; =20 vkms_device =3D devm_drm_dev_alloc(&pdev->dev, &vkms_driver, struct vkms_device, drm); if (IS_ERR(vkms_device)) { ret =3D PTR_ERR(vkms_device); - goto out_devres; + goto out_release_group; } + vkms_device->platform =3D pdev; - vkms_device->config =3D config; - config->dev =3D vkms_device; + vkms_device->config.cursor =3D enable_cursor; + vkms_device->config.writeback =3D enable_writeback; + vkms_device->config.overlay =3D enable_overlay; =20 ret =3D dma_coerce_mask_and_coherent(vkms_device->drm.dev, DMA_BIT_MASK(64)); - if (ret) { DRM_ERROR("Could not initialize DMA support\n"); - goto out_devres; + goto out_release_group; } =20 ret =3D drm_vblank_init(&vkms_device->drm, 1); if (ret) { DRM_ERROR("Failed to vblank\n"); - goto out_devres; + goto out_release_group; } =20 ret =3D vkms_modeset_init(vkms_device); - if (ret) - goto out_devres; + if (ret) { + DRM_ERROR("Unable to initialize modesetting\n"); + goto out_release_group; + } =20 drm_debugfs_add_files(&vkms_device->drm, vkms_config_debugfs_list, ARRAY_SIZE(vkms_config_debugfs_list)); =20 ret =3D drm_dev_register(&vkms_device->drm, 0); - if (ret) - goto out_devres; + if (ret) { + DRM_ERROR("Unable to register device with id %d\n", pdev->id); + goto out_release_group; + } =20 drm_fbdev_generic_setup(&vkms_device->drm, 0); + platform_set_drvdata(pdev, vkms_device); + devres_close_group(&pdev->dev, grp); =20 return 0; =20 -out_devres: - devres_release_group(&pdev->dev, NULL); -out_unregister: - platform_device_unregister(pdev); +out_release_group: + devres_release_group(&pdev->dev, grp); return ret; } =20 -static int __init vkms_init(void) +static int vkms_platform_remove(struct platform_device *pdev) { - int ret; - struct vkms_config *config; - - config =3D kmalloc(sizeof(*config), GFP_KERNEL); - if (!config) - return -ENOMEM; - - default_config =3D config; + struct vkms_device *vkms_device; =20 - config->cursor =3D enable_cursor; - config->writeback =3D enable_writeback; - config->overlay =3D enable_overlay; + vkms_device =3D platform_get_drvdata(pdev); + if (!vkms_device) + return 0; =20 - ret =3D vkms_create(config); - if (ret) - kfree(config); - - return ret; + drm_dev_unregister(&vkms_device->drm); + drm_atomic_helper_shutdown(&vkms_device->drm); + return 0; } =20 -static void vkms_destroy(struct vkms_config *config) +static struct platform_driver vkms_platform_driver =3D { + .probe =3D vkms_platform_probe, + .remove =3D vkms_platform_remove, + .driver.name =3D DRIVER_NAME, +}; + +static int __init vkms_init(void) { + int ret; struct platform_device *pdev; =20 - if (!config->dev) { - DRM_INFO("vkms_device is NULL.\n"); - return; + ret =3D platform_driver_register(&vkms_platform_driver); + if (ret) { + DRM_ERROR("Unable to register platform driver\n"); + return ret; } =20 - pdev =3D config->dev->platform; - - drm_dev_unregister(&config->dev->drm); - drm_atomic_helper_shutdown(&config->dev->drm); - devres_release_group(&pdev->dev, NULL); - platform_device_unregister(pdev); + pdev =3D platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); + if (IS_ERR(pdev)) { + platform_driver_unregister(&vkms_platform_driver); + return PTR_ERR(pdev); + } =20 - config->dev =3D NULL; + return 0; } =20 static void __exit vkms_exit(void) { - if (default_config->dev) - vkms_destroy(default_config); + struct device *dev; + + while ((dev =3D platform_find_device_by_driver( + NULL, &vkms_platform_driver.driver))) { + // platform_find_device_by_driver increments the refcount. Drop + // it so we don't leak memory. + put_device(dev); + platform_device_unregister(to_platform_device(dev)); + } =20 - kfree(default_config); + platform_driver_unregister(&vkms_platform_driver); } =20 module_init(vkms_init); diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_dr= v.h index c7ae6c2ba1df..4c35d6305f2a 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -124,15 +124,13 @@ struct vkms_config { bool writeback; bool cursor; bool overlay; - /* only set when instantiated */ - struct vkms_device *dev; }; =20 struct vkms_device { struct drm_device drm; struct platform_device *platform; struct vkms_output output; - const struct vkms_config *config; + struct vkms_config config; }; =20 #define drm_crtc_to_vkms_output(target) \ diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms= _output.c index 5ce70dd946aa..963a64cf068b 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -62,7 +62,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int ind= ex) if (IS_ERR(primary)) return PTR_ERR(primary); =20 - if (vkmsdev->config->overlay) { + if (vkmsdev->config.overlay) { for (n =3D 0; n < NUM_OVERLAY_PLANES; n++) { ret =3D vkms_add_overlay_plane(vkmsdev, index, crtc); if (ret) @@ -70,7 +70,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int ind= ex) } } =20 - if (vkmsdev->config->cursor) { + if (vkmsdev->config.cursor) { cursor =3D vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR, index); if (IS_ERR(cursor)) return PTR_ERR(cursor); @@ -103,7 +103,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int i= ndex) goto err_attach; } =20 - if (vkmsdev->config->writeback) { + if (vkmsdev->config.writeback) { writeback =3D vkms_enable_writeback_connector(vkmsdev); if (writeback) DRM_ERROR("Failed to init writeback connector\n"); --=20 2.42.0.rc2.253.gd59a3bf2b4-goog From nobody Thu Dec 18 01:35:38 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7DE4AC83F1C for ; Tue, 29 Aug 2023 05:33:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235815AbjH2Fcb (ORCPT ); Tue, 29 Aug 2023 01:32:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54688 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235905AbjH2FcV (ORCPT ); Tue, 29 Aug 2023 01:32:21 -0400 Received: from mail-pl1-x62b.google.com (mail-pl1-x62b.google.com [IPv6:2607:f8b0:4864:20::62b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 23EF21AB for ; Mon, 28 Aug 2023 22:32:15 -0700 (PDT) Received: by mail-pl1-x62b.google.com with SMTP id d9443c01a7336-1c1e780aa95so9445095ad.3 for ; Mon, 28 Aug 2023 22:32:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1693287134; x=1693891934; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=WL280DgNX+Y1mjj9kwNWscO6qBxvjxHIFxssphCjvCg=; b=DJFXrI26dgu9jmzJWI57UdxT0A2iUaWzDcCZEI6G0GyZcPTl1Qom4CGm9e5KApJKKH QfVHaydKOvqt91f+/XL7fi/sGQJksOYTtJTJRmL8faP1p5IbfjJn1QnOzeTqUCzjPw+A /iS3Stqe/GYF0+ay+mvquaYdmG3ByhRd2OEGw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1693287134; x=1693891934; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=WL280DgNX+Y1mjj9kwNWscO6qBxvjxHIFxssphCjvCg=; b=UsAGnjc9U0VfBsM5u3n8RtAK26ySsirmCBKwfpT8UzYuONujVClNXCci9Q6lMP+jY4 EqzYaSFRcfJg1s29nu+/WVAoZlyBpRqkpK/y4ejJPtA0mv10EWLuhO1y6e58x+QqjCGi pBygw+Wbf1oCtmqv8uhbgiQldCYApvfS0F3bRaN7/fDP27B256n0Oe0504VQ/molTzbW joDCltnagzSeIWLx/dOVwI2OxkI30WzSHoai07YGsyB1WgRTmZsP+Q+H6ykUhIJc30W9 B70GtlXTFomHdXIGJN5ip7/gYmPG2rouil2lg40f6bLJr1ZYVb4oXzBr+CeJq0/bkp+j Dmjw== X-Gm-Message-State: AOJu0YwJDeiVhGpt+Nd+AXsiKTJGZZ22mXN4to04KTQrzLMZQlYE5I8E vL2MrUqfFfCVbYpna69/w4HOjw== X-Google-Smtp-Source: AGHT+IE/zFjgWpr3Fjg0/QKqKph2H7AWdDaXOYhwMDZ9F8iwOwysiXkltXPK72tj57TCD4LLeaUqFw== X-Received: by 2002:a17:902:f54f:b0:1bd:f1ae:309d with SMTP id h15-20020a170902f54f00b001bdf1ae309dmr26684441plf.9.1693287134418; Mon, 28 Aug 2023 22:32:14 -0700 (PDT) Received: from datalore.c.googlers.com.com (148.175.199.104.bc.googleusercontent.com. [104.199.175.148]) by smtp.gmail.com with ESMTPSA id g6-20020a170902c38600b001bdccf6b8c9sm8420874plg.127.2023.08.28.22.32.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Aug 2023 22:32:14 -0700 (PDT) From: Brandon Pollack To: marius.vlad@collabora.com, mairacanal@riseup.net, jshargo@chromium.org Cc: corbet@lwn.net, dri-devel@lists.freedesktop.org, hamohammed.sa@gmail.com, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, melissa.srw@gmail.com, mripard@kernel.org, rodrigosiqueiramelo@gmail.com, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mduggan@chromium.org, hirono@chromium.org, Brandon Pollack Subject: [PATCH v6 2/7] drm/vkms: Support multiple DRM objects (crtcs, etc.) per VKMS device Date: Tue, 29 Aug 2023 05:30:54 +0000 Message-ID: <20230829053201.423261-3-brpol@chromium.org> X-Mailer: git-send-email 2.42.0.rc2.253.gd59a3bf2b4-goog In-Reply-To: <20230829053201.423261-1-brpol@chromium.org> References: <20230829053201.423261-1-brpol@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Jim Shargo This change supports multiple CRTCs, encoders, connectors instead of one of each per device. Since ConfigFS-based devices will support multiple crtcs, it's useful to move all of the writeback/composition data from being per-"output" to being per-CRTC. Since there's still only ever one CRTC, this should be a no-op refactor. Signed-off-by: Jim Shargo Signed-off-by: Brandon Pollack --- drivers/gpu/drm/vkms/vkms_composer.c | 30 +++---- drivers/gpu/drm/vkms/vkms_crtc.c | 100 ++++++++++++--------- drivers/gpu/drm/vkms/vkms_drv.c | 12 +-- drivers/gpu/drm/vkms/vkms_drv.h | 70 +++++++++------ drivers/gpu/drm/vkms/vkms_output.c | 122 ++++++++++++++++++-------- drivers/gpu/drm/vkms/vkms_plane.c | 38 ++++++-- drivers/gpu/drm/vkms/vkms_writeback.c | 42 ++++----- 7 files changed, 261 insertions(+), 153 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vk= ms_composer.c index d5d4f642d367..a59eb75a21c4 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -300,13 +300,13 @@ void vkms_composer_worker(struct work_struct *work) composer_work); struct drm_crtc *crtc =3D crtc_state->base.crtc; struct vkms_writeback_job *active_wb =3D crtc_state->active_writeback; - struct vkms_output *out =3D drm_crtc_to_vkms_output(crtc); + struct vkms_crtc *vkms_crtc =3D drm_crtc_to_vkms_crtc(crtc); bool crc_pending, wb_pending; u64 frame_start, frame_end; u32 crc32 =3D 0; int ret; =20 - spin_lock_irq(&out->composer_lock); + spin_lock_irq(&vkms_crtc->composer_lock); frame_start =3D crtc_state->frame_start; frame_end =3D crtc_state->frame_end; crc_pending =3D crtc_state->crc_pending; @@ -330,7 +330,7 @@ void vkms_composer_worker(struct work_struct *work) crtc_state->gamma_lut.base =3D NULL; } =20 - spin_unlock_irq(&out->composer_lock); + spin_unlock_irq(&vkms_crtc->composer_lock); =20 /* * We raced with the vblank hrtimer and previous work already computed @@ -348,10 +348,10 @@ void vkms_composer_worker(struct work_struct *work) return; =20 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 =3D false; - spin_unlock_irq(&out->composer_lock); + spin_unlock_irq(&vkms_crtc->composer_lock); } =20 /* @@ -401,30 +401,30 @@ int vkms_verify_crc_source(struct drm_crtc *crtc, con= st char *src_name, return 0; } =20 -void vkms_set_composer(struct vkms_output *out, bool enabled) +void vkms_set_composer(struct vkms_crtc *vkms_crtc, bool enabled) { bool old_enabled; =20 if (enabled) - drm_crtc_vblank_get(&out->crtc); + drm_crtc_vblank_get(&vkms_crtc->base); =20 - mutex_lock(&out->enabled_lock); - old_enabled =3D out->composer_enabled; - out->composer_enabled =3D enabled; + mutex_lock(&vkms_crtc->enabled_lock); + old_enabled =3D vkms_crtc->composer_enabled; + vkms_crtc->composer_enabled =3D enabled; =20 /* the composition wasn't enabled, so unlock the lock to make sure the lo= ck * will be balanced even if we have a failed commit */ - if (!out->composer_enabled) - mutex_unlock(&out->enabled_lock); + if (!vkms_crtc->composer_enabled) + mutex_unlock(&vkms_crtc->enabled_lock); =20 if (old_enabled) - drm_crtc_vblank_put(&out->crtc); + drm_crtc_vblank_put(&vkms_crtc->base); } =20 int vkms_set_crc_source(struct drm_crtc *crtc, const char *src_name) { - struct vkms_output *out =3D drm_crtc_to_vkms_output(crtc); + struct vkms_crtc *out =3D drm_crtc_to_vkms_crtc(crtc); bool enabled =3D false; int ret =3D 0; =20 diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_c= rtc.c index 3c5ebf106b66..74bbd675464b 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ =20 +#include "linux/mutex.h" #include =20 #include @@ -11,17 +12,16 @@ =20 static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) { - struct vkms_output *output =3D container_of(timer, struct vkms_output, - vblank_hrtimer); - struct drm_crtc *crtc =3D &output->crtc; + struct vkms_crtc *vkms_crtc =3D timer_to_vkms_crtc(timer); + struct drm_crtc *crtc =3D &vkms_crtc->base; struct vkms_crtc_state *state; u64 ret_overrun; bool ret, fence_cookie, composer_enabled; =20 fence_cookie =3D dma_fence_begin_signalling(); =20 - ret_overrun =3D hrtimer_forward_now(&output->vblank_hrtimer, - output->period_ns); + ret_overrun =3D hrtimer_forward_now(&vkms_crtc->vblank_hrtimer, + vkms_crtc->period_ns); if (ret_overrun !=3D 1) pr_warn("%s: vblank timer overrun\n", __func__); =20 @@ -29,9 +29,9 @@ static enum hrtimer_restart vkms_vblank_simulate(struct h= rtimer *timer) if (!ret) DRM_ERROR("vkms failure on handling vblank"); =20 - state =3D output->composer_state; - composer_enabled =3D output->composer_enabled; - mutex_unlock(&output->enabled_lock); + state =3D vkms_crtc->composer_state; + composer_enabled =3D vkms_crtc->composer_enabled; + mutex_unlock(&vkms_crtc->enabled_lock); =20 if (state && composer_enabled) { u64 frame =3D drm_crtc_accurate_vblank_count(crtc); @@ -39,7 +39,7 @@ static enum hrtimer_restart vkms_vblank_simulate(struct h= rtimer *timer) /* 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 =3D frame; else @@ -47,9 +47,10 @@ static enum hrtimer_restart vkms_vblank_simulate(struct = hrtimer *timer) state->frame_start, frame); state->frame_end =3D frame; state->crc_pending =3D true; - spin_unlock(&output->composer_lock); + spin_unlock(&vkms_crtc->composer_lock); =20 - ret =3D queue_work(output->composer_workq, &state->composer_work); + ret =3D queue_work(vkms_crtc->composer_workq, + &state->composer_work); if (!ret) DRM_DEBUG_DRIVER("Composer worker already queued\n"); } @@ -62,25 +63,27 @@ static enum hrtimer_restart vkms_vblank_simulate(struct= hrtimer *timer) static int vkms_enable_vblank(struct drm_crtc *crtc) { struct drm_device *dev =3D crtc->dev; + struct vkms_crtc *vkms_crtc =3D drm_crtc_to_vkms_crtc(crtc); unsigned int pipe =3D drm_crtc_index(crtc); struct drm_vblank_crtc *vblank =3D &dev->vblank[pipe]; - struct vkms_output *out =3D drm_crtc_to_vkms_output(crtc); =20 drm_calc_timestamping_constants(crtc, &crtc->mode); =20 - hrtimer_init(&out->vblank_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - out->vblank_hrtimer.function =3D &vkms_vblank_simulate; - out->period_ns =3D 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 =3D &vkms_vblank_simulate; + vkms_crtc->period_ns =3D ktime_set(0, vblank->framedur_ns); + hrtimer_start(&vkms_crtc->vblank_hrtimer, vkms_crtc->period_ns, + HRTIMER_MODE_REL); =20 return 0; } =20 static void vkms_disable_vblank(struct drm_crtc *crtc) { - struct vkms_output *out =3D drm_crtc_to_vkms_output(crtc); + struct vkms_crtc *vkms_crtc =3D drm_crtc_to_vkms_crtc(crtc); =20 - hrtimer_cancel(&out->vblank_hrtimer); + hrtimer_cancel(&vkms_crtc->vblank_hrtimer); } =20 static bool vkms_get_vblank_timestamp(struct drm_crtc *crtc, @@ -88,9 +91,8 @@ static bool vkms_get_vblank_timestamp(struct drm_crtc *cr= tc, bool in_vblank_irq) { struct drm_device *dev =3D crtc->dev; + struct vkms_crtc *vkms_crtc =3D drm_crtc_to_vkms_crtc(crtc); unsigned int pipe =3D crtc->index; - struct vkms_device *vkmsdev =3D drm_device_to_vkms_device(dev); - struct vkms_output *output =3D &vkmsdev->output; struct drm_vblank_crtc *vblank =3D &dev->vblank[pipe]; =20 if (!READ_ONCE(vblank->enabled)) { @@ -98,7 +100,7 @@ static bool vkms_get_vblank_timestamp(struct drm_crtc *c= rtc, return true; } =20 - *vblank_time =3D READ_ONCE(output->vblank_hrtimer.node.expires); + *vblank_time =3D READ_ONCE(vkms_crtc->vblank_hrtimer.node.expires); =20 if (WARN_ON(*vblank_time =3D=3D vblank->time)) return true; @@ -110,7 +112,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 -=3D output->period_ns; + *vblank_time -=3D vkms_crtc->period_ns; =20 return true; } @@ -236,18 +238,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 =3D drm_crtc_to_vkms_output(crtc); + struct vkms_crtc *vkms_crtc =3D drm_crtc_to_vkms_crtc(crtc); =20 /* 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); } =20 static void vkms_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_state *state) { - struct vkms_output *vkms_output =3D drm_crtc_to_vkms_output(crtc); + struct vkms_crtc *vkms_crtc =3D drm_crtc_to_vkms_crtc(crtc); =20 if (crtc->state->event) { spin_lock(&crtc->dev->event_lock); @@ -262,9 +264,9 @@ static void vkms_crtc_atomic_flush(struct drm_crtc *crt= c, crtc->state->event =3D NULL; } =20 - vkms_output->composer_state =3D to_vkms_crtc_state(crtc->state); + vkms_crtc->composer_state =3D to_vkms_crtc_state(crtc->state); =20 - spin_unlock_irq(&vkms_output->lock); + spin_unlock_irq(&vkms_crtc->lock); } =20 static const struct drm_crtc_helper_funcs vkms_crtc_helper_funcs =3D { @@ -275,31 +277,45 @@ static const struct drm_crtc_helper_funcs vkms_crtc_h= elper_funcs =3D { .atomic_disable =3D vkms_crtc_atomic_disable, }; =20 -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 vkms_device *vkmsdev, + struct drm_plane *primary, + struct drm_plane *cursor) { - struct vkms_output *vkms_out =3D drm_crtc_to_vkms_output(crtc); + struct drm_device *dev =3D &vkmsdev->drm; + struct vkms_crtc *vkms_crtc; int ret; =20 - ret =3D drmm_crtc_init_with_planes(dev, crtc, primary, cursor, + if (vkmsdev->output.num_crtcs >=3D VKMS_MAX_OUTPUT_OBJECTS) + return ERR_PTR(-ENOMEM); + + vkms_crtc =3D &vkmsdev->output.crtcs[vkmsdev->output.num_crtcs++]; + + ret =3D drmm_crtc_init_with_planes(dev, &vkms_crtc->base, primary, cursor, &vkms_crtc_funcs, NULL); if (ret) { DRM_ERROR("Failed to init CRTC\n"); - return ret; + goto out_error; } =20 - drm_crtc_helper_add(crtc, &vkms_crtc_helper_funcs); + drm_crtc_helper_add(&vkms_crtc->base, &vkms_crtc_helper_funcs); =20 - drm_mode_crtc_set_gamma_size(crtc, VKMS_LUT_SIZE); - drm_crtc_enable_color_mgmt(crtc, 0, false, VKMS_LUT_SIZE); + drm_mode_crtc_set_gamma_size(&vkms_crtc->base, VKMS_LUT_SIZE); + drm_crtc_enable_color_mgmt(&vkms_crtc->base, 0, false, VKMS_LUT_SIZE); =20 - spin_lock_init(&vkms_out->lock); - spin_lock_init(&vkms_out->composer_lock); - mutex_init(&vkms_out->enabled_lock); + spin_lock_init(&vkms_crtc->lock); + spin_lock_init(&vkms_crtc->composer_lock); + mutex_init(&vkms_crtc->enabled_lock); =20 - vkms_out->composer_workq =3D alloc_ordered_workqueue("vkms_composer", 0); - if (!vkms_out->composer_workq) - return -ENOMEM; + vkms_crtc->composer_workq =3D alloc_ordered_workqueue("vkms_composer", 0); + if (!vkms_crtc->composer_workq) { + ret =3D -ENOMEM; + goto out_error; + } + + return vkms_crtc; =20 - return ret; +out_error: + memset(vkms_crtc, 0, sizeof(*vkms_crtc)); + vkmsdev->output.num_crtcs -=3D 1; + return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_dr= v.c index 387c832f5dc9..65b1e2c52106 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -57,8 +57,8 @@ static void vkms_release(struct drm_device *dev) { struct vkms_device *vkms =3D drm_device_to_vkms_device(dev); =20 - if (vkms->output.composer_workq) - destroy_workqueue(vkms->output.composer_workq); + for (int i =3D 0; i < vkms->output.num_crtcs; i++) + destroy_workqueue(vkms->output.crtcs[i].composer_workq); } =20 static void vkms_atomic_commit_tail(struct drm_atomic_state *old_state) @@ -203,15 +203,15 @@ static int vkms_platform_probe(struct platform_device= *pdev) goto out_release_group; } =20 - ret =3D drm_vblank_init(&vkms_device->drm, 1); + ret =3D vkms_modeset_init(vkms_device); if (ret) { - DRM_ERROR("Failed to vblank\n"); + DRM_ERROR("Unable to initialize modesetting\n"); goto out_release_group; } =20 - ret =3D vkms_modeset_init(vkms_device); + ret =3D drm_vblank_init(&vkms_device->drm, vkms_device->output.num_crtcs); if (ret) { - DRM_ERROR("Unable to initialize modesetting\n"); + DRM_ERROR("Failed to vblank\n"); goto out_release_group; } =20 diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_dr= v.h index 4c35d6305f2a..761cd809617e 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -23,6 +23,10 @@ =20 #define NUM_OVERLAY_PLANES 8 =20 + +#define VKMS_MAX_OUTPUT_OBJECTS 16 +#define VKMS_MAX_PLANES (3 * VKMS_MAX_OUTPUT_OBJECTS) + #define VKMS_LUT_SIZE 256 =20 struct vkms_frame_info { @@ -66,6 +70,27 @@ struct vkms_plane { struct drm_plane base; }; =20 +struct vkms_crtc { + struct drm_crtc base; + + struct drm_writeback_connector wb_connector; + struct hrtimer vblank_hrtimer; + ktime_t period_ns; + struct drm_pending_vblank_event *event; + /* ordered wq for composer_work */ + struct workqueue_struct *composer_workq; + /* protects concurrent access to composer */ + spinlock_t lock; + /* guarantees that if the composer is enabled, a job will be queued */ + struct mutex enabled_lock; + + /* protected by @enabled_lock */ + bool composer_enabled; + struct vkms_crtc_state *composer_state; + + spinlock_t composer_lock; +}; + struct vkms_color_lut { struct drm_color_lut *base; size_t lut_length; @@ -97,25 +122,14 @@ struct vkms_crtc_state { }; =20 struct vkms_output { - struct drm_crtc crtc; - struct drm_encoder encoder; - struct drm_connector connector; - struct drm_writeback_connector wb_connector; - struct hrtimer vblank_hrtimer; - ktime_t period_ns; - struct drm_pending_vblank_event *event; - /* ordered wq for composer_work */ - struct workqueue_struct *composer_workq; - /* protects concurrent access to composer */ - spinlock_t lock; - /* guarantees that if the composer is enabled, a job will be queued */ - struct mutex enabled_lock; - - /* protected by @enabled_lock */ - bool composer_enabled; - struct vkms_crtc_state *composer_state; - - spinlock_t composer_lock; + int num_crtcs; + struct vkms_crtc crtcs[VKMS_MAX_OUTPUT_OBJECTS]; + int num_encoders; + struct drm_encoder encoders[VKMS_MAX_OUTPUT_OBJECTS]; + int num_connectors; + struct drm_connector connectors[VKMS_MAX_OUTPUT_OBJECTS]; + int num_planes; + struct vkms_plane planes[VKMS_MAX_PLANES]; }; =20 struct vkms_device; @@ -133,12 +147,14 @@ struct vkms_device { struct vkms_config config; }; =20 -#define drm_crtc_to_vkms_output(target) \ - container_of(target, struct vkms_output, crtc) +#define drm_crtc_to_vkms_crtc(crtc) container_of(crtc, struct vkms_crtc, b= ase) =20 #define drm_device_to_vkms_device(target) \ container_of(target, struct vkms_device, drm) =20 +#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) =20 @@ -146,13 +162,14 @@ struct vkms_device { container_of(target, struct vkms_plane_state, base.base) =20 /* 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 vkms_device *vkmsdev, + struct drm_plane *primary, + struct drm_plane *cursor); =20 int vkms_output_init(struct vkms_device *vkmsdev, int index); =20 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, - enum drm_plane_type type, int index); + enum drm_plane_type type); =20 /* CRC Support */ const char *const *vkms_get_crc_sources(struct drm_crtc *crtc, @@ -163,11 +180,12 @@ int vkms_verify_crc_source(struct drm_crtc *crtc, con= st char *source_name, =20 /* 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_b= uffer *src_buffer, int y); =20 /* Writeback */ -int vkms_enable_writeback_connector(struct vkms_device *vkmsdev); +int vkms_enable_writeback_connector(struct vkms_device *vkmsdev, + struct vkms_crtc *vkms_crtc); =20 #endif /* _VKMS_DRV_H_ */ diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms= _output.c index 963a64cf068b..86faf94f7408 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -1,9 +1,13 @@ // SPDX-License-Identifier: GPL-2.0+ =20 -#include "vkms_drv.h" #include +#include #include +#include #include +#include + +#include "vkms_drv.h" =20 static const struct drm_connector_funcs vkms_connector_funcs =3D { .fill_modes =3D drm_helper_probe_single_connector_modes, @@ -28,74 +32,116 @@ static int vkms_conn_get_modes(struct drm_connector *c= onnector) } =20 static const struct drm_connector_helper_funcs vkms_conn_helper_funcs =3D { - .get_modes =3D vkms_conn_get_modes, + .get_modes =3D vkms_conn_get_modes, }; =20 -static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index, - struct drm_crtc *crtc) +static struct drm_connector * +vkms_connector_init(struct vkms_device *vkms_device) { - struct vkms_plane *overlay; + struct drm_connector *connector; + int ret; =20 - overlay =3D vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, index); - if (IS_ERR(overlay)) - return PTR_ERR(overlay); + if (vkms_device->output.num_connectors >=3D VKMS_MAX_OUTPUT_OBJECTS) + return ERR_PTR(-ENOMEM); =20 - if (!overlay->base.possible_crtcs) - overlay->base.possible_crtcs =3D drm_crtc_mask(crtc); + connector =3D &vkms_device->output + .connectors[vkms_device->output.num_connectors++]; + ret =3D drm_connector_init(&vkms_device->drm, connector, + &vkms_connector_funcs, + DRM_MODE_CONNECTOR_VIRTUAL); + if (ret) { + memset(connector, 0, sizeof(*connector)); + vkms_device->output.num_connectors -=3D 1; + return ERR_PTR(ret); + } =20 - return 0; + drm_connector_helper_add(connector, &vkms_conn_helper_funcs); + + return connector; +} + +static struct drm_encoder *vkms_encoder_init(struct vkms_device *vkms_devi= ce) +{ + struct drm_encoder *encoder; + int ret; + + if (vkms_device->output.num_encoders >=3D VKMS_MAX_OUTPUT_OBJECTS) + return ERR_PTR(-ENOMEM); + + encoder =3D &vkms_device->output + .encoders[vkms_device->output.num_encoders++]; + ret =3D drm_encoder_init(&vkms_device->drm, encoder, &vkms_encoder_funcs, + DRM_MODE_ENCODER_VIRTUAL, NULL); + if (ret) { + memset(encoder, 0, sizeof(*encoder)); + vkms_device->output.num_encoders -=3D 1; + return ERR_PTR(ret); + } + return encoder; } =20 int vkms_output_init(struct vkms_device *vkmsdev, int index) { struct vkms_output *output =3D &vkmsdev->output; struct drm_device *dev =3D &vkmsdev->drm; - struct drm_connector *connector =3D &output->connector; - struct drm_encoder *encoder =3D &output->encoder; - struct drm_crtc *crtc =3D &output->crtc; + struct drm_connector *connector; + struct drm_encoder *encoder; + struct vkms_crtc *vkms_crtc; struct vkms_plane *primary, *cursor =3D NULL; int ret; int writeback; unsigned int n; =20 - primary =3D vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY, index); + primary =3D vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY); if (IS_ERR(primary)) return PTR_ERR(primary); =20 if (vkmsdev->config.overlay) { for (n =3D 0; n < NUM_OVERLAY_PLANES; n++) { - ret =3D vkms_add_overlay_plane(vkmsdev, index, crtc); - if (ret) - return ret; + struct vkms_plane *overlay =3D vkms_plane_init( + vkmsdev, DRM_PLANE_TYPE_OVERLAY); + if (IS_ERR(overlay)) { + ret =3D PTR_ERR(overlay); + goto err_planes; + } } } =20 if (vkmsdev->config.cursor) { - cursor =3D vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR, index); - if (IS_ERR(cursor)) - return PTR_ERR(cursor); + cursor =3D vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR); + if (IS_ERR(cursor)) { + ret =3D PTR_ERR(cursor); + goto err_planes; + } } =20 - ret =3D vkms_crtc_init(dev, crtc, &primary->base, &cursor->base); - if (ret) - return ret; + vkms_crtc =3D vkms_crtc_init(vkmsdev, &primary->base, + cursor ? &cursor->base : NULL); + if (IS_ERR(vkms_crtc)) { + DRM_ERROR("Failed to init crtc\n"); + ret =3D PTR_ERR(vkms_crtc); + goto err_planes; + } =20 - ret =3D drm_connector_init(dev, connector, &vkms_connector_funcs, - DRM_MODE_CONNECTOR_VIRTUAL); - if (ret) { + for (int i =3D 0; i < vkmsdev->output.num_planes; i++) { + vkmsdev->output.planes[i].base.possible_crtcs |=3D + drm_crtc_mask(&vkms_crtc->base); + } + + connector =3D vkms_connector_init(vkmsdev); + if (IS_ERR(connector)) { DRM_ERROR("Failed to init connector\n"); + ret =3D PTR_ERR(connector); goto err_connector; } =20 - drm_connector_helper_add(connector, &vkms_conn_helper_funcs); - - ret =3D drm_encoder_init(dev, encoder, &vkms_encoder_funcs, - DRM_MODE_ENCODER_VIRTUAL, NULL); - if (ret) { + encoder =3D vkms_encoder_init(vkmsdev); + if (IS_ERR(encoder)) { DRM_ERROR("Failed to init encoder\n"); + ret =3D PTR_ERR(encoder); goto err_encoder; } - encoder->possible_crtcs =3D 1; + encoder->possible_crtcs |=3D drm_crtc_mask(&vkms_crtc->base); =20 ret =3D drm_connector_attach_encoder(connector, encoder); if (ret) { @@ -104,7 +150,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int i= ndex) } =20 if (vkmsdev->config.writeback) { - writeback =3D vkms_enable_writeback_connector(vkmsdev); + writeback =3D vkms_enable_writeback_connector(vkmsdev, vkms_crtc); if (writeback) DRM_ERROR("Failed to init writeback connector\n"); } @@ -120,7 +166,13 @@ int vkms_output_init(struct vkms_device *vkmsdev, int = index) drm_connector_cleanup(connector); =20 err_connector: - drm_crtc_cleanup(crtc); + drm_crtc_cleanup(&vkms_crtc->base); + +err_planes: + for (int i =3D 0; i < output->num_planes; i++) + drm_plane_cleanup(&output->planes[i].base); + + memset(output, 0, sizeof(*output)); =20 return ret; } diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_= plane.c index e5c625ab8e3e..950e6c930273 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include =20 #include "vkms_drv.h" #include "vkms_formats.h" @@ -65,6 +67,20 @@ static void vkms_plane_destroy_state(struct drm_plane *p= lane, kfree(vkms_state); } =20 +static void vkms_plane_destroy(struct drm_plane *plane) +{ + struct vkms_plane *vkms_plane =3D + container_of(plane, struct vkms_plane, base); + + if (plane->state) { + vkms_plane_destroy_state(plane, plane->state); + plane->state =3D NULL; + } + + drm_plane_cleanup(plane); + memset(vkms_plane, 0, sizeof(struct vkms_plane)); +} + static void vkms_plane_reset(struct drm_plane *plane) { struct vkms_plane_state *vkms_state; @@ -86,9 +102,10 @@ static void vkms_plane_reset(struct drm_plane *plane) static const struct drm_plane_funcs vkms_plane_funcs =3D { .update_plane =3D drm_atomic_helper_update_plane, .disable_plane =3D drm_atomic_helper_disable_plane, + .destroy =3D vkms_plane_destroy, .reset =3D vkms_plane_reset, .atomic_duplicate_state =3D vkms_plane_duplicate_state, - .atomic_destroy_state =3D vkms_plane_destroy_state, + .atomic_destroy_state =3D vkms_plane_destroy_state, }; =20 static void vkms_plane_atomic_update(struct drm_plane *plane, @@ -198,17 +215,22 @@ static const struct drm_plane_helper_funcs vkms_plane= _helper_funcs =3D { }; =20 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, - enum drm_plane_type type, int index) + enum drm_plane_type type) { struct drm_device *dev =3D &vkmsdev->drm; + struct vkms_output *output =3D &vkmsdev->output; struct vkms_plane *plane; + int ret; =20 - plane =3D drmm_universal_plane_alloc(dev, struct vkms_plane, base, 1 << i= ndex, - &vkms_plane_funcs, - vkms_formats, ARRAY_SIZE(vkms_formats), - NULL, type, NULL); - if (IS_ERR(plane)) - return plane; + if (output->num_planes >=3D VKMS_MAX_PLANES) + return ERR_PTR(-ENOMEM); + + plane =3D &output->planes[output->num_planes++]; + ret =3D drm_universal_plane_init(dev, &plane->base, 0, &vkms_plane_funcs, + vkms_formats, ARRAY_SIZE(vkms_formats), + NULL, type, NULL); + if (ret) + return ERR_PTR(ret); =20 drm_plane_helper_add(&plane->base, &vkms_plane_helper_funcs); =20 diff --git a/drivers/gpu/drm/vkms/vkms_writeback.c b/drivers/gpu/drm/vkms/v= kms_writeback.c index d7e63aa14663..ec147774935e 100644 --- a/drivers/gpu/drm/vkms/vkms_writeback.c +++ b/drivers/gpu/drm/vkms/vkms_writeback.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ =20 #include +#include =20 #include #include @@ -102,7 +103,8 @@ static void vkms_wb_cleanup_job(struct drm_writeback_co= nnector *connector, struct drm_writeback_job *job) { struct vkms_writeback_job *vkmsjob =3D job->priv; - struct vkms_device *vkmsdev; + struct vkms_crtc *vkms_crtc =3D + container_of(connector, struct vkms_crtc, wb_connector); =20 if (!job->fb) return; @@ -111,8 +113,7 @@ static void vkms_wb_cleanup_job(struct drm_writeback_co= nnector *connector, =20 drm_framebuffer_put(vkmsjob->wb_frame_info.fb); =20 - vkmsdev =3D drm_device_to_vkms_device(job->fb->dev); - vkms_set_composer(&vkmsdev->output, false); + vkms_set_composer(vkms_crtc, false); kfree(vkmsjob); } =20 @@ -121,11 +122,10 @@ static void vkms_wb_atomic_commit(struct drm_connecto= r *conn, { struct drm_connector_state *connector_state =3D drm_atomic_get_new_connec= tor_state(state, conn); - struct vkms_device *vkmsdev =3D drm_device_to_vkms_device(conn->dev); - struct vkms_output *output =3D &vkmsdev->output; - struct drm_writeback_connector *wb_conn =3D &output->wb_connector; - struct drm_connector_state *conn_state =3D wb_conn->base.state; - struct vkms_crtc_state *crtc_state =3D output->composer_state; + struct vkms_crtc *vkms_crtc =3D + drm_crtc_to_vkms_crtc(connector_state->crtc); + struct drm_writeback_connector *wb_conn =3D &vkms_crtc->wb_connector; + struct vkms_crtc_state *crtc_state =3D vkms_crtc->composer_state; struct drm_framebuffer *fb =3D connector_state->writeback_job->fb; u16 crtc_height =3D crtc_state->base.crtc->mode.vdisplay; u16 crtc_width =3D crtc_state->base.crtc->mode.hdisplay; @@ -133,18 +133,18 @@ static void vkms_wb_atomic_commit(struct drm_connecto= r *conn, struct vkms_frame_info *wb_frame_info; u32 wb_format =3D fb->format->format; =20 - if (!conn_state) + if (!connector_state) return; =20 - vkms_set_composer(&vkmsdev->output, true); + vkms_set_composer(vkms_crtc, true); =20 - active_wb =3D conn_state->writeback_job->priv; + active_wb =3D connector_state->writeback_job->priv; wb_frame_info =3D &active_wb->wb_frame_info; =20 - spin_lock_irq(&output->composer_lock); + spin_lock_irq(&vkms_crtc->composer_lock); crtc_state->active_writeback =3D active_wb; crtc_state->wb_pending =3D true; - spin_unlock_irq(&output->composer_lock); + spin_unlock_irq(&vkms_crtc->composer_lock); =20 wb_frame_info->offset =3D fb->offsets[0]; wb_frame_info->pitch =3D fb->pitches[0]; @@ -163,16 +163,16 @@ static const struct drm_connector_helper_funcs vkms_w= b_conn_helper_funcs =3D { .atomic_commit =3D vkms_wb_atomic_commit, }; =20 -int vkms_enable_writeback_connector(struct vkms_device *vkmsdev) +int vkms_enable_writeback_connector(struct vkms_device *vkmsdev, + struct vkms_crtc *vkms_crtc) { - struct drm_writeback_connector *wb =3D &vkmsdev->output.wb_connector; + struct drm_writeback_connector *wb =3D &vkms_crtc->wb_connector; =20 drm_connector_helper_add(&wb->base, &vkms_wb_conn_helper_funcs); =20 - return drm_writeback_connector_init(&vkmsdev->drm, wb, - &vkms_wb_connector_funcs, - &vkms_wb_encoder_helper_funcs, - vkms_wb_formats, - ARRAY_SIZE(vkms_wb_formats), - 1); + return drm_writeback_connector_init( + &vkmsdev->drm, wb, &vkms_wb_connector_funcs, + &vkms_wb_encoder_helper_funcs, vkms_wb_formats, + ARRAY_SIZE(vkms_wb_formats), + BIT(drm_crtc_index(&vkms_crtc->base))); } --=20 2.42.0.rc2.253.gd59a3bf2b4-goog From nobody Thu Dec 18 01:35:38 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C706EC83F1F for ; Tue, 29 Aug 2023 05:33:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235819AbjH2Fc4 (ORCPT ); Tue, 29 Aug 2023 01:32:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48248 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235913AbjH2FcW (ORCPT ); Tue, 29 Aug 2023 01:32:22 -0400 Received: from mail-pl1-x632.google.com (mail-pl1-x632.google.com [IPv6:2607:f8b0:4864:20::632]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D71471A3 for ; Mon, 28 Aug 2023 22:32:17 -0700 (PDT) Received: by mail-pl1-x632.google.com with SMTP id d9443c01a7336-1bdca7cc28dso31716765ad.1 for ; Mon, 28 Aug 2023 22:32:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1693287137; x=1693891937; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=krVlbfIJg4Xwe64ktDdSsSaUeBzrUM8Oc2AR2dzOgtQ=; b=NtzyraengkJ4gnTGdaWWFZ8YIH5HtkzCKWcQXqKcf4PkBi8YA2kD2fgx/QOALlwwyt Zb+aD1ihVp+tlVUm1dbRrcAwrlaXtKL0LC6MSguZDimBdVzklOHkPeKfuOoh483etPq7 cDaXCaHniceiiwr/pf+nX7k1O0jQhpcipUCx4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1693287137; x=1693891937; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=krVlbfIJg4Xwe64ktDdSsSaUeBzrUM8Oc2AR2dzOgtQ=; b=iXEuuH37tU2ACF5Tcy7ADaqRNDo7ugAZ41jnt9LSJTzUfpYPDdfajtaFNEdDSXEx9i ugObBVbqbHgye+jhhEKnm3Z8io+CU6jNNQw3tdDKtzm1qQy1lL2okF3c92jVX9DZ0wDr RHoS+kJHBwO3vC7tLE9In1m5wgESTKtCfu+9TVGW7I0waKHMyEw5jNaoVgKy2EfeBBvS 5nrarAM7Gt9fGW5/u0SPVfBkmOpos/Wr35/ow25gD5KaPMQFle0nTN9nzGJljQ8x0qkV alUcVR9bNNqtvW4BPpxAjTOCOq1mvi6lGd67BYuwP/3N9hvUa4ougaduWKWe07vhcWcp bjQg== X-Gm-Message-State: AOJu0YxNIMZ1e68Dw+cN3HvbxtXMd0p08DDuK5t1o3KmZ7pltVSkRpLd Xx0d32TWhytm9DeXB3tsxCxhVg== X-Google-Smtp-Source: AGHT+IHKHMCi7PMPc9vOGopzObPqQopJ8ZLqFWan++E5xZTzjQJG1eTDyyZoQXGEhk29gxK9MlzI1Q== X-Received: by 2002:a17:902:f684:b0:1bf:205e:fe5d with SMTP id l4-20020a170902f68400b001bf205efe5dmr35867745plg.7.1693287137365; Mon, 28 Aug 2023 22:32:17 -0700 (PDT) Received: from datalore.c.googlers.com.com (148.175.199.104.bc.googleusercontent.com. [104.199.175.148]) by smtp.gmail.com with ESMTPSA id g6-20020a170902c38600b001bdccf6b8c9sm8420874plg.127.2023.08.28.22.32.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Aug 2023 22:32:17 -0700 (PDT) From: Brandon Pollack To: marius.vlad@collabora.com, mairacanal@riseup.net, jshargo@chromium.org Cc: corbet@lwn.net, dri-devel@lists.freedesktop.org, hamohammed.sa@gmail.com, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, melissa.srw@gmail.com, mripard@kernel.org, rodrigosiqueiramelo@gmail.com, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mduggan@chromium.org, hirono@chromium.org, Brandon Pollack Subject: [PATCH v6 3/7] drm/vkms: Provide platform data when creating VKMS devices Date: Tue, 29 Aug 2023 05:30:55 +0000 Message-ID: <20230829053201.423261-4-brpol@chromium.org> X-Mailer: git-send-email 2.42.0.rc2.253.gd59a3bf2b4-goog In-Reply-To: <20230829053201.423261-1-brpol@chromium.org> References: <20230829053201.423261-1-brpol@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Jim Shargo This is a small refactor to make ConfigFS support easier. This should be a no-op refactor. Signed-off-by: Jim Shargo Signed-off-by: Brandon Pollack --- drivers/gpu/drm/vkms/vkms_drv.c | 14 ++++++++++++-- drivers/gpu/drm/vkms/vkms_drv.h | 9 ++++++--- drivers/gpu/drm/vkms/vkms_output.c | 2 +- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_dr= v.c index 65b1e2c52106..6c94c2b5d529 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -9,6 +9,7 @@ * the GPU in DRM API tests. */ =20 +#include "asm-generic/errno-base.h" #include #include #include @@ -171,12 +172,14 @@ static int vkms_modeset_init(struct vkms_device *vkms= dev) dev->mode_config.preferred_depth =3D 0; dev->mode_config.helper_private =3D &vkms_mode_config_helpers; =20 - return vkms_output_init(vkmsdev, 0); + return vkmsdev->is_default ? vkms_output_init_default(vkmsdev) : + -EINVAL; } =20 static int vkms_platform_probe(struct platform_device *pdev) { int ret; + struct vkms_device_setup *vkms_device_setup =3D pdev->dev.platform_data; struct vkms_device *vkms_device; void *grp; =20 @@ -195,6 +198,7 @@ static int vkms_platform_probe(struct platform_device *= pdev) vkms_device->config.cursor =3D enable_cursor; vkms_device->config.writeback =3D enable_writeback; vkms_device->config.overlay =3D enable_overlay; + vkms_device->is_default =3D vkms_device_setup->is_default; =20 ret =3D dma_coerce_mask_and_coherent(vkms_device->drm.dev, DMA_BIT_MASK(64)); @@ -258,6 +262,9 @@ static int __init vkms_init(void) { int ret; struct platform_device *pdev; + struct vkms_device_setup vkms_device_setup =3D { + .is_default =3D true, + }; =20 ret =3D platform_driver_register(&vkms_platform_driver); if (ret) { @@ -265,8 +272,11 @@ static int __init vkms_init(void) return ret; } =20 - pdev =3D platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); + pdev =3D platform_device_register_data(NULL, DRIVER_NAME, 0, + &vkms_device_setup, + sizeof(vkms_device_setup)); if (IS_ERR(pdev)) { + DRM_ERROR("Unable to register default vkms device\n"); platform_driver_unregister(&vkms_platform_driver); return PTR_ERR(pdev); } diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_dr= v.h index 761cd809617e..4262dcffd7e1 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -132,17 +132,20 @@ struct vkms_output { struct vkms_plane planes[VKMS_MAX_PLANES]; }; =20 -struct vkms_device; - struct vkms_config { bool writeback; bool cursor; bool overlay; }; =20 +struct vkms_device_setup { + bool is_default; +}; + struct vkms_device { struct drm_device drm; struct platform_device *platform; + bool is_default; struct vkms_output output; struct vkms_config config; }; @@ -166,7 +169,7 @@ struct vkms_crtc *vkms_crtc_init(struct vkms_device *vk= msdev, struct drm_plane *primary, struct drm_plane *cursor); =20 -int vkms_output_init(struct vkms_device *vkmsdev, int index); +int vkms_output_init_default(struct vkms_device *vkmsdev); =20 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, enum drm_plane_type type); diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms= _output.c index 86faf94f7408..bfc2e2362c6d 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -80,7 +80,7 @@ static struct drm_encoder *vkms_encoder_init(struct vkms_= device *vkms_device) return encoder; } =20 -int vkms_output_init(struct vkms_device *vkmsdev, int index) +int vkms_output_init_default(struct vkms_device *vkmsdev) { struct vkms_output *output =3D &vkmsdev->output; struct drm_device *dev =3D &vkmsdev->drm; --=20 2.42.0.rc2.253.gd59a3bf2b4-goog From nobody Thu Dec 18 01:35:38 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3FBE2C83F22 for ; Tue, 29 Aug 2023 05:33:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235837AbjH2FdB (ORCPT ); Tue, 29 Aug 2023 01:33:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44388 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235820AbjH2Fcb (ORCPT ); Tue, 29 Aug 2023 01:32:31 -0400 Received: from mail-pl1-x630.google.com (mail-pl1-x630.google.com [IPv6:2607:f8b0:4864:20::630]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 12E551AC for ; Mon, 28 Aug 2023 22:32:21 -0700 (PDT) Received: by mail-pl1-x630.google.com with SMTP id d9443c01a7336-1bf1935f6c2so26501865ad.1 for ; Mon, 28 Aug 2023 22:32:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1693287140; x=1693891940; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=CPmTDH1Y+Da1X16cIwdPUZNqsYiHQwY7DBtREuux5BM=; b=EbiYI28RCJj/R04LlfJaKzTj4g4qoxMkbfLFTGJ7ZyEeFd6NpGP/edy6hQmB4rD9Ij RUtSsQWd+r2R/ErY1Kl5jNBtz0SfDWDrtjnMqJd/3VK9uE3k8UslV90p9Z1H++JGcnpm p9IaR/RzuwRFex/2Tu8sd3RLigvft2ZbzuN9Q= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1693287140; x=1693891940; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CPmTDH1Y+Da1X16cIwdPUZNqsYiHQwY7DBtREuux5BM=; b=Aj9LwCEc2mpSXEopsM7Jp8bBMGLZPLzNVy21YqudD29nakEKCIr+t6C2o/H6Q1jhEk DlXfj3vR6vRPzOj5JdClB4TbVtCZREWBpr4OryzTC3wdhww8nuzIrj9M4nwKoFl880QP Jb3JymhdDRuJWwfOiRm49ObkuEHqOFVEubA/D9POwjTGI0oET9X2ACs4PU/fF1/qs0dn ikMkbM0BEYq+Yquyj62Qys5Xbqw7od0+ptIOy8eIiuSPaHINGRN9UAY60nlX7jcDHzEb YYcrf2zjJ93Cqm8AFY3oCXN7VCpZ4YxgwAbkW3ZwmecFSyiArbsQeFWOzFNv3Axedm9y nAiA== X-Gm-Message-State: AOJu0YzbuSHoIaeDGB7rjQPru5E+Gn/1qcY2mqw9SAMp09qVEBnSKo2A EtjtnQTZfwO0H1d8e5DffcZpAQ== X-Google-Smtp-Source: AGHT+IGk7LP44I1BmmyHFcpgV+GqJdKwTvhsXMenG2RKDTl3RsRVhMIfSGWvMJnPh6c4yX3pkdJzPg== X-Received: by 2002:a17:903:11cc:b0:1bc:2fe1:1821 with SMTP id q12-20020a17090311cc00b001bc2fe11821mr2629106plh.17.1693287140436; Mon, 28 Aug 2023 22:32:20 -0700 (PDT) Received: from datalore.c.googlers.com.com (148.175.199.104.bc.googleusercontent.com. [104.199.175.148]) by smtp.gmail.com with ESMTPSA id g6-20020a170902c38600b001bdccf6b8c9sm8420874plg.127.2023.08.28.22.32.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Aug 2023 22:32:20 -0700 (PDT) From: Brandon Pollack To: marius.vlad@collabora.com, mairacanal@riseup.net, jshargo@chromium.org Cc: corbet@lwn.net, dri-devel@lists.freedesktop.org, hamohammed.sa@gmail.com, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, melissa.srw@gmail.com, mripard@kernel.org, rodrigosiqueiramelo@gmail.com, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mduggan@chromium.org, hirono@chromium.org, Brandon Pollack Subject: [PATCH v6 4/7] drm/vkms: Add ConfigFS scaffolding to VKMS Date: Tue, 29 Aug 2023 05:30:56 +0000 Message-ID: <20230829053201.423261-5-brpol@chromium.org> X-Mailer: git-send-email 2.42.0.rc2.253.gd59a3bf2b4-goog In-Reply-To: <20230829053201.423261-1-brpol@chromium.org> References: <20230829053201.423261-1-brpol@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Jim Shargo This change adds the basic scaffolding for ConfigFS, including setting up the default directories. It does not allow for the registration of configfs-backed devices, which is complex and provided in a follow-up commit. This CL includes docs about using ConfigFS with VKMS, but I'll summarize in brief here as well (assuming ConfigFS is mounted at /config/): To create a new device, you can do so via `mkdir /config/vkms/my-device`. This will create a number of directories and files automatically: /config `-- vkms `-- my-device |-- connectors |-- crtcs |-- encoders |-- planes `-- enabled You can then configure objects by mkdir'ing in each of the directories. When you're satisfied, you can `echo 1 > /config/vkms/my-device/enabled`. This will create a new device according to your configuration. For now, this will fail, but the next change will add support for it. Signed-off-by: Jim Shargo Signed-off-by: Brandon Pollack --- Documentation/gpu/vkms.rst | 18 +- drivers/gpu/drm/Kconfig | 1 + drivers/gpu/drm/vkms/Makefile | 1 + drivers/gpu/drm/vkms/vkms_configfs.c | 650 +++++++++++++++++++++++++++ drivers/gpu/drm/vkms/vkms_drv.c | 56 ++- drivers/gpu/drm/vkms/vkms_drv.h | 92 +++- drivers/gpu/drm/vkms/vkms_output.c | 5 + 7 files changed, 806 insertions(+), 17 deletions(-) create mode 100644 drivers/gpu/drm/vkms/vkms_configfs.c diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst index ba04ac7c2167..c3875bf66dba 100644 --- a/Documentation/gpu/vkms.rst +++ b/Documentation/gpu/vkms.rst @@ -51,6 +51,12 @@ To disable the driver, use :: =20 sudo modprobe -r vkms =20 +Configuration With ConfigFS +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + +.. kernel-doc:: drivers/gpu/drm/vkms/vkms_configfs.c + :doc: ConfigFS Support for VKMS + Testing With IGT =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 @@ -135,22 +141,16 @@ project. Runtime Configuration --------------------- =20 -We want to be able to reconfigure vkms instance without having to reload t= he -module. Use/Test-cases: +We want to be able to manipulate vkms instances without having to reload t= he +module. Such configuration can be added as extensions to vkms's ConfigFS +support. Use-cases: =20 - Hotplug/hotremove connectors on the fly (to be able to test DP MST handl= ing of compositors). =20 -- Configure planes/crtcs/connectors (we'd need some code to have more than= 1 of - them first). - - Change output configuration: Plug/unplug screens, change EDID, allow cha= nging the refresh rate. =20 -The currently proposed solution is to expose vkms configuration through -configfs. All existing module options should be supported through configfs -too. - Writeback support ----------------- =20 diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index ab9ef1c20349..e39ee0e8ca06 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -284,6 +284,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 diff --git a/drivers/gpu/drm/vkms/Makefile b/drivers/gpu/drm/vkms/Makefile index 1b28a6a32948..6b83907ad554 100644 --- a/drivers/gpu/drm/vkms/Makefile +++ b/drivers/gpu/drm/vkms/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only vkms-y :=3D \ + vkms_configfs.o \ vkms_drv.o \ vkms_plane.o \ vkms_output.o \ diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vk= ms_configfs.c new file mode 100644 index 000000000000..dae2e85d83a1 --- /dev/null +++ b/drivers/gpu/drm/vkms/vkms_configfs.c @@ -0,0 +1,650 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include + +#include +#include + +#include "vkms_drv.h" + +/** + * DOC: ConfigFS Support for VKMS + * + * VKMS is instrumented with support for configuration via :doc:`ConfigFS + * <../filesystems/configfs>`. + * + * With VKMS installed, you can mount ConfigFS at ``/config/`` like so:: + * + * mkdir -p /config/ + * sudo mount -t configfs none /config + * + * This allows you to configure multiple virtual devices. Note + * that the default device which can be enabled in the module params with:: + * + * modprobe vkms default_device=3D1 + * + * is immutable because we cannot pre-populate ConfigFS directories with n= ormal + * files. + * + * To set up a new device, create a new directory under the VKMS configfs + * directory:: + * + * mkdir /config/vkms/test + * + * With your device created you'll find an new directory ready to be + * configured:: + * + * /config + * `-- vkms + * `-- test + * |-- connectors + * |-- crtcs + * |-- encoders + * |-- planes + * `-- enabled + * + * Each directory you add within the connectors, crtcs, encoders, and plan= es + * directories will let you configure a new object of that type. Adding new + * objects will automatically create a set of default files and folders yo= u can + * use to configure that object. + * + * For instance, we can set up a two-output device like so:: + * + * DRM_PLANE_TYPE_PRIMARY=3D1 + * DRM_PLANE_TYPE_CURSOR=3D2 + * DRM_PLANE_TYPE_OVERLAY=3D0 + * + * mkdir /config/vkms/test/planes/primary + * echo $DRM_PLANE_TYPE_PRIMARY > /config/vkms/test/planes/primary/type + * + * mkdir /config/vkms/test/planes/other_primary + * echo $DRM_PLANE_TYPE_PRIMARY > /config/vkms/test/planes/other_primary= /type + * + * mkdir /config/vkms/test/crtcs/crtc + * mkdir /config/vkms/test/crtcs/crtc_other + * + * mkdir /config/vkms/test/encoders/encoder + * mkdir /config/vkms/test/encoders/encoder_other + * + * mkdir /config/vkms/test/connectors/connector + * mkdir /config/vkms/test/connectors/connector_other + * + * You can see that specific attributes, such as ``...//type``, can= be + * configured by writing into them. Associating objects together can be do= ne via + * symlinks:: + * + * ln -s /config/vkms/test/encoders/encoder /config/vkms/test/conn= ectors/connector/possible_encoders + * ln -s /config/vkms/test/encoders/encoder_other /config/vkms/test/conn= ectors/connector_other/possible_encoders + * + * ln -s /config/vkms/test/crtcs/crtc /config/vkms/test/plan= es/primary/possible_crtcs/ + * ln -s /config/vkms/test/crtcs/crtc_other /config/vkms/test/plan= es/other_primary/possible_crtcs/ + * + * ln -s /config/vkms/test/crtcs/crtc /config/vkms/test/enco= ders/encoder/possible_crtcs/ + * ln -s /config/vkms/test/crtcs/crtc_other /config/vkms/test/enco= ders/encoder_other/possible_crtcs/ + * + * Finally, to enable your configured device, just write 1 to the ``enable= d`` + * file:: + * + * echo 1 > /config/vkms/test/enabled + * + * When you're done with the virtual device, you can clean up the device l= ike + * so:: + * + * echo 0 > /config/vkms/test/enabled + * + * rm /config/vkms/test/connectors/connector/possible_encoders/encoder + * rm /config/vkms/test/encoders/encoder/possible_crtcs/crtc + * rm /config/vkms/test/planes/primary/possible_crtcs/crtc + * rm /config/vkms/test/planes/cursor/possible_crtcs/crtc + * rm /config/vkms/test/planes/overlay/possible_crtcs/crtc + * rm /config/vkms/test/planes/overlay/possible_crtcs/crtc_other + * rm /config/vkms/test/planes/other_primary/possible_crtcs/crtc_other + * + * rmdir /config/vkms/test/planes/primary + * rmdir /config/vkms/test/planes/other_primary + * rmdir /config/vkms/test/planes/cursor + * rmdir /config/vkms/test/planes/overlay + * rmdir /config/vkms/test/crtcs/crtc + * rmdir /config/vkms/test/crtcs/crtc_other + * rmdir /config/vkms/test/encoders/encoder + * rmdir /config/vkms/test/encoders/encoder_other + * rmdir /config/vkms/test/connectors/connector + * rmdir /config/vkms/test/connectors/connector_other + * + * rmdir /config/vkms/test + */ + +/* + * Common helpers (i.e. common sub-groups) + */ + +/* Possible CRTCs, e.g. /config/vkms/device//possible_crtcs/ */ + +static struct config_item_type crtc_type; + +static int possible_crtcs_allow_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_config_links *links =3D item_to_config_links(src); + struct vkms_config_crtc *crtc; + + if (target->ci_type !=3D &crtc_type) { + DRM_ERROR("Unable to link non-CRTCs.\n"); + return -EINVAL; + } + + crtc =3D item_to_config_crtc(target); + + if (links->linked_object_bitmap & BIT(crtc->crtc_config_idx)) { + DRM_ERROR( + "Tried to add two symlinks to the same CRTC from the same object\n"); + return -EINVAL; + } + + links->linked_object_bitmap |=3D BIT(crtc->crtc_config_idx); + + return 0; +} + +static void possible_crtcs_drop_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_config_links *links =3D item_to_config_links(src); + struct vkms_config_crtc *crtc =3D item_to_config_crtc(target); + + links->linked_object_bitmap &=3D ~BIT(crtc->crtc_config_idx); +} + +static struct configfs_item_operations possible_crtcs_item_ops =3D { + .allow_link =3D &possible_crtcs_allow_link, + .drop_link =3D &possible_crtcs_drop_link, +}; + +static struct config_item_type possible_crtcs_group_type =3D { + .ct_item_ops =3D &possible_crtcs_item_ops, + .ct_owner =3D THIS_MODULE, +}; + +static void add_possible_crtcs(struct config_group *parent, + struct config_group *possible_crtcs) +{ + config_group_init_type_name(possible_crtcs, "possible_crtcs", + &possible_crtcs_group_type); + configfs_add_default_group(possible_crtcs, parent); +} + +/* Possible encoders, e.g. /config/vkms/device/connector/possible_encoders= / */ + +static struct config_item_type encoder_type; + +static int possible_encoders_allow_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_config_links *links =3D item_to_config_links(src); + struct vkms_config_encoder *encoder; + + if (target->ci_type !=3D &encoder_type) { + DRM_ERROR("Unable to link non-encoders.\n"); + return -EINVAL; + } + + encoder =3D item_to_config_encoder(target); + + if (links->linked_object_bitmap & BIT(encoder->encoder_config_idx)) { + DRM_ERROR( + "Tried to add two symlinks to the same encoder from the same object\n"); + return -EINVAL; + } + + links->linked_object_bitmap |=3D BIT(encoder->encoder_config_idx); + + return 0; +} + +static void possible_encoders_drop_link(struct config_item *src, + struct config_item *target) +{ + struct vkms_config_links *links =3D item_to_config_links(src); + struct vkms_config_encoder *encoder =3D item_to_config_encoder(target); + + links->linked_object_bitmap &=3D ~BIT(encoder->encoder_config_idx); +} + +static struct configfs_item_operations possible_encoders_item_ops =3D { + .allow_link =3D &possible_encoders_allow_link, + .drop_link =3D &possible_encoders_drop_link, +}; + +static struct config_item_type possible_encoders_group_type =3D { + .ct_item_ops =3D &possible_encoders_item_ops, + .ct_owner =3D THIS_MODULE, +}; + +static void add_possible_encoders(struct config_group *parent, + struct config_group *possible_encoders) +{ + config_group_init_type_name(possible_encoders, "possible_encoders", + &possible_encoders_group_type); + configfs_add_default_group(possible_encoders, parent); +} + +/* + * Individual objects (connectors, crtcs, encoders, planes): + */ + +/* Connector item, e.g. /config/vkms/device/connectors/ID */ + +static struct config_item_type connector_type =3D { + .ct_owner =3D THIS_MODULE, +}; + +/* Crtc item, e.g. /config/vkms/device/crtcs/ID */ + +static struct config_item_type crtc_type =3D { + .ct_owner =3D THIS_MODULE, +}; + +/* Encoder item, e.g. /config/vkms/device/encoder/ID */ + +static struct config_item_type encoder_type =3D { + .ct_owner =3D THIS_MODULE, +}; + +/* Plane item, e.g. /config/vkms/device/planes/ID */ + +static ssize_t plane_type_show(struct config_item *item, char *buf) +{ + struct vkms_config_plane *plane =3D item_to_config_plane(item); + struct vkms_configfs *configfs =3D plane_item_to_configfs(item); + enum drm_plane_type plane_type; + + mutex_lock(&configfs->lock); + plane_type =3D plane->type; + mutex_unlock(&configfs->lock); + + return sprintf(buf, "%u", plane_type); +} + +static ssize_t plane_type_store(struct config_item *item, const char *buf, + size_t len) +{ + struct vkms_config_plane *plane =3D item_to_config_plane(item); + struct vkms_configfs *configfs =3D plane_item_to_configfs(item); + int val, ret; + + ret =3D kstrtouint(buf, 10, &val); + if (ret) + return ret; + + if (val !=3D DRM_PLANE_TYPE_PRIMARY && val !=3D DRM_PLANE_TYPE_CURSOR && + val !=3D DRM_PLANE_TYPE_OVERLAY) + return -EINVAL; + + mutex_lock(&configfs->lock); + plane->type =3D val; + mutex_unlock(&configfs->lock); + + return len; +} + +CONFIGFS_ATTR(plane_, type); + +static struct configfs_attribute *plane_attrs[] =3D { + &plane_attr_type, + NULL, +}; + +static struct config_item_type plane_type =3D { + .ct_attrs =3D plane_attrs, + .ct_owner =3D THIS_MODULE, +}; + +/* + * Directory groups, e.g. /config/vkms/device/{planes, crtcs, ...} + */ + +/* Connectors group: /config/vkms/device/connectors/ */ + +static struct config_group *connectors_group_make(struct config_group *gro= up, + const char *name) +{ + struct vkms_config_connector *connector =3D + kzalloc(sizeof(*connector), GFP_KERNEL); + if (!connector) + return ERR_PTR(-ENOMEM); + + config_group_init_type_name(&connector->config_group, name, + &connector_type); + add_possible_encoders(&connector->config_group, + &connector->possible_encoders.group); + + return &connector->config_group; +} + +static void connectors_group_drop(struct config_group *group, + struct config_item *item) +{ + struct vkms_config_connector *connector =3D + item_to_config_connector(item); + kfree(connector); +} + +static struct configfs_group_operations connectors_group_ops =3D { + .make_group =3D &connectors_group_make, + .drop_item =3D &connectors_group_drop, +}; + +static struct config_item_type connectors_group_type =3D { + .ct_group_ops =3D &connectors_group_ops, + .ct_owner =3D THIS_MODULE, +}; + +/* CRTCs group: /config/vkms/device/crtcs/ */ + +static struct config_group *crtcs_group_make(struct config_group *group, + const char *name) +{ + struct vkms_configfs *configfs =3D + container_of(group, struct vkms_configfs, crtcs_group); + unsigned long next_idx; + struct vkms_config_crtc *crtc; + + mutex_lock(&configfs->lock); + + next_idx =3D find_first_zero_bit(&configfs->allocated_crtcs, + VKMS_MAX_OUTPUT_OBJECTS); + + if (next_idx =3D=3D VKMS_MAX_OUTPUT_OBJECTS) { + DRM_ERROR("Unable to allocate another CRTC.\n"); + mutex_unlock(&configfs->lock); + return ERR_PTR(-ENOMEM); + } + + crtc =3D kzalloc(sizeof(*crtc), GFP_KERNEL); + if (!crtc) { + DRM_ERROR("Unable to allocate CRTC.\n"); + mutex_unlock(&configfs->lock); + return ERR_PTR(-ENOMEM); + } + + config_group_init_type_name(&crtc->config_group, name, &crtc_type); + crtc->crtc_config_idx =3D next_idx; + + set_bit(next_idx, &configfs->allocated_crtcs); + + mutex_unlock(&configfs->lock); + + return &crtc->config_group; +} + +static void crtcs_group_drop(struct config_group *group, + struct config_item *item) +{ + struct vkms_config_crtc *crtc =3D item_to_config_crtc(item); + + kfree(crtc); +} + +static struct configfs_group_operations crtcs_group_ops =3D { + .make_group =3D &crtcs_group_make, + .drop_item =3D &crtcs_group_drop, +}; + +static struct config_item_type crtcs_group_type =3D { + .ct_group_ops =3D &crtcs_group_ops, + .ct_owner =3D THIS_MODULE, +}; + +/* Encoders group: /config/vkms/device/encoders/ */ + +static struct config_group *encoders_group_make(struct config_group *group, + const char *name) +{ + struct vkms_configfs *configfs =3D + container_of(group, struct vkms_configfs, encoders_group); + unsigned long next_idx; + struct vkms_config_encoder *encoder; + + mutex_lock(&configfs->lock); + + next_idx =3D find_first_zero_bit(&configfs->allocated_encoders, + VKMS_MAX_OUTPUT_OBJECTS); + + if (next_idx =3D=3D VKMS_MAX_OUTPUT_OBJECTS) { + DRM_ERROR("Unable to allocate another encoder.\n"); + mutex_unlock(&configfs->lock); + return ERR_PTR(-ENOMEM); + } + + encoder =3D kzalloc(sizeof(*encoder), GFP_KERNEL); + if (!encoder) { + DRM_ERROR("Unable to allocate encoder.\n"); + mutex_unlock(&configfs->lock); + return ERR_PTR(-ENOMEM); + } + + config_group_init_type_name(&encoder->config_group, name, + &encoder_type); + add_possible_crtcs(&encoder->config_group, + &encoder->possible_crtcs.group); + encoder->encoder_config_idx =3D next_idx; + set_bit(next_idx, &configfs->allocated_encoders); + + mutex_unlock(&configfs->lock); + + return &encoder->config_group; +} + +static void encoders_group_drop(struct config_group *group, + struct config_item *item) +{ + struct vkms_config_encoder *encoder =3D item_to_config_encoder(item); + + kfree(encoder); +} + +static struct configfs_group_operations encoders_group_ops =3D { + .make_group =3D &encoders_group_make, + .drop_item =3D &encoders_group_drop, +}; + +static struct config_item_type encoders_group_type =3D { + .ct_group_ops =3D &encoders_group_ops, + .ct_owner =3D THIS_MODULE, +}; + +/* Planes group: /config/vkms/device/planes/ */ + +static struct config_group *make_plane_group(struct config_group *group, + const char *name) +{ + struct vkms_config_plane *plane =3D kzalloc(sizeof(*plane), GFP_KERNEL); + + if (!plane) + return ERR_PTR(-ENOMEM); + + config_group_init_type_name(&plane->config_group, name, &plane_type); + add_possible_crtcs(&plane->config_group, &plane->possible_crtcs.group); + + return &plane->config_group; +} + +static void drop_plane_group(struct config_group *group, + struct config_item *item) +{ + struct vkms_config_plane *plane =3D item_to_config_plane(item); + + kfree(plane); +} + +static struct configfs_group_operations plane_group_ops =3D { + .make_group =3D &make_plane_group, + .drop_item =3D &drop_plane_group, +}; + +static struct config_item_type planes_group_type =3D { + .ct_group_ops =3D &plane_group_ops, + .ct_owner =3D THIS_MODULE, +}; + +/* Root directory group, e.g. /config/vkms/device */ + +static ssize_t device_enabled_show(struct config_item *item, char *buf) +{ + struct vkms_configfs *configfs =3D item_to_configfs(item); + bool is_enabled; + + mutex_lock(&configfs->lock); + is_enabled =3D configfs->vkms_device !=3D NULL; + mutex_unlock(&configfs->lock); + + return sprintf(buf, "%d", is_enabled); +} + +static ssize_t device_enabled_store(struct config_item *item, const char *= buf, + size_t len) +{ + struct vkms_configfs *configfs =3D item_to_configfs(item); + struct vkms_device *device; + int value, ret; + + ret =3D kstrtoint(buf, 0, &value); + if (ret) + return ret; + + if (value !=3D 1) + return -EINVAL; + + mutex_lock(&configfs->lock); + + if (configfs->vkms_device) { + mutex_unlock(&configfs->lock); + return len; + } + + device =3D vkms_add_device(configfs); + mutex_unlock(&configfs->lock); + + if (IS_ERR(device)) + return -PTR_ERR(device); + + return len; +} + +CONFIGFS_ATTR(device_, enabled); + +static ssize_t device_id_show(struct config_item *item, char *buf) +{ + struct vkms_configfs *configfs =3D item_to_configfs(item); + int id =3D -1; + + mutex_lock(&configfs->lock); + if (configfs->vkms_device) + id =3D configfs->vkms_device->platform->id; + + mutex_unlock(&configfs->lock); + + return sprintf(buf, "%d", id); +} + +CONFIGFS_ATTR_RO(device_, id); + +static struct configfs_attribute *device_group_attrs[] =3D { + &device_attr_id, + &device_attr_enabled, + NULL, +}; + +static struct config_item_type device_group_type =3D { + .ct_attrs =3D device_group_attrs, + .ct_owner =3D THIS_MODULE, +}; + +static void vkms_configfs_setup_default_groups(struct vkms_configfs *confi= gfs, + const char *name) +{ + config_group_init_type_name(&configfs->device_group, name, + &device_group_type); + + config_group_init_type_name(&configfs->connectors_group, "connectors", + &connectors_group_type); + configfs_add_default_group(&configfs->connectors_group, + &configfs->device_group); + + config_group_init_type_name(&configfs->crtcs_group, "crtcs", + &crtcs_group_type); + configfs_add_default_group(&configfs->crtcs_group, + &configfs->device_group); + + config_group_init_type_name(&configfs->encoders_group, "encoders", + &encoders_group_type); + configfs_add_default_group(&configfs->encoders_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); +} + +/* Root directory group and subsystem, e.g. /config/vkms/ */ + +static struct config_group *make_root_group(struct config_group *group, + const char *name) +{ + struct vkms_configfs *configfs =3D kzalloc(sizeof(*configfs), GFP_KERNEL); + + if (!configfs) + return ERR_PTR(-ENOMEM); + + vkms_configfs_setup_default_groups(configfs, name); + mutex_init(&configfs->lock); + + return &configfs->device_group; +} + +static void drop_root_group(struct config_group *group, + struct config_item *item) +{ + struct vkms_configfs *configfs =3D item_to_configfs(item); + + mutex_lock(&configfs->lock); + if (configfs->vkms_device) + vkms_remove_device(configfs->vkms_device); + mutex_unlock(&configfs->lock); + + kfree(configfs); +} + +static struct configfs_group_operations root_group_ops =3D { + .make_group =3D &make_root_group, + .drop_item =3D &drop_root_group, +}; + +static struct config_item_type vkms_type =3D { + .ct_group_ops =3D &root_group_ops, + .ct_owner =3D THIS_MODULE, +}; + +static struct configfs_subsystem vkms_subsys =3D { + .su_group =3D { + .cg_item =3D { + .ci_name =3D "vkms", + .ci_type =3D &vkms_type, + }, + }, + .su_mutex =3D __MUTEX_INITIALIZER(vkms_subsys.su_mutex), +}; + +int vkms_init_configfs(void) +{ + config_group_init(&vkms_subsys.su_group); + return configfs_register_subsystem(&vkms_subsys); +} + +void vkms_unregister_configfs(void) +{ + configfs_unregister_subsystem(&vkms_subsys); +} diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_dr= v.c index 6c94c2b5d529..819e880a8cf7 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -9,8 +9,10 @@ * the GPU in DRM API tests. */ =20 -#include "asm-generic/errno-base.h" +#include #include +#include +#include #include #include #include @@ -172,8 +174,8 @@ static int vkms_modeset_init(struct vkms_device *vkmsde= v) dev->mode_config.preferred_depth =3D 0; dev->mode_config.helper_private =3D &vkms_mode_config_helpers; =20 - return vkmsdev->is_default ? vkms_output_init_default(vkmsdev) : - -EINVAL; + return vkmsdev->configfs ? vkms_output_init(vkmsdev) : + vkms_output_init_default(vkmsdev); } =20 static int vkms_platform_probe(struct platform_device *pdev) @@ -184,8 +186,10 @@ static int vkms_platform_probe(struct platform_device = *pdev) void *grp; =20 grp =3D devres_open_group(&pdev->dev, NULL, GFP_KERNEL); - if (!grp) + if (!grp) { + DRM_ERROR("Could not open devres group\n"); return -ENOMEM; + } =20 vkms_device =3D devm_drm_dev_alloc(&pdev->dev, &vkms_driver, struct vkms_device, drm); @@ -198,7 +202,7 @@ static int vkms_platform_probe(struct platform_device *= pdev) vkms_device->config.cursor =3D enable_cursor; vkms_device->config.writeback =3D enable_writeback; vkms_device->config.overlay =3D enable_overlay; - vkms_device->is_default =3D vkms_device_setup->is_default; + vkms_device->configfs =3D vkms_device_setup->configfs; =20 ret =3D dma_coerce_mask_and_coherent(vkms_device->drm.dev, DMA_BIT_MASK(64)); @@ -258,12 +262,43 @@ static struct platform_driver vkms_platform_driver = =3D { .driver.name =3D DRIVER_NAME, }; =20 +struct vkms_device *vkms_add_device(struct vkms_configfs *configfs) +{ + struct device *dev =3D NULL; + struct platform_device *pdev; + int max_id =3D 1; + struct vkms_device_setup vkms_device_setup =3D { + .configfs =3D configfs, + }; + + while ((dev =3D platform_find_device_by_driver( + dev, &vkms_platform_driver.driver))) { + pdev =3D to_platform_device(dev); + max_id =3D max(max_id, pdev->id); + } + + pdev =3D platform_device_register_data(NULL, DRIVER_NAME, max_id + 1, + &vkms_device_setup, + sizeof(vkms_device_setup)); + if (IS_ERR(pdev)) { + DRM_ERROR("Unable to register vkms device'\n"); + return ERR_PTR(PTR_ERR(pdev)); + } + + return platform_get_drvdata(pdev); +} + +void vkms_remove_device(struct vkms_device *vkms_device) +{ + platform_device_unregister(vkms_device->platform); +} + static int __init vkms_init(void) { int ret; struct platform_device *pdev; struct vkms_device_setup vkms_device_setup =3D { - .is_default =3D true, + .configfs =3D NULL, }; =20 ret =3D platform_driver_register(&vkms_platform_driver); @@ -281,6 +316,13 @@ static int __init vkms_init(void) return PTR_ERR(pdev); } =20 + ret =3D vkms_init_configfs(); + if (ret) { + DRM_ERROR("Unable to initialize configfs\n"); + platform_device_unregister(pdev); + platform_driver_unregister(&vkms_platform_driver); + } + return 0; } =20 @@ -288,6 +330,8 @@ static void __exit vkms_exit(void) { struct device *dev; =20 + vkms_unregister_configfs(); + while ((dev =3D platform_find_device_by_driver( NULL, &vkms_platform_driver.driver))) { // platform_find_device_by_driver increments the refcount. Drop diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_dr= v.h index 4262dcffd7e1..8cdd7949f661 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -3,6 +3,7 @@ #ifndef _VKMS_DRV_H_ #define _VKMS_DRV_H_ =20 +#include #include =20 #include @@ -10,6 +11,7 @@ #include #include #include +#include #include =20 #define XRES_MIN 10 @@ -138,14 +140,65 @@ struct vkms_config { bool overlay; }; =20 +struct vkms_config_links { + struct config_group group; + unsigned long linked_object_bitmap; +}; + +struct vkms_config_connector { + struct config_group config_group; + struct vkms_config_links possible_encoders; +}; + +struct vkms_config_crtc { + struct config_group config_group; + unsigned long crtc_config_idx; +}; + +struct vkms_config_encoder { + struct config_group config_group; + struct vkms_config_links possible_crtcs; + unsigned long encoder_config_idx; +}; + +struct vkms_config_plane { + struct vkms_configfs *configfs; + struct config_group config_group; + struct vkms_config_links possible_crtcs; + enum drm_plane_type type; +}; + +struct vkms_configfs { + /* Directory group containing connector configs, e.g. /config/vkms/device= / */ + struct config_group device_group; + /* Directory group containing connector configs, e.g. /config/vkms/device= /connectors/ */ + struct config_group connectors_group; + /* Directory group containing CRTC configs, e.g. /config/vkms/device/crtc= s/ */ + struct config_group crtcs_group; + /* Directory group containing encoder configs, e.g. /config/vkms/device/e= ncoders/ */ + struct config_group encoders_group; + /* Directory group containing plane configs, e.g. /config/vkms/device/pla= nes/ */ + struct config_group planes_group; + + unsigned long allocated_crtcs; + unsigned long allocated_encoders; + + struct mutex lock; + + /* The platform device if this is registered, otherwise NULL */ + struct vkms_device *vkms_device; +}; + struct vkms_device_setup { - bool is_default; + // Is NULL in the case of the default card. + struct vkms_configfs *configfs; }; =20 struct vkms_device { struct drm_device drm; struct platform_device *platform; - bool is_default; + // Is NULL in the case of the default card. + struct vkms_configfs *configfs; struct vkms_output output; struct vkms_config config; }; @@ -164,11 +217,42 @@ struct vkms_device { #define to_vkms_plane_state(target)\ container_of(target, struct vkms_plane_state, base.base) =20 +#define item_to_configfs(item) \ + container_of(to_config_group(item), struct vkms_configfs, device_group) + +#define item_to_config_connector(item) \ + container_of(to_config_group(item), struct vkms_config_connector, \ + config_group) + +#define item_to_config_crtc(item) \ + container_of(to_config_group(item), struct vkms_config_crtc, \ + config_group) + +#define item_to_config_encoder(item) \ + container_of(to_config_group(item), struct vkms_config_encoder, \ + config_group) + +#define item_to_config_plane(item) \ + container_of(to_config_group(item), struct vkms_config_plane, \ + config_group) + +#define item_to_config_links(item) \ + container_of(to_config_group(item), struct vkms_config_links, group) + +#define plane_item_to_configfs(item) = \ + container_of(to_config_group(item->ci_parent), struct vkms_configfs, \ + planes_group) + +/* Devices */ +struct vkms_device *vkms_add_device(struct vkms_configfs *configfs); +void vkms_remove_device(struct vkms_device *vkms_device); + /* CRTC */ struct vkms_crtc *vkms_crtc_init(struct vkms_device *vkmsdev, struct drm_plane *primary, struct drm_plane *cursor); =20 +int vkms_output_init(struct vkms_device *vkmsdev); int vkms_output_init_default(struct vkms_device *vkmsdev); =20 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, @@ -191,4 +275,8 @@ void vkms_writeback_row(struct vkms_writeback_job *wb, = const struct line_buffer int vkms_enable_writeback_connector(struct vkms_device *vkmsdev, struct vkms_crtc *vkms_crtc); =20 +/* ConfigFS Support */ +int vkms_init_configfs(void); +void vkms_unregister_configfs(void); + #endif /* _VKMS_DRV_H_ */ diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms= _output.c index bfc2e2362c6d..dc69959c5e1d 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -176,3 +176,8 @@ int vkms_output_init_default(struct vkms_device *vkmsde= v) =20 return ret; } + +int vkms_output_init(struct vkms_device *vkmsdev) +{ + return -EOPNOTSUPP; +} --=20 2.42.0.rc2.253.gd59a3bf2b4-goog From nobody Thu Dec 18 01:35:38 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4F2AEC83F24 for ; Tue, 29 Aug 2023 05:33:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235843AbjH2FdD (ORCPT ); Tue, 29 Aug 2023 01:33:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44374 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235829AbjH2Fcb (ORCPT ); Tue, 29 Aug 2023 01:32:31 -0400 Received: from mail-pl1-x636.google.com (mail-pl1-x636.google.com [IPv6:2607:f8b0:4864:20::636]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 319B61B4 for ; Mon, 28 Aug 2023 22:32:24 -0700 (PDT) Received: by mail-pl1-x636.google.com with SMTP id d9443c01a7336-1bc83a96067so23540595ad.0 for ; Mon, 28 Aug 2023 22:32:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1693287143; x=1693891943; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=qkJ4KwAcx+TQGTx0OTFOcApAR7YfD4hOh7t3xGiRrRk=; b=ZQ04fzVqF2jcMlxLXhYaY/LKeEVSh4fE86ZxRRBXUUqTTsArunvANVto1TzcVboxVd rT45sjX8m2K3I6yhhz9tG/6yxD2JM9W+BwPCvyw6voAb7jkT+Sk7dKTF0+D0bWuXPL1r LZ4Z7dwBOT23nlc4n5nj3J9DohWioC8okhI5w= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1693287143; x=1693891943; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=qkJ4KwAcx+TQGTx0OTFOcApAR7YfD4hOh7t3xGiRrRk=; b=QwsQux9AUtl4i77ZAOuaUHJ18d4+p/cME6KvNtnE0cWbZJJTxn6ywVQ5MoekEkzVVb 3ZSHe4ObLseCu1MvrQO/jehj3p0c3l5rWIJkoOuzLAgVr1J62rz9BLceb1jCBINnGPK/ KVvHSVP3GgBpw/HUAS1vj2tnYcdgA9X4iw54sDEMR7Dw1tAKyjGGZ6n57RLdgeFk74Ma 04bOTZR2SUuHOfHIMECrVj5jPRE71ZuGmIcXrxolTZgbxigzb+AMM8YMdGM/8TmBvXHa i0C5yhCzwunZTO+ecMEsX8u5THAwMOFikFpMxc8y1JYXhpfpy5X/YjhQqWsqM7LgRCgD /9WQ== X-Gm-Message-State: AOJu0YwWQo9Xcr5+hwPF6u1KBgza1TKrTy56E2jAbUENFLrP3t8Wuoxn i3Sm7Pz0EqlSYhAYXK7E0kZ7ew== X-Google-Smtp-Source: AGHT+IFnu9WJp/5ngWW8gHk5i3T5TrY+fcpcRQsOJ6/BJ3XvxgJhLPt+K6XWqGpzTILbKN9q94e4RA== X-Received: by 2002:a17:903:32c6:b0:1b3:d4ed:8306 with SMTP id i6-20020a17090332c600b001b3d4ed8306mr26898562plr.19.1693287143619; Mon, 28 Aug 2023 22:32:23 -0700 (PDT) Received: from datalore.c.googlers.com.com (148.175.199.104.bc.googleusercontent.com. [104.199.175.148]) by smtp.gmail.com with ESMTPSA id g6-20020a170902c38600b001bdccf6b8c9sm8420874plg.127.2023.08.28.22.32.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Aug 2023 22:32:23 -0700 (PDT) From: Brandon Pollack To: marius.vlad@collabora.com, mairacanal@riseup.net, jshargo@chromium.org Cc: corbet@lwn.net, dri-devel@lists.freedesktop.org, hamohammed.sa@gmail.com, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, melissa.srw@gmail.com, mripard@kernel.org, rodrigosiqueiramelo@gmail.com, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mduggan@chromium.org, hirono@chromium.org, Brandon Pollack Subject: [PATCH v6 5/7] drm/vkms: Support enabling ConfigFS devices Date: Tue, 29 Aug 2023 05:30:57 +0000 Message-ID: <20230829053201.423261-6-brpol@chromium.org> X-Mailer: git-send-email 2.42.0.rc2.253.gd59a3bf2b4-goog In-Reply-To: <20230829053201.423261-1-brpol@chromium.org> References: <20230829053201.423261-1-brpol@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Jim Shargo VKMS now supports creating and using virtual devices! In addition to the enabling logic, this commit also prevents users from adding new objects once a card is registered. Signed-off-by: Jim Shargo Signed-off-by: Brandon Pollack --- drivers/gpu/drm/vkms/vkms_configfs.c | 37 ++-- drivers/gpu/drm/vkms/vkms_crtc.c | 4 +- drivers/gpu/drm/vkms/vkms_drv.c | 1 + drivers/gpu/drm/vkms/vkms_drv.h | 4 +- drivers/gpu/drm/vkms/vkms_output.c | 282 +++++++++++++++++++++++---- drivers/gpu/drm/vkms/vkms_plane.c | 10 +- 6 files changed, 282 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vk= ms_configfs.c index dae2e85d83a1..bc35dcc47585 100644 --- a/drivers/gpu/drm/vkms/vkms_configfs.c +++ b/drivers/gpu/drm/vkms/vkms_configfs.c @@ -508,29 +508,40 @@ static ssize_t device_enabled_store(struct config_ite= m *item, const char *buf, { struct vkms_configfs *configfs =3D item_to_configfs(item); struct vkms_device *device; - int value, ret; + int enabled, ret; =20 - ret =3D kstrtoint(buf, 0, &value); + ret =3D kstrtoint(buf, 0, &enabled); if (ret) return ret; =20 - if (value !=3D 1) - return -EINVAL; - - mutex_lock(&configfs->lock); - - if (configfs->vkms_device) { + if (enabled =3D=3D 0) { + mutex_lock(&configfs->lock); + if (configfs->vkms_device) { + vkms_remove_device(configfs->vkms_device); + configfs->vkms_device =3D NULL; + } mutex_unlock(&configfs->lock); + return len; } =20 - device =3D vkms_add_device(configfs); - mutex_unlock(&configfs->lock); + if (enabled =3D=3D 1) { + mutex_lock(&configfs->lock); + if (!configfs->vkms_device) { + device =3D vkms_add_device(configfs); + if (IS_ERR(device)) { + mutex_unlock(&configfs->lock); + return -PTR_ERR(device); + } + + configfs->vkms_device =3D device; + } + mutex_unlock(&configfs->lock); =20 - if (IS_ERR(device)) - return -PTR_ERR(device); + return len; + } =20 - return len; + return -EINVAL; } =20 CONFIGFS_ATTR(device_, enabled); diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_c= rtc.c index 74bbd675464b..2aa1c5246b7e 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -279,7 +279,7 @@ static const struct drm_crtc_helper_funcs vkms_crtc_hel= per_funcs =3D { =20 struct vkms_crtc *vkms_crtc_init(struct vkms_device *vkmsdev, struct drm_plane *primary, - struct drm_plane *cursor) + struct drm_plane *cursor, const char *name) { struct drm_device *dev =3D &vkmsdev->drm; struct vkms_crtc *vkms_crtc; @@ -291,7 +291,7 @@ struct vkms_crtc *vkms_crtc_init(struct vkms_device *vk= msdev, vkms_crtc =3D &vkmsdev->output.crtcs[vkmsdev->output.num_crtcs++]; =20 ret =3D drmm_crtc_init_with_planes(dev, &vkms_crtc->base, primary, cursor, - &vkms_crtc_funcs, NULL); + &vkms_crtc_funcs, name); if (ret) { DRM_ERROR("Failed to init CRTC\n"); goto out_error; diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_dr= v.c index 819e880a8cf7..6e7f20681890 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -275,6 +275,7 @@ struct vkms_device *vkms_add_device(struct vkms_configf= s *configfs) dev, &vkms_platform_driver.driver))) { pdev =3D to_platform_device(dev); max_id =3D max(max_id, pdev->id); + put_device(dev); } =20 pdev =3D platform_device_register_data(NULL, DRIVER_NAME, max_id + 1, diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_dr= v.h index 8cdd7949f661..2b9545ada9c2 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -250,13 +250,13 @@ void vkms_remove_device(struct vkms_device *vkms_devi= ce); /* CRTC */ struct vkms_crtc *vkms_crtc_init(struct vkms_device *vkmsdev, struct drm_plane *primary, - struct drm_plane *cursor); + struct drm_plane *cursor, const char *name); =20 int vkms_output_init(struct vkms_device *vkmsdev); int vkms_output_init_default(struct vkms_device *vkmsdev); =20 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, - enum drm_plane_type type); + enum drm_plane_type type, char* name, ...); =20 /* 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 dc69959c5e1d..0ee1f3f4a305 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -2,8 +2,10 @@ =20 #include #include +#include #include #include +#include #include #include =20 @@ -60,7 +62,8 @@ vkms_connector_init(struct vkms_device *vkms_device) return connector; } =20 -static struct drm_encoder *vkms_encoder_init(struct vkms_device *vkms_devi= ce) +static struct drm_encoder *vkms_encoder_init(struct vkms_device *vkms_devi= ce, + char *name) { struct drm_encoder *encoder; int ret; @@ -71,7 +74,7 @@ static struct drm_encoder *vkms_encoder_init(struct vkms_= device *vkms_device) encoder =3D &vkms_device->output .encoders[vkms_device->output.num_encoders++]; ret =3D drm_encoder_init(&vkms_device->drm, encoder, &vkms_encoder_funcs, - DRM_MODE_ENCODER_VIRTUAL, NULL); + DRM_MODE_ENCODER_VIRTUAL, name); if (ret) { memset(encoder, 0, sizeof(*encoder)); vkms_device->output.num_encoders -=3D 1; @@ -82,7 +85,6 @@ static struct drm_encoder *vkms_encoder_init(struct vkms_= device *vkms_device) =20 int vkms_output_init_default(struct vkms_device *vkmsdev) { - struct vkms_output *output =3D &vkmsdev->output; struct drm_device *dev =3D &vkmsdev->drm; struct drm_connector *connector; struct drm_encoder *encoder; @@ -92,35 +94,34 @@ int vkms_output_init_default(struct vkms_device *vkmsde= v) int writeback; unsigned int n; =20 - primary =3D vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY); + primary =3D vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY, + "default-primary-plane"); if (IS_ERR(primary)) return PTR_ERR(primary); =20 if (vkmsdev->config.overlay) { for (n =3D 0; n < NUM_OVERLAY_PLANES; n++) { - struct vkms_plane *overlay =3D vkms_plane_init( - vkmsdev, DRM_PLANE_TYPE_OVERLAY); - if (IS_ERR(overlay)) { - ret =3D PTR_ERR(overlay); - goto err_planes; - } + struct vkms_plane *overlay =3D + vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, + "default-overlay-plane-%d", n); + if (IS_ERR(overlay)) + return PTR_ERR(overlay); } } =20 if (vkmsdev->config.cursor) { - cursor =3D vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR); - if (IS_ERR(cursor)) { - ret =3D PTR_ERR(cursor); - goto err_planes; - } + cursor =3D vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_CURSOR, + "default-cursor-plane"); + if (IS_ERR(cursor)) + return PTR_ERR(cursor); } =20 vkms_crtc =3D vkms_crtc_init(vkmsdev, &primary->base, - cursor ? &cursor->base : NULL); + cursor ? &cursor->base : NULL, + "crtc-default"); if (IS_ERR(vkms_crtc)) { DRM_ERROR("Failed to init crtc\n"); - ret =3D PTR_ERR(vkms_crtc); - goto err_planes; + return PTR_ERR(vkms_crtc); } =20 for (int i =3D 0; i < vkmsdev->output.num_planes; i++) { @@ -131,22 +132,20 @@ int vkms_output_init_default(struct vkms_device *vkms= dev) connector =3D vkms_connector_init(vkmsdev); if (IS_ERR(connector)) { DRM_ERROR("Failed to init connector\n"); - ret =3D PTR_ERR(connector); - goto err_connector; + return PTR_ERR(connector); } =20 - encoder =3D vkms_encoder_init(vkmsdev); + encoder =3D vkms_encoder_init(vkmsdev, "encoder-default"); if (IS_ERR(encoder)) { DRM_ERROR("Failed to init encoder\n"); - ret =3D PTR_ERR(encoder); - goto err_encoder; + return PTR_ERR(encoder); } encoder->possible_crtcs |=3D drm_crtc_mask(&vkms_crtc->base); =20 ret =3D drm_connector_attach_encoder(connector, encoder); if (ret) { DRM_ERROR("Failed to attach connector to encoder\n"); - goto err_attach; + return ret; } =20 if (vkmsdev->config.writeback) { @@ -158,26 +157,235 @@ int vkms_output_init_default(struct vkms_device *vkm= sdev) drm_mode_config_reset(dev); =20 return 0; +} =20 -err_attach: - drm_encoder_cleanup(encoder); - -err_encoder: - drm_connector_cleanup(connector); +static bool is_object_linked(struct vkms_config_links *links, unsigned lon= g idx) +{ + return links->linked_object_bitmap & (1 << idx); +} =20 -err_connector: - drm_crtc_cleanup(&vkms_crtc->base); +/** +* validate_vkms_configfs_no_dangling_objects - warn on unused objects in v= kms +* configfs. +* @vkmsdev: vkms device +* +* This gives slightly more visible warning messaging to the user before th= e drm +* system finds the configuration invalid and prints it's debug information= . In +* this case the user may have accidentally not included some links, or the= user +* could be testing this faulty configuration. +*/ +static void +validate_vkms_configfs_no_dangling_objects(struct vkms_device *vkmsdev) +{ + struct vkms_configfs *configfs =3D vkmsdev->configfs; + struct config_item *item; + + // 1. Planes + list_for_each_entry(item, &configfs->planes_group.cg_children, + ci_entry) { + struct vkms_config_plane *config_plane =3D + item_to_config_plane(item); + if (config_plane->possible_crtcs.linked_object_bitmap =3D=3D 0) + DRM_WARN( + "Vkms configfs created plane %s has no linked crtcs", + item->ci_name); + } =20 -err_planes: - for (int i =3D 0; i < output->num_planes; i++) - drm_plane_cleanup(&output->planes[i].base); + // 2. connectors + list_for_each_entry(item, &configfs->connectors_group.cg_children, + ci_entry) { + struct vkms_config_connector *config_connector =3D + item_to_config_connector(item); + if (config_connector->possible_encoders.linked_object_bitmap =3D=3D + 0) { + DRM_WARN( + "Vkms configfs created connector %s has no linked encoders", + item->ci_name); + } + } =20 - memset(output, 0, sizeof(*output)); + // 3. encoders + list_for_each_entry(item, &configfs->encoders_group.cg_children, + ci_entry) { + struct vkms_config_encoder *config_encoder =3D + item_to_config_encoder(item); + if (config_encoder->possible_crtcs.linked_object_bitmap =3D=3D 0) { + DRM_WARN( + "Vkms configfs created encoder %s has no linked crtcs", + item->ci_name); + } + } =20 - return ret; + // 4. crtcs only require a primary plane to function, this is checked dur= ing + // output initialization and returns an error. } =20 int vkms_output_init(struct vkms_device *vkmsdev) { - return -EOPNOTSUPP; + struct drm_device *dev =3D &vkmsdev->drm; + struct vkms_configfs *configfs =3D vkmsdev->configfs; + struct vkms_output *output =3D &vkmsdev->output; + struct plane_map { + struct vkms_config_plane *config_plane; + struct vkms_plane *plane; + } plane_map[VKMS_MAX_PLANES] =3D { 0 }; + struct encoder_map { + struct vkms_config_encoder *config_encoder; + struct drm_encoder *encoder; + } encoder_map[VKMS_MAX_OUTPUT_OBJECTS] =3D { 0 }; + struct config_item *item; + int map_idx =3D 0; + + // Ensure configfs has no unused objects, and warn if so. + validate_vkms_configfs_no_dangling_objects(vkmsdev); + + list_for_each_entry(item, &configfs->planes_group.cg_children, + ci_entry) { + struct vkms_config_plane *config_plane =3D + item_to_config_plane(item); + struct vkms_plane *plane =3D vkms_plane_init( + vkmsdev, config_plane->type, item->ci_name); + + if (IS_ERR(plane)) { + DRM_ERROR("Unable to init plane from config: %s", + item->ci_name); + return PTR_ERR(plane); + } + + plane_map[map_idx].config_plane =3D config_plane; + plane_map[map_idx].plane =3D plane; + map_idx +=3D 1; + } + + map_idx =3D 0; + list_for_each_entry(item, &configfs->encoders_group.cg_children, + ci_entry) { + struct vkms_config_encoder *config_encoder =3D + item_to_config_encoder(item); + struct drm_encoder *encoder =3D + vkms_encoder_init(vkmsdev, item->ci_name); + + if (IS_ERR(encoder)) { + DRM_ERROR("Failed to init config encoder: %s", + item->ci_name); + return PTR_ERR(encoder); + } + encoder_map[map_idx].config_encoder =3D config_encoder; + encoder_map[map_idx].encoder =3D encoder; + map_idx +=3D 1; + } + + list_for_each_entry(item, &configfs->connectors_group.cg_children, + ci_entry) { + struct vkms_config_connector *config_connector =3D + item_to_config_connector(item); + struct drm_connector *connector =3D vkms_connector_init(vkmsdev); + + if (IS_ERR(connector)) { + DRM_ERROR("Failed to init connector from config: %s", + item->ci_name); + return PTR_ERR(connector); + } + + for (int j =3D 0; j < output->num_encoders; j++) { + struct encoder_map *encoder =3D &encoder_map[j]; + + if (is_object_linked( + &config_connector->possible_encoders, + encoder->config_encoder + ->encoder_config_idx)) { + drm_connector_attach_encoder(connector, + encoder->encoder); + } + } + } + + list_for_each_entry(item, &configfs->crtcs_group.cg_children, + ci_entry) { + struct vkms_config_crtc *config_crtc =3D + item_to_config_crtc(item); + struct vkms_crtc *vkms_crtc; + struct drm_plane *primary =3D NULL, *cursor =3D NULL; + + for (int j =3D 0; j < output->num_planes; j++) { + struct plane_map *plane_entry =3D &plane_map[j]; + struct drm_plane *plane =3D &plane_entry->plane->base; + + if (!is_object_linked( + &plane_entry->config_plane->possible_crtcs, + config_crtc->crtc_config_idx)) { + continue; + } + + if (plane->type =3D=3D DRM_PLANE_TYPE_PRIMARY) { + if (primary) { + DRM_WARN( + "Too many primary planes found for crtc %s.", + item->ci_name); + return -EINVAL; + } + primary =3D plane; + } else if (plane->type =3D=3D DRM_PLANE_TYPE_CURSOR) { + if (cursor) { + DRM_WARN( + "Too many cursor planes found for crtc %s.", + item->ci_name); + return -EINVAL; + } + cursor =3D plane; + } + } + + if (!primary) { + DRM_WARN("No primary plane configured for crtc %s", + item->ci_name); + return -EINVAL; + } + + vkms_crtc =3D + vkms_crtc_init(vkmsdev, primary, cursor, item->ci_name); + if (IS_ERR(vkms_crtc)) { + DRM_WARN("Unable to init crtc from config: %s", + item->ci_name); + return PTR_ERR(vkms_crtc); + } + + for (int j =3D 0; j < output->num_planes; j++) { + struct plane_map *plane_entry =3D &plane_map[j]; + + if (!plane_entry->plane) + break; + + if (is_object_linked( + &plane_entry->config_plane->possible_crtcs, + config_crtc->crtc_config_idx)) { + plane_entry->plane->base.possible_crtcs |=3D + drm_crtc_mask(&vkms_crtc->base); + } + } + + for (int j =3D 0; j < output->num_encoders; j++) { + struct encoder_map *encoder_entry =3D &encoder_map[j]; + + if (is_object_linked(&encoder_entry->config_encoder + ->possible_crtcs, + config_crtc->crtc_config_idx)) { + encoder_entry->encoder->possible_crtcs |=3D + drm_crtc_mask(&vkms_crtc->base); + } + } + + if (vkmsdev->config.writeback) { + int ret =3D vkms_enable_writeback_connector(vkmsdev, + vkms_crtc); + if (ret) + DRM_WARN( + "Failed to init writeback connector for config crtc: %s. Error code %= d", + item->ci_name, ret); + } + } + + drm_mode_config_reset(dev); + + return 0; } diff --git a/drivers/gpu/drm/vkms/vkms_plane.c b/drivers/gpu/drm/vkms/vkms_= plane.c index 950e6c930273..3198bf0dca73 100644 --- a/drivers/gpu/drm/vkms/vkms_plane.c +++ b/drivers/gpu/drm/vkms/vkms_plane.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ =20 #include +#include =20 #include #include @@ -215,20 +216,25 @@ static const struct drm_plane_helper_funcs vkms_plane= _helper_funcs =3D { }; =20 struct vkms_plane *vkms_plane_init(struct vkms_device *vkmsdev, - enum drm_plane_type type) + enum drm_plane_type type, char *name, ...) { struct drm_device *dev =3D &vkmsdev->drm; struct vkms_output *output =3D &vkmsdev->output; struct vkms_plane *plane; + va_list va; int ret; =20 if (output->num_planes >=3D VKMS_MAX_PLANES) return ERR_PTR(-ENOMEM); =20 plane =3D &output->planes[output->num_planes++]; + + va_start(va, name); ret =3D drm_universal_plane_init(dev, &plane->base, 0, &vkms_plane_funcs, vkms_formats, ARRAY_SIZE(vkms_formats), - NULL, type, NULL); + NULL, type, name, va); + va_end(va); + if (ret) return ERR_PTR(ret); =20 --=20 2.42.0.rc2.253.gd59a3bf2b4-goog From nobody Thu Dec 18 01:35:38 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D3A23C83F25 for ; Tue, 29 Aug 2023 05:33:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235877AbjH2FdJ (ORCPT ); Tue, 29 Aug 2023 01:33:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44412 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235839AbjH2Fcc (ORCPT ); Tue, 29 Aug 2023 01:32:32 -0400 Received: from mail-pl1-x62c.google.com (mail-pl1-x62c.google.com [IPv6:2607:f8b0:4864:20::62c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2EB30CC1 for ; Mon, 28 Aug 2023 22:32:27 -0700 (PDT) Received: by mail-pl1-x62c.google.com with SMTP id d9443c01a7336-1bc3d94d40fso30713725ad.3 for ; Mon, 28 Aug 2023 22:32:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1693287146; x=1693891946; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=GH6e/PDFX3J0yo9vZn0uCvm8FwvX/251scvS5l4WGCQ=; b=FdhT9fRBOFRjJrUeAuMpM9bqB8dz6ecrZz/QkAKojpSbvFqE7PdYSUR6XqNXWISkf4 m8OyNyX0dJSF45eMyHzYLujUC6H0xXrqZgY/ruDdDNoKzNQwgnnyyBuBI1v2jkXhmwwx TL5dc+qM0slXwiFiOu1SmqGOh0ZHEARQGJDKY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1693287146; x=1693891946; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=GH6e/PDFX3J0yo9vZn0uCvm8FwvX/251scvS5l4WGCQ=; b=ZwBOguK3y+6U5HaeztYvhc4WnB4aQOUxAS4gXmZjRyli92YMNkedi0YDo7YWgFrUOX Ai2X9tS+SgW9EVVgwIDjfZiWqkAMwaY09Q2G58M7VNudzTg2Fu5r4hYPmS7brgoGfWfX Hzoy0Ms24nTwZPujBJgKhuo64S++r8EbAFc016F+Yet+Yme1c7jiQupyNWE4MN3iy1gz MFVmhYTwMlO901z7vO2j+4q4GvlycqQcH3UgtQ/HFPRN1S9HcPKqKebkYzb+mr/23nPn qRWp+nX19Oob+WN0IjfD/knvfYRdj+5XfmPTxqKZNI3cEMJvW8p5U6gMJ7Vek8YVSKMm dv8A== X-Gm-Message-State: AOJu0YwCmvTlUY3r1dqKj45AO5U0vGVvHOHTv0uyLNVUyvrlSmTI4f2B RGcQkb5Dzew2uwERytfSj3tf5w== X-Google-Smtp-Source: AGHT+IFezZbao32Sth8G9Y+W8ekjiQQYamS+hSNT70TKkD7S/75DizVTlnq97IgsXaA2V7/WoMVgRg== X-Received: by 2002:a17:902:dac4:b0:1be:eef7:98e0 with SMTP id q4-20020a170902dac400b001beeef798e0mr32233232plx.35.1693287146640; Mon, 28 Aug 2023 22:32:26 -0700 (PDT) Received: from datalore.c.googlers.com.com (148.175.199.104.bc.googleusercontent.com. [104.199.175.148]) by smtp.gmail.com with ESMTPSA id g6-20020a170902c38600b001bdccf6b8c9sm8420874plg.127.2023.08.28.22.32.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Aug 2023 22:32:26 -0700 (PDT) From: Brandon Pollack To: marius.vlad@collabora.com, mairacanal@riseup.net, jshargo@chromium.org Cc: corbet@lwn.net, dri-devel@lists.freedesktop.org, hamohammed.sa@gmail.com, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, melissa.srw@gmail.com, mripard@kernel.org, rodrigosiqueiramelo@gmail.com, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mduggan@chromium.org, hirono@chromium.org, Brandon Pollack Subject: [PATCH v6 6/7] drm/vkms: Add a module param to enable/disable the default device Date: Tue, 29 Aug 2023 05:30:58 +0000 Message-ID: <20230829053201.423261-7-brpol@chromium.org> X-Mailer: git-send-email 2.42.0.rc2.253.gd59a3bf2b4-goog In-Reply-To: <20230829053201.423261-1-brpol@chromium.org> References: <20230829053201.423261-1-brpol@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: Jim Shargo In many testing circumstances, we will want to just create a new device and test against that. If we create a default device, it can be annoying to have to manually select the new device instead of choosing the only one that exists. The param, enable_default, is defaulted to true to maintain backwards compatibility. Signed-off-by: Jim Shargo Signed-off-by: Brandon Pollack --- drivers/gpu/drm/vkms/vkms_drv.c | 45 ++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/vkms/vkms_drv.c b/drivers/gpu/drm/vkms/vkms_dr= v.c index 6e7f20681890..293bebf8e8ce 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.c +++ b/drivers/gpu/drm/vkms/vkms_drv.c @@ -42,17 +42,26 @@ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 =20 +static bool enable_default_device =3D true; +module_param_named(enable_default_device, enable_default_device, bool, 044= 4); +MODULE_PARM_DESC(enable_default_device, + "Enable/Disable creating the default device"); + static bool enable_cursor =3D true; module_param_named(enable_cursor, enable_cursor, bool, 0444); -MODULE_PARM_DESC(enable_cursor, "Enable/Disable cursor support"); +MODULE_PARM_DESC(enable_cursor, + "Enable/Disable cursor support for the default device"); =20 static bool enable_writeback =3D true; module_param_named(enable_writeback, enable_writeback, bool, 0444); -MODULE_PARM_DESC(enable_writeback, "Enable/Disable writeback connector sup= port"); +MODULE_PARM_DESC( + enable_writeback, + "Enable/Disable writeback connector support for the default device"); =20 static bool enable_overlay; module_param_named(enable_overlay, enable_overlay, bool, 0444); -MODULE_PARM_DESC(enable_overlay, "Enable/Disable overlay support"); +MODULE_PARM_DESC(enable_overlay, + "Enable/Disable overlay support for the default device"); =20 DEFINE_DRM_GEM_FOPS(vkms_driver_fops); =20 @@ -99,6 +108,7 @@ static int vkms_config_show(struct seq_file *m, void *da= ta) struct drm_device *dev =3D entry->dev; struct vkms_device *vkmsdev =3D drm_device_to_vkms_device(dev); =20 + seq_printf(m, "default_device=3D%d\n", enable_default_device); seq_printf(m, "writeback=3D%d\n", vkmsdev->config.writeback); seq_printf(m, "cursor=3D%d\n", vkmsdev->config.cursor); seq_printf(m, "overlay=3D%d\n", vkmsdev->config.overlay); @@ -297,10 +307,7 @@ void vkms_remove_device(struct vkms_device *vkms_devic= e) static int __init vkms_init(void) { int ret; - struct platform_device *pdev; - struct vkms_device_setup vkms_device_setup =3D { - .configfs =3D NULL, - }; + struct platform_device *default_pdev =3D NULL; =20 ret =3D platform_driver_register(&vkms_platform_driver); if (ret) { @@ -308,19 +315,27 @@ static int __init vkms_init(void) return ret; } =20 - pdev =3D platform_device_register_data(NULL, DRIVER_NAME, 0, - &vkms_device_setup, - sizeof(vkms_device_setup)); - if (IS_ERR(pdev)) { - DRM_ERROR("Unable to register default vkms device\n"); - platform_driver_unregister(&vkms_platform_driver); - return PTR_ERR(pdev); + if (enable_default_device) { + struct vkms_device_setup vkms_device_setup =3D { + .configfs =3D NULL, + }; + + default_pdev =3D platform_device_register_data( + NULL, DRIVER_NAME, 0, &vkms_device_setup, + sizeof(vkms_device_setup)); + if (IS_ERR(default_pdev)) { + DRM_ERROR("Unable to register default vkms device\n"); + platform_driver_unregister(&vkms_platform_driver); + return PTR_ERR(default_pdev); + } } =20 ret =3D vkms_init_configfs(); if (ret) { DRM_ERROR("Unable to initialize configfs\n"); - platform_device_unregister(pdev); + if (default_pdev) + platform_device_unregister(default_pdev); + platform_driver_unregister(&vkms_platform_driver); } =20 --=20 2.42.0.rc2.253.gd59a3bf2b4-goog From nobody Thu Dec 18 01:35:38 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C388DC83F26 for ; Tue, 29 Aug 2023 05:33:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235862AbjH2FdH (ORCPT ); Tue, 29 Aug 2023 01:33:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44528 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235853AbjH2Fce (ORCPT ); Tue, 29 Aug 2023 01:32:34 -0400 Received: from mail-pl1-x62b.google.com (mail-pl1-x62b.google.com [IPv6:2607:f8b0:4864:20::62b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 27418CD4 for ; Mon, 28 Aug 2023 22:32:30 -0700 (PDT) Received: by mail-pl1-x62b.google.com with SMTP id d9443c01a7336-1bf3a2f4528so31275595ad.2 for ; Mon, 28 Aug 2023 22:32:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1693287149; x=1693891949; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=zIko/pfmfBNdSwNrKy92dB84U18r5zxwiaqrbuGf80A=; b=GVzoIlZDIe2iucwo6PZtLUsc76tkdfPTXMqdXEZPNnsnEjiv1rCU71+zdwzk3UrMOH CoViq2PWJ0DsvAznqaTSwOHLBTNXNI+2FA3z5qZxFb6mB8KON3NrXLe5yO73VXikTO/Q ooa4l+FpkglPlFVTyAOn/yKLZlx5vqYuh16dw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1693287149; x=1693891949; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=zIko/pfmfBNdSwNrKy92dB84U18r5zxwiaqrbuGf80A=; b=Rw0/8nod6YuUcPADDAC9cq5VoBGyKf5J8cxWkQDClVzDgiwW7hurucAKuX2RlM0JBU evshZs6ND+eIU2Tl4bL70Yfbf4iqGy0raRnIefoXd8bZrS919Xl1L9bY0eoDb/Ff1WFo xMxSSXespSH5EVOnbstUOJ9C1sycZ6eOxrrXNux7xVQOTweCMafn9NUDRVKqVOaNf2ij p2C7uFXjKMEomLI8ypaNadX7MFzlLpGteZWw1bxY/FaKEFdH4pGxSCJ9MUSeONesKyBb 14tyJcm7xxcdJAXpxQn2ewSM6a5S38Ig3Zw4hVF/zg4XE1U3ulSCiBQlzHyGrjV17u5h JBCQ== X-Gm-Message-State: AOJu0YxFlmDnyRixouI0IYHi+h4wjnvi340G5VjRTqt0ky1EaMBNc794 6uSiIb0YLw0cOx02tfdlfsZg0g== X-Google-Smtp-Source: AGHT+IFUGa/BlgXJWxGcCYlZuKaAAgQjLsE+7T4pgGLrUAimwq0dcbXE3GHn/Aa5xHAduf0EY1XLKA== X-Received: by 2002:a17:902:f681:b0:1bb:9c45:130f with SMTP id l1-20020a170902f68100b001bb9c45130fmr31290027plg.69.1693287149564; Mon, 28 Aug 2023 22:32:29 -0700 (PDT) Received: from datalore.c.googlers.com.com (148.175.199.104.bc.googleusercontent.com. [104.199.175.148]) by smtp.gmail.com with ESMTPSA id g6-20020a170902c38600b001bdccf6b8c9sm8420874plg.127.2023.08.28.22.32.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Aug 2023 22:32:29 -0700 (PDT) From: Brandon Pollack To: marius.vlad@collabora.com, mairacanal@riseup.net, jshargo@chromium.org Cc: corbet@lwn.net, dri-devel@lists.freedesktop.org, hamohammed.sa@gmail.com, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, melissa.srw@gmail.com, mripard@kernel.org, rodrigosiqueiramelo@gmail.com, tzimmermann@suse.de, airlied@gmail.com, daniel@ffwll.ch, maarten.lankhorst@linux.intel.com, mduggan@chromium.org, hirono@chromium.org, Brandon Pollack Subject: [PATCH v6 7/7] drm/vkms Add hotplug support via configfs to VKMS. Date: Tue, 29 Aug 2023 05:30:59 +0000 Message-ID: <20230829053201.423261-8-brpol@chromium.org> X-Mailer: git-send-email 2.42.0.rc2.253.gd59a3bf2b4-goog In-Reply-To: <20230829053201.423261-1-brpol@chromium.org> References: <20230829053201.423261-1-brpol@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This change adds the ability to read or write a "1" or a "0" to the newly added "connected" attribute of a connector in the vkms entry in configfs. A write will trigger a call to drm_kms_helper_hotplug_event, causing a hotplug uevent. With this we can write virtualized multidisplay tests that involve hotplugging displays (eg recompositing windows when a monitor is turned off). Signed-off-by: Brandon Pollack --- Documentation/gpu/vkms.rst | 2 +- drivers/gpu/drm/vkms/vkms_configfs.c | 68 ++++++++++++++++++++++++++-- drivers/gpu/drm/vkms/vkms_drv.h | 11 +++++ drivers/gpu/drm/vkms/vkms_output.c | 47 ++++++++++++++++++- 4 files changed, 123 insertions(+), 5 deletions(-) diff --git a/Documentation/gpu/vkms.rst b/Documentation/gpu/vkms.rst index c3875bf66dba..7f715097539c 100644 --- a/Documentation/gpu/vkms.rst +++ b/Documentation/gpu/vkms.rst @@ -145,7 +145,7 @@ We want to be able to manipulate vkms instances without= having to reload the module. Such configuration can be added as extensions to vkms's ConfigFS support. Use-cases: =20 -- Hotplug/hotremove connectors on the fly (to be able to test DP MST handl= ing +- Hotremove connectors on the fly (to be able to test DP MST handling of compositors). =20 - Change output configuration: Plug/unplug screens, change EDID, allow cha= nging diff --git a/drivers/gpu/drm/vkms/vkms_configfs.c b/drivers/gpu/drm/vkms/vk= ms_configfs.c index bc35dcc47585..d231e28101ae 100644 --- a/drivers/gpu/drm/vkms/vkms_configfs.c +++ b/drivers/gpu/drm/vkms/vkms_configfs.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ =20 +#include "drm/drm_probe_helper.h" #include #include #include @@ -40,6 +41,7 @@ * `-- vkms * `-- test * |-- connectors + * `-- connected * |-- crtcs * |-- encoders * |-- planes @@ -89,6 +91,14 @@ * * echo 1 > /config/vkms/test/enabled * + * By default no display is "connected" so to connect a connector you'll a= lso + * have to write 1 to a connectors "connected" attribute:: + * + * echo 1 > /config/vkms/test/connectors/connector/connected + * + * One can verify that this is worked using the `modetest` utility or the + * equivalent for your platform. + * * When you're done with the virtual device, you can clean up the device l= ike * so:: * @@ -236,7 +246,58 @@ static void add_possible_encoders(struct config_group = *parent, =20 /* Connector item, e.g. /config/vkms/device/connectors/ID */ =20 +static ssize_t connector_connected_show(struct config_item *item, char *bu= f) +{ + struct vkms_config_connector *connector =3D + item_to_config_connector(item); + struct vkms_configfs *configfs =3D connector_item_to_configfs(item); + bool connected =3D false; + + mutex_lock(&configfs->lock); + connected =3D connector->connected; + mutex_unlock(&configfs->lock); + + return sprintf(buf, "%d\n", connected); +} + +static ssize_t connector_connected_store(struct config_item *item, + const char *buf, size_t len) +{ + struct vkms_config_connector *connector =3D + item_to_config_connector(item); + struct vkms_configfs *configfs =3D connector_item_to_configfs(item); + int val, ret; + + ret =3D kstrtouint(buf, 10, &val); + if (ret) + return ret; + + if (val !=3D 1 && val !=3D 0) + return -EINVAL; + + mutex_lock(&configfs->lock); + connector->connected =3D val; + if (!connector->connector) { + pr_info("VKMS Device %s is not yet enabled, connector will be enabled on= start", + configfs->device_group.cg_item.ci_name); + } + mutex_unlock(&configfs->lock); + + if (connector->connector) + drm_kms_helper_hotplug_event(connector->connector->dev); + + return len; +} + +CONFIGFS_ATTR(connector_, connected); + +static struct configfs_attribute *connector_attrs[] =3D { + &connector_attr_connected, + NULL, +}; + static struct config_item_type connector_type =3D { + .ct_attrs =3D connector_attrs, .ct_owner =3D THIS_MODULE, }; =20 @@ -264,7 +325,7 @@ static ssize_t plane_type_show(struct config_item *item= , char *buf) plane_type =3D plane->type; mutex_unlock(&configfs->lock); =20 - return sprintf(buf, "%u", plane_type); + return sprintf(buf, "%u\n", plane_type); } =20 static ssize_t plane_type_store(struct config_item *item, const char *buf, @@ -319,6 +380,7 @@ static struct config_group *connectors_group_make(struc= t config_group *group, &connector_type); add_possible_encoders(&connector->config_group, &connector->possible_encoders.group); + connector->connected =3D false; =20 return &connector->config_group; } @@ -500,7 +562,7 @@ static ssize_t device_enabled_show(struct config_item *= item, char *buf) is_enabled =3D configfs->vkms_device !=3D NULL; mutex_unlock(&configfs->lock); =20 - return sprintf(buf, "%d", is_enabled); + return sprintf(buf, "%d\n", is_enabled); } =20 static ssize_t device_enabled_store(struct config_item *item, const char *= buf, @@ -557,7 +619,7 @@ static ssize_t device_id_show(struct config_item *item,= char *buf) =20 mutex_unlock(&configfs->lock); =20 - return sprintf(buf, "%d", id); + return sprintf(buf, "%d\n", id); } =20 CONFIGFS_ATTR_RO(device_, id); diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_dr= v.h index 2b9545ada9c2..5336281f397e 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -3,6 +3,7 @@ #ifndef _VKMS_DRV_H_ #define _VKMS_DRV_H_ =20 +#include "drm/drm_connector.h" #include #include =20 @@ -147,7 +148,9 @@ struct vkms_config_links { =20 struct vkms_config_connector { struct config_group config_group; + struct drm_connector *connector; struct vkms_config_links possible_encoders; + bool connected; }; =20 struct vkms_config_crtc { @@ -220,6 +223,10 @@ struct vkms_device { #define item_to_configfs(item) \ container_of(to_config_group(item), struct vkms_configfs, device_group) =20 +#define connector_item_to_configfs(item) = \ + container_of(to_config_group(item->ci_parent), struct vkms_configfs, \ + connectors_group) + #define item_to_config_connector(item) \ container_of(to_config_group(item), struct vkms_config_connector, \ config_group) @@ -279,4 +286,8 @@ int vkms_enable_writeback_connector(struct vkms_device = *vkmsdev, int vkms_init_configfs(void); void vkms_unregister_configfs(void); =20 +/* Connector hotplugging */ +enum drm_connector_status vkms_connector_detect(struct drm_connector *conn= ector, + bool force); + #endif /* _VKMS_DRV_H_ */ diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms= _output.c index 0ee1f3f4a305..1a1cd0202c5f 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+ =20 +#include #include #include #include @@ -8,10 +9,12 @@ #include #include #include +#include =20 #include "vkms_drv.h" =20 static const struct drm_connector_funcs vkms_connector_funcs =3D { + .detect =3D vkms_connector_detect, .fill_modes =3D drm_helper_probe_single_connector_modes, .destroy =3D drm_connector_cleanup, .reset =3D drm_atomic_helper_connector_reset, @@ -19,6 +22,48 @@ static const struct drm_connector_funcs vkms_connector_f= uncs =3D { .atomic_destroy_state =3D drm_atomic_helper_connector_destroy_state, }; =20 +static const struct vkms_config_connector * +find_config_for_connector(struct drm_connector *connector) +{ + struct vkms_device *vkms =3D drm_device_to_vkms_device(connector->dev); + struct vkms_configfs *configfs =3D vkms->configfs; + struct config_item *item; + + if (!configfs) { + pr_info("Default connector has no configfs entry"); + return NULL; + } + + list_for_each_entry(item, &configfs->connectors_group.cg_children, + ci_entry) { + struct vkms_config_connector *config_connector =3D + item_to_config_connector(item); + if (config_connector->connector =3D=3D connector) + return config_connector; + } + + pr_warn("Could not find config to match connector %s, but configfs was in= itialized", + connector->name); + + return NULL; +} + +enum drm_connector_status vkms_connector_detect(struct drm_connector *conn= ector, + bool force) +{ + enum drm_connector_status status =3D connector_status_connected; + const struct vkms_config_connector *config_connector =3D + find_config_for_connector(connector); + + if (!config_connector) + return connector_status_connected; + + if (!config_connector->connected) + status =3D connector_status_disconnected; + + return status; +} + static const struct drm_encoder_funcs vkms_encoder_funcs =3D { .destroy =3D drm_encoder_cleanup, }; @@ -280,12 +325,12 @@ int vkms_output_init(struct vkms_device *vkmsdev) struct vkms_config_connector *config_connector =3D item_to_config_connector(item); struct drm_connector *connector =3D vkms_connector_init(vkmsdev); - if (IS_ERR(connector)) { DRM_ERROR("Failed to init connector from config: %s", item->ci_name); return PTR_ERR(connector); } + config_connector->connector =3D connector; =20 for (int j =3D 0; j < output->num_encoders; j++) { struct encoder_map *encoder =3D &encoder_map[j]; --=20 2.42.0.rc2.253.gd59a3bf2b4-goog