diff mbox

[v3] drm/core: Add drm_accurate_vblank_count, v3.

Message ID 570D06F3.4010806@linux.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Maarten Lankhorst April 12, 2016, 2:32 p.m. UTC
This function is useful for gen2 intel devices which have no frame
counter, but need a way to determine the current vblank count without
racing with the vblank interrupt handler.

intel_pipe_update_start checks if no vblank interrupt will occur
during vblank evasion, but cannot check whether the vblank handler has
run to completion. This function uses the timestamps to determine
when the last vblank has happened, and interpolates from there.

Changes since v1:
- Take vblank_time_lock and don't use drm_vblank_count_and_time.
Changes since v2:
- Don't return time of last vblank.

Cc: Mario Kleiner <mario.kleiner.de@gmail.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
---

Comments

Ville Syrjälä April 12, 2016, 3:03 p.m. UTC | #1
On Tue, Apr 12, 2016 at 04:32:19PM +0200, Maarten Lankhorst wrote:
> This function is useful for gen2 intel devices which have no frame
> counter, but need a way to determine the current vblank count without
> racing with the vblank interrupt handler.
> 
> intel_pipe_update_start checks if no vblank interrupt will occur
> during vblank evasion, but cannot check whether the vblank handler has
> run to completion. This function uses the timestamps to determine
> when the last vblank has happened, and interpolates from there.
> 
> Changes since v1:
> - Take vblank_time_lock and don't use drm_vblank_count_and_time.
> Changes since v2:
> - Don't return time of last vblank.
> 
> Cc: Mario Kleiner <mario.kleiner.de@gmail.com>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> ---
> diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
> index 3c1a6f18e71c..32bfa4bb8f41 100644
> --- a/drivers/gpu/drm/drm_irq.c
> +++ b/drivers/gpu/drm/drm_irq.c
> @@ -303,6 +303,32 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
>  	store_vblank(dev, pipe, diff, &t_vblank, cur_vblank);
>  }
>  
> +/**
> + * drm_accurate_vblank_count - retrieve the master vblank counter
> + * @crtc: which counter to retrieve
> + * @tv_ret: last time counter was updated
> + *
> + * This function is similar to @drm_crtc_vblank_count but this
> + * function interpolates to handle a race with vblank irq's.
> + */
> +
> +u32 drm_accurate_vblank_count(struct drm_crtc *crtc)
> +{
> +	struct drm_device *dev = crtc->dev;
> +	u32 vblank, pipe = drm_crtc_index(crtc);

pipe should be 'unsigned int' for consistency.

> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&dev->vblank_time_lock, flags);
> +
> +	drm_update_vblank_count(dev, pipe, 0);

One thing that came to mind is some callers might end up doing the
update twice if the irq wasn't yet enabled when drm_vblank_get() was
called. Eg. drm_wait_one_vblank() might do that. So it might be a bit
more efficient to add a drm_vblank_get_and_update() instead, or something
like that. But I don't really care too much.

Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

