162306a36Sopenharmony_ci/* SPDX-License-Identifier: MIT */
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci/*
462306a36Sopenharmony_ci * Copyright © 2019 Intel Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/delay.h>
862306a36Sopenharmony_ci#include <linux/dma-fence.h>
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/kthread.h>
1162306a36Sopenharmony_ci#include <linux/sched/signal.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/spinlock.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "selftest.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic struct kmem_cache *slab_fences;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic struct mock_fence {
2062306a36Sopenharmony_ci	struct dma_fence base;
2162306a36Sopenharmony_ci	struct spinlock lock;
2262306a36Sopenharmony_ci} *to_mock_fence(struct dma_fence *f) {
2362306a36Sopenharmony_ci	return container_of(f, struct mock_fence, base);
2462306a36Sopenharmony_ci}
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic const char *mock_name(struct dma_fence *f)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	return "mock";
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic void mock_fence_release(struct dma_fence *f)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	kmem_cache_free(slab_fences, to_mock_fence(f));
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistruct wait_cb {
3762306a36Sopenharmony_ci	struct dma_fence_cb cb;
3862306a36Sopenharmony_ci	struct task_struct *task;
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic void mock_wakeup(struct dma_fence *f, struct dma_fence_cb *cb)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	wake_up_process(container_of(cb, struct wait_cb, cb)->task);
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic long mock_wait(struct dma_fence *f, bool intr, long timeout)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	const int state = intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
4962306a36Sopenharmony_ci	struct wait_cb cb = { .task = current };
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	if (dma_fence_add_callback(f, &cb.cb, mock_wakeup))
5262306a36Sopenharmony_ci		return timeout;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	while (timeout) {
5562306a36Sopenharmony_ci		set_current_state(state);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci		if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &f->flags))
5862306a36Sopenharmony_ci			break;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci		if (signal_pending_state(state, current))
6162306a36Sopenharmony_ci			break;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		timeout = schedule_timeout(timeout);
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci	__set_current_state(TASK_RUNNING);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (!dma_fence_remove_callback(f, &cb.cb))
6862306a36Sopenharmony_ci		return timeout;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	if (signal_pending_state(state, current))
7162306a36Sopenharmony_ci		return -ERESTARTSYS;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	return -ETIME;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic const struct dma_fence_ops mock_ops = {
7762306a36Sopenharmony_ci	.get_driver_name = mock_name,
7862306a36Sopenharmony_ci	.get_timeline_name = mock_name,
7962306a36Sopenharmony_ci	.wait = mock_wait,
8062306a36Sopenharmony_ci	.release = mock_fence_release,
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic struct dma_fence *mock_fence(void)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct mock_fence *f;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	f = kmem_cache_alloc(slab_fences, GFP_KERNEL);
8862306a36Sopenharmony_ci	if (!f)
8962306a36Sopenharmony_ci		return NULL;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	spin_lock_init(&f->lock);
9262306a36Sopenharmony_ci	dma_fence_init(&f->base, &mock_ops, &f->lock, 0, 0);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	return &f->base;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic int sanitycheck(void *arg)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct dma_fence *f;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	f = mock_fence();
10262306a36Sopenharmony_ci	if (!f)
10362306a36Sopenharmony_ci		return -ENOMEM;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	dma_fence_enable_sw_signaling(f);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	dma_fence_signal(f);
10862306a36Sopenharmony_ci	dma_fence_put(f);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	return 0;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic int test_signaling(void *arg)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	struct dma_fence *f;
11662306a36Sopenharmony_ci	int err = -EINVAL;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	f = mock_fence();
11962306a36Sopenharmony_ci	if (!f)
12062306a36Sopenharmony_ci		return -ENOMEM;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	dma_fence_enable_sw_signaling(f);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (dma_fence_is_signaled(f)) {
12562306a36Sopenharmony_ci		pr_err("Fence unexpectedly signaled on creation\n");
12662306a36Sopenharmony_ci		goto err_free;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	if (dma_fence_signal(f)) {
13062306a36Sopenharmony_ci		pr_err("Fence reported being already signaled\n");
13162306a36Sopenharmony_ci		goto err_free;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	if (!dma_fence_is_signaled(f)) {
13562306a36Sopenharmony_ci		pr_err("Fence not reporting signaled\n");
13662306a36Sopenharmony_ci		goto err_free;
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (!dma_fence_signal(f)) {
14062306a36Sopenharmony_ci		pr_err("Fence reported not being already signaled\n");
14162306a36Sopenharmony_ci		goto err_free;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	err = 0;
14562306a36Sopenharmony_cierr_free:
14662306a36Sopenharmony_ci	dma_fence_put(f);
14762306a36Sopenharmony_ci	return err;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistruct simple_cb {
15162306a36Sopenharmony_ci	struct dma_fence_cb cb;
15262306a36Sopenharmony_ci	bool seen;
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic void simple_callback(struct dma_fence *f, struct dma_fence_cb *cb)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	smp_store_mb(container_of(cb, struct simple_cb, cb)->seen, true);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int test_add_callback(void *arg)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct simple_cb cb = {};
16362306a36Sopenharmony_ci	struct dma_fence *f;
16462306a36Sopenharmony_ci	int err = -EINVAL;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	f = mock_fence();
16762306a36Sopenharmony_ci	if (!f)
16862306a36Sopenharmony_ci		return -ENOMEM;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
17162306a36Sopenharmony_ci		pr_err("Failed to add callback, fence already signaled!\n");
17262306a36Sopenharmony_ci		goto err_free;
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	dma_fence_signal(f);
17662306a36Sopenharmony_ci	if (!cb.seen) {
17762306a36Sopenharmony_ci		pr_err("Callback failed!\n");
17862306a36Sopenharmony_ci		goto err_free;
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	err = 0;
18262306a36Sopenharmony_cierr_free:
18362306a36Sopenharmony_ci	dma_fence_put(f);
18462306a36Sopenharmony_ci	return err;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic int test_late_add_callback(void *arg)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct simple_cb cb = {};
19062306a36Sopenharmony_ci	struct dma_fence *f;
19162306a36Sopenharmony_ci	int err = -EINVAL;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	f = mock_fence();
19462306a36Sopenharmony_ci	if (!f)
19562306a36Sopenharmony_ci		return -ENOMEM;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	dma_fence_enable_sw_signaling(f);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	dma_fence_signal(f);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (!dma_fence_add_callback(f, &cb.cb, simple_callback)) {
20262306a36Sopenharmony_ci		pr_err("Added callback, but fence was already signaled!\n");
20362306a36Sopenharmony_ci		goto err_free;
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	dma_fence_signal(f);
20762306a36Sopenharmony_ci	if (cb.seen) {
20862306a36Sopenharmony_ci		pr_err("Callback called after failed attachment !\n");
20962306a36Sopenharmony_ci		goto err_free;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	err = 0;
21362306a36Sopenharmony_cierr_free:
21462306a36Sopenharmony_ci	dma_fence_put(f);
21562306a36Sopenharmony_ci	return err;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic int test_rm_callback(void *arg)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct simple_cb cb = {};
22162306a36Sopenharmony_ci	struct dma_fence *f;
22262306a36Sopenharmony_ci	int err = -EINVAL;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	f = mock_fence();
22562306a36Sopenharmony_ci	if (!f)
22662306a36Sopenharmony_ci		return -ENOMEM;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
22962306a36Sopenharmony_ci		pr_err("Failed to add callback, fence already signaled!\n");
23062306a36Sopenharmony_ci		goto err_free;
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	if (!dma_fence_remove_callback(f, &cb.cb)) {
23462306a36Sopenharmony_ci		pr_err("Failed to remove callback!\n");
23562306a36Sopenharmony_ci		goto err_free;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	dma_fence_signal(f);
23962306a36Sopenharmony_ci	if (cb.seen) {
24062306a36Sopenharmony_ci		pr_err("Callback still signaled after removal!\n");
24162306a36Sopenharmony_ci		goto err_free;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	err = 0;
24562306a36Sopenharmony_cierr_free:
24662306a36Sopenharmony_ci	dma_fence_put(f);
24762306a36Sopenharmony_ci	return err;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic int test_late_rm_callback(void *arg)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct simple_cb cb = {};
25362306a36Sopenharmony_ci	struct dma_fence *f;
25462306a36Sopenharmony_ci	int err = -EINVAL;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	f = mock_fence();
25762306a36Sopenharmony_ci	if (!f)
25862306a36Sopenharmony_ci		return -ENOMEM;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	if (dma_fence_add_callback(f, &cb.cb, simple_callback)) {
26162306a36Sopenharmony_ci		pr_err("Failed to add callback, fence already signaled!\n");
26262306a36Sopenharmony_ci		goto err_free;
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	dma_fence_signal(f);
26662306a36Sopenharmony_ci	if (!cb.seen) {
26762306a36Sopenharmony_ci		pr_err("Callback failed!\n");
26862306a36Sopenharmony_ci		goto err_free;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (dma_fence_remove_callback(f, &cb.cb)) {
27262306a36Sopenharmony_ci		pr_err("Callback removal succeed after being executed!\n");
27362306a36Sopenharmony_ci		goto err_free;
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	err = 0;
27762306a36Sopenharmony_cierr_free:
27862306a36Sopenharmony_ci	dma_fence_put(f);
27962306a36Sopenharmony_ci	return err;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int test_status(void *arg)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	struct dma_fence *f;
28562306a36Sopenharmony_ci	int err = -EINVAL;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	f = mock_fence();
28862306a36Sopenharmony_ci	if (!f)
28962306a36Sopenharmony_ci		return -ENOMEM;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	dma_fence_enable_sw_signaling(f);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	if (dma_fence_get_status(f)) {
29462306a36Sopenharmony_ci		pr_err("Fence unexpectedly has signaled status on creation\n");
29562306a36Sopenharmony_ci		goto err_free;
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	dma_fence_signal(f);
29962306a36Sopenharmony_ci	if (!dma_fence_get_status(f)) {
30062306a36Sopenharmony_ci		pr_err("Fence not reporting signaled status\n");
30162306a36Sopenharmony_ci		goto err_free;
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	err = 0;
30562306a36Sopenharmony_cierr_free:
30662306a36Sopenharmony_ci	dma_fence_put(f);
30762306a36Sopenharmony_ci	return err;
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic int test_error(void *arg)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	struct dma_fence *f;
31362306a36Sopenharmony_ci	int err = -EINVAL;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	f = mock_fence();
31662306a36Sopenharmony_ci	if (!f)
31762306a36Sopenharmony_ci		return -ENOMEM;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	dma_fence_enable_sw_signaling(f);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	dma_fence_set_error(f, -EIO);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	if (dma_fence_get_status(f)) {
32462306a36Sopenharmony_ci		pr_err("Fence unexpectedly has error status before signal\n");
32562306a36Sopenharmony_ci		goto err_free;
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	dma_fence_signal(f);
32962306a36Sopenharmony_ci	if (dma_fence_get_status(f) != -EIO) {
33062306a36Sopenharmony_ci		pr_err("Fence not reporting error status, got %d\n",
33162306a36Sopenharmony_ci		       dma_fence_get_status(f));
33262306a36Sopenharmony_ci		goto err_free;
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	err = 0;
33662306a36Sopenharmony_cierr_free:
33762306a36Sopenharmony_ci	dma_fence_put(f);
33862306a36Sopenharmony_ci	return err;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic int test_wait(void *arg)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct dma_fence *f;
34462306a36Sopenharmony_ci	int err = -EINVAL;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	f = mock_fence();
34762306a36Sopenharmony_ci	if (!f)
34862306a36Sopenharmony_ci		return -ENOMEM;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	dma_fence_enable_sw_signaling(f);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	if (dma_fence_wait_timeout(f, false, 0) != -ETIME) {
35362306a36Sopenharmony_ci		pr_err("Wait reported complete before being signaled\n");
35462306a36Sopenharmony_ci		goto err_free;
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	dma_fence_signal(f);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (dma_fence_wait_timeout(f, false, 0) != 0) {
36062306a36Sopenharmony_ci		pr_err("Wait reported incomplete after being signaled\n");
36162306a36Sopenharmony_ci		goto err_free;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	err = 0;
36562306a36Sopenharmony_cierr_free:
36662306a36Sopenharmony_ci	dma_fence_signal(f);
36762306a36Sopenharmony_ci	dma_fence_put(f);
36862306a36Sopenharmony_ci	return err;
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistruct wait_timer {
37262306a36Sopenharmony_ci	struct timer_list timer;
37362306a36Sopenharmony_ci	struct dma_fence *f;
37462306a36Sopenharmony_ci};
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic void wait_timer(struct timer_list *timer)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	struct wait_timer *wt = from_timer(wt, timer, timer);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	dma_fence_signal(wt->f);
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic int test_wait_timeout(void *arg)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct wait_timer wt;
38662306a36Sopenharmony_ci	int err = -EINVAL;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	timer_setup_on_stack(&wt.timer, wait_timer, 0);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	wt.f = mock_fence();
39162306a36Sopenharmony_ci	if (!wt.f)
39262306a36Sopenharmony_ci		return -ENOMEM;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	dma_fence_enable_sw_signaling(wt.f);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (dma_fence_wait_timeout(wt.f, false, 1) != -ETIME) {
39762306a36Sopenharmony_ci		pr_err("Wait reported complete before being signaled\n");
39862306a36Sopenharmony_ci		goto err_free;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	mod_timer(&wt.timer, jiffies + 1);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if (dma_fence_wait_timeout(wt.f, false, 2) == -ETIME) {
40462306a36Sopenharmony_ci		if (timer_pending(&wt.timer)) {
40562306a36Sopenharmony_ci			pr_notice("Timer did not fire within the jiffie!\n");
40662306a36Sopenharmony_ci			err = 0; /* not our fault! */
40762306a36Sopenharmony_ci		} else {
40862306a36Sopenharmony_ci			pr_err("Wait reported incomplete after timeout\n");
40962306a36Sopenharmony_ci		}
41062306a36Sopenharmony_ci		goto err_free;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	err = 0;
41462306a36Sopenharmony_cierr_free:
41562306a36Sopenharmony_ci	del_timer_sync(&wt.timer);
41662306a36Sopenharmony_ci	destroy_timer_on_stack(&wt.timer);
41762306a36Sopenharmony_ci	dma_fence_signal(wt.f);
41862306a36Sopenharmony_ci	dma_fence_put(wt.f);
41962306a36Sopenharmony_ci	return err;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic int test_stub(void *arg)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	struct dma_fence *f[64];
42562306a36Sopenharmony_ci	int err = -EINVAL;
42662306a36Sopenharmony_ci	int i;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(f); i++) {
42962306a36Sopenharmony_ci		f[i] = dma_fence_get_stub();
43062306a36Sopenharmony_ci		if (!dma_fence_is_signaled(f[i])) {
43162306a36Sopenharmony_ci			pr_err("Obtained unsignaled stub fence!\n");
43262306a36Sopenharmony_ci			goto err;
43362306a36Sopenharmony_ci		}
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	err = 0;
43762306a36Sopenharmony_cierr:
43862306a36Sopenharmony_ci	while (i--)
43962306a36Sopenharmony_ci		dma_fence_put(f[i]);
44062306a36Sopenharmony_ci	return err;
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci/* Now off to the races! */
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistruct race_thread {
44662306a36Sopenharmony_ci	struct dma_fence __rcu **fences;
44762306a36Sopenharmony_ci	struct task_struct *task;
44862306a36Sopenharmony_ci	bool before;
44962306a36Sopenharmony_ci	int id;
45062306a36Sopenharmony_ci};
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic void __wait_for_callbacks(struct dma_fence *f)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	spin_lock_irq(f->lock);
45562306a36Sopenharmony_ci	spin_unlock_irq(f->lock);
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_cistatic int thread_signal_callback(void *arg)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	const struct race_thread *t = arg;
46162306a36Sopenharmony_ci	unsigned long pass = 0;
46262306a36Sopenharmony_ci	unsigned long miss = 0;
46362306a36Sopenharmony_ci	int err = 0;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	while (!err && !kthread_should_stop()) {
46662306a36Sopenharmony_ci		struct dma_fence *f1, *f2;
46762306a36Sopenharmony_ci		struct simple_cb cb;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci		f1 = mock_fence();
47062306a36Sopenharmony_ci		if (!f1) {
47162306a36Sopenharmony_ci			err = -ENOMEM;
47262306a36Sopenharmony_ci			break;
47362306a36Sopenharmony_ci		}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		dma_fence_enable_sw_signaling(f1);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		rcu_assign_pointer(t->fences[t->id], f1);
47862306a36Sopenharmony_ci		smp_wmb();
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		rcu_read_lock();
48162306a36Sopenharmony_ci		do {
48262306a36Sopenharmony_ci			f2 = dma_fence_get_rcu_safe(&t->fences[!t->id]);
48362306a36Sopenharmony_ci		} while (!f2 && !kthread_should_stop());
48462306a36Sopenharmony_ci		rcu_read_unlock();
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci		if (t->before)
48762306a36Sopenharmony_ci			dma_fence_signal(f1);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci		smp_store_mb(cb.seen, false);
49062306a36Sopenharmony_ci		if (!f2 ||
49162306a36Sopenharmony_ci		    dma_fence_add_callback(f2, &cb.cb, simple_callback)) {
49262306a36Sopenharmony_ci			miss++;
49362306a36Sopenharmony_ci			cb.seen = true;
49462306a36Sopenharmony_ci		}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci		if (!t->before)
49762306a36Sopenharmony_ci			dma_fence_signal(f1);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci		if (!cb.seen) {
50062306a36Sopenharmony_ci			dma_fence_wait(f2, false);
50162306a36Sopenharmony_ci			__wait_for_callbacks(f2);
50262306a36Sopenharmony_ci		}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci		if (!READ_ONCE(cb.seen)) {
50562306a36Sopenharmony_ci			pr_err("Callback not seen on thread %d, pass %lu (%lu misses), signaling %s add_callback; fence signaled? %s\n",
50662306a36Sopenharmony_ci			       t->id, pass, miss,
50762306a36Sopenharmony_ci			       t->before ? "before" : "after",
50862306a36Sopenharmony_ci			       dma_fence_is_signaled(f2) ? "yes" : "no");
50962306a36Sopenharmony_ci			err = -EINVAL;
51062306a36Sopenharmony_ci		}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci		dma_fence_put(f2);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		rcu_assign_pointer(t->fences[t->id], NULL);
51562306a36Sopenharmony_ci		smp_wmb();
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci		dma_fence_put(f1);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci		pass++;
52062306a36Sopenharmony_ci	}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	pr_info("%s[%d] completed %lu passes, %lu misses\n",
52362306a36Sopenharmony_ci		__func__, t->id, pass, miss);
52462306a36Sopenharmony_ci	return err;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic int race_signal_callback(void *arg)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct dma_fence __rcu *f[2] = {};
53062306a36Sopenharmony_ci	int ret = 0;
53162306a36Sopenharmony_ci	int pass;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	for (pass = 0; !ret && pass <= 1; pass++) {
53462306a36Sopenharmony_ci		struct race_thread t[2];
53562306a36Sopenharmony_ci		int i;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(t); i++) {
53862306a36Sopenharmony_ci			t[i].fences = f;
53962306a36Sopenharmony_ci			t[i].id = i;
54062306a36Sopenharmony_ci			t[i].before = pass;
54162306a36Sopenharmony_ci			t[i].task = kthread_run(thread_signal_callback, &t[i],
54262306a36Sopenharmony_ci						"dma-fence:%d", i);
54362306a36Sopenharmony_ci			get_task_struct(t[i].task);
54462306a36Sopenharmony_ci		}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		msleep(50);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(t); i++) {
54962306a36Sopenharmony_ci			int err;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci			err = kthread_stop(t[i].task);
55262306a36Sopenharmony_ci			if (err && !ret)
55362306a36Sopenharmony_ci				ret = err;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci			put_task_struct(t[i].task);
55662306a36Sopenharmony_ci		}
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	return ret;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ciint dma_fence(void)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	static const struct subtest tests[] = {
56562306a36Sopenharmony_ci		SUBTEST(sanitycheck),
56662306a36Sopenharmony_ci		SUBTEST(test_signaling),
56762306a36Sopenharmony_ci		SUBTEST(test_add_callback),
56862306a36Sopenharmony_ci		SUBTEST(test_late_add_callback),
56962306a36Sopenharmony_ci		SUBTEST(test_rm_callback),
57062306a36Sopenharmony_ci		SUBTEST(test_late_rm_callback),
57162306a36Sopenharmony_ci		SUBTEST(test_status),
57262306a36Sopenharmony_ci		SUBTEST(test_error),
57362306a36Sopenharmony_ci		SUBTEST(test_wait),
57462306a36Sopenharmony_ci		SUBTEST(test_wait_timeout),
57562306a36Sopenharmony_ci		SUBTEST(test_stub),
57662306a36Sopenharmony_ci		SUBTEST(race_signal_callback),
57762306a36Sopenharmony_ci	};
57862306a36Sopenharmony_ci	int ret;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	pr_info("sizeof(dma_fence)=%zu\n", sizeof(struct dma_fence));
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	slab_fences = KMEM_CACHE(mock_fence,
58362306a36Sopenharmony_ci				 SLAB_TYPESAFE_BY_RCU |
58462306a36Sopenharmony_ci				 SLAB_HWCACHE_ALIGN);
58562306a36Sopenharmony_ci	if (!slab_fences)
58662306a36Sopenharmony_ci		return -ENOMEM;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	ret = subtests(tests, NULL);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	kmem_cache_destroy(slab_fences);
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	return ret;
59362306a36Sopenharmony_ci}
594