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 and put the prelocked obj */ 52 static void drm_exec_drop_prelocked(struct drm_exec *exec) 53 { 54 if (exec->prelocked) { 55 dma_resv_unlock(exec->prelocked->resv); 56 drm_gem_object_put(exec->prelocked); 57 exec->prelocked = NULL; 58 } 59 } 60 61 /* Unlock all objects and drop references */ 62 static void drm_exec_unlock_all(struct drm_exec *exec) 63 { 64 struct drm_gem_object *obj; 65 66 drm_exec_for_each_locked_object_reverse(exec, obj) { 67 dma_resv_unlock(obj->resv); 68 drm_gem_object_put(obj); 69 } 70 71 drm_exec_drop_prelocked(exec); 72 } 73 74 /** 75 * drm_exec_init - initialize a drm_exec object 76 * @exec: the drm_exec object to initialize 77 * @flags: controls locking behavior, see DRM_EXEC_* defines 78 * @nr: the initial # of objects 79 * 80 * Initialize the object and make sure that we can track locked objects. 81 * 82 * If nr is non-zero then it is used as the initial objects table size. 83 * In either case, the table will grow (be re-allocated) on demand. 84 */ 85 void drm_exec_init(struct drm_exec *exec, u32 flags, unsigned nr) 86 { 87 if (!nr) 88 nr = PAGE_SIZE / sizeof(void *); 89 90 exec->flags = flags; 91 exec->objects = kvmalloc_objs(*exec->objects, nr); 92 93 /* If allocation here fails, just delay that till the first use */ 94 exec->max_objects = exec->objects ? nr : 0; 95 exec->num_objects = 0; 96 exec->contended = DRM_EXEC_DUMMY; 97 exec->prelocked = NULL; 98 } 99 EXPORT_SYMBOL(drm_exec_init); 100 101 /** 102 * drm_exec_fini - finalize a drm_exec object 103 * @exec: the drm_exec object to finalize 104 * 105 * Unlock all locked objects, drop the references to objects and free all memory 106 * used for tracking the state. 107 */ 108 void drm_exec_fini(struct drm_exec *exec) 109 { 110 drm_exec_unlock_all(exec); 111 kvfree(exec->objects); 112 if (exec->contended != DRM_EXEC_DUMMY) { 113 drm_gem_object_put(exec->contended); 114 ww_acquire_fini(&exec->ticket); 115 } 116 } 117 EXPORT_SYMBOL(drm_exec_fini); 118 119 /** 120 * drm_exec_cleanup - cleanup when contention is detected 121 * @exec: the drm_exec object to cleanup 122 * 123 * Cleanup the current state and return true if we should stay inside the retry 124 * loop, false if there wasn't any contention detected and we can keep the 125 * objects locked. 126 */ 127 bool drm_exec_cleanup(struct drm_exec *exec) 128 { 129 if (likely(!exec->contended)) { 130 131 /* 132 * The contended and prelocked object might never be passed to 133 * drm_exec_lock_obj() again. This can happen when the object 134 * is about to be cleaned up and we now hold the last reference 135 * to it. Make sure that we don't unnecessarily keep it around. 136 */ 137 drm_exec_drop_prelocked(exec); 138 ww_acquire_done(&exec->ticket); 139 return false; 140 } 141 142 if (likely(exec->contended == DRM_EXEC_DUMMY)) { 143 exec->contended = NULL; 144 ww_acquire_init(&exec->ticket, &reservation_ww_class); 145 return true; 146 } 147 148 drm_exec_unlock_all(exec); 149 exec->num_objects = 0; 150 return true; 151 } 152 EXPORT_SYMBOL(drm_exec_cleanup); 153 154 /* Track the locked object in the array */ 155 static int drm_exec_obj_locked(struct drm_exec *exec, 156 struct drm_gem_object *obj) 157 { 158 if (unlikely(exec->num_objects == exec->max_objects)) { 159 size_t size = exec->max_objects * sizeof(void *); 160 void *tmp; 161 162 tmp = kvrealloc(exec->objects, size + PAGE_SIZE, GFP_KERNEL); 163 if (!tmp) 164 return -ENOMEM; 165 166 exec->objects = tmp; 167 exec->max_objects += PAGE_SIZE / sizeof(void *); 168 } 169 drm_gem_object_get(obj); 170 exec->objects[exec->num_objects++] = obj; 171 172 return 0; 173 } 174 175 /* Make sure the contended object is locked first */ 176 static int drm_exec_lock_contended(struct drm_exec *exec) 177 { 178 struct drm_gem_object *obj = exec->contended; 179 int ret; 180 181 if (likely(!obj)) 182 return 0; 183 184 /* Always cleanup the contention so that error handling can kick in */ 185 exec->contended = NULL; 186 if (exec->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) { 187 ret = dma_resv_lock_slow_interruptible(obj->resv, 188 &exec->ticket); 189 if (unlikely(ret)) 190 goto error_dropref; 191 } else { 192 dma_resv_lock_slow(obj->resv, &exec->ticket); 193 } 194 195 /* 196 * It is perfectly possible that we see another contention before the 197 * first one is fully handled. 198 */ 199 drm_exec_drop_prelocked(exec); 200 201 /* We move the reference from contended to prelocked here */ 202 exec->prelocked = obj; 203 return 0; 204 205 error_dropref: 206 drm_gem_object_put(obj); 207 return ret; 208 } 209 210 /** 211 * drm_exec_lock_obj - lock a GEM object for use 212 * @exec: the drm_exec object with the state 213 * @obj: the GEM object to lock 214 * 215 * Lock a GEM object for use and grab a reference to it. 216 * 217 * Returns: -EDEADLK if a contention is detected, -EALREADY when object is 218 * already locked (can be suppressed by setting the DRM_EXEC_IGNORE_DUPLICATES 219 * flag), -ENOMEM when memory allocation failed and zero for success. 220 */ 221 int drm_exec_lock_obj(struct drm_exec *exec, struct drm_gem_object *obj) 222 { 223 int ret; 224 225 ret = drm_exec_lock_contended(exec); 226 if (unlikely(ret)) 227 return ret; 228 229 if (exec->prelocked == obj) { 230 drm_gem_object_put(exec->prelocked); 231 exec->prelocked = NULL; 232 } else { 233 if (exec->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) 234 ret = dma_resv_lock_interruptible(obj->resv, 235 &exec->ticket); 236 else 237 ret = dma_resv_lock(obj->resv, &exec->ticket); 238 239 if (unlikely(ret == -EDEADLK)) { 240 drm_gem_object_get(obj); 241 exec->contended = obj; 242 return -EDEADLK; 243 } 244 245 if (unlikely(ret == -EALREADY) && 246 exec->flags & DRM_EXEC_IGNORE_DUPLICATES) 247 return 0; 248 249 if (unlikely(ret)) 250 return ret; 251 } 252 253 ret = drm_exec_obj_locked(exec, obj); 254 if (ret) 255 dma_resv_unlock(obj->resv); 256 257 return ret; 258 } 259 EXPORT_SYMBOL(drm_exec_lock_obj); 260 261 /** 262 * drm_exec_unlock_obj - unlock a GEM object in this exec context 263 * @exec: the drm_exec object with the state 264 * @obj: the GEM object to unlock 265 * 266 * Unlock the GEM object and remove it from the collection of locked objects. 267 * Should only be used to unlock the most recently locked objects. It's not time 268 * efficient to unlock objects locked long ago. 269 */ 270 void drm_exec_unlock_obj(struct drm_exec *exec, struct drm_gem_object *obj) 271 { 272 unsigned int i; 273 274 for (i = exec->num_objects; i--;) { 275 if (exec->objects[i] == obj) { 276 dma_resv_unlock(obj->resv); 277 for (++i; i < exec->num_objects; ++i) 278 exec->objects[i - 1] = exec->objects[i]; 279 --exec->num_objects; 280 drm_gem_object_put(obj); 281 return; 282 } 283 284 } 285 } 286 EXPORT_SYMBOL(drm_exec_unlock_obj); 287 288 /** 289 * drm_exec_prepare_obj - prepare a GEM object for use 290 * @exec: the drm_exec object with the state 291 * @obj: the GEM object to prepare 292 * @num_fences: how many fences to reserve 293 * 294 * Prepare a GEM object for use by locking it and reserving fence slots. 295 * 296 * Returns: -EDEADLK if a contention is detected, -EALREADY when object is 297 * already locked, -ENOMEM when memory allocation failed and zero for success. 298 */ 299 int drm_exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj, 300 unsigned int num_fences) 301 { 302 int ret; 303 304 ret = drm_exec_lock_obj(exec, obj); 305 if (ret) 306 return ret; 307 308 ret = dma_resv_reserve_fences(obj->resv, num_fences); 309 if (ret) { 310 drm_exec_unlock_obj(exec, obj); 311 return ret; 312 } 313 314 return 0; 315 } 316 EXPORT_SYMBOL(drm_exec_prepare_obj); 317 318 /** 319 * drm_exec_prepare_array - helper to prepare an array of objects 320 * @exec: the drm_exec object with the state 321 * @objects: array of GEM object to prepare 322 * @num_objects: number of GEM objects in the array 323 * @num_fences: number of fences to reserve on each GEM object 324 * 325 * Prepares all GEM objects in an array, aborts on first error. 326 * Reserves @num_fences on each GEM object after locking it. 327 * 328 * Returns: -EDEADLOCK on contention, -EALREADY when object is already locked, 329 * -ENOMEM when memory allocation failed and zero for success. 330 */ 331 int drm_exec_prepare_array(struct drm_exec *exec, 332 struct drm_gem_object **objects, 333 unsigned int num_objects, 334 unsigned int num_fences) 335 { 336 int ret; 337 338 /* 339 * Make sure to lock a contended object even when no objects are 340 * given, otherwise drm_exec_retry_on_contention() would loop 341 * forever on patterns like: 342 * 343 * ret = drm_exec_prepare_array(exec, objs, num_objects, ...); 344 * drm_exec_retry_on_contention(exec); 345 * 346 * with num_objects == 0. 347 */ 348 if (!num_objects) 349 return drm_exec_lock_contended(exec); 350 351 for (unsigned int i = 0; i < num_objects; ++i) { 352 ret = drm_exec_prepare_obj(exec, objects[i], num_fences); 353 if (unlikely(ret)) 354 return ret; 355 } 356 357 return 0; 358 } 359 EXPORT_SYMBOL(drm_exec_prepare_array); 360 361 MODULE_DESCRIPTION("DRM execution context"); 362 MODULE_LICENSE("Dual MIT/GPL"); 363