Commit 82174440 authored by Stanley Chu's avatar Stanley Chu Committed by Martin K. Petersen

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: default avatarStanley Chu <stanley.chu@mediatek.com>
Reviewed-by: default avatarBean Huo <beanhuo@micron.com>
Reviewed-by: default avatarAlim Akhtar <alim.akhtar@samsung.com>
Reviewed-by: default avatarAvri Altman <Avri.Altman@wdc.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent f571b377
...@@ -5254,6 +5254,7 @@ static void ufshcd_err_handler(struct work_struct *work) ...@@ -5254,6 +5254,7 @@ static void ufshcd_err_handler(struct work_struct *work)
goto skip_err_handling; goto skip_err_handling;
} }
if ((hba->saved_err & INT_FATAL_ERRORS) || if ((hba->saved_err & INT_FATAL_ERRORS) ||
(hba->saved_err & UFSHCD_UIC_HIBERN8_MASK) ||
((hba->saved_err & UIC_ERROR) && ((hba->saved_err & UIC_ERROR) &&
(hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR | (hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR |
UFSHCD_UIC_DL_NAC_RECEIVED_ERROR | UFSHCD_UIC_DL_NAC_RECEIVED_ERROR |
...@@ -5413,6 +5414,23 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba) ...@@ -5413,6 +5414,23 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba)
__func__, hba->uic_error); __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 * ufshcd_check_errors - Check for errors that need s/w attention
* @hba: per-adapter instance * @hba: per-adapter instance
...@@ -5431,6 +5449,15 @@ static void ufshcd_check_errors(struct ufs_hba *hba) ...@@ -5431,6 +5449,15 @@ static void ufshcd_check_errors(struct ufs_hba *hba)
queue_eh_work = true; 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) { if (queue_eh_work) {
/* /*
* update the transfer error masks to sticky bits, let's do this * 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) ...@@ -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) static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
{ {
hba->errors = UFSHCD_ERROR_MASK & 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) if (hba->errors)
ufshcd_check_errors(hba); ufshcd_check_errors(hba);
......
...@@ -144,8 +144,10 @@ enum { ...@@ -144,8 +144,10 @@ enum {
#define CONTROLLER_FATAL_ERROR 0x10000 #define CONTROLLER_FATAL_ERROR 0x10000
#define SYSTEM_BUS_FATAL_ERROR 0x20000 #define SYSTEM_BUS_FATAL_ERROR 0x20000
#define UFSHCD_UIC_PWR_MASK (UIC_HIBERNATE_ENTER |\ #define UFSHCD_UIC_HIBERN8_MASK (UIC_HIBERNATE_ENTER |\
UIC_HIBERNATE_EXIT |\ UIC_HIBERNATE_EXIT)
#define UFSHCD_UIC_PWR_MASK (UFSHCD_UIC_HIBERN8_MASK |\
UIC_POWER_MODE) UIC_POWER_MODE)
#define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK) #define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment