kernel_samsung_a34x-permissive/drivers/misc/mediatek/trusted_mem/peer_mgr.c
2024-04-28 15:51:13 +02:00

282 lines
6.8 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#define PR_FMT_HEADER_MUST_BE_INCLUDED_BEFORE_ALL_HDRS
#include "private/tmem_pr_fmt.h" PR_FMT_HEADER_MUST_BE_INCLUDED_BEFORE_ALL_HDRS
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/unistd.h>
#include <linux/types.h>
#include <linux/slab.h>
#include "private/mld_helper.h"
#include "private/tmem_priv.h"
#include "private/tmem_error.h"
#include "private/tmem_utils.h"
#define MGR_SESSION_LOCK() mutex_lock(&sess_data->lock)
#define MGR_SESSION_UNLOCK() mutex_unlock(&sess_data->lock)
static void set_session_ready(struct trusted_peer_session *sess_data,
bool ready)
{
sess_data->opened = ready;
}
static bool is_session_ready(struct trusted_peer_session *sess_data)
{
bool ret;
MGR_SESSION_LOCK();
ret = sess_data->opened;
MGR_SESSION_UNLOCK();
return ret;
}
static int peer_mgr_chunk_alloc_locked(
u32 alignment, u32 size, u32 *refcount, u32 *sec_handle, u8 *owner,
u32 id, u32 clean, struct trusted_driver_operations *drv_ops,
struct trusted_peer_session *sess_data, void *dev_desc)
{
int ret;
if (!is_session_ready(sess_data)) {
pr_err("%s:%d peer session is still not ready!\n", __func__,
__LINE__);
return TMEM_MGR_SESSION_IS_NOT_READY;
}
MGR_SESSION_LOCK();
ret = drv_ops->memory_alloc(alignment, size, refcount, sec_handle,
owner, id, clean, sess_data->peer_data,
dev_desc);
if (ret != 0) {
pr_err("peer alloc size: 0x%x failed:%d\n", size, ret);
MGR_SESSION_UNLOCK();
if (ret == -ENOMEM)
return ret;
return TMEM_MGR_ALLOC_MEM_FAILED;
}
*refcount = 1;
sess_data->ref_chunks++;
MGR_SESSION_UNLOCK();
return TMEM_OK;
}
static int peer_mgr_chunk_free_locked(u32 sec_handle, uint8_t *owner, u32 id,
struct trusted_driver_operations *drv_ops,
struct trusted_peer_session *sess_data,
void *dev_desc)
{
int ret;
if (!is_session_ready(sess_data)) {
pr_err("%s:%d peer session is still not ready!\n", __func__,
__LINE__);
return TMEM_MGR_SESSION_IS_NOT_READY;
}
MGR_SESSION_LOCK();
ret = drv_ops->memory_free(sec_handle, owner, id, sess_data->peer_data,
dev_desc);
if (ret != 0) {
pr_err("peer free chunk memory failed:%d\n", ret);
MGR_SESSION_UNLOCK();
return TMEM_MGR_FREE_MEM_FAILED;
}
if (IS_ZERO(sess_data->ref_chunks))
pr_err("system error, please check! (ref_chunks:0)\n");
else
sess_data->ref_chunks--;
MGR_SESSION_UNLOCK();
return TMEM_OK;
}
static int peer_mgr_mem_add_locked(u64 pa, u32 size,
struct trusted_driver_operations *drv_ops,
struct trusted_peer_session *sess_data,
void *dev_desc)
{
int ret;
if (!is_session_ready(sess_data)) {
pr_err("%s:%d peer session is still not ready!\n", __func__,
__LINE__);
return TMEM_MGR_SESSION_IS_NOT_READY;
}
MGR_SESSION_LOCK();
ret = drv_ops->memory_grant(pa, size, sess_data->peer_data, dev_desc);
if (ret != 0) {
pr_err("peer append reg mem failed:%d\n", ret);
MGR_SESSION_UNLOCK();
return TMEM_MGR_MEM_ADD_FAILED;
}
sess_data->mem_pa_start = pa;
sess_data->mem_size = size;
sess_data->mem_size_runtime = size;
MGR_SESSION_UNLOCK();
return TMEM_OK;
}
static int peer_mgr_mem_remove_locked(struct trusted_driver_operations *drv_ops,
struct trusted_peer_session *sess_data,
void *dev_desc)
{
int ret;
if (!is_session_ready(sess_data)) {
pr_err("%s:%d peer session is still not ready!\n", __func__,
__LINE__);
return TMEM_MGR_SESSION_IS_NOT_READY;
}
MGR_SESSION_LOCK();
ret = drv_ops->memory_reclaim(sess_data->peer_data, dev_desc);
if (ret != 0) {
pr_err("peer release reg mem failed:%d\n", ret);
MGR_SESSION_UNLOCK();
return TMEM_MGR_MEM_REMOVE_FAILED;
}
sess_data->mem_pa_start = 0x0ULL;
sess_data->mem_size = 0x0;
MGR_SESSION_UNLOCK();
return TMEM_OK;
}
static int
peer_mgr_session_open_locked(struct trusted_driver_operations *drv_ops,
struct trusted_peer_session *sess_data,
void *dev_desc)
{
int ret;
if (is_session_ready(sess_data)) {
pr_err("peer session is already opened!\n");
return TMEM_MGR_SESSION_IS_ALREADY_OPEN;
}
MGR_SESSION_LOCK();
ret = drv_ops->session_open(&sess_data->peer_data, dev_desc);
if (ret != 0) {
pr_err("peer open session failed:%d\n", ret);
MGR_SESSION_UNLOCK();
return TMEM_MGR_OPEN_SESSION_FAILED;
}
pr_debug("peer data is created:%p\n", sess_data->peer_data);
set_session_ready(sess_data, true);
MGR_SESSION_UNLOCK();
return TMEM_OK;
}
static int peer_mgr_session_close_locked(
bool keep_alive, struct trusted_driver_operations *drv_ops,
struct trusted_peer_session *sess_data, void *dev_desc)
{
int ret;
if (!is_session_ready(sess_data)) {
pr_err("peer session is already closed!\n");
return TMEM_MGR_SESSION_IS_ALREADY_CLOSE;
}
if (keep_alive) {
pr_debug("peer session won't close!\n");
return TMEM_OK;
}
MGR_SESSION_LOCK();
ret = drv_ops->session_close(sess_data->peer_data, dev_desc);
if (ret != 0) {
pr_err("peer close session failed:%d\n", ret);
MGR_SESSION_UNLOCK();
return TMEM_MGR_CLOSE_SESSION_FAILED;
}
set_session_ready(sess_data, false);
MGR_SESSION_UNLOCK();
return TMEM_OK;
}
static int peer_mgr_session_invoke_cmd_locked(
struct trusted_driver_cmd_params *invoke_params,
struct trusted_driver_operations *drv_ops,
struct trusted_peer_session *sess_data, void *dev_desc)
{
int ret;
if (!is_session_ready(sess_data)) {
pr_err("%s:%d peer session is still not ready!\n", __func__,
__LINE__);
return TMEM_MGR_SESSION_IS_NOT_READY;
}
MGR_SESSION_LOCK();
ret = drv_ops->invoke_cmd(invoke_params, sess_data->peer_data,
dev_desc);
if (ret != 0) {
pr_err("peer invoke command failed:%d\n", ret);
MGR_SESSION_UNLOCK();
return TMEM_MGR_INVOKE_COMMAND_FAILED;
}
MGR_SESSION_UNLOCK();
return TMEM_OK;
}
struct peer_mgr_desc *create_peer_mgr_desc(void)
{
struct peer_mgr_desc *t_mgr_desc;
t_mgr_desc = mld_kmalloc(sizeof(struct peer_mgr_desc), GFP_KERNEL);
if (INVALID(t_mgr_desc)) {
pr_err("%s:%d out of memory!\n", __func__, __LINE__);
return NULL;
}
memset(t_mgr_desc, 0x0, sizeof(struct peer_mgr_desc));
mutex_init(&t_mgr_desc->peer_mgr_data.lock);
t_mgr_desc->mgr_sess_open = peer_mgr_session_open_locked;
t_mgr_desc->mgr_sess_close = peer_mgr_session_close_locked;
t_mgr_desc->mgr_sess_mem_alloc = peer_mgr_chunk_alloc_locked;
t_mgr_desc->mgr_sess_mem_free = peer_mgr_chunk_free_locked;
t_mgr_desc->mgr_sess_mem_add = peer_mgr_mem_add_locked;
t_mgr_desc->mgr_sess_mem_remove = peer_mgr_mem_remove_locked;
t_mgr_desc->mgr_sess_invoke_cmd = peer_mgr_session_invoke_cmd_locked;
return t_mgr_desc;
}