drm/msm/sde: fix race condition in vblank control interrupts
In Dual display concurrencies there are certain cases where irq_idx and vblank_refcount state mismatch can occur. To avoid it, during setup of irq_hw_idx, reset the vblank_refcount and unregister read ptr irq if not yet done by then along with maintaining global mutex lock for vblank_refcount. Also, if register IRQ fails, correct vblank_refcount so that IRQ registration can be tried again. Change-Id: I06bcbf71c6a43bd161ff61093d9f6063a292d6bc Signed-off-by: Raviteja Tamatam <travitej@codeaurora.org> Signed-off-by: Samantha Tran <samtran@codeaurora.org>
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

parent
83ff89732a
commit
0064a0227b
@@ -320,6 +320,8 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx(
|
|||||||
struct sde_encoder_phys *phys_enc)
|
struct sde_encoder_phys *phys_enc)
|
||||||
{
|
{
|
||||||
struct sde_encoder_irq *irq;
|
struct sde_encoder_irq *irq;
|
||||||
|
struct sde_kms *sde_kms = phys_enc->sde_kms;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_ctl) {
|
if (!phys_enc || !phys_enc->hw_pp || !phys_enc->hw_ctl) {
|
||||||
SDE_ERROR("invalid args %d %d\n", !phys_enc,
|
SDE_ERROR("invalid args %d %d\n", !phys_enc,
|
||||||
@@ -332,6 +334,21 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&sde_kms->vblank_ctl_global_lock);
|
||||||
|
|
||||||
|
if (atomic_read(&phys_enc->vblank_refcount)) {
|
||||||
|
SDE_ERROR(
|
||||||
|
"vblank_refcount mismatch detected, try to reset %d\n",
|
||||||
|
atomic_read(&phys_enc->vblank_refcount));
|
||||||
|
ret = sde_encoder_helper_unregister_irq(phys_enc,
|
||||||
|
INTR_IDX_RDPTR);
|
||||||
|
if (ret)
|
||||||
|
SDE_ERROR(
|
||||||
|
"control vblank irq registration error %d\n",
|
||||||
|
ret);
|
||||||
|
}
|
||||||
|
atomic_set(&phys_enc->vblank_refcount, 0);
|
||||||
|
|
||||||
irq = &phys_enc->irq[INTR_IDX_CTL_START];
|
irq = &phys_enc->irq[INTR_IDX_CTL_START];
|
||||||
irq->hw_idx = phys_enc->hw_ctl->idx;
|
irq->hw_idx = phys_enc->hw_ctl->idx;
|
||||||
irq->irq_idx = -EINVAL;
|
irq->irq_idx = -EINVAL;
|
||||||
@@ -365,6 +382,8 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx(
|
|||||||
else
|
else
|
||||||
irq->hw_idx = phys_enc->hw_pp->idx;
|
irq->hw_idx = phys_enc->hw_pp->idx;
|
||||||
|
|
||||||
|
mutex_unlock(&sde_kms->vblank_ctl_global_lock);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sde_encoder_phys_cmd_cont_splash_mode_set(
|
static void sde_encoder_phys_cmd_cont_splash_mode_set(
|
||||||
@@ -800,13 +819,15 @@ static int sde_encoder_phys_cmd_control_vblank_irq(
|
|||||||
to_sde_encoder_phys_cmd(phys_enc);
|
to_sde_encoder_phys_cmd(phys_enc);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int refcount;
|
int refcount;
|
||||||
|
struct sde_kms *sde_kms;
|
||||||
|
|
||||||
if (!phys_enc || !phys_enc->hw_pp) {
|
if (!phys_enc || !phys_enc->hw_pp) {
|
||||||
SDE_ERROR("invalid encoder\n");
|
SDE_ERROR("invalid encoder\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
sde_kms = phys_enc->sde_kms;
|
||||||
|
|
||||||
mutex_lock(phys_enc->vblank_ctl_lock);
|
mutex_lock(&sde_kms->vblank_ctl_global_lock);
|
||||||
refcount = atomic_read(&phys_enc->vblank_refcount);
|
refcount = atomic_read(&phys_enc->vblank_refcount);
|
||||||
|
|
||||||
/* Slave encoders don't report vblank */
|
/* Slave encoders don't report vblank */
|
||||||
@@ -824,11 +845,17 @@ static int sde_encoder_phys_cmd_control_vblank_irq(
|
|||||||
SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
|
SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
|
||||||
enable, refcount);
|
enable, refcount);
|
||||||
|
|
||||||
if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
|
if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) {
|
||||||
ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_RDPTR);
|
ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_RDPTR);
|
||||||
else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0)
|
if (ret)
|
||||||
|
atomic_dec_return(&phys_enc->vblank_refcount);
|
||||||
|
} else if (!enable &&
|
||||||
|
atomic_dec_return(&phys_enc->vblank_refcount) == 0) {
|
||||||
ret = sde_encoder_helper_unregister_irq(phys_enc,
|
ret = sde_encoder_helper_unregister_irq(phys_enc,
|
||||||
INTR_IDX_RDPTR);
|
INTR_IDX_RDPTR);
|
||||||
|
if (ret)
|
||||||
|
atomic_inc_return(&phys_enc->vblank_refcount);
|
||||||
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -840,7 +867,7 @@ end:
|
|||||||
enable, refcount, SDE_EVTLOG_ERROR);
|
enable, refcount, SDE_EVTLOG_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(phys_enc->vblank_ctl_lock);
|
mutex_unlock(&sde_kms->vblank_ctl_global_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3418,6 +3418,8 @@ static int sde_kms_hw_init(struct msm_kms *kms)
|
|||||||
dev->mode_config.max_height = sde_kms->catalog->max_display_height;
|
dev->mode_config.max_height = sde_kms->catalog->max_display_height;
|
||||||
|
|
||||||
mutex_init(&sde_kms->secure_transition_lock);
|
mutex_init(&sde_kms->secure_transition_lock);
|
||||||
|
mutex_init(&sde_kms->vblank_ctl_global_lock);
|
||||||
|
|
||||||
atomic_set(&sde_kms->detach_sec_cb, 0);
|
atomic_set(&sde_kms->detach_sec_cb, 0);
|
||||||
atomic_set(&sde_kms->detach_all_cb, 0);
|
atomic_set(&sde_kms->detach_all_cb, 0);
|
||||||
|
|
||||||
|
@@ -299,6 +299,7 @@ struct sde_kms {
|
|||||||
atomic_t detach_sec_cb;
|
atomic_t detach_sec_cb;
|
||||||
atomic_t detach_all_cb;
|
atomic_t detach_all_cb;
|
||||||
struct mutex secure_transition_lock;
|
struct mutex secure_transition_lock;
|
||||||
|
struct mutex vblank_ctl_global_lock;
|
||||||
|
|
||||||
bool first_kickoff;
|
bool first_kickoff;
|
||||||
bool qdss_enabled;
|
bool qdss_enabled;
|
||||||
|
Reference in New Issue
Block a user