Skip to contentSkip to conversation

dma-buf: make fence sequence numbers 64 bit v2

PATCH In review Chunming Zhou 12 participants 41 messages Dec 7, 2018 – Feb 20, 2019 22 messages not in the archive

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

PATCH 1/11 dma-buf: make fence sequence numbers 64 bit v2

From: Christian König <[email protected]>

For a lot of use cases we need 64bit sequence numbers. Currently drivers overload the dma_fence structure to store the additional bits.

Stop doing that and make the sequence number in the dma_fence always 64bit.

For compatibility with hardware which can do only 32bit sequences the comparisons in __dma_fence_is_later only takes the lower 32bits as significant when the upper 32bits are all zero.

v2: change the logic in __dma_fence_is_later

---
 drivers/dma-buf/dma-fence.c            |  2 +-
 drivers/dma-buf/sw_sync.c              |  2 +-
 drivers/dma-buf/sync_file.c            |  4 ++--
 drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c |  2 +-
 drivers/gpu/drm/i915/i915_sw_fence.c   |  2 +-
 drivers/gpu/drm/i915/intel_engine_cs.c |  2 +-
 drivers/gpu/drm/vgem/vgem_fence.c      |  4 ++--
 include/linux/dma-fence.h              | 22 +++++++++++++++-------
 8 files changed, 24 insertions(+), 16 deletions(-)
drivers/dma-buf/dma-fence.c +1 -1
index 136ec04d683f..3aa8733f832a 100644
@@ -649,7 +649,7 @@ EXPORT_SYMBOL(dma_fence_wait_any_timeout);
  */
 void
 dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
