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@xxxxxxxxxxxxxxxxxx> --- 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 --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; +} -- 2.23.0 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel