diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 8a708f4862..6a4f0b9735 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -481,12 +481,9 @@ int sde_encoder_helper_wait_for_irq(struct sde_encoder_phys *phys_enc, unsigned long flags; SDE_EVT32(DRMID(phys_enc->parent), intr_idx, - irq->hw_idx, irq->irq_idx, - phys_enc->hw_pp->idx - PINGPONG_0, - atomic_read(wait_info->atomic_cnt)); - SDE_DEBUG_PHYS(phys_enc, - "done but irq %d not triggered\n", - irq->irq_idx); + irq->hw_idx, irq->irq_idx, phys_enc->hw_pp->idx - PINGPONG_0, + atomic_read(wait_info->atomic_cnt), SDE_EVTLOG_FUNC_CASE1); + SDE_DEBUG_PHYS(phys_enc, "done but irq %d not triggered\n", irq->irq_idx); local_irq_save(flags); irq->cb.func(phys_enc, irq->irq_idx); local_irq_restore(flags); @@ -503,7 +500,7 @@ int sde_encoder_helper_wait_for_irq(struct sde_encoder_phys *phys_enc, ret = 0; SDE_EVT32(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, irq->irq_idx, phys_enc->hw_pp->idx - PINGPONG_0, - atomic_read(wait_info->atomic_cnt)); + atomic_read(wait_info->atomic_cnt), SDE_EVTLOG_FUNC_CASE2); } SDE_EVT32_VERBOSE(DRMID(phys_enc->parent), intr_idx, irq->hw_idx, @@ -5573,8 +5570,13 @@ int sde_encoder_wait_for_event(struct drm_encoder *drm_enc, SDE_ATRACE_BEGIN(atrace_buf); ret = fn_wait(phys); SDE_ATRACE_END(atrace_buf); - if (ret) + if (ret) { + SDE_ERROR_ENC(sde_enc, "intf_type:%d, event:%d i:%d, failed:%d\n", + sde_enc->disp_info.intf_type, event, i, ret); + SDE_EVT32(DRMID(drm_enc), sde_enc->disp_info.intf_type, event, + i, ret, SDE_EVTLOG_ERROR); return ret; + } } } diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index 6b2cdeeea1..305ceb0d31 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -888,17 +888,21 @@ static int _sde_encoder_phys_vid_wait_for_vblank( struct sde_encoder_phys *phys_enc, bool notify) { struct sde_encoder_wait_info wait_info = {0}; - int ret = 0; + int ret = 0, new_cnt; u32 event = SDE_ENCODER_FRAME_EVENT_ERROR | SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE | SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE; struct drm_connector *conn; + struct sde_hw_ctl *hw_ctl; + u32 flush_register = 0xebad; + bool timeout = false; - if (!phys_enc) { + if (!phys_enc || !phys_enc->hw_ctl) { pr_err("invalid encoder\n"); return -EINVAL; } + hw_ctl = phys_enc->hw_ctl; conn = phys_enc->connector; wait_info.wq = &phys_enc->pending_kickoff_wq; @@ -909,20 +913,36 @@ static int _sde_encoder_phys_vid_wait_for_vblank( ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_VSYNC, &wait_info); - if (notify && (ret == -ETIMEDOUT) && - atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0) && - phys_enc->parent_ops.handle_frame_done) { - phys_enc->parent_ops.handle_frame_done( - phys_enc->parent, phys_enc, event); + if (ret == -ETIMEDOUT) { + new_cnt = atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0); + timeout = true; - if (sde_encoder_recovery_events_enabled(phys_enc->parent)) - sde_connector_event_notify(conn, - DRM_EVENT_SDE_HW_RECOVERY, + /* + * Reset ret when flush register is consumed. This handles a race condition between + * irq wait timeout handler reading the register status and the actual IRQ handler + */ + if (hw_ctl->ops.get_flush_register) + flush_register = hw_ctl->ops.get_flush_register(hw_ctl); + if (!flush_register) + ret = 0; + + SDE_EVT32(DRMID(phys_enc->parent), new_cnt, flush_register, ret, + SDE_EVTLOG_FUNC_CASE1); + } + + if (notify && timeout && atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0) + && phys_enc->parent_ops.handle_frame_done) { + phys_enc->parent_ops.handle_frame_done(phys_enc->parent, phys_enc, event); + + /* notify only on actual timeout cases */ + if ((ret == -ETIMEDOUT) && sde_encoder_recovery_events_enabled(phys_enc->parent)) + sde_connector_event_notify(conn, DRM_EVENT_SDE_HW_RECOVERY, sizeof(uint8_t), SDE_RECOVERY_HARD_RESET); } - SDE_EVT32(DRMID(phys_enc->parent), event, notify, ret, - ret ? SDE_EVTLOG_FATAL : 0); + SDE_EVT32(DRMID(phys_enc->parent), event, notify, timeout, ret, + ret ? SDE_EVTLOG_FATAL : 0, SDE_EVTLOG_FUNC_EXIT); + return ret; } diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 66769fdc96..a082eef41d 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1639,7 +1639,10 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms, ret = sde_encoder_wait_for_event(encoder, cwb_disabling ? MSM_ENC_TX_COMPLETE : MSM_ENC_COMMIT_DONE); if (ret && ret != -EWOULDBLOCK) { - SDE_ERROR("wait for commit done returned %d\n", ret); + SDE_ERROR("crtc:%d, enc:%d, cwb_d:%d, wait for commit done failed ret:%d\n", + DRMID(crtc), DRMID(encoder), cwb_disabling, ret); + SDE_EVT32(DRMID(crtc), DRMID(encoder), cwb_disabling, + ret, SDE_EVTLOG_ERROR); sde_crtc_request_frame_reset(crtc, encoder); break; }