config_pwr_mode:
/* check if the power mode needs to be changed or not? */
- ret = ufshcd_config_pwr_mode(hba, &new_pwr_info);
+ ret = ufshcd_config_pwr_mode(hba, &new_pwr_info,
+ UFSHCD_PMC_POLICY_DONT_FORCE);
if (ret)
dev_err(hba->dev, "%s: failed err %d, old gear: (tx %d rx %d), new gear: (tx %d rx %d)",
__func__, ret,
pwr_mode_change = true;
}
if (pwr_mode_change) {
- ret = ufshcd_change_power_mode(hba, &temp_pwr_info);
+ ret = ufshcd_change_power_mode(hba, &temp_pwr_info,
+ UFSHCD_PMC_POLICY_DONT_FORCE);
if (ret)
goto out;
}
if (peer && (hba->quirks & UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE)
&& pwr_mode_change)
- ufshcd_change_power_mode(hba, &orig_pwr_info);
+ ufshcd_change_power_mode(hba, &orig_pwr_info,
+ UFSHCD_PMC_POLICY_DONT_FORCE);
out:
return ret;
}
* ufshcd_dme_change_power_mode() - UniPro DME Power Mode change sequence
* @hba: per-adapter instance
* @pwr_mode: pointer to the target power mode (gear/lane) attributes
+ * @pmc_policy: Power Mode change policy
*
* This function handles the low-level DME (Device Management Entity)
* configuration required to transition the UFS link to a new power mode. It
* Return: 0 on success, non-zero error code on failure.
*/
static int ufshcd_dme_change_power_mode(struct ufs_hba *hba,
- struct ufs_pa_layer_attr *pwr_mode)
+ struct ufs_pa_layer_attr *pwr_mode,
+ enum ufshcd_pmc_policy pmc_policy)
{
int ret;
/* if already configured to the requested pwr_mode */
- if (!hba->force_pmc &&
+ if (pmc_policy == UFSHCD_PMC_POLICY_DONT_FORCE &&
pwr_mode->gear_rx == hba->pwr_info.gear_rx &&
pwr_mode->gear_tx == hba->pwr_info.gear_tx &&
pwr_mode->lane_rx == hba->pwr_info.lane_rx &&
* ufshcd_change_power_mode() - Change UFS Link Power Mode
* @hba: per-adapter instance
* @pwr_mode: pointer to the target power mode (gear/lane) attributes
+ * @pmc_policy: Power Mode change policy
*
* This function handles the high-level sequence for changing the UFS link
* power mode. It triggers vendor-specific pre-change notification,
* Return: 0 on success, non-zero error code on failure.
*/
int ufshcd_change_power_mode(struct ufs_hba *hba,
- struct ufs_pa_layer_attr *pwr_mode)
+ struct ufs_pa_layer_attr *pwr_mode,
+ enum ufshcd_pmc_policy pmc_policy)
{
int ret;
ufshcd_vops_pwr_change_notify(hba, PRE_CHANGE, pwr_mode);
- ret = ufshcd_dme_change_power_mode(hba, pwr_mode);
+ ret = ufshcd_dme_change_power_mode(hba, pwr_mode, pmc_policy);
if (!ret)
ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, pwr_mode);
* ufshcd_config_pwr_mode - configure a new power mode
* @hba: per-adapter instance
* @desired_pwr_mode: desired power configuration
+ * @pmc_policy: Power Mode change policy
*
* Return: 0 upon success; < 0 upon failure.
*/
int ufshcd_config_pwr_mode(struct ufs_hba *hba,
- struct ufs_pa_layer_attr *desired_pwr_mode)
+ struct ufs_pa_layer_attr *desired_pwr_mode,
+ enum ufshcd_pmc_policy pmc_policy)
{
struct ufs_pa_layer_attr final_params = { 0 };
int ret;
memcpy(&final_params, desired_pwr_mode, sizeof(final_params));
}
- return ufshcd_change_power_mode(hba, &final_params);
+ return ufshcd_change_power_mode(hba, &final_params, pmc_policy);
}
EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode);
* are sent via bsg and/or sysfs.
*/
down_write(&hba->clk_scaling_lock);
- hba->force_pmc = true;
- pmc_err = ufshcd_config_pwr_mode(hba, &(hba->pwr_info));
+ pmc_err = ufshcd_config_pwr_mode(hba, &hba->pwr_info,
+ UFSHCD_PMC_POLICY_FORCE);
if (pmc_err) {
needs_reset = true;
dev_err(hba->dev, "%s: Failed to restore power mode, err = %d\n",
__func__, pmc_err);
}
- hba->force_pmc = false;
ufshcd_print_pwr_info(hba);
up_write(&hba->clk_scaling_lock);
spin_lock_irqsave(hba->host->host_lock, flags);
if (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);
+ ret = ufshcd_config_pwr_mode(hba, &hba->max_pwr_info.info,
+ UFSHCD_PMC_POLICY_DONT_FORCE);
if (ret) {
dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n",
__func__, ret);
UFSHCD_STATE_ERROR,
};
+/**
+ * enum ufshcd_pmc_policy - Power Mode change policy
+ * @UFSHCD_PMC_POLICY_DONT_FORCE: Do not force a Power Mode change.
+ * @UFSHCD_PMC_POLICY_FORCE: Force a Power Mode change even if current Power
+ * Mode is same as target Power Mode.
+ */
+enum ufshcd_pmc_policy {
+ UFSHCD_PMC_POLICY_DONT_FORCE,
+ UFSHCD_PMC_POLICY_FORCE,
+};
+
enum ufshcd_quirks {
/* Interrupt aggregation support is broken */
UFSHCD_QUIRK_BROKEN_INTR_AGGR = 1 << 0,
* @saved_uic_err: sticky UIC error mask
* @ufs_stats: various error counters
* @force_reset: flag to force eh_work perform a full reset
- * @force_pmc: flag to force a power mode change
* @silence_err_logs: flag to silence error logs
* @dev_cmd: ufs device management command information
* @last_dme_cmd_tstamp: time stamp of the last completed DME command
u32 saved_uic_err;
struct ufs_stats ufs_stats;
bool force_reset;
- bool force_pmc;
bool silence_err_logs;
/* Device management request data */
extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
u32 *mib_val, u8 peer);
extern int ufshcd_change_power_mode(struct ufs_hba *hba,
- struct ufs_pa_layer_attr *pwr_mode);
+ struct ufs_pa_layer_attr *pwr_mode,
+ enum ufshcd_pmc_policy pmc_policy);
extern int ufshcd_config_pwr_mode(struct ufs_hba *hba,
- struct ufs_pa_layer_attr *desired_pwr_mode);
+ struct ufs_pa_layer_attr *desired_pwr_mode,
+ enum ufshcd_pmc_policy pmc_policy);
extern int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode);
/* UIC command interfaces for DME primitives */