Skip to content

Commit 10e5e37

Browse files
Vijay Viswanathmartinkpetersen
Vijay Viswanath
authored andcommitted
scsi: ufs: Add clock ungating to a separate workqueue
UFS driver can receive a request during memory reclaim by kswapd. So when ufs driver puts the ungate work in queue, and if there are no idle workers, kthreadd is invoked to create a new kworker. Since kswapd task holds a mutex which kthreadd also needs, this can cause a deadlock situation. So ungate work must be done in a separate work queue with WQ_MEM_RECLAIM flag enabled. Such a workqueue will have a rescue thread which will be called when the above deadlock condition is possible. Signed-off-by: Vijay Viswanath <[email protected]> Signed-off-by: Can Guo <[email protected]> Signed-off-by: Asutosh Das <[email protected]> Reviewed-by: Subhash Jadavani <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 7f6ba4f commit 10e5e37

File tree

2 files changed

+11
-1
lines changed

2 files changed

+11
-1
lines changed

Diff for: drivers/scsi/ufs/ufshcd.c

+10-1
Original file line numberDiff line numberDiff line change
@@ -1532,7 +1532,8 @@ int ufshcd_hold(struct ufs_hba *hba, bool async)
15321532
hba->clk_gating.state = REQ_CLKS_ON;
15331533
trace_ufshcd_clk_gating(dev_name(hba->dev),
15341534
hba->clk_gating.state);
1535-
schedule_work(&hba->clk_gating.ungate_work);
1535+
queue_work(hba->clk_gating.clk_gating_workq,
1536+
&hba->clk_gating.ungate_work);
15361537
/*
15371538
* fall through to check if we should wait for this
15381539
* work to be done or not.
@@ -1718,13 +1719,20 @@ static ssize_t ufshcd_clkgate_enable_store(struct device *dev,
17181719

17191720
static void ufshcd_init_clk_gating(struct ufs_hba *hba)
17201721
{
1722+
char wq_name[sizeof("ufs_clk_gating_00")];
1723+
17211724
if (!ufshcd_is_clkgating_allowed(hba))
17221725
return;
17231726

17241727
hba->clk_gating.delay_ms = 150;
17251728
INIT_DELAYED_WORK(&hba->clk_gating.gate_work, ufshcd_gate_work);
17261729
INIT_WORK(&hba->clk_gating.ungate_work, ufshcd_ungate_work);
17271730

1731+
snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_gating_%d",
1732+
hba->host->host_no);
1733+
hba->clk_gating.clk_gating_workq = alloc_ordered_workqueue(wq_name,
1734+
WQ_MEM_RECLAIM);
1735+
17281736
hba->clk_gating.is_enabled = true;
17291737

17301738
hba->clk_gating.delay_attr.show = ufshcd_clkgate_delay_show;
@@ -1752,6 +1760,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba)
17521760
device_remove_file(hba->dev, &hba->clk_gating.enable_attr);
17531761
cancel_work_sync(&hba->clk_gating.ungate_work);
17541762
cancel_delayed_work_sync(&hba->clk_gating.gate_work);
1763+
destroy_workqueue(hba->clk_gating.clk_gating_workq);
17551764
}
17561765

17571766
/* Must be called with host lock acquired */

Diff for: drivers/scsi/ufs/ufshcd.h

+1
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ struct ufs_clk_gating {
362362
struct device_attribute enable_attr;
363363
bool is_enabled;
364364
int active_reqs;
365+
struct workqueue_struct *clk_gating_workq;
365366
};
366367

367368
struct ufs_saved_pwr_info {

0 commit comments

Comments
 (0)