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 | |