From e55be430405c53cb9e3d6765de2b9e0a0bd5e834 Mon Sep 17 00:00:00 2001 From: Anmolpreet Kaur Date: Mon, 14 Dec 2020 22:30:02 +0530 Subject: [PATCH] smcinvoke: implement retry and timeout for CB processing CB requests are processed by HLOS userspace. It is possible that userspace never returns with a response. This could cause trusted environment that initiated CB request to reject processing anymore non-secure requests. This is not a desirable situation. Hence, adding timeout functionality along with retry mechanism to send error response back to trusted env after maximum number of retries are already done and continue processing requests from non-secure side. Change-Id: Idbd3048d0b9594c9927d55a24a8ca77e14214746 Signed-off-by: Anmolpreet Kaur --- drivers/soc/qcom/smcinvoke.c | 56 +++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c index bbfe6a4b92b8..8165a8cd633a 100644 --- a/drivers/soc/qcom/smcinvoke.c +++ b/drivers/soc/qcom/smcinvoke.c @@ -61,6 +61,7 @@ */ #define SMCINVOKE_SERVER_STATE_DEFUNCT 1 +#define CBOBJ_MAX_RETRIES 5 #define FOR_ARGS(ndxvar, counts, section) \ for (ndxvar = OBJECT_COUNTS_INDEX_##section(counts); \ ndxvar < (OBJECT_COUNTS_INDEX_##section(counts) \ @@ -1002,6 +1003,8 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp) { /* ret is going to TZ. Provide values from OBJECT_ERROR_<> */ int ret = OBJECT_ERROR_DEFUNCT; + int cbobj_retries = 0; + long timeout_jiff; struct smcinvoke_cb_txn *cb_txn = NULL; struct smcinvoke_tzcb_req *cb_req = NULL, *tmp_cb_req = NULL; struct smcinvoke_server_info *srvr_info = NULL; @@ -1079,9 +1082,26 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp) * as this CBObj is served by this server, srvr_info will be valid. */ wake_up_interruptible_all(&srvr_info->req_wait_q); - ret = wait_event_interruptible(srvr_info->rsp_wait_q, - (cb_txn->state == SMCINVOKE_REQ_PROCESSED) || - (srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT)); + /* timeout before 1s otherwise tzbusy would come */ + timeout_jiff = msecs_to_jiffies(1000); + + while (cbobj_retries < CBOBJ_MAX_RETRIES) { + ret = wait_event_interruptible_timeout(srvr_info->rsp_wait_q, + (cb_txn->state == SMCINVOKE_REQ_PROCESSED) || + (srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT), + 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, 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 { + break; + } + cbobj_retries++; + } out: /* @@ -1091,18 +1111,26 @@ out: */ mutex_lock(&g_smcinvoke_lock); hash_del(&cb_txn->hash); - if (cb_txn->state == SMCINVOKE_REQ_PROCESSED) { - /* - * it is possible that server was killed immediately - * after CB Req was processed but who cares now! - */ - } else if (!srvr_info || - srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT) { - cb_req->result = OBJECT_ERROR_DEFUNCT; - pr_err("server invalid, res: %d\n", cb_req->result); - } else { - pr_debug("%s wait_event interrupted ret = %d\n", __func__, ret); + if (ret == 0) { + pr_err("CBObj timed out! No more retries\n"); cb_req->result = OBJECT_ERROR_ABORT; + } else if (ret < 0) { + pr_err("wait event interruped, ret: %d\n", ret); + cb_req->result = OBJECT_ERROR_ABORT; + } else { + if (cb_txn->state == SMCINVOKE_REQ_PROCESSED) { + /* + * it is possible that server was killed immediately + * after CB Req was processed but who cares now! + */ + } else if (!srvr_info || + srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT) { + cb_req->result = OBJECT_ERROR_DEFUNCT; + pr_err("server invalid, res: %d\n", cb_req->result); + } else { + pr_err("%s: unexpected event happened\n", __func__); + cb_req->result = OBJECT_ERROR_ABORT; + } } --cb_reqs_inflight; memcpy(buf, cb_req, buf_len);