1 // SPDX-License-Identifier: MIT
2
3 /*
4 * Copyright (C) 2022 Advanced Micro Devices, Inc.
5 */
6
7 #include <linux/dma-fence-unwrap.h>
8 #if 0
9 #include <linux/kernel.h>
10 #include <linux/kthread.h>
11 #include <linux/mm.h>
12 #include <linux/sched/signal.h>
13 #include <linux/slab.h>
14 #include <linux/spinlock.h>
15 #include <linux/random.h>
16 #endif
17
18 #include "selftest.h"
19
20 #define CHAIN_SZ (4 << 10)
21
22 static inline struct mock_fence {
23 struct dma_fence base;
24 spinlock_t lock;
to_mock_fence(struct dma_fence * f)25 } *to_mock_fence(struct dma_fence *f) {
26 return container_of(f, struct mock_fence, base);
27 }
28
mock_name(struct dma_fence * f)29 static const char *mock_name(struct dma_fence *f)
30 {
31 return "mock";
32 }
33
34 static const struct dma_fence_ops mock_ops = {
35 .get_driver_name = mock_name,
36 .get_timeline_name = mock_name,
37 };
38
mock_fence(void)39 static struct dma_fence *mock_fence(void)
40 {
41 struct mock_fence *f;
42
43 f = kmalloc(sizeof(*f), GFP_KERNEL);
44 if (!f)
45 return NULL;
46
47 spin_lock_init(&f->lock);
48 dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
49
50 return &f->base;
51 }
52
mock_array(unsigned int num_fences,...)53 static struct dma_fence *mock_array(unsigned int num_fences, ...)
54 {
55 struct dma_fence_array *array;
56 struct dma_fence **fences;
57 va_list valist;
58 int i;
59
60 fences = kcalloc(num_fences, sizeof(*fences), GFP_KERNEL);
61 if (!fences)
62 return NULL;
63
64 va_start(valist, num_fences);
65 for (i = 0; i < num_fences; ++i)
66 fences[i] = va_arg(valist, typeof(*fences));
67 va_end(valist);
68
69 array = dma_fence_array_create(num_fences, fences,
70 dma_fence_context_alloc(1),
71 1, false);
72 if (!array)
73 goto cleanup;
74 return &array->base;
75
76 cleanup:
77 for (i = 0; i < num_fences; ++i)
78 dma_fence_put(fences[i]);
79 kfree(fences);
80 return NULL;
81 }
82
mock_chain(struct dma_fence * prev,struct dma_fence * fence)83 static struct dma_fence *mock_chain(struct dma_fence *prev,
84 struct dma_fence *fence)
85 {
86 struct dma_fence_chain *f;
87
88 f = dma_fence_chain_alloc();
89 if (!f) {
90 dma_fence_put(prev);
91 dma_fence_put(fence);
92 return NULL;
93 }
94
95 dma_fence_chain_init(f, prev, fence, 1);
96 return &f->base;
97 }
98
sanitycheck(void * arg)99 static int sanitycheck(void *arg)
100 {
101 struct dma_fence *f, *chain, *array;
102 int err = 0;
103
104 f = mock_fence();
105 if (!f)
106 return -ENOMEM;
107
108 array = mock_array(1, f);
109 if (!array)
110 return -ENOMEM;
111
112 chain = mock_chain(NULL, array);
113 if (!chain)
114 return -ENOMEM;
115
116 dma_fence_signal(f);
117 dma_fence_put(chain);
118 return err;
119 }
120
unwrap_array(void * arg)121 static int unwrap_array(void *arg)
122 {
123 struct dma_fence *fence, *f1, *f2, *array;
124 struct dma_fence_unwrap iter;
125 int err = 0;
126
127 f1 = mock_fence();
128 if (!f1)
129 return -ENOMEM;
130
131 f2 = mock_fence();
132 if (!f2) {
133 dma_fence_put(f1);
134 return -ENOMEM;
135 }
136
137 array = mock_array(2, f1, f2);
138 if (!array)
139 return -ENOMEM;
140
141 dma_fence_unwrap_for_each(fence, &iter, array) {
142 if (fence == f1) {
143 f1 = NULL;
144 } else if (fence == f2) {
145 f2 = NULL;
146 } else {
147 pr_err("Unexpected fence!\n");
148 err = -EINVAL;
149 }
150 }
151
152 if (f1 || f2) {
153 pr_err("Not all fences seen!\n");
154 err = -EINVAL;
155 }
156
157 dma_fence_signal(f1);
158 dma_fence_signal(f2);
159 dma_fence_put(array);
160 return 0;
161 }
162
unwrap_chain(void * arg)163 static int unwrap_chain(void *arg)
164 {
165 struct dma_fence *fence, *f1, *f2, *chain;
166 struct dma_fence_unwrap iter;
167 int err = 0;
168
169 f1 = mock_fence();
170 if (!f1)
171 return -ENOMEM;
172
173 f2 = mock_fence();
174 if (!f2) {
175 dma_fence_put(f1);
176 return -ENOMEM;
177 }
178
179 chain = mock_chain(f1, f2);
180 if (!chain)
181 return -ENOMEM;
182
183 dma_fence_unwrap_for_each(fence, &iter, chain) {
184 if (fence == f1) {
185 f1 = NULL;
186 } else if (fence == f2) {
187 f2 = NULL;
188 } else {
189 pr_err("Unexpected fence!\n");
190 err = -EINVAL;
191 }
192 }
193
194 if (f1 || f2) {
195 pr_err("Not all fences seen!\n");
196 err = -EINVAL;
197 }
198
199 dma_fence_signal(f1);
200 dma_fence_signal(f2);
201 dma_fence_put(chain);
202 return 0;
203 }
204
unwrap_chain_array(void * arg)205 static int unwrap_chain_array(void *arg)
206 {
207 struct dma_fence *fence, *f1, *f2, *array, *chain;
208 struct dma_fence_unwrap iter;
209 int err = 0;
210
211 f1 = mock_fence();
212 if (!f1)
213 return -ENOMEM;
214
215 f2 = mock_fence();
216 if (!f2) {
217 dma_fence_put(f1);
218 return -ENOMEM;
219 }
220
221 array = mock_array(2, f1, f2);
222 if (!array)
223 return -ENOMEM;
224
225 chain = mock_chain(NULL, array);
226 if (!chain)
227 return -ENOMEM;
228
229 dma_fence_unwrap_for_each(fence, &iter, chain) {
230 if (fence == f1) {
231 f1 = NULL;
232 } else if (fence == f2) {
233 f2 = NULL;
234 } else {
235 pr_err("Unexpected fence!\n");
236 err = -EINVAL;
237 }
238 }
239
240 if (f1 || f2) {
241 pr_err("Not all fences seen!\n");
242 err = -EINVAL;
243 }
244
245 dma_fence_signal(f1);
246 dma_fence_signal(f2);
247 dma_fence_put(chain);
248 return 0;
249 }
250
dma_fence_unwrap(void)251 int dma_fence_unwrap(void)
252 {
253 static const struct subtest tests[] = {
254 SUBTEST(sanitycheck),
255 SUBTEST(unwrap_array),
256 SUBTEST(unwrap_chain),
257 SUBTEST(unwrap_chain_array),
258 };
259
260 return subtests(tests, NULL);
261 }
262