All of lore.kernel.org
 help / color / mirror / Atom feed
* [Patches][nouveau/kms]: Precise Vblank and pageflip timestamping
@ 2012-02-15 22:55 Mario Kleiner
       [not found] ` <1329346511-27433-1-git-send-email-mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>
  2012-02-15 22:55 ` [PATCH 2/2] nouveau: implement precise vblank timestamping Mario Kleiner
  0 siblings, 2 replies; 7+ messages in thread
From: Mario Kleiner @ 2012-02-15 22:55 UTC (permalink / raw)
  To: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	bskeggs-H+wXaHxf7aLQT0dZR+AlfA,
	mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ

Hi,

these are two patches against the nouveau kms driver. The first patch
makes sure that pageflip completion events get their vblank count and
timestamp from the drm. The second patch from Lucas Stach, here included
with his permission, makes sure that the timestamps of vblanks are
calculated with high precision and robustness. Both patches together
make sure that all timestamps returned by the kms driver are consistent
with each other and conform to the OML_sync_control specification.

With Lucas permission i've already integrated my feedback from
reviewing his patch into the patch. The patches have been applied
against Linux 3.2 and tested with special measurement equipment on
a GeForce 7800, a GeForce 8800 and some QuadroFX 570 and 370. The
timestamps are accurate to less than 30 usecs deviation from the
ground truth measured with the external equipment.

I'll send out a couple of nouveau ddx patches that make use of
these timestamps.

It would be great if these could be reviewed and possibly included
for the Linux 3.4 merge window.

Thanks,
-mario

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] drm/nouveau: Use drm_vblank_count_and_time() for pageflip completion events.
       [not found] ` <1329346511-27433-1-git-send-email-mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>
@ 2012-02-15 22:55   ` Mario Kleiner
  0 siblings, 0 replies; 7+ messages in thread
From: Mario Kleiner @ 2012-02-15 22:55 UTC (permalink / raw)
  To: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	bskeggs-H+wXaHxf7aLQT0dZR+AlfA,
	mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ

Emit kms pageflip completion events with proper vblank count
and timestamp for the vblank interval in which the pageflip
completed. This makes the timestamps and counts consistent with
what the OML_sync_control spec defines.

Signed-off-by: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>
---
 drivers/gpu/drm/nouveau/nouveau_display.c |   29 +++++++++++++++++++++++------
 drivers/gpu/drm/nouveau/nouveau_drv.h     |    1 +
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index b12fd2c..5bd392f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -295,7 +295,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	*s = (struct nouveau_page_flip_state)
 		{ { }, event, nouveau_crtc(crtc)->index,
 		  fb->bits_per_pixel, fb->pitch, crtc->x, crtc->y,
-		  new_bo->bo.offset };
+		  new_bo->bo.offset, crtc->framedur_ns };
 
 	/* Choose the channel the flip will be handled in */
 	chan = nouveau_fence_channel(new_bo->bo.sync_obj);
@@ -338,6 +338,9 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
 	struct drm_device *dev = chan->dev;
 	struct nouveau_page_flip_state *s;
 	unsigned long flags;
+	struct timeval tnow, tvbl;
+
+	do_gettimeofday(&tnow);
 
 	spin_lock_irqsave(&dev->event_lock, flags);
 
