GNU Linux-libre 5.19-rc6-gnu
[releases.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)
62 {
63         enum dma_resv_usage usage = (unsigned long)arg;
64         struct dma_resv resv;
65         struct dma_fence *f;
66         int r;
67
68         f = alloc_fence();
69         if (!f)
70                 return -ENOMEM;
71
72         dma_resv_init(&resv);
73         r = dma_resv_lock(&resv, NULL);
74         if (r) {
75                 pr_err("Resv locking failed\n");
76                 goto err_free;
77         }
78
79         r = dma_resv_reserve_fences(&resv, 1);
80         if (r) {
81                 pr_err("Resv shared slot allocation failed\n");
82                 goto err_unlock;
83         }
84
85         dma_resv_add_fence(&resv, f, usage);
86         if (dma_resv_test_signaled(&resv, usage)) {
87                 pr_err("Resv unexpectedly signaled\n");
88                 r = -EINVAL;
89                 goto err_unlock;
90         }
91         dma_fence_signal(f);
92         if (!dma_resv_test_signaled(&resv, usage)) {
93                 pr_err("Resv not reporting signaled\n");
94                 r = -EINVAL;
95                 goto err_unlock;
96         }
97 err_unlock:
98         dma_resv_unlock(&resv);
99 err_free:
100         dma_resv_fini(&resv);
101         dma_fence_put(f);
102         return r;
103 }
104
105 static int test_for_each(void *arg)
106 {
107         enum dma_resv_usage usage = (unsigned long)arg;
108         struct dma_resv_iter cursor;
109         struct dma_fence *f, *fence;
110         struct dma_resv resv;
111         int r;
112
113         f = alloc_fence();
114         if (!f)
115                 return -ENOMEM;
116
117         dma_resv_init(&resv);
118         r = dma_resv_lock(&resv, NULL);
119         if (r) {
120                 pr_err("Resv locking failed\n");
121                 goto err_free;
122         }
123
124         r = dma_resv_reserve_fences(&resv, 1);
125         if (r) {
126                 pr_err("Resv shared slot allocation failed\n");
127                 goto err_unlock;
128         }
129
130         dma_resv_add_fence(&resv, f, usage);
131
132         r = -ENOENT;
133         dma_resv_for_each_fence(&cursor, &resv, usage, fence) {
134                 if (!r) {
135                         pr_err("More than one fence found\n");
136                         r = -EINVAL;
137                         goto err_unlock;
138                 }
139                 if (f != fence) {
140                         pr_err("Unexpected fence\n");
141                         r = -EINVAL;
142                         goto err_unlock;
143                 }
144                 if (dma_resv_iter_usage(&cursor) != usage) {
145                         pr_err("Unexpected fence usage\n");
146                         r = -EINVAL;
147                         goto err_unlock;
148                 }
149                 r = 0;
150         }
151         if (r) {
152                 pr_err("No fence found\n");
153                 goto err_unlock;
154         }
155         dma_fence_signal(f);
156 err_unlock:
157         dma_resv_unlock(&resv);
158 err_free:
159         dma_resv_fini(&resv);
160         dma_fence_put(f);
161         return r;
162 }
163
164 static int test_for_each_unlocked(void *arg)
165 {
166         enum dma_resv_usage usage = (unsigned long)arg;
167         struct dma_resv_iter cursor;
168         struct dma_fence *f, *fence;
169         struct dma_resv resv;
170         int r;
171
172         f = alloc_fence();
173         if (!f)
174                 return -ENOMEM;
175
176         dma_resv_init(&resv);
177         r = dma_resv_lock(&resv, NULL);
178         if (r) {
179                 pr_err("Resv locking failed\n");
180                 goto err_free;
181         }
182
183         r = dma_resv_reserve_fences(&resv, 1);
184         if (r) {
185                 pr_err("Resv shared slot allocation failed\n");
186                 dma_resv_unlock(&resv);
187                 goto err_free;
188         }
189
190         dma_resv_add_fence(&resv, f, usage);
191         dma_resv_unlock(&resv);
192
193         r = -ENOENT;
194         dma_resv_iter_begin(&cursor, &resv, usage);
195         dma_resv_for_each_fence_unlocked(&cursor, fence) {
196                 if (!r) {
197                         pr_err("More than one fence found\n");
198                         r = -EINVAL;
199                         goto err_iter_end;
200                 }
201                 if (!dma_resv_iter_is_restarted(&cursor)) {
202                         pr_err("No restart flag\n");
203                         goto err_iter_end;
204                 }
205                 if (f != fence) {
206                         pr_err("Unexpected fence\n");
207                         r = -EINVAL;
208                         goto err_iter_end;
209                 }
210                 if (dma_resv_iter_usage(&cursor) != usage) {
211                         pr_err("Unexpected fence usage\n");
212                         r = -EINVAL;
213                         goto err_iter_end;
214                 }
215
216                 /* We use r as state here */
217                 if (r == -ENOENT) {
218                         r = -EINVAL;
219                         /* That should trigger an restart */
220                         cursor.fences = (void*)~0;
221                 } else if (r == -EINVAL) {
222                         r = 0;
223                 }
224         }
225         if (r)
226                 pr_err("No fence found\n");
227 err_iter_end:
228         dma_resv_iter_end(&cursor);
229         dma_fence_signal(f);
230 err_free:
231         dma_resv_fini(&resv);
232         dma_fence_put(f);
233         return r;
234 }
235
236 static int test_get_fences(void *arg)
237 {
238         enum dma_resv_usage usage = (unsigned long)arg;
239         struct dma_fence *f, **fences = NULL;
240         struct dma_resv resv;
241         int r, i;
242
243         f = alloc_fence();
244         if (!f)
245                 return -ENOMEM;
246
247         dma_resv_init(&resv);
248         r = dma_resv_lock(&resv, NULL);
249         if (r) {
250                 pr_err("Resv locking failed\n");
251                 goto err_resv;
252         }
253
254         r = dma_resv_reserve_fences(&resv, 1);
255         if (r) {
256                 pr_err("Resv shared slot allocation failed\n");
257                 dma_resv_unlock(&resv);
258                 goto err_resv;
259         }
260
261         dma_resv_add_fence(&resv, f, usage);
262         dma_resv_unlock(&resv);
263
264         r = dma_resv_get_fences(&resv, usage, &i, &fences);
265         if (r) {
266                 pr_err("get_fences failed\n");
267                 goto err_free;
268         }
269
270         if (i != 1 || fences[0] != f) {
271                 pr_err("get_fences returned unexpected fence\n");
272                 goto err_free;
273         }
274
275         dma_fence_signal(f);
276 err_free:
277         while (i--)
278                 dma_fence_put(fences[i]);
279         kfree(fences);
280 err_resv:
281         dma_resv_fini(&resv);
282         dma_fence_put(f);
283         return r;
284 }
285
286 int dma_resv(void)
287 {
288         static const struct subtest tests[] = {
289                 SUBTEST(sanitycheck),
290                 SUBTEST(test_signaling),
291                 SUBTEST(test_for_each),
292                 SUBTEST(test_for_each_unlocked),
293                 SUBTEST(test_get_fences),
294         };
295         enum dma_resv_usage usage;
296         int r;
297
298         spin_lock_init(&fence_lock);
299         for (usage = DMA_RESV_USAGE_KERNEL; usage <= DMA_RESV_USAGE_BOOKKEEP;
300              ++usage) {
301                 r = subtests(tests, (void *)(unsigned long)usage);
302                 if (r)
303                         return r;
304         }
305         return 0;
306 }