diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 028492179101..77e2b3e1f8a2 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1532,7 +1532,8 @@ start: hba->clk_gating.state = REQ_CLKS_ON; trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); - schedule_work(&hba->clk_gating.ungate_work); + queue_work(hba->clk_gating.clk_gating_workq, + &hba->clk_gating.ungate_work); /* * fall through to check if we should wait for this * work to be done or not. @@ -1718,6 +1719,8 @@ out: static void ufshcd_init_clk_gating(struct ufs_hba *hba) { + char wq_name[sizeof("ufs_clk_gating_00")]; + if (!ufshcd_is_clkgating_allowed(hba)) return; @@ -1725,6 +1728,11 @@ static void ufshcd_init_clk_gating(struct ufs_hba *hba) INIT_DELAYED_WORK(&hba->clk_gating.gate_work, ufshcd_gate_work); INIT_WORK(&hba->clk_gating.ungate_work, ufshcd_ungate_work); + snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_gating_%d", + hba->host->host_no); + hba->clk_gating.clk_gating_workq = alloc_ordered_workqueue(wq_name, + WQ_MEM_RECLAIM); + hba->clk_gating.is_enabled = true; hba->clk_gating.delay_attr.show = ufshcd_clkgate_delay_show; @@ -1752,6 +1760,7 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) device_remove_file(hba->dev, &hba->clk_gating.enable_attr); cancel_work_sync(&hba->clk_gating.ungate_work); cancel_delayed_work_sync(&hba->clk_gating.gate_work); + destroy_workqueue(hba->clk_gating.clk_gating_workq); } /* Must be called with host lock acquired */ diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index a44b9f45ddd2..f51758f1e5cc 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -362,6 +362,7 @@ struct ufs_clk_gating { struct device_attribute enable_attr; bool is_enabled; int active_reqs; + struct workqueue_struct *clk_gating_workq; }; struct ufs_saved_pwr_info {