xref: /OK3568_Linux_fs/kernel/drivers/gpu/arm/midgard/mali_kbase_dma_fence.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  *
3  * (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved.
4  *
5  * This program is free software and is provided to you under the terms of the
6  * GNU General Public License version 2 as published by the Free Software
7  * Foundation, and any use by you of this program is subject to the terms
8  * of such GNU licence.
9  *
10  * A copy of the licence is included with the program, and can also be obtained
11  * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
12  * Boston, MA  02110-1301, USA.
13  *
14  */
15 
16 
17 
18 
19 /* Include mali_kbase_dma_fence.h before checking for CONFIG_MALI_DMA_FENCE as
20  * it will be set there.
21  */
22 #include "mali_kbase_dma_fence.h"
23 
24 #include <linux/atomic.h>
25 #include <linux/list.h>
26 #include <linux/lockdep.h>
27 #include <linux/mutex.h>
28 #include <linux/reservation.h>
29 #include <linux/slab.h>
30 #include <linux/spinlock.h>
31 #include <linux/workqueue.h>
32 #include <linux/ww_mutex.h>
33 
34 #include <mali_kbase.h>
35 
36 static void
37 kbase_dma_fence_work(struct work_struct *pwork);
38 
39 static void
kbase_dma_fence_waiters_add(struct kbase_jd_atom * katom)40 kbase_dma_fence_waiters_add(struct kbase_jd_atom *katom)
41 {
42 	struct kbase_context *kctx = katom->kctx;
43 
44 	list_add_tail(&katom->queue, &kctx->dma_fence.waiting_resource);
45 }
46 
47 static void
kbase_dma_fence_waiters_remove(struct kbase_jd_atom * katom)48 kbase_dma_fence_waiters_remove(struct kbase_jd_atom *katom)
49 {
50 	list_del(&katom->queue);
51 }
52 
53 static int
kbase_dma_fence_lock_reservations(struct kbase_dma_fence_resv_info * info,struct ww_acquire_ctx * ctx)54 kbase_dma_fence_lock_reservations(struct kbase_dma_fence_resv_info *info,
55 				  struct ww_acquire_ctx *ctx)
56 {
57 	struct reservation_object *content_res = NULL;
58 	unsigned int content_res_idx = 0;
59 	unsigned int r;
60 	int err = 0;
61 
62 	ww_acquire_init(ctx, &reservation_ww_class);
63 
64 retry:
65 	for (r = 0; r < info->dma_fence_resv_count; r++) {
66 		if (info->resv_objs[r] == content_res) {
67 			content_res = NULL;
68 			continue;
69 		}
70 
71 		err = ww_mutex_lock(&info->resv_objs[r]->lock, ctx);
72 		if (err)
73 			goto error;
74 	}
75 
76 	ww_acquire_done(ctx);
77 	return err;
78 
79 error:
80 	content_res_idx = r;
81 
82 	/* Unlock the locked one ones */
83 	while (r--)
84 		ww_mutex_unlock(&info->resv_objs[r]->lock);
85 
86 	if (content_res)
87 		ww_mutex_unlock(&content_res->lock);
88 
89 	/* If we deadlock try with lock_slow and retry */
90 	if (err == -EDEADLK) {
91 		content_res = info->resv_objs[content_res_idx];
92 		ww_mutex_lock_slow(&content_res->lock, ctx);
93 		goto retry;
94 	}
95 
96 	/* If we are here the function failed */
97 	ww_acquire_fini(ctx);
98 	return err;
99 }
100 
101 static void
kbase_dma_fence_unlock_reservations(struct kbase_dma_fence_resv_info * info,struct ww_acquire_ctx * ctx)102 kbase_dma_fence_unlock_reservations(struct kbase_dma_fence_resv_info *info,
103 				    struct ww_acquire_ctx *ctx)
104 {
105 	unsigned int r;
106 
107 	for (r = 0; r < info->dma_fence_resv_count; r++)
108 		ww_mutex_unlock(&info->resv_objs[r]->lock);
109 	ww_acquire_fini(ctx);
110 }
111 
112 /**
113  * kbase_dma_fence_queue_work() - Queue work to handle @katom
114  * @katom: Pointer to atom for which to queue work
115  *
116  * Queue kbase_dma_fence_work() for @katom to clean up the fence callbacks and
117  * submit the atom.
118  */
119 static void
kbase_dma_fence_queue_work(struct kbase_jd_atom * katom)120 kbase_dma_fence_queue_work(struct kbase_jd_atom *katom)
121 {
122 	struct kbase_context *kctx = katom->kctx;
123 	bool ret;
124 
125 	INIT_WORK(&katom->work, kbase_dma_fence_work);
126 	ret = queue_work(kctx->dma_fence.wq, &katom->work);
127 	/* Warn if work was already queued, that should not happen. */
128 	WARN_ON(!ret);
129 }
130 
131 /**
132  * kbase_dma_fence_cancel_atom() - Cancels waiting on an atom
133  * @katom:	Katom to cancel
134  *
135  * Locking: katom->dma_fence.callbacks list assumes jctx.lock is held.
136  */
137 static void
kbase_dma_fence_cancel_atom(struct kbase_jd_atom * katom)138 kbase_dma_fence_cancel_atom(struct kbase_jd_atom *katom)
139 {
140 	lockdep_assert_held(&katom->kctx->jctx.lock);
141 
142 	/* Cancel callbacks and clean up. */
143 	kbase_fence_free_callbacks(katom);
144 
145 	/* Mark the atom as handled in case all fences signaled just before
146 	 * canceling the callbacks and the worker was queued.
147 	 */
148 	kbase_fence_dep_count_set(katom, -1);
149 
150 	/* Prevent job_done_nolock from being called twice on an atom when
151 	 * there is a race between job completion and cancellation.
152 	 */
153 
154 	if (katom->status == KBASE_JD_ATOM_STATE_QUEUED) {
155 		/* Wait was cancelled - zap the atom */
156 		katom->event_code = BASE_JD_EVENT_JOB_CANCELLED;
157 		if (jd_done_nolock(katom, NULL))
158 			kbase_js_sched_all(katom->kctx->kbdev);
159 	}
160 }
161 
162 /**
163  * kbase_dma_fence_work() - Worker thread called when a fence is signaled
164  * @pwork:	work_struct containing a pointer to a katom
165  *
166  * This function will clean and mark all dependencies as satisfied
167  */
168 static void
kbase_dma_fence_work(struct work_struct * pwork)169 kbase_dma_fence_work(struct work_struct *pwork)
170 {
171 	struct kbase_jd_atom *katom;
172 	struct kbase_jd_context *ctx;
173 
174 	katom = container_of(pwork, struct kbase_jd_atom, work);
175 	ctx = &katom->kctx->jctx;
176 
177 	mutex_lock(&ctx->lock);
178 	if (kbase_fence_dep_count_read(katom) != 0)
179 		goto out;
180 
181 	kbase_fence_dep_count_set(katom, -1);
182 
183 	/* Remove atom from list of dma-fence waiting atoms. */
184 	kbase_dma_fence_waiters_remove(katom);
185 	/* Cleanup callbacks. */
186 	kbase_fence_free_callbacks(katom);
187 	/*
188 	 * Queue atom on GPU, unless it has already completed due to a failing
189 	 * dependency. Run jd_done_nolock() on the katom if it is completed.
190 	 */
191 	if (unlikely(katom->status == KBASE_JD_ATOM_STATE_COMPLETED))
192 		jd_done_nolock(katom, NULL);
193 	else
194 		kbase_jd_dep_clear_locked(katom);
195 
196 out:
197 	mutex_unlock(&ctx->lock);
198 }
199 
200 static void
201 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
kbase_dma_fence_cb(struct fence * fence,struct fence_cb * cb)202 kbase_dma_fence_cb(struct fence *fence, struct fence_cb *cb)
203 #else
204 kbase_dma_fence_cb(struct dma_fence *fence, struct dma_fence_cb *cb)
205 #endif
206 {
207 	struct kbase_fence_cb *kcb = container_of(cb,
208 				struct kbase_fence_cb,
209 				fence_cb);
210 	struct kbase_jd_atom *katom = kcb->katom;
211 
212 	/* If the atom is zapped dep_count will be forced to a negative number
213 	 * preventing this callback from ever scheduling work. Which in turn
214 	 * would reschedule the atom.
215 	 */
216 
217 	if (kbase_fence_dep_count_dec_and_test(katom))
218 		kbase_dma_fence_queue_work(katom);
219 }
220 
221 static int
kbase_dma_fence_add_reservation_callback(struct kbase_jd_atom * katom,struct reservation_object * resv,bool exclusive)222 kbase_dma_fence_add_reservation_callback(struct kbase_jd_atom *katom,
223 					 struct reservation_object *resv,
224 					 bool exclusive)
225 {
226 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
227 	struct fence *excl_fence = NULL;
228 	struct fence **shared_fences = NULL;
229 #else
230 	struct dma_fence *excl_fence = NULL;
231 	struct dma_fence **shared_fences = NULL;
232 #endif
233 	unsigned int shared_count = 0;
234 	int err, i;
235 
236 	err = reservation_object_get_fences_rcu(resv,
237 						&excl_fence,
238 						&shared_count,
239 						&shared_fences);
240 	if (err)
241 		return err;
242 
243 	if (excl_fence) {
244 		err = kbase_fence_add_callback(katom,
245 						excl_fence,
246 						kbase_dma_fence_cb);
247 
248 		/* Release our reference, taken by reservation_object_get_fences_rcu(),
249 		 * to the fence. We have set up our callback (if that was possible),
250 		 * and it's the fence's owner is responsible for singling the fence
251 		 * before allowing it to disappear.
252 		 */
253 		dma_fence_put(excl_fence);
254 
255 		if (err)
256 			goto out;
257 	}
258 
259 	if (exclusive) {
260 		for (i = 0; i < shared_count; i++) {
261 			err = kbase_fence_add_callback(katom,
262 							shared_fences[i],
263 							kbase_dma_fence_cb);
264 			if (err)
265 				goto out;
266 		}
267 	}
268 
269 	/* Release all our references to the shared fences, taken by
270 	 * reservation_object_get_fences_rcu(). We have set up our callback (if
271 	 * that was possible), and it's the fence's owner is responsible for
272 	 * signaling the fence before allowing it to disappear.
273 	 */
274 out:
275 	for (i = 0; i < shared_count; i++)
276 		dma_fence_put(shared_fences[i]);
277 	kfree(shared_fences);
278 
279 	if (err) {
280 		/*
281 		 * On error, cancel and clean up all callbacks that was set up
282 		 * before the error.
283 		 */
284 		kbase_fence_free_callbacks(katom);
285 	}
286 
287 	return err;
288 }
289 
kbase_dma_fence_add_reservation(struct reservation_object * resv,struct kbase_dma_fence_resv_info * info,bool exclusive)290 void kbase_dma_fence_add_reservation(struct reservation_object *resv,
291 				     struct kbase_dma_fence_resv_info *info,
292 				     bool exclusive)
293 {
294 	unsigned int i;
295 
296 	for (i = 0; i < info->dma_fence_resv_count; i++) {
297 		/* Duplicate resource, ignore */
298 		if (info->resv_objs[i] == resv)
299 			return;
300 	}
301 
302 	info->resv_objs[info->dma_fence_resv_count] = resv;
303 	if (exclusive)
304 		set_bit(info->dma_fence_resv_count,
305 			info->dma_fence_excl_bitmap);
306 	(info->dma_fence_resv_count)++;
307 }
308 
kbase_dma_fence_wait(struct kbase_jd_atom * katom,struct kbase_dma_fence_resv_info * info)309 int kbase_dma_fence_wait(struct kbase_jd_atom *katom,
310 			 struct kbase_dma_fence_resv_info *info)
311 {
312 	int err, i;
313 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
314 	struct fence *fence;
315 #else
316 	struct dma_fence *fence;
317 #endif
318 	struct ww_acquire_ctx ww_ctx;
319 
320 	lockdep_assert_held(&katom->kctx->jctx.lock);
321 
322 	fence = kbase_fence_out_new(katom);
323 	if (!fence) {
324 		err = -ENOMEM;
325 		dev_err(katom->kctx->kbdev->dev,
326 			"Error %d creating fence.\n", err);
327 		return err;
328 	}
329 
330 	kbase_fence_dep_count_set(katom, 1);
331 
332 	err = kbase_dma_fence_lock_reservations(info, &ww_ctx);
333 	if (err) {
334 		dev_err(katom->kctx->kbdev->dev,
335 			"Error %d locking reservations.\n", err);
336 		kbase_fence_dep_count_set(katom, -1);
337 		kbase_fence_out_remove(katom);
338 		return err;
339 	}
340 
341 	for (i = 0; i < info->dma_fence_resv_count; i++) {
342 		struct reservation_object *obj = info->resv_objs[i];
343 
344 		if (!test_bit(i, info->dma_fence_excl_bitmap)) {
345 			err = reservation_object_reserve_shared(obj);
346 			if (err) {
347 				dev_err(katom->kctx->kbdev->dev,
348 					"Error %d reserving space for shared fence.\n", err);
349 				goto end;
350 			}
351 
352 			err = kbase_dma_fence_add_reservation_callback(katom, obj, false);
353 			if (err) {
354 				dev_err(katom->kctx->kbdev->dev,
355 					"Error %d adding reservation to callback.\n", err);
356 				goto end;
357 			}
358 
359 			reservation_object_add_shared_fence(obj, fence);
360 		} else {
361 			err = kbase_dma_fence_add_reservation_callback(katom, obj, true);
362 			if (err) {
363 				dev_err(katom->kctx->kbdev->dev,
364 					"Error %d adding reservation to callback.\n", err);
365 				goto end;
366 			}
367 
368 			reservation_object_add_excl_fence(obj, fence);
369 		}
370 	}
371 
372 end:
373 	kbase_dma_fence_unlock_reservations(info, &ww_ctx);
374 
375 	if (likely(!err)) {
376 		/* Test if the callbacks are already triggered */
377 		if (kbase_fence_dep_count_dec_and_test(katom)) {
378 			kbase_fence_dep_count_set(katom, -1);
379 			kbase_fence_free_callbacks(katom);
380 		} else {
381 			/* Add katom to the list of dma-buf fence waiting atoms
382 			 * only if it is still waiting.
383 			 */
384 			kbase_dma_fence_waiters_add(katom);
385 		}
386 	} else {
387 		/* There was an error, cancel callbacks, set dep_count to -1 to
388 		 * indicate that the atom has been handled (the caller will
389 		 * kill it for us), signal the fence, free callbacks and the
390 		 * fence.
391 		 */
392 		kbase_fence_free_callbacks(katom);
393 		kbase_fence_dep_count_set(katom, -1);
394 		kbase_dma_fence_signal(katom);
395 	}
396 
397 	return err;
398 }
399 
kbase_dma_fence_cancel_all_atoms(struct kbase_context * kctx)400 void kbase_dma_fence_cancel_all_atoms(struct kbase_context *kctx)
401 {
402 	struct list_head *list = &kctx->dma_fence.waiting_resource;
403 
404 	while (!list_empty(list)) {
405 		struct kbase_jd_atom *katom;
406 
407 		katom = list_first_entry(list, struct kbase_jd_atom, queue);
408 		kbase_dma_fence_waiters_remove(katom);
409 		kbase_dma_fence_cancel_atom(katom);
410 	}
411 }
412 
kbase_dma_fence_cancel_callbacks(struct kbase_jd_atom * katom)413 void kbase_dma_fence_cancel_callbacks(struct kbase_jd_atom *katom)
414 {
415 	/* Cancel callbacks and clean up. */
416 	if (kbase_fence_free_callbacks(katom))
417 		kbase_dma_fence_queue_work(katom);
418 }
419 
kbase_dma_fence_signal(struct kbase_jd_atom * katom)420 void kbase_dma_fence_signal(struct kbase_jd_atom *katom)
421 {
422 	if (!katom->dma_fence.fence)
423 		return;
424 
425 	/* Signal the atom's fence. */
426 	dma_fence_signal(katom->dma_fence.fence);
427 
428 	kbase_fence_out_remove(katom);
429 
430 	kbase_fence_free_callbacks(katom);
431 }
432 
kbase_dma_fence_term(struct kbase_context * kctx)433 void kbase_dma_fence_term(struct kbase_context *kctx)
434 {
435 	destroy_workqueue(kctx->dma_fence.wq);
436 	kctx->dma_fence.wq = NULL;
437 }
438 
kbase_dma_fence_init(struct kbase_context * kctx)439 int kbase_dma_fence_init(struct kbase_context *kctx)
440 {
441 	INIT_LIST_HEAD(&kctx->dma_fence.waiting_resource);
442 
443 	kctx->dma_fence.wq = alloc_workqueue("mali-fence-%d",
444 					     WQ_UNBOUND, 1, kctx->pid);
445 	if (!kctx->dma_fence.wq)
446 		return -ENOMEM;
447 
448 	return 0;
449 }
450