[PATCH 7/7] dma-buf: drm sycobj testcases for timeline semaphore

Venkata Sandeep Dhanalakota venkata.s.dhanalakota at intel.com
Mon Mar 30 15:37:22 UTC 2020


A simple test cases to validate usage of drm syncobj
and dma-fence-chain for timeline semaphore.

Signed-off-by: Venkata Sandeep Dhanalakota <venkata.s.dhanalakota at intel.com>
---
 drivers/dma-buf/Makefile      |   3 +-
 drivers/dma-buf/st_timeline.c | 345 ++++++++++++++++++++++++++++++++++
 2 files changed, 347 insertions(+), 1 deletion(-)
 create mode 100644 drivers/dma-buf/st_timeline.c

diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
index 9c190026bfab..0165082263f3 100644
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_UDMABUF)		+= udmabuf.o
 
 dmabuf_selftests-y := \
 	selftest.o \
-	st-dma-fence.o
+	st-dma-fence.o \
+	st_timeline.o
 
 obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
diff --git a/drivers/dma-buf/st_timeline.c b/drivers/dma-buf/st_timeline.c
new file mode 100644
index 000000000000..82052dd19b4d
--- /dev/null
+++ b/drivers/dma-buf/st_timeline.c
@@ -0,0 +1,345 @@
+// SPDX-License-Identifier: MIT
+
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kdev_t.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include<linux/slab.h>                 //kmalloc()
+#include<linux/uaccess.h>              //copy_to/from_user()
+#include<linux/sysfs.h> 
+#include<linux/kobject.h> 
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+
+#include <linux/delay.h>
+#include <linux/dma-fence.h>
+#include <linux/dma-fence-chain.h>
+#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>
+#include <drm/drm_syncobj.h>
+#include "selftest.h"
+
+static struct kmem_cache *slab_timeline;
+static struct kmem_cache *slab_fence_chain;
+
+struct mock_timeline {
+	struct drm_syncobj *syncobj;
+
+	/* cb when base is signalled */
+	struct dma_fence_cb cb;
+	struct dma_fence base;
+	/* lock for dma_fence */
+	spinlock_t lock;
+	u64 point;
+	u32 flags;
+};
+
+struct fence_chain {
+	struct dma_fence_chain chain;
+	struct dma_fence fence;
+	/* cb when fence is signalled */
+	struct dma_fence_cb cb;
+	int signalers;
+	spinlock_t lock;
+};
+
+static const char *mock_name(struct dma_fence  *s)
+{
+	return "timeline";
+}
+
+static const struct dma_fence_ops mock_ops = {
+	.get_driver_name = mock_name,
+	.get_timeline_name = mock_name,
+};
+
+static void fence_callback(struct dma_fence *f, struct dma_fence_cb *cb)
+{
+	struct fence_chain *t =
+       		 container_of(cb, struct fence_chain, cb);
+	t->signalers--;
+	if (!t->signalers)
+		dma_fence_signal(&t->fence);
+}
+
+static void timeline_callback(struct dma_fence *f, struct dma_fence_cb *cb)
+{
+	struct mock_timeline *t =
+       		 container_of(cb, struct mock_timeline, cb);
+	dma_fence_signal(&t->base);
+}
+
+static struct mock_timeline *timeline(u64 point, u32 flags)
+{
+	struct mock_timeline *t;
+
+	t = kmem_cache_alloc(slab_timeline, GFP_KERNEL);
+	if (!t)
+		return NULL;
+
+	spin_lock_init(&t->lock);
+	dma_fence_init(&t->base, &mock_ops, &t->lock, 0, 0);
+	drm_syncobj_create(&t->syncobj, flags, &t->base);
+	t->point = point;
+	return t;
+}
+
+static struct dma_fence_chain *fence_chain(struct dma_fence *prev,
+				    struct dma_fence *fence,
+				    u64 seqno)
+{
+	struct dma_fence_chain *f;
+
+	f = kmem_cache_alloc(slab_fence_chain, GFP_KERNEL);
+
+	if (!f)
+		return NULL;
+
+	dma_fence_chain_init(f,
+			     dma_fence_get(prev),
+			     dma_fence_get(fence),
+			     seqno);
+
+	return f;
+}
+
+static struct fence_chain** make_chains(int count, int start)
+{
+	struct dma_fence *prev_chain = NULL;
+	struct fence_chain **chains;
+	int i;
+
+	chains = kvmalloc_array(count, sizeof(struct fence_chain *),
+				GFP_KERNEL | __GFP_ZERO);
+
+	for (i = 0; i < count; i++) {
+		chains[i] = kmalloc(sizeof(struct fence_chain), GFP_KERNEL);
+		spin_lock_init(&chains[i]->lock);	
+		dma_fence_init(&chains[i]->fence, &mock_ops,
+			       &chains[i]->lock, 0, 0);
+		dma_fence_chain_init(&chains[i]->chain, prev_chain,
+				     dma_fence_get(&chains[i]->fence), start + i);
+		prev_chain = &chains[i]->chain.base;
+	}
+	return chains;
+
+}
+
+static void
+free_chains(struct fence_chain** chains, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		dma_fence_put(&chains[i]->fence);
+		kfree(chains[i]);
+	}
+
+	kfree(chains);
+}
+
+static int sanitycheck(void *arg)
+{
+	struct mock_timeline *t;
+	struct dma_fence *f;
+	int err = 0;
+
+	t = timeline(1, 0);
+
+	if (!t)
+		return -ENOMEM;
+
+	dma_fence_signal(&t->base);
+
+	f = drm_syncobj_fence_get(t->syncobj);
+	drm_syncobj_put(t->syncobj);
+	if (!dma_fence_is_signaled(f))
+		err = -1;
+
+	dma_fence_put(&t->base);
+	kmem_cache_free(slab_timeline, t);
+	return err;
+}
+
+static int testchain(void *arg)
+{
+	struct fence_chain *last, *chain, **chains;
+	struct dma_fence *first = NULL;
+	int i, count = 10;
+	int err = 0;
+
+	chains = make_chains(count, 0);
+
+	chain = chains[0];
+	first = &chain->fence;
+
+	for (i = 1; i < count; i++) {
+		chain = chains[i];
+		dma_fence_signal(chain->chain.fence);
+		last = chain;
+	}	
+	dma_fence_signal(first);
+
+	if (!dma_fence_is_signaled(&last->chain.base))
+		err = -1;
+
+	free_chains(chains, count);
+	return err;
+}
+
+static int waitchain(void *arg)
+{
+	struct fence_chain *last, **chains, *first;
+	struct mock_timeline *t;
+	struct dma_fence *f;
+	int count = 10, i;
+	u32 flags = 0x0;
+	int start = 7;
+	int err = 0;
+
+	t = timeline(start, flags);
+	chains = make_chains(count, start+1);
+	last = chains[count - 1];	
+	first = chains[0];
+	if (!t) {
+		err = -ENOMEM;
+		goto err;
+	}
+	drm_syncobj_replace_fence(t->syncobj, &last->chain.base);
+
+	for (i = 0; i < count; i++)
+		dma_fence_signal(&chains[i]->fence);
+	f = drm_syncobj_fence_get(t->syncobj);
+
+	if(!dma_fence_is_signaled(f))
+		 err = -1;
+err:
+	drm_syncobj_put(t->syncobj);
+	kmem_cache_free(slab_timeline, t);
+	free_chains(chains, count);
+	return err;
+}
+
+static int signalseqno(void *arg)
+{
+	struct fence_chain **chains, *wait;
+	struct mock_timeline *t[6];
+	struct dma_fence *f;
+	int i, count = 5;
+	int err = 0;
+
+	chains = make_chains(1, 0);
+	wait = chains[0];
+	for (i = 0;i < count; i++) {
+		t[i] = timeline(i, 0x0);
+		dma_fence_add_callback(&wait->fence,
+				       &t[i]->cb,
+				       timeline_callback);
+	}
+
+	/* wait for available */
+	for (i = 0; i < count; i++) {
+		f = drm_syncobj_fence_get(t[i]->syncobj);
+		//dont put syncobj yet.
+		if(dma_fence_is_signaled(f)) {
+			 err = -1;
+		}
+	}
+	
+	dma_fence_signal(&wait->fence);
+	for (i = 0; i < count; i++) {
+		f = drm_syncobj_fence_get(t[i]->syncobj);
+
+		if(!dma_fence_is_signaled(f))
+			 err = -1;
+		drm_syncobj_put(t[i]->syncobj);
+	}
+
+	for (i = 0;i < count; i++)
+		kmem_cache_free(slab_timeline, t[i]);
+	free_chains(chains, 1);
+	return err;
+			      
+}
+
+static int waitseqno(void *arg)
+{
+	struct fence_chain **chains, *signal;
+	struct mock_timeline *t[6];
+	struct dma_fence *f;
+	int i, count = 5;
+	int err = 0;
+
+	chains = make_chains(1, 0);
+	signal = chains[0];
+	signal->signalers = count;
+
+	/* wait for submit */
+	for (i = 0;i < count; i++) {
+		t[i] = timeline(i, 0x0);
+		dma_fence_add_callback(t[i]->syncobj->fence,
+				       &signal->cb,
+				       fence_callback);
+	}
+
+	for (i = 0;i < count; i++) {
+		f = drm_syncobj_fence_get(t[i]->syncobj);
+
+		if(dma_fence_is_signaled(&signal->chain.base))
+			 err = -1;
+		dma_fence_signal(f);
+		drm_syncobj_put(t[i]->syncobj);
+	}
+
+	if(!dma_fence_is_signaled(&signal->chain.base))
+		 err = -1;
+
+	for (i = 0;i < count; i++)
+		kmem_cache_free(slab_timeline, t[i]);
+	free_chains(chains, 1);
+	return err;
+}			      
+
+int drm_syncobj_timeline(void)
+{
+	static const struct subtest tests[] = {
+		SUBTEST(sanitycheck),
+		SUBTEST(testchain),
+		SUBTEST(waitchain),
+		SUBTEST(signalseqno),
+		SUBTEST(waitseqno),
+	};
+	int ret = 0;
+
+	pr_info("sizeof(dma_fence_chain)=%zu\n",
+		sizeof(struct dma_fence_chain));
+
+	slab_timeline = KMEM_CACHE(mock_timeline,
+				 SLAB_TYPESAFE_BY_RCU |
+				 SLAB_HWCACHE_ALIGN);
+
+	slab_fence_chain = KMEM_CACHE(dma_fence_chain,
+				 SLAB_TYPESAFE_BY_RCU |
+				 SLAB_HWCACHE_ALIGN);
+	if (!slab_timeline)
+		return -ENOMEM;
+
+	ret = subtests(tests, NULL);
+
+	kmem_cache_destroy(slab_timeline);
+	kmem_cache_destroy(slab_fence_chain);
+	return ret;
+}
-- 
2.21.0.5.gaeb582a983



More information about the Intel-gfx-trybot mailing list