xref: /linux/drivers/dma-buf/st-dma-resv.c (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
1 /* SPDX-License-Identifier: MIT */
2 
3 /*
4 * Copyright © 2019 Intel Corporation
5 * Copyright © 2021 Advanced Micro Devices, Inc.
6 */
7 
8 #include <kunit/test.h>
9 #include <linux/slab.h>
10 #include <linux/spinlock.h>
11 #include <linux/dma-resv.h>
12 
13 static DEFINE_SPINLOCK(fence_lock);
14 
15 struct dma_resv_usage_param {
16 	enum dma_resv_usage usage;
17 	const char *desc;
18 };
19 
20 static const char *fence_name(struct dma_fence *f)
21 {
22 	return "selftest";
23 }
24 
25 static const struct dma_fence_ops fence_ops = {
26 	.get_driver_name = fence_name,
27 	.get_timeline_name = fence_name,
28 };
29 
30 static struct dma_fence *alloc_fence(void)
31 {
32 	struct dma_fence *f;
33 
34 	f = kmalloc_obj(*f);
35 	if (!f)
36 		return NULL;
37 
38 	dma_fence_init(f, &fence_ops, &fence_lock, 0, 0);
39 	return f;
40 }
41 
42 static void test_sanitycheck(struct kunit *test)
43 {
44 	struct dma_resv resv;
45 	struct dma_fence *f;
46 	int r;
47 
48 	f = alloc_fence();
49 	KUNIT_ASSERT_NOT_NULL(test, f);
50 
51 	dma_fence_enable_sw_signaling(f);
52 
53 	dma_fence_signal(f);
54 	dma_fence_put(f);
55 
56 	dma_resv_init(&resv);
57 	r = dma_resv_lock(&resv, NULL);
58 	if (r)
59 		KUNIT_FAIL(test, "Resv locking failed\n");
60 	else
61 		dma_resv_unlock(&resv);
62 	dma_resv_fini(&resv);
63 }
64 
65 static void test_signaling(struct kunit *test)
66 {
67 	const struct dma_resv_usage_param *param = test->param_value;
68 	enum dma_resv_usage usage = param->usage;
69 	struct dma_resv resv;
70 	struct dma_fence *f;
71 	int r;
72 
73 	f = alloc_fence();
74 	KUNIT_ASSERT_NOT_NULL(test, f);
75 
76 	dma_fence_enable_sw_signaling(f);
77 
78 	dma_resv_init(&resv);
79 	r = dma_resv_lock(&resv, NULL);
80 	if (r) {
81 		KUNIT_FAIL(test, "Resv locking failed");
82 		goto err_free;
83 	}
84 
85 	r = dma_resv_reserve_fences(&resv, 1);
86 	if (r) {
87 		KUNIT_FAIL(test, "Resv shared slot allocation failed");
88 		goto err_unlock;
89 	}
90 
91 	dma_resv_add_fence(&resv, f, usage);
92 	if (dma_resv_test_signaled(&resv, usage)) {
93 		KUNIT_FAIL(test, "Resv unexpectedly signaled");
94 		goto err_unlock;
95 	}
96 	dma_fence_signal(f);
97 	if (!dma_resv_test_signaled(&resv, usage)) {
98 		KUNIT_FAIL(test, "Resv not reporting signaled");
99 		goto err_unlock;
100 	}
101 err_unlock:
102 	dma_resv_unlock(&resv);
103 err_free:
104 	dma_resv_fini(&resv);
105 	dma_fence_put(f);
106 }
107 
108 static void test_for_each(struct kunit *test)
109 {
110 	const struct dma_resv_usage_param *param = test->param_value;
111 	enum dma_resv_usage usage = param->usage;
112 	struct dma_resv_iter cursor;
113 	struct dma_fence *f, *fence;
114 	struct dma_resv resv;
115 	int r;
116 
117 	f = alloc_fence();
118 	KUNIT_ASSERT_NOT_NULL(test, f);
119 
120 	dma_fence_enable_sw_signaling(f);
121 
122 	dma_resv_init(&resv);
123 	r = dma_resv_lock(&resv, NULL);
124 	if (r) {
125 		KUNIT_FAIL(test, "Resv locking failed");
126 		goto err_free;
127 	}
128 
129 	r = dma_resv_reserve_fences(&resv, 1);
130 	if (r) {
131 		KUNIT_FAIL(test, "Resv shared slot allocation failed");
132 		goto err_unlock;
133 	}
134 
135 	dma_resv_add_fence(&resv, f, usage);
136 
137 	r = -ENOENT;
138 	dma_resv_for_each_fence(&cursor, &resv, usage, fence) {
139 		if (!r) {
140 			KUNIT_FAIL(test, "More than one fence found");
141 			goto err_unlock;
142 		}
143 		if (f != fence) {
144 			KUNIT_FAIL(test, "Unexpected fence");
145 			r = -EINVAL;
146 			goto err_unlock;
147 		}
148 		if (dma_resv_iter_usage(&cursor) != usage) {
149 			KUNIT_FAIL(test, "Unexpected fence usage");
150 			r = -EINVAL;
151 			goto err_unlock;
152 		}
153 		r = 0;
154 	}
155 	if (r) {
156 		KUNIT_FAIL(test, "No fence found");
157 		goto err_unlock;
158 	}
159 	dma_fence_signal(f);
160 err_unlock:
161 	dma_resv_unlock(&resv);
162 err_free:
163 	dma_resv_fini(&resv);
164 	dma_fence_put(f);
165 }
166 
167 static void test_for_each_unlocked(struct kunit *test)
168 {
169 	const struct dma_resv_usage_param *param = test->param_value;
170 	enum dma_resv_usage usage = param->usage;
171 	struct dma_resv_iter cursor;
172 	struct dma_fence *f, *fence;
173 	struct dma_resv resv;
174 	int r;
175 
176 	f = alloc_fence();
177 	KUNIT_ASSERT_NOT_NULL(test, f);
178 
179 	dma_fence_enable_sw_signaling(f);
180 
181 	dma_resv_init(&resv);
182 	r = dma_resv_lock(&resv, NULL);
183 	if (r) {
184 		KUNIT_FAIL(test, "Resv locking failed");
185 		goto err_free;
186 	}
187 
188 	r = dma_resv_reserve_fences(&resv, 1);
189 	if (r) {
190 		KUNIT_FAIL(test, "Resv shared slot allocation failed");
191 		dma_resv_unlock(&resv);
192 		goto err_free;
193 	}
194 
195 	dma_resv_add_fence(&resv, f, usage);
196 	dma_resv_unlock(&resv);
197 
198 	r = -ENOENT;
199 	dma_resv_iter_begin(&cursor, &resv, usage);
200 	dma_resv_for_each_fence_unlocked(&cursor, fence) {
201 		if (!r) {
202 			KUNIT_FAIL(test, "More than one fence found");
203 			goto err_iter_end;
204 		}
205 		if (!dma_resv_iter_is_restarted(&cursor)) {
206 			KUNIT_FAIL(test, "No restart flag");
207 			goto err_iter_end;
208 		}
209 		if (f != fence) {
210 			KUNIT_FAIL(test, "Unexpected fence");
211 			r = -EINVAL;
212 			goto err_iter_end;
213 		}
214 		if (dma_resv_iter_usage(&cursor) != usage) {
215 			KUNIT_FAIL(test, "Unexpected fence usage");
216 			r = -EINVAL;
217 			goto err_iter_end;
218 		}
219 
220 		/* We use r as state here */
221 		if (r == -ENOENT) {
222 			r = -EINVAL;
223 			/* That should trigger an restart */
224 			cursor.fences = (void*)~0;
225 		} else if (r == -EINVAL) {
226 			r = 0;
227 		}
228 	}
229 	KUNIT_EXPECT_EQ(test, r, 0);
230 err_iter_end:
231 	dma_resv_iter_end(&cursor);
232 	dma_fence_signal(f);
233 err_free:
234 	dma_resv_fini(&resv);
235 	dma_fence_put(f);
236 }
237 
238 static void test_get_fences(struct kunit *test)
239 {
240 	const struct dma_resv_usage_param *param = test->param_value;
241 	enum dma_resv_usage usage = param->usage;
242 	struct dma_fence *f, **fences = NULL;
243 	struct dma_resv resv;
244 	int r, i;
245 
246 	f = alloc_fence();
247 	KUNIT_ASSERT_NOT_NULL(test, f);
248 
249 	dma_fence_enable_sw_signaling(f);
250 
251 	dma_resv_init(&resv);
252 	r = dma_resv_lock(&resv, NULL);
253 	if (r) {
254 		KUNIT_FAIL(test, "Resv locking failed");
255 		goto err_resv;
256 	}
257 
258 	r = dma_resv_reserve_fences(&resv, 1);
259 	if (r) {
260 		KUNIT_FAIL(test, "Resv shared slot allocation failed");
261 		dma_resv_unlock(&resv);
262 		goto err_resv;
263 	}
264 
265 	dma_resv_add_fence(&resv, f, usage);
266 	dma_resv_unlock(&resv);
267 
268 	r = dma_resv_get_fences(&resv, usage, &i, &fences);
269 	if (r) {
270 		KUNIT_FAIL(test, "get_fences failed");
271 		goto err_free;
272 	}
273 
274 	if (i != 1 || fences[0] != f) {
275 		KUNIT_FAIL(test, "get_fences returned unexpected fence");
276 		goto err_free;
277 	}
278 
279 	dma_fence_signal(f);
280 err_free:
281 	while (i--)
282 		dma_fence_put(fences[i]);
283 	kfree(fences);
284 err_resv:
285 	dma_resv_fini(&resv);
286 	dma_fence_put(f);
287 }
288 
289 static const struct dma_resv_usage_param dma_resv_usage_params[] = {
290 	{ DMA_RESV_USAGE_KERNEL, "kernel" },
291 	{ DMA_RESV_USAGE_WRITE, "write" },
292 	{ DMA_RESV_USAGE_READ, "read" },
293 	{ DMA_RESV_USAGE_BOOKKEEP, "bookkeep" },
294 };
295 
296 KUNIT_ARRAY_PARAM_DESC(dma_resv_usage, dma_resv_usage_params, desc);
297 
298 static struct kunit_case dma_resv_cases[] = {
299 	KUNIT_CASE(test_sanitycheck),
300 	KUNIT_CASE_PARAM(test_signaling, dma_resv_usage_gen_params),
301 	KUNIT_CASE_PARAM(test_for_each, dma_resv_usage_gen_params),
302 	KUNIT_CASE_PARAM(test_for_each_unlocked, dma_resv_usage_gen_params),
303 	KUNIT_CASE_PARAM(test_get_fences, dma_resv_usage_gen_params),
304 	{}
305 };
306 
307 static struct kunit_suite dma_resv_test_suite = {
308 	.name = "dma-buf-resv",
309 	.test_cases = dma_resv_cases,
310 };
311 
312 kunit_test_suite(dma_resv_test_suite);
313 
314 MODULE_DESCRIPTION("KUnit tests for DMA-BUF");
315 MODULE_LICENSE("GPL");
316