1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 3 #include <drm/drm_exec.h> 4 #include <drm/drm_gem.h> 5 6 #include <linux/dma-resv.h> 7 #include <linux/export.h> 8 9 /** 10 * DOC: Overview 11 * 12 * This component mainly abstracts the retry loop necessary for locking 13 * multiple GEM objects while preparing hardware operations (e.g. command 14 * submissions, page table updates etc..). 15 * 16 * If a contention is detected while locking a GEM object the cleanup procedure 17 * unlocks all previously locked GEM objects and locks the contended one first 18 * before locking any further objects. 19 * 20 * After an object is locked fences slots can optionally be reserved on the 21 * dma_resv object inside the GEM object. 22 * 23 * A typical usage pattern should look like this:: 24 * 25 * struct drm_gem_object *obj; 26 * struct drm_exec exec; 27 * int ret; 28 * 29 * drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); 30 * drm_exec_until_all_locked(&exec) { 31 * ret = drm_exec_prepare_obj(&exec, boA, 1); 32 * drm_exec_retry_on_contention(&exec); 33 * if (ret) 34 * goto error; 35 * 36 * ret = drm_exec_prepare_obj(&exec, boB, 1); 37 * drm_exec_retry_on_contention(&exec); 38 * if (ret) 39 * goto error; 40 * } 41 * 42 * drm_exec_for_each_locked_object(&exec, obj) { 43 * dma_resv_add_fence(obj->resv, fence, DMA_RESV_USAGE_READ); 44 * ... 45 * } 46 * drm_exec_fini(&exec); 47 * 48 * See struct dma_exec for more details. 49 */ 50 51 /* Unlock all objects and drop references */ 52 static void drm_exec_unlock_all(struct drm_exec *exec) 53 { 54 struct drm_gem_object *obj; 55 56 drm_exec_for_each_locked_object_reverse(exec, obj) { 57 dma_resv_unlock(obj->resv); 58 drm_gem_object_put(obj); 59 } 60 61 drm_gem_object_put(exec->prelocked); 62 exec->prelocked = NULL; 63 } 64 65 /** 66 * drm_exec_init - initialize a drm_exec object 67 * @exec: the drm_exec object to initialize 68 * @flags: controls locking behavior, see DRM_EXEC_* defines 69 * @nr: the initial # of objects 70 * 71 * Initialize the object and make sure that we can track locked objects. 72 * 73 * If nr is non-zero then it is used as the initial objects table size. 74 * In either case, the table will grow (be re-allocated) on demand. 75 */ 76 void drm_exec_init(struct drm_exec *exec, u32 flags, unsigned nr) 77 { 78 if (!nr) 79 nr = PAGE_SIZE / sizeof(void *); 80 81 exec->flags = flags; 82 exec->objects = kvmalloc_array(nr, sizeof(void *), GFP_KERNEL); 83 84 /* If allocation here fails, just delay that till the first use */ 85 exec->max_objects = exec->objects ? nr : 0; 86 exec->num_objects = 0; 87 exec->contended = DRM_EXEC_DUMMY; 88 exec->prelocked = NULL; 89 } 90 EXPORT_SYMBOL(drm_exec_init); 91 92 /** 93 * drm_exec_fini - finalize a drm_exec object 94 * @exec: the drm_exec object to finalize 95 * 96 * Unlock all locked objects, drop the references to objects and free all memory 97 * used for tracking the state. 98 */ 99 void drm_exec_fini(struct drm_exec *exec) 100 { 101 drm_exec_unlock_all(exec); 102 kvfree(exec->objects); 103 if (exec->contended != DRM_EXEC_DUMMY) { 104 drm_gem_object_put(exec->contended); 105 ww_acquire_fini(&exec->ticket); 106 } 107 } 108 EXPORT_SYMBOL(drm_exec_fini); 109 110 /** 111 * drm_exec_cleanup - cleanup when contention is detected 112 * @exec: the drm_exec object to cleanup 113 * 114 * Cleanup the current state and return true if we should stay inside the retry 115 * loop, false if there wasn't any contention detected and we can keep the 116 * objects locked. 117 */ 118 bool drm_exec_cleanup(struct drm_exec *exec) 119 { 120 if (likely(!exec->contended)) { 121 ww_acquire_done(&exec->ticket); 122 return false; 123 } 124 125 if (likely(exec->contended == DRM_EXEC_DUMMY)) { 126 exec->contended = NULL; 127 ww_acquire_init(&exec->ticket, &reservation_ww_class); 128 return true; 129 } 130 131 drm_exec_unlock_all(exec); 132 exec->num_objects = 0; 133 return true; 134 } 135 EXPORT_SYMBOL(drm_exec_cleanup); 136 137 /* Track the locked object in the array */ 138 static int drm_exec_obj_locked(struct drm_exec *exec, 139 struct drm_gem_object *obj) 140 { 141 if (unlikely(exec->num_objects == exec->max_objects)) { 142 size_t size = exec->max_objects * sizeof(void *); 143 void *tmp; 144 145 tmp = kvrealloc(exec->objects, size + PAGE_SIZE, GFP_KERNEL); 146 if (!tmp) 147 return -ENOMEM; 148 149 exec->objects = tmp; 150 exec->max_objects += PAGE_SIZE / sizeof(void *); 151 } 152 drm_gem_object_get(obj); 153 exec->objects[exec->num_objects++] = obj; 154 155 return 0; 156 } 157 158 /* Make sure the contended object is locked first */ 159 static int drm_exec_lock_contended(struct drm_exec *exec) 160 { 161 struct drm_gem_object *obj = exec->contended; 162 int ret; 163 164 if (likely(!obj)) 165 return 0; 166 167 /* Always cleanup the contention so that error handling can kick in */ 168 exec->contended = NULL; 169 if (exec->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) { 170 ret = dma_resv_lock_slow_interruptible(obj->resv, 171 &exec->ticket); 172 if (unlikely(ret)) 173 goto error_dropref; 174 } else { 175 dma_resv_lock_slow(obj->resv, &exec->ticket); 176 } 177 178 ret = drm_exec_obj_locked(exec, obj); 179 if (unlikely(ret)) 180 goto error_unlock; 181 182 exec->prelocked = obj; 183 return 0; 184 185 error_unlock: 186 dma_resv_unlock(obj->resv); 187 188 error_dropref: 189 drm_gem_object_put(obj); 190 return ret; 191 } 192 193 /** 194 * drm_exec_lock_obj - lock a GEM object for use 195 * @exec: the drm_exec object with the state 196 * @obj: the GEM object to lock 197 * 198 * Lock a GEM object for use and grab a reference to it. 199 * 200 * Returns: -EDEADLK if a contention is detected, -EALREADY when object is 201 * already locked (can be suppressed by setting the DRM_EXEC_IGNORE_DUPLICATES 202 * flag), -ENOMEM when memory allocation failed and zero for success. 203 */ 204 int drm_exec_lock_obj(struct drm_exec *exec, struct drm_gem_object *obj) 205 { 206 int ret; 207 208 ret = drm_exec_lock_contended(exec); 209 if (unlikely(ret)) 210 return ret; 211 212 if (exec->prelocked == obj) { 213 drm_gem_object_put(exec->prelocked); 214 exec->prelocked = NULL; 215 return 0; 216 } 217 218 if (exec->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) 219 ret = dma_resv_lock_interruptible(obj->resv, &exec->ticket); 220 else 221 ret = dma_resv_lock(obj->resv, &exec->ticket); 222 223 if (unlikely(ret == -EDEADLK)) { 224 drm_gem_object_get(obj); 225 exec->contended = obj; 226 return -EDEADLK; 227 } 228 229 if (unlikely(ret == -EALREADY) && 230 exec->flags & DRM_EXEC_IGNORE_DUPLICATES) 231 return 0; 232 233 if (unlikely(ret)) 234 return ret; 235 236 ret = drm_exec_obj_locked(exec, obj); 237 if (ret) 238 goto error_unlock; 239 240 return 0; 241 242 error_unlock: 243 dma_resv_unlock(obj->resv); 244 return ret; 245 } 246 EXPORT_SYMBOL(drm_exec_lock_obj); 247 248 /** 249 * drm_exec_unlock_obj - unlock a GEM object in this exec context 250 * @exec: the drm_exec object with the state 251 * @obj: the GEM object to unlock 252 * 253 * Unlock the GEM object and remove it from the collection of locked objects. 254 * Should only be used to unlock the most recently locked objects. It's not time 255 * efficient to unlock objects locked long ago. 256 */ 257 void drm_exec_unlock_obj(struct drm_exec *exec, struct drm_gem_object *obj) 258 { 259 unsigned int i; 260 261 for (i = exec->num_objects; i--;) { 262 if (exec->objects[i] == obj) { 263 dma_resv_unlock(obj->resv); 264 for (++i; i < exec->num_objects; ++i) 265 exec->objects[i - 1] = exec->objects[i]; 266 --exec->num_objects; 267 drm_gem_object_put(obj); 268 return; 269 } 270 271 } 272 } 273 EXPORT_SYMBOL(drm_exec_unlock_obj); 274 275 /** 276 * drm_exec_prepare_obj - prepare a GEM object for use 277 * @exec: the drm_exec object with the state 278 * @obj: the GEM object to prepare 279 * @num_fences: how many fences to reserve 280 * 281 * Prepare a GEM object for use by locking it and reserving fence slots. 282 * 283 * Returns: -EDEADLK if a contention is detected, -EALREADY when object is 284 * already locked, -ENOMEM when memory allocation failed and zero for success. 285 */ 286 int drm_exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj, 287 unsigned int num_fences) 288 { 289 int ret; 290 291 ret = drm_exec_lock_obj(exec, obj); 292 if (ret) 293 return ret; 294 295 ret = dma_resv_reserve_fences(obj->resv, num_fences); 296 if (ret) { 297 drm_exec_unlock_obj(exec, obj); 298 return ret; 299 } 300 301 return 0; 302 } 303 EXPORT_SYMBOL(drm_exec_prepare_obj); 304 305 /** 306 * drm_exec_prepare_array - helper to prepare an array of objects 307 * @exec: the drm_exec object with the state 308 * @objects: array of GEM object to prepare 309 * @num_objects: number of GEM objects in the array 310 * @num_fences: number of fences to reserve on each GEM object 311 * 312 * Prepares all GEM objects in an array, aborts on first error. 313 * Reserves @num_fences on each GEM object after locking it. 314 * 315 * Returns: -EDEADLOCK on contention, -EALREADY when object is already locked, 316 * -ENOMEM when memory allocation failed and zero for success. 317 */ 318 int drm_exec_prepare_array(struct drm_exec *exec, 319 struct drm_gem_object **objects, 320 unsigned int num_objects, 321 unsigned int num_fences) 322 { 323 int ret; 324 325 for (unsigned int i = 0; i < num_objects; ++i) { 326 ret = drm_exec_prepare_obj(exec, objects[i], num_fences); 327 if (unlikely(ret)) 328 return ret; 329 } 330 331 return 0; 332 } 333 EXPORT_SYMBOL(drm_exec_prepare_array); 334 335 MODULE_DESCRIPTION("DRM execution context"); 336 MODULE_LICENSE("Dual MIT/GPL"); 337