diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 72d083acd388..69d43c791a42 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -476,6 +476,8 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
 
 	if (flags & DRM_SYNCOBJ_CREATE_SIGNALED)
 		drm_syncobj_assign_null_handle(syncobj);
+	if (flags & DRM_SYNCOBJ_CREATE_TIMELINE)
+		syncobj->is_timeline = true;
 
 	if (fence)
 		drm_syncobj_replace_fence(syncobj, fence);
@@ -661,6 +663,10 @@ static int drm_syncobj_import_sync_file_fence(struct drm_file *file_private,
 		dma_fence_put(fence);
 		return -ENOENT;
 	}
+	if (syncobj->is_timeline) {
+		dma_fence_put(fence);
+		return -EINVAL;
+	}
 
 	drm_syncobj_replace_fence(syncobj, fence);
 	dma_fence_put(fence);
@@ -749,7 +755,13 @@ drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
 		return -EOPNOTSUPP;
 
 	/* no valid flags yet */
-	if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
+	if (args->flags & ~(DRM_SYNCOBJ_CREATE_SIGNALED |
+			    DRM_SYNCOBJ_CREATE_TIMELINE))
+		return -EINVAL;
+
+	/* Creating a signaled timeline makes no sense. */
+	if ((args->flags & DRM_SYNCOBJ_CREATE_SIGNALED) &&
+	    (args->flags & DRM_SYNCOBJ_CREATE_TIMELINE))
 		return -EINVAL;
 
 	return drm_syncobj_create_as_handle(file_private,
@@ -862,6 +874,10 @@ drm_syncobj_transfer_to_binary(struct drm_file *file_private,
 	binary_syncobj = drm_syncobj_find(file_private, args->dst_handle);
 	if (!binary_syncobj)
 		return -ENOENT;
+	if (binary_syncobj->is_timeline) {
+		ret = -EINVAL;
+		goto err;
+	}
 	ret = drm_syncobj_find_fence(file_private, args->src_handle,
 				     args->src_point, args->flags, &fence);
 	if (ret)
@@ -1137,6 +1153,7 @@ static int drm_syncobj_array_wait(struct drm_device *dev,
 static int drm_syncobj_array_find(struct drm_file *file_private,
 				  void __user *user_handles,
 				  uint32_t count_handles,
+				  bool no_timeline,
 				  struct drm_syncobj ***syncobjs_out)
 {
 	uint32_t i, *handles;
@@ -1165,6 +1182,10 @@ static int drm_syncobj_array_find(struct drm_file *file_private,
 			ret = -ENOENT;
 			goto err_put_syncobjs;
 		}
+		if (no_timeline && syncobjs[i]->is_timeline) {
+			ret = -EINVAL;
+			goto err_put_syncobjs;
+		}
 	}
 
 	kfree(handles);
@@ -1211,6 +1232,7 @@ drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
 	ret = drm_syncobj_array_find(file_private,
 				     u64_to_user_ptr(args->handles),
 				     args->count_handles,
+				     false,
 				     &syncobjs);
 	if (ret < 0)
 		return ret;
@@ -1245,6 +1267,7 @@ drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data,
 	ret = drm_syncobj_array_find(file_private,
 				     u64_to_user_ptr(args->handles),
 				     args->count_handles,
+				     false,
 				     &syncobjs);
 	if (ret < 0)
 		return ret;
@@ -1279,6 +1302,7 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
 	ret = drm_syncobj_array_find(file_private,
 				     u64_to_user_ptr(args->handles),
 				     args->count_handles,
+				     false,
 				     &syncobjs);
 	if (ret < 0)
 		return ret;
@@ -1314,6 +1338,7 @@ drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
 	ret = drm_syncobj_array_find(file_private,
 				     u64_to_user_ptr(args->handles),
 				     args->count_handles,
+				     true,
 				     &syncobjs);
 	if (ret < 0)
 		return ret;
@@ -1349,6 +1374,7 @@ drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
 	ret = drm_syncobj_array_find(file_private,
 				     u64_to_user_ptr(args->handles),
 				     args->count_handles,
+				     false,
 				     &syncobjs);
 	if (ret < 0)
 		return ret;
@@ -1420,6 +1446,7 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
 	ret = drm_syncobj_array_find(file_private,
 				     u64_to_user_ptr(args->handles),
 				     args->count_handles,
+				     false,
 				     &syncobjs);
 	if (ret < 0)
 		return ret;
@@ -1484,6 +1511,7 @@ int drm_syncobj_binary_ioctl(struct drm_device *dev, void *data,
 	ret = drm_syncobj_array_find(file_private,
 				     u64_to_user_ptr(args->handles),
 				     args->count_handles,
+				     false,
 				     &syncobjs);
 	if (ret < 0)
 		return ret;
diff --git a/include/drm/drm_syncobj.h b/include/drm/drm_syncobj.h
index aa76cb3f9107..f96a95fbe025 100644
--- a/include/drm/drm_syncobj.h
+++ b/include/drm/drm_syncobj.h
@@ -70,6 +70,14 @@ struct drm_syncobj {
 	 * seqno will be put into the syncobj.
 	 */
 	atomic64_t binary_payload;
+	/**
+	 * @is_timeline: Whether the syncobj holds a timeline.
+	 *
+	 * Holding a timeline adds some restriction to prevent userspace from
+	 * accidentally "losing" the timeline. This could happen for example
+	 * by replacing &fence.
+	 */
+	bool is_timeline;
 };
 
 void drm_syncobj_free(struct kref *kref);
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index 78a0a413b788..b3c46b2993be 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -719,6 +719,7 @@ struct drm_prime_handle {
 struct drm_syncobj_create {
 	__u32 handle;
 #define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0)
+#define DRM_SYNCOBJ_CREATE_TIMELINE (1 << 1)
 	__u32 flags;
 };
 
