]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | ||
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 | 63 | static 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 | } | |
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 | ||
73511edf | 109 | static 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); | |
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 | ||
73511edf | 170 | static 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"); | |
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 | ||
73511edf | 244 | static 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); | |
286 | err_free: | |
1d51775c CK |
287 | while (i--) |
288 | dma_fence_put(fences[i]); | |
289 | kfree(fences); | |
55d5e4f9 | 290 | err_resv: |
1d51775c CK |
291 | dma_resv_fini(&resv); |
292 | dma_fence_put(f); | |
293 | return r; | |
294 | } | |
295 | ||
1d51775c CK |
296 | int 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 | } |