|
@@ -78,7 +78,7 @@
|
|
|
|
|
|
static bool
|
|
|
drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
|
|
|
- struct timeval *tvblank, bool in_vblank_irq);
|
|
|
+ ktime_t *tvblank, bool in_vblank_irq);
|
|
|
|
|
|
static unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */
|
|
|
|
|
@@ -99,7 +99,7 @@ MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
|
|
|
|
|
|
static void store_vblank(struct drm_device *dev, unsigned int pipe,
|
|
|
u32 vblank_count_inc,
|
|
|
- struct timeval *t_vblank, u32 last)
|
|
|
+ ktime_t t_vblank, u32 last)
|
|
|
{
|
|
|
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
|
|
|
|
|
@@ -108,7 +108,7 @@ static void store_vblank(struct drm_device *dev, unsigned int pipe,
|
|
|
vblank->last = last;
|
|
|
|
|
|
write_seqlock(&vblank->seqlock);
|
|
|
- vblank->time = *t_vblank;
|
|
|
+ vblank->time = t_vblank;
|
|
|
vblank->count += vblank_count_inc;
|
|
|
write_sequnlock(&vblank->seqlock);
|
|
|
}
|
|
@@ -151,7 +151,7 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe
|
|
|
{
|
|
|
u32 cur_vblank;
|
|
|
bool rc;
|
|
|
- struct timeval t_vblank;
|
|
|
+ ktime_t t_vblank;
|
|
|
int count = DRM_TIMESTAMP_MAXRETRIES;
|
|
|
|
|
|
spin_lock(&dev->vblank_time_lock);
|
|
@@ -171,13 +171,13 @@ static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe
|
|
|
* interrupt and assign 0 for now, to mark the vblanktimestamp as invalid.
|
|
|
*/
|
|
|
if (!rc)
|
|
|
- t_vblank = (struct timeval) {0, 0};
|
|
|
+ t_vblank = 0;
|
|
|
|
|
|
/*
|
|
|
* +1 to make sure user will never see the same
|
|
|
* vblank counter value before and after a modeset
|
|
|
*/
|
|
|
- store_vblank(dev, pipe, 1, &t_vblank, cur_vblank);
|
|
|
+ store_vblank(dev, pipe, 1, t_vblank, cur_vblank);
|
|
|
|
|
|
spin_unlock(&dev->vblank_time_lock);
|
|
|
}
|
|
@@ -200,7 +200,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
|
|
|
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
|
|
|
u32 cur_vblank, diff;
|
|
|
bool rc;
|
|
|
- struct timeval t_vblank;
|
|
|
+ ktime_t t_vblank;
|
|
|
int count = DRM_TIMESTAMP_MAXRETRIES;
|
|
|
int framedur_ns = vblank->framedur_ns;
|
|
|
|
|
@@ -225,11 +225,7 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
|
|
|
/* trust the hw counter when it's around */
|
|
|
diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
|
|
|
} else if (rc && framedur_ns) {
|
|
|
- const struct timeval *t_old;
|
|
|
- u64 diff_ns;
|
|
|
-
|
|
|
- t_old = &vblank->time;
|
|
|
- diff_ns = timeval_to_ns(&t_vblank) - timeval_to_ns(t_old);
|
|
|
+ u64 diff_ns = ktime_to_ns(ktime_sub(t_vblank, vblank->time));
|
|
|
|
|
|
/*
|
|
|
* Figure out how many vblanks we've missed based
|
|
@@ -278,9 +274,9 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
|
|
|
* for now, to mark the vblanktimestamp as invalid.
|
|
|
*/
|
|
|
if (!rc && !in_vblank_irq)
|
|
|
- t_vblank = (struct timeval) {0, 0};
|
|
|
+ t_vblank = 0;
|
|
|
|
|
|
- store_vblank(dev, pipe, diff, &t_vblank, cur_vblank);
|
|
|
+ store_vblank(dev, pipe, diff, t_vblank, cur_vblank);
|
|
|
}
|
|
|
|
|
|
static u32 drm_vblank_count(struct drm_device *dev, unsigned int pipe)
|
|
@@ -556,7 +552,7 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
|
|
|
* @pipe: index of CRTC whose vblank timestamp to retrieve
|
|
|
* @max_error: Desired maximum allowable error in timestamps (nanosecs)
|
|
|
* On return contains true maximum error of timestamp
|
|
|
- * @vblank_time: Pointer to struct timeval which should receive the timestamp
|
|
|
+ * @vblank_time: Pointer to time which should receive the timestamp
|
|
|
* @in_vblank_irq:
|
|
|
* True when called from drm_crtc_handle_vblank(). Some drivers
|
|
|
* need to apply some workarounds for gpu-specific vblank irq quirks
|
|
@@ -584,10 +580,10 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
|
|
|
bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
|
|
|
unsigned int pipe,
|
|
|
int *max_error,
|
|
|
- struct timeval *vblank_time,
|
|
|
+ ktime_t *vblank_time,
|
|
|
bool in_vblank_irq)
|
|
|
{
|
|
|
- struct timeval tv_etime;
|
|
|
+ struct timespec64 ts_etime, ts_vblank_time;
|
|
|
ktime_t stime, etime;
|
|
|
bool vbl_status;
|
|
|
struct drm_crtc *crtc;
|
|
@@ -680,29 +676,27 @@ bool drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
|
|
|
etime = ktime_mono_to_real(etime);
|
|
|
|
|
|
/* save this only for debugging purposes */
|
|
|
- tv_etime = ktime_to_timeval(etime);
|
|
|
+ ts_etime = ktime_to_timespec64(etime);
|
|
|
+ ts_vblank_time = ktime_to_timespec64(*vblank_time);
|
|
|
/* Subtract time delta from raw timestamp to get final
|
|
|
* vblank_time timestamp for end of vblank.
|
|
|
*/
|
|
|
etime = ktime_sub_ns(etime, delta_ns);
|
|
|
- *vblank_time = ktime_to_timeval(etime);
|
|
|
+ *vblank_time = etime;
|
|
|
|
|
|
- DRM_DEBUG_VBL("crtc %u : v p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
|
|
|
+ DRM_DEBUG_VBL("crtc %u : v p(%d,%d)@ %lld.%06ld -> %lld.%06ld [e %d us, %d rep]\n",
|
|
|
pipe, hpos, vpos,
|
|
|
- (long)tv_etime.tv_sec, (long)tv_etime.tv_usec,
|
|
|
- (long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
|
|
|
- duration_ns/1000, i);
|
|
|
+ (u64)ts_etime.tv_sec, ts_etime.tv_nsec / 1000,
|
|
|
+ (u64)ts_vblank_time.tv_sec, ts_vblank_time.tv_nsec / 1000,
|
|
|
+ duration_ns / 1000, i);
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
|
|
|
|
|
|
-static struct timeval get_drm_timestamp(void)
|
|
|
+static ktime_t get_drm_timestamp(void)
|
|
|
{
|
|
|
- ktime_t now;
|
|
|
-
|
|
|
- now = drm_timestamp_monotonic ? ktime_get() : ktime_get_real();
|
|
|
- return ktime_to_timeval(now);
|
|
|
+ return drm_timestamp_monotonic ? ktime_get() : ktime_get_real();
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -710,7 +704,7 @@ static struct timeval get_drm_timestamp(void)
|
|
|
* vblank interval
|
|
|
* @dev: DRM device
|
|
|
* @pipe: index of CRTC whose vblank timestamp to retrieve
|
|
|
- * @tvblank: Pointer to target struct timeval which should receive the timestamp
|
|
|
+ * @tvblank: Pointer to target time which should receive the timestamp
|
|
|
* @in_vblank_irq:
|
|
|
* True when called from drm_crtc_handle_vblank(). Some drivers
|
|
|
* need to apply some workarounds for gpu-specific vblank irq quirks
|
|
@@ -728,7 +722,7 @@ static struct timeval get_drm_timestamp(void)
|
|
|
*/
|
|
|
static bool
|
|
|
drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
|
|
|
- struct timeval *tvblank, bool in_vblank_irq)
|
|
|
+ ktime_t *tvblank, bool in_vblank_irq)
|
|
|
{
|
|
|
bool ret = false;
|
|
|
|
|
@@ -769,14 +763,14 @@ u32 drm_crtc_vblank_count(struct drm_crtc *crtc)
|
|
|
EXPORT_SYMBOL(drm_crtc_vblank_count);
|
|
|
|
|
|
static u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe,
|
|
|
- struct timeval *vblanktime)
|
|
|
+ ktime_t *vblanktime)
|
|
|
{
|
|
|
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
|
|
|
u32 vblank_count;
|
|
|
unsigned int seq;
|
|
|
|
|
|
if (WARN_ON(pipe >= dev->num_crtcs)) {
|
|
|
- *vblanktime = (struct timeval) { 0 };
|
|
|
+ *vblanktime = 0;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -793,7 +787,7 @@ static u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe,
|
|
|
* drm_crtc_vblank_count_and_time - retrieve "cooked" vblank counter value
|
|
|
* and the system timestamp corresponding to that vblank counter value
|
|
|
* @crtc: which counter to retrieve
|
|
|
- * @vblanktime: Pointer to struct timeval to receive the vblank timestamp.
|
|
|
+ * @vblanktime: Pointer to time to receive the vblank timestamp.
|
|
|
*
|
|
|
* Fetches the "cooked" vblank count value that represents the number of
|
|
|
* vblank events since the system was booted, including lost events due to
|
|
@@ -801,7 +795,7 @@ static u32 drm_vblank_count_and_time(struct drm_device *dev, unsigned int pipe,
|
|
|
* of the vblank interval that corresponds to the current vblank counter value.
|
|
|
*/
|
|
|
u32 drm_crtc_vblank_count_and_time(struct drm_crtc *crtc,
|
|
|
- struct timeval *vblanktime)
|
|
|
+ ktime_t *vblanktime)
|
|
|
{
|
|
|
return drm_vblank_count_and_time(crtc->dev, drm_crtc_index(crtc),
|
|
|
vblanktime);
|
|
@@ -810,11 +804,18 @@ EXPORT_SYMBOL(drm_crtc_vblank_count_and_time);
|
|
|
|
|
|
static void send_vblank_event(struct drm_device *dev,
|
|
|
struct drm_pending_vblank_event *e,
|
|
|
- unsigned long seq, struct timeval *now)
|
|
|
+ unsigned long seq, ktime_t now)
|
|
|
{
|
|
|
+ struct timespec64 tv = ktime_to_timespec64(now);
|
|
|
+
|
|
|
e->event.sequence = seq;
|
|
|
- e->event.tv_sec = now->tv_sec;
|
|
|
- e->event.tv_usec = now->tv_usec;
|
|
|
+ /*
|
|
|
+ * e->event is a user space structure, with hardcoded unsigned
|
|
|
+ * 32-bit seconds/microseconds. This will overflow in 2106 for
|
|
|
+ * drm_timestamp_monotonic==0, but not with drm_timestamp_monotonic==1
|
|
|
+ */
|
|
|
+ e->event.tv_sec = tv.tv_sec;
|
|
|
+ e->event.tv_usec = tv.tv_nsec / 1000;
|
|
|
|
|
|
trace_drm_vblank_event_delivered(e->base.file_priv, e->pipe,
|
|
|
e->event.sequence);
|
|
@@ -891,7 +892,7 @@ void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
|
|
|
{
|
|
|
struct drm_device *dev = crtc->dev;
|
|
|
unsigned int seq, pipe = drm_crtc_index(crtc);
|
|
|
- struct timeval now;
|
|
|
+ ktime_t now;
|
|
|
|
|
|
if (dev->num_crtcs > 0) {
|
|
|
seq = drm_vblank_count_and_time(dev, pipe, &now);
|
|
@@ -902,7 +903,7 @@ void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
|
|
|
}
|
|
|
e->pipe = pipe;
|
|
|
e->event.crtc_id = crtc->base.id;
|
|
|
- send_vblank_event(dev, e, seq, &now);
|
|
|
+ send_vblank_event(dev, e, seq, now);
|
|
|
}
|
|
|
EXPORT_SYMBOL(drm_crtc_send_vblank_event);
|
|
|
|
|
@@ -1100,7 +1101,8 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc)
|
|
|
unsigned int pipe = drm_crtc_index(crtc);
|
|
|
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
|
|
|
struct drm_pending_vblank_event *e, *t;
|
|
|
- struct timeval now;
|
|
|
+
|
|
|
+ ktime_t now;
|
|
|
unsigned long irqflags;
|
|
|
unsigned int seq;
|
|
|
|
|
@@ -1141,7 +1143,7 @@ void drm_crtc_vblank_off(struct drm_crtc *crtc)
|
|
|
e->event.sequence, seq);
|
|
|
list_del(&e->base.link);
|
|
|
drm_vblank_put(dev, pipe);
|
|
|
- send_vblank_event(dev, e, seq, &now);
|
|
|
+ send_vblank_event(dev, e, seq, now);
|
|
|
}
|
|
|
spin_unlock_irqrestore(&dev->event_lock, irqflags);
|
|
|
|
|
@@ -1321,7 +1323,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe,
|
|
|
{
|
|
|
struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
|
|
|
struct drm_pending_vblank_event *e;
|
|
|
- struct timeval now;
|
|
|
+ ktime_t now;
|
|
|
unsigned long flags;
|
|
|
unsigned int seq;
|
|
|
int ret;
|
|
@@ -1367,7 +1369,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe,
|
|
|
e->event.sequence = vblwait->request.sequence;
|
|
|
if (vblank_passed(seq, vblwait->request.sequence)) {
|
|
|
drm_vblank_put(dev, pipe);
|
|
|
- send_vblank_event(dev, e, seq, &now);
|
|
|
+ send_vblank_event(dev, e, seq, now);
|
|
|
vblwait->reply.sequence = seq;
|
|
|
} else {
|
|
|
/* drm_handle_vblank_events will call drm_vblank_put */
|
|
@@ -1398,6 +1400,24 @@ static bool drm_wait_vblank_is_query(union drm_wait_vblank *vblwait)
|
|
|
_DRM_VBLANK_NEXTONMISS));
|
|
|
}
|
|
|
|
|
|
+static void drm_wait_vblank_reply(struct drm_device *dev, unsigned int pipe,
|
|
|
+ struct drm_wait_vblank_reply *reply)
|
|
|
+{
|
|
|
+ ktime_t now;
|
|
|
+ struct timespec64 ts;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * drm_wait_vblank_reply is a UAPI structure that uses 'long'
|
|
|
+ * to store the seconds. This will overflow in y2038 on 32-bit
|
|
|
+ * architectures with drm_timestamp_monotonic==0, but not with
|
|
|
+ * drm_timestamp_monotonic==1 (the default).
|
|
|
+ */
|
|
|
+ reply->sequence = drm_vblank_count_and_time(dev, pipe, &now);
|
|
|
+ ts = ktime_to_timespec64(now);
|
|
|
+ reply->tval_sec = (u32)ts.tv_sec;
|
|
|
+ reply->tval_usec = ts.tv_nsec / 1000;
|
|
|
+}
|
|
|
+
|
|
|
int drm_wait_vblank_ioctl(struct drm_device *dev, void *data,
|
|
|
struct drm_file *file_priv)
|
|
|
{
|
|
@@ -1439,12 +1459,7 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data,
|
|
|
if (dev->vblank_disable_immediate &&
|
|
|
drm_wait_vblank_is_query(vblwait) &&
|
|
|
READ_ONCE(vblank->enabled)) {
|
|
|
- struct timeval now;
|
|
|
-
|
|
|
- vblwait->reply.sequence =
|
|
|
- drm_vblank_count_and_time(dev, pipe, &now);
|
|
|
- vblwait->reply.tval_sec = now.tv_sec;
|
|
|
- vblwait->reply.tval_usec = now.tv_usec;
|
|
|
+ drm_wait_vblank_reply(dev, pipe, &vblwait->reply);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1487,11 +1502,7 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data,
|
|
|
}
|
|
|
|
|
|
if (ret != -EINTR) {
|
|
|
- struct timeval now;
|
|
|
-
|
|
|
- vblwait->reply.sequence = drm_vblank_count_and_time(dev, pipe, &now);
|
|
|
- vblwait->reply.tval_sec = now.tv_sec;
|
|
|
- vblwait->reply.tval_usec = now.tv_usec;
|
|
|
+ drm_wait_vblank_reply(dev, pipe, &vblwait->reply);
|
|
|
|
|
|
DRM_DEBUG("crtc %d returning %u to client\n",
|
|
|
pipe, vblwait->reply.sequence);
|
|
@@ -1507,7 +1518,7 @@ done:
|
|
|
static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe)
|
|
|
{
|
|
|
struct drm_pending_vblank_event *e, *t;
|
|
|
- struct timeval now;
|
|
|
+ ktime_t now;
|
|
|
unsigned int seq;
|
|
|
|
|
|
assert_spin_locked(&dev->event_lock);
|
|
@@ -1525,7 +1536,7 @@ static void drm_handle_vblank_events(struct drm_device *dev, unsigned int pipe)
|
|
|
|
|
|
list_del(&e->base.link);
|
|
|
drm_vblank_put(dev, pipe);
|
|
|
- send_vblank_event(dev, e, seq, &now);
|
|
|
+ send_vblank_event(dev, e, seq, now);
|
|
|
}
|
|
|
|
|
|
trace_drm_vblank_event(pipe, seq);
|