drm/msm/sde: fix race condition with mdp clk and bw vote update

Current driver has a race condition between the
commit and the validate, where the mdp clock or
the bandwidth can be updated for voting before
the actual configuration is taking place.
This is a problem when the validation is being
done for performance numbers that are lower than
what HW requires in the on-going configuration.
Fix this issue by caching the performance values
in the crtc for all the time that the current hw
configuration is on-going.

Change-Id: I898cfd03b8077a2f0fb7c7c14a0d5ce17f15bde4
Signed-off-by: Ingrid Gallardo <ingridg@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/sde/sde_core_perf.c b/drivers/gpu/drm/msm/sde/sde_core_perf.c
index 9ddca8c..6b36745 100644
--- a/drivers/gpu/drm/msm/sde/sde_core_perf.c
+++ b/drivers/gpu/drm/msm/sde/sde_core_perf.c
@@ -169,6 +169,7 @@
 		perf->core_clk_rate = kms->perf.fix_core_clk_rate;
 	}
 
+	SDE_EVT32(crtc->base.id, perf->core_clk_rate);
 	SDE_DEBUG(
 		"crtc=%d clk_rate=%llu core_ib=%llu core_ab=%llu llcc_ib=%llu llcc_ab=%llu mem_ib=%llu mem_ab=%llu\n",
 			crtc->base.id, perf->core_clk_rate,
@@ -293,7 +294,8 @@
 }
 
 static void _sde_core_perf_crtc_update_bus(struct sde_kms *kms,
-		struct drm_crtc *crtc, u32 bus_id)
+		struct drm_crtc *crtc, u32 bus_id,
+		struct sde_core_perf_params *crtc_perf)
 {
 	u64 bw_sum_of_intfs = 0, bus_ab_quota, bus_ib_quota;
 	struct sde_core_perf_params perf = { { 0 } };
@@ -303,21 +305,36 @@
 	struct sde_crtc_state *sde_cstate;
 	struct msm_drm_private *priv = kms->dev->dev_private;
 
+	u64 tmp_max_per_pipe_ib;
+	u64 tmp_bw_ctl;
+
 	drm_for_each_crtc(tmp_crtc, crtc->dev) {
 		if (_sde_core_perf_crtc_is_power_on(tmp_crtc) &&
 		    _is_crtc_client_type_matches(tmp_crtc, curr_client_type,
 								&kms->perf)) {
-			sde_cstate = to_sde_crtc_state(tmp_crtc->state);
+
+			if (crtc->base.id == tmp_crtc->base.id) {
+				/* for current crtc use the cached values */
+				tmp_max_per_pipe_ib =
+					crtc_perf->max_per_pipe_ib[bus_id];
+				tmp_bw_ctl = crtc_perf->bw_ctl[bus_id];
+			} else {
+				sde_cstate = to_sde_crtc_state(tmp_crtc->state);
+				tmp_max_per_pipe_ib =
+				  sde_cstate->new_perf.max_per_pipe_ib[bus_id];
+				tmp_bw_ctl =
+				  sde_cstate->new_perf.bw_ctl[bus_id];
+			}
 
 			perf.max_per_pipe_ib[bus_id] =
 				max(perf.max_per_pipe_ib[bus_id],
-				sde_cstate->new_perf.max_per_pipe_ib[bus_id]);
+				tmp_max_per_pipe_ib);
 
-			bw_sum_of_intfs += sde_cstate->new_perf.bw_ctl[bus_id];
+			bw_sum_of_intfs += tmp_bw_ctl;
 
-			SDE_DEBUG("crtc=%d bus_id=%d bw=%llu\n",
+			SDE_DEBUG("crtc=%d bus_id=%d bw=%llu perf_pipe:%llu\n",
 				tmp_crtc->base.id, bus_id,
-				sde_cstate->new_perf.bw_ctl[bus_id]);
+				tmp_bw_ctl, tmp_max_per_pipe_ib);
 		}
 	}
 
