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:
parent
bd20893138
commit
492d614a96
2 changed files with 58 additions and 3 deletions
|
@ -173,6 +173,9 @@ void ufshcd_update_query_stats(struct ufs_hba *hba,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define PWR_INFO_MASK 0xF
|
||||||
|
#define PWR_RX_OFFSET 4
|
||||||
|
|
||||||
#define UFSHCD_REQ_SENSE_SIZE 18
|
#define UFSHCD_REQ_SENSE_SIZE 18
|
||||||
|
|
||||||
#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
|
#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\
|
||||||
|
@ -4653,8 +4656,9 @@ int ufshcd_change_power_mode(struct ufs_hba *hba,
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/* if already configured to the requested pwr_mode */
|
/* if already configured to the requested pwr_mode */
|
||||||
if (pwr_mode->gear_rx == hba->pwr_info.gear_rx &&
|
if (!hba->restore_needed &&
|
||||||
pwr_mode->gear_tx == hba->pwr_info.gear_tx &&
|
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_rx == hba->pwr_info.lane_rx &&
|
||||||
pwr_mode->lane_tx == hba->pwr_info.lane_tx &&
|
pwr_mode->lane_tx == hba->pwr_info.lane_tx &&
|
||||||
pwr_mode->pwr_rx == hba->pwr_info.pwr_rx &&
|
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;
|
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.
|
* ufshcd_update_uic_error - check and set fatal UIC error flags.
|
||||||
* @hba: per-adapter instance
|
* @hba: per-adapter instance
|
||||||
|
@ -6314,6 +6364,8 @@ static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba)
|
||||||
hba->full_init_linereset = true;
|
hba->full_init_linereset = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!hba->full_init_linereset)
|
||||||
|
schedule_work(&hba->rls_work);
|
||||||
}
|
}
|
||||||
retval |= IRQ_HANDLED;
|
retval |= IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
@ -9922,6 +9974,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
|
||||||
/* Initialize work queues */
|
/* Initialize work queues */
|
||||||
INIT_WORK(&hba->eh_work, ufshcd_err_handler);
|
INIT_WORK(&hba->eh_work, ufshcd_err_handler);
|
||||||
INIT_WORK(&hba->eeh_work, ufshcd_exception_event_handler);
|
INIT_WORK(&hba->eeh_work, ufshcd_exception_event_handler);
|
||||||
|
INIT_WORK(&hba->rls_work, ufshcd_rls_handler);
|
||||||
|
|
||||||
/* Initialize UIC command mutex */
|
/* Initialize UIC command mutex */
|
||||||
mutex_init(&hba->uic_cmd_mutex);
|
mutex_init(&hba->uic_cmd_mutex);
|
||||||
|
|
|
@ -854,6 +854,7 @@ struct ufs_hba {
|
||||||
/* Work Queues */
|
/* Work Queues */
|
||||||
struct work_struct eh_work;
|
struct work_struct eh_work;
|
||||||
struct work_struct eeh_work;
|
struct work_struct eeh_work;
|
||||||
|
struct work_struct rls_work;
|
||||||
|
|
||||||
/* HBA Errors */
|
/* HBA Errors */
|
||||||
u32 errors;
|
u32 errors;
|
||||||
|
@ -950,9 +951,10 @@ struct ufs_hba {
|
||||||
|
|
||||||
bool full_init_linereset;
|
bool full_init_linereset;
|
||||||
struct pinctrl *pctrl;
|
struct pinctrl *pctrl;
|
||||||
|
|
||||||
int latency_hist_enabled;
|
int latency_hist_enabled;
|
||||||
struct io_latency_state io_lat_s;
|
struct io_latency_state io_lat_s;
|
||||||
|
bool restore_needed;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void ufshcd_mark_shutdown_ongoing(struct ufs_hba *hba)
|
static inline void ufshcd_mark_shutdown_ongoing(struct ufs_hba *hba)
|
||||||
|
|
Loading…
Add table
Reference in a new issue