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

Commit b69feebe authored by Prerna Kalla's avatar Prerna Kalla
Browse files

msm: ice: check for crypto engine state before processing request



Crypto engine can be put to suspend by host controller after workqueue
is scheduled. Also shutdown sequence can  be ongoing while workqueue is
scheduled / executing. The request passed to crypto driver in these
cases can be invalidated by host  device driver.  So check for crypto
engine state before processing  the pending requests.

Change-Id: I92b926e4963af86780e92e21a592106ef38a4624
Signed-off-by: default avatarPrerna Kalla <prernak@codeaurora.org>
parent dc9a2b8f
Loading
Loading
Loading
Loading
+42 −7
Original line number Diff line number Diff line
@@ -26,7 +26,8 @@
#include <soc/qcom/qseecomi.h>
#include "iceregs.h"
#include <linux/pfk.h>

#include <linux/atomic.h>
#include <linux/wait.h>

#define TZ_SYSCALL_CREATE_SMC_ID(o, s, f) \
	((uint32_t)((((o & 0x3f) << 24) | (s & 0xff) << 8) | (f & 0xff)))
@@ -114,6 +115,9 @@ struct ice_device {
	struct qcom_ice_bus_vote bus_vote;
	ktime_t			ice_reset_start_time;
	ktime_t			ice_reset_complete_time;
	atomic_t		is_ice_suspended;
	atomic_t		is_ice_busy;
	wait_queue_head_t	block_suspend_ice_queue;
};

static int qti_ice_setting_config(struct request *req,
@@ -807,7 +811,6 @@ static int qcom_ice_probe(struct platform_device *pdev)
	 * operation arrives.
	 */
	ice_dev->is_ice_enabled = false;

	platform_set_drvdata(pdev, ice_dev);
	list_add_tail(&ice_dev->list, &ice_devices);

@@ -842,6 +845,21 @@ static int qcom_ice_remove(struct platform_device *pdev)

static int  qcom_ice_suspend(struct platform_device *pdev)
{
	struct ice_device *ice_dev;

	ice_dev = (struct ice_device *)platform_get_drvdata(pdev);

	if (!ice_dev)
		return -EINVAL;

	if (atomic_read(&ice_dev->is_ice_busy) != 0)
		wait_event_interruptible_timeout(
			ice_dev->block_suspend_ice_queue,
			atomic_read(&ice_dev->is_ice_busy) != 0,
			msecs_to_jiffies(1000));

	atomic_set(&ice_dev->is_ice_suspended, 1);

	return 0;
}

@@ -1095,7 +1113,7 @@ static int qcom_ice_finish_init(struct ice_device *ice_dev)
		err = -EFAULT;
		goto out;
	}

	init_waitqueue_head(&ice_dev->block_suspend_ice_queue);
	qcom_ice_low_power_mode_enable(ice_dev);
	qcom_ice_optimization_enable(ice_dev);
	qcom_ice_config_proc_ignore(ice_dev);
@@ -1103,7 +1121,8 @@ static int qcom_ice_finish_init(struct ice_device *ice_dev)
	qcom_ice_enable(ice_dev);
	ice_dev->is_ice_enabled = true;
	qcom_ice_enable_intr(ice_dev);

	atomic_set(&ice_dev->is_ice_suspended, 0);
	atomic_set(&ice_dev->is_ice_busy, 0);
out:
	return err;
}
@@ -1200,7 +1219,6 @@ static int qcom_ice_resume(struct platform_device *pdev)
	 * after receiving this event
	 */
	struct ice_device *ice_dev;

	ice_dev = platform_get_drvdata(pdev);

	if (!ice_dev)
@@ -1214,7 +1232,7 @@ static int qcom_ice_resume(struct platform_device *pdev)
		 */
		qcom_ice_enable(ice_dev);
	}

	atomic_set(&ice_dev->is_ice_suspended, 0);
	return 0;
}

