diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 3101eca79823..284a7397e558 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1237,7 +1237,18 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba) } } -static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on) +/** + * ufs_qcom_setup_clocks - enables/disable clocks + * @hba: host controller instance + * @on: If true, enable clocks else disable them. + * @is_gating_context: If true then it means this function is called from + * aggressive clock gating context and we may only need to gate off important + * clocks. If false then make sure to gate off all clocks. + * + * Returns 0 on success, non-zero on failure. + */ +static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, + bool is_gating_context) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); int err; @@ -1813,7 +1824,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_set_caps(hba); ufs_qcom_advertise_quirks(hba); - ufs_qcom_setup_clocks(hba, true); + ufs_qcom_setup_clocks(hba, true, false); if (hba->dev->id < MAX_UFS_QCOM_HOSTS) ufs_qcom_hosts[hba->dev->id] = host; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d1ffa9406baa..b2571ac21f39 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -359,9 +359,11 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd); static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag); static void ufshcd_hba_exit(struct ufs_hba *hba); static int ufshcd_probe_hba(struct ufs_hba *hba); -static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, - bool skip_ref_clk); -static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on); +static int ufshcd_enable_clocks(struct ufs_hba *hba); +static int ufshcd_disable_clocks(struct ufs_hba *hba, + bool is_gating_context); +static int ufshcd_disable_clocks_skip_ref_clk(struct ufs_hba *hba, + bool is_gating_context); static int ufshcd_set_vccq_rail_unused(struct ufs_hba *hba, bool unused); static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba); static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba); @@ -1135,7 +1137,7 @@ static void ufshcd_ungate_work(struct work_struct *work) spin_unlock_irqrestore(hba->host->host_lock, flags); ufshcd_hba_vreg_set_hpm(hba); - ufshcd_setup_clocks(hba, true); + ufshcd_enable_clocks(hba); /* Exit from hibern8 */ if (ufshcd_can_hibern8_during_gating(hba)) { @@ -1271,10 +1273,10 @@ static void ufshcd_gate_work(struct work_struct *work) ufshcd_suspend_clkscaling(hba); if (!ufshcd_is_link_active(hba) && !hba->no_ref_clk_gating) - ufshcd_setup_clocks(hba, false); + ufshcd_disable_clocks(hba, true); else /* If link is active, device ref_clk can't be switched off */ - __ufshcd_setup_clocks(hba, false, true); + ufshcd_disable_clocks_skip_ref_clk(hba, true); /* Put the host controller in low power mode if possible */ ufshcd_hba_vreg_set_lpm(hba); @@ -7030,8 +7032,8 @@ out: return ret; } -static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, - bool skip_ref_clk) +static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on, + bool skip_ref_clk, bool is_gating_context) { int ret = 0; struct ufs_clk_info *clki; @@ -7049,7 +7051,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, * before disabling the clocks managed here. */ if (!on) { - ret = ufshcd_vops_setup_clocks(hba, on); + ret = ufshcd_vops_setup_clocks(hba, on, is_gating_context); if (ret) return ret; } @@ -7082,7 +7084,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, * after enabling the clocks managed here. */ if (on) - ret = ufshcd_vops_setup_clocks(hba, on); + ret = ufshcd_vops_setup_clocks(hba, on, is_gating_context); out: if (ret) { @@ -7107,9 +7109,21 @@ out: return ret; } -static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on) +static int ufshcd_enable_clocks(struct ufs_hba *hba) { - return __ufshcd_setup_clocks(hba, on, false); + return ufshcd_setup_clocks(hba, true, false, false); +} + +static int ufshcd_disable_clocks(struct ufs_hba *hba, + bool is_gating_context) +{ + return ufshcd_setup_clocks(hba, false, false, is_gating_context); +} + +static int ufshcd_disable_clocks_skip_ref_clk(struct ufs_hba *hba, + bool is_gating_context) +{ + return ufshcd_setup_clocks(hba, false, true, is_gating_context); } static int ufshcd_init_clocks(struct ufs_hba *hba) @@ -7182,8 +7196,6 @@ static void ufshcd_variant_hba_exit(struct ufs_hba *hba) if (!hba->var || !hba->var->vops) return; - ufshcd_vops_setup_clocks(hba, false); - ufshcd_vops_setup_regulators(hba, false); ufshcd_vops_exit(hba); @@ -7212,7 +7224,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba) if (err) goto out_disable_hba_vreg; - err = ufshcd_setup_clocks(hba, true); + err = ufshcd_enable_clocks(hba); if (err) goto out_disable_hba_vreg; @@ -7234,7 +7246,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba) out_disable_vreg: ufshcd_setup_vreg(hba, false); out_disable_clks: - ufshcd_setup_clocks(hba, false); + ufshcd_disable_clocks(hba, false); out_disable_hba_vreg: ufshcd_setup_hba_vreg(hba, false); out: @@ -7247,7 +7259,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba) ufshcd_variant_hba_exit(hba); ufshcd_setup_vreg(hba, false); ufshcd_suspend_clkscaling(hba); - ufshcd_setup_clocks(hba, false); + ufshcd_disable_clocks(hba, false); ufshcd_setup_hba_vreg(hba, false); hba->is_powered = false; } @@ -7590,15 +7602,13 @@ disable_clks: if (ret) goto set_link_active; - ret = ufshcd_vops_setup_clocks(hba, false); - if (ret) - goto vops_resume; - if (!ufshcd_is_link_active(hba)) - ufshcd_setup_clocks(hba, false); + ret = ufshcd_disable_clocks(hba, false); else /* If link is active, device ref_clk can't be switched off */ - __ufshcd_setup_clocks(hba, false, true); + ret = ufshcd_disable_clocks_skip_ref_clk(hba, false); + if (ret) + goto set_link_active; hba->clk_gating.state = CLKS_OFF; trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); @@ -7611,8 +7621,6 @@ disable_clks: ufshcd_hba_vreg_set_lpm(hba); goto out; -vops_resume: - ufshcd_vops_resume(hba, pm_op); set_link_active: ufshcd_resume_clkscaling(hba); ufshcd_vreg_set_hpm(hba); @@ -7659,7 +7667,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) ufshcd_hba_vreg_set_hpm(hba); /* Make sure clocks are enabled before accessing controller */ - ret = ufshcd_setup_clocks(hba, true); + ret = ufshcd_enable_clocks(hba); if (ret) goto out; @@ -7735,7 +7743,7 @@ disable_vreg: disable_irq_and_vops_clks: ufshcd_disable_irq(hba); ufshcd_suspend_clkscaling(hba); - ufshcd_setup_clocks(hba, false); + ufshcd_disable_clocks(hba, false); out: hba->pm_op_in_progress = 0; diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 8e2c2f509039..811af66c835c 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -314,7 +314,7 @@ struct ufs_hba_variant_ops { u32 (*get_ufs_hci_version)(struct ufs_hba *); int (*clk_scale_notify)(struct ufs_hba *, bool, enum ufs_notify_change_status); - int (*setup_clocks)(struct ufs_hba *, bool); + int (*setup_clocks)(struct ufs_hba *, bool, bool); int (*setup_regulators)(struct ufs_hba *, bool); int (*hce_enable_notify)(struct ufs_hba *, enum ufs_notify_change_status); @@ -1074,10 +1074,11 @@ static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba, return 0; } -static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on) +static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on, + bool is_gating_context) { if (hba->var && hba->var->vops && hba->var->vops->setup_clocks) - return hba->var->vops->setup_clocks(hba, on); + return hba->var->vops->setup_clocks(hba, on, is_gating_context); return 0; }