From 431c2111d8c4205eb3457f1fe35b00e513a06333 Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Thu, 25 Feb 2016 12:37:47 -0800 Subject: [PATCH] qseecom: improve listener resp processing if app is blocked When qseecom send listener A's resp to app A, if app A needs to request listener B but B is used by another app, TZ will return BLOCKED status to qseecom. Instead of returning an error to client directly, qseecom need to wait listener B become available and then notify TZ to continue blocked request for listener B. Change-Id: I5f7a19718b3b81a1e27d128bc69554cbaabf03f9 Signed-off-by: Zhen Kong --- drivers/misc/qseecom.c | 184 +++++++++++++++++++++++++++++------------ 1 file changed, 130 insertions(+), 54 deletions(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index c994f7e00a16..d71c90aac311 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1488,6 +1488,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head, list) { if (ptr_svc->svc.listener_id == lstnr) { + ptr_svc->listener_in_use = true; ptr_svc->rcv_req_flag = 1; wake_up_interruptible(&ptr_svc->rcv_req_wq); break; @@ -1570,6 +1571,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, (const void *)&send_data_rsp, sizeof(send_data_rsp), resp, sizeof(*resp)); + ptr_svc->listener_in_use = false; if (ret) { pr_err("scm_call() failed with err: %d (app_id = %d)\n", ret, data->client.app_id); @@ -1593,6 +1595,101 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, return ret; } +int __qseecom_process_reentrancy_blocked_on_listener( + struct qseecom_command_scm_resp *resp, + struct qseecom_registered_app_list *ptr_app, + struct qseecom_dev_handle *data) +{ + struct qseecom_registered_listener_list *list_ptr; + int ret = 0; + struct qseecom_continue_blocked_request_ireq ireq; + struct qseecom_command_scm_resp continue_resp; + sigset_t new_sigset, old_sigset; + unsigned long flags; + bool found_app = false; + + if (!resp || !data) { + pr_err("invalid resp or data pointer\n"); + ret = -EINVAL; + goto exit; + } + + /* find app_id & img_name from list */ + if (!ptr_app) { + spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); + list_for_each_entry(ptr_app, &qseecom.registered_app_list_head, + list) { + if ((ptr_app->app_id == data->client.app_id) && + (!strcmp(ptr_app->app_name, + data->client.app_name))) { + found_app = true; + break; + } + } + spin_unlock_irqrestore(&qseecom.registered_app_list_lock, + flags); + if (!found_app) { + pr_err("app_id %d (%s) is not found\n", + data->client.app_id, + (char *)data->client.app_name); + ret = -ENOENT; + goto exit; + } + } + + list_ptr = __qseecom_find_svc(resp->data); + if (!list_ptr) { + pr_err("Invalid listener ID\n"); + ret = -ENODATA; + goto exit; + } + pr_debug("lsntr %d in_use = %d\n", + resp->data, list_ptr->listener_in_use); + ptr_app->blocked_on_listener_id = resp->data; + /* sleep until listener is available */ + do { + qseecom.app_block_ref_cnt++; + ptr_app->app_blocked = true; + sigfillset(&new_sigset); + sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); + mutex_unlock(&app_access_lock); + do { + if (!wait_event_freezable( + list_ptr->listener_block_app_wq, + !list_ptr->listener_in_use)) { + break; + } + } while (1); + mutex_lock(&app_access_lock); + sigprocmask(SIG_SETMASK, &old_sigset, NULL); + ptr_app->app_blocked = false; + qseecom.app_block_ref_cnt--; + } while (list_ptr->listener_in_use == true); + ptr_app->blocked_on_listener_id = 0; + /* notify the blocked app that listener is available */ + pr_warn("Lsntr %d is available, unblock app(%d) %s in TZ\n", + resp->data, data->client.app_id, + data->client.app_name); + ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND; + ireq.app_id = data->client.app_id; + ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, + &ireq, sizeof(ireq), + &continue_resp, sizeof(continue_resp)); + if (ret) { + pr_err("scm_call for continue blocked req for app(%d) %s failed, ret %d\n", + data->client.app_id, + data->client.app_name, ret); + goto exit; + } + /* + * After TZ app is unblocked, then continue to next case + * for incomplete request processing + */ + resp->result = QSEOS_RESULT_INCOMPLETE; +exit: + return ret; +} + static int __qseecom_reentrancy_process_incomplete_cmd( struct qseecom_dev_handle *data, struct qseecom_command_scm_resp *resp) @@ -1606,7 +1703,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd( sigset_t new_sigset; sigset_t old_sigset; - while (resp->result == QSEOS_RESULT_INCOMPLETE) { + while (ret == 0 && rc == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) { lstnr = resp->data; /* * Wake up blocking lsitener service with the lstnr id @@ -1693,16 +1790,37 @@ static int __qseecom_reentrancy_process_incomplete_cmd( if (ret) { pr_err("scm_call() failed with err: %d (app_id = %d)\n", ret, data->client.app_id); - if (lstnr == RPMB_SERVICE) - __qseecom_disable_clk(CLK_QSEE); - return ret; + goto exit; } - if ((resp->result != QSEOS_RESULT_SUCCESS) && - (resp->result != QSEOS_RESULT_INCOMPLETE)) { + + switch (resp->result) { + case QSEOS_RESULT_BLOCKED_ON_LISTENER: + pr_warn("send lsr %d rsp, but app %d block on lsr %d\n", + lstnr, data->client.app_id, resp->data); + if (lstnr == resp->data) { + pr_err("lstnr %d should not be blocked!\n", + lstnr); + ret = -EINVAL; + goto exit; + } + ret = __qseecom_process_reentrancy_blocked_on_listener( + resp, NULL, data); + if (ret) { + pr_err("failed to process App(%d) %s blocked on listener %d\n", + data->client.app_id, + data->client.app_name, resp->data); + goto exit; + } + case QSEOS_RESULT_SUCCESS: + case QSEOS_RESULT_INCOMPLETE: + break; + default: pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n", resp->result, data->client.app_id, lstnr); ret = -EINVAL; + goto exit; } +exit: if (lstnr == RPMB_SERVICE) __qseecom_disable_clk(CLK_QSEE); @@ -2551,63 +2669,21 @@ int __qseecom_process_reentrancy(struct qseecom_command_scm_resp *resp, struct qseecom_registered_app_list *ptr_app, struct qseecom_dev_handle *data) { - struct qseecom_registered_listener_list *list_ptr; int ret = 0; - struct qseecom_continue_blocked_request_ireq ireq; - struct qseecom_command_scm_resp continue_resp; - sigset_t new_sigset, old_sigset; switch (resp->result) { case QSEOS_RESULT_BLOCKED_ON_LISTENER: - pr_debug("App(%d) %s is blocked on listener %d\n", + pr_warn("App(%d) %s is blocked on listener %d\n", data->client.app_id, data->client.app_name, resp->data); - list_ptr = __qseecom_find_svc(resp->data); - if (!list_ptr) { - pr_err("Invalid listener ID\n"); - return -ENODATA; - } - ptr_app->blocked_on_listener_id = resp->data; - list_ptr->listener_in_use = true; - /* sleep until listener is available */ - while (list_ptr->listener_in_use == true) { - qseecom.app_block_ref_cnt++; - ptr_app->app_blocked = true; - sigfillset(&new_sigset); - sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); - mutex_unlock(&app_access_lock); - do { - if (!wait_event_freezable( - list_ptr->listener_block_app_wq, - !list_ptr->listener_in_use)) { - break; - } - } while (1); - mutex_lock(&app_access_lock); - sigprocmask(SIG_SETMASK, &old_sigset, NULL); - ptr_app->app_blocked = false; - qseecom.app_block_ref_cnt--; - } - /* notify the blocked app that listener is available */ - pr_debug("Lsntr %d is available, unblock app(%d) %s in TZ\n", - resp->data, data->client.app_id, - data->client.app_name); - ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND; - ireq.app_id = data->client.app_id; - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, - &ireq, sizeof(ireq), - &continue_resp, sizeof(continue_resp)); + ret = __qseecom_process_reentrancy_blocked_on_listener( + resp, ptr_app, data); if (ret) { - pr_err("scm_call for continue blocked req for app(%d) %s failed, ret %d\n", - data->client.app_id, - data->client.app_name, ret); + pr_err("failed to process App(%d) %s is blocked on listener %d\n", + data->client.app_id, data->client.app_name, resp->data); return ret; } - /* - * After TZ app is unblocked, then continue to next case - * for incomplete request processing - */ - resp->result = QSEOS_RESULT_INCOMPLETE; + case QSEOS_RESULT_INCOMPLETE: qseecom.app_block_ref_cnt++; ptr_app->app_blocked = true;