@@ -1456,11 +1474,18 @@ static int qcom_ice_config_start(struct platform_device *pdev,
	bool is_pfe = false;
	unsigned long sec_end = 0;
	sector_t data_size;
	struct ice_device *ice_dev;

	if (!pdev || !req) {
		pr_err("%s: Invalid params passed\n", __func__);
		return -EINVAL;
	}
	ice_dev = platform_get_drvdata(pdev);

	if (!ice_dev) {
		pr_err("%s: INVALID ice_dev\n", __func__);
		return -EINVAL;
	}

	/*
	 * It is not an error to have a request with no  bio
@@ -1477,7 +1502,18 @@ static int qcom_ice_config_start(struct platform_device *pdev,
		return 0;
	}

	if (atomic_read(&ice_dev->is_ice_suspended) == 1)
		return -EINVAL;

	if (async)
		atomic_set(&ice_dev->is_ice_busy, 1);

	ret = pfk_load_key_start(req->bio, &pfk_crypto_data, &is_pfe, async);

	if (async) {
		atomic_set(&ice_dev->is_ice_busy, 0);
		wake_up_interruptible(&ice_dev->block_suspend_ice_queue);
	}
	if (is_pfe) {
		if (ret) {
			if (ret != -EBUSY && ret != -EAGAIN)
@@ -1544,7 +1580,6 @@ static int qcom_ice_config_end(struct request *req)
		/* It is not an error to have a request with no  bio */
		return 0;
	}

	ret = pfk_load_key_end(req->bio, &is_pfe);
	if (is_pfe) {
		if (ret != 0)
+26 −2
Original line number Diff line number Diff line
@@ -179,7 +179,8 @@ static void ufs_qcom_ice_cfg_work(struct work_struct *work)
		return;

	spin_lock_irqsave(&qcom_host->ice_work_lock, flags);
	if (!qcom_host->req_pending) {
	if (!qcom_host->req_pending ||
			ufshcd_is_shutdown_ongoing(qcom_host->hba)) {
		qcom_host->work_pending = false;
		spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
		return;
@@ -227,7 +228,7 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *qcom_host)
	qcom_host->dbg_print_en |= UFS_QCOM_ICE_DEFAULT_DBG_PRINT_EN;
	if (!ice_workqueue) {
		ice_workqueue = alloc_workqueue("ice-set-key",
			WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
			WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 0);
		if (!ice_workqueue) {
			dev_err(ufs_dev, "%s: workqueue allocation failed.\n",
			__func__);
@@ -610,6 +611,7 @@ int ufs_qcom_ice_reset(struct ufs_qcom_host *qcom_host)
	return err;
}


/**
 * ufs_qcom_ice_resume() - resumes UFS-ICE interface and ICE device from power
 * collapse
@@ -653,6 +655,28 @@ int ufs_qcom_ice_resume(struct ufs_qcom_host *qcom_host)
	return err;
}

/**
 * ufs_qcom_is_ice_busy() - lets the caller of the function know if
 * there is any ongoing operation in ICE in workqueue context.
 * @qcom_host:	Pointer to a UFS QCom internal host structure.
 *		qcom_host should be a valid pointer.
 *
 * Return:	1 if ICE is busy, 0 if it is free.
 *		-EINVAL in case of error.
 */
int ufs_qcom_is_ice_busy(struct ufs_qcom_host *qcom_host)
{
	if (!qcom_host) {
		pr_err("%s: invalid qcom_host %pK", __func__,  qcom_host);
		return -EINVAL;
	}

	if (qcom_host->req_pending)
		return 1;
	else
		return 0;
}

/**
 * ufs_qcom_ice_suspend() - suspends UFS-ICE interface and ICE device
 * @qcom_host:	Pointer to a UFS QCom internal host structure.
+6 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
 * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -83,6 +83,7 @@ int ufs_qcom_ice_resume(struct ufs_qcom_host *qcom_host);
int ufs_qcom_ice_suspend(struct ufs_qcom_host *qcom_host);
int ufs_qcom_ice_get_status(struct ufs_qcom_host *qcom_host, int *ice_status);
void ufs_qcom_ice_print_regs(struct ufs_qcom_host *qcom_host);
int ufs_qcom_is_ice_busy(struct ufs_qcom_host *qcom_host);
#else
inline int ufs_qcom_ice_get_dev(struct ufs_qcom_host *qcom_host)
{
@@ -127,6 +128,10 @@ inline void ufs_qcom_ice_print_regs(struct ufs_qcom_host *qcom_host)
{
	return;
}
inline int ufs_qcom_is_ice_busy(struct ufs_qcom_host *qcom_host)
{
	return 0;
}
#endif /* CONFIG_SCSI_UFS_QCOM_ICE */

#endif /* UFS_QCOM_ICE_H_ */