-	       spinlock_t *lock, u64 context, unsigned seqno)
+	       spinlock_t *lock, u64 context, u64 seqno)
 {
 	BUG_ON(!lock);
 	BUG_ON(!ops || !ops->get_driver_name || !ops->get_timeline_name);
drivers/dma-buf/sw_sync.c +1 -1
index 53c1d6d36a64..32dcf7b4c935 100644
@@ -172,7 +172,7 @@ static bool timeline_fence_enable_signaling(struct dma_fence *fence)
 static void timeline_fence_value_str(struct dma_fence *fence,
 				    char *str, int size)
 {
-	snprintf(str, size, "%d", fence->seqno);
+	snprintf(str, size, "%lld", fence->seqno);
 }
 
 static void timeline_fence_timeline_value_str(struct dma_fence *fence,
drivers/dma-buf/sync_file.c +2 -2
index 35dd06479867..4f6305ca52c8 100644
@@ -144,7 +144,7 @@ char *sync_file_get_name(struct sync_file *sync_file, char *buf, int len)
 	} else {
 		struct dma_fence *fence = sync_file->fence;
 
-		snprintf(buf, len, "%s-%s%llu-%d",
+		snprintf(buf, len, "%s-%s%llu-%lld",
 			 fence->ops->get_driver_name(fence),
 			 fence->ops->get_timeline_name(fence),
 			 fence->context,
@@ -258,7 +258,7 @@ static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
 
 			i_b++;
 		} else {
-			if (pt_a->seqno - pt_b->seqno <= INT_MAX)
+			if (__dma_fence_is_later(pt_a->seqno, pt_b->seqno))
 				add_fence(fences, &i, pt_a);
 			else
 				add_fence(fences, &i, pt_b);
drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +1 -1
index 12f2bf97611f..bfaf5c6323be 100644
@@ -388,7 +388,7 @@ void amdgpu_sa_bo_dump_debug_info(struct amdgpu_sa_manager *sa_manager,
 			   soffset, eoffset, eoffset - soffset);
 
 		if (i->fence)
-			seq_printf(m, " protected by 0x%08x on context %llu",
+			seq_printf(m, " protected by 0x%016llx on context %llu",
 				   i->fence->seqno, i->fence->context);
 
 		seq_printf(m, "\n");
drivers/gpu/drm/i915/i915_sw_fence.c +1 -1
index 6dbeed079ae5..11bcdabd5177 100644
@@ -393,7 +393,7 @@ static void timer_i915_sw_fence_wake(struct timer_list *t)
 	if (!fence)
 		return;
 
-	pr_notice("Asynchronous wait on fence %s:%s:%x timed out (hint:%pS)\n",
+	pr_notice("Asynchronous wait on fence %s:%s:%llx timed out (hint:%pS)\n",
 		  cb->dma->ops->get_driver_name(cb->dma),
 		  cb->dma->ops->get_timeline_name(cb->dma),
 		  cb->dma->seqno,
drivers/gpu/drm/i915/intel_engine_cs.c +1 -1
index 759c0fd58f8c..dfafa79171df 100644
@@ -1239,7 +1239,7 @@ static void print_request(struct drm_printer *m,
 
 	x = print_sched_attr(rq->i915, &rq->sched.attr, buf, x, sizeof(buf));
 
-	drm_printf(m, "%s%x%s [%llx:%x]%s @ %dms: %s\n",
+	drm_printf(m, "%s%x%s [%llx:%llx]%s @ %dms: %s\n",
 		   prefix,
 		   rq->global_seqno,
 		   i915_request_completed(rq) ? "!" : "",
drivers/gpu/drm/vgem/vgem_fence.c +2 -2
index c1c420afe2dd..eb17c0cd3727 100644
@@ -53,13 +53,13 @@ static void vgem_fence_release(struct dma_fence *base)
 
 static void vgem_fence_value_str(struct dma_fence *fence, char *str, int size)
 {
-	snprintf(str, size, "%u", fence->seqno);
+	snprintf(str, size, "%llu", fence->seqno);
 }
 
 static void vgem_fence_timeline_value_str(struct dma_fence *fence, char *str,
 					  int size)
 {
-	snprintf(str, size, "%u",
+	snprintf(str, size, "%llu",
 		 dma_fence_is_signaled(fence) ? fence->seqno : 0);
 }
 
include/linux/dma-fence.h +15 -7
index 999e4b104410..6b788467b2e3 100644
@@ -77,7 +77,7 @@ struct dma_fence {
 	struct list_head cb_list;
 	spinlock_t *lock;
 	u64 context;
-	unsigned seqno;
+	u64 seqno;
 	unsigned long flags;
 	ktime_t timestamp;
 	int error;
@@ -244,7 +244,7 @@ struct dma_fence_ops {
 };
 
 void dma_fence_init(struct dma_fence *fence, const struct dma_fence_ops *ops,
-		    spinlock_t *lock, u64 context, unsigned seqno);
+		    spinlock_t *lock, u64 context, u64 seqno);
 
 void dma_fence_release(struct kref *kref);
 void dma_fence_free(struct dma_fence *fence);
@@ -414,9 +414,17 @@ dma_fence_is_signaled(struct dma_fence *fence)
  * Returns true if f1 is chronologically later than f2. Both fences must be
  * from the same context, since a seqno is not common across contexts.
  */
-static inline bool __dma_fence_is_later(u32 f1, u32 f2)
+static inline bool __dma_fence_is_later(u64 f1, u64 f2)
 {
-	return (int)(f1 - f2) > 0;
+	/* This is for backward compatibility with drivers which can only handle
+	 * 32bit sequence numbers. Use a 64bit compare when any of the higher
+	 * bits are none zero, otherwise use a 32bit compare with wrap around
+	 * handling.
+	 */
+	if (upper_32_bits(f1) || upper_32_bits(f2))
+		return f1 > f2;
+
+	return (int)(lower_32_bits(f1) - lower_32_bits(f2)) > 0;
 }
 
 /**
@@ -548,21 +556,21 @@ u64 dma_fence_context_alloc(unsigned num);
 	do {								\
 		struct dma_fence *__ff = (f);				\
 		if (IS_ENABLED(CONFIG_DMA_FENCE_TRACE))			\
-			pr_info("f %llu#%u: " fmt,			\
+			pr_info("f %llu#%llu: " fmt,			\
 				__ff->context, __ff->seqno, ##args);	\
 	} while (0)
 
 #define DMA_FENCE_WARN(f, fmt, args...) \
 	do {								\
 		struct dma_fence *__ff = (f);				\
-		pr_warn("f %llu#%u: " fmt, __ff->context, __ff->seqno,	\
+		pr_warn("f %llu#%llu: " fmt, __ff->context, __ff->seqno,\
 			 ##args);					\
 	} while (0)
 
 #define DMA_FENCE_ERR(f, fmt, args...) \
 	do {								\
 		struct dma_fence *__ff = (f);				\
-		pr_err("f %llu#%u: " fmt, __ff->context, __ff->seqno,	\
+		pr_err("f %llu#%llu: " fmt, __ff->context, __ff->seqno,	\
 			##args);					\
 	} while (0)
 
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/11 dma-buf: add new dma_fence_chain container v4

From: Christian König <[email protected]>

Lockless container implementation similar to a dma_fence_array, but with only two elements per node and automatic garbage collection.

v2: properly document dma_fence_chain_for_each, add dma_fence_chain_find_seqno,
drop prev reference during garbage collection if it's not a chain fence.
v3: use head and iterator for dma_fence_chain_for_each
v4: fix reference count in dma_fence_chain_enable_signaling

---
 drivers/dma-buf/Makefile          |   3 +-
 drivers/dma-buf/dma-fence-chain.c | 241 ++++++++++++++++++++++++++++++
 include/linux/dma-fence-chain.h   |  81 ++++++++++
 3 files changed, 324 insertions(+), 1 deletion(-)
 create mode 100644 drivers/dma-buf/dma-fence-chain.c
 create mode 100644 include/linux/dma-fence-chain.h
drivers/dma-buf/Makefile +2 -1
index 0913a6ccab5a..1f006e083eb9 100644
@@ -1,4 +1,5 @@
-obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o seqno-fence.o
+obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
+	 reservation.o seqno-fence.o
 obj-$(CONFIG_SYNC_FILE)		+= sync_file.o
 obj-$(CONFIG_SW_SYNC)		+= sw_sync.o sync_debug.o
 obj-$(CONFIG_UDMABUF)		+= udmabuf.o
drivers/dma-buf/dma-fence-chain.c new file +241 -0

241 lines not on this page · raw message

include/linux/dma-fence-chain.h new file +81 -0

81 lines not on this page · raw message

Signature · 6 lines
2.17.1

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

Re: [PATCH 02/11] dma-buf: add new dma_fence_chain container v4

Hi Christian, David,

For timeline semaphore we need points to signaled in order.
I'm struggling to understand how this fence-chain implementation preserves ordering of the seqnos.

One of the scenario I can see an issue happening is when you have a timeline with points 1 & 2 and userspace submits for 2 different engines :
    - first with let's say a blitter style engine on point 2
    - then a 3d style engine on point 1

Another scenario would be signaling a timeline with points 1 & 2 with those points in reverse order in the submission array.

-Lionel

Quoted 354 lines · Chunming Zhou

From: Christian König <[email protected]>

Lockless container implementation similar to a dma_fence_array, but with only two elements per node and automatic garbage collection.

v2: properly document dma_fence_chain_for_each, add dma_fence_chain_find_seqno,
drop prev reference during garbage collection if it's not a chain fence.
v3: use head and iterator for dma_fence_chain_for_each
v4: fix reference count in dma_fence_chain_enable_signaling

---
  drivers/dma-buf/Makefile          |   3 +-
  drivers/dma-buf/dma-fence-chain.c | 241 ++++++++++++++++++++++++++++++
  include/linux/dma-fence-chain.h   |  81 ++++++++++
  3 files changed, 324 insertions(+), 1 deletion(-)

create mode 100644 drivers/dma-buf/dma-fence-chain.c create mode 100644 include/linux/dma-fence-chain.h

drivers/dma-buf/Makefile +2 -1
index 0913a6ccab5a..1f006e083eb9 100644
@@ -1,4 +1,5 @@
-obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o seqno-fence.o
+obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
+	 reservation.o seqno-fence.o
  obj-$(CONFIG_SYNC_FILE)		+= sync_file.o
  obj-$(CONFIG_SW_SYNC)		+= sw_sync.o sync_debug.o
  obj-$(CONFIG_UDMABUF)		+= udmabuf.o
drivers/dma-buf/dma-fence-chain.c new file +241 -0
new file mode 100644
index 000000000000..0c5e3c902fa0
@@ -0,0 +1,241 @@
+/*
+ * fence-chain: chain fences together in a timeline
+ *
+ * Copyright (C) 2018 Advanced Micro Devices, Inc.
+ * Authors:
+ *	Christian König <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/dma-fence-chain.h>
+
+static bool dma_fence_chain_enable_signaling(struct dma_fence *fence);
+
+/**
+ * dma_fence_chain_get_prev - use RCU to get a reference to the previous fence
+ * @chain: chain node to get the previous node from
+ *
+ * Use dma_fence_get_rcu_safe to get a reference to the previous fence of the
+ * chain node.
+ */
+static struct dma_fence *dma_fence_chain_get_prev(struct dma_fence_chain *chain)
+{
+	struct dma_fence *prev;
+
+	rcu_read_lock();
+	prev = dma_fence_get_rcu_safe(&chain->prev);
+	rcu_read_unlock();
+	return prev;
+}
+
+/**
+ * dma_fence_chain_walk - chain walking function
+ * @fence: current chain node
+ *
+ * Walk the chain to the next node. Returns the next fence or NULL if we are at
+ * the end of the chain. Garbage collects chain nodes which are already
+ * signaled.
+ */
+struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence)
+{
+	struct dma_fence_chain *chain, *prev_chain;
+	struct dma_fence *prev, *replacement, *tmp;
+
+	chain = to_dma_fence_chain(fence);
+	if (!chain) {
+		dma_fence_put(fence);
+		return NULL;
+	}
+
+	while ((prev = dma_fence_chain_get_prev(chain))) {
+
+		prev_chain = to_dma_fence_chain(prev);
+		if (prev_chain) {
+			if (!dma_fence_is_signaled(prev_chain->fence))
+				break;
+
+			replacement = dma_fence_chain_get_prev(prev_chain);
+		} else {
+			if (!dma_fence_is_signaled(prev))
+				break;
+
+			replacement = NULL;
+		}
+
+		tmp = cmpxchg(&chain->prev, prev, replacement);
+		if (tmp == prev)
+			dma_fence_put(tmp);
+		else
+			dma_fence_put(replacement);
+		dma_fence_put(prev);
+	}
+
+	dma_fence_put(fence);
+	return prev;
+}
+EXPORT_SYMBOL(dma_fence_chain_walk);
+
+/**
+ * dma_fence_chain_find_seqno - find fence chain node by seqno
+ * @pfence: pointer to the chain node where to start
+ * @seqno: the sequence number to search for
+ *
+ * Advance the fence pointer to the chain node which will signal this sequence
+ * number. If no sequence number is provided then this is a no-op.
+ *
+ * Returns EINVAL if the fence is not a chain node or the sequence number has
+ * not yet advanced far enough.
+ */
+int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t seqno)
+{
+	struct dma_fence_chain *chain;
+
+	if (!seqno)
+		return 0;
+
+	chain = to_dma_fence_chain(*pfence);
+	if (!chain || chain->base.seqno < seqno)
+		return -EINVAL;
+
+	dma_fence_chain_for_each(*pfence, &chain->base) {
+		if ((*pfence)->context != chain->base.context ||
+		    to_dma_fence_chain(*pfence)->prev_seqno < seqno)
+			break;
+	}
+	dma_fence_put(&chain->base);
+
+	return 0;
+}
+EXPORT_SYMBOL(dma_fence_chain_find_seqno);
+
+static const char *dma_fence_chain_get_driver_name(struct dma_fence *fence)
+{
+        return "dma_fence_chain";
+}
+
+static const char *dma_fence_chain_get_timeline_name(struct dma_fence *fence)
+{
+        return "unbound";
+}
+
+static void dma_fence_chain_irq_work(struct irq_work *work)
+{
+	struct dma_fence_chain *chain;
+
+	chain = container_of(work, typeof(*chain), work);
+
+	/* Try to rearm the callback */
+	if (!dma_fence_chain_enable_signaling(&chain->base))
+		/* Ok, we are done. No more unsignaled fences left */
+		dma_fence_signal(&chain->base);
+	dma_fence_put(&chain->base);
+}
+
+static void dma_fence_chain_cb(struct dma_fence *f, struct dma_fence_cb *cb)
+{
+	struct dma_fence_chain *chain;
+
+	chain = container_of(cb, typeof(*chain), cb);
+	irq_work_queue(&chain->work);
+	dma_fence_put(f);
+}
+
+static bool dma_fence_chain_enable_signaling(struct dma_fence *fence)
+{
+	struct dma_fence_chain *head = to_dma_fence_chain(fence);
+
+	dma_fence_get(&head->base);
+	dma_fence_chain_for_each(fence, &head->base) {
+		struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+		struct dma_fence *f = chain ? chain->fence : fence;
+
+		dma_fence_get(f);
+		if (!dma_fence_add_callback(f, &head->cb, dma_fence_chain_cb)) {
+			dma_fence_put(fence);
+			return true;
+		}
+		dma_fence_put(f);
+	}
+	dma_fence_put(&head->base);
+	return false;
+}
+
+static bool dma_fence_chain_signaled(struct dma_fence *fence)
+{
+	dma_fence_chain_for_each(fence, fence) {
+		struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+		struct dma_fence *f = chain ? chain->fence : fence;
+
+		if (!dma_fence_is_signaled(f)) {
+			dma_fence_put(fence);
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static void dma_fence_chain_release(struct dma_fence *fence)
+{
+	struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+
+	dma_fence_put(chain->prev);
+	dma_fence_put(chain->fence);
+	dma_fence_free(fence);
+}
+
+const struct dma_fence_ops dma_fence_chain_ops = {
+	.get_driver_name = dma_fence_chain_get_driver_name,
+	.get_timeline_name = dma_fence_chain_get_timeline_name,
+	.enable_signaling = dma_fence_chain_enable_signaling,
+	.signaled = dma_fence_chain_signaled,
+	.release = dma_fence_chain_release,
+};
+EXPORT_SYMBOL(dma_fence_chain_ops);
+
+/**
+ * dma_fence_chain_init - initialize a fence chain
+ * @chain: the chain node to initialize
+ * @prev: the previous fence
+ * @fence: the current fence
+ *
+ * Initialize a new chain node and either start a new chain or add the node to
+ * the existing chain of the previous fence.
+ */
+void dma_fence_chain_init(struct dma_fence_chain *chain,
+			  struct dma_fence *prev,
+			  struct dma_fence *fence,
+			  uint64_t seqno)
+{
+	struct dma_fence_chain *prev_chain = to_dma_fence_chain(prev);
+	uint64_t context;
+
+	spin_lock_init(&chain->lock);
+	chain->prev = prev;
+	chain->fence = fence;
+	chain->prev_seqno = 0;
+	init_irq_work(&chain->work, dma_fence_chain_irq_work);
+
+	/* Try to reuse the context of the previous chain node. */
+	if (prev_chain && __dma_fence_is_later(seqno, prev->seqno)) {
+		context = prev->context;
+		chain->prev_seqno = prev->seqno;
+	} else {
+		context = dma_fence_context_alloc(1);
+		/* Make sure that we always have a valid sequence number. */
+		if (prev_chain)
+			seqno = max(prev->seqno, seqno);
+	}
+
+	dma_fence_init(&chain->base, &dma_fence_chain_ops,
+		       &chain->lock, context, seqno);
+}
+EXPORT_SYMBOL(dma_fence_chain_init);
include/linux/dma-fence-chain.h new file +71 -0
new file mode 100644
index 000000000000..a5c2e8c6915c
@@ -0,0 +1,81 @@
+/*
+ * fence-chain: chain fences together in a timeline
+ *
+ * Copyright (C) 2018 Advanced Micro Devices, Inc.
+ * Authors:
+ *	Christian König <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __LINUX_DMA_FENCE_CHAIN_H
+#define __LINUX_DMA_FENCE_CHAIN_H
+
+#include <linux/dma-fence.h>
+#include <linux/irq_work.h>
+
+/**
+ * struct dma_fence_chain - fence to represent an node of a fence chain
+ * @base: fence base class
+ * @lock: spinlock for fence handling
+ * @prev: previous fence of the chain
+ * @prev_seqno: original previous seqno before garbage collection
+ * @fence: encapsulated fence
+ * @cb: callback structure for signaling
+ * @work: irq work item for signaling
+ */
+struct dma_fence_chain {
+	struct dma_fence base;
+	spinlock_t lock;
+	struct dma_fence *prev;
+	u64 prev_seqno;
+	struct dma_fence *fence;
+	struct dma_fence_cb cb;
+	struct irq_work work;
+};
+
+extern const struct dma_fence_ops dma_fence_chain_ops;
+
+/**
+ * to_dma_fence_chain - cast a fence to a dma_fence_chain
+ * @fence: fence to cast to a dma_fence_array
+ *
+ * Returns NULL if the fence is not a dma_fence_chain,
+ * or the dma_fence_chain otherwise.
+ */
+static inline struct dma_fence_chain *
+to_dma_fence_chain(struct dma_fence *fence)
+{
+	if (!fence || fence->ops != &dma_fence_chain_ops)
+		return NULL;
+
+	return container_of(fence, struct dma_fence_chain, base);
+}
+
+/**
+ * dma_fence_chain_for_each - iterate over all fences in chain
+ * @iter: current fence
+ * @head: starting point
+ *
+ * Iterate over all fences in the chain. We keep a reference to the current
+ * fence while inside the loop which must be dropped when breaking out.
+ */
+#define dma_fence_chain_for_each(iter, head)	\
+	for (iter = dma_fence_get(head); iter; \

include/linux/dma-fence-chain.h line 81

Quoted 10 lines
include/linux/dma-fence-chain.h new file +10 -0
+	     iter = dma_fence_chain_walk(head))
+
+struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence);
+int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t seqno);
+void dma_fence_chain_init(struct dma_fence_chain *chain,
+			  struct dma_fence *prev,
+			  struct dma_fence *fence,
+			  uint64_t seqno);
+
+#endif /* __LINUX_DMA_FENCE_CHAIN_H */

_______________________________________________
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): 6c2adaf5-6871-20be-a26d-182f8ca8ab8a-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org

#4 lore raw

Re: [PATCH 02/11] dma-buf: add new dma_fence_chain container v4

Am 15.02.19 um 15:23 schrieb Lionel Landwerlin:

Quoted 11 lines

Hi Christian, David,

For timeline semaphore we need points to signaled in order. I'm struggling to understand how this fence-chain implementation preserves ordering of the seqnos.

One of the scenario I can see an issue happening is when you have a timeline with points 1 & 2 and userspace submits for 2 different engines :
    - first with let's say a blitter style engine on point 2
    - then a 3d style engine on point 1

Yeah, and where exactly is the problem?

Seqno 1 will signal when the 3d style engine finishes work.

And seqno 2 will signal when both seqno 1 is signaled and the blitter style engine has finished its work.

Quoted 2 lines

Another scenario would be signaling a timeline with points 1 & 2 with those points in reverse order in the submission array.

That is actually illegal in the spec, but actually handled gracefully as well.

E.g. when you add seqno 1 to the syncobj container it will only signal when 2 is signaled as well.

Regards,
Christian.

Quoted 389 lines

-Lionel

Quoted 385 lines · Chunming Zhou

From: Christian König <[email protected]>

Lockless container implementation similar to a dma_fence_array, but with only two elements per node and automatic garbage collection.

v2: properly document dma_fence_chain_for_each, add dma_fence_chain_find_seqno,
     drop prev reference during garbage collection if it's not a chain fence.
v3: use head and iterator for dma_fence_chain_for_each
v4: fix reference count in dma_fence_chain_enable_signaling

---
  drivers/dma-buf/Makefile          |   3 +- drivers/dma-buf/dma-fence-chain.c | 241 ++++++++++++++++++++++++++++++ include/linux/dma-fence-chain.h   |  81 ++++++++++

  3 files changed, 324 insertions(+), 1 deletion(-)

  create mode 100644 drivers/dma-buf/dma-fence-chain.c create mode 100644 include/linux/dma-fence-chain.h

drivers/dma-buf/Makefile +0 -1
index 0913a6ccab5a..1f006e083eb9 100644
@@ -1,4 +1,5 @@
-obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o 

seqno-fence.o
+obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
+     reservation.o seqno-fence.o
  obj-$(CONFIG_SYNC_FILE)        += sync_file.o obj-$(CONFIG_SW_SYNC)        += sw_sync.o sync_debug.o obj-$(CONFIG_UDMABUF)        += udmabuf.o

drivers/dma-buf/dma-fence-chain.c new file +8 -0
new file mode 100644
index 000000000000..0c5e3c902fa0
@@ -0,0 +1,241 @@
+/*
+ * fence-chain: chain fences together in a timeline
+ *
+ * Copyright (C) 2018 Advanced Micro Devices, Inc.
+ * Authors:
+ *    Christian König <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or 

modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */

drivers/dma-buf/dma-fence-chain.c new file +7 -0
+
+#include <linux/dma-fence-chain.h>
+
+static bool dma_fence_chain_enable_signaling(struct dma_fence *fence);
+
+/**
+ * dma_fence_chain_get_prev - use RCU to get a reference to the 

previous fence
+ * @chain: chain node to get the previous node from
+ *
+ * Use dma_fence_get_rcu_safe to get a reference to the previous fence of the
+ * chain node.
+ */
+static struct dma_fence *dma_fence_chain_get_prev(struct dma_fence_chain *chain)

drivers/dma-buf/dma-fence-chain.c new file +14 -0
+{
+    struct dma_fence *prev;
+
+    rcu_read_lock();
+    prev = dma_fence_get_rcu_safe(&chain->prev);
+    rcu_read_unlock();
+    return prev;
+}
+
+/**
+ * dma_fence_chain_walk - chain walking function
+ * @fence: current chain node
+ *
+ * Walk the chain to the next node. Returns the next fence or NULL 

if we are at
+ * the end of the chain. Garbage collects chain nodes which are already
+ * signaled.
+ */

drivers/dma-buf/dma-fence-chain.c new file +45 -0
+struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence)
+{
+    struct dma_fence_chain *chain, *prev_chain;
+    struct dma_fence *prev, *replacement, *tmp;
+
+    chain = to_dma_fence_chain(fence);
+    if (!chain) {
+        dma_fence_put(fence);
+        return NULL;
+    }
+
+    while ((prev = dma_fence_chain_get_prev(chain))) {
+
+        prev_chain = to_dma_fence_chain(prev);
+        if (prev_chain) {
+            if (!dma_fence_is_signaled(prev_chain->fence))
+                break;
+
+            replacement = dma_fence_chain_get_prev(prev_chain);
+        } else {
+            if (!dma_fence_is_signaled(prev))
+                break;
+
+            replacement = NULL;
+        }
+
+        tmp = cmpxchg(&chain->prev, prev, replacement);
+        if (tmp == prev)
+            dma_fence_put(tmp);
+        else
+            dma_fence_put(replacement);
+        dma_fence_put(prev);
+    }
+
+    dma_fence_put(fence);
+    return prev;
+}
+EXPORT_SYMBOL(dma_fence_chain_walk);
+
+/**
+ * dma_fence_chain_find_seqno - find fence chain node by seqno
+ * @pfence: pointer to the chain node where to start
+ * @seqno: the sequence number to search for
+ *
+ * Advance the fence pointer to the chain node which will signal 

this sequence
+ * number. If no sequence number is provided then this is a no-op.
+ *
+ * Returns EINVAL if the fence is not a chain node or the sequence number has
+ * not yet advanced far enough.
+ */
+int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t seqno)

drivers/dma-buf/dma-fence-chain.c new file +22 -0
+{
+    struct dma_fence_chain *chain;
+
+    if (!seqno)
+        return 0;
+
+    chain = to_dma_fence_chain(*pfence);
+    if (!chain || chain->base.seqno < seqno)
+        return -EINVAL;
+
+    dma_fence_chain_for_each(*pfence, &chain->base) {
+        if ((*pfence)->context != chain->base.context ||
+            to_dma_fence_chain(*pfence)->prev_seqno < seqno)
+            break;
+    }
+    dma_fence_put(&chain->base);
+
+    return 0;
+}
+EXPORT_SYMBOL(dma_fence_chain_find_seqno);
+
+static const char *dma_fence_chain_get_driver_name(struct dma_fence 

*fence)

drivers/dma-buf/dma-fence-chain.c new file +5 -0
+{
+        return "dma_fence_chain";
+}
+
+static const char *dma_fence_chain_get_timeline_name(struct 

dma_fence *fence)

drivers/dma-buf/dma-fence-chain.c new file +18 -0
+{
+        return "unbound";
+}
+
+static void dma_fence_chain_irq_work(struct irq_work *work)
+{
+    struct dma_fence_chain *chain;
+
+    chain = container_of(work, typeof(*chain), work);
+
+    /* Try to rearm the callback */
+    if (!dma_fence_chain_enable_signaling(&chain->base))
+        /* Ok, we are done. No more unsignaled fences left */
+        dma_fence_signal(&chain->base);
+    dma_fence_put(&chain->base);
+}
+
+static void dma_fence_chain_cb(struct dma_fence *f, struct 

dma_fence_cb *cb)

drivers/dma-buf/dma-fence-chain.c new file +19 -0
+{
+    struct dma_fence_chain *chain;
+
+    chain = container_of(cb, typeof(*chain), cb);
+    irq_work_queue(&chain->work);
+    dma_fence_put(f);
+}
+
+static bool dma_fence_chain_enable_signaling(struct dma_fence *fence)
+{
+    struct dma_fence_chain *head = to_dma_fence_chain(fence);
+
+    dma_fence_get(&head->base);
+    dma_fence_chain_for_each(fence, &head->base) {
+        struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+        struct dma_fence *f = chain ? chain->fence : fence;
+
+        dma_fence_get(f);
+        if (!dma_fence_add_callback(f, &head->cb, 

dma_fence_chain_cb)) {
+            dma_fence_put(fence);
+            return true;
+        }
+        dma_fence_put(f);
+    }
+    dma_fence_put(&head->base);
+    return false;

drivers/dma-buf/dma-fence-chain.c new file +42 -0
+}
+
+static bool dma_fence_chain_signaled(struct dma_fence *fence)
+{
+    dma_fence_chain_for_each(fence, fence) {
+        struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+        struct dma_fence *f = chain ? chain->fence : fence;
+
+        if (!dma_fence_is_signaled(f)) {
+            dma_fence_put(fence);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void dma_fence_chain_release(struct dma_fence *fence)
+{
+    struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+
+    dma_fence_put(chain->prev);
+    dma_fence_put(chain->fence);
+    dma_fence_free(fence);
+}
+
+const struct dma_fence_ops dma_fence_chain_ops = {
+    .get_driver_name = dma_fence_chain_get_driver_name,
+    .get_timeline_name = dma_fence_chain_get_timeline_name,
+    .enable_signaling = dma_fence_chain_enable_signaling,
+    .signaled = dma_fence_chain_signaled,
+    .release = dma_fence_chain_release,
+};
+EXPORT_SYMBOL(dma_fence_chain_ops);
+
+/**
+ * dma_fence_chain_init - initialize a fence chain
+ * @chain: the chain node to initialize
+ * @prev: the previous fence
+ * @fence: the current fence
+ *
+ * Initialize a new chain node and either start a new chain or add 

the node to
+ * the existing chain of the previous fence.
+ */

drivers/dma-buf/dma-fence-chain.c new file +29 -0
+void dma_fence_chain_init(struct dma_fence_chain *chain,
+              struct dma_fence *prev,
+              struct dma_fence *fence,
+              uint64_t seqno)
+{
+    struct dma_fence_chain *prev_chain = to_dma_fence_chain(prev);
+    uint64_t context;
+
+    spin_lock_init(&chain->lock);
+    chain->prev = prev;
+    chain->fence = fence;
+    chain->prev_seqno = 0;
+    init_irq_work(&chain->work, dma_fence_chain_irq_work);
+
+    /* Try to reuse the context of the previous chain node. */
+    if (prev_chain && __dma_fence_is_later(seqno, prev->seqno)) {
+        context = prev->context;
+        chain->prev_seqno = prev->seqno;
+    } else {
+        context = dma_fence_context_alloc(1);
+        /* Make sure that we always have a valid sequence number. */
+        if (prev_chain)
+            seqno = max(prev->seqno, seqno);
+    }
+
+    dma_fence_init(&chain->base, &dma_fence_chain_ops,
+               &chain->lock, context, seqno);
+}
+EXPORT_SYMBOL(dma_fence_chain_init);
include/linux/dma-fence-chain.h new file +8 -0
new file mode 100644
index 000000000000..a5c2e8c6915c
@@ -0,0 +1,81 @@
+/*
+ * fence-chain: chain fences together in a timeline
+ *
+ * Copyright (C) 2018 Advanced Micro Devices, Inc.
+ * Authors:
+ *    Christian König <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or 

modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */

include/linux/dma-fence-chain.h new file +51 -0
+
+#ifndef __LINUX_DMA_FENCE_CHAIN_H
+#define __LINUX_DMA_FENCE_CHAIN_H
+
+#include <linux/dma-fence.h>
+#include <linux/irq_work.h>
+
+/**
+ * struct dma_fence_chain - fence to represent an node of a fence chain
+ * @base: fence base class
+ * @lock: spinlock for fence handling
+ * @prev: previous fence of the chain
+ * @prev_seqno: original previous seqno before garbage collection
+ * @fence: encapsulated fence
+ * @cb: callback structure for signaling
+ * @work: irq work item for signaling
+ */
+struct dma_fence_chain {
+    struct dma_fence base;
+    spinlock_t lock;
+    struct dma_fence *prev;
+    u64 prev_seqno;
+    struct dma_fence *fence;
+    struct dma_fence_cb cb;
+    struct irq_work work;
+};
+
+extern const struct dma_fence_ops dma_fence_chain_ops;
+
+/**
+ * to_dma_fence_chain - cast a fence to a dma_fence_chain
+ * @fence: fence to cast to a dma_fence_array
+ *
+ * Returns NULL if the fence is not a dma_fence_chain,
+ * or the dma_fence_chain otherwise.
+ */
+static inline struct dma_fence_chain *
+to_dma_fence_chain(struct dma_fence *fence)
+{
+    if (!fence || fence->ops != &dma_fence_chain_ops)
+        return NULL;
+
+    return container_of(fence, struct dma_fence_chain, base);
+}
+
+/**
+ * dma_fence_chain_for_each - iterate over all fences in chain
+ * @iter: current fence
+ * @head: starting point
+ *
+ * Iterate over all fences in the chain. We keep a reference to the 

current
+ * fence while inside the loop which must be dropped when breaking out.
+ */

include/linux/dma-fence-chain.h new file +5 -0
+#define dma_fence_chain_for_each(iter, head)    \
+    for (iter = dma_fence_get(head); iter; \
+         iter = dma_fence_chain_walk(head))
+
+struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence);
Quoted 10 lines

include/linux/dma-fence-chain.h line 81

Quoted 8 lines

+int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t seqno);

include/linux/dma-fence-chain.h new file +6 -0
+void dma_fence_chain_init(struct dma_fence_chain *chain,
+              struct dma_fence *prev,
+              struct dma_fence *fence,
+              uint64_t seqno);
+
+#endif /* __LINUX_DMA_FENCE_CHAIN_H */

_______________________________________________
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): e170ceed-fdb7-8b4a-93d7-e565641390b3-5C7GfCeVMHo@public.gmane.org

#6 lore raw

Re: [PATCH 02/11] dma-buf: add new dma_fence_chain container v4

Quoted 12 lines · Christian

Am 15.02.19 um 15:23 schrieb Lionel Landwerlin:

Quoted 11 lines

Hi Christian, David,

For timeline semaphore we need points to signaled in order. I'm struggling to understand how this fence-chain implementation preserves ordering of the seqnos.

One of the scenario I can see an issue happening is when you have a timeline with points 1 & 2 and userspace submits for 2 different engines :
    - first with let's say a blitter style engine on point 2
    - then a 3d style engine on point 1

Quoted 6 lines

Yeah, and where exactly is the problem?

Seqno 1 will signal when the 3d style engine finishes work.

And seqno 2 will signal when both seqno 1 is signaled and the blitter style engine has finished its work.

That's not really how I understood the spec, but I might be wrong.

What makes me thing 1 should be signaled as soon as 2 is signaled (regardless of whether the fence attached on point 1 is been signaled), is that the spec defines wait & signal operations in term of the value of the timeline.

-Lionel

Quoted 13 lines
Quoted 3 lines

Another scenario would be signaling a timeline with points 1 & 2 with those points in reverse order in the submission array.

That is actually illegal in the spec, but actually handled gracefully as well.

E.g. when you add seqno 1 to the syncobj container it will only signal when 2 is signaled as well.

Quoted 400 lines

Regards,
Christian.

Quoted 397 lines

-Lionel

Quoted 393 lines · Chunming Zhou

From: Christian König <[email protected]>

Lockless container implementation similar to a dma_fence_array, but with only two elements per node and automatic garbage collection.

v2: properly document dma_fence_chain_for_each, add dma_fence_chain_find_seqno,
     drop prev reference during garbage collection if it's not a
chain fence.
v3: use head and iterator for dma_fence_chain_for_each
v4: fix reference count in dma_fence_chain_enable_signaling

---
   drivers/dma-buf/Makefile          |   3 +-
   drivers/dma-buf/dma-fence-chain.c | 241 ++++++++++++++++++++++++++++++
   include/linux/dma-fence-chain.h   |  81 ++++++++++
   3 files changed, 324 insertions(+), 1 deletion(-)

  create mode 100644 drivers/dma-buf/dma-fence-chain.c create mode 100644 include/linux/dma-fence-chain.h

drivers/dma-buf/Makefile +0 -1
index 0913a6ccab5a..1f006e083eb9 100644
@@ -1,4 +1,5 @@
-obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o

seqno-fence.o

drivers/dma-buf/Makefile +2 -0
+obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
+     reservation.o seqno-fence.o
   obj-$(CONFIG_SYNC_FILE)        += sync_file.o
   obj-$(CONFIG_SW_SYNC)        += sw_sync.o sync_debug.o
   obj-$(CONFIG_UDMABUF)        += udmabuf.o
drivers/dma-buf/dma-fence-chain.c new file +8 -0
new file mode 100644
index 000000000000..0c5e3c902fa0
@@ -0,0 +1,241 @@
+/*
+ * fence-chain: chain fences together in a timeline
+ *
+ * Copyright (C) 2018 Advanced Micro Devices, Inc.
+ * Authors:
+ *    Christian König <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or

modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */

drivers/dma-buf/dma-fence-chain.c new file +7 -0
+
+#include <linux/dma-fence-chain.h>
+
+static bool dma_fence_chain_enable_signaling(struct dma_fence *fence);
+
+/**
+ * dma_fence_chain_get_prev - use RCU to get a reference to the

previous fence
+ * @chain: chain node to get the previous node from
+ *
+ * Use dma_fence_get_rcu_safe to get a reference to the previous fence of the
+ * chain node.
+ */
+static struct dma_fence *dma_fence_chain_get_prev(struct dma_fence_chain *chain)

drivers/dma-buf/dma-fence-chain.c new file +14 -0
+{
+    struct dma_fence *prev;
+
+    rcu_read_lock();
+    prev = dma_fence_get_rcu_safe(&chain->prev);
+    rcu_read_unlock();
+    return prev;
+}
+
+/**
+ * dma_fence_chain_walk - chain walking function
+ * @fence: current chain node
+ *
+ * Walk the chain to the next node. Returns the next fence or NULL

if we are at
+ * the end of the chain. Garbage collects chain nodes which are already
+ * signaled.
+ */

drivers/dma-buf/dma-fence-chain.c new file +45 -0
+struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence)
+{
+    struct dma_fence_chain *chain, *prev_chain;
+    struct dma_fence *prev, *replacement, *tmp;
+
+    chain = to_dma_fence_chain(fence);
+    if (!chain) {
+        dma_fence_put(fence);
+        return NULL;
+    }
+
+    while ((prev = dma_fence_chain_get_prev(chain))) {
+
+        prev_chain = to_dma_fence_chain(prev);
+        if (prev_chain) {
+            if (!dma_fence_is_signaled(prev_chain->fence))
+                break;
+
+            replacement = dma_fence_chain_get_prev(prev_chain);
+        } else {
+            if (!dma_fence_is_signaled(prev))
+                break;
+
+            replacement = NULL;
+        }
+
+        tmp = cmpxchg(&chain->prev, prev, replacement);
+        if (tmp == prev)
+            dma_fence_put(tmp);
+        else
+            dma_fence_put(replacement);
+        dma_fence_put(prev);
+    }
+
+    dma_fence_put(fence);
+    return prev;
+}
+EXPORT_SYMBOL(dma_fence_chain_walk);
+
+/**
+ * dma_fence_chain_find_seqno - find fence chain node by seqno
+ * @pfence: pointer to the chain node where to start
+ * @seqno: the sequence number to search for
+ *
+ * Advance the fence pointer to the chain node which will signal

this sequence
+ * number. If no sequence number is provided then this is a no-op.
+ *
+ * Returns EINVAL if the fence is not a chain node or the sequence number has
+ * not yet advanced far enough.
+ */
+int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t seqno)

drivers/dma-buf/dma-fence-chain.c new file +22 -0
+{
+    struct dma_fence_chain *chain;
+
+    if (!seqno)
+        return 0;
+
+    chain = to_dma_fence_chain(*pfence);
+    if (!chain || chain->base.seqno < seqno)
+        return -EINVAL;
+
+    dma_fence_chain_for_each(*pfence, &chain->base) {
+        if ((*pfence)->context != chain->base.context ||
+            to_dma_fence_chain(*pfence)->prev_seqno < seqno)
+            break;
+    }
+    dma_fence_put(&chain->base);
+
+    return 0;
+}
+EXPORT_SYMBOL(dma_fence_chain_find_seqno);
+
+static const char *dma_fence_chain_get_driver_name(struct dma_fence

*fence)

drivers/dma-buf/dma-fence-chain.c new file +5 -0
+{
+        return "dma_fence_chain";
+}
+
+static const char *dma_fence_chain_get_timeline_name(struct

dma_fence *fence)

drivers/dma-buf/dma-fence-chain.c new file +18 -0
+{
+        return "unbound";
+}
+
+static void dma_fence_chain_irq_work(struct irq_work *work)
+{
+    struct dma_fence_chain *chain;
+
+    chain = container_of(work, typeof(*chain), work);
+
+    /* Try to rearm the callback */
+    if (!dma_fence_chain_enable_signaling(&chain->base))
+        /* Ok, we are done. No more unsignaled fences left */
+        dma_fence_signal(&chain->base);
+    dma_fence_put(&chain->base);
+}
+
+static void dma_fence_chain_cb(struct dma_fence *f, struct

dma_fence_cb *cb)

drivers/dma-buf/dma-fence-chain.c new file +19 -0
+{
+    struct dma_fence_chain *chain;
+
+    chain = container_of(cb, typeof(*chain), cb);
+    irq_work_queue(&chain->work);
+    dma_fence_put(f);
+}
+
+static bool dma_fence_chain_enable_signaling(struct dma_fence *fence)
+{
+    struct dma_fence_chain *head = to_dma_fence_chain(fence);
+
+    dma_fence_get(&head->base);
+    dma_fence_chain_for_each(fence, &head->base) {
+        struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+        struct dma_fence *f = chain ? chain->fence : fence;
+
+        dma_fence_get(f);
+        if (!dma_fence_add_callback(f, &head->cb,

dma_fence_chain_cb)) {
+            dma_fence_put(fence);
+            return true;
+        }
+        dma_fence_put(f);
+    }
+    dma_fence_put(&head->base);
+    return false;

drivers/dma-buf/dma-fence-chain.c new file +42 -0
+}
+
+static bool dma_fence_chain_signaled(struct dma_fence *fence)
+{
+    dma_fence_chain_for_each(fence, fence) {
+        struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+        struct dma_fence *f = chain ? chain->fence : fence;
+
+        if (!dma_fence_is_signaled(f)) {
+            dma_fence_put(fence);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void dma_fence_chain_release(struct dma_fence *fence)
+{
+    struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+
+    dma_fence_put(chain->prev);
+    dma_fence_put(chain->fence);
+    dma_fence_free(fence);
+}
+
+const struct dma_fence_ops dma_fence_chain_ops = {
+    .get_driver_name = dma_fence_chain_get_driver_name,
+    .get_timeline_name = dma_fence_chain_get_timeline_name,
+    .enable_signaling = dma_fence_chain_enable_signaling,
+    .signaled = dma_fence_chain_signaled,
+    .release = dma_fence_chain_release,
+};
+EXPORT_SYMBOL(dma_fence_chain_ops);
+
+/**
+ * dma_fence_chain_init - initialize a fence chain
+ * @chain: the chain node to initialize
+ * @prev: the previous fence
+ * @fence: the current fence
+ *
+ * Initialize a new chain node and either start a new chain or add

the node to
+ * the existing chain of the previous fence.
+ */

drivers/dma-buf/dma-fence-chain.c new file +29 -0
+void dma_fence_chain_init(struct dma_fence_chain *chain,
+              struct dma_fence *prev,
+              struct dma_fence *fence,
+              uint64_t seqno)
+{
+    struct dma_fence_chain *prev_chain = to_dma_fence_chain(prev);
+    uint64_t context;
+
+    spin_lock_init(&chain->lock);
+    chain->prev = prev;
+    chain->fence = fence;
+    chain->prev_seqno = 0;
+    init_irq_work(&chain->work, dma_fence_chain_irq_work);
+
+    /* Try to reuse the context of the previous chain node. */
+    if (prev_chain && __dma_fence_is_later(seqno, prev->seqno)) {
+        context = prev->context;
+        chain->prev_seqno = prev->seqno;
+    } else {
+        context = dma_fence_context_alloc(1);
+        /* Make sure that we always have a valid sequence number. */
+        if (prev_chain)
+            seqno = max(prev->seqno, seqno);
+    }
+
+    dma_fence_init(&chain->base, &dma_fence_chain_ops,
+               &chain->lock, context, seqno);
+}
+EXPORT_SYMBOL(dma_fence_chain_init);
include/linux/dma-fence-chain.h new file +8 -0
new file mode 100644
index 000000000000..a5c2e8c6915c
@@ -0,0 +1,81 @@
+/*
+ * fence-chain: chain fences together in a timeline
+ *
+ * Copyright (C) 2018 Advanced Micro Devices, Inc.
+ * Authors:
+ *    Christian König <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or

modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */

include/linux/dma-fence-chain.h new file +51 -0
+
+#ifndef __LINUX_DMA_FENCE_CHAIN_H
+#define __LINUX_DMA_FENCE_CHAIN_H
+
+#include <linux/dma-fence.h>
+#include <linux/irq_work.h>
+
+/**
+ * struct dma_fence_chain - fence to represent an node of a fence chain
+ * @base: fence base class
+ * @lock: spinlock for fence handling
+ * @prev: previous fence of the chain
+ * @prev_seqno: original previous seqno before garbage collection
+ * @fence: encapsulated fence
+ * @cb: callback structure for signaling
+ * @work: irq work item for signaling
+ */
+struct dma_fence_chain {
+    struct dma_fence base;
+    spinlock_t lock;
+    struct dma_fence *prev;
+    u64 prev_seqno;
+    struct dma_fence *fence;
+    struct dma_fence_cb cb;
+    struct irq_work work;
+};
+
+extern const struct dma_fence_ops dma_fence_chain_ops;
+
+/**
+ * to_dma_fence_chain - cast a fence to a dma_fence_chain
+ * @fence: fence to cast to a dma_fence_array
+ *
+ * Returns NULL if the fence is not a dma_fence_chain,
+ * or the dma_fence_chain otherwise.
+ */
+static inline struct dma_fence_chain *
+to_dma_fence_chain(struct dma_fence *fence)
+{
+    if (!fence || fence->ops != &dma_fence_chain_ops)
+        return NULL;
+
+    return container_of(fence, struct dma_fence_chain, base);
+}
+
+/**
+ * dma_fence_chain_for_each - iterate over all fences in chain
+ * @iter: current fence
+ * @head: starting point
+ *
+ * Iterate over all fences in the chain. We keep a reference to the

current
+ * fence while inside the loop which must be dropped when breaking out.
+ */

include/linux/dma-fence-chain.h new file +6 -0
+#define dma_fence_chain_for_each(iter, head)    \
+    for (iter = dma_fence_get(head); iter; \
+         iter = dma_fence_chain_walk(head))
+
+struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence);
+int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t

seqno);

include/linux/dma-fence-chain.h new file +6 -0
+void dma_fence_chain_init(struct dma_fence_chain *chain,
+              struct dma_fence *prev,
+              struct dma_fence *fence,
+              uint64_t seqno);
+
+#endif /* __LINUX_DMA_FENCE_CHAIN_H */

_______________________________________________
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): bbae2023-8dee-692e-9549-40779a202587-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org

#8 lore raw

Re: [PATCH 02/11] dma-buf: add new dma_fence_chain container v4

Am 15.02.19 um 16:52 schrieb Lionel Landwerlin:

Quoted 20 lines · Christian
Quoted 12 lines

Am 15.02.19 um 15:23 schrieb Lionel Landwerlin:

Quoted 11 lines

Hi Christian, David,

For timeline semaphore we need points to signaled in order. I'm struggling to understand how this fence-chain implementation preserves ordering of the seqnos.

One of the scenario I can see an issue happening is when you have a timeline with points 1 & 2 and userspace submits for 2 different engines :
     - first with let's say a blitter style engine on point 2
     - then a 3d style engine on point 1

Quoted 6 lines

Yeah, and where exactly is the problem?

Seqno 1 will signal when the 3d style engine finishes work.

And seqno 2 will signal when both seqno 1 is signaled and the blitter style engine has finished its work.

Quoted 6 lines

That's not really how I understood the spec, but I might be wrong.

What makes me thing 1 should be signaled as soon as 2 is signaled (regardless of whether the fence attached on point 1 is been signaled), is that the spec defines wait & signal operations in term of the value of the timeline.

That's what we had initially as well and it was rejected.

When 2 signals before 1 is signaled you can't call this a timeline any more.

Christian.

Quoted 423 lines

-Lionel

Quoted 418 lines
Quoted 3 lines

Another scenario would be signaling a timeline with points 1 & 2 with those points in reverse order in the submission array.

That is actually illegal in the spec, but actually handled gracefully as well.

E.g. when you add seqno 1 to the syncobj container it will only signal when 2 is signaled as well.

Regards,
Christian.

Quoted 402 lines

-Lionel

Quoted 398 lines · Chunming Zhou

From: Christian König <[email protected]>

Lockless container implementation similar to a dma_fence_array, but with only two elements per node and automatic garbage collection.

v2: properly document dma_fence_chain_for_each, add dma_fence_chain_find_seqno,
      drop prev reference during garbage collection if it's not a chain fence.
v3: use head and iterator for dma_fence_chain_for_each
v4: fix reference count in dma_fence_chain_enable_signaling

---
   drivers/dma-buf/Makefile          |   3 +- drivers/dma-buf/dma-fence-chain.c | 241
++++++++++++++++++++++++++++++
   include/linux/dma-fence-chain.h   |  81 ++++++++++

   3 files changed, 324 insertions(+), 1 deletion(-)

   create mode 100644 drivers/dma-buf/dma-fence-chain.c create mode 100644 include/linux/dma-fence-chain.h

drivers/dma-buf/Makefile +0 -1
index 0913a6ccab5a..1f006e083eb9 100644
@@ -1,4 +1,5 @@
-obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o

seqno-fence.o
+obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
+     reservation.o seqno-fence.o
   obj-$(CONFIG_SYNC_FILE)        += sync_file.o obj-$(CONFIG_SW_SYNC)        += sw_sync.o sync_debug.o obj-$(CONFIG_UDMABUF)        += udmabuf.o

drivers/dma-buf/dma-fence-chain.c new file +8 -0
new file mode 100644
index 000000000000..0c5e3c902fa0
@@ -0,0 +1,241 @@
+/*
+ * fence-chain: chain fences together in a timeline
+ *
+ * Copyright (C) 2018 Advanced Micro Devices, Inc.
+ * Authors:
+ *    Christian König <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or

modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */

drivers/dma-buf/dma-fence-chain.c new file +4 -0
+
+#include <linux/dma-fence-chain.h>
+
+static bool dma_fence_chain_enable_signaling(struct dma_fence 

*fence);

drivers/dma-buf/dma-fence-chain.c new file +3 -0
+
+/**
+ * dma_fence_chain_get_prev - use RCU to get a reference to the

previous fence
+ * @chain: chain node to get the previous node from
+ *
+ * Use dma_fence_get_rcu_safe to get a reference to the previous fence of the
+ * chain node.
+ */
+static struct dma_fence *dma_fence_chain_get_prev(struct dma_fence_chain *chain)

drivers/dma-buf/dma-fence-chain.c new file +14 -0
+{
+    struct dma_fence *prev;
+
+    rcu_read_lock();
+    prev = dma_fence_get_rcu_safe(&chain->prev);
+    rcu_read_unlock();
+    return prev;
+}
+
+/**
+ * dma_fence_chain_walk - chain walking function
+ * @fence: current chain node
+ *
+ * Walk the chain to the next node. Returns the next fence or NULL

if we are at
+ * the end of the chain. Garbage collects chain nodes which are already
+ * signaled.
+ */

drivers/dma-buf/dma-fence-chain.c new file +45 -0
+struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence)
+{
+    struct dma_fence_chain *chain, *prev_chain;
+    struct dma_fence *prev, *replacement, *tmp;
+
+    chain = to_dma_fence_chain(fence);
+    if (!chain) {
+        dma_fence_put(fence);
+        return NULL;
+    }
+
+    while ((prev = dma_fence_chain_get_prev(chain))) {
+
+        prev_chain = to_dma_fence_chain(prev);
+        if (prev_chain) {
+            if (!dma_fence_is_signaled(prev_chain->fence))
+                break;
+
+            replacement = dma_fence_chain_get_prev(prev_chain);
+        } else {
+            if (!dma_fence_is_signaled(prev))
+                break;
+
+            replacement = NULL;
+        }
+
+        tmp = cmpxchg(&chain->prev, prev, replacement);
+        if (tmp == prev)
+            dma_fence_put(tmp);
+        else
+            dma_fence_put(replacement);
+        dma_fence_put(prev);
+    }
+
+    dma_fence_put(fence);
+    return prev;
+}
+EXPORT_SYMBOL(dma_fence_chain_walk);
+
+/**
+ * dma_fence_chain_find_seqno - find fence chain node by seqno
+ * @pfence: pointer to the chain node where to start
+ * @seqno: the sequence number to search for
+ *
+ * Advance the fence pointer to the chain node which will signal

this sequence
+ * number. If no sequence number is provided then this is a no-op.
+ *
+ * Returns EINVAL if the fence is not a chain node or the sequence number has
+ * not yet advanced far enough.
+ */
+int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t seqno)

drivers/dma-buf/dma-fence-chain.c new file +22 -0
+{
+    struct dma_fence_chain *chain;
+
+    if (!seqno)
+        return 0;
+
+    chain = to_dma_fence_chain(*pfence);
+    if (!chain || chain->base.seqno < seqno)
+        return -EINVAL;
+
+    dma_fence_chain_for_each(*pfence, &chain->base) {
+        if ((*pfence)->context != chain->base.context ||
+            to_dma_fence_chain(*pfence)->prev_seqno < seqno)
+            break;
+    }
+    dma_fence_put(&chain->base);
+
+    return 0;
+}
+EXPORT_SYMBOL(dma_fence_chain_find_seqno);
+
+static const char *dma_fence_chain_get_driver_name(struct dma_fence

*fence)

drivers/dma-buf/dma-fence-chain.c new file +5 -0
+{
+        return "dma_fence_chain";
+}
+
+static const char *dma_fence_chain_get_timeline_name(struct

dma_fence *fence)

drivers/dma-buf/dma-fence-chain.c new file +18 -0
+{
+        return "unbound";
+}
+
+static void dma_fence_chain_irq_work(struct irq_work *work)
+{
+    struct dma_fence_chain *chain;
+
+    chain = container_of(work, typeof(*chain), work);
+
+    /* Try to rearm the callback */
+    if (!dma_fence_chain_enable_signaling(&chain->base))
+        /* Ok, we are done. No more unsignaled fences left */
+        dma_fence_signal(&chain->base);
+    dma_fence_put(&chain->base);
+}
+
+static void dma_fence_chain_cb(struct dma_fence *f, struct

dma_fence_cb *cb)

drivers/dma-buf/dma-fence-chain.c new file +19 -0
+{
+    struct dma_fence_chain *chain;
+
+    chain = container_of(cb, typeof(*chain), cb);
+    irq_work_queue(&chain->work);
+    dma_fence_put(f);
+}
+
+static bool dma_fence_chain_enable_signaling(struct dma_fence *fence)
+{
+    struct dma_fence_chain *head = to_dma_fence_chain(fence);
+
+    dma_fence_get(&head->base);
+    dma_fence_chain_for_each(fence, &head->base) {
+        struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+        struct dma_fence *f = chain ? chain->fence : fence;
+
+        dma_fence_get(f);
+        if (!dma_fence_add_callback(f, &head->cb,

dma_fence_chain_cb)) {
+            dma_fence_put(fence);
+            return true;
+        }
+        dma_fence_put(f);
+    }
+    dma_fence_put(&head->base);
+    return false;

drivers/dma-buf/dma-fence-chain.c new file +42 -0
+}
+
+static bool dma_fence_chain_signaled(struct dma_fence *fence)
+{
+    dma_fence_chain_for_each(fence, fence) {
+        struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+        struct dma_fence *f = chain ? chain->fence : fence;
+
+        if (!dma_fence_is_signaled(f)) {
+            dma_fence_put(fence);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void dma_fence_chain_release(struct dma_fence *fence)
+{
+    struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+
+    dma_fence_put(chain->prev);
+    dma_fence_put(chain->fence);
+    dma_fence_free(fence);
+}
+
+const struct dma_fence_ops dma_fence_chain_ops = {
+    .get_driver_name = dma_fence_chain_get_driver_name,
+    .get_timeline_name = dma_fence_chain_get_timeline_name,
+    .enable_signaling = dma_fence_chain_enable_signaling,
+    .signaled = dma_fence_chain_signaled,
+    .release = dma_fence_chain_release,
+};
+EXPORT_SYMBOL(dma_fence_chain_ops);
+
+/**
+ * dma_fence_chain_init - initialize a fence chain
+ * @chain: the chain node to initialize
+ * @prev: the previous fence
+ * @fence: the current fence
+ *
+ * Initialize a new chain node and either start a new chain or add

the node to
+ * the existing chain of the previous fence.
+ */

drivers/dma-buf/dma-fence-chain.c new file +29 -0
+void dma_fence_chain_init(struct dma_fence_chain *chain,
+              struct dma_fence *prev,
+              struct dma_fence *fence,
+              uint64_t seqno)
+{
+    struct dma_fence_chain *prev_chain = to_dma_fence_chain(prev);
+    uint64_t context;
+
+    spin_lock_init(&chain->lock);
+    chain->prev = prev;
+    chain->fence = fence;
+    chain->prev_seqno = 0;
+    init_irq_work(&chain->work, dma_fence_chain_irq_work);
+
+    /* Try to reuse the context of the previous chain node. */
+    if (prev_chain && __dma_fence_is_later(seqno, prev->seqno)) {
+        context = prev->context;
+        chain->prev_seqno = prev->seqno;
+    } else {
+        context = dma_fence_context_alloc(1);
+        /* Make sure that we always have a valid sequence number. */
+        if (prev_chain)
+            seqno = max(prev->seqno, seqno);
+    }
+
+    dma_fence_init(&chain->base, &dma_fence_chain_ops,
+               &chain->lock, context, seqno);
+}
+EXPORT_SYMBOL(dma_fence_chain_init);
include/linux/dma-fence-chain.h new file +8 -0
new file mode 100644
index 000000000000..a5c2e8c6915c
@@ -0,0 +1,81 @@
+/*
+ * fence-chain: chain fences together in a timeline
+ *
+ * Copyright (C) 2018 Advanced Micro Devices, Inc.
+ * Authors:
+ *    Christian König <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or

modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */

include/linux/dma-fence-chain.h new file +9 -0
+
+#ifndef __LINUX_DMA_FENCE_CHAIN_H
+#define __LINUX_DMA_FENCE_CHAIN_H
+
+#include <linux/dma-fence.h>
+#include <linux/irq_work.h>
+
+/**
+ * struct dma_fence_chain - fence to represent an node of a fence 

chain
+ * @base: fence base class
+ * @lock: spinlock for fence handling
+ * @prev: previous fence of the chain
+ * @prev_seqno: original previous seqno before garbage collection
+ * @fence: encapsulated fence
+ * @cb: callback structure for signaling
+ * @work: irq work item for signaling
+ */

include/linux/dma-fence-chain.h new file +34 -0
+struct dma_fence_chain {
+    struct dma_fence base;
+    spinlock_t lock;
+    struct dma_fence *prev;
+    u64 prev_seqno;
+    struct dma_fence *fence;
+    struct dma_fence_cb cb;
+    struct irq_work work;
+};
+
+extern const struct dma_fence_ops dma_fence_chain_ops;
+
+/**
+ * to_dma_fence_chain - cast a fence to a dma_fence_chain
+ * @fence: fence to cast to a dma_fence_array
+ *
+ * Returns NULL if the fence is not a dma_fence_chain,
+ * or the dma_fence_chain otherwise.
+ */
+static inline struct dma_fence_chain *
+to_dma_fence_chain(struct dma_fence *fence)
+{
+    if (!fence || fence->ops != &dma_fence_chain_ops)
+        return NULL;
+
+    return container_of(fence, struct dma_fence_chain, base);
+}
+
+/**
+ * dma_fence_chain_for_each - iterate over all fences in chain
+ * @iter: current fence
+ * @head: starting point
+ *
+ * Iterate over all fences in the chain. We keep a reference to the

current
+ * fence while inside the loop which must be dropped when breaking out.
+ */

include/linux/dma-fence-chain.h new file +6 -0
+#define dma_fence_chain_for_each(iter, head)    \
+    for (iter = dma_fence_get(head); iter; \
+         iter = dma_fence_chain_walk(head))
+
+struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence);
+int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t

seqno);

include/linux/dma-fence-chain.h new file +6 -0
+void dma_fence_chain_init(struct dma_fence_chain *chain,
+              struct dma_fence *prev,
+              struct dma_fence *fence,
+              uint64_t seqno);
+
+#endif /* __LINUX_DMA_FENCE_CHAIN_H */

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

#9 lore raw

Re: [PATCH 02/11] dma-buf: add new dma_fence_chain container v4

In reply to Lionel Landwerlin via amd-gfx
Quoted 13 lines · Lionel Landwerlin via dri-devel
Quoted 12 lines · Christian

Am 15.02.19 um 15:23 schrieb Lionel Landwerlin:

Quoted 11 lines

Hi Christian, David,

For timeline semaphore we need points to signaled in order. I'm struggling to understand how this fence-chain implementation preserves ordering of the seqnos.

One of the scenario I can see an issue happening is when you have a timeline with points 1 & 2 and userspace submits for 2 different engines :
- first with let's say a blitter style engine on point 2
- then a 3d style engine on point 1

Quoted 7 lines
Quoted 6 lines

Yeah, and where exactly is the problem?

Seqno 1 will signal when the 3d style engine finishes work.

And seqno 2 will signal when both seqno 1 is signaled and the blitter style engine has finished its work.

That's an interesting interpretation of the spec. I think it's legal and I could see that behavior may be desirable in some ways.

Quoted 19 lines

That's not really how I understood the spec, but I might be wrong.

What makes me thing 1 should be signaled as soon as 2 is signaled (regardless of whether the fence attached on point 1 is been signaled), is that the spec defines wait & signal operations in term of the value of the timeline.

-Lionel

Quoted 8 lines
Quoted 3 lines

Another scenario would be signaling a timeline with points 1 & 2 with those points in reverse order in the submission array.

That is actually illegal in the spec, but actually handled gracefully as well.

E.g. when you add seqno 1 to the syncobj container it will only signal when 2 is signaled as well.

I think what Christian is suggesting is a valid interpretation of the spec though it is rather unconventional. The Vulkan spec, as it stands today, requires that the application ensure that at the time of signaling, the timeline semaphore value increases. This means that all of the above possible cases are technically illegal in Vulkan and so it doesn't really matter what we do as long as we don't do anyting especially stupid.

My understanding of how this works on Windows is that a wait operation on 3 is a wait until x >= 3 where x is a 64-bit value and a signal operation is simply a write to x. This means that, in the above cases, waits on 1 will be triggered immediately when 2 is written but waits on 2 may or may not happen at all depending on whether the GPU write which overwrites x to 1 or the CPU (or potentially GPU in a different context) read gets there first such that the reader observes 2. If you mess this up and something isn't signaled, that's your fault.

Instead of specifying things to be exactly the Windows behavior, Vulkan says that you must only ever increase the value and anything else is illegal and therefore leads to undefined behavior. The usual consequences of undefined behavior apply: anything can happen up to and including process termination. In other words, how we handle those cases is completely up to us as long as we do something sane that doesn't result in kernel crashes or anything like that. We do have to handle it in some way because we can't outright prevent those cases from happening. The question then becomes what's the best way for the behavior to degrade.

In my opinion, the smoothest degredation is if you take the windows model and replace the 64-bit write to x with a 64-bit atomic MAX operation. In other words, signaling 2 automatically unblocks 1 and any attempt to signal a value lower than the current value is a no-op. It has a few nice advantages:

1. Signaling N is guaranteed to unblock everything waiting on n <= N
regardless of what else may be pending.
2. It matches what I think is the next natural evolution of the Windows
model where the write is replaced with an atomic.
3. It gracefully handles the case where the operation to signal 1 is added
after the one to signal 2. We can also make this case illegal but this model extends to one in which it could be legal and well-defined.
4. If you do get into a sticky situation, you can unblock an entire
timeline by using the CPU signal ioctl to set it to a high value.

Of all these reasons, I think 1 and 2 carry the most weight. 2, in particular, is interesting if we one day want to implement the same behavior with a simple 64-bit value like Windows does. Immagine, for instance, a scenario where the GPU is doing it's own scheduling or command buffers are submitted ahead of the signal operation being available and told to just sit on the GPU until they see x >= 3. (Yes, there are issues here with residency, contention, etc. I'm asking you to use your immagination.) Assuming you can do 64-bit atomics (there are aparently issues here with PCIe that make things sticky), the behavior I'm suggesting is completely implementable in that way whereas the behavior Christian is suggesting is only implementable if you're maintaining a CPU-side list of fences. I don't think we want to paint ourselves into that corner.

--Jason

Quoted 407 lines
Quoted 10 lines

Regards,
Christian.

Quoted 6 lines

-Lionel

Quoted 3 lines · Chunming Zhou

From: Christian König <[email protected]>

Lockless container implementation similar to a dma_fence_array, but

with

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

only two elements per node and automatic garbage collection.

v2: properly document dma_fence_chain_for_each, add dma_fence_chain_find_seqno,
drop prev reference during garbage collection if it's not a
chain fence.
v3: use head and iterator for dma_fence_chain_for_each
v4: fix reference count in dma_fence_chain_enable_signaling

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
---
   drivers/dma-buf/Makefile          |   3 +-
   drivers/dma-buf/dma-fence-chain.c | 241

++++++++++++++++++++++++++++++

Quoted 69 lines
Quoted 69 lines
Quoted 69 lines
   include/linux/dma-fence-chain.h   |  81 ++++++++++
   3 files changed, 324 insertions(+), 1 deletion(-)

create mode 100644 drivers/dma-buf/dma-fence-chain.c create mode 100644 include/linux/dma-fence-chain.h

drivers/dma-buf/Makefile +0 -1
index 0913a6ccab5a..1f006e083eb9 100644
@@ -1,4 +1,5 @@
-obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o

seqno-fence.o

drivers/dma-buf/Makefile +2 -0
+obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
+     reservation.o seqno-fence.o
   obj-$(CONFIG_SYNC_FILE)        += sync_file.o
   obj-$(CONFIG_SW_SYNC)        += sw_sync.o sync_debug.o
   obj-$(CONFIG_UDMABUF)        += udmabuf.o
drivers/dma-buf/dma-fence-chain.c new file +8 -0
new file mode 100644
index 000000000000..0c5e3c902fa0
@@ -0,0 +1,241 @@
+/*
+ * fence-chain: chain fences together in a timeline
+ *
+ * Copyright (C) 2018 Advanced Micro Devices, Inc.
+ * Authors:
+ *    Christian König <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or

modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */

drivers/dma-buf/dma-fence-chain.c new file +7 -0
+
+#include <linux/dma-fence-chain.h>
+
+static bool dma_fence_chain_enable_signaling(struct dma_fence *fence);
+
+/**
+ * dma_fence_chain_get_prev - use RCU to get a reference to the

previous fence
+ * @chain: chain node to get the previous node from
+ *
+ * Use dma_fence_get_rcu_safe to get a reference to the previous fence of the
+ * chain node.
+ */
+static struct dma_fence *dma_fence_chain_get_prev(struct dma_fence_chain *chain)

drivers/dma-buf/dma-fence-chain.c new file +8 -0
+{
+    struct dma_fence *prev;
+
+    rcu_read_lock();
+    prev = dma_fence_get_rcu_safe(&chain->prev);
+    rcu_read_unlock();
+    return prev;
+}
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma-buf/dma-fence-chain.c new file +6 -0
+
+/**
+ * dma_fence_chain_walk - chain walking function
+ * @fence: current chain node
+ *
+ * Walk the chain to the next node. Returns the next fence or NULL

if we are at
+ * the end of the chain. Garbage collects chain nodes which are

already

Quoted 234 lines
Quoted 234 lines
Quoted 234 lines

+ * signaled.
+ */

drivers/dma-buf/dma-fence-chain.c new file +45 -0
+struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence)
+{
+    struct dma_fence_chain *chain, *prev_chain;
+    struct dma_fence *prev, *replacement, *tmp;
+
+    chain = to_dma_fence_chain(fence);
+    if (!chain) {
+        dma_fence_put(fence);
+        return NULL;
+    }
+
+    while ((prev = dma_fence_chain_get_prev(chain))) {
+
+        prev_chain = to_dma_fence_chain(prev);
+        if (prev_chain) {
+            if (!dma_fence_is_signaled(prev_chain->fence))
+                break;
+
+            replacement = dma_fence_chain_get_prev(prev_chain);
+        } else {
+            if (!dma_fence_is_signaled(prev))
+                break;
+
+            replacement = NULL;
+        }
+
+        tmp = cmpxchg(&chain->prev, prev, replacement);
+        if (tmp == prev)
+            dma_fence_put(tmp);
+        else
+            dma_fence_put(replacement);
+        dma_fence_put(prev);
+    }
+
+    dma_fence_put(fence);
+    return prev;
+}
+EXPORT_SYMBOL(dma_fence_chain_walk);
+
+/**
+ * dma_fence_chain_find_seqno - find fence chain node by seqno
+ * @pfence: pointer to the chain node where to start
+ * @seqno: the sequence number to search for
+ *
+ * Advance the fence pointer to the chain node which will signal

this sequence
+ * number. If no sequence number is provided then this is a no-op.
+ *
+ * Returns EINVAL if the fence is not a chain node or the sequence number has
+ * not yet advanced far enough.
+ */
+int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t seqno)

drivers/dma-buf/dma-fence-chain.c new file +22 -0
+{
+    struct dma_fence_chain *chain;
+
+    if (!seqno)
+        return 0;
+
+    chain = to_dma_fence_chain(*pfence);
+    if (!chain || chain->base.seqno < seqno)
+        return -EINVAL;
+
+    dma_fence_chain_for_each(*pfence, &chain->base) {
+        if ((*pfence)->context != chain->base.context ||
+            to_dma_fence_chain(*pfence)->prev_seqno < seqno)
+            break;
+    }
+    dma_fence_put(&chain->base);
+
+    return 0;
+}
+EXPORT_SYMBOL(dma_fence_chain_find_seqno);
+
+static const char *dma_fence_chain_get_driver_name(struct dma_fence

*fence)

drivers/dma-buf/dma-fence-chain.c new file +5 -0
+{
+        return "dma_fence_chain";
+}
+
+static const char *dma_fence_chain_get_timeline_name(struct

dma_fence *fence)

drivers/dma-buf/dma-fence-chain.c new file +18 -0
+{
+        return "unbound";
+}
+
+static void dma_fence_chain_irq_work(struct irq_work *work)
+{
+    struct dma_fence_chain *chain;
+
+    chain = container_of(work, typeof(*chain), work);
+
+    /* Try to rearm the callback */
+    if (!dma_fence_chain_enable_signaling(&chain->base))
+        /* Ok, we are done. No more unsignaled fences left */
+        dma_fence_signal(&chain->base);
+    dma_fence_put(&chain->base);
+}
+
+static void dma_fence_chain_cb(struct dma_fence *f, struct

dma_fence_cb *cb)

drivers/dma-buf/dma-fence-chain.c new file +19 -0
+{
+    struct dma_fence_chain *chain;
+
+    chain = container_of(cb, typeof(*chain), cb);
+    irq_work_queue(&chain->work);
+    dma_fence_put(f);
+}
+
+static bool dma_fence_chain_enable_signaling(struct dma_fence *fence)
+{
+    struct dma_fence_chain *head = to_dma_fence_chain(fence);
+
+    dma_fence_get(&head->base);
+    dma_fence_chain_for_each(fence, &head->base) {
+        struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+        struct dma_fence *f = chain ? chain->fence : fence;
+
+        dma_fence_get(f);
+        if (!dma_fence_add_callback(f, &head->cb,

dma_fence_chain_cb)) {

drivers/dma-buf/dma-fence-chain.c new file +49 -0
+            dma_fence_put(fence);
+            return true;
+        }
+        dma_fence_put(f);
+    }
+    dma_fence_put(&head->base);
+    return false;
+}
+
+static bool dma_fence_chain_signaled(struct dma_fence *fence)
+{
+    dma_fence_chain_for_each(fence, fence) {
+        struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+        struct dma_fence *f = chain ? chain->fence : fence;
+
+        if (!dma_fence_is_signaled(f)) {
+            dma_fence_put(fence);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void dma_fence_chain_release(struct dma_fence *fence)
+{
+    struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+
+    dma_fence_put(chain->prev);
+    dma_fence_put(chain->fence);
+    dma_fence_free(fence);
+}
+
+const struct dma_fence_ops dma_fence_chain_ops = {
+    .get_driver_name = dma_fence_chain_get_driver_name,
+    .get_timeline_name = dma_fence_chain_get_timeline_name,
+    .enable_signaling = dma_fence_chain_enable_signaling,
+    .signaled = dma_fence_chain_signaled,
+    .release = dma_fence_chain_release,
+};
+EXPORT_SYMBOL(dma_fence_chain_ops);
+
+/**
+ * dma_fence_chain_init - initialize a fence chain
+ * @chain: the chain node to initialize
+ * @prev: the previous fence
+ * @fence: the current fence
+ *
+ * Initialize a new chain node and either start a new chain or add

the node to
+ * the existing chain of the previous fence.
+ */

drivers/dma-buf/dma-fence-chain.c new file +29 -0
+void dma_fence_chain_init(struct dma_fence_chain *chain,
+              struct dma_fence *prev,
+              struct dma_fence *fence,
+              uint64_t seqno)
+{
+    struct dma_fence_chain *prev_chain = to_dma_fence_chain(prev);
+    uint64_t context;
+
+    spin_lock_init(&chain->lock);
+    chain->prev = prev;
+    chain->fence = fence;
+    chain->prev_seqno = 0;
+    init_irq_work(&chain->work, dma_fence_chain_irq_work);
+
+    /* Try to reuse the context of the previous chain node. */
+    if (prev_chain && __dma_fence_is_later(seqno, prev->seqno)) {
+        context = prev->context;
+        chain->prev_seqno = prev->seqno;
+    } else {
+        context = dma_fence_context_alloc(1);
+        /* Make sure that we always have a valid sequence number. */
+        if (prev_chain)
+            seqno = max(prev->seqno, seqno);
+    }
+
+    dma_fence_init(&chain->base, &dma_fence_chain_ops,
+               &chain->lock, context, seqno);
+}
+EXPORT_SYMBOL(dma_fence_chain_init);
include/linux/dma-fence-chain.h new file +8 -0
new file mode 100644
index 000000000000..a5c2e8c6915c
@@ -0,0 +1,81 @@
+/*
+ * fence-chain: chain fences together in a timeline
+ *
+ * Copyright (C) 2018 Advanced Micro Devices, Inc.
+ * Authors:
+ *    Christian König <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or

modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+

Quoted 8 lines
Quoted 8 lines

include/linux/dma-fence-chain.h

Quoted 8 lines
include/linux/dma-fence-chain.h new file +8 -0
+#ifndef __LINUX_DMA_FENCE_CHAIN_H
+#define __LINUX_DMA_FENCE_CHAIN_H
+
+#include <linux/dma-fence.h>
+#include <linux/irq_work.h>
+
+/**
+ * struct dma_fence_chain - fence to represent an node of a fence

chain

Quoted 36 lines
Quoted 36 lines
Quoted 36 lines

+ * @base: fence base class
+ * @lock: spinlock for fence handling
+ * @prev: previous fence of the chain
+ * @prev_seqno: original previous seqno before garbage collection
+ * @fence: encapsulated fence
+ * @cb: callback structure for signaling
+ * @work: irq work item for signaling
+ */

include/linux/dma-fence-chain.h new file +28 -0
+struct dma_fence_chain {
+    struct dma_fence base;
+    spinlock_t lock;
+    struct dma_fence *prev;
+    u64 prev_seqno;
+    struct dma_fence *fence;
+    struct dma_fence_cb cb;
+    struct irq_work work;
+};
+
+extern const struct dma_fence_ops dma_fence_chain_ops;
+
+/**
+ * to_dma_fence_chain - cast a fence to a dma_fence_chain
+ * @fence: fence to cast to a dma_fence_array
+ *
+ * Returns NULL if the fence is not a dma_fence_chain,
+ * or the dma_fence_chain otherwise.
+ */
+static inline struct dma_fence_chain *
+to_dma_fence_chain(struct dma_fence *fence)
+{
+    if (!fence || fence->ops != &dma_fence_chain_ops)
+        return NULL;
+
+    return container_of(fence, struct dma_fence_chain, base);
+}
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

+/**
+ * dma_fence_chain_for_each - iterate over all fences in chain
+ * @iter: current fence
+ * @head: starting point
+ *
+ * Iterate over all fences in the chain. We keep a reference to the current
+ * fence while inside the loop which must be dropped when breaking

out.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

+ */

include/linux/dma-fence-chain.h new file +6 -0
+#define dma_fence_chain_for_each(iter, head)    \
+    for (iter = dma_fence_get(head); iter; \
+         iter = dma_fence_chain_walk(head))
+
+struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence);
+int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t
Quoted 8 lines
Quoted 8 lines

include/linux/dma-fence-chain.h line 81

Quoted 7 lines

seqno);

include/linux/dma-fence-chain.h new file +6 -0
+void dma_fence_chain_init(struct dma_fence_chain *chain,
+              struct dma_fence *prev,
+              struct dma_fence *fence,
+              uint64_t seqno);
+
+#endif /* __LINUX_DMA_FENCE_CHAIN_H */
Quoted 4 lines

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

_______________________________________________
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): CAOFGe96HUkzHPJKYT-07X3vMvCRD-=Hba1=Ke24qt_PY2vn0YQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#11 lore raw

Re: [PATCH 02/11] dma-buf: add new dma_fence_chain container v4

Am 15.02.19 um 17:49 schrieb Jason Ekstrand:

Quoted 17 lines · On Fri, Feb 15, 2019 at 9:52 AM Lionel Landwerlin via dri-devel…

On 15/02/2019 14:32, Koenig, Christian wrote:
> Am 15.02.19 um 15:23 schrieb Lionel Landwerlin:
>> Hi Christian, David,
>>
>> For timeline semaphore we need points to signaled in order. >> I'm struggling to understand how this fence-chain implementation >> preserves ordering of the seqnos.
>>
>> One of the scenario I can see an issue happening is when you have a >> timeline with points 1 & 2 and userspace submits for 2 different >> engines :
>>      - first with let's say a blitter style engine on point 2 >>      - then a 3d style engine on point 1
> Yeah, and where exactly is the problem?
>

Quoted 8 lines

> Seqno 1 will signal when the 3d style engine finishes work. >
> And seqno 2 will signal when both seqno 1 is signaled and the blitter
> style engine has finished its work.

That's an interesting interpretation of the spec.  I think it's legal and I could see that behavior may be desirable in some ways.

Well we actually had this discussion multiple times now, both internally as well as on the mailing list. Please also see the previous mails with Daniel on this topic.

My initial suggestion was actually to exactly what Leonid suggested as well.

And following this I used a rather simple container for the implementation, e.g. just a ring buffer indexed by the sequence number. In this scenario userspace can specify on syncobj creation time how big the window for sequence numbers should be, e.g. in this implementation how big the ring buffer would be.

This was rejected by our guys who actually wrote a good part of the Vulkan specification. Daniel then has gone into the same direction during the public discussion.

[SNIP]

Quoted 1 line

I think what Christian is suggesting is a valid interpretation of the spec though it is rather unconventional.  The Vulkan spec, as it stands today, requires that the application ensure that at the time of signaling, the timeline semaphore value increases.  This means that all of the above possible cases are technically illegal in Vulkan and so it doesn't really matter what we do as long as we don't do anyting especially stupid.

And exactly that's the point. When an application does something stupid with its own submissions then this is not much of a problem.

But this interface is meant to be made for communication between processes, and here we want to be sure that nobody can do anything stupid.

Quoted 1 line

My understanding of how this works on Windows is that a wait operation on 3 is a wait until x >= 3 where x is a 64-bit value and a signal operation is simply a write to x. This means that, in the above cases, waits on 1 will be triggered immediately when 2 is written but waits on 2 may or may not happen at all depending on whether the GPU write which overwrites x to 1 or the CPU (or potentially GPU in a different context) read gets there first such that the reader observes 2.  If you mess this up and something isn't signaled, that's your fault.

Yeah and I think that this is actually not a good idea at all. Implementing it like this ultimately means that you can only use polling on the number.

Quoted 1 line

 4. If you do get into a sticky situation, you can unblock an entire timeline by using the CPU signal ioctl to set it to a high value.

Well I think that this could be problematic as well. Keep in mind that main use case for this is sharing timelines between processes.

In other words you don't want applications to be able to mess with it to much.

Quoted 2 lines

Of all these reasons, I think 1 and 2 carry the most weight.  2, in particular, is interesting if we one day want to implement the same behavior with a simple 64-bit value like Windows does.  Immagine, for instance, a scenario where the GPU is doing it's own scheduling or command buffers are submitted ahead of the signal operation being available and told to just sit on the GPU until they see x >= 3.  (Yes, there are issues here with residency, contention, etc.  I'm asking you to use your immagination.)  Assuming you can do 64-bit atomics (there are aparently issues here with PCIe that make things sticky), the behavior I'm suggesting is completely implementable in that way whereas the behavior Christian is suggesting is only implementable if you're maintaining a CPU-side list of fences.  I don't think we want to paint ourselves into that corner.

