Commit 7355965d authored by Daniel Vetter's avatar Daniel Vetter Committed by Rodrigo Siqueira

drm/vkms: Forward timer right after drm_crtc_handle_vblank

In

commit def35e7c
Author: Shayenne Moura <shayenneluzmoura@gmail.com>
Date:   Wed Jan 30 14:06:36 2019 -0200

    drm/vkms: Bugfix extra vblank frame

we fixed the vblank counter to give accurate results outside of
drm_crtc_handle_vblank, which fixed bugs around vblank timestamps
being off-by-one and causing the vblank counter to jump when it
shouldn't.

The trouble is that this completely broke crc generation. Shayenne and
Rodrigo tracked this down to the vblank timestamp going backwards in
time somehow. Which then resulted in an underflow in drm_vblank.c
code, which resulted in all kinds of things breaking really badly.

The reason for this is that once we've called drm_crtc_handle_vblank
and the hrtimer isn't forwarded yet, we're returning a vblank
timestamp in the past. This race is really hard to hit since it's
small, except when you enable crc generation: In that case there's a
call to drm_crtc_accurate_vblank right in-betwen, so we're guaranteed
to hit the bug.

The fix is to roll the hrtimer forward _before_ we do the vblank
processing (which has a side-effect of incrementing the vblank
counter), and we always subtract one frame from the hrtimer - since
now it's always one frame in the future.

To make sure we don't hit this again also add a WARN_ON checking for
whether our timestamp is somehow moving into the past, which is never
should.

This also aligns more with how real hw works:
1. first all registers are updated with the new timestamp/vblank
counter values.
2. then an interrupt is generated
3. kernel interrupt handler eventually fires.

So doing this aligns vkms closer with what drm_vblank.c expects.
Document this also in a comment.

Cc: Shayenne Moura <shayenneluzmoura@gmail.com>
Cc: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@intel.com>
Tested-by: default avatarRodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
Reviewed-by: default avatarRodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
Signed-off-by: default avatarRodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190606084404.12014-1-daniel.vetter@ffwll.ch
parent 1ae752bf
...@@ -15,6 +15,10 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) ...@@ -15,6 +15,10 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
spin_lock(&output->lock); spin_lock(&output->lock);
ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer,
output->period_ns);
WARN_ON(ret_overrun != 1);
ret = drm_crtc_handle_vblank(crtc); ret = drm_crtc_handle_vblank(crtc);
if (!ret) if (!ret)
DRM_ERROR("vkms failure on handling vblank"); DRM_ERROR("vkms failure on handling vblank");
...@@ -35,10 +39,6 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) ...@@ -35,10 +39,6 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
DRM_WARN("failed to queue vkms_crc_work_handle"); DRM_WARN("failed to queue vkms_crc_work_handle");
} }
ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer,
output->period_ns);
WARN_ON(ret_overrun != 1);
spin_unlock(&output->lock); spin_unlock(&output->lock);
return HRTIMER_RESTART; return HRTIMER_RESTART;
...@@ -74,11 +74,21 @@ bool vkms_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe, ...@@ -74,11 +74,21 @@ bool vkms_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
{ {
struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev); struct vkms_device *vkmsdev = drm_device_to_vkms_device(dev);
struct vkms_output *output = &vkmsdev->output; struct vkms_output *output = &vkmsdev->output;
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
*vblank_time = output->vblank_hrtimer.node.expires; *vblank_time = output->vblank_hrtimer.node.expires;
if (!in_vblank_irq) if (WARN_ON(*vblank_time == vblank->time))
*vblank_time -= output->period_ns; return true;
/*
* To prevent races we roll the hrtimer forward before we do any
* interrupt processing - this is how real hw works (the interrupt is
* only generated after all the vblank registers are updated) and what
* the vblank core expects. Therefore we need to always correct the
* timestampe by one frame.
*/
*vblank_time -= output->period_ns;
return true; return true;
} }
......
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