From 56e88a7fdc8f68b1a8f59834972c6be989b90c1f Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Fri, 17 May 2019 14:51:12 -0700 Subject: [PATCH] disp: msm: sde: avoid rc lock deadlock during esd failure Each mode_set call makes sure that previous frame is triggered and triggers the esd check if there is pp_timeout. This may lead to deadlock between crtc commit and event threads. Crtc commit thread acquires the rc_lock and triggers the flush_thread API on event_thread. Event thread again tries to acquire the rc_lock to wait for frame. This can be prevented by avoiding the pre_kickoff call from esd_failure notification if it is generated through pp_timeout. Change-Id: I561fef0345976ab0cae61aab6718214c47fa1393 Signed-off-by: Dhaval Patel --- msm/sde/sde_connector.c | 10 ++++++---- msm/sde/sde_encoder.c | 14 +++++++++----- msm/sde/sde_encoder.h | 5 ++++- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index d0a7bb1eaa..ba2efe1cdd 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -1918,7 +1918,8 @@ static int sde_connector_atomic_check(struct drm_connector *connector, return 0; } -static void _sde_connector_report_panel_dead(struct sde_connector *conn) +static void _sde_connector_report_panel_dead(struct sde_connector *conn, + bool skip_pre_kickoff) { struct drm_event event; @@ -1938,7 +1939,8 @@ static void _sde_connector_report_panel_dead(struct sde_connector *conn) event.length = sizeof(bool); msm_mode_object_event_notify(&conn->base.base, conn->base.dev, &event, (u8 *)&conn->panel_dead); - sde_encoder_display_failure_notification(conn->encoder); + sde_encoder_display_failure_notification(conn->encoder, + skip_pre_kickoff); SDE_EVT32(SDE_EVTLOG_ERROR); SDE_ERROR("esd check failed report PANEL_DEAD conn_id: %d enc_id: %d\n", conn->base.base.id, conn->encoder->base.id); @@ -1973,7 +1975,7 @@ int sde_connector_esd_status(struct drm_connector *conn) if (ret <= 0) { /* cancel if any pending esd work */ sde_connector_schedule_status_work(conn, false); - _sde_connector_report_panel_dead(sde_conn); + _sde_connector_report_panel_dead(sde_conn, true); ret = -ETIMEDOUT; } else { SDE_DEBUG("Successfully received TE from panel\n"); @@ -2021,7 +2023,7 @@ static void sde_connector_check_status_work(struct work_struct *work) return; } - _sde_connector_report_panel_dead(conn); + _sde_connector_report_panel_dead(conn, false); } static const struct drm_connector_helper_funcs sde_connector_helper_ops = { diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 3191e06a37..c3e2cf17c5 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -5813,7 +5813,8 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder, return ret; } -int sde_encoder_display_failure_notification(struct drm_encoder *enc) +int sde_encoder_display_failure_notification(struct drm_encoder *enc, + bool skip_pre_kickoff) { struct msm_drm_thread *event_thread = NULL; struct msm_drm_private *priv = NULL; @@ -5839,9 +5840,11 @@ int sde_encoder_display_failure_notification(struct drm_encoder *enc) event_thread = &priv->event_thread[sde_enc->crtc->index]; - kthread_queue_work(&event_thread->worker, - &sde_enc->esd_trigger_work); - kthread_flush_work(&sde_enc->esd_trigger_work); + if (!skip_pre_kickoff) { + kthread_queue_work(&event_thread->worker, + &sde_enc->esd_trigger_work); + kthread_flush_work(&sde_enc->esd_trigger_work); + } /** * panel may stop generating te signal (vsync) during esd failure. rsc @@ -5850,7 +5853,8 @@ int sde_encoder_display_failure_notification(struct drm_encoder *enc) */ _sde_encoder_switch_to_watchdog_vsync(enc); - sde_encoder_wait_for_event(enc, MSM_ENC_TX_COMPLETE); + if (!skip_pre_kickoff) + sde_encoder_wait_for_event(enc, MSM_ENC_TX_COMPLETE); return 0; } diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index 83c43d5b6d..20b55ec969 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -253,9 +253,12 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder, * * TODO: manage the event at sde_kms level for forward processing. * @drm_enc: Pointer to drm encoder structure + * @skip_pre_kickoff: Caller can avoid pre_kickoff if it is triggering this + * event only to switch the panel TE to watchdog mode. * @Return: true if successful in updating the encoder structure */ -int sde_encoder_display_failure_notification(struct drm_encoder *enc); +int sde_encoder_display_failure_notification(struct drm_encoder *enc, + bool skip_pre_kickoff); /** * sde_encoder_recovery_events_enabled - checks if client has enabled