1 // SPDX-License-Identifier: MIT
2 
3 /*
4  * Copyright (C) 2022 Advanced Micro Devices, Inc.
5  */
6 
7 #include <linux/dma-fence.h>
8 #include <linux/dma-fence-array.h>
9 #include <linux/dma-fence-chain.h>
10 #include <linux/dma-fence-unwrap.h>
11 
12 #include "selftest.h"
13 
14 #define CHAIN_SZ (4 << 10)
15 
16 struct mock_fence {
17 	struct dma_fence base;
18 	spinlock_t lock;
19 };
20 
21 static const char *mock_name(struct dma_fence *f)
22 {
23 	return "mock";
24 }
25 
26 static const struct dma_fence_ops mock_ops = {
27 	.get_driver_name = mock_name,
28 	.get_timeline_name = mock_name,
29 };
30 
31 static struct dma_fence *mock_fence(void)
32 {
33 	struct mock_fence *f;
34 
35 	f = kmalloc(sizeof(*f), GFP_KERNEL);
36 	if (!f)
37 		return NULL;
38 
39 	spin_lock_init(&f->lock);
40 	dma_fence_init(&f->base, &mock_ops, &f->lock,
41 		       dma_fence_context_alloc(1), 1);
42 
43 	return &f->base;
44 }
45 
46 static struct dma_fence *mock_array(unsigned int num_fences, ...)
47 {
48 	struct dma_fence_array *array;
49 	struct dma_fence **fences;
50 	va_list valist;
51 	int i;
52 
53 	fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
54 	if (!fences)
55 		goto error_put;
56 
57 	va_start(valist, num_fences);
58 	for (i = 0; i < num_fences; ++i)
59 		fences[i] = va_arg(valist, typeof(*fences));
60 	va_end(valist);
61 
62 	array = dma_fence_array_create(num_fences, fences,
63 				       dma_fence_context_alloc(1),
64 				       1, false);
65 	if (!array)
66 		goto error_free;
67 	return &array->base;
68 
69 error_free:
70 	kfree(fences);
71 
72 error_put:
73 	va_start(valist, num_fences);
74 	for (i = 0; i < num_fences; ++i)
75 		dma_fence_put(va_arg(valist, typeof(*fences)));
76 	va_end(valist);
77 	return NULL;
78 }
79 
80 static struct dma_fence *mock_chain(struct dma_fence *prev,
81 				    struct dma_fence *fence)
82 {
83 	struct dma_fence_chain *f;
84 
85 	f = dma_fence_chain_alloc();
86 	if (!f) {
87 		dma_fence_put(prev);
88 		dma_fence_put(fence);
89 		return NULL;
90 	}
91 
92 	dma_fence_chain_init(f, prev, fence, 1);
93 	return &f->base;
94 }
95 
96 static int sanitycheck(void *arg)
97 {
98 	struct dma_fence *f, *chain, *array;
99 	int err = 0;
100 
101 	f = mock_fence();
102 	if (!f)
103 		return -ENOMEM;
104 
105 	array = mock_array(1, f);
106 	if (!array)
107 		return -ENOMEM;
108 
109 	chain = mock_chain(NULL, array);
110 	if (!chain)
111 		return -ENOMEM;
112 
113 	dma_fence_put(chain);
114 	return err;
115 }
116 
117 static int unwrap_array(void *arg)
118 {
119 	struct dma_fence *fence, *f1, *f2, *array;
120 	struct dma_fence_unwrap iter;
121 	int err = 0;
122 
123 	f1 = mock_fence();
124 	if (!f1)
125 		return -ENOMEM;
126 
127 	f2 = mock_fence();
128 	if (!f2) {
129 		dma_fence_put(f1);
130 		return -ENOMEM;
131 	}
132 
133 	array = mock_array(2, f1, f2);
134 	if (!array)
135 		return -ENOMEM;
136 
137 	dma_fence_unwrap_for_each(fence, &iter, array) {
138 		if (fence == f1) {
139 			f1 = NULL;
140 		} else if (fence == f2) {
141 			f2 = NULL;
142 		} else {
143 			pr_err("Unexpected fence!\n");
144 			err = -EINVAL;
145 		}
146 	}
147 
148 	if (f1 || f2) {
149 		pr_err("Not all fences seen!\n");
150 		err = -EINVAL;
151 	}
152 
153 	dma_fence_put(array);
154 	return err;
155 }
156 
157 static int unwrap_chain(void *arg)
158 {
159 	struct dma_fence *fence, *f1, *f2, *chain;
160 	struct dma_fence_unwrap iter;
161 	int err = 0;
162 
163 	f1 = mock_fence();
164 	if (!f1)
165 		return -ENOMEM;
166 
167 	f2 = mock_fence();
168 	if (!f2) {
169 		dma_fence_put(f1);
170 		return -ENOMEM;
171 	}
172 
173 	chain = mock_chain(f1, f2);
174 	if (!chain)
175 		return -ENOMEM;
176 
177 	dma_fence_unwrap_for_each(fence, &iter, chain) {
178 		if (fence == f1) {
179 			f1 = NULL;
180 		} else if (fence == f2) {
181 			f2 = NULL;
182 		} else {
183 			pr_err("Unexpected fence!\n");
184 			err = -EINVAL;
185 		}
186 	}
187 
188 	if (f1 || f2) {
189 		pr_err("Not all fences seen!\n");
190 		err = -EINVAL;
191 	}
192 
193 	dma_fence_put(chain);
194 	return err;
195 }
196 
197 static int unwrap_chain_array(void *arg)
198 {
199 	struct dma_fence *fence, *f1, *f2, *array, *chain;
200 	struct dma_fence_unwrap iter;
201 	int err = 0;
202 
203 	f1 = mock_fence();
204 	if (!f1)
205 		return -ENOMEM;
206 
207 	f2 = mock_fence();
208 	if (!f2) {
209 		dma_fence_put(f1);
210 		return -ENOMEM;
211 	}
212 
213 	array = mock_array(2, f1, f2);
214 	if (!array)
215 		return -ENOMEM;
216 
217 	chain = mock_chain(NULL, array);
218 	if (!chain)
219 		return -ENOMEM;
220 
221 	dma_fence_unwrap_for_each(fence, &iter, chain) {
222 		if (fence == f1) {
223 			f1 = NULL;
224 		} else if (fence == f2) {
225 			f2 = NULL;
226 		} else {
227 			pr_err("Unexpected fence!\n");
228 			err = -EINVAL;
229 		}
230 	}
231 
232 	if (f1 || f2) {
233 		pr_err("Not all fences seen!\n");
234 		err = -EINVAL;
235 	}
236 
237 	dma_fence_put(chain);
238 	return err;
239 }
240 
241 static int unwrap_merge(void *arg)
242 {
243 	struct dma_fence *fence, *f1, *f2, *f3;
244 	struct dma_fence_unwrap iter;
245 	int err = 0;
246 
247 	f1 = mock_fence();
248 	if (!f1)
249 		return -ENOMEM;
250 
251 	f2 = mock_fence();
252 	if (!f2) {
253 		err = -ENOMEM;
254 		goto error_put_f1;
255 	}
256 
257 	f3 = dma_fence_unwrap_merge(f1, f2);
258 	if (!f3) {
259 		err = -ENOMEM;
260 		goto error_put_f2;
261 	}
262 
263 	dma_fence_unwrap_for_each(fence, &iter, f3) {
264 		if (fence == f1) {
265 			dma_fence_put(f1);
266 			f1 = NULL;
267 		} else if (fence == f2) {
268 			dma_fence_put(f2);
269 			f2 = NULL;
270 		} else {
271 			pr_err("Unexpected fence!\n");
272 			err = -EINVAL;
273 		}
274 	}
275 
276 	if (f1 || f2) {
277 		pr_err("Not all fences seen!\n");
278 		err = -EINVAL;
279 	}
280 
281 	dma_fence_put(f3);
282 error_put_f2:
283 	dma_fence_put(f2);
284 error_put_f1:
285 	dma_fence_put(f1);
286 	return err;
287 }
288 
289 static int unwrap_merge_complex(void *arg)
290 {
291 	struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5;
292 	struct dma_fence_unwrap iter;
293 	int err = -ENOMEM;
294 
295 	f1 = mock_fence();
296 	if (!f1)
297 		return -ENOMEM;
298 
299 	f2 = mock_fence();
300 	if (!f2)
301 		goto error_put_f1;
302 
303 	f3 = dma_fence_unwrap_merge(f1, f2);
304 	if (!f3)
305 		goto error_put_f2;
306 
307 	/* The resulting array has the fences in reverse */
308 	f4 = dma_fence_unwrap_merge(f2, f1);
309 	if (!f4)
310 		goto error_put_f3;
311 
312 	/* Signaled fences should be filtered, the two arrays merged. */
313 	f5 = dma_fence_unwrap_merge(f3, f4, dma_fence_get_stub());
314 	if (!f5)
315 		goto error_put_f4;
316 
317 	err = 0;
318 	dma_fence_unwrap_for_each(fence, &iter, f5) {
319 		if (fence == f1) {
320 			dma_fence_put(f1);
321 			f1 = NULL;
322 		} else if (fence == f2) {
323 			dma_fence_put(f2);
324 			f2 = NULL;
325 		} else {
326 			pr_err("Unexpected fence!\n");
327 			err = -EINVAL;
328 		}
329 	}
330 
331 	if (f1 || f2) {
332 		pr_err("Not all fences seen!\n");
333 		err = -EINVAL;
334 	}
335 
336 	dma_fence_put(f5);
337 error_put_f4:
338 	dma_fence_put(f4);
339 error_put_f3:
340 	dma_fence_put(f3);
341 error_put_f2:
342 	dma_fence_put(f2);
343 error_put_f1:
344 	dma_fence_put(f1);
345 	return err;
346 }
347 
348 int dma_fence_unwrap(void)
349 {
350 	static const struct subtest tests[] = {
351 		SUBTEST(sanitycheck),
352 		SUBTEST(unwrap_array),
353 		SUBTEST(unwrap_chain),
354 		SUBTEST(unwrap_chain_array),
355 		SUBTEST(unwrap_merge),
356 		SUBTEST(unwrap_merge_complex),
357 	};
358 
359 	return subtests(tests, NULL);
360 }
361