1 /* SPDX-License-Identifier: GPL-2.0 OR MIT */ 2 3 #ifndef __DRM_EXEC_H__ 4 #define __DRM_EXEC_H__ 5 6 #include <linux/compiler.h> 7 #include <linux/ww_mutex.h> 8 9 #define DRM_EXEC_INTERRUPTIBLE_WAIT BIT(0) 10 #define DRM_EXEC_IGNORE_DUPLICATES BIT(1) 11 12 /* 13 * Dummy value used to initially enter the retry loop. 14 * internal use only. 15 */ 16 #define DRM_EXEC_DUMMY ((void *)~0) 17 18 struct drm_gem_object; 19 20 /** 21 * struct drm_exec - Execution context 22 */ 23 struct drm_exec { 24 /** 25 * @flags: Flags to control locking behavior 26 */ 27 u32 flags; 28 29 /** 30 * @ticket: WW ticket used for acquiring locks 31 */ 32 struct ww_acquire_ctx ticket; 33 34 /** 35 * @num_objects: number of objects locked 36 */ 37 unsigned int num_objects; 38 39 /** 40 * @max_objects: maximum objects in array 41 */ 42 unsigned int max_objects; 43 44 /** 45 * @objects: array of the locked objects 46 */ 47 struct drm_gem_object **objects; 48 49 /** 50 * @contended: contended GEM object we backed off for 51 */ 52 struct drm_gem_object *contended; 53 54 /** 55 * @prelocked: already locked GEM object due to contention 56 */ 57 struct drm_gem_object *prelocked; 58 }; 59 60 /** 61 * drm_exec_obj() - Return the object for a give drm_exec index 62 * @exec: Pointer to the drm_exec context 63 * @index: The index. 64 * 65 * Return: Pointer to the locked object corresponding to @index if 66 * index is within the number of locked objects. NULL otherwise. 67 */ 68 static inline struct drm_gem_object * 69 drm_exec_obj(struct drm_exec *exec, unsigned long index) 70 { 71 return index < exec->num_objects ? exec->objects[index] : NULL; 72 } 73 74 /* Helper for drm_exec_for_each_locked_object(). Internal use only. */ 75 #define __drm_exec_for_each_locked_object(exec, obj, __index) \ 76 for (unsigned long __index = 0; ((obj) = drm_exec_obj(exec, __index)); ++__index) 77 /** 78 * drm_exec_for_each_locked_object - iterate over all the locked objects 79 * @exec: drm_exec object 80 * @obj: the current GEM object 81 * 82 * Iterate over all the locked GEM objects inside the drm_exec object. 83 */ 84 #define drm_exec_for_each_locked_object(exec, obj) \ 85 __drm_exec_for_each_locked_object(exec, obj, __UNIQUE_ID(drm_exec)) 86 87 /* Helper for drm_exec_for_each_locked_object_reverse(). Internal use only. */ 88 #define __drm_exec_for_each_locked_object_reverse(exec, obj, __index) \ 89 for (unsigned long __index = (exec)->num_objects - 1; \ 90 ((obj) = drm_exec_obj(exec, __index)); --__index) 91 /** 92 * drm_exec_for_each_locked_object_reverse - iterate over all the locked 93 * objects in reverse locking order 94 * @exec: drm_exec object 95 * @obj: the current GEM object 96 * 97 * Iterate over all the locked GEM objects inside the drm_exec object in 98 * reverse locking order. Note that the internal index may wrap around, 99 * but that will be caught by drm_exec_obj(), returning a NULL object. 100 */ 101 #define drm_exec_for_each_locked_object_reverse(exec, obj) \ 102 __drm_exec_for_each_locked_object_reverse(exec, obj, __UNIQUE_ID(drm_exec)) 103 104 /** 105 * drm_exec_until_all_locked - loop until all GEM objects are locked 106 * @exec: drm_exec object 107 * 108 * Core functionality of the drm_exec object. Loops until all GEM objects are 109 * locked and no more contention exists. At the beginning of the loop it is 110 * guaranteed that no GEM object is locked. 111 * 112 * A global label name drm_exec_retry is used, if you need to use more than one 113 * instance of this macro in the same function the label needs to be made local 114 * to the block with the __label__ keyword. 115 */ 116 #define drm_exec_until_all_locked(exec) \ 117 for (bool const __maybe_unused __drm_exec_loop = false; \ 118 drm_exec_cleanup(exec);) \ 119 if (false) { \ 120 drm_exec_retry: __maybe_unused; \ 121 continue; \ 122 } else 123 124 /** 125 * drm_exec_retry_on_contention - restart the loop to grap all locks 126 * @exec: drm_exec object 127 * 128 * Control flow helper to continue when a contention was detected and we need to 129 * clean up and re-start the loop to prepare all GEM objects. 130 * The __drm_exec_loop check exists to prevent usage outside of an 131 * drm_exec_until_all_locked() loop. 132 */ 133 #define drm_exec_retry_on_contention(exec) \ 134 do { \ 135 if (unlikely(drm_exec_is_contended(exec))) \ 136 goto drm_exec_retry; \ 137 } while (__drm_exec_loop) 138 139 /** 140 * drm_exec_is_contended - check for contention 141 * @exec: drm_exec object 142 * 143 * Returns true if the drm_exec object has run into some contention while 144 * locking a GEM object and needs to clean up. 145 */ 146 static inline bool drm_exec_is_contended(struct drm_exec *exec) 147 { 148 return !!exec->contended; 149 } 150 151 /** 152 * drm_exec_retry() - Unconditionally restart the loop to grab all locks. 153 * @exec: drm_exec object 154 * 155 * Unconditionally retry the loop to lock all objects. For consistency, 156 * the exec object needs to be newly initialized. 157 * The __drm_exec_loop check exists to prevent usage outside of an 158 * drm_exec_until_all_locked() loop. 159 */ 160 #define drm_exec_retry(_exec) \ 161 do { \ 162 WARN_ON((_exec)->contended != DRM_EXEC_DUMMY); \ 163 goto drm_exec_retry; \ 164 } while (__drm_exec_loop) 165 166 /** 167 * drm_exec_ticket - return the ww_acquire_ctx for this exec context 168 * @exec: drm_exec object 169 * 170 * Return: Pointer to the ww_acquire_ctx embedded in @exec. 171 */ 172 static inline struct ww_acquire_ctx *drm_exec_ticket(struct drm_exec *exec) 173 { 174 return &exec->ticket; 175 } 176 177 void drm_exec_init(struct drm_exec *exec, u32 flags, unsigned nr); 178 void drm_exec_fini(struct drm_exec *exec); 179 bool drm_exec_cleanup(struct drm_exec *exec); 180 int drm_exec_lock_obj(struct drm_exec *exec, struct drm_gem_object *obj); 181 void drm_exec_unlock_obj(struct drm_exec *exec, struct drm_gem_object *obj); 182 int drm_exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj, 183 unsigned int num_fences); 184 int drm_exec_prepare_array(struct drm_exec *exec, 185 struct drm_gem_object **objects, 186 unsigned int num_objects, 187 unsigned int num_fences); 188 189 #endif 190