19710631cSChristian König // SPDX-License-Identifier: MIT
29710631cSChristian König /*
39710631cSChristian König  * Copyright 2022 Advanced Micro Devices, Inc.
49710631cSChristian König  */
59710631cSChristian König 
69710631cSChristian König #define pr_fmt(fmt) "drm_exec: " fmt
79710631cSChristian König 
89710631cSChristian König #include <kunit/test.h>
99710631cSChristian König 
109710631cSChristian König #include <linux/module.h>
119710631cSChristian König #include <linux/prime_numbers.h>
129710631cSChristian König 
139710631cSChristian König #include <drm/drm_exec.h>
149710631cSChristian König #include <drm/drm_device.h>
15*0f249678SArthur Grillo #include <drm/drm_drv.h>
169710631cSChristian König #include <drm/drm_gem.h>
17*0f249678SArthur Grillo #include <drm/drm_kunit_helpers.h>
189710631cSChristian König 
199710631cSChristian König #include "../lib/drm_random.h"
209710631cSChristian König 
21*0f249678SArthur Grillo struct drm_exec_priv {
22*0f249678SArthur Grillo 	struct device *dev;
23*0f249678SArthur Grillo 	struct drm_device *drm;
24*0f249678SArthur Grillo };
25*0f249678SArthur Grillo 
26*0f249678SArthur Grillo static int drm_exec_test_init(struct kunit *test)
27*0f249678SArthur Grillo {
28*0f249678SArthur Grillo 	struct drm_exec_priv *priv;
29*0f249678SArthur Grillo 
30*0f249678SArthur Grillo 	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
31*0f249678SArthur Grillo 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
32*0f249678SArthur Grillo 
33*0f249678SArthur Grillo 	test->priv = priv;
34*0f249678SArthur Grillo 
35*0f249678SArthur Grillo 	priv->dev = drm_kunit_helper_alloc_device(test);
36*0f249678SArthur Grillo 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
37*0f249678SArthur Grillo 
38*0f249678SArthur Grillo 	priv->drm = __drm_kunit_helper_alloc_drm_device(test, priv->dev, sizeof(*priv->drm), 0,
39*0f249678SArthur Grillo 							DRIVER_MODESET);
40*0f249678SArthur Grillo 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
41*0f249678SArthur Grillo 
42*0f249678SArthur Grillo 	return 0;
43*0f249678SArthur Grillo }
449710631cSChristian König 
459710631cSChristian König static void sanitycheck(struct kunit *test)
469710631cSChristian König {
479710631cSChristian König 	struct drm_exec exec;
489710631cSChristian König 
499710631cSChristian König 	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
509710631cSChristian König 	drm_exec_fini(&exec);
519710631cSChristian König 	KUNIT_SUCCEED(test);
529710631cSChristian König }
539710631cSChristian König 
549710631cSChristian König static void test_lock(struct kunit *test)
559710631cSChristian König {
56*0f249678SArthur Grillo 	struct drm_exec_priv *priv = test->priv;
579710631cSChristian König 	struct drm_gem_object gobj = { };
589710631cSChristian König 	struct drm_exec exec;
599710631cSChristian König 	int ret;
609710631cSChristian König 
61*0f249678SArthur Grillo 	drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE);
629710631cSChristian König 
639710631cSChristian König 	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
649710631cSChristian König 	drm_exec_until_all_locked(&exec) {
659710631cSChristian König 		ret = drm_exec_lock_obj(&exec, &gobj);
669710631cSChristian König 		drm_exec_retry_on_contention(&exec);
679710631cSChristian König 		KUNIT_EXPECT_EQ(test, ret, 0);
689710631cSChristian König 		if (ret)
699710631cSChristian König 			break;
709710631cSChristian König 	}
719710631cSChristian König 	drm_exec_fini(&exec);
729710631cSChristian König }
739710631cSChristian König 
749710631cSChristian König static void test_lock_unlock(struct kunit *test)
759710631cSChristian König {
76*0f249678SArthur Grillo 	struct drm_exec_priv *priv = test->priv;
779710631cSChristian König 	struct drm_gem_object gobj = { };
789710631cSChristian König 	struct drm_exec exec;
799710631cSChristian König 	int ret;
809710631cSChristian König 
81*0f249678SArthur Grillo 	drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE);
829710631cSChristian König 
839710631cSChristian König 	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
849710631cSChristian König 	drm_exec_until_all_locked(&exec) {
859710631cSChristian König 		ret = drm_exec_lock_obj(&exec, &gobj);
869710631cSChristian König 		drm_exec_retry_on_contention(&exec);
879710631cSChristian König 		KUNIT_EXPECT_EQ(test, ret, 0);
889710631cSChristian König 		if (ret)
899710631cSChristian König 			break;
909710631cSChristian König 
919710631cSChristian König 		drm_exec_unlock_obj(&exec, &gobj);
929710631cSChristian König 		ret = drm_exec_lock_obj(&exec, &gobj);
939710631cSChristian König 		drm_exec_retry_on_contention(&exec);
949710631cSChristian König 		KUNIT_EXPECT_EQ(test, ret, 0);
959710631cSChristian König 		if (ret)
969710631cSChristian König 			break;
979710631cSChristian König 	}
989710631cSChristian König 	drm_exec_fini(&exec);
999710631cSChristian König }
1009710631cSChristian König 
1019710631cSChristian König static void test_duplicates(struct kunit *test)
1029710631cSChristian König {
103*0f249678SArthur Grillo 	struct drm_exec_priv *priv = test->priv;
1049710631cSChristian König 	struct drm_gem_object gobj = { };
1059710631cSChristian König 	struct drm_exec exec;
1069710631cSChristian König 	int ret;
1079710631cSChristian König 
108*0f249678SArthur Grillo 	drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE);
1099710631cSChristian König 
1109710631cSChristian König 	drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES);
1119710631cSChristian König 	drm_exec_until_all_locked(&exec) {
1129710631cSChristian König 		ret = drm_exec_lock_obj(&exec, &gobj);
1139710631cSChristian König 		drm_exec_retry_on_contention(&exec);
1149710631cSChristian König 		KUNIT_EXPECT_EQ(test, ret, 0);
1159710631cSChristian König 		if (ret)
1169710631cSChristian König 			break;
1179710631cSChristian König 
1189710631cSChristian König 		ret = drm_exec_lock_obj(&exec, &gobj);
1199710631cSChristian König 		drm_exec_retry_on_contention(&exec);
1209710631cSChristian König 		KUNIT_EXPECT_EQ(test, ret, 0);
1219710631cSChristian König 		if (ret)
1229710631cSChristian König 			break;
1239710631cSChristian König 	}
1249710631cSChristian König 	drm_exec_unlock_obj(&exec, &gobj);
1259710631cSChristian König 	drm_exec_fini(&exec);
1269710631cSChristian König }
1279710631cSChristian König 
1289710631cSChristian König 
1299710631cSChristian König 
1309710631cSChristian König static void test_prepare(struct kunit *test)
1319710631cSChristian König {
132*0f249678SArthur Grillo 	struct drm_exec_priv *priv = test->priv;
1339710631cSChristian König 	struct drm_gem_object gobj = { };
1349710631cSChristian König 	struct drm_exec exec;
1359710631cSChristian König 	int ret;
1369710631cSChristian König 
137*0f249678SArthur Grillo 	drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE);
1389710631cSChristian König 
1399710631cSChristian König 	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
1409710631cSChristian König 	drm_exec_until_all_locked(&exec) {
1419710631cSChristian König 		ret = drm_exec_prepare_obj(&exec, &gobj, 1);
1429710631cSChristian König 		drm_exec_retry_on_contention(&exec);
1439710631cSChristian König 		KUNIT_EXPECT_EQ(test, ret, 0);
1449710631cSChristian König 		if (ret)
1459710631cSChristian König 			break;
1469710631cSChristian König 	}
1479710631cSChristian König 	drm_exec_fini(&exec);
1489710631cSChristian König }
1499710631cSChristian König 
1509710631cSChristian König static void test_prepare_array(struct kunit *test)
1519710631cSChristian König {
152*0f249678SArthur Grillo 	struct drm_exec_priv *priv = test->priv;
1539710631cSChristian König 	struct drm_gem_object gobj1 = { };
1549710631cSChristian König 	struct drm_gem_object gobj2 = { };
1559710631cSChristian König 	struct drm_gem_object *array[] = { &gobj1, &gobj2 };
1569710631cSChristian König 	struct drm_exec exec;
1579710631cSChristian König 	int ret;
1589710631cSChristian König 
159*0f249678SArthur Grillo 	drm_gem_private_object_init(priv->drm, &gobj1, PAGE_SIZE);
160*0f249678SArthur Grillo 	drm_gem_private_object_init(priv->drm, &gobj2, PAGE_SIZE);
1619710631cSChristian König 
1629710631cSChristian König 	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
1639710631cSChristian König 	drm_exec_until_all_locked(&exec)
1649710631cSChristian König 		ret = drm_exec_prepare_array(&exec, array, ARRAY_SIZE(array),
1659710631cSChristian König 					     1);
1669710631cSChristian König 	KUNIT_EXPECT_EQ(test, ret, 0);
1679710631cSChristian König 	drm_exec_fini(&exec);
1689710631cSChristian König }
1699710631cSChristian König 
1709710631cSChristian König static struct kunit_case drm_exec_tests[] = {
1719710631cSChristian König 	KUNIT_CASE(sanitycheck),
1729710631cSChristian König 	KUNIT_CASE(test_lock),
1739710631cSChristian König 	KUNIT_CASE(test_lock_unlock),
1749710631cSChristian König 	KUNIT_CASE(test_duplicates),
1759710631cSChristian König 	KUNIT_CASE(test_prepare),
1769710631cSChristian König 	KUNIT_CASE(test_prepare_array),
1779710631cSChristian König 	{}
1789710631cSChristian König };
1799710631cSChristian König 
1809710631cSChristian König static struct kunit_suite drm_exec_test_suite = {
1819710631cSChristian König 	.name = "drm_exec",
182*0f249678SArthur Grillo 	.init = drm_exec_test_init,
1839710631cSChristian König 	.test_cases = drm_exec_tests,
1849710631cSChristian König };
1859710631cSChristian König 
1869710631cSChristian König kunit_test_suite(drm_exec_test_suite);
1879710631cSChristian König 
1889710631cSChristian König MODULE_AUTHOR("AMD");
1899710631cSChristian König MODULE_LICENSE("GPL and additional rights");
190