Skip to content

Commit

Permalink
drm: add support for monotonic vblank timestamps
Browse files Browse the repository at this point in the history
Jumps in the vblank and page flip event timestamps cause trouble for
clients, so we should avoid them. The timestamp we get currently with
gettimeofday can jump, so use instead monotonic timestamps.

For backward compatibility use a module flag to revert back to using
gettimeofday timestamps. Add also a DRM_CAP_TIMESTAMP_MONOTONIC flag
that is simply a read only version of the module flag, so that clients
can query this without depending on sysfs.

Signed-off-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Imre Deak authored and Dave Airlie committed Nov 20, 2012
1 parent e62f2f5 commit c61eef7
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 5 deletions.
3 changes: 3 additions & 0 deletions drivers/gpu/drm/drm_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,9 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
req->value |= dev->driver->prime_fd_to_handle ? DRM_PRIME_CAP_IMPORT : 0;
req->value |= dev->driver->prime_handle_to_fd ? DRM_PRIME_CAP_EXPORT : 0;
break;
case DRM_CAP_TIMESTAMP_MONOTONIC:
req->value = drm_timestamp_monotonic;
break;
default:
return -EINVAL;
}
Expand Down
25 changes: 20 additions & 5 deletions drivers/gpu/drm/drm_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,8 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,

/* Get system timestamp after query. */
etime = ktime_get();
mono_time_offset = ktime_get_monotonic_offset();
if (!drm_timestamp_monotonic)
mono_time_offset = ktime_get_monotonic_offset();

preempt_enable();

Expand Down Expand Up @@ -691,7 +692,9 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
vbl_status |= 0x8;
}

etime = ktime_sub(etime, mono_time_offset);
if (!drm_timestamp_monotonic)
etime = ktime_sub(etime, mono_time_offset);

/* save this only for debugging purposes */
tv_etime = ktime_to_timeval(etime);
/* Subtract time delta from raw timestamp to get final
Expand All @@ -714,6 +717,17 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
}
EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);

static struct timeval get_drm_timestamp(void)
{
ktime_t now;

now = ktime_get();
if (!drm_timestamp_monotonic)
now = ktime_sub(now, ktime_get_monotonic_offset());

return ktime_to_timeval(now);
}

/**
* drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent
* vblank interval.
Expand Down Expand Up @@ -751,9 +765,9 @@ u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
}

/* GPU high precision timestamp query unsupported or failed.
* Return gettimeofday timestamp as best estimate.
* Return current monotonic/gettimeofday timestamp as best estimate.
*/
do_gettimeofday(tvblank);
*tvblank = get_drm_timestamp();

return 0;
}
Expand Down Expand Up @@ -842,7 +856,8 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc,
seq = drm_vblank_count_and_time(dev, crtc, &now);
} else {
seq = 0;
do_gettimeofday(&now);

now = get_drm_timestamp();
}
send_vblank_event(dev, e, seq, &now);
}
Expand Down
8 changes: 8 additions & 0 deletions drivers/gpu/drm/drm_stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,24 @@ EXPORT_SYMBOL(drm_vblank_offdelay);
unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */
EXPORT_SYMBOL(drm_timestamp_precision);

/*
* Default to use monotonic timestamps for wait-for-vblank and page-flip
* complete events.
*/
unsigned int drm_timestamp_monotonic = 1;

MODULE_AUTHOR(CORE_AUTHOR);
MODULE_DESCRIPTION(CORE_DESC);
MODULE_LICENSE("GPL and additional rights");
MODULE_PARM_DESC(debug, "Enable debug output");
MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]");
MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");

module_param_named(debug, drm_debug, int, 0600);
module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);

struct idr drm_minors_idr;

Expand Down
1 change: 1 addition & 0 deletions include/drm/drmP.h
Original file line number Diff line number Diff line change
Expand Up @@ -1505,6 +1505,7 @@ extern unsigned int drm_debug;

extern unsigned int drm_vblank_offdelay;
extern unsigned int drm_timestamp_precision;
extern unsigned int drm_timestamp_monotonic;

extern struct class *drm_class;
extern struct proc_dir_entry *drm_proc_root;
Expand Down
1 change: 1 addition & 0 deletions include/uapi/drm/drm.h
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,7 @@ struct drm_event_vblank {
#define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
#define DRM_CAP_DUMB_PREFER_SHADOW 0x4
#define DRM_CAP_PRIME 0x5
#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6

#define DRM_PRIME_CAP_IMPORT 0x1
#define DRM_PRIME_CAP_EXPORT 0x2
Expand Down

0 comments on commit c61eef7

Please sign in to comment.