drm/msm: fix timeout calculation

The 'timeout' value comes from userspace (CLOCK_MONOTONIC), but
converting this directly to jiffies doesn't take into account the
initial jiffies count at boot, which may differ from the base time
of CLOCK_MONOTONIC.

TODO: add ktime_delta_jiffies() when rebasing on 4.1 and use that
instead of ktime_sub/ktime_to_timespec/timespec_to_jiffies combo (as
suggested by Arnd)

v2: switch over from 'struct timespec' to ktime_t throughout, since
'struct timespec' will be deprecated (as suggested by Arnd)
v3: minor cosmetic tweaks

Cc: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Rob Clark <robdclark@gmail.com>
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index b421c84..1b22d8b 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -204,7 +204,7 @@
 {
 	int nplanes = dev->mode_config.num_total_plane;
 	int ncrtcs = dev->mode_config.num_crtc;
-	struct timespec timeout;
+	ktime_t timeout;
 	struct msm_commit *c;
 	int i, ret;
 
@@ -281,7 +281,7 @@
 		return 0;
 	}
 
-	jiffies_to_timespec(jiffies + msecs_to_jiffies(1000), &timeout);
+	timeout = ktime_add_ms(ktime_get(), 1000);
 
 	ret = msm_wait_fence_interruptable(dev, c->fence, &timeout);
 	if (ret) {
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 7efd307..b7ef56e 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -638,7 +638,7 @@
  */
 
 int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
-		struct timespec *timeout)
+		ktime_t *timeout)
 {
 	struct msm_drm_private *priv = dev->dev_private;
 	int ret;
@@ -656,14 +656,16 @@
 		/* no-wait: */
 		ret = fence_completed(dev, fence) ? 0 : -EBUSY;
 	} else {
-		unsigned long timeout_jiffies = timespec_to_jiffies(timeout);
-		unsigned long start_jiffies = jiffies;
+		ktime_t now = ktime_get();
 		unsigned long remaining_jiffies;
 
-		if (time_after(start_jiffies, timeout_jiffies))
+		if (ktime_compare(*timeout, now) < 0) {
 			remaining_jiffies = 0;
-		else
-			remaining_jiffies = timeout_jiffies - start_jiffies;
+		} else {
+			ktime_t rem = ktime_sub(*timeout, now);
+			struct timespec ts = ktime_to_timespec(rem);
+			remaining_jiffies = timespec_to_jiffies(&ts);
+		}
 
 		ret = wait_event_interruptible_timeout(priv->fence_event,
 				fence_completed(dev, fence),
@@ -772,13 +774,17 @@
 			args->flags, &args->handle);
 }
 
-#define TS(t) ((struct timespec){ .tv_sec = (t).tv_sec, .tv_nsec = (t).tv_nsec })
+static inline ktime_t to_ktime(struct drm_msm_timespec timeout)
+{
+	return ktime_set(timeout.tv_sec, timeout.tv_nsec);
+}
 
 static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
 		struct drm_file *file)
 {
 	struct drm_msm_gem_cpu_prep *args = data;
 	struct drm_gem_object *obj;
+	ktime_t timeout = to_ktime(args->timeout);
 	int ret;
 
 	if (args->op & ~MSM_PREP_FLAGS) {
@@ -790,7 +796,7 @@
 	if (!obj)
 		return -ENOENT;
 
-	ret = msm_gem_cpu_prep(obj, args->op, &TS(args->timeout));
+	ret = msm_gem_cpu_prep(obj, args->op, &timeout);
 
 	drm_gem_object_unreference_unlocked(obj);
 
@@ -840,14 +846,14 @@
 		struct drm_file *file)
 {
 	struct drm_msm_wait_fence *args = data;
+	ktime_t timeout = to_ktime(args->timeout);
 
 	if (args->pad) {
 		DRM_ERROR("invalid pad: %08x\n", args->pad);
 		return -EINVAL;
 	}
 
-	return msm_wait_fence_interruptable(dev, args->fence,
-			&TS(args->timeout));
+	return msm_wait_fence_interruptable(dev, args->fence, &timeout);
 }
 
 static const struct drm_ioctl_desc msm_ioctls[] = {
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 04db4bd..e7c5ea1 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -165,7 +165,7 @@
 int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu);
 
 int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
-		struct timespec *timeout);
+		ktime_t *timeout);
 int msm_queue_fence_cb(struct drm_device *dev,
 		struct msm_fence_cb *cb, uint32_t fence);
 void msm_update_fence(struct drm_device *dev, uint32_t fence);
@@ -205,7 +205,7 @@
 		struct msm_gpu *gpu, bool write, uint32_t fence);
 void msm_gem_move_to_inactive(struct drm_gem_object *obj);
 int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
-		struct timespec *timeout);
+		ktime_t *timeout);
 int msm_gem_cpu_fini(struct drm_gem_object *obj);
 void msm_gem_free_object(struct drm_gem_object *obj);
 int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index dfc74a5..f211b80 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -448,8 +448,7 @@
 	list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
 }
 
-int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op,
-		struct timespec *timeout)
+int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout)
 {
 	struct drm_device *dev = obj->dev;
 	struct msm_gem_object *msm_obj = to_msm_bo(obj);