Merge branch 'signal-for-v5.17' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux.git] / drivers / dma-buf / st-dma-resv.c
1 /* SPDX-License-Identifier: MIT */
2
3 /*
4 * Copyright © 2019 Intel Corporation
5 * Copyright © 2021 Advanced Micro Devices, Inc.
6 */
7
8 #include <linux/slab.h>
9 #include <linux/spinlock.h>
10 #include <linux/dma-resv.h>
11
12 #include "selftest.h"
13
14 static struct spinlock fence_lock;
15
16 static const char *fence_name(struct dma_fence *f)
17 {
18         return "selftest";
19 }
20
21 static const struct dma_fence_ops fence_ops = {
22         .get_driver_name = fence_name,
23         .get_timeline_name = fence_name,
24 };
25
26 static struct dma_fence *alloc_fence(void)
27 {
28         struct dma_fence *f;
29
30         f = kmalloc(sizeof(*f), GFP_KERNEL);
31         if (!f)
32                 return NULL;
33
34         dma_fence_init(f, &fence_ops, &fence_lock, 0, 0);
35         return f;
36 }
37
38 static int sanitycheck(void *arg)
39 {
40         struct dma_resv resv;
41         struct dma_fence *f;
42         int r;
43
44         f = alloc_fence();
45         if (!f)
46                 return -ENOMEM;
47
48         dma_fence_signal(f);
49         dma_fence_put(f);
50
51         dma_resv_init(&resv);
52         r = dma_resv_lock(&resv, NULL);
53         if (r)
54                 pr_err("Resv locking failed\n");
55         else
56                 dma_resv_unlock(&resv);
57         dma_resv_fini(&resv);
58         return r;
59 }
60
61 static int test_signaling(void *arg, bool shared)
62 {
63         struct dma_resv resv;
64         struct dma_fence *f;
65         int r;
66
67         f = alloc_fence();
68         if (!f)
69                 return -ENOMEM;
70
71         dma_resv_init(&resv);
72         r = dma_resv_lock(&resv, NULL);
73         if (r) {
74                 pr_err("Resv locking failed\n");
75                 goto err_free;
76         }
77
78         if (shared) {
79                 r = dma_resv_reserve_shared(&resv, 1);
80                 if (r) {
81                         pr_err("Resv shared slot allocation failed\n");
82                         goto err_unlock;
83                 }
84
85                 dma_resv_add_shared_fence(&resv, f);
86         } else {
87                 dma_resv_add_excl_fence(&resv, f);
88         }
89
90         if (dma_resv_test_signaled(&resv, shared)) {
91                 pr_err("Resv unexpectedly signaled\n");
92                 r = -EINVAL;
93                 goto err_unlock;
94         }
95         dma_fence_signal(f);
96         if (!dma_resv_test_signaled(&resv, shared)) {
97                 pr_err("Resv not reporting signaled\n");
98                 r = -EINVAL;
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         return r;
107 }
108
109 static int test_excl_signaling(void *arg)
110 {
111         return test_signaling(arg, false);
112 }
113
114 static int test_shared_signaling(void *arg)
115 {
116         return test_signaling(arg, true);
117 }
118
119 static int test_for_each(void *arg, bool shared)
120 {
121         struct dma_resv_iter cursor;
122         struct dma_fence *f, *fence;
123         struct dma_resv resv;
124         int r;
125
126         f = alloc_fence();
127         if (!f)
128                 return -ENOMEM;
129
130         dma_resv_init(&resv);
131         r = dma_resv_lock(&resv, NULL);
132         if (r) {
133                 pr_err("Resv locking failed\n");
134                 goto err_free;
135         }
136
137         if (shared) {
138                 r = dma_resv_reserve_shared(&resv, 1);
139                 if (r) {
140                         pr_err("Resv shared slot allocation failed\n");
141                         goto err_unlock;
142                 }
143
144                 dma_resv_add_shared_fence(&resv, f);
145         } else {
146                 dma_resv_add_excl_fence(&resv, f);
147         }
148
149         r = -ENOENT;
150         dma_resv_for_each_fence(&cursor, &resv, shared, fence) {
151                 if (!r) {
152                         pr_err("More than one fence found\n");
153                         r = -EINVAL;
154                         goto err_unlock;
155                 }
156                 if (f != fence) {
157                         pr_err("Unexpected fence\n");
158                         r = -EINVAL;
159                         goto err_unlock;
160                 }
161                 if (dma_resv_iter_is_exclusive(&cursor) != !shared) {
162                         pr_err("Unexpected fence usage\n");
163                         r = -EINVAL;
164                         goto err_unlock;
165                 }
166                 r = 0;
167         }
168         if (r) {
169                 pr_err("No fence found\n");
170                 goto err_unlock;
171         }
172         dma_fence_signal(f);
173 err_unlock:
174         dma_resv_unlock(&resv);
175 err_free:
176         dma_resv_fini(&resv);
177         dma_fence_put(f);
178         return r;
179 }
180
181 static int test_excl_for_each(void *arg)
182 {
183         return test_for_each(arg, false);
184 }
185
186 static int test_shared_for_each(void *arg)
187 {
188         return test_for_each(arg, true);
189 }
190
191 static int test_for_each_unlocked(void *arg, bool shared)
192 {
193         struct dma_resv_iter cursor;
194         struct dma_fence *f, *fence;
195         struct dma_resv resv;
196         int r;
197
198         f = alloc_fence();
199         if (!f)
200                 return -ENOMEM;
201
202         dma_resv_init(&resv);
203         r = dma_resv_lock(&resv, NULL);
204         if (r) {
205                 pr_err("Resv locking failed\n");
206                 goto err_free;
207         }
208
209         if (shared) {
210                 r = dma_resv_reserve_shared(&resv, 1);
211                 if (r) {
212                         pr_err("Resv shared slot allocation failed\n");
213                         dma_resv_unlock(&resv);
214                         goto err_free;
215                 }
216
217                 dma_resv_add_shared_fence(&resv, f);
218         } else {
219                 dma_resv_add_excl_fence(&resv, f);
220         }
221         dma_resv_unlock(&resv);
222
223         r = -ENOENT;
224         dma_resv_iter_begin(&cursor, &resv, shared);
225         dma_resv_for_each_fence_unlocked(&cursor, fence) {
226                 if (!r) {
227                         pr_err("More than one fence found\n");
228                         r = -EINVAL;
229                         goto err_iter_end;
230                 }
231                 if (!dma_resv_iter_is_restarted(&cursor)) {
232                         pr_err("No restart flag\n");
233                         goto err_iter_end;
234                 }
235                 if (f != fence) {
236                         pr_err("Unexpected fence\n");
237                         r = -EINVAL;
238                         goto err_iter_end;
239                 }
240                 if (dma_resv_iter_is_exclusive(&cursor) != !shared) {
241                         pr_err("Unexpected fence usage\n");
242                         r = -EINVAL;
243                         goto err_iter_end;
244                 }
245
246                 /* We use r as state here */
247                 if (r == -ENOENT) {
248                         r = -EINVAL;
249                         /* That should trigger an restart */
250                         cursor.seq--;
251                 } else if (r == -EINVAL) {
252                         r = 0;
253                 }
254         }
255         if (r)
256                 pr_err("No fence found\n");
257 err_iter_end:
258         dma_resv_iter_end(&cursor);
259         dma_fence_signal(f);
260 err_free:
261         dma_resv_fini(&resv);
262         dma_fence_put(f);
263         return r;
264 }
265
266 static int test_excl_for_each_unlocked(void *arg)
267 {
268         return test_for_each_unlocked(arg, false);
269 }
270
271 static int test_shared_for_each_unlocked(void *arg)
272 {
273         return test_for_each_unlocked(arg, true);
274 }
275
276 static int test_get_fences(void *arg, bool shared)
277 {
278         struct dma_fence *f, *excl = NULL, **fences = NULL;
279         struct dma_resv resv;
280         int r, i;
281
282         f = alloc_fence();
283         if (!f)
284                 return -ENOMEM;
285
286         dma_resv_init(&resv);
287         r = dma_resv_lock(&resv, NULL);
288         if (r) {
289                 pr_err("Resv locking failed\n");
290                 goto err_resv;
291         }
292
293         if (shared) {
294                 r = dma_resv_reserve_shared(&resv, 1);
295                 if (r) {
296                         pr_err("Resv shared slot allocation failed\n");
297                         dma_resv_unlock(&resv);
298                         goto err_resv;
299                 }
300
301                 dma_resv_add_shared_fence(&resv, f);
302         } else {
303                 dma_resv_add_excl_fence(&resv, f);
304         }
305         dma_resv_unlock(&resv);
306
307         r = dma_resv_get_fences(&resv, &excl, &i, &fences);
308         if (r) {
309                 pr_err("get_fences failed\n");
310                 goto err_free;
311         }
312
313         if (shared) {
314                 if (excl != NULL) {
315                         pr_err("get_fences returned unexpected excl fence\n");
316                         goto err_free;
317                 }
318                 if (i != 1 || fences[0] != f) {
319                         pr_err("get_fences returned unexpected shared fence\n");
320                         goto err_free;
321                 }
322         } else {
323                 if (excl != f) {
324                         pr_err("get_fences returned unexpected excl fence\n");
325                         goto err_free;
326                 }
327                 if (i != 0) {
328                         pr_err("get_fences returned unexpected shared fence\n");
329                         goto err_free;
330                 }
331         }
332
333         dma_fence_signal(f);
334 err_free:
335         dma_fence_put(excl);
336         while (i--)
337                 dma_fence_put(fences[i]);
338         kfree(fences);
339 err_resv:
340         dma_resv_fini(&resv);
341         dma_fence_put(f);
342         return r;
343 }
344
345 static int test_excl_get_fences(void *arg)
346 {
347         return test_get_fences(arg, false);
348 }
349
350 static int test_shared_get_fences(void *arg)
351 {
352         return test_get_fences(arg, true);
353 }
354
355 int dma_resv(void)
356 {
357         static const struct subtest tests[] = {
358                 SUBTEST(sanitycheck),
359                 SUBTEST(test_excl_signaling),
360                 SUBTEST(test_shared_signaling),
361                 SUBTEST(test_excl_for_each),
362                 SUBTEST(test_shared_for_each),
363                 SUBTEST(test_excl_for_each_unlocked),
364                 SUBTEST(test_shared_for_each_unlocked),
365                 SUBTEST(test_excl_get_fences),
366                 SUBTEST(test_shared_get_fences),
367         };
368
369         spin_lock_init(&fence_lock);
370         return subtests(tests, NULL);
371 }