Bladeren bron

disp: msm: sde: remove fb's attached to a drm_file in preclose

This change avoids upstream drm issuing drm_atomic_commit in
drm_fb_release which is leading to artifacts on screen or
atomic_check failures due to atomically unstaging each fb
from plane_state and committing remaining planes on hardware.

 a) This patch moves the state operations for setting crtc to
    connector state to a helper api.
 b) This patch clears any dim_layers present in the crtc_state
    as part of null commit.
 c) This patch removes any framebuffers attached to a drm_file
    in msm_preclose whose refcount is not managed by composer kill
    inadvertently and issues null flush to hardware in such cases.
 d) This patch handles msm_preclose as part of msm_release
    operation since legacy feature is not supported
    for msm_driver.

Change-Id: Ib2068d74d4b23b73b7c84544858c9f6bb6adfa67
Signed-off-by: Jayaprakash Madisetty <[email protected]>
Signed-off-by: Samantha Tran <[email protected]>
Jayaprakash Madisetty 4 jaren geleden
bovenliggende
commit
0e3d422520
4 gewijzigde bestanden met toevoegingen van 111 en 45 verwijderingen
  1. 9 1
      msm/msm_drv.c
  2. 6 7
      msm/sde/sde_crtc.c
  3. 6 0
      msm/sde/sde_crtc.h
  4. 90 37
      msm/sde/sde_kms.c

+ 9 - 1
msm/msm_drv.c

@@ -45,6 +45,7 @@
 #include <drm/drm_ioctl.h>
 #include <drm/drm_vblank.h>
 #include <drm/drm_drv.h>
+#include <drm/drm_auth.h>
 #include <drm/drm_probe_helper.h>
 
 #include "msm_drv.h"
@@ -1480,6 +1481,14 @@ static int msm_release(struct inode *inode, struct file *filp)
 		kfree(node);
 	}
 
+	/**
+	 * Handle preclose operation here for removing fb's whose
+	 * refcount > 1. This operation is not triggered from upstream
+	 * drm as msm_driver does not support DRIVER_LEGACY feature.
+	 */
+	if (drm_is_current_master(file_priv))
+		msm_preclose(dev, file_priv);
+
 	return drm_release(inode, filp);
 }
 
@@ -1684,7 +1693,6 @@ 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,

+ 6 - 7
msm/sde/sde_crtc.c

@@ -2831,17 +2831,16 @@ static void _sde_crtc_set_input_fence_timeout(struct sde_crtc_state *cstate)
 	cstate->input_fence_timeout_ns *= NSEC_PER_MSEC;
 }
 
