162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2022 Advanced Micro Devices, Inc.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#define pr_fmt(fmt) "drm_exec: " fmt
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <kunit/test.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/prime_numbers.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <drm/drm_exec.h>
1462306a36Sopenharmony_ci#include <drm/drm_device.h>
1562306a36Sopenharmony_ci#include <drm/drm_drv.h>
1662306a36Sopenharmony_ci#include <drm/drm_gem.h>
1762306a36Sopenharmony_ci#include <drm/drm_kunit_helpers.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "../lib/drm_random.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistruct drm_exec_priv {
2262306a36Sopenharmony_ci	struct device *dev;
2362306a36Sopenharmony_ci	struct drm_device *drm;
2462306a36Sopenharmony_ci};
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic int drm_exec_test_init(struct kunit *test)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	struct drm_exec_priv *priv;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
3162306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	test->priv = priv;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	priv->dev = drm_kunit_helper_alloc_device(test);
3662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	priv->drm = __drm_kunit_helper_alloc_drm_device(test, priv->dev, sizeof(*priv->drm), 0,
3962306a36Sopenharmony_ci							DRIVER_MODESET);
4062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	return 0;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic void sanitycheck(struct kunit *test)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct drm_exec exec;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
5062306a36Sopenharmony_ci	drm_exec_fini(&exec);
5162306a36Sopenharmony_ci	KUNIT_SUCCEED(test);
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic void test_lock(struct kunit *test)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct drm_exec_priv *priv = test->priv;
5762306a36Sopenharmony_ci	struct drm_gem_object gobj = { };
5862306a36Sopenharmony_ci	struct drm_exec exec;
5962306a36Sopenharmony_ci	int ret;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
6462306a36Sopenharmony_ci	drm_exec_until_all_locked(&exec) {
6562306a36Sopenharmony_ci		ret = drm_exec_lock_obj(&exec, &gobj);
6662306a36Sopenharmony_ci		drm_exec_retry_on_contention(&exec);
6762306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, ret, 0);
6862306a36Sopenharmony_ci		if (ret)
6962306a36Sopenharmony_ci			break;
7062306a36Sopenharmony_ci	}
7162306a36Sopenharmony_ci	drm_exec_fini(&exec);
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic void test_lock_unlock(struct kunit *test)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	struct drm_exec_priv *priv = test->priv;
7762306a36Sopenharmony_ci	struct drm_gem_object gobj = { };
7862306a36Sopenharmony_ci	struct drm_exec exec;
7962306a36Sopenharmony_ci	int ret;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
8462306a36Sopenharmony_ci	drm_exec_until_all_locked(&exec) {
8562306a36Sopenharmony_ci		ret = drm_exec_lock_obj(&exec, &gobj);
8662306a36Sopenharmony_ci		drm_exec_retry_on_contention(&exec);
8762306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, ret, 0);
8862306a36Sopenharmony_ci		if (ret)
8962306a36Sopenharmony_ci			break;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci		drm_exec_unlock_obj(&exec, &gobj);
9262306a36Sopenharmony_ci		ret = drm_exec_lock_obj(&exec, &gobj);
9362306a36Sopenharmony_ci		drm_exec_retry_on_contention(&exec);
9462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, ret, 0);
9562306a36Sopenharmony_ci		if (ret)
9662306a36Sopenharmony_ci			break;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci	drm_exec_fini(&exec);
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic void test_duplicates(struct kunit *test)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	struct drm_exec_priv *priv = test->priv;
10462306a36Sopenharmony_ci	struct drm_gem_object gobj = { };
10562306a36Sopenharmony_ci	struct drm_exec exec;
10662306a36Sopenharmony_ci	int ret;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES);
11162306a36Sopenharmony_ci	drm_exec_until_all_locked(&exec) {
11262306a36Sopenharmony_ci		ret = drm_exec_lock_obj(&exec, &gobj);
11362306a36Sopenharmony_ci		drm_exec_retry_on_contention(&exec);
11462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, ret, 0);
11562306a36Sopenharmony_ci		if (ret)
11662306a36Sopenharmony_ci			break;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci		ret = drm_exec_lock_obj(&exec, &gobj);
11962306a36Sopenharmony_ci		drm_exec_retry_on_contention(&exec);
12062306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, ret, 0);
12162306a36Sopenharmony_ci		if (ret)
12262306a36Sopenharmony_ci			break;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci	drm_exec_unlock_obj(&exec, &gobj);
12562306a36Sopenharmony_ci	drm_exec_fini(&exec);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic void test_prepare(struct kunit *test)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct drm_exec_priv *priv = test->priv;
13162306a36Sopenharmony_ci	struct drm_gem_object gobj = { };
13262306a36Sopenharmony_ci	struct drm_exec exec;
13362306a36Sopenharmony_ci	int ret;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
13862306a36Sopenharmony_ci	drm_exec_until_all_locked(&exec) {
13962306a36Sopenharmony_ci		ret = drm_exec_prepare_obj(&exec, &gobj, 1);
14062306a36Sopenharmony_ci		drm_exec_retry_on_contention(&exec);
14162306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, ret, 0);
14262306a36Sopenharmony_ci		if (ret)
14362306a36Sopenharmony_ci			break;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci	drm_exec_fini(&exec);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	drm_gem_private_object_fini(&gobj);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void test_prepare_array(struct kunit *test)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct drm_exec_priv *priv = test->priv;
15362306a36Sopenharmony_ci	struct drm_gem_object gobj1 = { };
15462306a36Sopenharmony_ci	struct drm_gem_object gobj2 = { };
15562306a36Sopenharmony_ci	struct drm_gem_object *array[] = { &gobj1, &gobj2 };
15662306a36Sopenharmony_ci	struct drm_exec exec;
15762306a36Sopenharmony_ci	int ret;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	drm_gem_private_object_init(priv->drm, &gobj1, PAGE_SIZE);
16062306a36Sopenharmony_ci	drm_gem_private_object_init(priv->drm, &gobj2, PAGE_SIZE);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
16362306a36Sopenharmony_ci	drm_exec_until_all_locked(&exec)
16462306a36Sopenharmony_ci		ret = drm_exec_prepare_array(&exec, array, ARRAY_SIZE(array),
16562306a36Sopenharmony_ci					     1);
16662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, ret, 0);
16762306a36Sopenharmony_ci	drm_exec_fini(&exec);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	drm_gem_private_object_fini(&gobj1);
17062306a36Sopenharmony_ci	drm_gem_private_object_fini(&gobj2);
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic void test_multiple_loops(struct kunit *test)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	struct drm_exec exec;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
17862306a36Sopenharmony_ci	drm_exec_until_all_locked(&exec)
17962306a36Sopenharmony_ci	{
18062306a36Sopenharmony_ci		break;
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci	drm_exec_fini(&exec);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
18562306a36Sopenharmony_ci	drm_exec_until_all_locked(&exec)
18662306a36Sopenharmony_ci	{
18762306a36Sopenharmony_ci		break;
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci	drm_exec_fini(&exec);
19062306a36Sopenharmony_ci	KUNIT_SUCCEED(test);
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic struct kunit_case drm_exec_tests[] = {
19462306a36Sopenharmony_ci	KUNIT_CASE(sanitycheck),
19562306a36Sopenharmony_ci	KUNIT_CASE(test_lock),
19662306a36Sopenharmony_ci	KUNIT_CASE(test_lock_unlock),
19762306a36Sopenharmony_ci	KUNIT_CASE(test_duplicates),
19862306a36Sopenharmony_ci	KUNIT_CASE(test_prepare),
19962306a36Sopenharmony_ci	KUNIT_CASE(test_prepare_array),
20062306a36Sopenharmony_ci	KUNIT_CASE(test_multiple_loops),
20162306a36Sopenharmony_ci	{}
20262306a36Sopenharmony_ci};
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic struct kunit_suite drm_exec_test_suite = {
20562306a36Sopenharmony_ci	.name = "drm_exec",
20662306a36Sopenharmony_ci	.init = drm_exec_test_init,
20762306a36Sopenharmony_ci	.test_cases = drm_exec_tests,
20862306a36Sopenharmony_ci};
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cikunit_test_suite(drm_exec_test_suite);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ciMODULE_AUTHOR("AMD");
21362306a36Sopenharmony_ciMODULE_LICENSE("GPL and additional rights");
214