From patchwork Tue Oct 11 14:54:01 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brian Starkey X-Patchwork-Id: 37426 Received: from mail.tu-berlin.de ([130.149.7.33]) by www.linuxtv.org with esmtp (Exim 4.84_2) (envelope-from ) id 1btyUx-0000gl-J6; Tue, 11 Oct 2016 14:57:43 +0000 X-tubIT-Incoming-IP: 209.132.180.67 Received: from vger.kernel.org ([209.132.180.67]) by mail.tu-berlin.de (exim-4.84_2/mailfrontend-5) with esmtp id 1btyUv-0007fv-88; Tue, 11 Oct 2016 16:57:43 +0200 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753308AbcJKO45 (ORCPT + 1 other); Tue, 11 Oct 2016 10:56:57 -0400 Received: from foss.arm.com ([217.140.101.70]:35480 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752408AbcJKOyn (ORCPT ); Tue, 11 Oct 2016 10:54:43 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 3293A1478; Tue, 11 Oct 2016 07:54:22 -0700 (PDT) Received: from e106950-lin.cambridge.arm.com (e106950-lin.cambridge.arm.com [10.2.133.193]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id A089F3F32C; Tue, 11 Oct 2016 07:54:20 -0700 (PDT) From: Brian Starkey To: dri-devel@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, liviu.dudau@arm.com, robdclark@gmail.com, hverkuil@xs4all.nl, eric@anholt.net, ville.syrjala@linux.intel.com, daniel@ffwll.ch Subject: [RFC PATCH 04/11] drm: Add __drm_framebuffer_remove_atomic Date: Tue, 11 Oct 2016 15:54:01 +0100 Message-Id: <1476197648-24918-5-git-send-email-brian.starkey@arm.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1476197648-24918-1-git-send-email-brian.starkey@arm.com> References: <1476197648-24918-1-git-send-email-brian.starkey@arm.com> Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-PMX-Version: 6.0.0.2142326, Antispam-Engine: 2.7.2.2107409, Antispam-Data: 2016.10.11.145117 X-PMX-Spam: Gauge=IIIIIIII, Probability=8%, Report=' MULTIPLE_RCPTS 0.1, HTML_00_01 0.05, HTML_00_10 0.05, BODY_SIZE_5000_5999 0, BODY_SIZE_7000_LESS 0, IN_REP_TO 0, LEGITIMATE_NEGATE 0, LEGITIMATE_SIGNS 0, MSG_THREAD 0, MULTIPLE_REAL_RCPTS 0, NO_URI_HTTPS 0, REFERENCES 0, SINGLE_URI_IN_BODY 0, URI_ENDS_IN_HTML 0, __ANY_URI 0, __CP_URI_IN_BODY 0, __FROM_DOMAIN_IN_ANY_CC2 0, __FROM_DOMAIN_IN_RCPT 0, __HAS_CC_HDR 0, __HAS_FROM 0, __HAS_MSGID 0, __HAS_X_MAILER 0, __HAS_X_MAILING_LIST 0, __IN_REP_TO 0, __MIME_TEXT_ONLY 0, __MIME_TEXT_P 0, __MIME_TEXT_P1 0, __MULTIPLE_RCPTS_CC_X2 0, __REFERENCES 0, __SANE_MSGID 0, __SINGLE_URI_TEXT 0, __TO_MALFORMED_2 0, __TO_NO_NAME 0, __URI_IN_BODY 0, __URI_NO_WWW 0, __URI_NS , __URI_WITH_PATH 0' Implement the CRTC/Plane disable functionality of drm_framebuffer_remove using the atomic API, and use it if possible. For atomic drivers, this removes the possibility of several commits when a framebuffer is in use by more than one CRTC/plane. Additionally, this will provide a suitable place to support the removal of a framebuffer from a writeback connector, in the case that a writeback connector is still actively using a framebuffer when it is removed by userspace. Signed-off-by: Brian Starkey --- drivers/gpu/drm/drm_framebuffer.c | 154 ++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index 528f75d..b02cf73 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -795,6 +796,148 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) EXPORT_SYMBOL(drm_framebuffer_cleanup); /** + * __drm_framebuffer_remove_atomic - atomic version of __drm_framebuffer_remove + * @dev: drm device + * @fb: framebuffer to remove + * + * If the driver implements the atomic API, we can handle the disabling of all + * CRTCs/planes which use a framebuffer which is going away in a single atomic + * commit. + * + * This scans all CRTCs and planes in @dev's mode_config. If they're using @fb, + * it is removed and the CRTC/plane disabled. + * The legacy references are dropped and the ->fb pointers set to NULL + * accordingly. + * + * Returns: + * true if the framebuffer was successfully removed from use + */ +static bool __drm_framebuffer_remove_atomic(struct drm_device *dev, + struct drm_framebuffer *fb) +{ + struct drm_modeset_acquire_ctx ctx; + struct drm_atomic_state *state; + struct drm_connector_state *conn_state; + struct drm_connector *connector; + struct drm_plane *plane; + struct drm_crtc *crtc; + unsigned plane_mask; + int i, ret; + + drm_modeset_acquire_init(&ctx, 0); + + state = drm_atomic_state_alloc(dev); + if (!state) + return false; + + state->acquire_ctx = &ctx; + +retry: + drm_for_each_crtc(crtc, dev) { + struct drm_plane_state *primary_state; + struct drm_crtc_state *crtc_state; + + primary_state = drm_atomic_get_plane_state(state, crtc->primary); + if (IS_ERR(primary_state)) { + ret = PTR_ERR(primary_state); + goto fail; + } + + if (primary_state->fb != fb) + continue; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto fail; + } + + /* Only handle the CRTC itself here, handle the plane later */ + ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); + if (ret != 0) + goto fail; + + crtc_state->active = false; + + /* Get the connectors in order to disable them */ + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + goto fail; + } + + plane_mask = 0; + drm_for_each_plane(plane, dev) { + struct drm_plane_state *plane_state; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto fail; + } + + if (plane_state->fb != fb) + continue; + + plane->old_fb = plane->fb; + plane_mask |= 1 << drm_plane_index(plane); + + /* + * Open-coded copy of __drm_atomic_helper_disable_plane to avoid + * a dependency on atomic-helper + */ + ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); + if (ret != 0) + goto fail; + + drm_atomic_set_fb_for_plane(plane_state, NULL); + plane_state->crtc_x = 0; + plane_state->crtc_y = 0; + plane_state->crtc_w = 0; + plane_state->crtc_h = 0; + plane_state->src_x = 0; + plane_state->src_y = 0; + plane_state->src_w = 0; + plane_state->src_h = 0; + } + + /* All of the connectors in state need disabling */ + for_each_connector_in_state(state, connector, conn_state, i) { + ret = drm_atomic_set_crtc_for_connector(conn_state, + NULL); + if (ret) + goto fail; + } + + if (WARN_ON(!plane_mask)) { + DRM_ERROR("Couldn't find any usage of [FB:%d]\n", fb->base.id); + ret = -ENOENT; + goto fail; + } + + ret = drm_atomic_commit(state); + +fail: + drm_atomic_clean_old_fb(dev, plane_mask, ret); + + if (ret == -EDEADLK) + goto backoff; + + if (ret != 0) + drm_atomic_state_free(state); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret ? false : true; + +backoff: + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); + + goto retry; +} + +/** * __drm_framebuffer_remove - remove all usage of a framebuffer object * @dev: drm device * @fb: framebuffer to remove @@ -869,9 +1012,16 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot * in this manner. */ - if (drm_framebuffer_read_refcount(fb) > 1) - if (!__drm_framebuffer_remove(dev, fb)) + if (drm_framebuffer_read_refcount(fb) > 1) { + bool removed; + if (dev->mode_config.funcs->atomic_commit) + removed = __drm_framebuffer_remove_atomic(dev, fb); + else + removed = __drm_framebuffer_remove(dev, fb); + + if (!removed) DRM_ERROR("failed to remove fb from active usage\n"); + } drm_framebuffer_unreference(fb); }