@@ -351,12 +354,26 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
 			     struct nouveau_page_flip_state, head);
 	if (s->event) {
 		struct drm_pending_vblank_event *e = s->event;
-		struct timeval now;
 
-		do_gettimeofday(&now);
-		e->event.sequence = 0;
-		e->event.tv_sec = now.tv_sec;
-		e->event.tv_usec = now.tv_usec;
+		e->event.sequence = drm_vblank_count_and_time(dev, s->crtc, &tvbl);
+
+		/* Called before vblank count and timestamp have
+		 * been updated for the vblank interval of flip
+		 * completion? If so, need to increment vblank count and
+		 * add one videorefresh duration to returned timestamp
+		 * to account for this. We assume this happened if we
+		 * get called over 0.9 frame durations after the last
+		 * timestamped vblank.
+		 */
+		if (10 * (timeval_to_ns(&tnow) - timeval_to_ns(&tvbl)) >
+		     9 * s->framedur_ns) {
+			e->event.sequence++;
+			tvbl = ns_to_timeval(timeval_to_ns(&tvbl) +
+			s->framedur_ns);
+		}
+
+		e->event.tv_sec = tvbl.tv_sec;
+		e->event.tv_usec = tvbl.tv_usec;
 		list_add_tail(&e->base.link, &e->base.file_priv->event_list);
 		wake_up_interruptible(&e->base.file_priv->event_wait);
 	}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 4c0be3a..f489c22 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -202,6 +202,7 @@ struct nouveau_page_flip_state {
 	struct drm_pending_vblank_event *event;
 	int crtc, bpp, pitch, x, y;
 	uint64_t offset;
+	s64 framedur_ns;
 };
 
 enum nouveau_channel_mutex_class {
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] nouveau: implement precise vblank timestamping
  2012-02-15 22:55 [Patches][nouveau/kms]: Precise Vblank and pageflip timestamping Mario Kleiner
       [not found] ` <1329346511-27433-1-git-send-email-mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>
@ 2012-02-15 22:55 ` Mario Kleiner
  2012-02-16  4:28   ` Ben Skeggs
  1 sibling, 1 reply; 7+ messages in thread
From: Mario Kleiner @ 2012-02-15 22:55 UTC (permalink / raw)
  To: nouveau; +Cc: dri-devel, bskeggs, mario.kleiner

From: Lucas Stach <dev@lynxeye.de>

This patch implements the drivers hooks needed for precise vblank
timestamping. This is a complementary patch to Mario Kleiner's
patches to improve swap scheduling. With the complete
patchset applied nouveau will be able to provide correct and
precise pageflip timestamps (compliant to OML_sync_control spec)

Kudos to Mario for his many helpful comments and testing.

Signed-off-by: Lucas Stach <dev@lynxeye.de>
Reviewed-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
Tested-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
---
 drivers/gpu/drm/nouveau/nouveau_display.c |  124 +++++++++++++++++++++++++++++
 drivers/gpu/drm/nouveau/nouveau_drv.c     |    2 +
 drivers/gpu/drm/nouveau/nouveau_drv.h     |    5 +
 drivers/gpu/drm/nouveau/nouveau_reg.h     |    9 ++-
 drivers/gpu/drm/nouveau/nv50_crtc.c       |   19 +++++
 drivers/gpu/drm/nouveau/nvreg.h           |    1 +
 6 files changed, 159 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 5bd392f..7fdd6a4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -431,3 +431,127 @@ nouveau_display_dumb_map_offset(struct drm_file *file_priv,
 
 	return -ENOENT;
 }
+
+int
+nouveau_get_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos)
+{
+	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	int vline, hline, ret = 0;
+	u32 vbias, hbias, reg, vbl_start, vbl_end;
+	struct drm_crtc *drmcrtc;
+
+	if (crtc < 0 || crtc >= dev->num_crtcs) {
+		DRM_ERROR("Invalid crtc %d\n", crtc);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(drmcrtc, &dev->mode_config.crtc_list, head) {
+		if(nouveau_crtc(drmcrtc)->index == crtc)
+			/* stop if we have found crtc with matching index */
+			break;
+	}
+
+	if(dev_priv->card_type >= NV_50) {
+		/* get vsync and hsync area */
+		reg = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc,
+		                   SYNC_START_TO_BLANK_END));
+		vbias = (reg >> 16) & 0xffff;
+		hbias = reg & 0xffff;
+
+		/* get vertical display size including bias as vbl_start
+		 * and vtotal as vbl_end */
+		vbl_start = (nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc,
+		                          VBL_START)) >> 16) & 0xffff;
+		vbl_end = (nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc,
+		                        DISPLAY_TOTAL)) >> 16) & 0xffff;
+
+		/* get current scanout position from PDISPLAY */
+		vline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_VERT(crtc))
+		                & NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK;
+
+		/*
+		 * vline == 0 could be invalid:
+		 * Some gpu's get stuck on that value inside vblank. Try again
+		 * after one scanline duration, if it still reads 0 give up.
+		 */
+		if (vline == 0) {
+			ndelay(drmcrtc->linedur_ns & 0xffff);
+			vline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_VERT(crtc))
+			        & NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK;
+		}
+
+		hline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_HORZ(crtc))
+		                & NV50_PDISPLAY_CRTC_STAT_HORZ_HLINE__MASK;
+
+		if((vline > 0) && (vline < vbl_end))
+			ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
+
+		if((vline >= vbl_start) || (vline < vbias)) {
+			/* we are in vblank so do a neg countdown */
+			ret |= DRM_SCANOUTPOS_INVBL;
+			vline -= (vline < vbias) ? vbias : (vbl_end + vbias);
+			hline -= hbias;
+		} else {
+			/* apply corrective offset */
+			vline -= vbias;
+			hline -= hbias;
+		}
+	} else {
+		/* get vsync area from PRAMDAC */
+		vbl_start = NVReadRAMDAC(dev, crtc, NV_PRAMDAC_FP_VDISPLAY_END)
+		            & 0xffff;
+		vbl_end = (NVReadRAMDAC(dev, crtc, NV_PRAMDAC_FP_VTOTAL)
+			   & 0xffff) + 1;
+
+		/* get current scanout position from PCRTC */
+		vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0xffff;
+
+		/*
+		 * vline == 0 could be invalid:
+		 * Some gpu's get stuck on that value inside vblank. Try again
+		 * after one scanline duration, if it still reads 0 give up.
+		 */
+		if (vline == 0) {
+			ndelay(drmcrtc->linedur_ns & 0xffff);
+			vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0xffff;
+		}
+
+		if(vline > 0)
+			ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
+
+		/* are we in vblank? if yes: do neg countdown */
+		if((vline >= vbl_start) && (vline < vbl_end)) {
+			ret |= DRM_SCANOUTPOS_INVBL;
+			vline -= vbl_end;
+		}
+
+		hline = 0; /* don't use hline as it's unreliable */
+	}
+
+	*vpos = vline;
+	*hpos = hline;
+
+	return ret;
+}
+
+int
+nouveau_get_vblank_timestamp(struct drm_device *dev, int crtc,
+			     int *max_error, struct timeval *vblank_time,
+			     unsigned flags)
+{
+	struct drm_crtc *drmcrtc;
+
+	if (crtc < 0 || crtc >= dev->num_crtcs) {
+		DRM_ERROR("Invalid crtc %d\n", crtc);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(drmcrtc, &dev->mode_config.crtc_list, head) {
+		if(nouveau_crtc(drmcrtc)->index == crtc)
+			/* stop if we have found crtc with matching index */
+			break;
+	}
+
+	return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
+				vblank_time, flags, drmcrtc);
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 9791d13..555b4aa 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -411,6 +411,8 @@ static struct drm_driver driver = {
 	.get_vblank_counter = drm_vblank_count,
 	.enable_vblank = nouveau_vblank_enable,
 	.disable_vblank = nouveau_vblank_disable,
+	.get_vblank_timestamp = nouveau_get_vblank_timestamp,
+	.get_scanout_position = nouveau_get_scanoutpos,
 	.reclaim_buffers = drm_core_reclaim_buffers,
 	.ioctls = nouveau_ioctls,
 	.fops = {
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index f489c22..52c3de7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -1419,6 +1419,11 @@ int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 			   struct drm_pending_vblank_event *event);
 int nouveau_finish_page_flip(struct nouveau_channel *,
 			     struct nouveau_page_flip_state *);
+int nouveau_get_scanoutpos(struct drm_device *dev, int crtc,
+                            int *vpos, int *hpos);
+int nouveau_get_vblank_timestamp(struct drm_device *dev, int crtc,
+				 int *max_error, struct timeval *vblank_time,
+				 unsigned flags);
 int nouveau_display_dumb_create(struct drm_file *, struct drm_device *,
 				struct drm_mode_create_dumb *args);
 int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *,
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 43a96b9..0ec1945 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -762,7 +762,7 @@
 #define NV50_PDISPLAY_CRTC_CLOCK                                     0x00610ad0
 #define NV50_PDISPLAY_CRTC_COLOR_CTRL                                0x00610ae0
 #define NV50_PDISPLAY_CRTC_SYNC_START_TO_BLANK_END                   0x00610ae8
-#define NV50_PDISPLAY_CRTC_MODE_UNK1                                 0x00610af0
+#define NV50_PDISPLAY_CRTC_VBL_START                                 0x00610af0
 #define NV50_PDISPLAY_CRTC_DISPLAY_TOTAL                             0x00610af8
 #define NV50_PDISPLAY_CRTC_SYNC_DURATION                             0x00610b00
 #define NV50_PDISPLAY_CRTC_MODE_UNK2                                 0x00610b08
@@ -800,6 +800,13 @@
 #define NV50_PDISPLAY_SOR_CLK                                        0x00614000
 #define NV50_PDISPLAY_SOR_CLK_CTRL2(i)                  ((i) * 0x800 + 0x614300)
 
+#define NV50_PDISPLAY_CRTC_STAT_VERT(i0)		       (0x00616340 + 0x800*(i0))
+#define NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK		0x0000ffff
+#define NV50_PDISPLAY_CRTC_STAT_VERT_VBLANK_COUNT__MASK		0xffff0000
+#define NV50_PDISPLAY_CRTC_STAT_VERT_VBLANK_COUNT__SHIFT	16
+#define NV50_PDISPLAY_CRTC_STAT_HORZ(i0)		       (0x00616344 + 0x800*(i0))
+#define NV50_PDISPLAY_CRTC_STAT_HORZ_HLINE__MASK		0x0000ffff
+
 #define NV50_PDISPLAY_VGACRTC(r)                                ((r) + 0x619400)
 
 #define NV50_PDISPLAY_DAC                                            0x0061a000
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index 882080e..89fbc31 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -505,6 +505,25 @@ static bool
 nv50_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
 		     struct drm_display_mode *adjusted_mode)
 {
+	/* crtc_xxx fields are needed by drm core. Init them with the
+	 * settings we actually use for mode programming. */
+	adjusted_mode->synth_clock = adjusted_mode->clock;
+	adjusted_mode->crtc_hdisplay = adjusted_mode->hdisplay;
+	adjusted_mode->crtc_hblank_start = 0;
+	adjusted_mode->crtc_hblank_end = 0;
+	adjusted_mode->crtc_hsync_start = adjusted_mode->hsync_start;
+	adjusted_mode->crtc_hsync_end = adjusted_mode->hsync_end;
+	adjusted_mode->crtc_htotal = adjusted_mode->htotal;
+	adjusted_mode->crtc_hskew = adjusted_mode->hskew;
+	adjusted_mode->crtc_vdisplay = adjusted_mode->vdisplay;
+	adjusted_mode->crtc_vblank_start = 0;
+	adjusted_mode->crtc_vblank_end = 0;
+	adjusted_mode->crtc_vsync_start = adjusted_mode->vsync_start;
+	adjusted_mode->crtc_vsync_end = adjusted_mode->vsync_end;
+	adjusted_mode->crtc_vtotal = adjusted_mode->vtotal;
+	adjusted_mode->crtc_hadjusted = 0;
+	adjusted_mode->crtc_vadjusted = 0;
+
 	return true;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h
index bbfb1a6..e8281c4 100644
--- a/drivers/gpu/drm/nouveau/nvreg.h
+++ b/drivers/gpu/drm/nouveau/nvreg.h
@@ -172,6 +172,7 @@
 #define NV_PCRTC_834					0x00600834
 #define NV_PCRTC_850					0x00600850
 #define NV_PCRTC_ENGINE_CTRL				0x00600860
+#define NV_PCRTC_STAT(i0)			(0x00600868 + 0x2000*(i0))
 #	define NV_CRTC_FSEL_I2C					(1 << 4)
 #	define NV_CRTC_FSEL_OVERLAY				(1 << 12)
 
-- 
1.7.5.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] nouveau: implement precise vblank timestamping
  2012-02-15 22:55 ` [PATCH 2/2] nouveau: implement precise vblank timestamping Mario Kleiner
