diff mbox series

dma-buf: Extend selftests to exercise dma-fence-array

Message ID 20190824133806.8473-1-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show
Series dma-buf: Extend selftests to exercise dma-fence-array | expand

Commit Message

Chris Wilson Aug. 24, 2019, 1:38 p.m. UTC
A preliminary set of tests to exercise the basic dma-fence API on top of
struct dma_fence_array.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/dma-buf/Makefile             |   3 +-
 drivers/dma-buf/selftests.h          |   1 +
 drivers/dma-buf/st-dma-fence-array.c | 392 +++++++++++++++++++++++++++
 3 files changed, 395 insertions(+), 1 deletion(-)
 create mode 100644 drivers/dma-buf/st-dma-fence-array.c
diff mbox series

Patch

diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
index 03479da06422..822fb65b14e4 100644
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -7,6 +7,7 @@  obj-$(CONFIG_UDMABUF)		+= udmabuf.o
 
 dmabuf_selftests-y := \
 	selftest.o \
-	st-dma-fence.o
+	st-dma-fence.o \
+	st-dma-fence-array.o
 
 obj-$(CONFIG_DMABUF_SELFTESTS)	+= dmabuf_selftests.o
diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
index 5320386f02e5..12241b2c03f2 100644
--- a/drivers/dma-buf/selftests.h
+++ b/drivers/dma-buf/selftests.h
@@ -11,3 +11,4 @@ 
  */
 selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
 selftest(dma_fence, dma_fence)
