Skip to contentSkip to conversation

drm: add flags to drm_syncobj_find_fence

PATCH In review Chunming Zhou 10 participants 26 messages Oct 15, 2018 – Oct 19, 2018 13 messages not in the archive

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

PATCH 1/7 drm: add flags to drm_syncobj_find_fence

flags can be used by driver to decide whether need to block wait submission.

---
 drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +-
 drivers/gpu/drm/drm_syncobj.c          | 4 ++--
 drivers/gpu/drm/v3d/v3d_gem.c          | 4 ++--
 drivers/gpu/drm/vc4/vc4_gem.c          | 2 +-
 include/drm/drm_syncobj.h              | 2 +-
 5 files changed, 7 insertions(+), 7 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +1 -1
index d9d2ede96490..412fac238575 100644
@@ -1102,7 +1102,7 @@ static int amdgpu_syncobj_lookup_and_add_to_sync(struct amdgpu_cs_parser *p,
 {
 	int r;
 	struct dma_fence *fence;
-	r = drm_syncobj_find_fence(p->filp, handle, 0, &fence);
+	r = drm_syncobj_find_fence(p->filp, handle, 0, 0, &fence);
 	if (r)
 		return r;
 
drivers/gpu/drm/drm_syncobj.c +2 -2
index e9ce623d049e..f796c9fc3858 100644
@@ -235,7 +235,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
  * dma_fence_put().
  */
 int drm_syncobj_find_fence(struct drm_file *file_private,
-			   u32 handle, u64 point,
+			   u32 handle, u64 point, u64 flags,
 			   struct dma_fence **fence)
 {
 	struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
@@ -506,7 +506,7 @@ static int drm_syncobj_export_sync_file(struct drm_file *file_private,
 	if (fd < 0)
 		return fd;
 
-	ret = drm_syncobj_find_fence(file_private, handle, 0, &fence);
+	ret = drm_syncobj_find_fence(file_private, handle, 0, 0, &fence);
 	if (ret)
 		goto err_put_fd;
 
drivers/gpu/drm/v3d/v3d_gem.c +2 -2
index 70c54774400b..97477879d3d4 100644
@@ -521,12 +521,12 @@ v3d_submit_cl_ioctl(struct drm_device *dev, void *data,
 	kref_init(&exec->refcount);
 
 	ret = drm_syncobj_find_fence(file_priv, args->in_sync_bcl,
-				     0, &exec->bin.in_fence);
+				     0, 0, &exec->bin.in_fence);
 	if (ret == -EINVAL)
 		goto fail;
 
 	ret = drm_syncobj_find_fence(file_priv, args->in_sync_rcl,
-				     0, &exec->render.in_fence);
+				     0, 0, &exec->render.in_fence);
 	if (ret == -EINVAL)
 		goto fail;
 
drivers/gpu/drm/vc4/vc4_gem.c +1 -1
index 5b22e996af6c..251198194c38 100644
@@ -1173,7 +1173,7 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
 
 	if (args->in_sync) {
 		ret = drm_syncobj_find_fence(file_priv, args->in_sync,
-					     0, &in_fence);
+					     0, 0, &in_fence);
 		if (ret)
 			goto fail;
 
include/drm/drm_syncobj.h +1 -1
index 425432b85a87..2eda44def639 100644
@@ -134,7 +134,7 @@ struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
 void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point,
 			       struct dma_fence *fence);
 int drm_syncobj_find_fence(struct drm_file *file_private,
-			   u32 handle, u64 point,
+			   u32 handle, u64 point, u64 flags,
 			   struct dma_fence **fence);
 void drm_syncobj_free(struct kref *kref);
 int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
Signature · 6 lines
2.17.1

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
#1 lore raw

PATCH 2/7 drm: add syncobj timeline support v8

This patch is for VK_KHR_timeline_semaphore extension, semaphore is called syncobj in kernel side:
This extension introduces a new type of syncobj that has an integer payload identifying a point in a timeline. Such timeline syncobjs support the
following operations:
* CPU query - A host operation that allows querying the payload of the
timeline syncobj.
* CPU wait - A host operation that allows a blocking wait for a
timeline syncobj to reach a specified value.
* Device wait - A device operation that allows waiting for a
timeline syncobj to reach a specified value.
* Device signal - A device operation that allows advancing the
timeline syncobj to a specified value.

v1:
Since it's a timeline, that means the front time point(PT) always is signaled before the late PT. a. signal PT design:
Signal PT fence N depends on PT[N-1] fence and signal opertion fence, when PT[N] fence is signaled, the timeline will increase to value of PT[N].
b. wait PT design:
Wait PT fence is signaled by reaching timeline point value, when timeline is increasing, will compare wait PTs value with new timeline value, if PT value is lower than timeline value, then wait PT will be signaled, otherwise keep in list. syncobj wait operation can wait on any point of timeline, so need a RB tree to order them. And wait PT could ahead of signal PT, we need a sumission fence to perform that.

v2:
1. remove unused DRM_SYNCOBJ_CREATE_TYPE_NORMAL. (Christian)
2. move unexposed denitions to .c file. (Daniel Vetter)
3. split up the change to drm_syncobj_find_fence() in a separate patch. (Christian)
4. split up the change to drm_syncobj_replace_fence() in a separate patch.
5. drop the submission_fence implementation and instead use wait_event() for that. (Christian)
6. WARN_ON(point != 0) for NORMAL type syncobj case. (Daniel Vetter)

v3:
1. replace normal syncobj with timeline implemenation. (Vetter and Christian)
a. normal syncobj signal op will create a signal PT to tail of signal pt list.
b. normal syncobj wait op will create a wait pt with last signal point, and this wait PT is only signaled by related signal point PT.
2. many bug fix and clean up
3. stub fence moving is moved to other patch.

v4:
1. fix RB tree loop with while(node=rb_first(...)). (Christian)
2. fix syncobj lifecycle. (Christian)
3. only enable_signaling when there is wait_pt. (Christian)
4. fix timeline path issues.
5. write a timeline test in libdrm

v5: (Christian)
1. semaphore is called syncobj in kernel side.
2. don't need 'timeline' characters in some function name.
3. keep syncobj cb.

v6: (Christian)
1. merge syncobj_timeline to syncobj structure.
2. simplify some check sentences.
3. some misc change.
4. fix CTS failed issue.

v7: (Christian)
1. error handling when creating signal pt.
2. remove timeline naming in func.
3. export flags in find_fence.
4. allow reset timeline.

v8:
1. use wait_event_interruptible without timeout
2. rename _TYPE_INDIVIDUAL to _TYPE_BINARY

individual syncobj is tested by ./deqp-vk -n dEQP-VK*semaphore* timeline syncobj is tested by ./amdgpu_test -s 9

Cc Christian Konig <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Daniel Rakos <[email protected]>
Cc Daniel Vetter <[email protected]>
---
 drivers/gpu/drm/drm_syncobj.c              | 287 ++++++++++++++++++---
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |   2 +-
 include/drm/drm_syncobj.h                  |  65 ++---
 include/uapi/drm/drm.h                     |   1 +
 4 files changed, 281 insertions(+), 74 deletions(-)
drivers/gpu/drm/drm_syncobj.c +246 -41
index f796c9fc3858..67472bd77c83 100644
@@ -56,6 +56,9 @@
 #include "drm_internal.h"
 #include <drm/drm_syncobj.h>
 
+/* merge normal syncobj to timeline syncobj, the point interval is 1 */
+#define DRM_SYNCOBJ_BINARY_POINT 1
+
 struct drm_syncobj_stub_fence {
 	struct dma_fence base;
 	spinlock_t lock;
@@ -82,6 +85,11 @@ static const struct dma_fence_ops drm_syncobj_stub_fence_ops = {
 	.release = drm_syncobj_stub_fence_release,
 };
 
+struct drm_syncobj_signal_pt {
+	struct dma_fence_array *base;
+	u64    value;
+	struct list_head list;
+};
 
 /**
  * drm_syncobj_find - lookup and reference a sync object.
@@ -124,8 +132,8 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
 {
 	int ret;
 
-	*fence = drm_syncobj_fence_get(syncobj);
-	if (*fence)
+	ret = drm_syncobj_search_fence(syncobj, 0, 0, fence);
+	if (!ret)
 		return 1;
 
 	spin_lock(&syncobj->lock);
@@ -133,10 +141,12 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
 	 * have the lock, try one more time just to be sure we don't add a
 	 * callback when a fence has already been set.
 	 */
-	if (syncobj->fence) {
-		*fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
-								 lockdep_is_held(&syncobj->lock)));
-		ret = 1;
+	if (!list_empty(&syncobj->signal_pt_list)) {
+		spin_unlock(&syncobj->lock);
+		drm_syncobj_search_fence(syncobj, 0, 0, fence);
+		if (*fence)
+			return 1;
+		spin_lock(&syncobj->lock);
 	} else {
 		*fence = NULL;
 		drm_syncobj_add_callback_locked(syncobj, cb, func);
@@ -164,6 +174,159 @@ void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
 	spin_unlock(&syncobj->lock);
 }
 
+static void drm_syncobj_init(struct drm_syncobj *syncobj)
+{
+	spin_lock(&syncobj->lock);
+	syncobj->timeline_context = dma_fence_context_alloc(1);
+	syncobj->timeline = 0;
+	syncobj->signal_point = 0;
+	init_waitqueue_head(&syncobj->wq);
+
+	INIT_LIST_HEAD(&syncobj->signal_pt_list);
+	spin_unlock(&syncobj->lock);
+}
+
+static void drm_syncobj_fini(struct drm_syncobj *syncobj)
+{
+	struct drm_syncobj_signal_pt *signal_pt = NULL, *tmp;
+
+	spin_lock(&syncobj->lock);
+	list_for_each_entry_safe(signal_pt, tmp,
+				 &syncobj->signal_pt_list, list) {
+		list_del(&signal_pt->list);
+		dma_fence_put(&signal_pt->base->base);
+		kfree(signal_pt);
+	}
+	spin_unlock(&syncobj->lock);
+}
+
+static struct dma_fence
+*drm_syncobj_find_signal_pt_for_point(struct drm_syncobj *syncobj,
+				      uint64_t point)
+{
+	struct drm_syncobj_signal_pt *signal_pt;
+
+	if ((syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) &&
+	    (point <= syncobj->timeline)) {
+		struct drm_syncobj_stub_fence *fence =
+			kzalloc(sizeof(struct drm_syncobj_stub_fence),
+				GFP_KERNEL);
+
+		if (!fence)
+			return NULL;
+		spin_lock_init(&fence->lock);
+		dma_fence_init(&fence->base,
+			       &drm_syncobj_stub_fence_ops,
+			       &fence->lock,
+			       syncobj->timeline_context,
+			       point);
+
+		dma_fence_signal(&fence->base);
+		return &fence->base;
+	}
+
+	list_for_each_entry(signal_pt, &syncobj->signal_pt_list, list) {
+		if (point > signal_pt->value)
+			continue;
+		if ((syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) &&
+		    (point != signal_pt->value))
+			continue;
+		return dma_fence_get(&signal_pt->base->base);
+	}
+	return NULL;
+}
+
+static int drm_syncobj_create_signal_pt(struct drm_syncobj *syncobj,
+					struct dma_fence *fence,
+					u64 point)
+{
+	struct drm_syncobj_signal_pt *signal_pt =
+		kzalloc(sizeof(struct drm_syncobj_signal_pt), GFP_KERNEL);
+	struct drm_syncobj_signal_pt *tail_pt;
+	struct dma_fence **fences;
+	int num_fences = 0;
+	int ret = 0, i;
+
+	if (!signal_pt)
+		return -ENOMEM;
+	if (!fence)
+		goto out;
+
+	fences = kmalloc_array(sizeof(void *), 2, GFP_KERNEL);
+	if (!fences) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	fences[num_fences++] = dma_fence_get(fence);
+	/* timeline syncobj must take this dependency */
+	if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) {
+		spin_lock(&syncobj->lock);
+		if (!list_empty(&syncobj->signal_pt_list)) {
+			tail_pt = list_last_entry(&syncobj->signal_pt_list,
+						  struct drm_syncobj_signal_pt, list);
+			fences[num_fences++] = dma_fence_get(&tail_pt->base->base);
+		}
+		spin_unlock(&syncobj->lock);
+	}
+	signal_pt->base = dma_fence_array_create(num_fences, fences,
+						 syncobj->timeline_context,
+						 point, false);
+	if (!signal_pt->base) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	spin_lock(&syncobj->lock);
+	if (syncobj->signal_point >= point) {
+		DRM_WARN("A later signal is ready!");
+		spin_unlock(&syncobj->lock);
+		goto exist;
+	}
+	signal_pt->value = point;
+	list_add_tail(&signal_pt->list, &syncobj->signal_pt_list);
+	syncobj->signal_point = point;
+	spin_unlock(&syncobj->lock);
+	wake_up_all(&syncobj->wq);
+
+	return 0;
+exist:
+	dma_fence_put(&signal_pt->base->base);
+fail:
+	for (i = 0; i < num_fences; i++)
+		dma_fence_put(fences[i]);
+	kfree(fences);
+out:
+	kfree(signal_pt);
+	return ret;
+}
+
+static void drm_syncobj_garbage_collection(struct drm_syncobj *syncobj)
+{
+	struct drm_syncobj_signal_pt *signal_pt, *tmp, *tail_pt;
+
+	spin_lock(&syncobj->lock);
+	tail_pt = list_last_entry(&syncobj->signal_pt_list,
+				  struct drm_syncobj_signal_pt,
+				  list);
+	list_for_each_entry_safe(signal_pt, tmp,
+				 &syncobj->signal_pt_list, list) {
+		if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY &&
+		    signal_pt == tail_pt)
+			continue;
+		if (dma_fence_is_signaled(&signal_pt->base->base)) {
+			syncobj->timeline = signal_pt->value;
+			list_del(&signal_pt->list);
+			dma_fence_put(&signal_pt->base->base);
+			kfree(signal_pt);
+		} else {
+			/*signal_pt is in order in list, from small to big, so
+			 * the later must not be signal either */
+			break;
+		}
+	}
+
+	spin_unlock(&syncobj->lock);
+}
 /**
  * drm_syncobj_replace_fence - replace fence in a sync object.
  * @syncobj: Sync object to replace fence in
@@ -176,28 +339,29 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
 			       u64 point,
 			       struct dma_fence *fence)
 {
-	struct dma_fence *old_fence;
-	struct drm_syncobj_cb *cur, *tmp;
-
-	if (fence)
-		dma_fence_get(fence);
-
-	spin_lock(&syncobj->lock);
-
-	old_fence = rcu_dereference_protected(syncobj->fence,
-					      lockdep_is_held(&syncobj->lock));
-	rcu_assign_pointer(syncobj->fence, fence);
+	u64 pt_value = point;
+
+	drm_syncobj_garbage_collection(syncobj);
+	if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
+		if (!fence) {
+			drm_syncobj_fini(syncobj);
+			drm_syncobj_init(syncobj);
+			return;
+		}
+		pt_value = syncobj->signal_point +
+			DRM_SYNCOBJ_BINARY_POINT;
+	}
+	drm_syncobj_create_signal_pt(syncobj, fence, pt_value);
+	if (fence) {
+		struct drm_syncobj_cb *cur, *tmp;
 
-	if (fence != old_fence) {
+		spin_lock(&syncobj->lock);
 		list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) {
 			list_del_init(&cur->node);
 			cur->func(syncobj, cur);
 		}
+		spin_unlock(&syncobj->lock);
 	}
-
-	spin_unlock(&syncobj->lock);
-
-	dma_fence_put(old_fence);
 }
 EXPORT_SYMBOL(drm_syncobj_replace_fence);
 
@@ -220,6 +384,46 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
 	return 0;
 }
 
+static int
+drm_syncobj_point_get(struct drm_syncobj *syncobj, u64 point, u64 flags,
+		      struct dma_fence **fence)
+{
+	int ret = 0;
+
+	if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
+		ret = wait_event_interruptible(syncobj->wq,
+					       point <= syncobj->signal_point);
+		if (ret < 0)
+			return ret;
+	}
+	spin_lock(&syncobj->lock);
+	*fence = drm_syncobj_find_signal_pt_for_point(syncobj, point);
+	if (!*fence)
+		ret = -EINVAL;
+	spin_unlock(&syncobj->lock);
+	return ret;
+}
+
+int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point,
+			     u64 flags, struct dma_fence **fence)
+{
+	u64 pt_value = point;
+
+	if (!syncobj)
+		return -ENOENT;
+
+	drm_syncobj_garbage_collection(syncobj);
+	if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
+		/*BINARY syncobj always wait on last pt */
+		pt_value = syncobj->signal_point;
+
+		if (pt_value == 0)
+			pt_value += DRM_SYNCOBJ_BINARY_POINT;
+	}
+	return drm_syncobj_point_get(syncobj, pt_value, flags, fence);
+}
+EXPORT_SYMBOL(drm_syncobj_search_fence);
+
 /**
  * drm_syncobj_find_fence - lookup and reference the fence in a sync object
  * @file_private: drm file private pointer
@@ -228,7 +432,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
  * @fence: out parameter for the fence
  *
  * This is just a convenience function that combines drm_syncobj_find() and
- * drm_syncobj_fence_get().
+ * drm_syncobj_lookup_fence().
  *
  * Returns 0 on success or a negative error value on failure. On success @fence
  * contains a reference to the fence, which must be released by calling
@@ -239,15 +443,9 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
 			   struct dma_fence **fence)
 {
 	struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
-	int ret = 0;
-
-	if (!syncobj)
-		return -ENOENT;
+	int ret;
 
-	*fence = drm_syncobj_fence_get(syncobj);
-	if (!*fence) {
-		ret = -EINVAL;
-	}
+	ret = drm_syncobj_search_fence(syncobj, point, flags, fence);
 	drm_syncobj_put(syncobj);
 	return ret;
 }
@@ -264,7 +462,7 @@ void drm_syncobj_free(struct kref *kref)
 	struct drm_syncobj *syncobj = container_of(kref,
 						   struct drm_syncobj,
 						   refcount);
-	drm_syncobj_replace_fence(syncobj, 0, NULL);
+	drm_syncobj_fini(syncobj);
 	kfree(syncobj);
 }
 EXPORT_SYMBOL(drm_syncobj_free);
@@ -294,6 +492,11 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
 	kref_init(&syncobj->refcount);
 	INIT_LIST_HEAD(&syncobj->cb_list);
 	spin_lock_init(&syncobj->lock);
+	if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE)
+		syncobj->type = DRM_SYNCOBJ_TYPE_TIMELINE;
+	else
+		syncobj->type = DRM_SYNCOBJ_TYPE_BINARY;
+	drm_syncobj_init(syncobj);
 
 	if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
 		ret = drm_syncobj_assign_null_handle(syncobj);
@@ -576,7 +779,8 @@ drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
 		return -ENODEV;
 
 	/* no valid flags yet */
-	if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
+	if (args->flags & ~(DRM_SYNCOBJ_CREATE_SIGNALED |
+			    DRM_SYNCOBJ_CREATE_TYPE_TIMELINE))
 		return -EINVAL;
 
 	return drm_syncobj_create_as_handle(file_private,
@@ -669,9 +873,8 @@ static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
 	struct syncobj_wait_entry *wait =
 		container_of(cb, struct syncobj_wait_entry, syncobj_cb);
 
-	/* This happens inside the syncobj lock */
-	wait->fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
-							      lockdep_is_held(&syncobj->lock)));
+	drm_syncobj_search_fence(syncobj, 0, 0, &wait->fence);
+
 	wake_up_process(wait->task);
 }
 
