Commit 45284ff7 authored by Paloma Arellano's avatar Paloma Arellano Committed by Dmitry Baryshkov

drm/msm/dpu: Add mutex lock in control vblank irq

Add a mutex lock to control vblank irq to synchronize vblank
enable/disable operations happening from different threads to prevent
race conditions while registering/unregistering the vblank irq callback.

v4: -Removed vblank_ctl_lock from dpu_encoder_virt, so it is only a
    parameter of dpu_encoder_phys.
    -Switch from atomic refcnt to a simple int counter as mutex has
    now been added
v3: Mistakenly did not change wording in last version. It is done now.
v2: Slightly changed wording of commit message
Signed-off-by: default avatarPaloma Arellano <quic_parellan@quicinc.com>
Reviewed-by: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/571854/
Link: https://lore.kernel.org/r/20231212231101.9240-2-quic_parellan@quicinc.comSigned-off-by: default avatarDmitry Baryshkov <dmitry.baryshkov@linaro.org>
parent 341fb24a
...@@ -2464,7 +2464,6 @@ void dpu_encoder_phys_init(struct dpu_encoder_phys *phys_enc, ...@@ -2464,7 +2464,6 @@ void dpu_encoder_phys_init(struct dpu_encoder_phys *phys_enc,
phys_enc->enc_spinlock = p->enc_spinlock; phys_enc->enc_spinlock = p->enc_spinlock;
phys_enc->enable_state = DPU_ENC_DISABLED; phys_enc->enable_state = DPU_ENC_DISABLED;
atomic_set(&phys_enc->vblank_refcount, 0);
atomic_set(&phys_enc->pending_kickoff_cnt, 0); atomic_set(&phys_enc->pending_kickoff_cnt, 0);
atomic_set(&phys_enc->pending_ctlstart_cnt, 0); atomic_set(&phys_enc->pending_ctlstart_cnt, 0);
......
...@@ -155,6 +155,7 @@ enum dpu_intr_idx { ...@@ -155,6 +155,7 @@ enum dpu_intr_idx {
* @hw_cdm: Hardware interface to the CDM registers * @hw_cdm: Hardware interface to the CDM registers
* @dpu_kms: Pointer to the dpu_kms top level * @dpu_kms: Pointer to the dpu_kms top level
* @cached_mode: DRM mode cached at mode_set time, acted on in enable * @cached_mode: DRM mode cached at mode_set time, acted on in enable
* @vblank_ctl_lock: Vblank ctl mutex lock to protect vblank_refcount
* @enabled: Whether the encoder has enabled and running a mode * @enabled: Whether the encoder has enabled and running a mode
* @split_role: Role to play in a split-panel configuration * @split_role: Role to play in a split-panel configuration
* @intf_mode: Interface mode * @intf_mode: Interface mode
...@@ -184,11 +185,12 @@ struct dpu_encoder_phys { ...@@ -184,11 +185,12 @@ struct dpu_encoder_phys {
struct dpu_hw_cdm *hw_cdm; struct dpu_hw_cdm *hw_cdm;
struct dpu_kms *dpu_kms; struct dpu_kms *dpu_kms;
struct drm_display_mode cached_mode; struct drm_display_mode cached_mode;
struct mutex vblank_ctl_lock;
enum dpu_enc_split_role split_role; enum dpu_enc_split_role split_role;
enum dpu_intf_mode intf_mode; enum dpu_intf_mode intf_mode;
spinlock_t *enc_spinlock; spinlock_t *enc_spinlock;
enum dpu_enc_enable_state enable_state; enum dpu_enc_enable_state enable_state;
atomic_t vblank_refcount; int vblank_refcount;
atomic_t vsync_cnt; atomic_t vsync_cnt;
atomic_t underrun_cnt; atomic_t underrun_cnt;
atomic_t pending_ctlstart_cnt; atomic_t pending_ctlstart_cnt;
......
...@@ -246,7 +246,8 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( ...@@ -246,7 +246,8 @@ static int dpu_encoder_phys_cmd_control_vblank_irq(
return -EINVAL; return -EINVAL;
} }
refcount = atomic_read(&phys_enc->vblank_refcount); mutex_lock(&phys_enc->vblank_ctl_lock);
refcount = phys_enc->vblank_refcount;
/* Slave encoders don't report vblank */ /* Slave encoders don't report vblank */
if (!dpu_encoder_phys_cmd_is_master(phys_enc)) if (!dpu_encoder_phys_cmd_is_master(phys_enc))
...@@ -262,16 +263,24 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( ...@@ -262,16 +263,24 @@ static int dpu_encoder_phys_cmd_control_vblank_irq(
phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_pp->idx - PINGPONG_0,
enable ? "true" : "false", refcount); enable ? "true" : "false", refcount);
if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) if (enable) {
if (phys_enc->vblank_refcount == 0)
ret = dpu_core_irq_register_callback(phys_enc->dpu_kms, ret = dpu_core_irq_register_callback(phys_enc->dpu_kms,
phys_enc->irq[INTR_IDX_RDPTR], phys_enc->irq[INTR_IDX_RDPTR],
dpu_encoder_phys_cmd_te_rd_ptr_irq, dpu_encoder_phys_cmd_te_rd_ptr_irq,
phys_enc); phys_enc);
else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0) if (!ret)
phys_enc->vblank_refcount++;
} else if (!enable) {
if (phys_enc->vblank_refcount == 1)
ret = dpu_core_irq_unregister_callback(phys_enc->dpu_kms, ret = dpu_core_irq_unregister_callback(phys_enc->dpu_kms,
phys_enc->irq[INTR_IDX_RDPTR]); phys_enc->irq[INTR_IDX_RDPTR]);
if (!ret)
phys_enc->vblank_refcount--;
}
end: end:
mutex_unlock(&phys_enc->vblank_ctl_lock);
if (ret) { if (ret) {
DRM_ERROR("vblank irq err id:%u pp:%d ret:%d, enable %s/%d\n", DRM_ERROR("vblank irq err id:%u pp:%d ret:%d, enable %s/%d\n",
DRMID(phys_enc->parent), DRMID(phys_enc->parent),
...@@ -287,7 +296,7 @@ static void dpu_encoder_phys_cmd_irq_control(struct dpu_encoder_phys *phys_enc, ...@@ -287,7 +296,7 @@ static void dpu_encoder_phys_cmd_irq_control(struct dpu_encoder_phys *phys_enc,
{ {
trace_dpu_enc_phys_cmd_irq_ctrl(DRMID(phys_enc->parent), trace_dpu_enc_phys_cmd_irq_ctrl(DRMID(phys_enc->parent),
phys_enc->hw_pp->idx - PINGPONG_0, phys_enc->hw_pp->idx - PINGPONG_0,
enable, atomic_read(&phys_enc->vblank_refcount)); enable, phys_enc->vblank_refcount);
if (enable) { if (enable) {
dpu_core_irq_register_callback(phys_enc->dpu_kms, dpu_core_irq_register_callback(phys_enc->dpu_kms,
...@@ -728,6 +737,9 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(struct drm_device *dev, ...@@ -728,6 +737,9 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(struct drm_device *dev,
dpu_encoder_phys_init(phys_enc, p); dpu_encoder_phys_init(phys_enc, p);
mutex_init(&phys_enc->vblank_ctl_lock);
phys_enc->vblank_refcount = 0;
dpu_encoder_phys_cmd_init_ops(&phys_enc->ops); dpu_encoder_phys_cmd_init_ops(&phys_enc->ops);
phys_enc->intf_mode = INTF_MODE_CMD; phys_enc->intf_mode = INTF_MODE_CMD;
cmd_enc->stream_sel = 0; cmd_enc->stream_sel = 0;
......
...@@ -366,7 +366,8 @@ static int dpu_encoder_phys_vid_control_vblank_irq( ...@@ -366,7 +366,8 @@ static int dpu_encoder_phys_vid_control_vblank_irq(
int ret = 0; int ret = 0;
int refcount; int refcount;
refcount = atomic_read(&phys_enc->vblank_refcount); mutex_lock(&phys_enc->vblank_ctl_lock);
refcount = phys_enc->vblank_refcount;
/* Slave encoders don't report vblank */ /* Slave encoders don't report vblank */
if (!dpu_encoder_phys_vid_is_master(phys_enc)) if (!dpu_encoder_phys_vid_is_master(phys_enc))
...@@ -379,18 +380,26 @@ static int dpu_encoder_phys_vid_control_vblank_irq( ...@@ -379,18 +380,26 @@ static int dpu_encoder_phys_vid_control_vblank_irq(
} }
DRM_DEBUG_VBL("id:%u enable=%d/%d\n", DRMID(phys_enc->parent), enable, DRM_DEBUG_VBL("id:%u enable=%d/%d\n", DRMID(phys_enc->parent), enable,
atomic_read(&phys_enc->vblank_refcount)); refcount);
if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) if (enable) {
if (phys_enc->vblank_refcount == 0)
ret = dpu_core_irq_register_callback(phys_enc->dpu_kms, ret = dpu_core_irq_register_callback(phys_enc->dpu_kms,
phys_enc->irq[INTR_IDX_VSYNC], phys_enc->irq[INTR_IDX_VSYNC],
dpu_encoder_phys_vid_vblank_irq, dpu_encoder_phys_vid_vblank_irq,
phys_enc); phys_enc);
else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0) if (!ret)
phys_enc->vblank_refcount++;
} else if (!enable) {
if (phys_enc->vblank_refcount == 1)
ret = dpu_core_irq_unregister_callback(phys_enc->dpu_kms, ret = dpu_core_irq_unregister_callback(phys_enc->dpu_kms,
phys_enc->irq[INTR_IDX_VSYNC]); phys_enc->irq[INTR_IDX_VSYNC]);
if (!ret)
phys_enc->vblank_refcount--;
}
end: end:
mutex_unlock(&phys_enc->vblank_ctl_lock);
if (ret) { if (ret) {
DRM_ERROR("failed: id:%u intf:%d ret:%d enable:%d refcnt:%d\n", DRM_ERROR("failed: id:%u intf:%d ret:%d enable:%d refcnt:%d\n",
DRMID(phys_enc->parent), DRMID(phys_enc->parent),
...@@ -614,7 +623,7 @@ static void dpu_encoder_phys_vid_irq_control(struct dpu_encoder_phys *phys_enc, ...@@ -614,7 +623,7 @@ static void dpu_encoder_phys_vid_irq_control(struct dpu_encoder_phys *phys_enc,
trace_dpu_enc_phys_vid_irq_ctrl(DRMID(phys_enc->parent), trace_dpu_enc_phys_vid_irq_ctrl(DRMID(phys_enc->parent),
phys_enc->hw_intf->idx - INTF_0, phys_enc->hw_intf->idx - INTF_0,
enable, enable,
atomic_read(&phys_enc->vblank_refcount)); phys_enc->vblank_refcount);
if (enable) { if (enable) {
ret = dpu_encoder_phys_vid_control_vblank_irq(phys_enc, true); ret = dpu_encoder_phys_vid_control_vblank_irq(phys_enc, true);
...@@ -707,6 +716,8 @@ struct dpu_encoder_phys *dpu_encoder_phys_vid_init(struct drm_device *dev, ...@@ -707,6 +716,8 @@ struct dpu_encoder_phys *dpu_encoder_phys_vid_init(struct drm_device *dev,
DPU_DEBUG_VIDENC(phys_enc, "\n"); DPU_DEBUG_VIDENC(phys_enc, "\n");
dpu_encoder_phys_init(phys_enc, p); dpu_encoder_phys_init(phys_enc, p);
mutex_init(&phys_enc->vblank_ctl_lock);
phys_enc->vblank_refcount = 0;
dpu_encoder_phys_vid_init_ops(&phys_enc->ops); dpu_encoder_phys_vid_init_ops(&phys_enc->ops);
phys_enc->intf_mode = INTF_MODE_VIDEO; phys_enc->intf_mode = INTF_MODE_VIDEO;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment