xref: /linux/drivers/gpu/drm/drm_exec.c (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
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 */
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  */
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_array(nr, sizeof(void *), GFP_KERNEL);
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  */
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  */
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 */
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 */
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  */
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  */
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  */
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  */
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