1 From 30fc33f1ef475480dc5bea4fe1bda84b003b992c Mon Sep 17 00:00:00 2001
2 From: Subhash Jadavani <subhashj@codeaurora.org>
3 Date: Thu, 27 Oct 2016 17:25:47 -0700
4 Subject: scsi: ufs: fix race between clock gating and devfreq scaling work
6 From: Subhash Jadavani <subhashj@codeaurora.org>
8 commit 30fc33f1ef475480dc5bea4fe1bda84b003b992c upstream.
10 UFS devfreq clock scaling work may require clocks to be ON if it need to
11 execute some UFS commands hence it may request for clock hold before
12 issuing the command. But if UFS clock gating work is already running in
13 parallel, ungate work would end up waiting for the clock gating work to
14 finish and as clock gating work would also wait for the clock scaling
15 work to finish, we would enter in deadlock state. Here is the call trace
16 during this deadlock state:
18 Workqueue: devfreq_wq devfreq_monitor
29 ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div
30 ufs_qcom_clk_scale_notify
40 Workqueue: events ufshcd_gate_work
44 schedule_preempt_disabled
47 devfreq_monitor_suspend
48 devfreq_simple_ondemand_handler
49 devfreq_suspend_device
56 Workqueue: events ufshcd_ungate_work
65 cancel_delayed_work_sync
72 This change fixes this deadlock by doing this in devfreq work (devfreq_wq):
73 Try cancelling clock gating work. If we are able to cancel gating work
74 or it wasn't scheduled, hold the clock reference count until scaling is
75 in progress. If gate work is already running in parallel, let's skip
76 the frequecy scaling at this time and it will be retried once next scaling
79 Reviewed-by: Sahitya Tummala <stummala@codeaurora.org>
80 Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
81 Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
82 Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
83 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
86 drivers/scsi/ufs/ufshcd.c | 32 ++++++++++++++++++++++++++++++++
87 1 file changed, 32 insertions(+)
89 --- a/drivers/scsi/ufs/ufshcd.c
90 +++ b/drivers/scsi/ufs/ufshcd.c
91 @@ -5511,15 +5511,47 @@ static int ufshcd_devfreq_target(struct
94 struct ufs_hba *hba = dev_get_drvdata(dev);
95 + bool release_clk_hold = false;
96 + unsigned long irq_flags;
98 if (!ufshcd_is_clkscaling_enabled(hba))
101 + spin_lock_irqsave(hba->host->host_lock, irq_flags);
102 + if (ufshcd_eh_in_progress(hba)) {
103 + spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
107 + if (ufshcd_is_clkgating_allowed(hba) &&
108 + (hba->clk_gating.state != CLKS_ON)) {
109 + if (cancel_delayed_work(&hba->clk_gating.gate_work)) {
110 + /* hold the vote until the scaling work is completed */
111 + hba->clk_gating.active_reqs++;
112 + release_clk_hold = true;
113 + hba->clk_gating.state = CLKS_ON;
116 + * Clock gating work seems to be running in parallel
117 + * hence skip scaling work to avoid deadlock between
118 + * current scaling work and gating work.
120 + spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
124 + spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
126 if (*freq == UINT_MAX)
127 err = ufshcd_scale_clks(hba, true);
129 err = ufshcd_scale_clks(hba, false);
131 + spin_lock_irqsave(hba->host->host_lock, irq_flags);
132 + if (release_clk_hold)
133 + __ufshcd_release(hba);
134 + spin_unlock_irqrestore(hba->host->host_lock, irq_flags);