Actually we already had such an implementation with radeon. And I can only say that it was a totally PAIN IN THE A* to maintain.

This is one of the reason why we are not using hardware semaphores any more with amdgpu.

Regards,
Christian.

Quoted 428 lines

--Jason

Quoted 8 lines

Regards,
Christian.

Quoted 4 lines

-Lionel

Quoted 1 line · Chunming Zhou

From: Christian König <[email protected]

    <mailto:[email protected]>>
    >>>
    >>> Lockless container implementation similar to a
    dma_fence_array, but with
    >>> only two elements per node and automatic garbage collection.
    >>>
    >>> v2: properly document dma_fence_chain_for_each, add
    >>> dma_fence_chain_find_seqno,
    >>>       drop prev reference during garbage collection if it's not a
    >>> chain fence.
    >>> v3: use head and iterator for dma_fence_chain_for_each
    >>> v4: fix reference count in dma_fence_chain_enable_signaling
    >>>
    >>> Signed-off-by: Christian König <[email protected]
    <mailto:[email protected]>>
    >>> ---
    >>>    drivers/dma-buf/Makefile          |   3 +-
    >>>    drivers/dma-buf/dma-fence-chain.c | 241
    ++++++++++++++++++++++++++++++
    >>>    include/linux/dma-fence-chain.h   |  81 ++++++++++
    >>>    3 files changed, 324 insertions(+), 1 deletion(-)
    >>>    create mode 100644 drivers/dma-buf/dma-fence-chain.c
    >>>    create mode 100644 include/linux/dma-fence-chain.h
    >>>
    >>> diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
    >>> index 0913a6ccab5a..1f006e083eb9 100644
    >>> --- a/drivers/dma-buf/Makefile
    >>> +++ b/drivers/dma-buf/Makefile
    >>> @@ -1,4 +1,5 @@
    >>> -obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o
    >>> seqno-fence.o
    >>> +obj-y := dma-buf.o dma-fence.o dma-fence-array.o
    dma-fence-chain.o \
    >>> +     reservation.o seqno-fence.o
    >>>    obj-$(CONFIG_SYNC_FILE)        += sync_file.o
    >>>    obj-$(CONFIG_SW_SYNC)        += sw_sync.o sync_debug.o
    >>>    obj-$(CONFIG_UDMABUF)        += udmabuf.o
    >>> diff --git a/drivers/dma-buf/dma-fence-chain.c
    >>> b/drivers/dma-buf/dma-fence-chain.c
    >>> new file mode 100644
    >>> index 000000000000..0c5e3c902fa0
    >>> --- /dev/null
    >>> +++ b/drivers/dma-buf/dma-fence-chain.c
    >>> @@ -0,0 +1,241 @@
    >>> +/*
    >>> + * fence-chain: chain fences together in a timeline
    >>> + *
    >>> + * Copyright (C) 2018 Advanced Micro Devices, Inc.
    >>> + * Authors:
    >>> + *    Christian König <[email protected]
    <mailto:[email protected]>>
    >>> + *
    >>> + * This program is free software; you can redistribute it and/or
    >>> modify it
    >>> + * under the terms of the GNU General Public License version 2 as
    >>> published by
    >>> + * the Free Software Foundation.
    >>> + *
    >>> + * This program is distributed in the hope that it will be
    useful,
    >>> but WITHOUT
    >>> + * ANY WARRANTY; without even the implied warranty of
    >>> MERCHANTABILITY or
    >>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
    >>> License for
    >>> + * more details.
    >>> + */
    >>> +
    >>> +#include <linux/dma-fence-chain.h>
    >>> +
    >>> +static bool dma_fence_chain_enable_signaling(struct dma_fence
    *fence);
    >>> +
    >>> +/**
    >>> + * dma_fence_chain_get_prev - use RCU to get a reference to the
    >>> previous fence
    >>> + * @chain: chain node to get the previous node from
    >>> + *
    >>> + * Use dma_fence_get_rcu_safe to get a reference to the previous
    >>> fence of the
    >>> + * chain node.
    >>> + */
    >>> +static struct dma_fence *dma_fence_chain_get_prev(struct
    >>> dma_fence_chain *chain)
    >>> +{
    >>> +    struct dma_fence *prev;
    >>> +
    >>> +    rcu_read_lock();
    >>> +    prev = dma_fence_get_rcu_safe(&chain->prev);
    >>> +    rcu_read_unlock();
    >>> +    return prev;
    >>> +}
    >>> +
    >>> +/**
    >>> + * dma_fence_chain_walk - chain walking function
    >>> + * @fence: current chain node
    >>> + *
    >>> + * Walk the chain to the next node. Returns the next fence or
    NULL
    >>> if we are at
    >>> + * the end of the chain. Garbage collects chain nodes which
    are already
    >>> + * signaled.
    >>> + */
    >>> +struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence)
    >>> +{
    >>> +    struct dma_fence_chain *chain, *prev_chain;
    >>> +    struct dma_fence *prev, *replacement, *tmp;
    >>> +
    >>> +    chain = to_dma_fence_chain(fence);
    >>> +    if (!chain) {
    >>> +        dma_fence_put(fence);
    >>> +        return NULL;
    >>> +    }
    >>> +
    >>> +    while ((prev = dma_fence_chain_get_prev(chain))) {
    >>> +
    >>> +        prev_chain = to_dma_fence_chain(prev);
    >>> +        if (prev_chain) {
    >>> +            if (!dma_fence_is_signaled(prev_chain->fence))
    >>> +                break;
    >>> +
    >>> +            replacement = dma_fence_chain_get_prev(prev_chain);
    >>> +        } else {
    >>> +            if (!dma_fence_is_signaled(prev))
    >>> +                break;
    >>> +
    >>> +            replacement = NULL;
    >>> +        }
    >>> +
    >>> +        tmp = cmpxchg(&chain->prev, prev, replacement);
    >>> +        if (tmp == prev)
    >>> +            dma_fence_put(tmp);
    >>> +        else
    >>> +            dma_fence_put(replacement);
    >>> +        dma_fence_put(prev);
    >>> +    }
    >>> +
    >>> +    dma_fence_put(fence);
    >>> +    return prev;
    >>> +}
    >>> +EXPORT_SYMBOL(dma_fence_chain_walk);
    >>> +
    >>> +/**
    >>> + * dma_fence_chain_find_seqno - find fence chain node by seqno
    >>> + * @pfence: pointer to the chain node where to start
    >>> + * @seqno: the sequence number to search for
    >>> + *
    >>> + * Advance the fence pointer to the chain node which will signal
    >>> this sequence
    >>> + * number. If no sequence number is provided then this is a
    no-op.
    >>> + *
    >>> + * Returns EINVAL if the fence is not a chain node or the
    sequence
    >>> number has
    >>> + * not yet advanced far enough.
    >>> + */
    >>> +int dma_fence_chain_find_seqno(struct dma_fence **pfence,
    uint64_t
    >>> seqno)
    >>> +{
    >>> +    struct dma_fence_chain *chain;
    >>> +
    >>> +    if (!seqno)
    >>> +        return 0;
    >>> +
    >>> +    chain = to_dma_fence_chain(*pfence);
    >>> +    if (!chain || chain->base.seqno < seqno)
    >>> +        return -EINVAL;
    >>> +
    >>> +    dma_fence_chain_for_each(*pfence, &chain->base) {
    >>> +        if ((*pfence)->context != chain->base.context ||
    >>> + to_dma_fence_chain(*pfence)->prev_seqno < seqno)
    >>> +            break;
    >>> +    }
    >>> +    dma_fence_put(&chain->base);
    >>> +
    >>> +    return 0;
    >>> +}
    >>> +EXPORT_SYMBOL(dma_fence_chain_find_seqno);
    >>> +
    >>> +static const char *dma_fence_chain_get_driver_name(struct
    dma_fence
    >>> *fence)
    >>> +{
    >>> +        return "dma_fence_chain";
    >>> +}
    >>> +
    >>> +static const char *dma_fence_chain_get_timeline_name(struct
    >>> dma_fence *fence)
    >>> +{
    >>> +        return "unbound";
    >>> +}
    >>> +
    >>> +static void dma_fence_chain_irq_work(struct irq_work *work)
    >>> +{
    >>> +    struct dma_fence_chain *chain;
    >>> +
    >>> +    chain = container_of(work, typeof(*chain), work);
    >>> +
    >>> +    /* Try to rearm the callback */
    >>> +    if (!dma_fence_chain_enable_signaling(&chain->base))
    >>> +        /* Ok, we are done. No more unsignaled fences left */
    >>> +        dma_fence_signal(&chain->base);
    >>> +    dma_fence_put(&chain->base);
    >>> +}
    >>> +
    >>> +static void dma_fence_chain_cb(struct dma_fence *f, struct
    >>> dma_fence_cb *cb)
    >>> +{
    >>> +    struct dma_fence_chain *chain;
    >>> +
    >>> +    chain = container_of(cb, typeof(*chain), cb);
    >>> +    irq_work_queue(&chain->work);
    >>> +    dma_fence_put(f);
    >>> +}
    >>> +
    >>> +static bool dma_fence_chain_enable_signaling(struct dma_fence
    *fence)
    >>> +{
    >>> +    struct dma_fence_chain *head = to_dma_fence_chain(fence);
    >>> +
    >>> +    dma_fence_get(&head->base);
    >>> +    dma_fence_chain_for_each(fence, &head->base) {
    >>> +        struct dma_fence_chain *chain =
    to_dma_fence_chain(fence);
    >>> +        struct dma_fence *f = chain ? chain->fence : fence;
    >>> +
    >>> +        dma_fence_get(f);
    >>> +        if (!dma_fence_add_callback(f, &head->cb,
    >>> dma_fence_chain_cb)) {
    >>> +            dma_fence_put(fence);
    >>> +            return true;
    >>> +        }
    >>> +        dma_fence_put(f);
    >>> +    }
    >>> +    dma_fence_put(&head->base);
    >>> +    return false;
    >>> +}
    >>> +
    >>> +static bool dma_fence_chain_signaled(struct dma_fence *fence)
    >>> +{
    >>> +    dma_fence_chain_for_each(fence, fence) {
    >>> +        struct dma_fence_chain *chain =
    to_dma_fence_chain(fence);
    >>> +        struct dma_fence *f = chain ? chain->fence : fence;
    >>> +
    >>> +        if (!dma_fence_is_signaled(f)) {
    >>> +            dma_fence_put(fence);
    >>> +            return false;
    >>> +        }
    >>> +    }
    >>> +
    >>> +    return true;
    >>> +}
    >>> +
    >>> +static void dma_fence_chain_release(struct dma_fence *fence)
    >>> +{
    >>> +    struct dma_fence_chain *chain = to_dma_fence_chain(fence);
    >>> +
    >>> +    dma_fence_put(chain->prev);
    >>> +    dma_fence_put(chain->fence);
    >>> +    dma_fence_free(fence);
    >>> +}
    >>> +
    >>> +const struct dma_fence_ops dma_fence_chain_ops = {
    >>> +    .get_driver_name = dma_fence_chain_get_driver_name,
    >>> +    .get_timeline_name = dma_fence_chain_get_timeline_name,
    >>> +    .enable_signaling = dma_fence_chain_enable_signaling,
    >>> +    .signaled = dma_fence_chain_signaled,
    >>> +    .release = dma_fence_chain_release,
    >>> +};
    >>> +EXPORT_SYMBOL(dma_fence_chain_ops);
    >>> +
    >>> +/**
    >>> + * dma_fence_chain_init - initialize a fence chain
    >>> + * @chain: the chain node to initialize
    >>> + * @prev: the previous fence
    >>> + * @fence: the current fence
    >>> + *
    >>> + * Initialize a new chain node and either start a new chain
    or add
    >>> the node to
    >>> + * the existing chain of the previous fence.
    >>> + */
    >>> +void dma_fence_chain_init(struct dma_fence_chain *chain,
    >>> +              struct dma_fence *prev,
    >>> +              struct dma_fence *fence,
    >>> +              uint64_t seqno)
    >>> +{
    >>> +    struct dma_fence_chain *prev_chain =
    to_dma_fence_chain(prev);
    >>> +    uint64_t context;
    >>> +
    >>> +    spin_lock_init(&chain->lock);
    >>> +    chain->prev = prev;
    >>> +    chain->fence = fence;
    >>> +    chain->prev_seqno = 0;
    >>> +    init_irq_work(&chain->work, dma_fence_chain_irq_work);
    >>> +
    >>> +    /* Try to reuse the context of the previous chain node. */
    >>> +    if (prev_chain && __dma_fence_is_later(seqno, prev->seqno)) {
    >>> +        context = prev->context;
    >>> +        chain->prev_seqno = prev->seqno;
    >>> +    } else {
    >>> +        context = dma_fence_context_alloc(1);
    >>> +        /* Make sure that we always have a valid sequence
    number. */
    >>> +        if (prev_chain)
    >>> +            seqno = max(prev->seqno, seqno);
    >>> +    }
    >>> +
    >>> +    dma_fence_init(&chain->base, &dma_fence_chain_ops,
    >>> +               &chain->lock, context, seqno);
    >>> +}
    >>> +EXPORT_SYMBOL(dma_fence_chain_init);
    >>> diff --git a/include/linux/dma-fence-chain.h
    >>> b/include/linux/dma-fence-chain.h
    >>> new file mode 100644
    >>> index 000000000000..a5c2e8c6915c
    >>> --- /dev/null
    >>> +++ b/include/linux/dma-fence-chain.h
    >>> @@ -0,0 +1,81 @@
    >>> +/*
    >>> + * fence-chain: chain fences together in a timeline
    >>> + *
    >>> + * Copyright (C) 2018 Advanced Micro Devices, Inc.
    >>> + * Authors:
    >>> + *    Christian König <[email protected]
    <mailto:[email protected]>>
    >>> + *
    >>> + * This program is free software; you can redistribute it and/or
    >>> modify it
    >>> + * under the terms of the GNU General Public License version 2 as
    >>> published by
    >>> + * the Free Software Foundation.
    >>> + *
    >>> + * This program is distributed in the hope that it will be
    useful,
    >>> but WITHOUT
    >>> + * ANY WARRANTY; without even the implied warranty of
    >>> MERCHANTABILITY or
    >>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
    >>> License for
    >>> + * more details.
    >>> + */
    >>> +
    >>> +#ifndef __LINUX_DMA_FENCE_CHAIN_H
    >>> +#define __LINUX_DMA_FENCE_CHAIN_H
    >>> +
    >>> +#include <linux/dma-fence.h>
    >>> +#include <linux/irq_work.h>
    >>> +
    >>> +/**
    >>> + * struct dma_fence_chain - fence to represent an node of a
    fence chain
    >>> + * @base: fence base class
    >>> + * @lock: spinlock for fence handling
    >>> + * @prev: previous fence of the chain
    >>> + * @prev_seqno: original previous seqno before garbage collection
    >>> + * @fence: encapsulated fence
    >>> + * @cb: callback structure for signaling
    >>> + * @work: irq work item for signaling
    >>> + */
    >>> +struct dma_fence_chain {
    >>> +    struct dma_fence base;
    >>> +    spinlock_t lock;
    >>> +    struct dma_fence *prev;
    >>> +    u64 prev_seqno;
    >>> +    struct dma_fence *fence;
    >>> +    struct dma_fence_cb cb;
    >>> +    struct irq_work work;
    >>> +};
    >>> +
    >>> +extern const struct dma_fence_ops dma_fence_chain_ops;
    >>> +
    >>> +/**
    >>> + * to_dma_fence_chain - cast a fence to a dma_fence_chain
    >>> + * @fence: fence to cast to a dma_fence_array
    >>> + *
    >>> + * Returns NULL if the fence is not a dma_fence_chain,
    >>> + * or the dma_fence_chain otherwise.
    >>> + */
    >>> +static inline struct dma_fence_chain *
    >>> +to_dma_fence_chain(struct dma_fence *fence)
    >>> +{
    >>> +    if (!fence || fence->ops != &dma_fence_chain_ops)
    >>> +        return NULL;
    >>> +
    >>> +    return container_of(fence, struct dma_fence_chain, base);
    >>> +}
    >>> +
    >>> +/**
    >>> + * dma_fence_chain_for_each - iterate over all fences in chain
    >>> + * @iter: current fence
    >>> + * @head: starting point
    >>> + *
    >>> + * Iterate over all fences in the chain. We keep a reference
    to the
    >>> current
    >>> + * fence while inside the loop which must be dropped when
    breaking out.
    >>> + */
    >>> +#define dma_fence_chain_for_each(iter, head)    \
    >>> +    for (iter = dma_fence_get(head); iter; \
    >>> +         iter = dma_fence_chain_walk(head))
    >>> +
    >>> +struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence);
    >>> +int dma_fence_chain_find_seqno(struct dma_fence **pfence,
    uint64_t
    >>> seqno);
    >>> +void dma_fence_chain_init(struct dma_fence_chain *chain,
    >>> +              struct dma_fence *prev,
    >>> +              struct dma_fence *fence,
    >>> +              uint64_t seqno);
    >>> +
Quoted 9 lines
    >>> +#endif /* __LINUX_DMA_FENCE_CHAIN_H */
    >>

    _______________________________________________
    dri-devel mailing list
    [email protected]
    <mailto:[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): a0b27d87-50f2-56ce-1db7-5a1dc005a798-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

#13 lore raw

Re: [PATCH 02/11] dma-buf: add new dma_fence_chain container v4

Quoted 26 lines · Christian König

Am 15.02.19 um 17:49 schrieb Jason Ekstrand:

Quoted 13 lines · Lionel Landwerlin via dri-devel
Quoted 12 lines · Christian

Am 15.02.19 um 15:23 schrieb Lionel Landwerlin:

Quoted 11 lines

Hi Christian, David,

For timeline semaphore we need points to signaled in order. I'm struggling to understand how this fence-chain implementation preserves ordering of the seqnos.

One of the scenario I can see an issue happening is when you have a timeline with points 1 & 2 and userspace submits for 2 different engines :
- first with let's say a blitter style engine on point 2
- then a 3d style engine on point 1

Quoted 7 lines
Quoted 6 lines

Yeah, and where exactly is the problem?

Seqno 1 will signal when the 3d style engine finishes work.

And seqno 2 will signal when both seqno 1 is signaled and the blitter style engine has finished its work.

Quoted 8 lines

That's an interesting interpretation of the spec. I think it's legal and I could see that behavior may be desirable in some ways.

Well we actually had this discussion multiple times now, both internally as well as on the mailing list. Please also see the previous mails with Daniel on this topic.

I dug through dri-devel and read everything I could find with a search for "timeline semaphore" I didn't find all that much but this did come up once.

Quoted 9 lines

My initial suggestion was actually to exactly what Leonid suggested as well.

And following this I used a rather simple container for the implementation, e.g. just a ring buffer indexed by the sequence number. In this scenario userspace can specify on syncobj creation time how big the window for sequence numbers should be, e.g. in this implementation how big the ring buffer would be.

Quoted 4 lines

This was rejected by our guys who actually wrote a good part of the Vulkan specification. Daniel then has gone into the same direction during the public discussion.

I agree with whoever said that specifying a ringbuffer size is unacceptable. I'm not really sure how that's relevant though. Is a ringbuffer required to implement the behavior that is being suggested here? Genuine question; I'm trying to get back up to speed.

Quoted 26 lines

[SNIP]

I think what Christian is suggesting is a valid interpretation of the spec though it is rather unconventional. The Vulkan spec, as it stands today, requires that the application ensure that at the time of signaling, the timeline semaphore value increases. This means that all of the above possible cases are technically illegal in Vulkan and so it doesn't really matter what we do as long as we don't do anyting especially stupid.

And exactly that's the point. When an application does something stupid with its own submissions then this is not much of a problem.

But this interface is meant to be made for communication between processes, and here we want to be sure that nobody can do anything stupid.

My understanding of how this works on Windows is that a wait operation on 3 is a wait until x >= 3 where x is a 64-bit value and a signal operation is simply a write to x. This means that, in the above cases, waits on 1 will be triggered immediately when 2 is written but waits on 2 may or may not happen at all depending on whether the GPU write which overwrites x to 1 or the CPU (or potentially GPU in a different context) read gets there first such that the reader observes 2. If you mess this up and something isn't signaled, that's your fault.

Quoted 4 lines

Yeah and I think that this is actually not a good idea at all. Implementing it like this ultimately means that you can only use polling on the number.

Yeah, there are problems with it. I'm just putting it out there for reference and because it's what developers expect regardless of whether that's a good thing or not.

4. If you do get into a sticky situation, you can unblock an entire

Quoted 9 lines

timeline by using the CPU signal ioctl to set it to a high value.

Well I think that this could be problematic as well. Keep in mind that main use case for this is sharing timelines between processes.

In other words you don't want applications to be able to mess with it to much.

Cross-process is exactly why you want it. Suppose you're a compositor and you have a timeline shared with another application and you've submitted work which waits on it. Then you get a notification somehow (SIGHUP?) that the client has died leaving you hanging. What do you do? You take the semaphore that's shared with you and the client and whack it to UINT64_MAX to unblock yourself. Of course, this can be abused and that's always the risk you take with timelines.

Quoted 15 lines

Of all these reasons, I think 1 and 2 carry the most weight. 2, in particular, is interesting if we one day want to implement the same behavior with a simple 64-bit value like Windows does. Immagine, for instance, a scenario where the GPU is doing it's own scheduling or command buffers are submitted ahead of the signal operation being available and told to just sit on the GPU until they see x >= 3. (Yes, there are issues here with residency, contention, etc. I'm asking you to use your immagination.) Assuming you can do 64-bit atomics (there are aparently issues here with PCIe that make things sticky), the behavior I'm suggesting is completely implementable in that way whereas the behavior Christian is suggesting is only implementable if you're maintaining a CPU-side list of fences. I don't think we want to paint ourselves into that corner.

Quoted 6 lines

Actually we already had such an implementation with radeon. And I can only say that it was a totally PAIN IN THE A* to maintain.

This is one of the reason why we are not using hardware semaphores any more with amdgpu.

Yeah, there are serious issues with just using a 64-bit integer and, to be honest, I haven't thought (or fought, for that matter) through them all.

--Jason

Quoted 4 lines

Regards,
Christian.

Quoted 418 lines

--Jason

Quoted 412 lines
Quoted 10 lines

Regards,
Christian.

Quoted 6 lines

-Lionel

Quoted 3 lines · Chunming Zhou

From: Christian König <[email protected]>

Lockless container implementation similar to a dma_fence_array, but

with

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

only two elements per node and automatic garbage collection.

v2: properly document dma_fence_chain_for_each, add dma_fence_chain_find_seqno,
drop prev reference during garbage collection if it's not a
chain fence.
v3: use head and iterator for dma_fence_chain_for_each
v4: fix reference count in dma_fence_chain_enable_signaling

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
---
   drivers/dma-buf/Makefile          |   3 +-
   drivers/dma-buf/dma-fence-chain.c | 241

++++++++++++++++++++++++++++++

Quoted 41 lines
Quoted 41 lines
Quoted 41 lines
   include/linux/dma-fence-chain.h   |  81 ++++++++++
   3 files changed, 324 insertions(+), 1 deletion(-)

create mode 100644 drivers/dma-buf/dma-fence-chain.c create mode 100644 include/linux/dma-fence-chain.h

drivers/dma-buf/Makefile +0 -1
index 0913a6ccab5a..1f006e083eb9 100644
@@ -1,4 +1,5 @@
-obj-y := dma-buf.o dma-fence.o dma-fence-array.o reservation.o

seqno-fence.o

drivers/dma-buf/Makefile +2 -0
+obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
+     reservation.o seqno-fence.o
   obj-$(CONFIG_SYNC_FILE)        += sync_file.o
   obj-$(CONFIG_SW_SYNC)        += sw_sync.o sync_debug.o
   obj-$(CONFIG_UDMABUF)        += udmabuf.o
drivers/dma-buf/dma-fence-chain.c new file +8 -0
new file mode 100644
index 000000000000..0c5e3c902fa0
@@ -0,0 +1,241 @@
+/*
+ * fence-chain: chain fences together in a timeline
+ *
+ * Copyright (C) 2018 Advanced Micro Devices, Inc.
+ * Authors:
+ *    Christian König <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or

modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or

Quoted 8 lines
Quoted 8 lines

drivers/dma-buf/dma-fence-chain.c

Quoted 8 lines

+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */

drivers/dma-buf/dma-fence-chain.c new file +4 -0
+
+#include <linux/dma-fence-chain.h>
+
+static bool dma_fence_chain_enable_signaling(struct dma_fence

*fence);

Quoted 20 lines
Quoted 20 lines
Quoted 20 lines
drivers/dma-buf/dma-fence-chain.c new file +3 -0
+
+/**
+ * dma_fence_chain_get_prev - use RCU to get a reference to the

previous fence
+ * @chain: chain node to get the previous node from
+ *
+ * Use dma_fence_get_rcu_safe to get a reference to the previous fence of the
+ * chain node.
+ */
+static struct dma_fence *dma_fence_chain_get_prev(struct dma_fence_chain *chain)

drivers/dma-buf/dma-fence-chain.c new file +8 -0
+{
+    struct dma_fence *prev;
+
+    rcu_read_lock();
+    prev = dma_fence_get_rcu_safe(&chain->prev);
+    rcu_read_unlock();
+    return prev;
+}
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma-buf/dma-fence-chain.c new file +6 -0
+
+/**
+ * dma_fence_chain_walk - chain walking function
+ * @fence: current chain node
+ *
+ * Walk the chain to the next node. Returns the next fence or NULL

if we are at
+ * the end of the chain. Garbage collects chain nodes which are

already

Quoted 234 lines
Quoted 234 lines
Quoted 234 lines

+ * signaled.
+ */

drivers/dma-buf/dma-fence-chain.c new file +45 -0
+struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence)
+{
+    struct dma_fence_chain *chain, *prev_chain;
+    struct dma_fence *prev, *replacement, *tmp;
+
+    chain = to_dma_fence_chain(fence);
+    if (!chain) {
+        dma_fence_put(fence);
+        return NULL;
+    }
+
+    while ((prev = dma_fence_chain_get_prev(chain))) {
+
+        prev_chain = to_dma_fence_chain(prev);
+        if (prev_chain) {
+            if (!dma_fence_is_signaled(prev_chain->fence))
+                break;
+
+            replacement = dma_fence_chain_get_prev(prev_chain);
+        } else {
+            if (!dma_fence_is_signaled(prev))
+                break;
+
+            replacement = NULL;
+        }
+
+        tmp = cmpxchg(&chain->prev, prev, replacement);
+        if (tmp == prev)
+            dma_fence_put(tmp);
+        else
+            dma_fence_put(replacement);
+        dma_fence_put(prev);
+    }
+
+    dma_fence_put(fence);
+    return prev;
+}
+EXPORT_SYMBOL(dma_fence_chain_walk);
+
+/**
+ * dma_fence_chain_find_seqno - find fence chain node by seqno
+ * @pfence: pointer to the chain node where to start
+ * @seqno: the sequence number to search for
+ *
+ * Advance the fence pointer to the chain node which will signal

this sequence
+ * number. If no sequence number is provided then this is a no-op.
+ *
+ * Returns EINVAL if the fence is not a chain node or the sequence number has
+ * not yet advanced far enough.
+ */
+int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t seqno)

drivers/dma-buf/dma-fence-chain.c new file +22 -0
+{
+    struct dma_fence_chain *chain;
+
+    if (!seqno)
+        return 0;
+
+    chain = to_dma_fence_chain(*pfence);
+    if (!chain || chain->base.seqno < seqno)
+        return -EINVAL;
+
+    dma_fence_chain_for_each(*pfence, &chain->base) {
+        if ((*pfence)->context != chain->base.context ||
+            to_dma_fence_chain(*pfence)->prev_seqno < seqno)
+            break;
+    }
+    dma_fence_put(&chain->base);
+
+    return 0;
+}
+EXPORT_SYMBOL(dma_fence_chain_find_seqno);
+
+static const char *dma_fence_chain_get_driver_name(struct dma_fence

*fence)

drivers/dma-buf/dma-fence-chain.c new file +5 -0
+{
+        return "dma_fence_chain";
+}
+
+static const char *dma_fence_chain_get_timeline_name(struct

dma_fence *fence)

