Loading drivers/misc/qseecom.c +171 −137 Original line number Diff line number Diff line Loading @@ -154,6 +154,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; Loading Loading @@ -195,7 +197,7 @@ struct qseecom_registered_listener_list { phys_addr_t sb_phys; size_t sb_length; 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; Loading @@ -204,6 +206,12 @@ struct qseecom_registered_listener_list { 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 { Loading Loading @@ -250,7 +258,6 @@ struct qseecom_clk { struct qseecom_control { 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; Loading Loading @@ -298,6 +305,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 { Loading Loading @@ -328,6 +338,7 @@ struct qseecom_client_handle { struct qseecom_listener_handle { u32 id; bool unregister_pending; }; static struct qseecom_control qseecom; Loading Loading @@ -601,13 +612,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; Loading @@ -620,7 +628,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; } Loading Loading @@ -1077,42 +1084,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; } Loading Loading @@ -1327,9 +1310,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) { Loading @@ -1341,18 +1324,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; Loading @@ -1368,44 +1370,19 @@ 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_debug("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; 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; Loading @@ -1415,6 +1392,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; } Loading @@ -1426,7 +1405,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) { Loading @@ -1450,6 +1428,74 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data) 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; Loading Loading @@ -1776,19 +1822,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}; Loading @@ -1799,30 +1838,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); Loading @@ -1848,22 +1880,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*/ Loading @@ -1871,6 +1894,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 Loading @@ -1891,7 +1915,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) { Loading Loading @@ -1944,7 +1968,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) { ret = __qseecom_enable_clk(CLK_QSEE); if (ret) return ret; goto exit; } if (ptr_svc) { Loading Loading @@ -1987,10 +2011,12 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, ret = -EINVAL; } 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; Loading Loading @@ -2043,10 +2069,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; Loading @@ -2062,11 +2090,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); Loading Loading @@ -2099,9 +2129,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; Loading @@ -2123,7 +2155,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}; Loading @@ -2134,30 +2165,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); Loading @@ -2183,22 +2206,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*/ Loading @@ -2208,6 +2222,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, Loading @@ -2218,6 +2233,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; Loading Loading @@ -2270,7 +2286,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd( if (lstnr == RPMB_SERVICE) { ret = __qseecom_enable_clk(CLK_QSEE); if (ret) return ret; goto exit; } if (ptr_svc) { Loading Loading @@ -2332,6 +2348,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd( goto exit; } exit: mutex_unlock(&listener_access_lock); if (lstnr == RPMB_SERVICE) __qseecom_disable_clk(CLK_QSEE); Loading Loading @@ -3379,7 +3396,7 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, QSEECOM_CACHE_INVALIDATE); if (ret) { pr_err("cache operation failed %d\n", ret); return ret; goto exit; } } Loading @@ -3405,6 +3422,7 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, } } exit: __qseecom_processing_pending_lsnr_unregister(); return ret; } Loading Loading @@ -3985,7 +4003,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) Loading @@ -3993,14 +4011,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, Loading @@ -4009,16 +4027,17 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data) pr_debug("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; Loading Loading @@ -4549,6 +4568,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)); Loading Loading @@ -4701,6 +4722,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)); Loading Loading @@ -4752,6 +4775,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)); Loading Loading @@ -7081,6 +7106,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: { Loading @@ -7091,13 +7121,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; Loading @@ -7111,14 +7141,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; Loading Loading @@ -7273,6 +7301,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(); Loading @@ -7280,6 +7309,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; Loading Loading @@ -7615,6 +7645,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); Loading @@ -7622,6 +7653,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); Loading Loading @@ -7803,18 +7835,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); Loading Loading @@ -7854,8 +7886,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; } Loading Loading @@ -8691,12 +8724,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; Loading Loading
drivers/misc/qseecom.c +171 −137 Original line number Diff line number Diff line Loading @@ -154,6 +154,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; Loading Loading @@ -195,7 +197,7 @@ struct qseecom_registered_listener_list { phys_addr_t sb_phys; size_t sb_length; 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; Loading @@ -204,6 +206,12 @@ struct qseecom_registered_listener_list { 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 { Loading Loading @@ -250,7 +258,6 @@ struct qseecom_clk { struct qseecom_control { 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; Loading Loading @@ -298,6 +305,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 { Loading Loading @@ -328,6 +338,7 @@ struct qseecom_client_handle { struct qseecom_listener_handle { u32 id; bool unregister_pending; }; static struct qseecom_control qseecom; Loading Loading @@ -601,13 +612,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; Loading @@ -620,7 +628,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; } Loading Loading @@ -1077,42 +1084,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; } Loading Loading @@ -1327,9 +1310,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) { Loading @@ -1341,18 +1324,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; Loading @@ -1368,44 +1370,19 @@ 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_debug("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; 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; Loading @@ -1415,6 +1392,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; } Loading @@ -1426,7 +1405,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) { Loading @@ -1450,6 +1428,74 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data) 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; Loading Loading @@ -1776,19 +1822,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}; Loading @@ -1799,30 +1838,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); Loading @@ -1848,22 +1880,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*/ Loading @@ -1871,6 +1894,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 Loading @@ -1891,7 +1915,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) { Loading Loading @@ -1944,7 +1968,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) { ret = __qseecom_enable_clk(CLK_QSEE); if (ret) return ret; goto exit; } if (ptr_svc) { Loading Loading @@ -1987,10 +2011,12 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, ret = -EINVAL; } 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; Loading Loading @@ -2043,10 +2069,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; Loading @@ -2062,11 +2090,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); Loading Loading @@ -2099,9 +2129,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; Loading @@ -2123,7 +2155,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}; Loading @@ -2134,30 +2165,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); Loading @@ -2183,22 +2206,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*/ Loading @@ -2208,6 +2222,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, Loading @@ -2218,6 +2233,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; Loading Loading @@ -2270,7 +2286,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd( if (lstnr == RPMB_SERVICE) { ret = __qseecom_enable_clk(CLK_QSEE); if (ret) return ret; goto exit; } if (ptr_svc) { Loading Loading @@ -2332,6 +2348,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd( goto exit; } exit: mutex_unlock(&listener_access_lock); if (lstnr == RPMB_SERVICE) __qseecom_disable_clk(CLK_QSEE); Loading Loading @@ -3379,7 +3396,7 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, QSEECOM_CACHE_INVALIDATE); if (ret) { pr_err("cache operation failed %d\n", ret); return ret; goto exit; } } Loading @@ -3405,6 +3422,7 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, } } exit: __qseecom_processing_pending_lsnr_unregister(); return ret; } Loading Loading @@ -3985,7 +4003,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) Loading @@ -3993,14 +4011,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, Loading @@ -4009,16 +4027,17 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data) pr_debug("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; Loading Loading @@ -4549,6 +4568,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)); Loading Loading @@ -4701,6 +4722,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)); Loading Loading @@ -4752,6 +4775,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)); Loading Loading @@ -7081,6 +7106,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: { Loading @@ -7091,13 +7121,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; Loading @@ -7111,14 +7141,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; Loading Loading @@ -7273,6 +7301,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(); Loading @@ -7280,6 +7309,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; Loading Loading @@ -7615,6 +7645,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); Loading @@ -7622,6 +7653,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); Loading Loading @@ -7803,18 +7835,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); Loading Loading @@ -7854,8 +7886,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; } Loading Loading @@ -8691,12 +8724,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; Loading