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: Prerna Kalla <prernak@codeaurora.org>
This commit is contained in:
Prerna Kalla
2019-11-05 00:02:31 +05:30
parent 3ce6196d9f
commit 650400b459
4 changed files with 77 additions and 8 deletions

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
/* 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_ */

View File

@@ -8,6 +8,8 @@
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/atomic.h>
#include <linux/wait.h>
struct request;
@@ -67,7 +69,10 @@ struct ice_device {
struct qcom_ice_bus_vote bus_vote;
ktime_t ice_reset_start_time;
ktime_t ice_reset_complete_time;
void *key_table;
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 {