Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ebb15786 authored by Zhen Kong's avatar Zhen Kong Committed by Niranjan Reddy Dumbala
Browse files

qseecom: listener unregister and register optimization



Optimize listener unregister and register operations to avoid
deadlock and xpu violation.

Change-Id: Ic1af4ad60abe2422aa133f72c0523074ed7cdc5a
Signed-off-by: default avatarZhen Kong <zkong@codeaurora.org>
parent b5a18661
Loading
Loading
Loading
Loading
+171 −137
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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 {
@@ -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;
@@ -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 {
@@ -328,6 +338,7 @@ struct qseecom_client_handle {

struct qseecom_listener_handle {
	u32               id;
	bool              unregister_pending;
};

static struct qseecom_control qseecom;
@@ -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;
@@ -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;
		}
@@ -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;
	}

@@ -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) {
@@ -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;
@@ -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;
@@ -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;
	}

@@ -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) {
@@ -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;
@@ -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};
@@ -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);
@@ -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*/
@@ -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
@@ -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) {
@@ -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) {
@@ -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;

@@ -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;
@@ -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);
@@ -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;
@@ -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};
@@ -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);
@@ -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*/
@@ -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,
@@ -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;

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

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

@@ -3405,6 +3422,7 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
		}
	}
exit:
	__qseecom_processing_pending_lsnr_unregister();
	return ret;
}

@@ -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)
@@ -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,
@@ -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;
@@ -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));
@@ -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));
@@ -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));
@@ -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: {
@@ -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;
@@ -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;
@@ -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();
@@ -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;
@@ -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);
@@ -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);
@@ -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);
@@ -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;
}

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