@@ -698,7 +901,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
 	signaled_count = 0;
 	for (i = 0; i < count; ++i) {
 		entries[i].task = current;
-		entries[i].fence = drm_syncobj_fence_get(syncobjs[i]);
+		ret = drm_syncobj_search_fence(syncobjs[i], 0, 0,
+					       &entries[i].fence);
 		if (!entries[i].fence) {
 			if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
 				continue;
@@ -970,12 +1174,13 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
 	if (ret < 0)
 		return ret;
 
-	for (i = 0; i < args->count_handles; i++)
-		drm_syncobj_replace_fence(syncobjs[i], 0, NULL);
-
+	for (i = 0; i < args->count_handles; i++) {
+		drm_syncobj_fini(syncobjs[i]);
+		drm_syncobj_init(syncobjs[i]);
+	}
 	drm_syncobj_array_free(syncobjs, args->count_handles);
 
-	return 0;
+	return ret;
 }
 
 int
drivers/gpu/drm/i915/i915_gem_execbuffer.c +1 -1
index 0a8d2d64f380..8a8d21b24119 100644
@@ -2137,7 +2137,7 @@ await_fence_array(struct i915_execbuffer *eb,
 		if (!(flags & I915_EXEC_FENCE_WAIT))
 			continue;
 
-		fence = drm_syncobj_fence_get(syncobj);
+		drm_syncobj_search_fence(syncobj, 0, 0, &fence);
 		if (!fence)
 			return -EINVAL;
 
include/drm/drm_syncobj.h +33 -32

99 lines not on this page · raw message

include/uapi/drm/drm.h +1 -0
index 300f336633f2..cebdb2541eb7 100644
@@ -717,6 +717,7 @@ struct drm_prime_handle {
 struct drm_syncobj_create {
 	__u32 handle;
 #define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0)
+#define DRM_SYNCOBJ_CREATE_TYPE_TIMELINE (1 << 1)
 	__u32 flags;
 };
 
Signature · 6 lines
2.17.1

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
Acked-by on v1 2/7
#2 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

Quoted 64 lines · Chunming Zhou

This patch is for VK_KHR_timeline_semaphore extension, semaphore is called syncobj in kernel side:
This extension introduces a new type of syncobj that has an integer payload identifying a point in a timeline. Such timeline syncobjs support the
following operations:
* CPU query - A host operation that allows querying the payload of the
timeline syncobj.
* CPU wait - A host operation that allows a blocking wait for a
timeline syncobj to reach a specified value.
* Device wait - A device operation that allows waiting for a
timeline syncobj to reach a specified value.
* Device signal - A device operation that allows advancing the
timeline syncobj to a specified value.

v1:
Since it's a timeline, that means the front time point(PT) always is signaled before the late PT. a. signal PT design:
Signal PT fence N depends on PT[N-1] fence and signal opertion fence, when PT[N] fence is signaled, the timeline will increase to value of PT[N].
b. wait PT design:
Wait PT fence is signaled by reaching timeline point value, when timeline is increasing, will compare wait PTs value with new timeline value, if PT value is lower than timeline value, then wait PT will be signaled, otherwise keep in list. syncobj wait operation can wait on any point of timeline, so need a RB tree to order them. And wait PT could ahead of signal PT, we need a sumission fence to perform that.

v2:
1. remove unused DRM_SYNCOBJ_CREATE_TYPE_NORMAL. (Christian)
2. move unexposed denitions to .c file. (Daniel Vetter)
3. split up the change to drm_syncobj_find_fence() in a separate patch. (Christian)
4. split up the change to drm_syncobj_replace_fence() in a separate patch.
5. drop the submission_fence implementation and instead use wait_event() for that. (Christian)
6. WARN_ON(point != 0) for NORMAL type syncobj case. (Daniel Vetter)

v3:
1. replace normal syncobj with timeline implemenation. (Vetter and Christian)
a. normal syncobj signal op will create a signal PT to tail of signal pt list.
b. normal syncobj wait op will create a wait pt with last signal point, and this wait PT is only signaled by related signal point PT.
2. many bug fix and clean up
3. stub fence moving is moved to other patch.

v4:
1. fix RB tree loop with while(node=rb_first(...)). (Christian)
2. fix syncobj lifecycle. (Christian)
3. only enable_signaling when there is wait_pt. (Christian)
4. fix timeline path issues.
5. write a timeline test in libdrm

v5: (Christian)
1. semaphore is called syncobj in kernel side.
2. don't need 'timeline' characters in some function name.
3. keep syncobj cb.

v6: (Christian)
1. merge syncobj_timeline to syncobj structure.
2. simplify some check sentences.
3. some misc change.
4. fix CTS failed issue.

v7: (Christian)
1. error handling when creating signal pt.
2. remove timeline naming in func.
3. export flags in find_fence.
4. allow reset timeline.

Quoted 6 lines

v8:
1. use wait_event_interruptible without timeout
2. rename _TYPE_INDIVIDUAL to _TYPE_BINARY

individual syncobj is tested by ./deqp-vk -n dEQP-VK*semaphore* timeline syncobj is tested by ./amdgpu_test -s 9

Can we please have these low-level syncobj tests as part of igt, together with all the other syncobj tests which are there already? Really doesn't make much sense imo to splits things on the test suite front.

Quoted 29 lines
Cc Christian Konig <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Daniel Rakos <[email protected]>
Cc Daniel Vetter <[email protected]>
---
 drivers/gpu/drm/drm_syncobj.c              | 287 ++++++++++++++++++---
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |   2 +-
 include/drm/drm_syncobj.h                  |  65 ++---
 include/uapi/drm/drm.h                     |   1 +
 4 files changed, 281 insertions(+), 74 deletions(-)
drivers/gpu/drm/drm_syncobj.c +3 -0
index f796c9fc3858..67472bd77c83 100644
@@ -56,6 +56,9 @@
 #include "drm_internal.h"
 #include <drm/drm_syncobj.h>
 
+/* merge normal syncobj to timeline syncobj, the point interval is 1 */
+#define DRM_SYNCOBJ_BINARY_POINT 1
+
 struct drm_syncobj_stub_fence {
 	struct dma_fence base;
 	spinlock_t lock;

drivers/gpu/drm/drm_syncobj.c static const struct dma_fence_ops drm_syncobj_stub_fence_ops = { · line 89

Quoted 5 lines
drivers/gpu/drm/drm_syncobj.c +2 -0
@@ -82,6 +85,11 @@ static const struct dma_fence_ops drm_syncobj_stub_fence_ops = {
 	.release = drm_syncobj_stub_fence_release,
 };
 
+struct drm_syncobj_signal_pt {
+	struct dma_fence_array *base;

Out of curiosity, why the pointer and not embedding? base is kinda misleading for a pointer.

Quoted 256 lines
drivers/gpu/drm/drm_syncobj.c +193 -22
+	u64    value;
+	struct list_head list;
+};
 
 /**
  * drm_syncobj_find - lookup and reference a sync object.
@@ -124,8 +132,8 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
 {
 	int ret;
 
-	*fence = drm_syncobj_fence_get(syncobj);
-	if (*fence)
+	ret = drm_syncobj_search_fence(syncobj, 0, 0, fence);
+	if (!ret)
 		return 1;
 
 	spin_lock(&syncobj->lock);
@@ -133,10 +141,12 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
 	 * have the lock, try one more time just to be sure we don't add a
 	 * callback when a fence has already been set.
 	 */
-	if (syncobj->fence) {
-		*fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
-								 lockdep_is_held(&syncobj->lock)));
-		ret = 1;
+	if (!list_empty(&syncobj->signal_pt_list)) {
+		spin_unlock(&syncobj->lock);
+		drm_syncobj_search_fence(syncobj, 0, 0, fence);
+		if (*fence)
+			return 1;
+		spin_lock(&syncobj->lock);
 	} else {
 		*fence = NULL;
 		drm_syncobj_add_callback_locked(syncobj, cb, func);
@@ -164,6 +174,159 @@ void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
 	spin_unlock(&syncobj->lock);
 }
 
+static void drm_syncobj_init(struct drm_syncobj *syncobj)
+{
+	spin_lock(&syncobj->lock);
+	syncobj->timeline_context = dma_fence_context_alloc(1);
+	syncobj->timeline = 0;
+	syncobj->signal_point = 0;
+	init_waitqueue_head(&syncobj->wq);
+
+	INIT_LIST_HEAD(&syncobj->signal_pt_list);
+	spin_unlock(&syncobj->lock);
+}
+
+static void drm_syncobj_fini(struct drm_syncobj *syncobj)
+{
+	struct drm_syncobj_signal_pt *signal_pt = NULL, *tmp;
+
+	spin_lock(&syncobj->lock);
+	list_for_each_entry_safe(signal_pt, tmp,
+				 &syncobj->signal_pt_list, list) {
+		list_del(&signal_pt->list);
+		dma_fence_put(&signal_pt->base->base);
+		kfree(signal_pt);
+	}
+	spin_unlock(&syncobj->lock);
+}
+
+static struct dma_fence
+*drm_syncobj_find_signal_pt_for_point(struct drm_syncobj *syncobj,
+				      uint64_t point)
+{
+	struct drm_syncobj_signal_pt *signal_pt;
+
+	if ((syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) &&
+	    (point <= syncobj->timeline)) {
+		struct drm_syncobj_stub_fence *fence =
+			kzalloc(sizeof(struct drm_syncobj_stub_fence),
+				GFP_KERNEL);
+
+		if (!fence)
+			return NULL;
+		spin_lock_init(&fence->lock);
+		dma_fence_init(&fence->base,
+			       &drm_syncobj_stub_fence_ops,
+			       &fence->lock,
+			       syncobj->timeline_context,
+			       point);
+
+		dma_fence_signal(&fence->base);
+		return &fence->base;
+	}
+
+	list_for_each_entry(signal_pt, &syncobj->signal_pt_list, list) {
+		if (point > signal_pt->value)
+			continue;
+		if ((syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) &&
+		    (point != signal_pt->value))
+			continue;
+		return dma_fence_get(&signal_pt->base->base);
+	}
+	return NULL;
+}
+
+static int drm_syncobj_create_signal_pt(struct drm_syncobj *syncobj,
+					struct dma_fence *fence,
+					u64 point)
+{
+	struct drm_syncobj_signal_pt *signal_pt =
+		kzalloc(sizeof(struct drm_syncobj_signal_pt), GFP_KERNEL);
+	struct drm_syncobj_signal_pt *tail_pt;
+	struct dma_fence **fences;
+	int num_fences = 0;
+	int ret = 0, i;
+
+	if (!signal_pt)
+		return -ENOMEM;
+	if (!fence)
+		goto out;
+
+	fences = kmalloc_array(sizeof(void *), 2, GFP_KERNEL);
+	if (!fences) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	fences[num_fences++] = dma_fence_get(fence);
+	/* timeline syncobj must take this dependency */
+	if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) {
+		spin_lock(&syncobj->lock);
+		if (!list_empty(&syncobj->signal_pt_list)) {
+			tail_pt = list_last_entry(&syncobj->signal_pt_list,
+						  struct drm_syncobj_signal_pt, list);
+			fences[num_fences++] = dma_fence_get(&tail_pt->base->base);
+		}
+		spin_unlock(&syncobj->lock);
+	}
+	signal_pt->base = dma_fence_array_create(num_fences, fences,
+						 syncobj->timeline_context,
+						 point, false);
+	if (!signal_pt->base) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	spin_lock(&syncobj->lock);
+	if (syncobj->signal_point >= point) {
+		DRM_WARN("A later signal is ready!");
+		spin_unlock(&syncobj->lock);
+		goto exist;
+	}
+	signal_pt->value = point;
+	list_add_tail(&signal_pt->list, &syncobj->signal_pt_list);
+	syncobj->signal_point = point;
+	spin_unlock(&syncobj->lock);
+	wake_up_all(&syncobj->wq);
+
+	return 0;
+exist:
+	dma_fence_put(&signal_pt->base->base);
+fail:
+	for (i = 0; i < num_fences; i++)
+		dma_fence_put(fences[i]);
+	kfree(fences);
+out:
+	kfree(signal_pt);
+	return ret;
+}
+
+static void drm_syncobj_garbage_collection(struct drm_syncobj *syncobj)
+{
+	struct drm_syncobj_signal_pt *signal_pt, *tmp, *tail_pt;
+
+	spin_lock(&syncobj->lock);
+	tail_pt = list_last_entry(&syncobj->signal_pt_list,
+				  struct drm_syncobj_signal_pt,
+				  list);
+	list_for_each_entry_safe(signal_pt, tmp,
+				 &syncobj->signal_pt_list, list) {
+		if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY &&
+		    signal_pt == tail_pt)
+			continue;
+		if (dma_fence_is_signaled(&signal_pt->base->base)) {
+			syncobj->timeline = signal_pt->value;
+			list_del(&signal_pt->list);
+			dma_fence_put(&signal_pt->base->base);
+			kfree(signal_pt);
+		} else {
+			/*signal_pt is in order in list, from small to big, so
+			 * the later must not be signal either */
+			break;
+		}
+	}
+
+	spin_unlock(&syncobj->lock);
+}
 /**
  * drm_syncobj_replace_fence - replace fence in a sync object.
  * @syncobj: Sync object to replace fence in
@@ -176,28 +339,29 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
 			       u64 point,
 			       struct dma_fence *fence)
 {
-	struct dma_fence *old_fence;
-	struct drm_syncobj_cb *cur, *tmp;
-
-	if (fence)
-		dma_fence_get(fence);
-
-	spin_lock(&syncobj->lock);
-
-	old_fence = rcu_dereference_protected(syncobj->fence,
-					      lockdep_is_held(&syncobj->lock));
-	rcu_assign_pointer(syncobj->fence, fence);
+	u64 pt_value = point;
+
+	drm_syncobj_garbage_collection(syncobj);
+	if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
+		if (!fence) {
+			drm_syncobj_fini(syncobj);
+			drm_syncobj_init(syncobj);
+			return;
+		}
+		pt_value = syncobj->signal_point +
+			DRM_SYNCOBJ_BINARY_POINT;
+	}
+	drm_syncobj_create_signal_pt(syncobj, fence, pt_value);
+	if (fence) {
+		struct drm_syncobj_cb *cur, *tmp;
 
-	if (fence != old_fence) {
+		spin_lock(&syncobj->lock);
 		list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) {
 			list_del_init(&cur->node);
 			cur->func(syncobj, cur);
 		}
+		spin_unlock(&syncobj->lock);
 	}
-
-	spin_unlock(&syncobj->lock);
-
-	dma_fence_put(old_fence);
 }
 EXPORT_SYMBOL(drm_syncobj_replace_fence);
 
@@ -220,6 +384,46 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
 	return 0;
 }
 
+static int
+drm_syncobj_point_get(struct drm_syncobj *syncobj, u64 point, u64 flags,
+		      struct dma_fence **fence)
+{
+	int ret = 0;
+
+	if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
+		ret = wait_event_interruptible(syncobj->wq,
+					       point <= syncobj->signal_point);
+		if (ret < 0)
+			return ret;
+	}

drivers/gpu/drm/drm_syncobj.c static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) · line 408

Quoted 10 lines
drivers/gpu/drm/drm_syncobj.c +10 -0
+	spin_lock(&syncobj->lock);
+	*fence = drm_syncobj_find_signal_pt_for_point(syncobj, point);
+	if (!*fence)
+		ret = -EINVAL;
+	spin_unlock(&syncobj->lock);
+	return ret;
+}
+
+int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point,
+			     u64 flags, struct dma_fence **fence)

Kerneldoc is missing for this one here.

I also think improving the overview comment to explain the timeline stuff, e.g. link to the vulkan extension, and some words on how it's supposed to be used (you need a submit thread and block in userspace until all future timeline points have materialized, only then you can submit to the kernel).

Quoted 138 lines
drivers/gpu/drm/drm_syncobj.c +38 -19
+{
+	u64 pt_value = point;
+
+	if (!syncobj)
+		return -ENOENT;
+
+	drm_syncobj_garbage_collection(syncobj);
+	if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
+		/*BINARY syncobj always wait on last pt */
+		pt_value = syncobj->signal_point;
+
+		if (pt_value == 0)
+			pt_value += DRM_SYNCOBJ_BINARY_POINT;
+	}
+	return drm_syncobj_point_get(syncobj, pt_value, flags, fence);
+}
+EXPORT_SYMBOL(drm_syncobj_search_fence);
+
 /**
  * drm_syncobj_find_fence - lookup and reference the fence in a sync object
  * @file_private: drm file private pointer
@@ -228,7 +432,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
  * @fence: out parameter for the fence
  *
  * This is just a convenience function that combines drm_syncobj_find() and
- * drm_syncobj_fence_get().
+ * drm_syncobj_lookup_fence().
  *
  * Returns 0 on success or a negative error value on failure. On success @fence
  * contains a reference to the fence, which must be released by calling
@@ -239,15 +443,9 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
 			   struct dma_fence **fence)
 {
 	struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
-	int ret = 0;
-
-	if (!syncobj)
-		return -ENOENT;
+	int ret;
 
-	*fence = drm_syncobj_fence_get(syncobj);
-	if (!*fence) {
-		ret = -EINVAL;
-	}
+	ret = drm_syncobj_search_fence(syncobj, point, flags, fence);
 	drm_syncobj_put(syncobj);
 	return ret;
 }
@@ -264,7 +462,7 @@ void drm_syncobj_free(struct kref *kref)
 	struct drm_syncobj *syncobj = container_of(kref,
 						   struct drm_syncobj,
 						   refcount);
-	drm_syncobj_replace_fence(syncobj, 0, NULL);
+	drm_syncobj_fini(syncobj);
 	kfree(syncobj);
 }
 EXPORT_SYMBOL(drm_syncobj_free);
@@ -294,6 +492,11 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
 	kref_init(&syncobj->refcount);
 	INIT_LIST_HEAD(&syncobj->cb_list);
 	spin_lock_init(&syncobj->lock);
+	if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE)
+		syncobj->type = DRM_SYNCOBJ_TYPE_TIMELINE;
+	else
+		syncobj->type = DRM_SYNCOBJ_TYPE_BINARY;
+	drm_syncobj_init(syncobj);
 
 	if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
 		ret = drm_syncobj_assign_null_handle(syncobj);
@@ -576,7 +779,8 @@ drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
 		return -ENODEV;
 
 	/* no valid flags yet */
-	if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
+	if (args->flags & ~(DRM_SYNCOBJ_CREATE_SIGNALED |
+			    DRM_SYNCOBJ_CREATE_TYPE_TIMELINE))
 		return -EINVAL;
 
 	return drm_syncobj_create_as_handle(file_private,
@@ -669,9 +873,8 @@ static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
 	struct syncobj_wait_entry *wait =
 		container_of(cb, struct syncobj_wait_entry, syncobj_cb);
 
-	/* This happens inside the syncobj lock */
-	wait->fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
-							      lockdep_is_held(&syncobj->lock)));
+	drm_syncobj_search_fence(syncobj, 0, 0, &wait->fence);
+
 	wake_up_process(wait->task);
 }
 
