Explorar o código

disp: msm: sde: add pending ctl recovery mask in sde_kms

This change adds pending ctl recovery mask in sde kms
structure to check if there are any ctl paths pending
for recovery and stages only border fill during such
conditions to avoid device crash. Below is the issue
sequence observed during the crash:

1) On one of the ctl path, flush didn't take effect and
flush bits are still pending.

2) It was a NULL flush and last good flush on that
interface has DMA2 pipe staged along with other pipes.

3) Different ctl path re-uses the DMA2 pipe (attached to
ctl path in #1) causing wr_ptr timeout followed by
ppdone timeout.

Change-Id: I07eb9f2fe41f59963dc27655c551c05abe240392
Signed-off-by: Yashwanth <[email protected]>
Yashwanth %!s(int64=4) %!d(string=hai) anos
pai
achega
e96e5bd074
Modificáronse 3 ficheiros con 48 adicións e 2 borrados
  1. 10 2
      msm/sde/sde_crtc.c
  2. 27 0
      msm/sde/sde_kms.c
  3. 11 0
      msm/sde/sde_kms.h

+ 10 - 2
msm/sde/sde_crtc.c

@@ -3892,8 +3892,11 @@ int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state,
 	}
 
 	/* Early out if simple ctl reset succeeded */
-	if (i == sde_crtc->num_ctls)
+	if (i == sde_crtc->num_ctls) {
+		sde_kms_update_recovery_mask(_sde_crtc_get_kms(crtc),
+			crtc, false);
 		return 0;
+	}
 
 	SDE_DEBUG("crtc%d: issuing hard reset\n", DRMID(crtc));
 
@@ -3951,6 +3954,8 @@ int sde_crtc_reset_hw(struct drm_crtc *crtc, struct drm_crtc_state *old_state,
 			sde_encoder_kickoff(encoder, false, true);
 	}
 
+	sde_kms_update_recovery_mask(_sde_crtc_get_kms(crtc),
+			crtc, false);
 	/* panic the device if VBIF is not in good state */
 	return !recovery_events ? 0 : -EAGAIN;
 }
@@ -4025,6 +4030,8 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
 						params.recovery_events_enabled))
 			is_error = true;
 		sde_crtc->needs_hw_reset = false;
+	} else {
+		sde_kms_update_recovery_mask(sde_kms, crtc, false);
 	}
 
 	sde_crtc_calc_fps(sde_crtc);
@@ -4045,9 +4052,10 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
 
 	sde_vbif_clear_errors(sde_kms);
 
-	if (is_error) {
+	if (is_error || sde_kms->recovery_mask) {
 		_sde_crtc_remove_pipe_flush(crtc);
 		_sde_crtc_blend_setup(crtc, old_state, false);
+		SDE_EVT32(sde_kms->recovery_mask);
 	}
 
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {

+ 27 - 0
msm/sde/sde_kms.c

@@ -1531,6 +1531,31 @@ static void sde_kms_complete_commit(struct msm_kms *kms,
 	SDE_ATRACE_END("sde_kms_complete_commit");
 }
 
+void sde_kms_update_recovery_mask(struct sde_kms *sde_kms,
+		struct drm_crtc *crtc, bool flag)
+{
+	int i;
+	struct sde_hw_ctl *ctl;
+	struct sde_crtc *sde_crtc;
+
+	if (!crtc || !sde_kms) {
+		SDE_ERROR("invalid params\n");
+		return;
+	}
+
+	sde_crtc = to_sde_crtc(crtc);
+
+	for (i = 0; i < sde_crtc->num_ctls; ++i) {
+		ctl = sde_crtc->mixers[i].hw_ctl;
+		if (!ctl || !ctl->ops.reset)
+			continue;
+		if (flag)
+			sde_kms->recovery_mask |= BIT(ctl->idx - CTL_0);
+		else
+			sde_kms->recovery_mask &= ~BIT(ctl->idx - CTL_0);
+	}
+}
+
 static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
 		struct drm_crtc *crtc)
 {
@@ -1580,6 +1605,8 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
 		ret = sde_encoder_wait_for_event(encoder, MSM_ENC_COMMIT_DONE);
 		if (ret && ret != -EWOULDBLOCK) {
 			SDE_ERROR("wait for commit done returned %d\n", ret);
+			sde_kms_update_recovery_mask(to_sde_kms(kms),
+				crtc, true);
 			sde_crtc_request_frame_reset(crtc);
 			break;
 		}

+ 11 - 0
msm/sde/sde_kms.h

@@ -274,6 +274,7 @@ struct sde_kms {
 	int irq_num;	/* mdss irq number */
 	bool irq_enabled;
 
+	int recovery_mask;
 	struct sde_core_perf perf;
 
 	/* saved atomic state during system suspend */
@@ -764,4 +765,14 @@ int sde_kms_vm_trusted_prepare_commit(struct sde_kms *sde_kms,
  */
 int sde_kms_vm_primary_prepare_commit(struct sde_kms *sde_kms,
 					   struct drm_atomic_state *state);
+
+/**
+ * sde_kms_update_recovery_mask - function to update recovery ctl mask
+ *				  during error cases
+ * @sde_kms: pointer to sde_kms
+ * @crtc: pointer to drm_crtc
+ * @flag: to determine whether to clear/set recovery mask
+ */
+void sde_kms_update_recovery_mask(struct sde_kms *sde_kms,
+					struct drm_crtc *crtc, bool flag);
 #endif /* __sde_kms_H__ */