Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 12f72767 authored by Ray Zhang's avatar Ray Zhang
Browse files

disp: msm: sde: avoid multiple frame-done encoder events



Currently there is a race condition in checking the
pending_kickoff_cnt in wr_ptr_irq wait from display-thread
and pp_done_irq from interrupt context. In both places,
pending_kickoff_cnt is read first and modified later. In
partial update cases where the frame-transfer is short,
such a race condition might happen and would lead to both
triggering the frame-done/release fence for the same frame.
Fix it by combining read/modify to one statement in both places.

Change-Id: I9162e7dc3f12af3590514f1ebfd68023aa920181
Signed-off-by: default avatarVeera Sundaram Sankaran <veeras@codeaurora.org>
Signed-off-by: default avatarRay Zhang <rayz@codeaurora.org>
parent 5eb64992
Loading
Loading
Loading
Loading
+8 −10
Original line number Diff line number Diff line
@@ -183,10 +183,7 @@ static void _sde_encoder_phys_cmd_update_intf_cfg(
static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)
{
	struct sde_encoder_phys *phys_enc = arg;
	unsigned long lock_flags;
	int new_cnt;
	u32 event = SDE_ENCODER_FRAME_EVENT_DONE |
			SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
	u32 event = 0;

	if (!phys_enc || !phys_enc->hw_pp)
		return;
@@ -195,16 +192,17 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx)

	/* notify all synchronous clients first, then asynchronous clients */
	if (phys_enc->parent_ops.handle_frame_done &&
		atomic_read(&phys_enc->pending_kickoff_cnt))
		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_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
	new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
	spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
		spin_unlock(phys_enc->enc_spinlock);
	}

	SDE_EVT32_IRQ(DRMID(phys_enc->parent),
			phys_enc->hw_pp->idx - PINGPONG_0, new_cnt, event);
			phys_enc->hw_pp->idx - PINGPONG_0, event);

	/* Signal any waiting atomic commit thread */
	wake_up_all(&phys_enc->pending_kickoff_wq);