> +	vblank = dev->vblank[pipe].count;
> +
> +	spin_unlock_irqrestore(&dev->vblank_time_lock, flags);
> +
> +	return vblank;
> +}
> +EXPORT_SYMBOL(drm_accurate_vblank_count);
> +
>  /*
>   * Disable vblank irq's on crtc, make sure that last vblank count
>   * of hardware and corresponding consistent software vblank counter
> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> index 31483c2fef51..747c80da70e5 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -995,6 +995,7 @@ extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
>  extern void drm_crtc_vblank_reset(struct drm_crtc *crtc);
>  extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
>  extern void drm_vblank_cleanup(struct drm_device *dev);
> +extern u32 drm_accurate_vblank_count(struct drm_crtc *crtc);
>  extern u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe);
>  
>  extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
kernel test robot April 12, 2016, 4:43 p.m. UTC | #2
Hi Maarten,

[auto build test WARNING on drm/drm-next]
[also build test WARNING on v4.6-rc3 next-20160412]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url:    https://github.com/0day-ci/linux/commits/Maarten-Lankhorst/drm-core-Add-drm_accurate_vblank_count-v3/20160412-223507
base:   git://people.freedesktop.org/~airlied/linux.git drm-next
reproduce: make htmldocs

All warnings (new ones prefixed by >>):

   drivers/gpu/drm/i915/i915_irq.c:2663: warning: No description found for parameter 'fmt'
   include/drm/drm_crtc.h:364: warning: No description found for parameter 'mode_blob'
   include/drm/drm_crtc.h:779: warning: No description found for parameter 'name'
   include/drm/drm_crtc.h:1238: warning: No description found for parameter 'connector_id'
   include/drm/drm_crtc.h:1238: warning: No description found for parameter 'tile_blob_ptr'
   include/drm/drm_crtc.h:1277: warning: No description found for parameter 'rotation'
   include/drm/drm_crtc.h:1539: warning: No description found for parameter 'name'
   include/drm/drm_crtc.h:1539: warning: No description found for parameter 'mutex'
   include/drm/drm_crtc.h:1539: warning: No description found for parameter 'helper_private'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tile_idr'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'connector_ida'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'delayed_event'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'edid_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'dpms_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'path_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tile_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'plane_type_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'rotation_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'prop_src_x'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'prop_src_y'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'prop_src_w'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'prop_src_h'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'prop_crtc_x'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'prop_crtc_y'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'prop_crtc_w'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'prop_crtc_h'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'prop_fb_id'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'prop_crtc_id'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'prop_active'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'prop_mode_id'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'dvi_i_subconnector_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'dvi_i_select_subconnector_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tv_subconnector_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tv_select_subconnector_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tv_mode_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tv_left_margin_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tv_right_margin_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tv_top_margin_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tv_bottom_margin_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tv_brightness_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tv_contrast_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tv_flicker_reduction_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tv_overscan_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tv_saturation_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'tv_hue_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'scaling_mode_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'aspect_ratio_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'dirty_info_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'suggested_x_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'suggested_y_property'
   include/drm/drm_crtc.h:2175: warning: No description found for parameter 'allow_fb_modifiers'
   drivers/gpu/drm/drm_atomic_helper.c:2924: warning: No description found for parameter 'start'
   drivers/gpu/drm/drm_atomic_helper.c:2924: warning: No description found for parameter 'start'
   drivers/gpu/drm/drm_atomic_helper.c:2924: warning: No description found for parameter 'start'
   drivers/gpu/drm/drm_atomic_helper.c:2924: warning: No description found for parameter 'start'
   include/drm/drm_dp_helper.h:749: warning: No description found for parameter 'i2c_nack_count'
   include/drm/drm_dp_helper.h:749: warning: No description found for parameter 'i2c_defer_count'
   drivers/gpu/drm/drm_dp_mst_topology.c:2356: warning: No description found for parameter 'connector'
   include/drm/drm_dp_mst_helper.h:92: warning: No description found for parameter 'cached_edid'
   include/drm/drm_dp_mst_helper.h:92: warning: No description found for parameter 'has_audio'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'max_dpcd_transaction_bytes'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'sink_count'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'total_slots'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'avail_slots'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'total_pbn'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'qlock'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'tx_msg_downq'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'tx_down_in_progress'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'payload_lock'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'proposed_vcpis'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'payloads'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'payload_mask'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'vcpi_mask'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'tx_waitq'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'work'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'tx_work'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'destroy_connector_list'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'destroy_connector_lock'
   include/drm/drm_dp_mst_helper.h:466: warning: No description found for parameter 'destroy_connector_work'
   drivers/gpu/drm/drm_dp_mst_topology.c:2356: warning: No description found for parameter 'connector'
   drivers/gpu/drm/drm_irq.c:176: warning: No description found for parameter 'flags'
>> drivers/gpu/drm/drm_irq.c:316: warning: Excess function parameter 'tv_ret' description in 'drm_accurate_vblank_count'
   include/drm/drmP.h:168: warning: No description found for parameter 'fmt'
   include/drm/drmP.h:184: warning: No description found for parameter 'fmt'
   include/drm/drmP.h:202: warning: No description found for parameter 'fmt'
   include/drm/drmP.h:247: warning: No description found for parameter 'dev'
   include/drm/drmP.h:247: warning: No description found for parameter 'data'
   include/drm/drmP.h:247: warning: No description found for parameter 'file_priv'
   include/drm/drmP.h:280: warning: No description found for parameter 'ioctl'
   include/drm/drmP.h:280: warning: No description found for parameter '_func'
   include/drm/drmP.h:280: warning: No description found for parameter '_flags'
   include/drm/drmP.h:362: warning: cannot understand function prototype: 'struct drm_lock_data '
   include/drm/drmP.h:415: warning: cannot understand function prototype: 'struct drm_driver '
   include/drm/drmP.h:672: warning: cannot understand function prototype: 'struct drm_info_list '
   include/drm/drmP.h:682: warning: cannot understand function prototype: 'struct drm_info_node '
   include/drm/drmP.h:692: warning: cannot understand function prototype: 'struct drm_minor '
   include/drm/drmP.h:740: warning: cannot understand function prototype: 'struct drm_device '
   drivers/gpu/drm/i915/intel_runtime_pm.c:2275: warning: No description found for parameter 'resume'
   drivers/gpu/drm/i915/intel_runtime_pm.c:2275: warning: No description found for parameter 'resume'
   drivers/gpu/drm/i915/i915_irq.c:2663: warning: No description found for parameter 'fmt'
   drivers/gpu/drm/i915/i915_irq.c:2663: warning: No description found for parameter 'fmt'
   drivers/gpu/drm/i915/i915_irq.c:2663: warning: No description found for parameter 'fmt'
   drivers/gpu/drm/i915/i915_irq.c:2663: warning: No description found for parameter 'fmt'
   drivers/gpu/drm/i915/i915_gem.c:421: warning: No description found for parameter 'dev'
   drivers/gpu/drm/i915/i915_gem.c:421: warning: No description found for parameter 'data'
   drivers/gpu/drm/i915/i915_gem.c:421: warning: No description found for parameter 'file'
   drivers/gpu/drm/i915/i915_gem.c:686: warning: No description found for parameter 'dev'
   drivers/gpu/drm/i915/i915_gem.c:686: warning: No description found for parameter 'data'
   drivers/gpu/drm/i915/i915_gem.c:686: warning: No description found for parameter 'file'
   drivers/gpu/drm/i915/i915_gem.c:767: warning: No description found for parameter 'dev'
   drivers/gpu/drm/i915/i915_gem.c:767: warning: No description found for parameter 'obj'
   drivers/gpu/drm/i915/i915_gem.c:767: warning: No description found for parameter 'args'
   drivers/gpu/drm/i915/i915_gem.c:767: warning: No description found for parameter 'file'
   drivers/gpu/drm/i915/i915_gem.c:1029: warning: No description found for parameter 'dev'
   drivers/gpu/drm/i915/i915_gem.c:1029: warning: No description found for parameter 'data'
   drivers/gpu/drm/i915/i915_gem.c:1029: warning: No description found for parameter 'file'
   drivers/gpu/drm/i915/i915_gem.c:1245: warning: No description found for parameter 'rps'
   drivers/gpu/drm/i915/i915_gem.c:1459: warning: No description found for parameter 'req'
   drivers/gpu/drm/i915/i915_gem.c:1494: warning: No description found for parameter 'obj'
   drivers/gpu/drm/i915/i915_gem.c:1494: warning: No description found for parameter 'readonly'
   drivers/gpu/drm/i915/i915_gem.c:1617: warning: No description found for parameter 'dev'
   drivers/gpu/drm/i915/i915_gem.c:1617: warning: No description found for parameter 'data'
   drivers/gpu/drm/i915/i915_gem.c:1617: warning: No description found for parameter 'file'
   drivers/gpu/drm/i915/i915_gem.c:1680: warning: No description found for parameter 'dev'
   drivers/gpu/drm/i915/i915_gem.c:1680: warning: No description found for parameter 'data'
   drivers/gpu/drm/i915/i915_gem.c:1680: warning: No description found for parameter 'file'
   drivers/gpu/drm/i915/i915_gem.c:1725: warning: No description found for parameter 'dev'
   drivers/gpu/drm/i915/i915_gem.c:1725: warning: No description found for parameter 'data'
   drivers/gpu/drm/i915/i915_gem.c:1725: warning: No description found for parameter 'file'
   drivers/gpu/drm/i915/i915_gem.c:2013: warning: No description found for parameter 'dev'
   drivers/gpu/drm/i915/i915_gem.c:2013: warning: No description found for parameter 'size'
   drivers/gpu/drm/i915/i915_gem.c:2013: warning: No description found for parameter 'tiling_mode'
   drivers/gpu/drm/i915/i915_gem.c:2013: warning: No description found for parameter 'fenced'
   drivers/gpu/drm/i915/i915_gem.c:2013: warning: Excess function parameter 'obj' description in 'i915_gem_get_gtt_alignment'
   drivers/gpu/drm/i915/i915_gem.c:2911: warning: No description found for parameter 'engine'
   drivers/gpu/drm/i915/i915_gem.c:3037: warning: No description found for parameter 'obj'
   drivers/gpu/drm/i915/i915_gem.c:3087: warning: No description found for parameter 'dev'
   drivers/gpu/drm/i915/i915_gem.c:3087: warning: No description found for parameter 'data'
   drivers/gpu/drm/i915/i915_gem.c:3087: warning: No description found for parameter 'file'
   drivers/gpu/drm/i915/i915_gem.c:3087: warning: Excess function parameter 'DRM_IOCTL_ARGS' description in 'i915_gem_wait_ioctl'
   drivers/gpu/drm/i915/i915_gem.c:3459: warning: No description found for parameter 'obj'
   drivers/gpu/drm/i915/i915_gem.c:3459: warning: No description found for parameter 'vm'
   drivers/gpu/drm/i915/i915_gem.c:3459: warning: No description found for parameter 'ggtt_view'
   drivers/gpu/drm/i915/i915_gem.c:3459: warning: No description found for parameter 'alignment'
   drivers/gpu/drm/i915/i915_gem.c:3459: warning: No description found for parameter 'flags'
   drivers/gpu/drm/i915/i915_gem.c:3714: warning: No description found for parameter 'obj'
   drivers/gpu/drm/i915/i915_gem.c:3714: warning: No description found for parameter 'write'
   drivers/gpu/drm/i915/i915_gem.c:3789: warning: No description found for parameter 'obj'
   drivers/gpu/drm/i915/i915_gem.c:3789: warning: No description found for parameter 'cache_level'
   drivers/gpu/drm/i915/i915_gem.c:4063: warning: No description found for parameter 'obj'
   drivers/gpu/drm/i915/i915_gem.c:4063: warning: No description found for parameter 'write'
   drivers/gpu/drm/i915/i915_cmd_parser.c:748: warning: No description found for parameter 'engine'
   drivers/gpu/drm/i915/i915_cmd_parser.c:748: warning: Excess function parameter 'ring' description in 'i915_cmd_parser_init_ring'
   drivers/gpu/drm/i915/i915_cmd_parser.c:838: warning: No description found for parameter 'engine'
   drivers/gpu/drm/i915/i915_cmd_parser.c:838: warning: Excess function parameter 'ring' description in 'i915_cmd_parser_fini_ring'
   drivers/gpu/drm/i915/i915_cmd_parser.c:1034: warning: No description found for parameter 'engine'
   drivers/gpu/drm/i915/i915_cmd_parser.c:1034: warning: Excess function parameter 'ring' description in 'i915_needs_cmd_parser'
   drivers/gpu/drm/i915/i915_cmd_parser.c:1186: warning: No description found for parameter 'engine'
   drivers/gpu/drm/i915/i915_cmd_parser.c:1186: warning: Excess function parameter 'ring' description in 'i915_parse_cmds'
   drivers/gpu/drm/i915/i915_cmd_parser.c:748: warning: No description found for parameter 'engine'
   drivers/gpu/drm/i915/i915_cmd_parser.c:748: warning: Excess function parameter 'ring' description in 'i915_cmd_parser_init_ring'
   drivers/gpu/drm/i915/i915_cmd_parser.c:838: warning: No description found for parameter 'engine'
   drivers/gpu/drm/i915/i915_cmd_parser.c:838: warning: Excess function parameter 'ring' description in 'i915_cmd_parser_fini_ring'
   drivers/gpu/drm/i915/i915_cmd_parser.c:1034: warning: No description found for parameter 'engine'
   drivers/gpu/drm/i915/i915_cmd_parser.c:1034: warning: Excess function parameter 'ring' description in 'i915_needs_cmd_parser'
   drivers/gpu/drm/i915/i915_cmd_parser.c:1186: warning: No description found for parameter 'engine'
   drivers/gpu/drm/i915/i915_cmd_parser.c:1186: warning: Excess function parameter 'ring' description in 'i915_parse_cmds'
   drivers/gpu/drm/i915/intel_lrc.c:318: warning: No description found for parameter 'engine'
   drivers/gpu/drm/i915/intel_lrc.c:318: warning: Excess function parameter 'ring' description in 'intel_lr_context_descriptor_update'
   drivers/gpu/drm/i915/intel_lrc.c:355: warning: No description found for parameter 'engine'
   drivers/gpu/drm/i915/intel_lrc.c:355: warning: Excess function parameter 'ring' description in 'intel_execlists_ctx_id'
   drivers/gpu/drm/i915/intel_lrc.c:547: warning: No description found for parameter 'engine'
   drivers/gpu/drm/i915/intel_lrc.c:547: warning: Excess function parameter 'ring' description in 'intel_lrc_irq_handler'
   drivers/gpu/drm/i915/intel_lrc.c:951: warning: No description found for parameter 'params'
   drivers/gpu/drm/i915/intel_lrc.c:951: warning: Excess function parameter 'dev' description in 'intel_execlists_submission'
   drivers/gpu/drm/i915/intel_lrc.c:951: warning: Excess function parameter 'file' description in 'intel_execlists_submission'
   drivers/gpu/drm/i915/intel_lrc.c:951: warning: Excess function parameter 'ring' description in 'intel_execlists_submission'
   drivers/gpu/drm/i915/intel_lrc.c:951: warning: Excess function parameter 'ctx' description in 'intel_execlists_submission'
   drivers/gpu/drm/i915/intel_lrc.c:951: warning: Excess function parameter 'batch_obj' description in 'intel_execlists_submission'
   drivers/gpu/drm/i915/intel_lrc.c:951: warning: Excess function parameter 'exec_start' description in 'intel_execlists_submission'
   drivers/gpu/drm/i915/intel_lrc.c:951: warning: Excess function parameter 'dispatch_flags' description in 'intel_execlists_submission'
   drivers/gpu/drm/i915/intel_lrc.c:1334: warning: No description found for parameter 'engine'

vim +316 drivers/gpu/drm/drm_irq.c

   170	 *
   171	 * Note: caller must hold dev->vbl_lock since this reads & writes
   172	 * device vblank fields.
   173	 */
   174	static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
   175					    unsigned long flags)
 > 176	{
   177		struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
   178		u32 cur_vblank, diff;
   179		bool rc;
   180		struct timeval t_vblank;
   181		int count = DRM_TIMESTAMP_MAXRETRIES;
   182		int framedur_ns = vblank->framedur_ns;
   183	
   184		/*
   185		 * Interrupts were disabled prior to this call, so deal with counter
   186		 * wrap if needed.
   187		 * NOTE!  It's possible we lost a full dev->max_vblank_count + 1 events
   188		 * here if the register is small or we had vblank interrupts off for
   189		 * a long time.
   190		 *
   191		 * We repeat the hardware vblank counter & timestamp query until
   192		 * we get consistent results. This to prevent races between gpu
   193		 * updating its hardware counter while we are retrieving the
   194		 * corresponding vblank timestamp.
   195		 */
   196		do {
   197			cur_vblank = dev->driver->get_vblank_counter(dev, pipe);
   198			rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, flags);
   199		} while (cur_vblank != dev->driver->get_vblank_counter(dev, pipe) && --count > 0);
   200	
   201		if (dev->max_vblank_count != 0) {
   202			/* trust the hw counter when it's around */
   203			diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
   204		} else if (rc && framedur_ns) {
   205			const struct timeval *t_old;
   206			u64 diff_ns;
   207	
   208			t_old = &vblanktimestamp(dev, pipe, vblank->count);
   209			diff_ns = timeval_to_ns(&t_vblank) - timeval_to_ns(t_old);
   210	
   211			/*
   212			 * Figure out how many vblanks we've missed based
   213			 * on the difference in the timestamps and the
   214			 * frame/field duration.
   215			 */
   216			diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns);
   217	
   218			if (diff == 0 && flags & DRM_CALLED_FROM_VBLIRQ)
   219				DRM_DEBUG_VBL("crtc %u: Redundant vblirq ignored."
   220					      " diff_ns = %lld, framedur_ns = %d)\n",
   221					      pipe, (long long) diff_ns, framedur_ns);
   222		} else {
   223			/* some kind of default for drivers w/o accurate vbl timestamping */
   224			diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0;
   225		}
   226	
   227		/*
   228		 * Within a drm_vblank_pre_modeset - drm_vblank_post_modeset
   229		 * interval? If so then vblank irqs keep running and it will likely
   230		 * happen that the hardware vblank counter is not trustworthy as it
   231		 * might reset at some point in that interval and vblank timestamps
   232		 * are not trustworthy either in that interval. Iow. this can result
   233		 * in a bogus diff >> 1 which must be avoided as it would cause
   234		 * random large forward jumps of the software vblank counter.
   235		 */
   236		if (diff > 1 && (vblank->inmodeset & 0x2)) {
   237			DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u"
   238				      " due to pre-modeset.\n", pipe, diff);
   239			diff = 1;
   240		}
   241	
   242		/*
   243		 * FIMXE: Need to replace this hack with proper seqlocks.
   244		 *
   245		 * Restrict the bump of the software vblank counter to a safe maximum
   246		 * value of +1 whenever there is the possibility that concurrent readers
   247		 * of vblank timestamps could be active at the moment, as the current
   248		 * implementation of the timestamp caching and updating is not safe
   249		 * against concurrent readers for calls to store_vblank() with a bump
   250		 * of anything but +1. A bump != 1 would very likely return corrupted
   251		 * timestamps to userspace, because the same slot in the cache could
   252		 * be concurrently written by store_vblank() and read by one of those
   253		 * readers without the read-retry logic detecting the collision.
   254		 *
   255		 * Concurrent readers can exist when we are called from the
   256		 * drm_vblank_off() or drm_vblank_on() functions and other non-vblank-
   257		 * irq callers. However, all those calls to us are happening with the
   258		 * vbl_lock locked to prevent drm_vblank_get(), so the vblank refcount
   259		 * can't increase while we are executing. Therefore a zero refcount at
   260		 * this point is safe for arbitrary counter bumps if we are called
   261		 * outside vblank irq, a non-zero count is not 100% safe. Unfortunately
   262		 * we must also accept a refcount of 1, as whenever we are called from
   263		 * drm_vblank_get() -> drm_vblank_enable() the refcount will be 1 and
   264		 * we must let that one pass through in order to not lose vblank counts
   265		 * during vblank irq off - which would completely defeat the whole
   266		 * point of this routine.
   267		 *
   268		 * Whenever we are called from vblank irq, we have to assume concurrent
   269		 * readers exist or can show up any time during our execution, even if
   270		 * the refcount is currently zero, as vblank irqs are usually only
   271		 * enabled due to the presence of readers, and because when we are called
   272		 * from vblank irq we can't hold the vbl_lock to protect us from sudden
   273		 * bumps in vblank refcount. Therefore also restrict bumps to +1 when
   274		 * called from vblank irq.
   275		 */
   276		if ((diff > 1) && (atomic_read(&vblank->refcount) > 1 ||
   277		    (flags & DRM_CALLED_FROM_VBLIRQ))) {
   278			DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u "
   279				      "refcount %u, vblirq %u\n", pipe, diff,
   280				      atomic_read(&vblank->refcount),
   281				      (flags & DRM_CALLED_FROM_VBLIRQ) != 0);
   282			diff = 1;
   283		}
   284	
   285		DRM_DEBUG_VBL("updating vblank count on crtc %u:"
   286			      " current=%u, diff=%u, hw=%u hw_last=%u\n",
   287			      pipe, vblank->count, diff, cur_vblank, vblank->last);
   288	
   289		if (diff == 0) {
   290			WARN_ON_ONCE(cur_vblank != vblank->last);
   291			return;
   292		}
   293	
   294		/*
   295		 * Only reinitialize corresponding vblank timestamp if high-precision query
   296		 * available and didn't fail, or we were called from the vblank interrupt.
   297		 * Otherwise reinitialize delayed at next vblank interrupt and assign 0
   298		 * for now, to mark the vblanktimestamp as invalid.
   299		 */
   300		if (!rc && (flags & DRM_CALLED_FROM_VBLIRQ) == 0)
   301			t_vblank = (struct timeval) {0, 0};
   302	
   303		store_vblank(dev, pipe, diff, &t_vblank, cur_vblank);
   304	}
   305	
   306	/**
   307	 * drm_accurate_vblank_count - retrieve the master vblank counter
   308	 * @crtc: which counter to retrieve
   309	 * @tv_ret: last time counter was updated
   310	 *
   311	 * This function is similar to @drm_crtc_vblank_count but this
   312	 * function interpolates to handle a race with vblank irq's.
   313	 */
   314	
   315	u32 drm_accurate_vblank_count(struct drm_crtc *crtc)
 > 316	{
   317		struct drm_device *dev = crtc->dev;
   318		u32 vblank, pipe = drm_crtc_index(crtc);
   319		unsigned long flags;

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 3c1a6f18e71c..32bfa4bb8f41 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -303,6 +303,32 @@  static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
 	store_vblank(dev, pipe, diff, &t_vblank, cur_vblank);
 }
 
