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

Commit 650400b4 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: I4aa2a211e439a876c8525ab062a7cb917b4e2d7e
Signed-off-by: default avatarPrerna Kalla <prernak@codeaurora.org>
parent 3ce6196d
Loading
Loading
Loading
Loading
+40 −4
Original line number Diff line number Diff line
@@ -20,7 +20,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)))
@@ -800,6 +801,28 @@ static int qcom_ice_remove(struct platform_device *pdev)

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

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

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

		if (!ret) {
			pr_err("%s: Suspend ICE during an ongoing operation\n",
				__func__);
			atomic_set(&ice_dev->is_ice_suspended, 0);
			return ret;
		}
	}

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

@@ -1030,7 +1053,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);
@@ -1038,7 +1061,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;
}
@@ -1145,7 +1169,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;
}

@@ -1415,8 +1439,20 @@ 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, ice_dev, &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)
+25 −2
Original line number Diff line number Diff line
@@ -180,7 +180,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;
@@ -228,7 +229,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__);
@@ -659,6 +660,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\n", __func__);
		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
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2014-2018, 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
@@ -84,6 +84,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 int ufs_qcom_ice_get_status(struct ufs_qcom_host *qcom_host,
inline void ufs_qcom_ice_print_regs(struct ufs_qcom_host *qcom_host)
{
}
static 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_ */
+6 −1
Original line number Diff line number Diff line
@@ -8,6 +8,8 @@

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

struct request;

@@ -68,6 +70,9 @@ struct ice_device {
	ktime_t			ice_reset_start_time;
	ktime_t			ice_reset_complete_time;
	void                    *key_table;
	atomic_t		is_ice_suspended;
	atomic_t		is_ice_busy;
	wait_queue_head_t       block_suspend_ice_queue;
};

struct ice_crypto_setting {