/* 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 #include #include #include #include #include #include #include #include #include #include #include #include #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; }