@@ -698,7 +901,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
 	signaled_count = 0;
 	for (i = 0; i < count; ++i) {
 		entries[i].task = current;
-		entries[i].fence = drm_syncobj_fence_get(syncobjs[i]);
+		ret = drm_syncobj_search_fence(syncobjs[i], 0, 0,
+					       &entries[i].fence);
 		if (!entries[i].fence) {
 			if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
 				continue;
@@ -970,12 +1174,13 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
 	if (ret < 0)
 		return ret;
 
-	for (i = 0; i < args->count_handles; i++)
-		drm_syncobj_replace_fence(syncobjs[i], 0, NULL);
-
+	for (i = 0; i < args->count_handles; i++) {
+		drm_syncobj_fini(syncobjs[i]);
+		drm_syncobj_init(syncobjs[i]);
+	}
 	drm_syncobj_array_free(syncobjs, args->count_handles);
 
-	return 0;
+	return ret;
 }
 
 int
drivers/gpu/drm/i915/i915_gem_execbuffer.c +1 -1
index 0a8d2d64f380..8a8d21b24119 100644
@@ -2137,7 +2137,7 @@ await_fence_array(struct i915_execbuffer *eb,
 		if (!(flags & I915_EXEC_FENCE_WAIT))
 			continue;
 
-		fence = drm_syncobj_fence_get(syncobj);
+		drm_syncobj_search_fence(syncobj, 0, 0, &fence);
 		if (!fence)
 			return -EINVAL;
 
include/drm/drm_syncobj.h +0 -0
index 2eda44def639..85b36d4e53ee 100644
@@ -30,6 +30,11 @@
 

include/drm/drm_syncobj.h line 40

Quoted 10 lines
include/drm/drm_syncobj.h +5 -0
 struct drm_syncobj_cb;
 
+enum drm_syncobj_type {
+	DRM_SYNCOBJ_TYPE_BINARY,
+	DRM_SYNCOBJ_TYPE_TIMELINE
+};
+
 /**
  * struct drm_syncobj - sync object.
  *

The kerneldoc for this also isn't accurate anymore.

With the kernel-doc polished:

But I think we definitely want a full ack for the uapi from radv/anv guys (plus the userspace for either of those).
-Daniel

Quoted 107 lines
include/drm/drm_syncobj.h +28 -32
@@ -41,19 +46,36 @@ struct drm_syncobj {
 	 */
 	struct kref refcount;
 	/**
-	 * @fence:
-	 * NULL or a pointer to the fence bound to this object.
-	 *
-	 * This field should not be used directly. Use drm_syncobj_fence_get()
-	 * and drm_syncobj_replace_fence() instead.
+	 * @type: indicate syncobj type
+	 */
+	enum drm_syncobj_type type;
+	/**
+	 * @wq: wait signal operation work queue
+	 */
+	wait_queue_head_t	wq;
+	/**
+	 * @timeline_context: fence context used by timeline
 	 */
-	struct dma_fence __rcu *fence;
+	u64 timeline_context;
 	/**
-	 * @cb_list: List of callbacks to call when the &fence gets replaced.
+	 * @timeline: syncobj timeline value, which indicates point is signaled.
 	 */
+	u64 timeline;
+	/**
+	 * @signal_point: which indicates the latest signaler point.
+	 */
+	u64 signal_point;
+	/**
+	 * @signal_pt_list: signaler point list.
+	 */
+	struct list_head signal_pt_list;
+
+	/**
+         * @cb_list: List of callbacks to call when the &fence gets replaced.
+         */
 	struct list_head cb_list;
 	/**
-	 * @lock: Protects &cb_list and write-locks &fence.
+	 * @lock: Protects syncobj list and write-locks &fence.
 	 */
 	spinlock_t lock;
 	/**
@@ -68,7 +90,7 @@ typedef void (*drm_syncobj_func_t)(struct drm_syncobj *syncobj,
 /**
  * struct drm_syncobj_cb - callback for drm_syncobj_add_callback
  * @node: used by drm_syncob_add_callback to append this struct to
- *	  &drm_syncobj.cb_list
+ *       &drm_syncobj.cb_list
  * @func: drm_syncobj_func_t to call
  *
  * This struct will be initialized by drm_syncobj_add_callback, additional
@@ -106,29 +128,6 @@ drm_syncobj_put(struct drm_syncobj *obj)
 	kref_put(&obj->refcount, drm_syncobj_free);
 }
 
-/**
- * drm_syncobj_fence_get - get a reference to a fence in a sync object
- * @syncobj: sync object.
- *
- * This acquires additional reference to &drm_syncobj.fence contained in @obj,
- * if not NULL. It is illegal to call this without already holding a reference.
- * No locks required.
- *
- * Returns:
- * Either the fence of @obj or NULL if there's none.
- */
-static inline struct dma_fence *
-drm_syncobj_fence_get(struct drm_syncobj *syncobj)
-{
-	struct dma_fence *fence;
-
-	rcu_read_lock();
-	fence = dma_fence_get_rcu_safe(&syncobj->fence);
-	rcu_read_unlock();
-
-	return fence;
-}
-
 struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
 				     u32 handle);
 void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point,
@@ -142,5 +141,7 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
 int drm_syncobj_get_handle(struct drm_file *file_private,
 			   struct drm_syncobj *syncobj, u32 *handle);
 int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd);
+int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point, u64 flags,
+			     struct dma_fence **fence);
 
 #endif
include/uapi/drm/drm.h +1 -0
index 300f336633f2..cebdb2541eb7 100644
@@ -717,6 +717,7 @@ struct drm_prime_handle {
 struct drm_syncobj_create {
 	__u32 handle;
 #define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0)
+#define DRM_SYNCOBJ_CREATE_TYPE_TIMELINE (1 << 1)
 	__u32 flags;
 };
 
Signature · 1 line
2.17.1
Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

A message that is not in the archive (sent off-list or not yet received): 20181017080908.GK31561-dv86pmgwkMBes7Z6vYuT8azUEOm+Xw19@public.gmane.org

#4 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

Quoted 65 lines · Daniel Vetter
Quoted 64 lines · Chunming Zhou

This patch is for VK_KHR_timeline_semaphore extension, semaphore is called syncobj in kernel side:
This extension introduces a new type of syncobj that has an integer payload identifying a point in a timeline. Such timeline syncobjs support the
following operations:
* CPU query - A host operation that allows querying the payload of the timeline syncobj.
* CPU wait - A host operation that allows a blocking wait for a
timeline syncobj to reach a specified value.
* Device wait - A device operation that allows waiting for a
timeline syncobj to reach a specified value.
* Device signal - A device operation that allows advancing the
timeline syncobj to a specified value.

v1:
Since it's a timeline, that means the front time point(PT) always is signaled before the late PT. a. signal PT design:
Signal PT fence N depends on PT[N-1] fence and signal opertion fence, when PT[N] fence is signaled, the timeline will increase to value of PT[N].
b. wait PT design:
Wait PT fence is signaled by reaching timeline point value, when timeline is increasing, will compare wait PTs value with new timeline value, if PT value is lower than timeline value, then wait PT will be signaled, otherwise keep in list. syncobj wait operation can wait on any point of timeline, so need a RB tree to order them. And wait PT could ahead of signal PT, we need a sumission fence to perform that.

v2:
1. remove unused DRM_SYNCOBJ_CREATE_TYPE_NORMAL. (Christian)
2. move unexposed denitions to .c file. (Daniel Vetter)
3. split up the change to drm_syncobj_find_fence() in a separate patch. (Christian)
4. split up the change to drm_syncobj_replace_fence() in a separate patch.
5. drop the submission_fence implementation and instead use wait_event() for that. (Christian)
6. WARN_ON(point != 0) for NORMAL type syncobj case. (Daniel Vetter)

v3:
1. replace normal syncobj with timeline implemenation. (Vetter and Christian)
a. normal syncobj signal op will create a signal PT to tail of signal pt list.
b. normal syncobj wait op will create a wait pt with last signal point, and this wait PT is only signaled by related signal point PT.
2. many bug fix and clean up
3. stub fence moving is moved to other patch.

v4:
1. fix RB tree loop with while(node=rb_first(...)). (Christian)
2. fix syncobj lifecycle. (Christian)
3. only enable_signaling when there is wait_pt. (Christian)
4. fix timeline path issues.
5. write a timeline test in libdrm

v5: (Christian)
1. semaphore is called syncobj in kernel side.
2. don't need 'timeline' characters in some function name.
3. keep syncobj cb.

v6: (Christian)
1. merge syncobj_timeline to syncobj structure.
2. simplify some check sentences.
3. some misc change.
4. fix CTS failed issue.

v7: (Christian)
1. error handling when creating signal pt.
2. remove timeline naming in func.
3. export flags in find_fence.
4. allow reset timeline.

Quoted 8 lines
Quoted 6 lines

v8:
1. use wait_event_interruptible without timeout
2. rename _TYPE_INDIVIDUAL to _TYPE_BINARY

individual syncobj is tested by ./deqp-vk -n dEQP-VK*semaphore* timeline syncobj is tested by ./amdgpu_test -s 9

Can we please have these low-level syncobj tests as part of igt, together with all the other syncobj tests which are there already?

Good suggestion first, I'm just not familiar with igt( build, run cmd...), maybe we can add it later.

Quoted 33 lines

Really doesn't
make much sense imo to splits things on the test suite front.

Quoted 31 lines
Cc Christian Konig <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Daniel Rakos <[email protected]>
Cc Daniel Vetter <[email protected]>
---
  drivers/gpu/drm/drm_syncobj.c              | 287 ++++++++++++++++++---
  drivers/gpu/drm/i915/i915_gem_execbuffer.c |   2 +-
  include/drm/drm_syncobj.h                  |  65 ++---
  include/uapi/drm/drm.h                     |   1 +
  4 files changed, 281 insertions(+), 74 deletions(-)
drivers/gpu/drm/drm_syncobj.c +3 -0
index f796c9fc3858..67472bd77c83 100644
@@ -56,6 +56,9 @@
  #include "drm_internal.h"
  #include <drm/drm_syncobj.h>
 
+/* merge normal syncobj to timeline syncobj, the point interval is 1 */
+#define DRM_SYNCOBJ_BINARY_POINT 1
+
  struct drm_syncobj_stub_fence {
  	struct dma_fence base;
  	spinlock_t lock;
@@ -82,6 +85,11 @@ static const struct dma_fence_ops drm_syncobj_stub_fence_ops = {
  	.release = drm_syncobj_stub_fence_release,
  };
 
Quoted 4 lines

drivers/gpu/drm/drm_syncobj.c static const struct dma_fence_ops drm_syncobj_stub_fence_ops = { · line 89

Quoted 2 lines
drivers/gpu/drm/drm_syncobj.c +2 -0
+struct drm_syncobj_signal_pt {
+	struct dma_fence_array *base;

Out of curiosity, why the pointer and not embedding? base is kinda misleading for a pointer.

Yeah, Christian doesn't like signal_pt lifecycle same as fence, so it's a pointer. If you don't like 'base' name, I can change it.

Quoted 260 lines
Quoted 260 lines
drivers/gpu/drm/drm_syncobj.c +196 -22
+	u64    value;
+	struct list_head list;
+};
 
  /**
   * drm_syncobj_find - lookup and reference a sync object.
@@ -124,8 +132,8 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
  {
  	int ret;
 
-	*fence = drm_syncobj_fence_get(syncobj);
-	if (*fence)
+	ret = drm_syncobj_search_fence(syncobj, 0, 0, fence);
+	if (!ret)
  		return 1;
 
  	spin_lock(&syncobj->lock);
@@ -133,10 +141,12 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
  	 * have the lock, try one more time just to be sure we don't add a
  	 * callback when a fence has already been set.
  	 */
-	if (syncobj->fence) {
-		*fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
-								 lockdep_is_held(&syncobj->lock)));
-		ret = 1;
+	if (!list_empty(&syncobj->signal_pt_list)) {
+		spin_unlock(&syncobj->lock);
+		drm_syncobj_search_fence(syncobj, 0, 0, fence);
+		if (*fence)
+			return 1;
+		spin_lock(&syncobj->lock);
  	} else {
  		*fence = NULL;
  		drm_syncobj_add_callback_locked(syncobj, cb, func);
@@ -164,6 +174,159 @@ void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
  	spin_unlock(&syncobj->lock);
  }
 
+static void drm_syncobj_init(struct drm_syncobj *syncobj)
+{
+	spin_lock(&syncobj->lock);
+	syncobj->timeline_context = dma_fence_context_alloc(1);
+	syncobj->timeline = 0;
+	syncobj->signal_point = 0;
+	init_waitqueue_head(&syncobj->wq);
+
+	INIT_LIST_HEAD(&syncobj->signal_pt_list);
+	spin_unlock(&syncobj->lock);
+}
+
+static void drm_syncobj_fini(struct drm_syncobj *syncobj)
+{
+	struct drm_syncobj_signal_pt *signal_pt = NULL, *tmp;
+
+	spin_lock(&syncobj->lock);
+	list_for_each_entry_safe(signal_pt, tmp,
+				 &syncobj->signal_pt_list, list) {
+		list_del(&signal_pt->list);
+		dma_fence_put(&signal_pt->base->base);
+		kfree(signal_pt);
+	}
+	spin_unlock(&syncobj->lock);
+}
+
+static struct dma_fence
+*drm_syncobj_find_signal_pt_for_point(struct drm_syncobj *syncobj,
+				      uint64_t point)
+{
+	struct drm_syncobj_signal_pt *signal_pt;
+
+	if ((syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) &&
+	    (point <= syncobj->timeline)) {
+		struct drm_syncobj_stub_fence *fence =
+			kzalloc(sizeof(struct drm_syncobj_stub_fence),
+				GFP_KERNEL);
+
+		if (!fence)
+			return NULL;
+		spin_lock_init(&fence->lock);
+		dma_fence_init(&fence->base,
+			       &drm_syncobj_stub_fence_ops,
+			       &fence->lock,
+			       syncobj->timeline_context,
+			       point);
+
+		dma_fence_signal(&fence->base);
+		return &fence->base;
+	}
+
+	list_for_each_entry(signal_pt, &syncobj->signal_pt_list, list) {
+		if (point > signal_pt->value)
+			continue;
+		if ((syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) &&
+		    (point != signal_pt->value))
+			continue;
+		return dma_fence_get(&signal_pt->base->base);
+	}
+	return NULL;
+}
+
+static int drm_syncobj_create_signal_pt(struct drm_syncobj *syncobj,
+					struct dma_fence *fence,
+					u64 point)
+{
+	struct drm_syncobj_signal_pt *signal_pt =
+		kzalloc(sizeof(struct drm_syncobj_signal_pt), GFP_KERNEL);
+	struct drm_syncobj_signal_pt *tail_pt;
+	struct dma_fence **fences;
+	int num_fences = 0;
+	int ret = 0, i;
+
+	if (!signal_pt)
+		return -ENOMEM;
+	if (!fence)
+		goto out;
+
+	fences = kmalloc_array(sizeof(void *), 2, GFP_KERNEL);
+	if (!fences) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	fences[num_fences++] = dma_fence_get(fence);
+	/* timeline syncobj must take this dependency */
+	if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) {
+		spin_lock(&syncobj->lock);
+		if (!list_empty(&syncobj->signal_pt_list)) {
+			tail_pt = list_last_entry(&syncobj->signal_pt_list,
+						  struct drm_syncobj_signal_pt, list);
+			fences[num_fences++] = dma_fence_get(&tail_pt->base->base);
+		}
+		spin_unlock(&syncobj->lock);
+	}
+	signal_pt->base = dma_fence_array_create(num_fences, fences,
+						 syncobj->timeline_context,
+						 point, false);
+	if (!signal_pt->base) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	spin_lock(&syncobj->lock);
+	if (syncobj->signal_point >= point) {
+		DRM_WARN("A later signal is ready!");
+		spin_unlock(&syncobj->lock);
+		goto exist;
+	}
+	signal_pt->value = point;
+	list_add_tail(&signal_pt->list, &syncobj->signal_pt_list);
+	syncobj->signal_point = point;
+	spin_unlock(&syncobj->lock);
+	wake_up_all(&syncobj->wq);
+
+	return 0;
+exist:
+	dma_fence_put(&signal_pt->base->base);
+fail:
+	for (i = 0; i < num_fences; i++)
+		dma_fence_put(fences[i]);
+	kfree(fences);
+out:
+	kfree(signal_pt);
+	return ret;
+}
+
+static void drm_syncobj_garbage_collection(struct drm_syncobj *syncobj)
+{
+	struct drm_syncobj_signal_pt *signal_pt, *tmp, *tail_pt;
+
+	spin_lock(&syncobj->lock);
+	tail_pt = list_last_entry(&syncobj->signal_pt_list,
+				  struct drm_syncobj_signal_pt,
+				  list);
+	list_for_each_entry_safe(signal_pt, tmp,
+				 &syncobj->signal_pt_list, list) {
+		if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY &&
+		    signal_pt == tail_pt)
+			continue;
+		if (dma_fence_is_signaled(&signal_pt->base->base)) {
+			syncobj->timeline = signal_pt->value;
+			list_del(&signal_pt->list);
+			dma_fence_put(&signal_pt->base->base);
+			kfree(signal_pt);
+		} else {
+			/*signal_pt is in order in list, from small to big, so
+			 * the later must not be signal either */
+			break;
+		}
+	}
+
+	spin_unlock(&syncobj->lock);
+}
  /**
   * drm_syncobj_replace_fence - replace fence in a sync object.
   * @syncobj: Sync object to replace fence in
@@ -176,28 +339,29 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
  			       u64 point,
  			       struct dma_fence *fence)
  {
-	struct dma_fence *old_fence;
-	struct drm_syncobj_cb *cur, *tmp;
-
-	if (fence)
-		dma_fence_get(fence);
-
-	spin_lock(&syncobj->lock);
-
-	old_fence = rcu_dereference_protected(syncobj->fence,
-					      lockdep_is_held(&syncobj->lock));
-	rcu_assign_pointer(syncobj->fence, fence);
+	u64 pt_value = point;
+
+	drm_syncobj_garbage_collection(syncobj);
+	if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
+		if (!fence) {
+			drm_syncobj_fini(syncobj);
+			drm_syncobj_init(syncobj);
+			return;
+		}
+		pt_value = syncobj->signal_point +
+			DRM_SYNCOBJ_BINARY_POINT;
+	}
+	drm_syncobj_create_signal_pt(syncobj, fence, pt_value);
+	if (fence) {
+		struct drm_syncobj_cb *cur, *tmp;
 
-	if (fence != old_fence) {
+		spin_lock(&syncobj->lock);
  		list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) {
  			list_del_init(&cur->node);
  			cur->func(syncobj, cur);
  		}
+		spin_unlock(&syncobj->lock);
  	}
-
-	spin_unlock(&syncobj->lock);
-
-	dma_fence_put(old_fence);
  }
  EXPORT_SYMBOL(drm_syncobj_replace_fence);
 
@@ -220,6 +384,46 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
  	return 0;
  }
 
+static int
+drm_syncobj_point_get(struct drm_syncobj *syncobj, u64 point, u64 flags,
+		      struct dma_fence **fence)
+{
+	int ret = 0;
+
+	if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
+		ret = wait_event_interruptible(syncobj->wq,
+					       point <= syncobj->signal_point);
+		if (ret < 0)
+			return ret;
+	}
+	spin_lock(&syncobj->lock);
+	*fence = drm_syncobj_find_signal_pt_for_point(syncobj, point);
+	if (!*fence)
Quoted 8 lines

drivers/gpu/drm/drm_syncobj.c static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) · line 408

Quoted 7 lines
drivers/gpu/drm/drm_syncobj.c +7 -0
+		ret = -EINVAL;
+	spin_unlock(&syncobj->lock);
+	return ret;
+}
+
+int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point,
+			     u64 flags, struct dma_fence **fence)

Kerneldoc is missing for this one here.

It's almost same as drm_syncobj_find_fence, is it still necessary?

Quoted 147 lines

I also think improving the overview comment to explain the timeline stuff, e.g. link to the vulkan extension, and some words on how it's supposed to be used (you need a submit thread and block in userspace until all future timeline points have materialized, only then you can submit to the kernel).

Quoted 140 lines
drivers/gpu/drm/drm_syncobj.c +38 -19
+{
+	u64 pt_value = point;
+
+	if (!syncobj)
+		return -ENOENT;
+
+	drm_syncobj_garbage_collection(syncobj);
+	if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
+		/*BINARY syncobj always wait on last pt */
+		pt_value = syncobj->signal_point;
+
+		if (pt_value == 0)
+			pt_value += DRM_SYNCOBJ_BINARY_POINT;
+	}
+	return drm_syncobj_point_get(syncobj, pt_value, flags, fence);
+}
+EXPORT_SYMBOL(drm_syncobj_search_fence);
+
  /**
   * drm_syncobj_find_fence - lookup and reference the fence in a sync object
   * @file_private: drm file private pointer
@@ -228,7 +432,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
   * @fence: out parameter for the fence
   *
   * This is just a convenience function that combines drm_syncobj_find() and
- * drm_syncobj_fence_get().
+ * drm_syncobj_lookup_fence().
   *
   * Returns 0 on success or a negative error value on failure. On success @fence
   * contains a reference to the fence, which must be released by calling
@@ -239,15 +443,9 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
  			   struct dma_fence **fence)
  {
  	struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
-	int ret = 0;
-
-	if (!syncobj)
-		return -ENOENT;
+	int ret;
 
-	*fence = drm_syncobj_fence_get(syncobj);
-	if (!*fence) {
-		ret = -EINVAL;
-	}
+	ret = drm_syncobj_search_fence(syncobj, point, flags, fence);
  	drm_syncobj_put(syncobj);
  	return ret;
  }
@@ -264,7 +462,7 @@ void drm_syncobj_free(struct kref *kref)
  	struct drm_syncobj *syncobj = container_of(kref,
  						   struct drm_syncobj,
  						   refcount);
-	drm_syncobj_replace_fence(syncobj, 0, NULL);
+	drm_syncobj_fini(syncobj);
  	kfree(syncobj);
  }
  EXPORT_SYMBOL(drm_syncobj_free);
@@ -294,6 +492,11 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
  	kref_init(&syncobj->refcount);
  	INIT_LIST_HEAD(&syncobj->cb_list);
  	spin_lock_init(&syncobj->lock);
+	if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE)
+		syncobj->type = DRM_SYNCOBJ_TYPE_TIMELINE;
+	else
+		syncobj->type = DRM_SYNCOBJ_TYPE_BINARY;
+	drm_syncobj_init(syncobj);
 
  	if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
  		ret = drm_syncobj_assign_null_handle(syncobj);
@@ -576,7 +779,8 @@ drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
  		return -ENODEV;
 
  	/* no valid flags yet */
