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