drivers/dma-buf/dma-fence-chain.c new file +18 -0
+{
+        return "unbound";
+}
+
+static void dma_fence_chain_irq_work(struct irq_work *work)
+{
+    struct dma_fence_chain *chain;
+
+    chain = container_of(work, typeof(*chain), work);
+
+    /* Try to rearm the callback */
+    if (!dma_fence_chain_enable_signaling(&chain->base))
+        /* Ok, we are done. No more unsignaled fences left */
+        dma_fence_signal(&chain->base);
+    dma_fence_put(&chain->base);
+}
+
+static void dma_fence_chain_cb(struct dma_fence *f, struct

dma_fence_cb *cb)

drivers/dma-buf/dma-fence-chain.c new file +19 -0
+{
+    struct dma_fence_chain *chain;
+
+    chain = container_of(cb, typeof(*chain), cb);
+    irq_work_queue(&chain->work);
+    dma_fence_put(f);
+}
+
+static bool dma_fence_chain_enable_signaling(struct dma_fence *fence)
+{
+    struct dma_fence_chain *head = to_dma_fence_chain(fence);
+
+    dma_fence_get(&head->base);
+    dma_fence_chain_for_each(fence, &head->base) {
+        struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+        struct dma_fence *f = chain ? chain->fence : fence;
+
+        dma_fence_get(f);
+        if (!dma_fence_add_callback(f, &head->cb,

dma_fence_chain_cb)) {

drivers/dma-buf/dma-fence-chain.c new file +49 -0
+            dma_fence_put(fence);
+            return true;
+        }
+        dma_fence_put(f);
+    }
+    dma_fence_put(&head->base);
+    return false;
+}
+
+static bool dma_fence_chain_signaled(struct dma_fence *fence)
+{
+    dma_fence_chain_for_each(fence, fence) {
+        struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+        struct dma_fence *f = chain ? chain->fence : fence;
+
+        if (!dma_fence_is_signaled(f)) {
+            dma_fence_put(fence);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void dma_fence_chain_release(struct dma_fence *fence)
+{
+    struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+
+    dma_fence_put(chain->prev);
+    dma_fence_put(chain->fence);
+    dma_fence_free(fence);
+}
+
+const struct dma_fence_ops dma_fence_chain_ops = {
+    .get_driver_name = dma_fence_chain_get_driver_name,
+    .get_timeline_name = dma_fence_chain_get_timeline_name,
+    .enable_signaling = dma_fence_chain_enable_signaling,
+    .signaled = dma_fence_chain_signaled,
+    .release = dma_fence_chain_release,
+};
+EXPORT_SYMBOL(dma_fence_chain_ops);
+
+/**
+ * dma_fence_chain_init - initialize a fence chain
+ * @chain: the chain node to initialize
+ * @prev: the previous fence
+ * @fence: the current fence
+ *
+ * Initialize a new chain node and either start a new chain or add

the node to
+ * the existing chain of the previous fence.
+ */

drivers/dma-buf/dma-fence-chain.c new file +29 -0
+void dma_fence_chain_init(struct dma_fence_chain *chain,
+              struct dma_fence *prev,
+              struct dma_fence *fence,
+              uint64_t seqno)
+{
+    struct dma_fence_chain *prev_chain = to_dma_fence_chain(prev);
+    uint64_t context;
+
+    spin_lock_init(&chain->lock);
+    chain->prev = prev;
+    chain->fence = fence;
+    chain->prev_seqno = 0;
+    init_irq_work(&chain->work, dma_fence_chain_irq_work);
+
+    /* Try to reuse the context of the previous chain node. */
+    if (prev_chain && __dma_fence_is_later(seqno, prev->seqno)) {
+        context = prev->context;
+        chain->prev_seqno = prev->seqno;
+    } else {
+        context = dma_fence_context_alloc(1);
+        /* Make sure that we always have a valid sequence number. */
+        if (prev_chain)
+            seqno = max(prev->seqno, seqno);
+    }
+
+    dma_fence_init(&chain->base, &dma_fence_chain_ops,
+               &chain->lock, context, seqno);
+}
+EXPORT_SYMBOL(dma_fence_chain_init);
include/linux/dma-fence-chain.h new file +8 -0
new file mode 100644
index 000000000000..a5c2e8c6915c
@@ -0,0 +1,81 @@
+/*
+ * fence-chain: chain fences together in a timeline
+ *
+ * Copyright (C) 2018 Advanced Micro Devices, Inc.
+ * Authors:
+ *    Christian König <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or

modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+

Quoted 8 lines
Quoted 8 lines

include/linux/dma-fence-chain.h

Quoted 8 lines
include/linux/dma-fence-chain.h new file +8 -0
+#ifndef __LINUX_DMA_FENCE_CHAIN_H
+#define __LINUX_DMA_FENCE_CHAIN_H
+
+#include <linux/dma-fence.h>
+#include <linux/irq_work.h>
+
+/**
+ * struct dma_fence_chain - fence to represent an node of a fence

chain

Quoted 36 lines
Quoted 36 lines
Quoted 36 lines

+ * @base: fence base class
+ * @lock: spinlock for fence handling
+ * @prev: previous fence of the chain
+ * @prev_seqno: original previous seqno before garbage collection
+ * @fence: encapsulated fence
+ * @cb: callback structure for signaling
+ * @work: irq work item for signaling
+ */

include/linux/dma-fence-chain.h new file +28 -0
+struct dma_fence_chain {
+    struct dma_fence base;
+    spinlock_t lock;
+    struct dma_fence *prev;
+    u64 prev_seqno;
+    struct dma_fence *fence;
+    struct dma_fence_cb cb;
+    struct irq_work work;
+};
+
+extern const struct dma_fence_ops dma_fence_chain_ops;
+
+/**
+ * to_dma_fence_chain - cast a fence to a dma_fence_chain
+ * @fence: fence to cast to a dma_fence_array
+ *
+ * Returns NULL if the fence is not a dma_fence_chain,
+ * or the dma_fence_chain otherwise.
+ */
+static inline struct dma_fence_chain *
+to_dma_fence_chain(struct dma_fence *fence)
+{
+    if (!fence || fence->ops != &dma_fence_chain_ops)
+        return NULL;
+
+    return container_of(fence, struct dma_fence_chain, base);
+}
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

+/**
+ * dma_fence_chain_for_each - iterate over all fences in chain
+ * @iter: current fence
+ * @head: starting point
+ *
+ * Iterate over all fences in the chain. We keep a reference to the current
+ * fence while inside the loop which must be dropped when breaking

out.

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

+ */

include/linux/dma-fence-chain.h new file +6 -0
+#define dma_fence_chain_for_each(iter, head)    \
+    for (iter = dma_fence_get(head); iter; \
+         iter = dma_fence_chain_walk(head))
+
+struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence);
+int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t
Quoted 8 lines
Quoted 8 lines

include/linux/dma-fence-chain.h

Quoted 7 lines

seqno);

include/linux/dma-fence-chain.h new file +6 -0
+void dma_fence_chain_init(struct dma_fence_chain *chain,
+              struct dma_fence *prev,
+              struct dma_fence *fence,
+              uint64_t seqno);
+
+#endif /* __LINUX_DMA_FENCE_CHAIN_H */

_______________________________________________
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): CAOFGe9611MqmsvdvZS4_vuJjrrUAmjK5-41Z6tpaxTHJsB8CwA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#15 lore raw

Re: [PATCH 02/11] dma-buf: add new dma_fence_chain container v4

Am 15.02.19 um 19:16 schrieb Jason Ekstrand:
On Fri, Feb 15, 2019 at 11:51 AM Christian König <[email protected]<mailto:[email protected]>> wrote:
Am 15.02.19 um 17:49 schrieb Jason Ekstrand:
On Fri, Feb 15, 2019 at 9:52 AM Lionel Landwerlin via dri-devel <[email protected]<mailto:[email protected]>> wrote:

Quoted 12 lines · Christian

Am 15.02.19 um 15:23 schrieb Lionel Landwerlin:

Quoted 11 lines

Hi Christian, David,

For timeline semaphore we need points to signaled in order. I'm struggling to understand how this fence-chain implementation preserves ordering of the seqnos.

One of the scenario I can see an issue happening is when you have a timeline with points 1 & 2 and userspace submits for 2 different engines :
- first with let's say a blitter style engine on point 2
- then a 3d style engine on point 1

Quoted 6 lines

Yeah, and where exactly is the problem?

Seqno 1 will signal when the 3d style engine finishes work.

And seqno 2 will signal when both seqno 1 is signaled and the blitter style engine has finished its work.

That's an interesting interpretation of the spec. I think it's legal and I could see that behavior may be desirable in some ways.

Well we actually had this discussion multiple times now, both internally as well as on the mailing list. Please also see the previous mails with Daniel on this topic.

I dug through dri-devel and read everything I could find with a search for "timeline semaphore" I didn't find all that much but this did come up once.

Need to dig through my mails as well, that was back in November/December last year.

My initial suggestion was actually to exactly what Leonid suggested as well.

And following this I used a rather simple container for the implementation, e.g. just a ring buffer indexed by the sequence number. In this scenario userspace can specify on syncobj creation time how big the window for sequence numbers should be, e.g. in this implementation how big the ring buffer would be.

This was rejected by our guys who actually wrote a good part of the Vulkan specification. Daniel then has gone into the same direction during the public discussion.

I agree with whoever said that specifying a ringbuffer size is unacceptable. I'm not really sure how that's relevant though. Is a ringbuffer required to implement the behavior that is being suggested here? Genuine question; I'm trying to get back up to speed.

Using a ring buffer was just an example how we could do it if we follow my and Lionel's suggestion.

Key point is that we could simplify the implementation massively if sequence numbers don't need to depend on each other.

In other words we just see the syncobj as container where fences are added and retrieved from instead of something actively involved in the signaling.

Main reason we didn't do it this way is because the AMD Vulkan team has rejected this approach.

Additional to that chaining sequence numbers together is really the more defensive approach, e.g. it is less likely that applications can shoot themselves in the foot.

4. If you do get into a sticky situation, you can unblock an entire timeline by using the CPU signal ioctl to set it to a high value.

Well I think that this could be problematic as well. Keep in mind that main use case for this is sharing timelines between processes.

In other words you don't want applications to be able to mess with it to much.

Cross-process is exactly why you want it. Suppose you're a compositor and you have a timeline shared with another application and you've submitted work which waits on it. Then you get a notification somehow (SIGHUP?) that the client has died leaving you hanging. What do you do? You take the semaphore that's shared with you and the client and whack it to UINT64_MAX to unblock yourself. Of course, this can be abused and that's always the risk you take with timelines.

My last status is that basically everybody agrees now that wait before signal in the kernel is forbidden.

So when you get a SIGHUB because your client is dead you just kill your thread waiting on it.

Regards,
Christian.

_______________________________________________
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): f933f9ec-6e69-f9df-f12f-5f1844a2ad37-5C7GfCeVMHo@public.gmane.org

#17 lore raw

Re: [PATCH 02/11] dma-buf: add new dma_fence_chain container v4

Quoted 69 lines · Christian

Am 15.02.19 um 19:16 schrieb Jason Ekstrand:

Quoted 26 lines · Christian König

Am 15.02.19 um 17:49 schrieb Jason Ekstrand:

Quoted 13 lines · Lionel Landwerlin via dri-devel
Quoted 12 lines · Christian

Am 15.02.19 um 15:23 schrieb Lionel Landwerlin:

Quoted 11 lines

Hi Christian, David,

For timeline semaphore we need points to signaled in order. I'm struggling to understand how this fence-chain implementation preserves ordering of the seqnos.

One of the scenario I can see an issue happening is when you have a timeline with points 1 & 2 and userspace submits for 2 different engines :
- first with let's say a blitter style engine on point 2
- then a 3d style engine on point 1

Quoted 7 lines
Quoted 6 lines

Yeah, and where exactly is the problem?

Seqno 1 will signal when the 3d style engine finishes work.

And seqno 2 will signal when both seqno 1 is signaled and the blitter style engine has finished its work.

Quoted 8 lines

That's an interesting interpretation of the spec. I think it's legal and I could see that behavior may be desirable in some ways.

Well we actually had this discussion multiple times now, both internally as well as on the mailing list. Please also see the previous mails with Daniel on this topic.

I dug through dri-devel and read everything I could find with a search for "timeline semaphore" I didn't find all that much but this did come up once.

Need to dig through my mails as well, that was back in November/December last year.

Quoted 9 lines

My initial suggestion was actually to exactly what Leonid suggested as well.

And following this I used a rather simple container for the implementation, e.g. just a ring buffer indexed by the sequence number. In this scenario userspace can specify on syncobj creation time how big the window for sequence numbers should be, e.g. in this implementation how big the ring buffer would be.

Quoted 4 lines

This was rejected by our guys who actually wrote a good part of the Vulkan specification. Daniel then has gone into the same direction during the public discussion.

I agree with whoever said that specifying a ringbuffer size is unacceptable. I'm not really sure how that's relevant though. Is a ringbuffer required to implement the behavior that is being suggested here? Genuine question; I'm trying to get back up to speed.

Quoted 9 lines

Using a ring buffer was just an example how we could do it if we follow my and Lionel's suggestion.

Key point is that we could simplify the implementation massively if sequence numbers don't need to depend on each other.

In other words we just see the syncobj as container where fences are added and retrieved from instead of something actively involved in the signaling.

In principal, I think this is a reasonable argument. Having it involved in signalling doesn't seem terrible to me but it would mean that a driver wouldn't be able to detect that the fence it's waiting on actually belongs to itself and optimize things.

Quoted 3 lines

Main reason we didn't do it this way is because the AMD Vulkan team has rejected this approach.

Clearly, there's not quite as much agreement as I'd thought there was. Oh, well, that's why we have these discussions.

Quoted 4 lines

Additional to that chaining sequence numbers together is really the more defensive approach, e.g. it is less likely that applications can shoot themselves in the foot.

Yeah, I can see how the "everything prior to n must be signalled" could be safer. I think both wait-any and wait-all have their ups and downs. It just took me by surprise.

Quoted 21 lines

4. If you do get into a sticky situation, you can unblock an entire

Quoted 9 lines

timeline by using the CPU signal ioctl to set it to a high value.

Well I think that this could be problematic as well. Keep in mind that main use case for this is sharing timelines between processes.

In other words you don't want applications to be able to mess with it to much.

Cross-process is exactly why you want it. Suppose you're a compositor and you have a timeline shared with another application and you've submitted work which waits on it. Then you get a notification somehow (SIGHUP?) that the client has died leaving you hanging. What do you do? You take the semaphore that's shared with you and the client and whack it to UINT64_MAX to unblock yourself. Of course, this can be abused and that's always the risk you take with timelines.

Quoted 3 lines

My last status is that basically everybody agrees now that wait before signal in the kernel is forbidden.

Agreed. I'm not saying that wait before signal in the kernel should be a thing. I think we're all agreed that wait-before-signal with the current GEM infrastructure is utter insanity.

