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