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 {