summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wang <peter.wang@mediatek.com>2025-10-08 14:55:43 +0800
committerMartin K. Petersen <martin.petersen@oracle.com>2025-10-21 20:50:28 -0400
commite23ef4f22db30a1e49c8b060e4ebc9dc9ca99c49 (patch)
tree099eeb0a1d42386d6cf49e5c72b840d49eebe3c2
parenta0b7780602b1b196f47e527fec82166a7e67c4d0 (diff)
scsi: ufs: core: Fix error handler host_sem issue
Fix the issue where host_sem is not released due to a new return path in commit f966e02ae521 ("scsi: ufs: core: Fix runtime suspend error deadlock"). Check pm_op_in_progress before acquiring hba->host_sem to prevent deadlocks and ensure proper resource management during error handling. Add comment for use ufshcd_rpm_get_noresume() to safely perform link recovery without interfering with ongoing PM operations. Fixes: f966e02ae521 ("scsi: ufs: core: Fix runtime suspend error deadlock") Reported-by: Dan Carpenter <dan.carpenter@linaro.org> Signed-off-by: Peter Wang <peter.wang@mediatek.com> Reviewed-by: Bart Van Assche <bvanassche@acm.org> Link: https://patch.msgid.link/20251008065651.1589614-2-peter.wang@mediatek.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/ufs/core/ufshcd.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 8339fec975b9..8f4e884892a9 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -6673,6 +6673,20 @@ static void ufshcd_err_handler(struct work_struct *work)
hba->saved_uic_err, hba->force_reset,
ufshcd_is_link_broken(hba) ? "; link is broken" : "");
+ /*
+ * Use ufshcd_rpm_get_noresume() here to safely perform link recovery
+ * even if an error occurs during runtime suspend or runtime resume.
+ * This avoids potential deadlocks that could happen if we tried to
+ * resume the device while a PM operation is already in progress.
+ */
+ ufshcd_rpm_get_noresume(hba);
+ if (hba->pm_op_in_progress) {
+ ufshcd_link_recovery(hba);
+ ufshcd_rpm_put(hba);
+ return;
+ }
+ ufshcd_rpm_put(hba);
+
down(&hba->host_sem);
spin_lock_irqsave(hba->host->host_lock, flags);
if (ufshcd_err_handling_should_stop(hba)) {
@@ -6684,14 +6698,6 @@ static void ufshcd_err_handler(struct work_struct *work)
}
spin_unlock_irqrestore(hba->host->host_lock, flags);
- ufshcd_rpm_get_noresume(hba);
- if (hba->pm_op_in_progress) {
- ufshcd_link_recovery(hba);
- ufshcd_rpm_put(hba);
- return;
- }
- ufshcd_rpm_put(hba);
-
ufshcd_err_handling_prepare(hba);
spin_lock_irqsave(hba->host->host_lock, flags);