-	if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
+	if (args->flags & ~(DRM_SYNCOBJ_CREATE_SIGNALED |
+			    DRM_SYNCOBJ_CREATE_TYPE_TIMELINE))
  		return -EINVAL;
 
  	return drm_syncobj_create_as_handle(file_private,
@@ -669,9 +873,8 @@ static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
  	struct syncobj_wait_entry *wait =
  		container_of(cb, struct syncobj_wait_entry, syncobj_cb);
 
-	/* This happens inside the syncobj lock */
-	wait->fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
-							      lockdep_is_held(&syncobj->lock)));
+	drm_syncobj_search_fence(syncobj, 0, 0, &wait->fence);
+
  	wake_up_process(wait->task);
  }
 
@@ -698,7 +901,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
  	signaled_count = 0;
  	for (i = 0; i < count; ++i) {
  		entries[i].task = current;
-		entries[i].fence = drm_syncobj_fence_get(syncobjs[i]);
+		ret = drm_syncobj_search_fence(syncobjs[i], 0, 0,
+					       &entries[i].fence);
  		if (!entries[i].fence) {
  			if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
  				continue;
@@ -970,12 +1174,13 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
  	if (ret < 0)
  		return ret;
 
-	for (i = 0; i < args->count_handles; i++)
-		drm_syncobj_replace_fence(syncobjs[i], 0, NULL);
-
+	for (i = 0; i < args->count_handles; i++) {
+		drm_syncobj_fini(syncobjs[i]);
+		drm_syncobj_init(syncobjs[i]);
+	}
  	drm_syncobj_array_free(syncobjs, args->count_handles);
 
-	return 0;
+	return ret;
  }
 
  int
drivers/gpu/drm/i915/i915_gem_execbuffer.c +1 -1
index 0a8d2d64f380..8a8d21b24119 100644
@@ -2137,7 +2137,7 @@ await_fence_array(struct i915_execbuffer *eb,
  		if (!(flags & I915_EXEC_FENCE_WAIT))
  			continue;
 
-		fence = drm_syncobj_fence_get(syncobj);
+		drm_syncobj_search_fence(syncobj, 0, 0, &fence);
  		if (!fence)
  			return -EINVAL;
 
include/drm/drm_syncobj.h +0 -0
index 2eda44def639..85b36d4e53ee 100644
@@ -30,6 +30,11 @@
 
  struct drm_syncobj_cb;
 
Quoted 9 lines

include/drm/drm_syncobj.h line 40

Quoted 8 lines
include/drm/drm_syncobj.h +5 -0
+enum drm_syncobj_type {
+	DRM_SYNCOBJ_TYPE_BINARY,
+	DRM_SYNCOBJ_TYPE_TIMELINE
+};
+
  /**
   * struct drm_syncobj - sync object.
   *

The kerneldoc for this also isn't accurate anymore.

Can kerneldoc be a separate patch?

Quoted 4 lines

With the kernel-doc polished:

Thanks at least.

Quoted 3 lines

But I think we definitely want a full ack for the uapi from radv/anv guys (plus the userspace for either of those).

Dave and Bas are right people, right?

Thanks,
David

Quoted 106 lines

-Daniel

Quoted 104 lines
include/drm/drm_syncobj.h +28 -32
@@ -41,19 +46,36 @@ struct drm_syncobj {
  	 */
  	struct kref refcount;
  	/**
-	 * @fence:
-	 * NULL or a pointer to the fence bound to this object.
-	 *
-	 * This field should not be used directly. Use drm_syncobj_fence_get()
-	 * and drm_syncobj_replace_fence() instead.
+	 * @type: indicate syncobj type
+	 */
+	enum drm_syncobj_type type;
+	/**
+	 * @wq: wait signal operation work queue
+	 */
+	wait_queue_head_t	wq;
+	/**
+	 * @timeline_context: fence context used by timeline
  	 */
-	struct dma_fence __rcu *fence;
+	u64 timeline_context;
  	/**
-	 * @cb_list: List of callbacks to call when the &fence gets replaced.
+	 * @timeline: syncobj timeline value, which indicates point is signaled.
  	 */
+	u64 timeline;
+	/**
+	 * @signal_point: which indicates the latest signaler point.
+	 */
+	u64 signal_point;
+	/**
+	 * @signal_pt_list: signaler point list.
+	 */
+	struct list_head signal_pt_list;
+
+	/**
+         * @cb_list: List of callbacks to call when the &fence gets replaced.
+         */
  	struct list_head cb_list;
  	/**
-	 * @lock: Protects &cb_list and write-locks &fence.
+	 * @lock: Protects syncobj list and write-locks &fence.
  	 */
  	spinlock_t lock;
  	/**
@@ -68,7 +90,7 @@ typedef void (*drm_syncobj_func_t)(struct drm_syncobj *syncobj,
  /**
   * struct drm_syncobj_cb - callback for drm_syncobj_add_callback
   * @node: used by drm_syncob_add_callback to append this struct to
- *	  &drm_syncobj.cb_list
+ *       &drm_syncobj.cb_list
   * @func: drm_syncobj_func_t to call
   *
   * This struct will be initialized by drm_syncobj_add_callback, additional
@@ -106,29 +128,6 @@ drm_syncobj_put(struct drm_syncobj *obj)
  	kref_put(&obj->refcount, drm_syncobj_free);
  }
 
-/**
- * drm_syncobj_fence_get - get a reference to a fence in a sync object
- * @syncobj: sync object.
- *
- * This acquires additional reference to &drm_syncobj.fence contained in @obj,
- * if not NULL. It is illegal to call this without already holding a reference.
- * No locks required.
- *
- * Returns:
- * Either the fence of @obj or NULL if there's none.
- */
-static inline struct dma_fence *
-drm_syncobj_fence_get(struct drm_syncobj *syncobj)
-{
-	struct dma_fence *fence;
-
-	rcu_read_lock();
-	fence = dma_fence_get_rcu_safe(&syncobj->fence);
-	rcu_read_unlock();
-
-	return fence;
-}
-
  struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
  				     u32 handle);
  void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point,
@@ -142,5 +141,7 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
  int drm_syncobj_get_handle(struct drm_file *file_private,
  			   struct drm_syncobj *syncobj, u32 *handle);
  int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd);
+int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point, u64 flags,
+			     struct dma_fence **fence);
 
  #endif
