Replace HRTIMER_MODE_REL with HRTIMER_MODE_ABS. Align the vblank timeouts at multiples of the current mode's frame duration. Use CLOCK_BOOTTIME to avoid clock gaps from suspends. Allows the timer code to easily estimate future timeouts even while the timer is disabled.
Also add a separate error message for cases where the timeout handler tries to forward an unexpired timer. This would indicate a problem in how the timer is being set up. Suggested-by: Michel Dänzer <[email protected]> Signed-off-by: Thomas Zimmermann <[email protected]> --- drivers/gpu/drm/drm_vblank.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index d52df247d04e..03b07e3c2598 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -2192,7 +2192,9 @@ static enum hrtimer_restart drm_vblank_timer_function(struct hrtimer *timer) return HRTIMER_NORESTART; ret_overrun = hrtimer_forward_now(&vtimer->timer, interval); - if (ret_overrun != 1) + if (!ret_overrun) + drm_dbg_vbl(dev, "vblank timer underrun\n"); + else if (ret_overrun != 1) drm_dbg_vbl(dev, "vblank timer overrun\n"); if (crtc_funcs->handle_vblank_timeout) @@ -2221,6 +2223,7 @@ int drm_crtc_vblank_start_timer(struct drm_crtc *crtc) struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc); struct drm_vblank_crtc_timer *vtimer = &vblank->vblank_timer; unsigned long flags; + s64 vblank_time_ns; if (!vtimer->crtc) { /* @@ -2229,7 +2232,7 @@ int drm_crtc_vblank_start_timer(struct drm_crtc *crtc) vtimer->crtc = crtc; spin_lock_init(&vtimer->interval_lock); hrtimer_setup(&vtimer->timer, drm_vblank_timer_function, - CLOCK_MONOTONIC, HRTIMER_MODE_REL); + CLOCK_BOOTTIME, HRTIMER_MODE_ABS); } else { /* * Timer should not be active. If it is, wait for the @@ -2245,7 +2248,13 @@ int drm_crtc_vblank_start_timer(struct drm_crtc *crtc) vtimer->interval = ns_to_ktime(vblank->framedur_ns); spin_unlock_irqrestore(&vtimer->interval_lock, flags); - hrtimer_start(&vtimer->timer, vtimer->interval, HRTIMER_MODE_REL); + /* + * Always align the vblank timeout to the frame duration. Allows + * for estimating the next vblank even if the hrtimer has been + * disabled. + */ + vblank_time_ns = roundup(ktime_get_ns(), vblank->framedur_ns); + hrtimer_start(&vtimer->timer, ns_to_ktime(vblank_time_ns), HRTIMER_MODE_ABS); return 0; } -- 2.54.0
