| /* SPDX-License-Identifier: GPL-2.0 OR MIT */ | |
| #ifndef __DRM_EXEC_H__ | |
| #define __DRM_EXEC_H__ | |
| #include <linux/compiler.h> | |
| #include <linux/ww_mutex.h> | |
| #define DRM_EXEC_INTERRUPTIBLE_WAIT BIT(0) | |
| #define DRM_EXEC_IGNORE_DUPLICATES BIT(1) | |
| /* | |
| * Dummy value used to initially enter the retry loop. | |
| * internal use only. | |
| */ | |
| #define DRM_EXEC_DUMMY ((void *)~0) | |
| struct drm_gem_object; | |
| /** | |
| * struct drm_exec - Execution context | |
| */ | |
| struct drm_exec { | |
| /** | |
| * @flags: Flags to control locking behavior | |
| */ | |
| u32 flags; | |
| /** | |
| * @ticket: WW ticket used for acquiring locks | |
| */ | |
| struct ww_acquire_ctx ticket; | |
| /** | |
| * @num_objects: number of objects locked | |
| */ | |
| unsigned int num_objects; | |
| /** | |
| * @max_objects: maximum objects in array | |
| */ | |
| unsigned int max_objects; | |
| /** | |
| * @objects: array of the locked objects | |
| */ | |
| struct drm_gem_object **objects; | |
| /** | |
| * @contended: contended GEM object we backed off for | |
| */ | |
| struct drm_gem_object *contended; | |
| /** | |
| * @prelocked: already locked GEM object due to contention | |
| */ | |
| struct drm_gem_object *prelocked; | |
| }; | |
| /** | |
| * drm_exec_obj() - Return the object for a give drm_exec index | |
| * @exec: Pointer to the drm_exec context | |
| * @index: The index. | |
| * | |
| * Return: Pointer to the locked object corresponding to @index if | |
| * index is within the number of locked objects. NULL otherwise. | |
| */ | |
| static inline struct drm_gem_object * | |
| drm_exec_obj(struct drm_exec *exec, unsigned long index) | |
| { | |
| return index < exec->num_objects ? exec->objects[index] : NULL; | |
| } | |
| /* Helper for drm_exec_for_each_locked_object(). Internal use only. */ | |
| #define __drm_exec_for_each_locked_object(exec, obj, __index) \ | |
| for (unsigned long __index = 0; ((obj) = drm_exec_obj(exec, __index)); ++__index) | |
| /** | |
| * drm_exec_for_each_locked_object - iterate over all the locked objects | |
| * @exec: drm_exec object | |
| * @obj: the current GEM object | |
| * | |
| * Iterate over all the locked GEM objects inside the drm_exec object. | |
| */ | |
| #define drm_exec_for_each_locked_object(exec, obj) \ | |
| __drm_exec_for_each_locked_object(exec, obj, __UNIQUE_ID(drm_exec)) | |
| /* Helper for drm_exec_for_each_locked_object_reverse(). Internal use only. */ | |
| #define __drm_exec_for_each_locked_object_reverse(exec, obj, __index) \ | |
| for (unsigned long __index = (exec)->num_objects - 1; \ | |
| ((obj) = drm_exec_obj(exec, __index)); --__index) | |
| /** | |
| * drm_exec_for_each_locked_object_reverse - iterate over all the locked | |
| * objects in reverse locking order | |
| * @exec: drm_exec object | |
| * @obj: the current GEM object | |
| * | |
| * Iterate over all the locked GEM objects inside the drm_exec object in | |
| * reverse locking order. Note that the internal index may wrap around, | |
| * but that will be caught by drm_exec_obj(), returning a NULL object. | |
| */ | |
| #define drm_exec_for_each_locked_object_reverse(exec, obj) \ | |
| __drm_exec_for_each_locked_object_reverse(exec, obj, __UNIQUE_ID(drm_exec)) | |
| /** | |
| * drm_exec_until_all_locked - loop until all GEM objects are locked | |
| * @exec: drm_exec object | |
| * | |
| * Core functionality of the drm_exec object. Loops until all GEM objects are | |
| * locked and no more contention exists. At the beginning of the loop it is | |
| * guaranteed that no GEM object is locked. | |
| * | |
| * A global label name drm_exec_retry is used, if you need to use more than one | |
| * instance of this macro in the same function the label needs to be made local | |
| * to the block with the __label__ keyword. | |
| */ | |
| #define drm_exec_until_all_locked(exec) \ | |
| for (bool const __maybe_unused __drm_exec_loop = false; \ | |
| drm_exec_cleanup(exec);) \ | |
| if (false) { \ | |
| drm_exec_retry: __maybe_unused; \ | |
| continue; \ | |
| } else | |
| /** | |
| * drm_exec_retry_on_contention - restart the loop to grap all locks | |
| * @exec: drm_exec object | |
| * | |
| * Control flow helper to continue when a contention was detected and we need to | |
| * clean up and re-start the loop to prepare all GEM objects. | |
| * The __drm_exec_loop check exists to prevent usage outside of an | |
| * drm_exec_until_all_locked() loop. | |
| */ | |
| #define drm_exec_retry_on_contention(exec) \ | |
| do { \ | |
| if (unlikely(drm_exec_is_contended(exec))) \ | |
| goto drm_exec_retry; \ | |
| } while (__drm_exec_loop) | |
| /** | |
| * drm_exec_is_contended - check for contention | |
| * @exec: drm_exec object | |
| * | |
| * Returns true if the drm_exec object has run into some contention while | |
| * locking a GEM object and needs to clean up. | |
| */ | |
| static inline bool drm_exec_is_contended(struct drm_exec *exec) | |
| { | |
| return !!exec->contended; | |
| } | |
| /** | |
| * drm_exec_retry() - Unconditionally restart the loop to grab all locks. | |
| * @exec: drm_exec object | |
| * | |
| * Unconditionally retry the loop to lock all objects. For consistency, | |
| * the exec object needs to be newly initialized. | |
| * The __drm_exec_loop check exists to prevent usage outside of an | |
| * drm_exec_until_all_locked() loop. | |
| */ | |
| #define drm_exec_retry(_exec) \ | |
| do { \ | |
| WARN_ON((_exec)->contended != DRM_EXEC_DUMMY); \ | |
| goto drm_exec_retry; \ | |
| } while (__drm_exec_loop) | |
| /** | |
| * drm_exec_ticket - return the ww_acquire_ctx for this exec context | |
| * @exec: drm_exec object | |
| * | |
| * Return: Pointer to the ww_acquire_ctx embedded in @exec. | |
| */ | |
| static inline struct ww_acquire_ctx *drm_exec_ticket(struct drm_exec *exec) | |
| { | |
| return &exec->ticket; | |
| } | |
| void drm_exec_init(struct drm_exec *exec, u32 flags, unsigned nr); | |
| void drm_exec_fini(struct drm_exec *exec); | |
| bool drm_exec_cleanup(struct drm_exec *exec); | |
| int drm_exec_lock_obj(struct drm_exec *exec, struct drm_gem_object *obj); | |
| void drm_exec_unlock_obj(struct drm_exec *exec, struct drm_gem_object *obj); | |
| int drm_exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj, | |
| unsigned int num_fences); | |
| int drm_exec_prepare_array(struct drm_exec *exec, | |
| struct drm_gem_object **objects, | |
| unsigned int num_objects, | |
| unsigned int num_fences); | |
| #endif |