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:
Zhen Kong 2016-02-25 12:37:47 -08:00
parent ec9fd7cc51
commit 431c2111d8

View file

@ -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;