However, timeline syncobjs are both a kernel wait mechanism (only for time points that already have a known-to-signal dma_fence) and a userspace wait mechanism (which can wait for things which haven't materialized yet). The whacking to UINT64_MAX would be to unblock waiting userspace threads as you mentioned below.

That said, in the case that I suggested here, if the client process died, got kicked off the GPU, or whatever, then the kernel has likely declared it's context a loss and signalled all dma_fences associated with it. If this is true, then whacking it to UINT64_MAX still works to unblock the timeline because there would be nothing else pending to signal time points. Worst case, the process crashed and left valid GPU work pending in the kernel and the compositor ends up waiting a little while longer for said work to complete.

Ok, I think I'm reasonably convinced that the wait-all behaviour implied by the chaining approach, while unexpected, isn't harmful.

--Jason

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

#18 lore raw

PATCH 3/11 drm/syncobj: remove drm_syncobj_cb and cleanup

In reply to Chunming Zhou

From: Christian König <[email protected]>

This completes "drm/syncobj: Drop add/remove_callback from driver interface" and cleans up the implementation a bit.

---
 drivers/gpu/drm/drm_syncobj.c | 91 ++++++++++++-----------------------
 include/drm/drm_syncobj.h     | 21 --------
 2 files changed, 30 insertions(+), 82 deletions(-)
drivers/gpu/drm/drm_syncobj.c +30 -61
index db30a0e89db8..e19525af0cce 100644
@@ -56,6 +56,16 @@
 #include "drm_internal.h"
 #include <drm/drm_syncobj.h>
 
+struct syncobj_wait_entry {
+	struct list_head node;
+	struct task_struct *task;
+	struct dma_fence *fence;
+	struct dma_fence_cb fence_cb;
+};
+
+static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
+				      struct syncobj_wait_entry *wait);
+
 /**
  * drm_syncobj_find - lookup and reference a sync object.
  * @file_private: drm file private pointer
@@ -82,58 +92,33 @@ struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
 }
 EXPORT_SYMBOL(drm_syncobj_find);
 
-static void drm_syncobj_add_callback_locked(struct drm_syncobj *syncobj,
-					    struct drm_syncobj_cb *cb,
-					    drm_syncobj_func_t func)
+static void drm_syncobj_fence_add_wait(struct drm_syncobj *syncobj,
+				       struct syncobj_wait_entry *wait)
 {
-	cb->func = func;
-	list_add_tail(&cb->node, &syncobj->cb_list);
-}
-
-static int drm_syncobj_fence_get_or_add_callback(struct drm_syncobj *syncobj,
-						 struct dma_fence **fence,
-						 struct drm_syncobj_cb *cb,
-						 drm_syncobj_func_t func)
-{
-	int ret;
-
-	*fence = drm_syncobj_fence_get(syncobj);
-	if (*fence)
-		return 1;
+	if (wait->fence)
+		return;
 
 	spin_lock(&syncobj->lock);
 	/* We've already tried once to get a fence and failed.  Now that we
 	 * 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;
-	} else {
-		*fence = NULL;
-		drm_syncobj_add_callback_locked(syncobj, cb, func);
-		ret = 0;
-	}
+	if (syncobj->fence)
+		wait->fence = dma_fence_get(
+			rcu_dereference_protected(syncobj->fence, 1));
+	else
+		list_add_tail(&wait->node, &syncobj->cb_list);
 	spin_unlock(&syncobj->lock);
-
-	return ret;
 }
 
-void drm_syncobj_add_callback(struct drm_syncobj *syncobj,
-			      struct drm_syncobj_cb *cb,
-			      drm_syncobj_func_t func)
+static void drm_syncobj_remove_wait(struct drm_syncobj *syncobj,
+				    struct syncobj_wait_entry *wait)
 {
-	spin_lock(&syncobj->lock);
-	drm_syncobj_add_callback_locked(syncobj, cb, func);
-	spin_unlock(&syncobj->lock);
-}
+	if (!wait->node.next)
+		return;
 
-void drm_syncobj_remove_callback(struct drm_syncobj *syncobj,
-				 struct drm_syncobj_cb *cb)
-{
 	spin_lock(&syncobj->lock);
-	list_del_init(&cb->node);
+	list_del_init(&wait->node);
 	spin_unlock(&syncobj->lock);
 }
 
@@ -148,7 +133,7 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
 			       struct dma_fence *fence)
 {
 	struct dma_fence *old_fence;
-	struct drm_syncobj_cb *cur, *tmp;
+	struct syncobj_wait_entry *cur, *tmp;
 
 	if (fence)
 		dma_fence_get(fence);
@@ -162,7 +147,7 @@ void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
 	if (fence != old_fence) {
 		list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) {
 			list_del_init(&cur->node);
-			cur->func(syncobj, cur);
+			syncobj_wait_syncobj_func(syncobj, cur);
 		}
 	}
 
@@ -608,13 +593,6 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
 					&args->handle);
 }
 
-struct syncobj_wait_entry {
-	struct task_struct *task;
-	struct dma_fence *fence;
-	struct dma_fence_cb fence_cb;
-	struct drm_syncobj_cb syncobj_cb;
-};
-
 static void syncobj_wait_fence_func(struct dma_fence *fence,
 				    struct dma_fence_cb *cb)
 {
@@ -625,11 +603,8 @@ static void syncobj_wait_fence_func(struct dma_fence *fence,
 }
 
 static void syncobj_wait_syncobj_func(struct drm_syncobj *syncobj,
-				      struct drm_syncobj_cb *cb)
+				      struct syncobj_wait_entry *wait)
 {
-	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)));
@@ -688,12 +663,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
 	 */
 
 	if (flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT) {
-		for (i = 0; i < count; ++i) {
-			drm_syncobj_fence_get_or_add_callback(syncobjs[i],
-							      &entries[i].fence,
-							      &entries[i].syncobj_cb,
-							      syncobj_wait_syncobj_func);
-		}
+		for (i = 0; i < count; ++i)
+			drm_syncobj_fence_add_wait(syncobjs[i], &entries[i]);
 	}
 
 	do {
@@ -742,9 +713,7 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs,
 
 cleanup_entries:
 	for (i = 0; i < count; ++i) {
-		if (entries[i].syncobj_cb.func)
-			drm_syncobj_remove_callback(syncobjs[i],
-						    &entries[i].syncobj_cb);
+		drm_syncobj_remove_wait(syncobjs[i], &entries[i]);
 		if (entries[i].fence_cb.func)
 			dma_fence_remove_callback(entries[i].fence,
 						  &entries[i].fence_cb);
include/drm/drm_syncobj.h +0 -21
index b1fe921f8e8f..7c6ed845c70d 100644
@@ -28,8 +28,6 @@
 
 #include "linux/dma-fence.h"
 
-struct drm_syncobj_cb;
-
 /**
  * struct drm_syncobj - sync object.
  *
@@ -62,25 +60,6 @@ struct drm_syncobj {
 	struct file *file;
 };
 
-typedef void (*drm_syncobj_func_t)(struct drm_syncobj *syncobj,
-				   struct drm_syncobj_cb *cb);
-
-/**
- * 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
- * @func: drm_syncobj_func_t to call
- *
- * This struct will be initialized by drm_syncobj_add_callback, additional
- * data can be passed along by embedding drm_syncobj_cb in another struct.
- * The callback will get called the next time drm_syncobj_replace_fence is
- * called.
- */
-struct drm_syncobj_cb {
-	struct list_head node;
-	drm_syncobj_func_t func;
-};
-
 void drm_syncobj_free(struct kref *kref);
 
 /**
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]

#20 lore raw

PATCH 4/11 drm/syncobj: add new drm_syncobj_add_point interface v2

From: Christian König <[email protected]>

Use the dma_fence_chain object to create a timeline of fence objects instead of just replacing the existing fence.

v2: rebase and cleanup

---
 drivers/gpu/drm/drm_syncobj.c | 37 +++++++++++++++++++++++++++++++++++
 include/drm/drm_syncobj.h     |  5 +++++
 2 files changed, 42 insertions(+)
drivers/gpu/drm/drm_syncobj.c +37 -0
index e19525af0cce..51f798e2194f 100644
@@ -122,6 +122,43 @@ static void drm_syncobj_remove_wait(struct drm_syncobj *syncobj,
 	spin_unlock(&syncobj->lock);
 }
 
+/**
+ * drm_syncobj_add_point - add new timeline point to the syncobj
+ * @syncobj: sync object to add timeline point do
+ * @chain: chain node to use to add the point
+ * @fence: fence to encapsulate in the chain node
+ * @point: sequence number to use for the point
+ *
+ * Add the chain node as new timeline point to the syncobj.
+ */
+void drm_syncobj_add_point(struct drm_syncobj *syncobj,
+			   struct dma_fence_chain *chain,
+			   struct dma_fence *fence,
+			   uint64_t point)
+{
+	struct syncobj_wait_entry *cur, *tmp;
+	struct dma_fence *prev;
+
+	dma_fence_get(fence);
+
+	spin_lock(&syncobj->lock);
+
+	prev = rcu_dereference_protected(syncobj->fence,
+					 lockdep_is_held(&syncobj->lock));
+	dma_fence_chain_init(chain, prev, fence, point);
+	rcu_assign_pointer(syncobj->fence, &chain->base);
+
+	list_for_each_entry_safe(cur, tmp, &syncobj->cb_list, node) {
+		list_del_init(&cur->node);
+		syncobj_wait_syncobj_func(syncobj, cur);
+	}
+	spin_unlock(&syncobj->lock);
+
+	/* Walk the chain once to trigger garbage collection */
+	dma_fence_chain_for_each(prev, fence);
+}
+EXPORT_SYMBOL(drm_syncobj_add_point);
+
 /**
  * drm_syncobj_replace_fence - replace fence in a sync object.
  * @syncobj: Sync object to replace fence in
include/drm/drm_syncobj.h +5 -0
index 7c6ed845c70d..8acb4ae4f311 100644
@@ -27,6 +27,7 @@
 #define __DRM_SYNCOBJ_H__
 
 #include "linux/dma-fence.h"
+#include "linux/dma-fence-chain.h"
 
 /**
  * struct drm_syncobj - sync object.
@@ -110,6 +111,10 @@ drm_syncobj_fence_get(struct drm_syncobj *syncobj)
 
 struct drm_syncobj *drm_syncobj_find(struct drm_file *file_private,
 				     u32 handle);
+void drm_syncobj_add_point(struct drm_syncobj *syncobj,
+			   struct dma_fence_chain *chain,
+			   struct dma_fence *fence,
+			   uint64_t point);
 void drm_syncobj_replace_fence(struct drm_syncobj *syncobj,
 			       struct dma_fence *fence);
 int drm_syncobj_find_fence(struct drm_file *file_private,
Signature · 6 lines
2.17.1

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

PATCH 6/11 drm/syncobj: add timeline payload query ioctl v4

In reply to a message not in the archive

user mode can query timeline payload.
v2: check return value of copy_to_user
v3: handle querying entry by entry
v4: rebase on new chain container, simplify interface

Cc Daniel Rakos <[email protected]>
Cc Jason Ekstrand <[email protected]>
Cc Bas Nieuwenhuizen <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Christian König <[email protected]>
Cc Chris Wilson <[email protected]>
---
 drivers/gpu/drm/drm_internal.h |  2 ++
 drivers/gpu/drm/drm_ioctl.c    |  2 ++
 drivers/gpu/drm/drm_syncobj.c  | 43 ++++++++++++++++++++++++++++++++++
 include/uapi/drm/drm.h         | 10 ++++++++
 4 files changed, 57 insertions(+)
drivers/gpu/drm/drm_internal.h +2 -0
index 18b41e10195c..dab4d5936441 100644
@@ -184,6 +184,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 a9a17ed35cc4..7578ef6dc1d1 100644
@@ -681,6 +681,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 +43 -0

46 lines not on this page · raw message

include/uapi/drm/drm.h +10 -0
index 0092111d002c..b2c36f2b2599 100644
@@ -767,6 +767,14 @@ struct drm_syncobj_array {
 	__u32 pad;
 };
 
+struct drm_syncobj_timeline_array {
+	__u64 handles;
+	__u64 points;
+	__u32 count_handles;
+	__u32 pad;
+};
+
+
 /* Query current scanout sequence number */
 struct drm_crtc_get_sequence {
 	__u32 crtc_id;		/* requested crtc_id */
@@ -924,6 +932,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_array)
+
 /**
  * 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

_______________________________________________
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]

#23 lore raw

Re: [PATCH 06/11] drm/syncobj: add timeline payload query ioctl v4

Quoted 77 lines · Chunming Zhou

user mode can query timeline payload.
v2: check return value of copy_to_user
v3: handle querying entry by entry
v4: rebase on new chain container, simplify interface

Cc Daniel Rakos <[email protected]>
Cc Jason Ekstrand <[email protected]>
Cc Bas Nieuwenhuizen <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Christian König <[email protected]>
Cc Chris Wilson <[email protected]>
---
  drivers/gpu/drm/drm_internal.h |  2 ++
  drivers/gpu/drm/drm_ioctl.c    |  2 ++
  drivers/gpu/drm/drm_syncobj.c  | 43 ++++++++++++++++++++++++++++++++++
  include/uapi/drm/drm.h         | 10 ++++++++
  4 files changed, 57 insertions(+)
drivers/gpu/drm/drm_internal.h +2 -0
index 18b41e10195c..dab4d5936441 100644
@@ -184,6 +184,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 a9a17ed35cc4..7578ef6dc1d1 100644
@@ -681,6 +681,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 +24 -0
index 348079bb0965..f97fa00ca1d0 100644
@@ -1061,3 +1061,46 @@ drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
 
  	return ret;
  }
+
+int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
+			    struct drm_file *file_private)
+{
+	struct drm_syncobj_timeline_array *args = data;
+	struct drm_syncobj **syncobjs;
+	uint64_t __user *points = u64_to_user_ptr(args->points);
+	uint32_t i;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad != 0)
+		return -EINVAL;
+
+	if (args->count_handles == 0)
+		return -EINVAL;
+
+	ret = drm_syncobj_array_find(file_private,
+				     u64_to_user_ptr(args->handles),
+				     args->count_handles,
+				     &syncobjs);
+	if (ret < 0)

drivers/gpu/drm/drm_syncobj.c drm_syncobj_signal_ioctl(struct drm_device *dev, void *data, · line 1097

Quoted 10 lines
drivers/gpu/drm/drm_syncobj.c +10 -0
+		return ret;
+
+	for (i = 0; i < args->count_handles; i++) {
+		struct dma_fence_chain *chain;
+		struct dma_fence *fence;
+		uint64_t point;
+
+		fence = drm_syncobj_fence_get(syncobjs[i]);
+		chain = to_dma_fence_chain(fence);
+		point = chain ? fence->seqno : 0;

Sorry, I don' t want to sound annoying, but this looks like this could report values going backward.

Anything add a point X to a timeline that has reached value Y with X < Y would trigger that.

Either through the submission or userspace signaling or importing another syncpoint's fence.

-Lionel

Quoted 29 lines
drivers/gpu/drm/drm_syncobj.c +9 -0
+		ret = copy_to_user(&points[i], &point, sizeof(uint64_t));
+		ret = ret ? -EFAULT : 0;
+		if (ret)
+			break;
+	}
+	drm_syncobj_array_free(syncobjs, args->count_handles);
+
+	return ret;
+}
include/uapi/drm/drm.h +8 -0
index 0092111d002c..b2c36f2b2599 100644
@@ -767,6 +767,14 @@ struct drm_syncobj_array {
  	__u32 pad;
  };
 
+struct drm_syncobj_timeline_array {
+	__u64 handles;
+	__u64 points;
+	__u32 count_handles;
+	__u32 pad;
+};
+
+
  /* Query current scanout sequence number */
  struct drm_crtc_get_sequence {
  	__u32 crtc_id;		/* requested crtc_id */

include/uapi/drm/drm.h extern "C" { · line 939

Quoted 8 lines
include/uapi/drm/drm.h +2 -0
@@ -924,6 +932,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_array)
+
  /**
   * Device specific ioctls should only be in their respective headers
   * The device specific ioctl range is from 0x40 to 0x9f.

_______________________________________________
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): 157f8231-57e2-0492-de5d-f9ba4761c4c9-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org

#25 lore raw

Re: [PATCH 06/11] drm/syncobj: add timeline payload query ioctl v4

Am 15.02.19 um 20:31 schrieb Lionel Landwerlin via amd-gfx:

Quoted 83 lines · Chunming Zhou
Quoted 82 lines

user mode can query timeline payload.
v2: check return value of copy_to_user
v3: handle querying entry by entry
v4: rebase on new chain container, simplify interface

Cc Daniel Rakos <[email protected]>
Cc Jason Ekstrand <[email protected]>
Cc Bas Nieuwenhuizen <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Christian König <[email protected]>
Cc Chris Wilson <[email protected]>

---
  drivers/gpu/drm/drm_internal.h |  2 ++ drivers/gpu/drm/drm_ioctl.c    |  2 ++ drivers/gpu/drm/drm_syncobj.c  | 43 ++++++++++++++++++++++++++++++++++ include/uapi/drm/drm.h         | 10 ++++++++

  4 files changed, 57 insertions(+)
drivers/gpu/drm/drm_internal.h +2 -0
index 18b41e10195c..dab4d5936441 100644
@@ -184,6 +184,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 a9a17ed35cc4..7578ef6dc1d1 100644
@@ -681,6 +681,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 +29 -0
index 348079bb0965..f97fa00ca1d0 100644
@@ -1061,3 +1061,46 @@ drm_syncobj_signal_ioctl(struct drm_device 
 *dev, void *data,
         return ret;
   }
+
+int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
+                struct drm_file *file_private)
+{
+    struct drm_syncobj_timeline_array *args = data;
+    struct drm_syncobj **syncobjs;
+    uint64_t __user *points = u64_to_user_ptr(args->points);
+    uint32_t i;
+    int ret;
+
+    if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+        return -ENODEV;
+
+    if (args->pad != 0)
+        return -EINVAL;
+
+    if (args->count_handles == 0)
+        return -EINVAL;
+
+    ret = drm_syncobj_array_find(file_private,
+                     u64_to_user_ptr(args->handles),
+                     args->count_handles,
+                     &syncobjs);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < args->count_handles; i++) {
+        struct dma_fence_chain *chain;
+        struct dma_fence *fence;
Quoted 8 lines

drivers/gpu/drm/drm_syncobj.c drm_syncobj_signal_ioctl(struct drm_device *dev, void *data, · line 1097

Quoted 5 lines
drivers/gpu/drm/drm_syncobj.c +5 -0
+        uint64_t point;
+
+        fence = drm_syncobj_fence_get(syncobjs[i]);
+        chain = to_dma_fence_chain(fence);
+        point = chain ? fence->seqno : 0;

Sorry, I don' t want to sound annoying, but this looks like this could report values going backward.

Well please be annoying as much as you can :) But yeah all that stuff has been discussed before as well.

Quoted 2 lines

Anything add a point X to a timeline that has reached value Y with X < Y would trigger that.

Yes, that can indeed happen. But adding a timeline point X which is before the already added point Y is illegal in the first place :)

So when the application does something stupid and breaks it can just keep the pieces.

In the kernel we still do the most defensive thing and sync to everything in this case.

I'm just not sure if we should print an error into syslog or just continue silently.

Regards,
Christian.

Quoted 41 lines

Either through the submission or userspace signaling or importing another syncpoint's fence.

-Lionel

Quoted 34 lines
drivers/gpu/drm/drm_syncobj.c +9 -0
+        ret = copy_to_user(&points[i], &point, sizeof(uint64_t));
+        ret = ret ? -EFAULT : 0;
+        if (ret)
+            break;
+    }
+    drm_syncobj_array_free(syncobjs, args->count_handles);
+
+    return ret;
+}
include/uapi/drm/drm.h +7 -0
index 0092111d002c..b2c36f2b2599 100644
@@ -767,6 +767,14 @@ struct drm_syncobj_array {
       __u32 pad;
   };
   +struct drm_syncobj_timeline_array {
+    __u64 handles;
+    __u64 points;
+    __u32 count_handles;
+    __u32 pad;
+};
+
+
   /* Query current scanout sequence number */
   struct drm_crtc_get_sequence {

      __u32 crtc_id;        /* requested crtc_id */

include/uapi/drm/drm.h +2 -0
@@ -924,6 +932,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_array)
+
   /**
Quoted 8 lines

include/uapi/drm/drm.h extern "C" { · line 939

Quoted 2 lines
include/uapi/drm/drm.h +0 -0
    * Device specific ioctls should only be in their respective headers
    * The device specific ioctl range is from 0x40 to 0x9f.

_______________________________________________
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): a24728a8-5b80-e746-a1f2-6555cd817e99-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

#27 lore raw

Re: [PATCH 06/11] drm/syncobj: add timeline payload query ioctl v4

Quoted 94 lines · Christian König

Am 15.02.19 um 20:31 schrieb Lionel Landwerlin via amd-gfx:

Quoted 84 lines · Chunming Zhou
Quoted 83 lines

user mode can query timeline payload.
v2: check return value of copy_to_user
v3: handle querying entry by entry
v4: rebase on new chain container, simplify interface

Cc Daniel Rakos <[email protected]>
Cc Jason Ekstrand <[email protected]>
Cc Bas Nieuwenhuizen <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Christian König <[email protected]>
Cc Chris Wilson <[email protected]>

---
  drivers/gpu/drm/drm_internal.h |  2 ++ drivers/gpu/drm/drm_ioctl.c    |  2 ++ drivers/gpu/drm/drm_syncobj.c  | 43
++++++++++++++++++++++++++++++++++
  include/uapi/drm/drm.h         | 10 ++++++++

  4 files changed, 57 insertions(+)
drivers/gpu/drm/drm_internal.h +2 -0
index 18b41e10195c..dab4d5936441 100644
@@ -184,6 +184,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 a9a17ed35cc4..7578ef6dc1d1 100644
@@ -681,6 +681,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 +29 -0
index 348079bb0965..f97fa00ca1d0 100644
@@ -1061,3 +1061,46 @@ drm_syncobj_signal_ioctl(struct drm_device 
 *dev, void *data,
         return ret;
   }
+
+int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
+                struct drm_file *file_private)
+{
+    struct drm_syncobj_timeline_array *args = data;
+    struct drm_syncobj **syncobjs;
+    uint64_t __user *points = u64_to_user_ptr(args->points);
+    uint32_t i;
+    int ret;
+
+    if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+        return -ENODEV;
+
+    if (args->pad != 0)
+        return -EINVAL;
+
+    if (args->count_handles == 0)
+        return -EINVAL;
+
+    ret = drm_syncobj_array_find(file_private,
+                     u64_to_user_ptr(args->handles),
+                     args->count_handles,
+                     &syncobjs);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < args->count_handles; i++) {
+        struct dma_fence_chain *chain;
+        struct dma_fence *fence;
Quoted 8 lines

drivers/gpu/drm/drm_syncobj.c drm_syncobj_signal_ioctl(struct drm_device *dev, void *data, · line 1097

Quoted 5 lines
drivers/gpu/drm/drm_syncobj.c +5 -0
+        uint64_t point;
+
+        fence = drm_syncobj_fence_get(syncobjs[i]);
+        chain = to_dma_fence_chain(fence);
+        point = chain ? fence->seqno : 0;

Sorry, I don' t want to sound annoying, but this looks like this could report values going backward.

Quoted 6 lines

Well please be annoying as much as you can :) But yeah all that stuff has been discussed before as well.

Quoted 2 lines

Anything add a point X to a timeline that has reached value Y with X < Y would trigger that.

Yes, that can indeed happen.

trigger what? when adding x (x < y), then return 0 when query?
Why would this happen?
No, syncobj->fence should always be there and the last chain node, if it is ever added.

-David

Quoted 61 lines

But adding a timeline point X which is before the already added point Y is illegal in the first place :)

So when the application does something stupid and breaks it can just keep the pieces.

In the kernel we still do the most defensive thing and sync to everything in this case.

I'm just not sure if we should print an error into syslog or just continue silently.

Regards,
Christian.

Quoted 49 lines

Either through the submission or userspace signaling or importing another syncpoint's fence.

-Lionel

Quoted 28 lines
drivers/gpu/drm/drm_syncobj.c +9 -0
+        ret = copy_to_user(&points[i], &point, sizeof(uint64_t));
+        ret = ret ? -EFAULT : 0;
+        if (ret)
+            break;
+    }
+    drm_syncobj_array_free(syncobjs, args->count_handles);
+
+    return ret;
+}
include/uapi/drm/drm.h +7 -0
index 0092111d002c..b2c36f2b2599 100644
@@ -767,6 +767,14 @@ struct drm_syncobj_array {
       __u32 pad;
   };
   +struct drm_syncobj_timeline_array {
+    __u64 handles;
+    __u64 points;
+    __u32 count_handles;
+    __u32 pad;
+};
+
+
   /* Query current scanout sequence number */
   struct drm_crtc_get_sequence {

      __u32 crtc_id;        /* requested crtc_id */

include/uapi/drm/drm.h extern "C" { · line 939

Quoted 8 lines
include/uapi/drm/drm.h +2 -0
@@ -924,6 +932,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_array)
+
   /**
    * Device specific ioctls should only be in their respective headers
    * The device specific ioctl range is from 0x40 to 0x9f.

_______________________________________________
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): eae060f6-6493-ef71-ed9d-52d7dd768b03-5C7GfCeVMHo@public.gmane.org

#29 lore raw

Re: [PATCH 06/11] drm/syncobj: add timeline payload query ioctl v4

Am 18.02.19 um 04:10 schrieb zhoucm1:

Quoted 110 lines · Christian König
Quoted 107 lines

Am 15.02.19 um 20:31 schrieb Lionel Landwerlin via amd-gfx:

Quoted 93 lines · Chunming Zhou
Quoted 92 lines

user mode can query timeline payload.
v2: check return value of copy_to_user
v3: handle querying entry by entry
v4: rebase on new chain container, simplify interface

Cc Daniel Rakos <[email protected]>
Cc Jason Ekstrand <[email protected]>
Cc Bas Nieuwenhuizen <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Christian König <[email protected]>
Cc Chris Wilson <[email protected]>

---
  drivers/gpu/drm/drm_internal.h |  2 ++ drivers/gpu/drm/drm_ioctl.c    |  2 ++ drivers/gpu/drm/drm_syncobj.c  | 43
++++++++++++++++++++++++++++++++++
  include/uapi/drm/drm.h         | 10 ++++++++

  4 files changed, 57 insertions(+)
drivers/gpu/drm/drm_internal.h +2 -0
index 18b41e10195c..dab4d5936441 100644
@@ -184,6 +184,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 a9a17ed35cc4..7578ef6dc1d1 100644
@@ -681,6 +681,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 +30 -0
index 348079bb0965..f97fa00ca1d0 100644
@@ -1061,3 +1061,46 @@ drm_syncobj_signal_ioctl(struct drm_device 
 *dev, void *data,
         return ret;
   }
+
+int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
+                struct drm_file *file_private)
+{
+    struct drm_syncobj_timeline_array *args = data;
+    struct drm_syncobj **syncobjs;
+    uint64_t __user *points = u64_to_user_ptr(args->points);
+    uint32_t i;
+    int ret;
+
+    if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+        return -ENODEV;
+
+    if (args->pad != 0)
+        return -EINVAL;
+
+    if (args->count_handles == 0)
+        return -EINVAL;
+
+    ret = drm_syncobj_array_find(file_private,
+                     u64_to_user_ptr(args->handles),
+                     args->count_handles,
+                     &syncobjs);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < args->count_handles; i++) {
+        struct dma_fence_chain *chain;
+        struct dma_fence *fence;
+        uint64_t point;
Quoted 8 lines

drivers/gpu/drm/drm_syncobj.c drm_syncobj_signal_ioctl(struct drm_device · line 1097

Quoted 4 lines
drivers/gpu/drm/drm_syncobj.c +4 -0
+
+        fence = drm_syncobj_fence_get(syncobjs[i]);
+        chain = to_dma_fence_chain(fence);
+        point = chain ? fence->seqno : 0;

Sorry, I don' t want to sound annoying, but this looks like this could report values going backward.

Well please be annoying as much as you can :) But yeah all that stuff has been discussed before as well.

Quoted 1 line
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

Anything add a point X to a timeline that has reached value Y with X < Y would trigger that.

Yes, that can indeed happen.

trigger what? when adding x (x < y), then return 0 when query? Why would this happen?
No, syncobj->fence should always be there and the last chain node, if it is ever added.

Well maybe Lionel should clarify a bit what he means?

I thought he is concerned that the call could return values where X < Y, but that doesn't seem to be the case.

Christian.

Quoted 71 lines

-David

Quoted 68 lines

But adding a timeline point X which is before the already added point Y is illegal in the first place :)

So when the application does something stupid and breaks it can just keep the pieces.

In the kernel we still do the most defensive thing and sync to everything in this case.

I'm just not sure if we should print an error into syslog or just continue silently.

Regards,
Christian.

Quoted 52 lines

Either through the submission or userspace signaling or importing another syncpoint's fence.

-Lionel

Quoted 36 lines
drivers/gpu/drm/drm_syncobj.c +9 -0
+        ret = copy_to_user(&points[i], &point, sizeof(uint64_t));
+        ret = ret ? -EFAULT : 0;
+        if (ret)
+            break;
+    }
+    drm_syncobj_array_free(syncobjs, args->count_handles);
+
+    return ret;
+}
include/uapi/drm/drm.h +7 -0
index 0092111d002c..b2c36f2b2599 100644
@@ -767,6 +767,14 @@ struct drm_syncobj_array {
       __u32 pad;
   };
   +struct drm_syncobj_timeline_array {
+    __u64 handles;
+    __u64 points;
+    __u32 count_handles;
+    __u32 pad;
+};
+
+
   /* Query current scanout sequence number */
   struct drm_crtc_get_sequence {

      __u32 crtc_id;        /* requested crtc_id */

include/uapi/drm/drm.h +2 -0
@@ -924,6 +932,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_array)
+
   /**
Quoted 2 lines

   * Device specific ioctls should only be in their respective headers
   * The device specific ioctl range is from 0x40 to 0x9f.

_______________________________________________
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): 4becddef-3bb3-5a66-34d4-95cced896939-5C7GfCeVMHo@public.gmane.org

#31 lore raw

Re: [PATCH 06/11] drm/syncobj: add timeline payload query ioctl v4

Quoted 114 lines · Christian

Am 18.02.19 um 04:10 schrieb zhoucm1:

Quoted 106 lines · Christian König
Quoted 104 lines

Am 15.02.19 um 20:31 schrieb Lionel Landwerlin via amd-gfx:

Quoted 92 lines · Chunming Zhou
Quoted 91 lines

user mode can query timeline payload.
v2: check return value of copy_to_user
v3: handle querying entry by entry
v4: rebase on new chain container, simplify interface

Cc Daniel Rakos <[email protected]>
Cc Jason Ekstrand <[email protected]>
Cc Bas Nieuwenhuizen <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Christian König <[email protected]>
Cc Chris Wilson <[email protected]>
---
   drivers/gpu/drm/drm_internal.h |  2 ++
   drivers/gpu/drm/drm_ioctl.c    |  2 ++
   drivers/gpu/drm/drm_syncobj.c  | 43
++++++++++++++++++++++++++++++++++
   include/uapi/drm/drm.h         | 10 ++++++++
   4 files changed, 57 insertions(+)
drivers/gpu/drm/drm_internal.h +2 -0
index 18b41e10195c..dab4d5936441 100644
@@ -184,6 +184,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 a9a17ed35cc4..7578ef6dc1d1 100644
@@ -681,6 +681,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 +29 -0
index 348079bb0965..f97fa00ca1d0 100644
@@ -1061,3 +1061,46 @@ drm_syncobj_signal_ioctl(struct drm_device
 *dev, void *data,
         return ret;
   }
+
+int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
+                struct drm_file *file_private)
+{
+    struct drm_syncobj_timeline_array *args = data;
+    struct drm_syncobj **syncobjs;
+    uint64_t __user *points = u64_to_user_ptr(args->points);
+    uint32_t i;
+    int ret;
+
+    if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+        return -ENODEV;
+
+    if (args->pad != 0)
+        return -EINVAL;
+
+    if (args->count_handles == 0)
+        return -EINVAL;
+
+    ret = drm_syncobj_array_find(file_private,
+                     u64_to_user_ptr(args->handles),
+                     args->count_handles,
+                     &syncobjs);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < args->count_handles; i++) {
+        struct dma_fence_chain *chain;
+        struct dma_fence *fence;
Quoted 8 lines

drivers/gpu/drm/drm_syncobj.c drm_syncobj_signal_ioctl(struct drm_device · line 1097

Quoted 5 lines
drivers/gpu/drm/drm_syncobj.c +5 -0
+        uint64_t point;
+
+        fence = drm_syncobj_fence_get(syncobjs[i]);
+        chain = to_dma_fence_chain(fence);
+        point = chain ? fence->seqno : 0;

Sorry, I don' t want to sound annoying, but this looks like this could report values going backward.

Well please be annoying as much as you can :) But yeah all that stuff has been discussed before as well.

Quoted 7 lines
Quoted 3 lines
Quoted 2 lines

Anything add a point X to a timeline that has reached value Y with X < Y would trigger that.

Yes, that can indeed happen.

trigger what? when adding x (x < y), then return 0 when query? Why would this happen?
No, syncobj->fence should always be there and the last chain node, if it is ever added.

Quoted 6 lines

Well maybe Lionel should clarify a bit what he means?

I thought he is concerned that the call could return values where X < Y, but that doesn't seem to be the case.

Christian.

I meant something like this :

t = create_timeline_syncobj()

signal(t, 2)

query(t) => 2

signal(t, 1)

query(t) => 1

-Lionel

Quoted 59 lines
Quoted 59 lines

-David

Quoted 57 lines

But adding a timeline point X which is before the already added point Y is illegal in the first place :)

So when the application does something stupid and breaks it can just keep the pieces.

In the kernel we still do the most defensive thing and sync to everything in this case.

I'm just not sure if we should print an error into syslog or just continue silently.

Regards,
Christian.

Quoted 42 lines

Either through the submission or userspace signaling or importing another syncpoint's fence.

-Lionel

Quoted 35 lines
drivers/gpu/drm/drm_syncobj.c +9 -0
+        ret = copy_to_user(&points[i], &point, sizeof(uint64_t));
+        ret = ret ? -EFAULT : 0;
+        if (ret)
+            break;
+    }
+    drm_syncobj_array_free(syncobjs, args->count_handles);
+
+    return ret;
+}
include/uapi/drm/drm.h +9 -0
index 0092111d002c..b2c36f2b2599 100644
@@ -767,6 +767,14 @@ struct drm_syncobj_array {
       __u32 pad;
   };
   +struct drm_syncobj_timeline_array {
+    __u64 handles;
+    __u64 points;
+    __u32 count_handles;
+    __u32 pad;
+};
+
+
   /* Query current scanout sequence number */
   struct drm_crtc_get_sequence {
       __u32 crtc_id;        /* requested crtc_id */
@@ -924,6 +932,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_array)
+
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
include/uapi/drm/drm.h +0 -0
   /**

   * Device specific ioctls should only be in their respective headers
   * The device specific ioctl range is from 0x40 to 0x9f.

_______________________________________________
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

#32 lore raw

PATCH 7/11 drm/syncobj: use the timeline point in drm_syncobj_find_fence v3

In reply to a message not in the archive

From: Christian König <[email protected]>

Implement finding the right timeline point in drm_syncobj_find_fence.

v2: return -EINVAL when the point is not submitted yet.
v3: fix reference counting bug, add flags handling as well

---
 drivers/gpu/drm/drm_syncobj.c | 43 ++++++++++++++++++++++++++++++++---
 1 file changed, 40 insertions(+), 3 deletions(-)
drivers/gpu/drm/drm_syncobj.c +40 -3
index f97fa00ca1d0..282982e58dbd 100644
@@ -231,16 +231,53 @@ 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;
+	struct syncobj_wait_entry wait;
+	int ret;
 
 	if (!syncobj)
 		return -ENOENT;
 
 	*fence = drm_syncobj_fence_get(syncobj);
-	if (!*fence) {
+	drm_syncobj_put(syncobj);
+
+	if (*fence) {
+		ret = dma_fence_chain_find_seqno(fence, point);
+		if (!ret)
+			return 0;
+		dma_fence_put(*fence);
+	} else {
 		ret = -EINVAL;
 	}
-	drm_syncobj_put(syncobj);
+
+	if (!(flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT))
+		return ret;
+
+	memset(&wait, 0, sizeof(wait));
+	wait.task = current;
+	wait.point = point;
+	drm_syncobj_fence_add_wait(syncobj, &wait);
+
+	do {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (wait.fence) {
+			ret = 0;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+
+		schedule();
+	} while (1);
+
+	__set_current_state(TASK_RUNNING);
+	*fence = wait.fence;
+
+	if (wait.node.next)
+		drm_syncobj_remove_wait(syncobj, &wait);
+
 	return ret;
 }
 EXPORT_SYMBOL(drm_syncobj_find_fence);
Signature · 6 lines
2.17.1

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

PATCH 9/11 drm/syncobj: add transition iotcls between binary and timeline

In reply to a message not in the archive

we need to import/export timeline point

---
 drivers/gpu/drm/drm_internal.h |  4 +++
 drivers/gpu/drm/drm_ioctl.c    |  6 ++++
 drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
 include/uapi/drm/drm.h         | 10 ++++++
 4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+					 struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+		      drm_syncobj_binary_to_timeline_ioctl,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+		      drm_syncobj_timeline_to_binary_ioctl,
+		      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 +66 -0

72 lines not on this page · raw message

include/uapi/drm/drm.h +10 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
 	__u32 pad;
 };
 
+struct drm_syncobj_transfer {
+	__u32 binary_handle;
+	__u32 timeline_handle;
+	__u64 point;
+	__u32 flags;
+	__u32 pad;
+};
+
 #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
 #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
 #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
@@ -933,6 +941,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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE	DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY	DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
 /**
  * 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
#34 lore raw

Re: [PATCH 09/11] drm/syncobj: add transition iotcls between binary and timeline

I would rather just use a single IOCTL for this and handle point 0 as distinction if we should add a new point or replace the binary one.

Christian.

Am 07.12.18 um 10:55 schrieb Chunming Zhou:

Quoted 139 lines

we need to import/export timeline point

---
  drivers/gpu/drm/drm_internal.h |  4 +++
  drivers/gpu/drm/drm_ioctl.c    |  6 ++++
  drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
  include/uapi/drm/drm.h         | 10 ++++++
  4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+					 struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+		      drm_syncobj_binary_to_timeline_ioctl,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+		      drm_syncobj_timeline_to_binary_ioctl,
+		      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 +66 -0
index 282982e58dbd..cf4daa670252 100644
@@ -670,6 +670,72 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
  					&args->handle);
  }
 
+int
+drm_syncobj_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *timeline_syncobj = NULL;
+	struct dma_fence *fence;
+	struct dma_fence_chain *chain;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	timeline_syncobj = drm_syncobj_find(file_private, args->timeline_handle);
+	if (!timeline_syncobj) {
+		return -ENOENT;
+	}
+	ret = drm_syncobj_find_fence(file_private, args->binary_handle, 0, 0,
+				     &fence);
+	if (ret)
+		goto err;
+	chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL);
+	if (!chain)
+		goto err1;
+	drm_syncobj_add_point(timeline_syncobj, chain, fence, args->point);
+err1:
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(timeline_syncobj);
+
+	return ret;
+}
+
+int
+drm_syncobj_timeline_to_binary_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *binary_syncobj = NULL;
+	struct dma_fence *fence;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	binary_syncobj = drm_syncobj_find(file_private, args->binary_handle);
+	if (!binary_syncobj)
+		return -ENOENT;
+	ret = drm_syncobj_find_fence(file_private, args->timeline_handle,
+				     args->point, args->flags, &fence);
+	if (ret)
+		goto err;
+	drm_syncobj_replace_fence(binary_syncobj, fence);
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(binary_syncobj);
+
+	return ret;
+}
+
  static void syncobj_wait_fence_func(struct dma_fence *fence,
  				    struct dma_fence_cb *cb)
  {
include/uapi/drm/drm.h +8 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
  	__u32 pad;
  };
 
+struct drm_syncobj_transfer {
+	__u32 binary_handle;
+	__u32 timeline_handle;
+	__u64 point;
+	__u32 flags;
+	__u32 pad;
+};
+
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)

include/uapi/drm/drm.h extern "C" { · line 948

Quoted 8 lines
include/uapi/drm/drm.h +2 -0
@@ -933,6 +941,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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE	DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY	DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
  /**
   * Device specific ioctls should only be in their respective headers

_______________________________________________
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]

#36 lore raw

Re: [PATCH 09/11] drm/syncobj: add transition iotcls between binary and timeline

Hi David,

Thanks a lot for point me to the tests you've added in IGT.
While adding a test with that signals fences imported into a timeline syncobj out of order, I ran into a deadlock. Here is the test : https://github.com/djdeath/intel-gpu-tools/commit/1e46cf7e7bff09b78a24367ddc2314f97eb0a1b9

Trying to kill the deadlocked process I got this backtrace :

[   33.969136] [IGT] syncobj_timeline: starting subtest signal-order
[   60.452823] watchdog: BUG: soft lockup - CPU#6 stuck for 23s! [syncobj_timelin:2021]
[   60.452826] Modules linked in: rfcomm cmac bnep binfmt_misc nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio sch_fq_codel ib_iser snd_hda_intel rdma_cm iw_cm snd_hda_codec ib_cm snd_hda_core snd_hwdep intel_rapl snd_pcm ib_core x86_pkg_temp_thermal intel_powerclamp configf s coretemp iscsi_tcp snd_seq_midi libiscsi_tcp snd_seq_midi_event libiscsi kvm_intel scsi_transport_iscsi kvm btusb snd_rawmidi irqbypass btrtl intel_cstate intel_rapl_perf btbcm btintel bluetooth snd_seq snd_seq_device snd_timer input_leds ecdh_generic snd soundcore mei_me mei intel_pch_thermal mac_hid acpi_pad parp ort_pc ppdev lp parport ip_tables x_tables autofs4 btrfs zstd_decompress zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid i915 crct10dif_pclmul crc32_pclmul i2c_algo_bit ghash_clmulni_intel prime_numbers drm_kms_helper aesni_intel syscopyarea sysfillrect
[   60.452876]  sysimgblt fb_sys_fops aes_x86_64 crypto_simd sdhci_pci cryptd drm e1000e glue_helper cqhci sdhci wmi video
[   60.452881] CPU: 6 PID: 2021 Comm: syncobj_timelin Tainted: G     U            5.0.0-rc5+ #337
[   60.452882] Hardware name:  /NUC6i7KYB, BIOS KYSKLi70.86A.0042.2016.0929.1933 09/29/2016
[   60.452886] RIP: 0010:dma_fence_chain_walk+0x22c/0x260
[   60.452888] Code: ff e9 93 fe ff ff 48 8b 45 08 48 8b 40 18 48 85 c0 74 0c 48 89 ef e8 33 0f 58 00 84 c0 75 23 f0 41 ff 4d 00 0f 88 99 87 2f 00 <0f> 85 05 fe ff ff 4c 89 ef e8 56 ea ff ff 48 89 d8 5b 5d 41 5c 41
[   60.452888] RSP: 0018:ffff9a5804653ca8 EFLAGS: 00010296 ORIG_RAX: ffffffffffffff13
[   60.452889] RAX: 0000000000000000 RBX: ffff8f5690fb2480 RCX: ffff8f5690fb2f00
[   60.452890] RDX: 00000000003e3730 RSI: 0000000000000000 RDI: ffff8f5690fb2180
[   60.452891] RBP: ffff8f5690fb2180 R08: 0000000000000000 R09: ffff8f5690fb2eb0
[   60.452891] R10: 0000000000000000 R11: ffff8f5660469860 R12: ffff8f5690fb2f68
[   60.452892] R13: ffff8f5690fb2f00 R14: 0000000000000003 R15: ffff8f5655a45fc0
[   60.452913] FS:  00007fdc5c459980(0000) GS:ffff8f569eb80000(0000) knlGS:0000000000000000
[   60.452913] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   60.452914] CR2: 00007f9d74336dd8 CR3: 000000084a67e004 CR4: 00000000003606e0
[   60.452915] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   60.452915] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[   60.452916] Call Trace:
[   60.452958]  drm_syncobj_add_point+0x102/0x160 [drm]
[   60.452965]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm]
[   60.452971]  drm_syncobj_transfer_ioctl+0x10f/0x180 [drm]
[   60.452978]  drm_ioctl_kernel+0xac/0xf0 [drm]
[   60.452984]  drm_ioctl+0x2eb/0x3b0 [drm]
[   60.452990]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm]
[   60.452992]  ? sw_sync_ioctl+0x347/0x370
[   60.452994]  do_vfs_ioctl+0xa4/0x640
[   60.452995]  ? __fput+0x134/0x220
[   60.452997]  ? do_fcntl+0x1a5/0x650
[   60.452998]  ksys_ioctl+0x70/0x80
[   60.452999]  __x64_sys_ioctl+0x16/0x20
[   60.453002]  do_syscall_64+0x55/0x110
[   60.453004]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   60.453005] RIP: 0033:0x7fdc5b6e45d7
[   60.453006] 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
[   60.453007] RSP: 002b:00007fff25c4d198 EFLAGS: 00000206 ORIG_RAX: 0000000000000010
[   60.453008] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fdc5b6e45d7
[   60.453008] RDX: 00007fff25c4d200 RSI: 00000000c02064cc RDI: 0000000000000003
[   60.453009] RBP: 00007fff25c4d1d0 R08: 0000000000000000 R09: 000000000000001e
[   60.453010] R10: 0000000000000000 R11: 0000000000000206 R12: 0000563d3959e4d0
[   60.453010] R13: 00007fff25c4d620 R14: 0000000000000000 R15: 0000000000000000
[   88.447359] watchdog: BUG: soft lockup - CPU#6 stuck for 22s! [syncobj_timelin:2021]

-Lionel

Quoted 139 lines · Chunming Zhou

we need to import/export timeline point

---
  drivers/gpu/drm/drm_internal.h |  4 +++
  drivers/gpu/drm/drm_ioctl.c    |  6 ++++
  drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
  include/uapi/drm/drm.h         | 10 ++++++
  4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+					 struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+		      drm_syncobj_binary_to_timeline_ioctl,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+		      drm_syncobj_timeline_to_binary_ioctl,
+		      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 +66 -0
index 282982e58dbd..cf4daa670252 100644
@@ -670,6 +670,72 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
  					&args->handle);
  }
 
+int
+drm_syncobj_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *timeline_syncobj = NULL;
+	struct dma_fence *fence;
+	struct dma_fence_chain *chain;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	timeline_syncobj = drm_syncobj_find(file_private, args->timeline_handle);
+	if (!timeline_syncobj) {
+		return -ENOENT;
+	}
+	ret = drm_syncobj_find_fence(file_private, args->binary_handle, 0, 0,
+				     &fence);
+	if (ret)
+		goto err;
+	chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL);
+	if (!chain)
+		goto err1;
+	drm_syncobj_add_point(timeline_syncobj, chain, fence, args->point);
+err1:
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(timeline_syncobj);
+
+	return ret;
+}
+
+int
+drm_syncobj_timeline_to_binary_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *binary_syncobj = NULL;
+	struct dma_fence *fence;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	binary_syncobj = drm_syncobj_find(file_private, args->binary_handle);
+	if (!binary_syncobj)
+		return -ENOENT;
+	ret = drm_syncobj_find_fence(file_private, args->timeline_handle,
+				     args->point, args->flags, &fence);
+	if (ret)
+		goto err;
+	drm_syncobj_replace_fence(binary_syncobj, fence);
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(binary_syncobj);
+
+	return ret;
+}
+
  static void syncobj_wait_fence_func(struct dma_fence *fence,
  				    struct dma_fence_cb *cb)
  {
include/uapi/drm/drm.h +8 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
  	__u32 pad;
  };
 
+struct drm_syncobj_transfer {
+	__u32 binary_handle;
+	__u32 timeline_handle;
+	__u64 point;
+	__u32 flags;
+	__u32 pad;
+};
+
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)

include/uapi/drm/drm.h extern "C" { · line 948

Quoted 8 lines
include/uapi/drm/drm.h +2 -0
@@ -933,6 +941,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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE	DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY	DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
  /**
   * Device specific ioctls should only be in their respective headers

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

#37 lore raw

Re: [PATCH 09/11] drm/syncobj: add transition iotcls between binary and timeline

Hi Lionel,

I checked your igt test case,

uint64_t points[5] = { 1, 5, 3, 7, 6 };

which is illegal signal order.

I must admit we should handle it gracefully if signal isn't in-order, and we shouldn't lead to deadlock.

Hi Christian,

Can we just ignore when signal point X <= timeline Y? Or just give a warning?

Otherwise like Lionel's unexpected use cases, which easily leads to deadlock.

-David

Quoted 240 lines · Lionel Landwerlin

Hi David,

Thanks a lot for point me to the tests you've added in IGT. While adding a test with that signals fences imported into a timeline syncobj out of order, I ran into a deadlock.
Here is the test :
https://github.com/djdeath/intel-gpu-tools/commit/1e46cf7e7bff09b78a24367ddc2314f97eb0a1b9

Trying to kill the deadlocked process I got this backtrace :

[   33.969136] [IGT] syncobj_timeline: starting subtest signal-order [   60.452823] watchdog: BUG: soft lockup - CPU#6 stuck for 23s! [syncobj_timelin:2021]
[   60.452826] Modules linked in: rfcomm cmac bnep binfmt_misc nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio sch_fq_codel ib_iser snd_hda_intel rdma_cm iw_cm snd_hda_codec ib_cm snd_hda_core snd_hwdep intel_rapl snd_pcm ib_core x86_pkg_temp_thermal intel_powerclamp configf s coretemp iscsi_tcp snd_seq_midi libiscsi_tcp snd_seq_midi_event libiscsi kvm_intel scsi_transport_iscsi kvm btusb snd_rawmidi irqbypass btrtl intel_cstate intel_rapl_perf btbcm btintel bluetooth snd_seq snd_seq_device snd_timer input_leds ecdh_generic snd soundcore mei_me mei intel_pch_thermal mac_hid acpi_pad parp
ort_pc ppdev lp parport ip_tables x_tables autofs4 btrfs zstd_decompress zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid i915 crct10dif_pclmul crc32_pclmul i2c_algo_bit ghash_clmulni_intel prime_numbers
drm_kms_helper aesni_intel syscopyarea sysfillrect
[   60.452876]  sysimgblt fb_sys_fops aes_x86_64 crypto_simd sdhci_pci cryptd drm e1000e glue_helper cqhci sdhci wmi video
[   60.452881] CPU: 6 PID: 2021 Comm: syncobj_timelin Tainted: G U            5.0.0-rc5+ #337
[   60.452882] Hardware name:  /NUC6i7KYB, BIOS KYSKLi70.86A.0042.2016.0929.1933 09/29/2016
[   60.452886] RIP: 0010:dma_fence_chain_walk+0x22c/0x260
[   60.452888] Code: ff e9 93 fe ff ff 48 8b 45 08 48 8b 40 18 48 85 c0 74 0c 48 89 ef e8 33 0f 58 00 84 c0 75 23 f0 41 ff 4d 00 0f 88 99 87 2f 00 <0f> 85 05 fe ff ff 4c 89 ef e8 56 ea ff ff 48 89 d8 5b 5d 41 5c 41 [   60.452888] RSP: 0018:ffff9a5804653ca8 EFLAGS: 00010296 ORIG_RAX:
ffffffffffffff13
[   60.452889] RAX: 0000000000000000 RBX: ffff8f5690fb2480 RCX:
ffff8f5690fb2f00
[   60.452890] RDX: 00000000003e3730 RSI: 0000000000000000 RDI:
ffff8f5690fb2180
[   60.452891] RBP: ffff8f5690fb2180 R08: 0000000000000000 R09:
ffff8f5690fb2eb0
[   60.452891] R10: 0000000000000000 R11: ffff8f5660469860 R12:
ffff8f5690fb2f68
[   60.452892] R13: ffff8f5690fb2f00 R14: 0000000000000003 R15:
ffff8f5655a45fc0
[   60.452913] FS:  00007fdc5c459980(0000) GS:ffff8f569eb80000(0000) knlGS:0000000000000000
[   60.452913] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [   60.452914] CR2: 00007f9d74336dd8 CR3: 000000084a67e004 CR4:
00000000003606e0
[   60.452915] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[   60.452915] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[   60.452916] Call Trace:
[   60.452958]  drm_syncobj_add_point+0x102/0x160 [drm]
[   60.452965]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm] [   60.452971]  drm_syncobj_transfer_ioctl+0x10f/0x180 [drm] [   60.452978]  drm_ioctl_kernel+0xac/0xf0 [drm]
[   60.452984]  drm_ioctl+0x2eb/0x3b0 [drm]
[   60.452990]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm] [   60.452992]  ? sw_sync_ioctl+0x347/0x370
[   60.452994]  do_vfs_ioctl+0xa4/0x640
[   60.452995]  ? __fput+0x134/0x220
[   60.452997]  ? do_fcntl+0x1a5/0x650
[   60.452998]  ksys_ioctl+0x70/0x80
[   60.452999]  __x64_sys_ioctl+0x16/0x20
[   60.453002]  do_syscall_64+0x55/0x110
[   60.453004]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   60.453005] RIP: 0033:0x7fdc5b6e45d7
[   60.453006] 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 [   60.453007] RSP: 002b:00007fff25c4d198 EFLAGS: 00000206 ORIG_RAX:
0000000000000010
[   60.453008] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
00007fdc5b6e45d7
[   60.453008] RDX: 00007fff25c4d200 RSI: 00000000c02064cc RDI:
0000000000000003
[   60.453009] RBP: 00007fff25c4d1d0 R08: 0000000000000000 R09:
000000000000001e
[   60.453010] R10: 0000000000000000 R11: 0000000000000206 R12:
0000563d3959e4d0
[   60.453010] R13: 00007fff25c4d620 R14: 0000000000000000 R15:
0000000000000000
[   88.447359] watchdog: BUG: soft lockup - CPU#6 stuck for 22s! [syncobj_timelin:2021]

-Lionel

Quoted 140 lines · Chunming Zhou

we need to import/export timeline point

---
   drivers/gpu/drm/drm_internal.h |  4 +++
   drivers/gpu/drm/drm_ioctl.c    |  6 ++++
   drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
   include/uapi/drm/drm.h         | 10 ++++++
   4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+					 struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+		      drm_syncobj_binary_to_timeline_ioctl,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+		      drm_syncobj_timeline_to_binary_ioctl,
+		      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 +66 -0
index 282982e58dbd..cf4daa670252 100644
@@ -670,6 +670,72 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
   					&args->handle);
   }
 
+int
+drm_syncobj_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *timeline_syncobj = NULL;
+	struct dma_fence *fence;
+	struct dma_fence_chain *chain;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	timeline_syncobj = drm_syncobj_find(file_private, args->timeline_handle);
+	if (!timeline_syncobj) {
+		return -ENOENT;
+	}
+	ret = drm_syncobj_find_fence(file_private, args->binary_handle, 0, 0,
+				     &fence);
+	if (ret)
+		goto err;
+	chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL);
+	if (!chain)
+		goto err1;
+	drm_syncobj_add_point(timeline_syncobj, chain, fence, args->point);
+err1:
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(timeline_syncobj);
+
+	return ret;
+}
+
+int
+drm_syncobj_timeline_to_binary_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *binary_syncobj = NULL;
+	struct dma_fence *fence;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	binary_syncobj = drm_syncobj_find(file_private, args->binary_handle);
+	if (!binary_syncobj)
+		return -ENOENT;
+	ret = drm_syncobj_find_fence(file_private, args->timeline_handle,
+				     args->point, args->flags, &fence);
+	if (ret)
+		goto err;
+	drm_syncobj_replace_fence(binary_syncobj, fence);
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(binary_syncobj);
+
+	return ret;
+}
+
   static void syncobj_wait_fence_func(struct dma_fence *fence,
   				    struct dma_fence_cb *cb)
   {
include/uapi/drm/drm.h +8 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
   	__u32 pad;
   };
 
+struct drm_syncobj_transfer {
+	__u32 binary_handle;
+	__u32 timeline_handle;
+	__u64 point;
+	__u32 flags;
+	__u32 pad;
+};
+
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
@@ -933,6 +941,8 @@ extern "C" {
 
Quoted 8 lines

include/uapi/drm/drm.h extern "C" { · line 948

Quoted 7 lines
include/uapi/drm/drm.h +2 -0
   #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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE	DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY	DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
   /**
    * Device specific ioctls should only be in their respective headers

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

#38 lore raw

Re: [PATCH 09/11] drm/syncobj: add transition iotcls between binary and timeline

Hi David,

well I think Lionel is testing the invalid signal order on purpose :)

Anyway we really need to handle invalid order graceful here. E.g. either the same way as during CS or we abort and return an error message.

I think just using the same approach as during CS ist the best we can do.

Regards,
Christian

Am 18.02.2019 11:35 schrieb "Zhou, David(ChunMing)" <[email protected]>:

Hi Lionel,

I checked your igt test case,

uint64_t points[5] = { 1, 5, 3, 7, 6 };

which is illegal signal order.

I must admit we should handle it gracefully if signal isn't in-order, and we shouldn't lead to deadlock.

Hi Christian,

Can we just ignore when signal point X <= timeline Y? Or just give a warning?

Otherwise like Lionel's unexpected use cases, which easily leads to deadlock.

-David

On 2019年02月15日 22:28, Lionel Landwerlin wrote:

Hi David,

Thanks a lot for point me to the tests you've added in IGT. While adding a test with that signals fences imported into a timeline syncobj out of order, I ran into a deadlock.
Here is the test :
https://github.com/djdeath/intel-gpu-tools/commit/1e46cf7e7bff09b78a24367ddc2314f97eb0a1b9

Trying to kill the deadlocked process I got this backtrace :

[   33.969136] [IGT] syncobj_timeline: starting subtest signal-order
[   60.452823] watchdog: BUG: soft lockup - CPU#6 stuck for 23s!
[syncobj_timelin:2021]
[   60.452826] Modules linked in: rfcomm cmac bnep binfmt_misc

nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio sch_fq_codel ib_iser snd_hda_intel rdma_cm iw_cm snd_hda_codec ib_cm snd_hda_core snd_hwdep intel_rapl snd_pcm ib_core x86_pkg_temp_thermal intel_powerclamp configf s coretemp iscsi_tcp snd_seq_midi libiscsi_tcp snd_seq_midi_event libiscsi kvm_intel scsi_transport_iscsi kvm btusb snd_rawmidi irqbypass btrtl intel_cstate intel_rapl_perf btbcm btintel bluetooth snd_seq snd_seq_device snd_timer input_leds ecdh_generic snd soundcore mei_me mei intel_pch_thermal mac_hid acpi_pad parp
ort_pc ppdev lp parport ip_tables x_tables autofs4 btrfs zstd_decompress zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid i915 crct10dif_pclmul crc32_pclmul i2c_algo_bit ghash_clmulni_intel prime_numbers
drm_kms_helper aesni_intel syscopyarea sysfillrect

[   60.452876]  sysimgblt fb_sys_fops aes_x86_64 crypto_simd sdhci_pci
cryptd drm e1000e glue_helper cqhci sdhci wmi video
[   60.452881] CPU: 6 PID: 2021 Comm: syncobj_timelin Tainted: G
U            5.0.0-rc5+ #337
[   60.452882] Hardware name:  /NUC6i7KYB, BIOS
KYSKLi70.86A.0042.2016.0929.1933 09/29/2016
[   60.452886] RIP: 0010:dma_fence_chain_walk+0x22c/0x260
[   60.452888] Code: ff e9 93 fe ff ff 48 8b 45 08 48 8b 40 18 48 85 c0
74 0c 48 89 ef e8 33 0f 58 00 84 c0 75 23 f0 41 ff 4d 00 0f 88 99 87 2f
00 <0f> 85 05 fe ff ff 4c 89 ef e8 56 ea ff ff 48 89 d8 5b 5d 41 5c 41
[   60.452888] RSP: 0018:ffff9a5804653ca8 EFLAGS: 00010296 ORIG_RAX:
ffffffffffffff13
[   60.452889] RAX: 0000000000000000 RBX: ffff8f5690fb2480 RCX:
ffff8f5690fb2f00
[   60.452890] RDX: 00000000003e3730 RSI: 0000000000000000 RDI:
ffff8f5690fb2180
[   60.452891] RBP: ffff8f5690fb2180 R08: 0000000000000000 R09:
ffff8f5690fb2eb0
[   60.452891] R10: 0000000000000000 R11: ffff8f5660469860 R12:
ffff8f5690fb2f68
[   60.452892] R13: ffff8f5690fb2f00 R14: 0000000000000003 R15:
ffff8f5655a45fc0
[   60.452913] FS:  00007fdc5c459980(0000) GS:ffff8f569eb80000(0000)
knlGS:0000000000000000
[   60.452913] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   60.452914] CR2: 00007f9d74336dd8 CR3: 000000084a67e004 CR4:
00000000003606e0
[   60.452915] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[   60.452915] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[   60.452916] Call Trace:
[   60.452958]  drm_syncobj_add_point+0x102/0x160 [drm]
[   60.452965]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm]
[   60.452971]  drm_syncobj_transfer_ioctl+0x10f/0x180 [drm]
[   60.452978]  drm_ioctl_kernel+0xac/0xf0 [drm]
[   60.452984]  drm_ioctl+0x2eb/0x3b0 [drm]
[   60.452990]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm]
[   60.452992]  ? sw_sync_ioctl+0x347/0x370
[   60.452994]  do_vfs_ioctl+0xa4/0x640
[   60.452995]  ? __fput+0x134/0x220
[   60.452997]  ? do_fcntl+0x1a5/0x650
[   60.452998]  ksys_ioctl+0x70/0x80
[   60.452999]  __x64_sys_ioctl+0x16/0x20
[   60.453002]  do_syscall_64+0x55/0x110
[   60.453004]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   60.453005] RIP: 0033:0x7fdc5b6e45d7
[   60.453006] 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
[   60.453007] RSP: 002b:00007fff25c4d198 EFLAGS: 00000206 ORIG_RAX:
0000000000000010
[   60.453008] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
00007fdc5b6e45d7
[   60.453008] RDX: 00007fff25c4d200 RSI: 00000000c02064cc RDI:
0000000000000003
[   60.453009] RBP: 00007fff25c4d1d0 R08: 0000000000000000 R09:
000000000000001e
[   60.453010] R10: 0000000000000000 R11: 0000000000000206 R12:
0000563d3959e4d0
[   60.453010] R13: 00007fff25c4d620 R14: 0000000000000000 R15:
0000000000000000
[   88.447359] watchdog: BUG: soft lockup - CPU#6 stuck for 22s!

[syncobj_timelin:2021]

-Lionel

On 07/12/2018 09:55, Chunming Zhou wrote:

we need to import/export timeline point

---
  drivers/gpu/drm/drm_internal.h |  4 +++
  drivers/gpu/drm/drm_ioctl.c    |  6 ++++
  drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
  include/uapi/drm/drm.h         | 10 ++++++
  4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+                                        struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+                     drm_syncobj_binary_to_timeline_ioctl,
+                     DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+                     drm_syncobj_timeline_to_binary_ioctl,
+                     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 +66 -0

72 lines not on this page · raw message

include/uapi/drm/drm.h +10 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
        __u32 pad;
  };
 
+struct drm_syncobj_transfer {
+       __u32 binary_handle;
+       __u32 timeline_handle;
+       __u64 point;
+       __u32 flags;
+       __u32 pad;
+};
+
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
@@ -933,6 +941,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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE   DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY   DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
  /**
   * Device specific ioctls should only be in their respective headers

_______________________________________________
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): 27a38e11-0c77-4340-aac9-b02e816c6f58-2ueSQiBKiTY7tOexoI0I+QC/[email protected]

#40 lore raw

Re: [PATCH 09/11] drm/syncobj: add transition iotcls between binary and timeline

Thanks guys :)

You mentioned that signaling out of order is illegal.
Is this illegal with regard to the vulkan spec or to the syncobj implementation?

I'm not finding anything in the vulkan spec that makes out of order signaling illegal.
That's why I came up with this test, just verifying that the timeline does not go backward in term of its payload.

-Lionel

Quoted 275 lines · Christian

Hi David,

well I think Lionel is testing the invalid signal order on purpose :)

Anyway we really need to handle invalid order graceful here. E.g. either the same way as during CS or we abort and return an error message.

I think just using the same approach as during CS ist the best we can do.

Regards,
Christian

Am 18.02.2019 11:35 schrieb "Zhou, David(ChunMing)" <[email protected]>:

Hi Lionel,

I checked your igt test case,

uint64_t points[5] = { 1, 5, 3, 7, 6 };

which is illegal signal order.

I must admit we should handle it gracefully if signal isn't in-order, and we shouldn't lead to deadlock.

Hi Christian,

Can we just ignore when signal point X <= timeline Y? Or just give a warning?

Otherwise like Lionel's unexpected use cases, which easily leads to deadlock.

-David

Quoted 240 lines · Lionel Landwerlin

Hi David,

Thanks a lot for point me to the tests you've added in IGT. While adding a test with that signals fences imported into a timeline syncobj out of order, I ran into a deadlock.
Here is the test :
https://github.com/djdeath/intel-gpu-tools/commit/1e46cf7e7bff09b78a24367ddc2314f97eb0a1b9

Trying to kill the deadlocked process I got this backtrace :

[   33.969136] [IGT] syncobj_timeline: starting subtest signal-order [   60.452823] watchdog: BUG: soft lockup - CPU#6 stuck for 23s! [syncobj_timelin:2021]
[   60.452826] Modules linked in: rfcomm cmac bnep binfmt_misc nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio sch_fq_codel ib_iser snd_hda_intel rdma_cm iw_cm snd_hda_codec ib_cm snd_hda_core snd_hwdep intel_rapl snd_pcm ib_core x86_pkg_temp_thermal intel_powerclamp configf s coretemp iscsi_tcp snd_seq_midi libiscsi_tcp snd_seq_midi_event libiscsi kvm_intel scsi_transport_iscsi kvm btusb snd_rawmidi irqbypass btrtl intel_cstate intel_rapl_perf btbcm btintel bluetooth snd_seq snd_seq_device snd_timer input_leds ecdh_generic snd soundcore mei_me mei intel_pch_thermal mac_hid acpi_pad parp
ort_pc ppdev lp parport ip_tables x_tables autofs4 btrfs zstd_decompress zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid i915 crct10dif_pclmul crc32_pclmul i2c_algo_bit ghash_clmulni_intel prime_numbers
drm_kms_helper aesni_intel syscopyarea sysfillrect
[   60.452876]  sysimgblt fb_sys_fops aes_x86_64 crypto_simd sdhci_pci cryptd drm e1000e glue_helper cqhci sdhci wmi video
[   60.452881] CPU: 6 PID: 2021 Comm: syncobj_timelin Tainted: G U            5.0.0-rc5+ #337
[   60.452882] Hardware name:  /NUC6i7KYB, BIOS KYSKLi70.86A.0042.2016.0929.1933 09/29/2016
[   60.452886] RIP: 0010:dma_fence_chain_walk+0x22c/0x260
[   60.452888] Code: ff e9 93 fe ff ff 48 8b 45 08 48 8b 40 18 48 85 c0 74 0c 48 89 ef e8 33 0f 58 00 84 c0 75 23 f0 41 ff 4d 00 0f 88 99 87 2f 00 <0f> 85 05 fe ff ff 4c 89 ef e8 56 ea ff ff 48 89 d8 5b 5d 41 5c 41 [   60.452888] RSP: 0018:ffff9a5804653ca8 EFLAGS: 00010296 ORIG_RAX:
ffffffffffffff13
[   60.452889] RAX: 0000000000000000 RBX: ffff8f5690fb2480 RCX:
ffff8f5690fb2f00
[   60.452890] RDX: 00000000003e3730 RSI: 0000000000000000 RDI:
ffff8f5690fb2180
[   60.452891] RBP: ffff8f5690fb2180 R08: 0000000000000000 R09:
ffff8f5690fb2eb0
[   60.452891] R10: 0000000000000000 R11: ffff8f5660469860 R12:
ffff8f5690fb2f68
[   60.452892] R13: ffff8f5690fb2f00 R14: 0000000000000003 R15:
ffff8f5655a45fc0
[   60.452913] FS:  00007fdc5c459980(0000) GS:ffff8f569eb80000(0000) knlGS:0000000000000000
[   60.452913] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [   60.452914] CR2: 00007f9d74336dd8 CR3: 000000084a67e004 CR4:
00000000003606e0
[   60.452915] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[   60.452915] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[   60.452916] Call Trace:
[   60.452958]  drm_syncobj_add_point+0x102/0x160 [drm]
[   60.452965]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm] [   60.452971]  drm_syncobj_transfer_ioctl+0x10f/0x180 [drm] [   60.452978]  drm_ioctl_kernel+0xac/0xf0 [drm]
[   60.452984]  drm_ioctl+0x2eb/0x3b0 [drm]
[   60.452990]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm] [   60.452992]  ? sw_sync_ioctl+0x347/0x370
[   60.452994]  do_vfs_ioctl+0xa4/0x640
[   60.452995]  ? __fput+0x134/0x220
[   60.452997]  ? do_fcntl+0x1a5/0x650
[   60.452998]  ksys_ioctl+0x70/0x80
[   60.452999]  __x64_sys_ioctl+0x16/0x20
[   60.453002]  do_syscall_64+0x55/0x110
[   60.453004]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   60.453005] RIP: 0033:0x7fdc5b6e45d7
[   60.453006] 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 [   60.453007] RSP: 002b:00007fff25c4d198 EFLAGS: 00000206 ORIG_RAX:
0000000000000010
[   60.453008] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
00007fdc5b6e45d7
[   60.453008] RDX: 00007fff25c4d200 RSI: 00000000c02064cc RDI:
0000000000000003
[   60.453009] RBP: 00007fff25c4d1d0 R08: 0000000000000000 R09:
000000000000001e
[   60.453010] R10: 0000000000000000 R11: 0000000000000206 R12:
0000563d3959e4d0
[   60.453010] R13: 00007fff25c4d620 R14: 0000000000000000 R15:
0000000000000000
[   88.447359] watchdog: BUG: soft lockup - CPU#6 stuck for 22s! [syncobj_timelin:2021]

-Lionel

Quoted 140 lines · Chunming Zhou

we need to import/export timeline point

---
   drivers/gpu/drm/drm_internal.h |  4 +++
   drivers/gpu/drm/drm_ioctl.c    |  6 ++++
   drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
   include/uapi/drm/drm.h         | 10 ++++++
   4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+					 struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+		      drm_syncobj_binary_to_timeline_ioctl,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+		      drm_syncobj_timeline_to_binary_ioctl,
+		      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 +66 -0
index 282982e58dbd..cf4daa670252 100644
@@ -670,6 +670,72 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
   					&args->handle);
   }
 
+int
+drm_syncobj_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *timeline_syncobj = NULL;
+	struct dma_fence *fence;
+	struct dma_fence_chain *chain;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	timeline_syncobj = drm_syncobj_find(file_private, args->timeline_handle);
+	if (!timeline_syncobj) {
+		return -ENOENT;
+	}
+	ret = drm_syncobj_find_fence(file_private, args->binary_handle, 0, 0,
+				     &fence);
+	if (ret)
+		goto err;
+	chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL);
+	if (!chain)
+		goto err1;
+	drm_syncobj_add_point(timeline_syncobj, chain, fence, args->point);
+err1:
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(timeline_syncobj);
+
+	return ret;
+}
+
+int
+drm_syncobj_timeline_to_binary_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *binary_syncobj = NULL;
+	struct dma_fence *fence;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	binary_syncobj = drm_syncobj_find(file_private, args->binary_handle);
+	if (!binary_syncobj)
+		return -ENOENT;
+	ret = drm_syncobj_find_fence(file_private, args->timeline_handle,
+				     args->point, args->flags, &fence);
+	if (ret)
+		goto err;
+	drm_syncobj_replace_fence(binary_syncobj, fence);
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(binary_syncobj);
+
+	return ret;
+}
+
   static void syncobj_wait_fence_func(struct dma_fence *fence,
   				    struct dma_fence_cb *cb)
   {
include/uapi/drm/drm.h +8 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
   	__u32 pad;
   };
 
+struct drm_syncobj_transfer {
+	__u32 binary_handle;
+	__u32 timeline_handle;
+	__u64 point;
+	__u32 flags;
+	__u32 pad;
+};
+
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
@@ -933,6 +941,8 @@ extern "C" {
 
Quoted 8 lines
Quoted 7 lines

include/uapi/drm/drm.h extern "C" { · line 948

Quoted 7 lines
include/uapi/drm/drm.h +2 -0
   #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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE	DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY	DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
   /**
    * Device specific ioctls should only be in their respective headers

_______________________________________________
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): 83890a08-769a-b52a-f2f6-9fe425f2562c-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org

#42 lore raw

Re: [PATCH 09/11] drm/syncobj: add transition iotcls between binary and timeline

Am 18.02.19 um 13:07 schrieb Lionel Landwerlin:
Thanks guys :)

You mentioned that signaling out of order is illegal.
Is this illegal with regard to the vulkan spec or to the syncobj implementation?

David is the expert on that, but as far as I know that is forbidden by the vulkan spec.

I'm not finding anything in the vulkan spec that makes out of order signaling illegal.
That's why I came up with this test, just verifying that the timeline does not go backward in term of its payload.

Well we need to handle this case gracefully in the kernel, so it is still a good testcase.

Christian.

-Lionel

On 18/02/2019 11:01, Koenig, Christian wrote:
Hi David,

well I think Lionel is testing the invalid signal order on purpose :)

Anyway we really need to handle invalid order graceful here. E.g. either the same way as during CS or we abort and return an error message.

I think just using the same approach as during CS ist the best we can do.

Regards,
Christian

Am 18.02.2019 11:35 schrieb "Zhou, David(ChunMing)" <[email protected]><mailto:[email protected]>:

Hi Lionel,

I checked your igt test case,

uint64_t points[5] = { 1, 5, 3, 7, 6 };

which is illegal signal order.

I must admit we should handle it gracefully if signal isn't in-order, and we shouldn't lead to deadlock.

Hi Christian,

Can we just ignore when signal point X <= timeline Y? Or just give a warning?

Otherwise like Lionel's unexpected use cases, which easily leads to deadlock.

-David

On 2019年02月15日 22:28, Lionel Landwerlin wrote:

Hi David,

Thanks a lot for point me to the tests you've added in IGT. While adding a test with that signals fences imported into a timeline syncobj out of order, I ran into a deadlock.
Here is the test :
https://github.com/djdeath/intel-gpu-tools/commit/1e46cf7e7bff09b78a24367ddc2314f97eb0a1b9

Trying to kill the deadlocked process I got this backtrace :

[   33.969136] [IGT] syncobj_timeline: starting subtest signal-order
[   60.452823] watchdog: BUG: soft lockup - CPU#6 stuck for 23s!
[syncobj_timelin:2021]
[   60.452826] Modules linked in: rfcomm cmac bnep binfmt_misc

nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio sch_fq_codel ib_iser snd_hda_intel rdma_cm iw_cm snd_hda_codec ib_cm snd_hda_core snd_hwdep intel_rapl snd_pcm ib_core x86_pkg_temp_thermal intel_powerclamp configf s coretemp iscsi_tcp snd_seq_midi libiscsi_tcp snd_seq_midi_event libiscsi kvm_intel scsi_transport_iscsi kvm btusb snd_rawmidi irqbypass btrtl intel_cstate intel_rapl_perf btbcm btintel bluetooth snd_seq snd_seq_device snd_timer input_leds ecdh_generic snd soundcore mei_me mei intel_pch_thermal mac_hid acpi_pad parp
ort_pc ppdev lp parport ip_tables x_tables autofs4 btrfs zstd_decompress zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid i915 crct10dif_pclmul crc32_pclmul i2c_algo_bit ghash_clmulni_intel prime_numbers
drm_kms_helper aesni_intel syscopyarea sysfillrect

[   60.452876]  sysimgblt fb_sys_fops aes_x86_64 crypto_simd sdhci_pci
cryptd drm e1000e glue_helper cqhci sdhci wmi video
[   60.452881] CPU: 6 PID: 2021 Comm: syncobj_timelin Tainted: G
U            5.0.0-rc5+ #337
[   60.452882] Hardware name:  /NUC6i7KYB, BIOS
KYSKLi70.86A.0042.2016.0929.1933 09/29/2016
[   60.452886] RIP: 0010:dma_fence_chain_walk+0x22c/0x260
[   60.452888] Code: ff e9 93 fe ff ff 48 8b 45 08 48 8b 40 18 48 85 c0
74 0c 48 89 ef e8 33 0f 58 00 84 c0 75 23 f0 41 ff 4d 00 0f 88 99 87 2f
00 <0f> 85 05 fe ff ff 4c 89 ef e8 56 ea ff ff 48 89 d8 5b 5d 41 5c 41
[   60.452888] RSP: 0018:ffff9a5804653ca8 EFLAGS: 00010296 ORIG_RAX:
ffffffffffffff13
[   60.452889] RAX: 0000000000000000 RBX: ffff8f5690fb2480 RCX:
ffff8f5690fb2f00
[   60.452890] RDX: 00000000003e3730 RSI: 0000000000000000 RDI:
ffff8f5690fb2180
[   60.452891] RBP: ffff8f5690fb2180 R08: 0000000000000000 R09:
ffff8f5690fb2eb0
[   60.452891] R10: 0000000000000000 R11: ffff8f5660469860 R12:
ffff8f5690fb2f68
[   60.452892] R13: ffff8f5690fb2f00 R14: 0000000000000003 R15:
ffff8f5655a45fc0
[   60.452913] FS:  00007fdc5c459980(0000) GS:ffff8f569eb80000(0000)
knlGS:0000000000000000
[   60.452913] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   60.452914] CR2: 00007f9d74336dd8 CR3: 000000084a67e004 CR4:
00000000003606e0
[   60.452915] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[   60.452915] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[   60.452916] Call Trace:
[   60.452958]  drm_syncobj_add_point+0x102/0x160 [drm]
[   60.452965]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm]
[   60.452971]  drm_syncobj_transfer_ioctl+0x10f/0x180 [drm]
[   60.452978]  drm_ioctl_kernel+0xac/0xf0 [drm]
[   60.452984]  drm_ioctl+0x2eb/0x3b0 [drm]
[   60.452990]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm]
[   60.452992]  ? sw_sync_ioctl+0x347/0x370
[   60.452994]  do_vfs_ioctl+0xa4/0x640
[   60.452995]  ? __fput+0x134/0x220
[   60.452997]  ? do_fcntl+0x1a5/0x650
[   60.452998]  ksys_ioctl+0x70/0x80
[   60.452999]  __x64_sys_ioctl+0x16/0x20
[   60.453002]  do_syscall_64+0x55/0x110
[   60.453004]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   60.453005] RIP: 0033:0x7fdc5b6e45d7
[   60.453006] 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
[   60.453007] RSP: 002b:00007fff25c4d198 EFLAGS: 00000206 ORIG_RAX:
0000000000000010
[   60.453008] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
00007fdc5b6e45d7
[   60.453008] RDX: 00007fff25c4d200 RSI: 00000000c02064cc RDI:
0000000000000003
[   60.453009] RBP: 00007fff25c4d1d0 R08: 0000000000000000 R09:
000000000000001e
[   60.453010] R10: 0000000000000000 R11: 0000000000000206 R12:
0000563d3959e4d0
[   60.453010] R13: 00007fff25c4d620 R14: 0000000000000000 R15:
0000000000000000
[   88.447359] watchdog: BUG: soft lockup - CPU#6 stuck for 22s!

[syncobj_timelin:2021]

-Lionel

On 07/12/2018 09:55, Chunming Zhou wrote:

we need to import/export timeline point

---
  drivers/gpu/drm/drm_internal.h |  4 +++
  drivers/gpu/drm/drm_ioctl.c    |  6 ++++
  drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
  include/uapi/drm/drm.h         | 10 ++++++
  4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+                                        struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+                     drm_syncobj_binary_to_timeline_ioctl,
+                     DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+                     drm_syncobj_timeline_to_binary_ioctl,
+                     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 +66 -0

72 lines not on this page · raw message

include/uapi/drm/drm.h +10 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
        __u32 pad;
  };
 
+struct drm_syncobj_transfer {
+       __u32 binary_handle;
+       __u32 timeline_handle;
+       __u64 point;
+       __u32 flags;
+       __u32 pad;
+};
+
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
@@ -933,6 +941,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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE   DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY   DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
  /**
   * Device specific ioctls should only be in their respective headers

_______________________________________________
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): 64c548d0-b062-f937-30a5-5a4d3f296f91-5C7GfCeVMHo@public.gmane.org

#44 lore raw

Re: [PATCH 09/11] drm/syncobj: add transition iotcls between binary and timeline

Hi Lionel,

the attached should fix your problem and also messed signal order.

Hi Christian,

Could you have a look if it's reasonable?

btw: I pushed to change to https://github.com/amingriyue/timeline-syncobj-kernel, which is already rebased to latest drm-misc(kernel 5.0). You can directly use that branch.

-David

Quoted 299 lines · Christian

Am 18.02.19 um 13:07 schrieb Lionel Landwerlin:

Quoted 4 lines

Thanks guys :)

You mentioned that signaling out of order is illegal.
Is this illegal with regard to the vulkan spec or to the syncobj implementation?

David is the expert on that, but as far as I know that is forbidden by the vulkan spec.

Quoted 2 lines

I'm not finding anything in the vulkan spec that makes out of order signaling illegal.
That's why I came up with this test, just verifying that the timeline does not go backward in term of its payload.

Well we need to handle this case gracefully in the kernel, so it is still a good testcase.

Christian.

Quoted 284 lines

-Lionel

Quoted 280 lines · Christian

Hi David,

well I think Lionel is testing the invalid signal order on purpose :)

Anyway we really need to handle invalid order graceful here. E.g. either the same way as during CS or we abort and return an error message.

I think just using the same approach as during CS ist the best we can do.

Regards,
Christian

Am 18.02.2019 11:35 schrieb "Zhou, David(ChunMing)" <[email protected]>:

Hi Lionel,

I checked your igt test case,

uint64_t points[5] = { 1, 5, 3, 7, 6 };

which is illegal signal order.

I must admit we should handle it gracefully if signal isn't in-order, and we shouldn't lead to deadlock.

Hi Christian,

Can we just ignore when signal point X <= timeline Y? Or just give a warning?

Otherwise like Lionel's unexpected use cases, which easily leads to deadlock.

-David

Quoted 245 lines · Lionel Landwerlin

Hi David,

Thanks a lot for point me to the tests you've added in IGT. While adding a test with that signals fences imported into a timeline syncobj out of order, I ran into a deadlock.
Here is the test :
https://github.com/djdeath/intel-gpu-tools/commit/1e46cf7e7bff09b78a24367ddc2314f97eb0a1b9

Trying to kill the deadlocked process I got this backtrace :

[   33.969136] [IGT] syncobj_timeline: starting subtest signal-order [   60.452823] watchdog: BUG: soft lockup - CPU#6 stuck for 23s! [syncobj_timelin:2021]
[   60.452826] Modules linked in: rfcomm cmac bnep binfmt_misc nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio sch_fq_codel ib_iser snd_hda_intel rdma_cm iw_cm snd_hda_codec ib_cm snd_hda_core snd_hwdep intel_rapl snd_pcm ib_core x86_pkg_temp_thermal intel_powerclamp configf s coretemp iscsi_tcp snd_seq_midi libiscsi_tcp snd_seq_midi_event libiscsi kvm_intel scsi_transport_iscsi kvm btusb snd_rawmidi irqbypass btrtl intel_cstate intel_rapl_perf btbcm btintel bluetooth snd_seq snd_seq_device snd_timer input_leds ecdh_generic snd soundcore mei_me mei intel_pch_thermal mac_hid acpi_pad parp
ort_pc ppdev lp parport ip_tables x_tables autofs4 btrfs zstd_decompress zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid i915 crct10dif_pclmul crc32_pclmul i2c_algo_bit ghash_clmulni_intel prime_numbers
drm_kms_helper aesni_intel syscopyarea sysfillrect
[   60.452876]  sysimgblt fb_sys_fops aes_x86_64 crypto_simd sdhci_pci cryptd drm e1000e glue_helper cqhci sdhci wmi video
[   60.452881] CPU: 6 PID: 2021 Comm: syncobj_timelin Tainted: G U            5.0.0-rc5+ #337
[   60.452882] Hardware name:  /NUC6i7KYB, BIOS KYSKLi70.86A.0042.2016.0929.1933 09/29/2016
[   60.452886] RIP: 0010:dma_fence_chain_walk+0x22c/0x260
[   60.452888] Code: ff e9 93 fe ff ff 48 8b 45 08 48 8b 40 18 48 85 c0 74 0c 48 89 ef e8 33 0f 58 00 84 c0 75 23 f0 41 ff 4d 00 0f 88 99 87 2f 00 <0f> 85 05 fe ff ff 4c 89 ef e8 56 ea ff ff 48 89 d8 5b 5d 41 5c 41 [   60.452888] RSP: 0018:ffff9a5804653ca8 EFLAGS: 00010296 ORIG_RAX:
ffffffffffffff13
[   60.452889] RAX: 0000000000000000 RBX: ffff8f5690fb2480 RCX:
ffff8f5690fb2f00
[   60.452890] RDX: 00000000003e3730 RSI: 0000000000000000 RDI:
ffff8f5690fb2180
[   60.452891] RBP: ffff8f5690fb2180 R08: 0000000000000000 R09:
ffff8f5690fb2eb0
[   60.452891] R10: 0000000000000000 R11: ffff8f5660469860 R12:
ffff8f5690fb2f68
[   60.452892] R13: ffff8f5690fb2f00 R14: 0000000000000003 R15:
ffff8f5655a45fc0
[   60.452913] FS:  00007fdc5c459980(0000) GS:ffff8f569eb80000(0000) knlGS:0000000000000000
[   60.452913] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [   60.452914] CR2: 00007f9d74336dd8 CR3: 000000084a67e004 CR4:
00000000003606e0
[   60.452915] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[   60.452915] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[   60.452916] Call Trace:
[   60.452958]  drm_syncobj_add_point+0x102/0x160 [drm]
[   60.452965]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm] [   60.452971]  drm_syncobj_transfer_ioctl+0x10f/0x180 [drm] [   60.452978]  drm_ioctl_kernel+0xac/0xf0 [drm]
[   60.452984]  drm_ioctl+0x2eb/0x3b0 [drm]
[   60.452990]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm] [   60.452992]  ? sw_sync_ioctl+0x347/0x370
[   60.452994]  do_vfs_ioctl+0xa4/0x640
[   60.452995]  ? __fput+0x134/0x220
[   60.452997]  ? do_fcntl+0x1a5/0x650
[   60.452998]  ksys_ioctl+0x70/0x80
[   60.452999]  __x64_sys_ioctl+0x16/0x20
[   60.453002]  do_syscall_64+0x55/0x110
[   60.453004]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   60.453005] RIP: 0033:0x7fdc5b6e45d7
[   60.453006] 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 [   60.453007] RSP: 002b:00007fff25c4d198 EFLAGS: 00000206 ORIG_RAX:
0000000000000010
[   60.453008] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
00007fdc5b6e45d7
[   60.453008] RDX: 00007fff25c4d200 RSI: 00000000c02064cc RDI:
0000000000000003
[   60.453009] RBP: 00007fff25c4d1d0 R08: 0000000000000000 R09:
000000000000001e
[   60.453010] R10: 0000000000000000 R11: 0000000000000206 R12:
0000563d3959e4d0
[   60.453010] R13: 00007fff25c4d620 R14: 0000000000000000 R15:
0000000000000000
[   88.447359] watchdog: BUG: soft lockup - CPU#6 stuck for 22s! [syncobj_timelin:2021]

-Lionel

Quoted 145 lines · Chunming Zhou

we need to import/export timeline point

---
   drivers/gpu/drm/drm_internal.h |  4 +++
   drivers/gpu/drm/drm_ioctl.c    |  6 ++++
   drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
   include/uapi/drm/drm.h         | 10 ++++++
   4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+					 struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+		      drm_syncobj_binary_to_timeline_ioctl,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+		      drm_syncobj_timeline_to_binary_ioctl,
+		      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 +66 -0
index 282982e58dbd..cf4daa670252 100644
@@ -670,6 +670,72 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
   					&args->handle);
   }
 
+int
+drm_syncobj_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *timeline_syncobj = NULL;
+	struct dma_fence *fence;
+	struct dma_fence_chain *chain;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	timeline_syncobj = drm_syncobj_find(file_private, args->timeline_handle);
+	if (!timeline_syncobj) {
+		return -ENOENT;
+	}
+	ret = drm_syncobj_find_fence(file_private, args->binary_handle, 0, 0,
+				     &fence);
+	if (ret)
+		goto err;
+	chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL);
+	if (!chain)
+		goto err1;
+	drm_syncobj_add_point(timeline_syncobj, chain, fence, args->point);
+err1:
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(timeline_syncobj);
+
+	return ret;
+}
+
+int
+drm_syncobj_timeline_to_binary_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *binary_syncobj = NULL;
+	struct dma_fence *fence;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	binary_syncobj = drm_syncobj_find(file_private, args->binary_handle);
+	if (!binary_syncobj)
+		return -ENOENT;
+	ret = drm_syncobj_find_fence(file_private, args->timeline_handle,
+				     args->point, args->flags, &fence);
+	if (ret)
+		goto err;
+	drm_syncobj_replace_fence(binary_syncobj, fence);
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(binary_syncobj);
+
+	return ret;
+}
+
   static void syncobj_wait_fence_func(struct dma_fence *fence,
   				    struct dma_fence_cb *cb)
   {
include/uapi/drm/drm.h +10 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
   	__u32 pad;
   };
 
+struct drm_syncobj_transfer {
+	__u32 binary_handle;
+	__u32 timeline_handle;
+	__u64 point;
+	__u32 flags;
+	__u32 pad;
+};
+
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
@@ -933,6 +941,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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE	DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY	DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
Quoted 7 lines
Quoted 4 lines
Quoted 3 lines
Quoted 2 lines

include/uapi/drm/drm.h extern "C" { · line 948

Quoted 2 lines
include/uapi/drm/drm.h +0 -0
   /**
    * Device specific ioctls should only be in their respective headers

From 303419427d645e872fd7082c1b094d6eb1d487fc Mon Sep 17 00:00:00 2001

From: Chunming Zhou <[email protected]>
Date: Tue, 19 Feb 2019 17:29:31 +0800
Subject: [PATCH 1/2] fence-chian: fix iterate chain node

---
 include/linux/dma-fence-chain.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/dma-fence-chain.h +1 -1
index a5c2e8c6915c..09b038d3f5ef 100644
@@ -69,7 +69,7 @@ to_dma_fence_chain(struct dma_fence *fence)
  */
 #define dma_fence_chain_for_each(iter, head)	\
 	for (iter = dma_fence_get(head); iter; \
-	     iter = dma_fence_chain_walk(head))
+	     iter = dma_fence_chain_walk(iter))
 
 struct dma_fence *dma_fence_chain_walk(struct dma_fence *fence);
 int dma_fence_chain_find_seqno(struct dma_fence **pfence, uint64_t seqno);
Signature · 1 line
2.17.1
Quoted 1 line

From d2dbe497d51304bcdf3b1883ba6ed199c5147e2c Mon Sep 17 00:00:00 2001

From: Chunming Zhou <[email protected]>
Date: Tue, 19 Feb 2019 17:30:53 +0800
Subject: [PATCH 2/2] syncobj: don't allow messed order signal point for
timeline

---
 drivers/gpu/drm/drm_syncobj.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
drivers/gpu/drm/drm_syncobj.c +13 -0
index 961f6d343564..7da20c287c41 100644
@@ -145,12 +145,25 @@ void drm_syncobj_add_point(struct drm_syncobj *syncobj,
 {
 	struct syncobj_wait_entry *cur, *tmp;
 	struct dma_fence *prev;
+	struct dma_fence_chain *last_node;
+	uint64_t last_point;
 
 	dma_fence_get(fence);
 
 	spin_lock(&syncobj->lock);
 
 	prev = drm_syncobj_fence_get(syncobj);
+	last_node = to_dma_fence_chain(prev);
+	last_point = last_node ? prev->seqno : 0;
+	if (point <= last_point) {
+		/* timeline doesn't allow messed order signal points. */
+		DRM_ERROR("signal point %llu <= last point %llu!\n",
+			  point, last_point);
+		kfree(chain);
+		spin_unlock(&syncobj->lock);
+		dma_fence_put(prev);
+		return;
+	}
 	dma_fence_chain_init(chain, prev, fence, point);
 	rcu_assign_pointer(syncobj->fence, &chain->base);
 
Signature · 1 line
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): c2c12849-d26b-3212-40ca-682d6f8006fa-5C7GfCeVMHo@public.gmane.org

#46 lore raw

Re: [PATCH 09/11] drm/syncobj: add transition iotcls between binary and timeline

Thanks David,

Will give this a go!

-Lionel

Quoted 10 lines · On 19/02/2019 10:46, zhoucm1 wrote:

Hi Lionel,

the attached should fix your problem and also messed signal order.

Hi Christian,

Could you have a look if it's reasonable?

Quoted 312 lines

btw: I pushed to change to https://github.com/amingriyue/timeline-syncobj-kernel, which is already rebased to latest drm-misc(kernel 5.0). You can directly use that branch.

-David

Quoted 304 lines · Christian

Am 18.02.19 um 13:07 schrieb Lionel Landwerlin:

Quoted 4 lines

Thanks guys :)

You mentioned that signaling out of order is illegal.
Is this illegal with regard to the vulkan spec or to the syncobj implementation?

David is the expert on that, but as far as I know that is forbidden by the vulkan spec.

Quoted 2 lines

I'm not finding anything in the vulkan spec that makes out of order signaling illegal.
That's why I came up with this test, just verifying that the timeline does not go backward in term of its payload.

Well we need to handle this case gracefully in the kernel, so it is still a good testcase.

Christian.

Quoted 288 lines

-Lionel

Quoted 283 lines · Christian

Hi David,

well I think Lionel is testing the invalid signal order on purpose :)

Anyway we really need to handle invalid order graceful here. E.g. either the same way as during CS or we abort and return an error message.

I think just using the same approach as during CS ist the best we can do.

Regards,
Christian

Am 18.02.2019 11:35 schrieb "Zhou, David(ChunMing)" <[email protected]>:

Hi Lionel,

I checked your igt test case,

uint64_t points[5] = { 1, 5, 3, 7, 6 };

which is illegal signal order.

I must admit we should handle it gracefully if signal isn't in-order, and we shouldn't lead to deadlock.

Hi Christian,

Can we just ignore when signal point X <= timeline Y? Or just give a warning?

Otherwise like Lionel's unexpected use cases, which easily leads to deadlock.

-David

Quoted 247 lines · Lionel Landwerlin

Hi David,

Thanks a lot for point me to the tests you've added in IGT. While adding a test with that signals fences imported into a timeline syncobj out of order, I ran into a deadlock.
Here is the test :
https://github.com/djdeath/intel-gpu-tools/commit/1e46cf7e7bff09b78a24367ddc2314f97eb0a1b9

Trying to kill the deadlocked process I got this backtrace :

[   33.969136] [IGT] syncobj_timeline: starting subtest signal-order [   60.452823] watchdog: BUG: soft lockup - CPU#6 stuck for 23s! [syncobj_timelin:2021]
[   60.452826] Modules linked in: rfcomm cmac bnep binfmt_misc nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio sch_fq_codel ib_iser snd_hda_intel rdma_cm iw_cm snd_hda_codec ib_cm snd_hda_core snd_hwdep intel_rapl snd_pcm ib_core x86_pkg_temp_thermal intel_powerclamp configf s coretemp iscsi_tcp snd_seq_midi libiscsi_tcp snd_seq_midi_event libiscsi kvm_intel scsi_transport_iscsi kvm btusb snd_rawmidi irqbypass btrtl intel_cstate intel_rapl_perf btbcm btintel bluetooth snd_seq snd_seq_device snd_timer input_leds ecdh_generic snd soundcore mei_me mei intel_pch_thermal mac_hid acpi_pad parp
ort_pc ppdev lp parport ip_tables x_tables autofs4 btrfs zstd_decompress zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid i915 crct10dif_pclmul crc32_pclmul i2c_algo_bit ghash_clmulni_intel prime_numbers
drm_kms_helper aesni_intel syscopyarea sysfillrect
[   60.452876]  sysimgblt fb_sys_fops aes_x86_64 crypto_simd sdhci_pci cryptd drm e1000e glue_helper cqhci sdhci wmi video
[   60.452881] CPU: 6 PID: 2021 Comm: syncobj_timelin Tainted: G U            5.0.0-rc5+ #337
[   60.452882] Hardware name:  /NUC6i7KYB, BIOS KYSKLi70.86A.0042.2016.0929.1933 09/29/2016
[   60.452886] RIP: 0010:dma_fence_chain_walk+0x22c/0x260
[   60.452888] Code: ff e9 93 fe ff ff 48 8b 45 08 48 8b 40 18 48 85 c0 74 0c 48 89 ef e8 33 0f 58 00 84 c0 75 23 f0 41 ff 4d 00 0f 88 99 87 2f 00 <0f> 85 05 fe ff ff 4c 89 ef e8 56 ea ff ff 48 89 d8 5b 5d 41 5c 41 [   60.452888] RSP: 0018:ffff9a5804653ca8 EFLAGS: 00010296 ORIG_RAX:
ffffffffffffff13
[   60.452889] RAX: 0000000000000000 RBX: ffff8f5690fb2480 RCX:
ffff8f5690fb2f00
[   60.452890] RDX: 00000000003e3730 RSI: 0000000000000000 RDI:
ffff8f5690fb2180
[   60.452891] RBP: ffff8f5690fb2180 R08: 0000000000000000 R09:
ffff8f5690fb2eb0
[   60.452891] R10: 0000000000000000 R11: ffff8f5660469860 R12:
ffff8f5690fb2f68
[   60.452892] R13: ffff8f5690fb2f00 R14: 0000000000000003 R15:
ffff8f5655a45fc0
[   60.452913] FS:  00007fdc5c459980(0000) GS:ffff8f569eb80000(0000) knlGS:0000000000000000
[   60.452913] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [   60.452914] CR2: 00007f9d74336dd8 CR3: 000000084a67e004 CR4:
00000000003606e0
[   60.452915] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[   60.452915] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[   60.452916] Call Trace:
[   60.452958]  drm_syncobj_add_point+0x102/0x160 [drm]
[   60.452965]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm] [   60.452971]  drm_syncobj_transfer_ioctl+0x10f/0x180 [drm] [   60.452978]  drm_ioctl_kernel+0xac/0xf0 [drm]
[   60.452984]  drm_ioctl+0x2eb/0x3b0 [drm]
[   60.452990]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm] [   60.452992]  ? sw_sync_ioctl+0x347/0x370
[   60.452994]  do_vfs_ioctl+0xa4/0x640
[   60.452995]  ? __fput+0x134/0x220
[   60.452997]  ? do_fcntl+0x1a5/0x650
[   60.452998]  ksys_ioctl+0x70/0x80
[   60.452999]  __x64_sys_ioctl+0x16/0x20
[   60.453002]  do_syscall_64+0x55/0x110
[   60.453004]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   60.453005] RIP: 0033:0x7fdc5b6e45d7
[   60.453006] 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 [   60.453007] RSP: 002b:00007fff25c4d198 EFLAGS: 00000206 ORIG_RAX:
0000000000000010
[   60.453008] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
00007fdc5b6e45d7
[   60.453008] RDX: 00007fff25c4d200 RSI: 00000000c02064cc RDI:
0000000000000003
[   60.453009] RBP: 00007fff25c4d1d0 R08: 0000000000000000 R09:
000000000000001e
[   60.453010] R10: 0000000000000000 R11: 0000000000000206 R12:
0000563d3959e4d0
[   60.453010] R13: 00007fff25c4d620 R14: 0000000000000000 R15:
0000000000000000
[   88.447359] watchdog: BUG: soft lockup - CPU#6 stuck for 22s! [syncobj_timelin:2021]