@@ -442,22 +459,32 @@
 		SDE_DEBUG("Release BW crtc=%d\n", crtc->base.id);
 		for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
 			sde_crtc->cur_perf.bw_ctl[i] = 0;
-			_sde_core_perf_crtc_update_bus(kms, crtc, i);
+			_sde_core_perf_crtc_update_bus(kms, crtc, i,
+				&sde_crtc->cur_perf);
 		}
 	}
 }
 
-static u64 _sde_core_perf_get_core_clk_rate(struct sde_kms *kms)
+static u64 _sde_core_perf_get_core_clk_rate(struct sde_kms *kms,
+	struct sde_core_perf_params *crct_perf, struct drm_crtc *crtc)
 {
 	u64 clk_rate = kms->perf.perf_tune.min_core_clk;
-	struct drm_crtc *crtc;
+	struct drm_crtc *tmp_crtc;
 	struct sde_crtc_state *sde_cstate;
+	u64 tmp_rate;
 
-	drm_for_each_crtc(crtc, kms->dev) {
-		if (_sde_core_perf_crtc_is_power_on(crtc)) {
-			sde_cstate = to_sde_crtc_state(crtc->state);
-			clk_rate = max(sde_cstate->new_perf.core_clk_rate,
-							clk_rate);
+	drm_for_each_crtc(tmp_crtc, kms->dev) {
+		if (_sde_core_perf_crtc_is_power_on(tmp_crtc)) {
+
+			if (crtc->base.id == tmp_crtc->base.id) {
+				/* for current CRTC, use the cached value */
+				tmp_rate = crct_perf->core_clk_rate;
+			} else {
+				sde_cstate = to_sde_crtc_state(tmp_crtc->state);
+				tmp_rate = sde_cstate->new_perf.core_clk_rate;
+			}
+			clk_rate = max(tmp_rate, clk_rate);
+
 			clk_rate = clk_round_rate(kms->perf.core_clk, clk_rate);
 		}
 	}
@@ -504,8 +531,17 @@
 	SDE_DEBUG("crtc:%d stop_req:%d core_clk:%llu\n",
 			crtc->base.id, stop_req, kms->perf.core_clk_rate);
 
+	/*
+	 * cache the performance numbers in the crtc prior to the
+	 * crtc kickoff, so the same numbers are used during the
+	 * perf update that happens post kickoff.
+	 */
+	if (params_changed)
+		memcpy(&sde_crtc->new_perf, &sde_cstate->new_perf,
+			sizeof(struct sde_core_perf_params));
+
 	old = &sde_crtc->cur_perf;
-	new = &sde_cstate->new_perf;
+	new = &sde_crtc->new_perf;
 
 	if (_sde_core_perf_crtc_is_power_on(crtc) && !stop_req) {
 		for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
@@ -580,7 +616,7 @@
 
 	for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) {
 		if (update_bus & BIT(i))
-			_sde_core_perf_crtc_update_bus(kms, crtc, i);
+			_sde_core_perf_crtc_update_bus(kms, crtc, i, old);
 	}
 
 	/*
@@ -588,9 +624,10 @@
 	 * bandwidth is available before clock rate is increased.
 	 */
 	if (update_clk) {
-		clk_rate = _sde_core_perf_get_core_clk_rate(kms);
+		clk_rate = _sde_core_perf_get_core_clk_rate(kms, old, crtc);
 
-		SDE_EVT32(kms->dev, stop_req, clk_rate);
+		SDE_EVT32(kms->dev, stop_req, clk_rate, params_changed,
+			old->core_clk_rate, new->core_clk_rate);
 		ret = sde_power_clk_set_rate(&priv->phandle,
 				kms->perf.clk_name, clk_rate);
 		if (ret) {
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index dd18b63..e14e635 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -277,6 +277,7 @@
 	struct sde_power_event *power_event;
 
 	struct sde_core_perf_params cur_perf;
+	struct sde_core_perf_params new_perf;
 
 	struct mutex rp_lock;
 	struct list_head rp_head;