Merge tag 'unmap-fix-20230629' of git://git.infradead.org/users/dwmw2/linux
[linux-block.git] / drivers / dma-buf / st-dma-resv.c
CommitLineData
1d51775c
CK
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
14static struct spinlock fence_lock;
15
16static const char *fence_name(struct dma_fence *f)
17{
18 return "selftest";
19}
20
21static const struct dma_fence_ops fence_ops = {
22 .get_driver_name = fence_name,
23 .get_timeline_name = fence_name,
24};
25
26static 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
38static 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
d62c43a9
AY
48 dma_fence_enable_sw_signaling(f);
49
1d51775c
CK
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
73511edf 63static int test_signaling(void *arg)
1d51775c 64{
73511edf 65 enum dma_resv_usage usage = (unsigned long)arg;
1d51775c
CK
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
d62c43a9
AY
74 dma_fence_enable_sw_signaling(f);
75
1d51775c
CK
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
c8d4c18b
CK
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 }
1d51775c 88
73511edf 89 dma_resv_add_fence(&resv, f, usage);
7bc80a54 90 if (dma_resv_test_signaled(&resv, usage)) {
1d51775c
CK
91 pr_err("Resv unexpectedly signaled\n");
92 r = -EINVAL;
93 goto err_unlock;
94 }
95 dma_fence_signal(f);
7bc80a54 96 if (!dma_resv_test_signaled(&resv, usage)) {
1d51775c
CK
97 pr_err("Resv not reporting signaled\n");
98 r = -EINVAL;
99 goto err_unlock;
100 }
101err_unlock:
102 dma_resv_unlock(&resv);
103err_free:
104 dma_resv_fini(&resv);
105 dma_fence_put(f);
106 return r;
107}
108
73511edf 109static int test_for_each(void *arg)
1d51775c 110{
73511edf 111 enum dma_resv_usage usage = (unsigned long)arg;
1d51775c
CK
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
d62c43a9
AY
121 dma_fence_enable_sw_signaling(f);
122
1d51775c
CK
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
c8d4c18b
CK
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 }
1d51775c 135
73511edf 136 dma_resv_add_fence(&resv, f, usage);
1d51775c
CK
137
138 r = -ENOENT;
7bc80a54 139 dma_resv_for_each_fence(&cursor, &resv, usage, fence) {
1d51775c
CK
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 }
73511edf 150 if (dma_resv_iter_usage(&cursor) != usage) {
1d51775c
CK
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);
162err_unlock:
163 dma_resv_unlock(&resv);
164err_free:
165 dma_resv_fini(&resv);
166 dma_fence_put(f);
167 return r;
168}
169
73511edf 170static int test_for_each_unlocked(void *arg)
1d51775c 171{
73511edf 172 enum dma_resv_usage usage = (unsigned long)arg;
1d51775c
CK
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
d62c43a9
AY
182 dma_fence_enable_sw_signaling(f);
183
1d51775c
CK
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
c8d4c18b
CK
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 }
1d51775c 197
73511edf 198 dma_resv_add_fence(&resv, f, usage);
1d51775c
CK
199 dma_resv_unlock(&resv);
200
201 r = -ENOENT;
7bc80a54 202 dma_resv_iter_begin(&cursor, &resv, usage);
1d51775c
CK
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 }
73511edf 218 if (dma_resv_iter_usage(&cursor) != usage) {
1d51775c
CK
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 */
8f94eda3 228 cursor.fences = (void*)~0;
1d51775c
CK
229 } else if (r == -EINVAL) {
230 r = 0;
231 }
232 }
233 if (r)
234 pr_err("No fence found\n");
235err_iter_end:
236 dma_resv_iter_end(&cursor);
237 dma_fence_signal(f);
238err_free:
239 dma_resv_fini(&resv);
240 dma_fence_put(f);
241 return r;
242}
243
73511edf 244static int test_get_fences(void *arg)
1d51775c 245{
73511edf 246 enum dma_resv_usage usage = (unsigned long)arg;
75ab2b36 247 struct dma_fence *f, **fences = NULL;
1d51775c
CK
248 struct dma_resv resv;
249 int r, i;
250
251 f = alloc_fence();
252 if (!f)
253 return -ENOMEM;
254
d62c43a9
AY
255 dma_fence_enable_sw_signaling(f);
256
1d51775c
CK
257 dma_resv_init(&resv);
258 r = dma_resv_lock(&resv, NULL);
259 if (r) {
260 pr_err("Resv locking failed\n");
55d5e4f9 261 goto err_resv;
1d51775c
CK
262 }
263
c8d4c18b
CK
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 }
1d51775c 270
73511edf 271 dma_resv_add_fence(&resv, f, usage);
1d51775c
CK
272 dma_resv_unlock(&resv);
273
7bc80a54 274 r = dma_resv_get_fences(&resv, usage, &i, &fences);
1d51775c
CK
275 if (r) {
276 pr_err("get_fences failed\n");
277 goto err_free;
278 }
279
75ab2b36
CK
280 if (i != 1 || fences[0] != f) {
281 pr_err("get_fences returned unexpected fence\n");
282 goto err_free;
1d51775c
CK
283 }
284
285 dma_fence_signal(f);
286err_free:
1d51775c
CK
287 while (i--)
288 dma_fence_put(fences[i]);
289 kfree(fences);
55d5e4f9 290err_resv:
1d51775c
CK
291 dma_resv_fini(&resv);
292 dma_fence_put(f);
293 return r;
294}
295
1d51775c
CK
296int dma_resv(void)
297{
298 static const struct subtest tests[] = {
299 SUBTEST(sanitycheck),
73511edf
CK
300 SUBTEST(test_signaling),
301 SUBTEST(test_for_each),
302 SUBTEST(test_for_each_unlocked),
303 SUBTEST(test_get_fences),
1d51775c 304 };
73511edf
CK
305 enum dma_resv_usage usage;
306 int r;
1d51775c
CK
307
308 spin_lock_init(&fence_lock);
0cc848a7 309 for (usage = DMA_RESV_USAGE_KERNEL; usage <= DMA_RESV_USAGE_BOOKKEEP;
73511edf
CK
310 ++usage) {
311 r = subtests(tests, (void *)(unsigned long)usage);
312 if (r)
313 return r;
314 }
315 return 0;
1d51775c 316}