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

Commit 632ecc41 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "scsi: ufs: tune UniPro parameters to optimize hibern8 exit time"

parents b0353824 dd0b1193
Loading
Loading
Loading
Loading
+109 −0
Original line number Diff line number Diff line
@@ -791,6 +791,32 @@ static const char *ufschd_clk_gating_state_to_string(
	}
}

static u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba)
{
	/* HCI version < 2.0 supports UniPro 1.41 */
	if (hba->ufs_version < UFSHCI_VERSION_20)
		return UFS_UNIPRO_VER_1_41;
	else
		return UFS_UNIPRO_VER_1_6;
}

static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba)
{
	/*
	 * If both host and device support UniPro ver1.6 or later, PA layer
	 * parameters tuning happens during link startup itself.
	 *
	 * We can manually tune PA layer parameters if either host or device
	 * doesn't support UniPro ver 1.6 or later. But to keep manual tuning
	 * logic simple, we will only do manual tuning if local unipro version
	 * doesn't support ver1.6 or later.
	 */
	if (ufshcd_get_local_unipro_ver(hba) <= UFS_UNIPRO_VER_1_6)
		return true;
	else
		return false;
}

static void ufshcd_ungate_work(struct work_struct *work)
{
	int ret;
@@ -4891,6 +4917,88 @@ out:
	return err;
}

/**
 * ufshcd_tune_pa_tactivate - Tunes PA_TActivate of local UniPro
 * @hba: per-adapter instance
 *
 * PA_TActivate parameter can be tuned manually if UniPro version is less than
 * 1.61. PA_TActivate needs to be greater than or equal to peerM-PHY's
 * RX_MIN_ACTIVATETIME_CAPABILITY attribute. This optimal value can help reduce
 * the hibern8 exit latency.
 *
 * Returns zero on success, non-zero error value on failure.
 */
static int ufshcd_tune_pa_tactivate(struct ufs_hba *hba)
{
	int ret = 0;
	u32 peer_rx_min_activatetime = 0, tuned_pa_tactivate;

	if (!ufshcd_is_unipro_pa_params_tuning_req(hba))
		return 0;

	ret = ufshcd_dme_peer_get(hba,
				  UIC_ARG_MIB(RX_MIN_ACTIVATETIME_CAPABILITY),
				  &peer_rx_min_activatetime);
	if (ret)
		goto out;

	/* make sure proper unit conversion is applied */
	tuned_pa_tactivate =
		((peer_rx_min_activatetime * RX_MIN_ACTIVATETIME_UNIT_US)
		 / PA_TACTIVATE_TIME_UNIT_US);
	ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TACTIVATE),
			     tuned_pa_tactivate);

out:
	return ret;
}

/**
 * ufshcd_tune_pa_hibern8time - Tunes PA_Hibern8Time of local UniPro
 * @hba: per-adapter instance
 *
 * PA_Hibern8Time parameter can be tuned manually if UniPro version is less than
 * 1.61. PA_Hibern8Time needs to be maximum of local M-PHY's
 * TX_HIBERN8TIME_CAPABILITY & peer M-PHY's RX_HIBERN8TIME_CAPABILITY.
 * This optimal value can help reduce the hibern8 exit latency.
 *
 * Returns zero on success, non-zero error value on failure.
 */
static int ufshcd_tune_pa_hibern8time(struct ufs_hba *hba)
{
	int ret = 0;
	u32 local_tx_hibern8_time_cap = 0, peer_rx_hibern8_time_cap = 0;
	u32 max_hibern8_time, tuned_pa_hibern8time;

	ret = ufshcd_dme_get(hba, UIC_ARG_MIB(TX_HIBERN8TIME_CAPABILITY),
				  &local_tx_hibern8_time_cap);
	if (ret)
		goto out;

	ret = ufshcd_dme_peer_get(hba, UIC_ARG_MIB(RX_HIBERN8TIME_CAPABILITY),
				  &peer_rx_hibern8_time_cap);
	if (ret)
		goto out;

	max_hibern8_time = max(local_tx_hibern8_time_cap,
			       peer_rx_hibern8_time_cap);
	/* make sure proper unit conversion is applied */
	tuned_pa_hibern8time = ((max_hibern8_time * HIBERN8TIME_UNIT_US)
				/ PA_HIBERN8_TIME_UNIT_US);
	ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HIBERN8TIME),
			     tuned_pa_hibern8time);
out:
	return ret;
}

static void ufshcd_tune_unipro_params(struct ufs_hba *hba)
{
	if (ufshcd_is_unipro_pa_params_tuning_req(hba)) {
		ufshcd_tune_pa_tactivate(hba);
		ufshcd_tune_pa_hibern8time(hba);
	}
}

/**
 * ufshcd_probe_hba - probe hba to detect device and initialize
 * @hba: per-adapter instance
@@ -4921,6 +5029,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
		goto out;

	ufs_advertise_fixup_device(hba);
	ufshcd_tune_unipro_params(hba);

	if (!hba->is_init_prefetch) {
		ret = ufshcd_get_device_ref_clk(hba);
+1 −0
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ enum {
enum {
	UFSHCI_VERSION_10 = 0x00010000,
	UFSHCI_VERSION_11 = 0x00010100,
	UFSHCI_VERSION_20 = 0x00020000,
};

/*
+19 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
/*
 * M-TX Configuration Attributes
 */
#define TX_HIBERN8TIME_CAPABILITY		0x000F
#define TX_MODE					0x0021
#define TX_HSRATE_SERIES			0x0022
#define TX_HSGEAR				0x0023
@@ -46,8 +47,13 @@
#define RX_ENTER_HIBERN8			0x00A7
#define RX_BYPASS_8B10B_ENABLE			0x00A8
#define RX_TERMINATION_FORCE_ENABLE		0x0089
#define RX_MIN_ACTIVATETIME_CAPABILITY		0x008F
#define RX_HIBERN8TIME_CAPABILITY		0x0092

#define is_mphy_tx_attr(attr)			(attr < RX_MODE)
#define RX_MIN_ACTIVATETIME_UNIT_US		100
#define HIBERN8TIME_UNIT_US			100

/*
 * PHY Adpater attributes
 */
@@ -108,6 +114,9 @@
#define PA_STALLNOCONFIGTIME	0x15A3
#define PA_SAVECONFIGTIME	0x15A4

#define PA_TACTIVATE_TIME_UNIT_US	10
#define PA_HIBERN8_TIME_UNIT_US		100

/* PA power modes */
enum {
	FAST_MODE	= 1,
@@ -141,6 +150,16 @@ enum ufs_hs_gear_tag {
	UFS_HS_G3,		/* HS Gear 3 */
};

enum ufs_unipro_ver {
	UFS_UNIPRO_VER_RESERVED = 0,
	UFS_UNIPRO_VER_1_40 = 1, /* UniPro version 1.40 */
	UFS_UNIPRO_VER_1_41 = 2, /* UniPro version 1.41 */
	UFS_UNIPRO_VER_1_6 = 3,  /* UniPro version 1.6 */
	UFS_UNIPRO_VER_MAX = 4,  /* UniPro unsupported version */
	/* UniPro version field mask in PA_LOCALVERINFO */
	UFS_UNIPRO_VER_MASK = 0xF,
};

/*
 * Data Link Layer Attributes
 */