scsi: ufs: Change power mode on line reset

Line reset can occur during hibernate enter, exit or
during PA_INIT. In some cases, system slowness problem
is observed when line reset happened during hibernate
enter process in auto hibernate mode of operation as
link remains in PWM-G1 mode. To fix this problem, read
PA_PWRmode, PA_TxGear and PA_RxGear if line reset is
detected and if link is in PWM-G1 mode, initiate power
mode change to expected HS gear.

Change-Id: Ic06a11c917e8954743c4dcf80b89fedeec4584ed
Signed-off-by: Asutosh Das <asutoshd@codeaurora.org>
Signed-off-by: Sayali Lokhande <sayalil@codeaurora.org>
This commit is contained in:
Asutosh Das 2017-09-15 16:14:26 +05:30 committed by Sayali Lokhande
parent bd20893138
commit 492d614a96
2 changed files with 58 additions and 3 deletions

View file

@ -173,6 +173,9 @@ void ufshcd_update_query_stats(struct ufs_hba *hba,
}
#endif
#define PWR_INFO_MASK 0xF
#define PWR_RX_OFFSET 4
#define UFSHCD_REQ_SENSE_SIZE 18
#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
@ -4653,8 +4656,9 @@ int ufshcd_change_power_mode(struct ufs_hba *hba,
int ret = 0;
/* if already configured to the requested pwr_mode */
if (pwr_mode->gear_rx == hba->pwr_info.gear_rx &&
pwr_mode->gear_tx == hba->pwr_info.gear_tx &&
if (!hba->restore_needed &&
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 &&
pwr_mode->lane_tx == hba->pwr_info.lane_tx &&
pwr_mode->pwr_rx == hba->pwr_info.pwr_rx &&
@ -6275,6 +6279,52 @@ static void ufshcd_update_uic_reg_hist(struct ufs_uic_err_reg_hist *reg_hist,
reg_hist->pos = (reg_hist->pos + 1) % UIC_ERR_REG_HIST_LENGTH;
}
static void ufshcd_rls_handler(struct work_struct *work)
{
struct ufs_hba *hba;
int ret = 0;
u32 mode;
hba = container_of(work, struct ufs_hba, rls_work);
ufshcd_scsi_block_requests(hba);
pm_runtime_get_sync(hba->dev);
ret = ufshcd_wait_for_doorbell_clr(hba, U64_MAX);
if (ret) {
dev_err(hba->dev,
"Timed out (%d) waiting for DB to clear\n",
ret);
goto out;
}
ufshcd_dme_get(hba, UIC_ARG_MIB(PA_PWRMODE), &mode);
if (hba->pwr_info.pwr_rx != ((mode >> PWR_RX_OFFSET) & PWR_INFO_MASK))
hba->restore_needed = true;
if (hba->pwr_info.pwr_tx != (mode & PWR_INFO_MASK))
hba->restore_needed = true;
ufshcd_dme_get(hba, UIC_ARG_MIB(PA_RXGEAR), &mode);
if (hba->pwr_info.gear_rx != mode)
hba->restore_needed = true;
ufshcd_dme_get(hba, UIC_ARG_MIB(PA_TXGEAR), &mode);
if (hba->pwr_info.gear_tx != mode)
hba->restore_needed = true;
if (hba->restore_needed)
ret = ufshcd_config_pwr_mode(hba, &(hba->pwr_info));
if (ret)
dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n",
__func__, ret);
else
hba->restore_needed = false;
out:
ufshcd_scsi_unblock_requests(hba);
pm_runtime_put_sync(hba->dev);
}
/**
* ufshcd_update_uic_error - check and set fatal UIC error flags.
* @hba: per-adapter instance
@ -6314,6 +6364,8 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba)
hba->full_init_linereset = true;
}
}
if (!hba->full_init_linereset)
schedule_work(&hba->rls_work);
}
retval |= IRQ_HANDLED;
}
@ -9922,6 +9974,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
/* Initialize work queues */
INIT_WORK(&hba->eh_work, ufshcd_err_handler);
INIT_WORK(&hba->eeh_work, ufshcd_exception_event_handler);
INIT_WORK(&hba->rls_work, ufshcd_rls_handler);
/* Initialize UIC command mutex */
mutex_init(&hba->uic_cmd_mutex);

View file

@ -854,6 +854,7 @@ struct ufs_hba {
/* Work Queues */
struct work_struct eh_work;
struct work_struct eeh_work;
struct work_struct rls_work;
/* HBA Errors */
u32 errors;
@ -950,9 +951,10 @@ struct ufs_hba {
bool full_init_linereset;
struct pinctrl *pctrl;
int latency_hist_enabled;
struct io_latency_state io_lat_s;
bool restore_needed;
};
static inline void ufshcd_mark_shutdown_ongoing(struct ufs_hba *hba)