forked from Minki/linux
scsi: ufs: Add error-handling of Auto-Hibernate
Currently auto-hibernate is activated if host supports auto-hibern8 capability. However error-handling is not implemented, which makes the feature somewhat risky. If either "Hibernate Enter" or "Hibernate Exit" fail during auto-hibernate flow, the corresponding interrupt "UIC_HIBERNATE_ENTER" or "UIC_HIBERNATE_EXIT" shall be raised according to UFS specification. This patch adds auto-hibernate error-handling: - Monitor "Hibernate Enter" and "Hibernate Exit" interrupts after auto-hibernate feature is activated. - If a failure happens, trigger error-handling just like "manual-hibernate" failure and apply the same recovery flow: schedule UFS error handler in ufshcd_check_errors(), and then do host reset and restore in UFS error handler. Signed-off-by: Stanley Chu <stanley.chu@mediatek.com> Reviewed-by: Bean Huo <beanhuo@micron.com> Reviewed-by: Alim Akhtar <alim.akhtar@samsung.com> Reviewed-by: Avri Altman <Avri.Altman@wdc.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
f571b377de
commit
8217444039
@ -5254,6 +5254,7 @@ static void ufshcd_err_handler(struct work_struct *work)
|
||||
goto skip_err_handling;
|
||||
}
|
||||
if ((hba->saved_err & INT_FATAL_ERRORS) ||
|
||||
(hba->saved_err & UFSHCD_UIC_HIBERN8_MASK) ||
|
||||
((hba->saved_err & UIC_ERROR) &&
|
||||
(hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR |
|
||||
UFSHCD_UIC_DL_NAC_RECEIVED_ERROR |
|
||||
@ -5413,6 +5414,23 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba)
|
||||
__func__, hba->uic_error);
|
||||
}
|
||||
|
||||
static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba,
|
||||
u32 intr_mask)
|
||||
{
|
||||
if (!ufshcd_is_auto_hibern8_supported(hba))
|
||||
return false;
|
||||
|
||||
if (!(intr_mask & UFSHCD_UIC_HIBERN8_MASK))
|
||||
return false;
|
||||
|
||||
if (hba->active_uic_cmd &&
|
||||
(hba->active_uic_cmd->command == UIC_CMD_DME_HIBER_ENTER ||
|
||||
hba->active_uic_cmd->command == UIC_CMD_DME_HIBER_EXIT))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ufshcd_check_errors - Check for errors that need s/w attention
|
||||
* @hba: per-adapter instance
|
||||
@ -5431,6 +5449,15 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
|
||||
queue_eh_work = true;
|
||||
}
|
||||
|
||||
if (hba->errors & UFSHCD_UIC_HIBERN8_MASK) {
|
||||
dev_err(hba->dev,
|
||||
"%s: Auto Hibern8 %s failed - status: 0x%08x, upmcrs: 0x%08x\n",
|
||||
__func__, (hba->errors & UIC_HIBERNATE_ENTER) ?
|
||||
"Enter" : "Exit",
|
||||
hba->errors, ufshcd_get_upmcrs(hba));
|
||||
queue_eh_work = true;
|
||||
}
|
||||
|
||||
if (queue_eh_work) {
|
||||
/*
|
||||
* update the transfer error masks to sticky bits, let's do this
|
||||
@ -5493,6 +5520,10 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba)
|
||||
static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
|
||||
{
|
||||
hba->errors = UFSHCD_ERROR_MASK & intr_status;
|
||||
|
||||
if (ufshcd_is_auto_hibern8_error(hba, intr_status))
|
||||
hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status);
|
||||
|
||||
if (hba->errors)
|
||||
ufshcd_check_errors(hba);
|
||||
|
||||
|
@ -144,8 +144,10 @@ enum {
|
||||
#define CONTROLLER_FATAL_ERROR 0x10000
|
||||
#define SYSTEM_BUS_FATAL_ERROR 0x20000
|
||||
|
||||
#define UFSHCD_UIC_PWR_MASK (UIC_HIBERNATE_ENTER |\
|
||||
UIC_HIBERNATE_EXIT |\
|
||||
#define UFSHCD_UIC_HIBERN8_MASK (UIC_HIBERNATE_ENTER |\
|
||||
UIC_HIBERNATE_EXIT)
|
||||
|
||||
#define UFSHCD_UIC_PWR_MASK (UFSHCD_UIC_HIBERN8_MASK |\
|
||||
UIC_POWER_MODE)
|
||||
|
||||
#define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK)
|
||||
|
Loading…
Reference in New Issue
Block a user