xref: /openbmc/linux/drivers/dma-buf/st-dma-fence.c (revision 2989f6451084aed3f8cc9992477f7a9bf57a3716)
1*2989f645SChris Wilson /* SPDX-License-Identifier: MIT */
2*2989f645SChris Wilson 
3*2989f645SChris Wilson /*
4*2989f645SChris Wilson  * Copyright © 2019 Intel Corporation
5*2989f645SChris Wilson  */
6*2989f645SChris Wilson 
7*2989f645SChris Wilson #include <linux/delay.h>
8*2989f645SChris Wilson #include <linux/dma-fence.h>
9*2989f645SChris Wilson #include <linux/kernel.h>
10*2989f645SChris Wilson #include <linux/kthread.h>
11*2989f645SChris Wilson #include <linux/sched/signal.h>
12*2989f645SChris Wilson #include <linux/slab.h>
13*2989f645SChris Wilson #include <linux/spinlock.h>
14*2989f645SChris Wilson 
15*2989f645SChris Wilson #include "selftest.h"
16*2989f645SChris Wilson 
17*2989f645SChris Wilson static struct kmem_cache *slab_fences;
18*2989f645SChris Wilson 
19*2989f645SChris Wilson static struct mock_fence {
20*2989f645SChris Wilson 	struct dma_fence base;
21*2989f645SChris Wilson 	struct spinlock lock;
22*2989f645SChris Wilson } *to_mock_fence(struct dma_fence *f) {
23*2989f645SChris Wilson 	return container_of(f, struct mock_fence, base);
24*2989f645SChris Wilson }
25*2989f645SChris Wilson 
26*2989f645SChris Wilson static const char *mock_name(struct dma_fence *f)
27*2989f645SChris Wilson {
28*2989f645SChris Wilson 	return "mock";
29*2989f645SChris Wilson }
30*2989f645SChris Wilson 
31*2989f645SChris Wilson static void mock_fence_release(struct dma_fence *f)
32*2989f645SChris Wilson {
33*2989f645SChris Wilson 	kmem_cache_free(slab_fences, to_mock_fence(f));
34*2989f645SChris Wilson }
35*2989f645SChris Wilson 
36*2989f645SChris Wilson struct wait_cb {
37*2989f645SChris Wilson 	struct dma_fence_cb cb;
38*2989f645SChris Wilson 	struct task_struct *task;
39*2989f645SChris Wilson };
40*2989f645SChris Wilson 
41*2989f645SChris Wilson static void mock_wakeup(struct dma_fence *f, struct dma_fence_cb *cb)
42*2989f645SChris Wilson {
43*2989f645SChris Wilson 	wake_up_process(container_of(cb, struct wait_cb, cb)->task);
44*2989f645SChris Wilson }
45*2989f645SChris Wilson 
46*2989f645SChris Wilson static long mock_wait(struct dma_fence *f, bool intr, long timeout)
47*2989f645SChris Wilson {
48*2989f645SChris Wilson 	const int state = intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
49*2989f645SChris Wilson 	struct wait_cb cb = { .task = current };
50*2989f645SChris Wilson 
51*2989f645SChris Wilson 	if (dma_fence_add_callback(f, &cb.cb, mock_wakeup))
52*2989f645SChris Wilson 		return timeout;
53*2989f645SChris Wilson 
54*2989f645SChris Wilson 	while (timeout) {
55*2989f645SChris Wilson 		set_current_state(state);
56*2989f645SChris Wilson 
57*2989f645SChris Wilson 		if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags))
58*2989f645SChris Wilson 			break;
59*2989f645SChris Wilson 
60*2989f645SChris Wilson 		if (signal_pending_state(state, current))
61*2989f645SChris Wilson 			break;
62*2989f645SChris Wilson 
63*2989f645SChris Wilson 		timeout = schedule_timeout(timeout);
64*2989f645SChris Wilson 	}
65*2989f645SChris Wilson 	__set_current_state(TASK_RUNNING);
66*2989f645SChris Wilson 
67*2989f645SChris Wilson 	if (!dma_fence_remove_callback(f, &cb.cb))
68*2989f645SChris Wilson 		return timeout;
69*2989f645SChris Wilson 
70*2989f645SChris Wilson 	if (signal_pending_state(state, current))
71*2989f645SChris Wilson 		return -ERESTARTSYS;
72*2989f645SChris Wilson 
73*2989f645SChris Wilson 	return -ETIME;
74*2989f645SChris Wilson }
75*2989f645SChris Wilson 
76*2989f645SChris Wilson static const struct dma_fence_ops mock_ops = {
77*2989f645SChris Wilson 	.get_driver_name = mock_name,
78*2989f645SChris Wilson 	.get_timeline_name = mock_name,
79*2989f645SChris Wilson 	.wait = mock_wait,
80*2989f645SChris Wilson 	.release = mock_fence_release,
81*2989f645SChris Wilson };
82*2989f645SChris Wilson 
83*2989f645SChris Wilson static struct dma_fence *mock_fence(void)
84*2989f645SChris Wilson {
85*2989f645SChris Wilson 	struct mock_fence *f;
86*2989f645SChris Wilson 
87*2989f645SChris Wilson 	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
88*2989f645SChris Wilson 	if (!f)
89*2989f645SChris Wilson 		return NULL;
90*2989f645SChris Wilson 
91*2989f645SChris Wilson 	spin_lock_init(&f->lock);
92*2989f645SChris Wilson 	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
93*2989f645SChris Wilson 
94*2989f645SChris Wilson 	return &f->base;
95*2989f645SChris Wilson }
96*2989f645SChris Wilson 
97*2989f645SChris Wilson static int sanitycheck(void *arg)
98*2989f645SChris Wilson {
99*2989f645SChris Wilson 	struct dma_fence *f;
100*2989f645SChris Wilson 
101*2989f645SChris Wilson 	f = mock_fence();
102*2989f645SChris Wilson 	if (!f)
103*2989f645SChris Wilson 		return -ENOMEM;
104*2989f645SChris Wilson 
105*2989f645SChris Wilson 	dma_fence_signal(f);
106*2989f645SChris Wilson 	dma_fence_put(f);
107*2989f645SChris Wilson 
108*2989f645SChris Wilson 	return 0;
109*2989f645SChris Wilson }
110*2989f645SChris Wilson 
111*2989f645SChris Wilson static int test_signaling(void *arg)
112*2989f645SChris Wilson {
113*2989f645SChris Wilson 	struct dma_fence *f;
114*2989f645SChris Wilson 	int err = -EINVAL;
115*2989f645SChris Wilson 
116*2989f645SChris Wilson 	f = mock_fence();
117*2989f645SChris Wilson 	if (!f)
118*2989f645SChris Wilson 		return -ENOMEM;
119*2989f645SChris Wilson 
120*2989f645SChris Wilson 	if (dma_fence_is_signaled(f)) {
121*2989f645SChris Wilson 		pr_err("Fence unexpectedly signaled on creation\n");
122*2989f645SChris Wilson 		goto err_free;
123*2989f645SChris Wilson 	}
124*2989f645SChris Wilson 
125*2989f645SChris Wilson 	if (dma_fence_signal(f)) {
126*2989f645SChris Wilson 		pr_err("Fence reported being already signaled\n");
127*2989f645SChris Wilson 		goto err_free;
128*2989f645SChris Wilson 	}
129*2989f645SChris Wilson 
130*2989f645SChris Wilson 	if (!dma_fence_is_signaled(f)) {
131*2989f645SChris Wilson 		pr_err("Fence not reporting signaled\n");
132*2989f645SChris Wilson 		goto err_free;
133*2989f645SChris Wilson 	}
134*2989f645SChris Wilson 
135*2989f645SChris Wilson 	if (!dma_fence_signal(f)) {
136*2989f645SChris Wilson 		pr_err("Fence reported not being already signaled\n");
137*2989f645SChris Wilson 		goto err_free;
138*2989f645SChris Wilson 	}
139*2989f645SChris Wilson 
140*2989f645SChris Wilson 	err = 0;
141*2989f645SChris Wilson err_free:
142*2989f645SChris Wilson 	dma_fence_put(f);
143*2989f645SChris Wilson 	return err;
144*2989f645SChris Wilson }
145*2989f645SChris Wilson 
146*2989f645SChris Wilson struct simple_cb {
147*2989f645SChris Wilson 	struct dma_fence_cb cb;
148*2989f645SChris Wilson 	bool seen;
149*2989f645SChris Wilson };
150*2989f645SChris Wilson 
151*2989f645SChris Wilson static void simple_callback(struct dma_fence *f, struct dma_fence_cb *cb)
152*2989f645SChris Wilson {
153*2989f645SChris Wilson 	smp_store_mb(container_of(cb, struct simple_cb, cb)->seen, true);
154*2989f645SChris Wilson }
155*2989f645SChris Wilson 
156*2989f645SChris Wilson static int test_add_callback(void *arg)
157*2989f645SChris Wilson {
158*2989f645SChris Wilson 	struct simple_cb cb = {};
159*2989f645SChris Wilson 	struct dma_fence *f;
160*2989f645SChris Wilson 	int err = -EINVAL;
161*2989f645SChris Wilson 
162*2989f645SChris Wilson 	f = mock_fence();
163*2989f645SChris Wilson 	if (!f)
164*2989f645SChris Wilson 		return -ENOMEM;
165*2989f645SChris Wilson 
166*2989f645SChris Wilson 	if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
167*2989f645SChris Wilson 		pr_err("Failed to add callback, fence already signaled!\n");
168*2989f645SChris Wilson 		goto err_free;
169*2989f645SChris Wilson 	}
170*2989f645SChris Wilson 
171*2989f645SChris Wilson 	dma_fence_signal(f);
172*2989f645SChris Wilson 	if (!cb.seen) {
173*2989f645SChris Wilson 		pr_err("Callback failed!\n");
174*2989f645SChris Wilson 		goto err_free;
175*2989f645SChris Wilson 	}
176*2989f645SChris Wilson 
177*2989f645SChris Wilson 	err = 0;
178*2989f645SChris Wilson err_free:
179*2989f645SChris Wilson 	dma_fence_put(f);
180*2989f645SChris Wilson 	return err;
181*2989f645SChris Wilson }
182*2989f645SChris Wilson 
183*2989f645SChris Wilson static int test_late_add_callback(void *arg)
184*2989f645SChris Wilson {
185*2989f645SChris Wilson 	struct simple_cb cb = {};
186*2989f645SChris Wilson 	struct dma_fence *f;
187*2989f645SChris Wilson 	int err = -EINVAL;
188*2989f645SChris Wilson 
189*2989f645SChris Wilson 	f = mock_fence();
190*2989f645SChris Wilson 	if (!f)
191*2989f645SChris Wilson 		return -ENOMEM;
192*2989f645SChris Wilson 
193*2989f645SChris Wilson 	dma_fence_signal(f);
194*2989f645SChris Wilson 
195*2989f645SChris Wilson 	if (!dma_fence_add_callback(f, &cb.cb, simple_callback)) {
196*2989f645SChris Wilson 		pr_err("Added callback, but fence was already signaled!\n");
197*2989f645SChris Wilson 		goto err_free;
198*2989f645SChris Wilson 	}
199*2989f645SChris Wilson 
200*2989f645SChris Wilson 	dma_fence_signal(f);
201*2989f645SChris Wilson 	if (cb.seen) {
202*2989f645SChris Wilson 		pr_err("Callback called after failed attachment !\n");
203*2989f645SChris Wilson 		goto err_free;
204*2989f645SChris Wilson 	}
205*2989f645SChris Wilson 
206*2989f645SChris Wilson 	err = 0;
207*2989f645SChris Wilson err_free:
208*2989f645SChris Wilson 	dma_fence_put(f);
209*2989f645SChris Wilson 	return err;
210*2989f645SChris Wilson }
211*2989f645SChris Wilson 
212*2989f645SChris Wilson static int test_rm_callback(void *arg)
213*2989f645SChris Wilson {
214*2989f645SChris Wilson 	struct simple_cb cb = {};
215*2989f645SChris Wilson 	struct dma_fence *f;
216*2989f645SChris Wilson 	int err = -EINVAL;
217*2989f645SChris Wilson 
218*2989f645SChris Wilson 	f = mock_fence();
219*2989f645SChris Wilson 	if (!f)
220*2989f645SChris Wilson 		return -ENOMEM;
221*2989f645SChris Wilson 
222*2989f645SChris Wilson 	if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
223*2989f645SChris Wilson 		pr_err("Failed to add callback, fence already signaled!\n");
224*2989f645SChris Wilson 		goto err_free;
225*2989f645SChris Wilson 	}
226*2989f645SChris Wilson 
227*2989f645SChris Wilson 	if (!dma_fence_remove_callback(f, &cb.cb)) {
228*2989f645SChris Wilson 		pr_err("Failed to remove callback!\n");
229*2989f645SChris Wilson 		goto err_free;
230*2989f645SChris Wilson 	}
231*2989f645SChris Wilson 
232*2989f645SChris Wilson 	dma_fence_signal(f);
233*2989f645SChris Wilson 	if (cb.seen) {
234*2989f645SChris Wilson 		pr_err("Callback still signaled after removal!\n");
235*2989f645SChris Wilson 		goto err_free;
236*2989f645SChris Wilson 	}
237*2989f645SChris Wilson 
238*2989f645SChris Wilson 	err = 0;
239*2989f645SChris Wilson err_free:
240*2989f645SChris Wilson 	dma_fence_put(f);
241*2989f645SChris Wilson 	return err;
242*2989f645SChris Wilson }
243*2989f645SChris Wilson 
244*2989f645SChris Wilson static int test_late_rm_callback(void *arg)
245*2989f645SChris Wilson {
246*2989f645SChris Wilson 	struct simple_cb cb = {};
247*2989f645SChris Wilson 	struct dma_fence *f;
248*2989f645SChris Wilson 	int err = -EINVAL;
249*2989f645SChris Wilson 
250*2989f645SChris Wilson 	f = mock_fence();
251*2989f645SChris Wilson 	if (!f)
252*2989f645SChris Wilson 		return -ENOMEM;
253*2989f645SChris Wilson 
254*2989f645SChris Wilson 	if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
255*2989f645SChris Wilson 		pr_err("Failed to add callback, fence already signaled!\n");
256*2989f645SChris Wilson 		goto err_free;
257*2989f645SChris Wilson 	}
258*2989f645SChris Wilson 
259*2989f645SChris Wilson 	dma_fence_signal(f);
260*2989f645SChris Wilson 	if (!cb.seen) {
261*2989f645SChris Wilson 		pr_err("Callback failed!\n");
262*2989f645SChris Wilson 		goto err_free;
263*2989f645SChris Wilson 	}
264*2989f645SChris Wilson 
265*2989f645SChris Wilson 	if (dma_fence_remove_callback(f, &cb.cb)) {
266*2989f645SChris Wilson 		pr_err("Callback removal succeed after being executed!\n");
267*2989f645SChris Wilson 		goto err_free;
268*2989f645SChris Wilson 	}
269*2989f645SChris Wilson 
270*2989f645SChris Wilson 	err = 0;
271*2989f645SChris Wilson err_free:
272*2989f645SChris Wilson 	dma_fence_put(f);
273*2989f645SChris Wilson 	return err;
274*2989f645SChris Wilson }
275*2989f645SChris Wilson 
276*2989f645SChris Wilson static int test_status(void *arg)
277*2989f645SChris Wilson {
278*2989f645SChris Wilson 	struct dma_fence *f;
279*2989f645SChris Wilson 	int err = -EINVAL;
280*2989f645SChris Wilson 
281*2989f645SChris Wilson 	f = mock_fence();
282*2989f645SChris Wilson 	if (!f)
283*2989f645SChris Wilson 		return -ENOMEM;
284*2989f645SChris Wilson 
285*2989f645SChris Wilson 	if (dma_fence_get_status(f)) {
286*2989f645SChris Wilson 		pr_err("Fence unexpectedly has signaled status on creation\n");
287*2989f645SChris Wilson 		goto err_free;
288*2989f645SChris Wilson 	}
289*2989f645SChris Wilson 
290*2989f645SChris Wilson 	dma_fence_signal(f);
291*2989f645SChris Wilson 	if (!dma_fence_get_status(f)) {
292*2989f645SChris Wilson 		pr_err("Fence not reporting signaled status\n");
293*2989f645SChris Wilson 		goto err_free;
294*2989f645SChris Wilson 	}
295*2989f645SChris Wilson 
296*2989f645SChris Wilson 	err = 0;
297*2989f645SChris Wilson err_free:
298*2989f645SChris Wilson 	dma_fence_put(f);
299*2989f645SChris Wilson 	return err;
300*2989f645SChris Wilson }
301*2989f645SChris Wilson 
302*2989f645SChris Wilson static int test_error(void *arg)
303*2989f645SChris Wilson {
304*2989f645SChris Wilson 	struct dma_fence *f;
305*2989f645SChris Wilson 	int err = -EINVAL;
306*2989f645SChris Wilson 
307*2989f645SChris Wilson 	f = mock_fence();
308*2989f645SChris Wilson 	if (!f)
309*2989f645SChris Wilson 		return -ENOMEM;
310*2989f645SChris Wilson 
311*2989f645SChris Wilson 	dma_fence_set_error(f, -EIO);
312*2989f645SChris Wilson 
313*2989f645SChris Wilson 	if (dma_fence_get_status(f)) {
314*2989f645SChris Wilson 		pr_err("Fence unexpectedly has error status before signal\n");
315*2989f645SChris Wilson 		goto err_free;
316*2989f645SChris Wilson 	}
317*2989f645SChris Wilson 
318*2989f645SChris Wilson 	dma_fence_signal(f);
319*2989f645SChris Wilson 	if (dma_fence_get_status(f) != -EIO) {
320*2989f645SChris Wilson 		pr_err("Fence not reporting error status, got %d\n",
321*2989f645SChris Wilson 		       dma_fence_get_status(f));
322*2989f645SChris Wilson 		goto err_free;
323*2989f645SChris Wilson 	}
324*2989f645SChris Wilson 
325*2989f645SChris Wilson 	err = 0;
326*2989f645SChris Wilson err_free:
327*2989f645SChris Wilson 	dma_fence_put(f);
328*2989f645SChris Wilson 	return err;
329*2989f645SChris Wilson }
330*2989f645SChris Wilson 
331*2989f645SChris Wilson static int test_wait(void *arg)
332*2989f645SChris Wilson {
333*2989f645SChris Wilson 	struct dma_fence *f;
334*2989f645SChris Wilson 	int err = -EINVAL;
335*2989f645SChris Wilson 
336*2989f645SChris Wilson 	f = mock_fence();
337*2989f645SChris Wilson 	if (!f)
338*2989f645SChris Wilson 		return -ENOMEM;
339*2989f645SChris Wilson 
340*2989f645SChris Wilson 	if (dma_fence_wait_timeout(f, false, 0) != -ETIME) {
341*2989f645SChris Wilson 		pr_err("Wait reported complete before being signaled\n");
342*2989f645SChris Wilson 		goto err_free;
343*2989f645SChris Wilson 	}
344*2989f645SChris Wilson 
345*2989f645SChris Wilson 	dma_fence_signal(f);
346*2989f645SChris Wilson 
347*2989f645SChris Wilson 	if (dma_fence_wait_timeout(f, false, 0) != 0) {
348*2989f645SChris Wilson 		pr_err("Wait reported incomplete after being signaled\n");
349*2989f645SChris Wilson 		goto err_free;
350*2989f645SChris Wilson 	}
351*2989f645SChris Wilson 
352*2989f645SChris Wilson 	err = 0;
353*2989f645SChris Wilson err_free:
354*2989f645SChris Wilson 	dma_fence_signal(f);
355*2989f645SChris Wilson 	dma_fence_put(f);
356*2989f645SChris Wilson 	return err;
357*2989f645SChris Wilson }
358*2989f645SChris Wilson 
359*2989f645SChris Wilson struct wait_timer {
360*2989f645SChris Wilson 	struct timer_list timer;
361*2989f645SChris Wilson 	struct dma_fence *f;
362*2989f645SChris Wilson };
363*2989f645SChris Wilson 
364*2989f645SChris Wilson static void wait_timer(struct timer_list *timer)
365*2989f645SChris Wilson {
366*2989f645SChris Wilson 	struct wait_timer *wt = from_timer(wt, timer, timer);
367*2989f645SChris Wilson 
368*2989f645SChris Wilson 	dma_fence_signal(wt->f);
369*2989f645SChris Wilson }
370*2989f645SChris Wilson 
371*2989f645SChris Wilson static int test_wait_timeout(void *arg)
372*2989f645SChris Wilson {
373*2989f645SChris Wilson 	struct wait_timer wt;
374*2989f645SChris Wilson 	int err = -EINVAL;
375*2989f645SChris Wilson 
376*2989f645SChris Wilson 	timer_setup(&wt.timer, wait_timer, 0);
377*2989f645SChris Wilson 
378*2989f645SChris Wilson 	wt.f = mock_fence();
379*2989f645SChris Wilson 	if (!wt.f)
380*2989f645SChris Wilson 		return -ENOMEM;
381*2989f645SChris Wilson 
382*2989f645SChris Wilson 	if (dma_fence_wait_timeout(wt.f, false, 1) != -ETIME) {
383*2989f645SChris Wilson 		pr_err("Wait reported complete before being signaled\n");
384*2989f645SChris Wilson 		goto err_free;
385*2989f645SChris Wilson 	}
386*2989f645SChris Wilson 
387*2989f645SChris Wilson 	mod_timer(&wt.timer, jiffies + 1);
388*2989f645SChris Wilson 
389*2989f645SChris Wilson 	if (dma_fence_wait_timeout(wt.f, false, 2) == -ETIME) {
390*2989f645SChris Wilson 		if (timer_pending(&wt.timer)) {
391*2989f645SChris Wilson 			pr_notice("Timer did not fire within the jiffie!\n");
392*2989f645SChris Wilson 			err = 0; /* not our fault! */
393*2989f645SChris Wilson 		} else {
394*2989f645SChris Wilson 			pr_err("Wait reported incomplete after timeout\n");
395*2989f645SChris Wilson 		}
396*2989f645SChris Wilson 		goto err_free;
397*2989f645SChris Wilson 	}
398*2989f645SChris Wilson 
399*2989f645SChris Wilson 	err = 0;
400*2989f645SChris Wilson err_free:
401*2989f645SChris Wilson 	del_timer_sync(&wt.timer);
402*2989f645SChris Wilson 	dma_fence_signal(wt.f);
403*2989f645SChris Wilson 	dma_fence_put(wt.f);
404*2989f645SChris Wilson 	return err;
405*2989f645SChris Wilson }
406*2989f645SChris Wilson 
407*2989f645SChris Wilson static int test_stub(void *arg)
408*2989f645SChris Wilson {
409*2989f645SChris Wilson 	struct dma_fence *f[64];
410*2989f645SChris Wilson 	int err = -EINVAL;
411*2989f645SChris Wilson 	int i;
412*2989f645SChris Wilson 
413*2989f645SChris Wilson 	for (i = 0; i < ARRAY_SIZE(f); i++) {
414*2989f645SChris Wilson 		f[i] = dma_fence_get_stub();
415*2989f645SChris Wilson 		if (!dma_fence_is_signaled(f[i])) {
416*2989f645SChris Wilson 			pr_err("Obtained unsignaled stub fence!\n");
417*2989f645SChris Wilson 			goto err;
418*2989f645SChris Wilson 		}
419*2989f645SChris Wilson 	}
420*2989f645SChris Wilson 
421*2989f645SChris Wilson 	err = 0;
422*2989f645SChris Wilson err:
423*2989f645SChris Wilson 	while (i--)
424*2989f645SChris Wilson 		dma_fence_put(f[i]);
425*2989f645SChris Wilson 	return err;
426*2989f645SChris Wilson }
427*2989f645SChris Wilson 
428*2989f645SChris Wilson /* Now off to the races! */
429*2989f645SChris Wilson 
430*2989f645SChris Wilson struct race_thread {
431*2989f645SChris Wilson 	struct dma_fence __rcu **fences;
432*2989f645SChris Wilson 	struct task_struct *task;
433*2989f645SChris Wilson 	bool before;
434*2989f645SChris Wilson 	int id;
435*2989f645SChris Wilson };
436*2989f645SChris Wilson 
437*2989f645SChris Wilson static void __wait_for_callbacks(struct dma_fence *f)
438*2989f645SChris Wilson {
439*2989f645SChris Wilson 	spin_lock_irq(f->lock);
440*2989f645SChris Wilson 	spin_unlock_irq(f->lock);
441*2989f645SChris Wilson }
442*2989f645SChris Wilson 
443*2989f645SChris Wilson static int thread_signal_callback(void *arg)
444*2989f645SChris Wilson {
445*2989f645SChris Wilson 	const struct race_thread *t = arg;
446*2989f645SChris Wilson 	unsigned long pass = 0;
447*2989f645SChris Wilson 	unsigned long miss = 0;
448*2989f645SChris Wilson 	int err = 0;
449*2989f645SChris Wilson 
450*2989f645SChris Wilson 	while (!err && !kthread_should_stop()) {
451*2989f645SChris Wilson 		struct dma_fence *f1, *f2;
452*2989f645SChris Wilson 		struct simple_cb cb;
453*2989f645SChris Wilson 
454*2989f645SChris Wilson 		f1 = mock_fence();
455*2989f645SChris Wilson 		if (!f1) {
456*2989f645SChris Wilson 			err = -ENOMEM;
457*2989f645SChris Wilson 			break;
458*2989f645SChris Wilson 		}
459*2989f645SChris Wilson 
460*2989f645SChris Wilson 		rcu_assign_pointer(t->fences[t->id], f1);
461*2989f645SChris Wilson 		smp_wmb();
462*2989f645SChris Wilson 
463*2989f645SChris Wilson 		rcu_read_lock();
464*2989f645SChris Wilson 		do {
465*2989f645SChris Wilson 			f2 = dma_fence_get_rcu_safe(&t->fences[!t->id]);
466*2989f645SChris Wilson 		} while (!f2 && !kthread_should_stop());
467*2989f645SChris Wilson 		rcu_read_unlock();
468*2989f645SChris Wilson 
469*2989f645SChris Wilson 		if (t->before)
470*2989f645SChris Wilson 			dma_fence_signal(f1);
471*2989f645SChris Wilson 
472*2989f645SChris Wilson 		smp_store_mb(cb.seen, false);
473*2989f645SChris Wilson 		if (!f2 || dma_fence_add_callback(f2, &cb.cb, simple_callback))
474*2989f645SChris Wilson 			miss++, cb.seen = true;
475*2989f645SChris Wilson 
476*2989f645SChris Wilson 		if (!t->before)
477*2989f645SChris Wilson 			dma_fence_signal(f1);
478*2989f645SChris Wilson 
479*2989f645SChris Wilson 		if (!cb.seen) {
480*2989f645SChris Wilson 			dma_fence_wait(f2, false);
481*2989f645SChris Wilson 			__wait_for_callbacks(f2);
482*2989f645SChris Wilson 		}
483*2989f645SChris Wilson 
484*2989f645SChris Wilson 		if (!READ_ONCE(cb.seen)) {
485*2989f645SChris Wilson 			pr_err("Callback not seen on thread %d, pass %lu (%lu misses), signaling %s add_callback; fence signaled? %s\n",
486*2989f645SChris Wilson 			       t->id, pass, miss,
487*2989f645SChris Wilson 			       t->before ? "before" : "after",
488*2989f645SChris Wilson 			       dma_fence_is_signaled(f2) ? "yes" : "no");
489*2989f645SChris Wilson 			err = -EINVAL;
490*2989f645SChris Wilson 		}
491*2989f645SChris Wilson 
492*2989f645SChris Wilson 		dma_fence_put(f2);
493*2989f645SChris Wilson 
494*2989f645SChris Wilson 		rcu_assign_pointer(t->fences[t->id], NULL);
495*2989f645SChris Wilson 		smp_wmb();
496*2989f645SChris Wilson 
497*2989f645SChris Wilson 		dma_fence_put(f1);
498*2989f645SChris Wilson 
499*2989f645SChris Wilson 		pass++;
500*2989f645SChris Wilson 	}
501*2989f645SChris Wilson 
502*2989f645SChris Wilson 	pr_info("%s[%d] completed %lu passes, %lu misses\n",
503*2989f645SChris Wilson 		__func__, t->id, pass, miss);
504*2989f645SChris Wilson 	return err;
505*2989f645SChris Wilson }
506*2989f645SChris Wilson 
507*2989f645SChris Wilson static int race_signal_callback(void *arg)
508*2989f645SChris Wilson {
509*2989f645SChris Wilson 	struct dma_fence __rcu *f[2] = {};
510*2989f645SChris Wilson 	int ret = 0;
511*2989f645SChris Wilson 	int pass;
512*2989f645SChris Wilson 
513*2989f645SChris Wilson 	for (pass = 0; !ret && pass <= 1; pass++) {
514*2989f645SChris Wilson 		struct race_thread t[2];
515*2989f645SChris Wilson 		int i;
516*2989f645SChris Wilson 
517*2989f645SChris Wilson 		for (i = 0; i < ARRAY_SIZE(t); i++) {
518*2989f645SChris Wilson 			t[i].fences = f;
519*2989f645SChris Wilson 			t[i].id = i;
520*2989f645SChris Wilson 			t[i].before = pass;
521*2989f645SChris Wilson 			t[i].task = kthread_run(thread_signal_callback, &t[i],
522*2989f645SChris Wilson 						"dma-fence:%d", i);
523*2989f645SChris Wilson 			get_task_struct(t[i].task);
524*2989f645SChris Wilson 		}
525*2989f645SChris Wilson 
526*2989f645SChris Wilson 		msleep(50);
527*2989f645SChris Wilson 
528*2989f645SChris Wilson 		for (i = 0; i < ARRAY_SIZE(t); i++) {
529*2989f645SChris Wilson 			int err;
530*2989f645SChris Wilson 
531*2989f645SChris Wilson 			err = kthread_stop(t[i].task);
532*2989f645SChris Wilson 			if (err && !ret)
533*2989f645SChris Wilson 				ret = err;
534*2989f645SChris Wilson 
535*2989f645SChris Wilson 			put_task_struct(t[i].task);
536*2989f645SChris Wilson 		}
537*2989f645SChris Wilson 	}
538*2989f645SChris Wilson 
539*2989f645SChris Wilson 	return ret;
540*2989f645SChris Wilson }
541*2989f645SChris Wilson 
542*2989f645SChris Wilson int dma_fence(void)
543*2989f645SChris Wilson {
544*2989f645SChris Wilson 	static const struct subtest tests[] = {
545*2989f645SChris Wilson 		SUBTEST(sanitycheck),
546*2989f645SChris Wilson 		SUBTEST(test_signaling),
547*2989f645SChris Wilson 		SUBTEST(test_add_callback),
548*2989f645SChris Wilson 		SUBTEST(test_late_add_callback),
549*2989f645SChris Wilson 		SUBTEST(test_rm_callback),
550*2989f645SChris Wilson 		SUBTEST(test_late_rm_callback),
551*2989f645SChris Wilson 		SUBTEST(test_status),
552*2989f645SChris Wilson 		SUBTEST(test_error),
553*2989f645SChris Wilson 		SUBTEST(test_wait),
554*2989f645SChris Wilson 		SUBTEST(test_wait_timeout),
555*2989f645SChris Wilson 		SUBTEST(test_stub),
556*2989f645SChris Wilson 		SUBTEST(race_signal_callback),
557*2989f645SChris Wilson 	};
558*2989f645SChris Wilson 	int ret;
559*2989f645SChris Wilson 
560*2989f645SChris Wilson 	pr_info("sizeof(dma_fence)=%lu\n", sizeof(struct dma_fence));
561*2989f645SChris Wilson 
562*2989f645SChris Wilson 	slab_fences = KMEM_CACHE(mock_fence,
563*2989f645SChris Wilson 				 SLAB_TYPESAFE_BY_RCU |
564*2989f645SChris Wilson 				 SLAB_HWCACHE_ALIGN);
565*2989f645SChris Wilson 	if (!slab_fences)
566*2989f645SChris Wilson 		return -ENOMEM;
567*2989f645SChris Wilson 
568*2989f645SChris Wilson 	ret = subtests(tests, NULL);
569*2989f645SChris Wilson 
570*2989f645SChris Wilson 	kmem_cache_destroy(slab_fences);
571*2989f645SChris Wilson 
572*2989f645SChris Wilson 	return ret;
573*2989f645SChris Wilson }
574