public inbox for drm-ai-reviews@public-inbox.freedesktop.org
 help / color / mirror / Atom feed
From: Jason Gunthorpe <jgg@nvidia.com>
To: David Airlie <airlied@gmail.com>,
	Christian König <christian.koenig@amd.com>,
	dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org,
	Jani Nikula <jani.nikula@linux.intel.com>,
	Joonas Lahtinen <joonas.lahtinen@linux.intel.com>,
	linaro-mm-sig@lists.linaro.org, linux-media@vger.kernel.org,
	Rodrigo Vivi <rodrigo.vivi@intel.com>,
	Simona Vetter <simona@ffwll.ch>,
	Sumit Semwal <sumit.semwal@linaro.org>,
	Tvrtko Ursulin <tursulin@ursulin.net>
Cc: patches@lists.linux.dev
Subject: [PATCH 2/5] dma-buf: Change st-dma-fence.c to use kunit
Date: Sun,  1 Mar 2026 14:57:54 -0400	[thread overview]
Message-ID: <2-v1-0a349a394eff+14110-dmabuf_kunit_jgg@nvidia.com> (raw)
In-Reply-To: <0-v1-0a349a394eff+14110-dmabuf_kunit_jgg@nvidia.com>

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


  parent reply	other threads:[~2026-03-01 18:58 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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-03  3:50   ` Claude review: " Claude Code Review Bot
2026-03-01 18:57 ` Jason Gunthorpe [this message]
2026-03-03  3:50   ` Claude review: dma-buf: Change st-dma-fence.c " Claude Code Review Bot
2026-03-01 18:57 ` [PATCH 3/5] dma-buf: Change st-dma-fence-unwrap.c " Jason Gunthorpe
2026-03-03  3:50   ` Claude review: " Claude Code Review Bot
2026-03-01 18:57 ` [PATCH 4/5] dma-buf: Change st-dma-fence-chain.c " Jason Gunthorpe
2026-03-03  3:50   ` Claude review: " Claude Code Review Bot
2026-03-01 18:57 ` [PATCH 5/5] dma-buf: Remove the old selftest Jason Gunthorpe
2026-03-03  3:50   ` Claude review: " Claude Code Review Bot
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
2026-03-03  3:50 ` Claude review: " Claude Code Review Bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2-v1-0a349a394eff+14110-dmabuf_kunit_jgg@nvidia.com \
    --to=jgg@nvidia.com \
    --cc=airlied@gmail.com \
    --cc=christian.koenig@amd.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=jani.nikula@linux.intel.com \
    --cc=joonas.lahtinen@linux.intel.com \
    --cc=linaro-mm-sig@lists.linaro.org \
    --cc=linux-media@vger.kernel.org \
    --cc=patches@lists.linux.dev \
    --cc=rodrigo.vivi@intel.com \
    --cc=simona@ffwll.ch \
    --cc=sumit.semwal@linaro.org \
    --cc=tursulin@ursulin.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox