Commit b06cf63d authored by Wang Shuaiwei's avatar Wang Shuaiwei Committed by Martin K. Petersen
Browse files

scsi: ufs: core: Fix bRefClkFreq write failure in HS-LSS mode



According to the UFS spec, the bRefClkFreq attribute can only be written
when both sub-links are in LS-MODE. However, in HS LSS mode with
resetmode = HS_MODE, if the UFS device's default bRefClkFreq value
differs from the host controller's dev_ref_clk_freq setting, the write
operation will fail.

To fix this issue, introduce ufshcd_get_op_mode() function to detect the
current link operational mode. Call ufshcd_set_dev_ref_clk() only when
both sub-links are in LS-MODE to ensure the attribute can be written
successfully.

Signed-off-by: default avatarWang Shuaiwei <wangshuaiwei1@xiaomi.com>
Link: https://patch.msgid.link/20260414033718.1459540-1-wangshuaiwei1@xiaomi.com


Reviewed-by: default avatarPeter Wang <peter.wang@mediatek.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 47e66bec
Loading
Loading
Loading
Loading
+28 −2
Original line number Diff line number Diff line
@@ -9259,6 +9259,30 @@ static void ufshcd_config_mcq(struct ufs_hba *hba)
		 hba->nutrs);
}

/**
 * ufshcd_get_op_mode - get UFS operating mode.
 * @hba: per-adapter instance
 *
 * Use the PA_PWRMODE value to represent the operating mode of UFS.
 *
 */
static enum ufs_op_mode ufshcd_get_op_mode(struct ufs_hba *hba)
{
	u32 mode;
	u8 rx_mode;
	u8 tx_mode;

	ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PWRMODE), &mode);
	rx_mode = (mode >> PWRMODE_RX_OFFSET) & PWRMODE_MASK;
	tx_mode = mode & PWRMODE_MASK;

	if ((rx_mode == SLOW_MODE || rx_mode == SLOWAUTO_MODE) &&
	    (tx_mode == SLOW_MODE || tx_mode == SLOWAUTO_MODE))
		return LS_MODE;

	return HS_MODE;
}

static int ufshcd_post_device_init(struct ufs_hba *hba)
{
	int ret;
@@ -9281,11 +9305,13 @@ static int ufshcd_post_device_init(struct ufs_hba *hba)
		return 0;

	/*
	 * Set the right value to bRefClkFreq before attempting to
	 * Set the right value to bRefClkFreq in LS_MODE before attempting to
	 * switch to HS gears.
	 */
	if (hba->dev_ref_clk_freq != REF_CLK_FREQ_INVAL)
	if (ufshcd_get_op_mode(hba) == LS_MODE &&
	    hba->dev_ref_clk_freq != REF_CLK_FREQ_INVAL)
		ufshcd_set_dev_ref_clk(hba);

	/* Gear up to HS gear. */
	ret = ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info,
				     UFSHCD_PMC_POLICY_DONT_FORCE);
+5 −0
Original line number Diff line number Diff line
@@ -333,6 +333,11 @@ enum ufs_eom_eye_mask {
#define DME_LocalTC0ReplayTimeOutVal		0xD042
#define DME_LocalAFC0ReqTimeOutVal		0xD043

enum ufs_op_mode {
	LS_MODE = 1,
	HS_MODE = 2,
};

/* PA power modes */
enum ufs_pa_pwr_mode {
	FAST_MODE	= 1,