From 182aac6040a752624958a9b8522b242f3fbf4e32 Mon Sep 17 00:00:00 2001 From: Jayaprakash Madisetty Date: Wed, 16 Feb 2022 19:50:08 +0530 Subject: [PATCH] disp: msm: cancel all delayed_works before triggering msm_lastclose This patch cancels all the delayed_off_works if scheduled and flushes the display threads for completion during msm_lastclose. The commit from msm_lastclose client modeset to disable any crtcs if enabled is always scheduled on primary crtc_commit thread. In the current issue, delayed_off_work is scheduled on secondary display crtc_commit thread and primary crtc_commit thread is scheduled to turn off active crtcs from msm_lastclose leading to null dereference access of sde_enc's cur_master. This race is avoided by serializing the operations in msm_lastclose. Change-Id: I30cc95b925c8134f0064816ebe2cfdb86a49fb36 Signed-off-by: Jayaprakash Madisetty --- msm/msm_drv.c | 21 +++++++++++++++++++++ msm/msm_drv.h | 2 ++ msm/sde/sde_kms.c | 22 ++++++++++++---------- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/msm/msm_drv.c b/msm/msm_drv.c index 70b803da14..0b0d707176 100644 --- a/msm/msm_drv.c +++ b/msm/msm_drv.c @@ -1040,6 +1040,25 @@ mdss_init_fail: return ret; } +void msm_atomic_flush_display_threads(struct msm_drm_private *priv) +{ + int i; + + if (!priv) { + SDE_ERROR("invalid private data\n"); + return; + } + + for (i = 0; i < priv->num_crtcs; i++) { + if (priv->disp_thread[i].thread) + kthread_flush_worker(&priv->disp_thread[i].worker); + if (priv->event_thread[i].thread) + kthread_flush_worker(&priv->event_thread[i].worker); + } + + kthread_flush_worker(&priv->pp_event_worker); +} + /* * DRM operations: */ @@ -1165,6 +1184,8 @@ static void msm_lastclose(struct drm_device *dev) DRM_INFO("wait for crtc mask 0x%x failed, commit anyway...\n", priv->pending_crtcs); + msm_atomic_flush_display_threads(priv); + if (priv->fbdev) { rc = drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev); if (rc) diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 2a7c001052..16e91cb049 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -1115,6 +1115,8 @@ struct drm_atomic_state *msm_atomic_state_alloc(struct drm_device *dev); void msm_atomic_state_clear(struct drm_atomic_state *state); void msm_atomic_state_free(struct drm_atomic_state *state); +void msm_atomic_flush_display_threads(struct msm_drm_private *priv); + int msm_gem_init_vma(struct msm_gem_address_space *aspace, struct msm_gem_vma *vma, int npages); void msm_gem_unmap_vma(struct msm_gem_address_space *aspace, diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index e176b1aa17..45cd994f90 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -2655,6 +2655,11 @@ error: drm_framebuffer_put(fb); } + drm_for_each_crtc(crtc, dev) { + if (!ret && crtc_mask & drm_crtc_mask(crtc)) + sde_kms_cancel_delayed_work(crtc); + } + end: return ret; } @@ -3881,6 +3886,7 @@ static int sde_kms_trigger_null_flush(struct msm_kms *kms) { struct sde_kms *sde_kms; struct sde_splash_display *splash_display; + struct drm_crtc *crtc; int i, rc = 0; if (!kms) { @@ -3898,10 +3904,14 @@ static int sde_kms_trigger_null_flush(struct msm_kms *kms) splash_display = &sde_kms->splash_data.splash_display[i]; if (splash_display->cont_splash_enabled && splash_display->encoder) { + crtc = splash_display->encoder->crtc; SDE_DEBUG("triggering null commit on enc:%d\n", DRMID(splash_display->encoder)); SDE_EVT32(DRMID(splash_display->encoder), SDE_EVTLOG_FUNC_ENTRY); rc = _sde_kms_null_commit(sde_kms->dev, splash_display->encoder); + + if (!rc && crtc) + sde_kms_cancel_delayed_work(crtc); } } @@ -3911,7 +3921,7 @@ static int sde_kms_trigger_null_flush(struct msm_kms *kms) static void _sde_kms_pm_suspend_idle_helper(struct sde_kms *sde_kms, struct device *dev) { - int i, ret, crtc_id = 0; + int ret, crtc_id = 0; struct drm_device *ddev = dev_get_drvdata(dev); struct drm_connector *conn; struct drm_connector_list_iter conn_iter; @@ -3948,15 +3958,7 @@ static void _sde_kms_pm_suspend_idle_helper(struct sde_kms *sde_kms, } drm_connector_list_iter_end(&conn_iter); - for (i = 0; i < priv->num_crtcs; i++) { - if (priv->disp_thread[i].thread) - kthread_flush_worker( - &priv->disp_thread[i].worker); - if (priv->event_thread[i].thread) - kthread_flush_worker( - &priv->event_thread[i].worker); - } - kthread_flush_worker(&priv->pp_event_worker); + msm_atomic_flush_display_threads(priv); } struct msm_display_mode *sde_kms_get_msm_mode(struct drm_connector_state *conn_state)