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

Reply via email to