-Lionel

Quoted 147 lines · Chunming Zhou

we need to import/export timeline point

---
   drivers/gpu/drm/drm_internal.h |  4 +++
   drivers/gpu/drm/drm_ioctl.c    |  6 ++++
   drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
   include/uapi/drm/drm.h         | 10 ++++++
   4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+					 struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+		      drm_syncobj_binary_to_timeline_ioctl,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+		      drm_syncobj_timeline_to_binary_ioctl,
+		      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 +66 -0
index 282982e58dbd..cf4daa670252 100644
@@ -670,6 +670,72 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
   					&args->handle);
   }
 
+int
+drm_syncobj_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *timeline_syncobj = NULL;
+	struct dma_fence *fence;
+	struct dma_fence_chain *chain;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	timeline_syncobj = drm_syncobj_find(file_private, args->timeline_handle);
+	if (!timeline_syncobj) {
+		return -ENOENT;
+	}
+	ret = drm_syncobj_find_fence(file_private, args->binary_handle, 0, 0,
+				     &fence);
+	if (ret)
+		goto err;
+	chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL);
+	if (!chain)
+		goto err1;
+	drm_syncobj_add_point(timeline_syncobj, chain, fence, args->point);
+err1:
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(timeline_syncobj);
+
+	return ret;
+}
+
+int
+drm_syncobj_timeline_to_binary_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *binary_syncobj = NULL;
+	struct dma_fence *fence;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	binary_syncobj = drm_syncobj_find(file_private, args->binary_handle);
+	if (!binary_syncobj)
+		return -ENOENT;
+	ret = drm_syncobj_find_fence(file_private, args->timeline_handle,
+				     args->point, args->flags, &fence);
+	if (ret)
+		goto err;
+	drm_syncobj_replace_fence(binary_syncobj, fence);
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(binary_syncobj);
+
+	return ret;
+}
+
   static void syncobj_wait_fence_func(struct dma_fence *fence,
   				    struct dma_fence_cb *cb)
   {
include/uapi/drm/drm.h +10 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
   	__u32 pad;
   };
 
