1 // SPDX-License-Identifier: GPL-2.0 OR MIT
2
3 #include <drm/drm_exec.h>
4 #include <drm/drm_gem.h>
5
6 #include <linux/dma-resv.h>
7 #include <linux/export.h>
8
9 /**
10 * DOC: Overview
11 *
12 * This component mainly abstracts the retry loop necessary for locking
13 * multiple GEM objects while preparing hardware operations (e.g. command
14 * submissions, page table updates etc..).
15 *
16 * If a contention is detected while locking a GEM object the cleanup procedure
17 * unlocks all previously locked GEM objects and locks the contended one first
18 * before locking any further objects.
19 *
20 * After an object is locked fences slots can optionally be reserved on the
21 * dma_resv object inside the GEM object.
22 *
23 * A typical usage pattern should look like this::
24 *
25 * struct drm_gem_object *obj;
26 * struct drm_exec exec;
27 * int ret;
28 *
29 * drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT);
30 * drm_exec_until_all_locked(&exec) {
31 * ret = drm_exec_prepare_obj(&exec, boA, 1);
32 * drm_exec_retry_on_contention(&exec);
33 * if (ret)
34 * goto error;
35 *
36 * ret = drm_exec_prepare_obj(&exec, boB, 1);
37 * drm_exec_retry_on_contention(&exec);
38 * if (ret)
39 * goto error;
40 * }
41 *
42 * drm_exec_for_each_locked_object(&exec, obj) {
43 * dma_resv_add_fence(obj->resv, fence, DMA_RESV_USAGE_READ);
44 * ...
45 * }
46 * drm_exec_fini(&exec);
47 *
48 * See struct dma_exec for more details.
49 */
50
51 /* Unlock all objects and drop references */
drm_exec_unlock_all(struct drm_exec * exec)52 static void drm_exec_unlock_all(struct drm_exec *exec)
53 {
54 struct drm_gem_object *obj;
55
56 drm_exec_for_each_locked_object_reverse(exec, obj) {
57 dma_resv_unlock(obj->resv);
58 drm_gem_object_put(obj);
59 }
60
61 drm_gem_object_put(exec->prelocked);
62 exec->prelocked = NULL;
63 }
64
65 /**
66 * drm_exec_init - initialize a drm_exec object
67 * @exec: the drm_exec object to initialize
68 * @flags: controls locking behavior, see DRM_EXEC_* defines
69 * @nr: the initial # of objects
70 *
71 * Initialize the object and make sure that we can track locked objects.
72 *
73 * If nr is non-zero then it is used as the initial objects table size.
74 * In either case, the table will grow (be re-allocated) on demand.
75 */
drm_exec_init(struct drm_exec * exec,u32 flags,unsigned nr)76 void drm_exec_init(struct drm_exec *exec, u32 flags, unsigned nr)
77 {
78 if (!nr)
79 nr = PAGE_SIZE / sizeof(void *);
80
81 exec->flags = flags;
82 exec->objects = kvmalloc_objs(*exec->objects, nr);
83
84 /* If allocation here fails, just delay that till the first use */
85 exec->max_objects = exec->objects ? nr : 0;
86 exec->num_objects = 0;
87 exec->contended = DRM_EXEC_DUMMY;
88 exec->prelocked = NULL;
89 }
90 EXPORT_SYMBOL(drm_exec_init);
91
92 /**
93 * drm_exec_fini - finalize a drm_exec object
94 * @exec: the drm_exec object to finalize
95 *
96 * Unlock all locked objects, drop the references to objects and free all memory
97 * used for tracking the state.
98 */
drm_exec_fini(struct drm_exec * exec)99 void drm_exec_fini(struct drm_exec *exec)
100 {
101 drm_exec_unlock_all(exec);
102 kvfree(exec->objects);
103 if (exec->contended != DRM_EXEC_DUMMY) {
104 drm_gem_object_put(exec->contended);
105 ww_acquire_fini(&exec->ticket);
106 }
107 }
108 EXPORT_SYMBOL(drm_exec_fini);
109
110 /**
111 * drm_exec_cleanup - cleanup when contention is detected
112 * @exec: the drm_exec object to cleanup
113 *
114 * Cleanup the current state and return true if we should stay inside the retry
115 * loop, false if there wasn't any contention detected and we can keep the
116 * objects locked.
117 */
drm_exec_cleanup(struct drm_exec * exec)118 bool drm_exec_cleanup(struct drm_exec *exec)
119 {
120 if (likely(!exec->contended)) {
121 ww_acquire_done(&exec->ticket);
122 return false;
123 }
124
125 if (likely(exec->contended == DRM_EXEC_DUMMY)) {
126 exec->contended = NULL;
127 ww_acquire_init(&exec->ticket, &reservation_ww_class);
128 return true;
129 }
130
131 drm_exec_unlock_all(exec);
132 exec->num_objects = 0;
133 return true;
134 }
135 EXPORT_SYMBOL(drm_exec_cleanup);
136
137 /* Track the locked object in the array */
drm_exec_obj_locked(struct drm_exec * exec,struct drm_gem_object * obj)138 static int drm_exec_obj_locked(struct drm_exec *exec,
139 struct drm_gem_object *obj)
140 {
141 if (unlikely(exec->num_objects == exec->max_objects)) {
142 size_t size = exec->max_objects * sizeof(void *);
143 void *tmp;
144
145 tmp = kvrealloc(exec->objects, size + PAGE_SIZE, GFP_KERNEL);
146 if (!tmp)
147 return -ENOMEM;
148
149 exec->objects = tmp;
150 exec->max_objects += PAGE_SIZE / sizeof(void *);
151 }
152 drm_gem_object_get(obj);
153 exec->objects[exec->num_objects++] = obj;
154
155 return 0;
156 }
157
158 /* Make sure the contended object is locked first */
drm_exec_lock_contended(struct drm_exec * exec)159 static int drm_exec_lock_contended(struct drm_exec *exec)
160 {
161 struct drm_gem_object *obj = exec->contended;
162 int ret;
163
164 if (likely(!obj))
165 return 0;
166
167 /* Always cleanup the contention so that error handling can kick in */
168 exec->contended = NULL;
169 if (exec->flags & DRM_EXEC_INTERRUPTIBLE_WAIT) {
170 ret = dma_resv_lock_slow_interruptible(obj->resv,
171 &exec->ticket);
172 if (unlikely(ret))
173 goto error_dropref;
174 } else {
175 dma_resv_lock_slow(obj->resv, &exec->ticket);
176 }
177
178 ret = drm_exec_obj_locked(exec, obj);
179 if (unlikely(ret))
180 goto error_unlock;
181
182 exec->prelocked = obj;
183 return 0;
184
185 error_unlock:
186 dma_resv_unlock(obj->resv);
187
188 error_dropref:
189 drm_gem_object_put(obj);
190 return ret;
191 }
192
193 /**
194 * drm_exec_lock_obj - lock a GEM object for use
195 * @exec: the drm_exec object with the state
196 * @obj: the GEM object to lock
197 *
198 * Lock a GEM object for use and grab a reference to it.
199 *
200 * Returns: -EDEADLK if a contention is detected, -EALREADY when object is
201 * already locked (can be suppressed by setting the DRM_EXEC_IGNORE_DUPLICATES
202 * flag), -ENOMEM when memory allocation failed and zero for success.
203 */
drm_exec_lock_obj(struct drm_exec * exec,struct drm_gem_object * obj)204 int drm_exec_lock_obj(struct drm_exec *exec, struct drm_gem_object *obj)
205 {
206 int ret;
207
208 ret = drm_exec_lock_contended(exec);
209 if (unlikely(ret))
210 return ret;
211
212 if (exec->prelocked == obj) {
213 drm_gem_object_put(exec->prelocked);
214 exec->prelocked = NULL;
215 return 0;
216 }
217
218 if (exec->flags & DRM_EXEC_INTERRUPTIBLE_WAIT)
219 ret = dma_resv_lock_interruptible(obj->resv, &exec->ticket);
220 else
221 ret = dma_resv_lock(obj->resv, &exec->ticket);
222
223 if (unlikely(ret == -EDEADLK)) {
224 drm_gem_object_get(obj);
225 exec->contended = obj;
226 return -EDEADLK;
227 }
228
229 if (unlikely(ret == -EALREADY) &&
230 exec->flags & DRM_EXEC_IGNORE_DUPLICATES)
231 return 0;
232
233 if (unlikely(ret))
234 return ret;
235
236 ret = drm_exec_obj_locked(exec, obj);
237 if (ret)
238 goto error_unlock;
239
240 return 0;
241
242 error_unlock:
243 dma_resv_unlock(obj->resv);
244 return ret;
245 }
246 EXPORT_SYMBOL(drm_exec_lock_obj);
247
248 /**
249 * drm_exec_unlock_obj - unlock a GEM object in this exec context
250 * @exec: the drm_exec object with the state
251 * @obj: the GEM object to unlock
252 *
253 * Unlock the GEM object and remove it from the collection of locked objects.
254 * Should only be used to unlock the most recently locked objects. It's not time
255 * efficient to unlock objects locked long ago.
256 */
drm_exec_unlock_obj(struct drm_exec * exec,struct drm_gem_object * obj)257 void drm_exec_unlock_obj(struct drm_exec *exec, struct drm_gem_object *obj)
258 {
259 unsigned int i;
260
261 for (i = exec->num_objects; i--;) {
262 if (exec->objects[i] == obj) {
263 dma_resv_unlock(obj->resv);
264 for (++i; i < exec->num_objects; ++i)
265 exec->objects[i - 1] = exec->objects[i];
266 --exec->num_objects;
267 drm_gem_object_put(obj);
268 return;
269 }
270
271 }
272 }
273 EXPORT_SYMBOL(drm_exec_unlock_obj);
274
275 /**
276 * drm_exec_prepare_obj - prepare a GEM object for use
277 * @exec: the drm_exec object with the state
278 * @obj: the GEM object to prepare
279 * @num_fences: how many fences to reserve
280 *
281 * Prepare a GEM object for use by locking it and reserving fence slots.
282 *
283 * Returns: -EDEADLK if a contention is detected, -EALREADY when object is
284 * already locked, -ENOMEM when memory allocation failed and zero for success.
285 */
drm_exec_prepare_obj(struct drm_exec * exec,struct drm_gem_object * obj,unsigned int num_fences)286 int drm_exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj,
287 unsigned int num_fences)
288 {
289 int ret;
290
291 ret = drm_exec_lock_obj(exec, obj);
292 if (ret)
293 return ret;
294
295 ret = dma_resv_reserve_fences(obj->resv, num_fences);
296 if (ret) {
297 drm_exec_unlock_obj(exec, obj);
298 return ret;
299 }
300
301 return 0;
302 }
303 EXPORT_SYMBOL(drm_exec_prepare_obj);
304
305 /**
306 * drm_exec_prepare_array - helper to prepare an array of objects
307 * @exec: the drm_exec object with the state
308 * @objects: array of GEM object to prepare
309 * @num_objects: number of GEM objects in the array
310 * @num_fences: number of fences to reserve on each GEM object
311 *
312 * Prepares all GEM objects in an array, aborts on first error.
313 * Reserves @num_fences on each GEM object after locking it.
314 *
315 * Returns: -EDEADLOCK on contention, -EALREADY when object is already locked,
316 * -ENOMEM when memory allocation failed and zero for success.
317 */
drm_exec_prepare_array(struct drm_exec * exec,struct drm_gem_object ** objects,unsigned int num_objects,unsigned int num_fences)318 int drm_exec_prepare_array(struct drm_exec *exec,
319 struct drm_gem_object **objects,
320 unsigned int num_objects,
321 unsigned int num_fences)
322 {
323 int ret;
324
325 for (unsigned int i = 0; i < num_objects; ++i) {
326 ret = drm_exec_prepare_obj(exec, objects[i], num_fences);
327 if (unlikely(ret))
328 return ret;
329 }
330
331 return 0;
332 }
333 EXPORT_SYMBOL(drm_exec_prepare_array);
334
335 MODULE_DESCRIPTION("DRM execution context");
336 MODULE_LICENSE("Dual MIT/GPL");
337