aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhen Kong <zkong@codeaurora.org>2018-11-16 13:50:51 -0800
committerCraft Ju <craftju@google.com>2019-05-29 06:22:16 +0000
commit652759d40757197bdb78adfb1c06902a19525a3e (patch)
treecd63edf657708a9bb7b48b37350398cd6f3b79dc
parent86c9d191d40be47f15b367b2fecffc8f6cdc6ab6 (diff)
qseecom: listener unregister and register optimization
Optimize listener unregister and register operations to avoid deadlock and xpu violation. Bug: 133120616 Bug: 133128687 Change-Id: Ic1af4ad60abe2422aa133f72c0523074ed7cdc5a Signed-off-by: Zhen Kong <zkong@codeaurora.org>
-rw-r--r--drivers/misc/qseecom.c312
1 files changed, 174 insertions, 138 deletions
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 1ead78014123..eb505bb7ebf7 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -143,6 +143,8 @@ static dev_t qseecom_device_no;
static DEFINE_MUTEX(qsee_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
static DEFINE_MUTEX(clk_access_lock);
+static DEFINE_MUTEX(listener_access_lock);
+
struct sglist_info {
uint32_t indexAndFlags;
@@ -182,15 +184,21 @@ struct qseecom_registered_listener_list {
size_t sb_length;
struct ion_handle *ihandle; /* Retrieve phy addr */
wait_queue_head_t rcv_req_wq;
- /* rcv_req_flag: -1: not ready; 0: ready and empty; 1: received req */
+ /* rcv_req_flag: 0: ready and empty; 1: received req */
int rcv_req_flag;
int send_resp_flag;
bool listener_in_use;
/* wq for thread blocked on this listener*/
wait_queue_head_t listener_block_app_wq;
- struct sglist_info sglistinfo_ptr[MAX_ION_FD];
- uint32_t sglist_cnt;
- int abort;
+ struct sglist_info sglistinfo_ptr[MAX_ION_FD];
+ uint32_t sglist_cnt;
+ int abort;
+ bool unregister_pending;
+};
+
+struct qseecom_unregister_pending_list {
+ struct list_head list;
+ struct qseecom_dev_handle *data;
};
struct qseecom_registered_app_list {
@@ -238,7 +246,6 @@ struct qseecom_clk {
struct qseecom_control {
struct ion_client *ion_clnt; /* Ion client */
struct list_head registered_listener_list_head;
- spinlock_t registered_listener_list_lock;
struct list_head registered_app_list_head;
spinlock_t registered_app_list_lock;
@@ -284,6 +291,9 @@ struct qseecom_control {
atomic_t qseecom_state;
int is_apps_region_protected;
bool smcinvoke_support;
+
+ struct list_head unregister_lsnr_pending_list_head;
+ wait_queue_head_t register_lsnr_pending_wq;
};
struct qseecom_sec_buf_fd_info {
@@ -312,6 +322,7 @@ struct qseecom_client_handle {
struct qseecom_listener_handle {
u32 id;
+ bool unregister_pending;
};
static struct qseecom_control qseecom;
@@ -585,13 +596,10 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
}
qseecom.smcinvoke_support = true;
smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID;
- __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
ret = scm_call2(smc_id, &desc);
- if (ret) {
+ if (ret && ret != -EBUSY) {
qseecom.smcinvoke_support = false;
smc_id = TZ_OS_REGISTER_LISTENER_ID;
- __qseecom_reentrancy_check_if_no_app_blocked(
- smc_id);
ret = scm_call2(smc_id, &desc);
}
break;
@@ -604,7 +612,6 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
smc_id = TZ_OS_DEREGISTER_LISTENER_ID;
desc.arginfo = TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID;
desc.args[0] = req->listener_id;
- __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
ret = scm_call2(smc_id, &desc);
break;
}
@@ -1065,42 +1072,18 @@ static int qseecom_scm_call(u32 svc_id, u32 tz_cmd_id, const void *cmd_buf,
return qseecom_scm_call2(svc_id, tz_cmd_id, cmd_buf, resp_buf);
}
-static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
- struct qseecom_register_listener_req *svc)
-{
- struct qseecom_registered_listener_list *ptr;
- int unique = 1;
- unsigned long flags;
-
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
- list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
- if (ptr->svc.listener_id == svc->listener_id) {
- pr_err("Service id: %u is already registered\n",
- ptr->svc.listener_id);
- unique = 0;
- break;
- }
- }
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
- return unique;
-}
-
static struct qseecom_registered_listener_list *__qseecom_find_svc(
int32_t listener_id)
{
struct qseecom_registered_listener_list *entry = NULL;
- unsigned long flags;
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
list_for_each_entry(entry,
&qseecom.registered_listener_list_head, list) {
if (entry->svc.listener_id == listener_id)
break;
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
-
if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
- pr_err("Service id: %u is not found\n", listener_id);
+ pr_debug("Service id: %u is not found\n", listener_id);
return NULL;
}
@@ -1179,9 +1162,9 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
void __user *argp)
{
int ret = 0;
- unsigned long flags;
struct qseecom_register_listener_req rcvd_lstnr;
struct qseecom_registered_listener_list *new_entry;
+ struct qseecom_registered_listener_list *ptr_svc;
ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
if (ret) {
@@ -1193,18 +1176,37 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
return -EFAULT;
data->listener.id = rcvd_lstnr.listener_id;
- if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
- pr_err("Service %d is not unique and failed to register\n",
+
+ ptr_svc = __qseecom_find_svc(rcvd_lstnr.listener_id);
+ if (ptr_svc) {
+ if (ptr_svc->unregister_pending == false) {
+ pr_err("Service %d is not unique\n",
rcvd_lstnr.listener_id);
data->released = true;
return -EBUSY;
+ } else {
+ /*wait until listener is unregistered*/
+ pr_debug("register %d has to wait\n",
+ rcvd_lstnr.listener_id);
+ mutex_unlock(&listener_access_lock);
+ ret = wait_event_freezable(
+ qseecom.register_lsnr_pending_wq,
+ list_empty(
+ &qseecom.unregister_lsnr_pending_list_head));
+ if (ret) {
+ pr_err("interrupted register_pending_wq %d\n",
+ rcvd_lstnr.listener_id);
+ mutex_lock(&listener_access_lock);
+ return -ERESTARTSYS;
+ }
+ mutex_lock(&listener_access_lock);
+ }
}
-
new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
if (!new_entry)
return -ENOMEM;
memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
- new_entry->rcv_req_flag = -1;
+ new_entry->rcv_req_flag = 0;
new_entry->svc.listener_id = rcvd_lstnr.listener_id;
new_entry->sb_length = rcvd_lstnr.sb_size;
@@ -1220,45 +1222,20 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
init_waitqueue_head(&new_entry->listener_block_app_wq);
new_entry->send_resp_flag = 0;
new_entry->listener_in_use = false;
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
pr_warn("Service %d is registered\n", rcvd_lstnr.listener_id);
return ret;
}
-static void __qseecom_listener_abort_all(int abort)
-{
- struct qseecom_registered_listener_list *entry = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
- list_for_each_entry(entry,
- &qseecom.registered_listener_list_head, list) {
- pr_debug("set abort %d for listener %d\n",
- abort, entry->svc.listener_id);
- entry->abort = abort;
- }
- if (abort)
- wake_up_interruptible_all(&qseecom.send_resp_wq);
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
-}
-
-static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
+static int __qseecom_unregister_listener(struct qseecom_dev_handle *data,
+ struct qseecom_registered_listener_list *ptr_svc)
{
int ret = 0;
struct qseecom_register_listener_ireq req;
- struct qseecom_registered_listener_list *ptr_svc = NULL;
struct qseecom_command_scm_resp resp;
struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
- ptr_svc = __qseecom_find_svc(data->listener.id);
- if (!ptr_svc) {
- pr_err("Unregiser invalid listener ID %d\n", data->listener.id);
- return -ENODATA;
- }
-
req.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
req.listener_id = data->listener.id;
resp.result = QSEOS_RESULT_INCOMPLETE;
@@ -1268,6 +1245,8 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
if (ret) {
pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
ret, data->listener.id);
+ if (ret == -EBUSY)
+ return ret;
goto exit;
}
@@ -1279,7 +1258,6 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
}
data->abort = 1;
- ptr_svc->abort = 1;
wake_up_all(&ptr_svc->rcv_req_wq);
while (atomic_read(&data->ioctl_count) > 1) {
@@ -1306,6 +1284,74 @@ exit:
return ret;
}
+static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
+{
+ struct qseecom_registered_listener_list *ptr_svc = NULL;
+ struct qseecom_unregister_pending_list *entry = NULL;
+
+ ptr_svc = __qseecom_find_svc(data->listener.id);
+ if (!ptr_svc) {
+ pr_err("Unregiser invalid listener ID %d\n", data->listener.id);
+ return -ENODATA;
+ }
+ /* stop CA thread waiting for listener response */
+ ptr_svc->abort = 1;
+ wake_up_interruptible_all(&qseecom.send_resp_wq);
+
+ /* return directly if pending*/
+ if (ptr_svc->unregister_pending)
+ return 0;
+
+ /*add unregistration into pending list*/
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+ entry->data = data;
+ list_add_tail(&entry->list,
+ &qseecom.unregister_lsnr_pending_list_head);
+ ptr_svc->unregister_pending = true;
+ pr_debug("unregister %d pending\n", data->listener.id);
+ return 0;
+}
+
+static void __qseecom_processing_pending_lsnr_unregister(void)
+{
+ struct qseecom_unregister_pending_list *entry = NULL;
+ struct qseecom_registered_listener_list *ptr_svc = NULL;
+ struct list_head *pos;
+ int ret = 0;
+
+ mutex_lock(&listener_access_lock);
+ while (!list_empty(&qseecom.unregister_lsnr_pending_list_head)) {
+ pos = qseecom.unregister_lsnr_pending_list_head.next;
+ entry = list_entry(pos,
+ struct qseecom_unregister_pending_list, list);
+ if (entry && entry->data) {
+ pr_debug("process pending unregister %d\n",
+ entry->data->listener.id);
+ ptr_svc = __qseecom_find_svc(
+ entry->data->listener.id);
+ if (ptr_svc) {
+ ret = __qseecom_unregister_listener(
+ entry->data, ptr_svc);
+ if (ret == -EBUSY) {
+ pr_debug("unregister %d pending again\n",
+ entry->data->listener.id);
+ mutex_unlock(&listener_access_lock);
+ return;
+ }
+ } else
+ pr_err("invalid listener %d\n",
+ entry->data->listener.id);
+ kzfree(entry->data);
+ }
+ list_del(pos);
+ kzfree(entry);
+ }
+ mutex_unlock(&listener_access_lock);
+ wake_up_interruptible(&qseecom.register_lsnr_pending_wq);
+}
+
static int __qseecom_set_msm_bus_request(uint32_t mode)
{
int ret = 0;
@@ -1640,19 +1686,12 @@ static void __qseecom_clean_listener_sglistinfo(
}
}
-static int __is_listener_rcv_wq_not_ready(
- struct qseecom_registered_listener_list *ptr_svc)
-{
- return ptr_svc->rcv_req_flag == -1;
-}
-
static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
struct qseecom_command_scm_resp *resp)
{
int ret = 0;
int rc = 0;
uint32_t lstnr;
- unsigned long flags;
struct qseecom_client_listener_data_irsp send_data_rsp = {0};
struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
= {0};
@@ -1663,30 +1702,23 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
void *cmd_buf = NULL;
size_t cmd_len;
struct sglist_info *table = NULL;
- bool not_ready = false;
+ qseecom.app_block_ref_cnt++;
while (resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
/*
* Wake up blocking lsitener service with the lstnr id
*/
- spin_lock_irqsave(&qseecom.registered_listener_list_lock,
- flags);
+ mutex_lock(&listener_access_lock);
list_for_each_entry(ptr_svc,
&qseecom.registered_listener_list_head, list) {
if (ptr_svc->svc.listener_id == lstnr) {
- if (__is_listener_rcv_wq_not_ready(ptr_svc)) {
- not_ready = true;
- break;
- }
ptr_svc->listener_in_use = true;
ptr_svc->rcv_req_flag = 1;
wake_up_interruptible(&ptr_svc->rcv_req_wq);
break;
}
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
- flags);
if (ptr_svc == NULL) {
pr_err("Listener Svc %d does not exist\n", lstnr);
@@ -1712,22 +1744,13 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
}
if (ptr_svc->abort == 1) {
- pr_err("Service %d abort %d\n",
+ pr_debug("Service %d abort %d\n",
lstnr, ptr_svc->abort);
rc = -ENODEV;
status = QSEOS_RESULT_FAILURE;
goto err_resp;
}
- if (not_ready) {
- pr_err("Service %d is not ready to receive request\n",
- lstnr);
- rc = -ENOENT;
- status = QSEOS_RESULT_FAILURE;
- goto err_resp;
-
- }
-
pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");
/* initialize the new signal mask with all signals*/
@@ -1735,6 +1758,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
/* block all signals */
sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
+ mutex_unlock(&listener_access_lock);
do {
/*
* When reentrancy is not supported, check global
@@ -1755,7 +1779,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
break;
}
} while (1);
-
+ mutex_lock(&listener_access_lock);
/* restore signal mask */
sigprocmask(SIG_SETMASK, &old_sigset, NULL);
if (data->abort || ptr_svc->abort) {
@@ -1811,14 +1835,14 @@ err_resp:
ION_IOC_CLEAN_INV_CACHES);
if (ret) {
pr_err("cache operation failed %d\n", ret);
- return ret;
+ goto exit;
}
}
if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) {
ret = __qseecom_enable_clk(CLK_QSEE);
if (ret)
- return ret;
+ goto exit;
}
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
@@ -1832,7 +1856,7 @@ err_resp:
ret, data->client.app_id);
if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
__qseecom_disable_clk(CLK_QSEE);
- return ret;
+ goto exit;
}
pr_debug("resp status %d, res= %d, app_id = %d, lstr = %d\n",
status, resp->result, data->client.app_id, lstnr);
@@ -1841,11 +1865,15 @@ err_resp:
pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
resp->result, data->client.app_id, lstnr);
ret = -EINVAL;
+ goto exit;
}
+exit:
+ mutex_unlock(&listener_access_lock);
if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
__qseecom_disable_clk(CLK_QSEE);
}
+ qseecom.app_block_ref_cnt--;
if (rc)
return rc;
@@ -1898,10 +1926,12 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
do {
session_id = resp->resp_type;
+ mutex_lock(&listener_access_lock);
list_ptr = __qseecom_find_svc(resp->data);
if (!list_ptr) {
pr_err("Invalid listener ID %d\n", resp->data);
ret = -ENODATA;
+ mutex_unlock(&listener_access_lock);
goto exit;
}
ptr_app->blocked_on_listener_id = resp->data;
@@ -1917,11 +1947,13 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
do {
qseecom.app_block_ref_cnt++;
ptr_app->app_blocked = true;
+ mutex_unlock(&listener_access_lock);
mutex_unlock(&app_access_lock);
wait_event_freezable(
list_ptr->listener_block_app_wq,
!list_ptr->listener_in_use);
mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
ptr_app->app_blocked = false;
qseecom.app_block_ref_cnt--;
} while (list_ptr->listener_in_use);
@@ -1954,9 +1986,11 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
if (ret) {
pr_err("unblock app %d or session %d fail\n",
data->client.app_id, session_id);
+ mutex_unlock(&listener_access_lock);
goto exit;
}
}
+ mutex_unlock(&listener_access_lock);
resp->result = continue_resp.result;
resp->resp_type = continue_resp.resp_type;
resp->data = continue_resp.data;
@@ -1978,7 +2012,6 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
int ret = 0;
int rc = 0;
uint32_t lstnr;
- unsigned long flags;
struct qseecom_client_listener_data_irsp send_data_rsp = {0};
struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
= {0};
@@ -1989,30 +2022,22 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
void *cmd_buf = NULL;
size_t cmd_len;
struct sglist_info *table = NULL;
- bool not_ready = false;
while (ret == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
/*
* Wake up blocking lsitener service with the lstnr id
*/
- spin_lock_irqsave(&qseecom.registered_listener_list_lock,
- flags);
+ mutex_lock(&listener_access_lock);
list_for_each_entry(ptr_svc,
&qseecom.registered_listener_list_head, list) {
if (ptr_svc->svc.listener_id == lstnr) {
- if (__is_listener_rcv_wq_not_ready(ptr_svc)) {
- not_ready = true;
- break;
- }
ptr_svc->listener_in_use = true;
ptr_svc->rcv_req_flag = 1;
wake_up_interruptible(&ptr_svc->rcv_req_wq);
break;
}
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
- flags);
if (ptr_svc == NULL) {
pr_err("Listener Svc %d does not exist\n", lstnr);
@@ -2038,22 +2063,13 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
}
if (ptr_svc->abort == 1) {
- pr_err("Service %d abort %d\n",
+ pr_debug("Service %d abort %d\n",
lstnr, ptr_svc->abort);
rc = -ENODEV;
status = QSEOS_RESULT_FAILURE;
goto err_resp;
}
- if (not_ready) {
- pr_err("Service %d is not ready to receive request\n",
- lstnr);
- rc = -ENOENT;
- status = QSEOS_RESULT_FAILURE;
- goto err_resp;
-
- }
-
pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");
/* initialize the new signal mask with all signals*/
@@ -2063,6 +2079,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
/* unlock mutex btw waking listener and sleep-wait */
+ mutex_unlock(&listener_access_lock);
mutex_unlock(&app_access_lock);
do {
if (!wait_event_freezable(qseecom.send_resp_wq,
@@ -2073,6 +2090,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
} while (1);
/* lock mutex again after resp sent */
mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
ptr_svc->send_resp_flag = 0;
qseecom.send_resp_flag = 0;
@@ -2134,7 +2152,7 @@ err_resp:
if (lstnr == RPMB_SERVICE) {
ret = __qseecom_enable_clk(CLK_QSEE);
if (ret)
- return ret;
+ goto exit;
}
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
@@ -2179,6 +2197,7 @@ err_resp:
goto exit;
}
exit:
+ mutex_unlock(&listener_access_lock);
if (lstnr == RPMB_SERVICE)
__qseecom_disable_clk(CLK_QSEE);
@@ -3267,6 +3286,7 @@ exit:
pr_err("cache operation failed %d\n", ret2);
return ret2;
}
+ __qseecom_processing_pending_lsnr_unregister();
return ret;
}
@@ -3862,7 +3882,7 @@ static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
int ret;
ret = (svc->rcv_req_flag == 1);
- return ret || data->abort || svc->abort;
+ return ret || data->abort;
}
static int qseecom_receive_req(struct qseecom_dev_handle *data)
@@ -3870,14 +3890,14 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data)
int ret = 0;
struct qseecom_registered_listener_list *this_lstnr;
+ mutex_lock(&listener_access_lock);
this_lstnr = __qseecom_find_svc(data->listener.id);
if (!this_lstnr) {
pr_err("Invalid listener ID\n");
+ mutex_unlock(&listener_access_lock);
return -ENODATA;
}
-
- if (this_lstnr->rcv_req_flag == -1)
- this_lstnr->rcv_req_flag = 0;
+ mutex_unlock(&listener_access_lock);
while (1) {
if (wait_event_freezable(this_lstnr->rcv_req_wq,
@@ -3886,16 +3906,17 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data)
pr_warn("Interrupted: exiting Listener Service = %d\n",
(uint32_t)data->listener.id);
/* woken up for different reason */
- this_lstnr->rcv_req_flag = -1;
return -ERESTARTSYS;
}
- if (data->abort || this_lstnr->abort) {
+ if (data->abort) {
pr_err("Aborting Listener Service = %d\n",
(uint32_t)data->listener.id);
return -ENODEV;
}
+ mutex_lock(&listener_access_lock);
this_lstnr->rcv_req_flag = 0;
+ mutex_unlock(&listener_access_lock);
break;
}
return ret;
@@ -4475,6 +4496,8 @@ int qseecom_start_app(struct qseecom_handle **handle,
uint32_t fw_size, app_arch;
uint32_t app_id = 0;
+ __qseecom_processing_pending_lsnr_unregister();
+
if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
pr_err("Not allowed to be called in %d state\n",
atomic_read(&qseecom.qseecom_state));
@@ -4644,6 +4667,8 @@ int qseecom_shutdown_app(struct qseecom_handle **handle)
unsigned long flags = 0;
bool found_handle = false;
+ __qseecom_processing_pending_lsnr_unregister();
+
if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
pr_err("Not allowed to be called in %d state\n",
atomic_read(&qseecom.qseecom_state));
@@ -4692,6 +4717,8 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
struct qseecom_dev_handle *data;
bool perf_enabled = false;
+ __qseecom_processing_pending_lsnr_unregister();
+
if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
pr_err("Not allowed to be called in %d state\n",
atomic_read(&qseecom.qseecom_state));
@@ -7001,6 +7028,11 @@ static inline long qseecom_ioctl(struct file *file,
pr_err("Aborting qseecom driver\n");
return -ENODEV;
}
+ if (cmd != QSEECOM_IOCTL_RECEIVE_REQ &&
+ cmd != QSEECOM_IOCTL_SEND_RESP_REQ &&
+ cmd != QSEECOM_IOCTL_SEND_MODFD_RESP &&
+ cmd != QSEECOM_IOCTL_SEND_MODFD_RESP_64)
+ __qseecom_processing_pending_lsnr_unregister();
switch (cmd) {
case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
@@ -7011,13 +7043,13 @@ static inline long qseecom_ioctl(struct file *file,
break;
}
pr_debug("ioctl register_listener_req()\n");
- mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
data->type = QSEECOM_LISTENER_SERVICE;
ret = qseecom_register_listener(data, argp);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
- mutex_unlock(&app_access_lock);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_register_listener: %d\n", ret);
break;
@@ -7031,14 +7063,12 @@ static inline long qseecom_ioctl(struct file *file,
break;
}
pr_debug("ioctl unregister_listener_req()\n");
- __qseecom_listener_abort_all(1);
- mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
ret = qseecom_unregister_listener(data);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
- mutex_unlock(&app_access_lock);
- __qseecom_listener_abort_all(0);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_unregister_listener: %d\n", ret);
break;
@@ -7193,6 +7223,7 @@ static inline long qseecom_ioctl(struct file *file,
ret = -EINVAL;
break;
}
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
if (!qseecom.qsee_reentrancy_support)
ret = qseecom_send_resp();
@@ -7200,6 +7231,7 @@ static inline long qseecom_ioctl(struct file *file,
ret = qseecom_reentrancy_send_resp(data);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_send_resp: %d\n", ret);
break;
@@ -7535,6 +7567,7 @@ static inline long qseecom_ioctl(struct file *file,
ret = -EINVAL;
break;
}
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
if (cmd == QSEECOM_IOCTL_SEND_MODFD_RESP)
ret = qseecom_send_modfd_resp(data, argp);
@@ -7542,6 +7575,7 @@ static inline long qseecom_ioctl(struct file *file,
ret = qseecom_send_modfd_resp_64(data, argp);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_send_mod_resp: %d\n", ret);
__qseecom_clean_data_sglistinfo(data);
@@ -7699,18 +7733,18 @@ static int qseecom_release(struct inode *inode, struct file *file)
{
struct qseecom_dev_handle *data = file->private_data;
int ret = 0;
+ bool free_private_data = true;
if (data->released == false) {
pr_debug("data: released=false, type=%d, mode=%d, data=0x%pK\n",
data->type, data->mode, data);
switch (data->type) {
case QSEECOM_LISTENER_SERVICE:
- pr_warn("release lsnr svc %d\n", data->listener.id);
- __qseecom_listener_abort_all(1);
- mutex_lock(&app_access_lock);
+ pr_debug("release lsnr svc %d\n", data->listener.id);
+ free_private_data = false;
+ mutex_lock(&listener_access_lock);
ret = qseecom_unregister_listener(data);
- mutex_unlock(&app_access_lock);
- __qseecom_listener_abort_all(0);
+ mutex_unlock(&listener_access_lock);
break;
case QSEECOM_CLIENT_APP:
mutex_lock(&app_access_lock);
@@ -7749,8 +7783,9 @@ static int qseecom_release(struct inode *inode, struct file *file)
if (data->perf_enabled == true)
qsee_disable_clock_vote(data, CLK_DFAB);
}
- kfree(data);
+ if (free_private_data)
+ kfree(data);
return ret;
}
@@ -8577,12 +8612,13 @@ static int qseecom_probe(struct platform_device *pdev)
}
INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
- spin_lock_init(&qseecom.registered_listener_list_lock);
INIT_LIST_HEAD(&qseecom.registered_app_list_head);
spin_lock_init(&qseecom.registered_app_list_lock);
+ INIT_LIST_HEAD(&qseecom.unregister_lsnr_pending_list_head);
INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
spin_lock_init(&qseecom.registered_kclient_list_lock);
init_waitqueue_head(&qseecom.send_resp_wq);
+ init_waitqueue_head(&qseecom.register_lsnr_pending_wq);
qseecom.send_resp_flag = 0;
qseecom.qsee_version = QSEEE_VERSION_00;