18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * SPDX-License-Identifier: MIT
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * (C) Copyright 2016 Intel Corporation
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/slab.h>
88c2ecf20Sopenharmony_ci#include <linux/dma-fence.h>
98c2ecf20Sopenharmony_ci#include <linux/irq_work.h>
108c2ecf20Sopenharmony_ci#include <linux/dma-resv.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "i915_sw_fence.h"
138c2ecf20Sopenharmony_ci#include "i915_selftest.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_DEBUG)
168c2ecf20Sopenharmony_ci#define I915_SW_FENCE_BUG_ON(expr) BUG_ON(expr)
178c2ecf20Sopenharmony_ci#else
188c2ecf20Sopenharmony_ci#define I915_SW_FENCE_BUG_ON(expr) BUILD_BUG_ON_INVALID(expr)
198c2ecf20Sopenharmony_ci#endif
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define I915_SW_FENCE_FLAG_ALLOC BIT(3) /* after WQ_FLAG_* for safety */
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(i915_sw_fence_lock);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cienum {
268c2ecf20Sopenharmony_ci	DEBUG_FENCE_IDLE = 0,
278c2ecf20Sopenharmony_ci	DEBUG_FENCE_NOTIFY,
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic void *i915_sw_fence_debug_hint(void *addr)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	return (void *)(((struct i915_sw_fence *)addr)->flags & I915_SW_FENCE_MASK);
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic const struct debug_obj_descr i915_sw_fence_debug_descr = {
388c2ecf20Sopenharmony_ci	.name = "i915_sw_fence",
398c2ecf20Sopenharmony_ci	.debug_hint = i915_sw_fence_debug_hint,
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic inline void debug_fence_init(struct i915_sw_fence *fence)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	debug_object_init(fence, &i915_sw_fence_debug_descr);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic inline void debug_fence_init_onstack(struct i915_sw_fence *fence)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	debug_object_init_on_stack(fence, &i915_sw_fence_debug_descr);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic inline void debug_fence_activate(struct i915_sw_fence *fence)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	debug_object_activate(fence, &i915_sw_fence_debug_descr);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic inline void debug_fence_set_state(struct i915_sw_fence *fence,
588c2ecf20Sopenharmony_ci					 int old, int new)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	debug_object_active_state(fence, &i915_sw_fence_debug_descr, old, new);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic inline void debug_fence_deactivate(struct i915_sw_fence *fence)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	debug_object_deactivate(fence, &i915_sw_fence_debug_descr);
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic inline void debug_fence_destroy(struct i915_sw_fence *fence)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	debug_object_destroy(fence, &i915_sw_fence_debug_descr);
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic inline void debug_fence_free(struct i915_sw_fence *fence)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	debug_object_free(fence, &i915_sw_fence_debug_descr);
768c2ecf20Sopenharmony_ci	smp_wmb(); /* flush the change in state before reallocation */
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic inline void debug_fence_assert(struct i915_sw_fence *fence)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	debug_object_assert_init(fence, &i915_sw_fence_debug_descr);
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci#else
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic inline void debug_fence_init(struct i915_sw_fence *fence)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic inline void debug_fence_init_onstack(struct i915_sw_fence *fence)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic inline void debug_fence_activate(struct i915_sw_fence *fence)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic inline void debug_fence_set_state(struct i915_sw_fence *fence,
998c2ecf20Sopenharmony_ci					 int old, int new)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic inline void debug_fence_deactivate(struct i915_sw_fence *fence)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic inline void debug_fence_destroy(struct i915_sw_fence *fence)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic inline void debug_fence_free(struct i915_sw_fence *fence)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic inline void debug_fence_assert(struct i915_sw_fence *fence)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci#endif
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic int __i915_sw_fence_notify(struct i915_sw_fence *fence,
1228c2ecf20Sopenharmony_ci				  enum i915_sw_fence_notify state)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	i915_sw_fence_notify_t fn;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	fn = (i915_sw_fence_notify_t)(fence->flags & I915_SW_FENCE_MASK);
1278c2ecf20Sopenharmony_ci	return fn(fence, state);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_I915_SW_FENCE_DEBUG_OBJECTS
1318c2ecf20Sopenharmony_civoid i915_sw_fence_fini(struct i915_sw_fence *fence)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	debug_fence_free(fence);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci#endif
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic void __i915_sw_fence_wake_up_all(struct i915_sw_fence *fence,
1388c2ecf20Sopenharmony_ci					struct list_head *continuation)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	wait_queue_head_t *x = &fence->wait;
1418c2ecf20Sopenharmony_ci	wait_queue_entry_t *pos, *next;
1428c2ecf20Sopenharmony_ci	unsigned long flags;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	debug_fence_deactivate(fence);
1458c2ecf20Sopenharmony_ci	atomic_set_release(&fence->pending, -1); /* 0 -> -1 [done] */
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/*
1488c2ecf20Sopenharmony_ci	 * To prevent unbounded recursion as we traverse the graph of
1498c2ecf20Sopenharmony_ci	 * i915_sw_fences, we move the entry list from this, the next ready
1508c2ecf20Sopenharmony_ci	 * fence, to the tail of the original fence's entry list
1518c2ecf20Sopenharmony_ci	 * (and so added to the list to be woken).
1528c2ecf20Sopenharmony_ci	 */
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	spin_lock_irqsave_nested(&x->lock, flags, 1 + !!continuation);
1558c2ecf20Sopenharmony_ci	if (continuation) {
1568c2ecf20Sopenharmony_ci		list_for_each_entry_safe(pos, next, &x->head, entry) {
1578c2ecf20Sopenharmony_ci			if (pos->func == autoremove_wake_function)
1588c2ecf20Sopenharmony_ci				pos->func(pos, TASK_NORMAL, 0, continuation);
1598c2ecf20Sopenharmony_ci			else
1608c2ecf20Sopenharmony_ci				list_move_tail(&pos->entry, continuation);
1618c2ecf20Sopenharmony_ci		}
1628c2ecf20Sopenharmony_ci	} else {
1638c2ecf20Sopenharmony_ci		LIST_HEAD(extra);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci		do {
1668c2ecf20Sopenharmony_ci			list_for_each_entry_safe(pos, next, &x->head, entry) {
1678c2ecf20Sopenharmony_ci				int wake_flags;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci				wake_flags = fence->error;
1708c2ecf20Sopenharmony_ci				if (pos->func == autoremove_wake_function)
1718c2ecf20Sopenharmony_ci					wake_flags = 0;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci				pos->func(pos, TASK_NORMAL, wake_flags, &extra);
1748c2ecf20Sopenharmony_ci			}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci			if (list_empty(&extra))
1778c2ecf20Sopenharmony_ci				break;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci			list_splice_tail_init(&extra, &x->head);
1808c2ecf20Sopenharmony_ci		} while (1);
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&x->lock, flags);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	debug_fence_assert(fence);
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic void __i915_sw_fence_complete(struct i915_sw_fence *fence,
1888c2ecf20Sopenharmony_ci				     struct list_head *continuation)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	debug_fence_assert(fence);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (!atomic_dec_and_test(&fence->pending))
1938c2ecf20Sopenharmony_ci		return;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	debug_fence_set_state(fence, DEBUG_FENCE_IDLE, DEBUG_FENCE_NOTIFY);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (__i915_sw_fence_notify(fence, FENCE_COMPLETE) != NOTIFY_DONE)
1988c2ecf20Sopenharmony_ci		return;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	debug_fence_set_state(fence, DEBUG_FENCE_NOTIFY, DEBUG_FENCE_IDLE);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	__i915_sw_fence_wake_up_all(fence, continuation);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	debug_fence_destroy(fence);
2058c2ecf20Sopenharmony_ci	__i915_sw_fence_notify(fence, FENCE_FREE);
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_civoid i915_sw_fence_complete(struct i915_sw_fence *fence)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	debug_fence_assert(fence);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if (WARN_ON(i915_sw_fence_done(fence)))
2138c2ecf20Sopenharmony_ci		return;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	__i915_sw_fence_complete(fence, NULL);
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cibool i915_sw_fence_await(struct i915_sw_fence *fence)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	int pending;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	/*
2238c2ecf20Sopenharmony_ci	 * It is only safe to add a new await to the fence while it has
2248c2ecf20Sopenharmony_ci	 * not yet been signaled (i.e. there are still existing signalers).
2258c2ecf20Sopenharmony_ci	 */
2268c2ecf20Sopenharmony_ci	pending = atomic_read(&fence->pending);
2278c2ecf20Sopenharmony_ci	do {
2288c2ecf20Sopenharmony_ci		if (pending < 1)
2298c2ecf20Sopenharmony_ci			return false;
2308c2ecf20Sopenharmony_ci	} while (!atomic_try_cmpxchg(&fence->pending, &pending, pending + 1));
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	return true;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_civoid __i915_sw_fence_init(struct i915_sw_fence *fence,
2368c2ecf20Sopenharmony_ci			  i915_sw_fence_notify_t fn,
2378c2ecf20Sopenharmony_ci			  const char *name,
2388c2ecf20Sopenharmony_ci			  struct lock_class_key *key)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	BUG_ON(!fn || (unsigned long)fn & ~I915_SW_FENCE_MASK);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	__init_waitqueue_head(&fence->wait, name, key);
2438c2ecf20Sopenharmony_ci	fence->flags = (unsigned long)fn;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	i915_sw_fence_reinit(fence);
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_civoid i915_sw_fence_reinit(struct i915_sw_fence *fence)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	debug_fence_init(fence);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	atomic_set(&fence->pending, 1);
2538c2ecf20Sopenharmony_ci	fence->error = 0;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	I915_SW_FENCE_BUG_ON(!fence->flags);
2568c2ecf20Sopenharmony_ci	I915_SW_FENCE_BUG_ON(!list_empty(&fence->wait.head));
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_civoid i915_sw_fence_commit(struct i915_sw_fence *fence)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	debug_fence_activate(fence);
2628c2ecf20Sopenharmony_ci	i915_sw_fence_complete(fence);
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int i915_sw_fence_wake(wait_queue_entry_t *wq, unsigned mode, int flags, void *key)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	i915_sw_fence_set_error_once(wq->private, flags);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	list_del(&wq->entry);
2708c2ecf20Sopenharmony_ci	__i915_sw_fence_complete(wq->private, key);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (wq->flags & I915_SW_FENCE_FLAG_ALLOC)
2738c2ecf20Sopenharmony_ci		kfree(wq);
2748c2ecf20Sopenharmony_ci	return 0;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic bool __i915_sw_fence_check_if_after(struct i915_sw_fence *fence,
2788c2ecf20Sopenharmony_ci				    const struct i915_sw_fence * const signaler)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	wait_queue_entry_t *wq;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	if (__test_and_set_bit(I915_SW_FENCE_CHECKED_BIT, &fence->flags))
2838c2ecf20Sopenharmony_ci		return false;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	if (fence == signaler)
2868c2ecf20Sopenharmony_ci		return true;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	list_for_each_entry(wq, &fence->wait.head, entry) {
2898c2ecf20Sopenharmony_ci		if (wq->func != i915_sw_fence_wake)
2908c2ecf20Sopenharmony_ci			continue;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci		if (__i915_sw_fence_check_if_after(wq->private, signaler))
2938c2ecf20Sopenharmony_ci			return true;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	return false;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic void __i915_sw_fence_clear_checked_bit(struct i915_sw_fence *fence)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	wait_queue_entry_t *wq;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	if (!__test_and_clear_bit(I915_SW_FENCE_CHECKED_BIT, &fence->flags))
3048c2ecf20Sopenharmony_ci		return;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	list_for_each_entry(wq, &fence->wait.head, entry) {
3078c2ecf20Sopenharmony_ci		if (wq->func != i915_sw_fence_wake)
3088c2ecf20Sopenharmony_ci			continue;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci		__i915_sw_fence_clear_checked_bit(wq->private);
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_cistatic bool i915_sw_fence_check_if_after(struct i915_sw_fence *fence,
3158c2ecf20Sopenharmony_ci				  const struct i915_sw_fence * const signaler)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	unsigned long flags;
3188c2ecf20Sopenharmony_ci	bool err;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (!IS_ENABLED(CONFIG_DRM_I915_SW_FENCE_CHECK_DAG))
3218c2ecf20Sopenharmony_ci		return false;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	spin_lock_irqsave(&i915_sw_fence_lock, flags);
3248c2ecf20Sopenharmony_ci	err = __i915_sw_fence_check_if_after(fence, signaler);
3258c2ecf20Sopenharmony_ci	__i915_sw_fence_clear_checked_bit(fence);
3268c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&i915_sw_fence_lock, flags);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	return err;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic int __i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence,
3328c2ecf20Sopenharmony_ci					  struct i915_sw_fence *signaler,
3338c2ecf20Sopenharmony_ci					  wait_queue_entry_t *wq, gfp_t gfp)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	unsigned long flags;
3368c2ecf20Sopenharmony_ci	int pending;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	debug_fence_assert(fence);
3398c2ecf20Sopenharmony_ci	might_sleep_if(gfpflags_allow_blocking(gfp));
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	if (i915_sw_fence_done(signaler)) {
3428c2ecf20Sopenharmony_ci		i915_sw_fence_set_error_once(fence, signaler->error);
3438c2ecf20Sopenharmony_ci		return 0;
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	debug_fence_assert(signaler);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	/* The dependency graph must be acyclic. */
3498c2ecf20Sopenharmony_ci	if (unlikely(i915_sw_fence_check_if_after(fence, signaler)))
3508c2ecf20Sopenharmony_ci		return -EINVAL;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	pending = 0;
3538c2ecf20Sopenharmony_ci	if (!wq) {
3548c2ecf20Sopenharmony_ci		wq = kmalloc(sizeof(*wq), gfp);
3558c2ecf20Sopenharmony_ci		if (!wq) {
3568c2ecf20Sopenharmony_ci			if (!gfpflags_allow_blocking(gfp))
3578c2ecf20Sopenharmony_ci				return -ENOMEM;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci			i915_sw_fence_wait(signaler);
3608c2ecf20Sopenharmony_ci			i915_sw_fence_set_error_once(fence, signaler->error);
3618c2ecf20Sopenharmony_ci			return 0;
3628c2ecf20Sopenharmony_ci		}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci		pending |= I915_SW_FENCE_FLAG_ALLOC;
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&wq->entry);
3688c2ecf20Sopenharmony_ci	wq->flags = pending;
3698c2ecf20Sopenharmony_ci	wq->func = i915_sw_fence_wake;
3708c2ecf20Sopenharmony_ci	wq->private = fence;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	i915_sw_fence_await(fence);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	spin_lock_irqsave(&signaler->wait.lock, flags);
3758c2ecf20Sopenharmony_ci	if (likely(!i915_sw_fence_done(signaler))) {
3768c2ecf20Sopenharmony_ci		__add_wait_queue_entry_tail(&signaler->wait, wq);
3778c2ecf20Sopenharmony_ci		pending = 1;
3788c2ecf20Sopenharmony_ci	} else {
3798c2ecf20Sopenharmony_ci		i915_sw_fence_wake(wq, 0, signaler->error, NULL);
3808c2ecf20Sopenharmony_ci		pending = 0;
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&signaler->wait.lock, flags);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return pending;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ciint i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence,
3888c2ecf20Sopenharmony_ci				 struct i915_sw_fence *signaler,
3898c2ecf20Sopenharmony_ci				 wait_queue_entry_t *wq)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	return __i915_sw_fence_await_sw_fence(fence, signaler, wq, 0);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ciint i915_sw_fence_await_sw_fence_gfp(struct i915_sw_fence *fence,
3958c2ecf20Sopenharmony_ci				     struct i915_sw_fence *signaler,
3968c2ecf20Sopenharmony_ci				     gfp_t gfp)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci	return __i915_sw_fence_await_sw_fence(fence, signaler, NULL, gfp);
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistruct i915_sw_dma_fence_cb_timer {
4028c2ecf20Sopenharmony_ci	struct i915_sw_dma_fence_cb base;
4038c2ecf20Sopenharmony_ci	struct dma_fence *dma;
4048c2ecf20Sopenharmony_ci	struct timer_list timer;
4058c2ecf20Sopenharmony_ci	struct irq_work work;
4068c2ecf20Sopenharmony_ci	struct rcu_head rcu;
4078c2ecf20Sopenharmony_ci};
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic void dma_i915_sw_fence_wake(struct dma_fence *dma,
4108c2ecf20Sopenharmony_ci				   struct dma_fence_cb *data)
4118c2ecf20Sopenharmony_ci{
4128c2ecf20Sopenharmony_ci	struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	i915_sw_fence_set_error_once(cb->fence, dma->error);
4158c2ecf20Sopenharmony_ci	i915_sw_fence_complete(cb->fence);
4168c2ecf20Sopenharmony_ci	kfree(cb);
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic void timer_i915_sw_fence_wake(struct timer_list *t)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	struct i915_sw_dma_fence_cb_timer *cb = from_timer(cb, t, timer);
4228c2ecf20Sopenharmony_ci	struct i915_sw_fence *fence;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	fence = xchg(&cb->base.fence, NULL);
4258c2ecf20Sopenharmony_ci	if (!fence)
4268c2ecf20Sopenharmony_ci		return;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	pr_notice("Asynchronous wait on fence %s:%s:%llx timed out (hint:%ps)\n",
4298c2ecf20Sopenharmony_ci		  cb->dma->ops->get_driver_name(cb->dma),
4308c2ecf20Sopenharmony_ci		  cb->dma->ops->get_timeline_name(cb->dma),
4318c2ecf20Sopenharmony_ci		  cb->dma->seqno,
4328c2ecf20Sopenharmony_ci		  i915_sw_fence_debug_hint(fence));
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	i915_sw_fence_set_error_once(fence, -ETIMEDOUT);
4358c2ecf20Sopenharmony_ci	i915_sw_fence_complete(fence);
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic void dma_i915_sw_fence_wake_timer(struct dma_fence *dma,
4398c2ecf20Sopenharmony_ci					 struct dma_fence_cb *data)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	struct i915_sw_dma_fence_cb_timer *cb =
4428c2ecf20Sopenharmony_ci		container_of(data, typeof(*cb), base.base);
4438c2ecf20Sopenharmony_ci	struct i915_sw_fence *fence;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	fence = xchg(&cb->base.fence, NULL);
4468c2ecf20Sopenharmony_ci	if (fence) {
4478c2ecf20Sopenharmony_ci		i915_sw_fence_set_error_once(fence, dma->error);
4488c2ecf20Sopenharmony_ci		i915_sw_fence_complete(fence);
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	irq_work_queue(&cb->work);
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic void irq_i915_sw_fence_work(struct irq_work *wrk)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	struct i915_sw_dma_fence_cb_timer *cb =
4578c2ecf20Sopenharmony_ci		container_of(wrk, typeof(*cb), work);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	del_timer_sync(&cb->timer);
4608c2ecf20Sopenharmony_ci	dma_fence_put(cb->dma);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	kfree_rcu(cb, rcu);
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ciint i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
4668c2ecf20Sopenharmony_ci				  struct dma_fence *dma,
4678c2ecf20Sopenharmony_ci				  unsigned long timeout,
4688c2ecf20Sopenharmony_ci				  gfp_t gfp)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	struct i915_sw_dma_fence_cb *cb;
4718c2ecf20Sopenharmony_ci	dma_fence_func_t func;
4728c2ecf20Sopenharmony_ci	int ret;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	debug_fence_assert(fence);
4758c2ecf20Sopenharmony_ci	might_sleep_if(gfpflags_allow_blocking(gfp));
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	if (dma_fence_is_signaled(dma)) {
4788c2ecf20Sopenharmony_ci		i915_sw_fence_set_error_once(fence, dma->error);
4798c2ecf20Sopenharmony_ci		return 0;
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	cb = kmalloc(timeout ?
4838c2ecf20Sopenharmony_ci		     sizeof(struct i915_sw_dma_fence_cb_timer) :
4848c2ecf20Sopenharmony_ci		     sizeof(struct i915_sw_dma_fence_cb),
4858c2ecf20Sopenharmony_ci		     gfp);
4868c2ecf20Sopenharmony_ci	if (!cb) {
4878c2ecf20Sopenharmony_ci		if (!gfpflags_allow_blocking(gfp))
4888c2ecf20Sopenharmony_ci			return -ENOMEM;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci		ret = dma_fence_wait(dma, false);
4918c2ecf20Sopenharmony_ci		if (ret)
4928c2ecf20Sopenharmony_ci			return ret;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci		i915_sw_fence_set_error_once(fence, dma->error);
4958c2ecf20Sopenharmony_ci		return 0;
4968c2ecf20Sopenharmony_ci	}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	cb->fence = fence;
4998c2ecf20Sopenharmony_ci	i915_sw_fence_await(fence);
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	func = dma_i915_sw_fence_wake;
5028c2ecf20Sopenharmony_ci	if (timeout) {
5038c2ecf20Sopenharmony_ci		struct i915_sw_dma_fence_cb_timer *timer =
5048c2ecf20Sopenharmony_ci			container_of(cb, typeof(*timer), base);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci		timer->dma = dma_fence_get(dma);
5078c2ecf20Sopenharmony_ci		init_irq_work(&timer->work, irq_i915_sw_fence_work);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci		timer_setup(&timer->timer,
5108c2ecf20Sopenharmony_ci			    timer_i915_sw_fence_wake, TIMER_IRQSAFE);
5118c2ecf20Sopenharmony_ci		mod_timer(&timer->timer, round_jiffies_up(jiffies + timeout));
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		func = dma_i915_sw_fence_wake_timer;
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	ret = dma_fence_add_callback(dma, &cb->base, func);
5178c2ecf20Sopenharmony_ci	if (ret == 0) {
5188c2ecf20Sopenharmony_ci		ret = 1;
5198c2ecf20Sopenharmony_ci	} else {
5208c2ecf20Sopenharmony_ci		func(dma, &cb->base);
5218c2ecf20Sopenharmony_ci		if (ret == -ENOENT) /* fence already signaled */
5228c2ecf20Sopenharmony_ci			ret = 0;
5238c2ecf20Sopenharmony_ci	}
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	return ret;
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic void __dma_i915_sw_fence_wake(struct dma_fence *dma,
5298c2ecf20Sopenharmony_ci				     struct dma_fence_cb *data)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	i915_sw_fence_set_error_once(cb->fence, dma->error);
5348c2ecf20Sopenharmony_ci	i915_sw_fence_complete(cb->fence);
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ciint __i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
5388c2ecf20Sopenharmony_ci				    struct dma_fence *dma,
5398c2ecf20Sopenharmony_ci				    struct i915_sw_dma_fence_cb *cb)
5408c2ecf20Sopenharmony_ci{
5418c2ecf20Sopenharmony_ci	int ret;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	debug_fence_assert(fence);
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	if (dma_fence_is_signaled(dma)) {
5468c2ecf20Sopenharmony_ci		i915_sw_fence_set_error_once(fence, dma->error);
5478c2ecf20Sopenharmony_ci		return 0;
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	cb->fence = fence;
5518c2ecf20Sopenharmony_ci	i915_sw_fence_await(fence);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	ret = 1;
5548c2ecf20Sopenharmony_ci	if (dma_fence_add_callback(dma, &cb->base, __dma_i915_sw_fence_wake)) {
5558c2ecf20Sopenharmony_ci		/* fence already signaled */
5568c2ecf20Sopenharmony_ci		__dma_i915_sw_fence_wake(dma, &cb->base);
5578c2ecf20Sopenharmony_ci		ret = 0;
5588c2ecf20Sopenharmony_ci	}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	return ret;
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ciint i915_sw_fence_await_reservation(struct i915_sw_fence *fence,
5648c2ecf20Sopenharmony_ci				    struct dma_resv *resv,
5658c2ecf20Sopenharmony_ci				    const struct dma_fence_ops *exclude,
5668c2ecf20Sopenharmony_ci				    bool write,
5678c2ecf20Sopenharmony_ci				    unsigned long timeout,
5688c2ecf20Sopenharmony_ci				    gfp_t gfp)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	struct dma_fence *excl;
5718c2ecf20Sopenharmony_ci	int ret = 0, pending;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	debug_fence_assert(fence);
5748c2ecf20Sopenharmony_ci	might_sleep_if(gfpflags_allow_blocking(gfp));
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (write) {
5778c2ecf20Sopenharmony_ci		struct dma_fence **shared;
5788c2ecf20Sopenharmony_ci		unsigned int count, i;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci		ret = dma_resv_get_fences_rcu(resv, &excl, &count, &shared);
5818c2ecf20Sopenharmony_ci		if (ret)
5828c2ecf20Sopenharmony_ci			return ret;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci		for (i = 0; i < count; i++) {
5858c2ecf20Sopenharmony_ci			if (shared[i]->ops == exclude)
5868c2ecf20Sopenharmony_ci				continue;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci			pending = i915_sw_fence_await_dma_fence(fence,
5898c2ecf20Sopenharmony_ci								shared[i],
5908c2ecf20Sopenharmony_ci								timeout,
5918c2ecf20Sopenharmony_ci								gfp);
5928c2ecf20Sopenharmony_ci			if (pending < 0) {
5938c2ecf20Sopenharmony_ci				ret = pending;
5948c2ecf20Sopenharmony_ci				break;
5958c2ecf20Sopenharmony_ci			}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci			ret |= pending;
5988c2ecf20Sopenharmony_ci		}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci		for (i = 0; i < count; i++)
6018c2ecf20Sopenharmony_ci			dma_fence_put(shared[i]);
6028c2ecf20Sopenharmony_ci		kfree(shared);
6038c2ecf20Sopenharmony_ci	} else {
6048c2ecf20Sopenharmony_ci		excl = dma_resv_get_excl_rcu(resv);
6058c2ecf20Sopenharmony_ci	}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	if (ret >= 0 && excl && excl->ops != exclude) {
6088c2ecf20Sopenharmony_ci		pending = i915_sw_fence_await_dma_fence(fence,
6098c2ecf20Sopenharmony_ci							excl,
6108c2ecf20Sopenharmony_ci							timeout,
6118c2ecf20Sopenharmony_ci							gfp);
6128c2ecf20Sopenharmony_ci		if (pending < 0)
6138c2ecf20Sopenharmony_ci			ret = pending;
6148c2ecf20Sopenharmony_ci		else
6158c2ecf20Sopenharmony_ci			ret |= pending;
6168c2ecf20Sopenharmony_ci	}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	dma_fence_put(excl);
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	return ret;
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
6248c2ecf20Sopenharmony_ci#include "selftests/lib_sw_fence.c"
6258c2ecf20Sopenharmony_ci#include "selftests/i915_sw_fence.c"
6268c2ecf20Sopenharmony_ci#endif
627