drm/rockchip: vvop: fix a potential race condition when vvop_disable_vblank

A very similar case on amdgpu_vkms:
commit 826c1e923b ("drm/amdgpu/vkms: relax timer deactivation by
hrtimer_try_to_cancel")

Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
Change-Id: I0692cd2c4ad3e3f090c0df040537995f99c2fcff
This commit is contained in:
Andy Yan
2023-10-16 16:09:40 +08:00
parent f15552775d
commit 7f0033da72

View File

@@ -101,12 +101,15 @@ static enum hrtimer_restart vvop_vblank_simulate(struct hrtimer *timer)
struct drm_crtc *crtc = &vcrtc->crtc;
bool ret;
ret = drm_crtc_handle_vblank(crtc);
if (!ret)
DRM_ERROR("vvop failure on handling vblank");
hrtimer_forward_now(&vcrtc->vblank_hrtimer, vcrtc->period_ns);
ret = drm_crtc_handle_vblank(crtc);
/* Don't queue timer again when vblank is disabled. */
if (!ret) {
drm_dbg(crtc->dev, "vblank is already disabled\n");
return HRTIMER_NORESTART;
}
return HRTIMER_RESTART;
}
@@ -119,8 +122,6 @@ static int vvop_enable_vblank(struct drm_crtc *crtc)
drm_calc_timestamping_constants(crtc, &crtc->mode);
hrtimer_init(&vcrtc->vblank_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
vcrtc->vblank_hrtimer.function = &vvop_vblank_simulate;
vcrtc->period_ns = ktime_set(0, vblank->framedur_ns);
hrtimer_start(&vcrtc->vblank_hrtimer, vcrtc->period_ns, HRTIMER_MODE_REL);
@@ -131,7 +132,7 @@ static void vvop_disable_vblank(struct drm_crtc *crtc)
{
struct vvop_crtc *vcrtc = drm_crtc_to_vvop_crtc(crtc);
hrtimer_cancel(&vcrtc->vblank_hrtimer);
hrtimer_try_to_cancel(&vcrtc->vblank_hrtimer);
}
static void vvop_connector_destroy(struct drm_connector *connector)
@@ -460,6 +461,14 @@ static u64 vvop_get_soc_id(void)
return 0;
}
static int vvop_crtc_deinit(struct drm_crtc *vcrtc)
{
struct vvop_crtc *vcrtc = drm_crtc_to_vvop_crtc(crtc);
hrtimer_cancel(&vcrtc->vblank_hrtimer);
drm_crtc_cleanup(crtc);
}
static int vvop_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
struct drm_plane *primary, struct drm_plane *cursor)
{
@@ -487,6 +496,9 @@ static int vvop_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
"SOC_ID", DRM_MODE_OBJECT_CRTC);
drm_object_attach_property(&crtc->base, vcrtc->soc_id_prop, vvop_get_soc_id());
hrtimer_init(&vcrtc->vblank_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
vcrtc->vblank_hrtimer.function = &vvop_vblank_simulate;
return ret;
}
@@ -549,7 +561,7 @@ err_encoder:
err_connector_register:
drm_connector_cleanup(connector);
err_connector:
drm_crtc_cleanup(crtc);
vvop_crtc_deinit(crtc);
err_crtc:
drm_plane_cleanup(primary);
@@ -609,7 +621,7 @@ static void vvop_unbind(struct device *dev, struct device *master, void *data)
drm_connector_cleanup(&vcrtc->connector);
drm_plane_cleanup(&vcrtc->plane);
vvop->crtc_mask &= ~(drm_crtc_mask(crtc));
drm_crtc_cleanup(crtc);
vvop_crtc_deinit(crtc);
}
}
}