@ 2012-02-16  4:28   ` Ben Skeggs
  0 siblings, 0 replies; 7+ messages in thread
From: Ben Skeggs @ 2012-02-16  4:28 UTC (permalink / raw)
  To: Mario Kleiner; +Cc: nouveau, dri-devel

On Wed, 2012-02-15 at 23:55 +0100, Mario Kleiner wrote:
> From: Lucas Stach <dev@lynxeye.de>
> 
> This patch implements the drivers hooks needed for precise vblank
> timestamping. This is a complementary patch to Mario Kleiner's
> patches to improve swap scheduling. With the complete
> patchset applied nouveau will be able to provide correct and
> precise pageflip timestamps (compliant to OML_sync_control spec)
My only real issue with this patch after a quick review is that
NV50_PDISP_CRTC_P (proposed) is being used instead of _C (current).

There's also some minor formatting issues such as "if(blah)" instead of
"if (blah)" in a few places.

Ben.

> 
> Kudos to Mario for his many helpful comments and testing.
> 
> Signed-off-by: Lucas Stach <dev@lynxeye.de>
> Reviewed-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
> Tested-by: Mario Kleiner <mario.kleiner@tuebingen.mpg.de>
> ---
>  drivers/gpu/drm/nouveau/nouveau_display.c |  124 +++++++++++++++++++++++++++++
>  drivers/gpu/drm/nouveau/nouveau_drv.c     |    2 +
>  drivers/gpu/drm/nouveau/nouveau_drv.h     |    5 +
>  drivers/gpu/drm/nouveau/nouveau_reg.h     |    9 ++-
>  drivers/gpu/drm/nouveau/nv50_crtc.c       |   19 +++++
>  drivers/gpu/drm/nouveau/nvreg.h           |    1 +
>  6 files changed, 159 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
> index 5bd392f..7fdd6a4 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_display.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_display.c
> @@ -431,3 +431,127 @@ nouveau_display_dumb_map_offset(struct drm_file *file_priv,
>  
>  	return -ENOENT;
>  }
> +
> +int
> +nouveau_get_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos)
> +{
> +	struct drm_nouveau_private *dev_priv = dev->dev_private;
> +	int vline, hline, ret = 0;
> +	u32 vbias, hbias, reg, vbl_start, vbl_end;
> +	struct drm_crtc *drmcrtc;
> +
> +	if (crtc < 0 || crtc >= dev->num_crtcs) {
> +		DRM_ERROR("Invalid crtc %d\n", crtc);
> +		return -EINVAL;
> +	}
> +
> +	list_for_each_entry(drmcrtc, &dev->mode_config.crtc_list, head) {
> +		if(nouveau_crtc(drmcrtc)->index == crtc)
> +			/* stop if we have found crtc with matching index */
> +			break;
> +	}
> +
> +	if(dev_priv->card_type >= NV_50) {
> +		/* get vsync and hsync area */
> +		reg = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc,
> +		                   SYNC_START_TO_BLANK_END));
> +		vbias = (reg >> 16) & 0xffff;
> +		hbias = reg & 0xffff;
> +
> +		/* get vertical display size including bias as vbl_start
> +		 * and vtotal as vbl_end */
> +		vbl_start = (nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc,
> +		                          VBL_START)) >> 16) & 0xffff;
> +		vbl_end = (nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc,
> +		                        DISPLAY_TOTAL)) >> 16) & 0xffff;
> +
> +		/* get current scanout position from PDISPLAY */
> +		vline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_VERT(crtc))
> +		                & NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK;
> +
> +		/*
> +		 * vline == 0 could be invalid:
> +		 * Some gpu's get stuck on that value inside vblank. Try again
> +		 * after one scanline duration, if it still reads 0 give up.
> +		 */
> +		if (vline == 0) {
> +			ndelay(drmcrtc->linedur_ns & 0xffff);
> +			vline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_VERT(crtc))
> +			        & NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK;
> +		}
> +
> +		hline = nv_rd32(dev, NV50_PDISPLAY_CRTC_STAT_HORZ(crtc))
> +		                & NV50_PDISPLAY_CRTC_STAT_HORZ_HLINE__MASK;
> +
> +		if((vline > 0) && (vline < vbl_end))
> +			ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
> +
> +		if((vline >= vbl_start) || (vline < vbias)) {
> +			/* we are in vblank so do a neg countdown */
> +			ret |= DRM_SCANOUTPOS_INVBL;
> +			vline -= (vline < vbias) ? vbias : (vbl_end + vbias);
> +			hline -= hbias;
> +		} else {
> +			/* apply corrective offset */
> +			vline -= vbias;
> +			hline -= hbias;
> +		}
> +	} else {
> +		/* get vsync area from PRAMDAC */
> +		vbl_start = NVReadRAMDAC(dev, crtc, NV_PRAMDAC_FP_VDISPLAY_END)
> +		            & 0xffff;
> +		vbl_end = (NVReadRAMDAC(dev, crtc, NV_PRAMDAC_FP_VTOTAL)
> +			   & 0xffff) + 1;
> +
> +		/* get current scanout position from PCRTC */
> +		vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0xffff;
> +
> +		/*
> +		 * vline == 0 could be invalid:
> +		 * Some gpu's get stuck on that value inside vblank. Try again
> +		 * after one scanline duration, if it still reads 0 give up.
> +		 */
> +		if (vline == 0) {
> +			ndelay(drmcrtc->linedur_ns & 0xffff);
> +			vline = nv_rd32(dev, NV_PCRTC_STAT(crtc)) & 0xffff;
> +		}
> +
> +		if(vline > 0)
> +			ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
> +
> +		/* are we in vblank? if yes: do neg countdown */
> +		if((vline >= vbl_start) && (vline < vbl_end)) {
> +			ret |= DRM_SCANOUTPOS_INVBL;
> +			vline -= vbl_end;
> +		}
> +
> +		hline = 0; /* don't use hline as it's unreliable */
> +	}
> +
> +	*vpos = vline;
> +	*hpos = hline;
> +
> +	return ret;
> +}
> +
> +int
> +nouveau_get_vblank_timestamp(struct drm_device *dev, int crtc,
> +			     int *max_error, struct timeval *vblank_time,
> +			     unsigned flags)
> +{
> +	struct drm_crtc *drmcrtc;
> +
> +	if (crtc < 0 || crtc >= dev->num_crtcs) {
> +		DRM_ERROR("Invalid crtc %d\n", crtc);
> +		return -EINVAL;
> +	}
> +
> +	list_for_each_entry(drmcrtc, &dev->mode_config.crtc_list, head) {
> +		if(nouveau_crtc(drmcrtc)->index == crtc)
> +			/* stop if we have found crtc with matching index */
> +			break;
> +	}
> +
> +	return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
> +				vblank_time, flags, drmcrtc);
> +}
> diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
> index 9791d13..555b4aa 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_drv.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
> @@ -411,6 +411,8 @@ static struct drm_driver driver = {
>  	.get_vblank_counter = drm_vblank_count,
>  	.enable_vblank = nouveau_vblank_enable,
>  	.disable_vblank = nouveau_vblank_disable,
> +	.get_vblank_timestamp = nouveau_get_vblank_timestamp,
> +	.get_scanout_position = nouveau_get_scanoutpos,
>  	.reclaim_buffers = drm_core_reclaim_buffers,
>  	.ioctls = nouveau_ioctls,
>  	.fops = {
> diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
> index f489c22..52c3de7 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_drv.h
> +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
> @@ -1419,6 +1419,11 @@ int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  			   struct drm_pending_vblank_event *event);
>  int nouveau_finish_page_flip(struct nouveau_channel *,
>  			     struct nouveau_page_flip_state *);
> +int nouveau_get_scanoutpos(struct drm_device *dev, int crtc,
> +                            int *vpos, int *hpos);
> +int nouveau_get_vblank_timestamp(struct drm_device *dev, int crtc,
> +				 int *max_error, struct timeval *vblank_time,
> +				 unsigned flags);
>  int nouveau_display_dumb_create(struct drm_file *, struct drm_device *,
>  				struct drm_mode_create_dumb *args);
>  int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *,
> diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
> index 43a96b9..0ec1945 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_reg.h
> +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
> @@ -762,7 +762,7 @@
>  #define NV50_PDISPLAY_CRTC_CLOCK                                     0x00610ad0
>  #define NV50_PDISPLAY_CRTC_COLOR_CTRL                                0x00610ae0
>  #define NV50_PDISPLAY_CRTC_SYNC_START_TO_BLANK_END                   0x00610ae8
> -#define NV50_PDISPLAY_CRTC_MODE_UNK1                                 0x00610af0
> +#define NV50_PDISPLAY_CRTC_VBL_START                                 0x00610af0
>  #define NV50_PDISPLAY_CRTC_DISPLAY_TOTAL                             0x00610af8
>  #define NV50_PDISPLAY_CRTC_SYNC_DURATION                             0x00610b00
>  #define NV50_PDISPLAY_CRTC_MODE_UNK2                                 0x00610b08
> @@ -800,6 +800,13 @@
>  #define NV50_PDISPLAY_SOR_CLK                                        0x00614000
>  #define NV50_PDISPLAY_SOR_CLK_CTRL2(i)                  ((i) * 0x800 + 0x614300)
>  
> +#define NV50_PDISPLAY_CRTC_STAT_VERT(i0)		       (0x00616340 + 0x800*(i0))
> +#define NV50_PDISPLAY_CRTC_STAT_VERT_VLINE__MASK		0x0000ffff
> +#define NV50_PDISPLAY_CRTC_STAT_VERT_VBLANK_COUNT__MASK		0xffff0000
> +#define NV50_PDISPLAY_CRTC_STAT_VERT_VBLANK_COUNT__SHIFT	16
> +#define NV50_PDISPLAY_CRTC_STAT_HORZ(i0)		       (0x00616344 + 0x800*(i0))
> +#define NV50_PDISPLAY_CRTC_STAT_HORZ_HLINE__MASK		0x0000ffff
> +
>  #define NV50_PDISPLAY_VGACRTC(r)                                ((r) + 0x619400)
>  
>  #define NV50_PDISPLAY_DAC                                            0x0061a000
> diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
> index 882080e..89fbc31 100644
> --- a/drivers/gpu/drm/nouveau/nv50_crtc.c
> +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
> @@ -505,6 +505,25 @@ static bool
>  nv50_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode,
>  		     struct drm_display_mode *adjusted_mode)
>  {
> +	/* crtc_xxx fields are needed by drm core. Init them with the
> +	 * settings we actually use for mode programming. */
> +	adjusted_mode->synth_clock = adjusted_mode->clock;
> +	adjusted_mode->crtc_hdisplay = adjusted_mode->hdisplay;
> +	adjusted_mode->crtc_hblank_start = 0;
> +	adjusted_mode->crtc_hblank_end = 0;
> +	adjusted_mode->crtc_hsync_start = adjusted_mode->hsync_start;
> +	adjusted_mode->crtc_hsync_end = adjusted_mode->hsync_end;
> +	adjusted_mode->crtc_htotal = adjusted_mode->htotal;
> +	adjusted_mode->crtc_hskew = adjusted_mode->hskew;
> +	adjusted_mode->crtc_vdisplay = adjusted_mode->vdisplay;
> +	adjusted_mode->crtc_vblank_start = 0;
> +	adjusted_mode->crtc_vblank_end = 0;
> +	adjusted_mode->crtc_vsync_start = adjusted_mode->vsync_start;
> +	adjusted_mode->crtc_vsync_end = adjusted_mode->vsync_end;
> +	adjusted_mode->crtc_vtotal = adjusted_mode->vtotal;
> +	adjusted_mode->crtc_hadjusted = 0;
> +	adjusted_mode->crtc_vadjusted = 0;
> +
>  	return true;
>  }
>  
> diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h
> index bbfb1a6..e8281c4 100644
> --- a/drivers/gpu/drm/nouveau/nvreg.h
> +++ b/drivers/gpu/drm/nouveau/nvreg.h
> @@ -172,6 +172,7 @@
>  #define NV_PCRTC_834					0x00600834
>  #define NV_PCRTC_850					0x00600850
>  #define NV_PCRTC_ENGINE_CTRL				0x00600860
> +#define NV_PCRTC_STAT(i0)			(0x00600868 + 0x2000*(i0))
>  #	define NV_CRTC_FSEL_I2C					(1 << 4)
>  #	define NV_CRTC_FSEL_OVERLAY				(1 << 12)
>  

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] drm/nouveau: Use drm_vblank_count_and_time() for pageflip completion events.
@ 2012-04-25 22:26 Lucas Stach
  0 siblings, 0 replies; 7+ messages in thread
From: Lucas Stach @ 2012-04-25 22:26 UTC (permalink / raw)
  To: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW; +Cc: Ben Skeggs, Mario Kleiner

From: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>

Emit kms pageflip completion events with proper vblank count
and timestamp for the vblank interval in which the pageflip
completed. This makes the timestamps and counts consistent with
what the OML_sync_control spec defines.

v2 Lucas Stach: rebased on top of nouveau tree and resolved trivial
conflict.

Signed-off-by: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>

Conflicts:

	drivers/gpu/drm/nouveau/nouveau_display.c
---
 drivers/gpu/drm/nouveau/nouveau_display.c |   29 +++++++++++++++++++++++------
 drivers/gpu/drm/nouveau/nouveau_drv.h     |    1 +
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 71379f8..2c0f415 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -504,7 +504,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	*s = (struct nouveau_page_flip_state)
 		{ { }, event, nouveau_crtc(crtc)->index,
 		  fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y,
-		  new_bo->bo.offset };
+		  new_bo->bo.offset, crtc->framedur_ns };
 
 	/* Choose the channel the flip will be handled in */
 	chan = nouveau_fence_channel(new_bo->bo.sync_obj);
@@ -550,6 +550,9 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
 	struct drm_device *dev = chan->dev;
 	struct nouveau_page_flip_state *s;
 	unsigned long flags;
+	struct timeval tnow, tvbl;
+
+	do_gettimeofday(&tnow);
 
 	spin_lock_irqsave(&dev->event_lock, flags);
 
@@ -563,12 +566,26 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
 			     struct nouveau_page_flip_state, head);
 	if (s->event) {
 		struct drm_pending_vblank_event *e = s->event;
-		struct timeval now;
 
-		do_gettimeofday(&now);
-		e->event.sequence = 0;
-		e->event.tv_sec = now.tv_sec;
-		e->event.tv_usec = now.tv_usec;
+		e->event.sequence = drm_vblank_count_and_time(dev, s->crtc, &tvbl);
+
+		/* Called before vblank count and timestamp have
+		 * been updated for the vblank interval of flip
+		 * completion? If so, need to increment vblank count and
+		 * add one videorefresh duration to returned timestamp
+		 * to account for this. We assume this happened if we
+		 * get called over 0.9 frame durations after the last
+		 * timestamped vblank.
+		 */
+		if (10 * (timeval_to_ns(&tnow) - timeval_to_ns(&tvbl)) >
+		     9 * s->framedur_ns) {
+			e->event.sequence++;
+			tvbl = ns_to_timeval(timeval_to_ns(&tvbl) +
+			s->framedur_ns);
+		}
+
+		e->event.tv_sec = tvbl.tv_sec;
+		e->event.tv_usec = tvbl.tv_usec;
 		list_add_tail(&e->base.link, &e->base.file_priv->event_list);
 		wake_up_interruptible(&e->base.file_priv->event_wait);
 	}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index ab9f9e0..ba10ad7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -203,6 +203,7 @@ struct nouveau_page_flip_state {
 	struct drm_pending_vblank_event *event;
 	int crtc, bpp, pitch, x, y;
 	uint64_t offset;
+	s64 framedur_ns;
 };
 
 enum nouveau_channel_mutex_class {
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 1/2] drm/nouveau: Use drm_vblank_count_and_time() for pageflip completion events.
       [not found]   ` <1329722667-2240-1-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
