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 | |
21 | struct drm_exec_priv { |
22 | struct device *dev; |
23 | struct drm_device *drm; |
24 | }; |
25 | |
26 | static int drm_exec_test_init(struct kunit *test) |
27 | { |
28 | struct drm_exec_priv *priv; |
29 | |
30 | priv = kunit_kzalloc(test, size: 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, dev: priv->dev, size: sizeof(*priv->drm), offset: 0, |
39 | features: DRIVER_MODESET); |
40 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm); |
41 | |
42 | return 0; |
43 | } |
44 | |
45 | static void sanitycheck(struct kunit *test) |
46 | { |
47 | struct drm_exec exec; |
48 | |
49 | drm_exec_init(exec: &exec, DRM_EXEC_INTERRUPTIBLE_WAIT); |
50 | drm_exec_fini(exec: &exec); |
51 | KUNIT_SUCCEED(test); |
52 | } |
53 | |
54 | static 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(dev: priv->drm, obj: &gobj, PAGE_SIZE); |
62 | |
63 | drm_exec_init(exec: &exec, DRM_EXEC_INTERRUPTIBLE_WAIT); |
64 | drm_exec_until_all_locked(&exec) { |
65 | ret = drm_exec_lock_obj(exec: &exec, obj: &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: &exec); |
72 | } |
73 | |
74 | static 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(dev: priv->drm, obj: &gobj, PAGE_SIZE); |
82 | |
83 | drm_exec_init(exec: &exec, DRM_EXEC_INTERRUPTIBLE_WAIT); |
84 | drm_exec_until_all_locked(&exec) { |
85 | ret = drm_exec_lock_obj(exec: &exec, obj: &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: &exec, obj: &gobj); |
92 | ret = drm_exec_lock_obj(exec: &exec, obj: &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: &exec); |
99 | } |
100 | |
101 | static 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(dev: priv->drm, obj: &gobj, PAGE_SIZE); |
109 | |
110 | drm_exec_init(exec: &exec, DRM_EXEC_IGNORE_DUPLICATES); |
111 | drm_exec_until_all_locked(&exec) { |
112 | ret = drm_exec_lock_obj(exec: &exec, obj: &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: &exec, obj: &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: &exec, obj: &gobj); |
125 | drm_exec_fini(exec: &exec); |
126 | } |
127 | |
128 | static 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(dev: priv->drm, obj: &gobj, PAGE_SIZE); |
136 | |
137 | drm_exec_init(exec: &exec, DRM_EXEC_INTERRUPTIBLE_WAIT); |
138 | drm_exec_until_all_locked(&exec) { |
139 | ret = drm_exec_prepare_obj(exec: &exec, obj: &gobj, num_fences: 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: &exec); |
146 | |
147 | drm_gem_private_object_fini(obj: &gobj); |
148 | } |
149 | |
150 | static 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(dev: priv->drm, obj: &gobj1, PAGE_SIZE); |
160 | drm_gem_private_object_init(dev: priv->drm, obj: &gobj2, PAGE_SIZE); |
161 | |
162 | drm_exec_init(exec: &exec, DRM_EXEC_INTERRUPTIBLE_WAIT); |
163 | drm_exec_until_all_locked(&exec) |
164 | ret = drm_exec_prepare_array(exec: &exec, objects: array, ARRAY_SIZE(array), |
165 | num_fences: 1); |
166 | KUNIT_EXPECT_EQ(test, ret, 0); |
167 | drm_exec_fini(exec: &exec); |
168 | |
169 | drm_gem_private_object_fini(obj: &gobj1); |
170 | drm_gem_private_object_fini(obj: &gobj2); |
171 | } |
172 | |
173 | static void test_multiple_loops(struct kunit *test) |
174 | { |
175 | struct drm_exec exec; |
176 | |
177 | drm_exec_init(exec: &exec, DRM_EXEC_INTERRUPTIBLE_WAIT); |
178 | drm_exec_until_all_locked(&exec) |
179 | { |
180 | break; |
181 | } |
182 | drm_exec_fini(exec: &exec); |
183 | |
184 | drm_exec_init(exec: &exec, DRM_EXEC_INTERRUPTIBLE_WAIT); |
185 | drm_exec_until_all_locked(&exec) |
186 | { |
187 | break; |
188 | } |
189 | drm_exec_fini(exec: &exec); |
190 | KUNIT_SUCCEED(test); |
191 | } |
192 | |
193 | static 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 | |
204 | static 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 | |
210 | kunit_test_suite(drm_exec_test_suite); |
211 | |
212 | MODULE_AUTHOR("AMD" ); |
213 | MODULE_LICENSE("GPL and additional rights" ); |
214 | |