summaryrefslogtreecommitdiff
path: root/drivers/scsi/ufs/ufshcd.c
diff options
context:
space:
mode:
authorVenkat Gopalakrishnan <venkatg@codeaurora.org>2016-07-14 11:34:56 -0700
committerVenkat Gopalakrishnan <venkatg@codeaurora.org>2016-07-14 12:05:54 -0700
commit631771d3a059a1398118b41d15043e1dc515438f (patch)
tree3dfd8c431e3a2acfbb1f14a163e111365d7ff61d /drivers/scsi/ufs/ufshcd.c
parentaa958278d16faccd0cc79650b94ea6aa18d4131d (diff)
scsi: ufshcd: Fix race between clk scaling and ungate work
The ungate work turns on the clock before it exits hibern8, if the link was put in hibern8 during clock gating work. There occurs a race condition when clock scaling work calls ufshcd_hold() to make sure low power states cannot be entered, but that returns by checking only whether the clocks are on. This causes the clock scaling work to issue UIC commands when the link is in hibern8 causing failures. Make sure we exit hibern8 state before returning from ufshcd_hold(). Callstacks for race condition: ufshcd_scale_gear+0x120/0x138 ufshcd_devfreq_scale+0x98/0x154 ufshcd_devfreq_target+0x14c/0x250 update_devfreq+0xc4/0x10c devfreq_monitor+0x34/0x90 process_one_work+0x24c/0x430 worker_thread+0x2e0/0x408 kthread+0x100/0x108 ret_from_fork+0x10/0x40 ufshcd_uic_hibern8_exit+0x128/0x1f0 ufshcd_ungate_work+0xec/0x148 process_one_work+0x24c/0x430 worker_thread+0x2e0/0x408 kthread+0x100/0x108 ret_from_fork+0x10/0x40 CRs-Fixed: 1036530 Change-Id: I7f430abfb2a545ac97dee488a696a89cd18214f1 Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
Diffstat (limited to 'drivers/scsi/ufs/ufshcd.c')
-rw-r--r--drivers/scsi/ufs/ufshcd.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index ad679e5d3f76..9135415a5a51 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -1215,6 +1215,21 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
start:
switch (hba->clk_gating.state) {
case CLKS_ON:
+ /*
+ * Wait for the ungate work to complete if in progress.
+ * Though the clocks may be in ON state, the link could
+ * still be in hibner8 state if hibern8 is allowed
+ * during clock gating.
+ * Make sure we exit hibern8 state also in addition to
+ * clocks being ON.
+ */
+ if (ufshcd_can_hibern8_during_gating(hba) &&
+ ufshcd_is_link_hibern8(hba)) {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ flush_work(&hba->clk_gating.ungate_work);
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ goto start;
+ }
break;
case REQ_CLKS_OFF:
if (cancel_delayed_work(&hba->clk_gating.gate_work)) {