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

Commit 28871758 authored by Zhen Kong's avatar Zhen Kong
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 3ae2f21f
Loading
Loading
Loading
Loading
+174 −138
Original line number Original line Diff line number Diff line
@@ -143,6 +143,8 @@ static dev_t qseecom_device_no;
static DEFINE_MUTEX(qsee_bw_mutex);
static DEFINE_MUTEX(qsee_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
static DEFINE_MUTEX(app_access_lock);
static DEFINE_MUTEX(clk_access_lock);
static DEFINE_MUTEX(clk_access_lock);
static DEFINE_MUTEX(listener_access_lock);



struct sglist_info {
struct sglist_info {
	uint32_t indexAndFlags;
	uint32_t indexAndFlags;
@@ -182,7 +184,7 @@ struct qseecom_registered_listener_list {
	size_t sb_length;
	size_t sb_length;
	struct ion_handle *ihandle; /* Retrieve phy addr */
	struct ion_handle *ihandle; /* Retrieve phy addr */
	wait_queue_head_t          rcv_req_wq;
	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                        rcv_req_flag;
	int                        send_resp_flag;
	int                        send_resp_flag;
	bool                       listener_in_use;
	bool                       listener_in_use;
@@ -191,6 +193,12 @@ struct qseecom_registered_listener_list {
	struct sglist_info         sglistinfo_ptr[MAX_ION_FD];
	struct sglist_info         sglistinfo_ptr[MAX_ION_FD];
	uint32_t                   sglist_cnt;
	uint32_t                   sglist_cnt;
	int                        abort;
	int                        abort;
	bool                       unregister_pending;
};

struct qseecom_unregister_pending_list {
	struct list_head		list;
	struct qseecom_dev_handle	*data;
};
};


struct qseecom_registered_app_list {
struct qseecom_registered_app_list {
@@ -238,7 +246,6 @@ struct qseecom_clk {
struct qseecom_control {
struct qseecom_control {
	struct ion_client *ion_clnt;		/* Ion client */
	struct ion_client *ion_clnt;		/* Ion client */
	struct list_head  registered_listener_list_head;
	struct list_head  registered_listener_list_head;
	spinlock_t        registered_listener_list_lock;


	struct list_head  registered_app_list_head;
	struct list_head  registered_app_list_head;
	spinlock_t        registered_app_list_lock;
	spinlock_t        registered_app_list_lock;
@@ -284,6 +291,9 @@ struct qseecom_control {
	atomic_t qseecom_state;
	atomic_t qseecom_state;
	int is_apps_region_protected;
	int is_apps_region_protected;
	bool smcinvoke_support;
	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 {
struct qseecom_sec_buf_fd_info {
@@ -312,6 +322,7 @@ struct qseecom_client_handle {


struct qseecom_listener_handle {
struct qseecom_listener_handle {
	u32               id;
	u32               id;
	bool              unregister_pending;
};
};


static struct qseecom_control qseecom;
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;
			qseecom.smcinvoke_support = true;
			smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID;
			smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID;
			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
			ret = scm_call2(smc_id, &desc);
			ret = scm_call2(smc_id, &desc);
			if (ret) {
			if (ret && ret != -EBUSY) {
				qseecom.smcinvoke_support = false;
				qseecom.smcinvoke_support = false;
				smc_id = TZ_OS_REGISTER_LISTENER_ID;
				smc_id = TZ_OS_REGISTER_LISTENER_ID;
				__qseecom_reentrancy_check_if_no_app_blocked(
					smc_id);
				ret = scm_call2(smc_id, &desc);
				ret = scm_call2(smc_id, &desc);
			}
			}
			break;
			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;
			smc_id = TZ_OS_DEREGISTER_LISTENER_ID;
			desc.arginfo = TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID;
			desc.arginfo = TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID;
			desc.args[0] = req->listener_id;
			desc.args[0] = req->listener_id;
			__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
			ret = scm_call2(smc_id, &desc);
			ret = scm_call2(smc_id, &desc);
			break;
			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);
		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(
static struct qseecom_registered_listener_list *__qseecom_find_svc(
						int32_t listener_id)
						int32_t listener_id)
{
{
	struct qseecom_registered_listener_list *entry = NULL;
	struct qseecom_registered_listener_list *entry = NULL;
	unsigned long flags;


	spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
	list_for_each_entry(entry,
	list_for_each_entry(entry,
			&qseecom.registered_listener_list_head, list) {
			&qseecom.registered_listener_list_head, list) {
		if (entry->svc.listener_id == listener_id)
		if (entry->svc.listener_id == listener_id)
			break;
			break;
	}
	}
	spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);

	if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
	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;
		return NULL;
	}
	}


@@ -1179,9 +1162,9 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
					void __user *argp)
					void __user *argp)
{
{
	int ret = 0;
	int ret = 0;
	unsigned long flags;
	struct qseecom_register_listener_req rcvd_lstnr;
	struct qseecom_register_listener_req rcvd_lstnr;
	struct qseecom_registered_listener_list *new_entry;
	struct qseecom_registered_listener_list *new_entry;
	struct qseecom_registered_listener_list *ptr_svc;


	ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
	ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
	if (ret) {
	if (ret) {
@@ -1193,18 +1176,37 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
		return -EFAULT;
		return -EFAULT;


	data->listener.id = rcvd_lstnr.listener_id;
	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);
				rcvd_lstnr.listener_id);
		data->released = true;
		data->released = true;
		return -EBUSY;
		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);
	new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
	if (!new_entry)
	if (!new_entry)
		return -ENOMEM;
		return -ENOMEM;
	memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
	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->svc.listener_id = rcvd_lstnr.listener_id;
	new_entry->sb_length = rcvd_lstnr.sb_size;
	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);
	init_waitqueue_head(&new_entry->listener_block_app_wq);
	new_entry->send_resp_flag = 0;
	new_entry->send_resp_flag = 0;
	new_entry->listener_in_use = false;
	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);
	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);
	pr_warn("Service %d is registered\n", rcvd_lstnr.listener_id);
	return ret;
	return ret;
}
}


static void __qseecom_listener_abort_all(int abort)
static int __qseecom_unregister_listener(struct qseecom_dev_handle *data,
{
			struct qseecom_registered_listener_list *ptr_svc)
	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)
{
{
	int ret = 0;
	int ret = 0;
	struct qseecom_register_listener_ireq req;
	struct qseecom_register_listener_ireq req;
	struct qseecom_registered_listener_list *ptr_svc = NULL;
	struct qseecom_command_scm_resp resp;
	struct qseecom_command_scm_resp resp;
	struct ion_handle *ihandle = NULL;		/* Retrieve phy addr */
	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.qsee_cmd_id = QSEOS_DEREGISTER_LISTENER;
	req.listener_id = data->listener.id;
	req.listener_id = data->listener.id;
	resp.result = QSEOS_RESULT_INCOMPLETE;
	resp.result = QSEOS_RESULT_INCOMPLETE;
@@ -1268,6 +1245,8 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
	if (ret) {
	if (ret) {
		pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
		pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
				ret, data->listener.id);
				ret, data->listener.id);
		if (ret == -EBUSY)
			return ret;
		goto exit;
		goto exit;
	}
	}


@@ -1279,7 +1258,6 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
	}
	}


	data->abort = 1;
	data->abort = 1;
	ptr_svc->abort = 1;
	wake_up_all(&ptr_svc->rcv_req_wq);
	wake_up_all(&ptr_svc->rcv_req_wq);


	while (atomic_read(&data->ioctl_count) > 1) {
	while (atomic_read(&data->ioctl_count) > 1) {
@@ -1306,6 +1284,74 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
	return ret;
	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)
static int __qseecom_set_msm_bus_request(uint32_t mode)
{
{
	int ret = 0;
	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,
static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
					struct qseecom_command_scm_resp *resp)
					struct qseecom_command_scm_resp *resp)
{
{
	int ret = 0;
	int ret = 0;
	int rc = 0;
	int rc = 0;
	uint32_t lstnr;
	uint32_t lstnr;
	unsigned long flags;
	struct qseecom_client_listener_data_irsp send_data_rsp = {0};
	struct qseecom_client_listener_data_irsp send_data_rsp = {0};
	struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
	struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
									= {0};
									= {0};
@@ -1663,30 +1702,23 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
	void *cmd_buf = NULL;
	void *cmd_buf = NULL;
	size_t cmd_len;
	size_t cmd_len;
	struct sglist_info *table = NULL;
	struct sglist_info *table = NULL;
	bool not_ready = false;


	qseecom.app_block_ref_cnt++;
	while (resp->result == QSEOS_RESULT_INCOMPLETE) {
	while (resp->result == QSEOS_RESULT_INCOMPLETE) {
		lstnr = resp->data;
		lstnr = resp->data;
		/*
		/*
		 * Wake up blocking lsitener service with the lstnr id
		 * Wake up blocking lsitener service with the lstnr id
		 */
		 */
		spin_lock_irqsave(&qseecom.registered_listener_list_lock,
		mutex_lock(&listener_access_lock);
					flags);
		list_for_each_entry(ptr_svc,
		list_for_each_entry(ptr_svc,
				&qseecom.registered_listener_list_head, list) {
				&qseecom.registered_listener_list_head, list) {
			if (ptr_svc->svc.listener_id == lstnr) {
			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->listener_in_use = true;
				ptr_svc->rcv_req_flag = 1;
				ptr_svc->rcv_req_flag = 1;
				wake_up_interruptible(&ptr_svc->rcv_req_wq);
				wake_up_interruptible(&ptr_svc->rcv_req_wq);
				break;
				break;
			}
			}
		}
		}
		spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
				flags);


		if (ptr_svc == NULL) {
		if (ptr_svc == NULL) {
			pr_err("Listener Svc %d does not exist\n", lstnr);
			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) {
		if (ptr_svc->abort == 1) {
			pr_err("Service %d abort %d\n",
			pr_debug("Service %d abort %d\n",
						lstnr, ptr_svc->abort);
						lstnr, ptr_svc->abort);
			rc = -ENODEV;
			rc = -ENODEV;
			status = QSEOS_RESULT_FAILURE;
			status = QSEOS_RESULT_FAILURE;
			goto err_resp;
			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");
		pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");


		/* initialize the new signal mask with all signals*/
		/* 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 */
		/* block all signals */
		sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
		sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);


		mutex_unlock(&listener_access_lock);
		do {
		do {
			/*
			/*
			 * When reentrancy is not supported, check global
			 * When reentrancy is not supported, check global
@@ -1755,7 +1779,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
				break;
				break;
			}
			}
		} while (1);
		} while (1);

		mutex_lock(&listener_access_lock);
		/* restore signal mask */
		/* restore signal mask */
		sigprocmask(SIG_SETMASK, &old_sigset, NULL);
		sigprocmask(SIG_SETMASK, &old_sigset, NULL);
		if (data->abort || ptr_svc->abort) {
		if (data->abort || ptr_svc->abort) {
@@ -1811,14 +1835,14 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
					ION_IOC_CLEAN_INV_CACHES);
					ION_IOC_CLEAN_INV_CACHES);
			if (ret) {
			if (ret) {
				pr_err("cache operation failed %d\n", ret);
				pr_err("cache operation failed %d\n", ret);
				return ret;
				goto exit;
			}
			}
		}
		}


		if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) {
		if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) {
			ret = __qseecom_enable_clk(CLK_QSEE);
			ret = __qseecom_enable_clk(CLK_QSEE);
			if (ret)
			if (ret)
				return ret;
				goto exit;
		}
		}


		ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
		ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
@@ -1832,7 +1856,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
				ret, data->client.app_id);
				ret, data->client.app_id);
			if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
			if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
				__qseecom_disable_clk(CLK_QSEE);
				__qseecom_disable_clk(CLK_QSEE);
			return ret;
			goto exit;
		}
		}
		pr_debug("resp status %d, res= %d, app_id = %d, lstr = %d\n",
		pr_debug("resp status %d, res= %d, app_id = %d, lstr = %d\n",
			status, resp->result, data->client.app_id, lstnr);
			status, resp->result, data->client.app_id, lstnr);
@@ -1841,11 +1865,15 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
			pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
			pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
				resp->result, data->client.app_id, lstnr);
				resp->result, data->client.app_id, lstnr);
			ret = -EINVAL;
			ret = -EINVAL;
			goto exit;
		}
		}
