Commit ba420afa authored by Shayenne Moura's avatar Shayenne Moura Committed by Rodrigo Siqueira

drm/vkms: Bugfix racing hrtimer vblank handle

When the vblank irq happens, kernel time subsystem executes
`vkms_vblank_simulate`. In parallel or not, it prepares all stuff
necessary to the next vblank with arm, and it must flush these stuff
before the next vblank irq. However, vblank counter is ahead when arm is
executed in parallel with handle vblank.

CPU 0:					CPU 1:
 |					 |
atomic_commit_tail is ongoing		 |
 |					 |
 |					hrtimer: vkms_vblank_simulate()
 |					 |
 |					drm_crtc_handle_vblank()
 |					 |
drm_crtc_arm_vblank()			 |
 |					 |
->get_vblank_timestamp()		 |
 |					 |
 |					hrtimer_forward_now()

Then, we should guarantee that the vblank interval time is correct (not
changed) before finish the vblank handle.

Fix the bug including the call to `hrtimer_forward_now()` in the same
lock of `drm_crtc_handle_vblank()` to ensure that the timestamp update
is correct when finish the vblank handle.
Signed-off-by: default avatarShayenne Moura <shayenneluzmoura@gmail.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@intel.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/e2e4b8f3a5cab7b2dba75bf1930f86b0a4ee08c9.1548856186.git.shayenneluzmoura@gmail.com
parent def35e7c
...@@ -10,13 +10,17 @@ ...@@ -10,13 +10,17 @@
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
#include <drm/drm_probe_helper.h> #include <drm/drm_probe_helper.h>
static void _vblank_handle(struct vkms_output *output) static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
{ {
struct vkms_output *output = container_of(timer, struct vkms_output,
vblank_hrtimer);
struct drm_crtc *crtc = &output->crtc; struct drm_crtc *crtc = &output->crtc;
struct vkms_crtc_state *state = to_vkms_crtc_state(crtc->state); struct vkms_crtc_state *state = to_vkms_crtc_state(crtc->state);
int ret_overrun;
bool ret; bool ret;
spin_lock(&output->lock); spin_lock(&output->lock);
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");
...@@ -37,19 +41,9 @@ static void _vblank_handle(struct vkms_output *output) ...@@ -37,19 +41,9 @@ static void _vblank_handle(struct vkms_output *output)
DRM_WARN("failed to queue vkms_crc_work_handle"); DRM_WARN("failed to queue vkms_crc_work_handle");
} }
spin_unlock(&output->lock);
}
static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer)
{
struct vkms_output *output = container_of(timer, struct vkms_output,
vblank_hrtimer);
int ret_overrun;
_vblank_handle(output);
ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer, ret_overrun = hrtimer_forward_now(&output->vblank_hrtimer,
output->period_ns); output->period_ns);
spin_unlock(&output->lock);
return HRTIMER_RESTART; return HRTIMER_RESTART;
} }
......
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