-/**
- * _sde_crtc_clear_dim_layers_v1 - clear all dim layer settings
- * @cstate:      Pointer to sde crtc state
- */
-static void _sde_crtc_clear_dim_layers_v1(struct sde_crtc_state *cstate)
+void _sde_crtc_clear_dim_layers_v1(struct drm_crtc_state *state)
 {
 	u32 i;
+	struct sde_crtc_state *cstate;
 
-	if (!cstate)
+	if (!state)
 		return;
 
+	cstate = to_sde_crtc_state(state);
+
 	for (i = 0; i < cstate->num_dim_layers; i++)
 		memset(&cstate->dim_layer[i], 0, sizeof(cstate->dim_layer[i]));
 
@@ -2870,7 +2869,7 @@ static void _sde_crtc_set_dim_layer_v1(struct drm_crtc *crtc,
 
 	if (!usr_ptr) {
 		/* usr_ptr is null when setting the default property value */
-		_sde_crtc_clear_dim_layers_v1(cstate);
+		_sde_crtc_clear_dim_layers_v1(&cstate->base);
 		SDE_DEBUG("dim_layer data removed\n");
 		goto clear;
 	}

+ 6 - 0
msm/sde/sde_crtc.h

@@ -1022,4 +1022,10 @@ void sde_crtc_reset_sw_state(struct drm_crtc *crtc);
 */
 void sde_crtc_disable_cp_features(struct drm_crtc *crtc);
 
+/*
+ * _sde_crtc_clear_dim_layers_v1 - clear all dim layer settings
+ * @cstate:      Pointer to drm crtc state
+ */
+void _sde_crtc_clear_dim_layers_v1(struct drm_crtc_state *state);
+
 #endif /* _SDE_CRTC_H_ */

+ 90 - 37
msm/sde/sde_kms.c

@@ -2396,6 +2396,71 @@ static void sde_kms_destroy(struct msm_kms *kms)
 	kfree(sde_kms);
 }
 
+static void sde_kms_helper_clear_dim_layers(struct drm_atomic_state *state, struct drm_crtc *crtc)
+{
+	struct drm_crtc_state *crtc_state = NULL;
+	struct sde_crtc_state *c_state;
+
+	if (!state || !crtc) {
+		SDE_ERROR("invalid params\n");
+		return;
+	}
+
+	crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+	c_state = to_sde_crtc_state(crtc_state);
+
+	_sde_crtc_clear_dim_layers_v1(crtc_state);
+	set_bit(SDE_CRTC_DIRTY_DIM_LAYERS, c_state->dirty);
+}
+
+static int sde_kms_set_crtc_for_conn(struct drm_device *dev,
+		struct drm_encoder *enc, struct drm_atomic_state *state)
+{
+	struct drm_connector *conn = NULL;
+	struct drm_connector *tmp_conn = NULL;
+	struct drm_connector_list_iter conn_iter;
+	struct drm_crtc_state *crtc_state = NULL;
+	struct drm_connector_state *conn_state = NULL;
+	int ret = 0;
+
+	drm_connector_list_iter_begin(dev, &conn_iter);
+	drm_for_each_connector_iter(tmp_conn, &conn_iter) {
+		if (enc == tmp_conn->state->best_encoder) {
+			conn = tmp_conn;
+			break;
+		}
+	}
+	drm_connector_list_iter_end(&conn_iter);
+
+	if (!conn || !enc->crtc) {
+		SDE_ERROR("invalid params for enc:%d\n", DRMID(enc));
+		return -EINVAL;
+	}
+
+	crtc_state = drm_atomic_get_crtc_state(state, enc->crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		SDE_ERROR("error %d getting crtc %d state\n",
+				ret, DRMID(enc->crtc));
+		return ret;
+	}
+
+	conn_state = drm_atomic_get_connector_state(state, conn);
+	if (IS_ERR(conn_state)) {
+		ret = PTR_ERR(conn_state);
+		SDE_ERROR("error %d getting connector %d state\n",
+				ret, DRMID(conn));
+		return ret;
+	}
+
+	crtc_state->active = true;
+	ret = drm_atomic_set_crtc_for_connector(conn_state, enc->crtc);
+	if (ret)
+		SDE_ERROR("error %d setting the crtc\n", ret);
+
+	return ret;
+}
+
 static void _sde_kms_plane_force_remove(struct drm_plane *plane,
 			struct drm_atomic_state *state)
 {
@@ -2429,8 +2494,9 @@ static int _sde_kms_remove_fbs(struct sde_kms *sde_kms, struct drm_file *file,
 	struct drm_framebuffer *fb, *tfb;
 	struct list_head fbs;
 	struct drm_plane *plane;
+	struct drm_crtc *crtc = NULL;
+	unsigned int crtc_mask = 0;
 	int ret = 0;
-	u32 plane_mask = 0;
 
 	INIT_LIST_HEAD(&fbs);
 
@@ -2439,11 +2505,10 @@ static int _sde_kms_remove_fbs(struct sde_kms *sde_kms, struct drm_file *file,
 			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);
+				if (plane->state && plane->state->fb == fb) {
+					if (plane->state->crtc)
+						crtc_mask |= drm_crtc_mask(plane->state->crtc);
+					_sde_kms_plane_force_remove(plane, state);
 				}
 			}
 		} else {
@@ -2454,13 +2519,28 @@ static int _sde_kms_remove_fbs(struct sde_kms *sde_kms, struct drm_file *file,
 
 	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");
+	drm_for_each_crtc(crtc, dev) {
+		if ((crtc_mask & drm_crtc_mask(crtc)) && crtc->state->active) {
+			struct drm_encoder *drm_enc;
+
+			drm_for_each_encoder_mask(drm_enc, crtc->dev,
+					crtc->state->encoder_mask) {
+				ret = sde_kms_set_crtc_for_conn(dev, drm_enc, state);
+				if (ret)
+					goto error;
+			}
+			sde_kms_helper_clear_dim_layers(state, crtc);
+		}
+	}
+
+	SDE_EVT32(state, crtc_mask);
+	SDE_DEBUG("null commit after removing all the pipes\n");
 	ret = drm_atomic_commit(state);
 
+error:
 	if (ret) {
 		/*
 		 * move the fbs back to original list, so it would be
@@ -3584,12 +3664,7 @@ static void _sde_kms_null_commit(struct drm_device *dev,
 		struct drm_encoder *enc)
 {
 	struct drm_modeset_acquire_ctx ctx;
-	struct drm_connector *conn = NULL;
-	struct drm_connector *tmp_conn = NULL;
-	struct drm_connector_list_iter conn_iter;
 	struct drm_atomic_state *state = NULL;
-	struct drm_crtc_state *crtc_state = NULL;
-	struct drm_connector_state *conn_state = NULL;
 	int retry_cnt = 0;
 	int ret = 0;
 
@@ -3613,32 +3688,10 @@ retry:
 	}
 
 	state->acquire_ctx = &ctx;
-	drm_connector_list_iter_begin(dev, &conn_iter);
-	drm_for_each_connector_iter(tmp_conn, &conn_iter) {
-		if (enc == tmp_conn->state->best_encoder) {
-			conn = tmp_conn;
-			break;
-		}
-	}
-	drm_connector_list_iter_end(&conn_iter);
 
-	if (!conn) {
-		SDE_ERROR("error in finding conn for enc:%d\n", DRMID(enc));
-		goto end;
-	}
-
-	crtc_state = drm_atomic_get_crtc_state(state, enc->crtc);
-	conn_state = drm_atomic_get_connector_state(state, conn);
-	if (IS_ERR(conn_state)) {
-		SDE_ERROR("error %d getting connector %d state\n",
-				ret, DRMID(conn));
-		goto end;
-	}
-
-	crtc_state->active = true;
-	ret = drm_atomic_set_crtc_for_connector(conn_state, enc->crtc);
+	ret = sde_kms_set_crtc_for_conn(dev, enc, state);
 	if (ret)
-		SDE_ERROR("error %d setting the crtc\n", ret);
+		goto end;
 
 	ret = drm_atomic_commit(state);
 	if (ret)