+selftest(dma_fence_array, dma_fence_array)
diff --git a/drivers/dma-buf/st-dma-fence-array.c b/drivers/dma-buf/st-dma-fence-array.c
new file mode 100644
index 000000000000..685a564a2826
--- /dev/null
+++ b/drivers/dma-buf/st-dma-fence-array.c
@@ -0,0 +1,392 @@ 
+/* SPDX-License-Identifier: MIT */
+
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-fence.h>
+#include <linux/dma-fence-array.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/sched/signal.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "selftest.h"
+
+static struct kmem_cache *slab_fences;
+
+static struct mock_fence {
+	struct dma_fence base;
+	struct spinlock 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 *arg)
+{
+	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 *stub_fence(void *arg)
+{
+	return dma_fence_get_stub();
+}
+
+static struct dma_fence *same_fence(void *arg)
+{
+	return dma_fence_get(arg);
+}
+
+static int empty(void *arg)
+{
+	struct dma_fence_array *arr;
+	int err = 0;
+
+	arr = dma_fence_array_create(0, NULL, 0, 0, false);
+	if (!arr)
+		return -ENOMEM;
+
+	if (!dma_fence_is_signaled(&arr->base)) {
+		pr_err("Empty dma-fence-array is not signaled!\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_put(&arr->base);
+	return err;
+}
+
+static void free_fences(int count, struct dma_fence **fences)
+{
+	while (count--)
+		dma_fence_put(fences[count]);
+	kfree(fences);
+}
+
+static struct dma_fence **
+create_fences(int count, struct dma_fence *(*ctor)(void *arg), void *arg)
+{
+	struct dma_fence **fences;
+	int i;
+
+	fences = kmalloc_array(count, sizeof(*fences), GFP_KERNEL);
+	if (!fences)
+		return NULL;
+
+	for (i = 0; i < count; i++) {
+		fences[i] = ctor(arg);
+		if (!fences[i]) {
+			free_fences(i, fences);
+			return NULL;
+		}
+	}
+
+	return fences;
+}
+
+static int stub(void *arg)
+{
+	struct dma_fence_array *arr;
+	struct dma_fence **fences;
+	int err = 0;
+
+	fences = create_fences(1, stub_fence, NULL);
+	if (!fences)
+		return -ENOMEM;
+
+	arr = dma_fence_array_create(1, fences, 0, 0, false);
+	if (!arr) {
+		free_fences(1, fences);
+		return -ENOMEM;
+	}
+
+	dma_fence_enable_sw_signaling(&arr->base);
+
+	if (!dma_fence_is_signaled(&arr->base)) {
+		pr_err("dma-fence-array(stub) is not signaled!\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_put(&arr->base);
+	return err;
+}
+
+static int single(void *arg)
+{
+	struct dma_fence_array *arr;
+	struct dma_fence **fences;
+	int err = 0;
+
+	fences = create_fences(1, mock_fence, NULL);
+	if (!fences)
+		return -ENOMEM;
+
+	arr = dma_fence_array_create(1, fences, 0, 0, false);
+	if (!arr) {
+		free_fences(1, fences);
+		return -ENOMEM;
+	}
+
+	dma_fence_enable_sw_signaling(&arr->base);
+
+	if (dma_fence_is_signaled(&arr->base)) {
+		pr_err("dma-fence-array(single) is signaled upon creation!\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_signal(fences[0]);
+
+	if (!dma_fence_is_signaled(&arr->base)) {
+		pr_err("dma-fence-array(single) is not signaled\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_put(&arr->base);
+	return err;
+}
+
+static int pair(void *arg)
+{
+	struct dma_fence_array *arr;
+	struct dma_fence **fences;
+	int err = 0;
+
+	fences = create_fences(2, mock_fence, NULL);
+	if (!fences)
+		return -ENOMEM;
+
+	arr = dma_fence_array_create(2, fences, 0, 0, false);
+	if (!arr) {
+		free_fences(2, fences);
+		return -ENOMEM;
+	}
+
+	dma_fence_enable_sw_signaling(&arr->base);
+
+	if (dma_fence_is_signaled(&arr->base)) {
+		pr_err("dma-fence-array(pair) is signaled upon creation!\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_signal(fences[0]);
+
+	if (dma_fence_is_signaled(&arr->base)) {
+		pr_err("dma-fence-array(pair) is signaled after one signal!\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_signal(fences[0]);
+
+	if (dma_fence_is_signaled(&arr->base)) {
+		pr_err("dma-fence-array(pair) is signaled after a repeated signal!\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_signal(fences[1]);
+
+	if (!dma_fence_is_signaled(&arr->base)) {
+		pr_err("dma-fence-array(pair) is not signaled\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_put(&arr->base);
+	return err;
+}
+
+static int repeat(void *arg)
+{
+	struct dma_fence_array *arr;
+	struct dma_fence **fences;
+	struct dma_fence *f;
+	int err = 0;
+
+	f = mock_fence(NULL);
+	if (!f)
+		return -ENOMEM;
+
+	fences = create_fences(2, same_fence, f);
+	dma_fence_put(f);
+	if (!fences)
+		return -ENOMEM;
+
+	arr = dma_fence_array_create(2, fences, 0, 0, false);
+	if (!arr) {
+		free_fences(2, fences);
+		return -ENOMEM;
+	}
+
+	dma_fence_enable_sw_signaling(&arr->base);
+
+	if (dma_fence_is_signaled(&arr->base)) {
+		pr_err("dma-fence-array(pair) is signaled upon creation!\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_signal(fences[0]);
+
+	if (!dma_fence_is_signaled(&arr->base)) {
+		pr_err("dma-fence-array(pair) is not signaled\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_put(&arr->base);
+	return err;
+}
+
+static struct dma_fence *create_stub_array(void *arg)
+{
+	struct dma_fence_array *arr;
+	struct dma_fence **fences;
+
+	fences = create_fences(1, stub_fence, NULL);
+	if (!fences)
+		return NULL;
+
+	arr = dma_fence_array_create(1, fences, 0, 0, false);
+	if (!arr) {
+		free_fences(1, fences);
+		return NULL;
+	}
+
+	return &arr->base;
+}
+
+static int recurse_stub(void *arg)
+{
+	struct dma_fence_array *arr;
+	struct dma_fence **fences;
+	int err = 0;
+
+	fences = create_fences(1, create_stub_array, NULL);
+	if (!fences)
+		return -ENOMEM;
+
+	arr = dma_fence_array_create(1, fences, 0, 0, false);
+	if (!arr) {
+		free_fences(1, fences);
+		return -ENOMEM;
+	}
+
+	dma_fence_enable_sw_signaling(&arr->base);
+
+	if (!dma_fence_is_signaled(&arr->base)) {
+		pr_err("dma-fence-array(recurse-stub) is not signaled!\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_put(&arr->base);
+	return err;
+}
+
+static struct dma_fence *create_mock_array(void *arg)
+{
+	struct dma_fence_array *arr;
+	struct dma_fence **fences;
+
+	fences = create_fences(1, same_fence, arg);
+	if (!fences)
+		return NULL;
+
+	arr = dma_fence_array_create(1, fences, 0, 0, false);
+	if (!arr) {
+		free_fences(1, fences);
+		return NULL;
+	}
+
+	return &arr->base;
+}
+
+static int recurse_mock(void *arg)
+{
+	struct dma_fence_array *arr;
+	struct dma_fence **fences;
+	struct dma_fence *f;
+	int err = 0;
+
+	f = mock_fence(NULL);
+	if (!f)
+		return -ENOMEM;
+
+	fences = create_fences(1, create_mock_array, f);
+	if (!fences) {
+		dma_fence_put(f);
+		return -ENOMEM;
+	}
+
+	arr = dma_fence_array_create(1, fences, 0, 0, false);
+	if (!arr) {
+		free_fences(1, fences);
+		dma_fence_put(f);
+		return -ENOMEM;
+	}
+
+	dma_fence_enable_sw_signaling(&arr->base);
+
+	if (dma_fence_is_signaled(&arr->base)) {
+		pr_err("dma-fence-array(recurse-mock) is signaled on construction!\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_signal(f);
+
+	if (!dma_fence_is_signaled(&arr->base)) {
+		pr_err("dma-fence-array(recurse-mock) is not signaled!\n");
+		err = -EINVAL;
+	}
+
+	dma_fence_put(&arr->base);
+	dma_fence_put(f);
+	return err;
+}
+
+int dma_fence_array(void)
+{
+	static const struct subtest tests[] = {
+		SUBTEST(empty),
+		SUBTEST(stub),
+		SUBTEST(single),
+		SUBTEST(pair),
+		SUBTEST(repeat),
+		SUBTEST(recurse_stub),
+		SUBTEST(recurse_mock),
+	};
+	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;
+}