Commit edbaae5a authored by Dave Airlie's avatar Dave Airlie

Merge tag 'topic/vblank-rework-2014-09-12' of git://anongit.freedesktop.org/drm-intel into drm-next

So updated vblank-rework pull request, now with the polish that Mario
requested applied (and reviewed by him). Also with backmerge like you've
requested for easier merging.

The neat thing this finally allows is to immediately disable the vblank
interrupt on the last drm_vblank_put if the hardware has perfectly
accurate vblank counter and timestamp readout support. On i915 that
required piles of small adjustements from Ville since depending upon the
platform and port the vblank happens at different scanout lines.

Of course this is fully opt-in and per-device (we need that since gen2
doesn't have a hw vblank counter).

* tag 'topic/vblank-rework-2014-09-12' of git://anongit.freedesktop.org/drm-intel: (22 commits)
  drm: Clarify vblank ts/scanoutpos sampling #defines
  drm: Simplify return value of drm_get_last_vbltimestamp
  drm: Only update final vblank count when precise ts is available
  drm: Really never disable vblank irqs for offdelay==0
  drm: Use vblank_disable_and_save in drm_vblank_cleanup()
  drm: Remove drm_vblank_cleanup from drm_vblank_init error path.
  drm: Store the vblank timestamp when adjusting the counter during disable
  drm: Fix confusing debug message in drm_update_vblank_count()
  drm/i915: Update scanline_offset only for active crtcs
  drm: Kick start vblank interrupts at drm_vblank_on()
  drm/i915: Opt out of vblank disable timer on >gen2
  drm: Add dev->vblank_disable_immediate flag
  drm: Disable vblank interrupt immediately when drm_vblank_offdelay<0
  drm: Fix race between drm_vblank_off() and drm_queue_vblank_event()
  drm: Fix deadlock between event_lock and vbl_lock/vblank_time_lock
  drm: Reduce the amount of dev->vblank[crtc] in the code
  drm: Avoid random vblank counter jumps if the hardware counter has been reset
  drm: Have the vblank counter account for the time between vblank irq disable and drm_vblank_off()
  drm: Move drm_update_vblank_count()
  drm: Don't clear vblank timestamps when vblank interrupt is disabled
  ...
parents a9d6dd25 336879b1
...@@ -3385,6 +3385,13 @@ void (*disable_vblank) (struct drm_device *dev, int crtc);</synopsis> ...@@ -3385,6 +3385,13 @@ void (*disable_vblank) (struct drm_device *dev, int crtc);</synopsis>
by scheduling a timer. The delay is accessible through the vblankoffdelay by scheduling a timer. The delay is accessible through the vblankoffdelay
module parameter or the <varname>drm_vblank_offdelay</varname> global module parameter or the <varname>drm_vblank_offdelay</varname> global
variable and expressed in milliseconds. Its default value is 5000 ms. variable and expressed in milliseconds. Its default value is 5000 ms.
Zero means never disable, and a negative value means disable immediately.
Drivers may override the behaviour by setting the
<structname>drm_device</structname>
<structfield>vblank_disable_immediate</structfield> flag, which when set
causes vblank interrupts to be disabled immediately regardless of the
drm_vblank_offdelay value. The flag should only be set if there's a
properly working hardware vblank counter present.
</para> </para>
<para> <para>
When a vertical blanking interrupt occurs drivers only need to call the When a vertical blanking interrupt occurs drivers only need to call the
......
...@@ -39,7 +39,7 @@ ...@@ -39,7 +39,7 @@
unsigned int drm_debug = 0; /* 1 to enable debug output */ unsigned int drm_debug = 0; /* 1 to enable debug output */
EXPORT_SYMBOL(drm_debug); EXPORT_SYMBOL(drm_debug);
unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */
unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */
...@@ -53,7 +53,7 @@ MODULE_AUTHOR(CORE_AUTHOR); ...@@ -53,7 +53,7 @@ MODULE_AUTHOR(CORE_AUTHOR);
MODULE_DESCRIPTION(CORE_DESC); MODULE_DESCRIPTION(CORE_DESC);
MODULE_LICENSE("GPL and additional rights"); MODULE_LICENSE("GPL and additional rights");
MODULE_PARM_DESC(debug, "Enable debug output"); MODULE_PARM_DESC(debug, "Enable debug output");
MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]"); MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)");
MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
......
This diff is collapsed.
...@@ -1020,7 +1020,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, ...@@ -1020,7 +1020,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
/* In vblank? */ /* In vblank? */
if (in_vbl) if (in_vbl)
ret |= DRM_SCANOUTPOS_INVBL; ret |= DRM_SCANOUTPOS_IN_VBLANK;
return ret; return ret;
} }
...@@ -4701,6 +4701,14 @@ void intel_irq_init(struct drm_device *dev) ...@@ -4701,6 +4701,14 @@ void intel_irq_init(struct drm_device *dev)
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
} }
/*
* Opt out of the vblank disable timer on everything except gen2.
* Gen2 doesn't have a hardware frame counter and so depends on
* vblank interrupts to produce sane vblank seuquence numbers.
*/
if (!IS_GEN2(dev))
dev->vblank_disable_immediate = true;
if (drm_core_check_feature(dev, DRIVER_MODESET)) { if (drm_core_check_feature(dev, DRIVER_MODESET)) {
dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp;
dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
......
...@@ -1342,6 +1342,12 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv, ...@@ -1342,6 +1342,12 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
} }
} }
static void assert_vblank_disabled(struct drm_crtc *crtc)
{
if (WARN_ON(drm_crtc_vblank_get(crtc) == 0))
drm_crtc_vblank_put(crtc);
}
static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
{ {
u32 val; u32 val;
...@@ -3891,6 +3897,8 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc) ...@@ -3891,6 +3897,8 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc)
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe; int pipe = intel_crtc->pipe;
assert_vblank_disabled(crtc);
drm_vblank_on(dev, pipe); drm_vblank_on(dev, pipe);
intel_enable_primary_hw_plane(crtc->primary, crtc); intel_enable_primary_hw_plane(crtc->primary, crtc);
...@@ -3940,6 +3948,8 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) ...@@ -3940,6 +3948,8 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_ALL_MASK(pipe)); intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_ALL_MASK(pipe));
drm_vblank_off(dev, pipe); drm_vblank_off(dev, pipe);
assert_vblank_disabled(crtc);
} }
static void ironlake_crtc_enable(struct drm_crtc *crtc) static void ironlake_crtc_enable(struct drm_crtc *crtc)
...@@ -12766,9 +12776,10 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) ...@@ -12766,9 +12776,10 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
/* restore vblank interrupts to correct state */ /* restore vblank interrupts to correct state */
if (crtc->active) if (crtc->active) {
update_scanline_offset(crtc);
drm_vblank_on(dev, crtc->pipe); drm_vblank_on(dev, crtc->pipe);
else } else
drm_vblank_off(dev, crtc->pipe); drm_vblank_off(dev, crtc->pipe);
/* We need to sanitize the plane -> pipe mapping first because this will /* We need to sanitize the plane -> pipe mapping first because this will
...@@ -12867,8 +12878,6 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) ...@@ -12867,8 +12878,6 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
*/ */
crtc->cpu_fifo_underrun_disabled = true; crtc->cpu_fifo_underrun_disabled = true;
crtc->pch_fifo_underrun_disabled = true; crtc->pch_fifo_underrun_disabled = true;
update_scanline_offset(crtc);
} }
} }
......
...@@ -126,7 +126,7 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, ...@@ -126,7 +126,7 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
if (etime) *etime = ns_to_ktime(args.scan.time[1]); if (etime) *etime = ns_to_ktime(args.scan.time[1]);
if (*vpos < 0) if (*vpos < 0)
ret |= DRM_SCANOUTPOS_INVBL; ret |= DRM_SCANOUTPOS_IN_VBLANK;
return ret; return ret;
} }
......
...@@ -1914,7 +1914,7 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl ...@@ -1914,7 +1914,7 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl
/* In vblank? */ /* In vblank? */
if (in_vbl) if (in_vbl)
ret |= DRM_SCANOUTPOS_INVBL; ret |= DRM_SCANOUTPOS_IN_VBLANK;
/* Is vpos outside nominal vblank area, but less than /* Is vpos outside nominal vblank area, but less than
* 1/100 of a frame height away from start of vblank? * 1/100 of a frame height away from start of vblank?
......
...@@ -1556,7 +1556,7 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev) ...@@ -1556,7 +1556,7 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev)
if (rdev->pm.active_crtcs & (1 << crtc)) { if (rdev->pm.active_crtcs & (1 << crtc)) {
vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, &vpos, &hpos, NULL, NULL); vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, &vpos, &hpos, NULL, NULL);
if ((vbl_status & DRM_SCANOUTPOS_VALID) && if ((vbl_status & DRM_SCANOUTPOS_VALID) &&
!(vbl_status & DRM_SCANOUTPOS_INVBL)) !(vbl_status & DRM_SCANOUTPOS_IN_VBLANK))
in_vbl = false; in_vbl = false;
} }
} }
......
...@@ -580,11 +580,11 @@ struct drm_master { ...@@ -580,11 +580,11 @@ struct drm_master {
/* Flags and return codes for get_vblank_timestamp() driver function. */ /* Flags and return codes for get_vblank_timestamp() driver function. */
#define DRM_CALLED_FROM_VBLIRQ 1 #define DRM_CALLED_FROM_VBLIRQ 1
#define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0) #define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0)
#define DRM_VBLANKTIME_INVBL (1 << 1) #define DRM_VBLANKTIME_IN_VBLANK (1 << 1)
/* get_scanout_position() return flags */ /* get_scanout_position() return flags */
#define DRM_SCANOUTPOS_VALID (1 << 0) #define DRM_SCANOUTPOS_VALID (1 << 0)
#define DRM_SCANOUTPOS_INVBL (1 << 1) #define DRM_SCANOUTPOS_IN_VBLANK (1 << 1)
#define DRM_SCANOUTPOS_ACCURATE (1 << 2) #define DRM_SCANOUTPOS_ACCURATE (1 << 2)
/** /**
...@@ -978,6 +978,16 @@ struct drm_device { ...@@ -978,6 +978,16 @@ struct drm_device {
*/ */
bool vblank_disable_allowed; bool vblank_disable_allowed;
/*
* If true, vblank interrupt will be disabled immediately when the
* refcount drops to zero, as opposed to via the vblank disable
* timer.
* This can be set to true it the hardware has a working vblank
* counter and the driver uses drm_vblank_on() and drm_vblank_off()
* appropriately.
*/
bool vblank_disable_immediate;
/* array of size num_crtcs */ /* array of size num_crtcs */
struct drm_vblank_crtc *vblank; struct drm_vblank_crtc *vblank;
...@@ -1164,8 +1174,6 @@ extern void drm_crtc_vblank_off(struct drm_crtc *crtc); ...@@ -1164,8 +1174,6 @@ extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
extern void drm_crtc_vblank_on(struct drm_crtc *crtc); extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
extern void drm_vblank_cleanup(struct drm_device *dev); extern void drm_vblank_cleanup(struct drm_device *dev);
extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
struct timeval *tvblank, unsigned flags);
extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
int crtc, int *max_error, int crtc, int *max_error,
struct timeval *vblank_time, struct timeval *vblank_time,
...@@ -1206,7 +1214,7 @@ extern void drm_put_dev(struct drm_device *dev); ...@@ -1206,7 +1214,7 @@ extern void drm_put_dev(struct drm_device *dev);
extern void drm_unplug_dev(struct drm_device *dev); extern void drm_unplug_dev(struct drm_device *dev);
extern unsigned int drm_debug; extern unsigned int drm_debug;
extern unsigned int drm_vblank_offdelay; extern int drm_vblank_offdelay;
extern unsigned int drm_timestamp_precision; extern unsigned int drm_timestamp_precision;
extern unsigned int drm_timestamp_monotonic; extern unsigned int drm_timestamp_monotonic;
......
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