disp: msm: sde: prevent wb commit till cwb is disabled

There is race condition in below scenario leading to crash
in sde_encoder_virt_enable as sde_enc->cur_master is set to
NULL in sde_encoder_virt_reset in earlier CWB disable commit.
1) commit1-CWB retire fence signalled.
2) commit1-CWB disable commit still in progress.
3) commit2-New WB commit in progress.
4) commit1-sde_enc->cur_master is set to NULL in CWB disable commit.
5) commit2-Crash seen in sde_encoder_virt_enable in WB commit.

Also, as WB HW is still attached to commit1 till the next wr_ptr,
new WB session cannot be allowed. Adding validate check to fail
WB session when CWB is still not cleared in CTL path.

Change-Id: I62aca05f8380d3621d4980c0820cdd4da37b3dc1
Signed-off-by: Raviteja Tamatam <quic_travitej@quicinc.com>
This commit is contained in:
Raviteja Tamatam
2022-09-28 09:50:03 -07:00
committed by Andhavarapu Karthik
parent 1ad20d00ad
commit 32bd9ab86f
5 changed files with 46 additions and 9 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2014-2021, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
@@ -3237,6 +3237,23 @@ void sde_encoder_virt_reset(struct drm_encoder *drm_enc)
sde_rm_release(&sde_kms->rm, drm_enc, false);
}
void sde_encoder_set_cwb_pending(struct drm_encoder *drm_enc, bool enable)
{
struct sde_encoder_virt *sde_enc;
int i;
if (!drm_enc) {
SDE_ERROR("invalid encoder\n");
return;
}
sde_enc = to_sde_encoder_virt(drm_enc);
for (i = 0; i < sde_enc->num_phys_encs; i++) {
if (sde_enc->phys_encs[i])
sde_enc->phys_encs[i]->cwb_disable_pending = enable;
}
}
static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc = NULL;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
@@ -653,6 +653,13 @@ ktime_t sde_encoder_calc_last_vsync_timestamp(struct drm_encoder *drm_enc);
*/
void sde_encoder_cancel_delayed_work(struct drm_encoder *encoder);
/**
* sde_encoder_set_cwb_pending - set cwb_disable_pending flag
* @drm_enc: Pointer to drm encoder structure
* @enable: set or reset cwb_disable_pending
*/
void sde_encoder_set_cwb_pending(struct drm_encoder *drm_enc, bool enable);
/**
* sde_encoder_get_kms - retrieve the kms from encoder
* @drm_enc: Pointer to drm encoder structure

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
*/
@@ -315,6 +315,8 @@ struct sde_encoder_irq {
* mode display
* @recovered: flag set to true when recovered from pp timeout
* @autorefresh_disable_trans: flag set to true during autorefresh disable transition
* @cwb_disable_pending: Set to true when cwb disable is in progress
* and HW is still attached to CTL
*/
struct sde_encoder_phys {
struct drm_encoder *parent;
@@ -363,6 +365,7 @@ struct sde_encoder_phys {
enum frame_trigger_mode_type frame_trigger_mode;
bool recovered;
bool autorefresh_disable_trans;
bool cwb_disable_pending;
};
static inline int sde_encoder_phys_inc_pending(struct sde_encoder_phys *phys)

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
*/
@@ -987,6 +987,7 @@ static int sde_encoder_phys_wb_atomic_check(struct sde_encoder_phys *phys_enc,
const struct drm_display_mode *mode = &crtc_state->mode;
int rc;
bool clone_mode_curr = false;
bool cwb_disable_pending = false;
SDE_DEBUG("[enc:%d wb:%d] atomic_check:\"%s\",%d,%d]\n", DRMID(phys_enc->parent),
WBID(wb_enc), mode->name, mode->hdisplay, mode->vdisplay);
@@ -1003,12 +1004,13 @@ static int sde_encoder_phys_wb_atomic_check(struct sde_encoder_phys *phys_enc,
sde_conn_state = to_sde_connector_state(conn_state);
clone_mode_curr = phys_enc->in_clone_mode;
cwb_disable_pending = phys_enc->cwb_disable_pending;
_sde_enc_phys_wb_detect_cwb(phys_enc, crtc_state);
if (clone_mode_curr && !cstate->cwb_enc_mask) {
SDE_ERROR("[enc:%d wb:%d] WB commit before CWB disable\n",
DRMID(phys_enc->parent), WBID(wb_enc));
if ((clone_mode_curr || cwb_disable_pending) && !cstate->cwb_enc_mask) {
SDE_ERROR("[enc:%d wb:%d] WB commit before CWB disable, Clone mode %d %d\n",
DRMID(phys_enc->parent), WBID(wb_enc), clone_mode_curr, cwb_disable_pending);
return -EINVAL;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2014-2021, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
@@ -1601,6 +1601,7 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
{
struct sde_kms *sde_kms;
struct drm_encoder *encoder;
struct drm_encoder *cwb_encoder = NULL;
struct drm_device *dev;
int ret;
bool cwb_disabling;
@@ -1634,8 +1635,12 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
if (encoder->crtc != crtc) {
cwb_disabling = sde_encoder_is_cwb_disabling(encoder,
crtc);
if (!cwb_disabling)
if (cwb_disabling) {
cwb_encoder = encoder;
sde_encoder_set_cwb_pending(encoder, true);
} else {
continue;
}
}
/*
@@ -1661,6 +1666,9 @@ static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
sde_encoder_virt_reset(encoder);
}
if (cwb_encoder)
sde_encoder_set_cwb_pending(cwb_encoder, false);
/* avoid system cache update to set rd-noalloc bit when NSE feature is enabled */
if (!test_bit(SDE_FEATURE_SYS_CACHE_NSE, sde_kms->catalog->features))
sde_crtc_static_cache_read_kickoff(crtc);