Linux 6.9-rc1
[linux-2.6-microblaze.git] / drivers / dma-buf / st-dma-fence-unwrap.c
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         dma_fence_enable_sw_signaling(f);
106
107         array = mock_array(1, f);
108         if (!array)
109                 return -ENOMEM;
110
111         chain = mock_chain(NULL, array);
112         if (!chain)
113                 return -ENOMEM;
114
115         dma_fence_put(chain);
116         return err;
117 }
118
119 static int unwrap_array(void *arg)
120 {
121         struct dma_fence *fence, *f1, *f2, *array;
122         struct dma_fence_unwrap iter;
123         int err = 0;
124
125         f1 = mock_fence();
126         if (!f1)
127                 return -ENOMEM;
128
129         dma_fence_enable_sw_signaling(f1);
130
131         f2 = mock_fence();
132         if (!f2) {
133                 dma_fence_put(f1);
134                 return -ENOMEM;
135         }
136
137         dma_fence_enable_sw_signaling(f2);
138
139         array = mock_array(2, f1, f2);
140         if (!array)
141                 return -ENOMEM;
142
143         dma_fence_unwrap_for_each(fence, &iter, array) {
144                 if (fence == f1) {
145                         f1 = NULL;
146                 } else if (fence == f2) {
147                         f2 = NULL;
148                 } else {
149                         pr_err("Unexpected fence!\n");
150                         err = -EINVAL;
151                 }
152         }
153
154         if (f1 || f2) {
155                 pr_err("Not all fences seen!\n");
156                 err = -EINVAL;
157         }
158
159         dma_fence_put(array);
160         return err;
161 }
162
163 static int unwrap_chain(void *arg)
164 {
165         struct dma_fence *fence, *f1, *f2, *chain;
166         struct dma_fence_unwrap iter;
167         int err = 0;
168
169         f1 = mock_fence();
170         if (!f1)
171                 return -ENOMEM;
172
173         dma_fence_enable_sw_signaling(f1);
174
175         f2 = mock_fence();
176         if (!f2) {
177                 dma_fence_put(f1);
178                 return -ENOMEM;
179         }
180
181         dma_fence_enable_sw_signaling(f2);
182
183         chain = mock_chain(f1, f2);
184         if (!chain)
185                 return -ENOMEM;
186
187         dma_fence_unwrap_for_each(fence, &iter, chain) {
188                 if (fence == f1) {
189                         f1 = NULL;
190                 } else if (fence == f2) {
191                         f2 = NULL;
192                 } else {
193                         pr_err("Unexpected fence!\n");
194                         err = -EINVAL;
195                 }
196         }
197
198         if (f1 || f2) {
199                 pr_err("Not all fences seen!\n");
200                 err = -EINVAL;
201         }
202
203         dma_fence_put(chain);
204         return err;
205 }
206
207 static int unwrap_chain_array(void *arg)
208 {
209         struct dma_fence *fence, *f1, *f2, *array, *chain;
210         struct dma_fence_unwrap iter;
211         int err = 0;
212
213         f1 = mock_fence();
214         if (!f1)
215                 return -ENOMEM;
216
217         dma_fence_enable_sw_signaling(f1);
218
219         f2 = mock_fence();
220         if (!f2) {
221                 dma_fence_put(f1);
222                 return -ENOMEM;
223         }
224
225         dma_fence_enable_sw_signaling(f2);
226
227         array = mock_array(2, f1, f2);
228         if (!array)
229                 return -ENOMEM;
230
231         chain = mock_chain(NULL, array);
232         if (!chain)
233                 return -ENOMEM;
234
235         dma_fence_unwrap_for_each(fence, &iter, chain) {
236                 if (fence == f1) {
237                         f1 = NULL;
238                 } else if (fence == f2) {
239                         f2 = NULL;
240                 } else {
241                         pr_err("Unexpected fence!\n");
242                         err = -EINVAL;
243                 }
244         }
245
246         if (f1 || f2) {
247                 pr_err("Not all fences seen!\n");
248                 err = -EINVAL;
249         }
250
251         dma_fence_put(chain);
252         return err;
253 }
254
255 static int unwrap_merge(void *arg)
256 {
257         struct dma_fence *fence, *f1, *f2, *f3;
258         struct dma_fence_unwrap iter;
259         int err = 0;
260
261         f1 = mock_fence();
262         if (!f1)
263                 return -ENOMEM;
264
265         dma_fence_enable_sw_signaling(f1);
266
267         f2 = mock_fence();
268         if (!f2) {
269                 err = -ENOMEM;
270                 goto error_put_f1;
271         }
272
273         dma_fence_enable_sw_signaling(f2);
274
275         f3 = dma_fence_unwrap_merge(f1, f2);
276         if (!f3) {
277                 err = -ENOMEM;
278                 goto error_put_f2;
279         }
280
281         dma_fence_unwrap_for_each(fence, &iter, f3) {
282                 if (fence == f1) {
283                         dma_fence_put(f1);
284                         f1 = NULL;
285                 } else if (fence == f2) {
286                         dma_fence_put(f2);
287                         f2 = NULL;
288                 } else {
289                         pr_err("Unexpected fence!\n");
290                         err = -EINVAL;
291                 }
292         }
293
294         if (f1 || f2) {
295                 pr_err("Not all fences seen!\n");
296                 err = -EINVAL;
297         }
298
299         dma_fence_put(f3);
300 error_put_f2:
301         dma_fence_put(f2);
302 error_put_f1:
303         dma_fence_put(f1);
304         return err;
305 }
306
307 static int unwrap_merge_complex(void *arg)
308 {
309         struct dma_fence *fence, *f1, *f2, *f3, *f4, *f5;
310         struct dma_fence_unwrap iter;
311         int err = -ENOMEM;
312
313         f1 = mock_fence();
314         if (!f1)
315                 return -ENOMEM;
316
317         dma_fence_enable_sw_signaling(f1);
318
319         f2 = mock_fence();
320         if (!f2)
321                 goto error_put_f1;
322
323         dma_fence_enable_sw_signaling(f2);
324
325         f3 = dma_fence_unwrap_merge(f1, f2);
326         if (!f3)
327                 goto error_put_f2;
328
329         /* The resulting array has the fences in reverse */
330         f4 = dma_fence_unwrap_merge(f2, f1);
331         if (!f4)
332                 goto error_put_f3;
333
334         /* Signaled fences should be filtered, the two arrays merged. */
335         f5 = dma_fence_unwrap_merge(f3, f4, dma_fence_get_stub());
336         if (!f5)
337                 goto error_put_f4;
338
339         err = 0;
340         dma_fence_unwrap_for_each(fence, &iter, f5) {
341                 if (fence == f1) {
342                         dma_fence_put(f1);
343                         f1 = NULL;
344                 } else if (fence == f2) {
345                         dma_fence_put(f2);
346                         f2 = NULL;
347                 } else {
348                         pr_err("Unexpected fence!\n");
349                         err = -EINVAL;
350                 }
351         }
352
353         if (f1 || f2) {
354                 pr_err("Not all fences seen!\n");
355                 err = -EINVAL;
356         }
357
358         dma_fence_put(f5);
359 error_put_f4:
360         dma_fence_put(f4);
361 error_put_f3:
362         dma_fence_put(f3);
363 error_put_f2:
364         dma_fence_put(f2);
365 error_put_f1:
366         dma_fence_put(f1);
367         return err;
368 }
369
370 int dma_fence_unwrap(void)
371 {
372         static const struct subtest tests[] = {
373                 SUBTEST(sanitycheck),
374                 SUBTEST(unwrap_array),
375                 SUBTEST(unwrap_chain),
376                 SUBTEST(unwrap_chain_array),
377                 SUBTEST(unwrap_merge),
378                 SUBTEST(unwrap_merge_complex),
379         };
380
381         return subtests(tests, NULL);
382 }