Эх сурвалжийг харах

disp: msm: sde: avoid connector state mode update

There is a race condition between sdm thread and display thread, when
sdm thread may be accessing the mode_info field while duplicating the
connector state, display thread may be updating the current mode info.
This would lead to the next commit using invalid mode and could cause
wrong hw configuration.
This change removes copying the mode_info in encoder struct while
atomic check phase and also removes accessing the connector mode_info
during mode_set. The encoder struct is now updated at the mode_set
with the cached connector mode.

Change-Id: I069ed592ec017ce4aa5c9c94b340bf94c5e1ebff
Signed-off-by: Abhijit Kulkarni <[email protected]>
Signed-off-by: Samantha Tran <[email protected]>
Abhijit Kulkarni 6 жил өмнө
parent
commit
dcea657cce
1 өөрчлөгдсөн 13 нэмэгдсэн , 18 устгасан
  1. 13 18
      msm/sde/sde_encoder.c

+ 13 - 18
msm/sde/sde_encoder.c

@@ -227,7 +227,8 @@ enum sde_enc_rc_states {
  * @elevated_ahb_vote:		increase AHB bus speed for the first frame
  * @elevated_ahb_vote:		increase AHB bus speed for the first frame
  *				after power collapse
  *				after power collapse
  * @pm_qos_cpu_req:		pm_qos request for cpu frequency
  * @pm_qos_cpu_req:		pm_qos request for cpu frequency
- * @mode_info:                  stores the current mode information
+ * @mode_info:                  stores the current mode and should be used
+ *				 only in commit phase
  */
  */
 struct sde_encoder_virt {
 struct sde_encoder_virt {
 	struct drm_encoder base;
 	struct drm_encoder base;
@@ -658,6 +659,7 @@ void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc,
 		struct drm_connector_state *conn_state)
 		struct drm_connector_state *conn_state)
 {
 {
 	struct sde_encoder_virt *sde_enc = NULL;
 	struct sde_encoder_virt *sde_enc = NULL;
+	struct msm_mode_info mode_info;
 	int i = 0;
 	int i = 0;
 
 
 	if (!hw_res || !drm_enc || !conn_state) {
 	if (!hw_res || !drm_enc || !conn_state) {
@@ -680,8 +682,13 @@ void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc,
 			phys->ops.get_hw_resources(phys, hw_res, conn_state);
 			phys->ops.get_hw_resources(phys, hw_res, conn_state);
 	}
 	}
 
 
-	sde_connector_get_mode_info(conn_state, &sde_enc->mode_info);
-	hw_res->topology = sde_enc->mode_info.topology;
+	/*
+	 * NOTE: Do not use sde_encoder_get_mode_info here as this function is
+	 * called from atomic_check phase. Use the below API to get mode
+	 * information of the temporary conn_state passed
+	 */
+	sde_connector_get_mode_info(conn_state, &mode_info);
+	hw_res->topology = mode_info.topology;
 	hw_res->display_type = sde_enc->disp_info.display_type;
 	hw_res->display_type = sde_enc->disp_info.display_type;
 }
 }
 
 
@@ -2760,8 +2767,6 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
 	struct sde_kms *sde_kms;
 	struct sde_kms *sde_kms;
 	struct list_head *connector_list;
 	struct list_head *connector_list;
 	struct drm_connector *conn = NULL, *conn_iter;
 	struct drm_connector *conn = NULL, *conn_iter;
-	struct sde_connector_state *sde_conn_state = NULL;
-	struct sde_connector *sde_conn = NULL;
 	struct sde_rm_hw_iter dsc_iter, pp_iter, qdss_iter;
 	struct sde_rm_hw_iter dsc_iter, pp_iter, qdss_iter;
 	struct sde_rm_hw_request request_hw;
 	struct sde_rm_hw_request request_hw;
 	enum sde_intf_mode intf_mode;
 	enum sde_intf_mode intf_mode;
@@ -2812,21 +2817,11 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
 		return;
 		return;
 	}
 	}
 
 
-	sde_conn = to_sde_connector(conn);
-	sde_conn_state = to_sde_connector_state(conn->state);
-	if (sde_conn && sde_conn_state) {
-		ret = sde_conn->ops.get_mode_info(&sde_conn->base, adj_mode,
-				&sde_conn_state->mode_info,
-				sde_kms->catalog->max_mixer_width,
-				sde_conn->display);
-		if (ret) {
-			SDE_ERROR_ENC(sde_enc,
-				"failed to get mode info from the display\n");
-			return;
-		}
-	}
 	intf_mode = sde_encoder_get_intf_mode(drm_enc);
 	intf_mode = sde_encoder_get_intf_mode(drm_enc);
 
 
+	/* store the mode_info */
+	sde_connector_get_mode_info(conn->state, &sde_enc->mode_info);
+
 	/* release resources before seamless mode change */
 	/* release resources before seamless mode change */
 	if (msm_is_mode_seamless_dms(adj_mode) ||
 	if (msm_is_mode_seamless_dms(adj_mode) ||
 			(msm_is_mode_seamless_dyn_clk(adj_mode) &&
 			(msm_is_mode_seamless_dyn_clk(adj_mode) &&