Просмотр исходного кода

disp: msm: sde: add spinlocks to handle_frame_done call

By adding spin locks around the handle frame done, a race
condition, between the wait for idle of one frame, and the pp
done of the next frame, is mitigated.

Change-Id: I78650fc9688b22db6d314b9bed023e0ddad20dbf
Signed-off-by: Nilaan Gunabalachandran <[email protected]>
Nilaan Gunabalachandran 5 лет назад
Родитель
Сommit
47b493a29a
1 измененных файлов с 21 добавлено и 3 удалено
  1. 21 3
      msm/sde/sde_encoder_phys_cmd.c

+ 21 - 3
msm/sde/sde_encoder_phys_cmd.c

@@ -186,8 +186,10 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
 	    atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)) {
 		event = SDE_ENCODER_FRAME_EVENT_DONE |
 			SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
+		spin_lock(phys_enc->enc_spinlock);
 		phys_enc->parent_ops.handle_frame_done(phys_enc->parent,
 				phys_enc, event);
+		spin_unlock(phys_enc->enc_spinlock);
 	}
 
 	SDE_EVT32_IRQ(DRMID(phys_enc->parent),
@@ -285,9 +287,12 @@ static void sde_encoder_phys_cmd_wr_ptr_irq(void *arg, int irq_idx)
 
 	if (atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0)) {
 		event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
-		if (phys_enc->parent_ops.handle_frame_done)
+		if (phys_enc->parent_ops.handle_frame_done) {
+			spin_lock(phys_enc->enc_spinlock);
 			phys_enc->parent_ops.handle_frame_done(
 					phys_enc->parent, phys_enc, event);
+			spin_unlock(phys_enc->enc_spinlock);
+		}
 	}
 
 	sde_encoder_helper_get_pp_line_count(phys_enc->parent, info);
@@ -467,6 +472,7 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
 	struct drm_connector *conn;
 	int event;
 	u32 pending_kickoff_cnt;
+	unsigned long lock_flags;
 
 	if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_ctl)
 		return -EINVAL;
@@ -523,9 +529,12 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
 	phys_enc->enable_state = SDE_ENC_ERR_NEEDS_HW_RESET;
 
 exit:
-	if (phys_enc->parent_ops.handle_frame_done)
+	if (phys_enc->parent_ops.handle_frame_done) {
+		spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
 		phys_enc->parent_ops.handle_frame_done(
 				phys_enc->parent, phys_enc, frame_event);
+		spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+	}
 
 	return -ETIMEDOUT;
 }
@@ -664,6 +673,7 @@ static int _sde_encoder_phys_cmd_wait_for_idle(
 	int ret;
 	struct sde_hw_ctl *ctl;
 	bool wr_ptr_wait_success = true;
+	unsigned long lock_flags;
 
 	if (!phys_enc) {
 		SDE_ERROR("invalid encoder\n");
@@ -682,10 +692,12 @@ static int _sde_encoder_phys_cmd_wait_for_idle(
 	    atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0) &&
 	    phys_enc->parent_ops.handle_frame_done) {
 
+		spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
 		phys_enc->parent_ops.handle_frame_done(
 			phys_enc->parent, phys_enc,
 			SDE_ENCODER_FRAME_EVENT_DONE |
 			SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE);
+		spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
 		return 0;
 	}
 
@@ -1466,6 +1478,7 @@ static int _sde_encoder_phys_cmd_handle_wr_ptr_timeout(
 			to_sde_encoder_phys_cmd(phys_enc);
 	bool switch_te;
 	int ret = -ETIMEDOUT;
+	unsigned long lock_flags;
 
 	switch_te = _sde_encoder_phys_cmd_needs_vsync_change(
 				phys_enc, profile_timestamp);
@@ -1495,10 +1508,15 @@ static int _sde_encoder_phys_cmd_handle_wr_ptr_timeout(
 		SDE_EVT32(DRMID(phys_enc->parent), switch_te, SDE_EVTLOG_ERROR);
 
 		if (sde_encoder_phys_cmd_is_master(phys_enc) &&
-		  atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0))
+			atomic_add_unless(
+			&phys_enc->pending_retire_fence_cnt, -1, 0)) {
+			spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
 			phys_enc->parent_ops.handle_frame_done(
 				phys_enc->parent, phys_enc,
 				SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
+			spin_unlock_irqrestore(phys_enc->enc_spinlock,
+				lock_flags);
+		}
 	}
 
 	cmd_enc->wr_ptr_wait_success = (ret == 0) ? true : false;