|
@@ -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},
|
|
@@ -2105,6 +2096,7 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
|
|
|
}
|
|
|
/* Make sure that doorbell is committed immediately */
|
|
|
wmb();
|
|
|
+ trace_android_vh_ufs_send_command_post_change(hba, lrbp);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -2770,7 +2762,9 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
|
|
|
}
|
|
|
/* Make sure descriptors are ready before ringing the doorbell */
|
|
|
wmb();
|
|
|
-
|
|
|
+ trace_android_vh_ufs_perf_huristic_ctrl(hba, lrbp, &err);
|
|
|
+ if (err)
|
|
|
+ goto out;
|
|
|
ufshcd_send_command(hba, tag);
|
|
|
out:
|
|
|
up_read(&hba->clk_scaling_lock);
|
|
@@ -5203,7 +5197,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;
|
|
@@ -5214,6 +5208,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
|
|
@@ -5234,9 +5229,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);
|
|
@@ -5803,11 +5802,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
|
|
@@ -5921,7 +5922,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) {
|
|
@@ -5956,8 +5957,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);
|
|
@@ -5965,6 +5967,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)
|
|
|
{
|
|
@@ -6037,10 +6040,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)) {
|
|
@@ -6346,14 +6355,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);
|
|
@@ -6418,6 +6429,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);
|
|
@@ -6428,9 +6440,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;
|
|
|
}
|
|
|
|
|
@@ -7048,8 +7065,10 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
|
|
|
outstanding = __test_and_clear_bit(tag, &hba->outstanding_reqs);
|
|
|
spin_unlock_irqrestore(host->host_lock, flags);
|
|
|
|
|
|
- if (outstanding)
|
|
|
+ if (outstanding) {
|
|
|
ufshcd_release_scsi_cmd(hba, lrbp);
|
|
|
+ trace_android_vh_ufs_abort_success_ctrl(hba, lrbp);
|
|
|
+ }
|
|
|
|
|
|
err = SUCCESS;
|
|
|
|
|
@@ -7163,6 +7182,20 @@ static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd)
|
|
|
|
|
|
hba = shost_priv(cmd->device->host);
|
|
|
|
|
|
+ /*
|
|
|
+ * If runtime pm send SSU and got timeout, scsi_error_handler
|
|
|
+ * stuck at this function to wait for flush_work(&hba->eh_work).
|
|
|
+ * And ufshcd_err_handler(eh_work) stuck at wait for runtime pm active.
|
|
|
+ * Do ufshcd_link_recovery instead schedule eh_work can prevent
|
|
|
+ * dead lock to happen.
|
|
|
+ */
|
|
|
+ if (hba->pm_op_in_progress) {
|
|
|
+ if (ufshcd_link_recovery(hba))
|
|
|
+ err = FAILED;
|
|
|
+
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
spin_lock_irqsave(hba->host->host_lock, flags);
|
|
|
hba->force_reset = true;
|
|
|
ufshcd_schedule_eh_work(hba);
|