From 650400b459725009c2a48ef726bc8f107e3858a0 Mon Sep 17 00:00:00 2001 From: Prerna Kalla Date: Tue, 5 Nov 2019 00:02:31 +0530 Subject: [PATCH] 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 --- drivers/crypto/msm/ice.c | 44 ++++++++++++++++++++++++++++++--- drivers/scsi/ufs/ufs-qcom-ice.c | 27 ++++++++++++++++++-- drivers/scsi/ufs/ufs-qcom-ice.h | 7 +++++- include/crypto/ice.h | 7 +++++- 4 files changed, 77 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index dac0203397ef..46372bcb5caf 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -20,7 +20,8 @@ #include #include "iceregs.h" #include - +#include +#include #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) diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index 1a3046f69a4b..48fd18c989d7 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -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. diff --git a/drivers/scsi/ufs/ufs-qcom-ice.h b/drivers/scsi/ufs/ufs-qcom-ice.h index 50a0a8166550..2b424593f94d 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.h +++ b/drivers/scsi/ufs/ufs-qcom-ice.h @@ -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_ */ diff --git a/include/crypto/ice.h b/include/crypto/ice.h index 793262337945..27b285b774e7 100644 --- a/include/crypto/ice.h +++ b/include/crypto/ice.h @@ -8,6 +8,8 @@ #include #include +#include +#include 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 {