diff options
author | Zhen Kong <zkong@codeaurora.org> | 2018-11-16 13:50:51 -0800 |
---|---|---|
committer | Craft Ju <craftju@google.com> | 2019-05-29 06:22:16 +0000 |
commit | 652759d40757197bdb78adfb1c06902a19525a3e (patch) | |
tree | cd63edf657708a9bb7b48b37350398cd6f3b79dc | |
parent | 86c9d191d40be47f15b367b2fecffc8f6cdc6ab6 (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.c | 312 |
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; |