Przeglądaj źródła

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 <[email protected]>
Jayaprakash Madisetty 3 lat temu
rodzic
commit
182aac6040
3 zmienionych plików z 35 dodań i 10 usunięć
  1. 21 0
      msm/msm_drv.c
  2. 2 0
      msm/msm_drv.h
  3. 12 10
      msm/sde/sde_kms.c

+ 21 - 0
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)

+ 2 - 0
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,

+ 12 - 10
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)