From 2df01bf3aa5359ee29aff75b603399c82d491f1c Mon Sep 17 00:00:00 2001 From: Jayaprakash Madisetty Date: Mon, 21 Dec 2020 15:25:30 +0530 Subject: [PATCH] Revert "disp: msm: sde: remove all preclose logic" This change reverts commit ae2dceb0b690 ("disp: msm: sde: remove all preclose logic"). This change also modifies the force disable plane logic since __drm_atomic_helper_disable_plane is not exposed to drivers. Change-Id: I89e19dead9ade724798952b1934b45b5663e1a42 Signed-off-by: Jayaprakash Madisetty Signed-off-by: Samantha Tran --- msm/msm_drv.c | 10 ++++ msm/msm_kms.h | 1 + msm/sde/sde_kms.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) diff --git a/msm/msm_drv.c b/msm/msm_drv.c index 73ccaac548..f3cd152e1b 100644 --- a/msm/msm_drv.c +++ b/msm/msm_drv.c @@ -967,6 +967,15 @@ static void context_close(struct msm_file_private *ctx) kfree(ctx); } +static void msm_preclose(struct drm_device *dev, struct drm_file *file) +{ + struct msm_drm_private *priv = dev->dev_private; + struct msm_kms *kms = priv->kms; + + if (kms && kms->funcs && kms->funcs->preclose) + kms->funcs->preclose(kms, file); +} + static void msm_postclose(struct drm_device *dev, struct drm_file *file) { struct msm_drm_private *priv = dev->dev_private; @@ -1675,6 +1684,7 @@ static struct drm_driver msm_driver = { DRIVER_ATOMIC | DRIVER_MODESET, .open = msm_open, + .preclose = msm_preclose, .postclose = msm_postclose, .lastclose = msm_lastclose, .irq_handler = msm_irq, diff --git a/msm/msm_kms.h b/msm/msm_kms.h index 062a911107..f81824f222 100644 --- a/msm/msm_kms.h +++ b/msm/msm_kms.h @@ -97,6 +97,7 @@ struct msm_kms_funcs { struct drm_encoder *slave_encoder, bool is_cmd_mode); void (*postopen)(struct msm_kms *kms, struct drm_file *file); + void (*preclose)(struct msm_kms *kms, struct drm_file *file); void (*postclose)(struct msm_kms *kms, struct drm_file *file); void (*lastclose)(struct msm_kms *kms); int (*register_events)(struct msm_kms *kms, diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 1368df19c7..40283cb9be 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -2396,6 +2396,143 @@ static void sde_kms_destroy(struct msm_kms *kms) kfree(sde_kms); } +static void _sde_kms_plane_force_remove(struct drm_plane *plane, + struct drm_atomic_state *state) +{ + struct drm_plane_state *plane_state; + int ret = 0; + + plane_state = drm_atomic_get_plane_state(state, plane); + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + SDE_ERROR("error %d getting plane %d state\n", + ret, plane->base.id); + return; + } + + plane->old_fb = plane->fb; + + SDE_DEBUG("disabling plane %d\n", plane->base.id); + + ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); + if (ret != 0) + SDE_ERROR("error %d disabling plane %d\n", ret, + plane->base.id); + + drm_atomic_set_fb_for_plane(plane_state, NULL); +} + +static int _sde_kms_remove_fbs(struct sde_kms *sde_kms, struct drm_file *file, + struct drm_atomic_state *state) +{ + struct drm_device *dev = sde_kms->dev; + struct drm_framebuffer *fb, *tfb; + struct list_head fbs; + struct drm_plane *plane; + int ret = 0; + u32 plane_mask = 0; + + INIT_LIST_HEAD(&fbs); + + list_for_each_entry_safe(fb, tfb, &file->fbs, filp_head) { + if (drm_framebuffer_read_refcount(fb) > 1) { + list_move_tail(&fb->filp_head, &fbs); + + drm_for_each_plane(plane, dev) { + if (plane->fb == fb) { + plane_mask |= + 1 << drm_plane_index(plane); + _sde_kms_plane_force_remove( + plane, state); + } + } + } else { + list_del_init(&fb->filp_head); + drm_framebuffer_put(fb); + } + } + + if (list_empty(&fbs)) { + SDE_DEBUG("skip commit as no fb(s)\n"); + drm_atomic_state_put(state); + return 0; + } + + SDE_DEBUG("committing after removing all the pipes\n"); + ret = drm_atomic_commit(state); + + if (ret) { + /* + * move the fbs back to original list, so it would be + * handled during drm_release + */ + list_for_each_entry_safe(fb, tfb, &fbs, filp_head) + list_move_tail(&fb->filp_head, &file->fbs); + + SDE_ERROR("atomic commit failed in preclose, ret:%d\n", ret); + goto end; + } + + while (!list_empty(&fbs)) { + fb = list_first_entry(&fbs, typeof(*fb), filp_head); + + list_del_init(&fb->filp_head); + drm_framebuffer_put(fb); + } + +end: + return ret; +} + +static void sde_kms_preclose(struct msm_kms *kms, struct drm_file *file) +{ + struct sde_kms *sde_kms = to_sde_kms(kms); + struct drm_device *dev = sde_kms->dev; + struct msm_drm_private *priv = dev->dev_private; + unsigned int i; + struct drm_atomic_state *state = NULL; + struct drm_modeset_acquire_ctx ctx; + int ret = 0; + + /* cancel pending flip event */ + for (i = 0; i < priv->num_crtcs; i++) + sde_crtc_complete_flip(priv->crtcs[i], file); + + drm_modeset_acquire_init(&ctx, 0); +retry: + ret = drm_modeset_lock_all_ctx(dev, &ctx); + if (ret == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } else if (WARN_ON(ret)) { + goto end; + } + + state = drm_atomic_state_alloc(dev); + if (!state) { + ret = -ENOMEM; + goto end; + } + + state->acquire_ctx = &ctx; + + for (i = 0; i < TEARDOWN_DEADLOCK_RETRY_MAX; i++) { + ret = _sde_kms_remove_fbs(sde_kms, file, state); + if (ret != -EDEADLK) + break; + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); + } + +end: + if (state) + drm_atomic_state_put(state); + + SDE_DEBUG("sde preclose done, ret:%d\n", ret); + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); +} + static int _sde_kms_helper_reset_custom_properties(struct sde_kms *sde_kms, struct drm_atomic_state *state) { @@ -3818,6 +3955,7 @@ static const struct msm_kms_funcs kms_funcs = { .irq_postinstall = sde_irq_postinstall, .irq_uninstall = sde_irq_uninstall, .irq = sde_irq, + .preclose = sde_kms_preclose, .lastclose = sde_kms_lastclose, .prepare_fence = sde_kms_prepare_fence, .prepare_commit = sde_kms_prepare_commit,