exit:
		mutex_unlock(&listener_access_lock);
		if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
		if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
			__qseecom_disable_clk(CLK_QSEE);
			__qseecom_disable_clk(CLK_QSEE);


	}
	}
	qseecom.app_block_ref_cnt--;
	if (rc)
	if (rc)
		return rc;
		return rc;


@@ -1898,10 +1926,12 @@ static int __qseecom_process_reentrancy_blocked_on_listener(


	do {
	do {
		session_id = resp->resp_type;
		session_id = resp->resp_type;
		mutex_lock(&listener_access_lock);
		list_ptr = __qseecom_find_svc(resp->data);
		list_ptr = __qseecom_find_svc(resp->data);
		if (!list_ptr) {
		if (!list_ptr) {
			pr_err("Invalid listener ID %d\n", resp->data);
			pr_err("Invalid listener ID %d\n", resp->data);
			ret = -ENODATA;
			ret = -ENODATA;
			mutex_unlock(&listener_access_lock);
			goto exit;
			goto exit;
		}
		}
		ptr_app->blocked_on_listener_id = resp->data;
		ptr_app->blocked_on_listener_id = resp->data;
@@ -1917,11 +1947,13 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
		do {
		do {
			qseecom.app_block_ref_cnt++;
			qseecom.app_block_ref_cnt++;
			ptr_app->app_blocked = true;
			ptr_app->app_blocked = true;
			mutex_unlock(&listener_access_lock);
			mutex_unlock(&app_access_lock);
			mutex_unlock(&app_access_lock);
			wait_event_freezable(
			wait_event_freezable(
				list_ptr->listener_block_app_wq,
				list_ptr->listener_block_app_wq,
				!list_ptr->listener_in_use);
				!list_ptr->listener_in_use);
			mutex_lock(&app_access_lock);
			mutex_lock(&app_access_lock);
			mutex_lock(&listener_access_lock);
			ptr_app->app_blocked = false;
			ptr_app->app_blocked = false;
			qseecom.app_block_ref_cnt--;
			qseecom.app_block_ref_cnt--;
		}  while (list_ptr->listener_in_use);
		}  while (list_ptr->listener_in_use);
@@ -1954,9 +1986,11 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
			if (ret) {
			if (ret) {
				pr_err("unblock app %d or session %d fail\n",
				pr_err("unblock app %d or session %d fail\n",
					data->client.app_id, session_id);
					data->client.app_id, session_id);
				mutex_unlock(&listener_access_lock);
				goto exit;
				goto exit;
			}
			}
		}
		}
		mutex_unlock(&listener_access_lock);
		resp->result = continue_resp.result;
		resp->result = continue_resp.result;
		resp->resp_type = continue_resp.resp_type;
		resp->resp_type = continue_resp.resp_type;
		resp->data = continue_resp.data;
		resp->data = continue_resp.data;
@@ -1978,7 +2012,6 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
	int ret = 0;
	int ret = 0;
	int rc = 0;
	int rc = 0;
	uint32_t lstnr;
	uint32_t lstnr;
	unsigned long flags;
	struct qseecom_client_listener_data_irsp send_data_rsp = {0};
	struct qseecom_client_listener_data_irsp send_data_rsp = {0};
	struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
	struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
									= {0};
									= {0};
@@ -1989,30 +2022,22 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
	void *cmd_buf = NULL;
	void *cmd_buf = NULL;
	size_t cmd_len;
	size_t cmd_len;
	struct sglist_info *table = NULL;
	struct sglist_info *table = NULL;
	bool not_ready = false;


	while (ret == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) {
	while (ret == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) {
		lstnr = resp->data;
		lstnr = resp->data;
		/*
		/*
		 * Wake up blocking lsitener service with the lstnr id
		 * Wake up blocking lsitener service with the lstnr id
		 */
		 */
		spin_lock_irqsave(&qseecom.registered_listener_list_lock,
		mutex_lock(&listener_access_lock);
					flags);
		list_for_each_entry(ptr_svc,
		list_for_each_entry(ptr_svc,
				&qseecom.registered_listener_list_head, list) {
				&qseecom.registered_listener_list_head, list) {
			if (ptr_svc->svc.listener_id == lstnr) {
			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->listener_in_use = true;
				ptr_svc->rcv_req_flag = 1;
				ptr_svc->rcv_req_flag = 1;
				wake_up_interruptible(&ptr_svc->rcv_req_wq);
				wake_up_interruptible(&ptr_svc->rcv_req_wq);
				break;
				break;
			}
			}
		}
		}
		spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
				flags);


		if (ptr_svc == NULL) {
		if (ptr_svc == NULL) {
			pr_err("Listener Svc %d does not exist\n", lstnr);
			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) {
		if (ptr_svc->abort == 1) {
			pr_err("Service %d abort %d\n",
			pr_debug("Service %d abort %d\n",
						lstnr, ptr_svc->abort);
						lstnr, ptr_svc->abort);
			rc = -ENODEV;
			rc = -ENODEV;
			status = QSEOS_RESULT_FAILURE;
			status = QSEOS_RESULT_FAILURE;
			goto err_resp;
			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");
		pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");


		/* initialize the new signal mask with all signals*/
		/* 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);
		sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);


		/* unlock mutex btw waking listener and sleep-wait */
		/* unlock mutex btw waking listener and sleep-wait */
		mutex_unlock(&listener_access_lock);
		mutex_unlock(&app_access_lock);
		mutex_unlock(&app_access_lock);
		do {
		do {
			if (!wait_event_freezable(qseecom.send_resp_wq,
			if (!wait_event_freezable(qseecom.send_resp_wq,
@@ -2073,6 +2090,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
		} while (1);
		} while (1);
		/* lock mutex again after resp sent */
		/* lock mutex again after resp sent */
		mutex_lock(&app_access_lock);
		mutex_lock(&app_access_lock);
		mutex_lock(&listener_access_lock);
		ptr_svc->send_resp_flag = 0;
		ptr_svc->send_resp_flag = 0;
		qseecom.send_resp_flag = 0;
		qseecom.send_resp_flag = 0;


@@ -2134,7 +2152,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
		if (lstnr == RPMB_SERVICE) {
		if (lstnr == RPMB_SERVICE) {
			ret = __qseecom_enable_clk(CLK_QSEE);
			ret = __qseecom_enable_clk(CLK_QSEE);
			if (ret)
			if (ret)
				return ret;
				goto exit;
		}
		}


		ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
		ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
@@ -2179,6 +2197,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
			goto exit;
			goto exit;
		}
		}
exit:
exit:
		mutex_unlock(&listener_access_lock);
		if (lstnr == RPMB_SERVICE)
		if (lstnr == RPMB_SERVICE)
			__qseecom_disable_clk(CLK_QSEE);
			__qseecom_disable_clk(CLK_QSEE);


@@ -3267,6 +3286,7 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
		pr_err("cache operation failed %d\n", ret2);
		pr_err("cache operation failed %d\n", ret2);
		return ret2;
		return ret2;
	}
	}
	__qseecom_processing_pending_lsnr_unregister();
	return ret;
	return ret;
}
}


@@ -3862,7 +3882,7 @@ static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
	int ret;
	int ret;


	ret = (svc->rcv_req_flag == 1);
	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)
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;
	int ret = 0;
	struct qseecom_registered_listener_list *this_lstnr;
	struct qseecom_registered_listener_list *this_lstnr;


	mutex_lock(&listener_access_lock);
	this_lstnr = __qseecom_find_svc(data->listener.id);
	this_lstnr = __qseecom_find_svc(data->listener.id);
	if (!this_lstnr) {
	if (!this_lstnr) {
		pr_err("Invalid listener ID\n");
		pr_err("Invalid listener ID\n");
		mutex_unlock(&listener_access_lock);
		return -ENODATA;
		return -ENODATA;
	}
	}

	mutex_unlock(&listener_access_lock);
	if (this_lstnr->rcv_req_flag == -1)
		this_lstnr->rcv_req_flag = 0;


	while (1) {
	while (1) {
		if (wait_event_freezable(this_lstnr->rcv_req_wq,
		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",
			pr_warn("Interrupted: exiting Listener Service = %d\n",
						(uint32_t)data->listener.id);
						(uint32_t)data->listener.id);
			/* woken up for different reason */
			/* woken up for different reason */
			this_lstnr->rcv_req_flag = -1;
			return -ERESTARTSYS;
			return -ERESTARTSYS;
		}
		}


		if (data->abort || this_lstnr->abort) {
		if (data->abort) {
			pr_err("Aborting Listener Service = %d\n",
			pr_err("Aborting Listener Service = %d\n",
					(uint32_t)data->listener.id);
					(uint32_t)data->listener.id);
			return -ENODEV;
			return -ENODEV;
		}
		}
		mutex_lock(&listener_access_lock);
		this_lstnr->rcv_req_flag = 0;
		this_lstnr->rcv_req_flag = 0;
		mutex_unlock(&listener_access_lock);
		break;
		break;
	}
	}
	return ret;
	return ret;
