disp: msm: sde: avoid race on in_clone_mode flag in wb encoder
The issue scenario is as follows: 1. User space issues CWB commit N-1, frame got picked up and wr_ptr_irq is received. 2. Next commit N CWB disable commit is programmed waits for N-1 wb_done irq. 3. The kickoff count is decremented on wb_done_irq of commit N-1 and wb wait_for_idle is exited. 4. wb_frame_done irq thread execution stalled before populating fences and commit thread execution continues. 5. wb_reset disables in_clone_mode flag, the stalled wb_done_irq thread resumes its execution and signals the release fences on primary crtc. 6. Commit N-1 frame_done irq is received and release fences is signaled again. Made changes to avoid the race between irq thread and commit thread over in_clone_mode flag, by adding a lock over wb physical encoder. Change-Id: Iba9b6613c49d413239c9603228fe16b0d64c0ab6 Signed-off-by: Andhavarapu Karthik <quic_kartkart@quicinc.com>
This commit is contained in:
@@ -1814,11 +1814,13 @@ static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error)
|
||||
struct sde_encoder_phys *phys_enc = &wb_enc->base;
|
||||
u32 event = frame_error ? SDE_ENCODER_FRAME_EVENT_ERROR : 0;
|
||||
u32 ubwc_error = 0;
|
||||
unsigned long flags;
|
||||
|
||||
/* don't notify upper layer for internal commit */
|
||||
if (phys_enc->enable_state == SDE_ENC_DISABLING && !phys_enc->in_clone_mode)
|
||||
goto end;
|
||||
|
||||
spin_lock_irqsave(phys_enc->enc_spinlock, flags);
|
||||
if (phys_enc->parent_ops.handle_frame_done &&
|
||||
atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)) {
|
||||
event |= SDE_ENCODER_FRAME_EVENT_DONE;
|
||||
@@ -1840,9 +1842,11 @@ static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error)
|
||||
| SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
|
||||
else
|
||||
event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
|
||||
|
||||
phys_enc->parent_ops.handle_frame_done(phys_enc->parent, phys_enc, event);
|
||||
}
|
||||
spin_unlock_irqrestore(phys_enc->enc_spinlock, flags);
|
||||
|
||||
if (event & SDE_ENCODER_FRAME_EVENT_DONE)
|
||||
phys_enc->parent_ops.handle_frame_done(phys_enc->parent, phys_enc, event);
|
||||
|
||||
if (!phys_enc->in_clone_mode && phys_enc->parent_ops.handle_vblank_virt)
|
||||
phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent, phys_enc);
|
||||
@@ -2251,12 +2255,15 @@ end:
|
||||
static int sde_encoder_phys_wb_wait_for_tx_complete(struct sde_encoder_phys *phys_enc)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (atomic_read(&phys_enc->pending_kickoff_cnt))
|
||||
rc = _sde_encoder_phys_wb_wait_for_idle(phys_enc, true);
|
||||
|
||||
if ((phys_enc->enable_state == SDE_ENC_DISABLING) && phys_enc->in_clone_mode) {
|
||||
spin_lock_irqsave(phys_enc->enc_spinlock, flags);
|
||||
_sde_encoder_phys_wb_reset_state(phys_enc);
|
||||
spin_unlock_irqrestore(phys_enc->enc_spinlock, flags);
|
||||
sde_encoder_phys_wb_irq_ctrl(phys_enc, false);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user