1dc2f7e67SChris Wilson // SPDX-License-Identifier: MIT
2dc2f7e67SChris Wilson 
3dc2f7e67SChris Wilson /*
4dc2f7e67SChris Wilson  * Copyright © 2019 Intel Corporation
5dc2f7e67SChris Wilson  */
6dc2f7e67SChris Wilson 
7dc2f7e67SChris Wilson #include <linux/delay.h>
8dc2f7e67SChris Wilson #include <linux/dma-fence.h>
9dc2f7e67SChris Wilson #include <linux/dma-fence-chain.h>
10dc2f7e67SChris Wilson #include <linux/kernel.h>
11dc2f7e67SChris Wilson #include <linux/kthread.h>
12dc2f7e67SChris Wilson #include <linux/mm.h>
13dc2f7e67SChris Wilson #include <linux/sched/signal.h>
14dc2f7e67SChris Wilson #include <linux/slab.h>
15dc2f7e67SChris Wilson #include <linux/spinlock.h>
16dc2f7e67SChris Wilson #include <linux/random.h>
17dc2f7e67SChris Wilson 
18dc2f7e67SChris Wilson #include "selftest.h"
19dc2f7e67SChris Wilson 
20dc2f7e67SChris Wilson #define CHAIN_SZ (4 << 10)
21dc2f7e67SChris Wilson 
22dc2f7e67SChris Wilson static struct kmem_cache *slab_fences;
23dc2f7e67SChris Wilson 
24dc2f7e67SChris Wilson static inline struct mock_fence {
25dc2f7e67SChris Wilson 	struct dma_fence base;
26dc2f7e67SChris Wilson 	spinlock_t lock;
to_mock_fence(struct dma_fence * f)27dc2f7e67SChris Wilson } *to_mock_fence(struct dma_fence *f) {
28dc2f7e67SChris Wilson 	return container_of(f, struct mock_fence, base);
29dc2f7e67SChris Wilson }
30dc2f7e67SChris Wilson 
mock_name(struct dma_fence * f)31dc2f7e67SChris Wilson static const char *mock_name(struct dma_fence *f)
32dc2f7e67SChris Wilson {
33dc2f7e67SChris Wilson 	return "mock";
34dc2f7e67SChris Wilson }
35dc2f7e67SChris Wilson 
mock_fence_release(struct dma_fence * f)36dc2f7e67SChris Wilson static void mock_fence_release(struct dma_fence *f)
37dc2f7e67SChris Wilson {
38dc2f7e67SChris Wilson 	kmem_cache_free(slab_fences, to_mock_fence(f));
39dc2f7e67SChris Wilson }
40dc2f7e67SChris Wilson 
41dc2f7e67SChris Wilson static const struct dma_fence_ops mock_ops = {
42dc2f7e67SChris Wilson 	.get_driver_name = mock_name,
43dc2f7e67SChris Wilson 	.get_timeline_name = mock_name,
44dc2f7e67SChris Wilson 	.release = mock_fence_release,
45dc2f7e67SChris Wilson };
46dc2f7e67SChris Wilson 
mock_fence(void)47dc2f7e67SChris Wilson static struct dma_fence *mock_fence(void)
48dc2f7e67SChris Wilson {
49dc2f7e67SChris Wilson 	struct mock_fence *f;
50dc2f7e67SChris Wilson 
51dc2f7e67SChris Wilson 	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
52dc2f7e67SChris Wilson 	if (!f)
53dc2f7e67SChris Wilson 		return NULL;
54dc2f7e67SChris Wilson 
55dc2f7e67SChris Wilson 	spin_lock_init(&f->lock);
56dc2f7e67SChris Wilson 	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
57dc2f7e67SChris Wilson 
58dc2f7e67SChris Wilson 	return &f->base;
59dc2f7e67SChris Wilson }
60dc2f7e67SChris Wilson 
mock_chain(struct dma_fence * prev,struct dma_fence * fence,u64 seqno)61dc2f7e67SChris Wilson static struct dma_fence *mock_chain(struct dma_fence *prev,
62dc2f7e67SChris Wilson 				    struct dma_fence *fence,
63dc2f7e67SChris Wilson 				    u64 seqno)
64dc2f7e67SChris Wilson {
65440d0f12SChristian König 	struct dma_fence_chain *f;
66dc2f7e67SChris Wilson 
67440d0f12SChristian König 	f = dma_fence_chain_alloc();
68dc2f7e67SChris Wilson 	if (!f)
69dc2f7e67SChris Wilson 		return NULL;
70dc2f7e67SChris Wilson 
71440d0f12SChristian König 	dma_fence_chain_init(f, dma_fence_get(prev), dma_fence_get(fence),
72dc2f7e67SChris Wilson 			     seqno);
73dc2f7e67SChris Wilson 
74440d0f12SChristian König 	return &f->base;
75dc2f7e67SChris Wilson }
76dc2f7e67SChris Wilson 
sanitycheck(void * arg)77dc2f7e67SChris Wilson static int sanitycheck(void *arg)
78dc2f7e67SChris Wilson {
79dc2f7e67SChris Wilson 	struct dma_fence *f, *chain;
80dc2f7e67SChris Wilson 	int err = 0;
81dc2f7e67SChris Wilson 
82dc2f7e67SChris Wilson 	f = mock_fence();
83dc2f7e67SChris Wilson 	if (!f)
84dc2f7e67SChris Wilson 		return -ENOMEM;
85dc2f7e67SChris Wilson 
86dc2f7e67SChris Wilson 	chain = mock_chain(NULL, f, 1);
87156c226cSPavel Sakharov 	if (chain)
88d62c43a9SArvind Yadav 		dma_fence_enable_sw_signaling(chain);
89156c226cSPavel Sakharov 	else
90156c226cSPavel Sakharov 		err = -ENOMEM;
91d62c43a9SArvind Yadav 
92dc2f7e67SChris Wilson 	dma_fence_signal(f);
93dc2f7e67SChris Wilson 	dma_fence_put(f);
94dc2f7e67SChris Wilson 
95dc2f7e67SChris Wilson 	dma_fence_put(chain);
96dc2f7e67SChris Wilson 
97dc2f7e67SChris Wilson 	return err;
98dc2f7e67SChris Wilson }
99dc2f7e67SChris Wilson 
100dc2f7e67SChris Wilson struct fence_chains {
101dc2f7e67SChris Wilson 	unsigned int chain_length;
102dc2f7e67SChris Wilson 	struct dma_fence **fences;
103dc2f7e67SChris Wilson 	struct dma_fence **chains;
104dc2f7e67SChris Wilson 
105dc2f7e67SChris Wilson 	struct dma_fence *tail;
106dc2f7e67SChris Wilson };
107dc2f7e67SChris Wilson 
seqno_inc(unsigned int i)108dc2f7e67SChris Wilson static uint64_t seqno_inc(unsigned int i)
109dc2f7e67SChris Wilson {
110dc2f7e67SChris Wilson 	return i + 1;
111dc2f7e67SChris Wilson }
112dc2f7e67SChris Wilson 
fence_chains_init(struct fence_chains * fc,unsigned int count,uint64_t (* seqno_fn)(unsigned int))113dc2f7e67SChris Wilson static int fence_chains_init(struct fence_chains *fc, unsigned int count,
114dc2f7e67SChris Wilson 			     uint64_t (*seqno_fn)(unsigned int))
115dc2f7e67SChris Wilson {
116dc2f7e67SChris Wilson 	unsigned int i;
117dc2f7e67SChris Wilson 	int err = 0;
118dc2f7e67SChris Wilson 
119dc2f7e67SChris Wilson 	fc->chains = kvmalloc_array(count, sizeof(*fc->chains),
120dc2f7e67SChris Wilson 				    GFP_KERNEL | __GFP_ZERO);
121dc2f7e67SChris Wilson 	if (!fc->chains)
122dc2f7e67SChris Wilson 		return -ENOMEM;
123dc2f7e67SChris Wilson 
124dc2f7e67SChris Wilson 	fc->fences = kvmalloc_array(count, sizeof(*fc->fences),
125dc2f7e67SChris Wilson 				    GFP_KERNEL | __GFP_ZERO);
126dc2f7e67SChris Wilson 	if (!fc->fences) {
127dc2f7e67SChris Wilson 		err = -ENOMEM;
128dc2f7e67SChris Wilson 		goto err_chains;
129dc2f7e67SChris Wilson 	}
130dc2f7e67SChris Wilson 
131dc2f7e67SChris Wilson 	fc->tail = NULL;
132dc2f7e67SChris Wilson 	for (i = 0; i < count; i++) {
133dc2f7e67SChris Wilson 		fc->fences[i] = mock_fence();
134dc2f7e67SChris Wilson 		if (!fc->fences[i]) {
135dc2f7e67SChris Wilson 			err = -ENOMEM;
136dc2f7e67SChris Wilson 			goto unwind;
137dc2f7e67SChris Wilson 		}
138dc2f7e67SChris Wilson 
139dc2f7e67SChris Wilson 		fc->chains[i] = mock_chain(fc->tail,
140dc2f7e67SChris Wilson 					   fc->fences[i],
141dc2f7e67SChris Wilson 					   seqno_fn(i));
142dc2f7e67SChris Wilson 		if (!fc->chains[i]) {
143dc2f7e67SChris Wilson 			err = -ENOMEM;
144dc2f7e67SChris Wilson 			goto unwind;
145dc2f7e67SChris Wilson 		}
146dc2f7e67SChris Wilson 
147dc2f7e67SChris Wilson 		fc->tail = fc->chains[i];
148d62c43a9SArvind Yadav 
149d62c43a9SArvind Yadav 		dma_fence_enable_sw_signaling(fc->chains[i]);
150dc2f7e67SChris Wilson 	}
151dc2f7e67SChris Wilson 
152dc2f7e67SChris Wilson 	fc->chain_length = i;
153dc2f7e67SChris Wilson 	return 0;
154dc2f7e67SChris Wilson 
155dc2f7e67SChris Wilson unwind:
156dc2f7e67SChris Wilson 	for (i = 0; i < count; i++) {
157dc2f7e67SChris Wilson 		dma_fence_put(fc->fences[i]);
158dc2f7e67SChris Wilson 		dma_fence_put(fc->chains[i]);
159dc2f7e67SChris Wilson 	}
160dc2f7e67SChris Wilson 	kvfree(fc->fences);
161dc2f7e67SChris Wilson err_chains:
162dc2f7e67SChris Wilson 	kvfree(fc->chains);
163dc2f7e67SChris Wilson 	return err;
164dc2f7e67SChris Wilson }
165dc2f7e67SChris Wilson 
fence_chains_fini(struct fence_chains * fc)166dc2f7e67SChris Wilson static void fence_chains_fini(struct fence_chains *fc)
167dc2f7e67SChris Wilson {
168dc2f7e67SChris Wilson 	unsigned int i;
169dc2f7e67SChris Wilson 
170dc2f7e67SChris Wilson 	for (i = 0; i < fc->chain_length; i++) {
171dc2f7e67SChris Wilson 		dma_fence_signal(fc->fences[i]);
172dc2f7e67SChris Wilson 		dma_fence_put(fc->fences[i]);
173dc2f7e67SChris Wilson 	}
174dc2f7e67SChris Wilson 	kvfree(fc->fences);
175dc2f7e67SChris Wilson 
176dc2f7e67SChris Wilson 	for (i = 0; i < fc->chain_length; i++)
177dc2f7e67SChris Wilson 		dma_fence_put(fc->chains[i]);
178dc2f7e67SChris Wilson 	kvfree(fc->chains);
179dc2f7e67SChris Wilson }
180dc2f7e67SChris Wilson 
find_seqno(void * arg)181dc2f7e67SChris Wilson static int find_seqno(void *arg)
182dc2f7e67SChris Wilson {
183dc2f7e67SChris Wilson 	struct fence_chains fc;
184dc2f7e67SChris Wilson 	struct dma_fence *fence;
185dc2f7e67SChris Wilson 	int err;
186dc2f7e67SChris Wilson 	int i;
187dc2f7e67SChris Wilson 
188dc2f7e67SChris Wilson 	err = fence_chains_init(&fc, 64, seqno_inc);
189dc2f7e67SChris Wilson 	if (err)
190dc2f7e67SChris Wilson 		return err;
191dc2f7e67SChris Wilson 
192dc2f7e67SChris Wilson 	fence = dma_fence_get(fc.tail);
193dc2f7e67SChris Wilson 	err = dma_fence_chain_find_seqno(&fence, 0);
194dc2f7e67SChris Wilson 	dma_fence_put(fence);
195dc2f7e67SChris Wilson 	if (err) {
196dc2f7e67SChris Wilson 		pr_err("Reported %d for find_seqno(0)!\n", err);
197dc2f7e67SChris Wilson 		goto err;
198dc2f7e67SChris Wilson 	}
199dc2f7e67SChris Wilson 
200dc2f7e67SChris Wilson 	for (i = 0; i < fc.chain_length; i++) {
201dc2f7e67SChris Wilson 		fence = dma_fence_get(fc.tail);
202dc2f7e67SChris Wilson 		err = dma_fence_chain_find_seqno(&fence, i + 1);
203dc2f7e67SChris Wilson 		dma_fence_put(fence);
204dc2f7e67SChris Wilson 		if (err) {
205dc2f7e67SChris Wilson 			pr_err("Reported %d for find_seqno(%d:%d)!\n",
206dc2f7e67SChris Wilson 			       err, fc.chain_length + 1, i + 1);
207dc2f7e67SChris Wilson 			goto err;
208dc2f7e67SChris Wilson 		}
209dc2f7e67SChris Wilson 		if (fence != fc.chains[i]) {
210dc2f7e67SChris Wilson 			pr_err("Incorrect fence reported by find_seqno(%d:%d)\n",
211dc2f7e67SChris Wilson 			       fc.chain_length + 1, i + 1);
212dc2f7e67SChris Wilson 			err = -EINVAL;
213dc2f7e67SChris Wilson 			goto err;
214dc2f7e67SChris Wilson 		}
215dc2f7e67SChris Wilson 
216dc2f7e67SChris Wilson 		dma_fence_get(fence);
217dc2f7e67SChris Wilson 		err = dma_fence_chain_find_seqno(&fence, i + 1);
218dc2f7e67SChris Wilson 		dma_fence_put(fence);
219dc2f7e67SChris Wilson 		if (err) {
220dc2f7e67SChris Wilson 			pr_err("Error reported for finding self\n");
221dc2f7e67SChris Wilson 			goto err;
222dc2f7e67SChris Wilson 		}
223dc2f7e67SChris Wilson 		if (fence != fc.chains[i]) {
224dc2f7e67SChris Wilson 			pr_err("Incorrect fence reported by find self\n");
225dc2f7e67SChris Wilson 			err = -EINVAL;
226dc2f7e67SChris Wilson 			goto err;
227dc2f7e67SChris Wilson 		}
228dc2f7e67SChris Wilson 
229dc2f7e67SChris Wilson 		dma_fence_get(fence);
230dc2f7e67SChris Wilson 		err = dma_fence_chain_find_seqno(&fence, i + 2);
231dc2f7e67SChris Wilson 		dma_fence_put(fence);
232dc2f7e67SChris Wilson 		if (!err) {
233dc2f7e67SChris Wilson 			pr_err("Error not reported for future fence: find_seqno(%d:%d)!\n",
234dc2f7e67SChris Wilson 			       i + 1, i + 2);
235dc2f7e67SChris Wilson 			err = -EINVAL;
236dc2f7e67SChris Wilson 			goto err;
237dc2f7e67SChris Wilson 		}
238dc2f7e67SChris Wilson 
239dc2f7e67SChris Wilson 		dma_fence_get(fence);
240dc2f7e67SChris Wilson 		err = dma_fence_chain_find_seqno(&fence, i);
241dc2f7e67SChris Wilson 		dma_fence_put(fence);
242dc2f7e67SChris Wilson 		if (err) {
243dc2f7e67SChris Wilson 			pr_err("Error reported for previous fence!\n");
244dc2f7e67SChris Wilson 			goto err;
245dc2f7e67SChris Wilson 		}
246dc2f7e67SChris Wilson 		if (i > 0 && fence != fc.chains[i - 1]) {
247dc2f7e67SChris Wilson 			pr_err("Incorrect fence reported by find_seqno(%d:%d)\n",
248dc2f7e67SChris Wilson 			       i + 1, i);
249dc2f7e67SChris Wilson 			err = -EINVAL;
250dc2f7e67SChris Wilson 			goto err;
251dc2f7e67SChris Wilson 		}
252dc2f7e67SChris Wilson 	}
253dc2f7e67SChris Wilson 
254dc2f7e67SChris Wilson err:
255dc2f7e67SChris Wilson 	fence_chains_fini(&fc);
256dc2f7e67SChris Wilson 	return err;
257dc2f7e67SChris Wilson }
258dc2f7e67SChris Wilson 
find_signaled(void * arg)259dc2f7e67SChris Wilson static int find_signaled(void *arg)
260dc2f7e67SChris Wilson {
261dc2f7e67SChris Wilson 	struct fence_chains fc;
262dc2f7e67SChris Wilson 	struct dma_fence *fence;
263dc2f7e67SChris Wilson 	int err;
264dc2f7e67SChris Wilson 
265dc2f7e67SChris Wilson 	err = fence_chains_init(&fc, 2, seqno_inc);
266dc2f7e67SChris Wilson 	if (err)
267dc2f7e67SChris Wilson 		return err;
268dc2f7e67SChris Wilson 
269dc2f7e67SChris Wilson 	dma_fence_signal(fc.fences[0]);
270dc2f7e67SChris Wilson 
271dc2f7e67SChris Wilson 	fence = dma_fence_get(fc.tail);
272dc2f7e67SChris Wilson 	err = dma_fence_chain_find_seqno(&fence, 1);
273dc2f7e67SChris Wilson 	dma_fence_put(fence);
274dc2f7e67SChris Wilson 	if (err) {
275dc2f7e67SChris Wilson 		pr_err("Reported %d for find_seqno()!\n", err);
276dc2f7e67SChris Wilson 		goto err;
277dc2f7e67SChris Wilson 	}
278dc2f7e67SChris Wilson 
279dc2f7e67SChris Wilson 	if (fence && fence != fc.chains[0]) {
280dc2f7e67SChris Wilson 		pr_err("Incorrect chain-fence.seqno:%lld reported for completed seqno:1\n",
281dc2f7e67SChris Wilson 		       fence->seqno);
282dc2f7e67SChris Wilson 
283dc2f7e67SChris Wilson 		dma_fence_get(fence);
284dc2f7e67SChris Wilson 		err = dma_fence_chain_find_seqno(&fence, 1);
285dc2f7e67SChris Wilson 		dma_fence_put(fence);
286dc2f7e67SChris Wilson 		if (err)
287dc2f7e67SChris Wilson 			pr_err("Reported %d for finding self!\n", err);
288dc2f7e67SChris Wilson 
289dc2f7e67SChris Wilson 		err = -EINVAL;
290dc2f7e67SChris Wilson 	}
291dc2f7e67SChris Wilson 
292dc2f7e67SChris Wilson err:
293dc2f7e67SChris Wilson 	fence_chains_fini(&fc);
294dc2f7e67SChris Wilson 	return err;
295dc2f7e67SChris Wilson }
296dc2f7e67SChris Wilson 
find_out_of_order(void * arg)297dc2f7e67SChris Wilson static int find_out_of_order(void *arg)
298dc2f7e67SChris Wilson {
299dc2f7e67SChris Wilson 	struct fence_chains fc;
300dc2f7e67SChris Wilson 	struct dma_fence *fence;
301dc2f7e67SChris Wilson 	int err;
302dc2f7e67SChris Wilson 
303dc2f7e67SChris Wilson 	err = fence_chains_init(&fc, 3, seqno_inc);
304dc2f7e67SChris Wilson 	if (err)
305dc2f7e67SChris Wilson 		return err;
306dc2f7e67SChris Wilson 
307dc2f7e67SChris Wilson 	dma_fence_signal(fc.fences[1]);
308dc2f7e67SChris Wilson 
309dc2f7e67SChris Wilson 	fence = dma_fence_get(fc.tail);
310dc2f7e67SChris Wilson 	err = dma_fence_chain_find_seqno(&fence, 2);
311dc2f7e67SChris Wilson 	dma_fence_put(fence);
312dc2f7e67SChris Wilson 	if (err) {
313dc2f7e67SChris Wilson 		pr_err("Reported %d for find_seqno()!\n", err);
314dc2f7e67SChris Wilson 		goto err;
315dc2f7e67SChris Wilson 	}
316dc2f7e67SChris Wilson 
3174cca2e64SLionel Landwerlin 	/*
3184cca2e64SLionel Landwerlin 	 * We signaled the middle fence (2) of the 1-2-3 chain. The behavior
3194cca2e64SLionel Landwerlin 	 * of the dma-fence-chain is to make us wait for all the fences up to
3204cca2e64SLionel Landwerlin 	 * the point we want. Since fence 1 is still not signaled, this what
3214cca2e64SLionel Landwerlin 	 * we should get as fence to wait upon (fence 2 being garbage
3224cca2e64SLionel Landwerlin 	 * collected during the traversal of the chain).
3234cca2e64SLionel Landwerlin 	 */
3244cca2e64SLionel Landwerlin 	if (fence != fc.chains[0]) {
325dc2f7e67SChris Wilson 		pr_err("Incorrect chain-fence.seqno:%lld reported for completed seqno:2\n",
3264cca2e64SLionel Landwerlin 		       fence ? fence->seqno : 0);
327dc2f7e67SChris Wilson 
328dc2f7e67SChris Wilson 		err = -EINVAL;
329dc2f7e67SChris Wilson 	}
330dc2f7e67SChris Wilson 
331dc2f7e67SChris Wilson err:
332dc2f7e67SChris Wilson 	fence_chains_fini(&fc);
333dc2f7e67SChris Wilson 	return err;
334dc2f7e67SChris Wilson }
335dc2f7e67SChris Wilson 
seqno_inc2(unsigned int i)336dc2f7e67SChris Wilson static uint64_t seqno_inc2(unsigned int i)
337dc2f7e67SChris Wilson {
338dc2f7e67SChris Wilson 	return 2 * i + 2;
339dc2f7e67SChris Wilson }
340dc2f7e67SChris Wilson 
find_gap(void * arg)341dc2f7e67SChris Wilson static int find_gap(void *arg)
342dc2f7e67SChris Wilson {
343dc2f7e67SChris Wilson 	struct fence_chains fc;
344dc2f7e67SChris Wilson 	struct dma_fence *fence;
345dc2f7e67SChris Wilson 	int err;
346dc2f7e67SChris Wilson 	int i;
347dc2f7e67SChris Wilson 
348dc2f7e67SChris Wilson 	err = fence_chains_init(&fc, 64, seqno_inc2);
349dc2f7e67SChris Wilson 	if (err)
350dc2f7e67SChris Wilson 		return err;
351dc2f7e67SChris Wilson 
352dc2f7e67SChris Wilson 	for (i = 0; i < fc.chain_length; i++) {
353dc2f7e67SChris Wilson 		fence = dma_fence_get(fc.tail);
354dc2f7e67SChris Wilson 		err = dma_fence_chain_find_seqno(&fence, 2 * i + 1);
355dc2f7e67SChris Wilson 		dma_fence_put(fence);
356dc2f7e67SChris Wilson 		if (err) {
357dc2f7e67SChris Wilson 			pr_err("Reported %d for find_seqno(%d:%d)!\n",
358dc2f7e67SChris Wilson 			       err, fc.chain_length + 1, 2 * i + 1);
359dc2f7e67SChris Wilson 			goto err;
360dc2f7e67SChris Wilson 		}
361dc2f7e67SChris Wilson 		if (fence != fc.chains[i]) {
362dc2f7e67SChris Wilson 			pr_err("Incorrect fence.seqno:%lld reported by find_seqno(%d:%d)\n",
363dc2f7e67SChris Wilson 			       fence->seqno,
364dc2f7e67SChris Wilson 			       fc.chain_length + 1,
365dc2f7e67SChris Wilson 			       2 * i + 1);
366dc2f7e67SChris Wilson 			err = -EINVAL;
367dc2f7e67SChris Wilson 			goto err;
368dc2f7e67SChris Wilson 		}
369dc2f7e67SChris Wilson 
370dc2f7e67SChris Wilson 		dma_fence_get(fence);
371dc2f7e67SChris Wilson 		err = dma_fence_chain_find_seqno(&fence, 2 * i + 2);
372dc2f7e67SChris Wilson 		dma_fence_put(fence);
373dc2f7e67SChris Wilson 		if (err) {
374dc2f7e67SChris Wilson 			pr_err("Error reported for finding self\n");
375dc2f7e67SChris Wilson 			goto err;
376dc2f7e67SChris Wilson 		}
377dc2f7e67SChris Wilson 		if (fence != fc.chains[i]) {
378dc2f7e67SChris Wilson 			pr_err("Incorrect fence reported by find self\n");
379dc2f7e67SChris Wilson 			err = -EINVAL;
380dc2f7e67SChris Wilson 			goto err;
381dc2f7e67SChris Wilson 		}
382dc2f7e67SChris Wilson 	}
383dc2f7e67SChris Wilson 
384dc2f7e67SChris Wilson err:
385dc2f7e67SChris Wilson 	fence_chains_fini(&fc);
386dc2f7e67SChris Wilson 	return err;
387dc2f7e67SChris Wilson }
388dc2f7e67SChris Wilson 
389dc2f7e67SChris Wilson struct find_race {
390dc2f7e67SChris Wilson 	struct fence_chains fc;
391dc2f7e67SChris Wilson 	atomic_t children;
392dc2f7e67SChris Wilson };
393dc2f7e67SChris Wilson 
__find_race(void * arg)394dc2f7e67SChris Wilson static int __find_race(void *arg)
395dc2f7e67SChris Wilson {
396dc2f7e67SChris Wilson 	struct find_race *data = arg;
397dc2f7e67SChris Wilson 	int err = 0;
398dc2f7e67SChris Wilson 
399dc2f7e67SChris Wilson 	while (!kthread_should_stop()) {
400dc2f7e67SChris Wilson 		struct dma_fence *fence = dma_fence_get(data->fc.tail);
401dc2f7e67SChris Wilson 		int seqno;
402dc2f7e67SChris Wilson 
403e8a533cbSJason A. Donenfeld 		seqno = get_random_u32_inclusive(1, data->fc.chain_length);
404dc2f7e67SChris Wilson 
405dc2f7e67SChris Wilson 		err = dma_fence_chain_find_seqno(&fence, seqno);
406dc2f7e67SChris Wilson 		if (err) {
407dc2f7e67SChris Wilson 			pr_err("Failed to find fence seqno:%d\n",
408dc2f7e67SChris Wilson 			       seqno);
409dc2f7e67SChris Wilson 			dma_fence_put(fence);
410dc2f7e67SChris Wilson 			break;
411dc2f7e67SChris Wilson 		}
412dc2f7e67SChris Wilson 		if (!fence)
413dc2f7e67SChris Wilson 			goto signal;
414dc2f7e67SChris Wilson 
4154cca2e64SLionel Landwerlin 		/*
4164cca2e64SLionel Landwerlin 		 * We can only find ourselves if we are on fence we were
4174cca2e64SLionel Landwerlin 		 * looking for.
4184cca2e64SLionel Landwerlin 		 */
4194cca2e64SLionel Landwerlin 		if (fence->seqno == seqno) {
420dc2f7e67SChris Wilson 			err = dma_fence_chain_find_seqno(&fence, seqno);
421dc2f7e67SChris Wilson 			if (err) {
422dc2f7e67SChris Wilson 				pr_err("Reported an invalid fence for find-self:%d\n",
423dc2f7e67SChris Wilson 				       seqno);
424dc2f7e67SChris Wilson 				dma_fence_put(fence);
425dc2f7e67SChris Wilson 				break;
426dc2f7e67SChris Wilson 			}
427dc2f7e67SChris Wilson 		}
428dc2f7e67SChris Wilson 
429dc2f7e67SChris Wilson 		dma_fence_put(fence);
430dc2f7e67SChris Wilson 
431dc2f7e67SChris Wilson signal:
4328032bf12SJason A. Donenfeld 		seqno = get_random_u32_below(data->fc.chain_length - 1);
433dc2f7e67SChris Wilson 		dma_fence_signal(data->fc.fences[seqno]);
434dc2f7e67SChris Wilson 		cond_resched();
435dc2f7e67SChris Wilson 	}
436dc2f7e67SChris Wilson 
437dc2f7e67SChris Wilson 	if (atomic_dec_and_test(&data->children))
438dc2f7e67SChris Wilson 		wake_up_var(&data->children);
439dc2f7e67SChris Wilson 	return err;
440dc2f7e67SChris Wilson }
441dc2f7e67SChris Wilson 
find_race(void * arg)442dc2f7e67SChris Wilson static int find_race(void *arg)
443dc2f7e67SChris Wilson {
444dc2f7e67SChris Wilson 	struct find_race data;
445dc2f7e67SChris Wilson 	int ncpus = num_online_cpus();
446dc2f7e67SChris Wilson 	struct task_struct **threads;
447dc2f7e67SChris Wilson 	unsigned long count;
448dc2f7e67SChris Wilson 	int err;
449dc2f7e67SChris Wilson 	int i;
450dc2f7e67SChris Wilson 
451dc2f7e67SChris Wilson 	err = fence_chains_init(&data.fc, CHAIN_SZ, seqno_inc);
452dc2f7e67SChris Wilson 	if (err)
453dc2f7e67SChris Wilson 		return err;
454dc2f7e67SChris Wilson 
455dc2f7e67SChris Wilson 	threads = kmalloc_array(ncpus, sizeof(*threads), GFP_KERNEL);
456dc2f7e67SChris Wilson 	if (!threads) {
457dc2f7e67SChris Wilson 		err = -ENOMEM;
458dc2f7e67SChris Wilson 		goto err;
459dc2f7e67SChris Wilson 	}
460dc2f7e67SChris Wilson 
461dc2f7e67SChris Wilson 	atomic_set(&data.children, 0);
462dc2f7e67SChris Wilson 	for (i = 0; i < ncpus; i++) {
463dc2f7e67SChris Wilson 		threads[i] = kthread_run(__find_race, &data, "dmabuf/%d", i);
464dc2f7e67SChris Wilson 		if (IS_ERR(threads[i])) {
465dc2f7e67SChris Wilson 			ncpus = i;
466dc2f7e67SChris Wilson 			break;
467dc2f7e67SChris Wilson 		}
468dc2f7e67SChris Wilson 		atomic_inc(&data.children);
469dc2f7e67SChris Wilson 		get_task_struct(threads[i]);
470dc2f7e67SChris Wilson 	}
471dc2f7e67SChris Wilson 
472dc2f7e67SChris Wilson 	wait_var_event_timeout(&data.children,
473dc2f7e67SChris Wilson 			       !atomic_read(&data.children),
474dc2f7e67SChris Wilson 			       5 * HZ);
475dc2f7e67SChris Wilson 
476dc2f7e67SChris Wilson 	for (i = 0; i < ncpus; i++) {
477dc2f7e67SChris Wilson 		int ret;
478dc2f7e67SChris Wilson 
479a9da6ddaSAndreas Gruenbacher 		ret = kthread_stop_put(threads[i]);
480dc2f7e67SChris Wilson 		if (ret && !err)
481dc2f7e67SChris Wilson 			err = ret;
482dc2f7e67SChris Wilson 	}
483dc2f7e67SChris Wilson 	kfree(threads);
484dc2f7e67SChris Wilson 
485dc2f7e67SChris Wilson 	count = 0;
486dc2f7e67SChris Wilson 	for (i = 0; i < data.fc.chain_length; i++)
487dc2f7e67SChris Wilson 		if (dma_fence_is_signaled(data.fc.fences[i]))
488dc2f7e67SChris Wilson 			count++;
489dc2f7e67SChris Wilson 	pr_info("Completed %lu cycles\n", count);
490dc2f7e67SChris Wilson 
491dc2f7e67SChris Wilson err:
492dc2f7e67SChris Wilson 	fence_chains_fini(&data.fc);
493dc2f7e67SChris Wilson 	return err;
494dc2f7e67SChris Wilson }
495dc2f7e67SChris Wilson 
signal_forward(void * arg)496dc2f7e67SChris Wilson static int signal_forward(void *arg)
497dc2f7e67SChris Wilson {
498dc2f7e67SChris Wilson 	struct fence_chains fc;
499dc2f7e67SChris Wilson 	int err;
500dc2f7e67SChris Wilson 	int i;
501dc2f7e67SChris Wilson 
502dc2f7e67SChris Wilson 	err = fence_chains_init(&fc, 64, seqno_inc);
503dc2f7e67SChris Wilson 	if (err)
504dc2f7e67SChris Wilson 		return err;
505dc2f7e67SChris Wilson 
506dc2f7e67SChris Wilson 	for (i = 0; i < fc.chain_length; i++) {
507dc2f7e67SChris Wilson 		dma_fence_signal(fc.fences[i]);
508dc2f7e67SChris Wilson 
509dc2f7e67SChris Wilson 		if (!dma_fence_is_signaled(fc.chains[i])) {
510dc2f7e67SChris Wilson 			pr_err("chain[%d] not signaled!\n", i);
511dc2f7e67SChris Wilson 			err = -EINVAL;
512dc2f7e67SChris Wilson 			goto err;
513dc2f7e67SChris Wilson 		}
514dc2f7e67SChris Wilson 
515dc2f7e67SChris Wilson 		if (i + 1 < fc.chain_length &&
516dc2f7e67SChris Wilson 		    dma_fence_is_signaled(fc.chains[i + 1])) {
517dc2f7e67SChris Wilson 			pr_err("chain[%d] is signaled!\n", i);
518dc2f7e67SChris Wilson 			err = -EINVAL;
519dc2f7e67SChris Wilson 			goto err;
520dc2f7e67SChris Wilson 		}
521dc2f7e67SChris Wilson 	}
522dc2f7e67SChris Wilson 
523dc2f7e67SChris Wilson err:
524dc2f7e67SChris Wilson 	fence_chains_fini(&fc);
525dc2f7e67SChris Wilson 	return err;
526dc2f7e67SChris Wilson }
527dc2f7e67SChris Wilson 
signal_backward(void * arg)528dc2f7e67SChris Wilson static int signal_backward(void *arg)
529dc2f7e67SChris Wilson {
530dc2f7e67SChris Wilson 	struct fence_chains fc;
531dc2f7e67SChris Wilson 	int err;
532dc2f7e67SChris Wilson 	int i;
533dc2f7e67SChris Wilson 
534dc2f7e67SChris Wilson 	err = fence_chains_init(&fc, 64, seqno_inc);
535dc2f7e67SChris Wilson 	if (err)
536dc2f7e67SChris Wilson 		return err;
537dc2f7e67SChris Wilson 
538dc2f7e67SChris Wilson 	for (i = fc.chain_length; i--; ) {
539dc2f7e67SChris Wilson 		dma_fence_signal(fc.fences[i]);
540dc2f7e67SChris Wilson 
541dc2f7e67SChris Wilson 		if (i > 0 && dma_fence_is_signaled(fc.chains[i])) {
542dc2f7e67SChris Wilson 			pr_err("chain[%d] is signaled!\n", i);
543dc2f7e67SChris Wilson 			err = -EINVAL;
544dc2f7e67SChris Wilson 			goto err;
545dc2f7e67SChris Wilson 		}
546dc2f7e67SChris Wilson 	}
547dc2f7e67SChris Wilson 
548dc2f7e67SChris Wilson 	for (i = 0; i < fc.chain_length; i++) {
549dc2f7e67SChris Wilson 		if (!dma_fence_is_signaled(fc.chains[i])) {
550dc2f7e67SChris Wilson 			pr_err("chain[%d] was not signaled!\n", i);
551dc2f7e67SChris Wilson 			err = -EINVAL;
552dc2f7e67SChris Wilson 			goto err;
553dc2f7e67SChris Wilson 		}
554dc2f7e67SChris Wilson 	}
555dc2f7e67SChris Wilson 
556dc2f7e67SChris Wilson err:
557dc2f7e67SChris Wilson 	fence_chains_fini(&fc);
558dc2f7e67SChris Wilson 	return err;
559dc2f7e67SChris Wilson }
560dc2f7e67SChris Wilson 
__wait_fence_chains(void * arg)561dc2f7e67SChris Wilson static int __wait_fence_chains(void *arg)
562dc2f7e67SChris Wilson {
563dc2f7e67SChris Wilson 	struct fence_chains *fc = arg;
564dc2f7e67SChris Wilson 
565dc2f7e67SChris Wilson 	if (dma_fence_wait(fc->tail, false))
566dc2f7e67SChris Wilson 		return -EIO;
567dc2f7e67SChris Wilson 
568dc2f7e67SChris Wilson 	return 0;
569dc2f7e67SChris Wilson }
570dc2f7e67SChris Wilson 
wait_forward(void * arg)571dc2f7e67SChris Wilson static int wait_forward(void *arg)
572dc2f7e67SChris Wilson {
573dc2f7e67SChris Wilson 	struct fence_chains fc;
574dc2f7e67SChris Wilson 	struct task_struct *tsk;
575dc2f7e67SChris Wilson 	int err;
576dc2f7e67SChris Wilson 	int i;
577dc2f7e67SChris Wilson 
578dc2f7e67SChris Wilson 	err = fence_chains_init(&fc, CHAIN_SZ, seqno_inc);
579dc2f7e67SChris Wilson 	if (err)
580dc2f7e67SChris Wilson 		return err;
581dc2f7e67SChris Wilson 
582dc2f7e67SChris Wilson 	tsk = kthread_run(__wait_fence_chains, &fc, "dmabuf/wait");
583dc2f7e67SChris Wilson 	if (IS_ERR(tsk)) {
584dc2f7e67SChris Wilson 		err = PTR_ERR(tsk);
585dc2f7e67SChris Wilson 		goto err;
586dc2f7e67SChris Wilson 	}
587dc2f7e67SChris Wilson 	get_task_struct(tsk);
588dc2f7e67SChris Wilson 	yield_to(tsk, true);
589dc2f7e67SChris Wilson 
590dc2f7e67SChris Wilson 	for (i = 0; i < fc.chain_length; i++)
591dc2f7e67SChris Wilson 		dma_fence_signal(fc.fences[i]);
592dc2f7e67SChris Wilson 
593a9da6ddaSAndreas Gruenbacher 	err = kthread_stop_put(tsk);
594dc2f7e67SChris Wilson 
595dc2f7e67SChris Wilson err:
596dc2f7e67SChris Wilson 	fence_chains_fini(&fc);
597dc2f7e67SChris Wilson 	return err;
598dc2f7e67SChris Wilson }
599dc2f7e67SChris Wilson 
wait_backward(void * arg)600dc2f7e67SChris Wilson static int wait_backward(void *arg)
601dc2f7e67SChris Wilson {
602dc2f7e67SChris Wilson 	struct fence_chains fc;
603dc2f7e67SChris Wilson 	struct task_struct *tsk;
604dc2f7e67SChris Wilson 	int err;
605dc2f7e67SChris Wilson 	int i;
606dc2f7e67SChris Wilson 
607dc2f7e67SChris Wilson 	err = fence_chains_init(&fc, CHAIN_SZ, seqno_inc);
608dc2f7e67SChris Wilson 	if (err)
609dc2f7e67SChris Wilson 		return err;
610dc2f7e67SChris Wilson 
611dc2f7e67SChris Wilson 	tsk = kthread_run(__wait_fence_chains, &fc, "dmabuf/wait");
612dc2f7e67SChris Wilson 	if (IS_ERR(tsk)) {
613dc2f7e67SChris Wilson 		err = PTR_ERR(tsk);
614dc2f7e67SChris Wilson 		goto err;
615dc2f7e67SChris Wilson 	}
616dc2f7e67SChris Wilson 	get_task_struct(tsk);
617dc2f7e67SChris Wilson 	yield_to(tsk, true);
618dc2f7e67SChris Wilson 
619dc2f7e67SChris Wilson 	for (i = fc.chain_length; i--; )
620dc2f7e67SChris Wilson 		dma_fence_signal(fc.fences[i]);
621dc2f7e67SChris Wilson 
622a9da6ddaSAndreas Gruenbacher 	err = kthread_stop_put(tsk);
623dc2f7e67SChris Wilson 
624dc2f7e67SChris Wilson err:
625dc2f7e67SChris Wilson 	fence_chains_fini(&fc);
626dc2f7e67SChris Wilson 	return err;
627dc2f7e67SChris Wilson }
628dc2f7e67SChris Wilson 
randomise_fences(struct fence_chains * fc)629dc2f7e67SChris Wilson static void randomise_fences(struct fence_chains *fc)
630dc2f7e67SChris Wilson {
631dc2f7e67SChris Wilson 	unsigned int count = fc->chain_length;
632dc2f7e67SChris Wilson 
633dc2f7e67SChris Wilson 	/* Fisher-Yates shuffle courtesy of Knuth */
634dc2f7e67SChris Wilson 	while (--count) {
635dc2f7e67SChris Wilson 		unsigned int swp;
636dc2f7e67SChris Wilson 
6378032bf12SJason A. Donenfeld 		swp = get_random_u32_below(count + 1);
638dc2f7e67SChris Wilson 		if (swp == count)
639dc2f7e67SChris Wilson 			continue;
640dc2f7e67SChris Wilson 
641dc2f7e67SChris Wilson 		swap(fc->fences[count], fc->fences[swp]);
642dc2f7e67SChris Wilson 	}
643dc2f7e67SChris Wilson }
644dc2f7e67SChris Wilson 
wait_random(void * arg)645dc2f7e67SChris Wilson static int wait_random(void *arg)
646dc2f7e67SChris Wilson {
647dc2f7e67SChris Wilson 	struct fence_chains fc;
648dc2f7e67SChris Wilson 	struct task_struct *tsk;
649dc2f7e67SChris Wilson 	int err;
650dc2f7e67SChris Wilson 	int i;
651dc2f7e67SChris Wilson 
652dc2f7e67SChris Wilson 	err = fence_chains_init(&fc, CHAIN_SZ, seqno_inc);
653dc2f7e67SChris Wilson 	if (err)
654dc2f7e67SChris Wilson 		return err;
655dc2f7e67SChris Wilson 
656dc2f7e67SChris Wilson 	randomise_fences(&fc);
657dc2f7e67SChris Wilson 
658dc2f7e67SChris Wilson 	tsk = kthread_run(__wait_fence_chains, &fc, "dmabuf/wait");
659dc2f7e67SChris Wilson 	if (IS_ERR(tsk)) {
660dc2f7e67SChris Wilson 		err = PTR_ERR(tsk);
661dc2f7e67SChris Wilson 		goto err;
662dc2f7e67SChris Wilson 	}
663dc2f7e67SChris Wilson 	get_task_struct(tsk);
664dc2f7e67SChris Wilson 	yield_to(tsk, true);
665dc2f7e67SChris Wilson 
666dc2f7e67SChris Wilson 	for (i = 0; i < fc.chain_length; i++)
667dc2f7e67SChris Wilson 		dma_fence_signal(fc.fences[i]);
668dc2f7e67SChris Wilson 
669a9da6ddaSAndreas Gruenbacher 	err = kthread_stop_put(tsk);
670dc2f7e67SChris Wilson 
671dc2f7e67SChris Wilson err:
672dc2f7e67SChris Wilson 	fence_chains_fini(&fc);
673dc2f7e67SChris Wilson 	return err;
674dc2f7e67SChris Wilson }
675dc2f7e67SChris Wilson 
dma_fence_chain(void)676dc2f7e67SChris Wilson int dma_fence_chain(void)
677dc2f7e67SChris Wilson {
678dc2f7e67SChris Wilson 	static const struct subtest tests[] = {
679dc2f7e67SChris Wilson 		SUBTEST(sanitycheck),
680dc2f7e67SChris Wilson 		SUBTEST(find_seqno),
681dc2f7e67SChris Wilson 		SUBTEST(find_signaled),
682dc2f7e67SChris Wilson 		SUBTEST(find_out_of_order),
683dc2f7e67SChris Wilson 		SUBTEST(find_gap),
684dc2f7e67SChris Wilson 		SUBTEST(find_race),
685dc2f7e67SChris Wilson 		SUBTEST(signal_forward),
686dc2f7e67SChris Wilson 		SUBTEST(signal_backward),
687dc2f7e67SChris Wilson 		SUBTEST(wait_forward),
688dc2f7e67SChris Wilson 		SUBTEST(wait_backward),
689dc2f7e67SChris Wilson 		SUBTEST(wait_random),
690dc2f7e67SChris Wilson 	};
691dc2f7e67SChris Wilson 	int ret;
692dc2f7e67SChris Wilson 
693dc2f7e67SChris Wilson 	pr_info("sizeof(dma_fence_chain)=%zu\n",
694dc2f7e67SChris Wilson 		sizeof(struct dma_fence_chain));
695dc2f7e67SChris Wilson 
696dc2f7e67SChris Wilson 	slab_fences = KMEM_CACHE(mock_fence,
697dc2f7e67SChris Wilson 				 SLAB_TYPESAFE_BY_RCU |
698dc2f7e67SChris Wilson 				 SLAB_HWCACHE_ALIGN);
699dc2f7e67SChris Wilson 	if (!slab_fences)
700dc2f7e67SChris Wilson 		return -ENOMEM;
701dc2f7e67SChris Wilson 
702dc2f7e67SChris Wilson 	ret = subtests(tests, NULL);
703dc2f7e67SChris Wilson 
704dc2f7e67SChris Wilson 	kmem_cache_destroy(slab_fences);
705dc2f7e67SChris Wilson 	return ret;
706dc2f7e67SChris Wilson }
707