diff mbox series

[2/2] drm: vkms: Bugfix racing hrtimer vblank handle

Message ID e2e4b8f3a5cab7b2dba75bf1930f86b0a4ee08c9.1548856186.git.shayenneluzmoura@gmail.com (mailing list archive)
State New, archived
Headers show
Series drm/vkms: Bugfix for igt-tests | expand

Commit Message

Shayenne Moura Jan. 30, 2019, 4:07 p.m. UTC
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: Shayenne Moura <shayenneluzmoura@gmail.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
---
 drivers/gpu/drm/vkms/vkms_crtc.c | 18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

Comments

Rodrigo Siqueira Feb. 3, 2019, 8:57 p.m. UTC | #1
On 01/30, Shayenne Moura wrote:
> 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: Shayenne Moura <shayenneluzmoura@gmail.com>
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> ---
>  drivers/gpu/drm/vkms/vkms_crtc.c | 18 ++++++------------
>  1 file changed, 6 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
> index 23146ff2a25b..5a095610726b 100644
> --- a/drivers/gpu/drm/vkms/vkms_crtc.c
> +++ b/drivers/gpu/drm/vkms/vkms_crtc.c
> @@ -10,13 +10,17 @@
>  #include <drm/drm_atomic_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 vkms_crtc_state *state = to_vkms_crtc_state(crtc->state);
> +	int ret_overrun;
>  	bool ret;
>  
>  	spin_lock(&output->lock);
> +
>  	ret = drm_crtc_handle_vblank(crtc);
>  	if (!ret)
>  		DRM_ERROR("vkms failure on handling vblank");
> @@ -37,19 +41,9 @@ static void _vblank_handle(struct vkms_output *output)
>  			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,
>  					  output->period_ns);
> +	spin_unlock(&output->lock);
>  
>  	return HRTIMER_RESTART;
>  }
> -- 
> 2.17.1
> 

Reviewed-by: Rodrigo Siqueira <rodrigosiqueiramelo@gmail.com>
diff mbox series

Patch

diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c
index 23146ff2a25b..5a095610726b 100644
--- a/drivers/gpu/drm/vkms/vkms_crtc.c
+++ b/drivers/gpu/drm/vkms/vkms_crtc.c
@@ -10,13 +10,17 @@ 
 #include <drm/drm_atomic_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 vkms_crtc_state *state = to_vkms_crtc_state(crtc->state);
+	int ret_overrun;
 	bool ret;
 
 	spin_lock(&output->lock);
+
 	ret = drm_crtc_handle_vblank(crtc);
 	if (!ret)
 		DRM_ERROR("vkms failure on handling vblank");
@@ -37,19 +41,9 @@  static void _vblank_handle(struct vkms_output *output)
 			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,
 					  output->period_ns);
+	spin_unlock(&output->lock);
 
 	return HRTIMER_RESTART;
 }