All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] dma-buf: add dma_fence_unwrap
@ 2022-03-11 11:02 Christian König
  2022-03-11 11:02 ` [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers Christian König
                   ` (5 more replies)
  0 siblings, 6 replies; 40+ messages in thread
From: Christian König @ 2022-03-11 11:02 UTC (permalink / raw)
  To: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig
  Cc: Christian König

Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
structures and iterate over all the fences in them.

This is useful when we need to flatten out all fences in those structures.

Signed-off-by: Christian König <christian.koenig@amd.com>
---
 Documentation/driver-api/dma-buf.rst  |   6 +
 drivers/dma-buf/Makefile              |   1 +
 drivers/dma-buf/selftests.h           |   1 +
 drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
 include/linux/dma-fence-unwrap.h      |  99 +++++++++
 5 files changed, 386 insertions(+)
 create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
 create mode 100644 include/linux/dma-fence-unwrap.h

diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
index 2cd7db82d9fe..7209500f08c8 100644
--- a/Documentation/driver-api/dma-buf.rst
+++ b/Documentation/driver-api/dma-buf.rst
@@ -194,6 +194,12 @@ DMA Fence Chain
 .. kernel-doc:: include/linux/dma-fence-chain.h
    :internal:
 
+DMA Fence unwrap
+~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: include/linux/dma-fence-unwrap.h
+   :internal:
+
 DMA Fence uABI/Sync File
 ~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
index 511805dbeb75..4c9eb53ba3f8 100644
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -12,6 +12,7 @@ dmabuf_selftests-y := \
 	selftest.o \
 	st-dma-fence.o \
 	st-dma-fence-chain.o \
+	st-dma-fence-unwrap.o \
 	st-dma-resv.o
 
 obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
index 97d73aaa31da..851965867d9c 100644
--- a/drivers/dma-buf/selftests.h
+++ b/drivers/dma-buf/selftests.h
@@ -12,4 +12,5 @@
 selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
 selftest(dma_fence, dma_fence)
 selftest(dma_fence_chain, dma_fence_chain)
+selftest(dma_fence_unwrap, dma_fence_unwrap)
 selftest(dma_resv, dma_resv)
diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
new file mode 100644
index 000000000000..d821faaebe93
--- /dev/null
+++ b/drivers/dma-buf/st-dma-fence-unwrap.c
@@ -0,0 +1,279 @@
+// SPDX-License-Identifier: MIT
+
+/*
+ * Copyright (C) 2022 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/dma-fence-unwrap.h>
+#if 0
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/mm.h>
+#include <linux/sched/signal.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#endif
+
+#include "selftest.h"
+
+#define CHAIN_SZ (4 << 10)
+
+static struct kmem_cache *slab_fences;
+
+static inline struct mock_fence {
+	struct dma_fence base;
+	spinlock_t lock;
+} *to_mock_fence(struct dma_fence *f) {
+	return container_of(f, struct mock_fence, base);
+}
+
+static const char *mock_name(struct dma_fence *f)
+{
+	return "mock";
+}
+
+static void mock_fence_release(struct dma_fence *f)
+{
+	kmem_cache_free(slab_fences, to_mock_fence(f));
+}
+
+static const struct dma_fence_ops mock_ops = {
+	.get_driver_name = mock_name,
+	.get_timeline_name = mock_name,
+	.release = mock_fence_release,
+};
+
+static struct dma_fence *mock_fence(void)
+{
+	struct mock_fence *f;
+
+	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
+	if (!f)
+		return NULL;
+
+	spin_lock_init(&f->lock);
+	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
+
+	return &f->base;
+}
+
+static struct dma_fence *mock_array(unsigned int num_fences, ...)
+{
+	struct dma_fence_array *array;
+	struct dma_fence **fences;
+	va_list valist;
+	int i;
+
+	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
+	if (!fences)
+		return NULL;
+
+	va_start(valist, num_fences);
+	for (i = 0; i < num_fences; ++i)
+		fences[i] = va_arg(valist, typeof(*fences));
+	va_end(valist);
+
+	array = dma_fence_array_create(num_fences, fences,
+				       dma_fence_context_alloc(1),
+				       1, false);
+	if (!array)
+		goto cleanup;
+	return &array->base;
+
+cleanup:
+	for (i = 0; i < num_fences; ++i)
+		dma_fence_put(fences[i]);
+	kfree(fences);
+	return NULL;
+}
+
+static struct dma_fence *mock_chain(struct dma_fence *prev,
+				    struct dma_fence *fence)
+{
+	struct dma_fence_chain *f;
+
+	f = dma_fence_chain_alloc();
+	if (!f) {
+		dma_fence_put(prev);
+		dma_fence_put(fence);
+		return NULL;
+	}
+
+	dma_fence_chain_init(f, prev, fence, 1);
+	return &f->base;
+}
+
+static int sanitycheck(void *arg)
+{
+	struct dma_fence *f, *chain, *array;
+	int err = 0;
+
+	f = mock_fence();
+	if (!f)
+		return -ENOMEM;
+
+	array = mock_array(1, f);
+	if (!array)
+		return -ENOMEM;
+
+	chain = mock_chain(NULL, array);
+	if (!chain)
+		return -ENOMEM;
+
+	dma_fence_signal(f);
+	dma_fence_put(chain);
+	return err;
+}
+
+static int unwrap_array(void *arg)
+{
+	struct dma_fence *fence, *f1, *f2, *array;
+	struct dma_fence_unwrap iter;
+	int err = 0;
+
+	f1 = mock_fence();
+	if (!f1)
+		return -ENOMEM;
+
+	f2 = mock_fence();
+	if (!f2) {
+		dma_fence_put(f1);
+		return -ENOMEM;
+	}
+
+	array = mock_array(2, f1, f2);
+	if (!array)
+		return -ENOMEM;
+
+	dma_fence_unwrap_for_each(fence, &iter, array) {
+		if (fence == f1) {
+			f1 = NULL;
+		} else if (fence == f2) {
+			f2 = NULL;
+		} else {
+			pr_err("Unexpected fence!\n");
+			err = -EINVAL;
+		}
+	}
+
+	if (f1 || f2) {
+		pr_err("Not all fences seen!\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_signal(f1);
+	dma_fence_signal(f2);
+	dma_fence_put(array);
+	return 0;
+}
+
+static int unwrap_chain(void *arg)
+{
+	struct dma_fence *fence, *f1, *f2, *chain;
+	struct dma_fence_unwrap iter;
+	int err = 0;
+
+	f1 = mock_fence();
+	if (!f1)
+		return -ENOMEM;
+
+	f2 = mock_fence();
+	if (!f2) {
+		dma_fence_put(f1);
+		return -ENOMEM;
+	}
+
+	chain = mock_chain(f1, f2);
+	if (!chain)
+		return -ENOMEM;
+
+	dma_fence_unwrap_for_each(fence, &iter, chain) {
+		if (fence == f1) {
+			f1 = NULL;
+		} else if (fence == f2) {
+			f2 = NULL;
+		} else {
+			pr_err("Unexpected fence!\n");
+			err = -EINVAL;
+		}
+	}
+
+	if (f1 || f2) {
+		pr_err("Not all fences seen!\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_signal(f1);
+	dma_fence_signal(f2);
+	dma_fence_put(chain);
+	return 0;
+}
+
+static int unwrap_chain_array(void *arg)
+{
+	struct dma_fence *fence, *f1, *f2, *array, *chain;
+	struct dma_fence_unwrap iter;
+	int err = 0;
+
+	f1 = mock_fence();
+	if (!f1)
+		return -ENOMEM;
+
+	f2 = mock_fence();
+	if (!f2) {
+		dma_fence_put(f1);
+		return -ENOMEM;
+	}
+
+	array = mock_array(2, f1, f2);
+	if (!array)
+		return -ENOMEM;
+
+	chain = mock_chain(NULL, array);
+	if (!chain)
+		return -ENOMEM;
+
+	dma_fence_unwrap_for_each(fence, &iter, chain) {
+		if (fence == f1) {
+			f1 = NULL;
+		} else if (fence == f2) {
+			f2 = NULL;
+		} else {
+			pr_err("Unexpected fence!\n");
+			err = -EINVAL;
+		}
+	}
+
+	if (f1 || f2) {
+		pr_err("Not all fences seen!\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_signal(f1);
+	dma_fence_signal(f2);
+	dma_fence_put(chain);
+	return 0;
+}
+
+int dma_fence_unwrap(void)
+{
+	static const struct subtest tests[] = {
+		SUBTEST(sanitycheck),
+		SUBTEST(unwrap_array),
+		SUBTEST(unwrap_chain),
+		SUBTEST(unwrap_chain_array),
+	};
+	int ret;
+
+	slab_fences = KMEM_CACHE(mock_fence,
+				 SLAB_TYPESAFE_BY_RCU |
+				 SLAB_HWCACHE_ALIGN);
+	if (!slab_fences)
+		return -ENOMEM;
+
+	ret = subtests(tests, NULL);
+
+	kmem_cache_destroy(slab_fences);
+	return ret;
+}
diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
new file mode 100644
index 000000000000..54963df00c98
--- /dev/null
+++ b/include/linux/dma-fence-unwrap.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * fence-chain: chain fences together in a timeline
+ *
+ * Copyright (C) 2022 Advanced Micro Devices, Inc.
+ * Authors:
+ *	Christian König <christian.koenig@amd.com>
+ */
+
+#ifndef __LINUX_DMA_FENCE_UNWRAP_H
+#define __LINUX_DMA_FENCE_UNWRAP_H
+
+#include <linux/dma-fence-chain.h>
+#include <linux/dma-fence-array.h>
+
+/**
+ * struct dma_fence_unwrap - cursor into the container structure
+ */
+struct dma_fence_unwrap {
+	/**
+	 * @chain: potential dma_fence_chain, but can be other fence as well
+	 */
+	struct dma_fence *chain;
+	/**
+	 * @array: potential dma_fence_array, but can be other fence as well
+	 */
+	struct dma_fence *array;
+	/**
+	 * @index: last returned index if @array is really a dma_fence_array
+	 */
+	unsigned int index;
+};
+
+/**
+ * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
+ * @cursor: cursor to initialize
+ *
+ * Helper function to unwrap dma_fence_array containers, don't touch directly.
+ * Use dma_fence_unwrap_first/next instead.
+ */
+static inline struct dma_fence *
+dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
+{
+	cursor->array = dma_fence_chain_contained(cursor->chain);
+	cursor->index = 0;
+	return dma_fence_array_first(cursor->array);
+}
+
+/**
+ * dma_fence_unwrap_first - return the first fence from fence containers
+ * @head: the entrypoint into the containers
+ * @cursor: current position inside the containers
+ *
+ * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
+ * first fence.
+ */
+static inline struct dma_fence *
+dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
+{
+	cursor->chain = dma_fence_get(head);
+	return dma_fence_unwrap_array(cursor);
+}
+
+/**
+ * dma_fence_unwrap_next - return the next fence from a fence containers
+ * @cursor: current position inside the containers
+ *
+ * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
+ * the next fence from them.
+ */
+static inline struct dma_fence *
+dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
+{
+	struct dma_fence *tmp;
+
+	++cursor->index;
+	tmp = dma_fence_array_next(cursor->array, cursor->index);
+	if (tmp)
+		return tmp;
+
+	cursor->chain = dma_fence_chain_walk(cursor->chain);
+	return dma_fence_unwrap_array(cursor);
+}
+
+/**
+ * dma_fence_unwrap_for_each - iterate over all fences in containers
+ * @fence: current fence
+ * @cursor: current position inside the containers
+ * @head: starting point for the iterator
+ *
+ * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
+ * potential fences in them. If @head is just a normal fence only that one is
+ * returned.
+ */
+#define dma_fence_unwrap_for_each(fence, cursor, head)			\
+	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
+	     fence = dma_fence_unwrap_next(cursor))
+
+#endif
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers
  2022-03-11 11:02 [PATCH 1/2] dma-buf: add dma_fence_unwrap Christian König
@ 2022-03-11 11:02 ` Christian König
  2022-03-11 16:16   ` kernel test robot
                     ` (3 more replies)
  2022-03-11 15:45 ` [PATCH 1/2] dma-buf: add dma_fence_unwrap kernel test robot
                   ` (4 subsequent siblings)
  5 siblings, 4 replies; 40+ messages in thread
From: Christian König @ 2022-03-11 11:02 UTC (permalink / raw)
  To: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig
  Cc: Christian König

The dma_fence_chain containers can show up in sync_files as well resulting in
warnings that those can't be added to dma_fence_array containers when merging
multiple sync_files together.

Solve this by using the dma_fence_unwrap iterator to deep dive into the
contained fences and then add those flatten out into a dma_fence_array.

Signed-off-by: Christian König <christian.koenig@amd.com>
---
 drivers/dma-buf/sync_file.c | 141 +++++++++++++++++++-----------------
 1 file changed, 73 insertions(+), 68 deletions(-)

diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
index 394e6e1e9686..b8dea4ec123b 100644
--- a/drivers/dma-buf/sync_file.c
+++ b/drivers/dma-buf/sync_file.c
@@ -5,6 +5,7 @@
  * Copyright (C) 2012 Google, Inc.
  */
 
+#include <linux/dma-fence-unwrap.h>
 #include <linux/export.h>
 #include <linux/file.h>
 #include <linux/fs.h>
@@ -172,20 +173,6 @@ static int sync_file_set_fence(struct sync_file *sync_file,
 	return 0;
 }
 
-static struct dma_fence **get_fences(struct sync_file *sync_file,
-				     int *num_fences)
-{
-	if (dma_fence_is_array(sync_file->fence)) {
-		struct dma_fence_array *array = to_dma_fence_array(sync_file->fence);
-
-		*num_fences = array->num_fences;
-		return array->fences;
-	}
-
-	*num_fences = 1;
-	return &sync_file->fence;
-}
-
 static void add_fence(struct dma_fence **fences,
 		      int *i, struct dma_fence *fence)
 {
@@ -210,86 +197,97 @@ static void add_fence(struct dma_fence **fences,
 static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
 					 struct sync_file *b)
 {
+	struct dma_fence *a_fence, *b_fence, **fences;
+	struct dma_fence_unwrap a_iter, b_iter;
+	unsigned int index, num_fences;
 	struct sync_file *sync_file;
-	struct dma_fence **fences = NULL, **nfences, **a_fences, **b_fences;
-	int i = 0, i_a, i_b, num_fences, a_num_fences, b_num_fences;
 
 	sync_file = sync_file_alloc();
 	if (!sync_file)
 		return NULL;
 
-	a_fences = get_fences(a, &a_num_fences);
-	b_fences = get_fences(b, &b_num_fences);
-	if (a_num_fences > INT_MAX - b_num_fences)
-		goto err;
+	num_fences = 0;
+	dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence)
+		++num_fences;
+	dma_fence_unwrap_for_each(b_fence, &b_iter, b->fence)
+		++num_fences;
 
-	num_fences = a_num_fences + b_num_fences;
+	if (num_fences > INT_MAX)
+		goto err_free_sync_file;
 
 	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
 	if (!fences)
-		goto err;
+		goto err_free_sync_file;
 
 	/*
-	 * Assume sync_file a and b are both ordered and have no
-	 * duplicates with the same context.
+	 * We can't guarantee that fences in both a and b are ordered, but it is
+	 * still quite likely.
 	 *
-	 * If a sync_file can only be created with sync_file_merge
-	 * and sync_file_create, this is a reasonable assumption.
+	 * So attempt to order the fences as we pass over them and merge fences
+	 * with the same context.
 	 */
-	for (i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
-		struct dma_fence *pt_a = a_fences[i_a];
-		struct dma_fence *pt_b = b_fences[i_b];
 
-		if (pt_a->context < pt_b->context) {
-			add_fence(fences, &i, pt_a);
+	index = 0;
+	for (a_fence = dma_fence_unwrap_first(a->fence, &a_iter),
+	     b_fence = dma_fence_unwrap_first(b->fence, &b_iter);
+	     a_fence || b_fence; ) {
+
+		if (!b_fence) {
+			add_fence(fences, &index, a_fence);
+			a_fence = dma_fence_unwrap_next(&a_iter);
+
+		} else if (!a_fence) {
+			add_fence(fences, &index, b_fence);
+			b_fence = dma_fence_unwrap_next(&b_iter);
+
+		} else if (a_fence->context < b_fence->context) {
+			add_fence(fences, &index, a_fence);
+			a_fence = dma_fence_unwrap_next(&a_iter);
 
-			i_a++;
-		} else if (pt_a->context > pt_b->context) {
-			add_fence(fences, &i, pt_b);
+		} else if (b_fence->context < a_fence->context) {
+			add_fence(fences, &index, b_fence);
+			b_fence = dma_fence_unwrap_next(&b_iter);
+
+		} else if (__dma_fence_is_later(a_fence->seqno, b_fence->seqno,
+						a_fence->ops)) {
+			add_fence(fences, &index, a_fence);
+			a_fence = dma_fence_unwrap_next(&a_iter);
+			b_fence = dma_fence_unwrap_next(&b_iter);
 
-			i_b++;
 		} else {
-			if (__dma_fence_is_later(pt_a->seqno, pt_b->seqno,
-						 pt_a->ops))
-				add_fence(fences, &i, pt_a);
-			else
-				add_fence(fences, &i, pt_b);
-
-			i_a++;
-			i_b++;
+			add_fence(fences, &index, b_fence);
+			a_fence = dma_fence_unwrap_next(&a_iter);
+			b_fence = dma_fence_unwrap_next(&b_iter);
 		}
 	}
 
-	for (; i_a < a_num_fences; i_a++)
-		add_fence(fences, &i, a_fences[i_a]);
-
-	for (; i_b < b_num_fences; i_b++)
-		add_fence(fences, &i, b_fences[i_b]);
-
-	if (i == 0)
-		fences[i++] = dma_fence_get(a_fences[0]);
+	if (index == 0)
+		add_fence(fences, &index, dma_fence_get_stub());
 
-	if (num_fences > i) {
-		nfences = krealloc_array(fences, i, sizeof(*fences), GFP_KERNEL);
-		if (!nfences)
-			goto err;
+	if (num_fences > index) {
+		struct dma_fence **tmp;
 
-		fences = nfences;
+		/* Keep going even when reducing the size failed */
+		tmp = krealloc_array(fences, index, sizeof(*fences),
+				     GFP_KERNEL);
+		if (tmp)
+			fences = tmp;
 	}
 
-	if (sync_file_set_fence(sync_file, fences, i) < 0)
-		goto err;
+	if (sync_file_set_fence(sync_file, fences, index) < 0)
+		goto err_put_fences;
 
 	strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
 	return sync_file;
 
-err:
-	while (i)
-		dma_fence_put(fences[--i]);
+err_put_fences:
+	while (index)
+		dma_fence_put(fences[--index]);
 	kfree(fences);
+
+err_free_sync_file:
 	fput(sync_file->file);
 	return NULL;
-
 }
 
 static int sync_file_release(struct inode *inode, struct file *file)
@@ -398,11 +396,13 @@ static int sync_fill_fence_info(struct dma_fence *fence,
 static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
 				       unsigned long arg)
 {
-	struct sync_file_info info;
 	struct sync_fence_info *fence_info = NULL;
-	struct dma_fence **fences;
+	struct dma_fence_unwrap iter;
+	struct sync_file_info info;
+	unsigned int num_fences;
+	struct dma_fence *fence;
+	int ret;
 	__u32 size;
-	int num_fences, ret, i;
 
 	if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
 		return -EFAULT;
@@ -410,7 +410,9 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
 	if (info.flags || info.pad)
 		return -EINVAL;
 
-	fences = get_fences(sync_file, &num_fences);
+	num_fences = 0;
+	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence)
+		++num_fences;
 
 	/*
 	 * Passing num_fences = 0 means that userspace doesn't want to
@@ -433,8 +435,11 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
 	if (!fence_info)
 		return -ENOMEM;
 
-	for (i = 0; i < num_fences; i++) {
-		int status = sync_fill_fence_info(fences[i], &fence_info[i]);
+	num_fences = 0;
+	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) {
+		int status;
+
+		status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
 		info.status = info.status <= 0 ? info.status : status;
 	}
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-11 11:02 [PATCH 1/2] dma-buf: add dma_fence_unwrap Christian König
  2022-03-11 11:02 ` [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers Christian König
@ 2022-03-11 15:45 ` kernel test robot
  2022-03-11 17:28 ` kernel test robot
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2022-03-11 15:45 UTC (permalink / raw)
  To: Christian König, sumit.semwal, gustavo, linux-media,
	dri-devel, linaro-mm-sig
  Cc: kbuild-all, Christian König

Hi "Christian,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.17-rc7 next-20220310]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Christian-K-nig/dma-buf-add-dma_fence_unwrap/20220311-190352
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 79b00034e9dcd2b065c1665c8b42f62b6b80a9be
config: microblaze-randconfig-r011-20220310 (https://download.01.org/0day-ci/archive/20220311/202203112305.WcEordi2-lkp@intel.com/config)
compiler: microblaze-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/088aa14c0f5cad378854823fa661ee145dd2c01b
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Christian-K-nig/dma-buf-add-dma_fence_unwrap/20220311-190352
        git checkout 088aa14c0f5cad378854823fa661ee145dd2c01b
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=microblaze SHELL=/bin/bash drivers/dma-buf/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from drivers/dma-buf/st-dma-fence-unwrap.c:7:
   include/linux/dma-fence-unwrap.h: In function 'dma_fence_unwrap_array':
   include/linux/dma-fence-unwrap.h:44:25: error: implicit declaration of function 'dma_fence_chain_contained'; did you mean 'dma_fence_chain_init'? [-Werror=implicit-function-declaration]
      44 |         cursor->array = dma_fence_chain_contained(cursor->chain);
         |                         ^~~~~~~~~~~~~~~~~~~~~~~~~
         |                         dma_fence_chain_init
   include/linux/dma-fence-unwrap.h:44:23: warning: assignment to 'struct dma_fence *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
      44 |         cursor->array = dma_fence_chain_contained(cursor->chain);
         |                       ^
   include/linux/dma-fence-unwrap.h:46:16: error: implicit declaration of function 'dma_fence_array_first'; did you mean 'dma_fence_array_create'? [-Werror=implicit-function-declaration]
      46 |         return dma_fence_array_first(cursor->array);
         |                ^~~~~~~~~~~~~~~~~~~~~
         |                dma_fence_array_create
   include/linux/dma-fence-unwrap.h:46:16: warning: returning 'int' from a function with return type 'struct dma_fence *' makes pointer from integer without a cast [-Wint-conversion]
      46 |         return dma_fence_array_first(cursor->array);
         |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dma-fence-unwrap.h: In function 'dma_fence_unwrap_next':
   include/linux/dma-fence-unwrap.h:77:15: error: implicit declaration of function 'dma_fence_array_next'; did you mean 'dma_fence_unwrap_next'? [-Werror=implicit-function-declaration]
      77 |         tmp = dma_fence_array_next(cursor->array, cursor->index);
         |               ^~~~~~~~~~~~~~~~~~~~
         |               dma_fence_unwrap_next
   include/linux/dma-fence-unwrap.h:77:13: warning: assignment to 'struct dma_fence *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
      77 |         tmp = dma_fence_array_next(cursor->array, cursor->index);
         |             ^
   drivers/dma-buf/st-dma-fence-unwrap.c: In function 'unwrap_array':
>> drivers/dma-buf/st-dma-fence-unwrap.c:133:13: warning: variable 'err' set but not used [-Wunused-but-set-variable]
     133 |         int err = 0;
         |             ^~~
   drivers/dma-buf/st-dma-fence-unwrap.c: In function 'unwrap_chain':
   drivers/dma-buf/st-dma-fence-unwrap.c:175:13: warning: variable 'err' set but not used [-Wunused-but-set-variable]
     175 |         int err = 0;
         |             ^~~
   drivers/dma-buf/st-dma-fence-unwrap.c: In function 'unwrap_chain_array':
   drivers/dma-buf/st-dma-fence-unwrap.c:217:13: warning: variable 'err' set but not used [-Wunused-but-set-variable]
     217 |         int err = 0;
         |             ^~~
   cc1: some warnings being treated as errors


vim +/err +133 drivers/dma-buf/st-dma-fence-unwrap.c

   128	
   129	static int unwrap_array(void *arg)
   130	{
   131		struct dma_fence *fence, *f1, *f2, *array;
   132		struct dma_fence_unwrap iter;
 > 133		int err = 0;
   134	
   135		f1 = mock_fence();
   136		if (!f1)
   137			return -ENOMEM;
   138	
   139		f2 = mock_fence();
   140		if (!f2) {
   141			dma_fence_put(f1);
   142			return -ENOMEM;
   143		}
   144	
   145		array = mock_array(2, f1, f2);
   146		if (!array)
   147			return -ENOMEM;
   148	
   149		dma_fence_unwrap_for_each(fence, &iter, array) {
   150			if (fence == f1) {
   151				f1 = NULL;
   152			} else if (fence == f2) {
   153				f2 = NULL;
   154			} else {
   155				pr_err("Unexpected fence!\n");
   156				err = -EINVAL;
   157			}
   158		}
   159	
   160		if (f1 || f2) {
   161			pr_err("Not all fences seen!\n");
   162			err = -EINVAL;
   163		}
   164	
   165		dma_fence_signal(f1);
   166		dma_fence_signal(f2);
   167		dma_fence_put(array);
   168		return 0;
   169	}
   170	

---
0-DAY CI Kernel Test Service
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers
  2022-03-11 11:02 ` [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers Christian König
@ 2022-03-11 16:16   ` kernel test robot
  2022-03-11 17:59   ` kernel test robot
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2022-03-11 16:16 UTC (permalink / raw)
  To: Christian König, sumit.semwal, gustavo, linux-media,
	dri-devel, linaro-mm-sig
  Cc: kbuild-all, Christian König

Hi "Christian,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.17-rc7 next-20220310]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Christian-K-nig/dma-buf-add-dma_fence_unwrap/20220311-190352
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 79b00034e9dcd2b065c1665c8b42f62b6b80a9be
config: x86_64-randconfig-m001 (https://download.01.org/0day-ci/archive/20220312/202203120047.SyXpIs6H-lkp@intel.com/config)
compiler: gcc-9 (Ubuntu 9.4.0-1ubuntu1~20.04) 9.4.0
reproduce (this is a W=1 build):
        # https://github.com/0day-ci/linux/commit/ca3584ac05c4a450e69b1c6bcb0672b5ab026c7c
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Christian-K-nig/dma-buf-add-dma_fence_unwrap/20220311-190352
        git checkout ca3584ac05c4a450e69b1c6bcb0672b5ab026c7c
        # save the config file to linux build tree
        mkdir build_dir
        make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/dma-buf/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from drivers/dma-buf/sync_file.c:8:
   include/linux/dma-fence-unwrap.h: In function 'dma_fence_unwrap_array':
   include/linux/dma-fence-unwrap.h:44:18: error: implicit declaration of function 'dma_fence_chain_contained'; did you mean 'dma_fence_chain_init'? [-Werror=implicit-function-declaration]
      44 |  cursor->array = dma_fence_chain_contained(cursor->chain);
         |                  ^~~~~~~~~~~~~~~~~~~~~~~~~
         |                  dma_fence_chain_init
>> include/linux/dma-fence-unwrap.h:44:16: warning: assignment to 'struct dma_fence *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
      44 |  cursor->array = dma_fence_chain_contained(cursor->chain);
         |                ^
   include/linux/dma-fence-unwrap.h:46:9: error: implicit declaration of function 'dma_fence_array_first'; did you mean 'dma_fence_array_create'? [-Werror=implicit-function-declaration]
      46 |  return dma_fence_array_first(cursor->array);
         |         ^~~~~~~~~~~~~~~~~~~~~
         |         dma_fence_array_create
>> include/linux/dma-fence-unwrap.h:46:9: warning: returning 'int' from a function with return type 'struct dma_fence *' makes pointer from integer without a cast [-Wint-conversion]
      46 |  return dma_fence_array_first(cursor->array);
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dma-fence-unwrap.h: In function 'dma_fence_unwrap_next':
   include/linux/dma-fence-unwrap.h:77:8: error: implicit declaration of function 'dma_fence_array_next'; did you mean 'dma_fence_unwrap_next'? [-Werror=implicit-function-declaration]
      77 |  tmp = dma_fence_array_next(cursor->array, cursor->index);
         |        ^~~~~~~~~~~~~~~~~~~~
         |        dma_fence_unwrap_next
   include/linux/dma-fence-unwrap.h:77:6: warning: assignment to 'struct dma_fence *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
      77 |  tmp = dma_fence_array_next(cursor->array, cursor->index);
         |      ^
   cc1: some warnings being treated as errors


vim +44 include/linux/dma-fence-unwrap.h

088aa14c0f5cad Christian König 2022-03-11  33  
088aa14c0f5cad Christian König 2022-03-11  34  /**
088aa14c0f5cad Christian König 2022-03-11  35   * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
088aa14c0f5cad Christian König 2022-03-11  36   * @cursor: cursor to initialize
088aa14c0f5cad Christian König 2022-03-11  37   *
088aa14c0f5cad Christian König 2022-03-11  38   * Helper function to unwrap dma_fence_array containers, don't touch directly.
088aa14c0f5cad Christian König 2022-03-11  39   * Use dma_fence_unwrap_first/next instead.
088aa14c0f5cad Christian König 2022-03-11  40   */
088aa14c0f5cad Christian König 2022-03-11  41  static inline struct dma_fence *
088aa14c0f5cad Christian König 2022-03-11  42  dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
088aa14c0f5cad Christian König 2022-03-11  43  {
088aa14c0f5cad Christian König 2022-03-11 @44  	cursor->array = dma_fence_chain_contained(cursor->chain);
088aa14c0f5cad Christian König 2022-03-11  45  	cursor->index = 0;
088aa14c0f5cad Christian König 2022-03-11 @46  	return dma_fence_array_first(cursor->array);
088aa14c0f5cad Christian König 2022-03-11  47  }
088aa14c0f5cad Christian König 2022-03-11  48  

---
0-DAY CI Kernel Test Service
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-11 11:02 [PATCH 1/2] dma-buf: add dma_fence_unwrap Christian König
  2022-03-11 11:02 ` [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers Christian König
  2022-03-11 15:45 ` [PATCH 1/2] dma-buf: add dma_fence_unwrap kernel test robot
@ 2022-03-11 17:28 ` kernel test robot
  2022-03-14 11:14 ` Christian König
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2022-03-11 17:28 UTC (permalink / raw)
  To: Christian König, sumit.semwal, gustavo, linux-media,
	dri-devel, linaro-mm-sig
  Cc: llvm, kbuild-all, Christian König

Hi "Christian,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.17-rc7 next-20220310]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Christian-K-nig/dma-buf-add-dma_fence_unwrap/20220311-190352
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 79b00034e9dcd2b065c1665c8b42f62b6b80a9be
config: hexagon-randconfig-r045-20220310 (https://download.01.org/0day-ci/archive/20220312/202203120114.jpyQmShC-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 276ca87382b8f16a65bddac700202924228982f6)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/088aa14c0f5cad378854823fa661ee145dd2c01b
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Christian-K-nig/dma-buf-add-dma_fence_unwrap/20220311-190352
        git checkout 088aa14c0f5cad378854823fa661ee145dd2c01b
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash drivers/dma-buf/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from drivers/dma-buf/st-dma-fence-unwrap.c:7:
   include/linux/dma-fence-unwrap.h:44:18: error: implicit declaration of function 'dma_fence_chain_contained' [-Werror,-Wimplicit-function-declaration]
           cursor->array = dma_fence_chain_contained(cursor->chain);
                           ^
   include/linux/dma-fence-unwrap.h:44:18: note: did you mean 'dma_fence_chain_init'?
   include/linux/dma-fence-chain.h:108:6: note: 'dma_fence_chain_init' declared here
   void dma_fence_chain_init(struct dma_fence_chain *chain,
        ^
   In file included from drivers/dma-buf/st-dma-fence-unwrap.c:7:
>> include/linux/dma-fence-unwrap.h:44:16: warning: incompatible integer to pointer conversion assigning to 'struct dma_fence *' from 'int' [-Wint-conversion]
           cursor->array = dma_fence_chain_contained(cursor->chain);
                         ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dma-fence-unwrap.h:46:9: error: implicit declaration of function 'dma_fence_array_first' [-Werror,-Wimplicit-function-declaration]
           return dma_fence_array_first(cursor->array);
                  ^
   include/linux/dma-fence-unwrap.h:46:9: note: did you mean 'dma_fence_array_create'?
   include/linux/dma-fence-array.h:77:25: note: 'dma_fence_array_create' declared here
   struct dma_fence_array *dma_fence_array_create(int num_fences,
                           ^
   In file included from drivers/dma-buf/st-dma-fence-unwrap.c:7:
>> include/linux/dma-fence-unwrap.h:46:9: warning: incompatible integer to pointer conversion returning 'int' from a function with result type 'struct dma_fence *' [-Wint-conversion]
           return dma_fence_array_first(cursor->array);
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dma-fence-unwrap.h:77:8: error: implicit declaration of function 'dma_fence_array_next' [-Werror,-Wimplicit-function-declaration]
           tmp = dma_fence_array_next(cursor->array, cursor->index);
                 ^
   include/linux/dma-fence-unwrap.h:77:6: warning: incompatible integer to pointer conversion assigning to 'struct dma_fence *' from 'int' [-Wint-conversion]
           tmp = dma_fence_array_next(cursor->array, cursor->index);
               ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> drivers/dma-buf/st-dma-fence-unwrap.c:133:6: warning: variable 'err' set but not used [-Wunused-but-set-variable]
           int err = 0;
               ^
   drivers/dma-buf/st-dma-fence-unwrap.c:175:6: warning: variable 'err' set but not used [-Wunused-but-set-variable]
           int err = 0;
               ^
   drivers/dma-buf/st-dma-fence-unwrap.c:217:6: warning: variable 'err' set but not used [-Wunused-but-set-variable]
           int err = 0;
               ^
   6 warnings and 3 errors generated.


vim +44 include/linux/dma-fence-unwrap.h

    33	
    34	/**
    35	 * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
    36	 * @cursor: cursor to initialize
    37	 *
    38	 * Helper function to unwrap dma_fence_array containers, don't touch directly.
    39	 * Use dma_fence_unwrap_first/next instead.
    40	 */
    41	static inline struct dma_fence *
    42	dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
    43	{
  > 44		cursor->array = dma_fence_chain_contained(cursor->chain);
    45		cursor->index = 0;
  > 46		return dma_fence_array_first(cursor->array);
    47	}
    48	

---
0-DAY CI Kernel Test Service
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers
  2022-03-11 11:02 ` [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers Christian König
  2022-03-11 16:16   ` kernel test robot
@ 2022-03-11 17:59   ` kernel test robot
  2022-03-11 18:51   ` kernel test robot
  2022-03-25 10:13     ` Daniel Vetter
  3 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2022-03-11 17:59 UTC (permalink / raw)
  To: Christian König, sumit.semwal, gustavo, linux-media,
	dri-devel, linaro-mm-sig
  Cc: llvm, kbuild-all, Christian König

Hi "Christian,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.17-rc7 next-20220310]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Christian-K-nig/dma-buf-add-dma_fence_unwrap/20220311-190352
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 79b00034e9dcd2b065c1665c8b42f62b6b80a9be
config: arm64-randconfig-r014-20220310 (https://download.01.org/0day-ci/archive/20220312/202203120115.Qe4GABIV-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 276ca87382b8f16a65bddac700202924228982f6)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm64 cross compiling tool for clang build
        # apt-get install binutils-aarch64-linux-gnu
        # https://github.com/0day-ci/linux/commit/ca3584ac05c4a450e69b1c6bcb0672b5ab026c7c
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Christian-K-nig/dma-buf-add-dma_fence_unwrap/20220311-190352
        git checkout ca3584ac05c4a450e69b1c6bcb0672b5ab026c7c
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash drivers/dma-buf/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   In file included from drivers/dma-buf/sync_file.c:8:
   include/linux/dma-fence-unwrap.h:44:18: error: implicit declaration of function 'dma_fence_chain_contained' [-Werror,-Wimplicit-function-declaration]
           cursor->array = dma_fence_chain_contained(cursor->chain);
                           ^
   include/linux/dma-fence-unwrap.h:44:18: note: did you mean 'dma_fence_chain_init'?
   include/linux/dma-fence-chain.h:108:6: note: 'dma_fence_chain_init' declared here
   void dma_fence_chain_init(struct dma_fence_chain *chain,
        ^
   In file included from drivers/dma-buf/sync_file.c:8:
>> include/linux/dma-fence-unwrap.h:44:16: warning: incompatible integer to pointer conversion assigning to 'struct dma_fence *' from 'int' [-Wint-conversion]
           cursor->array = dma_fence_chain_contained(cursor->chain);
                         ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dma-fence-unwrap.h:46:9: error: implicit declaration of function 'dma_fence_array_first' [-Werror,-Wimplicit-function-declaration]
           return dma_fence_array_first(cursor->array);
                  ^
   include/linux/dma-fence-unwrap.h:46:9: note: did you mean 'dma_fence_array_create'?
   include/linux/dma-fence-array.h:77:25: note: 'dma_fence_array_create' declared here
   struct dma_fence_array *dma_fence_array_create(int num_fences,
                           ^
   In file included from drivers/dma-buf/sync_file.c:8:
>> include/linux/dma-fence-unwrap.h:46:9: warning: incompatible integer to pointer conversion returning 'int' from a function with result type 'struct dma_fence *' [-Wint-conversion]
           return dma_fence_array_first(cursor->array);
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dma-fence-unwrap.h:77:8: error: implicit declaration of function 'dma_fence_array_next' [-Werror,-Wimplicit-function-declaration]
           tmp = dma_fence_array_next(cursor->array, cursor->index);
                 ^
   include/linux/dma-fence-unwrap.h:77:6: warning: incompatible integer to pointer conversion assigning to 'struct dma_fence *' from 'int' [-Wint-conversion]
           tmp = dma_fence_array_next(cursor->array, cursor->index);
               ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   3 warnings and 3 errors generated.


vim +44 include/linux/dma-fence-unwrap.h

088aa14c0f5cad Christian König 2022-03-11  33  
088aa14c0f5cad Christian König 2022-03-11  34  /**
088aa14c0f5cad Christian König 2022-03-11  35   * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
088aa14c0f5cad Christian König 2022-03-11  36   * @cursor: cursor to initialize
088aa14c0f5cad Christian König 2022-03-11  37   *
088aa14c0f5cad Christian König 2022-03-11  38   * Helper function to unwrap dma_fence_array containers, don't touch directly.
088aa14c0f5cad Christian König 2022-03-11  39   * Use dma_fence_unwrap_first/next instead.
088aa14c0f5cad Christian König 2022-03-11  40   */
088aa14c0f5cad Christian König 2022-03-11  41  static inline struct dma_fence *
088aa14c0f5cad Christian König 2022-03-11  42  dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
088aa14c0f5cad Christian König 2022-03-11  43  {
088aa14c0f5cad Christian König 2022-03-11 @44  	cursor->array = dma_fence_chain_contained(cursor->chain);
088aa14c0f5cad Christian König 2022-03-11  45  	cursor->index = 0;
088aa14c0f5cad Christian König 2022-03-11 @46  	return dma_fence_array_first(cursor->array);
088aa14c0f5cad Christian König 2022-03-11  47  }
088aa14c0f5cad Christian König 2022-03-11  48  

---
0-DAY CI Kernel Test Service
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers
  2022-03-11 11:02 ` [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers Christian König
  2022-03-11 16:16   ` kernel test robot
  2022-03-11 17:59   ` kernel test robot
@ 2022-03-11 18:51   ` kernel test robot
  2022-03-25 10:13     ` Daniel Vetter
  3 siblings, 0 replies; 40+ messages in thread
From: kernel test robot @ 2022-03-11 18:51 UTC (permalink / raw)
  To: Christian König, sumit.semwal, gustavo, linux-media,
	dri-devel, linaro-mm-sig
  Cc: kbuild-all, Christian König

Hi "Christian,

I love your patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v5.17-rc7 next-20220310]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Christian-K-nig/dma-buf-add-dma_fence_unwrap/20220311-190352
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 79b00034e9dcd2b065c1665c8b42f62b6b80a9be
config: x86_64-randconfig-m001 (https://download.01.org/0day-ci/archive/20220312/202203120217.BFa438j9-lkp@intel.com/config)
compiler: gcc-9 (Ubuntu 9.4.0-1ubuntu1~20.04) 9.4.0
reproduce (this is a W=1 build):
        # https://github.com/0day-ci/linux/commit/ca3584ac05c4a450e69b1c6bcb0672b5ab026c7c
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Christian-K-nig/dma-buf-add-dma_fence_unwrap/20220311-190352
        git checkout ca3584ac05c4a450e69b1c6bcb0672b5ab026c7c
        # save the config file to linux build tree
        mkdir build_dir
        make W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   In file included from drivers/dma-buf/sync_file.c:8:
   include/linux/dma-fence-unwrap.h: In function 'dma_fence_unwrap_array':
>> include/linux/dma-fence-unwrap.h:44:18: error: implicit declaration of function 'dma_fence_chain_contained'; did you mean 'dma_fence_chain_init'? [-Werror=implicit-function-declaration]
      44 |  cursor->array = dma_fence_chain_contained(cursor->chain);
         |                  ^~~~~~~~~~~~~~~~~~~~~~~~~
         |                  dma_fence_chain_init
   include/linux/dma-fence-unwrap.h:44:16: warning: assignment to 'struct dma_fence *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
      44 |  cursor->array = dma_fence_chain_contained(cursor->chain);
         |                ^
>> include/linux/dma-fence-unwrap.h:46:9: error: implicit declaration of function 'dma_fence_array_first'; did you mean 'dma_fence_array_create'? [-Werror=implicit-function-declaration]
      46 |  return dma_fence_array_first(cursor->array);
         |         ^~~~~~~~~~~~~~~~~~~~~
         |         dma_fence_array_create
   include/linux/dma-fence-unwrap.h:46:9: warning: returning 'int' from a function with return type 'struct dma_fence *' makes pointer from integer without a cast [-Wint-conversion]
      46 |  return dma_fence_array_first(cursor->array);
         |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dma-fence-unwrap.h: In function 'dma_fence_unwrap_next':
>> include/linux/dma-fence-unwrap.h:77:8: error: implicit declaration of function 'dma_fence_array_next'; did you mean 'dma_fence_unwrap_next'? [-Werror=implicit-function-declaration]
      77 |  tmp = dma_fence_array_next(cursor->array, cursor->index);
         |        ^~~~~~~~~~~~~~~~~~~~
         |        dma_fence_unwrap_next
   include/linux/dma-fence-unwrap.h:77:6: warning: assignment to 'struct dma_fence *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
      77 |  tmp = dma_fence_array_next(cursor->array, cursor->index);
         |      ^
   cc1: some warnings being treated as errors


vim +44 include/linux/dma-fence-unwrap.h

088aa14c0f5cad Christian König 2022-03-11  33  
088aa14c0f5cad Christian König 2022-03-11  34  /**
088aa14c0f5cad Christian König 2022-03-11  35   * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
088aa14c0f5cad Christian König 2022-03-11  36   * @cursor: cursor to initialize
088aa14c0f5cad Christian König 2022-03-11  37   *
088aa14c0f5cad Christian König 2022-03-11  38   * Helper function to unwrap dma_fence_array containers, don't touch directly.
088aa14c0f5cad Christian König 2022-03-11  39   * Use dma_fence_unwrap_first/next instead.
088aa14c0f5cad Christian König 2022-03-11  40   */
088aa14c0f5cad Christian König 2022-03-11  41  static inline struct dma_fence *
088aa14c0f5cad Christian König 2022-03-11  42  dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
088aa14c0f5cad Christian König 2022-03-11  43  {
088aa14c0f5cad Christian König 2022-03-11 @44  	cursor->array = dma_fence_chain_contained(cursor->chain);
088aa14c0f5cad Christian König 2022-03-11  45  	cursor->index = 0;
088aa14c0f5cad Christian König 2022-03-11 @46  	return dma_fence_array_first(cursor->array);
088aa14c0f5cad Christian König 2022-03-11  47  }
088aa14c0f5cad Christian König 2022-03-11  48  
088aa14c0f5cad Christian König 2022-03-11  49  /**
088aa14c0f5cad Christian König 2022-03-11  50   * dma_fence_unwrap_first - return the first fence from fence containers
088aa14c0f5cad Christian König 2022-03-11  51   * @head: the entrypoint into the containers
088aa14c0f5cad Christian König 2022-03-11  52   * @cursor: current position inside the containers
088aa14c0f5cad Christian König 2022-03-11  53   *
088aa14c0f5cad Christian König 2022-03-11  54   * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
088aa14c0f5cad Christian König 2022-03-11  55   * first fence.
088aa14c0f5cad Christian König 2022-03-11  56   */
088aa14c0f5cad Christian König 2022-03-11  57  static inline struct dma_fence *
088aa14c0f5cad Christian König 2022-03-11  58  dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
088aa14c0f5cad Christian König 2022-03-11  59  {
088aa14c0f5cad Christian König 2022-03-11  60  	cursor->chain = dma_fence_get(head);
088aa14c0f5cad Christian König 2022-03-11  61  	return dma_fence_unwrap_array(cursor);
088aa14c0f5cad Christian König 2022-03-11  62  }
088aa14c0f5cad Christian König 2022-03-11  63  
088aa14c0f5cad Christian König 2022-03-11  64  /**
088aa14c0f5cad Christian König 2022-03-11  65   * dma_fence_unwrap_next - return the next fence from a fence containers
088aa14c0f5cad Christian König 2022-03-11  66   * @cursor: current position inside the containers
088aa14c0f5cad Christian König 2022-03-11  67   *
088aa14c0f5cad Christian König 2022-03-11  68   * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
088aa14c0f5cad Christian König 2022-03-11  69   * the next fence from them.
088aa14c0f5cad Christian König 2022-03-11  70   */
088aa14c0f5cad Christian König 2022-03-11  71  static inline struct dma_fence *
088aa14c0f5cad Christian König 2022-03-11  72  dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
088aa14c0f5cad Christian König 2022-03-11  73  {
088aa14c0f5cad Christian König 2022-03-11  74  	struct dma_fence *tmp;
088aa14c0f5cad Christian König 2022-03-11  75  
088aa14c0f5cad Christian König 2022-03-11  76  	++cursor->index;
088aa14c0f5cad Christian König 2022-03-11 @77  	tmp = dma_fence_array_next(cursor->array, cursor->index);
088aa14c0f5cad Christian König 2022-03-11  78  	if (tmp)
088aa14c0f5cad Christian König 2022-03-11  79  		return tmp;
088aa14c0f5cad Christian König 2022-03-11  80  
088aa14c0f5cad Christian König 2022-03-11  81  	cursor->chain = dma_fence_chain_walk(cursor->chain);
088aa14c0f5cad Christian König 2022-03-11  82  	return dma_fence_unwrap_array(cursor);
088aa14c0f5cad Christian König 2022-03-11  83  }
088aa14c0f5cad Christian König 2022-03-11  84  

---
0-DAY CI Kernel Test Service
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-11 11:02 [PATCH 1/2] dma-buf: add dma_fence_unwrap Christian König
                   ` (2 preceding siblings ...)
  2022-03-11 17:28 ` kernel test robot
@ 2022-03-14 11:14 ` Christian König
  2022-03-21 10:31   ` Christian König
  2022-03-25 10:03   ` Daniel Vetter
  2022-03-25 15:25   ` Ville Syrjälä
  5 siblings, 1 reply; 40+ messages in thread
From: Christian König @ 2022-03-14 11:14 UTC (permalink / raw)
  To: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig,
	Alex Deucher

Just a gentle ping.

This series is an important fix for drm-misc-next-fixes.

Regards,
Christian.

Am 11.03.22 um 12:02 schrieb Christian König:
> Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
> structures and iterate over all the fences in them.
>
> This is useful when we need to flatten out all fences in those structures.
>
> Signed-off-by: Christian König <christian.koenig@amd.com>
> ---
>   Documentation/driver-api/dma-buf.rst  |   6 +
>   drivers/dma-buf/Makefile              |   1 +
>   drivers/dma-buf/selftests.h           |   1 +
>   drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
>   include/linux/dma-fence-unwrap.h      |  99 +++++++++
>   5 files changed, 386 insertions(+)
>   create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
>   create mode 100644 include/linux/dma-fence-unwrap.h
>
> diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
> index 2cd7db82d9fe..7209500f08c8 100644
> --- a/Documentation/driver-api/dma-buf.rst
> +++ b/Documentation/driver-api/dma-buf.rst
> @@ -194,6 +194,12 @@ DMA Fence Chain
>   .. kernel-doc:: include/linux/dma-fence-chain.h
>      :internal:
>   
> +DMA Fence unwrap
> +~~~~~~~~~~~~~~~~
> +
> +.. kernel-doc:: include/linux/dma-fence-unwrap.h
> +   :internal:
> +
>   DMA Fence uABI/Sync File
>   ~~~~~~~~~~~~~~~~~~~~~~~~
>   
> diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
> index 511805dbeb75..4c9eb53ba3f8 100644
> --- a/drivers/dma-buf/Makefile
> +++ b/drivers/dma-buf/Makefile
> @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
>   	selftest.o \
>   	st-dma-fence.o \
>   	st-dma-fence-chain.o \
> +	st-dma-fence-unwrap.o \
>   	st-dma-resv.o
>   
>   obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
> diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
> index 97d73aaa31da..851965867d9c 100644
> --- a/drivers/dma-buf/selftests.h
> +++ b/drivers/dma-buf/selftests.h
> @@ -12,4 +12,5 @@
>   selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
>   selftest(dma_fence, dma_fence)
>   selftest(dma_fence_chain, dma_fence_chain)
> +selftest(dma_fence_unwrap, dma_fence_unwrap)
>   selftest(dma_resv, dma_resv)
> diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
> new file mode 100644
> index 000000000000..d821faaebe93
> --- /dev/null
> +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
> @@ -0,0 +1,279 @@
> +// SPDX-License-Identifier: MIT
> +
> +/*
> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> + */
> +
> +#include <linux/dma-fence-unwrap.h>
> +#if 0
> +#include <linux/kernel.h>
> +#include <linux/kthread.h>
> +#include <linux/mm.h>
> +#include <linux/sched/signal.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/random.h>
> +#endif
> +
> +#include "selftest.h"
> +
> +#define CHAIN_SZ (4 << 10)
> +
> +static struct kmem_cache *slab_fences;
> +
> +static inline struct mock_fence {
> +	struct dma_fence base;
> +	spinlock_t lock;
> +} *to_mock_fence(struct dma_fence *f) {
> +	return container_of(f, struct mock_fence, base);
> +}
> +
> +static const char *mock_name(struct dma_fence *f)
> +{
> +	return "mock";
> +}
> +
> +static void mock_fence_release(struct dma_fence *f)
> +{
> +	kmem_cache_free(slab_fences, to_mock_fence(f));
> +}
> +
> +static const struct dma_fence_ops mock_ops = {
> +	.get_driver_name = mock_name,
> +	.get_timeline_name = mock_name,
> +	.release = mock_fence_release,
> +};
> +
> +static struct dma_fence *mock_fence(void)
> +{
> +	struct mock_fence *f;
> +
> +	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
> +	if (!f)
> +		return NULL;
> +
> +	spin_lock_init(&f->lock);
> +	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
> +
> +	return &f->base;
> +}
> +
> +static struct dma_fence *mock_array(unsigned int num_fences, ...)
> +{
> +	struct dma_fence_array *array;
> +	struct dma_fence **fences;
> +	va_list valist;
> +	int i;
> +
> +	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
> +	if (!fences)
> +		return NULL;
> +
> +	va_start(valist, num_fences);
> +	for (i = 0; i < num_fences; ++i)
> +		fences[i] = va_arg(valist, typeof(*fences));
> +	va_end(valist);
> +
> +	array = dma_fence_array_create(num_fences, fences,
> +				       dma_fence_context_alloc(1),
> +				       1, false);
> +	if (!array)
> +		goto cleanup;
> +	return &array->base;
> +
> +cleanup:
> +	for (i = 0; i < num_fences; ++i)
> +		dma_fence_put(fences[i]);
> +	kfree(fences);
> +	return NULL;
> +}
> +
> +static struct dma_fence *mock_chain(struct dma_fence *prev,
> +				    struct dma_fence *fence)
> +{
> +	struct dma_fence_chain *f;
> +
> +	f = dma_fence_chain_alloc();
> +	if (!f) {
> +		dma_fence_put(prev);
> +		dma_fence_put(fence);
> +		return NULL;
> +	}
> +
> +	dma_fence_chain_init(f, prev, fence, 1);
> +	return &f->base;
> +}
> +
> +static int sanitycheck(void *arg)
> +{
> +	struct dma_fence *f, *chain, *array;
> +	int err = 0;
> +
> +	f = mock_fence();
> +	if (!f)
> +		return -ENOMEM;
> +
> +	array = mock_array(1, f);
> +	if (!array)
> +		return -ENOMEM;
> +
> +	chain = mock_chain(NULL, array);
> +	if (!chain)
> +		return -ENOMEM;
> +
> +	dma_fence_signal(f);
> +	dma_fence_put(chain);
> +	return err;
> +}
> +
> +static int unwrap_array(void *arg)
> +{
> +	struct dma_fence *fence, *f1, *f2, *array;
> +	struct dma_fence_unwrap iter;
> +	int err = 0;
> +
> +	f1 = mock_fence();
> +	if (!f1)
> +		return -ENOMEM;
> +
> +	f2 = mock_fence();
> +	if (!f2) {
> +		dma_fence_put(f1);
> +		return -ENOMEM;
> +	}
> +
> +	array = mock_array(2, f1, f2);
> +	if (!array)
> +		return -ENOMEM;
> +
> +	dma_fence_unwrap_for_each(fence, &iter, array) {
> +		if (fence == f1) {
> +			f1 = NULL;
> +		} else if (fence == f2) {
> +			f2 = NULL;
> +		} else {
> +			pr_err("Unexpected fence!\n");
> +			err = -EINVAL;
> +		}
> +	}
> +
> +	if (f1 || f2) {
> +		pr_err("Not all fences seen!\n");
> +		err = -EINVAL;
> +	}
> +
> +	dma_fence_signal(f1);
> +	dma_fence_signal(f2);
> +	dma_fence_put(array);
> +	return 0;
> +}
> +
> +static int unwrap_chain(void *arg)
> +{
> +	struct dma_fence *fence, *f1, *f2, *chain;
> +	struct dma_fence_unwrap iter;
> +	int err = 0;
> +
> +	f1 = mock_fence();
> +	if (!f1)
> +		return -ENOMEM;
> +
> +	f2 = mock_fence();
> +	if (!f2) {
> +		dma_fence_put(f1);
> +		return -ENOMEM;
> +	}
> +
> +	chain = mock_chain(f1, f2);
> +	if (!chain)
> +		return -ENOMEM;
> +
> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> +		if (fence == f1) {
> +			f1 = NULL;
> +		} else if (fence == f2) {
> +			f2 = NULL;
> +		} else {
> +			pr_err("Unexpected fence!\n");
> +			err = -EINVAL;
> +		}
> +	}
> +
> +	if (f1 || f2) {
> +		pr_err("Not all fences seen!\n");
> +		err = -EINVAL;
> +	}
> +
> +	dma_fence_signal(f1);
> +	dma_fence_signal(f2);
> +	dma_fence_put(chain);
> +	return 0;
> +}
> +
> +static int unwrap_chain_array(void *arg)
> +{
> +	struct dma_fence *fence, *f1, *f2, *array, *chain;
> +	struct dma_fence_unwrap iter;
> +	int err = 0;
> +
> +	f1 = mock_fence();
> +	if (!f1)
> +		return -ENOMEM;
> +
> +	f2 = mock_fence();
> +	if (!f2) {
> +		dma_fence_put(f1);
> +		return -ENOMEM;
> +	}
> +
> +	array = mock_array(2, f1, f2);
> +	if (!array)
> +		return -ENOMEM;
> +
> +	chain = mock_chain(NULL, array);
> +	if (!chain)
> +		return -ENOMEM;
> +
> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> +		if (fence == f1) {
> +			f1 = NULL;
> +		} else if (fence == f2) {
> +			f2 = NULL;
> +		} else {
> +			pr_err("Unexpected fence!\n");
> +			err = -EINVAL;
> +		}
> +	}
> +
> +	if (f1 || f2) {
> +		pr_err("Not all fences seen!\n");
> +		err = -EINVAL;
> +	}
> +
> +	dma_fence_signal(f1);
> +	dma_fence_signal(f2);
> +	dma_fence_put(chain);
> +	return 0;
> +}
> +
> +int dma_fence_unwrap(void)
> +{
> +	static const struct subtest tests[] = {
> +		SUBTEST(sanitycheck),
> +		SUBTEST(unwrap_array),
> +		SUBTEST(unwrap_chain),
> +		SUBTEST(unwrap_chain_array),
> +	};
> +	int ret;
> +
> +	slab_fences = KMEM_CACHE(mock_fence,
> +				 SLAB_TYPESAFE_BY_RCU |
> +				 SLAB_HWCACHE_ALIGN);
> +	if (!slab_fences)
> +		return -ENOMEM;
> +
> +	ret = subtests(tests, NULL);
> +
> +	kmem_cache_destroy(slab_fences);
> +	return ret;
> +}
> diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
> new file mode 100644
> index 000000000000..54963df00c98
> --- /dev/null
> +++ b/include/linux/dma-fence-unwrap.h
> @@ -0,0 +1,99 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * fence-chain: chain fences together in a timeline
> + *
> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> + * Authors:
> + *	Christian König <christian.koenig@amd.com>
> + */
> +
> +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
> +#define __LINUX_DMA_FENCE_UNWRAP_H
> +
> +#include <linux/dma-fence-chain.h>
> +#include <linux/dma-fence-array.h>
> +
> +/**
> + * struct dma_fence_unwrap - cursor into the container structure
> + */
> +struct dma_fence_unwrap {
> +	/**
> +	 * @chain: potential dma_fence_chain, but can be other fence as well
> +	 */
> +	struct dma_fence *chain;
> +	/**
> +	 * @array: potential dma_fence_array, but can be other fence as well
> +	 */
> +	struct dma_fence *array;
> +	/**
> +	 * @index: last returned index if @array is really a dma_fence_array
> +	 */
> +	unsigned int index;
> +};
> +
> +/**
> + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
> + * @cursor: cursor to initialize
> + *
> + * Helper function to unwrap dma_fence_array containers, don't touch directly.
> + * Use dma_fence_unwrap_first/next instead.
> + */
> +static inline struct dma_fence *
> +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
> +{
> +	cursor->array = dma_fence_chain_contained(cursor->chain);
> +	cursor->index = 0;
> +	return dma_fence_array_first(cursor->array);
> +}
> +
> +/**
> + * dma_fence_unwrap_first - return the first fence from fence containers
> + * @head: the entrypoint into the containers
> + * @cursor: current position inside the containers
> + *
> + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
> + * first fence.
> + */
> +static inline struct dma_fence *
> +dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
> +{
> +	cursor->chain = dma_fence_get(head);
> +	return dma_fence_unwrap_array(cursor);
> +}
> +
> +/**
> + * dma_fence_unwrap_next - return the next fence from a fence containers
> + * @cursor: current position inside the containers
> + *
> + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
> + * the next fence from them.
> + */
> +static inline struct dma_fence *
> +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
> +{
> +	struct dma_fence *tmp;
> +
> +	++cursor->index;
> +	tmp = dma_fence_array_next(cursor->array, cursor->index);
> +	if (tmp)
> +		return tmp;
> +
> +	cursor->chain = dma_fence_chain_walk(cursor->chain);
> +	return dma_fence_unwrap_array(cursor);
> +}
> +
> +/**
> + * dma_fence_unwrap_for_each - iterate over all fences in containers
> + * @fence: current fence
> + * @cursor: current position inside the containers
> + * @head: starting point for the iterator
> + *
> + * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
> + * potential fences in them. If @head is just a normal fence only that one is
> + * returned.
> + */
> +#define dma_fence_unwrap_for_each(fence, cursor, head)			\
> +	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
> +	     fence = dma_fence_unwrap_next(cursor))
> +
> +#endif


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-14 11:14 ` Christian König
@ 2022-03-21 10:31   ` Christian König
  2022-03-25  7:42     ` Christian König
  0 siblings, 1 reply; 40+ messages in thread
From: Christian König @ 2022-03-21 10:31 UTC (permalink / raw)
  To: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig,
	Alex Deucher, Daniel Vetter

[Adding Daniel]

Just once more a ping for this.

It's an important bug fix and the end user already reported that it works.

Regards,
Christian.

Am 14.03.22 um 12:14 schrieb Christian König:
> Just a gentle ping.
>
> This series is an important fix for drm-misc-next-fixes.
>
> Regards,
> Christian.
>
> Am 11.03.22 um 12:02 schrieb Christian König:
>> Add a general purpose helper to deep dive into 
>> dma_fence_chain/dma_fence_array
>> structures and iterate over all the fences in them.
>>
>> This is useful when we need to flatten out all fences in those 
>> structures.
>>
>> Signed-off-by: Christian König <christian.koenig@amd.com>
>> ---
>>   Documentation/driver-api/dma-buf.rst  |   6 +
>>   drivers/dma-buf/Makefile              |   1 +
>>   drivers/dma-buf/selftests.h           |   1 +
>>   drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
>>   include/linux/dma-fence-unwrap.h      |  99 +++++++++
>>   5 files changed, 386 insertions(+)
>>   create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
>>   create mode 100644 include/linux/dma-fence-unwrap.h
>>
>> diff --git a/Documentation/driver-api/dma-buf.rst 
>> b/Documentation/driver-api/dma-buf.rst
>> index 2cd7db82d9fe..7209500f08c8 100644
>> --- a/Documentation/driver-api/dma-buf.rst
>> +++ b/Documentation/driver-api/dma-buf.rst
>> @@ -194,6 +194,12 @@ DMA Fence Chain
>>   .. kernel-doc:: include/linux/dma-fence-chain.h
>>      :internal:
>>   +DMA Fence unwrap
>> +~~~~~~~~~~~~~~~~
>> +
>> +.. kernel-doc:: include/linux/dma-fence-unwrap.h
>> +   :internal:
>> +
>>   DMA Fence uABI/Sync File
>>   ~~~~~~~~~~~~~~~~~~~~~~~~
>>   diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
>> index 511805dbeb75..4c9eb53ba3f8 100644
>> --- a/drivers/dma-buf/Makefile
>> +++ b/drivers/dma-buf/Makefile
>> @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
>>       selftest.o \
>>       st-dma-fence.o \
>>       st-dma-fence-chain.o \
>> +    st-dma-fence-unwrap.o \
>>       st-dma-resv.o
>>     obj-$(CONFIG_DMABUF_SELFTESTS)    += dmabuf_selftests.o
>> diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
>> index 97d73aaa31da..851965867d9c 100644
>> --- a/drivers/dma-buf/selftests.h
>> +++ b/drivers/dma-buf/selftests.h
>> @@ -12,4 +12,5 @@
>>   selftest(sanitycheck, __sanitycheck__) /* keep first (igt 
>> selfcheck) */
>>   selftest(dma_fence, dma_fence)
>>   selftest(dma_fence_chain, dma_fence_chain)
>> +selftest(dma_fence_unwrap, dma_fence_unwrap)
>>   selftest(dma_resv, dma_resv)
>> diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c 
>> b/drivers/dma-buf/st-dma-fence-unwrap.c
>> new file mode 100644
>> index 000000000000..d821faaebe93
>> --- /dev/null
>> +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
>> @@ -0,0 +1,279 @@
>> +// SPDX-License-Identifier: MIT
>> +
>> +/*
>> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#include <linux/dma-fence-unwrap.h>
>> +#if 0
>> +#include <linux/kernel.h>
>> +#include <linux/kthread.h>
>> +#include <linux/mm.h>
>> +#include <linux/sched/signal.h>
>> +#include <linux/slab.h>
>> +#include <linux/spinlock.h>
>> +#include <linux/random.h>
>> +#endif
>> +
>> +#include "selftest.h"
>> +
>> +#define CHAIN_SZ (4 << 10)
>> +
>> +static struct kmem_cache *slab_fences;
>> +
>> +static inline struct mock_fence {
>> +    struct dma_fence base;
>> +    spinlock_t lock;
>> +} *to_mock_fence(struct dma_fence *f) {
>> +    return container_of(f, struct mock_fence, base);
>> +}
>> +
>> +static const char *mock_name(struct dma_fence *f)
>> +{
>> +    return "mock";
>> +}
>> +
>> +static void mock_fence_release(struct dma_fence *f)
>> +{
>> +    kmem_cache_free(slab_fences, to_mock_fence(f));
>> +}
>> +
>> +static const struct dma_fence_ops mock_ops = {
>> +    .get_driver_name = mock_name,
>> +    .get_timeline_name = mock_name,
>> +    .release = mock_fence_release,
>> +};
>> +
>> +static struct dma_fence *mock_fence(void)
>> +{
>> +    struct mock_fence *f;
>> +
>> +    f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
>> +    if (!f)
>> +        return NULL;
>> +
>> +    spin_lock_init(&f->lock);
>> +    dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
>> +
>> +    return &f->base;
>> +}
>> +
>> +static struct dma_fence *mock_array(unsigned int num_fences, ...)
>> +{
>> +    struct dma_fence_array *array;
>> +    struct dma_fence **fences;
>> +    va_list valist;
>> +    int i;
>> +
>> +    fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
>> +    if (!fences)
>> +        return NULL;
>> +
>> +    va_start(valist, num_fences);
>> +    for (i = 0; i < num_fences; ++i)
>> +        fences[i] = va_arg(valist, typeof(*fences));
>> +    va_end(valist);
>> +
>> +    array = dma_fence_array_create(num_fences, fences,
>> +                       dma_fence_context_alloc(1),
>> +                       1, false);
>> +    if (!array)
>> +        goto cleanup;
>> +    return &array->base;
>> +
>> +cleanup:
>> +    for (i = 0; i < num_fences; ++i)
>> +        dma_fence_put(fences[i]);
>> +    kfree(fences);
>> +    return NULL;
>> +}
>> +
>> +static struct dma_fence *mock_chain(struct dma_fence *prev,
>> +                    struct dma_fence *fence)
>> +{
>> +    struct dma_fence_chain *f;
>> +
>> +    f = dma_fence_chain_alloc();
>> +    if (!f) {
>> +        dma_fence_put(prev);
>> +        dma_fence_put(fence);
>> +        return NULL;
>> +    }
>> +
>> +    dma_fence_chain_init(f, prev, fence, 1);
>> +    return &f->base;
>> +}
>> +
>> +static int sanitycheck(void *arg)
>> +{
>> +    struct dma_fence *f, *chain, *array;
>> +    int err = 0;
>> +
>> +    f = mock_fence();
>> +    if (!f)
>> +        return -ENOMEM;
>> +
>> +    array = mock_array(1, f);
>> +    if (!array)
>> +        return -ENOMEM;
>> +
>> +    chain = mock_chain(NULL, array);
>> +    if (!chain)
>> +        return -ENOMEM;
>> +
>> +    dma_fence_signal(f);
>> +    dma_fence_put(chain);
>> +    return err;
>> +}
>> +
>> +static int unwrap_array(void *arg)
>> +{
>> +    struct dma_fence *fence, *f1, *f2, *array;
>> +    struct dma_fence_unwrap iter;
>> +    int err = 0;
>> +
>> +    f1 = mock_fence();
>> +    if (!f1)
>> +        return -ENOMEM;
>> +
>> +    f2 = mock_fence();
>> +    if (!f2) {
>> +        dma_fence_put(f1);
>> +        return -ENOMEM;
>> +    }
>> +
>> +    array = mock_array(2, f1, f2);
>> +    if (!array)
>> +        return -ENOMEM;
>> +
>> +    dma_fence_unwrap_for_each(fence, &iter, array) {
>> +        if (fence == f1) {
>> +            f1 = NULL;
>> +        } else if (fence == f2) {
>> +            f2 = NULL;
>> +        } else {
>> +            pr_err("Unexpected fence!\n");
>> +            err = -EINVAL;
>> +        }
>> +    }
>> +
>> +    if (f1 || f2) {
>> +        pr_err("Not all fences seen!\n");
>> +        err = -EINVAL;
>> +    }
>> +
>> +    dma_fence_signal(f1);
>> +    dma_fence_signal(f2);
>> +    dma_fence_put(array);
>> +    return 0;
>> +}
>> +
>> +static int unwrap_chain(void *arg)
>> +{
>> +    struct dma_fence *fence, *f1, *f2, *chain;
>> +    struct dma_fence_unwrap iter;
>> +    int err = 0;
>> +
>> +    f1 = mock_fence();
>> +    if (!f1)
>> +        return -ENOMEM;
>> +
>> +    f2 = mock_fence();
>> +    if (!f2) {
>> +        dma_fence_put(f1);
>> +        return -ENOMEM;
>> +    }
>> +
>> +    chain = mock_chain(f1, f2);
>> +    if (!chain)
>> +        return -ENOMEM;
>> +
>> +    dma_fence_unwrap_for_each(fence, &iter, chain) {
>> +        if (fence == f1) {
>> +            f1 = NULL;
>> +        } else if (fence == f2) {
>> +            f2 = NULL;
>> +        } else {
>> +            pr_err("Unexpected fence!\n");
>> +            err = -EINVAL;
>> +        }
>> +    }
>> +
>> +    if (f1 || f2) {
>> +        pr_err("Not all fences seen!\n");
>> +        err = -EINVAL;
>> +    }
>> +
>> +    dma_fence_signal(f1);
>> +    dma_fence_signal(f2);
>> +    dma_fence_put(chain);
>> +    return 0;
>> +}
>> +
>> +static int unwrap_chain_array(void *arg)
>> +{
>> +    struct dma_fence *fence, *f1, *f2, *array, *chain;
>> +    struct dma_fence_unwrap iter;
>> +    int err = 0;
>> +
>> +    f1 = mock_fence();
>> +    if (!f1)
>> +        return -ENOMEM;
>> +
>> +    f2 = mock_fence();
>> +    if (!f2) {
>> +        dma_fence_put(f1);
>> +        return -ENOMEM;
>> +    }
>> +
>> +    array = mock_array(2, f1, f2);
>> +    if (!array)
>> +        return -ENOMEM;
>> +
>> +    chain = mock_chain(NULL, array);
>> +    if (!chain)
>> +        return -ENOMEM;
>> +
>> +    dma_fence_unwrap_for_each(fence, &iter, chain) {
>> +        if (fence == f1) {
>> +            f1 = NULL;
>> +        } else if (fence == f2) {
>> +            f2 = NULL;
>> +        } else {
>> +            pr_err("Unexpected fence!\n");
>> +            err = -EINVAL;
>> +        }
>> +    }
>> +
>> +    if (f1 || f2) {
>> +        pr_err("Not all fences seen!\n");
>> +        err = -EINVAL;
>> +    }
>> +
>> +    dma_fence_signal(f1);
>> +    dma_fence_signal(f2);
>> +    dma_fence_put(chain);
>> +    return 0;
>> +}
>> +
>> +int dma_fence_unwrap(void)
>> +{
>> +    static const struct subtest tests[] = {
>> +        SUBTEST(sanitycheck),
>> +        SUBTEST(unwrap_array),
>> +        SUBTEST(unwrap_chain),
>> +        SUBTEST(unwrap_chain_array),
>> +    };
>> +    int ret;
>> +
>> +    slab_fences = KMEM_CACHE(mock_fence,
>> +                 SLAB_TYPESAFE_BY_RCU |
>> +                 SLAB_HWCACHE_ALIGN);
>> +    if (!slab_fences)
>> +        return -ENOMEM;
>> +
>> +    ret = subtests(tests, NULL);
>> +
>> +    kmem_cache_destroy(slab_fences);
>> +    return ret;
>> +}
>> diff --git a/include/linux/dma-fence-unwrap.h 
>> b/include/linux/dma-fence-unwrap.h
>> new file mode 100644
>> index 000000000000..54963df00c98
>> --- /dev/null
>> +++ b/include/linux/dma-fence-unwrap.h
>> @@ -0,0 +1,99 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * fence-chain: chain fences together in a timeline
>> + *
>> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
>> + * Authors:
>> + *    Christian König <christian.koenig@amd.com>
>> + */
>> +
>> +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
>> +#define __LINUX_DMA_FENCE_UNWRAP_H
>> +
>> +#include <linux/dma-fence-chain.h>
>> +#include <linux/dma-fence-array.h>
>> +
>> +/**
>> + * struct dma_fence_unwrap - cursor into the container structure
>> + */
>> +struct dma_fence_unwrap {
>> +    /**
>> +     * @chain: potential dma_fence_chain, but can be other fence as 
>> well
>> +     */
>> +    struct dma_fence *chain;
>> +    /**
>> +     * @array: potential dma_fence_array, but can be other fence as 
>> well
>> +     */
>> +    struct dma_fence *array;
>> +    /**
>> +     * @index: last returned index if @array is really a 
>> dma_fence_array
>> +     */
>> +    unsigned int index;
>> +};
>> +
>> +/**
>> + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
>> + * @cursor: cursor to initialize
>> + *
>> + * Helper function to unwrap dma_fence_array containers, don't touch 
>> directly.
>> + * Use dma_fence_unwrap_first/next instead.
>> + */
>> +static inline struct dma_fence *
>> +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
>> +{
>> +    cursor->array = dma_fence_chain_contained(cursor->chain);
>> +    cursor->index = 0;
>> +    return dma_fence_array_first(cursor->array);
>> +}
>> +
>> +/**
>> + * dma_fence_unwrap_first - return the first fence from fence 
>> containers
>> + * @head: the entrypoint into the containers
>> + * @cursor: current position inside the containers
>> + *
>> + * Unwraps potential dma_fence_chain/dma_fence_array containers and 
>> return the
>> + * first fence.
>> + */
>> +static inline struct dma_fence *
>> +dma_fence_unwrap_first(struct dma_fence *head, struct 
>> dma_fence_unwrap *cursor)
>> +{
>> +    cursor->chain = dma_fence_get(head);
>> +    return dma_fence_unwrap_array(cursor);
>> +}
>> +
>> +/**
>> + * dma_fence_unwrap_next - return the next fence from a fence 
>> containers
>> + * @cursor: current position inside the containers
>> + *
>> + * Continue unwrapping the dma_fence_chain/dma_fence_array 
>> containers and return
>> + * the next fence from them.
>> + */
>> +static inline struct dma_fence *
>> +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
>> +{
>> +    struct dma_fence *tmp;
>> +
>> +    ++cursor->index;
>> +    tmp = dma_fence_array_next(cursor->array, cursor->index);
>> +    if (tmp)
>> +        return tmp;
>> +
>> +    cursor->chain = dma_fence_chain_walk(cursor->chain);
>> +    return dma_fence_unwrap_array(cursor);
>> +}
>> +
>> +/**
>> + * dma_fence_unwrap_for_each - iterate over all fences in containers
>> + * @fence: current fence
>> + * @cursor: current position inside the containers
>> + * @head: starting point for the iterator
>> + *
>> + * Unwrap dma_fence_chain and dma_fence_array containers and deep 
>> dive into all
>> + * potential fences in them. If @head is just a normal fence only 
>> that one is
>> + * returned.
>> + */
>> +#define dma_fence_unwrap_for_each(fence, cursor, head)            \
>> +    for (fence = dma_fence_unwrap_first(head, cursor); fence;    \
>> +         fence = dma_fence_unwrap_next(cursor))
>> +
>> +#endif
>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-21 10:31   ` Christian König
@ 2022-03-25  7:42     ` Christian König
  0 siblings, 0 replies; 40+ messages in thread
From: Christian König @ 2022-03-25  7:42 UTC (permalink / raw)
  To: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig,
	Alex Deucher, Daniel Vetter

Once more a ping on this here.

It's fixing a warning with sync_files and is already tested.

Regards,
Christian.

Am 21.03.22 um 11:31 schrieb Christian König:
> [Adding Daniel]
>
> Just once more a ping for this.
>
> It's an important bug fix and the end user already reported that it 
> works.
>
> Regards,
> Christian.
>
> Am 14.03.22 um 12:14 schrieb Christian König:
>> Just a gentle ping.
>>
>> This series is an important fix for drm-misc-next-fixes.
>>
>> Regards,
>> Christian.
>>
>> Am 11.03.22 um 12:02 schrieb Christian König:
>>> Add a general purpose helper to deep dive into 
>>> dma_fence_chain/dma_fence_array
>>> structures and iterate over all the fences in them.
>>>
>>> This is useful when we need to flatten out all fences in those 
>>> structures.
>>>
>>> Signed-off-by: Christian König <christian.koenig@amd.com>
>>> ---
>>>   Documentation/driver-api/dma-buf.rst  |   6 +
>>>   drivers/dma-buf/Makefile              |   1 +
>>>   drivers/dma-buf/selftests.h           |   1 +
>>>   drivers/dma-buf/st-dma-fence-unwrap.c | 279 
>>> ++++++++++++++++++++++++++
>>>   include/linux/dma-fence-unwrap.h      |  99 +++++++++
>>>   5 files changed, 386 insertions(+)
>>>   create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
>>>   create mode 100644 include/linux/dma-fence-unwrap.h
>>>
>>> diff --git a/Documentation/driver-api/dma-buf.rst 
>>> b/Documentation/driver-api/dma-buf.rst
>>> index 2cd7db82d9fe..7209500f08c8 100644
>>> --- a/Documentation/driver-api/dma-buf.rst
>>> +++ b/Documentation/driver-api/dma-buf.rst
>>> @@ -194,6 +194,12 @@ DMA Fence Chain
>>>   .. kernel-doc:: include/linux/dma-fence-chain.h
>>>      :internal:
>>>   +DMA Fence unwrap
>>> +~~~~~~~~~~~~~~~~
>>> +
>>> +.. kernel-doc:: include/linux/dma-fence-unwrap.h
>>> +   :internal:
>>> +
>>>   DMA Fence uABI/Sync File
>>>   ~~~~~~~~~~~~~~~~~~~~~~~~
>>>   diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
>>> index 511805dbeb75..4c9eb53ba3f8 100644
>>> --- a/drivers/dma-buf/Makefile
>>> +++ b/drivers/dma-buf/Makefile
>>> @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
>>>       selftest.o \
>>>       st-dma-fence.o \
>>>       st-dma-fence-chain.o \
>>> +    st-dma-fence-unwrap.o \
>>>       st-dma-resv.o
>>>     obj-$(CONFIG_DMABUF_SELFTESTS)    += dmabuf_selftests.o
>>> diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
>>> index 97d73aaa31da..851965867d9c 100644
>>> --- a/drivers/dma-buf/selftests.h
>>> +++ b/drivers/dma-buf/selftests.h
>>> @@ -12,4 +12,5 @@
>>>   selftest(sanitycheck, __sanitycheck__) /* keep first (igt 
>>> selfcheck) */
>>>   selftest(dma_fence, dma_fence)
>>>   selftest(dma_fence_chain, dma_fence_chain)
>>> +selftest(dma_fence_unwrap, dma_fence_unwrap)
>>>   selftest(dma_resv, dma_resv)
>>> diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c 
>>> b/drivers/dma-buf/st-dma-fence-unwrap.c
>>> new file mode 100644
>>> index 000000000000..d821faaebe93
>>> --- /dev/null
>>> +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
>>> @@ -0,0 +1,279 @@
>>> +// SPDX-License-Identifier: MIT
>>> +
>>> +/*
>>> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
>>> + */
>>> +
>>> +#include <linux/dma-fence-unwrap.h>
>>> +#if 0
>>> +#include <linux/kernel.h>
>>> +#include <linux/kthread.h>
>>> +#include <linux/mm.h>
>>> +#include <linux/sched/signal.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/spinlock.h>
>>> +#include <linux/random.h>
>>> +#endif
>>> +
>>> +#include "selftest.h"
>>> +
>>> +#define CHAIN_SZ (4 << 10)
>>> +
>>> +static struct kmem_cache *slab_fences;
>>> +
>>> +static inline struct mock_fence {
>>> +    struct dma_fence base;
>>> +    spinlock_t lock;
>>> +} *to_mock_fence(struct dma_fence *f) {
>>> +    return container_of(f, struct mock_fence, base);
>>> +}
>>> +
>>> +static const char *mock_name(struct dma_fence *f)
>>> +{
>>> +    return "mock";
>>> +}
>>> +
>>> +static void mock_fence_release(struct dma_fence *f)
>>> +{
>>> +    kmem_cache_free(slab_fences, to_mock_fence(f));
>>> +}
>>> +
>>> +static const struct dma_fence_ops mock_ops = {
>>> +    .get_driver_name = mock_name,
>>> +    .get_timeline_name = mock_name,
>>> +    .release = mock_fence_release,
>>> +};
>>> +
>>> +static struct dma_fence *mock_fence(void)
>>> +{
>>> +    struct mock_fence *f;
>>> +
>>> +    f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
>>> +    if (!f)
>>> +        return NULL;
>>> +
>>> +    spin_lock_init(&f->lock);
>>> +    dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
>>> +
>>> +    return &f->base;
>>> +}
>>> +
>>> +static struct dma_fence *mock_array(unsigned int num_fences, ...)
>>> +{
>>> +    struct dma_fence_array *array;
>>> +    struct dma_fence **fences;
>>> +    va_list valist;
>>> +    int i;
>>> +
>>> +    fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
>>> +    if (!fences)
>>> +        return NULL;
>>> +
>>> +    va_start(valist, num_fences);
>>> +    for (i = 0; i < num_fences; ++i)
>>> +        fences[i] = va_arg(valist, typeof(*fences));
>>> +    va_end(valist);
>>> +
>>> +    array = dma_fence_array_create(num_fences, fences,
>>> +                       dma_fence_context_alloc(1),
>>> +                       1, false);
>>> +    if (!array)
>>> +        goto cleanup;
>>> +    return &array->base;
>>> +
>>> +cleanup:
>>> +    for (i = 0; i < num_fences; ++i)
>>> +        dma_fence_put(fences[i]);
>>> +    kfree(fences);
>>> +    return NULL;
>>> +}
>>> +
>>> +static struct dma_fence *mock_chain(struct dma_fence *prev,
>>> +                    struct dma_fence *fence)
>>> +{
>>> +    struct dma_fence_chain *f;
>>> +
>>> +    f = dma_fence_chain_alloc();
>>> +    if (!f) {
>>> +        dma_fence_put(prev);
>>> +        dma_fence_put(fence);
>>> +        return NULL;
>>> +    }
>>> +
>>> +    dma_fence_chain_init(f, prev, fence, 1);
>>> +    return &f->base;
>>> +}
>>> +
>>> +static int sanitycheck(void *arg)
>>> +{
>>> +    struct dma_fence *f, *chain, *array;
>>> +    int err = 0;
>>> +
>>> +    f = mock_fence();
>>> +    if (!f)
>>> +        return -ENOMEM;
>>> +
>>> +    array = mock_array(1, f);
>>> +    if (!array)
>>> +        return -ENOMEM;
>>> +
>>> +    chain = mock_chain(NULL, array);
>>> +    if (!chain)
>>> +        return -ENOMEM;
>>> +
>>> +    dma_fence_signal(f);
>>> +    dma_fence_put(chain);
>>> +    return err;
>>> +}
>>> +
>>> +static int unwrap_array(void *arg)
>>> +{
>>> +    struct dma_fence *fence, *f1, *f2, *array;
>>> +    struct dma_fence_unwrap iter;
>>> +    int err = 0;
>>> +
>>> +    f1 = mock_fence();
>>> +    if (!f1)
>>> +        return -ENOMEM;
>>> +
>>> +    f2 = mock_fence();
>>> +    if (!f2) {
>>> +        dma_fence_put(f1);
>>> +        return -ENOMEM;
>>> +    }
>>> +
>>> +    array = mock_array(2, f1, f2);
>>> +    if (!array)
>>> +        return -ENOMEM;
>>> +
>>> +    dma_fence_unwrap_for_each(fence, &iter, array) {
>>> +        if (fence == f1) {
>>> +            f1 = NULL;
>>> +        } else if (fence == f2) {
>>> +            f2 = NULL;
>>> +        } else {
>>> +            pr_err("Unexpected fence!\n");
>>> +            err = -EINVAL;
>>> +        }
>>> +    }
>>> +
>>> +    if (f1 || f2) {
>>> +        pr_err("Not all fences seen!\n");
>>> +        err = -EINVAL;
>>> +    }
>>> +
>>> +    dma_fence_signal(f1);
>>> +    dma_fence_signal(f2);
>>> +    dma_fence_put(array);
>>> +    return 0;
>>> +}
>>> +
>>> +static int unwrap_chain(void *arg)
>>> +{
>>> +    struct dma_fence *fence, *f1, *f2, *chain;
>>> +    struct dma_fence_unwrap iter;
>>> +    int err = 0;
>>> +
>>> +    f1 = mock_fence();
>>> +    if (!f1)
>>> +        return -ENOMEM;
>>> +
>>> +    f2 = mock_fence();
>>> +    if (!f2) {
>>> +        dma_fence_put(f1);
>>> +        return -ENOMEM;
>>> +    }
>>> +
>>> +    chain = mock_chain(f1, f2);
>>> +    if (!chain)
>>> +        return -ENOMEM;
>>> +
>>> +    dma_fence_unwrap_for_each(fence, &iter, chain) {
>>> +        if (fence == f1) {
>>> +            f1 = NULL;
>>> +        } else if (fence == f2) {
>>> +            f2 = NULL;
>>> +        } else {
>>> +            pr_err("Unexpected fence!\n");
>>> +            err = -EINVAL;
>>> +        }
>>> +    }
>>> +
>>> +    if (f1 || f2) {
>>> +        pr_err("Not all fences seen!\n");
>>> +        err = -EINVAL;
>>> +    }
>>> +
>>> +    dma_fence_signal(f1);
>>> +    dma_fence_signal(f2);
>>> +    dma_fence_put(chain);
>>> +    return 0;
>>> +}
>>> +
>>> +static int unwrap_chain_array(void *arg)
>>> +{
>>> +    struct dma_fence *fence, *f1, *f2, *array, *chain;
>>> +    struct dma_fence_unwrap iter;
>>> +    int err = 0;
>>> +
>>> +    f1 = mock_fence();
>>> +    if (!f1)
>>> +        return -ENOMEM;
>>> +
>>> +    f2 = mock_fence();
>>> +    if (!f2) {
>>> +        dma_fence_put(f1);
>>> +        return -ENOMEM;
>>> +    }
>>> +
>>> +    array = mock_array(2, f1, f2);
>>> +    if (!array)
>>> +        return -ENOMEM;
>>> +
>>> +    chain = mock_chain(NULL, array);
>>> +    if (!chain)
>>> +        return -ENOMEM;
>>> +
>>> +    dma_fence_unwrap_for_each(fence, &iter, chain) {
>>> +        if (fence == f1) {
>>> +            f1 = NULL;
>>> +        } else if (fence == f2) {
>>> +            f2 = NULL;
>>> +        } else {
>>> +            pr_err("Unexpected fence!\n");
>>> +            err = -EINVAL;
>>> +        }
>>> +    }
>>> +
>>> +    if (f1 || f2) {
>>> +        pr_err("Not all fences seen!\n");
>>> +        err = -EINVAL;
>>> +    }
>>> +
>>> +    dma_fence_signal(f1);
>>> +    dma_fence_signal(f2);
>>> +    dma_fence_put(chain);
>>> +    return 0;
>>> +}
>>> +
>>> +int dma_fence_unwrap(void)
>>> +{
>>> +    static const struct subtest tests[] = {
>>> +        SUBTEST(sanitycheck),
>>> +        SUBTEST(unwrap_array),
>>> +        SUBTEST(unwrap_chain),
>>> +        SUBTEST(unwrap_chain_array),
>>> +    };
>>> +    int ret;
>>> +
>>> +    slab_fences = KMEM_CACHE(mock_fence,
>>> +                 SLAB_TYPESAFE_BY_RCU |
>>> +                 SLAB_HWCACHE_ALIGN);
>>> +    if (!slab_fences)
>>> +        return -ENOMEM;
>>> +
>>> +    ret = subtests(tests, NULL);
>>> +
>>> +    kmem_cache_destroy(slab_fences);
>>> +    return ret;
>>> +}
>>> diff --git a/include/linux/dma-fence-unwrap.h 
>>> b/include/linux/dma-fence-unwrap.h
>>> new file mode 100644
>>> index 000000000000..54963df00c98
>>> --- /dev/null
>>> +++ b/include/linux/dma-fence-unwrap.h
>>> @@ -0,0 +1,99 @@
>>> +/* SPDX-License-Identifier: GPL-2.0-only */
>>> +/*
>>> + * fence-chain: chain fences together in a timeline
>>> + *
>>> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
>>> + * Authors:
>>> + *    Christian König <christian.koenig@amd.com>
>>> + */
>>> +
>>> +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
>>> +#define __LINUX_DMA_FENCE_UNWRAP_H
>>> +
>>> +#include <linux/dma-fence-chain.h>
>>> +#include <linux/dma-fence-array.h>
>>> +
>>> +/**
>>> + * struct dma_fence_unwrap - cursor into the container structure
>>> + */
>>> +struct dma_fence_unwrap {
>>> +    /**
>>> +     * @chain: potential dma_fence_chain, but can be other fence as 
>>> well
>>> +     */
>>> +    struct dma_fence *chain;
>>> +    /**
>>> +     * @array: potential dma_fence_array, but can be other fence as 
>>> well
>>> +     */
>>> +    struct dma_fence *array;
>>> +    /**
>>> +     * @index: last returned index if @array is really a 
>>> dma_fence_array
>>> +     */
>>> +    unsigned int index;
>>> +};
>>> +
>>> +/**
>>> + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
>>> + * @cursor: cursor to initialize
>>> + *
>>> + * Helper function to unwrap dma_fence_array containers, don't 
>>> touch directly.
>>> + * Use dma_fence_unwrap_first/next instead.
>>> + */
>>> +static inline struct dma_fence *
>>> +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
>>> +{
>>> +    cursor->array = dma_fence_chain_contained(cursor->chain);
>>> +    cursor->index = 0;
>>> +    return dma_fence_array_first(cursor->array);
>>> +}
>>> +
>>> +/**
>>> + * dma_fence_unwrap_first - return the first fence from fence 
>>> containers
>>> + * @head: the entrypoint into the containers
>>> + * @cursor: current position inside the containers
>>> + *
>>> + * Unwraps potential dma_fence_chain/dma_fence_array containers and 
>>> return the
>>> + * first fence.
>>> + */
>>> +static inline struct dma_fence *
>>> +dma_fence_unwrap_first(struct dma_fence *head, struct 
>>> dma_fence_unwrap *cursor)
>>> +{
>>> +    cursor->chain = dma_fence_get(head);
>>> +    return dma_fence_unwrap_array(cursor);
>>> +}
>>> +
>>> +/**
>>> + * dma_fence_unwrap_next - return the next fence from a fence 
>>> containers
>>> + * @cursor: current position inside the containers
>>> + *
>>> + * Continue unwrapping the dma_fence_chain/dma_fence_array 
>>> containers and return
>>> + * the next fence from them.
>>> + */
>>> +static inline struct dma_fence *
>>> +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
>>> +{
>>> +    struct dma_fence *tmp;
>>> +
>>> +    ++cursor->index;
>>> +    tmp = dma_fence_array_next(cursor->array, cursor->index);
>>> +    if (tmp)
>>> +        return tmp;
>>> +
>>> +    cursor->chain = dma_fence_chain_walk(cursor->chain);
>>> +    return dma_fence_unwrap_array(cursor);
>>> +}
>>> +
>>> +/**
>>> + * dma_fence_unwrap_for_each - iterate over all fences in containers
>>> + * @fence: current fence
>>> + * @cursor: current position inside the containers
>>> + * @head: starting point for the iterator
>>> + *
>>> + * Unwrap dma_fence_chain and dma_fence_array containers and deep 
>>> dive into all
>>> + * potential fences in them. If @head is just a normal fence only 
>>> that one is
>>> + * returned.
>>> + */
>>> +#define dma_fence_unwrap_for_each(fence, cursor, head)            \
>>> +    for (fence = dma_fence_unwrap_first(head, cursor); fence;    \
>>> +         fence = dma_fence_unwrap_next(cursor))
>>> +
>>> +#endif
>>
>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-11 11:02 [PATCH 1/2] dma-buf: add dma_fence_unwrap Christian König
@ 2022-03-25 10:03   ` Daniel Vetter
  2022-03-11 15:45 ` [PATCH 1/2] dma-buf: add dma_fence_unwrap kernel test robot
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-25 10:03 UTC (permalink / raw)
  To: Christian König
  Cc: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig,
	Christian König

On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
> structures and iterate over all the fences in them.
> 
> This is useful when we need to flatten out all fences in those structures.
> 
> Signed-off-by: Christian König <christian.koenig@amd.com>
> ---
>  Documentation/driver-api/dma-buf.rst  |   6 +
>  drivers/dma-buf/Makefile              |   1 +
>  drivers/dma-buf/selftests.h           |   1 +
>  drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
>  include/linux/dma-fence-unwrap.h      |  99 +++++++++
>  5 files changed, 386 insertions(+)
>  create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
>  create mode 100644 include/linux/dma-fence-unwrap.h
> 
> diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
> index 2cd7db82d9fe..7209500f08c8 100644
> --- a/Documentation/driver-api/dma-buf.rst
> +++ b/Documentation/driver-api/dma-buf.rst
> @@ -194,6 +194,12 @@ DMA Fence Chain
>  .. kernel-doc:: include/linux/dma-fence-chain.h
>     :internal:
>  
> +DMA Fence unwrap
> +~~~~~~~~~~~~~~~~
> +
> +.. kernel-doc:: include/linux/dma-fence-unwrap.h
> +   :internal:
> +
>  DMA Fence uABI/Sync File
>  ~~~~~~~~~~~~~~~~~~~~~~~~
>  
> diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
> index 511805dbeb75..4c9eb53ba3f8 100644
> --- a/drivers/dma-buf/Makefile
> +++ b/drivers/dma-buf/Makefile
> @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
>  	selftest.o \
>  	st-dma-fence.o \
>  	st-dma-fence-chain.o \
> +	st-dma-fence-unwrap.o \
>  	st-dma-resv.o
>  
>  obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
> diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
> index 97d73aaa31da..851965867d9c 100644
> --- a/drivers/dma-buf/selftests.h
> +++ b/drivers/dma-buf/selftests.h
> @@ -12,4 +12,5 @@
>  selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
>  selftest(dma_fence, dma_fence)
>  selftest(dma_fence_chain, dma_fence_chain)
> +selftest(dma_fence_unwrap, dma_fence_unwrap)
>  selftest(dma_resv, dma_resv)
> diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
> new file mode 100644
> index 000000000000..d821faaebe93
> --- /dev/null
> +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
> @@ -0,0 +1,279 @@
> +// SPDX-License-Identifier: MIT
> +
> +/*
> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> + */
> +
> +#include <linux/dma-fence-unwrap.h>
> +#if 0
> +#include <linux/kernel.h>
> +#include <linux/kthread.h>
> +#include <linux/mm.h>
> +#include <linux/sched/signal.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/random.h>
> +#endif
> +
> +#include "selftest.h"
> +
> +#define CHAIN_SZ (4 << 10)
> +
> +static struct kmem_cache *slab_fences;

Your own slab feels a bit like overkill. kmalloc/kfree not good enough?

> +
> +static inline struct mock_fence {
> +	struct dma_fence base;
> +	spinlock_t lock;
> +} *to_mock_fence(struct dma_fence *f) {
> +	return container_of(f, struct mock_fence, base);
> +}
> +
> +static const char *mock_name(struct dma_fence *f)
> +{
> +	return "mock";
> +}
> +
> +static void mock_fence_release(struct dma_fence *f)
> +{
> +	kmem_cache_free(slab_fences, to_mock_fence(f));
> +}
> +
> +static const struct dma_fence_ops mock_ops = {
> +	.get_driver_name = mock_name,
> +	.get_timeline_name = mock_name,
> +	.release = mock_fence_release,
> +};
> +
> +static struct dma_fence *mock_fence(void)
> +{
> +	struct mock_fence *f;
> +
> +	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
> +	if (!f)
> +		return NULL;
> +
> +	spin_lock_init(&f->lock);
> +	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
> +
> +	return &f->base;
> +}
> +
> +static struct dma_fence *mock_array(unsigned int num_fences, ...)
> +{
> +	struct dma_fence_array *array;
> +	struct dma_fence **fences;
> +	va_list valist;
> +	int i;
> +
> +	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
> +	if (!fences)
> +		return NULL;
> +
> +	va_start(valist, num_fences);
> +	for (i = 0; i < num_fences; ++i)
> +		fences[i] = va_arg(valist, typeof(*fences));
> +	va_end(valist);
> +
> +	array = dma_fence_array_create(num_fences, fences,
> +				       dma_fence_context_alloc(1),
> +				       1, false);
> +	if (!array)
> +		goto cleanup;
> +	return &array->base;
> +
> +cleanup:
> +	for (i = 0; i < num_fences; ++i)
> +		dma_fence_put(fences[i]);
> +	kfree(fences);
> +	return NULL;
> +}
> +
> +static struct dma_fence *mock_chain(struct dma_fence *prev,
> +				    struct dma_fence *fence)
> +{
> +	struct dma_fence_chain *f;
> +
> +	f = dma_fence_chain_alloc();
> +	if (!f) {
> +		dma_fence_put(prev);
> +		dma_fence_put(fence);
> +		return NULL;
> +	}
> +
> +	dma_fence_chain_init(f, prev, fence, 1);
> +	return &f->base;
> +}
> +
> +static int sanitycheck(void *arg)
> +{
> +	struct dma_fence *f, *chain, *array;
> +	int err = 0;
> +
> +	f = mock_fence();
> +	if (!f)
> +		return -ENOMEM;
> +
> +	array = mock_array(1, f);
> +	if (!array)
> +		return -ENOMEM;
> +
> +	chain = mock_chain(NULL, array);
> +	if (!chain)
> +		return -ENOMEM;
> +
> +	dma_fence_signal(f);
> +	dma_fence_put(chain);
> +	return err;
> +}
> +
> +static int unwrap_array(void *arg)
> +{
> +	struct dma_fence *fence, *f1, *f2, *array;
> +	struct dma_fence_unwrap iter;
> +	int err = 0;
> +
> +	f1 = mock_fence();
> +	if (!f1)
> +		return -ENOMEM;
> +
> +	f2 = mock_fence();
> +	if (!f2) {
> +		dma_fence_put(f1);
> +		return -ENOMEM;
> +	}
> +
> +	array = mock_array(2, f1, f2);
> +	if (!array)
> +		return -ENOMEM;
> +
> +	dma_fence_unwrap_for_each(fence, &iter, array) {
> +		if (fence == f1) {
> +			f1 = NULL;
> +		} else if (fence == f2) {
> +			f2 = NULL;
> +		} else {
> +			pr_err("Unexpected fence!\n");
> +			err = -EINVAL;
> +		}
> +	}
> +
> +	if (f1 || f2) {
> +		pr_err("Not all fences seen!\n");
> +		err = -EINVAL;
> +	}
> +
> +	dma_fence_signal(f1);
> +	dma_fence_signal(f2);
> +	dma_fence_put(array);
> +	return 0;
> +}
> +
> +static int unwrap_chain(void *arg)
> +{
> +	struct dma_fence *fence, *f1, *f2, *chain;
> +	struct dma_fence_unwrap iter;
> +	int err = 0;
> +
> +	f1 = mock_fence();
> +	if (!f1)
> +		return -ENOMEM;
> +
> +	f2 = mock_fence();
> +	if (!f2) {
> +		dma_fence_put(f1);
> +		return -ENOMEM;
> +	}
> +
> +	chain = mock_chain(f1, f2);
> +	if (!chain)
> +		return -ENOMEM;
> +
> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> +		if (fence == f1) {
> +			f1 = NULL;
> +		} else if (fence == f2) {
> +			f2 = NULL;
> +		} else {
> +			pr_err("Unexpected fence!\n");
> +			err = -EINVAL;
> +		}
> +	}
> +
> +	if (f1 || f2) {
> +		pr_err("Not all fences seen!\n");
> +		err = -EINVAL;
> +	}
> +
> +	dma_fence_signal(f1);
> +	dma_fence_signal(f2);
> +	dma_fence_put(chain);
> +	return 0;
> +}
> +
> +static int unwrap_chain_array(void *arg)
> +{
> +	struct dma_fence *fence, *f1, *f2, *array, *chain;
> +	struct dma_fence_unwrap iter;
> +	int err = 0;
> +
> +	f1 = mock_fence();
> +	if (!f1)
> +		return -ENOMEM;
> +
> +	f2 = mock_fence();
> +	if (!f2) {
> +		dma_fence_put(f1);
> +		return -ENOMEM;
> +	}
> +
> +	array = mock_array(2, f1, f2);
> +	if (!array)
> +		return -ENOMEM;
> +
> +	chain = mock_chain(NULL, array);
> +	if (!chain)
> +		return -ENOMEM;
> +
> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> +		if (fence == f1) {
> +			f1 = NULL;
> +		} else if (fence == f2) {
> +			f2 = NULL;
> +		} else {
> +			pr_err("Unexpected fence!\n");
> +			err = -EINVAL;
> +		}
> +	}
> +
> +	if (f1 || f2) {
> +		pr_err("Not all fences seen!\n");
> +		err = -EINVAL;
> +	}
> +
> +	dma_fence_signal(f1);
> +	dma_fence_signal(f2);
> +	dma_fence_put(chain);
> +	return 0;
> +}
> +
> +int dma_fence_unwrap(void)
> +{
> +	static const struct subtest tests[] = {
> +		SUBTEST(sanitycheck),
> +		SUBTEST(unwrap_array),
> +		SUBTEST(unwrap_chain),
> +		SUBTEST(unwrap_chain_array),
> +	};
> +	int ret;
> +
> +	slab_fences = KMEM_CACHE(mock_fence,
> +				 SLAB_TYPESAFE_BY_RCU |
> +				 SLAB_HWCACHE_ALIGN);
> +	if (!slab_fences)
> +		return -ENOMEM;
> +
> +	ret = subtests(tests, NULL);
> +
> +	kmem_cache_destroy(slab_fences);
> +	return ret;
> +}
> diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
> new file mode 100644
> index 000000000000..54963df00c98
> --- /dev/null
> +++ b/include/linux/dma-fence-unwrap.h
> @@ -0,0 +1,99 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * fence-chain: chain fences together in a timeline
> + *
> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> + * Authors:
> + *	Christian König <christian.koenig@amd.com>
> + */
> +
> +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
> +#define __LINUX_DMA_FENCE_UNWRAP_H
> +
> +#include <linux/dma-fence-chain.h>
> +#include <linux/dma-fence-array.h>
> +
> +/**
> + * struct dma_fence_unwrap - cursor into the container structure

I think adding "This should be used together with
dma_fence_unwrap_for_each() iterator macro." would be nice here. I just
like links :-)

> + */
> +struct dma_fence_unwrap {
> +	/**
> +	 * @chain: potential dma_fence_chain, but can be other fence as well
> +	 */
> +	struct dma_fence *chain;
> +	/**
> +	 * @array: potential dma_fence_array, but can be other fence as well
> +	 */
> +	struct dma_fence *array;
> +	/**
> +	 * @index: last returned index if @array is really a dma_fence_array
> +	 */
> +	unsigned int index;
> +};
> +
> +/**
> + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
> + * @cursor: cursor to initialize
> + *
> + * Helper function to unwrap dma_fence_array containers, don't touch directly.
> + * Use dma_fence_unwrap_first/next instead.
> + */
> +static inline struct dma_fence *
> +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)

Since this is a helper that no one should call I'd give it a __ prefix and
drop the kerneldoc. Documenting stuff that people shouldn't use is
confusing :-)

> +{
> +	cursor->array = dma_fence_chain_contained(cursor->chain);
> +	cursor->index = 0;
> +	return dma_fence_array_first(cursor->array);
> +}
> +
> +/**
> + * dma_fence_unwrap_first - return the first fence from fence containers
> + * @head: the entrypoint into the containers
> + * @cursor: current position inside the containers
> + *
> + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
> + * first fence.
> + */
> +static inline struct dma_fence *
> +dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
> +{
> +	cursor->chain = dma_fence_get(head);
> +	return dma_fence_unwrap_array(cursor);
> +}
> +
> +/**
> + * dma_fence_unwrap_next - return the next fence from a fence containers
> + * @cursor: current position inside the containers
> + *
> + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
> + * the next fence from them.
> + */
> +static inline struct dma_fence *
> +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
> +{
> +	struct dma_fence *tmp;
> +
> +	++cursor->index;
> +	tmp = dma_fence_array_next(cursor->array, cursor->index);
> +	if (tmp)
> +		return tmp;
> +
> +	cursor->chain = dma_fence_chain_walk(cursor->chain);
> +	return dma_fence_unwrap_array(cursor);
> +}
> +
> +/**
> + * dma_fence_unwrap_for_each - iterate over all fences in containers
> + * @fence: current fence
> + * @cursor: current position inside the containers
> + * @head: starting point for the iterator
> + *
> + * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
> + * potential fences in them. If @head is just a normal fence only that one is
> + * returned.
> + */
> +#define dma_fence_unwrap_for_each(fence, cursor, head)			\
> +	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
> +	     fence = dma_fence_unwrap_next(cursor))
> +
> +#endif

I think it'd be really good to add a small paragraph to struct
dma_fence_chain that this macro and iterator should be used for walking
over all fences in a chain, including any fence arrays or anything like
that.

With the bikesheds addressed:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> -- 
> 2.25.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
@ 2022-03-25 10:03   ` Daniel Vetter
  0 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-25 10:03 UTC (permalink / raw)
  To: Christian König
  Cc: gustavo, dri-devel, sumit.semwal, linaro-mm-sig,
	Christian König, linux-media

On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
> structures and iterate over all the fences in them.
> 
> This is useful when we need to flatten out all fences in those structures.
> 
> Signed-off-by: Christian König <christian.koenig@amd.com>
> ---
>  Documentation/driver-api/dma-buf.rst  |   6 +
>  drivers/dma-buf/Makefile              |   1 +
>  drivers/dma-buf/selftests.h           |   1 +
>  drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
>  include/linux/dma-fence-unwrap.h      |  99 +++++++++
>  5 files changed, 386 insertions(+)
>  create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
>  create mode 100644 include/linux/dma-fence-unwrap.h
> 
> diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
> index 2cd7db82d9fe..7209500f08c8 100644
> --- a/Documentation/driver-api/dma-buf.rst
> +++ b/Documentation/driver-api/dma-buf.rst
> @@ -194,6 +194,12 @@ DMA Fence Chain
>  .. kernel-doc:: include/linux/dma-fence-chain.h
>     :internal:
>  
> +DMA Fence unwrap
> +~~~~~~~~~~~~~~~~
> +
> +.. kernel-doc:: include/linux/dma-fence-unwrap.h
> +   :internal:
> +
>  DMA Fence uABI/Sync File
>  ~~~~~~~~~~~~~~~~~~~~~~~~
>  
> diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
> index 511805dbeb75..4c9eb53ba3f8 100644
> --- a/drivers/dma-buf/Makefile
> +++ b/drivers/dma-buf/Makefile
> @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
>  	selftest.o \
>  	st-dma-fence.o \
>  	st-dma-fence-chain.o \
> +	st-dma-fence-unwrap.o \
>  	st-dma-resv.o
>  
>  obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
> diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
> index 97d73aaa31da..851965867d9c 100644
> --- a/drivers/dma-buf/selftests.h
> +++ b/drivers/dma-buf/selftests.h
> @@ -12,4 +12,5 @@
>  selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
>  selftest(dma_fence, dma_fence)
>  selftest(dma_fence_chain, dma_fence_chain)
> +selftest(dma_fence_unwrap, dma_fence_unwrap)
>  selftest(dma_resv, dma_resv)
> diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
> new file mode 100644
> index 000000000000..d821faaebe93
> --- /dev/null
> +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
> @@ -0,0 +1,279 @@
> +// SPDX-License-Identifier: MIT
> +
> +/*
> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> + */
> +
> +#include <linux/dma-fence-unwrap.h>
> +#if 0
> +#include <linux/kernel.h>
> +#include <linux/kthread.h>
> +#include <linux/mm.h>
> +#include <linux/sched/signal.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/random.h>
> +#endif
> +
> +#include "selftest.h"
> +
> +#define CHAIN_SZ (4 << 10)
> +
> +static struct kmem_cache *slab_fences;

Your own slab feels a bit like overkill. kmalloc/kfree not good enough?

> +
> +static inline struct mock_fence {
> +	struct dma_fence base;
> +	spinlock_t lock;
> +} *to_mock_fence(struct dma_fence *f) {
> +	return container_of(f, struct mock_fence, base);
> +}
> +
> +static const char *mock_name(struct dma_fence *f)
> +{
> +	return "mock";
> +}
> +
> +static void mock_fence_release(struct dma_fence *f)
> +{
> +	kmem_cache_free(slab_fences, to_mock_fence(f));
> +}
> +
> +static const struct dma_fence_ops mock_ops = {
> +	.get_driver_name = mock_name,
> +	.get_timeline_name = mock_name,
> +	.release = mock_fence_release,
> +};
> +
> +static struct dma_fence *mock_fence(void)
> +{
> +	struct mock_fence *f;
> +
> +	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
> +	if (!f)
> +		return NULL;
> +
> +	spin_lock_init(&f->lock);
> +	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
> +
> +	return &f->base;
> +}
> +
> +static struct dma_fence *mock_array(unsigned int num_fences, ...)
> +{
> +	struct dma_fence_array *array;
> +	struct dma_fence **fences;
> +	va_list valist;
> +	int i;
> +
> +	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
> +	if (!fences)
> +		return NULL;
> +
> +	va_start(valist, num_fences);
> +	for (i = 0; i < num_fences; ++i)
> +		fences[i] = va_arg(valist, typeof(*fences));
> +	va_end(valist);
> +
> +	array = dma_fence_array_create(num_fences, fences,
> +				       dma_fence_context_alloc(1),
> +				       1, false);
> +	if (!array)
> +		goto cleanup;
> +	return &array->base;
> +
> +cleanup:
> +	for (i = 0; i < num_fences; ++i)
> +		dma_fence_put(fences[i]);
> +	kfree(fences);
> +	return NULL;
> +}
> +
> +static struct dma_fence *mock_chain(struct dma_fence *prev,
> +				    struct dma_fence *fence)
> +{
> +	struct dma_fence_chain *f;
> +
> +	f = dma_fence_chain_alloc();
> +	if (!f) {
> +		dma_fence_put(prev);
> +		dma_fence_put(fence);
> +		return NULL;
> +	}
> +
> +	dma_fence_chain_init(f, prev, fence, 1);
> +	return &f->base;
> +}
> +
> +static int sanitycheck(void *arg)
> +{
> +	struct dma_fence *f, *chain, *array;
> +	int err = 0;
> +
> +	f = mock_fence();
> +	if (!f)
> +		return -ENOMEM;
> +
> +	array = mock_array(1, f);
> +	if (!array)
> +		return -ENOMEM;
> +
> +	chain = mock_chain(NULL, array);
> +	if (!chain)
> +		return -ENOMEM;
> +
> +	dma_fence_signal(f);
> +	dma_fence_put(chain);
> +	return err;
> +}
> +
> +static int unwrap_array(void *arg)
> +{
> +	struct dma_fence *fence, *f1, *f2, *array;
> +	struct dma_fence_unwrap iter;
> +	int err = 0;
> +
> +	f1 = mock_fence();
> +	if (!f1)
> +		return -ENOMEM;
> +
> +	f2 = mock_fence();
> +	if (!f2) {
> +		dma_fence_put(f1);
> +		return -ENOMEM;
> +	}
> +
> +	array = mock_array(2, f1, f2);
> +	if (!array)
> +		return -ENOMEM;
> +
> +	dma_fence_unwrap_for_each(fence, &iter, array) {
> +		if (fence == f1) {
> +			f1 = NULL;
> +		} else if (fence == f2) {
> +			f2 = NULL;
> +		} else {
> +			pr_err("Unexpected fence!\n");
> +			err = -EINVAL;
> +		}
> +	}
> +
> +	if (f1 || f2) {
> +		pr_err("Not all fences seen!\n");
> +		err = -EINVAL;
> +	}
> +
> +	dma_fence_signal(f1);
> +	dma_fence_signal(f2);
> +	dma_fence_put(array);
> +	return 0;
> +}
> +
> +static int unwrap_chain(void *arg)
> +{
> +	struct dma_fence *fence, *f1, *f2, *chain;
> +	struct dma_fence_unwrap iter;
> +	int err = 0;
> +
> +	f1 = mock_fence();
> +	if (!f1)
> +		return -ENOMEM;
> +
> +	f2 = mock_fence();
> +	if (!f2) {
> +		dma_fence_put(f1);
> +		return -ENOMEM;
> +	}
> +
> +	chain = mock_chain(f1, f2);
> +	if (!chain)
> +		return -ENOMEM;
> +
> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> +		if (fence == f1) {
> +			f1 = NULL;
> +		} else if (fence == f2) {
> +			f2 = NULL;
> +		} else {
> +			pr_err("Unexpected fence!\n");
> +			err = -EINVAL;
> +		}
> +	}
> +
> +	if (f1 || f2) {
> +		pr_err("Not all fences seen!\n");
> +		err = -EINVAL;
> +	}
> +
> +	dma_fence_signal(f1);
> +	dma_fence_signal(f2);
> +	dma_fence_put(chain);
> +	return 0;
> +}
> +
> +static int unwrap_chain_array(void *arg)
> +{
> +	struct dma_fence *fence, *f1, *f2, *array, *chain;
> +	struct dma_fence_unwrap iter;
> +	int err = 0;
> +
> +	f1 = mock_fence();
> +	if (!f1)
> +		return -ENOMEM;
> +
> +	f2 = mock_fence();
> +	if (!f2) {
> +		dma_fence_put(f1);
> +		return -ENOMEM;
> +	}
> +
> +	array = mock_array(2, f1, f2);
> +	if (!array)
> +		return -ENOMEM;
> +
> +	chain = mock_chain(NULL, array);
> +	if (!chain)
> +		return -ENOMEM;
> +
> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> +		if (fence == f1) {
> +			f1 = NULL;
> +		} else if (fence == f2) {
> +			f2 = NULL;
> +		} else {
> +			pr_err("Unexpected fence!\n");
> +			err = -EINVAL;
> +		}
> +	}
> +
> +	if (f1 || f2) {
> +		pr_err("Not all fences seen!\n");
> +		err = -EINVAL;
> +	}
> +
> +	dma_fence_signal(f1);
> +	dma_fence_signal(f2);
> +	dma_fence_put(chain);
> +	return 0;
> +}
> +
> +int dma_fence_unwrap(void)
> +{
> +	static const struct subtest tests[] = {
> +		SUBTEST(sanitycheck),
> +		SUBTEST(unwrap_array),
> +		SUBTEST(unwrap_chain),
> +		SUBTEST(unwrap_chain_array),
> +	};
> +	int ret;
> +
> +	slab_fences = KMEM_CACHE(mock_fence,
> +				 SLAB_TYPESAFE_BY_RCU |
> +				 SLAB_HWCACHE_ALIGN);
> +	if (!slab_fences)
> +		return -ENOMEM;
> +
> +	ret = subtests(tests, NULL);
> +
> +	kmem_cache_destroy(slab_fences);
> +	return ret;
> +}
> diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
> new file mode 100644
> index 000000000000..54963df00c98
> --- /dev/null
> +++ b/include/linux/dma-fence-unwrap.h
> @@ -0,0 +1,99 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * fence-chain: chain fences together in a timeline
> + *
> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> + * Authors:
> + *	Christian König <christian.koenig@amd.com>
> + */
> +
> +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
> +#define __LINUX_DMA_FENCE_UNWRAP_H
> +
> +#include <linux/dma-fence-chain.h>
> +#include <linux/dma-fence-array.h>
> +
> +/**
> + * struct dma_fence_unwrap - cursor into the container structure

I think adding "This should be used together with
dma_fence_unwrap_for_each() iterator macro." would be nice here. I just
like links :-)

> + */
> +struct dma_fence_unwrap {
> +	/**
> +	 * @chain: potential dma_fence_chain, but can be other fence as well
> +	 */
> +	struct dma_fence *chain;
> +	/**
> +	 * @array: potential dma_fence_array, but can be other fence as well
> +	 */
> +	struct dma_fence *array;
> +	/**
> +	 * @index: last returned index if @array is really a dma_fence_array
> +	 */
> +	unsigned int index;
> +};
> +
> +/**
> + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
> + * @cursor: cursor to initialize
> + *
> + * Helper function to unwrap dma_fence_array containers, don't touch directly.
> + * Use dma_fence_unwrap_first/next instead.
> + */
> +static inline struct dma_fence *
> +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)

Since this is a helper that no one should call I'd give it a __ prefix and
drop the kerneldoc. Documenting stuff that people shouldn't use is
confusing :-)

> +{
> +	cursor->array = dma_fence_chain_contained(cursor->chain);
> +	cursor->index = 0;
> +	return dma_fence_array_first(cursor->array);
> +}
> +
> +/**
> + * dma_fence_unwrap_first - return the first fence from fence containers
> + * @head: the entrypoint into the containers
> + * @cursor: current position inside the containers
> + *
> + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
> + * first fence.
> + */
> +static inline struct dma_fence *
> +dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
> +{
> +	cursor->chain = dma_fence_get(head);
> +	return dma_fence_unwrap_array(cursor);
> +}
> +
> +/**
> + * dma_fence_unwrap_next - return the next fence from a fence containers
> + * @cursor: current position inside the containers
> + *
> + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
> + * the next fence from them.
> + */
> +static inline struct dma_fence *
> +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
> +{
> +	struct dma_fence *tmp;
> +
> +	++cursor->index;
> +	tmp = dma_fence_array_next(cursor->array, cursor->index);
> +	if (tmp)
> +		return tmp;
> +
> +	cursor->chain = dma_fence_chain_walk(cursor->chain);
> +	return dma_fence_unwrap_array(cursor);
> +}
> +
> +/**
> + * dma_fence_unwrap_for_each - iterate over all fences in containers
> + * @fence: current fence
> + * @cursor: current position inside the containers
> + * @head: starting point for the iterator
> + *
> + * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
> + * potential fences in them. If @head is just a normal fence only that one is
> + * returned.
> + */
> +#define dma_fence_unwrap_for_each(fence, cursor, head)			\
> +	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
> +	     fence = dma_fence_unwrap_next(cursor))
> +
> +#endif

I think it'd be really good to add a small paragraph to struct
dma_fence_chain that this macro and iterator should be used for walking
over all fences in a chain, including any fence arrays or anything like
that.

With the bikesheds addressed:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> -- 
> 2.25.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-25 10:03   ` Daniel Vetter
@ 2022-03-25 10:07     ` Daniel Vetter
  -1 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-25 10:07 UTC (permalink / raw)
  To: Christian König
  Cc: gustavo, dri-devel, sumit.semwal, linaro-mm-sig,
	Christian König, linux-media

On Fri, Mar 25, 2022 at 11:03:54AM +0100, Daniel Vetter wrote:
> On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> > Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
> > structures and iterate over all the fences in them.
> > 
> > This is useful when we need to flatten out all fences in those structures.
> > 
> > Signed-off-by: Christian König <christian.koenig@amd.com>
> > ---
> >  Documentation/driver-api/dma-buf.rst  |   6 +
> >  drivers/dma-buf/Makefile              |   1 +
> >  drivers/dma-buf/selftests.h           |   1 +
> >  drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
> >  include/linux/dma-fence-unwrap.h      |  99 +++++++++
> >  5 files changed, 386 insertions(+)
> >  create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
> >  create mode 100644 include/linux/dma-fence-unwrap.h
> > 
> > diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
> > index 2cd7db82d9fe..7209500f08c8 100644
> > --- a/Documentation/driver-api/dma-buf.rst
> > +++ b/Documentation/driver-api/dma-buf.rst
> > @@ -194,6 +194,12 @@ DMA Fence Chain
> >  .. kernel-doc:: include/linux/dma-fence-chain.h
> >     :internal:
> >  
> > +DMA Fence unwrap
> > +~~~~~~~~~~~~~~~~
> > +
> > +.. kernel-doc:: include/linux/dma-fence-unwrap.h
> > +   :internal:

Ok I forgot one bikeshed: I'd just include this in dma-fence-chain.h and
maybe go with the dma_fence_chain_unwrap_ prefix for everything. That
makes it even more clearer that the two are meant to go together. Plus ofc
the link from struct dma_fence_chain to this iterator in the docs too.

Or I'm just not understanding why you made this a separate thing?
-Daniel

> > +
> >  DMA Fence uABI/Sync File
> >  ~~~~~~~~~~~~~~~~~~~~~~~~
> >  
> > diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
> > index 511805dbeb75..4c9eb53ba3f8 100644
> > --- a/drivers/dma-buf/Makefile
> > +++ b/drivers/dma-buf/Makefile
> > @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
> >  	selftest.o \
> >  	st-dma-fence.o \
> >  	st-dma-fence-chain.o \
> > +	st-dma-fence-unwrap.o \
> >  	st-dma-resv.o
> >  
> >  obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
> > diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
> > index 97d73aaa31da..851965867d9c 100644
> > --- a/drivers/dma-buf/selftests.h
> > +++ b/drivers/dma-buf/selftests.h
> > @@ -12,4 +12,5 @@
> >  selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
> >  selftest(dma_fence, dma_fence)
> >  selftest(dma_fence_chain, dma_fence_chain)
> > +selftest(dma_fence_unwrap, dma_fence_unwrap)
> >  selftest(dma_resv, dma_resv)
> > diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
> > new file mode 100644
> > index 000000000000..d821faaebe93
> > --- /dev/null
> > +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
> > @@ -0,0 +1,279 @@
> > +// SPDX-License-Identifier: MIT
> > +
> > +/*
> > + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> > + */
> > +
> > +#include <linux/dma-fence-unwrap.h>
> > +#if 0
> > +#include <linux/kernel.h>
> > +#include <linux/kthread.h>
> > +#include <linux/mm.h>
> > +#include <linux/sched/signal.h>
> > +#include <linux/slab.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/random.h>
> > +#endif
> > +
> > +#include "selftest.h"
> > +
> > +#define CHAIN_SZ (4 << 10)
> > +
> > +static struct kmem_cache *slab_fences;
> 
> Your own slab feels a bit like overkill. kmalloc/kfree not good enough?
> 
> > +
> > +static inline struct mock_fence {
> > +	struct dma_fence base;
> > +	spinlock_t lock;
> > +} *to_mock_fence(struct dma_fence *f) {
> > +	return container_of(f, struct mock_fence, base);
> > +}
> > +
> > +static const char *mock_name(struct dma_fence *f)
> > +{
> > +	return "mock";
> > +}
> > +
> > +static void mock_fence_release(struct dma_fence *f)
> > +{
> > +	kmem_cache_free(slab_fences, to_mock_fence(f));
> > +}
> > +
> > +static const struct dma_fence_ops mock_ops = {
> > +	.get_driver_name = mock_name,
> > +	.get_timeline_name = mock_name,
> > +	.release = mock_fence_release,
> > +};
> > +
> > +static struct dma_fence *mock_fence(void)
> > +{
> > +	struct mock_fence *f;
> > +
> > +	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
> > +	if (!f)
> > +		return NULL;
> > +
> > +	spin_lock_init(&f->lock);
> > +	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
> > +
> > +	return &f->base;
> > +}
> > +
> > +static struct dma_fence *mock_array(unsigned int num_fences, ...)
> > +{
> > +	struct dma_fence_array *array;
> > +	struct dma_fence **fences;
> > +	va_list valist;
> > +	int i;
> > +
> > +	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
> > +	if (!fences)
> > +		return NULL;
> > +
> > +	va_start(valist, num_fences);
> > +	for (i = 0; i < num_fences; ++i)
> > +		fences[i] = va_arg(valist, typeof(*fences));
> > +	va_end(valist);
> > +
> > +	array = dma_fence_array_create(num_fences, fences,
> > +				       dma_fence_context_alloc(1),
> > +				       1, false);
> > +	if (!array)
> > +		goto cleanup;
> > +	return &array->base;
> > +
> > +cleanup:
> > +	for (i = 0; i < num_fences; ++i)
> > +		dma_fence_put(fences[i]);
> > +	kfree(fences);
> > +	return NULL;
> > +}
> > +
> > +static struct dma_fence *mock_chain(struct dma_fence *prev,
> > +				    struct dma_fence *fence)
> > +{
> > +	struct dma_fence_chain *f;
> > +
> > +	f = dma_fence_chain_alloc();
> > +	if (!f) {
> > +		dma_fence_put(prev);
> > +		dma_fence_put(fence);
> > +		return NULL;
> > +	}
> > +
> > +	dma_fence_chain_init(f, prev, fence, 1);
> > +	return &f->base;
> > +}
> > +
> > +static int sanitycheck(void *arg)
> > +{
> > +	struct dma_fence *f, *chain, *array;
> > +	int err = 0;
> > +
> > +	f = mock_fence();
> > +	if (!f)
> > +		return -ENOMEM;
> > +
> > +	array = mock_array(1, f);
> > +	if (!array)
> > +		return -ENOMEM;
> > +
> > +	chain = mock_chain(NULL, array);
> > +	if (!chain)
> > +		return -ENOMEM;
> > +
> > +	dma_fence_signal(f);
> > +	dma_fence_put(chain);
> > +	return err;
> > +}
> > +
> > +static int unwrap_array(void *arg)
> > +{
> > +	struct dma_fence *fence, *f1, *f2, *array;
> > +	struct dma_fence_unwrap iter;
> > +	int err = 0;
> > +
> > +	f1 = mock_fence();
> > +	if (!f1)
> > +		return -ENOMEM;
> > +
> > +	f2 = mock_fence();
> > +	if (!f2) {
> > +		dma_fence_put(f1);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	array = mock_array(2, f1, f2);
> > +	if (!array)
> > +		return -ENOMEM;
> > +
> > +	dma_fence_unwrap_for_each(fence, &iter, array) {
> > +		if (fence == f1) {
> > +			f1 = NULL;
> > +		} else if (fence == f2) {
> > +			f2 = NULL;
> > +		} else {
> > +			pr_err("Unexpected fence!\n");
> > +			err = -EINVAL;
> > +		}
> > +	}
> > +
> > +	if (f1 || f2) {
> > +		pr_err("Not all fences seen!\n");
> > +		err = -EINVAL;
> > +	}
> > +
> > +	dma_fence_signal(f1);
> > +	dma_fence_signal(f2);
> > +	dma_fence_put(array);
> > +	return 0;
> > +}
> > +
> > +static int unwrap_chain(void *arg)
> > +{
> > +	struct dma_fence *fence, *f1, *f2, *chain;
> > +	struct dma_fence_unwrap iter;
> > +	int err = 0;
> > +
> > +	f1 = mock_fence();
> > +	if (!f1)
> > +		return -ENOMEM;
> > +
> > +	f2 = mock_fence();
> > +	if (!f2) {
> > +		dma_fence_put(f1);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	chain = mock_chain(f1, f2);
> > +	if (!chain)
> > +		return -ENOMEM;
> > +
> > +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> > +		if (fence == f1) {
> > +			f1 = NULL;
> > +		} else if (fence == f2) {
> > +			f2 = NULL;
> > +		} else {
> > +			pr_err("Unexpected fence!\n");
> > +			err = -EINVAL;
> > +		}
> > +	}
> > +
> > +	if (f1 || f2) {
> > +		pr_err("Not all fences seen!\n");
> > +		err = -EINVAL;
> > +	}
> > +
> > +	dma_fence_signal(f1);
> > +	dma_fence_signal(f2);
> > +	dma_fence_put(chain);
> > +	return 0;
> > +}
> > +
> > +static int unwrap_chain_array(void *arg)
> > +{
> > +	struct dma_fence *fence, *f1, *f2, *array, *chain;
> > +	struct dma_fence_unwrap iter;
> > +	int err = 0;
> > +
> > +	f1 = mock_fence();
> > +	if (!f1)
> > +		return -ENOMEM;
> > +
> > +	f2 = mock_fence();
> > +	if (!f2) {
> > +		dma_fence_put(f1);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	array = mock_array(2, f1, f2);
> > +	if (!array)
> > +		return -ENOMEM;
> > +
> > +	chain = mock_chain(NULL, array);
> > +	if (!chain)
> > +		return -ENOMEM;
> > +
> > +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> > +		if (fence == f1) {
> > +			f1 = NULL;
> > +		} else if (fence == f2) {
> > +			f2 = NULL;
> > +		} else {
> > +			pr_err("Unexpected fence!\n");
> > +			err = -EINVAL;
> > +		}
> > +	}
> > +
> > +	if (f1 || f2) {
> > +		pr_err("Not all fences seen!\n");
> > +		err = -EINVAL;
> > +	}
> > +
> > +	dma_fence_signal(f1);
> > +	dma_fence_signal(f2);
> > +	dma_fence_put(chain);
> > +	return 0;
> > +}
> > +
> > +int dma_fence_unwrap(void)
> > +{
> > +	static const struct subtest tests[] = {
> > +		SUBTEST(sanitycheck),
> > +		SUBTEST(unwrap_array),
> > +		SUBTEST(unwrap_chain),
> > +		SUBTEST(unwrap_chain_array),
> > +	};
> > +	int ret;
> > +
> > +	slab_fences = KMEM_CACHE(mock_fence,
> > +				 SLAB_TYPESAFE_BY_RCU |
> > +				 SLAB_HWCACHE_ALIGN);
> > +	if (!slab_fences)
> > +		return -ENOMEM;
> > +
> > +	ret = subtests(tests, NULL);
> > +
> > +	kmem_cache_destroy(slab_fences);
> > +	return ret;
> > +}
> > diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
> > new file mode 100644
> > index 000000000000..54963df00c98
> > --- /dev/null
> > +++ b/include/linux/dma-fence-unwrap.h
> > @@ -0,0 +1,99 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * fence-chain: chain fences together in a timeline
> > + *
> > + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> > + * Authors:
> > + *	Christian König <christian.koenig@amd.com>
> > + */
> > +
> > +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
> > +#define __LINUX_DMA_FENCE_UNWRAP_H
> > +
> > +#include <linux/dma-fence-chain.h>
> > +#include <linux/dma-fence-array.h>
> > +
> > +/**
> > + * struct dma_fence_unwrap - cursor into the container structure
> 
> I think adding "This should be used together with
> dma_fence_unwrap_for_each() iterator macro." would be nice here. I just
> like links :-)
> 
> > + */
> > +struct dma_fence_unwrap {
> > +	/**
> > +	 * @chain: potential dma_fence_chain, but can be other fence as well
> > +	 */
> > +	struct dma_fence *chain;
> > +	/**
> > +	 * @array: potential dma_fence_array, but can be other fence as well
> > +	 */
> > +	struct dma_fence *array;
> > +	/**
> > +	 * @index: last returned index if @array is really a dma_fence_array
> > +	 */
> > +	unsigned int index;
> > +};
> > +
> > +/**
> > + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
> > + * @cursor: cursor to initialize
> > + *
> > + * Helper function to unwrap dma_fence_array containers, don't touch directly.
> > + * Use dma_fence_unwrap_first/next instead.
> > + */
> > +static inline struct dma_fence *
> > +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
> 
> Since this is a helper that no one should call I'd give it a __ prefix and
> drop the kerneldoc. Documenting stuff that people shouldn't use is
> confusing :-)
> 
> > +{
> > +	cursor->array = dma_fence_chain_contained(cursor->chain);
> > +	cursor->index = 0;
> > +	return dma_fence_array_first(cursor->array);
> > +}
> > +
> > +/**
> > + * dma_fence_unwrap_first - return the first fence from fence containers
> > + * @head: the entrypoint into the containers
> > + * @cursor: current position inside the containers
> > + *
> > + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
> > + * first fence.
> > + */
> > +static inline struct dma_fence *
> > +dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
> > +{
> > +	cursor->chain = dma_fence_get(head);
> > +	return dma_fence_unwrap_array(cursor);
> > +}
> > +
> > +/**
> > + * dma_fence_unwrap_next - return the next fence from a fence containers
> > + * @cursor: current position inside the containers
> > + *
> > + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
> > + * the next fence from them.
> > + */
> > +static inline struct dma_fence *
> > +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
> > +{
> > +	struct dma_fence *tmp;
> > +
> > +	++cursor->index;
> > +	tmp = dma_fence_array_next(cursor->array, cursor->index);
> > +	if (tmp)
> > +		return tmp;
> > +
> > +	cursor->chain = dma_fence_chain_walk(cursor->chain);
> > +	return dma_fence_unwrap_array(cursor);
> > +}
> > +
> > +/**
> > + * dma_fence_unwrap_for_each - iterate over all fences in containers
> > + * @fence: current fence
> > + * @cursor: current position inside the containers
> > + * @head: starting point for the iterator
> > + *
> > + * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
> > + * potential fences in them. If @head is just a normal fence only that one is
> > + * returned.
> > + */
> > +#define dma_fence_unwrap_for_each(fence, cursor, head)			\
> > +	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
> > +	     fence = dma_fence_unwrap_next(cursor))
> > +
> > +#endif
> 
> I think it'd be really good to add a small paragraph to struct
> dma_fence_chain that this macro and iterator should be used for walking
> over all fences in a chain, including any fence arrays or anything like
> that.
> 
> With the bikesheds addressed:
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> > -- 
> > 2.25.1
> > 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
@ 2022-03-25 10:07     ` Daniel Vetter
  0 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-25 10:07 UTC (permalink / raw)
  To: Christian König
  Cc: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig,
	Christian König

On Fri, Mar 25, 2022 at 11:03:54AM +0100, Daniel Vetter wrote:
> On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> > Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
> > structures and iterate over all the fences in them.
> > 
> > This is useful when we need to flatten out all fences in those structures.
> > 
> > Signed-off-by: Christian König <christian.koenig@amd.com>
> > ---
> >  Documentation/driver-api/dma-buf.rst  |   6 +
> >  drivers/dma-buf/Makefile              |   1 +
> >  drivers/dma-buf/selftests.h           |   1 +
> >  drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
> >  include/linux/dma-fence-unwrap.h      |  99 +++++++++
> >  5 files changed, 386 insertions(+)
> >  create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
> >  create mode 100644 include/linux/dma-fence-unwrap.h
> > 
> > diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
> > index 2cd7db82d9fe..7209500f08c8 100644
> > --- a/Documentation/driver-api/dma-buf.rst
> > +++ b/Documentation/driver-api/dma-buf.rst
> > @@ -194,6 +194,12 @@ DMA Fence Chain
> >  .. kernel-doc:: include/linux/dma-fence-chain.h
> >     :internal:
> >  
> > +DMA Fence unwrap
> > +~~~~~~~~~~~~~~~~
> > +
> > +.. kernel-doc:: include/linux/dma-fence-unwrap.h
> > +   :internal:

Ok I forgot one bikeshed: I'd just include this in dma-fence-chain.h and
maybe go with the dma_fence_chain_unwrap_ prefix for everything. That
makes it even more clearer that the two are meant to go together. Plus ofc
the link from struct dma_fence_chain to this iterator in the docs too.

Or I'm just not understanding why you made this a separate thing?
-Daniel

> > +
> >  DMA Fence uABI/Sync File
> >  ~~~~~~~~~~~~~~~~~~~~~~~~
> >  
> > diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
> > index 511805dbeb75..4c9eb53ba3f8 100644
> > --- a/drivers/dma-buf/Makefile
> > +++ b/drivers/dma-buf/Makefile
> > @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
> >  	selftest.o \
> >  	st-dma-fence.o \
> >  	st-dma-fence-chain.o \
> > +	st-dma-fence-unwrap.o \
> >  	st-dma-resv.o
> >  
> >  obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
> > diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
> > index 97d73aaa31da..851965867d9c 100644
> > --- a/drivers/dma-buf/selftests.h
> > +++ b/drivers/dma-buf/selftests.h
> > @@ -12,4 +12,5 @@
> >  selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
> >  selftest(dma_fence, dma_fence)
> >  selftest(dma_fence_chain, dma_fence_chain)
> > +selftest(dma_fence_unwrap, dma_fence_unwrap)
> >  selftest(dma_resv, dma_resv)
> > diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
> > new file mode 100644
> > index 000000000000..d821faaebe93
> > --- /dev/null
> > +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
> > @@ -0,0 +1,279 @@
> > +// SPDX-License-Identifier: MIT
> > +
> > +/*
> > + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> > + */
> > +
> > +#include <linux/dma-fence-unwrap.h>
> > +#if 0
> > +#include <linux/kernel.h>
> > +#include <linux/kthread.h>
> > +#include <linux/mm.h>
> > +#include <linux/sched/signal.h>
> > +#include <linux/slab.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/random.h>
> > +#endif
> > +
> > +#include "selftest.h"
> > +
> > +#define CHAIN_SZ (4 << 10)
> > +
> > +static struct kmem_cache *slab_fences;
> 
> Your own slab feels a bit like overkill. kmalloc/kfree not good enough?
> 
> > +
> > +static inline struct mock_fence {
> > +	struct dma_fence base;
> > +	spinlock_t lock;
> > +} *to_mock_fence(struct dma_fence *f) {
> > +	return container_of(f, struct mock_fence, base);
> > +}
> > +
> > +static const char *mock_name(struct dma_fence *f)
> > +{
> > +	return "mock";
> > +}
> > +
> > +static void mock_fence_release(struct dma_fence *f)
> > +{
> > +	kmem_cache_free(slab_fences, to_mock_fence(f));
> > +}
> > +
> > +static const struct dma_fence_ops mock_ops = {
> > +	.get_driver_name = mock_name,
> > +	.get_timeline_name = mock_name,
> > +	.release = mock_fence_release,
> > +};
> > +
> > +static struct dma_fence *mock_fence(void)
> > +{
> > +	struct mock_fence *f;
> > +
> > +	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
> > +	if (!f)
> > +		return NULL;
> > +
> > +	spin_lock_init(&f->lock);
> > +	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
> > +
> > +	return &f->base;
> > +}
> > +
> > +static struct dma_fence *mock_array(unsigned int num_fences, ...)
> > +{
> > +	struct dma_fence_array *array;
> > +	struct dma_fence **fences;
> > +	va_list valist;
> > +	int i;
> > +
> > +	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
> > +	if (!fences)
> > +		return NULL;
> > +
> > +	va_start(valist, num_fences);
> > +	for (i = 0; i < num_fences; ++i)
> > +		fences[i] = va_arg(valist, typeof(*fences));
> > +	va_end(valist);
> > +
> > +	array = dma_fence_array_create(num_fences, fences,
> > +				       dma_fence_context_alloc(1),
> > +				       1, false);
> > +	if (!array)
> > +		goto cleanup;
> > +	return &array->base;
> > +
> > +cleanup:
> > +	for (i = 0; i < num_fences; ++i)
> > +		dma_fence_put(fences[i]);
> > +	kfree(fences);
> > +	return NULL;
> > +}
> > +
> > +static struct dma_fence *mock_chain(struct dma_fence *prev,
> > +				    struct dma_fence *fence)
> > +{
> > +	struct dma_fence_chain *f;
> > +
> > +	f = dma_fence_chain_alloc();
> > +	if (!f) {
> > +		dma_fence_put(prev);
> > +		dma_fence_put(fence);
> > +		return NULL;
> > +	}
> > +
> > +	dma_fence_chain_init(f, prev, fence, 1);
> > +	return &f->base;
> > +}
> > +
> > +static int sanitycheck(void *arg)
> > +{
> > +	struct dma_fence *f, *chain, *array;
> > +	int err = 0;
> > +
> > +	f = mock_fence();
> > +	if (!f)
> > +		return -ENOMEM;
> > +
> > +	array = mock_array(1, f);
> > +	if (!array)
> > +		return -ENOMEM;
> > +
> > +	chain = mock_chain(NULL, array);
> > +	if (!chain)
> > +		return -ENOMEM;
> > +
> > +	dma_fence_signal(f);
> > +	dma_fence_put(chain);
> > +	return err;
> > +}
> > +
> > +static int unwrap_array(void *arg)
> > +{
> > +	struct dma_fence *fence, *f1, *f2, *array;
> > +	struct dma_fence_unwrap iter;
> > +	int err = 0;
> > +
> > +	f1 = mock_fence();
> > +	if (!f1)
> > +		return -ENOMEM;
> > +
> > +	f2 = mock_fence();
> > +	if (!f2) {
> > +		dma_fence_put(f1);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	array = mock_array(2, f1, f2);
> > +	if (!array)
> > +		return -ENOMEM;
> > +
> > +	dma_fence_unwrap_for_each(fence, &iter, array) {
> > +		if (fence == f1) {
> > +			f1 = NULL;
> > +		} else if (fence == f2) {
> > +			f2 = NULL;
> > +		} else {
> > +			pr_err("Unexpected fence!\n");
> > +			err = -EINVAL;
> > +		}
> > +	}
> > +
> > +	if (f1 || f2) {
> > +		pr_err("Not all fences seen!\n");
> > +		err = -EINVAL;
> > +	}
> > +
> > +	dma_fence_signal(f1);
> > +	dma_fence_signal(f2);
> > +	dma_fence_put(array);
> > +	return 0;
> > +}
> > +
> > +static int unwrap_chain(void *arg)
> > +{
> > +	struct dma_fence *fence, *f1, *f2, *chain;
> > +	struct dma_fence_unwrap iter;
> > +	int err = 0;
> > +
> > +	f1 = mock_fence();
> > +	if (!f1)
> > +		return -ENOMEM;
> > +
> > +	f2 = mock_fence();
> > +	if (!f2) {
> > +		dma_fence_put(f1);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	chain = mock_chain(f1, f2);
> > +	if (!chain)
> > +		return -ENOMEM;
> > +
> > +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> > +		if (fence == f1) {
> > +			f1 = NULL;
> > +		} else if (fence == f2) {
> > +			f2 = NULL;
> > +		} else {
> > +			pr_err("Unexpected fence!\n");
> > +			err = -EINVAL;
> > +		}
> > +	}
> > +
> > +	if (f1 || f2) {
> > +		pr_err("Not all fences seen!\n");
> > +		err = -EINVAL;
> > +	}
> > +
> > +	dma_fence_signal(f1);
> > +	dma_fence_signal(f2);
> > +	dma_fence_put(chain);
> > +	return 0;
> > +}
> > +
> > +static int unwrap_chain_array(void *arg)
> > +{
> > +	struct dma_fence *fence, *f1, *f2, *array, *chain;
> > +	struct dma_fence_unwrap iter;
> > +	int err = 0;
> > +
> > +	f1 = mock_fence();
> > +	if (!f1)
> > +		return -ENOMEM;
> > +
> > +	f2 = mock_fence();
> > +	if (!f2) {
> > +		dma_fence_put(f1);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	array = mock_array(2, f1, f2);
> > +	if (!array)
> > +		return -ENOMEM;
> > +
> > +	chain = mock_chain(NULL, array);
> > +	if (!chain)
> > +		return -ENOMEM;
> > +
> > +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> > +		if (fence == f1) {
> > +			f1 = NULL;
> > +		} else if (fence == f2) {
> > +			f2 = NULL;
> > +		} else {
> > +			pr_err("Unexpected fence!\n");
> > +			err = -EINVAL;
> > +		}
> > +	}
> > +
> > +	if (f1 || f2) {
> > +		pr_err("Not all fences seen!\n");
> > +		err = -EINVAL;
> > +	}
> > +
> > +	dma_fence_signal(f1);
> > +	dma_fence_signal(f2);
> > +	dma_fence_put(chain);
> > +	return 0;
> > +}
> > +
> > +int dma_fence_unwrap(void)
> > +{
> > +	static const struct subtest tests[] = {
> > +		SUBTEST(sanitycheck),
> > +		SUBTEST(unwrap_array),
> > +		SUBTEST(unwrap_chain),
> > +		SUBTEST(unwrap_chain_array),
> > +	};
> > +	int ret;
> > +
> > +	slab_fences = KMEM_CACHE(mock_fence,
> > +				 SLAB_TYPESAFE_BY_RCU |
> > +				 SLAB_HWCACHE_ALIGN);
> > +	if (!slab_fences)
> > +		return -ENOMEM;
> > +
> > +	ret = subtests(tests, NULL);
> > +
> > +	kmem_cache_destroy(slab_fences);
> > +	return ret;
> > +}
> > diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
> > new file mode 100644
> > index 000000000000..54963df00c98
> > --- /dev/null
> > +++ b/include/linux/dma-fence-unwrap.h
> > @@ -0,0 +1,99 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * fence-chain: chain fences together in a timeline
> > + *
> > + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> > + * Authors:
> > + *	Christian König <christian.koenig@amd.com>
> > + */
> > +
> > +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
> > +#define __LINUX_DMA_FENCE_UNWRAP_H
> > +
> > +#include <linux/dma-fence-chain.h>
> > +#include <linux/dma-fence-array.h>
> > +
> > +/**
> > + * struct dma_fence_unwrap - cursor into the container structure
> 
> I think adding "This should be used together with
> dma_fence_unwrap_for_each() iterator macro." would be nice here. I just
> like links :-)
> 
> > + */
> > +struct dma_fence_unwrap {
> > +	/**
> > +	 * @chain: potential dma_fence_chain, but can be other fence as well
> > +	 */
> > +	struct dma_fence *chain;
> > +	/**
> > +	 * @array: potential dma_fence_array, but can be other fence as well
> > +	 */
> > +	struct dma_fence *array;
> > +	/**
> > +	 * @index: last returned index if @array is really a dma_fence_array
> > +	 */
> > +	unsigned int index;
> > +};
> > +
> > +/**
> > + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
> > + * @cursor: cursor to initialize
> > + *
> > + * Helper function to unwrap dma_fence_array containers, don't touch directly.
> > + * Use dma_fence_unwrap_first/next instead.
> > + */
> > +static inline struct dma_fence *
> > +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
> 
> Since this is a helper that no one should call I'd give it a __ prefix and
> drop the kerneldoc. Documenting stuff that people shouldn't use is
> confusing :-)
> 
> > +{
> > +	cursor->array = dma_fence_chain_contained(cursor->chain);
> > +	cursor->index = 0;
> > +	return dma_fence_array_first(cursor->array);
> > +}
> > +
> > +/**
> > + * dma_fence_unwrap_first - return the first fence from fence containers
> > + * @head: the entrypoint into the containers
> > + * @cursor: current position inside the containers
> > + *
> > + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
> > + * first fence.
> > + */
> > +static inline struct dma_fence *
> > +dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
> > +{
> > +	cursor->chain = dma_fence_get(head);
> > +	return dma_fence_unwrap_array(cursor);
> > +}
> > +
> > +/**
> > + * dma_fence_unwrap_next - return the next fence from a fence containers
> > + * @cursor: current position inside the containers
> > + *
> > + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
> > + * the next fence from them.
> > + */
> > +static inline struct dma_fence *
> > +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
> > +{
> > +	struct dma_fence *tmp;
> > +
> > +	++cursor->index;
> > +	tmp = dma_fence_array_next(cursor->array, cursor->index);
> > +	if (tmp)
> > +		return tmp;
> > +
> > +	cursor->chain = dma_fence_chain_walk(cursor->chain);
> > +	return dma_fence_unwrap_array(cursor);
> > +}
> > +
> > +/**
> > + * dma_fence_unwrap_for_each - iterate over all fences in containers
> > + * @fence: current fence
> > + * @cursor: current position inside the containers
> > + * @head: starting point for the iterator
> > + *
> > + * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
> > + * potential fences in them. If @head is just a normal fence only that one is
> > + * returned.
> > + */
> > +#define dma_fence_unwrap_for_each(fence, cursor, head)			\
> > +	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
> > +	     fence = dma_fence_unwrap_next(cursor))
> > +
> > +#endif
> 
> I think it'd be really good to add a small paragraph to struct
> dma_fence_chain that this macro and iterator should be used for walking
> over all fences in a chain, including any fence arrays or anything like
> that.
> 
> With the bikesheds addressed:
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> > -- 
> > 2.25.1
> > 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-25 10:07     ` Daniel Vetter
@ 2022-03-25 10:10       ` Christian König
  -1 siblings, 0 replies; 40+ messages in thread
From: Christian König @ 2022-03-25 10:10 UTC (permalink / raw)
  To: Daniel Vetter, Christian König
  Cc: linaro-mm-sig, gustavo, sumit.semwal, dri-devel, linux-media

Am 25.03.22 um 11:07 schrieb Daniel Vetter:
> On Fri, Mar 25, 2022 at 11:03:54AM +0100, Daniel Vetter wrote:
>> On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
>>> Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
>>> structures and iterate over all the fences in them.
>>>
>>> This is useful when we need to flatten out all fences in those structures.
>>>
>>> Signed-off-by: Christian König <christian.koenig@amd.com>
>>> ---
>>>   Documentation/driver-api/dma-buf.rst  |   6 +
>>>   drivers/dma-buf/Makefile              |   1 +
>>>   drivers/dma-buf/selftests.h           |   1 +
>>>   drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
>>>   include/linux/dma-fence-unwrap.h      |  99 +++++++++
>>>   5 files changed, 386 insertions(+)
>>>   create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
>>>   create mode 100644 include/linux/dma-fence-unwrap.h
>>>
>>> diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
>>> index 2cd7db82d9fe..7209500f08c8 100644
>>> --- a/Documentation/driver-api/dma-buf.rst
>>> +++ b/Documentation/driver-api/dma-buf.rst
>>> @@ -194,6 +194,12 @@ DMA Fence Chain
>>>   .. kernel-doc:: include/linux/dma-fence-chain.h
>>>      :internal:
>>>   
>>> +DMA Fence unwrap
>>> +~~~~~~~~~~~~~~~~
>>> +
>>> +.. kernel-doc:: include/linux/dma-fence-unwrap.h
>>> +   :internal:
> Ok I forgot one bikeshed: I'd just include this in dma-fence-chain.h and
> maybe go with the dma_fence_chain_unwrap_ prefix for everything. That
> makes it even more clearer that the two are meant to go together. Plus ofc
> the link from struct dma_fence_chain to this iterator in the docs too.
>
> Or I'm just not understanding why you made this a separate thing?

Well it should be used to unwrap dma_fence_array containers as well and 
I don't really want to add a dependency between dma_fence_chain and 
dma_fence_array.

I've spend quite some work to keep the two containers separated and also 
describe the separate use cases for each.

I can of course add some kerneldoc to let the chain and array 
documentation point to this one here.

Thanks,
Christian.

> -Daniel
>
>>> +
>>>   DMA Fence uABI/Sync File
>>>   ~~~~~~~~~~~~~~~~~~~~~~~~
>>>   
>>> diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
>>> index 511805dbeb75..4c9eb53ba3f8 100644
>>> --- a/drivers/dma-buf/Makefile
>>> +++ b/drivers/dma-buf/Makefile
>>> @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
>>>   	selftest.o \
>>>   	st-dma-fence.o \
>>>   	st-dma-fence-chain.o \
>>> +	st-dma-fence-unwrap.o \
>>>   	st-dma-resv.o
>>>   
>>>   obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
>>> diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
>>> index 97d73aaa31da..851965867d9c 100644
>>> --- a/drivers/dma-buf/selftests.h
>>> +++ b/drivers/dma-buf/selftests.h
>>> @@ -12,4 +12,5 @@
>>>   selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
>>>   selftest(dma_fence, dma_fence)
>>>   selftest(dma_fence_chain, dma_fence_chain)
>>> +selftest(dma_fence_unwrap, dma_fence_unwrap)
>>>   selftest(dma_resv, dma_resv)
>>> diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
>>> new file mode 100644
>>> index 000000000000..d821faaebe93
>>> --- /dev/null
>>> +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
>>> @@ -0,0 +1,279 @@
>>> +// SPDX-License-Identifier: MIT
>>> +
>>> +/*
>>> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
>>> + */
>>> +
>>> +#include <linux/dma-fence-unwrap.h>
>>> +#if 0
>>> +#include <linux/kernel.h>
>>> +#include <linux/kthread.h>
>>> +#include <linux/mm.h>
>>> +#include <linux/sched/signal.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/spinlock.h>
>>> +#include <linux/random.h>
>>> +#endif
>>> +
>>> +#include "selftest.h"
>>> +
>>> +#define CHAIN_SZ (4 << 10)
>>> +
>>> +static struct kmem_cache *slab_fences;
>> Your own slab feels a bit like overkill. kmalloc/kfree not good enough?
>>
>>> +
>>> +static inline struct mock_fence {
>>> +	struct dma_fence base;
>>> +	spinlock_t lock;
>>> +} *to_mock_fence(struct dma_fence *f) {
>>> +	return container_of(f, struct mock_fence, base);
>>> +}
>>> +
>>> +static const char *mock_name(struct dma_fence *f)
>>> +{
>>> +	return "mock";
>>> +}
>>> +
>>> +static void mock_fence_release(struct dma_fence *f)
>>> +{
>>> +	kmem_cache_free(slab_fences, to_mock_fence(f));
>>> +}
>>> +
>>> +static const struct dma_fence_ops mock_ops = {
>>> +	.get_driver_name = mock_name,
>>> +	.get_timeline_name = mock_name,
>>> +	.release = mock_fence_release,
>>> +};
>>> +
>>> +static struct dma_fence *mock_fence(void)
>>> +{
>>> +	struct mock_fence *f;
>>> +
>>> +	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
>>> +	if (!f)
>>> +		return NULL;
>>> +
>>> +	spin_lock_init(&f->lock);
>>> +	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
>>> +
>>> +	return &f->base;
>>> +}
>>> +
>>> +static struct dma_fence *mock_array(unsigned int num_fences, ...)
>>> +{
>>> +	struct dma_fence_array *array;
>>> +	struct dma_fence **fences;
>>> +	va_list valist;
>>> +	int i;
>>> +
>>> +	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
>>> +	if (!fences)
>>> +		return NULL;
>>> +
>>> +	va_start(valist, num_fences);
>>> +	for (i = 0; i < num_fences; ++i)
>>> +		fences[i] = va_arg(valist, typeof(*fences));
>>> +	va_end(valist);
>>> +
>>> +	array = dma_fence_array_create(num_fences, fences,
>>> +				       dma_fence_context_alloc(1),
>>> +				       1, false);
>>> +	if (!array)
>>> +		goto cleanup;
>>> +	return &array->base;
>>> +
>>> +cleanup:
>>> +	for (i = 0; i < num_fences; ++i)
>>> +		dma_fence_put(fences[i]);
>>> +	kfree(fences);
>>> +	return NULL;
>>> +}
>>> +
>>> +static struct dma_fence *mock_chain(struct dma_fence *prev,
>>> +				    struct dma_fence *fence)
>>> +{
>>> +	struct dma_fence_chain *f;
>>> +
>>> +	f = dma_fence_chain_alloc();
>>> +	if (!f) {
>>> +		dma_fence_put(prev);
>>> +		dma_fence_put(fence);
>>> +		return NULL;
>>> +	}
>>> +
>>> +	dma_fence_chain_init(f, prev, fence, 1);
>>> +	return &f->base;
>>> +}
>>> +
>>> +static int sanitycheck(void *arg)
>>> +{
>>> +	struct dma_fence *f, *chain, *array;
>>> +	int err = 0;
>>> +
>>> +	f = mock_fence();
>>> +	if (!f)
>>> +		return -ENOMEM;
>>> +
>>> +	array = mock_array(1, f);
>>> +	if (!array)
>>> +		return -ENOMEM;
>>> +
>>> +	chain = mock_chain(NULL, array);
>>> +	if (!chain)
>>> +		return -ENOMEM;
>>> +
>>> +	dma_fence_signal(f);
>>> +	dma_fence_put(chain);
>>> +	return err;
>>> +}
>>> +
>>> +static int unwrap_array(void *arg)
>>> +{
>>> +	struct dma_fence *fence, *f1, *f2, *array;
>>> +	struct dma_fence_unwrap iter;
>>> +	int err = 0;
>>> +
>>> +	f1 = mock_fence();
>>> +	if (!f1)
>>> +		return -ENOMEM;
>>> +
>>> +	f2 = mock_fence();
>>> +	if (!f2) {
>>> +		dma_fence_put(f1);
>>> +		return -ENOMEM;
>>> +	}
>>> +
>>> +	array = mock_array(2, f1, f2);
>>> +	if (!array)
>>> +		return -ENOMEM;
>>> +
>>> +	dma_fence_unwrap_for_each(fence, &iter, array) {
>>> +		if (fence == f1) {
>>> +			f1 = NULL;
>>> +		} else if (fence == f2) {
>>> +			f2 = NULL;
>>> +		} else {
>>> +			pr_err("Unexpected fence!\n");
>>> +			err = -EINVAL;
>>> +		}
>>> +	}
>>> +
>>> +	if (f1 || f2) {
>>> +		pr_err("Not all fences seen!\n");
>>> +		err = -EINVAL;
>>> +	}
>>> +
>>> +	dma_fence_signal(f1);
>>> +	dma_fence_signal(f2);
>>> +	dma_fence_put(array);
>>> +	return 0;
>>> +}
>>> +
>>> +static int unwrap_chain(void *arg)
>>> +{
>>> +	struct dma_fence *fence, *f1, *f2, *chain;
>>> +	struct dma_fence_unwrap iter;
>>> +	int err = 0;
>>> +
>>> +	f1 = mock_fence();
>>> +	if (!f1)
>>> +		return -ENOMEM;
>>> +
>>> +	f2 = mock_fence();
>>> +	if (!f2) {
>>> +		dma_fence_put(f1);
>>> +		return -ENOMEM;
>>> +	}
>>> +
>>> +	chain = mock_chain(f1, f2);
>>> +	if (!chain)
>>> +		return -ENOMEM;
>>> +
>>> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
>>> +		if (fence == f1) {
>>> +			f1 = NULL;
>>> +		} else if (fence == f2) {
>>> +			f2 = NULL;
>>> +		} else {
>>> +			pr_err("Unexpected fence!\n");
>>> +			err = -EINVAL;
>>> +		}
>>> +	}
>>> +
>>> +	if (f1 || f2) {
>>> +		pr_err("Not all fences seen!\n");
>>> +		err = -EINVAL;
>>> +	}
>>> +
>>> +	dma_fence_signal(f1);
>>> +	dma_fence_signal(f2);
>>> +	dma_fence_put(chain);
>>> +	return 0;
>>> +}
>>> +
>>> +static int unwrap_chain_array(void *arg)
>>> +{
>>> +	struct dma_fence *fence, *f1, *f2, *array, *chain;
>>> +	struct dma_fence_unwrap iter;
>>> +	int err = 0;
>>> +
>>> +	f1 = mock_fence();
>>> +	if (!f1)
>>> +		return -ENOMEM;
>>> +
>>> +	f2 = mock_fence();
>>> +	if (!f2) {
>>> +		dma_fence_put(f1);
>>> +		return -ENOMEM;
>>> +	}
>>> +
>>> +	array = mock_array(2, f1, f2);
>>> +	if (!array)
>>> +		return -ENOMEM;
>>> +
>>> +	chain = mock_chain(NULL, array);
>>> +	if (!chain)
>>> +		return -ENOMEM;
>>> +
>>> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
>>> +		if (fence == f1) {
>>> +			f1 = NULL;
>>> +		} else if (fence == f2) {
>>> +			f2 = NULL;
>>> +		} else {
>>> +			pr_err("Unexpected fence!\n");
>>> +			err = -EINVAL;
>>> +		}
>>> +	}
>>> +
>>> +	if (f1 || f2) {
>>> +		pr_err("Not all fences seen!\n");
>>> +		err = -EINVAL;
>>> +	}
>>> +
>>> +	dma_fence_signal(f1);
>>> +	dma_fence_signal(f2);
>>> +	dma_fence_put(chain);
>>> +	return 0;
>>> +}
>>> +
>>> +int dma_fence_unwrap(void)
>>> +{
>>> +	static const struct subtest tests[] = {
>>> +		SUBTEST(sanitycheck),
>>> +		SUBTEST(unwrap_array),
>>> +		SUBTEST(unwrap_chain),
>>> +		SUBTEST(unwrap_chain_array),
>>> +	};
>>> +	int ret;
>>> +
>>> +	slab_fences = KMEM_CACHE(mock_fence,
>>> +				 SLAB_TYPESAFE_BY_RCU |
>>> +				 SLAB_HWCACHE_ALIGN);
>>> +	if (!slab_fences)
>>> +		return -ENOMEM;
>>> +
>>> +	ret = subtests(tests, NULL);
>>> +
>>> +	kmem_cache_destroy(slab_fences);
>>> +	return ret;
>>> +}
>>> diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
>>> new file mode 100644
>>> index 000000000000..54963df00c98
>>> --- /dev/null
>>> +++ b/include/linux/dma-fence-unwrap.h
>>> @@ -0,0 +1,99 @@
>>> +/* SPDX-License-Identifier: GPL-2.0-only */
>>> +/*
>>> + * fence-chain: chain fences together in a timeline
>>> + *
>>> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
>>> + * Authors:
>>> + *	Christian König <christian.koenig@amd.com>
>>> + */
>>> +
>>> +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
>>> +#define __LINUX_DMA_FENCE_UNWRAP_H
>>> +
>>> +#include <linux/dma-fence-chain.h>
>>> +#include <linux/dma-fence-array.h>
>>> +
>>> +/**
>>> + * struct dma_fence_unwrap - cursor into the container structure
>> I think adding "This should be used together with
>> dma_fence_unwrap_for_each() iterator macro." would be nice here. I just
>> like links :-)
>>
>>> + */
>>> +struct dma_fence_unwrap {
>>> +	/**
>>> +	 * @chain: potential dma_fence_chain, but can be other fence as well
>>> +	 */
>>> +	struct dma_fence *chain;
>>> +	/**
>>> +	 * @array: potential dma_fence_array, but can be other fence as well
>>> +	 */
>>> +	struct dma_fence *array;
>>> +	/**
>>> +	 * @index: last returned index if @array is really a dma_fence_array
>>> +	 */
>>> +	unsigned int index;
>>> +};
>>> +
>>> +/**
>>> + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
>>> + * @cursor: cursor to initialize
>>> + *
>>> + * Helper function to unwrap dma_fence_array containers, don't touch directly.
>>> + * Use dma_fence_unwrap_first/next instead.
>>> + */
>>> +static inline struct dma_fence *
>>> +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
>> Since this is a helper that no one should call I'd give it a __ prefix and
>> drop the kerneldoc. Documenting stuff that people shouldn't use is
>> confusing :-)
>>
>>> +{
>>> +	cursor->array = dma_fence_chain_contained(cursor->chain);
>>> +	cursor->index = 0;
>>> +	return dma_fence_array_first(cursor->array);
>>> +}
>>> +
>>> +/**
>>> + * dma_fence_unwrap_first - return the first fence from fence containers
>>> + * @head: the entrypoint into the containers
>>> + * @cursor: current position inside the containers
>>> + *
>>> + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
>>> + * first fence.
>>> + */
>>> +static inline struct dma_fence *
>>> +dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
>>> +{
>>> +	cursor->chain = dma_fence_get(head);
>>> +	return dma_fence_unwrap_array(cursor);
>>> +}
>>> +
>>> +/**
>>> + * dma_fence_unwrap_next - return the next fence from a fence containers
>>> + * @cursor: current position inside the containers
>>> + *
>>> + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
>>> + * the next fence from them.
>>> + */
>>> +static inline struct dma_fence *
>>> +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
>>> +{
>>> +	struct dma_fence *tmp;
>>> +
>>> +	++cursor->index;
>>> +	tmp = dma_fence_array_next(cursor->array, cursor->index);
>>> +	if (tmp)
>>> +		return tmp;
>>> +
>>> +	cursor->chain = dma_fence_chain_walk(cursor->chain);
>>> +	return dma_fence_unwrap_array(cursor);
>>> +}
>>> +
>>> +/**
>>> + * dma_fence_unwrap_for_each - iterate over all fences in containers
>>> + * @fence: current fence
>>> + * @cursor: current position inside the containers
>>> + * @head: starting point for the iterator
>>> + *
>>> + * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
>>> + * potential fences in them. If @head is just a normal fence only that one is
>>> + * returned.
>>> + */
>>> +#define dma_fence_unwrap_for_each(fence, cursor, head)			\
>>> +	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
>>> +	     fence = dma_fence_unwrap_next(cursor))
>>> +
>>> +#endif
>> I think it'd be really good to add a small paragraph to struct
>> dma_fence_chain that this macro and iterator should be used for walking
>> over all fences in a chain, including any fence arrays or anything like
>> that.
>>
>> With the bikesheds addressed:
>>
>> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>>
>>> -- 
>>> 2.25.1
>>>
>> -- 
>> Daniel Vetter
>> Software Engineer, Intel Corporation
>> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.ffwll.ch%2F&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7Caa747083900b451d359308da0e4745e3%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637837996532802687%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=Jts5%2BObWJHeUG4oy2biwj5Bf3PKkMrYU%2F0EihvQRNuY%3D&amp;reserved=0


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
@ 2022-03-25 10:10       ` Christian König
  0 siblings, 0 replies; 40+ messages in thread
From: Christian König @ 2022-03-25 10:10 UTC (permalink / raw)
  To: Daniel Vetter, Christian König
  Cc: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig

Am 25.03.22 um 11:07 schrieb Daniel Vetter:
> On Fri, Mar 25, 2022 at 11:03:54AM +0100, Daniel Vetter wrote:
>> On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
>>> Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
>>> structures and iterate over all the fences in them.
>>>
>>> This is useful when we need to flatten out all fences in those structures.
>>>
>>> Signed-off-by: Christian König <christian.koenig@amd.com>
>>> ---
>>>   Documentation/driver-api/dma-buf.rst  |   6 +
>>>   drivers/dma-buf/Makefile              |   1 +
>>>   drivers/dma-buf/selftests.h           |   1 +
>>>   drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
>>>   include/linux/dma-fence-unwrap.h      |  99 +++++++++
>>>   5 files changed, 386 insertions(+)
>>>   create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
>>>   create mode 100644 include/linux/dma-fence-unwrap.h
>>>
>>> diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
>>> index 2cd7db82d9fe..7209500f08c8 100644
>>> --- a/Documentation/driver-api/dma-buf.rst
>>> +++ b/Documentation/driver-api/dma-buf.rst
>>> @@ -194,6 +194,12 @@ DMA Fence Chain
>>>   .. kernel-doc:: include/linux/dma-fence-chain.h
>>>      :internal:
>>>   
>>> +DMA Fence unwrap
>>> +~~~~~~~~~~~~~~~~
>>> +
>>> +.. kernel-doc:: include/linux/dma-fence-unwrap.h
>>> +   :internal:
> Ok I forgot one bikeshed: I'd just include this in dma-fence-chain.h and
> maybe go with the dma_fence_chain_unwrap_ prefix for everything. That
> makes it even more clearer that the two are meant to go together. Plus ofc
> the link from struct dma_fence_chain to this iterator in the docs too.
>
> Or I'm just not understanding why you made this a separate thing?

Well it should be used to unwrap dma_fence_array containers as well and 
I don't really want to add a dependency between dma_fence_chain and 
dma_fence_array.

I've spend quite some work to keep the two containers separated and also 
describe the separate use cases for each.

I can of course add some kerneldoc to let the chain and array 
documentation point to this one here.

Thanks,
Christian.

> -Daniel
>
>>> +
>>>   DMA Fence uABI/Sync File
>>>   ~~~~~~~~~~~~~~~~~~~~~~~~
>>>   
>>> diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
>>> index 511805dbeb75..4c9eb53ba3f8 100644
>>> --- a/drivers/dma-buf/Makefile
>>> +++ b/drivers/dma-buf/Makefile
>>> @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
>>>   	selftest.o \
>>>   	st-dma-fence.o \
>>>   	st-dma-fence-chain.o \
>>> +	st-dma-fence-unwrap.o \
>>>   	st-dma-resv.o
>>>   
>>>   obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
>>> diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
>>> index 97d73aaa31da..851965867d9c 100644
>>> --- a/drivers/dma-buf/selftests.h
>>> +++ b/drivers/dma-buf/selftests.h
>>> @@ -12,4 +12,5 @@
>>>   selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
>>>   selftest(dma_fence, dma_fence)
>>>   selftest(dma_fence_chain, dma_fence_chain)
>>> +selftest(dma_fence_unwrap, dma_fence_unwrap)
>>>   selftest(dma_resv, dma_resv)
>>> diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
>>> new file mode 100644
>>> index 000000000000..d821faaebe93
>>> --- /dev/null
>>> +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
>>> @@ -0,0 +1,279 @@
>>> +// SPDX-License-Identifier: MIT
>>> +
>>> +/*
>>> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
>>> + */
>>> +
>>> +#include <linux/dma-fence-unwrap.h>
>>> +#if 0
>>> +#include <linux/kernel.h>
>>> +#include <linux/kthread.h>
>>> +#include <linux/mm.h>
>>> +#include <linux/sched/signal.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/spinlock.h>
>>> +#include <linux/random.h>
>>> +#endif
>>> +
>>> +#include "selftest.h"
>>> +
>>> +#define CHAIN_SZ (4 << 10)
>>> +
>>> +static struct kmem_cache *slab_fences;
>> Your own slab feels a bit like overkill. kmalloc/kfree not good enough?
>>
>>> +
>>> +static inline struct mock_fence {
>>> +	struct dma_fence base;
>>> +	spinlock_t lock;
>>> +} *to_mock_fence(struct dma_fence *f) {
>>> +	return container_of(f, struct mock_fence, base);
>>> +}
>>> +
>>> +static const char *mock_name(struct dma_fence *f)
>>> +{
>>> +	return "mock";
>>> +}
>>> +
>>> +static void mock_fence_release(struct dma_fence *f)
>>> +{
>>> +	kmem_cache_free(slab_fences, to_mock_fence(f));
>>> +}
>>> +
>>> +static const struct dma_fence_ops mock_ops = {
>>> +	.get_driver_name = mock_name,
>>> +	.get_timeline_name = mock_name,
>>> +	.release = mock_fence_release,
>>> +};
>>> +
>>> +static struct dma_fence *mock_fence(void)
>>> +{
>>> +	struct mock_fence *f;
>>> +
>>> +	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
>>> +	if (!f)
>>> +		return NULL;
>>> +
>>> +	spin_lock_init(&f->lock);
>>> +	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
>>> +
>>> +	return &f->base;
>>> +}
>>> +
>>> +static struct dma_fence *mock_array(unsigned int num_fences, ...)
>>> +{
>>> +	struct dma_fence_array *array;
>>> +	struct dma_fence **fences;
>>> +	va_list valist;
>>> +	int i;
>>> +
>>> +	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
>>> +	if (!fences)
>>> +		return NULL;
>>> +
>>> +	va_start(valist, num_fences);
>>> +	for (i = 0; i < num_fences; ++i)
>>> +		fences[i] = va_arg(valist, typeof(*fences));
>>> +	va_end(valist);
>>> +
>>> +	array = dma_fence_array_create(num_fences, fences,
>>> +				       dma_fence_context_alloc(1),
>>> +				       1, false);
>>> +	if (!array)
>>> +		goto cleanup;
>>> +	return &array->base;
>>> +
>>> +cleanup:
>>> +	for (i = 0; i < num_fences; ++i)
>>> +		dma_fence_put(fences[i]);
>>> +	kfree(fences);
>>> +	return NULL;
>>> +}
>>> +
>>> +static struct dma_fence *mock_chain(struct dma_fence *prev,
>>> +				    struct dma_fence *fence)
>>> +{
>>> +	struct dma_fence_chain *f;
>>> +
>>> +	f = dma_fence_chain_alloc();
>>> +	if (!f) {
>>> +		dma_fence_put(prev);
>>> +		dma_fence_put(fence);
>>> +		return NULL;
>>> +	}
>>> +
>>> +	dma_fence_chain_init(f, prev, fence, 1);
>>> +	return &f->base;
>>> +}
>>> +
>>> +static int sanitycheck(void *arg)
>>> +{
>>> +	struct dma_fence *f, *chain, *array;
>>> +	int err = 0;
>>> +
>>> +	f = mock_fence();
>>> +	if (!f)
>>> +		return -ENOMEM;
>>> +
>>> +	array = mock_array(1, f);
>>> +	if (!array)
>>> +		return -ENOMEM;
>>> +
>>> +	chain = mock_chain(NULL, array);
>>> +	if (!chain)
>>> +		return -ENOMEM;
>>> +
>>> +	dma_fence_signal(f);
>>> +	dma_fence_put(chain);
>>> +	return err;
>>> +}
>>> +
>>> +static int unwrap_array(void *arg)
>>> +{
>>> +	struct dma_fence *fence, *f1, *f2, *array;
>>> +	struct dma_fence_unwrap iter;
>>> +	int err = 0;
>>> +
>>> +	f1 = mock_fence();
>>> +	if (!f1)
>>> +		return -ENOMEM;
>>> +
>>> +	f2 = mock_fence();
>>> +	if (!f2) {
>>> +		dma_fence_put(f1);
>>> +		return -ENOMEM;
>>> +	}
>>> +
>>> +	array = mock_array(2, f1, f2);
>>> +	if (!array)
>>> +		return -ENOMEM;
>>> +
>>> +	dma_fence_unwrap_for_each(fence, &iter, array) {
>>> +		if (fence == f1) {
>>> +			f1 = NULL;
>>> +		} else if (fence == f2) {
>>> +			f2 = NULL;
>>> +		} else {
>>> +			pr_err("Unexpected fence!\n");
>>> +			err = -EINVAL;
>>> +		}
>>> +	}
>>> +
>>> +	if (f1 || f2) {
>>> +		pr_err("Not all fences seen!\n");
>>> +		err = -EINVAL;
>>> +	}
>>> +
>>> +	dma_fence_signal(f1);
>>> +	dma_fence_signal(f2);
>>> +	dma_fence_put(array);
>>> +	return 0;
>>> +}
>>> +
>>> +static int unwrap_chain(void *arg)
>>> +{
>>> +	struct dma_fence *fence, *f1, *f2, *chain;
>>> +	struct dma_fence_unwrap iter;
>>> +	int err = 0;
>>> +
>>> +	f1 = mock_fence();
>>> +	if (!f1)
>>> +		return -ENOMEM;
>>> +
>>> +	f2 = mock_fence();
>>> +	if (!f2) {
>>> +		dma_fence_put(f1);
>>> +		return -ENOMEM;
>>> +	}
>>> +
>>> +	chain = mock_chain(f1, f2);
>>> +	if (!chain)
>>> +		return -ENOMEM;
>>> +
>>> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
>>> +		if (fence == f1) {
>>> +			f1 = NULL;
>>> +		} else if (fence == f2) {
>>> +			f2 = NULL;
>>> +		} else {
>>> +			pr_err("Unexpected fence!\n");
>>> +			err = -EINVAL;
>>> +		}
>>> +	}
>>> +
>>> +	if (f1 || f2) {
>>> +		pr_err("Not all fences seen!\n");
>>> +		err = -EINVAL;
>>> +	}
>>> +
>>> +	dma_fence_signal(f1);
>>> +	dma_fence_signal(f2);
>>> +	dma_fence_put(chain);
>>> +	return 0;
>>> +}
>>> +
>>> +static int unwrap_chain_array(void *arg)
>>> +{
>>> +	struct dma_fence *fence, *f1, *f2, *array, *chain;
>>> +	struct dma_fence_unwrap iter;
>>> +	int err = 0;
>>> +
>>> +	f1 = mock_fence();
>>> +	if (!f1)
>>> +		return -ENOMEM;
>>> +
>>> +	f2 = mock_fence();
>>> +	if (!f2) {
>>> +		dma_fence_put(f1);
>>> +		return -ENOMEM;
>>> +	}
>>> +
>>> +	array = mock_array(2, f1, f2);
>>> +	if (!array)
>>> +		return -ENOMEM;
>>> +
>>> +	chain = mock_chain(NULL, array);
>>> +	if (!chain)
>>> +		return -ENOMEM;
>>> +
>>> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
>>> +		if (fence == f1) {
>>> +			f1 = NULL;
>>> +		} else if (fence == f2) {
>>> +			f2 = NULL;
>>> +		} else {
>>> +			pr_err("Unexpected fence!\n");
>>> +			err = -EINVAL;
>>> +		}
>>> +	}
>>> +
>>> +	if (f1 || f2) {
>>> +		pr_err("Not all fences seen!\n");
>>> +		err = -EINVAL;
>>> +	}
>>> +
>>> +	dma_fence_signal(f1);
>>> +	dma_fence_signal(f2);
>>> +	dma_fence_put(chain);
>>> +	return 0;
>>> +}
>>> +
>>> +int dma_fence_unwrap(void)
>>> +{
>>> +	static const struct subtest tests[] = {
>>> +		SUBTEST(sanitycheck),
>>> +		SUBTEST(unwrap_array),
>>> +		SUBTEST(unwrap_chain),
>>> +		SUBTEST(unwrap_chain_array),
>>> +	};
>>> +	int ret;
>>> +
>>> +	slab_fences = KMEM_CACHE(mock_fence,
>>> +				 SLAB_TYPESAFE_BY_RCU |
>>> +				 SLAB_HWCACHE_ALIGN);
>>> +	if (!slab_fences)
>>> +		return -ENOMEM;
>>> +
>>> +	ret = subtests(tests, NULL);
>>> +
>>> +	kmem_cache_destroy(slab_fences);
>>> +	return ret;
>>> +}
>>> diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
>>> new file mode 100644
>>> index 000000000000..54963df00c98
>>> --- /dev/null
>>> +++ b/include/linux/dma-fence-unwrap.h
>>> @@ -0,0 +1,99 @@
>>> +/* SPDX-License-Identifier: GPL-2.0-only */
>>> +/*
>>> + * fence-chain: chain fences together in a timeline
>>> + *
>>> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
>>> + * Authors:
>>> + *	Christian König <christian.koenig@amd.com>
>>> + */
>>> +
>>> +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
>>> +#define __LINUX_DMA_FENCE_UNWRAP_H
>>> +
>>> +#include <linux/dma-fence-chain.h>
>>> +#include <linux/dma-fence-array.h>
>>> +
>>> +/**
>>> + * struct dma_fence_unwrap - cursor into the container structure
>> I think adding "This should be used together with
>> dma_fence_unwrap_for_each() iterator macro." would be nice here. I just
>> like links :-)
>>
>>> + */
>>> +struct dma_fence_unwrap {
>>> +	/**
>>> +	 * @chain: potential dma_fence_chain, but can be other fence as well
>>> +	 */
>>> +	struct dma_fence *chain;
>>> +	/**
>>> +	 * @array: potential dma_fence_array, but can be other fence as well
>>> +	 */
>>> +	struct dma_fence *array;
>>> +	/**
>>> +	 * @index: last returned index if @array is really a dma_fence_array
>>> +	 */
>>> +	unsigned int index;
>>> +};
>>> +
>>> +/**
>>> + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
>>> + * @cursor: cursor to initialize
>>> + *
>>> + * Helper function to unwrap dma_fence_array containers, don't touch directly.
>>> + * Use dma_fence_unwrap_first/next instead.
>>> + */
>>> +static inline struct dma_fence *
>>> +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
>> Since this is a helper that no one should call I'd give it a __ prefix and
>> drop the kerneldoc. Documenting stuff that people shouldn't use is
>> confusing :-)
>>
>>> +{
>>> +	cursor->array = dma_fence_chain_contained(cursor->chain);
>>> +	cursor->index = 0;
>>> +	return dma_fence_array_first(cursor->array);
>>> +}
>>> +
>>> +/**
>>> + * dma_fence_unwrap_first - return the first fence from fence containers
>>> + * @head: the entrypoint into the containers
>>> + * @cursor: current position inside the containers
>>> + *
>>> + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
>>> + * first fence.
>>> + */
>>> +static inline struct dma_fence *
>>> +dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
>>> +{
>>> +	cursor->chain = dma_fence_get(head);
>>> +	return dma_fence_unwrap_array(cursor);
>>> +}
>>> +
>>> +/**
>>> + * dma_fence_unwrap_next - return the next fence from a fence containers
>>> + * @cursor: current position inside the containers
>>> + *
>>> + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
>>> + * the next fence from them.
>>> + */
>>> +static inline struct dma_fence *
>>> +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
>>> +{
>>> +	struct dma_fence *tmp;
>>> +
>>> +	++cursor->index;
>>> +	tmp = dma_fence_array_next(cursor->array, cursor->index);
>>> +	if (tmp)
>>> +		return tmp;
>>> +
>>> +	cursor->chain = dma_fence_chain_walk(cursor->chain);
>>> +	return dma_fence_unwrap_array(cursor);
>>> +}
>>> +
>>> +/**
>>> + * dma_fence_unwrap_for_each - iterate over all fences in containers
>>> + * @fence: current fence
>>> + * @cursor: current position inside the containers
>>> + * @head: starting point for the iterator
>>> + *
>>> + * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
>>> + * potential fences in them. If @head is just a normal fence only that one is
>>> + * returned.
>>> + */
>>> +#define dma_fence_unwrap_for_each(fence, cursor, head)			\
>>> +	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
>>> +	     fence = dma_fence_unwrap_next(cursor))
>>> +
>>> +#endif
>> I think it'd be really good to add a small paragraph to struct
>> dma_fence_chain that this macro and iterator should be used for walking
>> over all fences in a chain, including any fence arrays or anything like
>> that.
>>
>> With the bikesheds addressed:
>>
>> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>>
>>> -- 
>>> 2.25.1
>>>
>> -- 
>> Daniel Vetter
>> Software Engineer, Intel Corporation
>> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.ffwll.ch%2F&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7Caa747083900b451d359308da0e4745e3%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637837996532802687%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=Jts5%2BObWJHeUG4oy2biwj5Bf3PKkMrYU%2F0EihvQRNuY%3D&amp;reserved=0


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers
  2022-03-11 11:02 ` [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers Christian König
@ 2022-03-25 10:13     ` Daniel Vetter
  2022-03-11 17:59   ` kernel test robot
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-25 10:13 UTC (permalink / raw)
  To: Christian König
  Cc: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig,
	Christian König

On Fri, Mar 11, 2022 at 12:02:44PM +0100, Christian König wrote:
> The dma_fence_chain containers can show up in sync_files as well resulting in
> warnings that those can't be added to dma_fence_array containers when merging
> multiple sync_files together.
> 
> Solve this by using the dma_fence_unwrap iterator to deep dive into the
> contained fences and then add those flatten out into a dma_fence_array.
> 
> Signed-off-by: Christian König <christian.koenig@amd.com>

I have no idea why we try to keep fences sorted, but oh well it looks like
the merging is done correctly.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/dma-buf/sync_file.c | 141 +++++++++++++++++++-----------------
>  1 file changed, 73 insertions(+), 68 deletions(-)
> 
> diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
> index 394e6e1e9686..b8dea4ec123b 100644
> --- a/drivers/dma-buf/sync_file.c
> +++ b/drivers/dma-buf/sync_file.c
> @@ -5,6 +5,7 @@
>   * Copyright (C) 2012 Google, Inc.
>   */
>  
> +#include <linux/dma-fence-unwrap.h>
>  #include <linux/export.h>
>  #include <linux/file.h>
>  #include <linux/fs.h>
> @@ -172,20 +173,6 @@ static int sync_file_set_fence(struct sync_file *sync_file,
>  	return 0;
>  }
>  
> -static struct dma_fence **get_fences(struct sync_file *sync_file,
> -				     int *num_fences)
> -{
> -	if (dma_fence_is_array(sync_file->fence)) {
> -		struct dma_fence_array *array = to_dma_fence_array(sync_file->fence);
> -
> -		*num_fences = array->num_fences;
> -		return array->fences;
> -	}
> -
> -	*num_fences = 1;
> -	return &sync_file->fence;
> -}
> -
>  static void add_fence(struct dma_fence **fences,
>  		      int *i, struct dma_fence *fence)
>  {
> @@ -210,86 +197,97 @@ static void add_fence(struct dma_fence **fences,
>  static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
>  					 struct sync_file *b)
>  {
> +	struct dma_fence *a_fence, *b_fence, **fences;
> +	struct dma_fence_unwrap a_iter, b_iter;
> +	unsigned int index, num_fences;
>  	struct sync_file *sync_file;
> -	struct dma_fence **fences = NULL, **nfences, **a_fences, **b_fences;
> -	int i = 0, i_a, i_b, num_fences, a_num_fences, b_num_fences;
>  
>  	sync_file = sync_file_alloc();
>  	if (!sync_file)
>  		return NULL;
>  
> -	a_fences = get_fences(a, &a_num_fences);
> -	b_fences = get_fences(b, &b_num_fences);
> -	if (a_num_fences > INT_MAX - b_num_fences)
> -		goto err;
> +	num_fences = 0;
> +	dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence)
> +		++num_fences;
> +	dma_fence_unwrap_for_each(b_fence, &b_iter, b->fence)
> +		++num_fences;
>  
> -	num_fences = a_num_fences + b_num_fences;
> +	if (num_fences > INT_MAX)
> +		goto err_free_sync_file;
>  
>  	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
>  	if (!fences)
> -		goto err;
> +		goto err_free_sync_file;
>  
>  	/*
> -	 * Assume sync_file a and b are both ordered and have no
> -	 * duplicates with the same context.
> +	 * We can't guarantee that fences in both a and b are ordered, but it is
> +	 * still quite likely.
>  	 *
> -	 * If a sync_file can only be created with sync_file_merge
> -	 * and sync_file_create, this is a reasonable assumption.
> +	 * So attempt to order the fences as we pass over them and merge fences
> +	 * with the same context.
>  	 */
> -	for (i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
> -		struct dma_fence *pt_a = a_fences[i_a];
> -		struct dma_fence *pt_b = b_fences[i_b];
>  
> -		if (pt_a->context < pt_b->context) {
> -			add_fence(fences, &i, pt_a);
> +	index = 0;
> +	for (a_fence = dma_fence_unwrap_first(a->fence, &a_iter),
> +	     b_fence = dma_fence_unwrap_first(b->fence, &b_iter);
> +	     a_fence || b_fence; ) {
> +
> +		if (!b_fence) {
> +			add_fence(fences, &index, a_fence);
> +			a_fence = dma_fence_unwrap_next(&a_iter);
> +
> +		} else if (!a_fence) {
> +			add_fence(fences, &index, b_fence);
> +			b_fence = dma_fence_unwrap_next(&b_iter);
> +
> +		} else if (a_fence->context < b_fence->context) {
> +			add_fence(fences, &index, a_fence);
> +			a_fence = dma_fence_unwrap_next(&a_iter);
>  
> -			i_a++;
> -		} else if (pt_a->context > pt_b->context) {
> -			add_fence(fences, &i, pt_b);
> +		} else if (b_fence->context < a_fence->context) {
> +			add_fence(fences, &index, b_fence);
> +			b_fence = dma_fence_unwrap_next(&b_iter);
> +
> +		} else if (__dma_fence_is_later(a_fence->seqno, b_fence->seqno,
> +						a_fence->ops)) {
> +			add_fence(fences, &index, a_fence);
> +			a_fence = dma_fence_unwrap_next(&a_iter);
> +			b_fence = dma_fence_unwrap_next(&b_iter);
>  
> -			i_b++;
>  		} else {
> -			if (__dma_fence_is_later(pt_a->seqno, pt_b->seqno,
> -						 pt_a->ops))
> -				add_fence(fences, &i, pt_a);
> -			else
> -				add_fence(fences, &i, pt_b);
> -
> -			i_a++;
> -			i_b++;
> +			add_fence(fences, &index, b_fence);
> +			a_fence = dma_fence_unwrap_next(&a_iter);
> +			b_fence = dma_fence_unwrap_next(&b_iter);
>  		}
>  	}
>  
> -	for (; i_a < a_num_fences; i_a++)
> -		add_fence(fences, &i, a_fences[i_a]);
> -
> -	for (; i_b < b_num_fences; i_b++)
> -		add_fence(fences, &i, b_fences[i_b]);
> -
> -	if (i == 0)
> -		fences[i++] = dma_fence_get(a_fences[0]);
> +	if (index == 0)
> +		add_fence(fences, &index, dma_fence_get_stub());
>  
> -	if (num_fences > i) {
> -		nfences = krealloc_array(fences, i, sizeof(*fences), GFP_KERNEL);
> -		if (!nfences)
> -			goto err;
> +	if (num_fences > index) {
> +		struct dma_fence **tmp;
>  
> -		fences = nfences;
> +		/* Keep going even when reducing the size failed */
> +		tmp = krealloc_array(fences, index, sizeof(*fences),
> +				     GFP_KERNEL);
> +		if (tmp)
> +			fences = tmp;
>  	}
>  
> -	if (sync_file_set_fence(sync_file, fences, i) < 0)
> -		goto err;
> +	if (sync_file_set_fence(sync_file, fences, index) < 0)
> +		goto err_put_fences;
>  
>  	strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
>  	return sync_file;
>  
> -err:
> -	while (i)
> -		dma_fence_put(fences[--i]);
> +err_put_fences:
> +	while (index)
> +		dma_fence_put(fences[--index]);
>  	kfree(fences);
> +
> +err_free_sync_file:
>  	fput(sync_file->file);
>  	return NULL;
> -
>  }
>  
>  static int sync_file_release(struct inode *inode, struct file *file)
> @@ -398,11 +396,13 @@ static int sync_fill_fence_info(struct dma_fence *fence,
>  static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
>  				       unsigned long arg)
>  {
> -	struct sync_file_info info;
>  	struct sync_fence_info *fence_info = NULL;
> -	struct dma_fence **fences;
> +	struct dma_fence_unwrap iter;
> +	struct sync_file_info info;
> +	unsigned int num_fences;
> +	struct dma_fence *fence;
> +	int ret;
>  	__u32 size;
> -	int num_fences, ret, i;
>  
>  	if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
>  		return -EFAULT;
> @@ -410,7 +410,9 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
>  	if (info.flags || info.pad)
>  		return -EINVAL;
>  
> -	fences = get_fences(sync_file, &num_fences);
> +	num_fences = 0;
> +	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence)
> +		++num_fences;
>  
>  	/*
>  	 * Passing num_fences = 0 means that userspace doesn't want to
> @@ -433,8 +435,11 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
>  	if (!fence_info)
>  		return -ENOMEM;
>  
> -	for (i = 0; i < num_fences; i++) {
> -		int status = sync_fill_fence_info(fences[i], &fence_info[i]);
> +	num_fences = 0;
> +	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) {
> +		int status;
> +
> +		status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
>  		info.status = info.status <= 0 ? info.status : status;
>  	}
>  
> -- 
> 2.25.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers
@ 2022-03-25 10:13     ` Daniel Vetter
  0 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-25 10:13 UTC (permalink / raw)
  To: Christian König
  Cc: gustavo, dri-devel, sumit.semwal, linaro-mm-sig,
	Christian König, linux-media

On Fri, Mar 11, 2022 at 12:02:44PM +0100, Christian König wrote:
> The dma_fence_chain containers can show up in sync_files as well resulting in
> warnings that those can't be added to dma_fence_array containers when merging
> multiple sync_files together.
> 
> Solve this by using the dma_fence_unwrap iterator to deep dive into the
> contained fences and then add those flatten out into a dma_fence_array.
> 
> Signed-off-by: Christian König <christian.koenig@amd.com>

I have no idea why we try to keep fences sorted, but oh well it looks like
the merging is done correctly.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> ---
>  drivers/dma-buf/sync_file.c | 141 +++++++++++++++++++-----------------
>  1 file changed, 73 insertions(+), 68 deletions(-)
> 
> diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
> index 394e6e1e9686..b8dea4ec123b 100644
> --- a/drivers/dma-buf/sync_file.c
> +++ b/drivers/dma-buf/sync_file.c
> @@ -5,6 +5,7 @@
>   * Copyright (C) 2012 Google, Inc.
>   */
>  
> +#include <linux/dma-fence-unwrap.h>
>  #include <linux/export.h>
>  #include <linux/file.h>
>  #include <linux/fs.h>
> @@ -172,20 +173,6 @@ static int sync_file_set_fence(struct sync_file *sync_file,
>  	return 0;
>  }
>  
> -static struct dma_fence **get_fences(struct sync_file *sync_file,
> -				     int *num_fences)
> -{
> -	if (dma_fence_is_array(sync_file->fence)) {
> -		struct dma_fence_array *array = to_dma_fence_array(sync_file->fence);
> -
> -		*num_fences = array->num_fences;
> -		return array->fences;
> -	}
> -
> -	*num_fences = 1;
> -	return &sync_file->fence;
> -}
> -
>  static void add_fence(struct dma_fence **fences,
>  		      int *i, struct dma_fence *fence)
>  {
> @@ -210,86 +197,97 @@ static void add_fence(struct dma_fence **fences,
>  static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
>  					 struct sync_file *b)
>  {
> +	struct dma_fence *a_fence, *b_fence, **fences;
> +	struct dma_fence_unwrap a_iter, b_iter;
> +	unsigned int index, num_fences;
>  	struct sync_file *sync_file;
> -	struct dma_fence **fences = NULL, **nfences, **a_fences, **b_fences;
> -	int i = 0, i_a, i_b, num_fences, a_num_fences, b_num_fences;
>  
>  	sync_file = sync_file_alloc();
>  	if (!sync_file)
>  		return NULL;
>  
> -	a_fences = get_fences(a, &a_num_fences);
> -	b_fences = get_fences(b, &b_num_fences);
> -	if (a_num_fences > INT_MAX - b_num_fences)
> -		goto err;
> +	num_fences = 0;
> +	dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence)
> +		++num_fences;
> +	dma_fence_unwrap_for_each(b_fence, &b_iter, b->fence)
> +		++num_fences;
>  
> -	num_fences = a_num_fences + b_num_fences;
> +	if (num_fences > INT_MAX)
> +		goto err_free_sync_file;
>  
>  	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
>  	if (!fences)
> -		goto err;
> +		goto err_free_sync_file;
>  
>  	/*
> -	 * Assume sync_file a and b are both ordered and have no
> -	 * duplicates with the same context.
> +	 * We can't guarantee that fences in both a and b are ordered, but it is
> +	 * still quite likely.
>  	 *
> -	 * If a sync_file can only be created with sync_file_merge
> -	 * and sync_file_create, this is a reasonable assumption.
> +	 * So attempt to order the fences as we pass over them and merge fences
> +	 * with the same context.
>  	 */
> -	for (i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
> -		struct dma_fence *pt_a = a_fences[i_a];
> -		struct dma_fence *pt_b = b_fences[i_b];
>  
> -		if (pt_a->context < pt_b->context) {
> -			add_fence(fences, &i, pt_a);
> +	index = 0;
> +	for (a_fence = dma_fence_unwrap_first(a->fence, &a_iter),
> +	     b_fence = dma_fence_unwrap_first(b->fence, &b_iter);
> +	     a_fence || b_fence; ) {
> +
> +		if (!b_fence) {
> +			add_fence(fences, &index, a_fence);
> +			a_fence = dma_fence_unwrap_next(&a_iter);
> +
> +		} else if (!a_fence) {
> +			add_fence(fences, &index, b_fence);
> +			b_fence = dma_fence_unwrap_next(&b_iter);
> +
> +		} else if (a_fence->context < b_fence->context) {
> +			add_fence(fences, &index, a_fence);
> +			a_fence = dma_fence_unwrap_next(&a_iter);
>  
> -			i_a++;
> -		} else if (pt_a->context > pt_b->context) {
> -			add_fence(fences, &i, pt_b);
> +		} else if (b_fence->context < a_fence->context) {
> +			add_fence(fences, &index, b_fence);
> +			b_fence = dma_fence_unwrap_next(&b_iter);
> +
> +		} else if (__dma_fence_is_later(a_fence->seqno, b_fence->seqno,
> +						a_fence->ops)) {
> +			add_fence(fences, &index, a_fence);
> +			a_fence = dma_fence_unwrap_next(&a_iter);
> +			b_fence = dma_fence_unwrap_next(&b_iter);
>  
> -			i_b++;
>  		} else {
> -			if (__dma_fence_is_later(pt_a->seqno, pt_b->seqno,
> -						 pt_a->ops))
> -				add_fence(fences, &i, pt_a);
> -			else
> -				add_fence(fences, &i, pt_b);
> -
> -			i_a++;
> -			i_b++;
> +			add_fence(fences, &index, b_fence);
> +			a_fence = dma_fence_unwrap_next(&a_iter);
> +			b_fence = dma_fence_unwrap_next(&b_iter);
>  		}
>  	}
>  
> -	for (; i_a < a_num_fences; i_a++)
> -		add_fence(fences, &i, a_fences[i_a]);
> -
> -	for (; i_b < b_num_fences; i_b++)
> -		add_fence(fences, &i, b_fences[i_b]);
> -
> -	if (i == 0)
> -		fences[i++] = dma_fence_get(a_fences[0]);
> +	if (index == 0)
> +		add_fence(fences, &index, dma_fence_get_stub());
>  
> -	if (num_fences > i) {
> -		nfences = krealloc_array(fences, i, sizeof(*fences), GFP_KERNEL);
> -		if (!nfences)
> -			goto err;
> +	if (num_fences > index) {
> +		struct dma_fence **tmp;
>  
> -		fences = nfences;
> +		/* Keep going even when reducing the size failed */
> +		tmp = krealloc_array(fences, index, sizeof(*fences),
> +				     GFP_KERNEL);
> +		if (tmp)
> +			fences = tmp;
>  	}
>  
> -	if (sync_file_set_fence(sync_file, fences, i) < 0)
> -		goto err;
> +	if (sync_file_set_fence(sync_file, fences, index) < 0)
> +		goto err_put_fences;
>  
>  	strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
>  	return sync_file;
>  
> -err:
> -	while (i)
> -		dma_fence_put(fences[--i]);
> +err_put_fences:
> +	while (index)
> +		dma_fence_put(fences[--index]);
>  	kfree(fences);
> +
> +err_free_sync_file:
>  	fput(sync_file->file);
>  	return NULL;
> -
>  }
>  
>  static int sync_file_release(struct inode *inode, struct file *file)
> @@ -398,11 +396,13 @@ static int sync_fill_fence_info(struct dma_fence *fence,
>  static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
>  				       unsigned long arg)
>  {
> -	struct sync_file_info info;
>  	struct sync_fence_info *fence_info = NULL;
> -	struct dma_fence **fences;
> +	struct dma_fence_unwrap iter;
> +	struct sync_file_info info;
> +	unsigned int num_fences;
> +	struct dma_fence *fence;
> +	int ret;
>  	__u32 size;
> -	int num_fences, ret, i;
>  
>  	if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
>  		return -EFAULT;
> @@ -410,7 +410,9 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
>  	if (info.flags || info.pad)
>  		return -EINVAL;
>  
> -	fences = get_fences(sync_file, &num_fences);
> +	num_fences = 0;
> +	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence)
> +		++num_fences;
>  
>  	/*
>  	 * Passing num_fences = 0 means that userspace doesn't want to
> @@ -433,8 +435,11 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
>  	if (!fence_info)
>  		return -ENOMEM;
>  
> -	for (i = 0; i < num_fences; i++) {
> -		int status = sync_fill_fence_info(fences[i], &fence_info[i]);
> +	num_fences = 0;
> +	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) {
> +		int status;
> +
> +		status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
>  		info.status = info.status <= 0 ? info.status : status;
>  	}
>  
> -- 
> 2.25.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-25 10:10       ` Christian König
@ 2022-03-25 10:17         ` Daniel Vetter
  -1 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-25 10:17 UTC (permalink / raw)
  To: Christian König
  Cc: Daniel Vetter, Christian König, sumit.semwal, gustavo,
	linux-media, dri-devel, linaro-mm-sig

On Fri, Mar 25, 2022 at 11:10:15AM +0100, Christian König wrote:
> Am 25.03.22 um 11:07 schrieb Daniel Vetter:
> > On Fri, Mar 25, 2022 at 11:03:54AM +0100, Daniel Vetter wrote:
> > > On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> > > > Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
> > > > structures and iterate over all the fences in them.
> > > > 
> > > > This is useful when we need to flatten out all fences in those structures.
> > > > 
> > > > Signed-off-by: Christian König <christian.koenig@amd.com>
> > > > ---
> > > >   Documentation/driver-api/dma-buf.rst  |   6 +
> > > >   drivers/dma-buf/Makefile              |   1 +
> > > >   drivers/dma-buf/selftests.h           |   1 +
> > > >   drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
> > > >   include/linux/dma-fence-unwrap.h      |  99 +++++++++
> > > >   5 files changed, 386 insertions(+)
> > > >   create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
> > > >   create mode 100644 include/linux/dma-fence-unwrap.h
> > > > 
> > > > diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
> > > > index 2cd7db82d9fe..7209500f08c8 100644
> > > > --- a/Documentation/driver-api/dma-buf.rst
> > > > +++ b/Documentation/driver-api/dma-buf.rst
> > > > @@ -194,6 +194,12 @@ DMA Fence Chain
> > > >   .. kernel-doc:: include/linux/dma-fence-chain.h
> > > >      :internal:
> > > > +DMA Fence unwrap
> > > > +~~~~~~~~~~~~~~~~
> > > > +
> > > > +.. kernel-doc:: include/linux/dma-fence-unwrap.h
> > > > +   :internal:
> > Ok I forgot one bikeshed: I'd just include this in dma-fence-chain.h and
> > maybe go with the dma_fence_chain_unwrap_ prefix for everything. That
> > makes it even more clearer that the two are meant to go together. Plus ofc
> > the link from struct dma_fence_chain to this iterator in the docs too.
> > 
> > Or I'm just not understanding why you made this a separate thing?
> 
> Well it should be used to unwrap dma_fence_array containers as well and I
> don't really want to add a dependency between dma_fence_chain and
> dma_fence_array.
> 
> I've spend quite some work to keep the two containers separated and also
> describe the separate use cases for each.
> 
> I can of course add some kerneldoc to let the chain and array documentation
> point to this one here.

Yeah I think as a general iterator they should be fine as a separate
thing. Also just realized that we'd need links from both array and chain
to this since it's for both.

The other thing I noticed is that we have dma_fence_chain_for_each()
already. Should we replace all users of that outside of dma-fence-chain.c
with this new thing, and move the chain specific iterator into
dma-fence-chain.c so that it's hidden and people don't make funny
accidents? Just for more safety in this maze, also ofc that's all
follow-up.
-Daniel



> 
> Thanks,
> Christian.
> 
> > -Daniel
> > 
> > > > +
> > > >   DMA Fence uABI/Sync File
> > > >   ~~~~~~~~~~~~~~~~~~~~~~~~
> > > > diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
> > > > index 511805dbeb75..4c9eb53ba3f8 100644
> > > > --- a/drivers/dma-buf/Makefile
> > > > +++ b/drivers/dma-buf/Makefile
> > > > @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
> > > >   	selftest.o \
> > > >   	st-dma-fence.o \
> > > >   	st-dma-fence-chain.o \
> > > > +	st-dma-fence-unwrap.o \
> > > >   	st-dma-resv.o
> > > >   obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
> > > > diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
> > > > index 97d73aaa31da..851965867d9c 100644
> > > > --- a/drivers/dma-buf/selftests.h
> > > > +++ b/drivers/dma-buf/selftests.h
> > > > @@ -12,4 +12,5 @@
> > > >   selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
> > > >   selftest(dma_fence, dma_fence)
> > > >   selftest(dma_fence_chain, dma_fence_chain)
> > > > +selftest(dma_fence_unwrap, dma_fence_unwrap)
> > > >   selftest(dma_resv, dma_resv)
> > > > diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
> > > > new file mode 100644
> > > > index 000000000000..d821faaebe93
> > > > --- /dev/null
> > > > +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
> > > > @@ -0,0 +1,279 @@
> > > > +// SPDX-License-Identifier: MIT
> > > > +
> > > > +/*
> > > > + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> > > > + */
> > > > +
> > > > +#include <linux/dma-fence-unwrap.h>
> > > > +#if 0
> > > > +#include <linux/kernel.h>
> > > > +#include <linux/kthread.h>
> > > > +#include <linux/mm.h>
> > > > +#include <linux/sched/signal.h>
> > > > +#include <linux/slab.h>
> > > > +#include <linux/spinlock.h>
> > > > +#include <linux/random.h>
> > > > +#endif
> > > > +
> > > > +#include "selftest.h"
> > > > +
> > > > +#define CHAIN_SZ (4 << 10)
> > > > +
> > > > +static struct kmem_cache *slab_fences;
> > > Your own slab feels a bit like overkill. kmalloc/kfree not good enough?
> > > 
> > > > +
> > > > +static inline struct mock_fence {
> > > > +	struct dma_fence base;
> > > > +	spinlock_t lock;
> > > > +} *to_mock_fence(struct dma_fence *f) {
> > > > +	return container_of(f, struct mock_fence, base);
> > > > +}
> > > > +
> > > > +static const char *mock_name(struct dma_fence *f)
> > > > +{
> > > > +	return "mock";
> > > > +}
> > > > +
> > > > +static void mock_fence_release(struct dma_fence *f)
> > > > +{
> > > > +	kmem_cache_free(slab_fences, to_mock_fence(f));
> > > > +}
> > > > +
> > > > +static const struct dma_fence_ops mock_ops = {
> > > > +	.get_driver_name = mock_name,
> > > > +	.get_timeline_name = mock_name,
> > > > +	.release = mock_fence_release,
> > > > +};
> > > > +
> > > > +static struct dma_fence *mock_fence(void)
> > > > +{
> > > > +	struct mock_fence *f;
> > > > +
> > > > +	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
> > > > +	if (!f)
> > > > +		return NULL;
> > > > +
> > > > +	spin_lock_init(&f->lock);
> > > > +	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
> > > > +
> > > > +	return &f->base;
> > > > +}
> > > > +
> > > > +static struct dma_fence *mock_array(unsigned int num_fences, ...)
> > > > +{
> > > > +	struct dma_fence_array *array;
> > > > +	struct dma_fence **fences;
> > > > +	va_list valist;
> > > > +	int i;
> > > > +
> > > > +	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
> > > > +	if (!fences)
> > > > +		return NULL;
> > > > +
> > > > +	va_start(valist, num_fences);
> > > > +	for (i = 0; i < num_fences; ++i)
> > > > +		fences[i] = va_arg(valist, typeof(*fences));
> > > > +	va_end(valist);
> > > > +
> > > > +	array = dma_fence_array_create(num_fences, fences,
> > > > +				       dma_fence_context_alloc(1),
> > > > +				       1, false);
> > > > +	if (!array)
> > > > +		goto cleanup;
> > > > +	return &array->base;
> > > > +
> > > > +cleanup:
> > > > +	for (i = 0; i < num_fences; ++i)
> > > > +		dma_fence_put(fences[i]);
> > > > +	kfree(fences);
> > > > +	return NULL;
> > > > +}
> > > > +
> > > > +static struct dma_fence *mock_chain(struct dma_fence *prev,
> > > > +				    struct dma_fence *fence)
> > > > +{
> > > > +	struct dma_fence_chain *f;
> > > > +
> > > > +	f = dma_fence_chain_alloc();
> > > > +	if (!f) {
> > > > +		dma_fence_put(prev);
> > > > +		dma_fence_put(fence);
> > > > +		return NULL;
> > > > +	}
> > > > +
> > > > +	dma_fence_chain_init(f, prev, fence, 1);
> > > > +	return &f->base;
> > > > +}
> > > > +
> > > > +static int sanitycheck(void *arg)
> > > > +{
> > > > +	struct dma_fence *f, *chain, *array;
> > > > +	int err = 0;
> > > > +
> > > > +	f = mock_fence();
> > > > +	if (!f)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	array = mock_array(1, f);
> > > > +	if (!array)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	chain = mock_chain(NULL, array);
> > > > +	if (!chain)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	dma_fence_signal(f);
> > > > +	dma_fence_put(chain);
> > > > +	return err;
> > > > +}
> > > > +
> > > > +static int unwrap_array(void *arg)
> > > > +{
> > > > +	struct dma_fence *fence, *f1, *f2, *array;
> > > > +	struct dma_fence_unwrap iter;
> > > > +	int err = 0;
> > > > +
> > > > +	f1 = mock_fence();
> > > > +	if (!f1)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	f2 = mock_fence();
> > > > +	if (!f2) {
> > > > +		dma_fence_put(f1);
> > > > +		return -ENOMEM;
> > > > +	}
> > > > +
> > > > +	array = mock_array(2, f1, f2);
> > > > +	if (!array)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	dma_fence_unwrap_for_each(fence, &iter, array) {
> > > > +		if (fence == f1) {
> > > > +			f1 = NULL;
> > > > +		} else if (fence == f2) {
> > > > +			f2 = NULL;
> > > > +		} else {
> > > > +			pr_err("Unexpected fence!\n");
> > > > +			err = -EINVAL;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	if (f1 || f2) {
> > > > +		pr_err("Not all fences seen!\n");
> > > > +		err = -EINVAL;
> > > > +	}
> > > > +
> > > > +	dma_fence_signal(f1);
> > > > +	dma_fence_signal(f2);
> > > > +	dma_fence_put(array);
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int unwrap_chain(void *arg)
> > > > +{
> > > > +	struct dma_fence *fence, *f1, *f2, *chain;
> > > > +	struct dma_fence_unwrap iter;
> > > > +	int err = 0;
> > > > +
> > > > +	f1 = mock_fence();
> > > > +	if (!f1)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	f2 = mock_fence();
> > > > +	if (!f2) {
> > > > +		dma_fence_put(f1);
> > > > +		return -ENOMEM;
> > > > +	}
> > > > +
> > > > +	chain = mock_chain(f1, f2);
> > > > +	if (!chain)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> > > > +		if (fence == f1) {
> > > > +			f1 = NULL;
> > > > +		} else if (fence == f2) {
> > > > +			f2 = NULL;
> > > > +		} else {
> > > > +			pr_err("Unexpected fence!\n");
> > > > +			err = -EINVAL;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	if (f1 || f2) {
> > > > +		pr_err("Not all fences seen!\n");
> > > > +		err = -EINVAL;
> > > > +	}
> > > > +
> > > > +	dma_fence_signal(f1);
> > > > +	dma_fence_signal(f2);
> > > > +	dma_fence_put(chain);
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int unwrap_chain_array(void *arg)
> > > > +{
> > > > +	struct dma_fence *fence, *f1, *f2, *array, *chain;
> > > > +	struct dma_fence_unwrap iter;
> > > > +	int err = 0;
> > > > +
> > > > +	f1 = mock_fence();
> > > > +	if (!f1)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	f2 = mock_fence();
> > > > +	if (!f2) {
> > > > +		dma_fence_put(f1);
> > > > +		return -ENOMEM;
> > > > +	}
> > > > +
> > > > +	array = mock_array(2, f1, f2);
> > > > +	if (!array)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	chain = mock_chain(NULL, array);
> > > > +	if (!chain)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> > > > +		if (fence == f1) {
> > > > +			f1 = NULL;
> > > > +		} else if (fence == f2) {
> > > > +			f2 = NULL;
> > > > +		} else {
> > > > +			pr_err("Unexpected fence!\n");
> > > > +			err = -EINVAL;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	if (f1 || f2) {
> > > > +		pr_err("Not all fences seen!\n");
> > > > +		err = -EINVAL;
> > > > +	}
> > > > +
> > > > +	dma_fence_signal(f1);
> > > > +	dma_fence_signal(f2);
> > > > +	dma_fence_put(chain);
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +int dma_fence_unwrap(void)
> > > > +{
> > > > +	static const struct subtest tests[] = {
> > > > +		SUBTEST(sanitycheck),
> > > > +		SUBTEST(unwrap_array),
> > > > +		SUBTEST(unwrap_chain),
> > > > +		SUBTEST(unwrap_chain_array),
> > > > +	};
> > > > +	int ret;
> > > > +
> > > > +	slab_fences = KMEM_CACHE(mock_fence,
> > > > +				 SLAB_TYPESAFE_BY_RCU |
> > > > +				 SLAB_HWCACHE_ALIGN);
> > > > +	if (!slab_fences)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	ret = subtests(tests, NULL);
> > > > +
> > > > +	kmem_cache_destroy(slab_fences);
> > > > +	return ret;
> > > > +}
> > > > diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
> > > > new file mode 100644
> > > > index 000000000000..54963df00c98
> > > > --- /dev/null
> > > > +++ b/include/linux/dma-fence-unwrap.h
> > > > @@ -0,0 +1,99 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0-only */
> > > > +/*
> > > > + * fence-chain: chain fences together in a timeline
> > > > + *
> > > > + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> > > > + * Authors:
> > > > + *	Christian König <christian.koenig@amd.com>
> > > > + */
> > > > +
> > > > +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
> > > > +#define __LINUX_DMA_FENCE_UNWRAP_H
> > > > +
> > > > +#include <linux/dma-fence-chain.h>
> > > > +#include <linux/dma-fence-array.h>
> > > > +
> > > > +/**
> > > > + * struct dma_fence_unwrap - cursor into the container structure
> > > I think adding "This should be used together with
> > > dma_fence_unwrap_for_each() iterator macro." would be nice here. I just
> > > like links :-)
> > > 
> > > > + */
> > > > +struct dma_fence_unwrap {
> > > > +	/**
> > > > +	 * @chain: potential dma_fence_chain, but can be other fence as well
> > > > +	 */
> > > > +	struct dma_fence *chain;
> > > > +	/**
> > > > +	 * @array: potential dma_fence_array, but can be other fence as well
> > > > +	 */
> > > > +	struct dma_fence *array;
> > > > +	/**
> > > > +	 * @index: last returned index if @array is really a dma_fence_array
> > > > +	 */
> > > > +	unsigned int index;
> > > > +};
> > > > +
> > > > +/**
> > > > + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
> > > > + * @cursor: cursor to initialize
> > > > + *
> > > > + * Helper function to unwrap dma_fence_array containers, don't touch directly.
> > > > + * Use dma_fence_unwrap_first/next instead.
> > > > + */
> > > > +static inline struct dma_fence *
> > > > +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
> > > Since this is a helper that no one should call I'd give it a __ prefix and
> > > drop the kerneldoc. Documenting stuff that people shouldn't use is
> > > confusing :-)
> > > 
> > > > +{
> > > > +	cursor->array = dma_fence_chain_contained(cursor->chain);
> > > > +	cursor->index = 0;
> > > > +	return dma_fence_array_first(cursor->array);
> > > > +}
> > > > +
> > > > +/**
> > > > + * dma_fence_unwrap_first - return the first fence from fence containers
> > > > + * @head: the entrypoint into the containers
> > > > + * @cursor: current position inside the containers
> > > > + *
> > > > + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
> > > > + * first fence.
> > > > + */
> > > > +static inline struct dma_fence *
> > > > +dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
> > > > +{
> > > > +	cursor->chain = dma_fence_get(head);
> > > > +	return dma_fence_unwrap_array(cursor);
> > > > +}
> > > > +
> > > > +/**
> > > > + * dma_fence_unwrap_next - return the next fence from a fence containers
> > > > + * @cursor: current position inside the containers
> > > > + *
> > > > + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
> > > > + * the next fence from them.
> > > > + */
> > > > +static inline struct dma_fence *
> > > > +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
> > > > +{
> > > > +	struct dma_fence *tmp;
> > > > +
> > > > +	++cursor->index;
> > > > +	tmp = dma_fence_array_next(cursor->array, cursor->index);
> > > > +	if (tmp)
> > > > +		return tmp;
> > > > +
> > > > +	cursor->chain = dma_fence_chain_walk(cursor->chain);
> > > > +	return dma_fence_unwrap_array(cursor);
> > > > +}
> > > > +
> > > > +/**
> > > > + * dma_fence_unwrap_for_each - iterate over all fences in containers
> > > > + * @fence: current fence
> > > > + * @cursor: current position inside the containers
> > > > + * @head: starting point for the iterator
> > > > + *
> > > > + * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
> > > > + * potential fences in them. If @head is just a normal fence only that one is
> > > > + * returned.
> > > > + */
> > > > +#define dma_fence_unwrap_for_each(fence, cursor, head)			\
> > > > +	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
> > > > +	     fence = dma_fence_unwrap_next(cursor))
> > > > +
> > > > +#endif
> > > I think it'd be really good to add a small paragraph to struct
> > > dma_fence_chain that this macro and iterator should be used for walking
> > > over all fences in a chain, including any fence arrays or anything like
> > > that.
> > > 
> > > With the bikesheds addressed:
> > > 
> > > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > 
> > > > -- 
> > > > 2.25.1
> > > > 
> > > -- 
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.ffwll.ch%2F&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7Caa747083900b451d359308da0e4745e3%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637837996532802687%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=Jts5%2BObWJHeUG4oy2biwj5Bf3PKkMrYU%2F0EihvQRNuY%3D&amp;reserved=0
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
@ 2022-03-25 10:17         ` Daniel Vetter
  0 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-25 10:17 UTC (permalink / raw)
  To: Christian König
  Cc: Christian König, dri-devel, linaro-mm-sig, gustavo,
	sumit.semwal, linux-media

On Fri, Mar 25, 2022 at 11:10:15AM +0100, Christian König wrote:
> Am 25.03.22 um 11:07 schrieb Daniel Vetter:
> > On Fri, Mar 25, 2022 at 11:03:54AM +0100, Daniel Vetter wrote:
> > > On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> > > > Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
> > > > structures and iterate over all the fences in them.
> > > > 
> > > > This is useful when we need to flatten out all fences in those structures.
> > > > 
> > > > Signed-off-by: Christian König <christian.koenig@amd.com>
> > > > ---
> > > >   Documentation/driver-api/dma-buf.rst  |   6 +
> > > >   drivers/dma-buf/Makefile              |   1 +
> > > >   drivers/dma-buf/selftests.h           |   1 +
> > > >   drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
> > > >   include/linux/dma-fence-unwrap.h      |  99 +++++++++
> > > >   5 files changed, 386 insertions(+)
> > > >   create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
> > > >   create mode 100644 include/linux/dma-fence-unwrap.h
> > > > 
> > > > diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
> > > > index 2cd7db82d9fe..7209500f08c8 100644
> > > > --- a/Documentation/driver-api/dma-buf.rst
> > > > +++ b/Documentation/driver-api/dma-buf.rst
> > > > @@ -194,6 +194,12 @@ DMA Fence Chain
> > > >   .. kernel-doc:: include/linux/dma-fence-chain.h
> > > >      :internal:
> > > > +DMA Fence unwrap
> > > > +~~~~~~~~~~~~~~~~
> > > > +
> > > > +.. kernel-doc:: include/linux/dma-fence-unwrap.h
> > > > +   :internal:
> > Ok I forgot one bikeshed: I'd just include this in dma-fence-chain.h and
> > maybe go with the dma_fence_chain_unwrap_ prefix for everything. That
> > makes it even more clearer that the two are meant to go together. Plus ofc
> > the link from struct dma_fence_chain to this iterator in the docs too.
> > 
> > Or I'm just not understanding why you made this a separate thing?
> 
> Well it should be used to unwrap dma_fence_array containers as well and I
> don't really want to add a dependency between dma_fence_chain and
> dma_fence_array.
> 
> I've spend quite some work to keep the two containers separated and also
> describe the separate use cases for each.
> 
> I can of course add some kerneldoc to let the chain and array documentation
> point to this one here.

Yeah I think as a general iterator they should be fine as a separate
thing. Also just realized that we'd need links from both array and chain
to this since it's for both.

The other thing I noticed is that we have dma_fence_chain_for_each()
already. Should we replace all users of that outside of dma-fence-chain.c
with this new thing, and move the chain specific iterator into
dma-fence-chain.c so that it's hidden and people don't make funny
accidents? Just for more safety in this maze, also ofc that's all
follow-up.
-Daniel



> 
> Thanks,
> Christian.
> 
> > -Daniel
> > 
> > > > +
> > > >   DMA Fence uABI/Sync File
> > > >   ~~~~~~~~~~~~~~~~~~~~~~~~
> > > > diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
> > > > index 511805dbeb75..4c9eb53ba3f8 100644
> > > > --- a/drivers/dma-buf/Makefile
> > > > +++ b/drivers/dma-buf/Makefile
> > > > @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
> > > >   	selftest.o \
> > > >   	st-dma-fence.o \
> > > >   	st-dma-fence-chain.o \
> > > > +	st-dma-fence-unwrap.o \
> > > >   	st-dma-resv.o
> > > >   obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
> > > > diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
> > > > index 97d73aaa31da..851965867d9c 100644
> > > > --- a/drivers/dma-buf/selftests.h
> > > > +++ b/drivers/dma-buf/selftests.h
> > > > @@ -12,4 +12,5 @@
> > > >   selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
> > > >   selftest(dma_fence, dma_fence)
> > > >   selftest(dma_fence_chain, dma_fence_chain)
> > > > +selftest(dma_fence_unwrap, dma_fence_unwrap)
> > > >   selftest(dma_resv, dma_resv)
> > > > diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
> > > > new file mode 100644
> > > > index 000000000000..d821faaebe93
> > > > --- /dev/null
> > > > +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
> > > > @@ -0,0 +1,279 @@
> > > > +// SPDX-License-Identifier: MIT
> > > > +
> > > > +/*
> > > > + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> > > > + */
> > > > +
> > > > +#include <linux/dma-fence-unwrap.h>
> > > > +#if 0
> > > > +#include <linux/kernel.h>
> > > > +#include <linux/kthread.h>
> > > > +#include <linux/mm.h>
> > > > +#include <linux/sched/signal.h>
> > > > +#include <linux/slab.h>
> > > > +#include <linux/spinlock.h>
> > > > +#include <linux/random.h>
> > > > +#endif
> > > > +
> > > > +#include "selftest.h"
> > > > +
> > > > +#define CHAIN_SZ (4 << 10)
> > > > +
> > > > +static struct kmem_cache *slab_fences;
> > > Your own slab feels a bit like overkill. kmalloc/kfree not good enough?
> > > 
> > > > +
> > > > +static inline struct mock_fence {
> > > > +	struct dma_fence base;
> > > > +	spinlock_t lock;
> > > > +} *to_mock_fence(struct dma_fence *f) {
> > > > +	return container_of(f, struct mock_fence, base);
> > > > +}
> > > > +
> > > > +static const char *mock_name(struct dma_fence *f)
> > > > +{
> > > > +	return "mock";
> > > > +}
> > > > +
> > > > +static void mock_fence_release(struct dma_fence *f)
> > > > +{
> > > > +	kmem_cache_free(slab_fences, to_mock_fence(f));
> > > > +}
> > > > +
> > > > +static const struct dma_fence_ops mock_ops = {
> > > > +	.get_driver_name = mock_name,
> > > > +	.get_timeline_name = mock_name,
> > > > +	.release = mock_fence_release,
> > > > +};
> > > > +
> > > > +static struct dma_fence *mock_fence(void)
> > > > +{
> > > > +	struct mock_fence *f;
> > > > +
> > > > +	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
> > > > +	if (!f)
> > > > +		return NULL;
> > > > +
> > > > +	spin_lock_init(&f->lock);
> > > > +	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
> > > > +
> > > > +	return &f->base;
> > > > +}
> > > > +
> > > > +static struct dma_fence *mock_array(unsigned int num_fences, ...)
> > > > +{
> > > > +	struct dma_fence_array *array;
> > > > +	struct dma_fence **fences;
> > > > +	va_list valist;
> > > > +	int i;
> > > > +
> > > > +	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
> > > > +	if (!fences)
> > > > +		return NULL;
> > > > +
> > > > +	va_start(valist, num_fences);
> > > > +	for (i = 0; i < num_fences; ++i)
> > > > +		fences[i] = va_arg(valist, typeof(*fences));
> > > > +	va_end(valist);
> > > > +
> > > > +	array = dma_fence_array_create(num_fences, fences,
> > > > +				       dma_fence_context_alloc(1),
> > > > +				       1, false);
> > > > +	if (!array)
> > > > +		goto cleanup;
> > > > +	return &array->base;
> > > > +
> > > > +cleanup:
> > > > +	for (i = 0; i < num_fences; ++i)
> > > > +		dma_fence_put(fences[i]);
> > > > +	kfree(fences);
> > > > +	return NULL;
> > > > +}
> > > > +
> > > > +static struct dma_fence *mock_chain(struct dma_fence *prev,
> > > > +				    struct dma_fence *fence)
> > > > +{
> > > > +	struct dma_fence_chain *f;
> > > > +
> > > > +	f = dma_fence_chain_alloc();
> > > > +	if (!f) {
> > > > +		dma_fence_put(prev);
> > > > +		dma_fence_put(fence);
> > > > +		return NULL;
> > > > +	}
> > > > +
> > > > +	dma_fence_chain_init(f, prev, fence, 1);
> > > > +	return &f->base;
> > > > +}
> > > > +
> > > > +static int sanitycheck(void *arg)
> > > > +{
> > > > +	struct dma_fence *f, *chain, *array;
> > > > +	int err = 0;
> > > > +
> > > > +	f = mock_fence();
> > > > +	if (!f)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	array = mock_array(1, f);
> > > > +	if (!array)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	chain = mock_chain(NULL, array);
> > > > +	if (!chain)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	dma_fence_signal(f);
> > > > +	dma_fence_put(chain);
> > > > +	return err;
> > > > +}
> > > > +
> > > > +static int unwrap_array(void *arg)
> > > > +{
> > > > +	struct dma_fence *fence, *f1, *f2, *array;
> > > > +	struct dma_fence_unwrap iter;
> > > > +	int err = 0;
> > > > +
> > > > +	f1 = mock_fence();
> > > > +	if (!f1)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	f2 = mock_fence();
> > > > +	if (!f2) {
> > > > +		dma_fence_put(f1);
> > > > +		return -ENOMEM;
> > > > +	}
> > > > +
> > > > +	array = mock_array(2, f1, f2);
> > > > +	if (!array)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	dma_fence_unwrap_for_each(fence, &iter, array) {
> > > > +		if (fence == f1) {
> > > > +			f1 = NULL;
> > > > +		} else if (fence == f2) {
> > > > +			f2 = NULL;
> > > > +		} else {
> > > > +			pr_err("Unexpected fence!\n");
> > > > +			err = -EINVAL;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	if (f1 || f2) {
> > > > +		pr_err("Not all fences seen!\n");
> > > > +		err = -EINVAL;
> > > > +	}
> > > > +
> > > > +	dma_fence_signal(f1);
> > > > +	dma_fence_signal(f2);
> > > > +	dma_fence_put(array);
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int unwrap_chain(void *arg)
> > > > +{
> > > > +	struct dma_fence *fence, *f1, *f2, *chain;
> > > > +	struct dma_fence_unwrap iter;
> > > > +	int err = 0;
> > > > +
> > > > +	f1 = mock_fence();
> > > > +	if (!f1)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	f2 = mock_fence();
> > > > +	if (!f2) {
> > > > +		dma_fence_put(f1);
> > > > +		return -ENOMEM;
> > > > +	}
> > > > +
> > > > +	chain = mock_chain(f1, f2);
> > > > +	if (!chain)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> > > > +		if (fence == f1) {
> > > > +			f1 = NULL;
> > > > +		} else if (fence == f2) {
> > > > +			f2 = NULL;
> > > > +		} else {
> > > > +			pr_err("Unexpected fence!\n");
> > > > +			err = -EINVAL;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	if (f1 || f2) {
> > > > +		pr_err("Not all fences seen!\n");
> > > > +		err = -EINVAL;
> > > > +	}
> > > > +
> > > > +	dma_fence_signal(f1);
> > > > +	dma_fence_signal(f2);
> > > > +	dma_fence_put(chain);
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static int unwrap_chain_array(void *arg)
> > > > +{
> > > > +	struct dma_fence *fence, *f1, *f2, *array, *chain;
> > > > +	struct dma_fence_unwrap iter;
> > > > +	int err = 0;
> > > > +
> > > > +	f1 = mock_fence();
> > > > +	if (!f1)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	f2 = mock_fence();
> > > > +	if (!f2) {
> > > > +		dma_fence_put(f1);
> > > > +		return -ENOMEM;
> > > > +	}
> > > > +
> > > > +	array = mock_array(2, f1, f2);
> > > > +	if (!array)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	chain = mock_chain(NULL, array);
> > > > +	if (!chain)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> > > > +		if (fence == f1) {
> > > > +			f1 = NULL;
> > > > +		} else if (fence == f2) {
> > > > +			f2 = NULL;
> > > > +		} else {
> > > > +			pr_err("Unexpected fence!\n");
> > > > +			err = -EINVAL;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	if (f1 || f2) {
> > > > +		pr_err("Not all fences seen!\n");
> > > > +		err = -EINVAL;
> > > > +	}
> > > > +
> > > > +	dma_fence_signal(f1);
> > > > +	dma_fence_signal(f2);
> > > > +	dma_fence_put(chain);
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +int dma_fence_unwrap(void)
> > > > +{
> > > > +	static const struct subtest tests[] = {
> > > > +		SUBTEST(sanitycheck),
> > > > +		SUBTEST(unwrap_array),
> > > > +		SUBTEST(unwrap_chain),
> > > > +		SUBTEST(unwrap_chain_array),
> > > > +	};
> > > > +	int ret;
> > > > +
> > > > +	slab_fences = KMEM_CACHE(mock_fence,
> > > > +				 SLAB_TYPESAFE_BY_RCU |
> > > > +				 SLAB_HWCACHE_ALIGN);
> > > > +	if (!slab_fences)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	ret = subtests(tests, NULL);
> > > > +
> > > > +	kmem_cache_destroy(slab_fences);
> > > > +	return ret;
> > > > +}
> > > > diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
> > > > new file mode 100644
> > > > index 000000000000..54963df00c98
> > > > --- /dev/null
> > > > +++ b/include/linux/dma-fence-unwrap.h
> > > > @@ -0,0 +1,99 @@
> > > > +/* SPDX-License-Identifier: GPL-2.0-only */
> > > > +/*
> > > > + * fence-chain: chain fences together in a timeline
> > > > + *
> > > > + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> > > > + * Authors:
> > > > + *	Christian König <christian.koenig@amd.com>
> > > > + */
> > > > +
> > > > +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
> > > > +#define __LINUX_DMA_FENCE_UNWRAP_H
> > > > +
> > > > +#include <linux/dma-fence-chain.h>
> > > > +#include <linux/dma-fence-array.h>
> > > > +
> > > > +/**
> > > > + * struct dma_fence_unwrap - cursor into the container structure
> > > I think adding "This should be used together with
> > > dma_fence_unwrap_for_each() iterator macro." would be nice here. I just
> > > like links :-)
> > > 
> > > > + */
> > > > +struct dma_fence_unwrap {
> > > > +	/**
> > > > +	 * @chain: potential dma_fence_chain, but can be other fence as well
> > > > +	 */
> > > > +	struct dma_fence *chain;
> > > > +	/**
> > > > +	 * @array: potential dma_fence_array, but can be other fence as well
> > > > +	 */
> > > > +	struct dma_fence *array;
> > > > +	/**
> > > > +	 * @index: last returned index if @array is really a dma_fence_array
> > > > +	 */
> > > > +	unsigned int index;
> > > > +};
> > > > +
> > > > +/**
> > > > + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
> > > > + * @cursor: cursor to initialize
> > > > + *
> > > > + * Helper function to unwrap dma_fence_array containers, don't touch directly.
> > > > + * Use dma_fence_unwrap_first/next instead.
> > > > + */
> > > > +static inline struct dma_fence *
> > > > +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
> > > Since this is a helper that no one should call I'd give it a __ prefix and
> > > drop the kerneldoc. Documenting stuff that people shouldn't use is
> > > confusing :-)
> > > 
> > > > +{
> > > > +	cursor->array = dma_fence_chain_contained(cursor->chain);
> > > > +	cursor->index = 0;
> > > > +	return dma_fence_array_first(cursor->array);
> > > > +}
> > > > +
> > > > +/**
> > > > + * dma_fence_unwrap_first - return the first fence from fence containers
> > > > + * @head: the entrypoint into the containers
> > > > + * @cursor: current position inside the containers
> > > > + *
> > > > + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
> > > > + * first fence.
> > > > + */
> > > > +static inline struct dma_fence *
> > > > +dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
> > > > +{
> > > > +	cursor->chain = dma_fence_get(head);
> > > > +	return dma_fence_unwrap_array(cursor);
> > > > +}
> > > > +
> > > > +/**
> > > > + * dma_fence_unwrap_next - return the next fence from a fence containers
> > > > + * @cursor: current position inside the containers
> > > > + *
> > > > + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
> > > > + * the next fence from them.
> > > > + */
> > > > +static inline struct dma_fence *
> > > > +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
> > > > +{
> > > > +	struct dma_fence *tmp;
> > > > +
> > > > +	++cursor->index;
> > > > +	tmp = dma_fence_array_next(cursor->array, cursor->index);
> > > > +	if (tmp)
> > > > +		return tmp;
> > > > +
> > > > +	cursor->chain = dma_fence_chain_walk(cursor->chain);
> > > > +	return dma_fence_unwrap_array(cursor);
> > > > +}
> > > > +
> > > > +/**
> > > > + * dma_fence_unwrap_for_each - iterate over all fences in containers
> > > > + * @fence: current fence
> > > > + * @cursor: current position inside the containers
> > > > + * @head: starting point for the iterator
> > > > + *
> > > > + * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
> > > > + * potential fences in them. If @head is just a normal fence only that one is
> > > > + * returned.
> > > > + */
> > > > +#define dma_fence_unwrap_for_each(fence, cursor, head)			\
> > > > +	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
> > > > +	     fence = dma_fence_unwrap_next(cursor))
> > > > +
> > > > +#endif
> > > I think it'd be really good to add a small paragraph to struct
> > > dma_fence_chain that this macro and iterator should be used for walking
> > > over all fences in a chain, including any fence arrays or anything like
> > > that.
> > > 
> > > With the bikesheds addressed:
> > > 
> > > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > 
> > > > -- 
> > > > 2.25.1
> > > > 
> > > -- 
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.ffwll.ch%2F&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7Caa747083900b451d359308da0e4745e3%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637837996532802687%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=Jts5%2BObWJHeUG4oy2biwj5Bf3PKkMrYU%2F0EihvQRNuY%3D&amp;reserved=0
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers
  2022-03-25 10:13     ` Daniel Vetter
@ 2022-03-25 10:35       ` Christian König
  -1 siblings, 0 replies; 40+ messages in thread
From: Christian König @ 2022-03-25 10:35 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig,
	Christian König

Am 25.03.22 um 11:13 schrieb Daniel Vetter:
> On Fri, Mar 11, 2022 at 12:02:44PM +0100, Christian König wrote:
>> The dma_fence_chain containers can show up in sync_files as well resulting in
>> warnings that those can't be added to dma_fence_array containers when merging
>> multiple sync_files together.
>>
>> Solve this by using the dma_fence_unwrap iterator to deep dive into the
>> contained fences and then add those flatten out into a dma_fence_array.
>>
>> Signed-off-by: Christian König <christian.koenig@amd.com>
> I have no idea why we try to keep fences sorted, but oh well it looks like
> the merging is done correctly.

To be honest I don't fully know either.

Keeping the array sorted by context allows to merge it without adding 
duplicates, but adding duplicates is not an extra overhead to begin with 
because we always allocate memory for the worst case anyway.

Just keeping it around for now.

> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Thanks,
Christian.

>
>> ---
>>   drivers/dma-buf/sync_file.c | 141 +++++++++++++++++++-----------------
>>   1 file changed, 73 insertions(+), 68 deletions(-)
>>
>> diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
>> index 394e6e1e9686..b8dea4ec123b 100644
>> --- a/drivers/dma-buf/sync_file.c
>> +++ b/drivers/dma-buf/sync_file.c
>> @@ -5,6 +5,7 @@
>>    * Copyright (C) 2012 Google, Inc.
>>    */
>>   
>> +#include <linux/dma-fence-unwrap.h>
>>   #include <linux/export.h>
>>   #include <linux/file.h>
>>   #include <linux/fs.h>
>> @@ -172,20 +173,6 @@ static int sync_file_set_fence(struct sync_file *sync_file,
>>   	return 0;
>>   }
>>   
>> -static struct dma_fence **get_fences(struct sync_file *sync_file,
>> -				     int *num_fences)
>> -{
>> -	if (dma_fence_is_array(sync_file->fence)) {
>> -		struct dma_fence_array *array = to_dma_fence_array(sync_file->fence);
>> -
>> -		*num_fences = array->num_fences;
>> -		return array->fences;
>> -	}
>> -
>> -	*num_fences = 1;
>> -	return &sync_file->fence;
>> -}
>> -
>>   static void add_fence(struct dma_fence **fences,
>>   		      int *i, struct dma_fence *fence)
>>   {
>> @@ -210,86 +197,97 @@ static void add_fence(struct dma_fence **fences,
>>   static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
>>   					 struct sync_file *b)
>>   {
>> +	struct dma_fence *a_fence, *b_fence, **fences;
>> +	struct dma_fence_unwrap a_iter, b_iter;
>> +	unsigned int index, num_fences;
>>   	struct sync_file *sync_file;
>> -	struct dma_fence **fences = NULL, **nfences, **a_fences, **b_fences;
>> -	int i = 0, i_a, i_b, num_fences, a_num_fences, b_num_fences;
>>   
>>   	sync_file = sync_file_alloc();
>>   	if (!sync_file)
>>   		return NULL;
>>   
>> -	a_fences = get_fences(a, &a_num_fences);
>> -	b_fences = get_fences(b, &b_num_fences);
>> -	if (a_num_fences > INT_MAX - b_num_fences)
>> -		goto err;
>> +	num_fences = 0;
>> +	dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence)
>> +		++num_fences;
>> +	dma_fence_unwrap_for_each(b_fence, &b_iter, b->fence)
>> +		++num_fences;
>>   
>> -	num_fences = a_num_fences + b_num_fences;
>> +	if (num_fences > INT_MAX)
>> +		goto err_free_sync_file;
>>   
>>   	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
>>   	if (!fences)
>> -		goto err;
>> +		goto err_free_sync_file;
>>   
>>   	/*
>> -	 * Assume sync_file a and b are both ordered and have no
>> -	 * duplicates with the same context.
>> +	 * We can't guarantee that fences in both a and b are ordered, but it is
>> +	 * still quite likely.
>>   	 *
>> -	 * If a sync_file can only be created with sync_file_merge
>> -	 * and sync_file_create, this is a reasonable assumption.
>> +	 * So attempt to order the fences as we pass over them and merge fences
>> +	 * with the same context.
>>   	 */
>> -	for (i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
>> -		struct dma_fence *pt_a = a_fences[i_a];
>> -		struct dma_fence *pt_b = b_fences[i_b];
>>   
>> -		if (pt_a->context < pt_b->context) {
>> -			add_fence(fences, &i, pt_a);
>> +	index = 0;
>> +	for (a_fence = dma_fence_unwrap_first(a->fence, &a_iter),
>> +	     b_fence = dma_fence_unwrap_first(b->fence, &b_iter);
>> +	     a_fence || b_fence; ) {
>> +
>> +		if (!b_fence) {
>> +			add_fence(fences, &index, a_fence);
>> +			a_fence = dma_fence_unwrap_next(&a_iter);
>> +
>> +		} else if (!a_fence) {
>> +			add_fence(fences, &index, b_fence);
>> +			b_fence = dma_fence_unwrap_next(&b_iter);
>> +
>> +		} else if (a_fence->context < b_fence->context) {
>> +			add_fence(fences, &index, a_fence);
>> +			a_fence = dma_fence_unwrap_next(&a_iter);
>>   
>> -			i_a++;
>> -		} else if (pt_a->context > pt_b->context) {
>> -			add_fence(fences, &i, pt_b);
>> +		} else if (b_fence->context < a_fence->context) {
>> +			add_fence(fences, &index, b_fence);
>> +			b_fence = dma_fence_unwrap_next(&b_iter);
>> +
>> +		} else if (__dma_fence_is_later(a_fence->seqno, b_fence->seqno,
>> +						a_fence->ops)) {
>> +			add_fence(fences, &index, a_fence);
>> +			a_fence = dma_fence_unwrap_next(&a_iter);
>> +			b_fence = dma_fence_unwrap_next(&b_iter);
>>   
>> -			i_b++;
>>   		} else {
>> -			if (__dma_fence_is_later(pt_a->seqno, pt_b->seqno,
>> -						 pt_a->ops))
>> -				add_fence(fences, &i, pt_a);
>> -			else
>> -				add_fence(fences, &i, pt_b);
>> -
>> -			i_a++;
>> -			i_b++;
>> +			add_fence(fences, &index, b_fence);
>> +			a_fence = dma_fence_unwrap_next(&a_iter);
>> +			b_fence = dma_fence_unwrap_next(&b_iter);
>>   		}
>>   	}
>>   
>> -	for (; i_a < a_num_fences; i_a++)
>> -		add_fence(fences, &i, a_fences[i_a]);
>> -
>> -	for (; i_b < b_num_fences; i_b++)
>> -		add_fence(fences, &i, b_fences[i_b]);
>> -
>> -	if (i == 0)
>> -		fences[i++] = dma_fence_get(a_fences[0]);
>> +	if (index == 0)
>> +		add_fence(fences, &index, dma_fence_get_stub());
>>   
>> -	if (num_fences > i) {
>> -		nfences = krealloc_array(fences, i, sizeof(*fences), GFP_KERNEL);
>> -		if (!nfences)
>> -			goto err;
>> +	if (num_fences > index) {
>> +		struct dma_fence **tmp;
>>   
>> -		fences = nfences;
>> +		/* Keep going even when reducing the size failed */
>> +		tmp = krealloc_array(fences, index, sizeof(*fences),
>> +				     GFP_KERNEL);
>> +		if (tmp)
>> +			fences = tmp;
>>   	}
>>   
>> -	if (sync_file_set_fence(sync_file, fences, i) < 0)
>> -		goto err;
>> +	if (sync_file_set_fence(sync_file, fences, index) < 0)
>> +		goto err_put_fences;
>>   
>>   	strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
>>   	return sync_file;
>>   
>> -err:
>> -	while (i)
>> -		dma_fence_put(fences[--i]);
>> +err_put_fences:
>> +	while (index)
>> +		dma_fence_put(fences[--index]);
>>   	kfree(fences);
>> +
>> +err_free_sync_file:
>>   	fput(sync_file->file);
>>   	return NULL;
>> -
>>   }
>>   
>>   static int sync_file_release(struct inode *inode, struct file *file)
>> @@ -398,11 +396,13 @@ static int sync_fill_fence_info(struct dma_fence *fence,
>>   static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
>>   				       unsigned long arg)
>>   {
>> -	struct sync_file_info info;
>>   	struct sync_fence_info *fence_info = NULL;
>> -	struct dma_fence **fences;
>> +	struct dma_fence_unwrap iter;
>> +	struct sync_file_info info;
>> +	unsigned int num_fences;
>> +	struct dma_fence *fence;
>> +	int ret;
>>   	__u32 size;
>> -	int num_fences, ret, i;
>>   
>>   	if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
>>   		return -EFAULT;
>> @@ -410,7 +410,9 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
>>   	if (info.flags || info.pad)
>>   		return -EINVAL;
>>   
>> -	fences = get_fences(sync_file, &num_fences);
>> +	num_fences = 0;
>> +	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence)
>> +		++num_fences;
>>   
>>   	/*
>>   	 * Passing num_fences = 0 means that userspace doesn't want to
>> @@ -433,8 +435,11 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
>>   	if (!fence_info)
>>   		return -ENOMEM;
>>   
>> -	for (i = 0; i < num_fences; i++) {
>> -		int status = sync_fill_fence_info(fences[i], &fence_info[i]);
>> +	num_fences = 0;
>> +	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) {
>> +		int status;
>> +
>> +		status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
>>   		info.status = info.status <= 0 ? info.status : status;
>>   	}
>>   
>> -- 
>> 2.25.1
>>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers
@ 2022-03-25 10:35       ` Christian König
  0 siblings, 0 replies; 40+ messages in thread
From: Christian König @ 2022-03-25 10:35 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: gustavo, dri-devel, sumit.semwal, linaro-mm-sig,
	Christian König, linux-media

Am 25.03.22 um 11:13 schrieb Daniel Vetter:
> On Fri, Mar 11, 2022 at 12:02:44PM +0100, Christian König wrote:
>> The dma_fence_chain containers can show up in sync_files as well resulting in
>> warnings that those can't be added to dma_fence_array containers when merging
>> multiple sync_files together.
>>
>> Solve this by using the dma_fence_unwrap iterator to deep dive into the
>> contained fences and then add those flatten out into a dma_fence_array.
>>
>> Signed-off-by: Christian König <christian.koenig@amd.com>
> I have no idea why we try to keep fences sorted, but oh well it looks like
> the merging is done correctly.

To be honest I don't fully know either.

Keeping the array sorted by context allows to merge it without adding 
duplicates, but adding duplicates is not an extra overhead to begin with 
because we always allocate memory for the worst case anyway.

Just keeping it around for now.

> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Thanks,
Christian.

>
>> ---
>>   drivers/dma-buf/sync_file.c | 141 +++++++++++++++++++-----------------
>>   1 file changed, 73 insertions(+), 68 deletions(-)
>>
>> diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
>> index 394e6e1e9686..b8dea4ec123b 100644
>> --- a/drivers/dma-buf/sync_file.c
>> +++ b/drivers/dma-buf/sync_file.c
>> @@ -5,6 +5,7 @@
>>    * Copyright (C) 2012 Google, Inc.
>>    */
>>   
>> +#include <linux/dma-fence-unwrap.h>
>>   #include <linux/export.h>
>>   #include <linux/file.h>
>>   #include <linux/fs.h>
>> @@ -172,20 +173,6 @@ static int sync_file_set_fence(struct sync_file *sync_file,
>>   	return 0;
>>   }
>>   
>> -static struct dma_fence **get_fences(struct sync_file *sync_file,
>> -				     int *num_fences)
>> -{
>> -	if (dma_fence_is_array(sync_file->fence)) {
>> -		struct dma_fence_array *array = to_dma_fence_array(sync_file->fence);
>> -
>> -		*num_fences = array->num_fences;
>> -		return array->fences;
>> -	}
>> -
>> -	*num_fences = 1;
>> -	return &sync_file->fence;
>> -}
>> -
>>   static void add_fence(struct dma_fence **fences,
>>   		      int *i, struct dma_fence *fence)
>>   {
>> @@ -210,86 +197,97 @@ static void add_fence(struct dma_fence **fences,
>>   static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
>>   					 struct sync_file *b)
>>   {
>> +	struct dma_fence *a_fence, *b_fence, **fences;
>> +	struct dma_fence_unwrap a_iter, b_iter;
>> +	unsigned int index, num_fences;
>>   	struct sync_file *sync_file;
>> -	struct dma_fence **fences = NULL, **nfences, **a_fences, **b_fences;
>> -	int i = 0, i_a, i_b, num_fences, a_num_fences, b_num_fences;
>>   
>>   	sync_file = sync_file_alloc();
>>   	if (!sync_file)
>>   		return NULL;
>>   
>> -	a_fences = get_fences(a, &a_num_fences);
>> -	b_fences = get_fences(b, &b_num_fences);
>> -	if (a_num_fences > INT_MAX - b_num_fences)
>> -		goto err;
>> +	num_fences = 0;
>> +	dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence)
>> +		++num_fences;
>> +	dma_fence_unwrap_for_each(b_fence, &b_iter, b->fence)
>> +		++num_fences;
>>   
>> -	num_fences = a_num_fences + b_num_fences;
>> +	if (num_fences > INT_MAX)
>> +		goto err_free_sync_file;
>>   
>>   	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
>>   	if (!fences)
>> -		goto err;
>> +		goto err_free_sync_file;
>>   
>>   	/*
>> -	 * Assume sync_file a and b are both ordered and have no
>> -	 * duplicates with the same context.
>> +	 * We can't guarantee that fences in both a and b are ordered, but it is
>> +	 * still quite likely.
>>   	 *
>> -	 * If a sync_file can only be created with sync_file_merge
>> -	 * and sync_file_create, this is a reasonable assumption.
>> +	 * So attempt to order the fences as we pass over them and merge fences
>> +	 * with the same context.
>>   	 */
>> -	for (i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
>> -		struct dma_fence *pt_a = a_fences[i_a];
>> -		struct dma_fence *pt_b = b_fences[i_b];
>>   
>> -		if (pt_a->context < pt_b->context) {
>> -			add_fence(fences, &i, pt_a);
>> +	index = 0;
>> +	for (a_fence = dma_fence_unwrap_first(a->fence, &a_iter),
>> +	     b_fence = dma_fence_unwrap_first(b->fence, &b_iter);
>> +	     a_fence || b_fence; ) {
>> +
>> +		if (!b_fence) {
>> +			add_fence(fences, &index, a_fence);
>> +			a_fence = dma_fence_unwrap_next(&a_iter);
>> +
>> +		} else if (!a_fence) {
>> +			add_fence(fences, &index, b_fence);
>> +			b_fence = dma_fence_unwrap_next(&b_iter);
>> +
>> +		} else if (a_fence->context < b_fence->context) {
>> +			add_fence(fences, &index, a_fence);
>> +			a_fence = dma_fence_unwrap_next(&a_iter);
>>   
>> -			i_a++;
>> -		} else if (pt_a->context > pt_b->context) {
>> -			add_fence(fences, &i, pt_b);
>> +		} else if (b_fence->context < a_fence->context) {
>> +			add_fence(fences, &index, b_fence);
>> +			b_fence = dma_fence_unwrap_next(&b_iter);
>> +
>> +		} else if (__dma_fence_is_later(a_fence->seqno, b_fence->seqno,
>> +						a_fence->ops)) {
>> +			add_fence(fences, &index, a_fence);
>> +			a_fence = dma_fence_unwrap_next(&a_iter);
>> +			b_fence = dma_fence_unwrap_next(&b_iter);
>>   
>> -			i_b++;
>>   		} else {
>> -			if (__dma_fence_is_later(pt_a->seqno, pt_b->seqno,
>> -						 pt_a->ops))
>> -				add_fence(fences, &i, pt_a);
>> -			else
>> -				add_fence(fences, &i, pt_b);
>> -
>> -			i_a++;
>> -			i_b++;
>> +			add_fence(fences, &index, b_fence);
>> +			a_fence = dma_fence_unwrap_next(&a_iter);
>> +			b_fence = dma_fence_unwrap_next(&b_iter);
>>   		}
>>   	}
>>   
>> -	for (; i_a < a_num_fences; i_a++)
>> -		add_fence(fences, &i, a_fences[i_a]);
>> -
>> -	for (; i_b < b_num_fences; i_b++)
>> -		add_fence(fences, &i, b_fences[i_b]);
>> -
>> -	if (i == 0)
>> -		fences[i++] = dma_fence_get(a_fences[0]);
>> +	if (index == 0)
>> +		add_fence(fences, &index, dma_fence_get_stub());
>>   
>> -	if (num_fences > i) {
>> -		nfences = krealloc_array(fences, i, sizeof(*fences), GFP_KERNEL);
>> -		if (!nfences)
>> -			goto err;
>> +	if (num_fences > index) {
>> +		struct dma_fence **tmp;
>>   
>> -		fences = nfences;
>> +		/* Keep going even when reducing the size failed */
>> +		tmp = krealloc_array(fences, index, sizeof(*fences),
>> +				     GFP_KERNEL);
>> +		if (tmp)
>> +			fences = tmp;
>>   	}
>>   
>> -	if (sync_file_set_fence(sync_file, fences, i) < 0)
>> -		goto err;
>> +	if (sync_file_set_fence(sync_file, fences, index) < 0)
>> +		goto err_put_fences;
>>   
>>   	strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
>>   	return sync_file;
>>   
>> -err:
>> -	while (i)
>> -		dma_fence_put(fences[--i]);
>> +err_put_fences:
>> +	while (index)
>> +		dma_fence_put(fences[--index]);
>>   	kfree(fences);
>> +
>> +err_free_sync_file:
>>   	fput(sync_file->file);
>>   	return NULL;
>> -
>>   }
>>   
>>   static int sync_file_release(struct inode *inode, struct file *file)
>> @@ -398,11 +396,13 @@ static int sync_fill_fence_info(struct dma_fence *fence,
>>   static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
>>   				       unsigned long arg)
>>   {
>> -	struct sync_file_info info;
>>   	struct sync_fence_info *fence_info = NULL;
>> -	struct dma_fence **fences;
>> +	struct dma_fence_unwrap iter;
>> +	struct sync_file_info info;
>> +	unsigned int num_fences;
>> +	struct dma_fence *fence;
>> +	int ret;
>>   	__u32 size;
>> -	int num_fences, ret, i;
>>   
>>   	if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
>>   		return -EFAULT;
>> @@ -410,7 +410,9 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
>>   	if (info.flags || info.pad)
>>   		return -EINVAL;
>>   
>> -	fences = get_fences(sync_file, &num_fences);
>> +	num_fences = 0;
>> +	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence)
>> +		++num_fences;
>>   
>>   	/*
>>   	 * Passing num_fences = 0 means that userspace doesn't want to
>> @@ -433,8 +435,11 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
>>   	if (!fence_info)
>>   		return -ENOMEM;
>>   
>> -	for (i = 0; i < num_fences; i++) {
>> -		int status = sync_fill_fence_info(fences[i], &fence_info[i]);
>> +	num_fences = 0;
>> +	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) {
>> +		int status;
>> +
>> +		status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
>>   		info.status = info.status <= 0 ? info.status : status;
>>   	}
>>   
>> -- 
>> 2.25.1
>>


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-25 10:17         ` Daniel Vetter
@ 2022-03-25 12:56           ` Christian König
  -1 siblings, 0 replies; 40+ messages in thread
From: Christian König @ 2022-03-25 12:56 UTC (permalink / raw)
  To: Daniel Vetter, Christian König
  Cc: linaro-mm-sig, gustavo, sumit.semwal, dri-devel, linux-media

Am 25.03.22 um 11:17 schrieb Daniel Vetter:
> On Fri, Mar 25, 2022 at 11:10:15AM +0100, Christian König wrote:
>> Am 25.03.22 um 11:07 schrieb Daniel Vetter:
>>> On Fri, Mar 25, 2022 at 11:03:54AM +0100, Daniel Vetter wrote:
>>>> On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
>>>>> Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
>>>>> structures and iterate over all the fences in them.
>>>>>
>>>>> This is useful when we need to flatten out all fences in those structures.
>>>>>
>>>>> Signed-off-by: Christian König <christian.koenig@amd.com>
>>>>> ---
>>>>>    Documentation/driver-api/dma-buf.rst  |   6 +
>>>>>    drivers/dma-buf/Makefile              |   1 +
>>>>>    drivers/dma-buf/selftests.h           |   1 +
>>>>>    drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
>>>>>    include/linux/dma-fence-unwrap.h      |  99 +++++++++
>>>>>    5 files changed, 386 insertions(+)
>>>>>    create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
>>>>>    create mode 100644 include/linux/dma-fence-unwrap.h
>>>>>
>>>>> diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
>>>>> index 2cd7db82d9fe..7209500f08c8 100644
>>>>> --- a/Documentation/driver-api/dma-buf.rst
>>>>> +++ b/Documentation/driver-api/dma-buf.rst
>>>>> @@ -194,6 +194,12 @@ DMA Fence Chain
>>>>>    .. kernel-doc:: include/linux/dma-fence-chain.h
>>>>>       :internal:
>>>>> +DMA Fence unwrap
>>>>> +~~~~~~~~~~~~~~~~
>>>>> +
>>>>> +.. kernel-doc:: include/linux/dma-fence-unwrap.h
>>>>> +   :internal:
>>> Ok I forgot one bikeshed: I'd just include this in dma-fence-chain.h and
>>> maybe go with the dma_fence_chain_unwrap_ prefix for everything. That
>>> makes it even more clearer that the two are meant to go together. Plus ofc
>>> the link from struct dma_fence_chain to this iterator in the docs too.
>>>
>>> Or I'm just not understanding why you made this a separate thing?
>> Well it should be used to unwrap dma_fence_array containers as well and I
>> don't really want to add a dependency between dma_fence_chain and
>> dma_fence_array.
>>
>> I've spend quite some work to keep the two containers separated and also
>> describe the separate use cases for each.
>>
>> I can of course add some kerneldoc to let the chain and array documentation
>> point to this one here.
> Yeah I think as a general iterator they should be fine as a separate
> thing. Also just realized that we'd need links from both array and chain
> to this since it's for both.

Done.

>
> The other thing I noticed is that we have dma_fence_chain_for_each()
> already. Should we replace all users of that outside of dma-fence-chain.c
> with this new thing, and move the chain specific iterator into
> dma-fence-chain.c so that it's hidden and people don't make funny
> accidents? Just for more safety in this maze, also ofc that's all
> follow-up.

Uff, good question. There are some valid use cases for it I think.

Especially the timeline syncobj handling only want to work with chain 
structures and not with the eventually contained array.

It could just be that we might want to wrap those use cases into 
dma_fence_chain helpers.

Anyway, not stuff for drm-misc-next-fixes, but going to keep that in mind.

Christian.

> -Daniel
>
>
>
>> Thanks,
>> Christian.
>>
>>> -Daniel
>>>
>>>>> +
>>>>>    DMA Fence uABI/Sync File
>>>>>    ~~~~~~~~~~~~~~~~~~~~~~~~
>>>>> diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
>>>>> index 511805dbeb75..4c9eb53ba3f8 100644
>>>>> --- a/drivers/dma-buf/Makefile
>>>>> +++ b/drivers/dma-buf/Makefile
>>>>> @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
>>>>>    	selftest.o \
>>>>>    	st-dma-fence.o \
>>>>>    	st-dma-fence-chain.o \
>>>>> +	st-dma-fence-unwrap.o \
>>>>>    	st-dma-resv.o
>>>>>    obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
>>>>> diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
>>>>> index 97d73aaa31da..851965867d9c 100644
>>>>> --- a/drivers/dma-buf/selftests.h
>>>>> +++ b/drivers/dma-buf/selftests.h
>>>>> @@ -12,4 +12,5 @@
>>>>>    selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
>>>>>    selftest(dma_fence, dma_fence)
>>>>>    selftest(dma_fence_chain, dma_fence_chain)
>>>>> +selftest(dma_fence_unwrap, dma_fence_unwrap)
>>>>>    selftest(dma_resv, dma_resv)
>>>>> diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
>>>>> new file mode 100644
>>>>> index 000000000000..d821faaebe93
>>>>> --- /dev/null
>>>>> +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
>>>>> @@ -0,0 +1,279 @@
>>>>> +// SPDX-License-Identifier: MIT
>>>>> +
>>>>> +/*
>>>>> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
>>>>> + */
>>>>> +
>>>>> +#include <linux/dma-fence-unwrap.h>
>>>>> +#if 0
>>>>> +#include <linux/kernel.h>
>>>>> +#include <linux/kthread.h>
>>>>> +#include <linux/mm.h>
>>>>> +#include <linux/sched/signal.h>
>>>>> +#include <linux/slab.h>
>>>>> +#include <linux/spinlock.h>
>>>>> +#include <linux/random.h>
>>>>> +#endif
>>>>> +
>>>>> +#include "selftest.h"
>>>>> +
>>>>> +#define CHAIN_SZ (4 << 10)
>>>>> +
>>>>> +static struct kmem_cache *slab_fences;
>>>> Your own slab feels a bit like overkill. kmalloc/kfree not good enough?
>>>>
>>>>> +
>>>>> +static inline struct mock_fence {
>>>>> +	struct dma_fence base;
>>>>> +	spinlock_t lock;
>>>>> +} *to_mock_fence(struct dma_fence *f) {
>>>>> +	return container_of(f, struct mock_fence, base);
>>>>> +}
>>>>> +
>>>>> +static const char *mock_name(struct dma_fence *f)
>>>>> +{
>>>>> +	return "mock";
>>>>> +}
>>>>> +
>>>>> +static void mock_fence_release(struct dma_fence *f)
>>>>> +{
>>>>> +	kmem_cache_free(slab_fences, to_mock_fence(f));
>>>>> +}
>>>>> +
>>>>> +static const struct dma_fence_ops mock_ops = {
>>>>> +	.get_driver_name = mock_name,
>>>>> +	.get_timeline_name = mock_name,
>>>>> +	.release = mock_fence_release,
>>>>> +};
>>>>> +
>>>>> +static struct dma_fence *mock_fence(void)
>>>>> +{
>>>>> +	struct mock_fence *f;
>>>>> +
>>>>> +	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
>>>>> +	if (!f)
>>>>> +		return NULL;
>>>>> +
>>>>> +	spin_lock_init(&f->lock);
>>>>> +	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
>>>>> +
>>>>> +	return &f->base;
>>>>> +}
>>>>> +
>>>>> +static struct dma_fence *mock_array(unsigned int num_fences, ...)
>>>>> +{
>>>>> +	struct dma_fence_array *array;
>>>>> +	struct dma_fence **fences;
>>>>> +	va_list valist;
>>>>> +	int i;
>>>>> +
>>>>> +	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
>>>>> +	if (!fences)
>>>>> +		return NULL;
>>>>> +
>>>>> +	va_start(valist, num_fences);
>>>>> +	for (i = 0; i < num_fences; ++i)
>>>>> +		fences[i] = va_arg(valist, typeof(*fences));
>>>>> +	va_end(valist);
>>>>> +
>>>>> +	array = dma_fence_array_create(num_fences, fences,
>>>>> +				       dma_fence_context_alloc(1),
>>>>> +				       1, false);
>>>>> +	if (!array)
>>>>> +		goto cleanup;
>>>>> +	return &array->base;
>>>>> +
>>>>> +cleanup:
>>>>> +	for (i = 0; i < num_fences; ++i)
>>>>> +		dma_fence_put(fences[i]);
>>>>> +	kfree(fences);
>>>>> +	return NULL;
>>>>> +}
>>>>> +
>>>>> +static struct dma_fence *mock_chain(struct dma_fence *prev,
>>>>> +				    struct dma_fence *fence)
>>>>> +{
>>>>> +	struct dma_fence_chain *f;
>>>>> +
>>>>> +	f = dma_fence_chain_alloc();
>>>>> +	if (!f) {
>>>>> +		dma_fence_put(prev);
>>>>> +		dma_fence_put(fence);
>>>>> +		return NULL;
>>>>> +	}
>>>>> +
>>>>> +	dma_fence_chain_init(f, prev, fence, 1);
>>>>> +	return &f->base;
>>>>> +}
>>>>> +
>>>>> +static int sanitycheck(void *arg)
>>>>> +{
>>>>> +	struct dma_fence *f, *chain, *array;
>>>>> +	int err = 0;
>>>>> +
>>>>> +	f = mock_fence();
>>>>> +	if (!f)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	array = mock_array(1, f);
>>>>> +	if (!array)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	chain = mock_chain(NULL, array);
>>>>> +	if (!chain)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	dma_fence_signal(f);
>>>>> +	dma_fence_put(chain);
>>>>> +	return err;
>>>>> +}
>>>>> +
>>>>> +static int unwrap_array(void *arg)
>>>>> +{
>>>>> +	struct dma_fence *fence, *f1, *f2, *array;
>>>>> +	struct dma_fence_unwrap iter;
>>>>> +	int err = 0;
>>>>> +
>>>>> +	f1 = mock_fence();
>>>>> +	if (!f1)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	f2 = mock_fence();
>>>>> +	if (!f2) {
>>>>> +		dma_fence_put(f1);
>>>>> +		return -ENOMEM;
>>>>> +	}
>>>>> +
>>>>> +	array = mock_array(2, f1, f2);
>>>>> +	if (!array)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	dma_fence_unwrap_for_each(fence, &iter, array) {
>>>>> +		if (fence == f1) {
>>>>> +			f1 = NULL;
>>>>> +		} else if (fence == f2) {
>>>>> +			f2 = NULL;
>>>>> +		} else {
>>>>> +			pr_err("Unexpected fence!\n");
>>>>> +			err = -EINVAL;
>>>>> +		}
>>>>> +	}
>>>>> +
>>>>> +	if (f1 || f2) {
>>>>> +		pr_err("Not all fences seen!\n");
>>>>> +		err = -EINVAL;
>>>>> +	}
>>>>> +
>>>>> +	dma_fence_signal(f1);
>>>>> +	dma_fence_signal(f2);
>>>>> +	dma_fence_put(array);
>>>>> +	return 0;
>>>>> +}
>>>>> +
>>>>> +static int unwrap_chain(void *arg)
>>>>> +{
>>>>> +	struct dma_fence *fence, *f1, *f2, *chain;
>>>>> +	struct dma_fence_unwrap iter;
>>>>> +	int err = 0;
>>>>> +
>>>>> +	f1 = mock_fence();
>>>>> +	if (!f1)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	f2 = mock_fence();
>>>>> +	if (!f2) {
>>>>> +		dma_fence_put(f1);
>>>>> +		return -ENOMEM;
>>>>> +	}
>>>>> +
>>>>> +	chain = mock_chain(f1, f2);
>>>>> +	if (!chain)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
>>>>> +		if (fence == f1) {
>>>>> +			f1 = NULL;
>>>>> +		} else if (fence == f2) {
>>>>> +			f2 = NULL;
>>>>> +		} else {
>>>>> +			pr_err("Unexpected fence!\n");
>>>>> +			err = -EINVAL;
>>>>> +		}
>>>>> +	}
>>>>> +
>>>>> +	if (f1 || f2) {
>>>>> +		pr_err("Not all fences seen!\n");
>>>>> +		err = -EINVAL;
>>>>> +	}
>>>>> +
>>>>> +	dma_fence_signal(f1);
>>>>> +	dma_fence_signal(f2);
>>>>> +	dma_fence_put(chain);
>>>>> +	return 0;
>>>>> +}
>>>>> +
>>>>> +static int unwrap_chain_array(void *arg)
>>>>> +{
>>>>> +	struct dma_fence *fence, *f1, *f2, *array, *chain;
>>>>> +	struct dma_fence_unwrap iter;
>>>>> +	int err = 0;
>>>>> +
>>>>> +	f1 = mock_fence();
>>>>> +	if (!f1)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	f2 = mock_fence();
>>>>> +	if (!f2) {
>>>>> +		dma_fence_put(f1);
>>>>> +		return -ENOMEM;
>>>>> +	}
>>>>> +
>>>>> +	array = mock_array(2, f1, f2);
>>>>> +	if (!array)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	chain = mock_chain(NULL, array);
>>>>> +	if (!chain)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
>>>>> +		if (fence == f1) {
>>>>> +			f1 = NULL;
>>>>> +		} else if (fence == f2) {
>>>>> +			f2 = NULL;
>>>>> +		} else {
>>>>> +			pr_err("Unexpected fence!\n");
>>>>> +			err = -EINVAL;
>>>>> +		}
>>>>> +	}
>>>>> +
>>>>> +	if (f1 || f2) {
>>>>> +		pr_err("Not all fences seen!\n");
>>>>> +		err = -EINVAL;
>>>>> +	}
>>>>> +
>>>>> +	dma_fence_signal(f1);
>>>>> +	dma_fence_signal(f2);
>>>>> +	dma_fence_put(chain);
>>>>> +	return 0;
>>>>> +}
>>>>> +
>>>>> +int dma_fence_unwrap(void)
>>>>> +{
>>>>> +	static const struct subtest tests[] = {
>>>>> +		SUBTEST(sanitycheck),
>>>>> +		SUBTEST(unwrap_array),
>>>>> +		SUBTEST(unwrap_chain),
>>>>> +		SUBTEST(unwrap_chain_array),
>>>>> +	};
>>>>> +	int ret;
>>>>> +
>>>>> +	slab_fences = KMEM_CACHE(mock_fence,
>>>>> +				 SLAB_TYPESAFE_BY_RCU |
>>>>> +				 SLAB_HWCACHE_ALIGN);
>>>>> +	if (!slab_fences)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	ret = subtests(tests, NULL);
>>>>> +
>>>>> +	kmem_cache_destroy(slab_fences);
>>>>> +	return ret;
>>>>> +}
>>>>> diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
>>>>> new file mode 100644
>>>>> index 000000000000..54963df00c98
>>>>> --- /dev/null
>>>>> +++ b/include/linux/dma-fence-unwrap.h
>>>>> @@ -0,0 +1,99 @@
>>>>> +/* SPDX-License-Identifier: GPL-2.0-only */
>>>>> +/*
>>>>> + * fence-chain: chain fences together in a timeline
>>>>> + *
>>>>> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
>>>>> + * Authors:
>>>>> + *	Christian König <christian.koenig@amd.com>
>>>>> + */
>>>>> +
>>>>> +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
>>>>> +#define __LINUX_DMA_FENCE_UNWRAP_H
>>>>> +
>>>>> +#include <linux/dma-fence-chain.h>
>>>>> +#include <linux/dma-fence-array.h>
>>>>> +
>>>>> +/**
>>>>> + * struct dma_fence_unwrap - cursor into the container structure
>>>> I think adding "This should be used together with
>>>> dma_fence_unwrap_for_each() iterator macro." would be nice here. I just
>>>> like links :-)
>>>>
>>>>> + */
>>>>> +struct dma_fence_unwrap {
>>>>> +	/**
>>>>> +	 * @chain: potential dma_fence_chain, but can be other fence as well
>>>>> +	 */
>>>>> +	struct dma_fence *chain;
>>>>> +	/**
>>>>> +	 * @array: potential dma_fence_array, but can be other fence as well
>>>>> +	 */
>>>>> +	struct dma_fence *array;
>>>>> +	/**
>>>>> +	 * @index: last returned index if @array is really a dma_fence_array
>>>>> +	 */
>>>>> +	unsigned int index;
>>>>> +};
>>>>> +
>>>>> +/**
>>>>> + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
>>>>> + * @cursor: cursor to initialize
>>>>> + *
>>>>> + * Helper function to unwrap dma_fence_array containers, don't touch directly.
>>>>> + * Use dma_fence_unwrap_first/next instead.
>>>>> + */
>>>>> +static inline struct dma_fence *
>>>>> +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
>>>> Since this is a helper that no one should call I'd give it a __ prefix and
>>>> drop the kerneldoc. Documenting stuff that people shouldn't use is
>>>> confusing :-)
>>>>
>>>>> +{
>>>>> +	cursor->array = dma_fence_chain_contained(cursor->chain);
>>>>> +	cursor->index = 0;
>>>>> +	return dma_fence_array_first(cursor->array);
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * dma_fence_unwrap_first - return the first fence from fence containers
>>>>> + * @head: the entrypoint into the containers
>>>>> + * @cursor: current position inside the containers
>>>>> + *
>>>>> + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
>>>>> + * first fence.
>>>>> + */
>>>>> +static inline struct dma_fence *
>>>>> +dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
>>>>> +{
>>>>> +	cursor->chain = dma_fence_get(head);
>>>>> +	return dma_fence_unwrap_array(cursor);
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * dma_fence_unwrap_next - return the next fence from a fence containers
>>>>> + * @cursor: current position inside the containers
>>>>> + *
>>>>> + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
>>>>> + * the next fence from them.
>>>>> + */
>>>>> +static inline struct dma_fence *
>>>>> +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
>>>>> +{
>>>>> +	struct dma_fence *tmp;
>>>>> +
>>>>> +	++cursor->index;
>>>>> +	tmp = dma_fence_array_next(cursor->array, cursor->index);
>>>>> +	if (tmp)
>>>>> +		return tmp;
>>>>> +
>>>>> +	cursor->chain = dma_fence_chain_walk(cursor->chain);
>>>>> +	return dma_fence_unwrap_array(cursor);
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * dma_fence_unwrap_for_each - iterate over all fences in containers
>>>>> + * @fence: current fence
>>>>> + * @cursor: current position inside the containers
>>>>> + * @head: starting point for the iterator
>>>>> + *
>>>>> + * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
>>>>> + * potential fences in them. If @head is just a normal fence only that one is
>>>>> + * returned.
>>>>> + */
>>>>> +#define dma_fence_unwrap_for_each(fence, cursor, head)			\
>>>>> +	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
>>>>> +	     fence = dma_fence_unwrap_next(cursor))
>>>>> +
>>>>> +#endif
>>>> I think it'd be really good to add a small paragraph to struct
>>>> dma_fence_chain that this macro and iterator should be used for walking
>>>> over all fences in a chain, including any fence arrays or anything like
>>>> that.
>>>>
>>>> With the bikesheds addressed:
>>>>
>>>> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>>>>
>>>>> -- 
>>>>> 2.25.1
>>>>>
>>>> -- 
>>>> Daniel Vetter
>>>> Software Engineer, Intel Corporation
>>>> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.ffwll.ch%2F&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7Caa747083900b451d359308da0e4745e3%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637837996532802687%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=Jts5%2BObWJHeUG4oy2biwj5Bf3PKkMrYU%2F0EihvQRNuY%3D&amp;reserved=0


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
@ 2022-03-25 12:56           ` Christian König
  0 siblings, 0 replies; 40+ messages in thread
From: Christian König @ 2022-03-25 12:56 UTC (permalink / raw)
  To: Daniel Vetter, Christian König
  Cc: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig

Am 25.03.22 um 11:17 schrieb Daniel Vetter:
> On Fri, Mar 25, 2022 at 11:10:15AM +0100, Christian König wrote:
>> Am 25.03.22 um 11:07 schrieb Daniel Vetter:
>>> On Fri, Mar 25, 2022 at 11:03:54AM +0100, Daniel Vetter wrote:
>>>> On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
>>>>> Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
>>>>> structures and iterate over all the fences in them.
>>>>>
>>>>> This is useful when we need to flatten out all fences in those structures.
>>>>>
>>>>> Signed-off-by: Christian König <christian.koenig@amd.com>
>>>>> ---
>>>>>    Documentation/driver-api/dma-buf.rst  |   6 +
>>>>>    drivers/dma-buf/Makefile              |   1 +
>>>>>    drivers/dma-buf/selftests.h           |   1 +
>>>>>    drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
>>>>>    include/linux/dma-fence-unwrap.h      |  99 +++++++++
>>>>>    5 files changed, 386 insertions(+)
>>>>>    create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
>>>>>    create mode 100644 include/linux/dma-fence-unwrap.h
>>>>>
>>>>> diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
>>>>> index 2cd7db82d9fe..7209500f08c8 100644
>>>>> --- a/Documentation/driver-api/dma-buf.rst
>>>>> +++ b/Documentation/driver-api/dma-buf.rst
>>>>> @@ -194,6 +194,12 @@ DMA Fence Chain
>>>>>    .. kernel-doc:: include/linux/dma-fence-chain.h
>>>>>       :internal:
>>>>> +DMA Fence unwrap
>>>>> +~~~~~~~~~~~~~~~~
>>>>> +
>>>>> +.. kernel-doc:: include/linux/dma-fence-unwrap.h
>>>>> +   :internal:
>>> Ok I forgot one bikeshed: I'd just include this in dma-fence-chain.h and
>>> maybe go with the dma_fence_chain_unwrap_ prefix for everything. That
>>> makes it even more clearer that the two are meant to go together. Plus ofc
>>> the link from struct dma_fence_chain to this iterator in the docs too.
>>>
>>> Or I'm just not understanding why you made this a separate thing?
>> Well it should be used to unwrap dma_fence_array containers as well and I
>> don't really want to add a dependency between dma_fence_chain and
>> dma_fence_array.
>>
>> I've spend quite some work to keep the two containers separated and also
>> describe the separate use cases for each.
>>
>> I can of course add some kerneldoc to let the chain and array documentation
>> point to this one here.
> Yeah I think as a general iterator they should be fine as a separate
> thing. Also just realized that we'd need links from both array and chain
> to this since it's for both.

Done.

>
> The other thing I noticed is that we have dma_fence_chain_for_each()
> already. Should we replace all users of that outside of dma-fence-chain.c
> with this new thing, and move the chain specific iterator into
> dma-fence-chain.c so that it's hidden and people don't make funny
> accidents? Just for more safety in this maze, also ofc that's all
> follow-up.

Uff, good question. There are some valid use cases for it I think.

Especially the timeline syncobj handling only want to work with chain 
structures and not with the eventually contained array.

It could just be that we might want to wrap those use cases into 
dma_fence_chain helpers.

Anyway, not stuff for drm-misc-next-fixes, but going to keep that in mind.

Christian.

> -Daniel
>
>
>
>> Thanks,
>> Christian.
>>
>>> -Daniel
>>>
>>>>> +
>>>>>    DMA Fence uABI/Sync File
>>>>>    ~~~~~~~~~~~~~~~~~~~~~~~~
>>>>> diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
>>>>> index 511805dbeb75..4c9eb53ba3f8 100644
>>>>> --- a/drivers/dma-buf/Makefile
>>>>> +++ b/drivers/dma-buf/Makefile
>>>>> @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
>>>>>    	selftest.o \
>>>>>    	st-dma-fence.o \
>>>>>    	st-dma-fence-chain.o \
>>>>> +	st-dma-fence-unwrap.o \
>>>>>    	st-dma-resv.o
>>>>>    obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
>>>>> diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
>>>>> index 97d73aaa31da..851965867d9c 100644
>>>>> --- a/drivers/dma-buf/selftests.h
>>>>> +++ b/drivers/dma-buf/selftests.h
>>>>> @@ -12,4 +12,5 @@
>>>>>    selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
>>>>>    selftest(dma_fence, dma_fence)
>>>>>    selftest(dma_fence_chain, dma_fence_chain)
>>>>> +selftest(dma_fence_unwrap, dma_fence_unwrap)
>>>>>    selftest(dma_resv, dma_resv)
>>>>> diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
>>>>> new file mode 100644
>>>>> index 000000000000..d821faaebe93
>>>>> --- /dev/null
>>>>> +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
>>>>> @@ -0,0 +1,279 @@
>>>>> +// SPDX-License-Identifier: MIT
>>>>> +
>>>>> +/*
>>>>> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
>>>>> + */
>>>>> +
>>>>> +#include <linux/dma-fence-unwrap.h>
>>>>> +#if 0
>>>>> +#include <linux/kernel.h>
>>>>> +#include <linux/kthread.h>
>>>>> +#include <linux/mm.h>
>>>>> +#include <linux/sched/signal.h>
>>>>> +#include <linux/slab.h>
>>>>> +#include <linux/spinlock.h>
>>>>> +#include <linux/random.h>
>>>>> +#endif
>>>>> +
>>>>> +#include "selftest.h"
>>>>> +
>>>>> +#define CHAIN_SZ (4 << 10)
>>>>> +
>>>>> +static struct kmem_cache *slab_fences;
>>>> Your own slab feels a bit like overkill. kmalloc/kfree not good enough?
>>>>
>>>>> +
>>>>> +static inline struct mock_fence {
>>>>> +	struct dma_fence base;
>>>>> +	spinlock_t lock;
>>>>> +} *to_mock_fence(struct dma_fence *f) {
>>>>> +	return container_of(f, struct mock_fence, base);
>>>>> +}
>>>>> +
>>>>> +static const char *mock_name(struct dma_fence *f)
>>>>> +{
>>>>> +	return "mock";
>>>>> +}
>>>>> +
>>>>> +static void mock_fence_release(struct dma_fence *f)
>>>>> +{
>>>>> +	kmem_cache_free(slab_fences, to_mock_fence(f));
>>>>> +}
>>>>> +
>>>>> +static const struct dma_fence_ops mock_ops = {
>>>>> +	.get_driver_name = mock_name,
>>>>> +	.get_timeline_name = mock_name,
>>>>> +	.release = mock_fence_release,
>>>>> +};
>>>>> +
>>>>> +static struct dma_fence *mock_fence(void)
>>>>> +{
>>>>> +	struct mock_fence *f;
>>>>> +
>>>>> +	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
>>>>> +	if (!f)
>>>>> +		return NULL;
>>>>> +
>>>>> +	spin_lock_init(&f->lock);
>>>>> +	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
>>>>> +
>>>>> +	return &f->base;
>>>>> +}
>>>>> +
>>>>> +static struct dma_fence *mock_array(unsigned int num_fences, ...)
>>>>> +{
>>>>> +	struct dma_fence_array *array;
>>>>> +	struct dma_fence **fences;
>>>>> +	va_list valist;
>>>>> +	int i;
>>>>> +
>>>>> +	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
>>>>> +	if (!fences)
>>>>> +		return NULL;
>>>>> +
>>>>> +	va_start(valist, num_fences);
>>>>> +	for (i = 0; i < num_fences; ++i)
>>>>> +		fences[i] = va_arg(valist, typeof(*fences));
>>>>> +	va_end(valist);
>>>>> +
>>>>> +	array = dma_fence_array_create(num_fences, fences,
>>>>> +				       dma_fence_context_alloc(1),
>>>>> +				       1, false);
>>>>> +	if (!array)
>>>>> +		goto cleanup;
>>>>> +	return &array->base;
>>>>> +
>>>>> +cleanup:
>>>>> +	for (i = 0; i < num_fences; ++i)
>>>>> +		dma_fence_put(fences[i]);
>>>>> +	kfree(fences);
>>>>> +	return NULL;
>>>>> +}
>>>>> +
>>>>> +static struct dma_fence *mock_chain(struct dma_fence *prev,
>>>>> +				    struct dma_fence *fence)
>>>>> +{
>>>>> +	struct dma_fence_chain *f;
>>>>> +
>>>>> +	f = dma_fence_chain_alloc();
>>>>> +	if (!f) {
>>>>> +		dma_fence_put(prev);
>>>>> +		dma_fence_put(fence);
>>>>> +		return NULL;
>>>>> +	}
>>>>> +
>>>>> +	dma_fence_chain_init(f, prev, fence, 1);
>>>>> +	return &f->base;
>>>>> +}
>>>>> +
>>>>> +static int sanitycheck(void *arg)
>>>>> +{
>>>>> +	struct dma_fence *f, *chain, *array;
>>>>> +	int err = 0;
>>>>> +
>>>>> +	f = mock_fence();
>>>>> +	if (!f)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	array = mock_array(1, f);
>>>>> +	if (!array)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	chain = mock_chain(NULL, array);
>>>>> +	if (!chain)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	dma_fence_signal(f);
>>>>> +	dma_fence_put(chain);
>>>>> +	return err;
>>>>> +}
>>>>> +
>>>>> +static int unwrap_array(void *arg)
>>>>> +{
>>>>> +	struct dma_fence *fence, *f1, *f2, *array;
>>>>> +	struct dma_fence_unwrap iter;
>>>>> +	int err = 0;
>>>>> +
>>>>> +	f1 = mock_fence();
>>>>> +	if (!f1)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	f2 = mock_fence();
>>>>> +	if (!f2) {
>>>>> +		dma_fence_put(f1);
>>>>> +		return -ENOMEM;
>>>>> +	}
>>>>> +
>>>>> +	array = mock_array(2, f1, f2);
>>>>> +	if (!array)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	dma_fence_unwrap_for_each(fence, &iter, array) {
>>>>> +		if (fence == f1) {
>>>>> +			f1 = NULL;
>>>>> +		} else if (fence == f2) {
>>>>> +			f2 = NULL;
>>>>> +		} else {
>>>>> +			pr_err("Unexpected fence!\n");
>>>>> +			err = -EINVAL;
>>>>> +		}
>>>>> +	}
>>>>> +
>>>>> +	if (f1 || f2) {
>>>>> +		pr_err("Not all fences seen!\n");
>>>>> +		err = -EINVAL;
>>>>> +	}
>>>>> +
>>>>> +	dma_fence_signal(f1);
>>>>> +	dma_fence_signal(f2);
>>>>> +	dma_fence_put(array);
>>>>> +	return 0;
>>>>> +}
>>>>> +
>>>>> +static int unwrap_chain(void *arg)
>>>>> +{
>>>>> +	struct dma_fence *fence, *f1, *f2, *chain;
>>>>> +	struct dma_fence_unwrap iter;
>>>>> +	int err = 0;
>>>>> +
>>>>> +	f1 = mock_fence();
>>>>> +	if (!f1)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	f2 = mock_fence();
>>>>> +	if (!f2) {
>>>>> +		dma_fence_put(f1);
>>>>> +		return -ENOMEM;
>>>>> +	}
>>>>> +
>>>>> +	chain = mock_chain(f1, f2);
>>>>> +	if (!chain)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
>>>>> +		if (fence == f1) {
>>>>> +			f1 = NULL;
>>>>> +		} else if (fence == f2) {
>>>>> +			f2 = NULL;
>>>>> +		} else {
>>>>> +			pr_err("Unexpected fence!\n");
>>>>> +			err = -EINVAL;
>>>>> +		}
>>>>> +	}
>>>>> +
>>>>> +	if (f1 || f2) {
>>>>> +		pr_err("Not all fences seen!\n");
>>>>> +		err = -EINVAL;
>>>>> +	}
>>>>> +
>>>>> +	dma_fence_signal(f1);
>>>>> +	dma_fence_signal(f2);
>>>>> +	dma_fence_put(chain);
>>>>> +	return 0;
>>>>> +}
>>>>> +
>>>>> +static int unwrap_chain_array(void *arg)
>>>>> +{
>>>>> +	struct dma_fence *fence, *f1, *f2, *array, *chain;
>>>>> +	struct dma_fence_unwrap iter;
>>>>> +	int err = 0;
>>>>> +
>>>>> +	f1 = mock_fence();
>>>>> +	if (!f1)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	f2 = mock_fence();
>>>>> +	if (!f2) {
>>>>> +		dma_fence_put(f1);
>>>>> +		return -ENOMEM;
>>>>> +	}
>>>>> +
>>>>> +	array = mock_array(2, f1, f2);
>>>>> +	if (!array)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	chain = mock_chain(NULL, array);
>>>>> +	if (!chain)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	dma_fence_unwrap_for_each(fence, &iter, chain) {
>>>>> +		if (fence == f1) {
>>>>> +			f1 = NULL;
>>>>> +		} else if (fence == f2) {
>>>>> +			f2 = NULL;
>>>>> +		} else {
>>>>> +			pr_err("Unexpected fence!\n");
>>>>> +			err = -EINVAL;
>>>>> +		}
>>>>> +	}
>>>>> +
>>>>> +	if (f1 || f2) {
>>>>> +		pr_err("Not all fences seen!\n");
>>>>> +		err = -EINVAL;
>>>>> +	}
>>>>> +
>>>>> +	dma_fence_signal(f1);
>>>>> +	dma_fence_signal(f2);
>>>>> +	dma_fence_put(chain);
>>>>> +	return 0;
>>>>> +}
>>>>> +
>>>>> +int dma_fence_unwrap(void)
>>>>> +{
>>>>> +	static const struct subtest tests[] = {
>>>>> +		SUBTEST(sanitycheck),
>>>>> +		SUBTEST(unwrap_array),
>>>>> +		SUBTEST(unwrap_chain),
>>>>> +		SUBTEST(unwrap_chain_array),
>>>>> +	};
>>>>> +	int ret;
>>>>> +
>>>>> +	slab_fences = KMEM_CACHE(mock_fence,
>>>>> +				 SLAB_TYPESAFE_BY_RCU |
>>>>> +				 SLAB_HWCACHE_ALIGN);
>>>>> +	if (!slab_fences)
>>>>> +		return -ENOMEM;
>>>>> +
>>>>> +	ret = subtests(tests, NULL);
>>>>> +
>>>>> +	kmem_cache_destroy(slab_fences);
>>>>> +	return ret;
>>>>> +}
>>>>> diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
>>>>> new file mode 100644
>>>>> index 000000000000..54963df00c98
>>>>> --- /dev/null
>>>>> +++ b/include/linux/dma-fence-unwrap.h
>>>>> @@ -0,0 +1,99 @@
>>>>> +/* SPDX-License-Identifier: GPL-2.0-only */
>>>>> +/*
>>>>> + * fence-chain: chain fences together in a timeline
>>>>> + *
>>>>> + * Copyright (C) 2022 Advanced Micro Devices, Inc.
>>>>> + * Authors:
>>>>> + *	Christian König <christian.koenig@amd.com>
>>>>> + */
>>>>> +
>>>>> +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
>>>>> +#define __LINUX_DMA_FENCE_UNWRAP_H
>>>>> +
>>>>> +#include <linux/dma-fence-chain.h>
>>>>> +#include <linux/dma-fence-array.h>
>>>>> +
>>>>> +/**
>>>>> + * struct dma_fence_unwrap - cursor into the container structure
>>>> I think adding "This should be used together with
>>>> dma_fence_unwrap_for_each() iterator macro." would be nice here. I just
>>>> like links :-)
>>>>
>>>>> + */
>>>>> +struct dma_fence_unwrap {
>>>>> +	/**
>>>>> +	 * @chain: potential dma_fence_chain, but can be other fence as well
>>>>> +	 */
>>>>> +	struct dma_fence *chain;
>>>>> +	/**
>>>>> +	 * @array: potential dma_fence_array, but can be other fence as well
>>>>> +	 */
>>>>> +	struct dma_fence *array;
>>>>> +	/**
>>>>> +	 * @index: last returned index if @array is really a dma_fence_array
>>>>> +	 */
>>>>> +	unsigned int index;
>>>>> +};
>>>>> +
>>>>> +/**
>>>>> + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
>>>>> + * @cursor: cursor to initialize
>>>>> + *
>>>>> + * Helper function to unwrap dma_fence_array containers, don't touch directly.
>>>>> + * Use dma_fence_unwrap_first/next instead.
>>>>> + */
>>>>> +static inline struct dma_fence *
>>>>> +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
>>>> Since this is a helper that no one should call I'd give it a __ prefix and
>>>> drop the kerneldoc. Documenting stuff that people shouldn't use is
>>>> confusing :-)
>>>>
>>>>> +{
>>>>> +	cursor->array = dma_fence_chain_contained(cursor->chain);
>>>>> +	cursor->index = 0;
>>>>> +	return dma_fence_array_first(cursor->array);
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * dma_fence_unwrap_first - return the first fence from fence containers
>>>>> + * @head: the entrypoint into the containers
>>>>> + * @cursor: current position inside the containers
>>>>> + *
>>>>> + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
>>>>> + * first fence.
>>>>> + */
>>>>> +static inline struct dma_fence *
>>>>> +dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
>>>>> +{
>>>>> +	cursor->chain = dma_fence_get(head);
>>>>> +	return dma_fence_unwrap_array(cursor);
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * dma_fence_unwrap_next - return the next fence from a fence containers
>>>>> + * @cursor: current position inside the containers
>>>>> + *
>>>>> + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
>>>>> + * the next fence from them.
>>>>> + */
>>>>> +static inline struct dma_fence *
>>>>> +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
>>>>> +{
>>>>> +	struct dma_fence *tmp;
>>>>> +
>>>>> +	++cursor->index;
>>>>> +	tmp = dma_fence_array_next(cursor->array, cursor->index);
>>>>> +	if (tmp)
>>>>> +		return tmp;
>>>>> +
>>>>> +	cursor->chain = dma_fence_chain_walk(cursor->chain);
>>>>> +	return dma_fence_unwrap_array(cursor);
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * dma_fence_unwrap_for_each - iterate over all fences in containers
>>>>> + * @fence: current fence
>>>>> + * @cursor: current position inside the containers
>>>>> + * @head: starting point for the iterator
>>>>> + *
>>>>> + * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
>>>>> + * potential fences in them. If @head is just a normal fence only that one is
>>>>> + * returned.
>>>>> + */
>>>>> +#define dma_fence_unwrap_for_each(fence, cursor, head)			\
>>>>> +	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
>>>>> +	     fence = dma_fence_unwrap_next(cursor))
>>>>> +
>>>>> +#endif
>>>> I think it'd be really good to add a small paragraph to struct
>>>> dma_fence_chain that this macro and iterator should be used for walking
>>>> over all fences in a chain, including any fence arrays or anything like
>>>> that.
>>>>
>>>> With the bikesheds addressed:
>>>>
>>>> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>>>>
>>>>> -- 
>>>>> 2.25.1
>>>>>
>>>> -- 
>>>> Daniel Vetter
>>>> Software Engineer, Intel Corporation
>>>> https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.ffwll.ch%2F&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7Caa747083900b451d359308da0e4745e3%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637837996532802687%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=Jts5%2BObWJHeUG4oy2biwj5Bf3PKkMrYU%2F0EihvQRNuY%3D&amp;reserved=0


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-11 11:02 [PATCH 1/2] dma-buf: add dma_fence_unwrap Christian König
@ 2022-03-25 15:25   ` Ville Syrjälä
  2022-03-11 15:45 ` [PATCH 1/2] dma-buf: add dma_fence_unwrap kernel test robot
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 40+ messages in thread
From: Ville Syrjälä @ 2022-03-25 15:25 UTC (permalink / raw)
  To: Christian König
  Cc: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig,
	Christian König, Daniel Vetter, Dave Airlie

On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
> structures and iterate over all the fences in them.
> 
> This is useful when we need to flatten out all fences in those structures.
> 
> Signed-off-by: Christian König <christian.koenig@amd.com>

One of the dma-buf patches took down Intel CI. Looks like every
machine oopses in some sync_file thing now:
<1>[  260.470008] BUG: kernel NULL pointer dereference, address: 0000000000000010
<1>[  260.470020] #PF: supervisor read access in kernel mode
<1>[  260.470025] #PF: error_code(0x0000) - not-present page
<6>[  260.470030] PGD 0 P4D 0 
<4>[  260.470035] Oops: 0000 [#1] PREEMPT SMP NOPTI
<4>[  260.470040] CPU: 0 PID: 5306 Comm: core_hotunplug Not tainted 5.17.0-CI-CI_DRM_11405+ #1
<4>[  260.470049] Hardware name: Intel Corporation Jasper Lake Client Platform/Jasperlake DDR4 SODIMM RVP, BIOS JSLSFWI1.R00.2385.D02.2010160831 10/16/2020
<4>[  260.470058] RIP: 0010:dma_fence_array_first+0x19/0x20
<4>[  260.470068] Code: c3 31 c0 c3 0f 1f 00 66 2e 0f 1f 84 00 00 00 00 00 48 85 ff 74 18 48 89 f8 48 81 7f 08 60 7f 0a 82 75 0d 48 8b 87 88 00 00 00 <48> 8b 00 c3 31 c0 c3 31 c0 48 85 ff 74 20 48 81 7f 08 60 7f 0a 82
<4>[  260.470080] RSP: 0018:ffffc900009a7e40 EFLAGS: 00010246
<4>[  260.470086] RAX: 0000000000000010 RBX: 000000000000000b RCX: 0000000000000000
<4>[  260.470100] RDX: 0000000000000001 RSI: 0000000000000001 RDI: ffff888109a796b8
<4>[  260.470106] RBP: ffff888109a796b8 R08: 0000000000000002 R09: 0000000000000000
<4>[  260.470112] R10: 0000000000000001 R11: 0000000000000000 R12: ffff888109a796b8
<4>[  260.470118] R13: 00007ffc5d21f750 R14: ffff8881065be340 R15: 0000000000000000
<4>[  260.470124] FS:  00007f08bd6d04c0(0000) GS:ffff88885fc00000(0000) knlGS:0000000000000000
<4>[  260.470131] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
<4>[  260.470137] CR2: 0000000000000010 CR3: 000000010e690000 CR4: 0000000000350ef0
<4>[  260.470143] Call Trace:
<4>[  260.470146]  <TASK>
<4>[  260.470149]  sync_file_ioctl+0x2eb/0xc90
<4>[  260.470157]  __x64_sys_ioctl+0x6a/0xa0
<4>[  260.470164]  do_syscall_64+0x37/0xb0
<4>[  260.470170]  entry_SYSCALL_64_after_hwframe+0x44/0xae
<4>[  260.470176] RIP: 0033:0x7f08c047750b
<4>[  260.470182] Code: 0f 1e fa 48 8b 05 85 39 0d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 55 39 0d 00 f7 d8 64 89 01 48
<4>[  260.470195] RSP: 002b:00007ffc5d21f748 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
<4>[  260.470202] RAX: ffffffffffffffda RBX: 000000000000000a RCX: 00007f08c047750b
<4>[  260.470208] RDX: 00007ffc5d21f750 RSI: 00000000c0303e03 RDI: 000000000000000a
<4>[  260.470214] RBP: 0000000000000005 R08: 0000000000000000 R09: 00007ffc5d21ebb0
<4>[  260.470219] R10: 00007f08c0a6170e R11: 0000000000000246 R12: 0000000000000000
<4>[  260.470225] R13: 00007ffc5d21f840 R14: 000055e80d13d1b0 R15: 0000000000000009
<4>[  260.470233]  </TASK>
<4>[  260.470239] Modules linked in: vgem drm_shmem_helper fuse snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio i915 snd_hda_intel snd_intel_dspcfg snd_hda_codec x86_pkg_temp_thermal coretemp crct10dif_pclmul crc32_pclmul snd_hwdep ghash_clmulni_intel snd_hda_core ttm drm_buddy drm_dp_helper snd_pcm drm_kms_helper i2c_i801 r8169 i2c_smbus syscopyarea realtek sysfillrect sysimgblt fb_sys_fops prime_numbers intel_lpss_pci
<4>[  260.470289] CR2: 0000000000000010
<4>[  260.470312] ---[ end trace 0000000000000000 ]---

Can we please start running dma-buf stuff through CI so this
kind of stuff doesn't keep happening so often?

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
@ 2022-03-25 15:25   ` Ville Syrjälä
  0 siblings, 0 replies; 40+ messages in thread
From: Ville Syrjälä @ 2022-03-25 15:25 UTC (permalink / raw)
  To: Christian König
  Cc: gustavo, dri-devel, sumit.semwal, linaro-mm-sig, Daniel Vetter,
	Christian König, linux-media

On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
> structures and iterate over all the fences in them.
> 
> This is useful when we need to flatten out all fences in those structures.
> 
> Signed-off-by: Christian König <christian.koenig@amd.com>

One of the dma-buf patches took down Intel CI. Looks like every
machine oopses in some sync_file thing now:
<1>[  260.470008] BUG: kernel NULL pointer dereference, address: 0000000000000010
<1>[  260.470020] #PF: supervisor read access in kernel mode
<1>[  260.470025] #PF: error_code(0x0000) - not-present page
<6>[  260.470030] PGD 0 P4D 0 
<4>[  260.470035] Oops: 0000 [#1] PREEMPT SMP NOPTI
<4>[  260.470040] CPU: 0 PID: 5306 Comm: core_hotunplug Not tainted 5.17.0-CI-CI_DRM_11405+ #1
<4>[  260.470049] Hardware name: Intel Corporation Jasper Lake Client Platform/Jasperlake DDR4 SODIMM RVP, BIOS JSLSFWI1.R00.2385.D02.2010160831 10/16/2020
<4>[  260.470058] RIP: 0010:dma_fence_array_first+0x19/0x20
<4>[  260.470068] Code: c3 31 c0 c3 0f 1f 00 66 2e 0f 1f 84 00 00 00 00 00 48 85 ff 74 18 48 89 f8 48 81 7f 08 60 7f 0a 82 75 0d 48 8b 87 88 00 00 00 <48> 8b 00 c3 31 c0 c3 31 c0 48 85 ff 74 20 48 81 7f 08 60 7f 0a 82
<4>[  260.470080] RSP: 0018:ffffc900009a7e40 EFLAGS: 00010246
<4>[  260.470086] RAX: 0000000000000010 RBX: 000000000000000b RCX: 0000000000000000
<4>[  260.470100] RDX: 0000000000000001 RSI: 0000000000000001 RDI: ffff888109a796b8
<4>[  260.470106] RBP: ffff888109a796b8 R08: 0000000000000002 R09: 0000000000000000
<4>[  260.470112] R10: 0000000000000001 R11: 0000000000000000 R12: ffff888109a796b8
<4>[  260.470118] R13: 00007ffc5d21f750 R14: ffff8881065be340 R15: 0000000000000000
<4>[  260.470124] FS:  00007f08bd6d04c0(0000) GS:ffff88885fc00000(0000) knlGS:0000000000000000
<4>[  260.470131] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
<4>[  260.470137] CR2: 0000000000000010 CR3: 000000010e690000 CR4: 0000000000350ef0
<4>[  260.470143] Call Trace:
<4>[  260.470146]  <TASK>
<4>[  260.470149]  sync_file_ioctl+0x2eb/0xc90
<4>[  260.470157]  __x64_sys_ioctl+0x6a/0xa0
<4>[  260.470164]  do_syscall_64+0x37/0xb0
<4>[  260.470170]  entry_SYSCALL_64_after_hwframe+0x44/0xae
<4>[  260.470176] RIP: 0033:0x7f08c047750b
<4>[  260.470182] Code: 0f 1e fa 48 8b 05 85 39 0d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 55 39 0d 00 f7 d8 64 89 01 48
<4>[  260.470195] RSP: 002b:00007ffc5d21f748 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
<4>[  260.470202] RAX: ffffffffffffffda RBX: 000000000000000a RCX: 00007f08c047750b
<4>[  260.470208] RDX: 00007ffc5d21f750 RSI: 00000000c0303e03 RDI: 000000000000000a
<4>[  260.470214] RBP: 0000000000000005 R08: 0000000000000000 R09: 00007ffc5d21ebb0
<4>[  260.470219] R10: 00007f08c0a6170e R11: 0000000000000246 R12: 0000000000000000
<4>[  260.470225] R13: 00007ffc5d21f840 R14: 000055e80d13d1b0 R15: 0000000000000009
<4>[  260.470233]  </TASK>
<4>[  260.470239] Modules linked in: vgem drm_shmem_helper fuse snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio i915 snd_hda_intel snd_intel_dspcfg snd_hda_codec x86_pkg_temp_thermal coretemp crct10dif_pclmul crc32_pclmul snd_hwdep ghash_clmulni_intel snd_hda_core ttm drm_buddy drm_dp_helper snd_pcm drm_kms_helper i2c_i801 r8169 i2c_smbus syscopyarea realtek sysfillrect sysimgblt fb_sys_fops prime_numbers intel_lpss_pci
<4>[  260.470289] CR2: 0000000000000010
<4>[  260.470312] ---[ end trace 0000000000000000 ]---

Can we please start running dma-buf stuff through CI so this
kind of stuff doesn't keep happening so often?

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-25 15:25   ` Ville Syrjälä
@ 2022-03-25 15:28     ` Christian König
  -1 siblings, 0 replies; 40+ messages in thread
From: Christian König @ 2022-03-25 15:28 UTC (permalink / raw)
  To: Ville Syrjälä, Christian König
  Cc: gustavo, dri-devel, linaro-mm-sig, Daniel Vetter, sumit.semwal,
	linux-media

Am 25.03.22 um 16:25 schrieb Ville Syrjälä:
> On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
>> Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
>> structures and iterate over all the fences in them.
>>
>> This is useful when we need to flatten out all fences in those structures.
>>
>> Signed-off-by: Christian König <christian.koenig@amd.com>
> One of the dma-buf patches took down Intel CI. Looks like every
> machine oopses in some sync_file thing now:
> <1>[  260.470008] BUG: kernel NULL pointer dereference, address: 0000000000000010
> <1>[  260.470020] #PF: supervisor read access in kernel mode
> <1>[  260.470025] #PF: error_code(0x0000) - not-present page
> <6>[  260.470030] PGD 0 P4D 0
> <4>[  260.470035] Oops: 0000 [#1] PREEMPT SMP NOPTI
> <4>[  260.470040] CPU: 0 PID: 5306 Comm: core_hotunplug Not tainted 5.17.0-CI-CI_DRM_11405+ #1
> <4>[  260.470049] Hardware name: Intel Corporation Jasper Lake Client Platform/Jasperlake DDR4 SODIMM RVP, BIOS JSLSFWI1.R00.2385.D02.2010160831 10/16/2020
> <4>[  260.470058] RIP: 0010:dma_fence_array_first+0x19/0x20
> <4>[  260.470068] Code: c3 31 c0 c3 0f 1f 00 66 2e 0f 1f 84 00 00 00 00 00 48 85 ff 74 18 48 89 f8 48 81 7f 08 60 7f 0a 82 75 0d 48 8b 87 88 00 00 00 <48> 8b 00 c3 31 c0 c3 31 c0 48 85 ff 74 20 48 81 7f 08 60 7f 0a 82
> <4>[  260.470080] RSP: 0018:ffffc900009a7e40 EFLAGS: 00010246
> <4>[  260.470086] RAX: 0000000000000010 RBX: 000000000000000b RCX: 0000000000000000
> <4>[  260.470100] RDX: 0000000000000001 RSI: 0000000000000001 RDI: ffff888109a796b8
> <4>[  260.470106] RBP: ffff888109a796b8 R08: 0000000000000002 R09: 0000000000000000
> <4>[  260.470112] R10: 0000000000000001 R11: 0000000000000000 R12: ffff888109a796b8
> <4>[  260.470118] R13: 00007ffc5d21f750 R14: ffff8881065be340 R15: 0000000000000000
> <4>[  260.470124] FS:  00007f08bd6d04c0(0000) GS:ffff88885fc00000(0000) knlGS:0000000000000000
> <4>[  260.470131] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> <4>[  260.470137] CR2: 0000000000000010 CR3: 000000010e690000 CR4: 0000000000350ef0
> <4>[  260.470143] Call Trace:
> <4>[  260.470146]  <TASK>
> <4>[  260.470149]  sync_file_ioctl+0x2eb/0xc90
> <4>[  260.470157]  __x64_sys_ioctl+0x6a/0xa0
> <4>[  260.470164]  do_syscall_64+0x37/0xb0
> <4>[  260.470170]  entry_SYSCALL_64_after_hwframe+0x44/0xae
> <4>[  260.470176] RIP: 0033:0x7f08c047750b
> <4>[  260.470182] Code: 0f 1e fa 48 8b 05 85 39 0d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 55 39 0d 00 f7 d8 64 89 01 48
> <4>[  260.470195] RSP: 002b:00007ffc5d21f748 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
> <4>[  260.470202] RAX: ffffffffffffffda RBX: 000000000000000a RCX: 00007f08c047750b
> <4>[  260.470208] RDX: 00007ffc5d21f750 RSI: 00000000c0303e03 RDI: 000000000000000a
> <4>[  260.470214] RBP: 0000000000000005 R08: 0000000000000000 R09: 00007ffc5d21ebb0
> <4>[  260.470219] R10: 00007f08c0a6170e R11: 0000000000000246 R12: 0000000000000000
> <4>[  260.470225] R13: 00007ffc5d21f840 R14: 000055e80d13d1b0 R15: 0000000000000009
> <4>[  260.470233]  </TASK>
> <4>[  260.470239] Modules linked in: vgem drm_shmem_helper fuse snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio i915 snd_hda_intel snd_intel_dspcfg snd_hda_codec x86_pkg_temp_thermal coretemp crct10dif_pclmul crc32_pclmul snd_hwdep ghash_clmulni_intel snd_hda_core ttm drm_buddy drm_dp_helper snd_pcm drm_kms_helper i2c_i801 r8169 i2c_smbus syscopyarea realtek sysfillrect sysimgblt fb_sys_fops prime_numbers intel_lpss_pci
> <4>[  260.470289] CR2: 0000000000000010
> <4>[  260.470312] ---[ end trace 0000000000000000 ]---
>
> Can we please start running dma-buf stuff through CI so this
> kind of stuff doesn't keep happening so often?

I've did ran it through CI, but since the most recent patches didn't 
applied on top of drm-tip for some reason the result was just garbage.

Going to take a look into this immediately, looks like something which 
I've seen during development maybe the wrong patch was pushed to 
drm-misc-next-fixes or something like this.

Thanks for letting me know,
Christian.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
@ 2022-03-25 15:28     ` Christian König
  0 siblings, 0 replies; 40+ messages in thread
From: Christian König @ 2022-03-25 15:28 UTC (permalink / raw)
  To: Ville Syrjälä, Christian König
  Cc: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig,
	Daniel Vetter, Dave Airlie

Am 25.03.22 um 16:25 schrieb Ville Syrjälä:
> On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
>> Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
>> structures and iterate over all the fences in them.
>>
>> This is useful when we need to flatten out all fences in those structures.
>>
>> Signed-off-by: Christian König <christian.koenig@amd.com>
> One of the dma-buf patches took down Intel CI. Looks like every
> machine oopses in some sync_file thing now:
> <1>[  260.470008] BUG: kernel NULL pointer dereference, address: 0000000000000010
> <1>[  260.470020] #PF: supervisor read access in kernel mode
> <1>[  260.470025] #PF: error_code(0x0000) - not-present page
> <6>[  260.470030] PGD 0 P4D 0
> <4>[  260.470035] Oops: 0000 [#1] PREEMPT SMP NOPTI
> <4>[  260.470040] CPU: 0 PID: 5306 Comm: core_hotunplug Not tainted 5.17.0-CI-CI_DRM_11405+ #1
> <4>[  260.470049] Hardware name: Intel Corporation Jasper Lake Client Platform/Jasperlake DDR4 SODIMM RVP, BIOS JSLSFWI1.R00.2385.D02.2010160831 10/16/2020
> <4>[  260.470058] RIP: 0010:dma_fence_array_first+0x19/0x20
> <4>[  260.470068] Code: c3 31 c0 c3 0f 1f 00 66 2e 0f 1f 84 00 00 00 00 00 48 85 ff 74 18 48 89 f8 48 81 7f 08 60 7f 0a 82 75 0d 48 8b 87 88 00 00 00 <48> 8b 00 c3 31 c0 c3 31 c0 48 85 ff 74 20 48 81 7f 08 60 7f 0a 82
> <4>[  260.470080] RSP: 0018:ffffc900009a7e40 EFLAGS: 00010246
> <4>[  260.470086] RAX: 0000000000000010 RBX: 000000000000000b RCX: 0000000000000000
> <4>[  260.470100] RDX: 0000000000000001 RSI: 0000000000000001 RDI: ffff888109a796b8
> <4>[  260.470106] RBP: ffff888109a796b8 R08: 0000000000000002 R09: 0000000000000000
> <4>[  260.470112] R10: 0000000000000001 R11: 0000000000000000 R12: ffff888109a796b8
> <4>[  260.470118] R13: 00007ffc5d21f750 R14: ffff8881065be340 R15: 0000000000000000
> <4>[  260.470124] FS:  00007f08bd6d04c0(0000) GS:ffff88885fc00000(0000) knlGS:0000000000000000
> <4>[  260.470131] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> <4>[  260.470137] CR2: 0000000000000010 CR3: 000000010e690000 CR4: 0000000000350ef0
> <4>[  260.470143] Call Trace:
> <4>[  260.470146]  <TASK>
> <4>[  260.470149]  sync_file_ioctl+0x2eb/0xc90
> <4>[  260.470157]  __x64_sys_ioctl+0x6a/0xa0
> <4>[  260.470164]  do_syscall_64+0x37/0xb0
> <4>[  260.470170]  entry_SYSCALL_64_after_hwframe+0x44/0xae
> <4>[  260.470176] RIP: 0033:0x7f08c047750b
> <4>[  260.470182] Code: 0f 1e fa 48 8b 05 85 39 0d 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 55 39 0d 00 f7 d8 64 89 01 48
> <4>[  260.470195] RSP: 002b:00007ffc5d21f748 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
> <4>[  260.470202] RAX: ffffffffffffffda RBX: 000000000000000a RCX: 00007f08c047750b
> <4>[  260.470208] RDX: 00007ffc5d21f750 RSI: 00000000c0303e03 RDI: 000000000000000a
> <4>[  260.470214] RBP: 0000000000000005 R08: 0000000000000000 R09: 00007ffc5d21ebb0
> <4>[  260.470219] R10: 00007f08c0a6170e R11: 0000000000000246 R12: 0000000000000000
> <4>[  260.470225] R13: 00007ffc5d21f840 R14: 000055e80d13d1b0 R15: 0000000000000009
> <4>[  260.470233]  </TASK>
> <4>[  260.470239] Modules linked in: vgem drm_shmem_helper fuse snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic ledtrig_audio i915 snd_hda_intel snd_intel_dspcfg snd_hda_codec x86_pkg_temp_thermal coretemp crct10dif_pclmul crc32_pclmul snd_hwdep ghash_clmulni_intel snd_hda_core ttm drm_buddy drm_dp_helper snd_pcm drm_kms_helper i2c_i801 r8169 i2c_smbus syscopyarea realtek sysfillrect sysimgblt fb_sys_fops prime_numbers intel_lpss_pci
> <4>[  260.470289] CR2: 0000000000000010
> <4>[  260.470312] ---[ end trace 0000000000000000 ]---
>
> Can we please start running dma-buf stuff through CI so this
> kind of stuff doesn't keep happening so often?

I've did ran it through CI, but since the most recent patches didn't 
applied on top of drm-tip for some reason the result was just garbage.

Going to take a look into this immediately, looks like something which 
I've seen during development maybe the wrong patch was pushed to 
drm-misc-next-fixes or something like this.

Thanks for letting me know,
Christian.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-25 12:56           ` Christian König
@ 2022-03-25 16:00             ` Daniel Vetter
  -1 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-25 16:00 UTC (permalink / raw)
  To: Christian König
  Cc: Daniel Vetter, Christian König, sumit.semwal, gustavo,
	linux-media, dri-devel, linaro-mm-sig

On Fri, Mar 25, 2022 at 01:56:23PM +0100, Christian König wrote:
> Am 25.03.22 um 11:17 schrieb Daniel Vetter:
> > On Fri, Mar 25, 2022 at 11:10:15AM +0100, Christian König wrote:
> > > Am 25.03.22 um 11:07 schrieb Daniel Vetter:
> > > > On Fri, Mar 25, 2022 at 11:03:54AM +0100, Daniel Vetter wrote:
> > > > > On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> > > > > > Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
> > > > > > structures and iterate over all the fences in them.
> > > > > > 
> > > > > > This is useful when we need to flatten out all fences in those structures.
> > > > > > 
> > > > > > Signed-off-by: Christian König <christian.koenig@amd.com>
> > > > > > ---
> > > > > >    Documentation/driver-api/dma-buf.rst  |   6 +
> > > > > >    drivers/dma-buf/Makefile              |   1 +
> > > > > >    drivers/dma-buf/selftests.h           |   1 +
> > > > > >    drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
> > > > > >    include/linux/dma-fence-unwrap.h      |  99 +++++++++
> > > > > >    5 files changed, 386 insertions(+)
> > > > > >    create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
> > > > > >    create mode 100644 include/linux/dma-fence-unwrap.h
> > > > > > 
> > > > > > diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
> > > > > > index 2cd7db82d9fe..7209500f08c8 100644
> > > > > > --- a/Documentation/driver-api/dma-buf.rst
> > > > > > +++ b/Documentation/driver-api/dma-buf.rst
> > > > > > @@ -194,6 +194,12 @@ DMA Fence Chain
> > > > > >    .. kernel-doc:: include/linux/dma-fence-chain.h
> > > > > >       :internal:
> > > > > > +DMA Fence unwrap
> > > > > > +~~~~~~~~~~~~~~~~
> > > > > > +
> > > > > > +.. kernel-doc:: include/linux/dma-fence-unwrap.h
> > > > > > +   :internal:
> > > > Ok I forgot one bikeshed: I'd just include this in dma-fence-chain.h and
> > > > maybe go with the dma_fence_chain_unwrap_ prefix for everything. That
> > > > makes it even more clearer that the two are meant to go together. Plus ofc
> > > > the link from struct dma_fence_chain to this iterator in the docs too.
> > > > 
> > > > Or I'm just not understanding why you made this a separate thing?
> > > Well it should be used to unwrap dma_fence_array containers as well and I
> > > don't really want to add a dependency between dma_fence_chain and
> > > dma_fence_array.
> > > 
> > > I've spend quite some work to keep the two containers separated and also
> > > describe the separate use cases for each.
> > > 
> > > I can of course add some kerneldoc to let the chain and array documentation
> > > point to this one here.
> > Yeah I think as a general iterator they should be fine as a separate
> > thing. Also just realized that we'd need links from both array and chain
> > to this since it's for both.
> 
> Done.
> 
> > 
> > The other thing I noticed is that we have dma_fence_chain_for_each()
> > already. Should we replace all users of that outside of dma-fence-chain.c
> > with this new thing, and move the chain specific iterator into
> > dma-fence-chain.c so that it's hidden and people don't make funny
> > accidents? Just for more safety in this maze, also ofc that's all
> > follow-up.
> 
> Uff, good question. There are some valid use cases for it I think.
> 
> Especially the timeline syncobj handling only want to work with chain
> structures and not with the eventually contained array.
> 
> It could just be that we might want to wrap those use cases into
> dma_fence_chain helpers.

Yeah one of the drm_syncobj ones looked somewhat legit, the other is just
a dma_fence_chain_do_gc() in a trechcoat and should be wrapped in a proper
interface I guess. The driver ones looked more like they really want to
just walk fences (some iirc even hand-roll the array unwrapping further
down on their own).

> Anyway, not stuff for drm-misc-next-fixes, but going to keep that in mind.

Agreed.
-Daniel

> 
> Christian.
> 
> > -Daniel
> > 
> > 
> > 
> > > Thanks,
> > > Christian.
> > > 
> > > > -Daniel
> > > > 
> > > > > > +
> > > > > >    DMA Fence uABI/Sync File
> > > > > >    ~~~~~~~~~~~~~~~~~~~~~~~~
> > > > > > diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
> > > > > > index 511805dbeb75..4c9eb53ba3f8 100644
> > > > > > --- a/drivers/dma-buf/Makefile
> > > > > > +++ b/drivers/dma-buf/Makefile
> > > > > > @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
> > > > > >    	selftest.o \
> > > > > >    	st-dma-fence.o \
> > > > > >    	st-dma-fence-chain.o \
> > > > > > +	st-dma-fence-unwrap.o \
> > > > > >    	st-dma-resv.o
> > > > > >    obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
> > > > > > diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
> > > > > > index 97d73aaa31da..851965867d9c 100644
> > > > > > --- a/drivers/dma-buf/selftests.h
> > > > > > +++ b/drivers/dma-buf/selftests.h
> > > > > > @@ -12,4 +12,5 @@
> > > > > >    selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
> > > > > >    selftest(dma_fence, dma_fence)
> > > > > >    selftest(dma_fence_chain, dma_fence_chain)
> > > > > > +selftest(dma_fence_unwrap, dma_fence_unwrap)
> > > > > >    selftest(dma_resv, dma_resv)
> > > > > > diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
> > > > > > new file mode 100644
> > > > > > index 000000000000..d821faaebe93
> > > > > > --- /dev/null
> > > > > > +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
> > > > > > @@ -0,0 +1,279 @@
> > > > > > +// SPDX-License-Identifier: MIT
> > > > > > +
> > > > > > +/*
> > > > > > + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> > > > > > + */
> > > > > > +
> > > > > > +#include <linux/dma-fence-unwrap.h>
> > > > > > +#if 0
> > > > > > +#include <linux/kernel.h>
> > > > > > +#include <linux/kthread.h>
> > > > > > +#include <linux/mm.h>
> > > > > > +#include <linux/sched/signal.h>
> > > > > > +#include <linux/slab.h>
> > > > > > +#include <linux/spinlock.h>
> > > > > > +#include <linux/random.h>
> > > > > > +#endif
> > > > > > +
> > > > > > +#include "selftest.h"
> > > > > > +
> > > > > > +#define CHAIN_SZ (4 << 10)
> > > > > > +
> > > > > > +static struct kmem_cache *slab_fences;
> > > > > Your own slab feels a bit like overkill. kmalloc/kfree not good enough?
> > > > > 
> > > > > > +
> > > > > > +static inline struct mock_fence {
> > > > > > +	struct dma_fence base;
> > > > > > +	spinlock_t lock;
> > > > > > +} *to_mock_fence(struct dma_fence *f) {
> > > > > > +	return container_of(f, struct mock_fence, base);
> > > > > > +}
> > > > > > +
> > > > > > +static const char *mock_name(struct dma_fence *f)
> > > > > > +{
> > > > > > +	return "mock";
> > > > > > +}
> > > > > > +
> > > > > > +static void mock_fence_release(struct dma_fence *f)
> > > > > > +{
> > > > > > +	kmem_cache_free(slab_fences, to_mock_fence(f));
> > > > > > +}
> > > > > > +
> > > > > > +static const struct dma_fence_ops mock_ops = {
> > > > > > +	.get_driver_name = mock_name,
> > > > > > +	.get_timeline_name = mock_name,
> > > > > > +	.release = mock_fence_release,
> > > > > > +};
> > > > > > +
> > > > > > +static struct dma_fence *mock_fence(void)
> > > > > > +{
> > > > > > +	struct mock_fence *f;
> > > > > > +
> > > > > > +	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
> > > > > > +	if (!f)
> > > > > > +		return NULL;
> > > > > > +
> > > > > > +	spin_lock_init(&f->lock);
> > > > > > +	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
> > > > > > +
> > > > > > +	return &f->base;
> > > > > > +}
> > > > > > +
> > > > > > +static struct dma_fence *mock_array(unsigned int num_fences, ...)
> > > > > > +{
> > > > > > +	struct dma_fence_array *array;
> > > > > > +	struct dma_fence **fences;
> > > > > > +	va_list valist;
> > > > > > +	int i;
> > > > > > +
> > > > > > +	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
> > > > > > +	if (!fences)
> > > > > > +		return NULL;
> > > > > > +
> > > > > > +	va_start(valist, num_fences);
> > > > > > +	for (i = 0; i < num_fences; ++i)
> > > > > > +		fences[i] = va_arg(valist, typeof(*fences));
> > > > > > +	va_end(valist);
> > > > > > +
> > > > > > +	array = dma_fence_array_create(num_fences, fences,
> > > > > > +				       dma_fence_context_alloc(1),
> > > > > > +				       1, false);
> > > > > > +	if (!array)
> > > > > > +		goto cleanup;
> > > > > > +	return &array->base;
> > > > > > +
> > > > > > +cleanup:
> > > > > > +	for (i = 0; i < num_fences; ++i)
> > > > > > +		dma_fence_put(fences[i]);
> > > > > > +	kfree(fences);
> > > > > > +	return NULL;
> > > > > > +}
> > > > > > +
> > > > > > +static struct dma_fence *mock_chain(struct dma_fence *prev,
> > > > > > +				    struct dma_fence *fence)
> > > > > > +{
> > > > > > +	struct dma_fence_chain *f;
> > > > > > +
> > > > > > +	f = dma_fence_chain_alloc();
> > > > > > +	if (!f) {
> > > > > > +		dma_fence_put(prev);
> > > > > > +		dma_fence_put(fence);
> > > > > > +		return NULL;
> > > > > > +	}
> > > > > > +
> > > > > > +	dma_fence_chain_init(f, prev, fence, 1);
> > > > > > +	return &f->base;
> > > > > > +}
> > > > > > +
> > > > > > +static int sanitycheck(void *arg)
> > > > > > +{
> > > > > > +	struct dma_fence *f, *chain, *array;
> > > > > > +	int err = 0;
> > > > > > +
> > > > > > +	f = mock_fence();
> > > > > > +	if (!f)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	array = mock_array(1, f);
> > > > > > +	if (!array)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	chain = mock_chain(NULL, array);
> > > > > > +	if (!chain)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	dma_fence_signal(f);
> > > > > > +	dma_fence_put(chain);
> > > > > > +	return err;
> > > > > > +}
> > > > > > +
> > > > > > +static int unwrap_array(void *arg)
> > > > > > +{
> > > > > > +	struct dma_fence *fence, *f1, *f2, *array;
> > > > > > +	struct dma_fence_unwrap iter;
> > > > > > +	int err = 0;
> > > > > > +
> > > > > > +	f1 = mock_fence();
> > > > > > +	if (!f1)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	f2 = mock_fence();
> > > > > > +	if (!f2) {
> > > > > > +		dma_fence_put(f1);
> > > > > > +		return -ENOMEM;
> > > > > > +	}
> > > > > > +
> > > > > > +	array = mock_array(2, f1, f2);
> > > > > > +	if (!array)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	dma_fence_unwrap_for_each(fence, &iter, array) {
> > > > > > +		if (fence == f1) {
> > > > > > +			f1 = NULL;
> > > > > > +		} else if (fence == f2) {
> > > > > > +			f2 = NULL;
> > > > > > +		} else {
> > > > > > +			pr_err("Unexpected fence!\n");
> > > > > > +			err = -EINVAL;
> > > > > > +		}
> > > > > > +	}
> > > > > > +
> > > > > > +	if (f1 || f2) {
> > > > > > +		pr_err("Not all fences seen!\n");
> > > > > > +		err = -EINVAL;
> > > > > > +	}
> > > > > > +
> > > > > > +	dma_fence_signal(f1);
> > > > > > +	dma_fence_signal(f2);
> > > > > > +	dma_fence_put(array);
> > > > > > +	return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static int unwrap_chain(void *arg)
> > > > > > +{
> > > > > > +	struct dma_fence *fence, *f1, *f2, *chain;
> > > > > > +	struct dma_fence_unwrap iter;
> > > > > > +	int err = 0;
> > > > > > +
> > > > > > +	f1 = mock_fence();
> > > > > > +	if (!f1)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	f2 = mock_fence();
> > > > > > +	if (!f2) {
> > > > > > +		dma_fence_put(f1);
> > > > > > +		return -ENOMEM;
> > > > > > +	}
> > > > > > +
> > > > > > +	chain = mock_chain(f1, f2);
> > > > > > +	if (!chain)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> > > > > > +		if (fence == f1) {
> > > > > > +			f1 = NULL;
> > > > > > +		} else if (fence == f2) {
> > > > > > +			f2 = NULL;
> > > > > > +		} else {
> > > > > > +			pr_err("Unexpected fence!\n");
> > > > > > +			err = -EINVAL;
> > > > > > +		}
> > > > > > +	}
> > > > > > +
> > > > > > +	if (f1 || f2) {
> > > > > > +		pr_err("Not all fences seen!\n");
> > > > > > +		err = -EINVAL;
> > > > > > +	}
> > > > > > +
> > > > > > +	dma_fence_signal(f1);
> > > > > > +	dma_fence_signal(f2);
> > > > > > +	dma_fence_put(chain);
> > > > > > +	return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static int unwrap_chain_array(void *arg)
> > > > > > +{
> > > > > > +	struct dma_fence *fence, *f1, *f2, *array, *chain;
> > > > > > +	struct dma_fence_unwrap iter;
> > > > > > +	int err = 0;
> > > > > > +
> > > > > > +	f1 = mock_fence();
> > > > > > +	if (!f1)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	f2 = mock_fence();
> > > > > > +	if (!f2) {
> > > > > > +		dma_fence_put(f1);
> > > > > > +		return -ENOMEM;
> > > > > > +	}
> > > > > > +
> > > > > > +	array = mock_array(2, f1, f2);
> > > > > > +	if (!array)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	chain = mock_chain(NULL, array);
> > > > > > +	if (!chain)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> > > > > > +		if (fence == f1) {
> > > > > > +			f1 = NULL;
> > > > > > +		} else if (fence == f2) {
> > > > > > +			f2 = NULL;
> > > > > > +		} else {
> > > > > > +			pr_err("Unexpected fence!\n");
> > > > > > +			err = -EINVAL;
> > > > > > +		}
> > > > > > +	}
> > > > > > +
> > > > > > +	if (f1 || f2) {
> > > > > > +		pr_err("Not all fences seen!\n");
> > > > > > +		err = -EINVAL;
> > > > > > +	}
> > > > > > +
> > > > > > +	dma_fence_signal(f1);
> > > > > > +	dma_fence_signal(f2);
> > > > > > +	dma_fence_put(chain);
> > > > > > +	return 0;
> > > > > > +}
> > > > > > +
> > > > > > +int dma_fence_unwrap(void)
> > > > > > +{
> > > > > > +	static const struct subtest tests[] = {
> > > > > > +		SUBTEST(sanitycheck),
> > > > > > +		SUBTEST(unwrap_array),
> > > > > > +		SUBTEST(unwrap_chain),
> > > > > > +		SUBTEST(unwrap_chain_array),
> > > > > > +	};
> > > > > > +	int ret;
> > > > > > +
> > > > > > +	slab_fences = KMEM_CACHE(mock_fence,
> > > > > > +				 SLAB_TYPESAFE_BY_RCU |
> > > > > > +				 SLAB_HWCACHE_ALIGN);
> > > > > > +	if (!slab_fences)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	ret = subtests(tests, NULL);
> > > > > > +
> > > > > > +	kmem_cache_destroy(slab_fences);
> > > > > > +	return ret;
> > > > > > +}
> > > > > > diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
> > > > > > new file mode 100644
> > > > > > index 000000000000..54963df00c98
> > > > > > --- /dev/null
> > > > > > +++ b/include/linux/dma-fence-unwrap.h
> > > > > > @@ -0,0 +1,99 @@
> > > > > > +/* SPDX-License-Identifier: GPL-2.0-only */
> > > > > > +/*
> > > > > > + * fence-chain: chain fences together in a timeline
> > > > > > + *
> > > > > > + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> > > > > > + * Authors:
> > > > > > + *	Christian König <christian.koenig@amd.com>
> > > > > > + */
> > > > > > +
> > > > > > +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
> > > > > > +#define __LINUX_DMA_FENCE_UNWRAP_H
> > > > > > +
> > > > > > +#include <linux/dma-fence-chain.h>
> > > > > > +#include <linux/dma-fence-array.h>
> > > > > > +
> > > > > > +/**
> > > > > > + * struct dma_fence_unwrap - cursor into the container structure
> > > > > I think adding "This should be used together with
> > > > > dma_fence_unwrap_for_each() iterator macro." would be nice here. I just
> > > > > like links :-)
> > > > > 
> > > > > > + */
> > > > > > +struct dma_fence_unwrap {
> > > > > > +	/**
> > > > > > +	 * @chain: potential dma_fence_chain, but can be other fence as well
> > > > > > +	 */
> > > > > > +	struct dma_fence *chain;
> > > > > > +	/**
> > > > > > +	 * @array: potential dma_fence_array, but can be other fence as well
> > > > > > +	 */
> > > > > > +	struct dma_fence *array;
> > > > > > +	/**
> > > > > > +	 * @index: last returned index if @array is really a dma_fence_array
> > > > > > +	 */
> > > > > > +	unsigned int index;
> > > > > > +};
> > > > > > +
> > > > > > +/**
> > > > > > + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
> > > > > > + * @cursor: cursor to initialize
> > > > > > + *
> > > > > > + * Helper function to unwrap dma_fence_array containers, don't touch directly.
> > > > > > + * Use dma_fence_unwrap_first/next instead.
> > > > > > + */
> > > > > > +static inline struct dma_fence *
> > > > > > +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
> > > > > Since this is a helper that no one should call I'd give it a __ prefix and
> > > > > drop the kerneldoc. Documenting stuff that people shouldn't use is
> > > > > confusing :-)
> > > > > 
> > > > > > +{
> > > > > > +	cursor->array = dma_fence_chain_contained(cursor->chain);
> > > > > > +	cursor->index = 0;
> > > > > > +	return dma_fence_array_first(cursor->array);
> > > > > > +}
> > > > > > +
> > > > > > +/**
> > > > > > + * dma_fence_unwrap_first - return the first fence from fence containers
> > > > > > + * @head: the entrypoint into the containers
> > > > > > + * @cursor: current position inside the containers
> > > > > > + *
> > > > > > + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
> > > > > > + * first fence.
> > > > > > + */
> > > > > > +static inline struct dma_fence *
> > > > > > +dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
> > > > > > +{
> > > > > > +	cursor->chain = dma_fence_get(head);
> > > > > > +	return dma_fence_unwrap_array(cursor);
> > > > > > +}
> > > > > > +
> > > > > > +/**
> > > > > > + * dma_fence_unwrap_next - return the next fence from a fence containers
> > > > > > + * @cursor: current position inside the containers
> > > > > > + *
> > > > > > + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
> > > > > > + * the next fence from them.
> > > > > > + */
> > > > > > +static inline struct dma_fence *
> > > > > > +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
> > > > > > +{
> > > > > > +	struct dma_fence *tmp;
> > > > > > +
> > > > > > +	++cursor->index;
> > > > > > +	tmp = dma_fence_array_next(cursor->array, cursor->index);
> > > > > > +	if (tmp)
> > > > > > +		return tmp;
> > > > > > +
> > > > > > +	cursor->chain = dma_fence_chain_walk(cursor->chain);
> > > > > > +	return dma_fence_unwrap_array(cursor);
> > > > > > +}
> > > > > > +
> > > > > > +/**
> > > > > > + * dma_fence_unwrap_for_each - iterate over all fences in containers
> > > > > > + * @fence: current fence
> > > > > > + * @cursor: current position inside the containers
> > > > > > + * @head: starting point for the iterator
> > > > > > + *
> > > > > > + * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
> > > > > > + * potential fences in them. If @head is just a normal fence only that one is
> > > > > > + * returned.
> > > > > > + */
> > > > > > +#define dma_fence_unwrap_for_each(fence, cursor, head)			\
> > > > > > +	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
> > > > > > +	     fence = dma_fence_unwrap_next(cursor))
> > > > > > +
> > > > > > +#endif
> > > > > I think it'd be really good to add a small paragraph to struct
> > > > > dma_fence_chain that this macro and iterator should be used for walking
> > > > > over all fences in a chain, including any fence arrays or anything like
> > > > > that.
> > > > > 
> > > > > With the bikesheds addressed:
> > > > > 
> > > > > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > > > 
> > > > > > -- 
> > > > > > 2.25.1
> > > > > > 
> > > > > -- 
> > > > > Daniel Vetter
> > > > > Software Engineer, Intel Corporation
> > > > > https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.ffwll.ch%2F&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7Caa747083900b451d359308da0e4745e3%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637837996532802687%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=Jts5%2BObWJHeUG4oy2biwj5Bf3PKkMrYU%2F0EihvQRNuY%3D&amp;reserved=0
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
@ 2022-03-25 16:00             ` Daniel Vetter
  0 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-25 16:00 UTC (permalink / raw)
  To: Christian König
  Cc: gustavo, dri-devel, sumit.semwal, linaro-mm-sig,
	Christian König, linux-media

On Fri, Mar 25, 2022 at 01:56:23PM +0100, Christian König wrote:
> Am 25.03.22 um 11:17 schrieb Daniel Vetter:
> > On Fri, Mar 25, 2022 at 11:10:15AM +0100, Christian König wrote:
> > > Am 25.03.22 um 11:07 schrieb Daniel Vetter:
> > > > On Fri, Mar 25, 2022 at 11:03:54AM +0100, Daniel Vetter wrote:
> > > > > On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> > > > > > Add a general purpose helper to deep dive into dma_fence_chain/dma_fence_array
> > > > > > structures and iterate over all the fences in them.
> > > > > > 
> > > > > > This is useful when we need to flatten out all fences in those structures.
> > > > > > 
> > > > > > Signed-off-by: Christian König <christian.koenig@amd.com>
> > > > > > ---
> > > > > >    Documentation/driver-api/dma-buf.rst  |   6 +
> > > > > >    drivers/dma-buf/Makefile              |   1 +
> > > > > >    drivers/dma-buf/selftests.h           |   1 +
> > > > > >    drivers/dma-buf/st-dma-fence-unwrap.c | 279 ++++++++++++++++++++++++++
> > > > > >    include/linux/dma-fence-unwrap.h      |  99 +++++++++
> > > > > >    5 files changed, 386 insertions(+)
> > > > > >    create mode 100644 drivers/dma-buf/st-dma-fence-unwrap.c
> > > > > >    create mode 100644 include/linux/dma-fence-unwrap.h
> > > > > > 
> > > > > > diff --git a/Documentation/driver-api/dma-buf.rst b/Documentation/driver-api/dma-buf.rst
> > > > > > index 2cd7db82d9fe..7209500f08c8 100644
> > > > > > --- a/Documentation/driver-api/dma-buf.rst
> > > > > > +++ b/Documentation/driver-api/dma-buf.rst
> > > > > > @@ -194,6 +194,12 @@ DMA Fence Chain
> > > > > >    .. kernel-doc:: include/linux/dma-fence-chain.h
> > > > > >       :internal:
> > > > > > +DMA Fence unwrap
> > > > > > +~~~~~~~~~~~~~~~~
> > > > > > +
> > > > > > +.. kernel-doc:: include/linux/dma-fence-unwrap.h
> > > > > > +   :internal:
> > > > Ok I forgot one bikeshed: I'd just include this in dma-fence-chain.h and
> > > > maybe go with the dma_fence_chain_unwrap_ prefix for everything. That
> > > > makes it even more clearer that the two are meant to go together. Plus ofc
> > > > the link from struct dma_fence_chain to this iterator in the docs too.
> > > > 
> > > > Or I'm just not understanding why you made this a separate thing?
> > > Well it should be used to unwrap dma_fence_array containers as well and I
> > > don't really want to add a dependency between dma_fence_chain and
> > > dma_fence_array.
> > > 
> > > I've spend quite some work to keep the two containers separated and also
> > > describe the separate use cases for each.
> > > 
> > > I can of course add some kerneldoc to let the chain and array documentation
> > > point to this one here.
> > Yeah I think as a general iterator they should be fine as a separate
> > thing. Also just realized that we'd need links from both array and chain
> > to this since it's for both.
> 
> Done.
> 
> > 
> > The other thing I noticed is that we have dma_fence_chain_for_each()
> > already. Should we replace all users of that outside of dma-fence-chain.c
> > with this new thing, and move the chain specific iterator into
> > dma-fence-chain.c so that it's hidden and people don't make funny
> > accidents? Just for more safety in this maze, also ofc that's all
> > follow-up.
> 
> Uff, good question. There are some valid use cases for it I think.
> 
> Especially the timeline syncobj handling only want to work with chain
> structures and not with the eventually contained array.
> 
> It could just be that we might want to wrap those use cases into
> dma_fence_chain helpers.

Yeah one of the drm_syncobj ones looked somewhat legit, the other is just
a dma_fence_chain_do_gc() in a trechcoat and should be wrapped in a proper
interface I guess. The driver ones looked more like they really want to
just walk fences (some iirc even hand-roll the array unwrapping further
down on their own).

> Anyway, not stuff for drm-misc-next-fixes, but going to keep that in mind.

Agreed.
-Daniel

> 
> Christian.
> 
> > -Daniel
> > 
> > 
> > 
> > > Thanks,
> > > Christian.
> > > 
> > > > -Daniel
> > > > 
> > > > > > +
> > > > > >    DMA Fence uABI/Sync File
> > > > > >    ~~~~~~~~~~~~~~~~~~~~~~~~
> > > > > > diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
> > > > > > index 511805dbeb75..4c9eb53ba3f8 100644
> > > > > > --- a/drivers/dma-buf/Makefile
> > > > > > +++ b/drivers/dma-buf/Makefile
> > > > > > @@ -12,6 +12,7 @@ dmabuf_selftests-y := \
> > > > > >    	selftest.o \
> > > > > >    	st-dma-fence.o \
> > > > > >    	st-dma-fence-chain.o \
> > > > > > +	st-dma-fence-unwrap.o \
> > > > > >    	st-dma-resv.o
> > > > > >    obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
> > > > > > diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
> > > > > > index 97d73aaa31da..851965867d9c 100644
> > > > > > --- a/drivers/dma-buf/selftests.h
> > > > > > +++ b/drivers/dma-buf/selftests.h
> > > > > > @@ -12,4 +12,5 @@
> > > > > >    selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
> > > > > >    selftest(dma_fence, dma_fence)
> > > > > >    selftest(dma_fence_chain, dma_fence_chain)
> > > > > > +selftest(dma_fence_unwrap, dma_fence_unwrap)
> > > > > >    selftest(dma_resv, dma_resv)
> > > > > > diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
> > > > > > new file mode 100644
> > > > > > index 000000000000..d821faaebe93
> > > > > > --- /dev/null
> > > > > > +++ b/drivers/dma-buf/st-dma-fence-unwrap.c
> > > > > > @@ -0,0 +1,279 @@
> > > > > > +// SPDX-License-Identifier: MIT
> > > > > > +
> > > > > > +/*
> > > > > > + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> > > > > > + */
> > > > > > +
> > > > > > +#include <linux/dma-fence-unwrap.h>
> > > > > > +#if 0
> > > > > > +#include <linux/kernel.h>
> > > > > > +#include <linux/kthread.h>
> > > > > > +#include <linux/mm.h>
> > > > > > +#include <linux/sched/signal.h>
> > > > > > +#include <linux/slab.h>
> > > > > > +#include <linux/spinlock.h>
> > > > > > +#include <linux/random.h>
> > > > > > +#endif
> > > > > > +
> > > > > > +#include "selftest.h"
> > > > > > +
> > > > > > +#define CHAIN_SZ (4 << 10)
> > > > > > +
> > > > > > +static struct kmem_cache *slab_fences;
> > > > > Your own slab feels a bit like overkill. kmalloc/kfree not good enough?
> > > > > 
> > > > > > +
> > > > > > +static inline struct mock_fence {
> > > > > > +	struct dma_fence base;
> > > > > > +	spinlock_t lock;
> > > > > > +} *to_mock_fence(struct dma_fence *f) {
> > > > > > +	return container_of(f, struct mock_fence, base);
> > > > > > +}
> > > > > > +
> > > > > > +static const char *mock_name(struct dma_fence *f)
> > > > > > +{
> > > > > > +	return "mock";
> > > > > > +}
> > > > > > +
> > > > > > +static void mock_fence_release(struct dma_fence *f)
> > > > > > +{
> > > > > > +	kmem_cache_free(slab_fences, to_mock_fence(f));
> > > > > > +}
> > > > > > +
> > > > > > +static const struct dma_fence_ops mock_ops = {
> > > > > > +	.get_driver_name = mock_name,
> > > > > > +	.get_timeline_name = mock_name,
> > > > > > +	.release = mock_fence_release,
> > > > > > +};
> > > > > > +
> > > > > > +static struct dma_fence *mock_fence(void)
> > > > > > +{
> > > > > > +	struct mock_fence *f;
> > > > > > +
> > > > > > +	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
> > > > > > +	if (!f)
> > > > > > +		return NULL;
> > > > > > +
> > > > > > +	spin_lock_init(&f->lock);
> > > > > > +	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
> > > > > > +
> > > > > > +	return &f->base;
> > > > > > +}
> > > > > > +
> > > > > > +static struct dma_fence *mock_array(unsigned int num_fences, ...)
> > > > > > +{
> > > > > > +	struct dma_fence_array *array;
> > > > > > +	struct dma_fence **fences;
> > > > > > +	va_list valist;
> > > > > > +	int i;
> > > > > > +
> > > > > > +	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
> > > > > > +	if (!fences)
> > > > > > +		return NULL;
> > > > > > +
> > > > > > +	va_start(valist, num_fences);
> > > > > > +	for (i = 0; i < num_fences; ++i)
> > > > > > +		fences[i] = va_arg(valist, typeof(*fences));
> > > > > > +	va_end(valist);
> > > > > > +
> > > > > > +	array = dma_fence_array_create(num_fences, fences,
> > > > > > +				       dma_fence_context_alloc(1),
> > > > > > +				       1, false);
> > > > > > +	if (!array)
> > > > > > +		goto cleanup;
> > > > > > +	return &array->base;
> > > > > > +
> > > > > > +cleanup:
> > > > > > +	for (i = 0; i < num_fences; ++i)
> > > > > > +		dma_fence_put(fences[i]);
> > > > > > +	kfree(fences);
> > > > > > +	return NULL;
> > > > > > +}
> > > > > > +
> > > > > > +static struct dma_fence *mock_chain(struct dma_fence *prev,
> > > > > > +				    struct dma_fence *fence)
> > > > > > +{
> > > > > > +	struct dma_fence_chain *f;
> > > > > > +
> > > > > > +	f = dma_fence_chain_alloc();
> > > > > > +	if (!f) {
> > > > > > +		dma_fence_put(prev);
> > > > > > +		dma_fence_put(fence);
> > > > > > +		return NULL;
> > > > > > +	}
> > > > > > +
> > > > > > +	dma_fence_chain_init(f, prev, fence, 1);
> > > > > > +	return &f->base;
> > > > > > +}
> > > > > > +
> > > > > > +static int sanitycheck(void *arg)
> > > > > > +{
> > > > > > +	struct dma_fence *f, *chain, *array;
> > > > > > +	int err = 0;
> > > > > > +
> > > > > > +	f = mock_fence();
> > > > > > +	if (!f)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	array = mock_array(1, f);
> > > > > > +	if (!array)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	chain = mock_chain(NULL, array);
> > > > > > +	if (!chain)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	dma_fence_signal(f);
> > > > > > +	dma_fence_put(chain);
> > > > > > +	return err;
> > > > > > +}
> > > > > > +
> > > > > > +static int unwrap_array(void *arg)
> > > > > > +{
> > > > > > +	struct dma_fence *fence, *f1, *f2, *array;
> > > > > > +	struct dma_fence_unwrap iter;
> > > > > > +	int err = 0;
> > > > > > +
> > > > > > +	f1 = mock_fence();
> > > > > > +	if (!f1)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	f2 = mock_fence();
> > > > > > +	if (!f2) {
> > > > > > +		dma_fence_put(f1);
> > > > > > +		return -ENOMEM;
> > > > > > +	}
> > > > > > +
> > > > > > +	array = mock_array(2, f1, f2);
> > > > > > +	if (!array)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	dma_fence_unwrap_for_each(fence, &iter, array) {
> > > > > > +		if (fence == f1) {
> > > > > > +			f1 = NULL;
> > > > > > +		} else if (fence == f2) {
> > > > > > +			f2 = NULL;
> > > > > > +		} else {
> > > > > > +			pr_err("Unexpected fence!\n");
> > > > > > +			err = -EINVAL;
> > > > > > +		}
> > > > > > +	}
> > > > > > +
> > > > > > +	if (f1 || f2) {
> > > > > > +		pr_err("Not all fences seen!\n");
> > > > > > +		err = -EINVAL;
> > > > > > +	}
> > > > > > +
> > > > > > +	dma_fence_signal(f1);
> > > > > > +	dma_fence_signal(f2);
> > > > > > +	dma_fence_put(array);
> > > > > > +	return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static int unwrap_chain(void *arg)
> > > > > > +{
> > > > > > +	struct dma_fence *fence, *f1, *f2, *chain;
> > > > > > +	struct dma_fence_unwrap iter;
> > > > > > +	int err = 0;
> > > > > > +
> > > > > > +	f1 = mock_fence();
> > > > > > +	if (!f1)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	f2 = mock_fence();
> > > > > > +	if (!f2) {
> > > > > > +		dma_fence_put(f1);
> > > > > > +		return -ENOMEM;
> > > > > > +	}
> > > > > > +
> > > > > > +	chain = mock_chain(f1, f2);
> > > > > > +	if (!chain)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> > > > > > +		if (fence == f1) {
> > > > > > +			f1 = NULL;
> > > > > > +		} else if (fence == f2) {
> > > > > > +			f2 = NULL;
> > > > > > +		} else {
> > > > > > +			pr_err("Unexpected fence!\n");
> > > > > > +			err = -EINVAL;
> > > > > > +		}
> > > > > > +	}
> > > > > > +
> > > > > > +	if (f1 || f2) {
> > > > > > +		pr_err("Not all fences seen!\n");
> > > > > > +		err = -EINVAL;
> > > > > > +	}
> > > > > > +
> > > > > > +	dma_fence_signal(f1);
> > > > > > +	dma_fence_signal(f2);
> > > > > > +	dma_fence_put(chain);
> > > > > > +	return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static int unwrap_chain_array(void *arg)
> > > > > > +{
> > > > > > +	struct dma_fence *fence, *f1, *f2, *array, *chain;
> > > > > > +	struct dma_fence_unwrap iter;
> > > > > > +	int err = 0;
> > > > > > +
> > > > > > +	f1 = mock_fence();
> > > > > > +	if (!f1)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	f2 = mock_fence();
> > > > > > +	if (!f2) {
> > > > > > +		dma_fence_put(f1);
> > > > > > +		return -ENOMEM;
> > > > > > +	}
> > > > > > +
> > > > > > +	array = mock_array(2, f1, f2);
> > > > > > +	if (!array)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	chain = mock_chain(NULL, array);
> > > > > > +	if (!chain)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	dma_fence_unwrap_for_each(fence, &iter, chain) {
> > > > > > +		if (fence == f1) {
> > > > > > +			f1 = NULL;
> > > > > > +		} else if (fence == f2) {
> > > > > > +			f2 = NULL;
> > > > > > +		} else {
> > > > > > +			pr_err("Unexpected fence!\n");
> > > > > > +			err = -EINVAL;
> > > > > > +		}
> > > > > > +	}
> > > > > > +
> > > > > > +	if (f1 || f2) {
> > > > > > +		pr_err("Not all fences seen!\n");
> > > > > > +		err = -EINVAL;
> > > > > > +	}
> > > > > > +
> > > > > > +	dma_fence_signal(f1);
> > > > > > +	dma_fence_signal(f2);
> > > > > > +	dma_fence_put(chain);
> > > > > > +	return 0;
> > > > > > +}
> > > > > > +
> > > > > > +int dma_fence_unwrap(void)
> > > > > > +{
> > > > > > +	static const struct subtest tests[] = {
> > > > > > +		SUBTEST(sanitycheck),
> > > > > > +		SUBTEST(unwrap_array),
> > > > > > +		SUBTEST(unwrap_chain),
> > > > > > +		SUBTEST(unwrap_chain_array),
> > > > > > +	};
> > > > > > +	int ret;
> > > > > > +
> > > > > > +	slab_fences = KMEM_CACHE(mock_fence,
> > > > > > +				 SLAB_TYPESAFE_BY_RCU |
> > > > > > +				 SLAB_HWCACHE_ALIGN);
> > > > > > +	if (!slab_fences)
> > > > > > +		return -ENOMEM;
> > > > > > +
> > > > > > +	ret = subtests(tests, NULL);
> > > > > > +
> > > > > > +	kmem_cache_destroy(slab_fences);
> > > > > > +	return ret;
> > > > > > +}
> > > > > > diff --git a/include/linux/dma-fence-unwrap.h b/include/linux/dma-fence-unwrap.h
> > > > > > new file mode 100644
> > > > > > index 000000000000..54963df00c98
> > > > > > --- /dev/null
> > > > > > +++ b/include/linux/dma-fence-unwrap.h
> > > > > > @@ -0,0 +1,99 @@
> > > > > > +/* SPDX-License-Identifier: GPL-2.0-only */
> > > > > > +/*
> > > > > > + * fence-chain: chain fences together in a timeline
> > > > > > + *
> > > > > > + * Copyright (C) 2022 Advanced Micro Devices, Inc.
> > > > > > + * Authors:
> > > > > > + *	Christian König <christian.koenig@amd.com>
> > > > > > + */
> > > > > > +
> > > > > > +#ifndef __LINUX_DMA_FENCE_UNWRAP_H
> > > > > > +#define __LINUX_DMA_FENCE_UNWRAP_H
> > > > > > +
> > > > > > +#include <linux/dma-fence-chain.h>
> > > > > > +#include <linux/dma-fence-array.h>
> > > > > > +
> > > > > > +/**
> > > > > > + * struct dma_fence_unwrap - cursor into the container structure
> > > > > I think adding "This should be used together with
> > > > > dma_fence_unwrap_for_each() iterator macro." would be nice here. I just
> > > > > like links :-)
> > > > > 
> > > > > > + */
> > > > > > +struct dma_fence_unwrap {
> > > > > > +	/**
> > > > > > +	 * @chain: potential dma_fence_chain, but can be other fence as well
> > > > > > +	 */
> > > > > > +	struct dma_fence *chain;
> > > > > > +	/**
> > > > > > +	 * @array: potential dma_fence_array, but can be other fence as well
> > > > > > +	 */
> > > > > > +	struct dma_fence *array;
> > > > > > +	/**
> > > > > > +	 * @index: last returned index if @array is really a dma_fence_array
> > > > > > +	 */
> > > > > > +	unsigned int index;
> > > > > > +};
> > > > > > +
> > > > > > +/**
> > > > > > + * dma_fence_unwrap_array - helper to unwrap dma_fence_arrays
> > > > > > + * @cursor: cursor to initialize
> > > > > > + *
> > > > > > + * Helper function to unwrap dma_fence_array containers, don't touch directly.
> > > > > > + * Use dma_fence_unwrap_first/next instead.
> > > > > > + */
> > > > > > +static inline struct dma_fence *
> > > > > > +dma_fence_unwrap_array(struct dma_fence_unwrap * cursor)
> > > > > Since this is a helper that no one should call I'd give it a __ prefix and
> > > > > drop the kerneldoc. Documenting stuff that people shouldn't use is
> > > > > confusing :-)
> > > > > 
> > > > > > +{
> > > > > > +	cursor->array = dma_fence_chain_contained(cursor->chain);
> > > > > > +	cursor->index = 0;
> > > > > > +	return dma_fence_array_first(cursor->array);
> > > > > > +}
> > > > > > +
> > > > > > +/**
> > > > > > + * dma_fence_unwrap_first - return the first fence from fence containers
> > > > > > + * @head: the entrypoint into the containers
> > > > > > + * @cursor: current position inside the containers
> > > > > > + *
> > > > > > + * Unwraps potential dma_fence_chain/dma_fence_array containers and return the
> > > > > > + * first fence.
> > > > > > + */
> > > > > > +static inline struct dma_fence *
> > > > > > +dma_fence_unwrap_first(struct dma_fence *head, struct dma_fence_unwrap *cursor)
> > > > > > +{
> > > > > > +	cursor->chain = dma_fence_get(head);
> > > > > > +	return dma_fence_unwrap_array(cursor);
> > > > > > +}
> > > > > > +
> > > > > > +/**
> > > > > > + * dma_fence_unwrap_next - return the next fence from a fence containers
> > > > > > + * @cursor: current position inside the containers
> > > > > > + *
> > > > > > + * Continue unwrapping the dma_fence_chain/dma_fence_array containers and return
> > > > > > + * the next fence from them.
> > > > > > + */
> > > > > > +static inline struct dma_fence *
> > > > > > +dma_fence_unwrap_next(struct dma_fence_unwrap *cursor)
> > > > > > +{
> > > > > > +	struct dma_fence *tmp;
> > > > > > +
> > > > > > +	++cursor->index;
> > > > > > +	tmp = dma_fence_array_next(cursor->array, cursor->index);
> > > > > > +	if (tmp)
> > > > > > +		return tmp;
> > > > > > +
> > > > > > +	cursor->chain = dma_fence_chain_walk(cursor->chain);
> > > > > > +	return dma_fence_unwrap_array(cursor);
> > > > > > +}
> > > > > > +
> > > > > > +/**
> > > > > > + * dma_fence_unwrap_for_each - iterate over all fences in containers
> > > > > > + * @fence: current fence
> > > > > > + * @cursor: current position inside the containers
> > > > > > + * @head: starting point for the iterator
> > > > > > + *
> > > > > > + * Unwrap dma_fence_chain and dma_fence_array containers and deep dive into all
> > > > > > + * potential fences in them. If @head is just a normal fence only that one is
> > > > > > + * returned.
> > > > > > + */
> > > > > > +#define dma_fence_unwrap_for_each(fence, cursor, head)			\
> > > > > > +	for (fence = dma_fence_unwrap_first(head, cursor); fence;	\
> > > > > > +	     fence = dma_fence_unwrap_next(cursor))
> > > > > > +
> > > > > > +#endif
> > > > > I think it'd be really good to add a small paragraph to struct
> > > > > dma_fence_chain that this macro and iterator should be used for walking
> > > > > over all fences in a chain, including any fence arrays or anything like
> > > > > that.
> > > > > 
> > > > > With the bikesheds addressed:
> > > > > 
> > > > > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> > > > > 
> > > > > > -- 
> > > > > > 2.25.1
> > > > > > 
> > > > > -- 
> > > > > Daniel Vetter
> > > > > Software Engineer, Intel Corporation
> > > > > https://nam11.safelinks.protection.outlook.com/?url=http%3A%2F%2Fblog.ffwll.ch%2F&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7Caa747083900b451d359308da0e4745e3%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637837996532802687%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=Jts5%2BObWJHeUG4oy2biwj5Bf3PKkMrYU%2F0EihvQRNuY%3D&amp;reserved=0
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers
  2022-03-25 10:35       ` Christian König
@ 2022-03-25 19:28         ` Daniel Vetter
  -1 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-25 19:28 UTC (permalink / raw)
  To: Christian König
  Cc: gustavo, dri-devel, Christian König, linaro-mm-sig,
	sumit.semwal, linux-media

On Fri, Mar 25, 2022 at 11:35:49AM +0100, Christian König wrote:
> Am 25.03.22 um 11:13 schrieb Daniel Vetter:
> > On Fri, Mar 11, 2022 at 12:02:44PM +0100, Christian König wrote:
> > > The dma_fence_chain containers can show up in sync_files as well resulting in
> > > warnings that those can't be added to dma_fence_array containers when merging
> > > multiple sync_files together.
> > > 
> > > Solve this by using the dma_fence_unwrap iterator to deep dive into the
> > > contained fences and then add those flatten out into a dma_fence_array.
> > > 
> > > Signed-off-by: Christian König <christian.koenig@amd.com>
> > I have no idea why we try to keep fences sorted, but oh well it looks like
> > the merging is done correctly.
> 
> To be honest I don't fully know either.
> 
> Keeping the array sorted by context allows to merge it without adding
> duplicates, but adding duplicates is not an extra overhead to begin with
> because we always allocate memory for the worst case anyway.
> 
> Just keeping it around for now.

Hm I guess if we want to keep that we could make that an invariant of dma
fence arrays, i.e. sorted and deduplicated. Usually there should be few
enough fences that de-duping shouldn't be expensive really.

But no idea whether that's worth it.
-Daniel

> 
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> Thanks,
> Christian.
> 
> > 
> > > ---
> > >   drivers/dma-buf/sync_file.c | 141 +++++++++++++++++++-----------------
> > >   1 file changed, 73 insertions(+), 68 deletions(-)
> > > 
> > > diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
> > > index 394e6e1e9686..b8dea4ec123b 100644
> > > --- a/drivers/dma-buf/sync_file.c
> > > +++ b/drivers/dma-buf/sync_file.c
> > > @@ -5,6 +5,7 @@
> > >    * Copyright (C) 2012 Google, Inc.
> > >    */
> > > +#include <linux/dma-fence-unwrap.h>
> > >   #include <linux/export.h>
> > >   #include <linux/file.h>
> > >   #include <linux/fs.h>
> > > @@ -172,20 +173,6 @@ static int sync_file_set_fence(struct sync_file *sync_file,
> > >   	return 0;
> > >   }
> > > -static struct dma_fence **get_fences(struct sync_file *sync_file,
> > > -				     int *num_fences)
> > > -{
> > > -	if (dma_fence_is_array(sync_file->fence)) {
> > > -		struct dma_fence_array *array = to_dma_fence_array(sync_file->fence);
> > > -
> > > -		*num_fences = array->num_fences;
> > > -		return array->fences;
> > > -	}
> > > -
> > > -	*num_fences = 1;
> > > -	return &sync_file->fence;
> > > -}
> > > -
> > >   static void add_fence(struct dma_fence **fences,
> > >   		      int *i, struct dma_fence *fence)
> > >   {
> > > @@ -210,86 +197,97 @@ static void add_fence(struct dma_fence **fences,
> > >   static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
> > >   					 struct sync_file *b)
> > >   {
> > > +	struct dma_fence *a_fence, *b_fence, **fences;
> > > +	struct dma_fence_unwrap a_iter, b_iter;
> > > +	unsigned int index, num_fences;
> > >   	struct sync_file *sync_file;
> > > -	struct dma_fence **fences = NULL, **nfences, **a_fences, **b_fences;
> > > -	int i = 0, i_a, i_b, num_fences, a_num_fences, b_num_fences;
> > >   	sync_file = sync_file_alloc();
> > >   	if (!sync_file)
> > >   		return NULL;
> > > -	a_fences = get_fences(a, &a_num_fences);
> > > -	b_fences = get_fences(b, &b_num_fences);
> > > -	if (a_num_fences > INT_MAX - b_num_fences)
> > > -		goto err;
> > > +	num_fences = 0;
> > > +	dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence)
> > > +		++num_fences;
> > > +	dma_fence_unwrap_for_each(b_fence, &b_iter, b->fence)
> > > +		++num_fences;
> > > -	num_fences = a_num_fences + b_num_fences;
> > > +	if (num_fences > INT_MAX)
> > > +		goto err_free_sync_file;
> > >   	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
> > >   	if (!fences)
> > > -		goto err;
> > > +		goto err_free_sync_file;
> > >   	/*
> > > -	 * Assume sync_file a and b are both ordered and have no
> > > -	 * duplicates with the same context.
> > > +	 * We can't guarantee that fences in both a and b are ordered, but it is
> > > +	 * still quite likely.
> > >   	 *
> > > -	 * If a sync_file can only be created with sync_file_merge
> > > -	 * and sync_file_create, this is a reasonable assumption.
> > > +	 * So attempt to order the fences as we pass over them and merge fences
> > > +	 * with the same context.
> > >   	 */
> > > -	for (i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
> > > -		struct dma_fence *pt_a = a_fences[i_a];
> > > -		struct dma_fence *pt_b = b_fences[i_b];
> > > -		if (pt_a->context < pt_b->context) {
> > > -			add_fence(fences, &i, pt_a);
> > > +	index = 0;
> > > +	for (a_fence = dma_fence_unwrap_first(a->fence, &a_iter),
> > > +	     b_fence = dma_fence_unwrap_first(b->fence, &b_iter);
> > > +	     a_fence || b_fence; ) {
> > > +
> > > +		if (!b_fence) {
> > > +			add_fence(fences, &index, a_fence);
> > > +			a_fence = dma_fence_unwrap_next(&a_iter);
> > > +
> > > +		} else if (!a_fence) {
> > > +			add_fence(fences, &index, b_fence);
> > > +			b_fence = dma_fence_unwrap_next(&b_iter);
> > > +
> > > +		} else if (a_fence->context < b_fence->context) {
> > > +			add_fence(fences, &index, a_fence);
> > > +			a_fence = dma_fence_unwrap_next(&a_iter);
> > > -			i_a++;
> > > -		} else if (pt_a->context > pt_b->context) {
> > > -			add_fence(fences, &i, pt_b);
> > > +		} else if (b_fence->context < a_fence->context) {
> > > +			add_fence(fences, &index, b_fence);
> > > +			b_fence = dma_fence_unwrap_next(&b_iter);
> > > +
> > > +		} else if (__dma_fence_is_later(a_fence->seqno, b_fence->seqno,
> > > +						a_fence->ops)) {
> > > +			add_fence(fences, &index, a_fence);
> > > +			a_fence = dma_fence_unwrap_next(&a_iter);
> > > +			b_fence = dma_fence_unwrap_next(&b_iter);
> > > -			i_b++;
> > >   		} else {
> > > -			if (__dma_fence_is_later(pt_a->seqno, pt_b->seqno,
> > > -						 pt_a->ops))
> > > -				add_fence(fences, &i, pt_a);
> > > -			else
> > > -				add_fence(fences, &i, pt_b);
> > > -
> > > -			i_a++;
> > > -			i_b++;
> > > +			add_fence(fences, &index, b_fence);
> > > +			a_fence = dma_fence_unwrap_next(&a_iter);
> > > +			b_fence = dma_fence_unwrap_next(&b_iter);
> > >   		}
> > >   	}
> > > -	for (; i_a < a_num_fences; i_a++)
> > > -		add_fence(fences, &i, a_fences[i_a]);
> > > -
> > > -	for (; i_b < b_num_fences; i_b++)
> > > -		add_fence(fences, &i, b_fences[i_b]);
> > > -
> > > -	if (i == 0)
> > > -		fences[i++] = dma_fence_get(a_fences[0]);
> > > +	if (index == 0)
> > > +		add_fence(fences, &index, dma_fence_get_stub());
> > > -	if (num_fences > i) {
> > > -		nfences = krealloc_array(fences, i, sizeof(*fences), GFP_KERNEL);
> > > -		if (!nfences)
> > > -			goto err;
> > > +	if (num_fences > index) {
> > > +		struct dma_fence **tmp;
> > > -		fences = nfences;
> > > +		/* Keep going even when reducing the size failed */
> > > +		tmp = krealloc_array(fences, index, sizeof(*fences),
> > > +				     GFP_KERNEL);
> > > +		if (tmp)
> > > +			fences = tmp;
> > >   	}
> > > -	if (sync_file_set_fence(sync_file, fences, i) < 0)
> > > -		goto err;
> > > +	if (sync_file_set_fence(sync_file, fences, index) < 0)
> > > +		goto err_put_fences;
> > >   	strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
> > >   	return sync_file;
> > > -err:
> > > -	while (i)
> > > -		dma_fence_put(fences[--i]);
> > > +err_put_fences:
> > > +	while (index)
> > > +		dma_fence_put(fences[--index]);
> > >   	kfree(fences);
> > > +
> > > +err_free_sync_file:
> > >   	fput(sync_file->file);
> > >   	return NULL;
> > > -
> > >   }
> > >   static int sync_file_release(struct inode *inode, struct file *file)
> > > @@ -398,11 +396,13 @@ static int sync_fill_fence_info(struct dma_fence *fence,
> > >   static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
> > >   				       unsigned long arg)
> > >   {
> > > -	struct sync_file_info info;
> > >   	struct sync_fence_info *fence_info = NULL;
> > > -	struct dma_fence **fences;
> > > +	struct dma_fence_unwrap iter;
> > > +	struct sync_file_info info;
> > > +	unsigned int num_fences;
> > > +	struct dma_fence *fence;
> > > +	int ret;
> > >   	__u32 size;
> > > -	int num_fences, ret, i;
> > >   	if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
> > >   		return -EFAULT;
> > > @@ -410,7 +410,9 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
> > >   	if (info.flags || info.pad)
> > >   		return -EINVAL;
> > > -	fences = get_fences(sync_file, &num_fences);
> > > +	num_fences = 0;
> > > +	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence)
> > > +		++num_fences;
> > >   	/*
> > >   	 * Passing num_fences = 0 means that userspace doesn't want to
> > > @@ -433,8 +435,11 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
> > >   	if (!fence_info)
> > >   		return -ENOMEM;
> > > -	for (i = 0; i < num_fences; i++) {
> > > -		int status = sync_fill_fence_info(fences[i], &fence_info[i]);
> > > +	num_fences = 0;
> > > +	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) {
> > > +		int status;
> > > +
> > > +		status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
> > >   		info.status = info.status <= 0 ? info.status : status;
> > >   	}
> > > -- 
> > > 2.25.1
> > > 
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers
@ 2022-03-25 19:28         ` Daniel Vetter
  0 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-25 19:28 UTC (permalink / raw)
  To: Christian König
  Cc: Daniel Vetter, sumit.semwal, gustavo, linux-media, dri-devel,
	linaro-mm-sig, Christian König

On Fri, Mar 25, 2022 at 11:35:49AM +0100, Christian König wrote:
> Am 25.03.22 um 11:13 schrieb Daniel Vetter:
> > On Fri, Mar 11, 2022 at 12:02:44PM +0100, Christian König wrote:
> > > The dma_fence_chain containers can show up in sync_files as well resulting in
> > > warnings that those can't be added to dma_fence_array containers when merging
> > > multiple sync_files together.
> > > 
> > > Solve this by using the dma_fence_unwrap iterator to deep dive into the
> > > contained fences and then add those flatten out into a dma_fence_array.
> > > 
> > > Signed-off-by: Christian König <christian.koenig@amd.com>
> > I have no idea why we try to keep fences sorted, but oh well it looks like
> > the merging is done correctly.
> 
> To be honest I don't fully know either.
> 
> Keeping the array sorted by context allows to merge it without adding
> duplicates, but adding duplicates is not an extra overhead to begin with
> because we always allocate memory for the worst case anyway.
> 
> Just keeping it around for now.

Hm I guess if we want to keep that we could make that an invariant of dma
fence arrays, i.e. sorted and deduplicated. Usually there should be few
enough fences that de-duping shouldn't be expensive really.

But no idea whether that's worth it.
-Daniel

> 
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> 
> Thanks,
> Christian.
> 
> > 
> > > ---
> > >   drivers/dma-buf/sync_file.c | 141 +++++++++++++++++++-----------------
> > >   1 file changed, 73 insertions(+), 68 deletions(-)
> > > 
> > > diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c
> > > index 394e6e1e9686..b8dea4ec123b 100644
> > > --- a/drivers/dma-buf/sync_file.c
> > > +++ b/drivers/dma-buf/sync_file.c
> > > @@ -5,6 +5,7 @@
> > >    * Copyright (C) 2012 Google, Inc.
> > >    */
> > > +#include <linux/dma-fence-unwrap.h>
> > >   #include <linux/export.h>
> > >   #include <linux/file.h>
> > >   #include <linux/fs.h>
> > > @@ -172,20 +173,6 @@ static int sync_file_set_fence(struct sync_file *sync_file,
> > >   	return 0;
> > >   }
> > > -static struct dma_fence **get_fences(struct sync_file *sync_file,
> > > -				     int *num_fences)
> > > -{
> > > -	if (dma_fence_is_array(sync_file->fence)) {
> > > -		struct dma_fence_array *array = to_dma_fence_array(sync_file->fence);
> > > -
> > > -		*num_fences = array->num_fences;
> > > -		return array->fences;
> > > -	}
> > > -
> > > -	*num_fences = 1;
> > > -	return &sync_file->fence;
> > > -}
> > > -
> > >   static void add_fence(struct dma_fence **fences,
> > >   		      int *i, struct dma_fence *fence)
> > >   {
> > > @@ -210,86 +197,97 @@ static void add_fence(struct dma_fence **fences,
> > >   static struct sync_file *sync_file_merge(const char *name, struct sync_file *a,
> > >   					 struct sync_file *b)
> > >   {
> > > +	struct dma_fence *a_fence, *b_fence, **fences;
> > > +	struct dma_fence_unwrap a_iter, b_iter;
> > > +	unsigned int index, num_fences;
> > >   	struct sync_file *sync_file;
> > > -	struct dma_fence **fences = NULL, **nfences, **a_fences, **b_fences;
> > > -	int i = 0, i_a, i_b, num_fences, a_num_fences, b_num_fences;
> > >   	sync_file = sync_file_alloc();
> > >   	if (!sync_file)
> > >   		return NULL;
> > > -	a_fences = get_fences(a, &a_num_fences);
> > > -	b_fences = get_fences(b, &b_num_fences);
> > > -	if (a_num_fences > INT_MAX - b_num_fences)
> > > -		goto err;
> > > +	num_fences = 0;
> > > +	dma_fence_unwrap_for_each(a_fence, &a_iter, a->fence)
> > > +		++num_fences;
> > > +	dma_fence_unwrap_for_each(b_fence, &b_iter, b->fence)
> > > +		++num_fences;
> > > -	num_fences = a_num_fences + b_num_fences;
> > > +	if (num_fences > INT_MAX)
> > > +		goto err_free_sync_file;
> > >   	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
> > >   	if (!fences)
> > > -		goto err;
> > > +		goto err_free_sync_file;
> > >   	/*
> > > -	 * Assume sync_file a and b are both ordered and have no
> > > -	 * duplicates with the same context.
> > > +	 * We can't guarantee that fences in both a and b are ordered, but it is
> > > +	 * still quite likely.
> > >   	 *
> > > -	 * If a sync_file can only be created with sync_file_merge
> > > -	 * and sync_file_create, this is a reasonable assumption.
> > > +	 * So attempt to order the fences as we pass over them and merge fences
> > > +	 * with the same context.
> > >   	 */
> > > -	for (i_a = i_b = 0; i_a < a_num_fences && i_b < b_num_fences; ) {
> > > -		struct dma_fence *pt_a = a_fences[i_a];
> > > -		struct dma_fence *pt_b = b_fences[i_b];
> > > -		if (pt_a->context < pt_b->context) {
> > > -			add_fence(fences, &i, pt_a);
> > > +	index = 0;
> > > +	for (a_fence = dma_fence_unwrap_first(a->fence, &a_iter),
> > > +	     b_fence = dma_fence_unwrap_first(b->fence, &b_iter);
> > > +	     a_fence || b_fence; ) {
> > > +
> > > +		if (!b_fence) {
> > > +			add_fence(fences, &index, a_fence);
> > > +			a_fence = dma_fence_unwrap_next(&a_iter);
> > > +
> > > +		} else if (!a_fence) {
> > > +			add_fence(fences, &index, b_fence);
> > > +			b_fence = dma_fence_unwrap_next(&b_iter);
> > > +
> > > +		} else if (a_fence->context < b_fence->context) {
> > > +			add_fence(fences, &index, a_fence);
> > > +			a_fence = dma_fence_unwrap_next(&a_iter);
> > > -			i_a++;
> > > -		} else if (pt_a->context > pt_b->context) {
> > > -			add_fence(fences, &i, pt_b);
> > > +		} else if (b_fence->context < a_fence->context) {
> > > +			add_fence(fences, &index, b_fence);
> > > +			b_fence = dma_fence_unwrap_next(&b_iter);
> > > +
> > > +		} else if (__dma_fence_is_later(a_fence->seqno, b_fence->seqno,
> > > +						a_fence->ops)) {
> > > +			add_fence(fences, &index, a_fence);
> > > +			a_fence = dma_fence_unwrap_next(&a_iter);
> > > +			b_fence = dma_fence_unwrap_next(&b_iter);
> > > -			i_b++;
> > >   		} else {
> > > -			if (__dma_fence_is_later(pt_a->seqno, pt_b->seqno,
> > > -						 pt_a->ops))
> > > -				add_fence(fences, &i, pt_a);
> > > -			else
> > > -				add_fence(fences, &i, pt_b);
> > > -
> > > -			i_a++;
> > > -			i_b++;
> > > +			add_fence(fences, &index, b_fence);
> > > +			a_fence = dma_fence_unwrap_next(&a_iter);
> > > +			b_fence = dma_fence_unwrap_next(&b_iter);
> > >   		}
> > >   	}
> > > -	for (; i_a < a_num_fences; i_a++)
> > > -		add_fence(fences, &i, a_fences[i_a]);
> > > -
> > > -	for (; i_b < b_num_fences; i_b++)
> > > -		add_fence(fences, &i, b_fences[i_b]);
> > > -
> > > -	if (i == 0)
> > > -		fences[i++] = dma_fence_get(a_fences[0]);
> > > +	if (index == 0)
> > > +		add_fence(fences, &index, dma_fence_get_stub());
> > > -	if (num_fences > i) {
> > > -		nfences = krealloc_array(fences, i, sizeof(*fences), GFP_KERNEL);
> > > -		if (!nfences)
> > > -			goto err;
> > > +	if (num_fences > index) {
> > > +		struct dma_fence **tmp;
> > > -		fences = nfences;
> > > +		/* Keep going even when reducing the size failed */
> > > +		tmp = krealloc_array(fences, index, sizeof(*fences),
> > > +				     GFP_KERNEL);
> > > +		if (tmp)
> > > +			fences = tmp;
> > >   	}
> > > -	if (sync_file_set_fence(sync_file, fences, i) < 0)
> > > -		goto err;
> > > +	if (sync_file_set_fence(sync_file, fences, index) < 0)
> > > +		goto err_put_fences;
> > >   	strlcpy(sync_file->user_name, name, sizeof(sync_file->user_name));
> > >   	return sync_file;
> > > -err:
> > > -	while (i)
> > > -		dma_fence_put(fences[--i]);
> > > +err_put_fences:
> > > +	while (index)
> > > +		dma_fence_put(fences[--index]);
> > >   	kfree(fences);
> > > +
> > > +err_free_sync_file:
> > >   	fput(sync_file->file);
> > >   	return NULL;
> > > -
> > >   }
> > >   static int sync_file_release(struct inode *inode, struct file *file)
> > > @@ -398,11 +396,13 @@ static int sync_fill_fence_info(struct dma_fence *fence,
> > >   static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
> > >   				       unsigned long arg)
> > >   {
> > > -	struct sync_file_info info;
> > >   	struct sync_fence_info *fence_info = NULL;
> > > -	struct dma_fence **fences;
> > > +	struct dma_fence_unwrap iter;
> > > +	struct sync_file_info info;
> > > +	unsigned int num_fences;
> > > +	struct dma_fence *fence;
> > > +	int ret;
> > >   	__u32 size;
> > > -	int num_fences, ret, i;
> > >   	if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
> > >   		return -EFAULT;
> > > @@ -410,7 +410,9 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
> > >   	if (info.flags || info.pad)
> > >   		return -EINVAL;
> > > -	fences = get_fences(sync_file, &num_fences);
> > > +	num_fences = 0;
> > > +	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence)
> > > +		++num_fences;
> > >   	/*
> > >   	 * Passing num_fences = 0 means that userspace doesn't want to
> > > @@ -433,8 +435,11 @@ static long sync_file_ioctl_fence_info(struct sync_file *sync_file,
> > >   	if (!fence_info)
> > >   		return -ENOMEM;
> > > -	for (i = 0; i < num_fences; i++) {
> > > -		int status = sync_fill_fence_info(fences[i], &fence_info[i]);
> > > +	num_fences = 0;
> > > +	dma_fence_unwrap_for_each(fence, &iter, sync_file->fence) {
> > > +		int status;
> > > +
> > > +		status = sync_fill_fence_info(fence, &fence_info[num_fences++]);
> > >   		info.status = info.status <= 0 ? info.status : status;
> > >   	}
> > > -- 
> > > 2.25.1
> > > 
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-25 15:28     ` Christian König
@ 2022-03-28 10:28       ` Christian König
  -1 siblings, 0 replies; 40+ messages in thread
From: Christian König @ 2022-03-28 10:28 UTC (permalink / raw)
  To: Christian König, Ville Syrjälä, Daniel Vetter
  Cc: sumit.semwal, gustavo, linux-media, dri-devel, linaro-mm-sig,
	Dave Airlie

Hi Ville & Daniel,

Am 25.03.22 um 16:28 schrieb Christian König:
> Am 25.03.22 um 16:25 schrieb Ville Syrjälä:
>> On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
>>> Add a general purpose helper to deep dive into 
>>> dma_fence_chain/dma_fence_array
>>> structures and iterate over all the fences in them.
>>>
>>> This is useful when we need to flatten out all fences in those 
>>> structures.
>>>
>>> Signed-off-by: Christian König <christian.koenig@amd.com>
>> One of the dma-buf patches took down Intel CI. Looks like every
>> machine oopses in some sync_file thing now:
>> <1>[  260.470008] BUG: kernel NULL pointer dereference, address: 
>> 0000000000000010
>> <1>[  260.470020] #PF: supervisor read access in kernel mode
>> <1>[  260.470025] #PF: error_code(0x0000) - not-present page
>> <6>[  260.470030] PGD 0 P4D 0
>> <4>[  260.470035] Oops: 0000 [#1] PREEMPT SMP NOPTI
>> <4>[  260.470040] CPU: 0 PID: 5306 Comm: core_hotunplug Not tainted 
>> 5.17.0-CI-CI_DRM_11405+ #1
>> <4>[  260.470049] Hardware name: Intel Corporation Jasper Lake Client 
>> Platform/Jasperlake DDR4 SODIMM RVP, BIOS 
>> JSLSFWI1.R00.2385.D02.2010160831 10/16/2020
>> <4>[  260.470058] RIP: 0010:dma_fence_array_first+0x19/0x20

I've looked into this and the root cause seems to be that the new code 
doesn't handle dma_fence_arrays with zero elements.

That is rather easy to fix, but a dma_fence_array with zero number of 
elements is most likely a bug because under the wrong circumstances it 
can create a dma_fence instance which will never signal.

I've send out a patch on Frinday ([PATCH] dma-buf: WIP 
dma_fence_array_first fix) which avoids the crash and prints a warning 
if anybody tries to create a dma_fence_array with zero length.

Can you test this?

Thanks in advance,
Christian.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
@ 2022-03-28 10:28       ` Christian König
  0 siblings, 0 replies; 40+ messages in thread
From: Christian König @ 2022-03-28 10:28 UTC (permalink / raw)
  To: Christian König, Ville Syrjälä, Daniel Vetter
  Cc: gustavo, dri-devel, linaro-mm-sig, sumit.semwal, linux-media

Hi Ville & Daniel,

Am 25.03.22 um 16:28 schrieb Christian König:
> Am 25.03.22 um 16:25 schrieb Ville Syrjälä:
>> On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
>>> Add a general purpose helper to deep dive into 
>>> dma_fence_chain/dma_fence_array
>>> structures and iterate over all the fences in them.
>>>
>>> This is useful when we need to flatten out all fences in those 
>>> structures.
>>>
>>> Signed-off-by: Christian König <christian.koenig@amd.com>
>> One of the dma-buf patches took down Intel CI. Looks like every
>> machine oopses in some sync_file thing now:
>> <1>[  260.470008] BUG: kernel NULL pointer dereference, address: 
>> 0000000000000010
>> <1>[  260.470020] #PF: supervisor read access in kernel mode
>> <1>[  260.470025] #PF: error_code(0x0000) - not-present page
>> <6>[  260.470030] PGD 0 P4D 0
>> <4>[  260.470035] Oops: 0000 [#1] PREEMPT SMP NOPTI
>> <4>[  260.470040] CPU: 0 PID: 5306 Comm: core_hotunplug Not tainted 
>> 5.17.0-CI-CI_DRM_11405+ #1
>> <4>[  260.470049] Hardware name: Intel Corporation Jasper Lake Client 
>> Platform/Jasperlake DDR4 SODIMM RVP, BIOS 
>> JSLSFWI1.R00.2385.D02.2010160831 10/16/2020
>> <4>[  260.470058] RIP: 0010:dma_fence_array_first+0x19/0x20

I've looked into this and the root cause seems to be that the new code 
doesn't handle dma_fence_arrays with zero elements.

That is rather easy to fix, but a dma_fence_array with zero number of 
elements is most likely a bug because under the wrong circumstances it 
can create a dma_fence instance which will never signal.

I've send out a patch on Frinday ([PATCH] dma-buf: WIP 
dma_fence_array_first fix) which avoids the crash and prints a warning 
if anybody tries to create a dma_fence_array with zero length.

Can you test this?

Thanks in advance,
Christian.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-28 10:28       ` Christian König
@ 2022-03-28 14:22         ` Daniel Vetter
  -1 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-28 14:22 UTC (permalink / raw)
  To: Christian König
  Cc: Christian König, Ville Syrjälä,
	Daniel Vetter, sumit.semwal, gustavo, linux-media, dri-devel,
	linaro-mm-sig, Dave Airlie

On Mon, Mar 28, 2022 at 12:28:31PM +0200, Christian König wrote:
> Hi Ville & Daniel,
> 
> Am 25.03.22 um 16:28 schrieb Christian König:
> > Am 25.03.22 um 16:25 schrieb Ville Syrjälä:
> > > On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> > > > Add a general purpose helper to deep dive into
> > > > dma_fence_chain/dma_fence_array
> > > > structures and iterate over all the fences in them.
> > > > 
> > > > This is useful when we need to flatten out all fences in those
> > > > structures.
> > > > 
> > > > Signed-off-by: Christian König <christian.koenig@amd.com>
> > > One of the dma-buf patches took down Intel CI. Looks like every
> > > machine oopses in some sync_file thing now:
> > > <1>[  260.470008] BUG: kernel NULL pointer dereference, address:
> > > 0000000000000010
> > > <1>[  260.470020] #PF: supervisor read access in kernel mode
> > > <1>[  260.470025] #PF: error_code(0x0000) - not-present page
> > > <6>[  260.470030] PGD 0 P4D 0
> > > <4>[  260.470035] Oops: 0000 [#1] PREEMPT SMP NOPTI
> > > <4>[  260.470040] CPU: 0 PID: 5306 Comm: core_hotunplug Not tainted
> > > 5.17.0-CI-CI_DRM_11405+ #1
> > > <4>[  260.470049] Hardware name: Intel Corporation Jasper Lake
> > > Client Platform/Jasperlake DDR4 SODIMM RVP, BIOS
> > > JSLSFWI1.R00.2385.D02.2010160831 10/16/2020
> > > <4>[  260.470058] RIP: 0010:dma_fence_array_first+0x19/0x20
> 
> I've looked into this and the root cause seems to be that the new code
> doesn't handle dma_fence_arrays with zero elements.
> 
> That is rather easy to fix, but a dma_fence_array with zero number of
> elements is most likely a bug because under the wrong circumstances it can
> create a dma_fence instance which will never signal.
> 
> I've send out a patch on Frinday ([PATCH] dma-buf: WIP dma_fence_array_first
> fix) which avoids the crash and prints a warning if anybody tries to create
> a dma_fence_array with zero length.
> 
> Can you test this?

It's in drm-tip now (in the fixup branch) so drm-tip results should have
the result soonish:

https://intel-gfx-ci.01.org/tree/drm-tip/index.html?

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
@ 2022-03-28 14:22         ` Daniel Vetter
  0 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-28 14:22 UTC (permalink / raw)
  To: Christian König
  Cc: gustavo, dri-devel, sumit.semwal, linaro-mm-sig, Daniel Vetter,
	Christian König, linux-media

On Mon, Mar 28, 2022 at 12:28:31PM +0200, Christian König wrote:
> Hi Ville & Daniel,
> 
> Am 25.03.22 um 16:28 schrieb Christian König:
> > Am 25.03.22 um 16:25 schrieb Ville Syrjälä:
> > > On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> > > > Add a general purpose helper to deep dive into
> > > > dma_fence_chain/dma_fence_array
> > > > structures and iterate over all the fences in them.
> > > > 
> > > > This is useful when we need to flatten out all fences in those
> > > > structures.
> > > > 
> > > > Signed-off-by: Christian König <christian.koenig@amd.com>
> > > One of the dma-buf patches took down Intel CI. Looks like every
> > > machine oopses in some sync_file thing now:
> > > <1>[  260.470008] BUG: kernel NULL pointer dereference, address:
> > > 0000000000000010
> > > <1>[  260.470020] #PF: supervisor read access in kernel mode
> > > <1>[  260.470025] #PF: error_code(0x0000) - not-present page
> > > <6>[  260.470030] PGD 0 P4D 0
> > > <4>[  260.470035] Oops: 0000 [#1] PREEMPT SMP NOPTI
> > > <4>[  260.470040] CPU: 0 PID: 5306 Comm: core_hotunplug Not tainted
> > > 5.17.0-CI-CI_DRM_11405+ #1
> > > <4>[  260.470049] Hardware name: Intel Corporation Jasper Lake
> > > Client Platform/Jasperlake DDR4 SODIMM RVP, BIOS
> > > JSLSFWI1.R00.2385.D02.2010160831 10/16/2020
> > > <4>[  260.470058] RIP: 0010:dma_fence_array_first+0x19/0x20
> 
> I've looked into this and the root cause seems to be that the new code
> doesn't handle dma_fence_arrays with zero elements.
> 
> That is rather easy to fix, but a dma_fence_array with zero number of
> elements is most likely a bug because under the wrong circumstances it can
> create a dma_fence instance which will never signal.
> 
> I've send out a patch on Frinday ([PATCH] dma-buf: WIP dma_fence_array_first
> fix) which avoids the crash and prints a warning if anybody tries to create
> a dma_fence_array with zero length.
> 
> Can you test this?

It's in drm-tip now (in the fixup branch) so drm-tip results should have
the result soonish:

https://intel-gfx-ci.01.org/tree/drm-tip/index.html?

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-28 14:22         ` Daniel Vetter
@ 2022-03-28 14:26           ` Christian König
  -1 siblings, 0 replies; 40+ messages in thread
From: Christian König @ 2022-03-28 14:26 UTC (permalink / raw)
  To: Daniel Vetter, Christian König
  Cc: Daniel Vetter, dri-devel, linaro-mm-sig, gustavo, sumit.semwal,
	linux-media

Am 28.03.22 um 16:22 schrieb Daniel Vetter:
> On Mon, Mar 28, 2022 at 12:28:31PM +0200, Christian König wrote:
>> Hi Ville & Daniel,
>>
>> Am 25.03.22 um 16:28 schrieb Christian König:
>>> Am 25.03.22 um 16:25 schrieb Ville Syrjälä:
>>>> On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
>>>>> Add a general purpose helper to deep dive into
>>>>> dma_fence_chain/dma_fence_array
>>>>> structures and iterate over all the fences in them.
>>>>>
>>>>> This is useful when we need to flatten out all fences in those
>>>>> structures.
>>>>>
>>>>> Signed-off-by: Christian König <christian.koenig@amd.com>
>>>> One of the dma-buf patches took down Intel CI. Looks like every
>>>> machine oopses in some sync_file thing now:
>>>> <1>[  260.470008] BUG: kernel NULL pointer dereference, address:
>>>> 0000000000000010
>>>> <1>[  260.470020] #PF: supervisor read access in kernel mode
>>>> <1>[  260.470025] #PF: error_code(0x0000) - not-present page
>>>> <6>[  260.470030] PGD 0 P4D 0
>>>> <4>[  260.470035] Oops: 0000 [#1] PREEMPT SMP NOPTI
>>>> <4>[  260.470040] CPU: 0 PID: 5306 Comm: core_hotunplug Not tainted
>>>> 5.17.0-CI-CI_DRM_11405+ #1
>>>> <4>[  260.470049] Hardware name: Intel Corporation Jasper Lake
>>>> Client Platform/Jasperlake DDR4 SODIMM RVP, BIOS
>>>> JSLSFWI1.R00.2385.D02.2010160831 10/16/2020
>>>> <4>[  260.470058] RIP: 0010:dma_fence_array_first+0x19/0x20
>> I've looked into this and the root cause seems to be that the new code
>> doesn't handle dma_fence_arrays with zero elements.
>>
>> That is rather easy to fix, but a dma_fence_array with zero number of
>> elements is most likely a bug because under the wrong circumstances it can
>> create a dma_fence instance which will never signal.
>>
>> I've send out a patch on Frinday ([PATCH] dma-buf: WIP dma_fence_array_first
>> fix) which avoids the crash and prints a warning if anybody tries to create
>> a dma_fence_array with zero length.
>>
>> Can you test this?
> It's in drm-tip now (in the fixup branch) so drm-tip results should have
> the result soonish:
>
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fintel-gfx-ci.01.org%2Ftree%2Fdrm-tip%2Findex.html&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7C0afc74b5df0c4ea384af08da10c672fa%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637840742273792356%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=SL2CuMgM6lCSOhDTvs%2FaFg6zRlc7F3X%2BNkf6GuGMGXI%3D&amp;reserved=0?

How do I find something in there? Is there a search function over all 
the test results?

Thanks,
Christian.

>
> Cheers, Daniel


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
@ 2022-03-28 14:26           ` Christian König
  0 siblings, 0 replies; 40+ messages in thread
From: Christian König @ 2022-03-28 14:26 UTC (permalink / raw)
  To: Daniel Vetter, Christian König
  Cc: Ville Syrjälä,
	Daniel Vetter, sumit.semwal, gustavo, linux-media, dri-devel,
	linaro-mm-sig, Dave Airlie

Am 28.03.22 um 16:22 schrieb Daniel Vetter:
> On Mon, Mar 28, 2022 at 12:28:31PM +0200, Christian König wrote:
>> Hi Ville & Daniel,
>>
>> Am 25.03.22 um 16:28 schrieb Christian König:
>>> Am 25.03.22 um 16:25 schrieb Ville Syrjälä:
>>>> On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
>>>>> Add a general purpose helper to deep dive into
>>>>> dma_fence_chain/dma_fence_array
>>>>> structures and iterate over all the fences in them.
>>>>>
>>>>> This is useful when we need to flatten out all fences in those
>>>>> structures.
>>>>>
>>>>> Signed-off-by: Christian König <christian.koenig@amd.com>
>>>> One of the dma-buf patches took down Intel CI. Looks like every
>>>> machine oopses in some sync_file thing now:
>>>> <1>[  260.470008] BUG: kernel NULL pointer dereference, address:
>>>> 0000000000000010
>>>> <1>[  260.470020] #PF: supervisor read access in kernel mode
>>>> <1>[  260.470025] #PF: error_code(0x0000) - not-present page
>>>> <6>[  260.470030] PGD 0 P4D 0
>>>> <4>[  260.470035] Oops: 0000 [#1] PREEMPT SMP NOPTI
>>>> <4>[  260.470040] CPU: 0 PID: 5306 Comm: core_hotunplug Not tainted
>>>> 5.17.0-CI-CI_DRM_11405+ #1
>>>> <4>[  260.470049] Hardware name: Intel Corporation Jasper Lake
>>>> Client Platform/Jasperlake DDR4 SODIMM RVP, BIOS
>>>> JSLSFWI1.R00.2385.D02.2010160831 10/16/2020
>>>> <4>[  260.470058] RIP: 0010:dma_fence_array_first+0x19/0x20
>> I've looked into this and the root cause seems to be that the new code
>> doesn't handle dma_fence_arrays with zero elements.
>>
>> That is rather easy to fix, but a dma_fence_array with zero number of
>> elements is most likely a bug because under the wrong circumstances it can
>> create a dma_fence instance which will never signal.
>>
>> I've send out a patch on Frinday ([PATCH] dma-buf: WIP dma_fence_array_first
>> fix) which avoids the crash and prints a warning if anybody tries to create
>> a dma_fence_array with zero length.
>>
>> Can you test this?
> It's in drm-tip now (in the fixup branch) so drm-tip results should have
> the result soonish:
>
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fintel-gfx-ci.01.org%2Ftree%2Fdrm-tip%2Findex.html&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7C0afc74b5df0c4ea384af08da10c672fa%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637840742273792356%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=SL2CuMgM6lCSOhDTvs%2FaFg6zRlc7F3X%2BNkf6GuGMGXI%3D&amp;reserved=0?

How do I find something in there? Is there a search function over all 
the test results?

Thanks,
Christian.

>
> Cheers, Daniel


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
  2022-03-28 14:26           ` Christian König
@ 2022-03-28 14:28             ` Daniel Vetter
  -1 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-28 14:28 UTC (permalink / raw)
  To: Christian König
  Cc: Daniel Vetter, Christian König, Ville Syrjälä,
	Daniel Vetter, sumit.semwal, gustavo, linux-media, dri-devel,
	linaro-mm-sig, Dave Airlie

On Mon, Mar 28, 2022 at 04:26:44PM +0200, Christian König wrote:
> Am 28.03.22 um 16:22 schrieb Daniel Vetter:
> > On Mon, Mar 28, 2022 at 12:28:31PM +0200, Christian König wrote:
> > > Hi Ville & Daniel,
> > > 
> > > Am 25.03.22 um 16:28 schrieb Christian König:
> > > > Am 25.03.22 um 16:25 schrieb Ville Syrjälä:
> > > > > On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> > > > > > Add a general purpose helper to deep dive into
> > > > > > dma_fence_chain/dma_fence_array
> > > > > > structures and iterate over all the fences in them.
> > > > > > 
> > > > > > This is useful when we need to flatten out all fences in those
> > > > > > structures.
> > > > > > 
> > > > > > Signed-off-by: Christian König <christian.koenig@amd.com>
> > > > > One of the dma-buf patches took down Intel CI. Looks like every
> > > > > machine oopses in some sync_file thing now:
> > > > > <1>[  260.470008] BUG: kernel NULL pointer dereference, address:
> > > > > 0000000000000010
> > > > > <1>[  260.470020] #PF: supervisor read access in kernel mode
> > > > > <1>[  260.470025] #PF: error_code(0x0000) - not-present page
> > > > > <6>[  260.470030] PGD 0 P4D 0
> > > > > <4>[  260.470035] Oops: 0000 [#1] PREEMPT SMP NOPTI
> > > > > <4>[  260.470040] CPU: 0 PID: 5306 Comm: core_hotunplug Not tainted
> > > > > 5.17.0-CI-CI_DRM_11405+ #1
> > > > > <4>[  260.470049] Hardware name: Intel Corporation Jasper Lake
> > > > > Client Platform/Jasperlake DDR4 SODIMM RVP, BIOS
> > > > > JSLSFWI1.R00.2385.D02.2010160831 10/16/2020
> > > > > <4>[  260.470058] RIP: 0010:dma_fence_array_first+0x19/0x20
> > > I've looked into this and the root cause seems to be that the new code
> > > doesn't handle dma_fence_arrays with zero elements.
> > > 
> > > That is rather easy to fix, but a dma_fence_array with zero number of
> > > elements is most likely a bug because under the wrong circumstances it can
> > > create a dma_fence instance which will never signal.
> > > 
> > > I've send out a patch on Frinday ([PATCH] dma-buf: WIP dma_fence_array_first
> > > fix) which avoids the crash and prints a warning if anybody tries to create
> > > a dma_fence_array with zero length.
> > > 
> > > Can you test this?
> > It's in drm-tip now (in the fixup branch) so drm-tip results should have
> > the result soonish:
> > 
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fintel-gfx-ci.01.org%2Ftree%2Fdrm-tip%2Findex.html&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7C0afc74b5df0c4ea384af08da10c672fa%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637840742273792356%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=SL2CuMgM6lCSOhDTvs%2FaFg6zRlc7F3X%2BNkf6GuGMGXI%3D&amp;reserved=0?
> 
> How do I find something in there? Is there a search function over all the
> test results?

Not really. You can ask on #intel-gfx-ci, or look at the tests that have
blown up without this to know where to look.

You can also download all the logfiles with wget recursive or so from the
build directory (the links in the top row) and search locally.
-Daniel

> 
> Thanks,
> Christian.
> 
> > 
> > Cheers, Daniel
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 1/2] dma-buf: add dma_fence_unwrap
@ 2022-03-28 14:28             ` Daniel Vetter
  0 siblings, 0 replies; 40+ messages in thread
From: Daniel Vetter @ 2022-03-28 14:28 UTC (permalink / raw)
  To: Christian König
  Cc: linaro-mm-sig, gustavo, dri-devel, Daniel Vetter,
	Christian König, sumit.semwal, linux-media

On Mon, Mar 28, 2022 at 04:26:44PM +0200, Christian König wrote:
> Am 28.03.22 um 16:22 schrieb Daniel Vetter:
> > On Mon, Mar 28, 2022 at 12:28:31PM +0200, Christian König wrote:
> > > Hi Ville & Daniel,
> > > 
> > > Am 25.03.22 um 16:28 schrieb Christian König:
> > > > Am 25.03.22 um 16:25 schrieb Ville Syrjälä:
> > > > > On Fri, Mar 11, 2022 at 12:02:43PM +0100, Christian König wrote:
> > > > > > Add a general purpose helper to deep dive into
> > > > > > dma_fence_chain/dma_fence_array
> > > > > > structures and iterate over all the fences in them.
> > > > > > 
> > > > > > This is useful when we need to flatten out all fences in those
> > > > > > structures.
> > > > > > 
> > > > > > Signed-off-by: Christian König <christian.koenig@amd.com>
> > > > > One of the dma-buf patches took down Intel CI. Looks like every
> > > > > machine oopses in some sync_file thing now:
> > > > > <1>[  260.470008] BUG: kernel NULL pointer dereference, address:
> > > > > 0000000000000010
> > > > > <1>[  260.470020] #PF: supervisor read access in kernel mode
> > > > > <1>[  260.470025] #PF: error_code(0x0000) - not-present page
> > > > > <6>[  260.470030] PGD 0 P4D 0
> > > > > <4>[  260.470035] Oops: 0000 [#1] PREEMPT SMP NOPTI
> > > > > <4>[  260.470040] CPU: 0 PID: 5306 Comm: core_hotunplug Not tainted
> > > > > 5.17.0-CI-CI_DRM_11405+ #1
> > > > > <4>[  260.470049] Hardware name: Intel Corporation Jasper Lake
> > > > > Client Platform/Jasperlake DDR4 SODIMM RVP, BIOS
> > > > > JSLSFWI1.R00.2385.D02.2010160831 10/16/2020
> > > > > <4>[  260.470058] RIP: 0010:dma_fence_array_first+0x19/0x20
> > > I've looked into this and the root cause seems to be that the new code
> > > doesn't handle dma_fence_arrays with zero elements.
> > > 
> > > That is rather easy to fix, but a dma_fence_array with zero number of
> > > elements is most likely a bug because under the wrong circumstances it can
> > > create a dma_fence instance which will never signal.
> > > 
> > > I've send out a patch on Frinday ([PATCH] dma-buf: WIP dma_fence_array_first
> > > fix) which avoids the crash and prints a warning if anybody tries to create
> > > a dma_fence_array with zero length.
> > > 
> > > Can you test this?
> > It's in drm-tip now (in the fixup branch) so drm-tip results should have
> > the result soonish:
> > 
> > https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fintel-gfx-ci.01.org%2Ftree%2Fdrm-tip%2Findex.html&amp;data=04%7C01%7Cchristian.koenig%40amd.com%7C0afc74b5df0c4ea384af08da10c672fa%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637840742273792356%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=SL2CuMgM6lCSOhDTvs%2FaFg6zRlc7F3X%2BNkf6GuGMGXI%3D&amp;reserved=0?
> 
> How do I find something in there? Is there a search function over all the
> test results?

Not really. You can ask on #intel-gfx-ci, or look at the tests that have
blown up without this to know where to look.

You can also download all the logfiles with wget recursive or so from the
build directory (the links in the top row) and search locally.
-Daniel

> 
> Thanks,
> Christian.
> 
> > 
> > Cheers, Daniel
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2022-03-28 14:28 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-11 11:02 [PATCH 1/2] dma-buf: add dma_fence_unwrap Christian König
2022-03-11 11:02 ` [PATCH 2/2] dma-buf/sync-file: fix warning about fence containers Christian König
2022-03-11 16:16   ` kernel test robot
2022-03-11 17:59   ` kernel test robot
2022-03-11 18:51   ` kernel test robot
2022-03-25 10:13   ` Daniel Vetter
2022-03-25 10:13     ` Daniel Vetter
2022-03-25 10:35     ` Christian König
2022-03-25 10:35       ` Christian König
2022-03-25 19:28       ` Daniel Vetter
2022-03-25 19:28         ` Daniel Vetter
2022-03-11 15:45 ` [PATCH 1/2] dma-buf: add dma_fence_unwrap kernel test robot
2022-03-11 17:28 ` kernel test robot
2022-03-14 11:14 ` Christian König
2022-03-21 10:31   ` Christian König
2022-03-25  7:42     ` Christian König
2022-03-25 10:03 ` Daniel Vetter
2022-03-25 10:03   ` Daniel Vetter
2022-03-25 10:07   ` Daniel Vetter
2022-03-25 10:07     ` Daniel Vetter
2022-03-25 10:10     ` Christian König
2022-03-25 10:10       ` Christian König
2022-03-25 10:17       ` Daniel Vetter
2022-03-25 10:17         ` Daniel Vetter
2022-03-25 12:56         ` Christian König
2022-03-25 12:56           ` Christian König
2022-03-25 16:00           ` Daniel Vetter
2022-03-25 16:00             ` Daniel Vetter
2022-03-25 15:25 ` Ville Syrjälä
2022-03-25 15:25   ` Ville Syrjälä
2022-03-25 15:28   ` Christian König
2022-03-25 15:28     ` Christian König
2022-03-28 10:28     ` Christian König
2022-03-28 10:28       ` Christian König
2022-03-28 14:22       ` Daniel Vetter
2022-03-28 14:22         ` Daniel Vetter
2022-03-28 14:26         ` Christian König
2022-03-28 14:26           ` Christian König
2022-03-28 14:28           ` Daniel Vetter
2022-03-28 14:28             ` Daniel Vetter

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.