+struct drm_syncobj_transfer {
+	__u32 binary_handle;
+	__u32 timeline_handle;
+	__u64 point;
+	__u32 flags;
+	__u32 pad;
+};
+
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
@@ -933,6 +941,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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE	DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY	DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
   /**
    * Device specific ioctls should only be in their respective headers

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

#47 lore raw

Re: [PATCH 09/11] drm/syncobj: add transition iotcls between binary and timeline

In reply to a message not in the archive

Hi David,

Could you have a look if it's reasonable?

Patch #1 is also something I already fixed on my local branch.

But patch #2 won't work like this.

We can't return an error from drm_syncobj_add_point() because we already submitted work to the hardware. And just dropping the fence like you do in the patch is a clearly no-go as well.

Regards,
Christian.

Am 19.02.19 um 11:46 schrieb zhoucm1:

Hi Lionel,

the attached should fix your problem and also messed signal order.

Hi Christian,

Could you have a look if it's reasonable?

btw: I pushed to change to https://github.com/amingriyue/timeline-syncobj-kernel, which is already rebased to latest drm-misc(kernel 5.0). You can directly use that branch.

-David

On 2019年02月19日 01:01, Koenig, Christian wrote:
Am 18.02.19 um 13:07 schrieb Lionel Landwerlin:
Thanks guys :)

You mentioned that signaling out of order is illegal.
Is this illegal with regard to the vulkan spec or to the syncobj implementation?

David is the expert on that, but as far as I know that is forbidden by the vulkan spec.

I'm not finding anything in the vulkan spec that makes out of order signaling illegal.
That's why I came up with this test, just verifying that the timeline does not go backward in term of its payload.

Well we need to handle this case gracefully in the kernel, so it is still a good testcase.

Christian.

-Lionel

On 18/02/2019 11:01, Koenig, Christian wrote:
Hi David,

well I think Lionel is testing the invalid signal order on purpose :)

Anyway we really need to handle invalid order graceful here. E.g. either the same way as during CS or we abort and return an error message.

I think just using the same approach as during CS ist the best we can do.

Regards,
Christian

Am 18.02.2019 11:35 schrieb "Zhou, David(ChunMing)" <[email protected]><mailto:[email protected]>:

Hi Lionel,

I checked your igt test case,

uint64_t points[5] = { 1, 5, 3, 7, 6 };

which is illegal signal order.

I must admit we should handle it gracefully if signal isn't in-order, and we shouldn't lead to deadlock.

Hi Christian,

Can we just ignore when signal point X <= timeline Y? Or just give a warning?

Otherwise like Lionel's unexpected use cases, which easily leads to deadlock.

-David

On 2019年02月15日 22:28, Lionel Landwerlin wrote:

Hi David,

Thanks a lot for point me to the tests you've added in IGT. While adding a test with that signals fences imported into a timeline syncobj out of order, I ran into a deadlock.
Here is the test :
https://github.com/djdeath/intel-gpu-tools/commit/1e46cf7e7bff09b78a24367ddc2314f97eb0a1b9

Trying to kill the deadlocked process I got this backtrace :

[   33.969136] [IGT] syncobj_timeline: starting subtest signal-order
[   60.452823] watchdog: BUG: soft lockup - CPU#6 stuck for 23s!
[syncobj_timelin:2021]
[   60.452826] Modules linked in: rfcomm cmac bnep binfmt_misc

nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio sch_fq_codel ib_iser snd_hda_intel rdma_cm iw_cm snd_hda_codec ib_cm snd_hda_core snd_hwdep intel_rapl snd_pcm ib_core x86_pkg_temp_thermal intel_powerclamp configf s coretemp iscsi_tcp snd_seq_midi libiscsi_tcp snd_seq_midi_event libiscsi kvm_intel scsi_transport_iscsi kvm btusb snd_rawmidi irqbypass btrtl intel_cstate intel_rapl_perf btbcm btintel bluetooth snd_seq snd_seq_device snd_timer input_leds ecdh_generic snd soundcore mei_me mei intel_pch_thermal mac_hid acpi_pad parp
ort_pc ppdev lp parport ip_tables x_tables autofs4 btrfs zstd_decompress zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid i915 crct10dif_pclmul crc32_pclmul i2c_algo_bit ghash_clmulni_intel prime_numbers
drm_kms_helper aesni_intel syscopyarea sysfillrect

[   60.452876]  sysimgblt fb_sys_fops aes_x86_64 crypto_simd sdhci_pci
cryptd drm e1000e glue_helper cqhci sdhci wmi video
[   60.452881] CPU: 6 PID: 2021 Comm: syncobj_timelin Tainted: G
U            5.0.0-rc5+ #337
[   60.452882] Hardware name:  /NUC6i7KYB, BIOS
KYSKLi70.86A.0042.2016.0929.1933 09/29/2016
[   60.452886] RIP: 0010:dma_fence_chain_walk+0x22c/0x260
[   60.452888] Code: ff e9 93 fe ff ff 48 8b 45 08 48 8b 40 18 48 85 c0
74 0c 48 89 ef e8 33 0f 58 00 84 c0 75 23 f0 41 ff 4d 00 0f 88 99 87 2f
00 <0f> 85 05 fe ff ff 4c 89 ef e8 56 ea ff ff 48 89 d8 5b 5d 41 5c 41
[   60.452888] RSP: 0018:ffff9a5804653ca8 EFLAGS: 00010296 ORIG_RAX:
ffffffffffffff13
[   60.452889] RAX: 0000000000000000 RBX: ffff8f5690fb2480 RCX:
ffff8f5690fb2f00
[   60.452890] RDX: 00000000003e3730 RSI: 0000000000000000 RDI:
ffff8f5690fb2180
[   60.452891] RBP: ffff8f5690fb2180 R08: 0000000000000000 R09:
ffff8f5690fb2eb0
[   60.452891] R10: 0000000000000000 R11: ffff8f5660469860 R12:
ffff8f5690fb2f68
[   60.452892] R13: ffff8f5690fb2f00 R14: 0000000000000003 R15:
ffff8f5655a45fc0
[   60.452913] FS:  00007fdc5c459980(0000) GS:ffff8f569eb80000(0000)
knlGS:0000000000000000
[   60.452913] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   60.452914] CR2: 00007f9d74336dd8 CR3: 000000084a67e004 CR4:
00000000003606e0
[   60.452915] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[   60.452915] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[   60.452916] Call Trace:
[   60.452958]  drm_syncobj_add_point+0x102/0x160 [drm]
[   60.452965]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm]
[   60.452971]  drm_syncobj_transfer_ioctl+0x10f/0x180 [drm]
[   60.452978]  drm_ioctl_kernel+0xac/0xf0 [drm]
[   60.452984]  drm_ioctl+0x2eb/0x3b0 [drm]
[   60.452990]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm]
[   60.452992]  ? sw_sync_ioctl+0x347/0x370
[   60.452994]  do_vfs_ioctl+0xa4/0x640
[   60.452995]  ? __fput+0x134/0x220
[   60.452997]  ? do_fcntl+0x1a5/0x650
[   60.452998]  ksys_ioctl+0x70/0x80
[   60.452999]  __x64_sys_ioctl+0x16/0x20
[   60.453002]  do_syscall_64+0x55/0x110
[   60.453004]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   60.453005] RIP: 0033:0x7fdc5b6e45d7
[   60.453006] 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
[   60.453007] RSP: 002b:00007fff25c4d198 EFLAGS: 00000206 ORIG_RAX:
0000000000000010
[   60.453008] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
00007fdc5b6e45d7
[   60.453008] RDX: 00007fff25c4d200 RSI: 00000000c02064cc RDI:
0000000000000003
[   60.453009] RBP: 00007fff25c4d1d0 R08: 0000000000000000 R09:
000000000000001e
[   60.453010] R10: 0000000000000000 R11: 0000000000000206 R12:
0000563d3959e4d0
[   60.453010] R13: 00007fff25c4d620 R14: 0000000000000000 R15:
0000000000000000
[   88.447359] watchdog: BUG: soft lockup - CPU#6 stuck for 22s!

[syncobj_timelin:2021]

-Lionel

On 07/12/2018 09:55, Chunming Zhou wrote:

we need to import/export timeline point

---
  drivers/gpu/drm/drm_internal.h |  4 +++
  drivers/gpu/drm/drm_ioctl.c    |  6 ++++
  drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
  include/uapi/drm/drm.h         | 10 ++++++
  4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+                                        struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+                     drm_syncobj_binary_to_timeline_ioctl,
+                     DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+                     drm_syncobj_timeline_to_binary_ioctl,
+                     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 +66 -0

72 lines not on this page · raw message

include/uapi/drm/drm.h +10 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
        __u32 pad;
  };
 
+struct drm_syncobj_transfer {
+       __u32 binary_handle;
+       __u32 timeline_handle;
+       __u64 point;
+       __u32 flags;
+       __u32 pad;
+};
+
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
@@ -933,6 +941,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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE   DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY   DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
  /**
   * Device specific ioctls should only be in their respective headers

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

#48 lore raw

Re: [PATCH 09/11] drm/syncobj: add transition iotcls between binary and timeline

Quoted 9 lines · Christian

Hi David,

Quoted 1 line

Could you have a look if it's reasonable?

Patch #1 is also something I already fixed on my local branch.

But patch #2 won't work like this.

We can't return an error from drm_syncobj_add_point() because we already submitted work to the hardware. And just dropping the fence like you do in the patch is a clearly no-go as well.

Then do you have any idea to skip the messed order signal point?

-David

Quoted 328 lines

Regards,
Christian.

Am 19.02.19 um 11:46 schrieb zhoucm1:

Quoted 322 lines

Hi Lionel,

the attached should fix your problem and also messed signal order.

Hi Christian,

Could you have a look if it's reasonable?

btw: I pushed to change to https://github.com/amingriyue/timeline-syncobj-kernel, which is already rebased to latest drm-misc(kernel 5.0). You can directly use that branch.

-David

Quoted 304 lines · Christian

Am 18.02.19 um 13:07 schrieb Lionel Landwerlin:

Quoted 4 lines

Thanks guys :)

You mentioned that signaling out of order is illegal.
Is this illegal with regard to the vulkan spec or to the syncobj implementation?

David is the expert on that, but as far as I know that is forbidden by the vulkan spec.

Quoted 2 lines

I'm not finding anything in the vulkan spec that makes out of order signaling illegal.
That's why I came up with this test, just verifying that the timeline does not go backward in term of its payload.

Well we need to handle this case gracefully in the kernel, so it is still a good testcase.

Christian.

Quoted 288 lines

-Lionel

Quoted 283 lines · Christian

Hi David,

well I think Lionel is testing the invalid signal order on purpose :)

Anyway we really need to handle invalid order graceful here. E.g. either the same way as during CS or we abort and return an error message.

I think just using the same approach as during CS ist the best we can do.

Regards,
Christian

Am 18.02.2019 11:35 schrieb "Zhou, David(ChunMing)" <[email protected]>:

Hi Lionel,

I checked your igt test case,

uint64_t points[5] = { 1, 5, 3, 7, 6 };

which is illegal signal order.

I must admit we should handle it gracefully if signal isn't in-order, and we shouldn't lead to deadlock.

Hi Christian,

Can we just ignore when signal point X <= timeline Y? Or just give a warning?

Otherwise like Lionel's unexpected use cases, which easily leads to deadlock.

-David

Quoted 247 lines · Lionel Landwerlin

Hi David,

Thanks a lot for point me to the tests you've added in IGT. While adding a test with that signals fences imported into a timeline syncobj out of order, I ran into a deadlock.
Here is the test :
https://github.com/djdeath/intel-gpu-tools/commit/1e46cf7e7bff09b78a24367ddc2314f97eb0a1b9

Trying to kill the deadlocked process I got this backtrace :

[   33.969136] [IGT] syncobj_timeline: starting subtest signal-order [   60.452823] watchdog: BUG: soft lockup - CPU#6 stuck for 23s! [syncobj_timelin:2021]
[   60.452826] Modules linked in: rfcomm cmac bnep binfmt_misc nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio sch_fq_codel ib_iser snd_hda_intel rdma_cm iw_cm snd_hda_codec ib_cm snd_hda_core snd_hwdep intel_rapl snd_pcm ib_core x86_pkg_temp_thermal intel_powerclamp configf s coretemp iscsi_tcp snd_seq_midi libiscsi_tcp snd_seq_midi_event libiscsi kvm_intel scsi_transport_iscsi kvm btusb snd_rawmidi irqbypass btrtl intel_cstate intel_rapl_perf btbcm btintel bluetooth snd_seq snd_seq_device snd_timer input_leds ecdh_generic snd soundcore mei_me mei intel_pch_thermal mac_hid acpi_pad parp
ort_pc ppdev lp parport ip_tables x_tables autofs4 btrfs zstd_decompress zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid i915 crct10dif_pclmul crc32_pclmul i2c_algo_bit ghash_clmulni_intel prime_numbers
drm_kms_helper aesni_intel syscopyarea sysfillrect
[   60.452876]  sysimgblt fb_sys_fops aes_x86_64 crypto_simd sdhci_pci cryptd drm e1000e glue_helper cqhci sdhci wmi video
[   60.452881] CPU: 6 PID: 2021 Comm: syncobj_timelin Tainted: G U            5.0.0-rc5+ #337
[   60.452882] Hardware name:  /NUC6i7KYB, BIOS KYSKLi70.86A.0042.2016.0929.1933 09/29/2016
[   60.452886] RIP: 0010:dma_fence_chain_walk+0x22c/0x260
[   60.452888] Code: ff e9 93 fe ff ff 48 8b 45 08 48 8b 40 18 48 85 c0 74 0c 48 89 ef e8 33 0f 58 00 84 c0 75 23 f0 41 ff 4d 00 0f 88 99 87 2f 00 <0f> 85 05 fe ff ff 4c 89 ef e8 56 ea ff ff 48 89 d8 5b 5d 41 5c 41 [   60.452888] RSP: 0018:ffff9a5804653ca8 EFLAGS: 00010296 ORIG_RAX:
ffffffffffffff13
[   60.452889] RAX: 0000000000000000 RBX: ffff8f5690fb2480 RCX:
ffff8f5690fb2f00
[   60.452890] RDX: 00000000003e3730 RSI: 0000000000000000 RDI:
ffff8f5690fb2180
[   60.452891] RBP: ffff8f5690fb2180 R08: 0000000000000000 R09:
ffff8f5690fb2eb0
[   60.452891] R10: 0000000000000000 R11: ffff8f5660469860 R12:
ffff8f5690fb2f68
[   60.452892] R13: ffff8f5690fb2f00 R14: 0000000000000003 R15:
ffff8f5655a45fc0
[   60.452913] FS:  00007fdc5c459980(0000) GS:ffff8f569eb80000(0000) knlGS:0000000000000000
[   60.452913] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [   60.452914] CR2: 00007f9d74336dd8 CR3: 000000084a67e004 CR4:
00000000003606e0
[   60.452915] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[   60.452915] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[   60.452916] Call Trace:
[   60.452958]  drm_syncobj_add_point+0x102/0x160 [drm]
[   60.452965]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm] [   60.452971]  drm_syncobj_transfer_ioctl+0x10f/0x180 [drm] [   60.452978]  drm_ioctl_kernel+0xac/0xf0 [drm]
[   60.452984]  drm_ioctl+0x2eb/0x3b0 [drm]
[   60.452990]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm] [   60.452992]  ? sw_sync_ioctl+0x347/0x370
[   60.452994]  do_vfs_ioctl+0xa4/0x640
[   60.452995]  ? __fput+0x134/0x220
[   60.452997]  ? do_fcntl+0x1a5/0x650
[   60.452998]  ksys_ioctl+0x70/0x80
[   60.452999]  __x64_sys_ioctl+0x16/0x20
[   60.453002]  do_syscall_64+0x55/0x110
[   60.453004]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   60.453005] RIP: 0033:0x7fdc5b6e45d7
[   60.453006] 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 [   60.453007] RSP: 002b:00007fff25c4d198 EFLAGS: 00000206 ORIG_RAX:
0000000000000010
[   60.453008] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
00007fdc5b6e45d7
[   60.453008] RDX: 00007fff25c4d200 RSI: 00000000c02064cc RDI:
0000000000000003
[   60.453009] RBP: 00007fff25c4d1d0 R08: 0000000000000000 R09:
000000000000001e
[   60.453010] R10: 0000000000000000 R11: 0000000000000206 R12:
0000563d3959e4d0
[   60.453010] R13: 00007fff25c4d620 R14: 0000000000000000 R15:
0000000000000000
[   88.447359] watchdog: BUG: soft lockup - CPU#6 stuck for 22s! [syncobj_timelin:2021]

-Lionel

Quoted 147 lines · Chunming Zhou

we need to import/export timeline point

---
   drivers/gpu/drm/drm_internal.h |  4 +++
   drivers/gpu/drm/drm_ioctl.c    |  6 ++++
   drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
   include/uapi/drm/drm.h         | 10 ++++++
   4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+					 struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+		      drm_syncobj_binary_to_timeline_ioctl,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+		      drm_syncobj_timeline_to_binary_ioctl,
+		      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 +66 -0
index 282982e58dbd..cf4daa670252 100644
@@ -670,6 +670,72 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
   					&args->handle);
   }
 
+int
+drm_syncobj_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *timeline_syncobj = NULL;
+	struct dma_fence *fence;
+	struct dma_fence_chain *chain;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	timeline_syncobj = drm_syncobj_find(file_private, args->timeline_handle);
+	if (!timeline_syncobj) {
+		return -ENOENT;
+	}
+	ret = drm_syncobj_find_fence(file_private, args->binary_handle, 0, 0,
+				     &fence);
+	if (ret)
+		goto err;
+	chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL);
+	if (!chain)
+		goto err1;
+	drm_syncobj_add_point(timeline_syncobj, chain, fence, args->point);
+err1:
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(timeline_syncobj);
+
+	return ret;
+}
+
+int
+drm_syncobj_timeline_to_binary_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *binary_syncobj = NULL;
+	struct dma_fence *fence;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	binary_syncobj = drm_syncobj_find(file_private, args->binary_handle);
+	if (!binary_syncobj)
+		return -ENOENT;
+	ret = drm_syncobj_find_fence(file_private, args->timeline_handle,
+				     args->point, args->flags, &fence);
+	if (ret)
+		goto err;
+	drm_syncobj_replace_fence(binary_syncobj, fence);
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(binary_syncobj);
+
+	return ret;
+}
+
   static void syncobj_wait_fence_func(struct dma_fence *fence,
   				    struct dma_fence_cb *cb)
   {
include/uapi/drm/drm.h +10 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
   	__u32 pad;
   };
 
+struct drm_syncobj_transfer {
+	__u32 binary_handle;
+	__u32 timeline_handle;
+	__u64 point;
+	__u32 flags;
+	__u32 pad;
+};
+
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
@@ -933,6 +941,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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE	DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY	DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
   /**
    * Device specific ioctls should only be in their respective headers

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

#49 lore raw

Re: [PATCH 09/11] drm/syncobj: add transition iotcls between binary and timeline

Am 20.02.19 um 05:53 schrieb zhoucm1:

On 2019年02月19日 19:32, Koenig, Christian wrote:
Hi David,

Could you have a look if it's reasonable?

Patch #1 is also something I already fixed on my local branch.

But patch #2 won't work like this.

We can't return an error from drm_syncobj_add_point() because we already submitted work to the hardware. And just dropping the fence like you do in the patch is a clearly no-go as well.

Then do you have any idea to skip the messed order signal point?

No, I don't think we can actually do this.

The only solution I can see would be to lock down the syncobj to modifications while command submission is in progress. And that in turn would mean a huge bunch of ww_mutex overhead we will certainly want to avoid.

Christian.

-David

Regards,
Christian.

Am 19.02.19 um 11:46 schrieb zhoucm1:

Hi Lionel,

the attached should fix your problem and also messed signal order.

Hi Christian,

Could you have a look if it's reasonable?

btw: I pushed to change to https://github.com/amingriyue/timeline-syncobj-kernel, which is already rebased to latest drm-misc(kernel 5.0). You can directly use that branch.

-David

On 2019年02月19日 01:01, Koenig, Christian wrote:
Am 18.02.19 um 13:07 schrieb Lionel Landwerlin:
Thanks guys :)

You mentioned that signaling out of order is illegal.
Is this illegal with regard to the vulkan spec or to the syncobj implementation?

David is the expert on that, but as far as I know that is forbidden by the vulkan spec.

I'm not finding anything in the vulkan spec that makes out of order signaling illegal.
That's why I came up with this test, just verifying that the timeline does not go backward in term of its payload.

Well we need to handle this case gracefully in the kernel, so it is still a good testcase.

Christian.

-Lionel

On 18/02/2019 11:01, Koenig, Christian wrote:
Hi David,

well I think Lionel is testing the invalid signal order on purpose :)

Anyway we really need to handle invalid order graceful here. E.g. either the same way as during CS or we abort and return an error message.

I think just using the same approach as during CS ist the best we can do.

Regards,
Christian

Am 18.02.2019 11:35 schrieb "Zhou, David(ChunMing)" <[email protected]><mailto:[email protected]>:

Hi Lionel,

I checked your igt test case,

uint64_t points[5] = { 1, 5, 3, 7, 6 };

which is illegal signal order.

I must admit we should handle it gracefully if signal isn't in-order, and we shouldn't lead to deadlock.

Hi Christian,

Can we just ignore when signal point X <= timeline Y? Or just give a warning?

Otherwise like Lionel's unexpected use cases, which easily leads to deadlock.

-David

On 2019年02月15日 22:28, Lionel Landwerlin wrote:

Hi David,

Thanks a lot for point me to the tests you've added in IGT. While adding a test with that signals fences imported into a timeline syncobj out of order, I ran into a deadlock.
Here is the test :
https://github.com/djdeath/intel-gpu-tools/commit/1e46cf7e7bff09b78a24367ddc2314f97eb0a1b9

Trying to kill the deadlocked process I got this backtrace :

[   33.969136] [IGT] syncobj_timeline: starting subtest signal-order
[   60.452823] watchdog: BUG: soft lockup - CPU#6 stuck for 23s!
[syncobj_timelin:2021]
[   60.452826] Modules linked in: rfcomm cmac bnep binfmt_misc

nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio sch_fq_codel ib_iser snd_hda_intel rdma_cm iw_cm snd_hda_codec ib_cm snd_hda_core snd_hwdep intel_rapl snd_pcm ib_core x86_pkg_temp_thermal intel_powerclamp configf s coretemp iscsi_tcp snd_seq_midi libiscsi_tcp snd_seq_midi_event libiscsi kvm_intel scsi_transport_iscsi kvm btusb snd_rawmidi irqbypass btrtl intel_cstate intel_rapl_perf btbcm btintel bluetooth snd_seq snd_seq_device snd_timer input_leds ecdh_generic snd soundcore mei_me mei intel_pch_thermal mac_hid acpi_pad parp
ort_pc ppdev lp parport ip_tables x_tables autofs4 btrfs zstd_decompress zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid i915 crct10dif_pclmul crc32_pclmul i2c_algo_bit ghash_clmulni_intel prime_numbers
drm_kms_helper aesni_intel syscopyarea sysfillrect

[   60.452876]  sysimgblt fb_sys_fops aes_x86_64 crypto_simd sdhci_pci
cryptd drm e1000e glue_helper cqhci sdhci wmi video
[   60.452881] CPU: 6 PID: 2021 Comm: syncobj_timelin Tainted: G
U            5.0.0-rc5+ #337
[   60.452882] Hardware name:  /NUC6i7KYB, BIOS
KYSKLi70.86A.0042.2016.0929.1933 09/29/2016
[   60.452886] RIP: 0010:dma_fence_chain_walk+0x22c/0x260
[   60.452888] Code: ff e9 93 fe ff ff 48 8b 45 08 48 8b 40 18 48 85 c0
74 0c 48 89 ef e8 33 0f 58 00 84 c0 75 23 f0 41 ff 4d 00 0f 88 99 87 2f
00 <0f> 85 05 fe ff ff 4c 89 ef e8 56 ea ff ff 48 89 d8 5b 5d 41 5c 41
[   60.452888] RSP: 0018:ffff9a5804653ca8 EFLAGS: 00010296 ORIG_RAX:
ffffffffffffff13
[   60.452889] RAX: 0000000000000000 RBX: ffff8f5690fb2480 RCX:
ffff8f5690fb2f00
[   60.452890] RDX: 00000000003e3730 RSI: 0000000000000000 RDI:
ffff8f5690fb2180
[   60.452891] RBP: ffff8f5690fb2180 R08: 0000000000000000 R09:
ffff8f5690fb2eb0
[   60.452891] R10: 0000000000000000 R11: ffff8f5660469860 R12:
ffff8f5690fb2f68
[   60.452892] R13: ffff8f5690fb2f00 R14: 0000000000000003 R15:
ffff8f5655a45fc0
[   60.452913] FS:  00007fdc5c459980(0000) GS:ffff8f569eb80000(0000)
knlGS:0000000000000000
[   60.452913] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   60.452914] CR2: 00007f9d74336dd8 CR3: 000000084a67e004 CR4:
00000000003606e0
[   60.452915] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[   60.452915] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[   60.452916] Call Trace:
[   60.452958]  drm_syncobj_add_point+0x102/0x160 [drm]
[   60.452965]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm]
[   60.452971]  drm_syncobj_transfer_ioctl+0x10f/0x180 [drm]
[   60.452978]  drm_ioctl_kernel+0xac/0xf0 [drm]
[   60.452984]  drm_ioctl+0x2eb/0x3b0 [drm]
[   60.452990]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm]
[   60.452992]  ? sw_sync_ioctl+0x347/0x370
[   60.452994]  do_vfs_ioctl+0xa4/0x640
[   60.452995]  ? __fput+0x134/0x220
[   60.452997]  ? do_fcntl+0x1a5/0x650
[   60.452998]  ksys_ioctl+0x70/0x80
[   60.452999]  __x64_sys_ioctl+0x16/0x20
[   60.453002]  do_syscall_64+0x55/0x110
[   60.453004]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   60.453005] RIP: 0033:0x7fdc5b6e45d7
[   60.453006] 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
[   60.453007] RSP: 002b:00007fff25c4d198 EFLAGS: 00000206 ORIG_RAX:
0000000000000010
[   60.453008] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
00007fdc5b6e45d7
[   60.453008] RDX: 00007fff25c4d200 RSI: 00000000c02064cc RDI:
0000000000000003
[   60.453009] RBP: 00007fff25c4d1d0 R08: 0000000000000000 R09:
000000000000001e
[   60.453010] R10: 0000000000000000 R11: 0000000000000206 R12:
0000563d3959e4d0
[   60.453010] R13: 00007fff25c4d620 R14: 0000000000000000 R15:
0000000000000000
[   88.447359] watchdog: BUG: soft lockup - CPU#6 stuck for 22s!

[syncobj_timelin:2021]

-Lionel

On 07/12/2018 09:55, Chunming Zhou wrote:

we need to import/export timeline point

---
  drivers/gpu/drm/drm_internal.h |  4 +++
  drivers/gpu/drm/drm_ioctl.c    |  6 ++++
  drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
  include/uapi/drm/drm.h         | 10 ++++++
  4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+                                        struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+                     drm_syncobj_binary_to_timeline_ioctl,
+                     DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+                     drm_syncobj_timeline_to_binary_ioctl,
+                     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 +66 -0

72 lines not on this page · raw message

include/uapi/drm/drm.h +10 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
        __u32 pad;
  };
 
+struct drm_syncobj_transfer {
+       __u32 binary_handle;
+       __u32 timeline_handle;
+       __u64 point;
+       __u32 flags;
+       __u32 pad;
+};
+
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
@@ -933,6 +941,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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE   DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY   DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
  /**
   * Device specific ioctls should only be in their respective headers

_______________________________________________
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): 976d7032-1cde-0427-ce56-38c2ac8881ec-5C7GfCeVMHo@public.gmane.org

#51 lore raw

Re: [PATCH 09/11] drm/syncobj: add transition iotcls between binary and timeline

Quoted 11 lines · Christian

Am 20.02.19 um 05:53 schrieb zhoucm1:

Quoted 10 lines · Christian
Quoted 6 lines

Hi David,

Quoted 1 line

Could you have a look if it's reasonable?

Patch #1 is also something I already fixed on my local branch.

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

But patch #2 won't work like this.

We can't return an error from drm_syncobj_add_point() because we already submitted work to the hardware. And just dropping the fence like you do in the patch is a clearly no-go as well.

Then do you have any idea to skip the messed order signal point?

No, I don't think we can actually do this.

But as Lionel pointed out, user mode shouldn't query a smaller timeline payload compared to last time, we must skip messed order signal point!

-David

Quoted 337 lines

The only solution I can see would be to lock down the syncobj to modifications while command submission is in progress. And that in turn would mean a huge bunch of ww_mutex overhead we will certainly want to avoid.

Christian.

Quoted 331 lines

-David

Quoted 328 lines

Regards,
Christian.

Am 19.02.19 um 11:46 schrieb zhoucm1:

Quoted 322 lines

Hi Lionel,

the attached should fix your problem and also messed signal order.

Hi Christian,

Could you have a look if it's reasonable?

btw: I pushed to change to https://github.com/amingriyue/timeline-syncobj-kernel, which is already rebased to latest drm-misc(kernel 5.0). You can directly use that branch.

-David

Quoted 304 lines · Christian

Am 18.02.19 um 13:07 schrieb Lionel Landwerlin:

Quoted 4 lines

Thanks guys :)

You mentioned that signaling out of order is illegal.
Is this illegal with regard to the vulkan spec or to the syncobj implementation?

David is the expert on that, but as far as I know that is forbidden by the vulkan spec.

Quoted 2 lines

I'm not finding anything in the vulkan spec that makes out of order signaling illegal.
That's why I came up with this test, just verifying that the timeline does not go backward in term of its payload.

Well we need to handle this case gracefully in the kernel, so it is still a good testcase.

Christian.

Quoted 288 lines

-Lionel

Quoted 283 lines · Christian

Hi David,

well I think Lionel is testing the invalid signal order on purpose :)

Anyway we really need to handle invalid order graceful here. E.g. either the same way as during CS or we abort and return an error message.

I think just using the same approach as during CS ist the best we can do.

Regards,
Christian

Am 18.02.2019 11:35 schrieb "Zhou, David(ChunMing)" <[email protected]>:

Hi Lionel,

I checked your igt test case,

uint64_t points[5] = { 1, 5, 3, 7, 6 };

which is illegal signal order.

I must admit we should handle it gracefully if signal isn't in-order, and we shouldn't lead to deadlock.

Hi Christian,

Can we just ignore when signal point X <= timeline Y? Or just give a warning?

Otherwise like Lionel's unexpected use cases, which easily leads to deadlock.

-David

Quoted 247 lines · Lionel Landwerlin

Hi David,

Thanks a lot for point me to the tests you've added in IGT. While adding a test with that signals fences imported into a timeline syncobj out of order, I ran into a deadlock.
Here is the test :
https://github.com/djdeath/intel-gpu-tools/commit/1e46cf7e7bff09b78a24367ddc2314f97eb0a1b9

Trying to kill the deadlocked process I got this backtrace :

[   33.969136] [IGT] syncobj_timeline: starting subtest signal-order [   60.452823] watchdog: BUG: soft lockup - CPU#6 stuck for 23s! [syncobj_timelin:2021]
[   60.452826] Modules linked in: rfcomm cmac bnep binfmt_misc nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio sch_fq_codel ib_iser snd_hda_intel rdma_cm iw_cm snd_hda_codec ib_cm snd_hda_core snd_hwdep intel_rapl snd_pcm ib_core x86_pkg_temp_thermal intel_powerclamp configf s coretemp iscsi_tcp snd_seq_midi libiscsi_tcp snd_seq_midi_event libiscsi kvm_intel scsi_transport_iscsi kvm btusb snd_rawmidi irqbypass btrtl intel_cstate intel_rapl_perf btbcm btintel bluetooth snd_seq snd_seq_device snd_timer input_leds ecdh_generic snd soundcore mei_me mei intel_pch_thermal mac_hid acpi_pad parp
ort_pc ppdev lp parport ip_tables x_tables autofs4 btrfs zstd_decompress zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid i915 crct10dif_pclmul crc32_pclmul i2c_algo_bit ghash_clmulni_intel prime_numbers
drm_kms_helper aesni_intel syscopyarea sysfillrect
[   60.452876]  sysimgblt fb_sys_fops aes_x86_64 crypto_simd sdhci_pci cryptd drm e1000e glue_helper cqhci sdhci wmi video
[   60.452881] CPU: 6 PID: 2021 Comm: syncobj_timelin Tainted: G U            5.0.0-rc5+ #337
[   60.452882] Hardware name:  /NUC6i7KYB, BIOS KYSKLi70.86A.0042.2016.0929.1933 09/29/2016
[   60.452886] RIP: 0010:dma_fence_chain_walk+0x22c/0x260
[   60.452888] Code: ff e9 93 fe ff ff 48 8b 45 08 48 8b 40 18 48 85 c0 74 0c 48 89 ef e8 33 0f 58 00 84 c0 75 23 f0 41 ff 4d 00 0f 88 99 87 2f 00 <0f> 85 05 fe ff ff 4c 89 ef e8 56 ea ff ff 48 89 d8 5b 5d 41 5c 41 [   60.452888] RSP: 0018:ffff9a5804653ca8 EFLAGS: 00010296 ORIG_RAX:
ffffffffffffff13
[   60.452889] RAX: 0000000000000000 RBX: ffff8f5690fb2480 RCX:
ffff8f5690fb2f00
[   60.452890] RDX: 00000000003e3730 RSI: 0000000000000000 RDI:
ffff8f5690fb2180
[   60.452891] RBP: ffff8f5690fb2180 R08: 0000000000000000 R09:
ffff8f5690fb2eb0
[   60.452891] R10: 0000000000000000 R11: ffff8f5660469860 R12:
ffff8f5690fb2f68
[   60.452892] R13: ffff8f5690fb2f00 R14: 0000000000000003 R15:
ffff8f5655a45fc0
[   60.452913] FS:  00007fdc5c459980(0000) GS:ffff8f569eb80000(0000) knlGS:0000000000000000
[   60.452913] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [   60.452914] CR2: 00007f9d74336dd8 CR3: 000000084a67e004 CR4:
00000000003606e0
[   60.452915] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[   60.452915] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[   60.452916] Call Trace:
[   60.452958]  drm_syncobj_add_point+0x102/0x160 [drm]
[   60.452965]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm] [   60.452971]  drm_syncobj_transfer_ioctl+0x10f/0x180 [drm] [   60.452978]  drm_ioctl_kernel+0xac/0xf0 [drm]
[   60.452984]  drm_ioctl+0x2eb/0x3b0 [drm]
[   60.452990]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm] [   60.452992]  ? sw_sync_ioctl+0x347/0x370
[   60.452994]  do_vfs_ioctl+0xa4/0x640
[   60.452995]  ? __fput+0x134/0x220
[   60.452997]  ? do_fcntl+0x1a5/0x650
[   60.452998]  ksys_ioctl+0x70/0x80
[   60.452999]  __x64_sys_ioctl+0x16/0x20
[   60.453002]  do_syscall_64+0x55/0x110
[   60.453004]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   60.453005] RIP: 0033:0x7fdc5b6e45d7
[   60.453006] 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 [   60.453007] RSP: 002b:00007fff25c4d198 EFLAGS: 00000206 ORIG_RAX:
0000000000000010
[   60.453008] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
00007fdc5b6e45d7
[   60.453008] RDX: 00007fff25c4d200 RSI: 00000000c02064cc RDI:
0000000000000003
[   60.453009] RBP: 00007fff25c4d1d0 R08: 0000000000000000 R09:
000000000000001e
[   60.453010] R10: 0000000000000000 R11: 0000000000000206 R12:
0000563d3959e4d0
[   60.453010] R13: 00007fff25c4d620 R14: 0000000000000000 R15:
0000000000000000
[   88.447359] watchdog: BUG: soft lockup - CPU#6 stuck for 22s! [syncobj_timelin:2021]

-Lionel

Quoted 147 lines · Chunming Zhou

we need to import/export timeline point

---
   drivers/gpu/drm/drm_internal.h |  4 +++
   drivers/gpu/drm/drm_ioctl.c    |  6 ++++
   drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
   include/uapi/drm/drm.h         | 10 ++++++
   4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+					 struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+		      drm_syncobj_binary_to_timeline_ioctl,
+		      DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+		      drm_syncobj_timeline_to_binary_ioctl,
+		      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 +66 -0
index 282982e58dbd..cf4daa670252 100644
@@ -670,6 +670,72 @@ drm_syncobj_fd_to_handle_ioctl(struct drm_device *dev, void *data,
   					&args->handle);
   }
 
+int
+drm_syncobj_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *timeline_syncobj = NULL;
+	struct dma_fence *fence;
+	struct dma_fence_chain *chain;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	timeline_syncobj = drm_syncobj_find(file_private, args->timeline_handle);
+	if (!timeline_syncobj) {
+		return -ENOENT;
+	}
+	ret = drm_syncobj_find_fence(file_private, args->binary_handle, 0, 0,
+				     &fence);
+	if (ret)
+		goto err;
+	chain = kzalloc(sizeof(struct dma_fence_chain), GFP_KERNEL);
+	if (!chain)
+		goto err1;
+	drm_syncobj_add_point(timeline_syncobj, chain, fence, args->point);
+err1:
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(timeline_syncobj);
+
+	return ret;
+}
+
+int
+drm_syncobj_timeline_to_binary_ioctl(struct drm_device *dev, void *data,
+				     struct drm_file *file_private)
+{
+	struct drm_syncobj_transfer *args = data;
+	struct drm_syncobj *binary_syncobj = NULL;
+	struct dma_fence *fence;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -ENODEV;
+
+	if (args->pad)
+		return -EINVAL;
+
+	binary_syncobj = drm_syncobj_find(file_private, args->binary_handle);
+	if (!binary_syncobj)
+		return -ENOENT;
+	ret = drm_syncobj_find_fence(file_private, args->timeline_handle,
+				     args->point, args->flags, &fence);
+	if (ret)
+		goto err;
+	drm_syncobj_replace_fence(binary_syncobj, fence);
+	dma_fence_put(fence);
+err:
+	drm_syncobj_put(binary_syncobj);
+
+	return ret;
+}
+
   static void syncobj_wait_fence_func(struct dma_fence *fence,
   				    struct dma_fence_cb *cb)
   {
include/uapi/drm/drm.h +10 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
   	__u32 pad;
   };
 
+struct drm_syncobj_transfer {
+	__u32 binary_handle;
+	__u32 timeline_handle;
+	__u64 point;
+	__u32 flags;
+	__u32 pad;
+};
+
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
   #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
@@ -933,6 +941,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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE	DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY	DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
   /**
    * Device specific ioctls should only be in their respective headers

_______________________________________________
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): 730eaa42-d852-e9d8-7756-43fb256a466f-5C7GfCeVMHo@public.gmane.org

#53 lore raw

Re: [PATCH 09/11] drm/syncobj: add transition iotcls between binary and timeline

Am 20.02.19 um 09:10 schrieb zhoucm1:

On 2019年02月20日 15:59, Koenig, Christian wrote:
Am 20.02.19 um 05:53 schrieb zhoucm1:

On 2019年02月19日 19:32, Koenig, Christian wrote:
Hi David,

Could you have a look if it's reasonable?

Patch #1 is also something I already fixed on my local branch.

But patch #2 won't work like this.

We can't return an error from drm_syncobj_add_point() because we already submitted work to the hardware. And just dropping the fence like you do in the patch is a clearly no-go as well.

Then do you have any idea to skip the messed order signal point?

No, I don't think we can actually do this.
But as Lionel pointed out, user mode shouldn't query a smaller timeline payload compared to last time, we must skip messed order signal point!

No we don't.

That userspace queries a smaller timeline payload compared to last time is because userspace messed up signaling order in the first place.

Additional to that I'm not sure that userspace would query a smaller timeline payload. IIRC our workaround for messed up signaling order handled that case gracefully as well.

Christian.

-David

The only solution I can see would be to lock down the syncobj to modifications while command submission is in progress. And that in turn would mean a huge bunch of ww_mutex overhead we will certainly want to avoid.

Christian.

-David

Regards,
Christian.

Am 19.02.19 um 11:46 schrieb zhoucm1:

Hi Lionel,

the attached should fix your problem and also messed signal order.

Hi Christian,

Could you have a look if it's reasonable?

btw: I pushed to change to https://github.com/amingriyue/timeline-syncobj-kernel, which is already rebased to latest drm-misc(kernel 5.0). You can directly use that branch.

-David

On 2019年02月19日 01:01, Koenig, Christian wrote:
Am 18.02.19 um 13:07 schrieb Lionel Landwerlin:
Thanks guys :)

You mentioned that signaling out of order is illegal.
Is this illegal with regard to the vulkan spec or to the syncobj implementation?

David is the expert on that, but as far as I know that is forbidden by the vulkan spec.

I'm not finding anything in the vulkan spec that makes out of order signaling illegal.
That's why I came up with this test, just verifying that the timeline does not go backward in term of its payload.

Well we need to handle this case gracefully in the kernel, so it is still a good testcase.

Christian.

-Lionel

On 18/02/2019 11:01, Koenig, Christian wrote:
Hi David,

well I think Lionel is testing the invalid signal order on purpose :)

Anyway we really need to handle invalid order graceful here. E.g. either the same way as during CS or we abort and return an error message.

I think just using the same approach as during CS ist the best we can do.

Regards,
Christian

Am 18.02.2019 11:35 schrieb "Zhou, David(ChunMing)" <[email protected]><mailto:[email protected]>:

Hi Lionel,

I checked your igt test case,

uint64_t points[5] = { 1, 5, 3, 7, 6 };

which is illegal signal order.

I must admit we should handle it gracefully if signal isn't in-order, and we shouldn't lead to deadlock.

Hi Christian,

Can we just ignore when signal point X <= timeline Y? Or just give a warning?

Otherwise like Lionel's unexpected use cases, which easily leads to deadlock.

-David

On 2019年02月15日 22:28, Lionel Landwerlin wrote:

Hi David,

Thanks a lot for point me to the tests you've added in IGT. While adding a test with that signals fences imported into a timeline syncobj out of order, I ran into a deadlock.
Here is the test :
https://github.com/djdeath/intel-gpu-tools/commit/1e46cf7e7bff09b78a24367ddc2314f97eb0a1b9

Trying to kill the deadlocked process I got this backtrace :

[   33.969136] [IGT] syncobj_timeline: starting subtest signal-order
[   60.452823] watchdog: BUG: soft lockup - CPU#6 stuck for 23s!
[syncobj_timelin:2021]
[   60.452826] Modules linked in: rfcomm cmac bnep binfmt_misc

nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio sch_fq_codel ib_iser snd_hda_intel rdma_cm iw_cm snd_hda_codec ib_cm snd_hda_core snd_hwdep intel_rapl snd_pcm ib_core x86_pkg_temp_thermal intel_powerclamp configf s coretemp iscsi_tcp snd_seq_midi libiscsi_tcp snd_seq_midi_event libiscsi kvm_intel scsi_transport_iscsi kvm btusb snd_rawmidi irqbypass btrtl intel_cstate intel_rapl_perf btbcm btintel bluetooth snd_seq snd_seq_device snd_timer input_leds ecdh_generic snd soundcore mei_me mei intel_pch_thermal mac_hid acpi_pad parp
ort_pc ppdev lp parport ip_tables x_tables autofs4 btrfs zstd_decompress zstd_compress raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid i915 crct10dif_pclmul crc32_pclmul i2c_algo_bit ghash_clmulni_intel prime_numbers
drm_kms_helper aesni_intel syscopyarea sysfillrect

[   60.452876]  sysimgblt fb_sys_fops aes_x86_64 crypto_simd sdhci_pci
cryptd drm e1000e glue_helper cqhci sdhci wmi video
[   60.452881] CPU: 6 PID: 2021 Comm: syncobj_timelin Tainted: G
U            5.0.0-rc5+ #337
[   60.452882] Hardware name:  /NUC6i7KYB, BIOS
KYSKLi70.86A.0042.2016.0929.1933 09/29/2016
[   60.452886] RIP: 0010:dma_fence_chain_walk+0x22c/0x260
[   60.452888] Code: ff e9 93 fe ff ff 48 8b 45 08 48 8b 40 18 48 85 c0
74 0c 48 89 ef e8 33 0f 58 00 84 c0 75 23 f0 41 ff 4d 00 0f 88 99 87 2f
00 <0f> 85 05 fe ff ff 4c 89 ef e8 56 ea ff ff 48 89 d8 5b 5d 41 5c 41
[   60.452888] RSP: 0018:ffff9a5804653ca8 EFLAGS: 00010296 ORIG_RAX:
ffffffffffffff13
[   60.452889] RAX: 0000000000000000 RBX: ffff8f5690fb2480 RCX:
ffff8f5690fb2f00
[   60.452890] RDX: 00000000003e3730 RSI: 0000000000000000 RDI:
ffff8f5690fb2180
[   60.452891] RBP: ffff8f5690fb2180 R08: 0000000000000000 R09:
ffff8f5690fb2eb0
[   60.452891] R10: 0000000000000000 R11: ffff8f5660469860 R12:
ffff8f5690fb2f68
[   60.452892] R13: ffff8f5690fb2f00 R14: 0000000000000003 R15:
ffff8f5655a45fc0
[   60.452913] FS:  00007fdc5c459980(0000) GS:ffff8f569eb80000(0000)
knlGS:0000000000000000
[   60.452913] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   60.452914] CR2: 00007f9d74336dd8 CR3: 000000084a67e004 CR4:
00000000003606e0
[   60.452915] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[   60.452915] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7:
0000000000000400
[   60.452916] Call Trace:
[   60.452958]  drm_syncobj_add_point+0x102/0x160 [drm]
[   60.452965]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm]
[   60.452971]  drm_syncobj_transfer_ioctl+0x10f/0x180 [drm]
[   60.452978]  drm_ioctl_kernel+0xac/0xf0 [drm]
[   60.452984]  drm_ioctl+0x2eb/0x3b0 [drm]
[   60.452990]  ? drm_syncobj_fd_to_handle_ioctl+0x1b0/0x1b0 [drm]
[   60.452992]  ? sw_sync_ioctl+0x347/0x370
[   60.452994]  do_vfs_ioctl+0xa4/0x640
[   60.452995]  ? __fput+0x134/0x220
[   60.452997]  ? do_fcntl+0x1a5/0x650
[   60.452998]  ksys_ioctl+0x70/0x80
[   60.452999]  __x64_sys_ioctl+0x16/0x20
[   60.453002]  do_syscall_64+0x55/0x110
[   60.453004]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[   60.453005] RIP: 0033:0x7fdc5b6e45d7
[   60.453006] 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
[   60.453007] RSP: 002b:00007fff25c4d198 EFLAGS: 00000206 ORIG_RAX:
0000000000000010
[   60.453008] RAX: ffffffffffffffda RBX: 0000000000000000 RCX:
00007fdc5b6e45d7
[   60.453008] RDX: 00007fff25c4d200 RSI: 00000000c02064cc RDI:
0000000000000003
[   60.453009] RBP: 00007fff25c4d1d0 R08: 0000000000000000 R09:
000000000000001e
[   60.453010] R10: 0000000000000000 R11: 0000000000000206 R12:
0000563d3959e4d0
[   60.453010] R13: 00007fff25c4d620 R14: 0000000000000000 R15:
0000000000000000
[   88.447359] watchdog: BUG: soft lockup - CPU#6 stuck for 22s!

[syncobj_timelin:2021]

-Lionel

On 07/12/2018 09:55, Chunming Zhou wrote:

we need to import/export timeline point

---
  drivers/gpu/drm/drm_internal.h |  4 +++
  drivers/gpu/drm/drm_ioctl.c    |  6 ++++
  drivers/gpu/drm/drm_syncobj.c  | 66 ++++++++++++++++++++++++++++++++++
  include/uapi/drm/drm.h         | 10 ++++++
  4 files changed, 86 insertions(+)
drivers/gpu/drm/drm_internal.h +4 -0
index dab4d5936441..ecbe3d51a702 100644
@@ -176,6 +176,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_binary_to_timeline_ioctl(struct drm_device *dev, void *data,
+                                        struct drm_file *file_private);
+int drm_syncobj_timeline_to_binary_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,
drivers/gpu/drm/drm_ioctl.c +6 -0
index 7578ef6dc1d1..6b417e3c3ea5 100644
@@ -673,6 +673,12 @@ 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_BINARY_TO_TIMELINE,
+                     drm_syncobj_binary_to_timeline_ioctl,
+                     DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY,
+                     drm_syncobj_timeline_to_binary_ioctl,
+                     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 +66 -0

72 lines not on this page · raw message

include/uapi/drm/drm.h +10 -0
index b2c36f2b2599..88d6129d4a18 100644
@@ -735,6 +735,14 @@ struct drm_syncobj_handle {
        __u32 pad;
  };
 
+struct drm_syncobj_transfer {
+       __u32 binary_handle;
+       __u32 timeline_handle;
+       __u64 point;
+       __u32 flags;
+       __u32 pad;
+};
+
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
  #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
@@ -933,6 +941,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_array)
+#define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE   DRM_IOWR(0xCC, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY   DRM_IOWR(0xCD, struct drm_syncobj_transfer)
 
  /**
   * Device specific ioctls should only be in their respective headers

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

#54 lore raw

PATCH 11/11 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 8de55f7f1a3a..cafafdb1d03f 100644
@@ -71,9 +71,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
#55 lore raw

PATCH 5/11 drm/syncobj: add support for timeline point wait v8

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
v4:
rebase
v5:
add comment for xxx_WAIT_AVAILABLE
v6: rebase and rework on new container
v7: drop _WAIT_COMPLETED, it is the default anyway
v8: correctly handle garbage collected fences

Cc Daniel Rakos <[email protected]>
Cc Jason Ekstrand <[email protected]>
Cc Bas Nieuwenhuizen <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Chris Wilson <[email protected]>
---
 drivers/gpu/drm/drm_internal.h |   2 +
 drivers/gpu/drm/drm_ioctl.c    |   2 +
 drivers/gpu/drm/drm_syncobj.c  | 153 ++++++++++++++++++++++++++-------
 include/uapi/drm/drm.h         |  15 ++++
 4 files changed, 143 insertions(+), 29 deletions(-)
drivers/gpu/drm/drm_internal.h +2 -0
index c7a7d7ce5d1c..18b41e10195c 100644
@@ -178,6 +178,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 94bd872d56c4..a9a17ed35cc4 100644
@@ -675,6 +675,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 +124 -29

253 lines not on this page · raw message

include/uapi/drm/drm.h +15 -0
index 300f336633f2..0092111d002c 100644
@@ -737,6 +737,7 @@ struct drm_syncobj_handle {
 
 #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0)
 #define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1)
+#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2)
 struct drm_syncobj_wait {
 	__u64 handles;
 	/* absolute timeout */
