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

Commit 279f4d7c authored by Subhash Jadavani's avatar Subhash Jadavani Committed by David Keitel
Browse files

scsi: ufs: remove unwanted checks from hibern8 sequence



We are unnecessarily checking for the request/task doorbell status
during hibern8 enter/exit path but it's very important to have the
minimal latencies for hibern8 enter/exit in order to achieve agressive
power management strategies for UFS. So these unecessary checks are moved
out of this hot path.

Change-Id: Ibaeddca7bd516d71eb03b02a1fc1a86f05038f08
Signed-off-by: default avatarSubhash Jadavani <subhashj@codeaurora.org>
[venkatg@codeaurora.org: resolved trivial merge conflicts]
Signed-off-by: default avatarVenkat Gopalakrishnan <venkatg@codeaurora.org>
parent ad03d1f9
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -668,6 +668,7 @@ static ssize_t ufsdbg_power_mode_write(struct file *file,
	loff_t buff_pos = 0;
	int ret;
	int idx = 0;
	#define DOORBELL_CLR_TOUT_US	(1000 * 1000) /* 1 sec */

	ret = simple_write_to_buffer(pwr_mode_str, BUFF_LINE_CAPACITY,
		&buff_pos, ubuf, cnt);
@@ -695,7 +696,11 @@ static ssize_t ufsdbg_power_mode_write(struct file *file,
		pwr_mode.lane_tx, pwr_mode.pwr_rx, pwr_mode.pwr_tx);

	pm_runtime_get_sync(hba->dev);
	scsi_block_requests(hba->host);
	ret = ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US);
	if (!ret)
		ret = ufshcd_config_pwr_mode(hba, &pwr_mode);
	scsi_unblock_requests(hba->host);
	pm_runtime_put_sync(hba->dev);
	if (ret == -EBUSY)
		dev_err(hba->dev,
+47 −31
Original line number Diff line number Diff line
@@ -2715,43 +2715,13 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
	unsigned long flags;
	u8 status;
	int ret;
	u32 tm_doorbell;
	u32 tr_doorbell;
	bool uic_ready;
	int retries = POWER_MODE_RETRIES;

	mutex_lock(&hba->uic_cmd_mutex);
	init_completion(&uic_async_done);
	ufshcd_add_delay_before_dme_cmd(hba);

	/*
	 * Before changing the power mode there should be no outstanding
	 * tasks/transfer requests. Verify by checking the doorbell registers
	 * are clear.
	 */
	do {
	spin_lock_irqsave(hba->host->host_lock, flags);
		uic_ready = ufshcd_ready_for_uic_cmd(hba);
		tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
		tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
		if (!tm_doorbell && !tr_doorbell && uic_ready)
			break;

		spin_unlock_irqrestore(hba->host->host_lock, flags);
		schedule();
		retries--;
	} while (retries && (tm_doorbell || tr_doorbell || !uic_ready));

	if (!retries) {
		dev_err(hba->dev,
			"%s: too many retries waiting for doorbell to clear (tm=0x%x, tr=0x%x, uicrdy=%d)\n",
			__func__, tm_doorbell, tr_doorbell, uic_ready);
		ret = -EBUSY;
		goto out;
	}

	hba->uic_async_done = &uic_async_done;

	ret = __ufshcd_send_uic_cmd(hba, cmd);
	spin_unlock_irqrestore(hba->host->host_lock, flags);
	if (ret) {
@@ -2792,6 +2762,52 @@ out:
	return ret;
}

int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us)
{
	unsigned long flags;
	int ret = 0;
	u32 tm_doorbell;
	u32 tr_doorbell;
	bool timeout = false;
	ktime_t start = ktime_get();

	spin_lock_irqsave(hba->host->host_lock, flags);
	if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
		ret = -EBUSY;
		goto out;
	}

	/*
	 * Wait for all the outstanding tasks/transfer requests.
	 * Verify by checking the doorbell registers are clear.
	 */
	do {
		tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
		tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
		if (!tm_doorbell && !tr_doorbell) {
			timeout = false;
			break;
		}

		spin_unlock_irqrestore(hba->host->host_lock, flags);
		schedule();
		if (ktime_to_us(ktime_sub(ktime_get(), start)) >
		    wait_timeout_us)
			timeout = true;
		spin_lock_irqsave(hba->host->host_lock, flags);
	} while (tm_doorbell || tr_doorbell);

	if (timeout) {
		dev_err(hba->dev,
			"%s: timedout waiting for doorbell to clear (tm=0x%x, tr=0x%x)\n",
			__func__, tm_doorbell, tr_doorbell);
		ret = -EBUSY;
	}
out:
	spin_unlock_irqrestore(hba->host->host_lock, flags);
	return ret;
}

/**
 * ufshcd_uic_change_pwr_mode - Perform the UIC power mode chage
 *				using DME_SET primitives.
+59 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#ifndef PHY_QCOM_UFS_H_
#define PHY_QCOM_UFS_H_

#include "phy.h"

/**
 * ufs_qcom_phy_enable_ref_clk() - Enable the phy
 * ref clock.
 * @phy: reference to a generic phy
 *
 * returns 0 for success, and non-zero for error.
 */
int ufs_qcom_phy_enable_ref_clk(struct phy *phy);

/**
 * ufs_qcom_phy_disable_ref_clk() - Disable the phy
 * ref clock.
 * @phy: reference to a generic phy.
 */
void ufs_qcom_phy_disable_ref_clk(struct phy *phy);

/**
 * ufs_qcom_phy_enable_dev_ref_clk() - Enable the device
 * ref clock.
 * @phy: reference to a generic phy.
 */
void ufs_qcom_phy_enable_dev_ref_clk(struct phy *phy);

/**
 * ufs_qcom_phy_disable_dev_ref_clk() - Disable the device
 * ref clock.
 * @phy: reference to a generic phy.
 */
void ufs_qcom_phy_disable_dev_ref_clk(struct phy *phy);

int ufs_qcom_phy_enable_iface_clk(struct phy *phy);
void ufs_qcom_phy_disable_iface_clk(struct phy *phy);
int ufs_qcom_phy_start_serdes(struct phy *phy);
int ufs_qcom_phy_set_tx_lane_enable(struct phy *phy, u32 tx_lanes);
int ufs_qcom_phy_calibrate_phy(struct phy *phy, bool is_rate_B);
int ufs_qcom_phy_is_pcs_ready(struct phy *phy);
void ufs_qcom_phy_save_controller_version(struct phy *phy,
			u8 major, u16 minor, u16 step);

#endif /* PHY_QCOM_UFS_H_ */
+1 −1
Original line number Diff line number Diff line
@@ -771,6 +771,7 @@ int ufshcd_query_descriptor(struct ufs_hba *hba, enum query_opcode opcode,

int ufshcd_hold(struct ufs_hba *hba, bool async);
void ufshcd_release(struct ufs_hba *hba);
int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us);

/* Wrapper functions for safely calling variant operations */
static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
@@ -875,5 +876,4 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
	if (hba->vops && hba->vops->dbg_register_dump)
		hba->vops->dbg_register_dump(hba);
}

#endif /* End of Header */