@ 2012-02-20  7:24     ` Lucas Stach
  0 siblings, 0 replies; 7+ messages in thread
From: Lucas Stach @ 2012-02-20  7:24 UTC (permalink / raw)
  To: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: bskeggs-H+wXaHxf7aLQT0dZR+AlfA, mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ

From: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>

Emit kms pageflip completion events with proper vblank count
and timestamp for the vblank interval in which the pageflip
completed. This makes the timestamps and counts consistent with
what the OML_sync_control spec defines.

v2 Lucas Stach: rebased on top of nouveau tree and resolved trivial
conflict.

Signed-off-by: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>

Conflicts:

	drivers/gpu/drm/nouveau/nouveau_display.c
---
 drivers/gpu/drm/nouveau/nouveau_display.c |   29 +++++++++++++++++++++++------
 drivers/gpu/drm/nouveau/nouveau_drv.h     |    1 +
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 260ebeb..818cfc9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -496,7 +496,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	*s = (struct nouveau_page_flip_state)
 		{ { }, event, nouveau_crtc(crtc)->index,
 		  fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y,
-		  new_bo->bo.offset };
+		  new_bo->bo.offset, crtc->framedur_ns };
 
 	/* Choose the channel the flip will be handled in */
 	chan = nouveau_fence_channel(new_bo->bo.sync_obj);
@@ -542,6 +542,9 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
 	struct drm_device *dev = chan->dev;
 	struct nouveau_page_flip_state *s;
 	unsigned long flags;
+	struct timeval tnow, tvbl;
+
+	do_gettimeofday(&tnow);
 
 	spin_lock_irqsave(&dev->event_lock, flags);
 
@@ -555,12 +558,26 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
 			     struct nouveau_page_flip_state, head);
 	if (s->event) {
 		struct drm_pending_vblank_event *e = s->event;
-		struct timeval now;
 
-		do_gettimeofday(&now);
-		e->event.sequence = 0;
-		e->event.tv_sec = now.tv_sec;
-		e->event.tv_usec = now.tv_usec;
+		e->event.sequence = drm_vblank_count_and_time(dev, s->crtc, &tvbl);
+
+		/* Called before vblank count and timestamp have
+		 * been updated for the vblank interval of flip
+		 * completion? If so, need to increment vblank count and
+		 * add one videorefresh duration to returned timestamp
+		 * to account for this. We assume this happened if we
+		 * get called over 0.9 frame durations after the last
+		 * timestamped vblank.
+		 */
+		if (10 * (timeval_to_ns(&tnow) - timeval_to_ns(&tvbl)) >
+		     9 * s->framedur_ns) {
+			e->event.sequence++;
+			tvbl = ns_to_timeval(timeval_to_ns(&tvbl) +
+			s->framedur_ns);
+		}
+
+		e->event.tv_sec = tvbl.tv_sec;
+		e->event.tv_usec = tvbl.tv_usec;
 		list_add_tail(&e->base.link, &e->base.file_priv->event_list);
 		wake_up_interruptible(&e->base.file_priv->event_wait);
 	}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 4bb6aee..72c015d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -205,6 +205,7 @@ struct nouveau_page_flip_state {
 	struct drm_pending_vblank_event *event;
 	int crtc, bpp, pitch, x, y;
 	uint64_t offset;
+	s64 framedur_ns;
 };
 
 enum nouveau_channel_mutex_class {
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 1/2] drm/nouveau: Use drm_vblank_count_and_time() for pageflip completion events.
       [not found]   ` <1329434903-19977-1-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