@@ -4482,6 +4503,8 @@ int qseecom_start_app(struct qseecom_handle **handle,
	uint32_t fw_size, app_arch;
	uint32_t fw_size, app_arch;
	uint32_t app_id = 0;
	uint32_t app_id = 0;


	__qseecom_processing_pending_lsnr_unregister();

	if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
	if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
		pr_err("Not allowed to be called in %d state\n",
		pr_err("Not allowed to be called in %d state\n",
				atomic_read(&qseecom.qseecom_state));
				atomic_read(&qseecom.qseecom_state));
@@ -4655,6 +4678,8 @@ int qseecom_shutdown_app(struct qseecom_handle **handle)
	unsigned long flags = 0;
	unsigned long flags = 0;
	bool found_handle = false;
	bool found_handle = false;


	__qseecom_processing_pending_lsnr_unregister();

	if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
	if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
		pr_err("Not allowed to be called in %d state\n",
		pr_err("Not allowed to be called in %d state\n",
				atomic_read(&qseecom.qseecom_state));
				atomic_read(&qseecom.qseecom_state));
@@ -4703,6 +4728,8 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
	struct qseecom_dev_handle *data;
	struct qseecom_dev_handle *data;
	bool perf_enabled = false;
	bool perf_enabled = false;


	__qseecom_processing_pending_lsnr_unregister();

	if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
	if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
		pr_err("Not allowed to be called in %d state\n",
		pr_err("Not allowed to be called in %d state\n",
				atomic_read(&qseecom.qseecom_state));
				atomic_read(&qseecom.qseecom_state));
@@ -7012,6 +7039,11 @@ static inline long qseecom_ioctl(struct file *file,
		pr_err("Aborting qseecom driver\n");
		pr_err("Aborting qseecom driver\n");
		return -ENODEV;
		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) {
	switch (cmd) {
	case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
	case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
@@ -7022,13 +7054,13 @@ static inline long qseecom_ioctl(struct file *file,
			break;
			break;
		}
		}
		pr_debug("ioctl register_listener_req()\n");
		pr_debug("ioctl register_listener_req()\n");
		mutex_lock(&app_access_lock);
		mutex_lock(&listener_access_lock);
		atomic_inc(&data->ioctl_count);
		atomic_inc(&data->ioctl_count);
		data->type = QSEECOM_LISTENER_SERVICE;
		data->type = QSEECOM_LISTENER_SERVICE;
		ret = qseecom_register_listener(data, argp);
		ret = qseecom_register_listener(data, argp);
		atomic_dec(&data->ioctl_count);
		atomic_dec(&data->ioctl_count);
		wake_up_all(&data->abort_wq);
		wake_up_all(&data->abort_wq);
		mutex_unlock(&app_access_lock);
		mutex_unlock(&listener_access_lock);
		if (ret)
		if (ret)
			pr_err("failed qseecom_register_listener: %d\n", ret);
			pr_err("failed qseecom_register_listener: %d\n", ret);
		break;
		break;
@@ -7054,14 +7086,12 @@ static inline long qseecom_ioctl(struct file *file,
			break;
			break;
		}
		}
		pr_debug("ioctl unregister_listener_req()\n");
		pr_debug("ioctl unregister_listener_req()\n");
		__qseecom_listener_abort_all(1);
		mutex_lock(&listener_access_lock);
		mutex_lock(&app_access_lock);
		atomic_inc(&data->ioctl_count);
		atomic_inc(&data->ioctl_count);
		ret = qseecom_unregister_listener(data);
		ret = qseecom_unregister_listener(data);
		atomic_dec(&data->ioctl_count);
		atomic_dec(&data->ioctl_count);
		wake_up_all(&data->abort_wq);
		wake_up_all(&data->abort_wq);
		mutex_unlock(&app_access_lock);
		mutex_unlock(&listener_access_lock);
		__qseecom_listener_abort_all(0);
		if (ret)
		if (ret)
			pr_err("failed qseecom_unregister_listener: %d\n", ret);
			pr_err("failed qseecom_unregister_listener: %d\n", ret);
		break;
		break;
@@ -7216,6 +7246,7 @@ static inline long qseecom_ioctl(struct file *file,
			ret = -EINVAL;
			ret = -EINVAL;
			break;
			break;
		}
		}
		mutex_lock(&listener_access_lock);
		atomic_inc(&data->ioctl_count);
		atomic_inc(&data->ioctl_count);
		if (!qseecom.qsee_reentrancy_support)
		if (!qseecom.qsee_reentrancy_support)
			ret = qseecom_send_resp();
			ret = qseecom_send_resp();
