scsi: ufs: let aggressive clock gating context known
It is quite possible that we might need multiple clocks to be enabled when UFS transfers are active and we generally turn these clocks off during runtime & system suspend. In addition, we also vote these clocks off if aggressive clock gating feature is enabled. Idle timeout for aggressive clock gating feature is generally ~50 milliseconds. But turning these clocks on/off could have huge latencies hence we might only want to turn off few essential (and low latency) clocks during aggressive clock gating. This change adds support to let the vendor specific setup_clocks callback know whether it is called from aggressive clock gating context or normal clock gating context. Having this context information should help vendor specific setup_clocks callback to selectively disable clocks. Change-Id: I5e1523a57bc45a91faef463baac1cea2a2c8d2d6 Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org> [venkatg@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
This commit is contained in:
parent
029a8b38f6
commit
ae27e5f46a
3 changed files with 52 additions and 32 deletions
|
@ -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);
|
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
|
||||||
int err;
|
int err;
|
||||||
|
@ -1813,7 +1824,7 @@ static int ufs_qcom_init(struct ufs_hba *hba)
|
||||||
ufs_qcom_set_caps(hba);
|
ufs_qcom_set_caps(hba);
|
||||||
ufs_qcom_advertise_quirks(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)
|
if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
|
||||||
ufs_qcom_hosts[hba->dev->id] = host;
|
ufs_qcom_hosts[hba->dev->id] = host;
|
||||||
|
|
|
@ -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 int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag);
|
||||||
static void ufshcd_hba_exit(struct ufs_hba *hba);
|
static void ufshcd_hba_exit(struct ufs_hba *hba);
|
||||||
static int ufshcd_probe_hba(struct ufs_hba *hba);
|
static int ufshcd_probe_hba(struct ufs_hba *hba);
|
||||||
static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
|
static int ufshcd_enable_clocks(struct ufs_hba *hba);
|
||||||
bool skip_ref_clk);
|
static int ufshcd_disable_clocks(struct ufs_hba *hba,
|
||||||
static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on);
|
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_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_exit(struct ufs_hba *hba);
|
||||||
static int ufshcd_uic_hibern8_enter(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);
|
spin_unlock_irqrestore(hba->host->host_lock, flags);
|
||||||
ufshcd_hba_vreg_set_hpm(hba);
|
ufshcd_hba_vreg_set_hpm(hba);
|
||||||
ufshcd_setup_clocks(hba, true);
|
ufshcd_enable_clocks(hba);
|
||||||
|
|
||||||
/* Exit from hibern8 */
|
/* Exit from hibern8 */
|
||||||
if (ufshcd_can_hibern8_during_gating(hba)) {
|
if (ufshcd_can_hibern8_during_gating(hba)) {
|
||||||
|
@ -1271,10 +1273,10 @@ static void ufshcd_gate_work(struct work_struct *work)
|
||||||
ufshcd_suspend_clkscaling(hba);
|
ufshcd_suspend_clkscaling(hba);
|
||||||
|
|
||||||
if (!ufshcd_is_link_active(hba) && !hba->no_ref_clk_gating)
|
if (!ufshcd_is_link_active(hba) && !hba->no_ref_clk_gating)
|
||||||
ufshcd_setup_clocks(hba, false);
|
ufshcd_disable_clocks(hba, true);
|
||||||
else
|
else
|
||||||
/* If link is active, device ref_clk can't be switched off */
|
/* 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 */
|
/* Put the host controller in low power mode if possible */
|
||||||
ufshcd_hba_vreg_set_lpm(hba);
|
ufshcd_hba_vreg_set_lpm(hba);
|
||||||
|
@ -7030,8 +7032,8 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
|
static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
|
||||||
bool skip_ref_clk)
|
bool skip_ref_clk, bool is_gating_context)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct ufs_clk_info *clki;
|
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.
|
* before disabling the clocks managed here.
|
||||||
*/
|
*/
|
||||||
if (!on) {
|
if (!on) {
|
||||||
ret = ufshcd_vops_setup_clocks(hba, on);
|
ret = ufshcd_vops_setup_clocks(hba, on, is_gating_context);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -7082,7 +7084,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
|
||||||
* after enabling the clocks managed here.
|
* after enabling the clocks managed here.
|
||||||
*/
|
*/
|
||||||
if (on)
|
if (on)
|
||||||
ret = ufshcd_vops_setup_clocks(hba, on);
|
ret = ufshcd_vops_setup_clocks(hba, on, is_gating_context);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -7107,9 +7109,21 @@ out:
|
||||||
return ret;
|
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)
|
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)
|
if (!hba->var || !hba->var->vops)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ufshcd_vops_setup_clocks(hba, false);
|
|
||||||
|
|
||||||
ufshcd_vops_setup_regulators(hba, false);
|
ufshcd_vops_setup_regulators(hba, false);
|
||||||
|
|
||||||
ufshcd_vops_exit(hba);
|
ufshcd_vops_exit(hba);
|
||||||
|
@ -7212,7 +7224,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
|
||||||
if (err)
|
if (err)
|
||||||
goto out_disable_hba_vreg;
|
goto out_disable_hba_vreg;
|
||||||
|
|
||||||
err = ufshcd_setup_clocks(hba, true);
|
err = ufshcd_enable_clocks(hba);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_disable_hba_vreg;
|
goto out_disable_hba_vreg;
|
||||||
|
|
||||||
|
@ -7234,7 +7246,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
|
||||||
out_disable_vreg:
|
out_disable_vreg:
|
||||||
ufshcd_setup_vreg(hba, false);
|
ufshcd_setup_vreg(hba, false);
|
||||||
out_disable_clks:
|
out_disable_clks:
|
||||||
ufshcd_setup_clocks(hba, false);
|
ufshcd_disable_clocks(hba, false);
|
||||||
out_disable_hba_vreg:
|
out_disable_hba_vreg:
|
||||||
ufshcd_setup_hba_vreg(hba, false);
|
ufshcd_setup_hba_vreg(hba, false);
|
||||||
out:
|
out:
|
||||||
|
@ -7247,7 +7259,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
|
||||||
ufshcd_variant_hba_exit(hba);
|
ufshcd_variant_hba_exit(hba);
|
||||||
ufshcd_setup_vreg(hba, false);
|
ufshcd_setup_vreg(hba, false);
|
||||||
ufshcd_suspend_clkscaling(hba);
|
ufshcd_suspend_clkscaling(hba);
|
||||||
ufshcd_setup_clocks(hba, false);
|
ufshcd_disable_clocks(hba, false);
|
||||||
ufshcd_setup_hba_vreg(hba, false);
|
ufshcd_setup_hba_vreg(hba, false);
|
||||||
hba->is_powered = false;
|
hba->is_powered = false;
|
||||||
}
|
}
|
||||||
|
@ -7590,15 +7602,13 @@ disable_clks:
|
||||||
if (ret)
|
if (ret)
|
||||||
goto set_link_active;
|
goto set_link_active;
|
||||||
|
|
||||||
ret = ufshcd_vops_setup_clocks(hba, false);
|
|
||||||
if (ret)
|
|
||||||
goto vops_resume;
|
|
||||||
|
|
||||||
if (!ufshcd_is_link_active(hba))
|
if (!ufshcd_is_link_active(hba))
|
||||||
ufshcd_setup_clocks(hba, false);
|
ret = ufshcd_disable_clocks(hba, false);
|
||||||
else
|
else
|
||||||
/* If link is active, device ref_clk can't be switched off */
|
/* 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;
|
hba->clk_gating.state = CLKS_OFF;
|
||||||
trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state);
|
trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state);
|
||||||
|
@ -7611,8 +7621,6 @@ disable_clks:
|
||||||
ufshcd_hba_vreg_set_lpm(hba);
|
ufshcd_hba_vreg_set_lpm(hba);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
vops_resume:
|
|
||||||
ufshcd_vops_resume(hba, pm_op);
|
|
||||||
set_link_active:
|
set_link_active:
|
||||||
ufshcd_resume_clkscaling(hba);
|
ufshcd_resume_clkscaling(hba);
|
||||||
ufshcd_vreg_set_hpm(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);
|
ufshcd_hba_vreg_set_hpm(hba);
|
||||||
/* Make sure clocks are enabled before accessing controller */
|
/* Make sure clocks are enabled before accessing controller */
|
||||||
ret = ufshcd_setup_clocks(hba, true);
|
ret = ufshcd_enable_clocks(hba);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -7735,7 +7743,7 @@ disable_vreg:
|
||||||
disable_irq_and_vops_clks:
|
disable_irq_and_vops_clks:
|
||||||
ufshcd_disable_irq(hba);
|
ufshcd_disable_irq(hba);
|
||||||
ufshcd_suspend_clkscaling(hba);
|
ufshcd_suspend_clkscaling(hba);
|
||||||
ufshcd_setup_clocks(hba, false);
|
ufshcd_disable_clocks(hba, false);
|
||||||
out:
|
out:
|
||||||
hba->pm_op_in_progress = 0;
|
hba->pm_op_in_progress = 0;
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,7 @@ struct ufs_hba_variant_ops {
|
||||||
u32 (*get_ufs_hci_version)(struct ufs_hba *);
|
u32 (*get_ufs_hci_version)(struct ufs_hba *);
|
||||||
int (*clk_scale_notify)(struct ufs_hba *, bool,
|
int (*clk_scale_notify)(struct ufs_hba *, bool,
|
||||||
enum ufs_notify_change_status);
|
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 (*setup_regulators)(struct ufs_hba *, bool);
|
||||||
int (*hce_enable_notify)(struct ufs_hba *,
|
int (*hce_enable_notify)(struct ufs_hba *,
|
||||||
enum ufs_notify_change_status);
|
enum ufs_notify_change_status);
|
||||||
|
@ -1074,10 +1074,11 @@ static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba,
|
||||||
return 0;
|
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)
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue