Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6bc35755 authored by Subhash Jadavani's avatar Subhash Jadavani
Browse files

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: default avatarSubhash Jadavani <subhashj@codeaurora.org>
parent b2e8be93
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -1236,7 +1236,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;
@@ -1812,7 +1823,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;
+35 −27
Original line number Diff line number Diff line
@@ -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);
@@ -1136,7 +1138,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);
@@ -7057,8 +7059,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;
@@ -7076,7 +7078,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;
	}
@@ -7109,7 +7111,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) {
@@ -7134,9 +7136,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)
@@ -7209,8 +7223,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);
@@ -7239,7 +7251,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;

@@ -7261,7 +7273,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:
@@ -7274,7 +7286,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;
	}
@@ -7619,15 +7631,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);
@@ -7640,8 +7650,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);
@@ -7688,7 +7696,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;

@@ -7764,7 +7772,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;

+4 −3
Original line number Diff line number Diff line
@@ -313,7 +313,7 @@ struct ufs_hba_variant_ops {
	void	(*exit)(struct ufs_hba *);
	u32	(*get_ufs_hci_version)(struct ufs_hba *);
	int	(*clk_scale_notify)(struct ufs_hba *, bool, bool);
	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);
@@ -1081,10 +1081,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;
}