[PATCH 7/7] dma-buf: drm sycobj testcases for timeline semaphore
Venkata Sandeep Dhanalakota
venkata.s.dhanalakota at intel.com
Mon Mar 30 15:43:36 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