scsi: ufs: Fix up auto hibern8 enablement
authorCan Guo <cang@codeaurora.org>
Fri, 15 Nov 2019 06:09:26 +0000 (22:09 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 4 Jan 2020 18:18:17 +0000 (19:18 +0100)
[ Upstream commit 71d848b8d97ec0f8e993d63cf9de6ac8b3f7c43d ]

Fix up possible unclocked register access to auto hibern8 register in
resume path and through sysfs entry. Meanwhile, enable auto hibern8 only
after device is fully initialized in probe path.

Link: https://lore.kernel.org/r/1573798172-20534-4-git-send-email-cang@codeaurora.org
Reviewed-by: Stanley Chu <stanley.chu@mediatek.com>
Signed-off-by: Can Guo <cang@codeaurora.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/scsi/ufs/ufs-sysfs.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h

index 969a36b15897b9820877b12c0589322053f888c4..ad2abc96c0f19cc36008632d0adf0606f6b6c429 100644 (file)
@@ -126,13 +126,16 @@ static void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit)
                return;
 
        spin_lock_irqsave(hba->host->host_lock, flags);
-       if (hba->ahit == ahit)
-               goto out_unlock;
-       hba->ahit = ahit;
-       if (!pm_runtime_suspended(hba->dev))
-               ufshcd_writel(hba, hba->ahit, REG_AUTO_HIBERNATE_IDLE_TIMER);
-out_unlock:
+       if (hba->ahit != ahit)
+               hba->ahit = ahit;
        spin_unlock_irqrestore(hba->host->host_lock, flags);
+       if (!pm_runtime_suspended(hba->dev)) {
+               pm_runtime_get_sync(hba->dev);
+               ufshcd_hold(hba, false);
+               ufshcd_auto_hibern8_enable(hba);
+               ufshcd_release(hba);
+               pm_runtime_put(hba->dev);
+       }
 }
 
 /* Convert Auto-Hibernate Idle Timer register value to microseconds */
index 0036dcffc4a9085f99aef78ead58c2a3b7167d49..25a6a25b17a283e16dad7d7468d086c134b1f759 100644 (file)
@@ -3950,7 +3950,7 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba)
        return ret;
 }
 
-static void ufshcd_auto_hibern8_enable(struct ufs_hba *hba)
+void ufshcd_auto_hibern8_enable(struct ufs_hba *hba)
 {
        unsigned long flags;
 
@@ -6890,9 +6890,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
        /* UniPro link is active now */
        ufshcd_set_link_active(hba);
 
-       /* Enable Auto-Hibernate if configured */
-       ufshcd_auto_hibern8_enable(hba);
-
        ret = ufshcd_verify_dev_init(hba);
        if (ret)
                goto out;
@@ -6943,6 +6940,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
        /* set the state as operational after switching to desired gear */
        hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
 
+       /* Enable Auto-Hibernate if configured */
+       ufshcd_auto_hibern8_enable(hba);
+
        /*
         * If we are in error handling context or in power management callbacks
         * context, no need to scan the host
@@ -7959,12 +7959,12 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
        if (hba->clk_scaling.is_allowed)
                ufshcd_resume_clkscaling(hba);
 
-       /* Schedule clock gating in case of no access to UFS device yet */
-       ufshcd_release(hba);
-
        /* Enable Auto-Hibernate if configured */
        ufshcd_auto_hibern8_enable(hba);
 
+       /* Schedule clock gating in case of no access to UFS device yet */
+       ufshcd_release(hba);
+
        goto out;
 
 set_old_link_state:
index c94cfda528290f186bbf64a1c1797cef549cc55f..52c9676a12425621210098ac710c0a807b88d73a 100644 (file)
@@ -916,6 +916,8 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
 int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
        enum flag_idn idn, bool *flag_res);
 
+void ufshcd_auto_hibern8_enable(struct ufs_hba *hba);
+
 #define SD_ASCII_STD true
 #define SD_RAW false
 int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index,