include/uapi/drm/drm.h +1 -0
index 300f336633f2..cebdb2541eb7 100644
@@ -717,6 +717,7 @@ struct drm_prime_handle {
  struct drm_syncobj_create {
  	__u32 handle;
  #define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0)
+#define DRM_SYNCOBJ_CREATE_TYPE_TIMELINE (1 << 1)
  	__u32 flags;
  };
 
Quoted 3 lines
Quoted 3 lines
Signature · 1 line
2.17.1

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

#5 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

Am 17.10.18 um 11:17 schrieb zhoucm1:

Quoted 8 lines

[SNIP]

Quoted 4 lines
Quoted 2 lines

  +struct drm_syncobj_signal_pt {
+    struct dma_fence_array *base;

Out of curiosity, why the pointer and not embedding? base is kinda misleading for a pointer.

Yeah, Christian doesn't like signal_pt lifecycle same as fence, so it's a pointer.
If you don't like 'base' name, I can change it.

Well I never said that you can't embed the fence array into the signal_pt.

You just need to make sure that we don't affect the drm_syncobj lilecycle as well, e.g. that we don't also need to keep that around.

Regards,
Christian.
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#6 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

Quoted 7 lines · Christian

Am 17.10.18 um 11:17 schrieb zhoucm1:

Quoted 5 lines

[SNIP]

Quoted 4 lines
Quoted 2 lines

+struct drm_syncobj_signal_pt {
+ struct dma_fence_array *base;

Out of curiosity, why the pointer and not embedding? base is kinda misleading for a pointer.

Quoted 8 lines
Quoted 3 lines

Yeah, Christian doesn't like signal_pt lifecycle same as fence, so it's a pointer.
If you don't like 'base' name, I can change it.

Well I never said that you can't embed the fence array into the signal_pt.

You just need to make sure that we don't affect the drm_syncobj lilecycle as well, e.g. that we don't also need to keep that around.

I don't see a problem with that, as long as drm_syncobj keeps a reference to the fence while it's on the timeline list. Which it already does. And embedding would avoid that 2nd separate allocation, aside from making base less confusing.
-Daniel

Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

A message that is not in the archive (sent off-list or not yet received): CAKMK7uGxptMKtz-4JzT9us3M2dsLGhTSVuAKduNH+VGCsCSsQw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#8 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

Quoted 11 lines · Daniel Vetter
Quoted 9 lines · Christian

Am 17.10.18 um 11:17 schrieb zhoucm1:

Quoted 8 lines

[SNIP]

Quoted 4 lines
Quoted 2 lines
   +struct drm_syncobj_signal_pt {

+ struct dma_fence_array *base;

Out of curiosity, why the pointer and not embedding? base is kinda misleading for a pointer.

Yeah, Christian doesn't like signal_pt lifecycle same as fence, so it's a pointer.
If you don't like 'base' name, I can change it.

Quoted 8 lines
Quoted 4 lines

Well I never said that you can't embed the fence array into the signal_pt.

You just need to make sure that we don't affect the drm_syncobj lilecycle as well, e.g. that we don't also need to keep that around.

I don't see a problem with that, as long as drm_syncobj keeps a reference to the fence while it's on the timeline list. Which it already does. And embedding would avoid that 2nd separate allocation, aside from making base less confusing.

That's indeed my initial implementation for signal_pt/wait_pt with fence based, but after long and many discussions, we get current solution, as you see, the version is up to v8 :).

For here  why the pointer and not embedding?
Two reasons:
1. their lifecycles are not same.
2. It is a fence array usage, which always needs separate allocation, seems which is mandatory. So it is a pointer.

But the name is historical from initial, and indeed be kinda misleading for a pointer, I will change it to fence_array instead in coming v9.

Thanks,
David Zhou

Quoted 1 line

-Daniel

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

A message that is not in the archive (sent off-list or not yet received): b08b1f23-d8dc-a294-2176-5125075c9acc-5C7GfCeVMHo@public.gmane.org

#10 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

Am 18.10.18 um 05:11 schrieb zhoucm1:

Quoted 24 lines · Daniel Vetter
Quoted 11 lines
Quoted 9 lines · Christian

Am 17.10.18 um 11:17 schrieb zhoucm1:

Quoted 8 lines

[SNIP]

Quoted 4 lines
Quoted 2 lines

   +struct drm_syncobj_signal_pt {
+    struct dma_fence_array *base;

Out of curiosity, why the pointer and not embedding? base is kinda misleading for a pointer.

Yeah, Christian doesn't like signal_pt lifecycle same as fence, so it's a pointer.
If you don't like 'base' name, I can change it.

Quoted 8 lines
Quoted 4 lines

Well I never said that you can't embed the fence array into the signal_pt.

You just need to make sure that we don't affect the drm_syncobj lilecycle as well, e.g. that we don't also need to keep that around.

I don't see a problem with that, as long as drm_syncobj keeps a reference to the fence while it's on the timeline list. Which it already does. And embedding would avoid that 2nd separate allocation, aside from making base less confusing.

That's indeed my initial implementation for signal_pt/wait_pt with fence based, but after long and many discussions, we get current solution, as you see, the version is up to v8 :).

Quoted 7 lines

For here  why the pointer and not embedding?
Two reasons:
1. their lifecycles are not same.
2. It is a fence array usage, which always needs separate allocation, seems which is mandatory. So it is a pointer.

But the name is historical from initial, and indeed be kinda misleading for a pointer, I will change it to fence_array instead in coming v9.

To avoid running into a v10 I've just pushed this version upstream :)

The rest in the series looks good to me as well, but I certainly want the radv/anv developers to take a look as well as Daniel suggested.

Christian.

Quoted 10 lines

Thanks,
David Zhou

Quoted 1 line

-Daniel

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

#11 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

Quoted 31 lines · Christian König

Am 18.10.18 um 05:11 schrieb zhoucm1:

Quoted 30 lines · Daniel Vetter
Quoted 11 lines
Quoted 9 lines · Christian

Am 17.10.18 um 11:17 schrieb zhoucm1:

Quoted 8 lines

[SNIP]

Quoted 4 lines
Quoted 2 lines

   +struct drm_syncobj_signal_pt {
+    struct dma_fence_array *base;

Out of curiosity, why the pointer and not embedding? base is kinda misleading for a pointer.

Yeah, Christian doesn't like signal_pt lifecycle same as fence, so it's a pointer.
If you don't like 'base' name, I can change it.

Quoted 8 lines
Quoted 4 lines

Well I never said that you can't embed the fence array into the signal_pt.

You just need to make sure that we don't affect the drm_syncobj lilecycle as well, e.g. that we don't also need to keep that around.

I don't see a problem with that, as long as drm_syncobj keeps a reference to the fence while it's on the timeline list. Which it already does. And embedding would avoid that 2nd separate allocation, aside from making base less confusing.

That's indeed my initial implementation for signal_pt/wait_pt with fence based, but after long and many discussions, we get current solution, as you see, the version is up to v8 :).

For here  why the pointer and not embedding?
Two reasons:
1. their lifecycles are not same.
2. It is a fence array usage, which always needs separate allocation, seems which is mandatory. So it is a pointer.

Quoted 3 lines
Quoted 1 line

But the name is historical from initial, and indeed be kinda misleading for a pointer, I will change it to fence_array instead in coming v9.

To avoid running into a v10 I've just pushed this version upstream :)

Thanks a lot.

Quoted 2 lines

The rest in the series looks good to me as well,

Can I get your RB on them first?

Quoted 1 line

but I certainly want the radv/anv developers to take a look as well as Daniel suggested.

Ping @Dave/Bas/Jason or other radv/anv developers, Could anyone of you take a look the rest of series for u/k interface? So that we can move to next step for libdrm patches?

Thanks,
David

Quoted 14 lines

Christian.

Quoted 10 lines

Thanks,
David Zhou

Quoted 1 line

-Daniel

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

#12 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

Quoted 38 lines · On Fri, Oct 19, 2018 at 10:29:55AM +0800, zhoucm1 wrote:
Quoted 35 lines · Christian König

Am 18.10.18 um 05:11 schrieb zhoucm1:

Quoted 34 lines · Daniel Vetter
Quoted 14 lines
Quoted 12 lines · Christian

Am 17.10.18 um 11:17 schrieb zhoucm1:

Quoted 8 lines

[SNIP]

Quoted 4 lines
Quoted 2 lines

   +struct drm_syncobj_signal_pt {
+    struct dma_fence_array *base;

Out of curiosity, why the pointer and not embedding? base is kinda misleading for a pointer.

Yeah, Christian doesn't like signal_pt lifecycle same as fence, so it's a pointer.
If you don't like 'base' name, I can change it.

Well I never said that you can't embed the fence array into the signal_pt.

Quoted 6 lines
Quoted 2 lines

You just need to make sure that we don't affect the drm_syncobj lilecycle as well, e.g. that we don't also need to keep that around.

I don't see a problem with that, as long as drm_syncobj keeps a reference to the fence while it's on the timeline list. Which it already does. And embedding would avoid that 2nd separate allocation, aside from making base less confusing.

That's indeed my initial implementation for signal_pt/wait_pt with fence based, but after long and many discussions, we get current solution, as you see, the version is up to v8 :).

For here  why the pointer and not embedding?
Two reasons:
1. their lifecycles are not same.
2. It is a fence array usage, which always needs separate allocation, seems which is mandatory.
So it is a pointer.

Quoted 6 lines
Quoted 5 lines
Quoted 3 lines

But the name is historical from initial, and indeed be kinda misleading for a pointer, I will change it to fence_array instead in coming v9.

To avoid running into a v10 I've just pushed this version upstream :)

Thanks a lot.

(This time reply to the right patch, silly me)

Went boom:

https://bugs.freedesktop.org/show_bug.cgi?id=108490

Can we revert pls?

Also, can we please have igts for this stuff so that intel-gfx-ci could test this properly before it's all fireworks?

Thanks, Daniel

Quoted 27 lines
Quoted 2 lines

The rest in the series looks good to me as well,

Can I get your RB on them first?

Quoted 2 lines

but I certainly want the radv/anv developers to take a look as well as Daniel suggested.

Ping @Dave/Bas/Jason or other radv/anv developers, Could anyone of you take a look the rest of series for u/k interface? So that we can move to next step for libdrm patches?

Thanks,
David

Quoted 14 lines

Christian.

Quoted 10 lines

Thanks,
David Zhou

Quoted 1 line

-Daniel

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#13 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

Quoted 41 lines · Daniel Vetter
Quoted 40 lines · On Fri, Oct 19, 2018 at 10:29:55AM +0800, zhoucm1 wrote:
Quoted 38 lines · Christian König

Am 18.10.18 um 05:11 schrieb zhoucm1:

Quoted 33 lines · Daniel Vetter
Quoted 14 lines
Quoted 12 lines · Christian

Am 17.10.18 um 11:17 schrieb zhoucm1:

Quoted 8 lines

[SNIP]

Quoted 4 lines
Quoted 2 lines

   +struct drm_syncobj_signal_pt {
+    struct dma_fence_array *base;

Out of curiosity, why the pointer and not embedding? base is kinda misleading for a pointer.

Yeah, Christian doesn't like signal_pt lifecycle same as fence, so it's a pointer.
If you don't like 'base' name, I can change it.

Well I never said that you can't embed the fence array into the signal_pt.

Quoted 6 lines
Quoted 2 lines

You just need to make sure that we don't affect the drm_syncobj lilecycle as well, e.g. that we don't also need to keep that around.

I don't see a problem with that, as long as drm_syncobj keeps a reference to the fence while it's on the timeline list. Which it already does. And embedding would avoid that 2nd separate allocation, aside from making base less confusing.

That's indeed my initial implementation for signal_pt/wait_pt with fence based, but after long and many discussions, we get current solution, as you see, the version is up to v8 :).

For here  why the pointer and not embedding?
Two reasons:
1. their lifecycles are not same.
2. It is a fence array usage, which always needs separate allocation, seems which is mandatory.
So it is a pointer.

Quoted 3 lines

But the name is historical from initial, and indeed be kinda misleading for a pointer, I will change it to fence_array instead in coming v9.

To avoid running into a v10 I've just pushed this version upstream :)

Quoted 8 lines
Quoted 1 line

Thanks a lot.

(This time reply to the right patch, silly me)

Went boom:

https://bugs.freedesktop.org/show_bug.cgi?id=108490

Can we revert pls?

Sorry for bug, please.

Quoted 3 lines

Also, can we please have igts for this stuff so that intel-gfx-ci could test this properly before it's all fireworks?

Seems we cannot avoid igt now and vulkan CTS isn't enough, I will find some time next week to lean IGT, looks v10 is need.

Regards,
David Zhou

Quoted 24 lines

Thanks, Daniel

Quoted 21 lines
Quoted 1 line

The rest in the series looks good to me as well,

Can I get your RB on them first?

Quoted 2 lines

but I certainly want the radv/anv developers to take a look as well as Daniel suggested.

Ping @Dave/Bas/Jason or other radv/anv developers, Could anyone of you take a look the rest of series for u/k interface? So that we can move to next step for libdrm patches?

Thanks,
David

Quoted 10 lines

Christian.

Quoted 8 lines

Thanks,
David Zhou

Quoted 1 line

-Daniel

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

A message that is not in the archive (sent off-list or not yet received): 19972bac-f2a9-49ee-592d-85f9eaf06145-5C7GfCeVMHo@public.gmane.org

#15 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

Quoted 45 lines · On 2018年10月19日 17:20, zhoucm1 wrote:
Quoted 42 lines · Daniel Vetter
Quoted 41 lines · On Fri, Oct 19, 2018 at 10:29:55AM +0800, zhoucm1 wrote:
Quoted 34 lines · Christian König

Am 18.10.18 um 05:11 schrieb zhoucm1:

Quoted 33 lines · Daniel Vetter
Quoted 14 lines
Quoted 12 lines · Christian

Am 17.10.18 um 11:17 schrieb zhoucm1:

Quoted 8 lines

[SNIP]

Quoted 4 lines
Quoted 2 lines

    +struct drm_syncobj_signal_pt {
+    struct dma_fence_array *base;

Out of curiosity, why the pointer and not embedding? base is kinda misleading for a pointer.

Yeah, Christian doesn't like signal_pt lifecycle same as fence, so it's a pointer.
If you don't like 'base' name, I can change it.

Well I never said that you can't embed the fence array into the signal_pt.

Quoted 6 lines
Quoted 2 lines

You just need to make sure that we don't affect the drm_syncobj lilecycle as well, e.g. that we don't also need to keep that around.

I don't see a problem with that, as long as drm_syncobj keeps a reference to the fence while it's on the timeline list. Which it already does. And embedding would avoid that 2nd separate allocation, aside from making base less confusing.

That's indeed my initial implementation for signal_pt/wait_pt with fence based, but after long and many discussions, we get current solution, as you see, the version is up to v8 :).

For here  why the pointer and not embedding?
Two reasons:
1. their lifecycles are not same.
2. It is a fence array usage, which always needs separate allocation, seems which is mandatory.
So it is a pointer.

Quoted 4 lines
Quoted 3 lines

But the name is historical from initial, and indeed be kinda misleading for a pointer, I will change it to fence_array instead in coming v9.

To avoid running into a v10 I've just pushed this version upstream :)

Thanks a lot.

Quoted 8 lines
Quoted 7 lines

(This time reply to the right patch, silly me)

Went boom:

https://bugs.freedesktop.org/show_bug.cgi?id=108490

Can we revert pls?

Sorry for bug, please.

In fact, the bug is already caught and fixed, just the fix part isn't in patch#1, but in patch#2:

Have you reverted? If not, I can send that fix in one minute.

Regards,
David Zhou

Quoted 32 lines
Quoted 3 lines

Also, can we please have igts for this stuff so that intel-gfx-ci could test this properly before it's all fireworks?

Seems we cannot avoid igt now and vulkan CTS isn't enough, I will find some time next week to lean IGT, looks v10 is need.

Regards,
David Zhou

Quoted 24 lines

Thanks, Daniel

Quoted 21 lines
Quoted 1 line

The rest in the series looks good to me as well,

Can I get your RB on them first?

Quoted 2 lines

but I certainly want the radv/anv developers to take a look as well as Daniel suggested.

Ping @Dave/Bas/Jason or other radv/anv developers, Could anyone of you take a look the rest of series for u/k interface? So that we can move to next step for libdrm patches?

Thanks,
David

Quoted 10 lines

Christian.

Quoted 8 lines

Thanks,
David Zhou

Quoted 1 line

-Daniel

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Quoted 4 lines

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

A message that is not in the archive (sent off-list or not yet received): 22a52713-0ab5-80d9-a604-b171f916eedd-5C7GfCeVMHo@public.gmane.org

#17 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

[snip]

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

Went boom:

https://bugs.freedesktop.org/show_bug.cgi?id=108490

Can we revert pls?

Quoted 11 lines
Quoted 1 line

Sorry for bug, please.

In fact, the bug is already caught and fixed, just the fix part isn't in patch#1, but in patch#2:

Have you reverted? If not, I can send that fix in one minute.

Regards,
David Zhou

Quoted 3 lines
Quoted 3 lines

Also, can we please have igts for this stuff so that intel-gfx-ci could test this properly before it's all fireworks?

Hi Daniel V,

Could you point me which problem I encounter when I run syncobj_wait of igt?

jenkins@jenkins-MS-7984:~/freedesktop/igt-gpu-tools/tests$ ./syncobj_wait
IGT-Version: 1.23-g94ebd21 (x86_64) (Linux: 4.19.0-rc5-custom+ x86_64)
Test requirement not met in function igt_require_sw_sync, file sw_sync.c:240:
Test requirement: kernel_has_sw_sync()
Last errno: 2, No such file or directory

Thanks,
David Zhou

Quoted 34 lines
Quoted 29 lines

Seems we cannot avoid igt now and vulkan CTS isn't enough, I will find some time next week to lean IGT, looks v10 is need.

Regards,
David Zhou

Quoted 24 lines

Thanks, Daniel

Quoted 21 lines
Quoted 1 line

The rest in the series looks good to me as well,

Can I get your RB on them first?

Quoted 2 lines

but I certainly want the radv/anv developers to take a look as well as Daniel suggested.

Ping @Dave/Bas/Jason or other radv/anv developers, Could anyone of you take a look the rest of series for u/k interface? So that we can move to next step for libdrm patches?

Thanks,
David

Quoted 10 lines

Christian.

Quoted 8 lines

Thanks,
David Zhou

Quoted 1 line

-Daniel

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Quoted 4 lines

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Quoted 4 lines

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

A message that is not in the archive (sent off-list or not yet received): 69039ffa-425e-81e7-4b08-1d431d8a212f-5C7GfCeVMHo@public.gmane.org

#19 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

Quoted 22 lines · On Fri, Oct 19, 2018 at 12:45 PM zhoucm1 <[email protected]> wrote:

[snip]

Quoted 6 lines
Quoted 6 lines
Quoted 5 lines

Went boom:

https://bugs.freedesktop.org/show_bug.cgi?id=108490

Can we revert pls?

Sorry for bug, please.

Quoted 11 lines

In fact, the bug is already caught and fixed, just the fix part isn't in patch#1, but in patch#2:

Have you reverted? If not, I can send that fix in one minute.

Regards,
David Zhou

Quoted 3 lines
Quoted 3 lines

Also, can we please have igts for this stuff so that intel-gfx-ci could test this properly before it's all fireworks?

Hi Daniel V,

Quoted 8 lines

Could you point me which problem I encounter when I run syncobj_wait of igt?

jenkins@jenkins-MS-7984:~/freedesktop/igt-gpu-tools/tests$ ./syncobj_wait
IGT-Version: 1.23-g94ebd21 (x86_64) (Linux: 4.19.0-rc5-custom+ x86_64)
Test requirement not met in function igt_require_sw_sync, file
sw_sync.c:240:
Test requirement: kernel_has_sw_sync()
Last errno: 2, No such file or directory

The test isn't even run because one of it's requirements isn't met. In this case here you don't have the SW_SYNC stuff enabled, which is used to for testing. CONFIG_SW_SYNC in the kernel. You could do a quick igt patch to change the igt_require() to an igt_require_f() with something like "You need to enable CONFIG_SW_SYNC in your kernel build" as the help text.
-Daniel

Quoted 46 lines

Thanks,
David Zhou

Quoted 42 lines
Quoted 33 lines

Seems we cannot avoid igt now and vulkan CTS isn't enough, I will find some time next week to lean IGT, looks v10 is need.

Regards,
David Zhou

Quoted 27 lines

Thanks, Daniel

Quoted 24 lines
Quoted 1 line

The rest in the series looks good to me as well,

Can I get your RB on them first?

Quoted 3 lines

but I certainly want the radv/anv developers to take a look as well as
Daniel suggested.

Ping @Dave/Bas/Jason or other radv/anv developers, Could anyone of you take
a look the rest of series for u/k interface? So that we can move to next
step for libdrm patches?

Thanks,
David

Quoted 10 lines

Christian.

Quoted 8 lines

Thanks,
David Zhou

Quoted 1 line

-Daniel

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Quoted 4 lines

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

A message that is not in the archive (sent off-list or not yet received): 2066a18d-8002-014b-ef3c-a6f6014bdb55-5C7GfCeVMHo@public.gmane.org

#21 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

Quoted 389 lines · On Wed, Oct 17, 2018 at 11:17 AM zhoucm1 <[email protected]> wrote:
Quoted 65 lines · Daniel Vetter
Quoted 64 lines · Chunming Zhou

This patch is for VK_KHR_timeline_semaphore extension, semaphore is called syncobj in kernel side:
This extension introduces a new type of syncobj that has an integer payload identifying a point in a timeline. Such timeline syncobjs support the
following operations:
* CPU query - A host operation that allows querying the payload of the timeline syncobj.
* CPU wait - A host operation that allows a blocking wait for a
timeline syncobj to reach a specified value.
* Device wait - A device operation that allows waiting for a
timeline syncobj to reach a specified value.
* Device signal - A device operation that allows advancing the
timeline syncobj to a specified value.

v1:
Since it's a timeline, that means the front time point(PT) always is signaled before the late PT. a. signal PT design:
Signal PT fence N depends on PT[N-1] fence and signal opertion fence, when PT[N] fence is signaled, the timeline will increase to value of PT[N].
b. wait PT design:
Wait PT fence is signaled by reaching timeline point value, when timeline is increasing, will compare wait PTs value with new timeline value, if PT value is lower than timeline value, then wait PT will be signaled, otherwise keep in list. syncobj wait operation can wait on any point of timeline, so need a RB tree to order them. And wait PT could ahead of signal PT, we need a sumission fence to perform that.

v2:
1. remove unused DRM_SYNCOBJ_CREATE_TYPE_NORMAL. (Christian)
2. move unexposed denitions to .c file. (Daniel Vetter)
3. split up the change to drm_syncobj_find_fence() in a separate patch. (Christian)
4. split up the change to drm_syncobj_replace_fence() in a separate patch.
5. drop the submission_fence implementation and instead use wait_event() for that. (Christian)
6. WARN_ON(point != 0) for NORMAL type syncobj case. (Daniel Vetter)

v3:
1. replace normal syncobj with timeline implemenation. (Vetter and Christian)
a. normal syncobj signal op will create a signal PT to tail of signal pt list.
b. normal syncobj wait op will create a wait pt with last signal point, and this wait PT is only signaled by related signal point PT.
2. many bug fix and clean up
3. stub fence moving is moved to other patch.

v4:
1. fix RB tree loop with while(node=rb_first(...)). (Christian)
2. fix syncobj lifecycle. (Christian)
3. only enable_signaling when there is wait_pt. (Christian)
4. fix timeline path issues.
5. write a timeline test in libdrm

v5: (Christian)
1. semaphore is called syncobj in kernel side.
2. don't need 'timeline' characters in some function name.
3. keep syncobj cb.

v6: (Christian)
1. merge syncobj_timeline to syncobj structure.
2. simplify some check sentences.
3. some misc change.
4. fix CTS failed issue.

v7: (Christian)
1. error handling when creating signal pt.
2. remove timeline naming in func.
3. export flags in find_fence.
4. allow reset timeline.

Quoted 8 lines
Quoted 6 lines

v8:
1. use wait_event_interruptible without timeout
2. rename _TYPE_INDIVIDUAL to _TYPE_BINARY

individual syncobj is tested by ./deqp-vk -n dEQP-VK*semaphore* timeline syncobj is tested by ./amdgpu_test -s 9

Can we please have these low-level syncobj tests as part of igt, together with all the other syncobj tests which are there already?

Good suggestion first, I'm just not familiar with igt( build, run cmd...), maybe we can add it later.

Quoted 33 lines

Really doesn't
make much sense imo to splits things on the test suite front.

Quoted 31 lines
Cc Christian Konig <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Daniel Rakos <[email protected]>
Cc Daniel Vetter <[email protected]>
---
  drivers/gpu/drm/drm_syncobj.c              | 287 ++++++++++++++++++---
  drivers/gpu/drm/i915/i915_gem_execbuffer.c |   2 +-
  include/drm/drm_syncobj.h                  |  65 ++---
  include/uapi/drm/drm.h                     |   1 +
  4 files changed, 281 insertions(+), 74 deletions(-)
drivers/gpu/drm/drm_syncobj.c +3 -0
index f796c9fc3858..67472bd77c83 100644
@@ -56,6 +56,9 @@
  #include "drm_internal.h"
  #include <drm/drm_syncobj.h>
 
+/* merge normal syncobj to timeline syncobj, the point interval is 1 */
+#define DRM_SYNCOBJ_BINARY_POINT 1
+
  struct drm_syncobj_stub_fence {
     struct dma_fence base;
     spinlock_t lock;
@@ -82,6 +85,11 @@ static const struct dma_fence_ops drm_syncobj_stub_fence_ops = {
     .release = drm_syncobj_stub_fence_release,
  };
 
Quoted 4 lines

drivers/gpu/drm/drm_syncobj.c static const struct dma_fence_ops drm_syncobj_stub_fence_ops = { · line 89

Quoted 2 lines
drivers/gpu/drm/drm_syncobj.c +2 -0
+struct drm_syncobj_signal_pt {
+    struct dma_fence_array *base;

Out of curiosity, why the pointer and not embedding? base is kinda misleading for a pointer.

Yeah, Christian doesn't like signal_pt lifecycle same as fence, so it's a pointer.
If you don't like 'base' name, I can change it.

Quoted 260 lines
Quoted 260 lines
drivers/gpu/drm/drm_syncobj.c +196 -22
+    u64    value;
+    struct list_head list;
+};
 
  /**
   * drm_syncobj_find - lookup and reference a sync object.
@@ -124,8 +132,8 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
  {
     int ret;
 
-    *fence = drm_syncobj_fence_get(syncobj);
-    if (*fence)
+    ret = drm_syncobj_search_fence(syncobj, 0, 0, fence);
+    if (!ret)
             return 1;
 
     spin_lock(&syncobj->lock);
@@ -133,10 +141,12 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
      * have the lock, try one more time just to be sure we don't add a
      * callback when a fence has already been set.
      */
-    if (syncobj->fence) {
-            *fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
-                                                             lockdep_is_held(&syncobj->lock)));
-            ret = 1;
+    if (!list_empty(&syncobj->signal_pt_list)) {
+            spin_unlock(&syncobj->lock);
+            drm_syncobj_search_fence(syncobj, 0, 0, fence);
+            if (*fence)
+                    return 1;
+            spin_lock(&syncobj->lock);
     } else {
             *fence = NULL;
             drm_syncobj_add_callback_locked(syncobj, cb, func);
@@ -164,6 +174,159 @@ void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
     spin_unlock(&syncobj->lock);
  }
 
+static void drm_syncobj_init(struct drm_syncobj *syncobj)
+{
+    spin_lock(&syncobj->lock);
+    syncobj->timeline_context = dma_fence_context_alloc(1);
+    syncobj->timeline = 0;
+    syncobj->signal_point = 0;
+    init_waitqueue_head(&syncobj->wq);
+
+    INIT_LIST_HEAD(&syncobj->signal_pt_list);
+    spin_unlock(&syncobj->lock);
+}
+
+static void drm_syncobj_fini(struct drm_syncobj *syncobj)
+{
+    struct drm_syncobj_signal_pt *signal_pt = NULL, *tmp;
+
+    spin_lock(&syncobj->lock);
+    list_for_each_entry_safe(signal_pt, tmp,
+                             &syncobj->signal_pt_list, list) {
+            list_del(&signal_pt->list);
+            dma_fence_put(&signal_pt->base->base);
+            kfree(signal_pt);
+    }
+    spin_unlock(&syncobj->lock);
+}
+
+static struct dma_fence
+*drm_syncobj_find_signal_pt_for_point(struct drm_syncobj *syncobj,
+                                  uint64_t point)
+{
+    struct drm_syncobj_signal_pt *signal_pt;
+
+    if ((syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) &&
+        (point <= syncobj->timeline)) {
+            struct drm_syncobj_stub_fence *fence =
+                    kzalloc(sizeof(struct drm_syncobj_stub_fence),
+                            GFP_KERNEL);
+
+            if (!fence)
+                    return NULL;
+            spin_lock_init(&fence->lock);
+            dma_fence_init(&fence->base,
+                           &drm_syncobj_stub_fence_ops,
+                           &fence->lock,
+                           syncobj->timeline_context,
+                           point);
+
+            dma_fence_signal(&fence->base);
+            return &fence->base;
+    }
+
+    list_for_each_entry(signal_pt, &syncobj->signal_pt_list, list) {
+            if (point > signal_pt->value)
+                    continue;
+            if ((syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) &&
+                (point != signal_pt->value))
+                    continue;
+            return dma_fence_get(&signal_pt->base->base);
+    }
+    return NULL;
+}
+
+static int drm_syncobj_create_signal_pt(struct drm_syncobj *syncobj,
+                                    struct dma_fence *fence,
+                                    u64 point)
+{
+    struct drm_syncobj_signal_pt *signal_pt =
+            kzalloc(sizeof(struct drm_syncobj_signal_pt), GFP_KERNEL);
+    struct drm_syncobj_signal_pt *tail_pt;
+    struct dma_fence **fences;
+    int num_fences = 0;
+    int ret = 0, i;
+
+    if (!signal_pt)
+            return -ENOMEM;
+    if (!fence)
+            goto out;
+
+    fences = kmalloc_array(sizeof(void *), 2, GFP_KERNEL);
+    if (!fences) {
+            ret = -ENOMEM;
+            goto out;
+    }
+    fences[num_fences++] = dma_fence_get(fence);
+    /* timeline syncobj must take this dependency */
+    if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) {
+            spin_lock(&syncobj->lock);
+            if (!list_empty(&syncobj->signal_pt_list)) {
+                    tail_pt = list_last_entry(&syncobj->signal_pt_list,
+                                              struct drm_syncobj_signal_pt, list);
+                    fences[num_fences++] = dma_fence_get(&tail_pt->base->base);
+            }
+            spin_unlock(&syncobj->lock);
+    }
+    signal_pt->base = dma_fence_array_create(num_fences, fences,
+                                             syncobj->timeline_context,
+                                             point, false);
+    if (!signal_pt->base) {
+            ret = -ENOMEM;
+            goto fail;
+    }
+
+    spin_lock(&syncobj->lock);
+    if (syncobj->signal_point >= point) {
+            DRM_WARN("A later signal is ready!");
+            spin_unlock(&syncobj->lock);
+            goto exist;
+    }
+    signal_pt->value = point;
+    list_add_tail(&signal_pt->list, &syncobj->signal_pt_list);
+    syncobj->signal_point = point;
+    spin_unlock(&syncobj->lock);
+    wake_up_all(&syncobj->wq);
+
+    return 0;
+exist:
+    dma_fence_put(&signal_pt->base->base);
+fail:
+    for (i = 0; i < num_fences; i++)
+            dma_fence_put(fences[i]);
+    kfree(fences);
+out:
+    kfree(signal_pt);
+    return ret;
+}
+
+static void drm_syncobj_garbage_collection(struct drm_syncobj *syncobj)
+{
+    struct drm_syncobj_signal_pt *signal_pt, *tmp, *tail_pt;
+
+    spin_lock(&syncobj->lock);
+    tail_pt = list_last_entry(&syncobj->signal_pt_list,
+                              struct drm_syncobj_signal_pt,
+                              list);
+    list_for_each_entry_safe(signal_pt, tmp,
+                             &syncobj->signal_pt_list, list) {
+            if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY &&
+                signal_pt == tail_pt)
+                    continue;
+            if (dma_fence_is_signaled(&signal_pt->base->base)) {
+                    syncobj->timeline = signal_pt->value;
+                    list_del(&signal_pt->list);
+                    dma_fence_put(&signal_pt->base->base);
+                    kfree(signal_pt);
+            } else {
+                    /*signal_pt is in order in list, from small to big, so
+                     * the later must not be signal either */
+                    break;
+            }
+    }
+
+    spin_unlock(&syncobj->lock);
+}
  /**
   * drm_syncobj_replace_fence - replace fence in a sync object.
   * @syncobj: Sync object to replace fence in
@@ -176,28 +339,29 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
                            u64 point,
                            struct dma_fence *fence)
  {
-    struct dma_fence *old_fence;
-    struct drm_syncobj_cb *cur, *tmp;
-
-    if (fence)
-            dma_fence_get(fence);
-
-    spin_lock(&syncobj->lock);
-
-    old_fence = rcu_dereference_protected(syncobj->fence,
-                                          lockdep_is_held(&syncobj->lock));
-    rcu_assign_pointer(syncobj->fence, fence);
+    u64 pt_value = point;
+
+    drm_syncobj_garbage_collection(syncobj);
+    if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
+            if (!fence) {
+                    drm_syncobj_fini(syncobj);
+                    drm_syncobj_init(syncobj);
+                    return;
+            }
+            pt_value = syncobj->signal_point +
+                    DRM_SYNCOBJ_BINARY_POINT;
+    }
+    drm_syncobj_create_signal_pt(syncobj, fence, pt_value);
+    if (fence) {
+            struct drm_syncobj_cb *cur, *tmp;
 
-    if (fence != old_fence) {
+            spin_lock(&syncobj->lock);
             list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) {
                     list_del_init(&cur->node);
                     cur->func(syncobj, cur);
             }
+            spin_unlock(&syncobj->lock);
     }
-
-    spin_unlock(&syncobj->lock);
-
-    dma_fence_put(old_fence);
  }
  EXPORT_SYMBOL(drm_syncobj_replace_fence);
 
@@ -220,6 +384,46 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
     return 0;
  }
 
+static int
+drm_syncobj_point_get(struct drm_syncobj *syncobj, u64 point, u64 flags,
+                  struct dma_fence **fence)
+{
+    int ret = 0;
+
+    if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
+            ret = wait_event_interruptible(syncobj->wq,
+                                           point <= syncobj->signal_point);
+            if (ret < 0)
+                    return ret;
+    }
+    spin_lock(&syncobj->lock);
+    *fence = drm_syncobj_find_signal_pt_for_point(syncobj, point);
+    if (!*fence)
Quoted 8 lines

drivers/gpu/drm/drm_syncobj.c static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) · line 408

Quoted 7 lines
drivers/gpu/drm/drm_syncobj.c +7 -0
+            ret = -EINVAL;
+    spin_unlock(&syncobj->lock);
+    return ret;
+}
+
+int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point,
+                         u64 flags, struct dma_fence **fence)

Kerneldoc is missing for this one here.

Quoted 1 line

It's almost same as drm_syncobj_find_fence, is it still necessary?

Even more reasons, if you do a few links between closely related functions :-)

Quoted 155 lines
Quoted 146 lines

I also think improving the overview comment to explain the timeline stuff, e.g. link to the vulkan extension, and some words on how it's supposed to be used (you need a submit thread and block in userspace until all future timeline points have materialized, only then you can submit to the kernel).

Quoted 140 lines
drivers/gpu/drm/drm_syncobj.c +38 -19
+{
+    u64 pt_value = point;
+
+    if (!syncobj)
+            return -ENOENT;
+
+    drm_syncobj_garbage_collection(syncobj);
+    if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
+            /*BINARY syncobj always wait on last pt */
+            pt_value = syncobj->signal_point;
+
+            if (pt_value == 0)
+                    pt_value += DRM_SYNCOBJ_BINARY_POINT;
+    }
+    return drm_syncobj_point_get(syncobj, pt_value, flags, fence);
+}
+EXPORT_SYMBOL(drm_syncobj_search_fence);
+
  /**
   * drm_syncobj_find_fence - lookup and reference the fence in a sync object
   * @file_private: drm file private pointer
@@ -228,7 +432,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
   * @fence: out parameter for the fence
   *
   * This is just a convenience function that combines drm_syncobj_find() and
- * drm_syncobj_fence_get().
+ * drm_syncobj_lookup_fence().
   *
   * Returns 0 on success or a negative error value on failure. On success @fence
   * contains a reference to the fence, which must be released by calling
@@ -239,15 +443,9 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
                        struct dma_fence **fence)
  {
     struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
-    int ret = 0;
-
-    if (!syncobj)
-            return -ENOENT;
+    int ret;
 
-    *fence = drm_syncobj_fence_get(syncobj);
-    if (!*fence) {
-            ret = -EINVAL;
-    }
+    ret = drm_syncobj_search_fence(syncobj, point, flags, fence);
     drm_syncobj_put(syncobj);
     return ret;
  }
@@ -264,7 +462,7 @@ void drm_syncobj_free(struct kref *kref)
     struct drm_syncobj *syncobj = container_of(kref,
                                                struct drm_syncobj,
                                                refcount);
-    drm_syncobj_replace_fence(syncobj, 0, NULL);
+    drm_syncobj_fini(syncobj);
     kfree(syncobj);
  }
  EXPORT_SYMBOL(drm_syncobj_free);
@@ -294,6 +492,11 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
     kref_init(&syncobj->refcount);
     INIT_LIST_HEAD(&syncobj->cb_list);
     spin_lock_init(&syncobj->lock);
+    if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE)
+            syncobj->type = DRM_SYNCOBJ_TYPE_TIMELINE;
+    else
+            syncobj->type = DRM_SYNCOBJ_TYPE_BINARY;
+    drm_syncobj_init(syncobj);
 
     if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
             ret = drm_syncobj_assign_null_handle(syncobj);
@@ -576,7 +779,8 @@ drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
             return -ENODEV;
 
     /* no valid flags yet */
-    if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
+    if (args->flags & ~(DRM_SYNCOBJ_CREATE_SIGNALED |
+                        DRM_SYNCOBJ_CREATE_TYPE_TIMELINE))
             return -EINVAL;
 
     return drm_syncobj_create_as_handle(file_private,
@@ -669,9 +873,8 @@ static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
     struct syncobj_wait_entry *wait =
             container_of(cb, struct syncobj_wait_entry, syncobj_cb);
 
-    /* This happens inside the syncobj lock */
-    wait->fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
-                                                          lockdep_is_held(&syncobj->lock)));
+    drm_syncobj_search_fence(syncobj, 0, 0, &wait->fence);
+
     wake_up_process(wait->task);
  }
 
@@ -698,7 +901,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
     signaled_count = 0;
     for (i = 0; i < count; ++i) {
             entries[i].task = current;
-            entries[i].fence = drm_syncobj_fence_get(syncobjs[i]);
+            ret = drm_syncobj_search_fence(syncobjs[i], 0, 0,
+                                           &entries[i].fence);
             if (!entries[i].fence) {
                     if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
                             continue;
@@ -970,12 +1174,13 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
     if (ret < 0)
             return ret;
 
-    for (i = 0; i < args->count_handles; i++)
-            drm_syncobj_replace_fence(syncobjs[i], 0, NULL);
-
+    for (i = 0; i < args->count_handles; i++) {
+            drm_syncobj_fini(syncobjs[i]);
+            drm_syncobj_init(syncobjs[i]);
+    }
     drm_syncobj_array_free(syncobjs, args->count_handles);
 
-    return 0;
+    return ret;
  }
 
  int
drivers/gpu/drm/i915/i915_gem_execbuffer.c +1 -1
index 0a8d2d64f380..8a8d21b24119 100644
@@ -2137,7 +2137,7 @@ await_fence_array(struct i915_execbuffer *eb,
             if (!(flags & I915_EXEC_FENCE_WAIT))
                     continue;
 
-            fence = drm_syncobj_fence_get(syncobj);
+            drm_syncobj_search_fence(syncobj, 0, 0, &fence);
             if (!fence)
                     return -EINVAL;
 
include/drm/drm_syncobj.h +0 -0
index 2eda44def639..85b36d4e53ee 100644
@@ -30,6 +30,11 @@
 
  struct drm_syncobj_cb;
 
Quoted 9 lines

include/drm/drm_syncobj.h line 40

Quoted 8 lines
include/drm/drm_syncobj.h +5 -0
+enum drm_syncobj_type {
+    DRM_SYNCOBJ_TYPE_BINARY,
+    DRM_SYNCOBJ_TYPE_TIMELINE
+};
+
  /**
   * struct drm_syncobj - sync object.
   *

The kerneldoc for this also isn't accurate anymore.

Quoted 1 line

Can kerneldoc be a separate patch?

You already update the kerneldoc, but not completely in this patch. That doesn't make sense to split up.

Quoted 9 lines
Quoted 3 lines

With the kernel-doc polished:

Thanks at least.

Quoted 3 lines

But I think we definitely want a full ack for the uapi from radv/anv guys (plus the userspace for either of those).

Dave and Bas are right people, right?

For radv yes, for anv we want Jason Ekstrand I think. -Daniel

Quoted 113 lines

Thanks,
David

Quoted 109 lines

-Daniel

Quoted 107 lines
include/drm/drm_syncobj.h +28 -32
@@ -41,19 +46,36 @@ struct drm_syncobj {
      */
     struct kref refcount;
     /**
-     * @fence:
-     * NULL or a pointer to the fence bound to this object.
-     *
-     * This field should not be used directly. Use drm_syncobj_fence_get()
-     * and drm_syncobj_replace_fence() instead.
+     * @type: indicate syncobj type
+     */
+    enum drm_syncobj_type type;
+    /**
+     * @wq: wait signal operation work queue
+     */
+    wait_queue_head_t       wq;
+    /**
+     * @timeline_context: fence context used by timeline
      */
-    struct dma_fence __rcu *fence;
+    u64 timeline_context;
     /**
-     * @cb_list: List of callbacks to call when the &fence gets replaced.
+     * @timeline: syncobj timeline value, which indicates point is signaled.
      */
+    u64 timeline;
+    /**
+     * @signal_point: which indicates the latest signaler point.
+     */
+    u64 signal_point;
+    /**
+     * @signal_pt_list: signaler point list.
+     */
+    struct list_head signal_pt_list;
+
+    /**
+         * @cb_list: List of callbacks to call when the &fence gets replaced.
+         */
     struct list_head cb_list;
     /**
-     * @lock: Protects &cb_list and write-locks &fence.
+     * @lock: Protects syncobj list and write-locks &fence.
      */
     spinlock_t lock;
     /**
@@ -68,7 +90,7 @@ typedef void (*drm_syncobj_func_t)(struct drm_syncobj *syncobj,
  /**
   * struct drm_syncobj_cb - callback for drm_syncobj_add_callback
   * @node: used by drm_syncob_add_callback to append this struct to
- *    &drm_syncobj.cb_list
+ *       &drm_syncobj.cb_list
   * @func: drm_syncobj_func_t to call
   *
   * This struct will be initialized by drm_syncobj_add_callback, additional
@@ -106,29 +128,6 @@ drm_syncobj_put(struct drm_syncobj *obj)
     kref_put(&obj->refcount, drm_syncobj_free);
  }
 
-/**
- * drm_syncobj_fence_get - get a reference to a fence in a sync object
- * @syncobj: sync object.
- *
- * This acquires additional reference to &drm_syncobj.fence contained in @obj,
- * if not NULL. It is illegal to call this without already holding a reference.
- * No locks required.
- *
- * Returns:
- * Either the fence of @obj or NULL if there's none.
- */
-static inline struct dma_fence *
-drm_syncobj_fence_get(struct drm_syncobj *syncobj)
-{
-    struct dma_fence *fence;
-
-    rcu_read_lock();
-    fence = dma_fence_get_rcu_safe(&syncobj->fence);
-    rcu_read_unlock();
-
-    return fence;
-}
-
  struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
                                  u32 handle);
  void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point,
@@ -142,5 +141,7 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
  int drm_syncobj_get_handle(struct drm_file *file_private,
                        struct drm_syncobj *syncobj, u32 *handle);
  int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd);
+int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point, u64 flags,
+                         struct dma_fence **fence);
 
  #endif
include/uapi/drm/drm.h +1 -1
index 300f336633f2..cebdb2541eb7 100644
@@ -717,6 +717,7 @@ struct drm_prime_handle {
  struct drm_syncobj_create {
     __u32 handle;
  #define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0)
+#define DRM_SYNCOBJ_CREATE_TYPE_TIMELINE (1 << 1)
     __u32 flags;
  };
 
--

2.17.1

Signature · 7 lines
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

A message that is not in the archive (sent off-list or not yet received): CAKMK7uEEKpzjdON-qOstM67OYfDjHc5gS0+kSpuh1pm5t4BAHA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#23 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

+Jason as well.

Quoted 669 lines · Daniel Vetter
Quoted 387 lines · On Wed, Oct 17, 2018 at 11:17 AM zhoucm1 <[email protected]> wrote:
Quoted 65 lines · Daniel Vetter
Quoted 64 lines · Chunming Zhou

This patch is for VK_KHR_timeline_semaphore extension, semaphore is called syncobj in kernel side:
This extension introduces a new type of syncobj that has an integer payload identifying a point in a timeline. Such timeline syncobjs support the
following operations:
* CPU query - A host operation that allows querying the payload of the timeline syncobj.
* CPU wait - A host operation that allows a blocking wait for a
timeline syncobj to reach a specified value.
* Device wait - A device operation that allows waiting for a
timeline syncobj to reach a specified value.
* Device signal - A device operation that allows advancing the
timeline syncobj to a specified value.

v1:
Since it's a timeline, that means the front time point(PT) always is signaled before the late PT. a. signal PT design:
Signal PT fence N depends on PT[N-1] fence and signal opertion fence, when PT[N] fence is signaled, the timeline will increase to value of PT[N].
b. wait PT design:
Wait PT fence is signaled by reaching timeline point value, when timeline is increasing, will compare wait PTs value with new timeline value, if PT value is lower than timeline value, then wait PT will be signaled, otherwise keep in list. syncobj wait operation can wait on any point of timeline, so need a RB tree to order them. And wait PT could ahead of signal PT, we need a sumission fence to perform that.

v2:
1. remove unused DRM_SYNCOBJ_CREATE_TYPE_NORMAL. (Christian)
2. move unexposed denitions to .c file. (Daniel Vetter)
3. split up the change to drm_syncobj_find_fence() in a separate patch. (Christian)
4. split up the change to drm_syncobj_replace_fence() in a separate patch.
5. drop the submission_fence implementation and instead use wait_event() for that. (Christian)
6. WARN_ON(point != 0) for NORMAL type syncobj case. (Daniel Vetter)

v3:
1. replace normal syncobj with timeline implemenation. (Vetter and Christian)
a. normal syncobj signal op will create a signal PT to tail of signal pt list.
b. normal syncobj wait op will create a wait pt with last signal point, and this wait PT is only signaled by related signal point PT.
2. many bug fix and clean up
3. stub fence moving is moved to other patch.

v4:
1. fix RB tree loop with while(node=rb_first(...)). (Christian)
2. fix syncobj lifecycle. (Christian)
3. only enable_signaling when there is wait_pt. (Christian)
4. fix timeline path issues.
5. write a timeline test in libdrm

v5: (Christian)
1. semaphore is called syncobj in kernel side.
2. don't need 'timeline' characters in some function name.
3. keep syncobj cb.

v6: (Christian)
1. merge syncobj_timeline to syncobj structure.
2. simplify some check sentences.
3. some misc change.
4. fix CTS failed issue.

v7: (Christian)
1. error handling when creating signal pt.
2. remove timeline naming in func.
3. export flags in find_fence.
4. allow reset timeline.

Quoted 8 lines
Quoted 6 lines

v8:
1. use wait_event_interruptible without timeout
2. rename _TYPE_INDIVIDUAL to _TYPE_BINARY

individual syncobj is tested by ./deqp-vk -n dEQP-VK*semaphore* timeline syncobj is tested by ./amdgpu_test -s 9

Can we please have these low-level syncobj tests as part of igt, together with all the other syncobj tests which are there already?

Good suggestion first, I'm just not familiar with igt( build, run cmd...), maybe we can add it later.

Quoted 33 lines

Really doesn't
make much sense imo to splits things on the test suite front.

Quoted 31 lines
Cc Christian Konig <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Daniel Rakos <[email protected]>
Cc Daniel Vetter <[email protected]>
---
   drivers/gpu/drm/drm_syncobj.c              | 287 ++++++++++++++++++---
   drivers/gpu/drm/i915/i915_gem_execbuffer.c |   2 +-
   include/drm/drm_syncobj.h                  |  65 ++---
   include/uapi/drm/drm.h                     |   1 +
   4 files changed, 281 insertions(+), 74 deletions(-)
drivers/gpu/drm/drm_syncobj.c +3 -0
index f796c9fc3858..67472bd77c83 100644
@@ -56,6 +56,9 @@
   #include "drm_internal.h"
   #include <drm/drm_syncobj.h>
 
+/* merge normal syncobj to timeline syncobj, the point interval is 1 */
+#define DRM_SYNCOBJ_BINARY_POINT 1
+
   struct drm_syncobj_stub_fence {
      struct dma_fence base;
      spinlock_t lock;
@@ -82,6 +85,11 @@ static const struct dma_fence_ops drm_syncobj_stub_fence_ops = {
      .release = drm_syncobj_stub_fence_release,
   };
 
Quoted 4 lines

drivers/gpu/drm/drm_syncobj.c static const struct dma_fence_ops drm_syncobj_stub_fence_ops = { · line 89

Quoted 2 lines
drivers/gpu/drm/drm_syncobj.c +2 -0
+struct drm_syncobj_signal_pt {
+    struct dma_fence_array *base;

Out of curiosity, why the pointer and not embedding? base is kinda misleading for a pointer.

Yeah, Christian doesn't like signal_pt lifecycle same as fence, so it's a pointer.
If you don't like 'base' name, I can change it.

Quoted 259 lines
Quoted 259 lines
drivers/gpu/drm/drm_syncobj.c +196 -22
+    u64    value;
+    struct list_head list;
+};
 
   /**
    * drm_syncobj_find - lookup and reference a sync object.
@@ -124,8 +132,8 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
   {
      int ret;
 
-    *fence = drm_syncobj_fence_get(syncobj);
-    if (*fence)
+    ret = drm_syncobj_search_fence(syncobj, 0, 0, fence);
+    if (!ret)
              return 1;
 
      spin_lock(&syncobj->lock);
@@ -133,10 +141,12 @@ static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
       * have the lock, try one more time just to be sure we don't add a
       * callback when a fence has already been set.
       */
-    if (syncobj->fence) {
-            *fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
-                                                             lockdep_is_held(&syncobj->lock)));
-            ret = 1;
+    if (!list_empty(&syncobj->signal_pt_list)) {
+            spin_unlock(&syncobj->lock);
+            drm_syncobj_search_fence(syncobj, 0, 0, fence);
+            if (*fence)
+                    return 1;
+            spin_lock(&syncobj->lock);
      } else {
              *fence = NULL;
              drm_syncobj_add_callback_locked(syncobj, cb, func);
@@ -164,6 +174,159 @@ void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
      spin_unlock(&syncobj->lock);
   }
 
+static void drm_syncobj_init(struct drm_syncobj *syncobj)
+{
+    spin_lock(&syncobj->lock);
+    syncobj->timeline_context = dma_fence_context_alloc(1);
+    syncobj->timeline = 0;
+    syncobj->signal_point = 0;
+    init_waitqueue_head(&syncobj->wq);
+
+    INIT_LIST_HEAD(&syncobj->signal_pt_list);
+    spin_unlock(&syncobj->lock);
+}
+
+static void drm_syncobj_fini(struct drm_syncobj *syncobj)
+{
+    struct drm_syncobj_signal_pt *signal_pt = NULL, *tmp;
+
+    spin_lock(&syncobj->lock);
+    list_for_each_entry_safe(signal_pt, tmp,
+                             &syncobj->signal_pt_list, list) {
+            list_del(&signal_pt->list);
+            dma_fence_put(&signal_pt->base->base);
+            kfree(signal_pt);
+    }
+    spin_unlock(&syncobj->lock);
+}
+
+static struct dma_fence
+*drm_syncobj_find_signal_pt_for_point(struct drm_syncobj *syncobj,
+                                  uint64_t point)
+{
+    struct drm_syncobj_signal_pt *signal_pt;
+
+    if ((syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) &&
+        (point <= syncobj->timeline)) {
+            struct drm_syncobj_stub_fence *fence =
+                    kzalloc(sizeof(struct drm_syncobj_stub_fence),
+                            GFP_KERNEL);
+
+            if (!fence)
+                    return NULL;
+            spin_lock_init(&fence->lock);
+            dma_fence_init(&fence->base,
+                           &drm_syncobj_stub_fence_ops,
+                           &fence->lock,
+                           syncobj->timeline_context,
+                           point);
+
+            dma_fence_signal(&fence->base);
+            return &fence->base;
+    }
+
+    list_for_each_entry(signal_pt, &syncobj->signal_pt_list, list) {
+            if (point > signal_pt->value)
+                    continue;
+            if ((syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) &&
+                (point != signal_pt->value))
+                    continue;
+            return dma_fence_get(&signal_pt->base->base);
+    }
+    return NULL;
+}
+
+static int drm_syncobj_create_signal_pt(struct drm_syncobj *syncobj,
+                                    struct dma_fence *fence,
+                                    u64 point)
+{
+    struct drm_syncobj_signal_pt *signal_pt =
+            kzalloc(sizeof(struct drm_syncobj_signal_pt), GFP_KERNEL);
+    struct drm_syncobj_signal_pt *tail_pt;
+    struct dma_fence **fences;
+    int num_fences = 0;
+    int ret = 0, i;
+
+    if (!signal_pt)
+            return -ENOMEM;
+    if (!fence)
+            goto out;
+
+    fences = kmalloc_array(sizeof(void *), 2, GFP_KERNEL);
+    if (!fences) {
+            ret = -ENOMEM;
+            goto out;
+    }
+    fences[num_fences++] = dma_fence_get(fence);
+    /* timeline syncobj must take this dependency */
+    if (syncobj->type == DRM_SYNCOBJ_TYPE_TIMELINE) {
+            spin_lock(&syncobj->lock);
+            if (!list_empty(&syncobj->signal_pt_list)) {
+                    tail_pt = list_last_entry(&syncobj->signal_pt_list,
+                                              struct drm_syncobj_signal_pt, list);
+                    fences[num_fences++] = dma_fence_get(&tail_pt->base->base);
+            }
+            spin_unlock(&syncobj->lock);
+    }
+    signal_pt->base = dma_fence_array_create(num_fences, fences,
+                                             syncobj->timeline_context,
+                                             point, false);
+    if (!signal_pt->base) {
+            ret = -ENOMEM;
+            goto fail;
+    }
+
+    spin_lock(&syncobj->lock);
+    if (syncobj->signal_point >= point) {
+            DRM_WARN("A later signal is ready!");
+            spin_unlock(&syncobj->lock);
+            goto exist;
+    }
+    signal_pt->value = point;
+    list_add_tail(&signal_pt->list, &syncobj->signal_pt_list);
+    syncobj->signal_point = point;
+    spin_unlock(&syncobj->lock);
+    wake_up_all(&syncobj->wq);
+
+    return 0;
+exist:
+    dma_fence_put(&signal_pt->base->base);
+fail:
+    for (i = 0; i < num_fences; i++)
+            dma_fence_put(fences[i]);
+    kfree(fences);
+out:
+    kfree(signal_pt);
+    return ret;
+}
+
+static void drm_syncobj_garbage_collection(struct drm_syncobj *syncobj)
+{
+    struct drm_syncobj_signal_pt *signal_pt, *tmp, *tail_pt;
+
+    spin_lock(&syncobj->lock);
+    tail_pt = list_last_entry(&syncobj->signal_pt_list,
+                              struct drm_syncobj_signal_pt,
+                              list);
+    list_for_each_entry_safe(signal_pt, tmp,
+                             &syncobj->signal_pt_list, list) {
+            if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY &&
+                signal_pt == tail_pt)
+                    continue;
+            if (dma_fence_is_signaled(&signal_pt->base->base)) {
+                    syncobj->timeline = signal_pt->value;
+                    list_del(&signal_pt->list);
+                    dma_fence_put(&signal_pt->base->base);
+                    kfree(signal_pt);
+            } else {
+                    /*signal_pt is in order in list, from small to big, so
+                     * the later must not be signal either */
+                    break;
+            }
+    }
+
+    spin_unlock(&syncobj->lock);
+}
   /**
    * drm_syncobj_replace_fence - replace fence in a sync object.
    * @syncobj: Sync object to replace fence in
@@ -176,28 +339,29 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
                             u64 point,
                             struct dma_fence *fence)
   {
-    struct dma_fence *old_fence;
-    struct drm_syncobj_cb *cur, *tmp;
-
-    if (fence)
-            dma_fence_get(fence);
-
-    spin_lock(&syncobj->lock);
-
-    old_fence = rcu_dereference_protected(syncobj->fence,
-                                          lockdep_is_held(&syncobj->lock));
-    rcu_assign_pointer(syncobj->fence, fence);
+    u64 pt_value = point;
+
+    drm_syncobj_garbage_collection(syncobj);
+    if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
+            if (!fence) {
+                    drm_syncobj_fini(syncobj);
+                    drm_syncobj_init(syncobj);
+                    return;
+            }
+            pt_value = syncobj->signal_point +
+                    DRM_SYNCOBJ_BINARY_POINT;
+    }
+    drm_syncobj_create_signal_pt(syncobj, fence, pt_value);
+    if (fence) {
+            struct drm_syncobj_cb *cur, *tmp;
 
-    if (fence != old_fence) {
+            spin_lock(&syncobj->lock);
              list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) {
                      list_del_init(&cur->node);
                      cur->func(syncobj, cur);
              }
+            spin_unlock(&syncobj->lock);
      }
-
-    spin_unlock(&syncobj->lock);
-
-    dma_fence_put(old_fence);
   }
   EXPORT_SYMBOL(drm_syncobj_replace_fence);
 
@@ -220,6 +384,46 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
      return 0;
   }
 
+static int
+drm_syncobj_point_get(struct drm_syncobj *syncobj, u64 point, u64 flags,
+                  struct dma_fence **fence)
+{
+    int ret = 0;
+
+    if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
+            ret = wait_event_interruptible(syncobj->wq,
+                                           point <= syncobj->signal_point);
+            if (ret < 0)
+                    return ret;
+    }
+    spin_lock(&syncobj->lock);
+    *fence = drm_syncobj_find_signal_pt_for_point(syncobj, point);
+    if (!*fence)
Quoted 8 lines

drivers/gpu/drm/drm_syncobj.c static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj) · line 408

Quoted 7 lines
drivers/gpu/drm/drm_syncobj.c +7 -0
+            ret = -EINVAL;
+    spin_unlock(&syncobj->lock);
+    return ret;
+}
+
+int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point,
+                         u64 flags, struct dma_fence **fence)

Kerneldoc is missing for this one here.

Quoted 1 line

It's almost same as drm_syncobj_find_fence, is it still necessary?

Even more reasons, if you do a few links between closely related functions :-)

Quoted 155 lines
Quoted 146 lines

I also think improving the overview comment to explain the timeline stuff, e.g. link to the vulkan extension, and some words on how it's supposed to be used (you need a submit thread and block in userspace until all future timeline points have materialized, only then you can submit to the kernel).

Quoted 140 lines
drivers/gpu/drm/drm_syncobj.c +38 -19
+{
+    u64 pt_value = point;
+
+    if (!syncobj)
+            return -ENOENT;
+
+    drm_syncobj_garbage_collection(syncobj);
+    if (syncobj->type == DRM_SYNCOBJ_TYPE_BINARY) {
+            /*BINARY syncobj always wait on last pt */
+            pt_value = syncobj->signal_point;
+
+            if (pt_value == 0)
+                    pt_value += DRM_SYNCOBJ_BINARY_POINT;
+    }
+    return drm_syncobj_point_get(syncobj, pt_value, flags, fence);
+}
+EXPORT_SYMBOL(drm_syncobj_search_fence);
+
   /**
    * drm_syncobj_find_fence - lookup and reference the fence in a sync object
    * @file_private: drm file private pointer
@@ -228,7 +432,7 @@ static int drm_syncobj_assign_null_handle(struct drm_syncobj *syncobj)
    * @fence: out parameter for the fence
    *
    * This is just a convenience function that combines drm_syncobj_find() and
- * drm_syncobj_fence_get().
+ * drm_syncobj_lookup_fence().
    *
    * Returns 0 on success or a negative error value on failure. On success @fence
    * contains a reference to the fence, which must be released by calling
@@ -239,15 +443,9 @@ int drm_syncobj_find_fence(struct drm_file *file_private,
                         struct dma_fence **fence)
   {
      struct drm_syncobj *syncobj = drm_syncobj_find(file_private, handle);
-    int ret = 0;
-
-    if (!syncobj)
-            return -ENOENT;
+    int ret;
 
-    *fence = drm_syncobj_fence_get(syncobj);
-    if (!*fence) {
-            ret = -EINVAL;
-    }
+    ret = drm_syncobj_search_fence(syncobj, point, flags, fence);
      drm_syncobj_put(syncobj);
      return ret;
   }
@@ -264,7 +462,7 @@ void drm_syncobj_free(struct kref *kref)
      struct drm_syncobj *syncobj = container_of(kref,
                                                 struct drm_syncobj,
                                                 refcount);
-    drm_syncobj_replace_fence(syncobj, 0, NULL);
+    drm_syncobj_fini(syncobj);
      kfree(syncobj);
   }
   EXPORT_SYMBOL(drm_syncobj_free);
@@ -294,6 +492,11 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
      kref_init(&syncobj->refcount);
      INIT_LIST_HEAD(&syncobj->cb_list);
      spin_lock_init(&syncobj->lock);
+    if (flags & DRM_SYNCOBJ_CREATE_TYPE_TIMELINE)
+            syncobj->type = DRM_SYNCOBJ_TYPE_TIMELINE;
+    else
+            syncobj->type = DRM_SYNCOBJ_TYPE_BINARY;
+    drm_syncobj_init(syncobj);
 
      if (flags & DRM_SYNCOBJ_CREATE_SIGNALED) {
              ret = drm_syncobj_assign_null_handle(syncobj);
@@ -576,7 +779,8 @@ drm_syncobj_create_ioctl(struct drm_device *dev, void *data,
              return -ENODEV;
 
      /* no valid flags yet */
-    if (args->flags & ~DRM_SYNCOBJ_CREATE_SIGNALED)
+    if (args->flags & ~(DRM_SYNCOBJ_CREATE_SIGNALED |
+                        DRM_SYNCOBJ_CREATE_TYPE_TIMELINE))
              return -EINVAL;
 
      return drm_syncobj_create_as_handle(file_private,
@@ -669,9 +873,8 @@ static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
      struct syncobj_wait_entry *wait =
              container_of(cb, struct syncobj_wait_entry, syncobj_cb);
 
-    /* This happens inside the syncobj lock */
-    wait->fence = dma_fence_get(rcu_dereference_protected(syncobj->fence,
-                                                          lockdep_is_held(&syncobj->lock)));
+    drm_syncobj_search_fence(syncobj, 0, 0, &wait->fence);
+
      wake_up_process(wait->task);
   }
 
@@ -698,7 +901,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
      signaled_count = 0;
      for (i = 0; i < count; ++i) {
              entries[i].task = current;
-            entries[i].fence = drm_syncobj_fence_get(syncobjs[i]);
+            ret = drm_syncobj_search_fence(syncobjs[i], 0, 0,
+                                           &entries[i].fence);
              if (!entries[i].fence) {
                      if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
                              continue;
@@ -970,12 +1174,13 @@ drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
      if (ret < 0)
              return ret;
 
-    for (i = 0; i < args->count_handles; i++)
-            drm_syncobj_replace_fence(syncobjs[i], 0, NULL);
-
+    for (i = 0; i < args->count_handles; i++) {
+            drm_syncobj_fini(syncobjs[i]);
+            drm_syncobj_init(syncobjs[i]);
+    }
      drm_syncobj_array_free(syncobjs, args->count_handles);
 
-    return 0;
+    return ret;
   }
 
   int
drivers/gpu/drm/i915/i915_gem_execbuffer.c +1 -1
index 0a8d2d64f380..8a8d21b24119 100644
@@ -2137,7 +2137,7 @@ await_fence_array(struct i915_execbuffer *eb,
              if (!(flags & I915_EXEC_FENCE_WAIT))
                      continue;
 
-            fence = drm_syncobj_fence_get(syncobj);
+            drm_syncobj_search_fence(syncobj, 0, 0, &fence);
              if (!fence)
                      return -EINVAL;
 
include/drm/drm_syncobj.h +0 -0
index 2eda44def639..85b36d4e53ee 100644
@@ -30,6 +30,11 @@
 
   struct drm_syncobj_cb;
 
Quoted 9 lines

include/drm/drm_syncobj.h line 40

Quoted 8 lines
include/drm/drm_syncobj.h +5 -0
+enum drm_syncobj_type {
+    DRM_SYNCOBJ_TYPE_BINARY,
+    DRM_SYNCOBJ_TYPE_TIMELINE
+};
+
   /**
    * struct drm_syncobj - sync object.
    *

The kerneldoc for this also isn't accurate anymore.

Quoted 1 line

Can kerneldoc be a separate patch?

You already update the kerneldoc, but not completely in this patch. That doesn't make sense to split up.

Quoted 8 lines
Quoted 3 lines

With the kernel-doc polished:

Thanks at least.

Quoted 2 lines

But I think we definitely want a full ack for the uapi from radv/anv guys (plus the userspace for either of those).

Dave and Bas are right people, right?

For radv yes, for anv we want Jason Ekstrand I think. -Daniel

Quoted 108 lines

Thanks,
David

Quoted 106 lines

-Daniel

Quoted 104 lines
include/drm/drm_syncobj.h +28 -32
@@ -41,19 +46,36 @@ struct drm_syncobj {
       */
      struct kref refcount;
      /**
-     * @fence:
-     * NULL or a pointer to the fence bound to this object.
-     *
-     * This field should not be used directly. Use drm_syncobj_fence_get()
-     * and drm_syncobj_replace_fence() instead.
+     * @type: indicate syncobj type
+     */
+    enum drm_syncobj_type type;
+    /**
+     * @wq: wait signal operation work queue
+     */
+    wait_queue_head_t       wq;
+    /**
+     * @timeline_context: fence context used by timeline
       */
-    struct dma_fence __rcu *fence;
+    u64 timeline_context;
      /**
-     * @cb_list: List of callbacks to call when the &fence gets replaced.
+     * @timeline: syncobj timeline value, which indicates point is signaled.
       */
+    u64 timeline;
+    /**
+     * @signal_point: which indicates the latest signaler point.
+     */
+    u64 signal_point;
+    /**
+     * @signal_pt_list: signaler point list.
+     */
+    struct list_head signal_pt_list;
+
+    /**
+         * @cb_list: List of callbacks to call when the &fence gets replaced.
+         */
      struct list_head cb_list;
      /**
-     * @lock: Protects &cb_list and write-locks &fence.
+     * @lock: Protects syncobj list and write-locks &fence.
       */
      spinlock_t lock;
      /**
@@ -68,7 +90,7 @@ typedef void (*drm_syncobj_func_t)(struct drm_syncobj *syncobj,
   /**
    * struct drm_syncobj_cb - callback for drm_syncobj_add_callback
    * @node: used by drm_syncob_add_callback to append this struct to
- *    &drm_syncobj.cb_list
+ *       &drm_syncobj.cb_list
    * @func: drm_syncobj_func_t to call
    *
    * This struct will be initialized by drm_syncobj_add_callback, additional
@@ -106,29 +128,6 @@ drm_syncobj_put(struct drm_syncobj *obj)
      kref_put(&obj->refcount, drm_syncobj_free);
   }
 
-/**
- * drm_syncobj_fence_get - get a reference to a fence in a sync object
- * @syncobj: sync object.
- *
- * This acquires additional reference to &drm_syncobj.fence contained in @obj,
- * if not NULL. It is illegal to call this without already holding a reference.
- * No locks required.
- *
- * Returns:
- * Either the fence of @obj or NULL if there's none.
- */
-static inline struct dma_fence *
-drm_syncobj_fence_get(struct drm_syncobj *syncobj)
-{
-    struct dma_fence *fence;
-
-    rcu_read_lock();
-    fence = dma_fence_get_rcu_safe(&syncobj->fence);
-    rcu_read_unlock();
-
-    return fence;
-}
-
   struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
                                   u32 handle);
   void drm_syncobj_replace_fence(struct drm_syncobj *syncobj, u64 point,
@@ -142,5 +141,7 @@ int drm_syncobj_create(struct drm_syncobj **out_syncobj, uint32_t flags,
   int drm_syncobj_get_handle(struct drm_file *file_private,
                         struct drm_syncobj *syncobj, u32 *handle);
   int drm_syncobj_get_fd(struct drm_syncobj *syncobj, int *p_fd);
+int drm_syncobj_search_fence(struct drm_syncobj *syncobj, u64 point, u64 flags,
+                         struct dma_fence **fence);
 
   #endif
include/uapi/drm/drm.h +1 -0
index 300f336633f2..cebdb2541eb7 100644
@@ -717,6 +717,7 @@ struct drm_prime_handle {
   struct drm_syncobj_create {
      __u32 handle;
   #define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0)
+#define DRM_SYNCOBJ_CREATE_TYPE_TIMELINE (1 << 1)
      __u32 flags;
   };
 
Quoted 4 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

--
2.17.1

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

A message that is not in the archive (sent off-list or not yet received): [email protected]

#25 lore raw

Re: [PATCH 2/7] drm: add syncobj timeline support v8

Quoting Chunming Zhou (2018-10-15 09:55:48)

Quoted 4 lines

This patch is for VK_KHR_timeline_semaphore extension, semaphore is called syncobj in kernel side:
This extension introduces a new type of syncobj that has an integer payload identifying a point in a timeline. Such timeline syncobjs support the
following operations:

Quoted 8 lines

* CPU query - A host operation that allows querying the payload of the timeline syncobj.
* CPU wait - A host operation that allows a blocking wait for a timeline syncobj to reach a specified value.
* Device wait - A device operation that allows waiting for a timeline syncobj to reach a specified value.
* Device signal - A device operation that allows advancing the timeline syncobj to a specified value.

Spinlock recursion:

https://bugs.freedesktop.org/show_bug.cgi?id=108490
<6> [363.585915] [IGT] syncobj_wait: executing
<6> [363.646916] [IGT] syncobj_wait: starting subtest wait-for-submit-delayed-submit
<4> [363.752517]
<4> [363.752542] ============================================
<4> [363.752561] WARNING: possible recursive locking detected
<4> [363.752582] 4.19.0-rc8-CI-CI_DRM_5006+ #1 Tainted: G U
<4> [363.752602] --------------------------------------------
<4> [363.752621] syncobj_wait/2297 is trying to acquire lock:
<4> [363.752641] 0000000029228054 (&(&syncobj->lock)->rlock){+.+.}, at: drm_syncobj_garbage_collection+0x25/0x140
<4> [363.752699] \x0abut task is already holding lock:
<4> [363.752721] 0000000029228054 (&(&syncobj->lock)->rlock){+.+.}, at: drm_syncobj_replace_fence+0x1b6/0x2c0
<4> [363.752768] \x0aother info that might help us debug this:
<4> [363.752791] Possible unsafe locking scenario:\x0a
<4> [363.752812] CPU0
<4> [363.752824] ----
<4> [363.752835] lock(&(&syncobj->lock)->rlock);
<4> [363.752856] lock(&(&syncobj->lock)->rlock);
<4> [363.752877] \x0a *** DEADLOCK ***\x0a
<4> [363.752905] May be due to missing lock nesting notation\x0a
<4> [363.752932] 1 lock held by syncobj_wait/2297:
<4> [363.752949] #0: 0000000029228054 (&(&syncobj->lock)->rlock){+.+.}, at: drm_syncobj_replace_fence+0x1b6/0x2c0
<4> [363.753001] \x0astack backtrace:
<4> [363.753030] CPU: 2 PID: 2297 Comm: syncobj_wait Tainted: G U 4.19.0-rc8-CI-CI_DRM_5006+ #1
<4> [363.753060] Hardware name: Google Caroline/Caroline, BIOS MrChromebox 08/27/2018
<4> [363.753083] Call Trace:
<4> [363.753109] dump_stack+0x67/0x9b
<4> [363.753136] __lock_acquire+0xc67/0x1b50
<4> [363.753164] ? deactivate_slab.isra.26+0x7a4/0x7e0
<4> [363.753203] ? __lock_acquire+0x3c8/0x1b50
<4> [363.753242] ? __wake_up_common_lock+0x5e/0xb0
<4> [363.753285] ? lock_acquire+0xa6/0x1c0
<4> [363.753306] lock_acquire+0xa6/0x1c0
<4> [363.753334] ? drm_syncobj_garbage_collection+0x25/0x140
<4> [363.753365] _raw_spin_lock+0x2a/0x40
<4> [363.753392] ? drm_syncobj_garbage_collection+0x25/0x140
<4> [363.753419] drm_syncobj_garbage_collection+0x25/0x140
<4> [363.753450] drm_syncobj_search_fence+0x38/0x200
<4> [363.753478] ? drm_syncobj_replace_fence+0x1b6/0x2c0
<4> [363.753509] syncobj_wait_syncobj_func+0x11/0x20
<4> [363.753536] drm_syncobj_replace_fence+0x1f8/0x2c0
<4> [363.753561] ? drm_syncobj_handle_to_fd_ioctl+0x170/0x170
<4> [363.753585] drm_syncobj_fd_to_handle_ioctl+0x120/0x1d0
<4> [363.753609] ? drm_syncobj_handle_to_fd_ioctl+0x170/0x170
<4> [363.753638] drm_ioctl_kernel+0x81/0xf0
<4> [363.753665] drm_ioctl+0x2e6/0x3a0
<4> [363.753686] ? drm_syncobj_handle_to_fd_ioctl+0x170/0x170
<4> [363.753717] ? lock_acquire+0xa6/0x1c0
<4> [363.753743] do_vfs_ioctl+0xa0/0x6d0
<4> [363.753769] ? __fget+0xfc/0x1e0
<4> [363.753792] ksys_ioctl+0x35/0x60
<4> [363.753816] __x64_sys_ioctl+0x11/0x20
<4> [363.753840] do_syscall_64+0x55/0x190
<4> [363.753866] entry_SYSCALL_64_after_hwframe+0x49/0xbe
<4> [363.753890] RIP: 0033:0x7f0d84f9a5d7
<4> [363.753911] Code: b3 66 90 48 8b 05 b1 48 2d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 81 48 2d 00 f7 d8 64 89 01 48 <4> [363.753959] RSP: 002b:00007f0d79804ac8 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
<4> [363.753990] RAX: ffffffffffffffda RBX: 00007f0d74000b20 RCX: 00007f0d84f9a5d7
<4> [363.754016] RDX: 00007f0d79804b50 RSI: 00000000c01064c2 RDI: 0000000000000005
<4> [363.754040] RBP: 00007f0d79804b50 R08: 0000000000000000 R09: 000000000000001e
<4> [363.754064] R10: 0000000000000054 R11: 0000000000000246 R12: 00000000c01064c2
<4> [363.754088] R13: 0000000000000005 R14: 00007f0d74000b20 R15: 000055ab44e2c3f8
-Chris
_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

#26 lore raw

PATCH 3/7 drm: add support of syncobj timeline point wait v2

In reply to Chunming Zhou

points array is one-to-one match with syncobjs array. v2:
add seperate ioctl for timeline point wait, otherwise break uapi. v3:
userspace can specify two kinds waits::
a. Wait for time point to be completed.
b. and wait for time point to become available

---
 drivers/gpu/drm/drm_internal.h |   2 +
 drivers/gpu/drm/drm_ioctl.c    |   2 +
 drivers/gpu/drm/drm_syncobj.c  | 118 ++++++++++++++++++++++++++++-----
 include/uapi/drm/drm.h         |  18 +++++
 4 files changed, 124 insertions(+), 16 deletions(-)
drivers/gpu/drm/drm_internal.h +2 -0
index 0c4eb4a9ab31..566d44e3c782 100644
@@ -183,6 +183,8 @@ int drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
 				   struct drm_file *file_private);
 int drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
 			   struct drm_file *file_private);
+int drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data,
+				    struct drm_file *file_private);
 int drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
 			    struct drm_file *file_private);
 int drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
drivers/gpu/drm/drm_ioctl.c +2 -0
index 6b4a633b4240..c0891614f516 100644
@@ -669,6 +669,8 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
 		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_WAIT, drm_syncobj_wait_ioctl,
 		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, drm_syncobj_timeline_wait_ioctl,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_RESET, drm_syncobj_reset_ioctl,
 		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_SIGNAL, drm_syncobj_signal_ioctl,
drivers/gpu/drm/drm_syncobj.c +102 -16

218 lines not on this page · raw message

include/uapi/drm/drm.h +18 -0
index cebdb2541eb7..c8bc1414753d 100644
@@ -738,6 +738,10 @@ struct drm_syncobj_handle {
 
 #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
 #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
+/* wait for time point to be completed */
+#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_COMPLETED (1 << 2)
+/* wait for time point to become available */
+#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 3)
 struct drm_syncobj_wait {
 	__u64 handles;
 	/* absolute timeout */
@@ -748,6 +752,19 @@ struct drm_syncobj_wait {
 	__u32 pad;
 };
 
+struct drm_syncobj_timeline_wait {
+	__u64 handles;
+	/* wait on specific timeline point for every handles*/
+	__u64 points;
+	/* absolute timeout */
+	__s64 timeout_nsec;
+	__u32 count_handles;
+	__u32 flags;
+	__u32 first_signaled; /* only valid when not waiting all */
+	__u32 pad;
+};
+
+
 struct drm_syncobj_array {
 	__u64 handles;
 	__u32 count_handles;
@@ -910,6 +927,7 @@ extern "C" {
 #define DRM_IOCTL_MODE_GET_LEASE	DRM_IOWR(0xC8, struct drm_mode_get_lease)
 #define DRM_IOCTL_MODE_REVOKE_LEASE	DRM_IOWR(0xC9, struct drm_mode_revoke_lease)
 
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT	DRM_IOWR(0xCA, struct drm_syncobj_timeline_wait)
 /**
  * Device specific ioctls should only be in their respective headers
  * The device specific ioctl range is from 0x40 to 0x9f.
Signature · 6 lines
2.17.1

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel
#27 lore raw

PATCH 4/7 drm: add timeline syncobj payload query ioctl v2

In reply to Chunming Zhou

user mode can query timeline payload.
v2: check return value of copy_to_user

---
 drivers/gpu/drm/drm_internal.h |  2 ++
 drivers/gpu/drm/drm_ioctl.c    |  2 ++
 drivers/gpu/drm/drm_syncobj.c  | 52 ++++++++++++++++++++++++++++++++++
 include/uapi/drm/drm.h         | 11 +++++++
 4 files changed, 67 insertions(+)
drivers/gpu/drm/drm_internal.h +2 -0
index 566d44e3c782..9c4826411a3c 100644
@@ -189,6 +189,8 @@ int drm_syncobj_reset_ioctl(struct drm_device *dev, void *data,
 			    struct drm_file *file_private);
 int drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
 			     struct drm_file *file_private);
+int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
+			    struct drm_file *file_private);
 
 /* drm_framebuffer.c */
 void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent,
drivers/gpu/drm/drm_ioctl.c +2 -0
index c0891614f516..c3c0617e6372 100644
@@ -675,6 +675,8 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
 		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_SIGNAL, drm_syncobj_signal_ioctl,
 		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_QUERY, drm_syncobj_query_ioctl,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_CRTC_GET_SEQUENCE, drm_crtc_get_sequence_ioctl, DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_CRTC_QUEUE_SEQUENCE, drm_crtc_queue_sequence_ioctl, DRM_UNLOCKED),
 	DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_LEASE, drm_mode_create_lease_ioctl, DRM_MASTER|DRM_UNLOCKED),
drivers/gpu/drm/drm_syncobj.c +52 -0

55 lines not on this page · raw message

include/uapi/drm/drm.h +11 -0
index c8bc1414753d..23c4979d8a1c 100644
@@ -771,6 +771,15 @@ struct drm_syncobj_array {
 	__u32 pad;
 };
 
+struct drm_syncobj_timeline_query {
+	__u64 handles;
+	/* points are timeline syncobjs payloads returned by query ioctl */
+	__u64 points;
+	__u32 count_handles;
+	__u32 pad;
+};
+
+
 /* Query current scanout sequence number */
 struct drm_crtc_get_sequence {
 	__u32 crtc_id;		/* requested crtc_id */
@@ -928,6 +937,8 @@ extern "C" {
 #define DRM_IOCTL_MODE_REVOKE_LEASE	DRM_IOWR(0xC9, struct drm_mode_revoke_lease)
 
 #define DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT	DRM_IOWR(0xCA, struct drm_syncobj_timeline_wait)
+#define DRM_IOCTL_SYNCOBJ_QUERY		DRM_IOWR(0xCB, struct drm_syncobj_timeline_query)
+
 /**
  * Device specific ioctls should only be in their respective headers
  * The device specific ioctl range is from 0x40 to 0x9f.
Signature · 6 lines
2.17.1

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

A message that is not in the archive (sent off-list or not yet received): [email protected]

#29 lore raw

PATCH 5/7 drm: add timeline support for syncobj export/import

user space can specify timeline point fence to export/import.

---
 drivers/gpu/drm/drm_internal.h |  4 ++
 drivers/gpu/drm/drm_ioctl.c    |  4 ++
 drivers/gpu/drm/drm_syncobj.c  | 76 ++++++++++++++++++++++++++++++----
 include/uapi/drm/drm.h         | 11 +++++
 4 files changed, 88 insertions(+), 7 deletions(-)
drivers/gpu/drm/drm_internal.h +4 -0
index 9c4826411a3c..5ad6cbdb68ab 100644
@@ -181,6 +181,10 @@ int drm_syncobj_handle_to_fd_ioctl(struct drm_device *dev, void *data,
 				   struct drm_file *file_private);
 int drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
 				   struct drm_file *file_private);
+int drm_syncobj_handle_to_fd_ioctl2(struct drm_device *dev, void *data,
+				    struct drm_file *file_private);
+int drm_syncobj_fd_to_handle_ioctl2(struct drm_device *dev, void *data,
+				    struct drm_file *file_private);
 int drm_syncobj_wait_ioctl(struct drm_device *dev, void *data,
 			   struct drm_file *file_private);
 int drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data,
drivers/gpu/drm/drm_ioctl.c +4 -0
index c3c0617e6372..b80c2c28aee0 100644
@@ -667,6 +667,10 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
 		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, drm_syncobj_fd_to_handle_ioctl,
 		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD2, drm_syncobj_handle_to_fd_ioctl2,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE2, drm_syncobj_fd_to_handle_ioctl2,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_WAIT, drm_syncobj_wait_ioctl,
 		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, drm_syncobj_timeline_wait_ioctl,
drivers/gpu/drm/drm_syncobj.c +69 -7

124 lines not on this page · raw message

include/uapi/drm/drm.h +11 -0
index 23c4979d8a1c..da5df2a42fc3 100644
@@ -735,6 +735,15 @@ struct drm_syncobj_handle {
 	__s32 fd;
 	__u32 pad;
 };
+struct drm_syncobj_handle2 {
+	__u32 handle;
+	__u32 flags;
+	__u64 point;
+
+	__s32 fd;
+	__u32 pad;
+};
+
 
 #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
 #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
@@ -938,6 +947,8 @@ extern "C" {
 
 #define DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT	DRM_IOWR(0xCA, struct drm_syncobj_timeline_wait)
 #define DRM_IOCTL_SYNCOBJ_QUERY		DRM_IOWR(0xCB, struct drm_syncobj_timeline_query)
+#define DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD2	DRM_IOWR(0xCC, struct drm_syncobj_handle2)
+#define DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE2	DRM_IOWR(0xCD, struct drm_syncobj_handle2)
 
 /**
  * Device specific ioctls should only be in their respective headers
Signature · 6 lines
2.17.1

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
#30 lore raw

PATCH 6/7 drm/amdgpu: add timeline support in amdgpu CS v2

In reply to a message not in the archive

syncobj wait/signal operation is appending in command submission.
v2: separate to two kinds in/out_deps functions

---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h    |   8 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 111 +++++++++++++++++++++----
 include/uapi/drm/amdgpu_drm.h          |   9 ++
 3 files changed, 112 insertions(+), 16 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu.h +6 -2
index 447c4c7a36d6..6e4a3db56833 100644
@@ -975,6 +975,11 @@ struct amdgpu_cs_chunk {
 	void			*kdata;
 };
 
+struct amdgpu_cs_syncobj_post_dep {
+	struct drm_syncobj *post_dep_syncobj;
+	u64 point;
+};
+
 struct amdgpu_cs_parser {
 	struct amdgpu_device	*adev;
 	struct drm_file		*filp;
@@ -1003,9 +1008,8 @@ struct amdgpu_cs_parser {
 
 	/* user fence */
 	struct amdgpu_bo_list_entry	uf_entry;
-
+	struct amdgpu_cs_syncobj_post_dep *post_dep_syncobjs;
 	unsigned num_post_dep_syncobjs;
-	struct drm_syncobj **post_dep_syncobjs;
 };
 
 static inline u32 amdgpu_get_ib_value(struct amdgpu_cs_parser *p,
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +97 -14

194 lines not on this page · raw message

include/uapi/drm/amdgpu_drm.h +9 -0
index 1ceec56de015..44a34a77f986 100644
@@ -517,6 +517,8 @@ struct drm_amdgpu_gem_va {
 #define AMDGPU_CHUNK_ID_SYNCOBJ_IN      0x04
 #define AMDGPU_CHUNK_ID_SYNCOBJ_OUT     0x05
 #define AMDGPU_CHUNK_ID_BO_HANDLES      0x06
+#define AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_WAIT    0x07
+#define AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_SIGNAL  0x08
 
 struct drm_amdgpu_cs_chunk {
 	__u32		chunk_id;
@@ -592,6 +594,13 @@ struct drm_amdgpu_cs_chunk_sem {
 	__u32 handle;
 };
 
+struct drm_amdgpu_cs_chunk_syncobj {
+       __u32 handle;
+       __u32 flags;
+       __u64 point;
+};
+
+
 #define AMDGPU_FENCE_TO_HANDLE_GET_SYNCOBJ	0
 #define AMDGPU_FENCE_TO_HANDLE_GET_SYNCOBJ_FD	1
 #define AMDGPU_FENCE_TO_HANDLE_GET_SYNC_FILE_FD	2
Signature · 6 lines
2.17.1

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
#31 lore raw

PATCH 7/7 drm/amdgpu: update version for timeline syncobj support in amdgpu

In reply to a message not in the archive
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +2 -1
index 6870909da926..58cba492ba55 100644
@@ -70,9 +70,10 @@
  * - 3.25.0 - Add support for sensor query info (stable pstate sclk/mclk).
  * - 3.26.0 - GFX9: Process AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE.
  * - 3.27.0 - Add new chunk to to AMDGPU_CS to enable BO_LIST creation.
+ * - 3.28.0 - Add syncobj timeline support to AMDGPU_CS.
  */
 #define KMS_DRIVER_MAJOR	3
-#define KMS_DRIVER_MINOR	27
+#define KMS_DRIVER_MINOR	28
 #define KMS_DRIVER_PATCHLEVEL	0
 
 int amdgpu_vram_limit = 0;
Signature · 6 lines
2.17.1

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
#32 lore raw

RE: [PATCH 7/7] drm/amdgpu: update version for timeline syncobj support in amdgpu

Ping...
Christian, Could I get your RB on the series? And help me to push to drm-misc? After that I can rebase libdrm header file based on drm-next.

Thanks,
David Zhou

Quoted 35 lines

-----Original Message-----
From: amd-gfx <[email protected]> On Behalf Of Chunming Zhou
Sent: Monday, October 15, 2018 4:56 PM
To: [email protected]
Cc: Zhou, David(ChunMing) <[email protected]>; amd- [email protected]
Subject: [PATCH 7/7] drm/amdgpu: update version for timeline syncobj support in amdgpu

---
 drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +2 -2
index 6870909da926..58cba492ba55 100644
@@ -70,9 +70,10 @@
  * - 3.25.0 - Add support for sensor query info (stable pstate sclk/mclk).
  * - 3.26.0 - GFX9: Process AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE.
  * - 3.27.0 - Add new chunk to to AMDGPU_CS to enable BO_LIST creation.
+ * - 3.28.0 - Add syncobj timeline support to AMDGPU_CS.
  */
 #define KMS_DRIVER_MAJOR	3
-#define KMS_DRIVER_MINOR	27
+#define KMS_DRIVER_MINOR	28
 #define KMS_DRIVER_PATCHLEVEL	0
 
 int amdgpu_vram_limit = 0;
--

2.17.1

Quoted 4 lines

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

A message that is not in the archive (sent off-list or not yet received): BY1PR12MB0502F0E543F50239A43E5F94B4FD0-PicGAnIBOobrCwm+z9iKNgdYzm3356FpvxpqHgZTriW3zl9H0oFU5g@public.gmane.org

#34 lore raw

Re: [PATCH 7/7] drm/amdgpu: update version for timeline syncobj support in amdgpu

I'm on sick leave today.

But I will see what I can do later in the afternoon, Christian.

Am 15.10.2018 um 11:01 schrieb Zhou, David(ChunMing):

Quoted 38 lines

Ping...
Christian, Could I get your RB on the series? And help me to push to drm-misc? After that I can rebase libdrm header file based on drm-next.

Thanks,
David Zhou

Quoted 31 lines

-----Original Message-----
From: amd-gfx <[email protected]> On Behalf Of Chunming Zhou
Sent: Monday, October 15, 2018 4:56 PM
To: [email protected]
Cc: Zhou, David(ChunMing) <[email protected]>; amd- [email protected]
Subject: [PATCH 7/7] drm/amdgpu: update version for timeline syncobj support in amdgpu

---
  drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +2 -1
index 6870909da926..58cba492ba55 100644
@@ -70,9 +70,10 @@
   * - 3.25.0 - Add support for sensor query info (stable pstate sclk/mclk).
   * - 3.26.0 - GFX9: Process AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE.
   * - 3.27.0 - Add new chunk to to AMDGPU_CS to enable BO_LIST creation.
+ * - 3.28.0 - Add syncobj timeline support to AMDGPU_CS.
   */
  #define KMS_DRIVER_MAJOR	3
-#define KMS_DRIVER_MINOR	27
+#define KMS_DRIVER_MINOR	28
  #define KMS_DRIVER_PATCHLEVEL	0
 
Quoted 8 lines
Quoted 8 lines
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +0 -1
  int amdgpu_vram_limit = 0;
--

2.17.1

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

A message that is not in the archive (sent off-list or not yet received): cf4590f5-8e0a-ac0e-f34b-3e1b4b01fd99-5C7GfCeVMHo@public.gmane.org

#36 lore raw

Re: [PATCH 7/7] drm/amdgpu: update version for timeline syncobj support in amdgpu

I've added my rb to patch #1 and pushed it to drm-misc-next.

I would really like to get an rb from other people on patch #2 before proceeding.

Daniel, Dave and all the other usual suspects on the list what is your opinion on this implementation?

Christian.

Am 15.10.2018 um 11:04 schrieb Koenig, Christian:

Quoted 48 lines

I'm on sick leave today.

But I will see what I can do later in the afternoon, Christian.

Am 15.10.2018 um 11:01 schrieb Zhou, David(ChunMing):

Quoted 42 lines

Ping...
Christian, Could I get your RB on the series? And help me to push to drm-misc? After that I can rebase libdrm header file based on drm-next.

Thanks,
David Zhou

Quoted 35 lines

-----Original Message-----
From: amd-gfx <[email protected]> On Behalf Of Chunming Zhou
Sent: Monday, October 15, 2018 4:56 PM
To: [email protected]
Cc: Zhou, David(ChunMing) <[email protected]>; amd- [email protected]
Subject: [PATCH 7/7] drm/amdgpu: update version for timeline syncobj support in amdgpu

---
   drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 ++-
   1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +2 -2
index 6870909da926..58cba492ba55 100644
@@ -70,9 +70,10 @@
    * - 3.25.0 - Add support for sensor query info (stable pstate sclk/mclk).
    * - 3.26.0 - GFX9: Process AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE.
    * - 3.27.0 - Add new chunk to to AMDGPU_CS to enable BO_LIST creation.
+ * - 3.28.0 - Add syncobj timeline support to AMDGPU_CS.
    */
   #define KMS_DRIVER_MAJOR	3
-#define KMS_DRIVER_MINOR	27
+#define KMS_DRIVER_MINOR	28
   #define KMS_DRIVER_PATCHLEVEL	0
 
   int amdgpu_vram_limit = 0;
--

2.17.1

Quoted 8 lines
Quoted 4 lines
Quoted 4 lines

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

A message that is not in the archive (sent off-list or not yet received): dcb28515-7250-9a1c-2784-a4cbf517e467-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

#38 lore raw

Re: [PATCH 7/7] drm/amdgpu: update version for timeline syncobj support in amdgpu

Quoted 5 lines · Christian König

I've added my rb to patch #1 and pushed it to drm-misc-next.

I would really like to get an rb from other people on patch #2 before proceeding.

Daniel, Dave and all the other usual suspects on the list what is your opinion on this implementation?

Thanks for head up, @Daniel, @Dave, or the others, Could you take a look for the series?

Thanks,
David

Quoted 61 lines

Christian.

Am 15.10.2018 um 11:04 schrieb Koenig, Christian:

Quoted 56 lines

I'm on sick leave today.

But I will see what I can do later in the afternoon, Christian.

Am 15.10.2018 um 11:01 schrieb Zhou, David(ChunMing):

Quoted 38 lines

Ping...
Christian, Could I get your RB on the series? And help me to push to drm-misc? After that I can rebase libdrm header file based on drm-next.

Thanks,
David Zhou

Quoted 31 lines

-----Original Message-----
From: amd-gfx <[email protected]> On Behalf Of Chunming Zhou
Sent: Monday, October 15, 2018 4:56 PM
To: [email protected]
Cc: Zhou, David(ChunMing) <[email protected]>; amd- [email protected]
Subject: [PATCH 7/7] drm/amdgpu: update version for timeline syncobj support in amdgpu

---
   drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 3 ++-

   1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +2 -1
index 6870909da926..58cba492ba55 100644
@@ -70,9 +70,10 @@
     * - 3.25.0 - Add support for sensor query info (stable pstate sclk/mclk).
     * - 3.26.0 - GFX9: Process AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE.
     * - 3.27.0 - Add new chunk to to AMDGPU_CS to enable BO_LIST creation.
+ * - 3.28.0 - Add syncobj timeline support to AMDGPU_CS.
     */
    #define KMS_DRIVER_MAJOR    3
-#define KMS_DRIVER_MINOR    27
+#define KMS_DRIVER_MINOR    28
    #define KMS_DRIVER_PATCHLEVEL    0
 
Quoted 8 lines
Quoted 8 lines
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +0 -0
    int amdgpu_vram_limit = 0;
Signature · 6 lines
2.17.1

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

_______________________________________________
amd-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/amd-gfx