Modernize the open coded test framework by using kunit.
The kunit tool can be used to build a kernel and run it in a VM with:
$ tools/testing/kunit/kunit.py run --build_dir build_kunit_x86_64 --arch x86_64 --kunitconfig ./drivers/dma-buf/.kunitconfig
Along with the other ways to run kunits.
To make the kunit tool work like this the DMABUF_KUNIT_TEST kconfig must select DMA_SHARED_BUFFER to get it turned on without building a driver using it.
Signed-off-by: Jason Gunthorpe jgg@nvidia.com --- drivers/dma-buf/.kunitconfig | 2 + drivers/dma-buf/Kconfig | 8 ++ drivers/dma-buf/Makefile | 8 +- drivers/dma-buf/selftests.h | 1 - drivers/dma-buf/st-dma-resv.c | 145 +++++++++++++++++----------------- 5 files changed, 88 insertions(+), 76 deletions(-) create mode 100644 drivers/dma-buf/.kunitconfig
diff --git a/drivers/dma-buf/.kunitconfig b/drivers/dma-buf/.kunitconfig new file mode 100644 index 00000000000000..1ce5fb7e6cf9ff --- /dev/null +++ b/drivers/dma-buf/.kunitconfig @@ -0,0 +1,2 @@ +CONFIG_KUNIT=y +CONFIG_DMABUF_KUNIT_TEST=y diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig index 8d4f2f89f24e3c..7d13c8f4484dd3 100644 --- a/drivers/dma-buf/Kconfig +++ b/drivers/dma-buf/Kconfig @@ -54,6 +54,14 @@ config DMABUF_SELFTESTS default n depends on DMA_SHARED_BUFFER
+config DMABUF_KUNIT_TEST + tristate "KUnit tests for DMA-BUF" if !KUNIT_ALL_TESTS + depends on KUNIT + select DMA_SHARED_BUFFER + default KUNIT_ALL_TESTS + help + Enable kunit tests for DMA-BUF + menuconfig DMABUF_HEAPS bool "DMA-BUF Userland Memory Heaps" select DMA_SHARED_BUFFER diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile index 7a85565d906ba1..2e7a1453e2fe04 100644 --- a/drivers/dma-buf/Makefile +++ b/drivers/dma-buf/Makefile @@ -11,7 +11,11 @@ dmabuf_selftests-y := \ selftest.o \ st-dma-fence.o \ st-dma-fence-chain.o \ - st-dma-fence-unwrap.o \ - st-dma-resv.o + st-dma-fence-unwrap.o
obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o + +dmabuf_kunit-y := \ + st-dma-resv.o + +obj-$(CONFIG_DMABUF_KUNIT_TEST) += dmabuf_kunit.o diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h index 851965867d9c7f..2fdaca6b3e92e2 100644 --- a/drivers/dma-buf/selftests.h +++ b/drivers/dma-buf/selftests.h @@ -13,4 +13,3 @@ 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-resv.c b/drivers/dma-buf/st-dma-resv.c index ad4dfb49dcd9fa..95a4becdb8926d 100644 --- a/drivers/dma-buf/st-dma-resv.c +++ b/drivers/dma-buf/st-dma-resv.c @@ -5,13 +5,17 @@ * Copyright © 2021 Advanced Micro Devices, Inc. */
+#include <kunit/test.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/dma-resv.h>
-#include "selftest.h" +static DEFINE_SPINLOCK(fence_lock);
-static struct spinlock fence_lock; +struct dma_resv_usage_param { + enum dma_resv_usage usage; + const char *desc; +};
static const char *fence_name(struct dma_fence *f) { @@ -35,15 +39,14 @@ static struct dma_fence *alloc_fence(void) return f; }
-static int sanitycheck(void *arg) +static void test_sanitycheck(struct kunit *test) { struct dma_resv resv; struct dma_fence *f; int r;
f = alloc_fence(); - if (!f) - return -ENOMEM; + KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
@@ -53,49 +56,46 @@ static int sanitycheck(void *arg) dma_resv_init(&resv); r = dma_resv_lock(&resv, NULL); if (r) - pr_err("Resv locking failed\n"); + KUNIT_FAIL(test, "Resv locking failed\n"); else dma_resv_unlock(&resv); dma_resv_fini(&resv); - return r; }
-static int test_signaling(void *arg) +static void test_signaling(struct kunit *test) { - enum dma_resv_usage usage = (unsigned long)arg; + const struct dma_resv_usage_param *param = test->param_value; + enum dma_resv_usage usage = param->usage; struct dma_resv resv; struct dma_fence *f; int r;
f = alloc_fence(); - if (!f) - return -ENOMEM; + KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_resv_init(&resv); r = dma_resv_lock(&resv, NULL); if (r) { - pr_err("Resv locking failed\n"); + KUNIT_FAIL(test, "Resv locking failed"); goto err_free; }
r = dma_resv_reserve_fences(&resv, 1); if (r) { - pr_err("Resv shared slot allocation failed\n"); + KUNIT_FAIL(test, "Resv shared slot allocation failed"); goto err_unlock; }
dma_resv_add_fence(&resv, f, usage); if (dma_resv_test_signaled(&resv, usage)) { - pr_err("Resv unexpectedly signaled\n"); - r = -EINVAL; + KUNIT_FAIL(test, "Resv unexpectedly signaled"); goto err_unlock; } dma_fence_signal(f); if (!dma_resv_test_signaled(&resv, usage)) { - pr_err("Resv not reporting signaled\n"); - r = -EINVAL; + KUNIT_FAIL(test, "Resv not reporting signaled"); goto err_unlock; } err_unlock: @@ -103,33 +103,32 @@ static int test_signaling(void *arg) err_free: dma_resv_fini(&resv); dma_fence_put(f); - return r; }
-static int test_for_each(void *arg) +static void test_for_each(struct kunit *test) { - enum dma_resv_usage usage = (unsigned long)arg; + const struct dma_resv_usage_param *param = test->param_value; + enum dma_resv_usage usage = param->usage; struct dma_resv_iter cursor; struct dma_fence *f, *fence; struct dma_resv resv; int r;
f = alloc_fence(); - if (!f) - return -ENOMEM; + KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_resv_init(&resv); r = dma_resv_lock(&resv, NULL); if (r) { - pr_err("Resv locking failed\n"); + KUNIT_FAIL(test, "Resv locking failed"); goto err_free; }
r = dma_resv_reserve_fences(&resv, 1); if (r) { - pr_err("Resv shared slot allocation failed\n"); + KUNIT_FAIL(test, "Resv shared slot allocation failed"); goto err_unlock; }
@@ -138,24 +137,23 @@ static int test_for_each(void *arg) r = -ENOENT; dma_resv_for_each_fence(&cursor, &resv, usage, fence) { if (!r) { - pr_err("More than one fence found\n"); - r = -EINVAL; + KUNIT_FAIL(test, "More than one fence found"); goto err_unlock; } if (f != fence) { - pr_err("Unexpected fence\n"); + KUNIT_FAIL(test, "Unexpected fence"); r = -EINVAL; goto err_unlock; } if (dma_resv_iter_usage(&cursor) != usage) { - pr_err("Unexpected fence usage\n"); + KUNIT_FAIL(test, "Unexpected fence usage"); r = -EINVAL; goto err_unlock; } r = 0; } if (r) { - pr_err("No fence found\n"); + KUNIT_FAIL(test, "No fence found"); goto err_unlock; } dma_fence_signal(f); @@ -164,33 +162,32 @@ static int test_for_each(void *arg) err_free: dma_resv_fini(&resv); dma_fence_put(f); - return r; }
-static int test_for_each_unlocked(void *arg) +static void test_for_each_unlocked(struct kunit *test) { - enum dma_resv_usage usage = (unsigned long)arg; + const struct dma_resv_usage_param *param = test->param_value; + enum dma_resv_usage usage = param->usage; struct dma_resv_iter cursor; struct dma_fence *f, *fence; struct dma_resv resv; int r;
f = alloc_fence(); - if (!f) - return -ENOMEM; + KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_resv_init(&resv); r = dma_resv_lock(&resv, NULL); if (r) { - pr_err("Resv locking failed\n"); + KUNIT_FAIL(test, "Resv locking failed"); goto err_free; }
r = dma_resv_reserve_fences(&resv, 1); if (r) { - pr_err("Resv shared slot allocation failed\n"); + KUNIT_FAIL(test, "Resv shared slot allocation failed"); dma_resv_unlock(&resv); goto err_free; } @@ -202,21 +199,20 @@ static int test_for_each_unlocked(void *arg) dma_resv_iter_begin(&cursor, &resv, usage); dma_resv_for_each_fence_unlocked(&cursor, fence) { if (!r) { - pr_err("More than one fence found\n"); - r = -EINVAL; + KUNIT_FAIL(test, "More than one fence found"); goto err_iter_end; } if (!dma_resv_iter_is_restarted(&cursor)) { - pr_err("No restart flag\n"); + KUNIT_FAIL(test, "No restart flag"); goto err_iter_end; } if (f != fence) { - pr_err("Unexpected fence\n"); + KUNIT_FAIL(test, "Unexpected fence"); r = -EINVAL; goto err_iter_end; } if (dma_resv_iter_usage(&cursor) != usage) { - pr_err("Unexpected fence usage\n"); + KUNIT_FAIL(test, "Unexpected fence usage"); r = -EINVAL; goto err_iter_end; } @@ -230,40 +226,38 @@ static int test_for_each_unlocked(void *arg) r = 0; } } - if (r) - pr_err("No fence found\n"); + KUNIT_EXPECT_EQ(test, r, 0); err_iter_end: dma_resv_iter_end(&cursor); dma_fence_signal(f); err_free: dma_resv_fini(&resv); dma_fence_put(f); - return r; }
-static int test_get_fences(void *arg) +static void test_get_fences(struct kunit *test) { - enum dma_resv_usage usage = (unsigned long)arg; + const struct dma_resv_usage_param *param = test->param_value; + enum dma_resv_usage usage = param->usage; struct dma_fence *f, **fences = NULL; struct dma_resv resv; int r, i;
f = alloc_fence(); - if (!f) - return -ENOMEM; + KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_resv_init(&resv); r = dma_resv_lock(&resv, NULL); if (r) { - pr_err("Resv locking failed\n"); + KUNIT_FAIL(test, "Resv locking failed"); goto err_resv; }
r = dma_resv_reserve_fences(&resv, 1); if (r) { - pr_err("Resv shared slot allocation failed\n"); + KUNIT_FAIL(test, "Resv shared slot allocation failed"); dma_resv_unlock(&resv); goto err_resv; } @@ -273,12 +267,12 @@ static int test_get_fences(void *arg)
r = dma_resv_get_fences(&resv, usage, &i, &fences); if (r) { - pr_err("get_fences failed\n"); + KUNIT_FAIL(test, "get_fences failed"); goto err_free; }
if (i != 1 || fences[0] != f) { - pr_err("get_fences returned unexpected fence\n"); + KUNIT_FAIL(test, "get_fences returned unexpected fence"); goto err_free; }
@@ -290,27 +284,32 @@ static int test_get_fences(void *arg) err_resv: dma_resv_fini(&resv); dma_fence_put(f); - return r; }
-int dma_resv(void) -{ - static const struct subtest tests[] = { - SUBTEST(sanitycheck), - SUBTEST(test_signaling), - SUBTEST(test_for_each), - SUBTEST(test_for_each_unlocked), - SUBTEST(test_get_fences), - }; - enum dma_resv_usage usage; - int r; +static const struct dma_resv_usage_param dma_resv_usage_params[] = { + { DMA_RESV_USAGE_KERNEL, "kernel" }, + { DMA_RESV_USAGE_WRITE, "write" }, + { DMA_RESV_USAGE_READ, "read" }, + { DMA_RESV_USAGE_BOOKKEEP, "bookkeep" }, +};
- spin_lock_init(&fence_lock); - for (usage = DMA_RESV_USAGE_KERNEL; usage <= DMA_RESV_USAGE_BOOKKEEP; - ++usage) { - r = subtests(tests, (void *)(unsigned long)usage); - if (r) - return r; - } - return 0; -} +KUNIT_ARRAY_PARAM_DESC(dma_resv_usage, dma_resv_usage_params, desc); + +static struct kunit_case dma_resv_cases[] = { + KUNIT_CASE(test_sanitycheck), + KUNIT_CASE_PARAM(test_signaling, dma_resv_usage_gen_params), + KUNIT_CASE_PARAM(test_for_each, dma_resv_usage_gen_params), + KUNIT_CASE_PARAM(test_for_each_unlocked, dma_resv_usage_gen_params), + KUNIT_CASE_PARAM(test_get_fences, dma_resv_usage_gen_params), + {} +}; + +static struct kunit_suite dma_resv_test_suite = { + .name = "dma-buf-resv", + .test_cases = dma_resv_cases, +}; + +kunit_test_suite(dma_resv_test_suite); + +MODULE_DESCRIPTION("KUnit tests for DMA-BUF"); +MODULE_LICENSE("GPL");