@@ -7223,6 +7254,7 @@ static inline long qseecom_ioctl(struct file *file,
			ret = qseecom_reentrancy_send_resp(data);
			ret = qseecom_reentrancy_send_resp(data);
		atomic_dec(&data->ioctl_count);
		atomic_dec(&data->ioctl_count);
		wake_up_all(&data->abort_wq);
		wake_up_all(&data->abort_wq);
		mutex_unlock(&listener_access_lock);
		if (ret)
		if (ret)
			pr_err("failed qseecom_send_resp: %d\n", ret);
			pr_err("failed qseecom_send_resp: %d\n", ret);
		break;
		break;
@@ -7558,6 +7590,7 @@ static inline long qseecom_ioctl(struct file *file,
			ret = -EINVAL;
			ret = -EINVAL;
			break;
			break;
		}
		}
		mutex_lock(&listener_access_lock);
		atomic_inc(&data->ioctl_count);
		atomic_inc(&data->ioctl_count);
		if (cmd == QSEECOM_IOCTL_SEND_MODFD_RESP)
		if (cmd == QSEECOM_IOCTL_SEND_MODFD_RESP)
			ret = qseecom_send_modfd_resp(data, argp);
			ret = qseecom_send_modfd_resp(data, argp);
@@ -7565,6 +7598,7 @@ static inline long qseecom_ioctl(struct file *file,
			ret = qseecom_send_modfd_resp_64(data, argp);
			ret = qseecom_send_modfd_resp_64(data, argp);
		atomic_dec(&data->ioctl_count);
		atomic_dec(&data->ioctl_count);
		wake_up_all(&data->abort_wq);
		wake_up_all(&data->abort_wq);
		mutex_unlock(&listener_access_lock);
		if (ret)
		if (ret)
			pr_err("failed qseecom_send_mod_resp: %d\n", ret);
			pr_err("failed qseecom_send_mod_resp: %d\n", ret);
		__qseecom_clean_data_sglistinfo(data);
		__qseecom_clean_data_sglistinfo(data);
@@ -7722,18 +7756,18 @@ static int qseecom_release(struct inode *inode, struct file *file)
{
{
	struct qseecom_dev_handle *data = file->private_data;
	struct qseecom_dev_handle *data = file->private_data;
	int ret = 0;
	int ret = 0;
	bool free_private_data = true;


	if (data->released == false) {
	if (data->released == false) {
		pr_debug("data: released=false, type=%d, mode=%d, data=0x%pK\n",
		pr_debug("data: released=false, type=%d, mode=%d, data=0x%pK\n",
			data->type, data->mode, data);
			data->type, data->mode, data);
		switch (data->type) {
		switch (data->type) {
		case QSEECOM_LISTENER_SERVICE:
		case QSEECOM_LISTENER_SERVICE:
			pr_warn("release lsnr svc %d\n", data->listener.id);
			pr_debug("release lsnr svc %d\n", data->listener.id);
			__qseecom_listener_abort_all(1);
			free_private_data = false;
			mutex_lock(&app_access_lock);
			mutex_lock(&listener_access_lock);
			ret = qseecom_unregister_listener(data);
			ret = qseecom_unregister_listener(data);
			mutex_unlock(&app_access_lock);
			mutex_unlock(&listener_access_lock);
			__qseecom_listener_abort_all(0);
			break;
			break;
		case QSEECOM_CLIENT_APP:
		case QSEECOM_CLIENT_APP:
			mutex_lock(&app_access_lock);
			mutex_lock(&app_access_lock);
@@ -7772,8 +7806,9 @@ static int qseecom_release(struct inode *inode, struct file *file)
		if (data->perf_enabled == true)
		if (data->perf_enabled == true)
			qsee_disable_clock_vote(data, CLK_DFAB);
			qsee_disable_clock_vote(data, CLK_DFAB);
	}
	}
	kfree(data);


	if (free_private_data)
		kfree(data);
	return ret;
	return ret;
}
}


@@ -8600,12 +8635,13 @@ static int qseecom_probe(struct platform_device *pdev)
	}
	}


	INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
	INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
	spin_lock_init(&qseecom.registered_listener_list_lock);
	INIT_LIST_HEAD(&qseecom.registered_app_list_head);
	INIT_LIST_HEAD(&qseecom.registered_app_list_head);
	spin_lock_init(&qseecom.registered_app_list_lock);
	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);
	INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
	spin_lock_init(&qseecom.registered_kclient_list_lock);
	spin_lock_init(&qseecom.registered_kclient_list_lock);
	init_waitqueue_head(&qseecom.send_resp_wq);
	init_waitqueue_head(&qseecom.send_resp_wq);
	init_waitqueue_head(&qseecom.register_lsnr_pending_wq);
	qseecom.send_resp_flag = 0;
	qseecom.send_resp_flag = 0;


	qseecom.qsee_version = QSEEE_VERSION_00;
	qseecom.qsee_version = QSEEE_VERSION_00;