Merge tag 'loongarch-5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuaca...
[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         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 }