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 <maarten.lankhorst@xxxxxxxxxxxxxxx> --- 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; \ -- 2.5.5 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx