1 /* 2 * SPDX-License-Identifier: MIT 3 * 4 * Copyright © 2019 Intel Corporation 5 */ 6 7 #ifndef _I915_ACTIVE_H_ 8 #define _I915_ACTIVE_H_ 9 10 #include <linux/lockdep.h> 11 12 #include "i915_active_types.h" 13 #include "i915_request.h" 14 15 struct i915_request; 16 struct intel_engine_cs; 17 struct intel_timeline; 18 19 /* 20 * We treat requests as fences. This is not be to confused with our 21 * "fence registers" but pipeline synchronisation objects ala GL_ARB_sync. 22 * We use the fences to synchronize access from the CPU with activity on the 23 * GPU, for example, we should not rewrite an object's PTE whilst the GPU 24 * is reading them. We also track fences at a higher level to provide 25 * implicit synchronisation around GEM objects, e.g. set-domain will wait 26 * for outstanding GPU rendering before marking the object ready for CPU 27 * access, or a pageflip will wait until the GPU is complete before showing 28 * the frame on the scanout. 29 * 30 * In order to use a fence, the object must track the fence it needs to 31 * serialise with. For example, GEM objects want to track both read and 32 * write access so that we can perform concurrent read operations between 33 * the CPU and GPU engines, as well as waiting for all rendering to 34 * complete, or waiting for the last GPU user of a "fence register". The 35 * object then embeds a #i915_active_fence to track the most recent (in 36 * retirement order) request relevant for the desired mode of access. 37 * The #i915_active_fence is updated with i915_active_fence_set() to 38 * track the most recent fence request, typically this is done as part of 39 * i915_vma_move_to_active(). 40 * 41 * When the #i915_active_fence completes (is retired), it will 42 * signal its completion to the owner through a callback as well as mark 43 * itself as idle (i915_active_fence.request == NULL). The owner 44 * can then perform any action, such as delayed freeing of an active 45 * resource including itself. 46 */ 47 48 void i915_active_noop(struct dma_fence *fence, struct dma_fence_cb *cb); 49 50 /** 51 * __i915_active_fence_init - prepares the activity tracker for use 52 * @active - the active tracker 53 * @fence - initial fence to track, can be NULL 54 * @func - a callback when then the tracker is retired (becomes idle), 55 * can be NULL 56 * 57 * i915_active_fence_init() prepares the embedded @active struct for use as 58 * an activity tracker, that is for tracking the last known active fence 59 * associated with it. When the last fence becomes idle, when it is retired 60 * after completion, the optional callback @func is invoked. 61 */ 62 static inline void 63 __i915_active_fence_init(struct i915_active_fence *active, 64 struct mutex *lock, 65 void *fence, 66 dma_fence_func_t fn) 67 { 68 RCU_INIT_POINTER(active->fence, fence); 69 active->cb.func = fn ?: i915_active_noop; 70 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) 71 active->lock = lock; 72 #endif 73 } 74 75 #define INIT_ACTIVE_FENCE(A, LOCK) \ 76 __i915_active_fence_init((A), (LOCK), NULL, NULL) 77 78 struct dma_fence * 79 __i915_active_fence_set(struct i915_active_fence *active, 80 struct dma_fence *fence); 81 82 /** 83 * i915_active_fence_set - updates the tracker to watch the current fence 84 * @active - the active tracker 85 * @rq - the request to watch 86 * 87 * i915_active_fence_set() watches the given @rq for completion. While 88 * that @rq is busy, the @active reports busy. When that @rq is signaled 89 * (or else retired) the @active tracker is updated to report idle. 90 */ 91 int __must_check 92 i915_active_fence_set(struct i915_active_fence *active, 93 struct i915_request *rq); 94 /** 95 * i915_active_fence_get - return a reference to the active fence 96 * @active - the active tracker 97 * 98 * i915_active_fence_get() returns a reference to the active fence, 99 * or NULL if the active tracker is idle. The reference is obtained under RCU, 100 * so no locking is required by the caller. 101 * 102 * The reference should be freed with dma_fence_put(). 103 */ 104 static inline struct dma_fence * 105 i915_active_fence_get(struct i915_active_fence *active) 106 { 107 struct dma_fence *fence; 108 109 rcu_read_lock(); 110 fence = dma_fence_get_rcu_safe(&active->fence); 111 rcu_read_unlock(); 112 113 return fence; 114 } 115 116 /** 117 * i915_active_fence_isset - report whether the active tracker is assigned 118 * @active - the active tracker 119 * 120 * i915_active_fence_isset() returns true if the active tracker is currently 121 * assigned to a fence. Due to the lazy retiring, that fence may be idle 122 * and this may report stale information. 123 */ 124 static inline bool 125 i915_active_fence_isset(const struct i915_active_fence *active) 126 { 127 return rcu_access_pointer(active->fence); 128 } 129 130 static inline void 131 i915_active_fence_cb(struct dma_fence *fence, struct dma_fence_cb *cb) 132 { 133 struct i915_active_fence *active = 134 container_of(cb, typeof(*active), cb); 135 136 RCU_INIT_POINTER(active->fence, NULL); 137 } 138 139 /* 140 * GPU activity tracking 141 * 142 * Each set of commands submitted to the GPU compromises a single request that 143 * signals a fence upon completion. struct i915_request combines the 144 * command submission, scheduling and fence signaling roles. If we want to see 145 * if a particular task is complete, we need to grab the fence (struct 146 * i915_request) for that task and check or wait for it to be signaled. More 147 * often though we want to track the status of a bunch of tasks, for example 148 * to wait for the GPU to finish accessing some memory across a variety of 149 * different command pipelines from different clients. We could choose to 150 * track every single request associated with the task, but knowing that 151 * each request belongs to an ordered timeline (later requests within a 152 * timeline must wait for earlier requests), we need only track the 153 * latest request in each timeline to determine the overall status of the 154 * task. 155 * 156 * struct i915_active provides this tracking across timelines. It builds a 157 * composite shared-fence, and is updated as new work is submitted to the task, 158 * forming a snapshot of the current status. It should be embedded into the 159 * different resources that need to track their associated GPU activity to 160 * provide a callback when that GPU activity has ceased, or otherwise to 161 * provide a serialisation point either for request submission or for CPU 162 * synchronisation. 163 */ 164 165 void __i915_active_init(struct i915_active *ref, 166 int (*active)(struct i915_active *ref), 167 void (*retire)(struct i915_active *ref), 168 struct lock_class_key *key); 169 #define i915_active_init(ref, active, retire) do { \ 170 static struct lock_class_key __key; \ 171 \ 172 __i915_active_init(ref, active, retire, &__key); \ 173 } while (0) 174 175 int i915_active_ref(struct i915_active *ref, 176 struct intel_timeline *tl, 177 struct dma_fence *fence); 178 179 static inline int 180 i915_active_add_request(struct i915_active *ref, struct i915_request *rq) 181 { 182 return i915_active_ref(ref, i915_request_timeline(rq), &rq->fence); 183 } 184 185 void i915_active_set_exclusive(struct i915_active *ref, struct dma_fence *f); 186 187 static inline bool i915_active_has_exclusive(struct i915_active *ref) 188 { 189 return rcu_access_pointer(ref->excl.fence); 190 } 191 192 int i915_active_wait(struct i915_active *ref); 193 194 int i915_request_await_active(struct i915_request *rq, struct i915_active *ref); 195 196 int i915_active_acquire(struct i915_active *ref); 197 bool i915_active_acquire_if_busy(struct i915_active *ref); 198 void i915_active_release(struct i915_active *ref); 199 200 static inline bool 201 i915_active_is_idle(const struct i915_active *ref) 202 { 203 return !atomic_read(&ref->count); 204 } 205 206 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM) 207 void i915_active_fini(struct i915_active *ref); 208 #else 209 static inline void i915_active_fini(struct i915_active *ref) { } 210 #endif 211 212 int i915_active_acquire_preallocate_barrier(struct i915_active *ref, 213 struct intel_engine_cs *engine); 214 void i915_active_acquire_barrier(struct i915_active *ref); 215 void i915_request_add_active_barriers(struct i915_request *rq); 216 217 #endif /* _I915_ACTIVE_H_ */ 218