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

Commit 850cbe65 authored by Subhash Jadavani's avatar Subhash Jadavani
Browse files

scsi: ufs: move dme peer quirk handling to ufshcd_dme_get_attr()



Some UFS host controllers may only allow accessing the peer DME attribute
in AUTO mode (FAST AUTO or SLOW AUTO) hence we had added a quirk for
switching to AUTO power mode before accessing the peer DME attribute.
But this quirk handling was only done in UFS driver's debugfs handling
hence this patch moves it to main driver ufshcd.c so that this quirk
handling is applied to all the peer DME accesses.

As we are doing this, this patch fixes 2 more related problem:
1. Current quirk was only handling the switch from FAST to FAST AUTO hence
this change adds the handling for SLOW to SLOW AUTO mode change as well.
2. ufsdbg_dme_read() helper function was always reading the local DME
attribute hence this change fix the same.

Change-Id: I475375fb57cd27cdafe1573c14d09dc7f9a2791b
Signed-off-by: default avatarSubhash Jadavani <subhashj@codeaurora.org>
parent e33b9fba
Loading
Loading
Loading
Loading
+9 −31
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@ struct desc_field_offset {
		}							\
	} while (0)

#define DOORBELL_CLR_TOUT_US	(1000 * 1000) /* 1 sec */

#ifdef CONFIG_UFS_FAULT_INJECTION

#define INJECT_COMMAND_HANG (0x0)
@@ -756,7 +758,6 @@ out:
static int ufsdbg_config_pwr_mode(struct ufs_hba *hba,
		struct ufs_pa_layer_attr *desired_pwr_mode)
{
	#define DOORBELL_CLR_TOUT_US	(1000 * 1000) /* 1 sec */
	int ret;

	pm_runtime_get_sync(hba->dev);
@@ -854,7 +855,11 @@ static int ufsdbg_dme_read(void *data, u64 *attr_val, bool peer)
	attr_id = peer ? hba->debugfs_files.dme_peer_attr_id :
			 hba->debugfs_files.dme_local_attr_id;
	pm_runtime_get_sync(hba->dev);
	ret = ufshcd_dme_get(hba, UIC_ARG_MIB(attr_id), &read_val);
	scsi_block_requests(hba->host);
	ret = ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US);
	if (!ret)
		ret = read_func(hba, UIC_ARG_MIB(attr_id), &read_val);
	scsi_unblock_requests(hba->host);
	pm_runtime_put_sync(hba->dev);

	if (!ret)
@@ -887,39 +892,12 @@ DEFINE_SIMPLE_ATTRIBUTE(ufsdbg_dme_local_read_ops,

static int ufsdbg_dme_peer_read(void *data, u64 *attr_val)
{
	int ret;
	struct ufs_hba *hba = data;
	struct ufs_pa_layer_attr orig_pwr_info;
	struct ufs_pa_layer_attr temp_pwr_info;
	bool restore_pwr_mode = false;

	if (!hba)
		return -EINVAL;

	if (hba->quirks & UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE) {
		orig_pwr_info = hba->pwr_info;
		temp_pwr_info = orig_pwr_info;
		if (orig_pwr_info.pwr_tx == FAST_MODE ||
		    orig_pwr_info.pwr_rx == FAST_MODE) {
			temp_pwr_info.pwr_tx = FASTAUTO_MODE;
			temp_pwr_info.pwr_rx = FASTAUTO_MODE;
			ret = ufsdbg_config_pwr_mode(hba, &temp_pwr_info);
			if (ret)
				goto out;
	else
				restore_pwr_mode = true;
		}
	}

	ret = ufsdbg_dme_read(data, attr_val, true);

	if (hba->quirks & UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE) {
		if (restore_pwr_mode)
			ufsdbg_config_pwr_mode(hba, &orig_pwr_info);
	}

out:
	return ret;
		return ufsdbg_dme_read(data, attr_val, true);
}

static int ufsdbg_dme_peer_set_attr_id(void *data, u64 attr_id)
+1 −1
Original line number Diff line number Diff line
@@ -764,7 +764,7 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
		hba->quirks |= (UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS
			      | UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP
			      | UFSHCD_QUIRK_BROKEN_LCC
			      | UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE);
			      | UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE);

		if ((minor == 0x001) && (step == 0x0001))
			hba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR;
+29 −0
Original line number Diff line number Diff line
@@ -2600,6 +2600,31 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
	const char *get = action[!!peer];
	int ret;
	int retries = UFS_UIC_COMMAND_RETRIES;
	struct ufs_pa_layer_attr orig_pwr_info;
	struct ufs_pa_layer_attr temp_pwr_info;
	bool pwr_mode_change = false;

	if (peer && (hba->quirks & UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE)) {
		orig_pwr_info = hba->pwr_info;
		temp_pwr_info = orig_pwr_info;

		if (orig_pwr_info.pwr_tx == FAST_MODE ||
		    orig_pwr_info.pwr_rx == FAST_MODE) {
			temp_pwr_info.pwr_tx = FASTAUTO_MODE;
			temp_pwr_info.pwr_rx = FASTAUTO_MODE;
			pwr_mode_change = true;
		} else if (orig_pwr_info.pwr_tx == SLOW_MODE ||
		    orig_pwr_info.pwr_rx == SLOW_MODE) {
			temp_pwr_info.pwr_tx = SLOWAUTO_MODE;
			temp_pwr_info.pwr_rx = SLOWAUTO_MODE;
			pwr_mode_change = true;
		}
		if (pwr_mode_change) {
			ret = ufshcd_change_power_mode(hba, &temp_pwr_info);
			if (ret)
				goto out;
		}
	}

	uic_cmd.command = peer ?
		UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
@@ -2624,6 +2649,10 @@ int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
	if (mib_val && !ret)
		*mib_val = uic_cmd.argument3;

	if (peer && (hba->quirks & UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE)
	    && pwr_mode_change)
		ufshcd_change_power_mode(hba, &orig_pwr_info);
out:
	return ret;
}
EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
+4 −3
Original line number Diff line number Diff line
@@ -510,10 +510,11 @@ struct ufs_hba {
	#define UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP		UFS_BIT(3)

	/*
	 * This quirk needs to be enabled if the host contoller doesn't
	 * allow reading the dme attributes of peer UniPro in FAST_MODE.
	 * This quirk needs to be enabled if the host contoller only allows
	 * accessing the peer dme attributes in AUTO mode (FAST AUTO or
	 * SLOW AUTO).
	 */
	#define UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE		UFS_BIT(4)
	#define UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE		UFS_BIT(4)

	unsigned int quirks;	/* Deviations from standard UFSHCI spec. */