+/**
+ * drm_accurate_vblank_count - retrieve the master vblank counter
+ * @crtc: which counter to retrieve
+ * @tv_ret: last time counter was updated
+ *
+ * This function is similar to @drm_crtc_vblank_count but this
+ * function interpolates to handle a race with vblank irq's.
+ */
+
+u32 drm_accurate_vblank_count(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	u32 vblank, pipe = drm_crtc_index(crtc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->vblank_time_lock, flags);
+
+	drm_update_vblank_count(dev, pipe, 0);
+	vblank = dev->vblank[pipe].count;
+
+	spin_unlock_irqrestore(&dev->vblank_time_lock, flags);
+
+	return vblank;
+}
+EXPORT_SYMBOL(drm_accurate_vblank_count);
+
 /*
  * Disable vblank irq's on crtc, make sure that last vblank count
  * of hardware and corresponding consistent software vblank counter
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 31483c2fef51..747c80da70e5 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -995,6 +995,7 @@  extern void drm_crtc_vblank_off(struct drm_crtc *crtc);
 extern void drm_crtc_vblank_reset(struct drm_crtc *crtc);
 extern void drm_crtc_vblank_on(struct drm_crtc *crtc);
 extern void drm_vblank_cleanup(struct drm_device *dev);
+extern u32 drm_accurate_vblank_count(struct drm_crtc *crtc);
 extern u32 drm_vblank_no_hw_counter(struct drm_device *dev, unsigned int pipe);
 
 extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,