* [PATCH 1/5] dma-buf: Change st-dma-resv.c to use kunit
2026-03-01 18:57 [PATCH 0/5] Replace the dmabuf custom test framework with kunit Jason Gunthorpe
@ 2026-03-01 18:57 ` Jason Gunthorpe
2026-03-01 18:57 ` [PATCH 2/5] dma-buf: Change st-dma-fence.c " Jason Gunthorpe
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Jason Gunthorpe @ 2026-03-01 18:57 UTC (permalink / raw)
To: David Airlie, Christian König, dri-devel, intel-gfx,
Jani Nikula, Joonas Lahtinen, linaro-mm-sig, linux-media,
Rodrigo Vivi, Simona Vetter, Sumit Semwal, Tvrtko Ursulin
Cc: patches
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");
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 2/5] dma-buf: Change st-dma-fence.c to use kunit
2026-03-01 18:57 [PATCH 0/5] Replace the dmabuf custom test framework with kunit Jason Gunthorpe
2026-03-01 18:57 ` [PATCH 1/5] dma-buf: Change st-dma-resv.c to use kunit Jason Gunthorpe
@ 2026-03-01 18:57 ` Jason Gunthorpe
2026-03-01 18:57 ` [PATCH 3/5] dma-buf: Change st-dma-fence-unwrap.c " Jason Gunthorpe
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Jason Gunthorpe @ 2026-03-01 18:57 UTC (permalink / raw)
To: David Airlie, Christian König, dri-devel, intel-gfx,
Jani Nikula, Joonas Lahtinen, linaro-mm-sig, linux-media,
Rodrigo Vivi, Simona Vetter, Sumit Semwal, Tvrtko Ursulin
Cc: patches
Modernize the open coded test framework by using kunit.
Add a num_online_cpus() check to test_race_signal_callback() as the
default kunit.py runs the VM with a single CPU and this test depends on
two truly parallel kthreads. Skip it instead of hanging.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/dma-buf/Makefile | 2 +-
drivers/dma-buf/selftests.h | 1 -
drivers/dma-buf/st-dma-fence.c | 200 ++++++++++++++-------------------
3 files changed, 88 insertions(+), 115 deletions(-)
diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
index 2e7a1453e2fe04..37c94562e677ca 100644
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -9,13 +9,13 @@ obj-$(CONFIG_UDMABUF) += udmabuf.o
dmabuf_selftests-y := \
selftest.o \
- st-dma-fence.o \
st-dma-fence-chain.o \
st-dma-fence-unwrap.o
obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
dmabuf_kunit-y := \
+ st-dma-fence.o \
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 2fdaca6b3e92e2..0a348a5cbbebc7 100644
--- a/drivers/dma-buf/selftests.h
+++ b/drivers/dma-buf/selftests.h
@@ -10,6 +10,5 @@
* Tests are executed in order by igt/dmabuf_selftest
*/
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)
diff --git a/drivers/dma-buf/st-dma-fence.c b/drivers/dma-buf/st-dma-fence.c
index 0d9d524d79b6d9..4992722296968d 100644
--- a/drivers/dma-buf/st-dma-fence.c
+++ b/drivers/dma-buf/st-dma-fence.c
@@ -4,6 +4,7 @@
* Copyright © 2019 Intel Corporation
*/
+#include <kunit/test.h>
#include <linux/delay.h>
#include <linux/dma-fence.h>
#include <linux/kernel.h>
@@ -12,8 +13,6 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include "selftest.h"
-
static const char *mock_name(struct dma_fence *f)
{
return "mock";
@@ -36,62 +35,55 @@ static struct dma_fence *mock_fence(void)
return f;
}
-static int sanitycheck(void *arg)
+static void test_sanitycheck(struct kunit *test)
{
struct dma_fence *f;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_fence_signal(f);
dma_fence_put(f);
-
- return 0;
}
-static int test_signaling(void *arg)
+static void test_signaling(struct kunit *test)
{
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
if (dma_fence_is_signaled(f)) {
- pr_err("Fence unexpectedly signaled on creation\n");
+ KUNIT_FAIL(test, "Fence unexpectedly signaled on creation");
goto err_free;
}
if (dma_fence_check_and_signal(f)) {
- pr_err("Fence reported being already signaled\n");
+ KUNIT_FAIL(test, "Fence reported being already signaled");
goto err_free;
}
if (!dma_fence_is_signaled(f)) {
- pr_err("Fence not reporting signaled\n");
+ KUNIT_FAIL(test, "Fence not reporting signaled");
goto err_free;
}
if (!dma_fence_test_signaled_flag(f)) {
- pr_err("Fence reported not being already signaled\n");
+ KUNIT_FAIL(test, "Fence reported not being already signaled");
goto err_free;
}
if (rcu_dereference_protected(f->ops, true)) {
- pr_err("Fence ops not cleared on signal\n");
+ KUNIT_FAIL(test, "Fence ops not cleared on signal");
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
struct simple_cb {
@@ -104,215 +96,187 @@ static void simple_callback(struct dma_fence *f, struct dma_fence_cb *cb)
smp_store_mb(container_of(cb, struct simple_cb, cb)->seen, true);
}
-static int test_add_callback(void *arg)
+static void test_add_callback(struct kunit *test)
{
struct simple_cb cb = {};
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
- pr_err("Failed to add callback, fence already signaled!\n");
+ KUNIT_FAIL(test, "Failed to add callback, fence already signaled!");
goto err_free;
}
dma_fence_signal(f);
if (!cb.seen) {
- pr_err("Callback failed!\n");
+ KUNIT_FAIL(test, "Callback failed!");
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
-static int test_late_add_callback(void *arg)
+static void test_late_add_callback(struct kunit *test)
{
struct simple_cb cb = {};
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_fence_signal(f);
if (!dma_fence_add_callback(f, &cb.cb, simple_callback)) {
- pr_err("Added callback, but fence was already signaled!\n");
+ KUNIT_FAIL(test, "Added callback, but fence was already signaled!");
goto err_free;
}
dma_fence_signal(f);
if (cb.seen) {
- pr_err("Callback called after failed attachment !\n");
+ KUNIT_FAIL(test, "Callback called after failed attachment!");
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
-static int test_rm_callback(void *arg)
+static void test_rm_callback(struct kunit *test)
{
struct simple_cb cb = {};
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
- pr_err("Failed to add callback, fence already signaled!\n");
+ KUNIT_FAIL(test, "Failed to add callback, fence already signaled!");
goto err_free;
}
if (!dma_fence_remove_callback(f, &cb.cb)) {
- pr_err("Failed to remove callback!\n");
+ KUNIT_FAIL(test, "Failed to remove callback!");
goto err_free;
}
dma_fence_signal(f);
if (cb.seen) {
- pr_err("Callback still signaled after removal!\n");
+ KUNIT_FAIL(test, "Callback still signaled after removal!");
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
-static int test_late_rm_callback(void *arg)
+static void test_late_rm_callback(struct kunit *test)
{
struct simple_cb cb = {};
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
- pr_err("Failed to add callback, fence already signaled!\n");
+ KUNIT_FAIL(test, "Failed to add callback, fence already signaled!");
goto err_free;
}
dma_fence_signal(f);
if (!cb.seen) {
- pr_err("Callback failed!\n");
+ KUNIT_FAIL(test, "Callback failed!");
goto err_free;
}
if (dma_fence_remove_callback(f, &cb.cb)) {
- pr_err("Callback removal succeed after being executed!\n");
+ KUNIT_FAIL(test, "Callback removal succeeded after being executed!");
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
-static int test_status(void *arg)
+static void test_status(struct kunit *test)
{
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
if (dma_fence_get_status(f)) {
- pr_err("Fence unexpectedly has signaled status on creation\n");
+ KUNIT_FAIL(test, "Fence unexpectedly has signaled status on creation");
goto err_free;
}
dma_fence_signal(f);
if (!dma_fence_get_status(f)) {
- pr_err("Fence not reporting signaled status\n");
+ KUNIT_FAIL(test, "Fence not reporting signaled status");
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
-static int test_error(void *arg)
+static void test_error(struct kunit *test)
{
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
dma_fence_set_error(f, -EIO);
if (dma_fence_get_status(f)) {
- pr_err("Fence unexpectedly has error status before signal\n");
+ KUNIT_FAIL(test, "Fence unexpectedly has error status before signal");
goto err_free;
}
dma_fence_signal(f);
if (dma_fence_get_status(f) != -EIO) {
- pr_err("Fence not reporting error status, got %d\n",
- dma_fence_get_status(f));
+ KUNIT_FAIL(test, "Fence not reporting error status, got %d",
+ dma_fence_get_status(f));
goto err_free;
}
- err = 0;
err_free:
dma_fence_put(f);
- return err;
}
-static int test_wait(void *arg)
+static void test_wait(struct kunit *test)
{
struct dma_fence *f;
- int err = -EINVAL;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
if (dma_fence_wait_timeout(f, false, 0) != 0) {
- pr_err("Wait reported complete before being signaled\n");
+ KUNIT_FAIL(test, "Wait reported complete before being signaled");
goto err_free;
}
dma_fence_signal(f);
if (dma_fence_wait_timeout(f, false, 0) != 1) {
- pr_err("Wait reported incomplete after being signaled\n");
+ KUNIT_FAIL(test, "Wait reported incomplete after being signaled");
goto err_free;
}
- err = 0;
err_free:
dma_fence_signal(f);
dma_fence_put(f);
- return err;
}
struct wait_timer {
@@ -327,21 +291,19 @@ static void wait_timer(struct timer_list *timer)
dma_fence_signal(wt->f);
}
-static int test_wait_timeout(void *arg)
+static void test_wait_timeout(struct kunit *test)
{
struct wait_timer wt;
- int err = -EINVAL;
timer_setup_on_stack(&wt.timer, wait_timer, 0);
wt.f = mock_fence();
- if (!wt.f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, wt.f);
dma_fence_enable_sw_signaling(wt.f);
if (dma_fence_wait_timeout(wt.f, false, 1) != 0) {
- pr_err("Wait reported complete before being signaled\n");
+ KUNIT_FAIL(test, "Wait reported complete before being signaled");
goto err_free;
}
@@ -349,42 +311,38 @@ static int test_wait_timeout(void *arg)
if (dma_fence_wait_timeout(wt.f, false, HZ) == 0) {
if (timer_pending(&wt.timer)) {
- pr_notice("Timer did not fire within one HZ!\n");
- err = 0; /* not our fault! */
+ kunit_mark_skipped(
+ test, "Timer did not fire within on HZ!\n");
} else {
- pr_err("Wait reported incomplete after timeout\n");
+ KUNIT_FAIL(test,
+ "Wait reported incomplete after timeout");
}
goto err_free;
}
- err = 0;
err_free:
timer_delete_sync(&wt.timer);
timer_destroy_on_stack(&wt.timer);
dma_fence_signal(wt.f);
dma_fence_put(wt.f);
- return err;
}
-static int test_stub(void *arg)
+static void test_stub(struct kunit *test)
{
struct dma_fence *f[64];
- int err = -EINVAL;
int i;
for (i = 0; i < ARRAY_SIZE(f); i++) {
f[i] = dma_fence_get_stub();
if (!dma_fence_is_signaled(f[i])) {
- pr_err("Obtained unsignaled stub fence!\n");
+ KUNIT_FAIL(test, "Obtained unsignaled stub fence!");
goto err;
}
}
- err = 0;
err:
while (i--)
dma_fence_put(f[i]);
- return err;
}
/* Now off to the races! */
@@ -473,12 +431,19 @@ static int thread_signal_callback(void *arg)
return err;
}
-static int race_signal_callback(void *arg)
+static void test_race_signal_callback(struct kunit *test)
{
struct dma_fence __rcu *f[2] = {};
int ret = 0;
int pass;
+ /*
+ * thread_signal_callback() spins under RCU and it cannot make forward
+ * progress unless the threads are truly running concurrently.
+ */
+ if (num_online_cpus() < 2)
+ kunit_skip(test, "requires at least 2 CPUs");
+
for (pass = 0; !ret && pass <= 1; pass++) {
struct race_thread t[2];
int i;
@@ -490,10 +455,10 @@ static int race_signal_callback(void *arg)
t[i].task = kthread_run(thread_signal_callback, &t[i],
"dma-fence:%d", i);
if (IS_ERR(t[i].task)) {
- ret = PTR_ERR(t[i].task);
+ KUNIT_FAIL(test, "Failed to create kthread");
while (--i >= 0)
kthread_stop_put(t[i].task);
- return ret;
+ return;
}
get_task_struct(t[i].task);
}
@@ -509,26 +474,35 @@ static int race_signal_callback(void *arg)
}
}
- return ret;
+ KUNIT_EXPECT_EQ(test, ret, 0);
}
-int dma_fence(void)
+static int dma_fence_suite_init(struct kunit_suite *suite)
{
- static const struct subtest tests[] = {
- SUBTEST(sanitycheck),
- SUBTEST(test_signaling),
- SUBTEST(test_add_callback),
- SUBTEST(test_late_add_callback),
- SUBTEST(test_rm_callback),
- SUBTEST(test_late_rm_callback),
- SUBTEST(test_status),
- SUBTEST(test_error),
- SUBTEST(test_wait),
- SUBTEST(test_wait_timeout),
- SUBTEST(test_stub),
- SUBTEST(race_signal_callback),
- };
-
pr_info("sizeof(dma_fence)=%zu\n", sizeof(struct dma_fence));
- return subtests(tests, NULL);
+ return 0;
}
+
+static struct kunit_case dma_fence_cases[] = {
+ KUNIT_CASE(test_sanitycheck),
+ KUNIT_CASE(test_signaling),
+ KUNIT_CASE(test_add_callback),
+ KUNIT_CASE(test_late_add_callback),
+ KUNIT_CASE(test_rm_callback),
+ KUNIT_CASE(test_late_rm_callback),
+ KUNIT_CASE(test_status),
+ KUNIT_CASE(test_error),
+ KUNIT_CASE(test_wait),
+ KUNIT_CASE(test_wait_timeout),
+ KUNIT_CASE(test_stub),
+ KUNIT_CASE(test_race_signal_callback),
+ {}
+};
+
+static struct kunit_suite dma_fence_test_suite = {
+ .name = "dma-buf-fence",
+ .suite_init = dma_fence_suite_init,
+ .test_cases = dma_fence_cases,
+};
+
+kunit_test_suite(dma_fence_test_suite);
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 3/5] dma-buf: Change st-dma-fence-unwrap.c to use kunit
2026-03-01 18:57 [PATCH 0/5] Replace the dmabuf custom test framework with kunit Jason Gunthorpe
2026-03-01 18:57 ` [PATCH 1/5] dma-buf: Change st-dma-resv.c to use kunit Jason Gunthorpe
2026-03-01 18:57 ` [PATCH 2/5] dma-buf: Change st-dma-fence.c " Jason Gunthorpe
@ 2026-03-01 18:57 ` Jason Gunthorpe
2026-03-01 18:57 ` [PATCH 4/5] dma-buf: Change st-dma-fence-chain.c " Jason Gunthorpe
` (2 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Jason Gunthorpe @ 2026-03-01 18:57 UTC (permalink / raw)
To: David Airlie, Christian König, dri-devel, intel-gfx,
Jani Nikula, Joonas Lahtinen, linaro-mm-sig, linux-media,
Rodrigo Vivi, Simona Vetter, Sumit Semwal, Tvrtko Ursulin
Cc: patches
Modernize the open coded test framework by using kunit.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/dma-buf/Makefile | 4 +-
drivers/dma-buf/selftests.h | 1 -
drivers/dma-buf/st-dma-fence-unwrap.c | 290 +++++++++++---------------
3 files changed, 129 insertions(+), 166 deletions(-)
diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
index 37c94562e677ca..65bda1b7cc73eb 100644
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -9,13 +9,13 @@ obj-$(CONFIG_UDMABUF) += udmabuf.o
dmabuf_selftests-y := \
selftest.o \
- st-dma-fence-chain.o \
- st-dma-fence-unwrap.o
+ st-dma-fence-chain.o
obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
dmabuf_kunit-y := \
st-dma-fence.o \
+ st-dma-fence-unwrap.o \
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 0a348a5cbbebc7..7104cf0cce26d1 100644
--- a/drivers/dma-buf/selftests.h
+++ b/drivers/dma-buf/selftests.h
@@ -11,4 +11,3 @@
*/
selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
selftest(dma_fence_chain, dma_fence_chain)
-selftest(dma_fence_unwrap, dma_fence_unwrap)
diff --git a/drivers/dma-buf/st-dma-fence-unwrap.c b/drivers/dma-buf/st-dma-fence-unwrap.c
index 9c74195f47fd33..51c87869b7b82c 100644
--- a/drivers/dma-buf/st-dma-fence-unwrap.c
+++ b/drivers/dma-buf/st-dma-fence-unwrap.c
@@ -4,13 +4,12 @@
* Copyright (C) 2022 Advanced Micro Devices, Inc.
*/
+#include <kunit/test.h>
#include <linux/dma-fence.h>
#include <linux/dma-fence-array.h>
#include <linux/dma-fence-chain.h>
#include <linux/dma-fence-unwrap.h>
-#include "selftest.h"
-
#define CHAIN_SZ (4 << 10)
struct mock_fence {
@@ -97,52 +96,45 @@ static struct dma_fence *mock_chain(struct dma_fence *prev,
return &f->base;
}
-static int sanitycheck(void *arg)
+static void test_sanitycheck(struct kunit *test)
{
struct dma_fence *f, *chain, *array;
- int err = 0;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
dma_fence_enable_sw_signaling(f);
array = mock_array(1, f);
- if (!array)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, array);
chain = mock_chain(NULL, array);
- if (!chain)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, chain);
dma_fence_put(chain);
- return err;
}
-static int unwrap_array(void *arg)
+static void test_unwrap_array(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *array;
struct dma_fence_unwrap iter;
- int err = 0;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = mock_fence();
if (!f2) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
dma_fence_put(f1);
- return -ENOMEM;
+ return;
}
dma_fence_enable_sw_signaling(f2);
array = mock_array(2, f1, f2);
- if (!array)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, array);
dma_fence_unwrap_for_each(fence, &iter, array) {
if (fence == f1) {
@@ -150,43 +142,37 @@ static int unwrap_array(void *arg)
} else if (fence == f2) {
f2 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f2)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(array);
- return err;
}
-static int unwrap_chain(void *arg)
+static void test_unwrap_chain(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *chain;
struct dma_fence_unwrap iter;
- int err = 0;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = mock_fence();
if (!f2) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
dma_fence_put(f1);
- return -ENOMEM;
+ return;
}
dma_fence_enable_sw_signaling(f2);
chain = mock_chain(f1, f2);
- if (!chain)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, chain);
dma_fence_unwrap_for_each(fence, &iter, chain) {
if (fence == f1) {
@@ -194,47 +180,40 @@ static int unwrap_chain(void *arg)
} else if (fence == f2) {
f2 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f2)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(chain);
- return err;
}
-static int unwrap_chain_array(void *arg)
+static void test_unwrap_chain_array(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *array, *chain;
struct dma_fence_unwrap iter;
- int err = 0;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = mock_fence();
if (!f2) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
dma_fence_put(f1);
- return -ENOMEM;
+ return;
}
dma_fence_enable_sw_signaling(f2);
array = mock_array(2, f1, f2);
- if (!array)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, array);
chain = mock_chain(NULL, array);
- if (!chain)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, chain);
dma_fence_unwrap_for_each(fence, &iter, chain) {
if (fence == f1) {
@@ -242,35 +221,29 @@ static int unwrap_chain_array(void *arg)
} else if (fence == f2) {
f2 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f2)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(chain);
- return err;
}
-static int unwrap_merge(void *arg)
+static void test_unwrap_merge(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *f3;
struct dma_fence_unwrap iter;
- int err = 0;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = mock_fence();
if (!f2) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f1;
}
@@ -278,7 +251,7 @@ static int unwrap_merge(void *arg)
f3 = dma_fence_unwrap_merge(f1, f2);
if (!f3) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to merge fences");
goto error_put_f2;
}
@@ -290,39 +263,33 @@ static int unwrap_merge(void *arg)
dma_fence_put(f2);
f2 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f2)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(f3);
error_put_f2:
dma_fence_put(f2);
error_put_f1:
dma_fence_put(f1);
- return err;
}
-static int unwrap_merge_duplicate(void *arg)
+static void test_unwrap_merge_duplicate(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2;
struct dma_fence_unwrap iter;
- int err = 0;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = dma_fence_unwrap_merge(f1, f1);
if (!f2) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to merge fences");
goto error_put_f1;
}
@@ -331,41 +298,35 @@ static int unwrap_merge_duplicate(void *arg)
dma_fence_put(f1);
f1 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(f2);
error_put_f1:
dma_fence_put(f1);
- return err;
}
-static int unwrap_merge_seqno(void *arg)
+static void test_unwrap_merge_seqno(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *f3, *f4;
struct dma_fence_unwrap iter;
- int err = 0;
u64 ctx[2];
ctx[0] = dma_fence_context_alloc(1);
ctx[1] = dma_fence_context_alloc(1);
f1 = __mock_fence(ctx[1], 1);
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = __mock_fence(ctx[1], 2);
if (!f2) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f1;
}
@@ -373,7 +334,7 @@ static int unwrap_merge_seqno(void *arg)
f3 = __mock_fence(ctx[0], 1);
if (!f3) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f2;
}
@@ -381,7 +342,7 @@ static int unwrap_merge_seqno(void *arg)
f4 = dma_fence_unwrap_merge(f1, f2, f3);
if (!f4) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to merge fences");
goto error_put_f3;
}
@@ -393,15 +354,12 @@ static int unwrap_merge_seqno(void *arg)
dma_fence_put(f2);
f2 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f2 || f3) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f2 || f3)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(f4);
error_put_f3:
@@ -410,40 +368,41 @@ static int unwrap_merge_seqno(void *arg)
dma_fence_put(f2);
error_put_f1:
dma_fence_put(f1);
- return err;
}
-static int unwrap_merge_order(void *arg)
+static void test_unwrap_merge_order(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *a1, *a2, *c1, *c2;
struct dma_fence_unwrap iter;
- int err = 0;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = mock_fence();
if (!f2) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
dma_fence_put(f1);
- return -ENOMEM;
+ return;
}
dma_fence_enable_sw_signaling(f2);
a1 = mock_array(2, f1, f2);
- if (!a1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, a1);
c1 = mock_chain(NULL, dma_fence_get(f1));
- if (!c1)
+ if (!c1) {
+ KUNIT_FAIL(test, "Failed to create chain");
goto error_put_a1;
+ }
c2 = mock_chain(c1, dma_fence_get(f2));
- if (!c2)
+ if (!c2) {
+ KUNIT_FAIL(test, "Failed to create chain");
goto error_put_a1;
+ }
/*
* The fences in the chain are the same as in a1 but in oposite order,
@@ -455,63 +414,64 @@ static int unwrap_merge_order(void *arg)
if (fence == f1) {
f1 = NULL;
if (!f2)
- pr_err("Unexpected order!\n");
+ KUNIT_FAIL(test, "Unexpected order!");
} else if (fence == f2) {
f2 = NULL;
if (f1)
- pr_err("Unexpected order!\n");
+ KUNIT_FAIL(test, "Unexpected order!");
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f2)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(a2);
- return err;
+ return;
error_put_a1:
dma_fence_put(a1);
- return -ENOMEM;
}
-static int unwrap_merge_complex(void *arg)
+static void test_unwrap_merge_complex(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5;
struct dma_fence_unwrap iter;
- int err = -ENOMEM;
f1 = mock_fence();
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = mock_fence();
- if (!f2)
+ if (!f2) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f1;
+ }
dma_fence_enable_sw_signaling(f2);
f3 = dma_fence_unwrap_merge(f1, f2);
- if (!f3)
+ if (!f3) {
+ KUNIT_FAIL(test, "Failed to merge fences");
goto error_put_f2;
+ }
/* The resulting array has the fences in reverse */
f4 = mock_array(2, dma_fence_get(f2), dma_fence_get(f1));
- if (!f4)
+ if (!f4) {
+ KUNIT_FAIL(test, "Failed to create array");
goto error_put_f3;
+ }
/* Signaled fences should be filtered, the two arrays merged. */
f5 = dma_fence_unwrap_merge(f3, f4, dma_fence_get_stub());
- if (!f5)
+ if (!f5) {
+ KUNIT_FAIL(test, "Failed to merge fences");
goto error_put_f4;
+ }
- err = 0;
dma_fence_unwrap_for_each(fence, &iter, f5) {
if (fence == f1) {
dma_fence_put(f1);
@@ -520,15 +480,12 @@ static int unwrap_merge_complex(void *arg)
dma_fence_put(f2);
f2 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f2) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f2)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(f5);
error_put_f4:
@@ -539,56 +496,64 @@ static int unwrap_merge_complex(void *arg)
dma_fence_put(f2);
error_put_f1:
dma_fence_put(f1);
- return err;
}
-static int unwrap_merge_complex_seqno(void *arg)
+static void test_unwrap_merge_complex_seqno(struct kunit *test)
{
struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5, *f6, *f7;
struct dma_fence_unwrap iter;
- int err = -ENOMEM;
u64 ctx[2];
ctx[0] = dma_fence_context_alloc(1);
ctx[1] = dma_fence_context_alloc(1);
f1 = __mock_fence(ctx[0], 2);
- if (!f1)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f1);
dma_fence_enable_sw_signaling(f1);
f2 = __mock_fence(ctx[1], 1);
- if (!f2)
+ if (!f2) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f1;
+ }
dma_fence_enable_sw_signaling(f2);
f3 = __mock_fence(ctx[0], 1);
- if (!f3)
+ if (!f3) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f2;
+ }
dma_fence_enable_sw_signaling(f3);
f4 = __mock_fence(ctx[1], 2);
- if (!f4)
+ if (!f4) {
+ KUNIT_FAIL(test, "Failed to create mock fence");
goto error_put_f3;
+ }
dma_fence_enable_sw_signaling(f4);
f5 = mock_array(2, dma_fence_get(f1), dma_fence_get(f2));
- if (!f5)
+ if (!f5) {
+ KUNIT_FAIL(test, "Failed to create array");
goto error_put_f4;
+ }
f6 = mock_array(2, dma_fence_get(f3), dma_fence_get(f4));
- if (!f6)
+ if (!f6) {
+ KUNIT_FAIL(test, "Failed to create array");
goto error_put_f5;
+ }
f7 = dma_fence_unwrap_merge(f5, f6);
- if (!f7)
+ if (!f7) {
+ KUNIT_FAIL(test, "Failed to merge fences");
goto error_put_f6;
+ }
- err = 0;
dma_fence_unwrap_for_each(fence, &iter, f7) {
if (fence == f1 && f4) {
dma_fence_put(f1);
@@ -597,15 +562,12 @@ static int unwrap_merge_complex_seqno(void *arg)
dma_fence_put(f4);
f4 = NULL;
} else {
- pr_err("Unexpected fence!\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Unexpected fence!");
}
}
- if (f1 || f4) {
- pr_err("Not all fences seen!\n");
- err = -EINVAL;
- }
+ if (f1 || f4)
+ KUNIT_FAIL(test, "Not all fences seen!");
dma_fence_put(f7);
error_put_f6:
@@ -620,23 +582,25 @@ static int unwrap_merge_complex_seqno(void *arg)
dma_fence_put(f2);
error_put_f1:
dma_fence_put(f1);
- return err;
}
-int dma_fence_unwrap(void)
-{
- static const struct subtest tests[] = {
- SUBTEST(sanitycheck),
- SUBTEST(unwrap_array),
- SUBTEST(unwrap_chain),
- SUBTEST(unwrap_chain_array),
- SUBTEST(unwrap_merge),
- SUBTEST(unwrap_merge_duplicate),
- SUBTEST(unwrap_merge_seqno),
- SUBTEST(unwrap_merge_order),
- SUBTEST(unwrap_merge_complex),
- SUBTEST(unwrap_merge_complex_seqno),
- };
+static struct kunit_case dma_fence_unwrap_cases[] = {
+ KUNIT_CASE(test_sanitycheck),
+ KUNIT_CASE(test_unwrap_array),
+ KUNIT_CASE(test_unwrap_chain),
+ KUNIT_CASE(test_unwrap_chain_array),
+ KUNIT_CASE(test_unwrap_merge),
+ KUNIT_CASE(test_unwrap_merge_duplicate),
+ KUNIT_CASE(test_unwrap_merge_seqno),
+ KUNIT_CASE(test_unwrap_merge_order),
+ KUNIT_CASE(test_unwrap_merge_complex),
+ KUNIT_CASE(test_unwrap_merge_complex_seqno),
+ {}
+};
- return subtests(tests, NULL);
-}
+static struct kunit_suite dma_fence_unwrap_test_suite = {
+ .name = "dma-buf-fence-unwrap",
+ .test_cases = dma_fence_unwrap_cases,
+};
+
+kunit_test_suite(dma_fence_unwrap_test_suite);
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 4/5] dma-buf: Change st-dma-fence-chain.c to use kunit
2026-03-01 18:57 [PATCH 0/5] Replace the dmabuf custom test framework with kunit Jason Gunthorpe
` (2 preceding siblings ...)
2026-03-01 18:57 ` [PATCH 3/5] dma-buf: Change st-dma-fence-unwrap.c " Jason Gunthorpe
@ 2026-03-01 18:57 ` Jason Gunthorpe
2026-03-01 18:57 ` [PATCH 5/5] dma-buf: Remove the old selftest Jason Gunthorpe
2026-03-02 11:43 ` [PATCH 0/5] Replace the dmabuf custom test framework with kunit Christian König
5 siblings, 0 replies; 9+ messages in thread
From: Jason Gunthorpe @ 2026-03-01 18:57 UTC (permalink / raw)
To: David Airlie, Christian König, dri-devel, intel-gfx,
Jani Nikula, Joonas Lahtinen, linaro-mm-sig, linux-media,
Rodrigo Vivi, Simona Vetter, Sumit Semwal, Tvrtko Ursulin
Cc: patches
Modernize the open coded test framework by using kunit.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/dma-buf/Makefile | 4 +-
drivers/dma-buf/selftests.h | 1 -
drivers/dma-buf/st-dma-fence-chain.c | 217 ++++++++++++---------------
3 files changed, 98 insertions(+), 124 deletions(-)
diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
index 65bda1b7cc73eb..c97ab2d01a7e68 100644
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -8,13 +8,13 @@ obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
obj-$(CONFIG_UDMABUF) += udmabuf.o
dmabuf_selftests-y := \
- selftest.o \
- st-dma-fence-chain.o
+ selftest.o
obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
dmabuf_kunit-y := \
st-dma-fence.o \
+ st-dma-fence-chain.o \
st-dma-fence-unwrap.o \
st-dma-resv.o
diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
index 7104cf0cce26d1..37b7251841278e 100644
--- a/drivers/dma-buf/selftests.h
+++ b/drivers/dma-buf/selftests.h
@@ -10,4 +10,3 @@
* Tests are executed in order by igt/dmabuf_selftest
*/
selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
-selftest(dma_fence_chain, dma_fence_chain)
diff --git a/drivers/dma-buf/st-dma-fence-chain.c b/drivers/dma-buf/st-dma-fence-chain.c
index 821023dd34df68..a3023d3fedc9d8 100644
--- a/drivers/dma-buf/st-dma-fence-chain.c
+++ b/drivers/dma-buf/st-dma-fence-chain.c
@@ -4,6 +4,7 @@
* Copyright © 2019 Intel Corporation
*/
+#include <kunit/test.h>
#include <linux/delay.h>
#include <linux/dma-fence.h>
#include <linux/dma-fence-chain.h>
@@ -15,8 +16,6 @@
#include <linux/spinlock.h>
#include <linux/random.h>
-#include "selftest.h"
-
#define CHAIN_SZ (4 << 10)
static struct kmem_cache *slab_fences;
@@ -74,27 +73,23 @@ static struct dma_fence *mock_chain(struct dma_fence *prev,
return &f->base;
}
-static int sanitycheck(void *arg)
+static void test_sanitycheck(struct kunit *test)
{
struct dma_fence *f, *chain;
- int err = 0;
f = mock_fence();
- if (!f)
- return -ENOMEM;
+ KUNIT_ASSERT_NOT_NULL(test, f);
chain = mock_chain(NULL, f, 1);
if (chain)
dma_fence_enable_sw_signaling(chain);
else
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to create chain");
dma_fence_signal(f);
dma_fence_put(f);
dma_fence_put(chain);
-
- return err;
}
struct fence_chains {
@@ -176,7 +171,7 @@ static void fence_chains_fini(struct fence_chains *fc)
kvfree(fc->chains);
}
-static int find_seqno(void *arg)
+static void test_find_seqno(struct kunit *test)
{
struct fence_chains fc;
struct dma_fence *fence;
@@ -184,14 +179,13 @@ static int find_seqno(void *arg)
int i;
err = fence_chains_init(&fc, 64, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
fence = dma_fence_get(fc.tail);
err = dma_fence_chain_find_seqno(&fence, 0);
dma_fence_put(fence);
if (err) {
- pr_err("Reported %d for find_seqno(0)!\n", err);
+ KUNIT_FAIL(test, "Reported %d for find_seqno(0)!", err);
goto err;
}
@@ -200,14 +194,13 @@ static int find_seqno(void *arg)
err = dma_fence_chain_find_seqno(&fence, i + 1);
dma_fence_put(fence);
if (err) {
- pr_err("Reported %d for find_seqno(%d:%d)!\n",
- err, fc.chain_length + 1, i + 1);
+ KUNIT_FAIL(test, "Reported %d for find_seqno(%d:%d)!",
+ err, fc.chain_length + 1, i + 1);
goto err;
}
if (fence != fc.chains[i]) {
- pr_err("Incorrect fence reported by find_seqno(%d:%d)\n",
- fc.chain_length + 1, i + 1);
- err = -EINVAL;
+ KUNIT_FAIL(test, "Incorrect fence reported by find_seqno(%d:%d)",
+ fc.chain_length + 1, i + 1);
goto err;
}
@@ -215,12 +208,11 @@ static int find_seqno(void *arg)
err = dma_fence_chain_find_seqno(&fence, i + 1);
dma_fence_put(fence);
if (err) {
- pr_err("Error reported for finding self\n");
+ KUNIT_FAIL(test, "Error reported for finding self");
goto err;
}
if (fence != fc.chains[i]) {
- pr_err("Incorrect fence reported by find self\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Incorrect fence reported by find self");
goto err;
}
@@ -228,9 +220,8 @@ static int find_seqno(void *arg)
err = dma_fence_chain_find_seqno(&fence, i + 2);
dma_fence_put(fence);
if (!err) {
- pr_err("Error not reported for future fence: find_seqno(%d:%d)!\n",
- i + 1, i + 2);
- err = -EINVAL;
+ KUNIT_FAIL(test, "Error not reported for future fence: find_seqno(%d:%d)!",
+ i + 1, i + 2);
goto err;
}
@@ -238,31 +229,28 @@ static int find_seqno(void *arg)
err = dma_fence_chain_find_seqno(&fence, i);
dma_fence_put(fence);
if (err) {
- pr_err("Error reported for previous fence!\n");
+ KUNIT_FAIL(test, "Error reported for previous fence!");
goto err;
}
if (i > 0 && fence != fc.chains[i - 1]) {
- pr_err("Incorrect fence reported by find_seqno(%d:%d)\n",
- i + 1, i);
- err = -EINVAL;
+ KUNIT_FAIL(test, "Incorrect fence reported by find_seqno(%d:%d)",
+ i + 1, i);
goto err;
}
}
err:
fence_chains_fini(&fc);
- return err;
}
-static int find_signaled(void *arg)
+static void test_find_signaled(struct kunit *test)
{
struct fence_chains fc;
struct dma_fence *fence;
int err;
err = fence_chains_init(&fc, 2, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
dma_fence_signal(fc.fences[0]);
@@ -270,37 +258,33 @@ static int find_signaled(void *arg)
err = dma_fence_chain_find_seqno(&fence, 1);
dma_fence_put(fence);
if (err) {
- pr_err("Reported %d for find_seqno()!\n", err);
+ KUNIT_FAIL(test, "Reported %d for find_seqno()!", err);
goto err;
}
if (fence && fence != fc.chains[0]) {
- pr_err("Incorrect chain-fence.seqno:%lld reported for completed seqno:1\n",
- fence->seqno);
+ KUNIT_FAIL(test, "Incorrect chain-fence.seqno:%lld reported for completed seqno:1",
+ fence->seqno);
dma_fence_get(fence);
err = dma_fence_chain_find_seqno(&fence, 1);
dma_fence_put(fence);
if (err)
- pr_err("Reported %d for finding self!\n", err);
-
- err = -EINVAL;
+ KUNIT_FAIL(test, "Reported %d for finding self!", err);
}
err:
fence_chains_fini(&fc);
- return err;
}
-static int find_out_of_order(void *arg)
+static void test_find_out_of_order(struct kunit *test)
{
struct fence_chains fc;
struct dma_fence *fence;
int err;
err = fence_chains_init(&fc, 3, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
dma_fence_signal(fc.fences[1]);
@@ -308,7 +292,7 @@ static int find_out_of_order(void *arg)
err = dma_fence_chain_find_seqno(&fence, 2);
dma_fence_put(fence);
if (err) {
- pr_err("Reported %d for find_seqno()!\n", err);
+ KUNIT_FAIL(test, "Reported %d for find_seqno()!", err);
goto err;
}
@@ -319,16 +303,12 @@ static int find_out_of_order(void *arg)
* we should get as fence to wait upon (fence 2 being garbage
* collected during the traversal of the chain).
*/
- if (fence != fc.chains[0]) {
- pr_err("Incorrect chain-fence.seqno:%lld reported for completed seqno:2\n",
- fence ? fence->seqno : 0);
-
- err = -EINVAL;
- }
+ if (fence != fc.chains[0])
+ KUNIT_FAIL(test, "Incorrect chain-fence.seqno:%lld reported for completed seqno:2",
+ fence ? fence->seqno : 0);
err:
fence_chains_fini(&fc);
- return err;
}
static uint64_t seqno_inc2(unsigned int i)
@@ -336,7 +316,7 @@ static uint64_t seqno_inc2(unsigned int i)
return 2 * i + 2;
}
-static int find_gap(void *arg)
+static void test_find_gap(struct kunit *test)
{
struct fence_chains fc;
struct dma_fence *fence;
@@ -344,24 +324,22 @@ static int find_gap(void *arg)
int i;
err = fence_chains_init(&fc, 64, seqno_inc2);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
for (i = 0; i < fc.chain_length; i++) {
fence = dma_fence_get(fc.tail);
err = dma_fence_chain_find_seqno(&fence, 2 * i + 1);
dma_fence_put(fence);
if (err) {
- pr_err("Reported %d for find_seqno(%d:%d)!\n",
- err, fc.chain_length + 1, 2 * i + 1);
+ KUNIT_FAIL(test, "Reported %d for find_seqno(%d:%d)!",
+ err, fc.chain_length + 1, 2 * i + 1);
goto err;
}
if (fence != fc.chains[i]) {
- pr_err("Incorrect fence.seqno:%lld reported by find_seqno(%d:%d)\n",
- fence->seqno,
- fc.chain_length + 1,
- 2 * i + 1);
- err = -EINVAL;
+ KUNIT_FAIL(test, "Incorrect fence.seqno:%lld reported by find_seqno(%d:%d)",
+ fence->seqno,
+ fc.chain_length + 1,
+ 2 * i + 1);
goto err;
}
@@ -369,19 +347,17 @@ static int find_gap(void *arg)
err = dma_fence_chain_find_seqno(&fence, 2 * i + 2);
dma_fence_put(fence);
if (err) {
- pr_err("Error reported for finding self\n");
+ KUNIT_FAIL(test, "Error reported for finding self");
goto err;
}
if (fence != fc.chains[i]) {
- pr_err("Incorrect fence reported by find self\n");
- err = -EINVAL;
+ KUNIT_FAIL(test, "Incorrect fence reported by find self");
goto err;
}
}
err:
fence_chains_fini(&fc);
- return err;
}
struct find_race {
@@ -437,7 +413,7 @@ static int __find_race(void *arg)
return err;
}
-static int find_race(void *arg)
+static void test_find_race(struct kunit *test)
{
struct find_race data;
int ncpus = num_online_cpus();
@@ -447,12 +423,11 @@ static int find_race(void *arg)
int i;
err = fence_chains_init(&data.fc, CHAIN_SZ, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
threads = kmalloc_objs(*threads, ncpus);
if (!threads) {
- err = -ENOMEM;
+ KUNIT_FAIL(test, "Failed to allocate threads array");
goto err;
}
@@ -486,74 +461,67 @@ static int find_race(void *arg)
count++;
pr_info("Completed %lu cycles\n", count);
+ KUNIT_EXPECT_EQ(test, err, 0);
+
err:
fence_chains_fini(&data.fc);
- return err;
}
-static int signal_forward(void *arg)
+static void test_signal_forward(struct kunit *test)
{
struct fence_chains fc;
int err;
int i;
err = fence_chains_init(&fc, 64, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
for (i = 0; i < fc.chain_length; i++) {
dma_fence_signal(fc.fences[i]);
if (!dma_fence_is_signaled(fc.chains[i])) {
- pr_err("chain[%d] not signaled!\n", i);
- err = -EINVAL;
+ KUNIT_FAIL(test, "chain[%d] not signaled!", i);
goto err;
}
if (i + 1 < fc.chain_length &&
dma_fence_is_signaled(fc.chains[i + 1])) {
- pr_err("chain[%d] is signaled!\n", i);
- err = -EINVAL;
+ KUNIT_FAIL(test, "chain[%d] is signaled!", i);
goto err;
}
}
err:
fence_chains_fini(&fc);
- return err;
}
-static int signal_backward(void *arg)
+static void test_signal_backward(struct kunit *test)
{
struct fence_chains fc;
int err;
int i;
err = fence_chains_init(&fc, 64, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
for (i = fc.chain_length; i--; ) {
dma_fence_signal(fc.fences[i]);
if (i > 0 && dma_fence_is_signaled(fc.chains[i])) {
- pr_err("chain[%d] is signaled!\n", i);
- err = -EINVAL;
+ KUNIT_FAIL(test, "chain[%d] is signaled!", i);
goto err;
}
}
for (i = 0; i < fc.chain_length; i++) {
if (!dma_fence_is_signaled(fc.chains[i])) {
- pr_err("chain[%d] was not signaled!\n", i);
- err = -EINVAL;
+ KUNIT_FAIL(test, "chain[%d] was not signaled!", i);
goto err;
}
}
err:
fence_chains_fini(&fc);
- return err;
}
static int __wait_fence_chains(void *arg)
@@ -566,7 +534,7 @@ static int __wait_fence_chains(void *arg)
return 0;
}
-static int wait_forward(void *arg)
+static void test_wait_forward(struct kunit *test)
{
struct fence_chains fc;
struct task_struct *tsk;
@@ -574,12 +542,11 @@ static int wait_forward(void *arg)
int i;
err = fence_chains_init(&fc, CHAIN_SZ, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
tsk = kthread_run(__wait_fence_chains, &fc, "dmabuf/wait");
if (IS_ERR(tsk)) {
- err = PTR_ERR(tsk);
+ KUNIT_FAIL(test, "Failed to create kthread");
goto err;
}
get_task_struct(tsk);
@@ -589,13 +556,13 @@ static int wait_forward(void *arg)
dma_fence_signal(fc.fences[i]);
err = kthread_stop_put(tsk);
+ KUNIT_EXPECT_EQ(test, err, 0);
err:
fence_chains_fini(&fc);
- return err;
}
-static int wait_backward(void *arg)
+static void test_wait_backward(struct kunit *test)
{
struct fence_chains fc;
struct task_struct *tsk;
@@ -603,12 +570,11 @@ static int wait_backward(void *arg)
int i;
err = fence_chains_init(&fc, CHAIN_SZ, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
tsk = kthread_run(__wait_fence_chains, &fc, "dmabuf/wait");
if (IS_ERR(tsk)) {
- err = PTR_ERR(tsk);
+ KUNIT_FAIL(test, "Failed to create kthread");
goto err;
}
get_task_struct(tsk);
@@ -618,10 +584,10 @@ static int wait_backward(void *arg)
dma_fence_signal(fc.fences[i]);
err = kthread_stop_put(tsk);
+ KUNIT_EXPECT_EQ(test, err, 0);
err:
fence_chains_fini(&fc);
- return err;
}
static void randomise_fences(struct fence_chains *fc)
@@ -640,7 +606,7 @@ static void randomise_fences(struct fence_chains *fc)
}
}
-static int wait_random(void *arg)
+static void test_wait_random(struct kunit *test)
{
struct fence_chains fc;
struct task_struct *tsk;
@@ -648,14 +614,13 @@ static int wait_random(void *arg)
int i;
err = fence_chains_init(&fc, CHAIN_SZ, seqno_inc);
- if (err)
- return err;
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "Failed to init fence chains");
randomise_fences(&fc);
tsk = kthread_run(__wait_fence_chains, &fc, "dmabuf/wait");
if (IS_ERR(tsk)) {
- err = PTR_ERR(tsk);
+ KUNIT_FAIL(test, "Failed to create kthread");
goto err;
}
get_task_struct(tsk);
@@ -665,29 +630,14 @@ static int wait_random(void *arg)
dma_fence_signal(fc.fences[i]);
err = kthread_stop_put(tsk);
+ KUNIT_EXPECT_EQ(test, err, 0);
err:
fence_chains_fini(&fc);
- return err;
}
-int dma_fence_chain(void)
+static int dma_fence_chain_suite_init(struct kunit_suite *suite)
{
- static const struct subtest tests[] = {
- SUBTEST(sanitycheck),
- SUBTEST(find_seqno),
- SUBTEST(find_signaled),
- SUBTEST(find_out_of_order),
- SUBTEST(find_gap),
- SUBTEST(find_race),
- SUBTEST(signal_forward),
- SUBTEST(signal_backward),
- SUBTEST(wait_forward),
- SUBTEST(wait_backward),
- SUBTEST(wait_random),
- };
- int ret;
-
pr_info("sizeof(dma_fence_chain)=%zu\n",
sizeof(struct dma_fence_chain));
@@ -696,9 +646,34 @@ int dma_fence_chain(void)
SLAB_HWCACHE_ALIGN);
if (!slab_fences)
return -ENOMEM;
-
- ret = subtests(tests, NULL);
-
- kmem_cache_destroy(slab_fences);
- return ret;
+ return 0;
}
+
+static void dma_fence_chain_suite_exit(struct kunit_suite *suite)
+{
+ kmem_cache_destroy(slab_fences);
+}
+
+static struct kunit_case dma_fence_chain_cases[] = {
+ KUNIT_CASE(test_sanitycheck),
+ KUNIT_CASE(test_find_seqno),
+ KUNIT_CASE(test_find_signaled),
+ KUNIT_CASE(test_find_out_of_order),
+ KUNIT_CASE(test_find_gap),
+ KUNIT_CASE(test_find_race),
+ KUNIT_CASE(test_signal_forward),
+ KUNIT_CASE(test_signal_backward),
+ KUNIT_CASE(test_wait_forward),
+ KUNIT_CASE(test_wait_backward),
+ KUNIT_CASE(test_wait_random),
+ {}
+};
+
+static struct kunit_suite dma_fence_chain_test_suite = {
+ .name = "dma-buf-fence-chain",
+ .suite_init = dma_fence_chain_suite_init,
+ .suite_exit = dma_fence_chain_suite_exit,
+ .test_cases = dma_fence_chain_cases,
+};
+
+kunit_test_suite(dma_fence_chain_test_suite);
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 5/5] dma-buf: Remove the old selftest
2026-03-01 18:57 [PATCH 0/5] Replace the dmabuf custom test framework with kunit Jason Gunthorpe
` (3 preceding siblings ...)
2026-03-01 18:57 ` [PATCH 4/5] dma-buf: Change st-dma-fence-chain.c " Jason Gunthorpe
@ 2026-03-01 18:57 ` Jason Gunthorpe
2026-03-02 11:43 ` [PATCH 0/5] Replace the dmabuf custom test framework with kunit Christian König
5 siblings, 0 replies; 9+ messages in thread
From: Jason Gunthorpe @ 2026-03-01 18:57 UTC (permalink / raw)
To: David Airlie, Christian König, dri-devel, intel-gfx,
Jani Nikula, Joonas Lahtinen, linaro-mm-sig, linux-media,
Rodrigo Vivi, Simona Vetter, Sumit Semwal, Tvrtko Ursulin
Cc: patches
Nothing uses this framework anymore, remove it.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/dma-buf/Kconfig | 5 -
drivers/dma-buf/Makefile | 5 -
drivers/dma-buf/selftest.c | 167 -----------------------------
drivers/dma-buf/selftest.h | 30 ------
drivers/dma-buf/selftests.h | 12 ---
drivers/gpu/drm/i915/Kconfig.debug | 2 +-
6 files changed, 1 insertion(+), 220 deletions(-)
delete mode 100644 drivers/dma-buf/selftest.c
delete mode 100644 drivers/dma-buf/selftest.h
delete mode 100644 drivers/dma-buf/selftests.h
diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig
index 7d13c8f4484dd3..7efc0f0d07126c 100644
--- a/drivers/dma-buf/Kconfig
+++ b/drivers/dma-buf/Kconfig
@@ -49,11 +49,6 @@ config DMABUF_DEBUG
exporters. Specifically it validates that importers do not peek at the
underlying struct page when they import a buffer.
-config DMABUF_SELFTESTS
- tristate "Selftests for the dma-buf interfaces"
- default n
- depends on DMA_SHARED_BUFFER
-
config DMABUF_KUNIT_TEST
tristate "KUnit tests for DMA-BUF" if !KUNIT_ALL_TESTS
depends on KUNIT
diff --git a/drivers/dma-buf/Makefile b/drivers/dma-buf/Makefile
index c97ab2d01a7e68..b25d7550bacfd5 100644
--- a/drivers/dma-buf/Makefile
+++ b/drivers/dma-buf/Makefile
@@ -7,11 +7,6 @@ obj-$(CONFIG_SYNC_FILE) += sync_file.o
obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
obj-$(CONFIG_UDMABUF) += udmabuf.o
-dmabuf_selftests-y := \
- selftest.o
-
-obj-$(CONFIG_DMABUF_SELFTESTS) += dmabuf_selftests.o
-
dmabuf_kunit-y := \
st-dma-fence.o \
st-dma-fence-chain.o \
diff --git a/drivers/dma-buf/selftest.c b/drivers/dma-buf/selftest.c
deleted file mode 100644
index c60b6944b4bd18..00000000000000
--- a/drivers/dma-buf/selftest.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#include <linux/compiler.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched/signal.h>
-#include <linux/slab.h>
-
-#include "selftest.h"
-
-enum {
-#define selftest(n, func) __idx_##n,
-#include "selftests.h"
-#undef selftest
-};
-
-#define selftest(n, f) [__idx_##n] = { .name = #n, .func = f },
-static struct selftest {
- bool enabled;
- const char *name;
- int (*func)(void);
-} selftests[] = {
-#include "selftests.h"
-};
-#undef selftest
-
-/* Embed the line number into the parameter name so that we can order tests */
-#define param(n) __PASTE(igt__, __PASTE(__PASTE(__LINE__, __), n))
-#define selftest_0(n, func, id) \
-module_param_named(id, selftests[__idx_##n].enabled, bool, 0400);
-#define selftest(n, func) selftest_0(n, func, param(n))
-#include "selftests.h"
-#undef selftest
-
-int __sanitycheck__(void)
-{
- pr_debug("Hello World!\n");
- return 0;
-}
-
-static char *__st_filter;
-
-static bool apply_subtest_filter(const char *caller, const char *name)
-{
- char *filter, *sep, *tok;
- bool result = true;
-
- filter = kstrdup(__st_filter, GFP_KERNEL);
- for (sep = filter; (tok = strsep(&sep, ","));) {
- bool allow = true;
- char *sl;
-
- if (*tok == '!') {
- allow = false;
- tok++;
- }
-
- if (*tok == '\0')
- continue;
-
- sl = strchr(tok, '/');
- if (sl) {
- *sl++ = '\0';
- if (strcmp(tok, caller)) {
- if (allow)
- result = false;
- continue;
- }
- tok = sl;
- }
-
- if (strcmp(tok, name)) {
- if (allow)
- result = false;
- continue;
- }
-
- result = allow;
- break;
- }
- kfree(filter);
-
- return result;
-}
-
-int
-__subtests(const char *caller, const struct subtest *st, int count, void *data)
-{
- int err;
-
- for (; count--; st++) {
- cond_resched();
- if (signal_pending(current))
- return -EINTR;
-
- if (!apply_subtest_filter(caller, st->name))
- continue;
-
- pr_info("dma-buf: Running %s/%s\n", caller, st->name);
-
- err = st->func(data);
- if (err && err != -EINTR) {
- pr_err("dma-buf/%s: %s failed with error %d\n",
- caller, st->name, err);
- return err;
- }
- }
-
- return 0;
-}
-
-static void set_default_test_all(struct selftest *st, unsigned long count)
-{
- unsigned long i;
-
- for (i = 0; i < count; i++)
- if (st[i].enabled)
- return;
-
- for (i = 0; i < count; i++)
- st[i].enabled = true;
-}
-
-static int run_selftests(struct selftest *st, unsigned long count)
-{
- int err = 0;
-
- set_default_test_all(st, count);
-
- /* Tests are listed in natural order in selftests.h */
- for (; count--; st++) {
- if (!st->enabled)
- continue;
-
- pr_info("dma-buf: Running %s\n", st->name);
- err = st->func();
- if (err)
- break;
- }
-
- if (WARN(err > 0 || err == -ENOTTY,
- "%s returned %d, conflicting with selftest's magic values!\n",
- st->name, err))
- err = -1;
-
- return err;
-}
-
-static int __init st_init(void)
-{
- return run_selftests(selftests, ARRAY_SIZE(selftests));
-}
-
-static void __exit st_exit(void)
-{
-}
-
-module_param_named(st_filter, __st_filter, charp, 0400);
-module_init(st_init);
-module_exit(st_exit);
-
-MODULE_DESCRIPTION("Self-test harness for dma-buf");
-MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/dma-buf/selftest.h b/drivers/dma-buf/selftest.h
deleted file mode 100644
index 45793aff61425a..00000000000000
--- a/drivers/dma-buf/selftest.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// SPDX-License-Identifier: MIT
-
-/*
- * Copyright © 2019 Intel Corporation
- */
-
-#ifndef __SELFTEST_H__
-#define __SELFTEST_H__
-
-#include <linux/compiler.h>
-
-#define selftest(name, func) int func(void);
-#include "selftests.h"
-#undef selftest
-
-struct subtest {
- int (*func)(void *data);
- const char *name;
-};
-
-int __subtests(const char *caller,
- const struct subtest *st,
- int count,
- void *data);
-#define subtests(T, data) \
- __subtests(__func__, T, ARRAY_SIZE(T), data)
-
-#define SUBTEST(x) { x, #x }
-
-#endif /* __SELFTEST_H__ */
diff --git a/drivers/dma-buf/selftests.h b/drivers/dma-buf/selftests.h
deleted file mode 100644
index 37b7251841278e..00000000000000
--- a/drivers/dma-buf/selftests.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-/* List each unit test as selftest(name, function)
- *
- * The name is used as both an enum and expanded as subtest__name to create
- * a module parameter. It must be unique and legal for a C identifier.
- *
- * The function should be of type int function(void). It may be conditionally
- * compiled using #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST).
- *
- * Tests are executed in order by igt/dmabuf_selftest
- */
-selftest(sanitycheck, __sanitycheck__) /* keep first (igt selfcheck) */
diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug
index 3562a02ef7adca..52a3a59b4ba2c3 100644
--- a/drivers/gpu/drm/i915/Kconfig.debug
+++ b/drivers/gpu/drm/i915/Kconfig.debug
@@ -51,7 +51,7 @@ config DRM_I915_DEBUG
select DRM_DEBUG_MM if DRM=y
select DRM_EXPORT_FOR_TESTS if m
select DRM_KUNIT_TEST if KUNIT
- select DMABUF_SELFTESTS
+ select DMABUF_KUNIT_TEST if KUNIT
select SW_SYNC # signaling validation framework (igt/syncobj*)
select DRM_I915_WERROR
select DRM_I915_DEBUG_GEM
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 0/5] Replace the dmabuf custom test framework with kunit
2026-03-01 18:57 [PATCH 0/5] Replace the dmabuf custom test framework with kunit Jason Gunthorpe
` (4 preceding siblings ...)
2026-03-01 18:57 ` [PATCH 5/5] dma-buf: Remove the old selftest Jason Gunthorpe
@ 2026-03-02 11:43 ` Christian König
2026-03-02 13:01 ` Jason Gunthorpe
5 siblings, 1 reply; 9+ messages in thread
From: Christian König @ 2026-03-02 11:43 UTC (permalink / raw)
To: Jason Gunthorpe, David Airlie, dri-devel, intel-gfx, Jani Nikula,
Joonas Lahtinen, linaro-mm-sig, linux-media, Rodrigo Vivi,
Simona Vetter, Sumit Semwal, Tvrtko Ursulin
Cc: patches
On 3/1/26 19:57, Jason Gunthorpe wrote:
> Using kunit to write tests for new work on dmabuf is coming up:
>
> https://lore.kernel.org/all/26-v1-b5cab63049c0+191af-dmabuf_map_type_jgg@nvidia.com/
>
> Replace the custom test framework with kunit to avoid maintaining two
> concurrent test frameworks.
Oh, yes that was on my todo list for like an eternity as well.
No idea when or even if I have time to review that, but feel free to add my Acked-by should that go upstream.
Regards,
Christian.
>
> The conversion minimizes code changes and uses simple pattern-oriented
> reworks to reduce the chance of breaking any tests. Aside from adding the
> kunit_test_suite() boilerplate, the conversion follows a number of
> patterns:
>
> Test failures without cleanup. For example:
> if (!ptr)
> return -ENOMEM;
> Becomes:
> KUNIT_ASSERT_NOT_NULL(test, ptr);
>
> In kunit ASSERT longjumps out of the test.
>
> Check for error, fail and cleanup:
> if (err) {
> pr_err("msg\n");
> goto cleanup;
> }
> Becomes:
> if (err) {
> KUNIT_FAIL(test, "msg");
> goto cleanup;
> }
> Preserve the existing failure messages and cleanup code.
>
> Cases where the test returns err but prints no message:
> if (err)
> goto cleanup;
> Becomes:
> if (err) {
> KUNIT_FAIL(test, "msg");
> goto cleanup;
> }
> Use KUNIT_FAIL to retain the 'cleanup on err' behavior.
>
> Overall, the conversion is straightforward.
>
> The result can be run with kunit.py:
>
> $ tools/testing/kunit/kunit.py run --build_dir build_kunit_x86_64 --arch x86_64 --kunitconfig ./drivers/dma-buf/.kunitconfig
> [20:37:23] Configuring KUnit Kernel ...
> [20:37:23] Building KUnit Kernel ...
> Populating config with:
> $ make ARCH=x86_64 O=build_kunit_x86_64 olddefconfig
> Building with:
> $ make all compile_commands.json scripts_gdb ARCH=x86_64 O=build_kunit_x86_64 --jobs=20
> [20:37:29] Starting KUnit Kernel (1/1)...
> [20:37:29] ============================================================
> Running tests with:
> $ qemu-system-x86_64 -nodefaults -m 1024 -kernel build_kunit_x86_64/arch/x86/boot/bzImage -append 'kunit.enable=1 console=ttyS0 kunit_shutdown=reboot' -no-reboot -nographic -accel kvm -accel hvf -accel tcg -serial stdio -bios qboot.rom
> [20:37:30] ================ dma-buf-resv (5 subtests) =================
> [20:37:30] [PASSED] test_sanitycheck
> [20:37:30] ===================== test_signaling ======================
> [20:37:30] [PASSED] kernel
> [20:37:30] [PASSED] write
> [20:37:30] [PASSED] read
> [20:37:30] [PASSED] bookkeep
> [20:37:30] ================= [PASSED] test_signaling ==================
> ...
> [20:37:35] Testing complete. Ran 50 tests: passed: 49, skipped: 1
> [20:37:35] Elapsed time: 12.635s total, 0.001s configuring, 6.551s building, 6.017s running
>
> One test that requires two CPUs is skipped since the default VM has a
> single CPU and cannot run the test.
>
> All other usual ways to run kunit work as well, and all tests are placed
> in a module to provide more options for how they are run.
>
> AI was used to do the large scale semantic search and replaces described
> above, then everything was hand checked. AI also deduced the issue with
> test_race_signal_callback() in a couple of seconds from the kunit
> crash (!!), again was hand checked though I am not so familiar with this
> test to be fully certain this is the best answer.
>
> Jason Gunthorpe (5):
> dma-buf: Change st-dma-resv.c to use kunit
> dma-buf: Change st-dma-fence.c to use kunit
> dma-buf: Change st-dma-fence-unwrap.c to use kunit
> dma-buf: Change st-dma-fence-chain.c to use kunit
> dma-buf: Remove the old selftest
>
> drivers/dma-buf/.kunitconfig | 2 +
> drivers/dma-buf/Kconfig | 11 +-
> drivers/dma-buf/Makefile | 5 +-
> drivers/dma-buf/selftest.c | 167 ---------------
> drivers/dma-buf/selftest.h | 30 ---
> drivers/dma-buf/selftests.h | 16 --
> drivers/dma-buf/st-dma-fence-chain.c | 217 +++++++++----------
> drivers/dma-buf/st-dma-fence-unwrap.c | 290 +++++++++++---------------
> drivers/dma-buf/st-dma-fence.c | 200 ++++++++----------
> drivers/dma-buf/st-dma-resv.c | 145 +++++++------
> drivers/gpu/drm/i915/Kconfig.debug | 2 +-
> 11 files changed, 394 insertions(+), 691 deletions(-)
> create mode 100644 drivers/dma-buf/.kunitconfig
> delete mode 100644 drivers/dma-buf/selftest.c
> delete mode 100644 drivers/dma-buf/selftest.h
> delete mode 100644 drivers/dma-buf/selftests.h
>
>
> base-commit: 41dae5ac5e157b0bb260f381eb3df2f4a4610205
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH 0/5] Replace the dmabuf custom test framework with kunit
2026-03-02 11:43 ` [PATCH 0/5] Replace the dmabuf custom test framework with kunit Christian König
@ 2026-03-02 13:01 ` Jason Gunthorpe
2026-03-02 13:58 ` Christian König
0 siblings, 1 reply; 9+ messages in thread
From: Jason Gunthorpe @ 2026-03-02 13:01 UTC (permalink / raw)
To: Christian König
Cc: David Airlie, dri-devel, intel-gfx, Jani Nikula, Joonas Lahtinen,
linaro-mm-sig, linux-media, Rodrigo Vivi, Simona Vetter,
Sumit Semwal, Tvrtko Ursulin, patches
On Mon, Mar 02, 2026 at 12:43:34PM +0100, Christian König wrote:
> On 3/1/26 19:57, Jason Gunthorpe wrote:
> > Using kunit to write tests for new work on dmabuf is coming up:
> >
> > https://lore.kernel.org/all/26-v1-b5cab63049c0+191af-dmabuf_map_type_jgg@nvidia.com/
> >
> > Replace the custom test framework with kunit to avoid maintaining two
> > concurrent test frameworks.
>
> Oh, yes that was on my todo list for like an eternity as well.
>
> No idea when or even if I have time to review that, but feel free to
> add my Acked-by should that go upstream.
I'm confused by this statement, aren't you the person who would send
it upstream?
It is just a kunit, I wouldn't expect an intensive review. The tests
still run after all
Thanks,
Jason
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 0/5] Replace the dmabuf custom test framework with kunit
2026-03-02 13:01 ` Jason Gunthorpe
@ 2026-03-02 13:58 ` Christian König
0 siblings, 0 replies; 9+ messages in thread
From: Christian König @ 2026-03-02 13:58 UTC (permalink / raw)
To: Jason Gunthorpe
Cc: David Airlie, dri-devel, intel-gfx, Jani Nikula, Joonas Lahtinen,
linaro-mm-sig, linux-media, Rodrigo Vivi, Simona Vetter,
Sumit Semwal, Tvrtko Ursulin, patches
On 3/2/26 14:01, Jason Gunthorpe wrote:
> On Mon, Mar 02, 2026 at 12:43:34PM +0100, Christian König wrote:
>> On 3/1/26 19:57, Jason Gunthorpe wrote:
>>> Using kunit to write tests for new work on dmabuf is coming up:
>>>
>>> https://lore.kernel.org/all/26-v1-b5cab63049c0+191af-dmabuf_map_type_jgg@nvidia.com/
>>>
>>> Replace the custom test framework with kunit to avoid maintaining two
>>> concurrent test frameworks.
>>
>> Oh, yes that was on my todo list for like an eternity as well.
>>
>> No idea when or even if I have time to review that, but feel free to
>> add my Acked-by should that go upstream.
>
> I'm confused by this statement, aren't you the person who would send
> it upstream?
Sumit and me are the maintainers for DMA-buf, but the drm-misc-next/-fixes branches used to send DMA-buf patches upstream are used by much more people.
> It is just a kunit, I wouldn't expect an intensive review. The tests
> still run after all
When somebody else has time to take a look over those patches I think we can push them to drm-misc-next ASAP. I just wanted to note that I'm ok with that as maintainer and those patches doesn't need to be reviewed by me.
Regards,
Christian.
>
> Thanks,
> Jason
^ permalink raw reply [flat|nested] 9+ messages in thread