162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * SPDX-License-Identifier: MIT
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright © 2019 Intel Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#ifndef _I915_ACTIVE_H_
862306a36Sopenharmony_ci#define _I915_ACTIVE_H_
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/lockdep.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "i915_active_types.h"
1362306a36Sopenharmony_ci#include "i915_request.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistruct i915_request;
1662306a36Sopenharmony_cistruct intel_engine_cs;
1762306a36Sopenharmony_cistruct intel_timeline;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * We treat requests as fences. This is not be to confused with our
2162306a36Sopenharmony_ci * "fence registers" but pipeline synchronisation objects ala GL_ARB_sync.
2262306a36Sopenharmony_ci * We use the fences to synchronize access from the CPU with activity on the
2362306a36Sopenharmony_ci * GPU, for example, we should not rewrite an object's PTE whilst the GPU
2462306a36Sopenharmony_ci * is reading them. We also track fences at a higher level to provide
2562306a36Sopenharmony_ci * implicit synchronisation around GEM objects, e.g. set-domain will wait
2662306a36Sopenharmony_ci * for outstanding GPU rendering before marking the object ready for CPU
2762306a36Sopenharmony_ci * access, or a pageflip will wait until the GPU is complete before showing
2862306a36Sopenharmony_ci * the frame on the scanout.
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * In order to use a fence, the object must track the fence it needs to
3162306a36Sopenharmony_ci * serialise with. For example, GEM objects want to track both read and
3262306a36Sopenharmony_ci * write access so that we can perform concurrent read operations between
3362306a36Sopenharmony_ci * the CPU and GPU engines, as well as waiting for all rendering to
3462306a36Sopenharmony_ci * complete, or waiting for the last GPU user of a "fence register". The
3562306a36Sopenharmony_ci * object then embeds a #i915_active_fence to track the most recent (in
3662306a36Sopenharmony_ci * retirement order) request relevant for the desired mode of access.
3762306a36Sopenharmony_ci * The #i915_active_fence is updated with i915_active_fence_set() to
3862306a36Sopenharmony_ci * track the most recent fence request, typically this is done as part of
3962306a36Sopenharmony_ci * i915_vma_move_to_active().
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * When the #i915_active_fence completes (is retired), it will
4262306a36Sopenharmony_ci * signal its completion to the owner through a callback as well as mark
4362306a36Sopenharmony_ci * itself as idle (i915_active_fence.request == NULL). The owner
4462306a36Sopenharmony_ci * can then perform any action, such as delayed freeing of an active
4562306a36Sopenharmony_ci * resource including itself.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_civoid i915_active_noop(struct dma_fence *fence, struct dma_fence_cb *cb);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/**
5162306a36Sopenharmony_ci * __i915_active_fence_init - prepares the activity tracker for use
5262306a36Sopenharmony_ci * @active: the active tracker
5362306a36Sopenharmony_ci * @fence: initial fence to track, can be NULL
5462306a36Sopenharmony_ci * @fn: a callback when then the tracker is retired (becomes idle),
5562306a36Sopenharmony_ci *         can be NULL
5662306a36Sopenharmony_ci *
5762306a36Sopenharmony_ci * i915_active_fence_init() prepares the embedded @active struct for use as
5862306a36Sopenharmony_ci * an activity tracker, that is for tracking the last known active fence
5962306a36Sopenharmony_ci * associated with it. When the last fence becomes idle, when it is retired
6062306a36Sopenharmony_ci * after completion, the optional callback @func is invoked.
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_cistatic inline void
6362306a36Sopenharmony_ci__i915_active_fence_init(struct i915_active_fence *active,
6462306a36Sopenharmony_ci			 void *fence,
6562306a36Sopenharmony_ci			 dma_fence_func_t fn)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	RCU_INIT_POINTER(active->fence, fence);
6862306a36Sopenharmony_ci	active->cb.func = fn ?: i915_active_noop;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define INIT_ACTIVE_FENCE(A) \
7262306a36Sopenharmony_ci	__i915_active_fence_init((A), NULL, NULL)
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistruct dma_fence *
7562306a36Sopenharmony_ci__i915_active_fence_set(struct i915_active_fence *active,
7662306a36Sopenharmony_ci			struct dma_fence *fence);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/**
7962306a36Sopenharmony_ci * i915_active_fence_set - updates the tracker to watch the current fence
8062306a36Sopenharmony_ci * @active: the active tracker
8162306a36Sopenharmony_ci * @rq: the request to watch
8262306a36Sopenharmony_ci *
8362306a36Sopenharmony_ci * i915_active_fence_set() watches the given @rq for completion. While
8462306a36Sopenharmony_ci * that @rq is busy, the @active reports busy. When that @rq is signaled
8562306a36Sopenharmony_ci * (or else retired) the @active tracker is updated to report idle.
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_ciint __must_check
8862306a36Sopenharmony_cii915_active_fence_set(struct i915_active_fence *active,
8962306a36Sopenharmony_ci		      struct i915_request *rq);
9062306a36Sopenharmony_ci/**
9162306a36Sopenharmony_ci * i915_active_fence_get - return a reference to the active fence
9262306a36Sopenharmony_ci * @active: the active tracker
9362306a36Sopenharmony_ci *
9462306a36Sopenharmony_ci * i915_active_fence_get() returns a reference to the active fence,
9562306a36Sopenharmony_ci * or NULL if the active tracker is idle. The reference is obtained under RCU,
9662306a36Sopenharmony_ci * so no locking is required by the caller.
9762306a36Sopenharmony_ci *
9862306a36Sopenharmony_ci * The reference should be freed with dma_fence_put().
9962306a36Sopenharmony_ci */
10062306a36Sopenharmony_cistatic inline struct dma_fence *
10162306a36Sopenharmony_cii915_active_fence_get(struct i915_active_fence *active)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	struct dma_fence *fence;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	rcu_read_lock();
10662306a36Sopenharmony_ci	fence = dma_fence_get_rcu_safe(&active->fence);
10762306a36Sopenharmony_ci	rcu_read_unlock();
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	return fence;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/**
11362306a36Sopenharmony_ci * i915_active_fence_isset - report whether the active tracker is assigned
11462306a36Sopenharmony_ci * @active: the active tracker
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * i915_active_fence_isset() returns true if the active tracker is currently
11762306a36Sopenharmony_ci * assigned to a fence. Due to the lazy retiring, that fence may be idle
11862306a36Sopenharmony_ci * and this may report stale information.
11962306a36Sopenharmony_ci */
12062306a36Sopenharmony_cistatic inline bool
12162306a36Sopenharmony_cii915_active_fence_isset(const struct i915_active_fence *active)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	return rcu_access_pointer(active->fence);
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/*
12762306a36Sopenharmony_ci * GPU activity tracking
12862306a36Sopenharmony_ci *
12962306a36Sopenharmony_ci * Each set of commands submitted to the GPU compromises a single request that
13062306a36Sopenharmony_ci * signals a fence upon completion. struct i915_request combines the
13162306a36Sopenharmony_ci * command submission, scheduling and fence signaling roles. If we want to see
13262306a36Sopenharmony_ci * if a particular task is complete, we need to grab the fence (struct
13362306a36Sopenharmony_ci * i915_request) for that task and check or wait for it to be signaled. More
13462306a36Sopenharmony_ci * often though we want to track the status of a bunch of tasks, for example
13562306a36Sopenharmony_ci * to wait for the GPU to finish accessing some memory across a variety of
13662306a36Sopenharmony_ci * different command pipelines from different clients. We could choose to
13762306a36Sopenharmony_ci * track every single request associated with the task, but knowing that
13862306a36Sopenharmony_ci * each request belongs to an ordered timeline (later requests within a
13962306a36Sopenharmony_ci * timeline must wait for earlier requests), we need only track the
14062306a36Sopenharmony_ci * latest request in each timeline to determine the overall status of the
14162306a36Sopenharmony_ci * task.
14262306a36Sopenharmony_ci *
14362306a36Sopenharmony_ci * struct i915_active provides this tracking across timelines. It builds a
14462306a36Sopenharmony_ci * composite shared-fence, and is updated as new work is submitted to the task,
14562306a36Sopenharmony_ci * forming a snapshot of the current status. It should be embedded into the
14662306a36Sopenharmony_ci * different resources that need to track their associated GPU activity to
14762306a36Sopenharmony_ci * provide a callback when that GPU activity has ceased, or otherwise to
14862306a36Sopenharmony_ci * provide a serialisation point either for request submission or for CPU
14962306a36Sopenharmony_ci * synchronisation.
15062306a36Sopenharmony_ci */
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_civoid __i915_active_init(struct i915_active *ref,
15362306a36Sopenharmony_ci			int (*active)(struct i915_active *ref),
15462306a36Sopenharmony_ci			void (*retire)(struct i915_active *ref),
15562306a36Sopenharmony_ci			unsigned long flags,
15662306a36Sopenharmony_ci			struct lock_class_key *mkey,
15762306a36Sopenharmony_ci			struct lock_class_key *wkey);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/* Specialise each class of i915_active to avoid impossible lockdep cycles. */
16062306a36Sopenharmony_ci#define i915_active_init(ref, active, retire, flags) do {			\
16162306a36Sopenharmony_ci	static struct lock_class_key __mkey;					\
16262306a36Sopenharmony_ci	static struct lock_class_key __wkey;					\
16362306a36Sopenharmony_ci										\
16462306a36Sopenharmony_ci	__i915_active_init(ref, active, retire, flags, &__mkey, &__wkey);	\
16562306a36Sopenharmony_ci} while (0)
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ciint i915_active_add_request(struct i915_active *ref, struct i915_request *rq);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistruct dma_fence *
17062306a36Sopenharmony_cii915_active_set_exclusive(struct i915_active *ref, struct dma_fence *f);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ciint __i915_active_wait(struct i915_active *ref, int state);
17362306a36Sopenharmony_cistatic inline int i915_active_wait(struct i915_active *ref)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	return __i915_active_wait(ref, TASK_INTERRUPTIBLE);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ciint i915_sw_fence_await_active(struct i915_sw_fence *fence,
17962306a36Sopenharmony_ci			       struct i915_active *ref,
18062306a36Sopenharmony_ci			       unsigned int flags);
18162306a36Sopenharmony_ciint i915_request_await_active(struct i915_request *rq,
18262306a36Sopenharmony_ci			      struct i915_active *ref,
18362306a36Sopenharmony_ci			      unsigned int flags);
18462306a36Sopenharmony_ci#define I915_ACTIVE_AWAIT_EXCL BIT(0)
18562306a36Sopenharmony_ci#define I915_ACTIVE_AWAIT_ACTIVE BIT(1)
18662306a36Sopenharmony_ci#define I915_ACTIVE_AWAIT_BARRIER BIT(2)
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ciint i915_active_acquire(struct i915_active *ref);
18962306a36Sopenharmony_ciint i915_active_acquire_for_context(struct i915_active *ref, u64 idx);
19062306a36Sopenharmony_cibool i915_active_acquire_if_busy(struct i915_active *ref);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_civoid i915_active_release(struct i915_active *ref);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic inline void __i915_active_acquire(struct i915_active *ref)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	GEM_BUG_ON(!atomic_read(&ref->count));
19762306a36Sopenharmony_ci	atomic_inc(&ref->count);
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic inline bool
20162306a36Sopenharmony_cii915_active_is_idle(const struct i915_active *ref)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	return !atomic_read(&ref->count);
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_civoid i915_active_fini(struct i915_active *ref);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ciint i915_active_acquire_preallocate_barrier(struct i915_active *ref,
20962306a36Sopenharmony_ci					    struct intel_engine_cs *engine);
21062306a36Sopenharmony_civoid i915_active_acquire_barrier(struct i915_active *ref);
21162306a36Sopenharmony_civoid i915_request_add_active_barriers(struct i915_request *rq);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_civoid i915_active_print(struct i915_active *ref, struct drm_printer *m);
21462306a36Sopenharmony_civoid i915_active_unlock_wait(struct i915_active *ref);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistruct i915_active *i915_active_create(void);
21762306a36Sopenharmony_cistruct i915_active *i915_active_get(struct i915_active *ref);
21862306a36Sopenharmony_civoid i915_active_put(struct i915_active *ref);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic inline int __i915_request_await_exclusive(struct i915_request *rq,
22162306a36Sopenharmony_ci						 struct i915_active *active)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct dma_fence *fence;
22462306a36Sopenharmony_ci	int err = 0;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	fence = i915_active_fence_get(&active->excl);
22762306a36Sopenharmony_ci	if (fence) {
22862306a36Sopenharmony_ci		err = i915_request_await_dma_fence(rq, fence);
22962306a36Sopenharmony_ci		dma_fence_put(fence);
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return err;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_civoid i915_active_module_exit(void);
23662306a36Sopenharmony_ciint i915_active_module_init(void);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci#endif /* _I915_ACTIVE_H_ */
239