From patchwork Tue Feb 9 12:10:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 12077887 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 73D0FC433DB for ; Tue, 9 Feb 2021 12:10:54 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 3490A64E6F for ; Tue, 9 Feb 2021 12:10:54 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3490A64E6F Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 135086EAD3; Tue, 9 Feb 2021 12:10:49 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id 8D1C96E971 for ; Tue, 9 Feb 2021 12:10:47 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 2193AAF2B; Tue, 9 Feb 2021 12:10:46 +0000 (UTC) From: Thomas Zimmermann To: hdegoede@redhat.com, daniel@ffwll.ch, airlied@linux.ie, mripard@kernel.org, maarten.lankhorst@linux.intel.com Subject: [PATCH v3 1/2] drm/gem: Export helpers for shadow-buffered planes Date: Tue, 9 Feb 2021 13:10:41 +0100 Message-Id: <20210209121042.24098-2-tzimmermann@suse.de> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210209121042.24098-1-tzimmermann@suse.de> References: <20210209121042.24098-1-tzimmermann@suse.de> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Daniel Vetter , Thomas Zimmermann , dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Export the helpers for shadow-buffered planes. These will be used by several drivers. v3: * fix documentation typos and formatting (Daniel) Signed-off-by: Thomas Zimmermann Reviewed-by: Daniel Vetter Tested-by: Hans de Goede --- drivers/gpu/drm/drm_gem_atomic_helper.c | 148 +++++++++++++++++++++++- include/drm/drm_gem_atomic_helper.h | 32 +++++ 2 files changed, 174 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c index e27762cef360..fa4eae492b81 100644 --- a/drivers/gpu/drm/drm_gem_atomic_helper.c +++ b/drivers/gpu/drm/drm_gem_atomic_helper.c @@ -14,13 +14,101 @@ * functions for drivers that use GEM objects. Currently, it provides * plane state and framebuffer BO mappings for planes with shadow * buffers. + * + * A driver using a shadow buffer copies the content of the shadow buffers + * into the HW's framebuffer memory during an atomic update. This requires + * a mapping of the shadow buffer into kernel address space. The mappings + * cannot be established by commit-tail functions, such as atomic_update, + * as this would violate locking rules around dma_buf_vmap(). + * + * The helpers for shadow-buffered planes establish and release mappings, + * and provide struct drm_shadow_plane_state, which stores the plane's mapping + * for commit-tail functons. + * + * Shadow-buffered planes can easily be enabled by using the provided macros + * %DRM_GEM_SHADOW_PLANE_FUNCS and %DRM_GEM_SHADOW_PLANE_HELPER_FUNCS. + * These macros set up the plane and plane-helper callbacks to point to the + * shadow-buffer helpers. + * + * .. code-block:: c + * + * #include + * + * struct drm_plane_funcs driver_plane_funcs = { + * ..., + * DRM_GEM_SHADOW_PLANE_FUNCS, + * }; + * + * struct drm_plane_helper_funcs driver_plane_helper_funcs = { + * ..., + * DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, + * }; + * + * In the driver's atomic-update function, shadow-buffer mappings are available + * from the plane state. Use to_drm_shadow_plane_state() to upcast from + * struct drm_plane_state. + * + * .. code-block:: c + * + * void driver_plane_atomic_update(struct drm_plane *plane, + * struct drm_plane_state *old_plane_state) + * { + * struct drm_plane_state *plane_state = plane->state; + * struct drm_shadow_plane_state *shadow_plane_state = + * to_drm_shadow_plane_state(plane_state); + * + * // access shadow buffer via shadow_plane_state->map + * } + * + * A mapping address for each of the framebuffer's buffer object is stored in + * struct &drm_shadow_plane_state.map. The mappings are valid while the state + * is being used. + * + * Drivers that use struct drm_simple_display_pipe can use + * %DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS to initialize the rsp + * callbacks. Access to shadow-buffer mappings is similar to regular + * atomic_update. + * + * .. code-block:: c + * + * struct drm_simple_display_pipe_funcs driver_pipe_funcs = { + * ..., + * DRM_GEM_SIMPLE_DISPLAY_PIPE_SHADOW_PLANE_FUNCS, + * }; + * + * void driver_pipe_enable(struct drm_simple_display_pipe *pipe, + * struct drm_crtc_state *crtc_state, + * struct drm_plane_state *plane_state) + * { + * struct drm_shadow_plane_state *shadow_plane_state = + * to_drm_shadow_plane_state(plane_state); + * + * // access shadow buffer via shadow_plane_state->map + * } */ /* * Shadow-buffered Planes */ -static struct drm_plane_state * +/** + * drm_gem_duplicate_shadow_plane_state - duplicates shadow-buffered plane state + * @plane: the plane + * + * This function implements struct &drm_plane_funcs.atomic_duplicate_state for + * shadow-buffered planes. It assumes the existing state to be of type + * struct drm_shadow_plane_state and it allocates the new state to be of this + * type. + * + * The function does not duplicate existing mappings of the shadow buffers. + * Mappings are maintained during the atomic commit by the plane's prepare_fb + * and cleanup_fb helpers. See drm_gem_prepare_shadow_fb() and drm_gem_cleanup_shadow_fb() + * for corresponding helpers. + * + * Returns: + * A pointer to a new plane state on success, or NULL otherwise. + */ +struct drm_plane_state * drm_gem_duplicate_shadow_plane_state(struct drm_plane *plane) { struct drm_plane_state *plane_state = plane->state; @@ -36,9 +124,19 @@ drm_gem_duplicate_shadow_plane_state(struct drm_plane *plane) return &new_shadow_plane_state->base; } +EXPORT_SYMBOL(drm_gem_duplicate_shadow_plane_state); -static void drm_gem_destroy_shadow_plane_state(struct drm_plane *plane, - struct drm_plane_state *plane_state) +/** + * drm_gem_destroy_shadow_plane_state - deletes shadow-buffered plane state + * @plane: the plane + * @plane_state: the plane state of type struct drm_shadow_plane_state + * + * This function implements struct &drm_plane_funcs.atomic_destroy_state + * for shadow-buffered planes. It expects that mappings of shadow buffers + * have been released already. + */ +void drm_gem_destroy_shadow_plane_state(struct drm_plane *plane, + struct drm_plane_state *plane_state) { struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); @@ -46,8 +144,18 @@ static void drm_gem_destroy_shadow_plane_state(struct drm_plane *plane, __drm_atomic_helper_plane_destroy_state(&shadow_plane_state->base); kfree(shadow_plane_state); } +EXPORT_SYMBOL(drm_gem_destroy_shadow_plane_state); -static void drm_gem_reset_shadow_plane(struct drm_plane *plane) +/** + * drm_gem_reset_shadow_plane - resets a shadow-buffered plane + * @plane: the plane + * + * This function implements struct &drm_plane_funcs.reset_plane for + * shadow-buffered planes. It assumes the current plane state to be + * of type struct drm_shadow_plane and it allocates the new state of + * this type. + */ +void drm_gem_reset_shadow_plane(struct drm_plane *plane) { struct drm_shadow_plane_state *shadow_plane_state; @@ -61,8 +169,24 @@ static void drm_gem_reset_shadow_plane(struct drm_plane *plane) return; __drm_atomic_helper_plane_reset(plane, &shadow_plane_state->base); } +EXPORT_SYMBOL(drm_gem_reset_shadow_plane); -static int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state) +/** + * drm_gem_prepare_shadow_fb - prepares shadow framebuffers + * @plane: the plane + * @plane_state: the plane state of type struct drm_shadow_plane_state + * + * This function implements struct &drm_plane_helper_funcs.prepare_fb. It + * maps all buffer objects of the plane's framebuffer into kernel address + * space and stores them in &struct drm_shadow_plane_state.map. The + * framebuffer will be synchronized as part of the atomic commit. + * + * See drm_gem_cleanup_shadow_fb() for cleanup. + * + * Returns: + * 0 on success, or a negative errno code otherwise. + */ +int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state) { struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; @@ -100,8 +224,19 @@ static int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_s } return ret; } +EXPORT_SYMBOL(drm_gem_prepare_shadow_fb); -static void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state) +/** + * drm_gem_cleanup_shadow_fb - releases shadow framebuffers + * @plane: the plane + * @plane_state: the plane state of type struct drm_shadow_plane_state + * + * This function implements struct &drm_plane_helper_funcs.cleanup_fb. + * This function unmaps all buffer objects of the plane's framebuffer. + * + * See drm_gem_prepare_shadow_fb() for more inforamtion. + */ +void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state) { struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state); struct drm_framebuffer *fb = plane_state->fb; @@ -119,6 +254,7 @@ static void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_ drm_gem_vunmap(obj, &shadow_plane_state->map[i]); } } +EXPORT_SYMBOL(drm_gem_cleanup_shadow_fb); /** * drm_gem_simple_kms_prepare_shadow_fb - prepares shadow framebuffers diff --git a/include/drm/drm_gem_atomic_helper.h b/include/drm/drm_gem_atomic_helper.h index 08b96ccea325..7abf40bdab3d 100644 --- a/include/drm/drm_gem_atomic_helper.h +++ b/include/drm/drm_gem_atomic_helper.h @@ -45,6 +45,38 @@ to_drm_shadow_plane_state(struct drm_plane_state *state) return container_of(state, struct drm_shadow_plane_state, base); } +void drm_gem_reset_shadow_plane(struct drm_plane *plane); +struct drm_plane_state *drm_gem_duplicate_shadow_plane_state(struct drm_plane *plane); +void drm_gem_destroy_shadow_plane_state(struct drm_plane *plane, + struct drm_plane_state *plane_state); + +/** + * DRM_GEM_SHADOW_PLANE_FUNCS - + * Initializes struct drm_plane_funcs for shadow-buffered planes + * + * Drivers may use GEM BOs as shadow buffers over the framebuffer memory. This + * macro initializes struct drm_plane_funcs to use the rsp helper functions. + */ +#define DRM_GEM_SHADOW_PLANE_FUNCS \ + .reset = drm_gem_reset_shadow_plane, \ + .atomic_duplicate_state = drm_gem_duplicate_shadow_plane_state, \ + .atomic_destroy_state = drm_gem_destroy_shadow_plane_state + +int drm_gem_prepare_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state); +void drm_gem_cleanup_shadow_fb(struct drm_plane *plane, struct drm_plane_state *plane_state); + +/** + * DRM_GEM_SHADOW_PLANE_HELPER_FUNCS - + * Initializes struct drm_plane_helper_funcs for shadow-buffered planes + * + * Drivers may use GEM BOs as shadow buffers over the framebuffer memory. This + * macro initializes struct drm_plane_helper_funcs to use the rsp helper + * functions. + */ +#define DRM_GEM_SHADOW_PLANE_HELPER_FUNCS \ + .prepare_fb = drm_gem_prepare_shadow_fb, \ + .cleanup_fb = drm_gem_cleanup_shadow_fb + int drm_gem_simple_kms_prepare_shadow_fb(struct drm_simple_display_pipe *pipe, struct drm_plane_state *plane_state); void drm_gem_simple_kms_cleanup_shadow_fb(struct drm_simple_display_pipe *pipe, From patchwork Tue Feb 9 12:10:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Zimmermann X-Patchwork-Id: 12077889 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4F217C433E0 for ; Tue, 9 Feb 2021 12:10:57 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id CF9F764E6F for ; Tue, 9 Feb 2021 12:10:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CF9F764E6F Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 589F76E047; Tue, 9 Feb 2021 12:10:49 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by gabe.freedesktop.org (Postfix) with ESMTPS id 07B9E6E971 for ; Tue, 9 Feb 2021 12:10:48 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 8F5D1AF49; Tue, 9 Feb 2021 12:10:46 +0000 (UTC) From: Thomas Zimmermann To: hdegoede@redhat.com, daniel@ffwll.ch, airlied@linux.ie, mripard@kernel.org, maarten.lankhorst@linux.intel.com Subject: [PATCH v3 2/2] drm/vboxvideo: Implement cursor plane with struct drm_shadow_plane_state Date: Tue, 9 Feb 2021 13:10:42 +0100 Message-Id: <20210209121042.24098-3-tzimmermann@suse.de> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210209121042.24098-1-tzimmermann@suse.de> References: <20210209121042.24098-1-tzimmermann@suse.de> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Thomas Zimmermann , dri-devel@lists.freedesktop.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Functions in the atomic commit tail are not allowed to acquire the dmabuf's reservation lock. So we cannot legally call the GEM object's vmap functionality in atomic_update. Instead use struct drm_shadow_plane_state and friends. It vmaps the framebuffer BOs in prepare_fb and vunmaps them in cleanup_fb. The cursor plane state stores the mapping's address. The pinning of the BO is implicitly done by vmap. As an extra benefit, there's no source of runtime errors left in atomic_update. v2: * rebase patch onto struct drm_shadow_plane_state Signed-off-by: Thomas Zimmermann Reviewed-by: Hans de Goede Tested-by: Hans de Goede --- drivers/gpu/drm/vboxvideo/vbox_mode.c | 28 +++++++-------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/vboxvideo/vbox_mode.c b/drivers/gpu/drm/vboxvideo/vbox_mode.c index dbc0dd53c69e..6e4ad966be71 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_mode.c +++ b/drivers/gpu/drm/vboxvideo/vbox_mode.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -381,14 +382,14 @@ static void vbox_cursor_atomic_update(struct drm_plane *plane, container_of(plane->dev, struct vbox_private, ddev); struct vbox_crtc *vbox_crtc = to_vbox_crtc(plane->state->crtc); struct drm_framebuffer *fb = plane->state->fb; - struct drm_gem_vram_object *gbo = drm_gem_vram_of_gem(fb->obj[0]); u32 width = plane->state->crtc_w; u32 height = plane->state->crtc_h; + struct drm_shadow_plane_state *shadow_plane_state = + to_drm_shadow_plane_state(plane->state); + struct dma_buf_map map = shadow_plane_state->map[0]; + u8 *src = map.vaddr; /* TODO: Use mapping abstraction properly */ size_t data_size, mask_size; u32 flags; - struct dma_buf_map map; - int ret; - u8 *src; /* * VirtualBox uses the host windowing system to draw the cursor so @@ -401,17 +402,6 @@ static void vbox_cursor_atomic_update(struct drm_plane *plane, vbox_crtc->cursor_enabled = true; - ret = drm_gem_vram_vmap(gbo, &map); - if (ret) { - /* - * BUG: we should have pinned the BO in prepare_fb(). - */ - mutex_unlock(&vbox->hw_mutex); - DRM_WARN("Could not map cursor bo, skipping update\n"); - return; - } - src = map.vaddr; /* TODO: Use mapping abstraction properly */ - /* * The mask must be calculated based on the alpha * channel, one bit per ARGB word, and must be 32-bit @@ -421,7 +411,6 @@ static void vbox_cursor_atomic_update(struct drm_plane *plane, data_size = width * height * 4 + mask_size; copy_cursor_image(src, vbox->cursor_data, width, height, mask_size); - drm_gem_vram_vunmap(gbo, &map); flags = VBOX_MOUSE_POINTER_VISIBLE | VBOX_MOUSE_POINTER_SHAPE | VBOX_MOUSE_POINTER_ALPHA; @@ -466,17 +455,14 @@ static const struct drm_plane_helper_funcs vbox_cursor_helper_funcs = { .atomic_check = vbox_cursor_atomic_check, .atomic_update = vbox_cursor_atomic_update, .atomic_disable = vbox_cursor_atomic_disable, - .prepare_fb = drm_gem_vram_plane_helper_prepare_fb, - .cleanup_fb = drm_gem_vram_plane_helper_cleanup_fb, + DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, }; static const struct drm_plane_funcs vbox_cursor_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, .destroy = drm_primary_helper_destroy, - .reset = drm_atomic_helper_plane_reset, - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + DRM_GEM_SHADOW_PLANE_FUNCS, }; static const u32 vbox_primary_plane_formats[] = {