scsi: ufs: fix deadlock between clock scaling and shutdown
There's a deadlock in which shutdown context is waiting for a mutex acquired by clock-scaling monitor, which in turn is waiting for the mutex acquired by shutdown context. Fix this by not allowing clocks to scale after being suspended & also de-register this device from the devfreq framework. As below: <call stack : init> -005|current_thread_info(inline) -005|mutex_set_owner(inline) -005|mutex_lock -006|devfreq_monitor_suspend -007|devfreq_simple_ondemand_handler -008|devfreq_suspend_device(?) -009|__ufshcd_suspend_clkscaling(inline) -009|ufshcd_suspend_clkscaling -010|ufshcd_shutdown -011|ufshcd_pltfrm_shutdown(?) -012|platform_drv_shutdown -013|device_unlock(inline) -013|device_shutdown() -014|kernel_restart_prepare(?) -015|kernel_restart -016|SYSC_reboot(inline) -016|sys_reboot(?, ?, ?) -017|el0_svc_naked(asm) -->|exception -018|NUX:0x538F6C(asm) <call stack : kworker/u16:4> -008|rwsem_down_write_failed | sem = -> ( | count = -8589934591, | wait_list = (next = , prev = ), | wait_lock = (raw_lock = (owner = 4, next = 4)), | osq = (tail = (counter = 0)), | owner = -> ( | comm = "init", -009|current_thread_info(inline) -009|rwsem_set_owner(inline) -009|down_write -010|ufshcd_clock_scaling_prepare(inline) -010|ufshcd_devfreq_scale -011|ufshcd_devfreq_target(?, ?, ?) -012|update_devfreq -013|devfreq_monitor -014|__read_once_size(inline) -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) ---|end of frame Change-Id: Ic1853ef5143cadd95f0a6df474b35ad45fa918e1 Signed-off-by: Asutosh Das <asutoshd@codeaurora.org>
This commit is contained in:
parent
c7835c5795
commit
3b284d45b4
1 changed files with 34 additions and 11 deletions
|
@ -8790,6 +8790,35 @@ static inline void ufshcd_add_sysfs_nodes(struct ufs_hba *hba)
|
|||
ufshcd_add_spm_lvl_sysfs_nodes(hba);
|
||||
}
|
||||
|
||||
static void ufshcd_shutdown_clkscaling(struct ufs_hba *hba)
|
||||
{
|
||||
bool suspend = false;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(hba->host->host_lock, flags);
|
||||
if (hba->clk_scaling.is_allowed) {
|
||||
hba->clk_scaling.is_allowed = false;
|
||||
suspend = true;
|
||||
}
|
||||
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
||||
|
||||
/**
|
||||
* Scaling may be scheduled before, hence make sure it
|
||||
* doesn't race with shutdown
|
||||
*/
|
||||
if (ufshcd_is_clkscaling_supported(hba)) {
|
||||
device_remove_file(hba->dev, &hba->clk_scaling.enable_attr);
|
||||
cancel_work_sync(&hba->clk_scaling.suspend_work);
|
||||
cancel_work_sync(&hba->clk_scaling.resume_work);
|
||||
if (suspend)
|
||||
ufshcd_suspend_clkscaling(hba);
|
||||
}
|
||||
|
||||
/* Unregister so that devfreq_monitor can't race with shutdown */
|
||||
if (hba->devfreq)
|
||||
devfreq_remove_device(hba->devfreq);
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_shutdown - shutdown routine
|
||||
* @hba: per adapter instance
|
||||
|
@ -8807,16 +8836,14 @@ int ufshcd_shutdown(struct ufs_hba *hba)
|
|||
|
||||
pm_runtime_get_sync(hba->dev);
|
||||
ufshcd_hold_all(hba);
|
||||
/**
|
||||
* (1) Set state to shutting down
|
||||
* (2) Acquire the lock to stop any more requests
|
||||
* (3) Suspend clock scaling
|
||||
* (4) Wait for all issued requests to complete
|
||||
*/
|
||||
ufshcd_mark_shutdown_ongoing(hba);
|
||||
ufshcd_shutdown_clkscaling(hba);
|
||||
/**
|
||||
* (1) Acquire the lock to stop any more requests
|
||||
* (2) Wait for all issued requests to complete
|
||||
*/
|
||||
ufshcd_get_write_lock(hba);
|
||||
ufshcd_scsi_block_requests(hba);
|
||||
ufshcd_suspend_clkscaling(hba);
|
||||
ret = ufshcd_wait_for_doorbell_clr(hba, U64_MAX);
|
||||
if (ret)
|
||||
dev_err(hba->dev, "%s: waiting for DB clear: failed: %d\n",
|
||||
|
@ -9210,10 +9237,6 @@ static void ufshcd_clk_scaling_resume_work(struct work_struct *work)
|
|||
clk_scaling.resume_work);
|
||||
unsigned long irq_flags;
|
||||
|
||||
/* Let's not resume scaling if shutdown is ongoing */
|
||||
if (ufshcd_is_shutdown_ongoing(hba))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(hba->host->host_lock, irq_flags);
|
||||
if (!hba->clk_scaling.is_suspended) {
|
||||
spin_unlock_irqrestore(hba->host->host_lock, irq_flags);
|
||||
|
|
Loading…
Add table
Reference in a new issue