From bf01359e5f60240479f71b0147bef7921a165bb3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 3 Feb 2020 15:51:00 +0000 Subject: [PATCH] Revert "Revert "FROMLIST: scsi: ufs: Flush exception event before suspend"" This reverts commit 4b4777168d4d9296d6b23ae26674bd60307e7fc1 which was a revert of commit 12db3a26e47e79e3a24b797726a8cdfcb98c95d5. We added it back by hand after the scsi upstream tree merge Bug: 143632303 Cc: Sayali Lokhande Cc: Asutosh Das Cc: Can Guo Cc: Asutosh Das Signed-off-by: Greg Kroah-Hartman Change-Id: I36f2931b04f7963b7121511d6061c13a18891b77 --- drivers/scsi/ufs/ufshcd.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 5710204f8ef5..6a51eb80c3a1 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -4800,8 +4800,15 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) * UFS device needs urgent BKOPs. */ if (!hba->pm_op_in_progress && - ufshcd_is_exception_event(lrbp->ucd_rsp_ptr)) - schedule_work(&hba->eeh_work); + ufshcd_is_exception_event(lrbp->ucd_rsp_ptr)) { + /* + * Prevent suspend once eeh_work is scheduled + * to avoid deadlock between ufshcd_suspend + * and exception event handler. + */ + if (schedule_work(&hba->eeh_work)) + pm_runtime_get_noresume(hba->dev); + } break; case UPIU_TRANSACTION_REJECT_UPIU: /* TODO: handle Reject UPIU Response */ @@ -5257,7 +5264,14 @@ static void ufshcd_exception_event_handler(struct work_struct *work) out: ufshcd_scsi_unblock_requests(hba); - pm_runtime_put_sync(hba->dev); + /* + * pm_runtime_get_noresume is called while scheduling + * eeh_work to avoid suspend racing with exception work. + * Hence decrement usage counter using pm_runtime_put_noidle + * to allow suspend on completion of exception event handler. + */ + pm_runtime_put_noidle(hba->dev); + pm_runtime_put(hba->dev); return; } @@ -7987,6 +8001,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) goto enable_gating; } + flush_work(&hba->eeh_work); ret = ufshcd_link_state_transition(hba, req_link_state, 1); if (ret) goto set_dev_active;