| 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 | struct drm_gem_object; |
| 13 | |
| 14 | /** |
| 15 | * struct drm_exec - Execution context |
| 16 | */ |
| 17 | struct drm_exec { |
| 18 | /** |
| 19 | * @flags: Flags to control locking behavior |
| 20 | */ |
| 21 | u32 flags; |
| 22 | |
| 23 | /** |
| 24 | * @ticket: WW ticket used for acquiring locks |
| 25 | */ |
| 26 | struct ww_acquire_ctx ticket; |
| 27 | |
| 28 | /** |
| 29 | * @num_objects: number of objects locked |
| 30 | */ |
| 31 | unsigned int num_objects; |
| 32 | |
| 33 | /** |
| 34 | * @max_objects: maximum objects in array |
| 35 | */ |
| 36 | unsigned int max_objects; |
| 37 | |
| 38 | /** |
| 39 | * @objects: array of the locked objects |
| 40 | */ |
| 41 | struct drm_gem_object **objects; |
| 42 | |
| 43 | /** |
| 44 | * @contended: contended GEM object we backed off for |
| 45 | */ |
| 46 | struct drm_gem_object *contended; |
| 47 | |
| 48 | /** |
| 49 | * @prelocked: already locked GEM object due to contention |
| 50 | */ |
| 51 | struct drm_gem_object *prelocked; |
| 52 | }; |
| 53 | |
| 54 | /** |
| 55 | * drm_exec_obj() - Return the object for a give drm_exec index |
| 56 | * @exec: Pointer to the drm_exec context |
| 57 | * @index: The index. |
| 58 | * |
| 59 | * Return: Pointer to the locked object corresponding to @index if |
| 60 | * index is within the number of locked objects. NULL otherwise. |
| 61 | */ |
| 62 | static inline struct drm_gem_object * |
| 63 | drm_exec_obj(struct drm_exec *exec, unsigned long index) |
| 64 | { |
| 65 | return index < exec->num_objects ? exec->objects[index] : NULL; |
| 66 | } |
| 67 | |
| 68 | /** |
| 69 | * drm_exec_for_each_locked_object - iterate over all the locked objects |
| 70 | * @exec: drm_exec object |
| 71 | * @index: unsigned long index for the iteration |
| 72 | * @obj: the current GEM object |
| 73 | * |
| 74 | * Iterate over all the locked GEM objects inside the drm_exec object. |
| 75 | */ |
| 76 | #define drm_exec_for_each_locked_object(exec, index, obj) \ |
| 77 | for ((index) = 0; ((obj) = drm_exec_obj(exec, index)); ++(index)) |
| 78 | |
| 79 | /** |
| 80 | * drm_exec_for_each_locked_object_reverse - iterate over all the locked |
| 81 | * objects in reverse locking order |
| 82 | * @exec: drm_exec object |
| 83 | * @index: unsigned long index for the iteration |
| 84 | * @obj: the current GEM object |
| 85 | * |
| 86 | * Iterate over all the locked GEM objects inside the drm_exec object in |
| 87 | * reverse locking order. Note that @index may go below zero and wrap, |
| 88 | * but that will be caught by drm_exec_obj(), returning a NULL object. |
| 89 | */ |
| 90 | #define drm_exec_for_each_locked_object_reverse(exec, index, obj) \ |
| 91 | for ((index) = (exec)->num_objects - 1; \ |
| 92 | ((obj) = drm_exec_obj(exec, index)); --(index)) |
| 93 | |
| 94 | /** |
| 95 | * drm_exec_until_all_locked - loop until all GEM objects are locked |
| 96 | * @exec: drm_exec object |
| 97 | * |
| 98 | * Core functionality of the drm_exec object. Loops until all GEM objects are |
| 99 | * locked and no more contention exists. At the beginning of the loop it is |
| 100 | * guaranteed that no GEM object is locked. |
| 101 | * |
| 102 | * Since labels can't be defined local to the loops body we use a jump pointer |
| 103 | * to make sure that the retry is only used from within the loops body. |
| 104 | */ |
| 105 | #define drm_exec_until_all_locked(exec) \ |
| 106 | __PASTE(__drm_exec_, __LINE__): \ |
| 107 | for (void *__drm_exec_retry_ptr; ({ \ |
| 108 | __drm_exec_retry_ptr = &&__PASTE(__drm_exec_, __LINE__);\ |
| 109 | (void)__drm_exec_retry_ptr; \ |
| 110 | drm_exec_cleanup(exec); \ |
| 111 | });) |
| 112 | |
| 113 | /** |
| 114 | * drm_exec_retry_on_contention - restart the loop to grap all locks |
| 115 | * @exec: drm_exec object |
| 116 | * |
| 117 | * Control flow helper to continue when a contention was detected and we need to |
| 118 | * clean up and re-start the loop to prepare all GEM objects. |
| 119 | */ |
| 120 | #define drm_exec_retry_on_contention(exec) \ |
| 121 | do { \ |
| 122 | if (unlikely(drm_exec_is_contended(exec))) \ |
| 123 | goto *__drm_exec_retry_ptr; \ |
| 124 | } while (0) |
| 125 | |
| 126 | /** |
| 127 | * drm_exec_is_contended - check for contention |
| 128 | * @exec: drm_exec object |
| 129 | * |
| 130 | * Returns true if the drm_exec object has run into some contention while |
| 131 | * locking a GEM object and needs to clean up. |
| 132 | */ |
| 133 | static inline bool drm_exec_is_contended(struct drm_exec *exec) |
| 134 | { |
| 135 | return !!exec->contended; |
| 136 | } |
| 137 | |
| 138 | void drm_exec_init(struct drm_exec *exec, u32 flags, unsigned nr); |
| 139 | void drm_exec_fini(struct drm_exec *exec); |
| 140 | bool drm_exec_cleanup(struct drm_exec *exec); |
| 141 | int drm_exec_lock_obj(struct drm_exec *exec, struct drm_gem_object *obj); |
| 142 | void drm_exec_unlock_obj(struct drm_exec *exec, struct drm_gem_object *obj); |
| 143 | int drm_exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj, |
| 144 | unsigned int num_fences); |
| 145 | int drm_exec_prepare_array(struct drm_exec *exec, |
| 146 | struct drm_gem_object **objects, |
| 147 | unsigned int num_objects, |
| 148 | unsigned int num_fences); |
| 149 | |
| 150 | #endif |
| 151 | |