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;
25 } *to_mock_fence(struct dma_fence *f) {
26 	return container_of(f, struct mock_fence, base);
27 }
28 
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 
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 
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 
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 
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 
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 
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 
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 
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