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 * Helper to drm_exec_until_all_locked(). Don't use directly. 106 * 107 * Since labels can't be defined local to the loop's body we use a jump pointer 108 * to make sure that the retry is only used from within the loop's body. 109 */ 110 #define __drm_exec_until_all_locked(exec, _label) \ 111 _label: \ 112 for (void *const __maybe_unused __drm_exec_retry_ptr = &&_label; \ 113 drm_exec_cleanup(exec);) 114 115 /** 116 * drm_exec_until_all_locked - loop until all GEM objects are locked 117 * @exec: drm_exec object 118 * 119 * Core functionality of the drm_exec object. Loops until all GEM objects are 120 * locked and no more contention exists. At the beginning of the loop it is 121 * guaranteed that no GEM object is locked. 122 */ 123 #define drm_exec_until_all_locked(exec) \ 124 __drm_exec_until_all_locked(exec, __UNIQUE_ID(drm_exec)) 125 126 /** 127 * drm_exec_retry_on_contention - restart the loop to grap all locks 128 * @exec: drm_exec object 129 * 130 * Control flow helper to continue when a contention was detected and we need to 131 * clean up and re-start the loop to prepare all GEM objects. 132 */ 133 #define drm_exec_retry_on_contention(exec) \ 134 do { \ 135 if (unlikely(drm_exec_is_contended(exec))) \ 136 goto *__drm_exec_retry_ptr; \ 137 } while (0) 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 */ 158 #define drm_exec_retry(_exec) \ 159 do { \ 160 WARN_ON((_exec)->contended != DRM_EXEC_DUMMY); \ 161 goto *__drm_exec_retry_ptr; \ 162 } while (0) 163 164 /** 165 * drm_exec_ticket - return the ww_acquire_ctx for this exec context 166 * @exec: drm_exec object 167 * 168 * Return: Pointer to the ww_acquire_ctx embedded in @exec. 169 */ 170 static inline struct ww_acquire_ctx *drm_exec_ticket(struct drm_exec *exec) 171 { 172 return &exec->ticket; 173 } 174 175 void drm_exec_init(struct drm_exec *exec, u32 flags, unsigned nr); 176 void drm_exec_fini(struct drm_exec *exec); 177 bool drm_exec_cleanup(struct drm_exec *exec); 178 int drm_exec_lock_obj(struct drm_exec *exec, struct drm_gem_object *obj); 179 void drm_exec_unlock_obj(struct drm_exec *exec, struct drm_gem_object *obj); 180 int drm_exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj, 181 unsigned int num_fences); 182 int drm_exec_prepare_array(struct drm_exec *exec, 183 struct drm_gem_object **objects, 184 unsigned int num_objects, 185 unsigned int num_fences); 186 187 #endif 188