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 <pdhaval@codeaurora.org>
This commit is contained in:
Dhaval Patel
2019-05-17 14:51:12 -07:00
parent 74f328561e
commit 56e88a7fdc
3 changed files with 19 additions and 10 deletions

View File

@@ -1918,7 +1918,8 @@ static int sde_connector_atomic_check(struct drm_connector *connector,
return 0; 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; struct drm_event event;
@@ -1938,7 +1939,8 @@ static void _sde_connector_report_panel_dead(struct sde_connector *conn)
event.length = sizeof(bool); event.length = sizeof(bool);
msm_mode_object_event_notify(&conn->base.base, msm_mode_object_event_notify(&conn->base.base,
conn->base.dev, &event, (u8 *)&conn->panel_dead); 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_EVT32(SDE_EVTLOG_ERROR);
SDE_ERROR("esd check failed report PANEL_DEAD conn_id: %d enc_id: %d\n", SDE_ERROR("esd check failed report PANEL_DEAD conn_id: %d enc_id: %d\n",
conn->base.base.id, conn->encoder->base.id); conn->base.base.id, conn->encoder->base.id);
@@ -1973,7 +1975,7 @@ int sde_connector_esd_status(struct drm_connector *conn)
if (ret <= 0) { if (ret <= 0) {
/* cancel if any pending esd work */ /* cancel if any pending esd work */
sde_connector_schedule_status_work(conn, false); sde_connector_schedule_status_work(conn, false);
_sde_connector_report_panel_dead(sde_conn); _sde_connector_report_panel_dead(sde_conn, true);
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
} else { } else {
SDE_DEBUG("Successfully received TE from panel\n"); SDE_DEBUG("Successfully received TE from panel\n");
@@ -2021,7 +2023,7 @@ static void sde_connector_check_status_work(struct work_struct *work)
return; 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 = { static const struct drm_connector_helper_funcs sde_connector_helper_ops = {

View File

@@ -5813,7 +5813,8 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder,
return ret; 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_thread *event_thread = NULL;
struct msm_drm_private *priv = 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]; event_thread = &priv->event_thread[sde_enc->crtc->index];
kthread_queue_work(&event_thread->worker, if (!skip_pre_kickoff) {
&sde_enc->esd_trigger_work); kthread_queue_work(&event_thread->worker,
kthread_flush_work(&sde_enc->esd_trigger_work); &sde_enc->esd_trigger_work);
kthread_flush_work(&sde_enc->esd_trigger_work);
}
/** /**
* panel may stop generating te signal (vsync) during esd failure. rsc * 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_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; return 0;
} }

View File

@@ -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. * TODO: manage the event at sde_kms level for forward processing.
* @drm_enc: Pointer to drm encoder structure * @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 * @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 * sde_encoder_recovery_events_enabled - checks if client has enabled