@ 2012-02-16 23:28     ` Lucas Stach
  0 siblings, 0 replies; 7+ messages in thread
From: Lucas Stach @ 2012-02-16 23:28 UTC (permalink / raw)
  To: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
  Cc: bskeggs-H+wXaHxf7aLQT0dZR+AlfA, mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ

From: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>

Emit kms pageflip completion events with proper vblank count
and timestamp for the vblank interval in which the pageflip
completed. This makes the timestamps and counts consistent with
what the OML_sync_control spec defines.

v2 Lucas Stach: rebased on top of nouveau tree and resolved trivial
conflict.

Signed-off-by: Mario Kleiner <mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>

Conflicts:

	drivers/gpu/drm/nouveau/nouveau_display.c
---
 drivers/gpu/drm/nouveau/nouveau_display.c |   29 +++++++++++++++++++++++------
 drivers/gpu/drm/nouveau/nouveau_drv.h     |    1 +
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 260ebeb..818cfc9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -496,7 +496,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 	*s = (struct nouveau_page_flip_state)
 		{ { }, event, nouveau_crtc(crtc)->index,
 		  fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y,
-		  new_bo->bo.offset };
+		  new_bo->bo.offset, crtc->framedur_ns };
 
 	/* Choose the channel the flip will be handled in */
 	chan = nouveau_fence_channel(new_bo->bo.sync_obj);
@@ -542,6 +542,9 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
 	struct drm_device *dev = chan->dev;
 	struct nouveau_page_flip_state *s;
 	unsigned long flags;
+	struct timeval tnow, tvbl;
+
+	do_gettimeofday(&tnow);
 
 	spin_lock_irqsave(&dev->event_lock, flags);
 
@@ -555,12 +558,26 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
 			     struct nouveau_page_flip_state, head);
 	if (s->event) {
 		struct drm_pending_vblank_event *e = s->event;
-		struct timeval now;
 
-		do_gettimeofday(&now);
-		e->event.sequence = 0;
-		e->event.tv_sec = now.tv_sec;
-		e->event.tv_usec = now.tv_usec;
+		e->event.sequence = drm_vblank_count_and_time(dev, s->crtc, &tvbl);
+
+		/* Called before vblank count and timestamp have
+		 * been updated for the vblank interval of flip
+		 * completion? If so, need to increment vblank count and
+		 * add one videorefresh duration to returned timestamp
+		 * to account for this. We assume this happened if we
+		 * get called over 0.9 frame durations after the last
+		 * timestamped vblank.
+		 */
+		if (10 * (timeval_to_ns(&tnow) - timeval_to_ns(&tvbl)) >
+		     9 * s->framedur_ns) {
+			e->event.sequence++;
+			tvbl = ns_to_timeval(timeval_to_ns(&tvbl) +
+			s->framedur_ns);
+		}
+
+		e->event.tv_sec = tvbl.tv_sec;
+		e->event.tv_usec = tvbl.tv_usec;
 		list_add_tail(&e->base.link, &e->base.file_priv->event_list);
 		wake_up_interruptible(&e->base.file_priv->event_wait);
 	}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 4bb6aee..72c015d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -205,6 +205,7 @@ struct nouveau_page_flip_state {
 	struct drm_pending_vblank_event *event;
 	int crtc, bpp, pitch, x, y;
 	uint64_t offset;
+	s64 framedur_ns;
 };
 
 enum nouveau_channel_mutex_class {
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2012-04-25 22:26 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-02-15 22:55 [Patches][nouveau/kms]: Precise Vblank and pageflip timestamping Mario Kleiner
     [not found] ` <1329346511-27433-1-git-send-email-mario.kleiner-TdbV1Z3I5XE0NhjG498hmQ@public.gmane.org>
