1// SPDX-License-Identifier: MIT
2/*
3 * Copyright 2022 Advanced Micro Devices, Inc.
4 */
5
6#define pr_fmt(fmt) "drm_exec: " fmt
7
8#include <kunit/test.h>
9
10#include <linux/module.h>
11#include <linux/prime_numbers.h>
12
13#include <drm/drm_exec.h>
14#include <drm/drm_device.h>
15#include <drm/drm_drv.h>
16#include <drm/drm_gem.h>
17#include <drm/drm_kunit_helpers.h>
18
19#include "../lib/drm_random.h"
20
21struct drm_exec_priv {
22	struct device *dev;
23	struct drm_device *drm;
24};
25
26static int drm_exec_test_init(struct kunit *test)
27{
28	struct drm_exec_priv *priv;
29
30	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
31	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
32
33	test->priv = priv;
34
35	priv->dev = drm_kunit_helper_alloc_device(test);
36	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
37
38	priv->drm = __drm_kunit_helper_alloc_drm_device(test, priv->dev, sizeof(*priv->drm), 0,
39							DRIVER_MODESET);
40	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
41
42	return 0;
43}
44
45static void sanitycheck(struct kunit *test)
46{
47	struct drm_exec exec;
48
49	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
50	drm_exec_fini(&exec);
51	KUNIT_SUCCEED(test);
52}
53
54static void test_lock(struct kunit *test)
55{
56	struct drm_exec_priv *priv = test->priv;
57	struct drm_gem_object gobj = { };
58	struct drm_exec exec;
59	int ret;
60
61	drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE);
62
63	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
64	drm_exec_until_all_locked(&exec) {
65		ret = drm_exec_lock_obj(&exec, &gobj);
66		drm_exec_retry_on_contention(&exec);
67		KUNIT_EXPECT_EQ(test, ret, 0);
68		if (ret)
69			break;
70	}
71	drm_exec_fini(&exec);
72}
73
74static void test_lock_unlock(struct kunit *test)
75{
76	struct drm_exec_priv *priv = test->priv;
77	struct drm_gem_object gobj = { };
78	struct drm_exec exec;
79	int ret;
80
81	drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE);
82
83	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
84	drm_exec_until_all_locked(&exec) {
85		ret = drm_exec_lock_obj(&exec, &gobj);
86		drm_exec_retry_on_contention(&exec);
87		KUNIT_EXPECT_EQ(test, ret, 0);
88		if (ret)
89			break;
90
91		drm_exec_unlock_obj(&exec, &gobj);
92		ret = drm_exec_lock_obj(&exec, &gobj);
93		drm_exec_retry_on_contention(&exec);
94		KUNIT_EXPECT_EQ(test, ret, 0);
95		if (ret)
96			break;
97	}
98	drm_exec_fini(&exec);
99}
100
101static void test_duplicates(struct kunit *test)
102{
103	struct drm_exec_priv *priv = test->priv;
104	struct drm_gem_object gobj = { };
105	struct drm_exec exec;
106	int ret;
107
108	drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE);
109
110	drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES);
111	drm_exec_until_all_locked(&exec) {
112		ret = drm_exec_lock_obj(&exec, &gobj);
113		drm_exec_retry_on_contention(&exec);
114		KUNIT_EXPECT_EQ(test, ret, 0);
115		if (ret)
116			break;
117
118		ret = drm_exec_lock_obj(&exec, &gobj);
119		drm_exec_retry_on_contention(&exec);
120		KUNIT_EXPECT_EQ(test, ret, 0);
121		if (ret)
122			break;
123	}
124	drm_exec_unlock_obj(&exec, &gobj);
125	drm_exec_fini(&exec);
126}
127
128static void test_prepare(struct kunit *test)
129{
130	struct drm_exec_priv *priv = test->priv;
131	struct drm_gem_object gobj = { };
132	struct drm_exec exec;
133	int ret;
134
135	drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE);
136
137	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
138	drm_exec_until_all_locked(&exec) {
139		ret = drm_exec_prepare_obj(&exec, &gobj, 1);
140		drm_exec_retry_on_contention(&exec);
141		KUNIT_EXPECT_EQ(test, ret, 0);
142		if (ret)
143			break;
144	}
145	drm_exec_fini(&exec);
146
147	drm_gem_private_object_fini(&gobj);
148}
149
150static void test_prepare_array(struct kunit *test)
151{
152	struct drm_exec_priv *priv = test->priv;
153	struct drm_gem_object gobj1 = { };
154	struct drm_gem_object gobj2 = { };
155	struct drm_gem_object *array[] = { &gobj1, &gobj2 };
156	struct drm_exec exec;
157	int ret;
158
159	drm_gem_private_object_init(priv->drm, &gobj1, PAGE_SIZE);
160	drm_gem_private_object_init(priv->drm, &gobj2, PAGE_SIZE);
161
162	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
163	drm_exec_until_all_locked(&exec)
164		ret = drm_exec_prepare_array(&exec, array, ARRAY_SIZE(array),
165					     1);
166	KUNIT_EXPECT_EQ(test, ret, 0);
167	drm_exec_fini(&exec);
168
169	drm_gem_private_object_fini(&gobj1);
170	drm_gem_private_object_fini(&gobj2);
171}
172
173static void test_multiple_loops(struct kunit *test)
174{
175	struct drm_exec exec;
176
177	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
178	drm_exec_until_all_locked(&exec)
179	{
180		break;
181	}
182	drm_exec_fini(&exec);
183
184	drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
185	drm_exec_until_all_locked(&exec)
186	{
187		break;
188	}
189	drm_exec_fini(&exec);
190	KUNIT_SUCCEED(test);
191}
192
193static struct kunit_case drm_exec_tests[] = {
194	KUNIT_CASE(sanitycheck),
195	KUNIT_CASE(test_lock),
196	KUNIT_CASE(test_lock_unlock),
197	KUNIT_CASE(test_duplicates),
198	KUNIT_CASE(test_prepare),
199	KUNIT_CASE(test_prepare_array),
200	KUNIT_CASE(test_multiple_loops),
201	{}
202};
203
204static struct kunit_suite drm_exec_test_suite = {
205	.name = "drm_exec",
206	.init = drm_exec_test_init,
207	.test_cases = drm_exec_tests,
208};
209
210kunit_test_suite(drm_exec_test_suite);
211
212MODULE_AUTHOR("AMD");
213MODULE_LICENSE("GPL and additional rights");
214