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 <zkong@codeaurora.org>
This commit is contained in:
parent
ec9fd7cc51
commit
431c2111d8
1 changed files with 130 additions and 54 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue