summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSubhash Jadavani <subhashj@codeaurora.org>2016-01-18 13:10:32 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 21:25:42 -0700
commit90e939642217543245ae5016621d10f4ddd1e948 (patch)
treef616ddacc171c3fb9f657fd79aa0be5ca1894dca
parentfb86dfdbb0a2b7f98e3ac3055d30734ac8140772 (diff)
scsi: ufs: fix deadlock between clock scaling and clock ungating work
There's a deadlock between clock scaling and clock ungating work if hibern8 exit fails while ungating clocks. ufshcd_exec_dev_cmd() in clock ungating work blocks at taking "clk_scaling_lock" unless clock scaling work completes which had taken "clock_scaling_lock" and it will never be released hence this is a deadlock. Clock ungating context: ---------------------- -000|__switch_to() -001|context_switch(inline) -001|__schedule() -002|schedule() -003|rwsem_down_read_failed() -004|down_read() -005|ufshcd_get_dev_cmd_tag(inline) -005|ufshcd_exec_dev_cmd() -006|ufshcd_verify_dev_init() -007|ufshcd_probe_hba() -008|ufshcd_host_reset_and_restore() -009|ufshcd_link_recovery() -010|ufshcd_uic_hibern8_exit() -011|ufshcd_ungate_work() -012|static_key_count(inline) -012|static_key_false(inline) -012|trace_workqueue_execute_end(inline) -012|process_one_work() -013|process_scheduled_works(inline) -013|worker_thread() -014|kthread() -015|ret_from_fork(asm) -->|exception -016|NSX:0xF0440E59300(asm) ---|end of frame Clock scaling context: ---------------------- -000|__switch_to() -001|context_switch(inline) -001|__schedule() -002|schedule() -003|schedule_timeout() -004|do_wait_for_common(inline) -004|__wait_for_common(inline) -004|wait_for_common() -005|wait_for_completion() -006|flush_work() -007|ufshcd_hold() -008|ufshcd_hold_all() -009|ufshcd_wait_for_doorbell_clr() -010|ufshcd_clock_scaling_prepare(inline) -010|ufshcd_devfreq_scale() -011|ufshcd_devfreq_target() -012|update_devfreq() -013|devfreq_monitor() -014|static_key_count(inline) -014|static_key_false(inline) -014|trace_workqueue_execute_end(inline) -014|process_one_work() -015|worker_thread() -016|kthread() -017|ret_from_fork(asm) -->|exception -018|NSR:0x2A714C(asm) ---|end of frame This change is fixing this by moving ufshcd_hold_all() in ufshcd_devfreq_scale() to the beginning of the function so that clk_scaling_lock is acquired only after clock ungating completes. CRs-Fixed: 963407 Change-Id: I83788c3212baeab31cf1bf877ca0aaf9005ca661 Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
-rw-r--r--drivers/scsi/ufs/ufshcd.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 740509c34b0a..b2a16e465246 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -8589,17 +8589,18 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
{
int ret = 0;
+ /* let's not get into low power until clock scaling is completed */
+ ufshcd_hold_all(hba);
+
ret = ufshcd_clock_scaling_prepare(hba);
if (ret)
- return ret;
+ goto out;
- /* let's not get into low power until clock scaling is completed */
- ufshcd_hold_all(hba);
/* scale down the gear before scaling down clocks */
if (!scale_up) {
ret = ufshcd_scale_gear(hba, false);
if (ret)
- goto out;
+ goto clk_scaling_unprepare;
}
ret = ufshcd_scale_clks(hba, scale_up);
@@ -8611,7 +8612,7 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
ret = ufshcd_scale_gear(hba, true);
if (ret) {
ufshcd_scale_clks(hba, false);
- goto out;
+ goto clk_scaling_unprepare;
}
}
@@ -8625,13 +8626,14 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up)
hba->clk_gating.delay_ms_pwr_save;
}
- goto out;
+ goto clk_scaling_unprepare;
scale_up_gear:
if (!scale_up)
ufshcd_scale_gear(hba, true);
-out:
+clk_scaling_unprepare:
ufshcd_clock_scaling_unprepare(hba);
+out:
ufshcd_release_all(hba);
return ret;
}