2012-02-15 22:55   ` [PATCH 1/2] drm/nouveau: Use drm_vblank_count_and_time() for pageflip completion events Mario Kleiner
2012-02-15 22:55 ` [PATCH 2/2] nouveau: implement precise vblank timestamping Mario Kleiner
2012-02-16  4:28   ` Ben Skeggs
     [not found] <[Patches][nouveau/kms]: Precise Vblank and pageflip timestamping>
2012-02-16 23:28 ` [Patches][nouveau/kms]: Precise Vblank and pageflip timestamping v2 Lucas Stach
     [not found]   ` <1329434903-19977-1-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
2012-02-16 23:28     ` [PATCH 1/2] drm/nouveau: Use drm_vblank_count_and_time() for pageflip completion events Lucas Stach
     [not found] <[Patches][nouveau/kms]: Precise Vblank and pageflip timestamping v2>
2012-02-20  7:24 ` [Patches][nouveau/kms]: Precise Vblank and pageflip timestamping v2 Lucas Stach
     [not found]   ` <1329722667-2240-1-git-send-email-dev-8ppwABl0HbeELgA04lAiVw@public.gmane.org>
2012-02-20  7:24     ` [PATCH 1/2] drm/nouveau: Use drm_vblank_count_and_time() for pageflip completion events Lucas Stach
2012-04-25 22:26 Lucas Stach

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.