From c128400dc563bc5514ed3773730fc282197e08eb Mon Sep 17 00:00:00 2001 From: Venkat Gopalakrishnan Date: Mon, 23 Jan 2017 15:00:09 -0800 Subject: [PATCH] scsi: ufs: fix ufshcd_hold deadlock If ufs_qcom_testbus_config is called as part of dumping registers inside ufshcd_ungate_work then a ufshcd_hold in this function will deadlock triggering another ungate work and waiting for it to finish. Fix this by making sure the caller already holds the needed locks for clocks and runtime status. Change-Id: I8f4c10d952c8f74c93b991088f5ee1eaf719ca84 Signed-off-by: Venkat Gopalakrishnan --- drivers/scsi/ufs/ufs-qcom-debugfs.c | 13 ++++++++++++- drivers/scsi/ufs/ufs-qcom.c | 9 +++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufs-qcom-debugfs.c b/drivers/scsi/ufs/ufs-qcom-debugfs.c index 8532439c392d..4547a6dbdb23 100644 --- a/drivers/scsi/ufs/ufs-qcom-debugfs.c +++ b/drivers/scsi/ufs/ufs-qcom-debugfs.c @@ -67,6 +67,7 @@ static int ufs_qcom_dbg_testbus_en_read(void *data, u64 *attr_val) static int ufs_qcom_dbg_testbus_en_set(void *data, u64 attr_id) { struct ufs_qcom_host *host = data; + int ret = 0; if (!host) return -EINVAL; @@ -76,7 +77,13 @@ static int ufs_qcom_dbg_testbus_en_set(void *data, u64 attr_id) else host->dbg_print_en &= ~UFS_QCOM_DBG_PRINT_TEST_BUS_EN; - return ufs_qcom_testbus_config(host); + pm_runtime_get_sync(host->hba->dev); + ufshcd_hold(host->hba, false); + ret = ufs_qcom_testbus_config(host); + ufshcd_release(host->hba, false); + pm_runtime_put_sync(host->hba->dev); + + return ret; } DEFINE_SIMPLE_ATTRIBUTE(ufs_qcom_dbg_testbus_en_ops, @@ -142,7 +149,11 @@ static ssize_t ufs_qcom_dbg_testbus_cfg_write(struct file *file, * Sanity check of the {major, minor} tuple is done in the * config function */ + pm_runtime_get_sync(host->hba->dev); + ufshcd_hold(host->hba, false); ret = ufs_qcom_testbus_config(host); + ufshcd_release(host->hba, false); + pm_runtime_put_sync(host->hba->dev); if (!ret) dev_dbg(host->hba->dev, "%s: New configuration: major=%d, minor=%d\n", diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 03b222d8be93..7369478a8c5d 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -2452,6 +2452,11 @@ static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host) return true; } +/* + * The caller of this function must make sure that the controller + * is out of runtime suspend and appropriate clocks are enabled + * before accessing. + */ int ufs_qcom_testbus_config(struct ufs_qcom_host *host) { int reg; @@ -2522,8 +2527,6 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host) } mask <<= offset; - pm_runtime_get_sync(host->hba->dev); - ufshcd_hold(host->hba, false); ufshcd_rmwl(host->hba, TEST_BUS_SEL, (u32)host->testbus.select_major << 19, REG_UFS_CFG1); @@ -2536,8 +2539,6 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host) * committed before returning. */ mb(); - ufshcd_release(host->hba, false); - pm_runtime_put_sync(host->hba->dev); return 0; }