344 lines
7.3 KiB
C
Executable File
344 lines
7.3 KiB
C
Executable File
/*
|
|
* 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 "vipx-log.h"
|
|
#include "vipx-util.h"
|
|
#include "vipx-ioctl.h"
|
|
#include "vipx-device.h"
|
|
#include "vipx-graph.h"
|
|
#include "vipx-context.h"
|
|
#include "vipx-core.h"
|
|
|
|
static int vipx_core_load_kernel_binary(struct vipx_context *vctx,
|
|
struct vipx_ioc_load_kernel_binary *args)
|
|
{
|
|
int ret;
|
|
|
|
vipx_enter();
|
|
if (mutex_lock_interruptible(&vctx->lock)) {
|
|
ret = -ERESTARTSYS;
|
|
vipx_err("Failed to lock for loading kernel binary (%d)\n",
|
|
ret);
|
|
goto p_err_lock;
|
|
}
|
|
|
|
ret = vctx->vops->load_kernel_binary(vctx, args);
|
|
if (ret)
|
|
goto p_err_vops;
|
|
|
|
mutex_unlock(&vctx->lock);
|
|
args->ret = 0;
|
|
vipx_leave();
|
|
return 0;
|
|
p_err_vops:
|
|
mutex_unlock(&vctx->lock);
|
|
p_err_lock:
|
|
args->ret = ret;
|
|
vipx_err("Failed to load kernel binary(%d)\n", ret);
|
|
/* return value is included in args->ret */
|
|
return 0;
|
|
}
|
|
|
|
static int vipx_core_unload_kernel_binary(struct vipx_context *vctx,
|
|
struct vipx_ioc_unload_kernel_binary *args)
|
|
{
|
|
int ret;
|
|
|
|
vipx_enter();
|
|
if (mutex_lock_interruptible(&vctx->lock)) {
|
|
ret = -ERESTARTSYS;
|
|
vipx_err("Failed to lock for loading kernel binary (%d)\n",
|
|
ret);
|
|
goto p_err_lock;
|
|
}
|
|
|
|
ret = vctx->vops->unload_kernel_binary(vctx, args);
|
|
if (ret)
|
|
goto p_err_vops;
|
|
|
|
mutex_unlock(&vctx->lock);
|
|
args->ret = 0;
|
|
vipx_leave();
|
|
return 0;
|
|
p_err_vops:
|
|
mutex_unlock(&vctx->lock);
|
|
p_err_lock:
|
|
args->ret = ret;
|
|
vipx_err("Failed to unload kernel binary(%d)\n", ret);
|
|
/* return value is included in args->ret */
|
|
return 0;
|
|
}
|
|
|
|
static int vipx_core_load_graph_info(struct vipx_context *vctx,
|
|
struct vipx_ioc_load_graph_info *args)
|
|
{
|
|
int ret;
|
|
|
|
vipx_enter();
|
|
if (mutex_lock_interruptible(&vctx->lock)) {
|
|
ret = -ERESTARTSYS;
|
|
vipx_err("Failed to lock for loadding graph info (%d)\n", ret);
|
|
goto p_err_lock;
|
|
}
|
|
|
|
ret = vctx->vops->load_graph_info(vctx, args);
|
|
if (ret)
|
|
goto p_err_vops;
|
|
|
|
mutex_unlock(&vctx->lock);
|
|
args->ret = 0;
|
|
vipx_leave();
|
|
return 0;
|
|
p_err_vops:
|
|
mutex_unlock(&vctx->lock);
|
|
p_err_lock:
|
|
args->ret = ret;
|
|
vipx_err("Failed to load graph(%d)\n", ret);
|
|
/* return value is included in args->ret */
|
|
return 0;
|
|
}
|
|
|
|
static int vipx_core_unload_graph_info(struct vipx_context *vctx,
|
|
struct vipx_ioc_unload_graph_info *args)
|
|
{
|
|
int ret;
|
|
|
|
vipx_enter();
|
|
if (mutex_lock_interruptible(&vctx->lock)) {
|
|
ret = -ERESTARTSYS;
|
|
vipx_err("Failed to lock for unloading graph info (%d)\n", ret);
|
|
goto p_err_lock;
|
|
}
|
|
|
|
ret = vctx->vops->unload_graph_info(vctx, args);
|
|
if (ret)
|
|
goto p_err_vops;
|
|
|
|
mutex_unlock(&vctx->lock);
|
|
args->ret = 0;
|
|
vipx_leave();
|
|
return 0;
|
|
p_err_vops:
|
|
mutex_unlock(&vctx->lock);
|
|
p_err_lock:
|
|
args->ret = ret;
|
|
vipx_err("Failed to unload graph(%d)\n", ret);
|
|
/* return value is included in args->ret */
|
|
return 0;
|
|
}
|
|
|
|
static int vipx_core_execute_submodel(struct vipx_context *vctx,
|
|
struct vipx_ioc_execute_submodel *args)
|
|
{
|
|
int ret;
|
|
|
|
vipx_enter();
|
|
if (mutex_lock_interruptible(&vctx->lock)) {
|
|
ret = -ERESTARTSYS;
|
|
vipx_err("Failed to lock for executing submodel (%d)\n", ret);
|
|
goto p_err_lock;
|
|
}
|
|
|
|
ret = vctx->vops->execute_submodel(vctx, args);
|
|
if (ret)
|
|
goto p_err_vops;
|
|
|
|
mutex_unlock(&vctx->lock);
|
|
args->ret = 0;
|
|
vipx_leave();
|
|
return 0;
|
|
p_err_vops:
|
|
mutex_unlock(&vctx->lock);
|
|
p_err_lock:
|
|
args->ret = ret;
|
|
vipx_err("Failed to execute submodel(%d)\n", ret);
|
|
/* return value is included in args->ret */
|
|
return 0;
|
|
}
|
|
|
|
const struct vipx_ioctl_ops vipx_core_ioctl_ops = {
|
|
.load_kernel_binary = vipx_core_load_kernel_binary,
|
|
.unload_kernel_binary = vipx_core_unload_kernel_binary,
|
|
.load_graph_info = vipx_core_load_graph_info,
|
|
.unload_graph_info = vipx_core_unload_graph_info,
|
|
.execute_submodel = vipx_core_execute_submodel,
|
|
};
|
|
|
|
static int vipx_open(struct inode *inode, struct file *file)
|
|
{
|
|
int ret;
|
|
struct miscdevice *miscdev;
|
|
struct vipx_device *vdev;
|
|
struct vipx_core *core;
|
|
struct vipx_context *vctx;
|
|
struct vipx_graph *graph;
|
|
|
|
vipx_enter();
|
|
miscdev = file->private_data;
|
|
vdev = dev_get_drvdata(miscdev->parent);
|
|
core = &vdev->core;
|
|
|
|
if (mutex_lock_interruptible(&core->lock)) {
|
|
ret = -ERESTARTSYS;
|
|
vipx_err("Failed to lock device lock for open (%d)\n", ret);
|
|
goto p_err_lock;
|
|
}
|
|
|
|
ret = vipx_device_open(vdev);
|
|
if (ret)
|
|
goto p_err_device_open;
|
|
|
|
ret = vipx_device_start(vdev);
|
|
if (ret)
|
|
goto p_err_device_start;
|
|
|
|
vctx = vipx_context_create(core);
|
|
if (IS_ERR(vctx)) {
|
|
ret = PTR_ERR(vctx);
|
|
goto p_err_vctx;
|
|
}
|
|
|
|
graph = vipx_graph_create(vctx, &core->system->graphmgr);
|
|
if (IS_ERR(graph)) {
|
|
ret = PTR_ERR(graph);
|
|
goto p_err_graph;
|
|
}
|
|
vctx->graph = graph;
|
|
|
|
file->private_data = vctx;
|
|
|
|
mutex_unlock(&core->lock);
|
|
|
|
vipx_info("The vipx has been successfully opened(count:%d)\n",
|
|
vdev->open_count);
|
|
|
|
vipx_leave();
|
|
return 0;
|
|
p_err_graph:
|
|
p_err_vctx:
|
|
vipx_device_stop(vdev);
|
|
p_err_device_start:
|
|
vipx_device_close(vdev);
|
|
p_err_device_open:
|
|
mutex_unlock(&core->lock);
|
|
vipx_err("Failed to open the vipx(count:%d)(%d)\n",
|
|
vdev->open_count, ret);
|
|
p_err_lock:
|
|
return ret;
|
|
}
|
|
|
|
static int vipx_release(struct inode *inode, struct file *file)
|
|
{
|
|
int ret;
|
|
struct vipx_context *vctx;
|
|
struct vipx_core *core;
|
|
|
|
vipx_enter();
|
|
vctx = file->private_data;
|
|
core = vctx->core;
|
|
|
|
if (mutex_lock_interruptible(&core->lock)) {
|
|
ret = -ERESTARTSYS;
|
|
vipx_err("Failed to lock device lock for release (%d)\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
vipx_graph_destroy(vctx->graph);
|
|
vipx_context_destroy(vctx);
|
|
vipx_device_stop(core->device);
|
|
vipx_device_close(core->device);
|
|
|
|
mutex_unlock(&core->lock);
|
|
vipx_info("The vipx has been closed(count:%d)\n",
|
|
core->device->open_count);
|
|
vipx_leave();
|
|
return 0;
|
|
}
|
|
|
|
static unsigned int vipx_poll(struct file *file, struct poll_table_struct *poll)
|
|
{
|
|
int ret;
|
|
struct vipx_context *vctx;
|
|
|
|
vipx_enter();
|
|
vctx = file->private_data;
|
|
if (!(vctx->state & BIT(VIPX_CONTEXT_START))) {
|
|
ret = POLLERR;
|
|
vipx_err("Context state(%x) is not start (%d)\n",
|
|
vctx->state, ret);
|
|
goto p_err;
|
|
}
|
|
|
|
ret = vctx->queue_ops->poll(&vctx->queue_list, file, poll);
|
|
if (ret)
|
|
goto p_err;
|
|
|
|
vipx_leave();
|
|
return 0;
|
|
p_err:
|
|
return ret;
|
|
}
|
|
|
|
const struct file_operations vipx_file_ops = {
|
|
.owner = THIS_MODULE,
|
|
.open = vipx_open,
|
|
.release = vipx_release,
|
|
.poll = vipx_poll,
|
|
.unlocked_ioctl = vipx_ioctl,
|
|
.compat_ioctl = vipx_compat_ioctl
|
|
};
|
|
|
|
/* Top-level data for debugging */
|
|
static struct vipx_miscdev *misc_vdev;
|
|
|
|
int vipx_core_probe(struct vipx_device *vdev)
|
|
{
|
|
int ret;
|
|
struct vipx_core *core;
|
|
|
|
vipx_enter();
|
|
core = &vdev->core;
|
|
core->device = vdev;
|
|
core->system = &vdev->system;
|
|
misc_vdev = &core->misc_vdev;
|
|
|
|
mutex_init(&core->lock);
|
|
core->ioc_ops = &vipx_core_ioctl_ops;
|
|
|
|
vipx_util_bitmap_init(core->vctx_map, VIPX_MAX_CONTEXT);
|
|
INIT_LIST_HEAD(&core->vctx_list);
|
|
core->vctx_count = 0;
|
|
|
|
core->misc_vdev.miscdev.minor = MISC_DYNAMIC_MINOR;
|
|
core->misc_vdev.miscdev.name = VIPX_DEV_NAME;
|
|
core->misc_vdev.miscdev.fops = &vipx_file_ops;
|
|
core->misc_vdev.miscdev.parent = vdev->dev;
|
|
|
|
ret = misc_register(&core->misc_vdev.miscdev);
|
|
if (ret) {
|
|
vipx_err("miscdevice is not registered (%d)\n", ret);
|
|
goto p_err_misc;
|
|
}
|
|
|
|
vipx_leave();
|
|
return 0;
|
|
p_err_misc:
|
|
mutex_destroy(&core->lock);
|
|
return ret;
|
|
}
|
|
|
|
void vipx_core_remove(struct vipx_core *core)
|
|
{
|
|
vipx_enter();
|
|
misc_deregister(&core->misc_vdev.miscdev);
|
|
mutex_destroy(&core->lock);
|
|
vipx_leave();
|
|
}
|