|
@@ -1,7 +1,7 @@
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
|
|
/*
|
|
|
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
|
|
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
|
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
|
*/
|
|
|
|
|
|
#define pr_fmt(fmt) "smcinvoke: %s: " fmt, __func__
|
|
@@ -26,6 +26,7 @@
|
|
|
#include <linux/of_platform.h>
|
|
|
#include <linux/firmware.h>
|
|
|
#include <linux/qcom_scm.h>
|
|
|
+#include <linux/freezer.h>
|
|
|
#include <asm/cacheflush.h>
|
|
|
#include <soc/qcom/qseecomi.h>
|
|
|
#include <linux/qtee_shmbridge.h>
|
|
@@ -138,6 +139,8 @@
|
|
|
#define TZHANDLE_GET_SERVER(h) ((uint16_t)((h) & 0xFFFF))
|
|
|
#define TZHANDLE_GET_OBJID(h) (((h) >> 16) & 0x7FFF)
|
|
|
#define TZHANDLE_MAKE_LOCAL(s, o) (((0x8000 | (o)) << 16) | s)
|
|
|
+#define SET_BIT(s,b) (s | (1 << b))
|
|
|
+#define UNSET_BIT(s,b) (s & (~ (1 << b)))
|
|
|
|
|
|
#define TZHANDLE_IS_NULL(h) ((h) == SMCINVOKE_TZ_OBJ_NULL)
|
|
|
#define TZHANDLE_IS_LOCAL(h) ((h) & 0x80000000)
|
|
@@ -304,6 +307,7 @@ struct smcinvoke_server_info {
|
|
|
DECLARE_HASHTABLE(responses_table, 4);
|
|
|
struct hlist_node hash;
|
|
|
struct list_head pending_cbobjs;
|
|
|
+ uint8_t is_server_suspended;
|
|
|
};
|
|
|
|
|
|
struct smcinvoke_cbobj {
|
|
@@ -618,23 +622,25 @@ static void smcinvoke_start_adci_thread(void)
|
|
|
ret = get_client_env_object(&adci_clientEnv);
|
|
|
if (ret) {
|
|
|
pr_err("failed to get clientEnv for ADCI invoke thread. ret = %d\n", ret);
|
|
|
+ /* Marking it Object_NULL in case of failure scenario in order to avoid
|
|
|
+ * undefined behavior while releasing garbage adci_clientEnv object.
|
|
|
+ */
|
|
|
adci_clientEnv = Object_NULL;
|
|
|
goto out;
|
|
|
}
|
|
|
/* Invoke call to QTEE which should never return if ADCI is supported */
|
|
|
do {
|
|
|
- ret = IClientEnv_accept(adci_clientEnv);
|
|
|
+ ret = IClientEnv_adciAccept(adci_clientEnv);
|
|
|
if (ret == OBJECT_ERROR_BUSY) {
|
|
|
pr_err("Secure side is busy,will retry after 5 ms, retry_count = %d",retry_count);
|
|
|
- msleep(5);
|
|
|
+ msleep(SMCINVOKE_INTERFACE_BUSY_WAIT_MS);
|
|
|
}
|
|
|
} while ((ret == OBJECT_ERROR_BUSY) && (retry_count++ < SMCINVOKE_INTERFACE_MAX_RETRY));
|
|
|
|
|
|
if (ret == OBJECT_ERROR_INVALID)
|
|
|
pr_err("ADCI feature is not supported on this chipsets, ret = %d\n", ret);
|
|
|
- /* Need to take decesion here if we want to restart the ADCI thread */
|
|
|
else
|
|
|
- pr_err("Received response from QTEE, ret = %d\n", ret);
|
|
|
+ pr_debug("Received response from QTEE, ret = %d\n", ret);
|
|
|
out:
|
|
|
/* Control should reach to this point only if ADCI feature is not supported by QTEE
|
|
|
(or) ADCI thread held in QTEE is released. */
|
|
@@ -747,7 +753,7 @@ static void smcinvoke_destroy_kthreads(void)
|
|
|
ret = IClientEnv_adciShutdown(adci_clientEnv);
|
|
|
if (ret == OBJECT_ERROR_BUSY) {
|
|
|
pr_err("Secure side is busy,will retry after 5 ms, retry_count = %d",retry_count);
|
|
|
- msleep(5);
|
|
|
+ msleep(SMCINVOKE_INTERFACE_BUSY_WAIT_MS);
|
|
|
}
|
|
|
} while ((ret == OBJECT_ERROR_BUSY) && (retry_count++ < SMCINVOKE_INTERFACE_MAX_RETRY));
|
|
|
if(OBJECT_isERROR(ret)) {
|
|
@@ -1717,13 +1723,15 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp)
|
|
|
timeout_jiff);
|
|
|
}
|
|
|
if (ret == 0) {
|
|
|
- pr_err("CBobj timed out cb-tzhandle:%d, retry:%d, op:%d counts :%d\n",
|
|
|
- cb_req->hdr.tzhandle, cbobj_retries,
|
|
|
+ if (srvr_info->is_server_suspended == 0) {
|
|
|
+ pr_err("CBobj timed out waiting on cbtxn :%d,cb-tzhandle:%d, retry:%d, op:%d counts :%d\n",
|
|
|
+ cb_txn->txn_id,cb_req->hdr.tzhandle, cbobj_retries,
|
|
|
cb_req->hdr.op, cb_req->hdr.counts);
|
|
|
pr_err("CBobj %d timedout pid %x,tid %x, srvr state=%d, srvr id:%u\n",
|
|
|
cb_req->hdr.tzhandle, current->pid,
|
|
|
current->tgid, srvr_info->state,
|
|
|
srvr_info->server_id);
|
|
|
+ }
|
|
|
} else {
|
|
|
/* wait_event returned due to a signal */
|
|
|
if (srvr_info->state != SMCINVOKE_SERVER_STATE_DEFUNCT &&
|
|
@@ -1733,7 +1741,16 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp)
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
- cbobj_retries++;
|
|
|
+ /*
|
|
|
+ * If bit corresponding to any accept thread is set, invoke threads
|
|
|
+ * should wait infinitely for the accept thread to come back with
|
|
|
+ * response.
|
|
|
+ */
|
|
|
+ if (srvr_info->is_server_suspended > 0) {
|
|
|
+ cbobj_retries = 0;
|
|
|
+ } else {
|
|
|
+ cbobj_retries++;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
out:
|
|
@@ -2396,6 +2413,7 @@ static long process_server_req(struct file *filp, unsigned int cmd,
|
|
|
hash_init(server_info->reqs_table);
|
|
|
hash_init(server_info->responses_table);
|
|
|
INIT_LIST_HEAD(&server_info->pending_cbobjs);
|
|
|
+ server_info->is_server_suspended = 0;
|
|
|
|
|
|
mutex_lock(&g_smcinvoke_lock);
|
|
|
|
|
@@ -2459,6 +2477,9 @@ static long process_accept_req(struct file *filp, unsigned int cmd,
|
|
|
if (server_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT)
|
|
|
server_info->state = 0;
|
|
|
|
|
|
+ server_info->is_server_suspended = UNSET_BIT(server_info->is_server_suspended,
|
|
|
+ (current->pid)%DEFAULT_CB_OBJ_THREAD_CNT);
|
|
|
+
|
|
|
mutex_unlock(&g_smcinvoke_lock);
|
|
|
|
|
|
/* First check if it has response otherwise wait for req */
|
|
@@ -2522,7 +2543,26 @@ start_waiting_for_requests:
|
|
|
* using server_info and would crash. So dont do that.
|
|
|
*/
|
|
|
mutex_lock(&g_smcinvoke_lock);
|
|
|
- server_info->state = SMCINVOKE_SERVER_STATE_DEFUNCT;
|
|
|
+
|
|
|
+ if(freezing(current)) {
|
|
|
+ pr_err("Server id :%d interrupted probaby due to suspend, pid:%d",
|
|
|
+ server_info->server_id, current->pid);
|
|
|
+ /*
|
|
|
+ * Each accept thread is identified by bits ranging from
|
|
|
+ * 0 to DEFAULT_CBOBJ_THREAD_CNT-1. When an accept thread is
|
|
|
+ * interrupted by a signal other than SIGUSR1,SIGKILL,SIGTERM,
|
|
|
+ * set the corresponding bit of accept thread, indicating that
|
|
|
+ * current accept thread's state to be "suspended"/ or something
|
|
|
+ * that needs infinite timeout for invoke thread.
|
|
|
+ */
|
|
|
+ server_info->is_server_suspended =
|
|
|
+ SET_BIT(server_info->is_server_suspended,
|
|
|
+ (current->pid)%DEFAULT_CB_OBJ_THREAD_CNT);
|
|
|
+ } else {
|
|
|
+ pr_err("Setting pid:%d, server id : %d state to defunct",
|
|
|
+ current->pid, server_info->server_id);
|
|
|
+ server_info->state = SMCINVOKE_SERVER_STATE_DEFUNCT;
|
|
|
+ }
|
|
|
mutex_unlock(&g_smcinvoke_lock);
|
|
|
wake_up_interruptible(&server_info->rsp_wait_q);
|
|
|
goto out;
|
|
@@ -2622,7 +2662,7 @@ static long process_invoke_req(struct file *filp, unsigned int cmd,
|
|
|
tzobj->tzhandle == SMCINVOKE_TZ_ROOT_OBJ &&
|
|
|
(req.op == IClientEnv_OP_notifyDomainChange ||
|
|
|
req.op == IClientEnv_OP_registerWithCredentials ||
|
|
|
- req.op == IClientEnv_OP_accept ||
|
|
|
+ req.op == IClientEnv_OP_adciAccept ||
|
|
|
req.op == IClientEnv_OP_adciShutdown)) {
|
|
|
pr_err("invalid rootenv op\n");
|
|
|
return -EINVAL;
|