201 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *
 | |
|  * (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved.
 | |
|  *
 | |
|  * This program is free software and is provided to you under the terms of the
 | |
|  * GNU General Public License version 2 as published by the Free Software
 | |
|  * Foundation, and any use by you of this program is subject to the terms
 | |
|  * of such GNU licence.
 | |
|  *
 | |
|  * A copy of the licence is included with the program, and can also be obtained
 | |
|  * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 | |
|  * Boston, MA  02110-1301, USA.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| 
 | |
| 
 | |
| #include <linux/atomic.h>
 | |
| #include <linux/list.h>
 | |
| #include <linux/spinlock.h>
 | |
| #include <mali_kbase_fence_defs.h>
 | |
| #include <mali_kbase_fence.h>
 | |
| #include <mali_kbase.h>
 | |
| 
 | |
| /* Spin lock protecting all Mali fences as fence->lock. */
 | |
| static DEFINE_SPINLOCK(kbase_fence_lock);
 | |
| 
 | |
| static const char *
 | |
| #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
 | |
| kbase_fence_get_driver_name(struct fence *fence)
 | |
| #else
 | |
| kbase_fence_get_driver_name(struct dma_fence *fence)
 | |
| #endif
 | |
| {
 | |
| 	return kbase_drv_name;
 | |
| }
 | |
| 
 | |
| static const char *
 | |
| #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
 | |
| kbase_fence_get_timeline_name(struct fence *fence)
 | |
| #else
 | |
| kbase_fence_get_timeline_name(struct dma_fence *fence)
 | |
| #endif
 | |
| {
 | |
| 	return kbase_timeline_name;
 | |
| }
 | |
| 
 | |
| static bool
 | |
| #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
 | |
| kbase_fence_enable_signaling(struct fence *fence)
 | |
| #else
 | |
| kbase_fence_enable_signaling(struct dma_fence *fence)
 | |
| #endif
 | |
| {
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| static void
 | |
| #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
 | |
| kbase_fence_fence_value_str(struct fence *fence, char *str, int size)
 | |
| #else
 | |
| kbase_fence_fence_value_str(struct dma_fence *fence, char *str, int size)
 | |
| #endif
 | |
| {
 | |
| #if (KERNEL_VERSION(5, 1, 0) > LINUX_VERSION_CODE)
 | |
| 	snprintf(str, size, "%u", fence->seqno);
 | |
| #else
 | |
| 	snprintf(str, size, "%llu", fence->seqno);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
 | |
| const struct fence_ops kbase_fence_ops = {
 | |
| 	.wait = fence_default_wait,
 | |
| #else
 | |
| const struct dma_fence_ops kbase_fence_ops = {
 | |
| 	.wait = dma_fence_default_wait,
 | |
| #endif
 | |
| 	.get_driver_name = kbase_fence_get_driver_name,
 | |
| 	.get_timeline_name = kbase_fence_get_timeline_name,
 | |
| 	.enable_signaling = kbase_fence_enable_signaling,
 | |
| 	.fence_value_str = kbase_fence_fence_value_str
 | |
| };
 | |
| 
 | |
| #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
 | |
| struct fence *
 | |
| kbase_fence_out_new(struct kbase_jd_atom *katom)
 | |
| #else
 | |
| struct dma_fence *
 | |
| kbase_fence_out_new(struct kbase_jd_atom *katom)
 | |
| #endif
 | |
| {
 | |
| #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
 | |
| 	struct fence *fence;
 | |
| #else
 | |
| 	struct dma_fence *fence;
 | |
| #endif
 | |
| 
 | |
| 	WARN_ON(katom->dma_fence.fence);
 | |
| 
 | |
| 	fence = kzalloc(sizeof(*fence), GFP_KERNEL);
 | |
| 	if (!fence)
 | |
| 		return NULL;
 | |
| 
 | |
| 	dma_fence_init(fence,
 | |
| 		       &kbase_fence_ops,
 | |
| 		       &kbase_fence_lock,
 | |
| 		       katom->dma_fence.context,
 | |
| 		       atomic_inc_return(&katom->dma_fence.seqno));
 | |
| 
 | |
| 	katom->dma_fence.fence = fence;
 | |
| 
 | |
| 	return fence;
 | |
| }
 | |
| 
 | |
| bool
 | |
| kbase_fence_free_callbacks(struct kbase_jd_atom *katom)
 | |
| {
 | |
| 	struct kbase_fence_cb *cb, *tmp;
 | |
| 	bool res = false;
 | |
| 
 | |
| 	lockdep_assert_held(&katom->kctx->jctx.lock);
 | |
| 
 | |
| 	/* Clean up and free callbacks. */
 | |
| 	list_for_each_entry_safe(cb, tmp, &katom->dma_fence.callbacks, node) {
 | |
| 		bool ret;
 | |
| 
 | |
| 		/* Cancel callbacks that hasn't been called yet. */
 | |
| 		ret = dma_fence_remove_callback(cb->fence, &cb->fence_cb);
 | |
| 		if (ret) {
 | |
| 			int ret;
 | |
| 
 | |
| 			/* Fence had not signaled, clean up after
 | |
| 			 * canceling.
 | |
| 			 */
 | |
| 			ret = atomic_dec_return(&katom->dma_fence.dep_count);
 | |
| 
 | |
| 			if (unlikely(ret == 0))
 | |
| 				res = true;
 | |
| 		}
 | |
| 
 | |
| 		/*
 | |
| 		 * Release the reference taken in
 | |
| 		 * kbase_fence_add_callback().
 | |
| 		 */
 | |
| 		dma_fence_put(cb->fence);
 | |
| 		list_del(&cb->node);
 | |
| 		kfree(cb);
 | |
| 	}
 | |
| 
 | |
| 	return res;
 | |
| }
 | |
| 
 | |
| #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
 | |
| int
 | |
| kbase_fence_add_callback(struct kbase_jd_atom *katom,
 | |
| 			 struct fence *fence,
 | |
| 			 fence_func_t callback)
 | |
| #else
 | |
| int
 | |
| kbase_fence_add_callback(struct kbase_jd_atom *katom,
 | |
| 			 struct dma_fence *fence,
 | |
| 			 dma_fence_func_t callback)
 | |
| #endif
 | |
| {
 | |
| 	int err = 0;
 | |
| 	struct kbase_fence_cb *kbase_fence_cb;
 | |
| 
 | |
| 	if (!fence)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	kbase_fence_cb = kmalloc(sizeof(*kbase_fence_cb), GFP_KERNEL);
 | |
| 	if (!kbase_fence_cb)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	kbase_fence_cb->fence = fence;
 | |
| 	kbase_fence_cb->katom = katom;
 | |
| 	INIT_LIST_HEAD(&kbase_fence_cb->node);
 | |
| 
 | |
| 	err = dma_fence_add_callback(fence, &kbase_fence_cb->fence_cb,
 | |
| 				     callback);
 | |
| 	if (err == -ENOENT) {
 | |
| 		/* Fence signaled, clear the error and return */
 | |
| 		err = 0;
 | |
| 		kfree(kbase_fence_cb);
 | |
| 	} else if (err) {
 | |
| 		kfree(kbase_fence_cb);
 | |
| 	} else {
 | |
| 		/*
 | |
| 		 * Get reference to fence that will be kept until callback gets
 | |
| 		 * cleaned up in kbase_fence_free_callbacks().
 | |
| 		 */
 | |
| 		dma_fence_get(fence);
 | |
| 		atomic_inc(&katom->dma_fence.dep_count);
 | |
| 		/* Add callback to katom's list of callbacks */
 | |
| 		list_add(&kbase_fence_cb->node, &katom->dma_fence.callbacks);
 | |
| 	}
 | |
| 
 | |
| 	return err;
 | |
| }
 |