From: HOYOUNG SEO <hy50.seo@samsung.com>
To: linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org,
bvanassche@acm.org, mkp@kernel.org, martin.petersen@oracle.com,
stanleyjhu@google.com, peter.wang@mediatek.com,
alim.akhtar@samsung.com, kwangwon.min@samsung.com,
kwmad.kim@samsung.com, cpgsproxy1@samsung.com,
h10.kim@samsung.com
Cc: HOYOUNG SEO <hy50.seo@samsung.com>
Subject: [PATCH v10 4/4] scsi: ufs: core: Limit early link recovery in the error handler to runtime PM
Date: Wed, 11 Nov 2026 17:18:34 +0900 [thread overview]
Message-ID: <282821294.121794387787588.JavaMail.epsvc@epcpadp2new> (raw)
In-Reply-To: <cover.1794384665.git.hy50.seo@samsung.com>
ufshcd_err_handler() recovers the link without taking hba->host_sem
whenever hba->pm_op_in_progress is set. That early path was added by
commit f966e02ae521 ("scsi: ufs: core: Fix runtime suspend error
deadlock") because the regular error handling would wait for a runtime
PM operation that cannot complete while the error handler is waiting.
pm_op_in_progress is also set during system suspend, system resume,
shutdown and poweroff, where the early path is not needed and runs
concurrently with the PM path itself. For example, if a LINERESET is
reported and the hibern8 exit fails in __ufshcd_wl_resume() during
system resume, both ufshcd_err_handler() and __ufshcd_wl_resume() call
ufshcd_link_recovery(), and the host and the device may be reset at the
same time.
Only take the early path while pm_op_in_progress is set and a runtime
suspend or resume of the WLUN is in progress. The runtime PM core sets
the runtime status of the WLUN to RPM_SUSPENDING or RPM_RESUMING while
ufshcd_wl_runtime_suspend() or ufshcd_wl_runtime_resume() runs, and it
is RPM_ACTIVE or RPM_SUSPENDED during system PM. The runtime status
alone is not enough: it also covers the block layer steps before and
after the driver callbacks, where the early link recovery must not run.
pm_op_in_progress is only set while __ufshcd_wl_suspend() or
__ufshcd_wl_resume() run, which is inside that window.
Both checks are done in the new function ufshcd_in_wl_rpm_callback().
The runtime status is only available with CONFIG_PM, so the function
returns false without it. Both values are read without locking, so use
READ_ONCE() for them and WRITE_ONCE() when pm_op_in_progress is
updated. As the window of pm_op_in_progress is contained in the runtime
PM window, a stale value of either one can only make the error handler
take the regular path, like an error handler that starts just before or
after the PM operation.
For the other PM operations the regular error handling is safe:
- the system PM callbacks hold host_sem from ufshcd_wl_suspend() until
ufshcd_wl_resume() returns, and ufshcd_wl_poweroff() holds it as
well, so the error handler waits for them;
- during shutdown, hba->shutting_down makes the error handler stop.
This changes the behavior during shutdown: errors that occur while the
final START STOP UNIT command is being processed are no longer handled
by the error handler. Recovery then only happens through
ufshcd_eh_timed_out().
Fixes: e23ef4f22db3 ("scsi: ufs: core: Fix error handler host_sem issue")
Signed-off-by: HOYOUNG SEO <hy50.seo@samsung.com>
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
---
drivers/ufs/core/ufshcd.c | 32 +++++++++++++++++++++++++++-----
1 file changed, 27 insertions(+), 5 deletions(-)
diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c
index 8aea99f5c364..09c8095141e2 100644
--- a/drivers/ufs/core/ufshcd.c
+++ b/drivers/ufs/core/ufshcd.c
@@ -7062,6 +7062,23 @@ static bool ufshcd_abort_all(struct ufs_hba *hba)
return ret != 0;
}
+/*
+ * Whether a runtime PM callback of the WLUN runs __ufshcd_wl_suspend() or
+ * __ufshcd_wl_resume().
+ */
+static bool ufshcd_in_wl_rpm_callback(struct ufs_hba *hba)
+{
+#ifdef CONFIG_PM
+ enum rpm_status status =
+ READ_ONCE(hba->ufs_device_wlun->sdev_gendev.power.runtime_status);
+
+ return READ_ONCE(hba->pm_op_in_progress) &&
+ (status == RPM_SUSPENDING || status == RPM_RESUMING);
+#else
+ return false;
+#endif
+}
+
/**
* ufshcd_err_handler - handle UFS errors that require s/w attention
* @work: pointer to work structure
@@ -7091,9 +7108,14 @@ static void ufshcd_err_handler(struct work_struct *work)
* runtime resume. This avoids potential deadlocks that could
* happen if we tried to resume the device while a PM operation
* is already in progress.
+ *
+ * Do this only while the PM callbacks run for a runtime PM
+ * operation. The system PM and poweroff callbacks hold
+ * host_sem, and shutting_down makes the regular path below
+ * stop, so it does not reset the link concurrently with them.
*/
ufshcd_rpm_get_noresume(hba);
- if (hba->pm_op_in_progress) {
+ if (ufshcd_in_wl_rpm_callback(hba)) {
ufshcd_link_recovery(hba);
ufshcd_rpm_put(hba);
return;
@@ -10392,7 +10414,7 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
enum ufs_dev_pwr_mode req_dev_pwr_mode;
enum uic_link_state req_link_state;
- hba->pm_op_in_progress = true;
+ WRITE_ONCE(hba->pm_op_in_progress, true);
if (pm_op != UFS_SHUTDOWN_PM) {
pm_lvl = pm_op == UFS_RUNTIME_PM ?
hba->rpm_lvl : hba->spm_lvl;
@@ -10565,7 +10587,7 @@ static int __ufshcd_wl_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
hba->clk_gating.is_suspended = false;
ufshcd_release(hba);
}
- hba->pm_op_in_progress = false;
+ WRITE_ONCE(hba->pm_op_in_progress, false);
return ret;
}
@@ -10575,7 +10597,7 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
int ret;
enum uic_link_state old_link_state = hba->uic_link_state;
- hba->pm_op_in_progress = true;
+ WRITE_ONCE(hba->pm_op_in_progress, true);
/*
* Call vendor specific resume callback. As these callbacks may access
@@ -10666,7 +10688,7 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
ufshcd_update_evt_hist(hba, UFS_EVT_WL_RES_ERR, (u32)ret);
hba->clk_gating.is_suspended = false;
ufshcd_release(hba);
- hba->pm_op_in_progress = false;
+ WRITE_ONCE(hba->pm_op_in_progress, false);
return ret;
}
--
2.34.1
prev parent reply other threads:[~2026-11-11 9:03 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <cover.1794384665.git.hy50.seo@samsung.com>
[not found] ` <CGME20261111082304epcas2p4887d72756d51a72b94729439d25dd3e8@epcas2p4.samsung.com>
2026-11-11 8:18 ` [PATCH v10 1/4] scsi: ufs: core: Clear saved errors in ufshcd_link_recovery() HOYOUNG SEO
[not found] ` <CGME20261111082305epcas2p28dd4b104523c10c82457a29e7e89c56c@epcas2p2.samsung.com>
2026-11-11 8:18 ` [PATCH v10 2/4] scsi: ufs: core: Add a helper for the system suspend callbacks HOYOUNG SEO
[not found] ` <CGME20261111082306epcas2p21456a0a7d81ed5328ec01f022b87ee32@epcas2p2.samsung.com>
2026-11-11 8:18 ` [PATCH v10 3/4] scsi: ufs: core: Make ufshcd_wl_poweroff() behave like ufshcd_wl_suspend() HOYOUNG SEO
[not found] ` <CGME20261111082307epcas2p3b1376d94048de0aa228515860e892641@epcas2p3.samsung.com>
2026-11-11 8:18 ` HOYOUNG SEO [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=282821294.121794387787588.JavaMail.epsvc@epcpadp2new \
--to=hy50.seo@samsung.com \
--cc=alim.akhtar@samsung.com \
--cc=bvanassche@acm.org \
--cc=cpgsproxy1@samsung.com \
--cc=h10.kim@samsung.com \
--cc=kwangwon.min@samsung.com \
--cc=kwmad.kim@samsung.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=martin.petersen@oracle.com \
--cc=mkp@kernel.org \
--cc=peter.wang@mediatek.com \
--cc=stanleyjhu@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®