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