diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 36c6646873c5..fa7106d2c8aa 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -145,10 +145,7 @@ enum { UFSHCD_STATE_EH_SCHEDULED_NON_FATAL, }; -/* UFSHCD error handling flags */ -enum { - UFSHCD_EH_IN_PROGRESS = (1 << 0), -}; + /* UFSHCD UIC layer error flags */ enum { @@ -161,12 +158,6 @@ enum { UFSHCD_UIC_PA_GENERIC_ERROR = (1 << 6), /* Generic PA error */ }; -#define ufshcd_set_eh_in_progress(h) \ - ((h)->eh_flags |= UFSHCD_EH_IN_PROGRESS) -#define ufshcd_eh_in_progress(h) \ - ((h)->eh_flags & UFSHCD_EH_IN_PROGRESS) -#define ufshcd_clear_eh_in_progress(h) \ - ((h)->eh_flags &= ~UFSHCD_EH_IN_PROGRESS) struct ufs_pm_lvl_states ufs_pm_lvl_states[] = { {UFS_ACTIVE_PWR_MODE, UIC_LINK_ACTIVE_STATE}, @@ -5207,7 +5198,7 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) } /* Release the resources allocated for processing a SCSI command. */ -static void ufshcd_release_scsi_cmd(struct ufs_hba *hba, +void ufshcd_release_scsi_cmd(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) { struct scsi_cmnd *cmd = lrbp->cmd; @@ -5218,6 +5209,7 @@ static void ufshcd_release_scsi_cmd(struct ufs_hba *hba, ufshcd_release(hba); ufshcd_clk_scaling_update_busy(hba); } +EXPORT_SYMBOL_GPL(ufshcd_release_scsi_cmd); /** * __ufshcd_transfer_req_compl - handle SCSI and query command completion @@ -5238,9 +5230,13 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, lrbp->compl_time_stamp = ktime_get(); cmd = lrbp->cmd; if (cmd) { + bool done = false; if (unlikely(ufshcd_should_inform_monitor(hba, lrbp))) ufshcd_update_monitor(hba, lrbp); trace_android_vh_ufs_compl_command(hba, lrbp); + trace_android_vh_ufs_compl_rsp_check_done(hba, lrbp, &done); + if (done) + return; ufshcd_add_command_trace(hba, index, "complete"); cmd->result = ufshcd_transfer_rsp_status(hba, lrbp); ufshcd_release_scsi_cmd(hba, lrbp); @@ -5807,11 +5803,13 @@ out: } /* Complete requests that have door-bell cleared */ -static void ufshcd_complete_requests(struct ufs_hba *hba) +void ufshcd_complete_requests(struct ufs_hba *hba) { ufshcd_trc_handler(hba, false); ufshcd_tmc_handler(hba); } +EXPORT_SYMBOL_GPL(ufshcd_complete_requests); + /** * ufshcd_quirk_dl_nac_errors - This function checks if error handling is @@ -5925,7 +5923,7 @@ static void ufshcd_clk_scaling_suspend(struct ufs_hba *hba, bool suspend) } } -static void ufshcd_err_handling_prepare(struct ufs_hba *hba) +void ufshcd_err_handling_prepare(struct ufs_hba *hba) { pm_runtime_get_sync(hba->dev); if (pm_runtime_status_suspended(hba->dev) || hba->is_sys_suspended) { @@ -5960,8 +5958,9 @@ static void ufshcd_err_handling_prepare(struct ufs_hba *hba) up_write(&hba->clk_scaling_lock); cancel_work_sync(&hba->eeh_work); } +EXPORT_SYMBOL_GPL(ufshcd_err_handling_prepare); -static void ufshcd_err_handling_unprepare(struct ufs_hba *hba) +void ufshcd_err_handling_unprepare(struct ufs_hba *hba) { ufshcd_scsi_unblock_requests(hba); ufshcd_release(hba); @@ -5969,6 +5968,7 @@ static void ufshcd_err_handling_unprepare(struct ufs_hba *hba) ufshcd_clk_scaling_suspend(hba, false); pm_runtime_put(hba->dev); } +EXPORT_SYMBOL_GPL(ufshcd_err_handling_unprepare); static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba) { @@ -6041,10 +6041,16 @@ static void ufshcd_err_handler(struct work_struct *work) bool err_tm = false; int err = 0, pmc_err; int tag; + bool err_handled = false; bool needs_reset = false, needs_restore = false; hba = container_of(work, struct ufs_hba, eh_work); + trace_android_vh_ufs_err_handler(hba, &err_handled); + + if (err_handled) + return; + down(&hba->host_sem); spin_lock_irqsave(hba->host->host_lock, flags); if (ufshcd_err_handling_should_stop(hba)) { @@ -6350,14 +6356,16 @@ static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba, u32 intr_status) * update the transfer error masks to sticky bits, let's do this * irrespective of current ufshcd_state. */ + bool skip = false; hba->saved_err |= hba->errors; hba->saved_uic_err |= hba->uic_error; + trace_android_vh_ufs_err_print_ctrl(hba, &skip); /* dump controller state before resetting */ - if ((hba->saved_err & + if (!skip &&((hba->saved_err & (INT_FATAL_ERRORS | UFSHCD_UIC_HIBERN8_MASK)) || (hba->saved_uic_err && - (hba->saved_uic_err != UFSHCD_UIC_PA_GENERIC_ERROR))) { + (hba->saved_uic_err != UFSHCD_UIC_PA_GENERIC_ERROR)))) { dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x\n", __func__, hba->saved_err, hba->saved_uic_err); @@ -6422,6 +6430,7 @@ static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba) static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) { irqreturn_t retval = IRQ_NONE; + bool err_check = false; if (intr_status & UFSHCD_UIC_MASK) retval |= ufshcd_uic_cmd_compl(hba, intr_status); @@ -6432,9 +6441,14 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) if (intr_status & UTP_TASK_REQ_COMPL) retval |= ufshcd_tmc_handler(hba); - if (intr_status & UTP_TRANSFER_REQ_COMPL) + if (intr_status & UTP_TRANSFER_REQ_COMPL) { retval |= ufshcd_trc_handler(hba, ufshcd_has_utrlcnr(hba)); + trace_android_vh_ufs_err_check_ctrl(hba, &err_check); + if (err_check) + ufshcd_check_errors(hba, hba->errors); + } + return retval; } diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 6b80ac49908c..00a844f6dfa6 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -82,6 +82,19 @@ enum ufs_event_type { UFS_EVT_CNT, }; +/* UFSHCD error handling flags */ +enum { + UFSHCD_EH_IN_PROGRESS = (1 << 0), +}; + +#define ufshcd_set_eh_in_progress(h) \ + ((h)->eh_flags |= UFSHCD_EH_IN_PROGRESS) +#define ufshcd_eh_in_progress(h) \ + ((h)->eh_flags & UFSHCD_EH_IN_PROGRESS) +#define ufshcd_clear_eh_in_progress(h) \ + ((h)->eh_flags &= ~UFSHCD_EH_IN_PROGRESS) + + /** * struct uic_command - UIC command structure * @command: UIC command @@ -1048,6 +1061,12 @@ int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, void ufshcd_parse_dev_ref_clk_freq(struct ufs_hba *hba, struct clk *refclk); void ufshcd_update_evt_hist(struct ufs_hba *hba, u32 id, u32 val); void ufshcd_hba_stop(struct ufs_hba *hba); +void ufshcd_complete_requests(struct ufs_hba *hba); +void ufshcd_release_scsi_cmd(struct ufs_hba *hba, + struct ufshcd_lrb *lrbp); +void ufshcd_err_handling_prepare(struct ufs_hba *hba); +void ufshcd_err_handling_unprepare(struct ufs_hba *hba); + static inline void check_upiu_size(void) {