blob: cb4aef712fb336b4a5b1eede49ddd41cf8dfe530 [file] [log] [blame]
/*
* Samsung Exynos SoC series VIPx driver
*
* Copyright (c) 2018 Samsung Electronics Co., Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/slab.h>
#include "vipx-log.h"
#include "vipx-common-type.h"
#include "vipx-kernel-binary.h"
int vipx_kernel_binary_set_gmodel(struct vipx_context *vctx,
struct vipx_graph_model *gmodel)
{
struct vipx_kernel_binary *kbin, *temp, *gbin, *temp2;
unsigned int kid, gid;
int kfd, gfd;
size_t ksize, gsize;
bool is_duplicate;
vipx_enter();
gid = GET_COMMON_GRAPH_MODEL_ID(gmodel->id);
list_for_each_entry_safe(kbin, temp, &vctx->binary_list, clist) {
kid = GET_COMMON_GRAPH_MODEL_ID(kbin->global_id);
if (gid == kid) {
kfd = kbin->buffer.m.fd;
ksize = kbin->buffer.size;
is_duplicate = false;
list_for_each_entry_safe(gbin, temp2,
&gmodel->kbin_list, glist) {
gfd = gbin->buffer.m.fd;
gsize = gbin->buffer.size;
if ((kfd == gfd) && (ksize == gsize)) {
is_duplicate = true;
break;
}
}
if (!is_duplicate) {
//TODO check if list cleanup is needed
list_add_tail(&kbin->glist, &gmodel->kbin_list);
gmodel->kbin_count++;
}
}
}
vipx_leave();
return 0;
}
static int __vipx_kernel_binary_check(struct vipx_context *vctx,
unsigned int id, int fd, unsigned int size)
{
unsigned int model_id, kid;
struct vipx_kernel_binary *kbin, *temp;
model_id = GET_COMMON_GRAPH_MODEL_ID(id);
list_for_each_entry_safe(kbin, temp, &vctx->binary_list, clist) {
kid = GET_COMMON_GRAPH_MODEL_ID(kbin->global_id);
if ((model_id == kid) &&
(fd == kbin->buffer.m.fd) &&
(size == kbin->buffer.size))
return true;
}
return false;
}
int vipx_kernel_binary_add(struct vipx_context *vctx, unsigned int id,
int fd, unsigned int size)
{
int ret;
struct vipx_kernel_binary *kbin;
struct vipx_memory *mem;
unsigned long flags;
vipx_enter();
ret = __vipx_kernel_binary_check(vctx, id, fd, size);
if (ret) {
vipx_leave();
return 0;
}
kbin = kzalloc(sizeof(*kbin), GFP_KERNEL);
if (!kbin) {
ret = -ENOMEM;
vipx_err("Failed to alloc kernel binary\n");
goto p_err;
}
kbin->global_id = id;
kbin->buffer.m.fd = fd;
kbin->buffer.size = size;
mem = &vctx->core->system->memory;
ret = mem->mops->map_dmabuf(mem, &kbin->buffer);
if (ret)
goto p_err_map;
spin_lock_irqsave(&vctx->binary_slock, flags);
vctx->binary_count++;
list_add_tail(&kbin->clist, &vctx->binary_list);
spin_unlock_irqrestore(&vctx->binary_slock, flags);
kbin->vctx = vctx;
vipx_leave();
return 0;
p_err_map:
kfree(kbin);
p_err:
return ret;
}
int vipx_kernel_binary_unload(struct vipx_context *vctx, unsigned int id,
int fd, unsigned int size)
{
unsigned int model_id, kid;
struct vipx_kernel_binary *kbin, *temp;
bool found;
vipx_enter();
found = false;
model_id = GET_COMMON_GRAPH_MODEL_ID(id);
list_for_each_entry_safe(kbin, temp, &vctx->binary_list, clist) {
kid = GET_COMMON_GRAPH_MODEL_ID(kbin->global_id);
if ((model_id == kid) &&
(fd == kbin->buffer.m.fd) &&
(size == kbin->buffer.size)) {
vipx_kernel_binary_remove(kbin);
found = true;
break;
}
}
if (!found) {
vipx_err("There is no kernel binary to unload\n");
vipx_leave();
return -ENOENT;
}
vipx_leave();
return 0;
}
void vipx_kernel_binary_remove(struct vipx_kernel_binary *kbin)
{
struct vipx_context *vctx;
unsigned long flags;
struct vipx_memory *mem;
vipx_enter();
vctx = kbin->vctx;
spin_lock_irqsave(&vctx->binary_slock, flags);
list_del(&kbin->clist);
vctx->binary_count--;
spin_unlock_irqrestore(&vctx->binary_slock, flags);
mem = &vctx->core->system->memory;
mem->mops->unmap_dmabuf(mem, &kbin->buffer);
kfree(kbin);
vipx_leave();
}
void vipx_kernel_binary_all_remove(struct vipx_context *vctx)
{
struct vipx_kernel_binary *kbin, *temp;
vipx_enter();
list_for_each_entry_safe(kbin, temp, &vctx->binary_list, clist) {
vipx_kernel_binary_remove(kbin);
}
vipx_leave();
}