162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * SPDX-License-Identifier: MIT
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * (C) Copyright 2016 Intel Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/slab.h>
862306a36Sopenharmony_ci#include <linux/dma-fence.h>
962306a36Sopenharmony_ci#include <linux/irq_work.h>
1062306a36Sopenharmony_ci#include <linux/dma-resv.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "i915_sw_fence.h"
1362306a36Sopenharmony_ci#include "i915_selftest.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_DEBUG)
1662306a36Sopenharmony_ci#define I915_SW_FENCE_BUG_ON(expr) BUG_ON(expr)
1762306a36Sopenharmony_ci#else
1862306a36Sopenharmony_ci#define I915_SW_FENCE_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr)
1962306a36Sopenharmony_ci#endif
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_CHECK_DAG
2262306a36Sopenharmony_cistatic DEFINE_SPINLOCK(i915_sw_fence_lock);
2362306a36Sopenharmony_ci#endif
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define WQ_FLAG_BITS \
2662306a36Sopenharmony_ci	BITS_PER_TYPE(typeof_member(struct wait_queue_entry, flags))
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/* after WQ_FLAG_* for safety */
2962306a36Sopenharmony_ci#define I915_SW_FENCE_FLAG_FENCE BIT(WQ_FLAG_BITS - 1)
3062306a36Sopenharmony_ci#define I915_SW_FENCE_FLAG_ALLOC BIT(WQ_FLAG_BITS - 2)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cienum {
3362306a36Sopenharmony_ci	DEBUG_FENCE_IDLE = 0,
3462306a36Sopenharmony_ci	DEBUG_FENCE_NOTIFY,
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic void *i915_sw_fence_debug_hint(void *addr)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	return (void *)(((struct i915_sw_fence *)addr)->fn);
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic const struct debug_obj_descr i915_sw_fence_debug_descr = {
4562306a36Sopenharmony_ci	.name = "i915_sw_fence",
4662306a36Sopenharmony_ci	.debug_hint = i915_sw_fence_debug_hint,
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic inline void debug_fence_init(struct i915_sw_fence *fence)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	debug_object_init(fence, &i915_sw_fence_debug_descr);
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic inline void debug_fence_init_onstack(struct i915_sw_fence *fence)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	debug_object_init_on_stack(fence, &i915_sw_fence_debug_descr);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic inline void debug_fence_activate(struct i915_sw_fence *fence)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	debug_object_activate(fence, &i915_sw_fence_debug_descr);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic inline void debug_fence_set_state(struct i915_sw_fence *fence,
6562306a36Sopenharmony_ci					 int old, int new)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	debug_object_active_state(fence, &i915_sw_fence_debug_descr, old, new);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic inline void debug_fence_deactivate(struct i915_sw_fence *fence)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	debug_object_deactivate(fence, &i915_sw_fence_debug_descr);
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic inline void debug_fence_destroy(struct i915_sw_fence *fence)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	debug_object_destroy(fence, &i915_sw_fence_debug_descr);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic inline void debug_fence_free(struct i915_sw_fence *fence)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	debug_object_free(fence, &i915_sw_fence_debug_descr);
8362306a36Sopenharmony_ci	smp_wmb(); /* flush the change in state before reallocation */
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic inline void debug_fence_assert(struct i915_sw_fence *fence)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	debug_object_assert_init(fence, &i915_sw_fence_debug_descr);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#else
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic inline void debug_fence_init(struct i915_sw_fence *fence)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic inline void debug_fence_init_onstack(struct i915_sw_fence *fence)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic inline void debug_fence_activate(struct i915_sw_fence *fence)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic inline void debug_fence_set_state(struct i915_sw_fence *fence,
10662306a36Sopenharmony_ci					 int old, int new)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic inline void debug_fence_deactivate(struct i915_sw_fence *fence)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic inline void debug_fence_destroy(struct i915_sw_fence *fence)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic inline void debug_fence_free(struct i915_sw_fence *fence)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic inline void debug_fence_assert(struct i915_sw_fence *fence)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci#endif
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic int __i915_sw_fence_notify(struct i915_sw_fence *fence,
12962306a36Sopenharmony_ci				  enum i915_sw_fence_notify state)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	return fence->fn(fence, state);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS
13562306a36Sopenharmony_civoid i915_sw_fence_fini(struct i915_sw_fence *fence)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	debug_fence_free(fence);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci#endif
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic void __i915_sw_fence_wake_up_all(struct i915_sw_fence *fence,
14262306a36Sopenharmony_ci					struct list_head *continuation)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	wait_queue_head_t *x = &fence->wait;
14562306a36Sopenharmony_ci	wait_queue_entry_t *pos, *next;
14662306a36Sopenharmony_ci	unsigned long flags;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	debug_fence_deactivate(fence);
14962306a36Sopenharmony_ci	atomic_set_release(&fence->pending, -1); /* 0 -> -1 [done] */
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/*
15262306a36Sopenharmony_ci	 * To prevent unbounded recursion as we traverse the graph of
15362306a36Sopenharmony_ci	 * i915_sw_fences, we move the entry list from this, the next ready
15462306a36Sopenharmony_ci	 * fence, to the tail of the original fence's entry list
15562306a36Sopenharmony_ci	 * (and so added to the list to be woken).
15662306a36Sopenharmony_ci	 */
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	spin_lock_irqsave_nested(&x->lock, flags, 1 + !!continuation);
15962306a36Sopenharmony_ci	if (continuation) {
16062306a36Sopenharmony_ci		list_for_each_entry_safe(pos, next, &x->head, entry) {
16162306a36Sopenharmony_ci			if (pos->flags & I915_SW_FENCE_FLAG_FENCE)
16262306a36Sopenharmony_ci				list_move_tail(&pos->entry, continuation);
16362306a36Sopenharmony_ci			else
16462306a36Sopenharmony_ci				pos->func(pos, TASK_NORMAL, 0, continuation);
16562306a36Sopenharmony_ci		}
16662306a36Sopenharmony_ci	} else {
16762306a36Sopenharmony_ci		LIST_HEAD(extra);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci		do {
17062306a36Sopenharmony_ci			list_for_each_entry_safe(pos, next, &x->head, entry) {
17162306a36Sopenharmony_ci				int wake_flags;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci				wake_flags = 0;
17462306a36Sopenharmony_ci				if (pos->flags & I915_SW_FENCE_FLAG_FENCE)
17562306a36Sopenharmony_ci					wake_flags = fence->error;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci				pos->func(pos, TASK_NORMAL, wake_flags, &extra);
17862306a36Sopenharmony_ci			}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci			if (list_empty(&extra))
18162306a36Sopenharmony_ci				break;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci			list_splice_tail_init(&extra, &x->head);
18462306a36Sopenharmony_ci		} while (1);
18562306a36Sopenharmony_ci	}
18662306a36Sopenharmony_ci	spin_unlock_irqrestore(&x->lock, flags);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	debug_fence_assert(fence);
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic void __i915_sw_fence_complete(struct i915_sw_fence *fence,
19262306a36Sopenharmony_ci				     struct list_head *continuation)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	debug_fence_assert(fence);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (!atomic_dec_and_test(&fence->pending))
19762306a36Sopenharmony_ci		return;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	debug_fence_set_state(fence, DEBUG_FENCE_IDLE, DEBUG_FENCE_NOTIFY);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (__i915_sw_fence_notify(fence, FENCE_COMPLETE) != NOTIFY_DONE)
20262306a36Sopenharmony_ci		return;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	debug_fence_set_state(fence, DEBUG_FENCE_NOTIFY, DEBUG_FENCE_IDLE);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	__i915_sw_fence_wake_up_all(fence, continuation);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	debug_fence_destroy(fence);
20962306a36Sopenharmony_ci	__i915_sw_fence_notify(fence, FENCE_FREE);
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_civoid i915_sw_fence_complete(struct i915_sw_fence *fence)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	debug_fence_assert(fence);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (WARN_ON(i915_sw_fence_done(fence)))
21762306a36Sopenharmony_ci		return;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	__i915_sw_fence_complete(fence, NULL);
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cibool i915_sw_fence_await(struct i915_sw_fence *fence)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	int pending;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/*
22762306a36Sopenharmony_ci	 * It is only safe to add a new await to the fence while it has
22862306a36Sopenharmony_ci	 * not yet been signaled (i.e. there are still existing signalers).
22962306a36Sopenharmony_ci	 */
23062306a36Sopenharmony_ci	pending = atomic_read(&fence->pending);
23162306a36Sopenharmony_ci	do {
23262306a36Sopenharmony_ci		if (pending < 1)
23362306a36Sopenharmony_ci			return false;
23462306a36Sopenharmony_ci	} while (!atomic_try_cmpxchg(&fence->pending, &pending, pending + 1));
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return true;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_civoid __i915_sw_fence_init(struct i915_sw_fence *fence,
24062306a36Sopenharmony_ci			  i915_sw_fence_notify_t fn,
24162306a36Sopenharmony_ci			  const char *name,
24262306a36Sopenharmony_ci			  struct lock_class_key *key)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	__init_waitqueue_head(&fence->wait, name, key);
24562306a36Sopenharmony_ci	fence->fn = fn;
24662306a36Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_CHECK_DAG
24762306a36Sopenharmony_ci	fence->flags = 0;
24862306a36Sopenharmony_ci#endif
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	i915_sw_fence_reinit(fence);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_civoid i915_sw_fence_reinit(struct i915_sw_fence *fence)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	debug_fence_init(fence);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	atomic_set(&fence->pending, 1);
25862306a36Sopenharmony_ci	fence->error = 0;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	I915_SW_FENCE_BUG_ON(!list_empty(&fence->wait.head));
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_civoid i915_sw_fence_commit(struct i915_sw_fence *fence)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	debug_fence_activate(fence);
26662306a36Sopenharmony_ci	i915_sw_fence_complete(fence);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic int i915_sw_fence_wake(wait_queue_entry_t *wq, unsigned mode, int flags, void *key)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	i915_sw_fence_set_error_once(wq->private, flags);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	list_del(&wq->entry);
27462306a36Sopenharmony_ci	__i915_sw_fence_complete(wq->private, key);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if (wq->flags & I915_SW_FENCE_FLAG_ALLOC)
27762306a36Sopenharmony_ci		kfree(wq);
27862306a36Sopenharmony_ci	return 0;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_CHECK_DAG
28262306a36Sopenharmony_cistatic bool __i915_sw_fence_check_if_after(struct i915_sw_fence *fence,
28362306a36Sopenharmony_ci				    const struct i915_sw_fence * const signaler)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	wait_queue_entry_t *wq;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	if (__test_and_set_bit(I915_SW_FENCE_CHECKED_BIT, &fence->flags))
28862306a36Sopenharmony_ci		return false;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	if (fence == signaler)
29162306a36Sopenharmony_ci		return true;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	list_for_each_entry(wq, &fence->wait.head, entry) {
29462306a36Sopenharmony_ci		if (wq->func != i915_sw_fence_wake)
29562306a36Sopenharmony_ci			continue;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci		if (__i915_sw_fence_check_if_after(wq->private, signaler))
29862306a36Sopenharmony_ci			return true;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	return false;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic void __i915_sw_fence_clear_checked_bit(struct i915_sw_fence *fence)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	wait_queue_entry_t *wq;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (!__test_and_clear_bit(I915_SW_FENCE_CHECKED_BIT, &fence->flags))
30962306a36Sopenharmony_ci		return;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	list_for_each_entry(wq, &fence->wait.head, entry) {
31262306a36Sopenharmony_ci		if (wq->func != i915_sw_fence_wake)
31362306a36Sopenharmony_ci			continue;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		__i915_sw_fence_clear_checked_bit(wq->private);
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic bool i915_sw_fence_check_if_after(struct i915_sw_fence *fence,
32062306a36Sopenharmony_ci				  const struct i915_sw_fence * const signaler)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	unsigned long flags;
32362306a36Sopenharmony_ci	bool err;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	spin_lock_irqsave(&i915_sw_fence_lock, flags);
32662306a36Sopenharmony_ci	err = __i915_sw_fence_check_if_after(fence, signaler);
32762306a36Sopenharmony_ci	__i915_sw_fence_clear_checked_bit(fence);
32862306a36Sopenharmony_ci	spin_unlock_irqrestore(&i915_sw_fence_lock, flags);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	return err;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci#else
33362306a36Sopenharmony_cistatic bool i915_sw_fence_check_if_after(struct i915_sw_fence *fence,
33462306a36Sopenharmony_ci					 const struct i915_sw_fence * const signaler)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	return false;
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci#endif
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic int __i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence,
34162306a36Sopenharmony_ci					  struct i915_sw_fence *signaler,
34262306a36Sopenharmony_ci					  wait_queue_entry_t *wq, gfp_t gfp)
34362306a36Sopenharmony_ci{
34462306a36Sopenharmony_ci	unsigned int pending;
34562306a36Sopenharmony_ci	unsigned long flags;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	debug_fence_assert(fence);
34862306a36Sopenharmony_ci	might_sleep_if(gfpflags_allow_blocking(gfp));
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	if (i915_sw_fence_done(signaler)) {
35162306a36Sopenharmony_ci		i915_sw_fence_set_error_once(fence, signaler->error);
35262306a36Sopenharmony_ci		return 0;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	debug_fence_assert(signaler);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	/* The dependency graph must be acyclic. */
35862306a36Sopenharmony_ci	if (unlikely(i915_sw_fence_check_if_after(fence, signaler)))
35962306a36Sopenharmony_ci		return -EINVAL;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	pending = I915_SW_FENCE_FLAG_FENCE;
36262306a36Sopenharmony_ci	if (!wq) {
36362306a36Sopenharmony_ci		wq = kmalloc(sizeof(*wq), gfp);
36462306a36Sopenharmony_ci		if (!wq) {
36562306a36Sopenharmony_ci			if (!gfpflags_allow_blocking(gfp))
36662306a36Sopenharmony_ci				return -ENOMEM;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci			i915_sw_fence_wait(signaler);
36962306a36Sopenharmony_ci			i915_sw_fence_set_error_once(fence, signaler->error);
37062306a36Sopenharmony_ci			return 0;
37162306a36Sopenharmony_ci		}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		pending |= I915_SW_FENCE_FLAG_ALLOC;
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	INIT_LIST_HEAD(&wq->entry);
37762306a36Sopenharmony_ci	wq->flags = pending;
37862306a36Sopenharmony_ci	wq->func = i915_sw_fence_wake;
37962306a36Sopenharmony_ci	wq->private = fence;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	i915_sw_fence_await(fence);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	spin_lock_irqsave(&signaler->wait.lock, flags);
38462306a36Sopenharmony_ci	if (likely(!i915_sw_fence_done(signaler))) {
38562306a36Sopenharmony_ci		__add_wait_queue_entry_tail(&signaler->wait, wq);
38662306a36Sopenharmony_ci		pending = 1;
38762306a36Sopenharmony_ci	} else {
38862306a36Sopenharmony_ci		i915_sw_fence_wake(wq, 0, signaler->error, NULL);
38962306a36Sopenharmony_ci		pending = 0;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci	spin_unlock_irqrestore(&signaler->wait.lock, flags);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return pending;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ciint i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence,
39762306a36Sopenharmony_ci				 struct i915_sw_fence *signaler,
39862306a36Sopenharmony_ci				 wait_queue_entry_t *wq)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	return __i915_sw_fence_await_sw_fence(fence, signaler, wq, 0);
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ciint i915_sw_fence_await_sw_fence_gfp(struct i915_sw_fence *fence,
40462306a36Sopenharmony_ci				     struct i915_sw_fence *signaler,
40562306a36Sopenharmony_ci				     gfp_t gfp)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	return __i915_sw_fence_await_sw_fence(fence, signaler, NULL, gfp);
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistruct i915_sw_dma_fence_cb_timer {
41162306a36Sopenharmony_ci	struct i915_sw_dma_fence_cb base;
41262306a36Sopenharmony_ci	struct dma_fence *dma;
41362306a36Sopenharmony_ci	struct timer_list timer;
41462306a36Sopenharmony_ci	struct irq_work work;
41562306a36Sopenharmony_ci	struct rcu_head rcu;
41662306a36Sopenharmony_ci};
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic void dma_i915_sw_fence_wake(struct dma_fence *dma,
41962306a36Sopenharmony_ci				   struct dma_fence_cb *data)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	i915_sw_fence_set_error_once(cb->fence, dma->error);
42462306a36Sopenharmony_ci	i915_sw_fence_complete(cb->fence);
42562306a36Sopenharmony_ci	kfree(cb);
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic void timer_i915_sw_fence_wake(struct timer_list *t)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	struct i915_sw_dma_fence_cb_timer *cb = from_timer(cb, t, timer);
43162306a36Sopenharmony_ci	struct i915_sw_fence *fence;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	fence = xchg(&cb->base.fence, NULL);
43462306a36Sopenharmony_ci	if (!fence)
43562306a36Sopenharmony_ci		return;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	pr_notice("Asynchronous wait on fence %s:%s:%llx timed out (hint:%ps)\n",
43862306a36Sopenharmony_ci		  cb->dma->ops->get_driver_name(cb->dma),
43962306a36Sopenharmony_ci		  cb->dma->ops->get_timeline_name(cb->dma),
44062306a36Sopenharmony_ci		  cb->dma->seqno,
44162306a36Sopenharmony_ci		  i915_sw_fence_debug_hint(fence));
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	i915_sw_fence_set_error_once(fence, -ETIMEDOUT);
44462306a36Sopenharmony_ci	i915_sw_fence_complete(fence);
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic void dma_i915_sw_fence_wake_timer(struct dma_fence *dma,
44862306a36Sopenharmony_ci					 struct dma_fence_cb *data)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	struct i915_sw_dma_fence_cb_timer *cb =
45162306a36Sopenharmony_ci		container_of(data, typeof(*cb), base.base);
45262306a36Sopenharmony_ci	struct i915_sw_fence *fence;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	fence = xchg(&cb->base.fence, NULL);
45562306a36Sopenharmony_ci	if (fence) {
45662306a36Sopenharmony_ci		i915_sw_fence_set_error_once(fence, dma->error);
45762306a36Sopenharmony_ci		i915_sw_fence_complete(fence);
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	irq_work_queue(&cb->work);
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic void irq_i915_sw_fence_work(struct irq_work *wrk)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct i915_sw_dma_fence_cb_timer *cb =
46662306a36Sopenharmony_ci		container_of(wrk, typeof(*cb), work);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	timer_shutdown_sync(&cb->timer);
46962306a36Sopenharmony_ci	dma_fence_put(cb->dma);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	kfree_rcu(cb, rcu);
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ciint i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
47562306a36Sopenharmony_ci				  struct dma_fence *dma,
47662306a36Sopenharmony_ci				  unsigned long timeout,
47762306a36Sopenharmony_ci				  gfp_t gfp)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	struct i915_sw_dma_fence_cb *cb;
48062306a36Sopenharmony_ci	dma_fence_func_t func;
48162306a36Sopenharmony_ci	int ret;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	debug_fence_assert(fence);
48462306a36Sopenharmony_ci	might_sleep_if(gfpflags_allow_blocking(gfp));
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (dma_fence_is_signaled(dma)) {
48762306a36Sopenharmony_ci		i915_sw_fence_set_error_once(fence, dma->error);
48862306a36Sopenharmony_ci		return 0;
48962306a36Sopenharmony_ci	}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	cb = kmalloc(timeout ?
49262306a36Sopenharmony_ci		     sizeof(struct i915_sw_dma_fence_cb_timer) :
49362306a36Sopenharmony_ci		     sizeof(struct i915_sw_dma_fence_cb),
49462306a36Sopenharmony_ci		     gfp);
49562306a36Sopenharmony_ci	if (!cb) {
49662306a36Sopenharmony_ci		if (!gfpflags_allow_blocking(gfp))
49762306a36Sopenharmony_ci			return -ENOMEM;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci		ret = dma_fence_wait(dma, false);
50062306a36Sopenharmony_ci		if (ret)
50162306a36Sopenharmony_ci			return ret;
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci		i915_sw_fence_set_error_once(fence, dma->error);
50462306a36Sopenharmony_ci		return 0;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	cb->fence = fence;
50862306a36Sopenharmony_ci	i915_sw_fence_await(fence);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	func = dma_i915_sw_fence_wake;
51162306a36Sopenharmony_ci	if (timeout) {
51262306a36Sopenharmony_ci		struct i915_sw_dma_fence_cb_timer *timer =
51362306a36Sopenharmony_ci			container_of(cb, typeof(*timer), base);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci		timer->dma = dma_fence_get(dma);
51662306a36Sopenharmony_ci		init_irq_work(&timer->work, irq_i915_sw_fence_work);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci		timer_setup(&timer->timer,
51962306a36Sopenharmony_ci			    timer_i915_sw_fence_wake, TIMER_IRQSAFE);
52062306a36Sopenharmony_ci		mod_timer(&timer->timer, round_jiffies_up(jiffies + timeout));
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		func = dma_i915_sw_fence_wake_timer;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	ret = dma_fence_add_callback(dma, &cb->base, func);
52662306a36Sopenharmony_ci	if (ret == 0) {
52762306a36Sopenharmony_ci		ret = 1;
52862306a36Sopenharmony_ci	} else {
52962306a36Sopenharmony_ci		func(dma, &cb->base);
53062306a36Sopenharmony_ci		if (ret == -ENOENT) /* fence already signaled */
53162306a36Sopenharmony_ci			ret = 0;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	return ret;
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic void __dma_i915_sw_fence_wake(struct dma_fence *dma,
53862306a36Sopenharmony_ci				     struct dma_fence_cb *data)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	i915_sw_fence_set_error_once(cb->fence, dma->error);
54362306a36Sopenharmony_ci	i915_sw_fence_complete(cb->fence);
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ciint __i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
54762306a36Sopenharmony_ci				    struct dma_fence *dma,
54862306a36Sopenharmony_ci				    struct i915_sw_dma_fence_cb *cb)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	int ret;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	debug_fence_assert(fence);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	if (dma_fence_is_signaled(dma)) {
55562306a36Sopenharmony_ci		i915_sw_fence_set_error_once(fence, dma->error);
55662306a36Sopenharmony_ci		return 0;
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	cb->fence = fence;
56062306a36Sopenharmony_ci	i915_sw_fence_await(fence);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	ret = 1;
56362306a36Sopenharmony_ci	if (dma_fence_add_callback(dma, &cb->base, __dma_i915_sw_fence_wake)) {
56462306a36Sopenharmony_ci		/* fence already signaled */
56562306a36Sopenharmony_ci		__dma_i915_sw_fence_wake(dma, &cb->base);
56662306a36Sopenharmony_ci		ret = 0;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	return ret;
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ciint i915_sw_fence_await_reservation(struct i915_sw_fence *fence,
57362306a36Sopenharmony_ci				    struct dma_resv *resv,
57462306a36Sopenharmony_ci				    bool write,
57562306a36Sopenharmony_ci				    unsigned long timeout,
57662306a36Sopenharmony_ci				    gfp_t gfp)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	struct dma_resv_iter cursor;
57962306a36Sopenharmony_ci	struct dma_fence *f;
58062306a36Sopenharmony_ci	int ret = 0, pending;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	debug_fence_assert(fence);
58362306a36Sopenharmony_ci	might_sleep_if(gfpflags_allow_blocking(gfp));
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	dma_resv_iter_begin(&cursor, resv, dma_resv_usage_rw(write));
58662306a36Sopenharmony_ci	dma_resv_for_each_fence_unlocked(&cursor, f) {
58762306a36Sopenharmony_ci		pending = i915_sw_fence_await_dma_fence(fence, f, timeout,
58862306a36Sopenharmony_ci							gfp);
58962306a36Sopenharmony_ci		if (pending < 0) {
59062306a36Sopenharmony_ci			ret = pending;
59162306a36Sopenharmony_ci			break;
59262306a36Sopenharmony_ci		}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		ret |= pending;
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci	dma_resv_iter_end(&cursor);
59762306a36Sopenharmony_ci	return ret;
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
60162306a36Sopenharmony_ci#include "selftests/lib_sw_fence.c"
60262306a36Sopenharmony_ci#include "selftests/i915_sw_fence.c"
60362306a36Sopenharmony_ci#endif
604