From patchwork Mon May 9 12:02:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maarten Lankhorst X-Patchwork-Id: 9045651 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 9DEC0BF29F for ; Mon, 9 May 2016 12:02:17 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 807AD20155 for ; Mon, 9 May 2016 12:02:16 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 492552011E for ; Mon, 9 May 2016 12:02:15 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 444A56E1E8; Mon, 9 May 2016 12:02:11 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mblankhorst.nl (mblankhorst.nl [IPv6:2a02:2308::216:3eff:fe92:dfa3]) by gabe.freedesktop.org (Postfix) with ESMTPS id 7635F6E1C8; Mon, 9 May 2016 12:02:09 +0000 (UTC) From: Maarten Lankhorst To: dri-devel@lists.freedesktop.org Subject: [PATCH 1/2] drm/atomic: Add a way to call remove_fb atomically, v2. Date: Mon, 9 May 2016 14:02:02 +0200 Message-Id: <1462795323-4303-3-git-send-email-maarten.lankhorst@linux.intel.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1462795323-4303-1-git-send-email-maarten.lankhorst@linux.intel.com> References: <1462795323-4303-1-git-send-email-maarten.lankhorst@linux.intel.com> Cc: intel-gfx@lists.freedesktop.org X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-6.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Use this in drm_framebuffer_remove, this is to remove the fb in an atomic way. i915 doesn't export DRIVER_ATOMIC yet by default but is atomic, so add a function pointer to allow drivers to use the atomic framebuffer remove. Changes since v1: - Move the atomic framebuffer removal function from helpers to atomic core. - Only override rmfb for i915, for atomic drivers it defaults to atomic rmfb. Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/drm_atomic.c | 67 +++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_crtc.c | 65 ++++++++++++++++++++++++++------------- drivers/gpu/drm/i915/i915_drv.c | 1 + include/drm/drmP.h | 3 ++ include/drm/drm_atomic.h | 1 + 5 files changed, 116 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 86e89db02ed7..5a54d9e2d938 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1741,3 +1741,70 @@ out: return ret; } + +int drm_atomic_remove_fb(struct drm_framebuffer *fb) +{ + struct drm_modeset_acquire_ctx ctx; + struct drm_device *dev = fb->dev; + struct drm_atomic_state *state; + struct drm_plane *plane; + int ret = 0; + unsigned plane_mask; + + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + + drm_modeset_acquire_init(&ctx, 0); + state->acquire_ctx = &ctx; + +retry: + plane_mask = 0; + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (ret) + goto unlock; + + drm_for_each_plane(plane, dev) { + struct drm_plane_state *plane_state; + + if (plane->state->fb != fb) + continue; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto unlock; + } + + drm_atomic_set_fb_for_plane(plane_state, NULL); + ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); + if (ret) + goto unlock; + + plane_mask |= BIT(drm_plane_index(plane)); + + plane->old_fb = plane->fb; + plane->fb = NULL; + } + + if (plane_mask) + ret = drm_atomic_commit(state); + +unlock: + if (plane_mask) + drm_atomic_clean_old_fb(dev, plane_mask, ret); + + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + if (ret || !plane_mask) + drm_atomic_state_free(state); + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + + return ret; +} +EXPORT_SYMBOL(drm_atomic_remove_fb); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 70f9c682d144..a9a3557f9f2b 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -557,6 +557,42 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb) } EXPORT_SYMBOL(drm_framebuffer_cleanup); +static int +legacy_remove_fb(struct drm_framebuffer *fb) +{ + struct drm_device *dev = fb->dev; + struct drm_crtc *crtc; + struct drm_plane *plane; + struct drm_mode_set set; + int ret = 0; + + /* atomic drivers must use drm_atomic_helper_remove_fb */ + WARN_ON(drm_core_check_feature(dev, DRIVER_ATOMIC)); + + drm_modeset_lock_all(dev); + /* remove from any CRTC */ + drm_for_each_crtc(crtc, dev) { + if (crtc->primary->fb == fb) { + /* should turn off the crtc */ + memset(&set, 0, sizeof(struct drm_mode_set)); + set.crtc = crtc; + set.fb = NULL; + ret = drm_mode_set_config_internal(&set); + if (ret) + goto out; + } + } + + drm_for_each_plane(plane, dev) { + if (plane->fb == fb) + drm_plane_force_disable(plane); + } + +out: + drm_modeset_unlock_all(dev); + return ret; +} + /** * drm_framebuffer_remove - remove and unreference a framebuffer object * @fb: framebuffer to remove @@ -572,9 +608,6 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup); void drm_framebuffer_remove(struct drm_framebuffer *fb) { struct drm_device *dev; - struct drm_crtc *crtc; - struct drm_plane *plane; - struct drm_mode_set set; int ret; if (!fb) @@ -600,25 +633,15 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) * in this manner. */ if (drm_framebuffer_read_refcount(fb) > 1) { - drm_modeset_lock_all(dev); - /* remove from any CRTC */ - drm_for_each_crtc(crtc, dev) { - if (crtc->primary->fb == fb) { - /* should turn off the crtc */ - memset(&set, 0, sizeof(struct drm_mode_set)); - set.crtc = crtc; - set.fb = NULL; - ret = drm_mode_set_config_internal(&set); - if (ret) - DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc); - } - } + if (dev->driver->remove_fb) + ret = dev->driver->remove_fb(fb); + else if (drm_core_check_feature(dev, DRIVER_ATOMIC)) + ret = drm_atomic_remove_fb(fb); + else + ret = legacy_remove_fb(fb); - drm_for_each_plane(plane, dev) { - if (plane->fb == fb) - drm_plane_force_disable(plane); - } - drm_modeset_unlock_all(dev); + if (ret) + DRM_ERROR("failed to remove fb %i/%p with %i\n", fb->base.id, fb, ret); } drm_framebuffer_unreference(fb); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 9fd221c97275..8736d15e8848 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1724,6 +1724,7 @@ static struct drm_driver driver = { .dumb_create = i915_gem_dumb_create, .dumb_map_offset = i915_gem_mmap_gtt, .dumb_destroy = drm_gem_dumb_destroy, + .remove_fb = drm_atomic_remove_fb, .ioctls = i915_ioctls, .fops = &i915_driver_fops, .name = DRIVER_NAME, diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 360b2a74e1ef..d63791039387 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -647,6 +647,9 @@ struct drm_driver { struct drm_device *dev, uint32_t handle); + /* rmfb and drm_framebuffer_remove hook */ + int (*remove_fb)(struct drm_framebuffer *fb); + /* Driver private ops for this object */ const struct vm_operations_struct *gem_vm_ops; diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 92c84e9ab09a..0a04314534a5 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -138,6 +138,7 @@ drm_atomic_clean_old_fb(struct drm_device *dev, unsigned plane_mask, int ret); int __must_check drm_atomic_check_only(struct drm_atomic_state *state); int __must_check drm_atomic_commit(struct drm_atomic_state *state); int __must_check drm_atomic_nonblocking_commit(struct drm_atomic_state *state); +int __must_check drm_atomic_remove_fb(struct drm_framebuffer *fb); #define for_each_connector_in_state(state, connector, connector_state, __i) \ for ((__i) = 0; \