@@ -747,6 +748,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;
@@ -909,6 +923,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
#56 lore raw

PATCH 8/11 drm/amdgpu: add timeline support in amdgpu CS v2

In reply to Chunming Zhou

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

Cc Daniel Rakos <[email protected]>
Cc Jason Ekstrand <[email protected]>
Cc Bas Nieuwenhuizen <[email protected]>
Cc Dave Airlie <[email protected]>
Cc Christian König <[email protected]>
Cc Chris Wilson <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu.h    |  10 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 147 +++++++++++++++++++++----
 include/uapi/drm/amdgpu_drm.h          |   8 ++
 3 files changed, 140 insertions(+), 25 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu.h +8 -2
index 42f882c633ee..f9160ea1396a 100644
@@ -545,6 +545,12 @@ struct amdgpu_cs_chunk {
 	void			*kdata;
 };
 
+struct amdgpu_cs_post_dep {
+	struct drm_syncobj *syncobj;
+	struct dma_fence_chain *chain;
+	u64 point;
+};
+
 struct amdgpu_cs_parser {
 	struct amdgpu_device	*adev;
 	struct drm_file		*filp;
@@ -574,8 +580,8 @@ struct amdgpu_cs_parser {
 	/* user fence */
 	struct amdgpu_bo_list_entry	uf_entry;
 
-	unsigned num_post_dep_syncobjs;
-	struct drm_syncobj **post_dep_syncobjs;
+	unsigned			num_post_deps;
+	struct amdgpu_cs_post_dep	*post_deps;
 };
 
 static inline u32 amdgpu_get_ib_value(struct amdgpu_cs_parser *p,
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +124 -23

224 lines not on this page · raw message

include/uapi/drm/amdgpu_drm.h +8 -0
index be84e43c1e19..997222bc1afe 100644
@@ -523,6 +523,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;
@@ -598,6 +600,12 @@ 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

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

PATCH 10/11 drm/syncobj: add timeline signal ioctl for syncobj

In reply to Chunming Zhou
---
 drivers/gpu/drm/drm_internal.h |  2 +
 drivers/gpu/drm/drm_ioctl.c    |  2 +
 drivers/gpu/drm/drm_syncobj.c  | 70 ++++++++++++++++++++++++++++++++++
 include/uapi/drm/drm.h         |  1 +
 4 files changed, 75 insertions(+)
drivers/gpu/drm/drm_internal.h +2 -0
index ecbe3d51a702..149c2f589ec9 100644
@@ -188,6 +188,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_timeline_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);
 
drivers/gpu/drm/drm_ioctl.c +2 -0
index 6b417e3c3ea5..d05586601eb5 100644
@@ -687,6 +687,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_TIMELINE_SIGNAL, drm_syncobj_timeline_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),
drivers/gpu/drm/drm_syncobj.c +70 -0

76 lines not on this page · raw message

include/uapi/drm/drm.h +1 -0
index 88d6129d4a18..9a5fa3c26f22 100644
@@ -943,6 +943,7 @@ extern "C" {
 #define DRM_IOCTL_SYNCOBJ_QUERY		DRM_IOWR(0xCB, struct drm_syncobj_timeline_array)
 #define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE	DRM_IOWR(0xCC, struct drm_syncobj_transfer)
 #define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY	DRM_IOWR(0xCD, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL	DRM_IOWR(0xCE, struct drm_syncobj_timeline_array)
 
 /**
  * Device specific ioctls should only be in their respective headers
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]

#59 lore raw

Re: [PATCH 10/11] drm/syncobj: add timeline signal ioctl for syncobj

Am 07.12.18 um 10:56 schrieb Chunming Zhou:

Quoted 79 lines
---
  drivers/gpu/drm/drm_internal.h |  2 +
  drivers/gpu/drm/drm_ioctl.c    |  2 +
  drivers/gpu/drm/drm_syncobj.c  | 70 ++++++++++++++++++++++++++++++++++
  include/uapi/drm/drm.h         |  1 +
  4 files changed, 75 insertions(+)
drivers/gpu/drm/drm_internal.h +2 -0
index ecbe3d51a702..149c2f589ec9 100644
@@ -188,6 +188,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_timeline_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);
 
drivers/gpu/drm/drm_ioctl.c +2 -0
index 6b417e3c3ea5..d05586601eb5 100644
@@ -687,6 +687,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_TIMELINE_SIGNAL, drm_syncobj_timeline_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),
drivers/gpu/drm/drm_syncobj.c +37 -0
index cf4daa670252..238ed89593a7 100644
@@ -1165,6 +1165,76 @@ drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
  	return ret;
  }
 
+int
+drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
+				  struct drm_file *file_private)
+{
+	struct drm_syncobj_timeline_array *args = data;
+	struct drm_syncobj **syncobjs;
+	struct dma_fence_chain *chains;
+	uint64_t *points;
+	uint32_t i, j, timeline_count = 0;
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+		return -EOPNOTSUPP;
+
+	if (args->pad != 0)
+		return -EINVAL;
+
+	if (args->count_handles == 0)
+		return -EINVAL;
+
+	ret = drm_syncobj_array_find(file_private,
+				     u64_to_user_ptr(args->handles),
+				     args->count_handles,
+				     &syncobjs);
+	if (ret < 0)
+		return ret;
+
+	points = kmalloc_array(args->count_handles, sizeof(*points),
+			       GFP_KERNEL);
+	if (!points) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	if (!u64_to_user_ptr(args->points)) {
+		memset(points, 0, args->count_handles * sizeof(uint64_t));
+	} else if (copy_from_user(points, u64_to_user_ptr(args->points),
+				  sizeof(uint64_t) * args->count_handles)) {

drivers/gpu/drm/drm_syncobj.c drm_syncobj_signal_ioctl(struct drm_device *dev, void *data, · line 1214

Quoted 10 lines
drivers/gpu/drm/drm_syncobj.c +10 -0
+		ret = -EFAULT;
+		goto err_points;
+	}
+
+
+	for (i = 0; i < args->count_handles; i++) {
+		if (points[i])
+			timeline_count++;
+	}
+	chains = kmalloc_array(timeline_count, sizeof(*chains), GFP_KERNEL);

I don't think that this will work. We need individually allocated chain objects.

Apart from that this looks good to me,
Christian.

Quoted 31 lines
drivers/gpu/drm/drm_syncobj.c +23 -0
+	if (!chains) {
+		ret = -ENOMEM;
+		goto err_points;
+	}
+
+	for (i = 0, j = 0; i < args->count_handles; i++) {
+		if (points[i]) {
+			struct dma_fence *fence = dma_fence_get_stub();
+
+			drm_syncobj_add_point(syncobjs[i], &chains[j++],
+					      fence, points[i]);
+			dma_fence_put(fence);
+		} else
+			drm_syncobj_assign_null_handle(syncobjs[i]);
+	}
+err_points:
+	kfree(points);
+out:
+	drm_syncobj_array_free(syncobjs, args->count_handles);
+
+	return ret;
+}
+
  int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
  			    struct drm_file *file_private)
  {
include/uapi/drm/drm.h +0 -0
index 88d6129d4a18..9a5fa3c26f22 100644

include/uapi/drm/drm.h extern "C" { · line 949

Quoted 7 lines
include/uapi/drm/drm.h +1 -0
@@ -943,6 +943,7 @@ extern "C" {
  #define DRM_IOCTL_SYNCOBJ_QUERY		DRM_IOWR(0xCB, struct drm_syncobj_timeline_array)
  #define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE	DRM_IOWR(0xCC, struct drm_syncobj_transfer)
  #define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY	DRM_IOWR(0xCD, struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL	DRM_IOWR(0xCE, struct drm_syncobj_timeline_array)
 
  /**
   * Device specific ioctls should only be in their respective headers

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

#60 lore raw

Re: [PATCH 10/11] drm/syncobj: add timeline signal ioctl for syncobj

Quoted 91 lines · Christian König

Am 07.12.18 um 10:56 schrieb Chunming Zhou:

Quoted 90 lines

---
  drivers/gpu/drm/drm_internal.h |  2 + drivers/gpu/drm/drm_ioctl.c    |  2 + drivers/gpu/drm/drm_syncobj.c  | 70 ++++++++++++++++++++++++++++++++++ include/uapi/drm/drm.h         |  1 +

  4 files changed, 75 insertions(+)
drivers/gpu/drm/drm_internal.h +2 -0
index ecbe3d51a702..149c2f589ec9 100644
@@ -188,6 +188,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_timeline_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);
  diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 6b417e3c3ea5..d05586601eb5 100644

drivers/gpu/drm/drm_ioctl.c +2 -0
@@ -687,6 +687,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_TIMELINE_SIGNAL, 
 drm_syncobj_timeline_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),

drivers/gpu/drm/drm_syncobj.c +0 -0
index cf4daa670252..238ed89593a7 100644
@@ -1165,6 +1165,76 @@ drm_syncobj_signal_ioctl(struct drm_device 
 *dev, void *data,
       return ret;
   }

  +int

drivers/gpu/drm/drm_syncobj.c +42 -0
+drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
+                  struct drm_file *file_private)
+{
+    struct drm_syncobj_timeline_array *args = data;
+    struct drm_syncobj **syncobjs;
+    struct dma_fence_chain *chains;
+    uint64_t *points;
+    uint32_t i, j, timeline_count = 0;
+    int ret;
+
+    if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+        return -EOPNOTSUPP;
+
+    if (args->pad != 0)
+        return -EINVAL;
+
+    if (args->count_handles == 0)
+        return -EINVAL;
+
+    ret = drm_syncobj_array_find(file_private,
+                     u64_to_user_ptr(args->handles),
+                     args->count_handles,
+                     &syncobjs);
+    if (ret < 0)
+        return ret;
+
+    points = kmalloc_array(args->count_handles, sizeof(*points),
+                   GFP_KERNEL);
+    if (!points) {
+        ret = -ENOMEM;
+        goto out;
+    }
+    if (!u64_to_user_ptr(args->points)) {
+        memset(points, 0, args->count_handles * sizeof(uint64_t));
+    } else if (copy_from_user(points, u64_to_user_ptr(args->points),
+                  sizeof(uint64_t) * args->count_handles)) {
+        ret = -EFAULT;
+        goto err_points;
+    }
+
+
+    for (i = 0; i < args->count_handles; i++) {
Quoted 8 lines
Quoted 5 lines

+        if (points[i])
+            timeline_count++;
+    }
+    chains = kmalloc_array(timeline_count, sizeof(*chains), GFP_KERNEL);

I don't think that this will work. We need individually allocated chain objects.

Yeah, I shouldn't use &chains[i] to get address, how about using cast like "(struct dma_fence_chain *)chains[i]".

btw, I will add a test case for signal array in igt.

-David

Quoted 37 lines

Apart from that this looks good to me,
Christian.

Quoted 33 lines

+    if (!chains) {
+        ret = -ENOMEM;
+        goto err_points;
+    }

drivers/gpu/drm/drm_syncobj.c +19 -0
+
+    for (i = 0, j = 0; i < args->count_handles; i++) {
+        if (points[i]) {
+            struct dma_fence *fence = dma_fence_get_stub();
+
+            drm_syncobj_add_point(syncobjs[i], &chains[j++],
+                          fence, points[i]);
+            dma_fence_put(fence);
+        } else
+            drm_syncobj_assign_null_handle(syncobjs[i]);
+    }
+err_points:
+    kfree(points);
+out:
+    drm_syncobj_array_free(syncobjs, args->count_handles);
+
+    return ret;
+}
+

  int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file_private)
  {

include/uapi/drm/drm.h +0 -0
index 88d6129d4a18..9a5fa3c26f22 100644
@@ -943,6 +943,7 @@ extern "C" {
   #define DRM_IOCTL_SYNCOBJ_QUERY        DRM_IOWR(0xCB, struct 
 drm_syncobj_timeline_array)
Quoted 9 lines
Quoted 8 lines
include/uapi/drm/drm.h +1 -0
   #define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE    DRM_IOWR(0xCC, 
 struct drm_syncobj_transfer)
   #define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY    DRM_IOWR(0xCD, 
 struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL    DRM_IOWR(0xCE, struct 

drm_syncobj_timeline_array)
    /**
   * Device specific ioctls should only be in their respective headers

_______________________________________________
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): 8c34aaf0-13b3-4070-f4ef-076fe1ab3197-5C7GfCeVMHo@public.gmane.org

#62 lore raw

Re: [PATCH 10/11] drm/syncobj: add timeline signal ioctl for syncobj

Am 07.12.18 um 14:09 schrieb Zhou, David(ChunMing):

Quoted 99 lines · Christian König
Quoted 90 lines

Am 07.12.18 um 10:56 schrieb Chunming Zhou:

Quoted 89 lines
---
   drivers/gpu/drm/drm_internal.h |  2 +
   drivers/gpu/drm/drm_ioctl.c    |  2 +
   drivers/gpu/drm/drm_syncobj.c  | 70 ++++++++++++++++++++++++++++++++++
   include/uapi/drm/drm.h         |  1 +
   4 files changed, 75 insertions(+)
drivers/gpu/drm/drm_internal.h +2 -0
index ecbe3d51a702..149c2f589ec9 100644
@@ -188,6 +188,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_timeline_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);
  diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 6b417e3c3ea5..d05586601eb5 100644

drivers/gpu/drm/drm_ioctl.c +2 -0
@@ -687,6 +687,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_TIMELINE_SIGNAL,
 drm_syncobj_timeline_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),

drivers/gpu/drm/drm_syncobj.c +41 -0
index cf4daa670252..238ed89593a7 100644
@@ -1165,6 +1165,76 @@ drm_syncobj_signal_ioctl(struct drm_device
 *dev, void *data,
       return ret;
   }
   +int
+drm_syncobj_timeline_signal_ioctl(struct drm_device *dev, void *data,
+                  struct drm_file *file_private)
+{
+    struct drm_syncobj_timeline_array *args = data;
+    struct drm_syncobj **syncobjs;
+    struct dma_fence_chain *chains;
+    uint64_t *points;
+    uint32_t i, j, timeline_count = 0;
+    int ret;
+
+    if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+        return -EOPNOTSUPP;
+
+    if (args->pad != 0)
+        return -EINVAL;
+
+    if (args->count_handles == 0)
+        return -EINVAL;
+
+    ret = drm_syncobj_array_find(file_private,
+                     u64_to_user_ptr(args->handles),
+                     args->count_handles,
+                     &syncobjs);
+    if (ret < 0)
+        return ret;
+
+    points = kmalloc_array(args->count_handles, sizeof(*points),
+                   GFP_KERNEL);
+    if (!points) {
+        ret = -ENOMEM;
+        goto out;
+    }
+    if (!u64_to_user_ptr(args->points)) {
+        memset(points, 0, args->count_handles * sizeof(uint64_t));
+    } else if (copy_from_user(points, u64_to_user_ptr(args->points),
+                  sizeof(uint64_t) * args->count_handles)) {
+        ret = -EFAULT;
+        goto err_points;
+    }
+
+
Quoted 8 lines

drivers/gpu/drm/drm_syncobj.c drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,

Quoted 6 lines
drivers/gpu/drm/drm_syncobj.c +5 -0
+    for (i = 0; i < args->count_handles; i++) {
+        if (points[i])
+            timeline_count++;
+    }
+    chains = kmalloc_array(timeline_count, sizeof(*chains),
 GFP_KERNEL);

I don't think that this will work. We need individually allocated chain objects.

Quoted 2 lines

Yeah, I shouldn't use &chains[i] to get address, how about using cast like "(struct dma_fence_chain *)chains[i]".

No, that still won't work. You need an array of individual objects here, not a single array with many entries.

E.g. something like this:

struct dma_fence_chain **chains = kmalloc_array(count, sizeof(void*));

for (i = 0; i < count; ++i)
    chains[i] = kmalloc(....);

Christian.

Quoted 42 lines

btw, I will add a test case for signal array in igt.

-David

Quoted 36 lines

Apart from that this looks good to me,
Christian.

Quoted 33 lines
drivers/gpu/drm/drm_syncobj.c +23 -0
+    if (!chains) {
+        ret = -ENOMEM;
+        goto err_points;
+    }
+
+    for (i = 0, j = 0; i < args->count_handles; i++) {
+        if (points[i]) {
+            struct dma_fence *fence = dma_fence_get_stub();
+
+            drm_syncobj_add_point(syncobjs[i], &chains[j++],
+                          fence, points[i]);
+            dma_fence_put(fence);
+        } else
+            drm_syncobj_assign_null_handle(syncobjs[i]);
+    }
+err_points:
+    kfree(points);
+out:
+    drm_syncobj_array_free(syncobjs, args->count_handles);
+
+    return ret;
+}
+
   int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
                   struct drm_file *file_private)
   {
include/uapi/drm/drm.h +0 -0
index 88d6129d4a18..9a5fa3c26f22 100644
@@ -943,6 +943,7 @@ extern "C" {
   #define DRM_IOCTL_SYNCOBJ_QUERY        DRM_IOWR(0xCB, struct
 drm_syncobj_timeline_array)
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
include/uapi/drm/drm.h +1 -0
   #define DRM_IOCTL_SYNCOBJ_BINARY_TO_TIMELINE    DRM_IOWR(0xCC,
 struct drm_syncobj_transfer)
   #define DRM_IOCTL_SYNCOBJ_TIMELINE_TO_BINARY    DRM_IOWR(0xCD,
 struct drm_syncobj_transfer)
+#define DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL    DRM_IOWR(0xCE, struct

drm_syncobj_timeline_array)
    /**
   * Device specific ioctls should only be in their respective headers

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