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 <venkatg@codeaurora.org>
This commit is contained in:
Venkat Gopalakrishnan 2017-01-23 15:00:09 -08:00
parent 8fa25e8c0e
commit c128400dc5
2 changed files with 17 additions and 5 deletions

View file

@ -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",

View file

@ -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;
}