From: Tim JH Chen <tim770802@gmail.com>
To: netdev@vger.kernel.org
Cc: pabeni@redhat.com, haijun.liu@mediatek.com,
chandrashekar.devegowda@intel.com,
ricardo.martinez@linux.intel.com, loic.poulain@oss.qualcomm.com,
ryazanov.s.a@gmail.com, johannes@sipsolutions.net,
andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
kuba@kernel.org, linux-kernel@vger.kernel.org,
tim.jh.chen@wnc.com.tw, Chih.Hung.Huang@wnc.com.tw,
Tim JH Chen <tim770802@gmail.com>
Subject: [PATCH net v4] net: wwan: t7xx: fix race between TX path and system PM suspend
Date: Wed, 10 Jun 2026 14:10:14 +0800 [thread overview]
Message-ID: <20260610061014.597533-1-tim770802@gmail.com> (raw)
Two DPMAIF TX contexts run pm_runtime_resume_and_get() followed by MMIO
independently of the PM core: the TX push kthread
(t7xx_dpmaif_tx_hw_push_thread) and the TX-done work
(t7xx_dpmaif_tx_done). Neither is stopped during a system suspend
transition, and system suspend does not honour the runtime PM reference
they hold, so they can touch the hardware while t7xx_dpmaif_suspend()
tears it down. With ASPM L1 enabled and repeated suspend/resume cycles
this ends in a CPU soft lockup:
watchdog: BUG: soft lockup - CPU#N stuck for 26s! [dpmaif_tx_hw_pu]
__pm_runtime_resume+0x5b/0x80
t7xx_dpmaif_tx_hw_push_thread+0xc4 [mtk_t7xx]
Runtime suspend is already safe: while either context holds its PM
reference the runtime suspend callback cannot run. Only system suspend,
which ignores that reference, is exposed.
Quiesce both contexts with the PM freezer, which runs before dpm_suspend()
invokes the device suspend callbacks:
- The push kthread is made freezable: set_freezable() and
wait_event_freezable() for the idle wait, plus try_to_freeze() before
the pm_runtime section so it also reaches a freeze point under
continuous TX traffic.
- The TX-done workqueue is marked WQ_FREEZABLE so the workqueue freezer
drains it before suspend; this also parks its self-requeue until thaw.
Tasks are thawed only after the resume callbacks have re-armed the
hardware, so neither context can issue MMIO against a torn-down or
not-yet-rearmed device. No lock is shared with the PM callbacks, so this
cannot deadlock.
Tested with 500+ suspend/resume cycles, SIM registered and ASPM L1 enabled.
Fixes: 46e8f49ed7b3 ("net: wwan: t7xx: Introduce power management")
Signed-off-by: Tim JH Chen <tim770802@gmail.com>
---
v3 -> v4:
- Drop the tx_pm_lock / state-snapshot approach entirely and use the PM
freezer for both TX contexts instead. The previous approach deadlocked
through the runtime PM wait queue (t7xx_dpmaif_suspend() is also the
.runtime_suspend callback) and opened ISR windows by writing
dpmaif_ctrl->state in suspend/resume.
- Also cover t7xx_dpmaif_tx_done() (WQ_FREEZABLE), which has the same
pm_runtime + MMIO pattern as the kthread.
- Trim the changelog/commit message.
v2 -> v3: process fixes (Fixes tag, changelog placement).
v1 -> v2: save/restore pre-suspend state; wrap pm_runtime with a mutex.
drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c
index 236d632cf591..804bd730c40f 100644
--- a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c
+++ b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c
@@ -22,6 +22,7 @@
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
+#include <linux/freezer.h>
#include <linux/gfp.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
@@ -447,19 +448,28 @@ static int t7xx_dpmaif_tx_hw_push_thread(void *arg)
struct dpmaif_ctrl *dpmaif_ctrl = arg;
int ret;
+ set_freezable();
+
while (!kthread_should_stop()) {
if (t7xx_tx_lists_are_all_empty(dpmaif_ctrl) ||
dpmaif_ctrl->state != DPMAIF_STATE_PWRON) {
- if (wait_event_interruptible(dpmaif_ctrl->tx_wq,
- (!t7xx_tx_lists_are_all_empty(dpmaif_ctrl) &&
- dpmaif_ctrl->state == DPMAIF_STATE_PWRON) ||
- kthread_should_stop()))
+ if (wait_event_freezable(dpmaif_ctrl->tx_wq,
+ (!t7xx_tx_lists_are_all_empty(dpmaif_ctrl) &&
+ dpmaif_ctrl->state == DPMAIF_STATE_PWRON) ||
+ kthread_should_stop()))
continue;
if (kthread_should_stop())
break;
}
+ /* Freeze here, outside the runtime-PM and MMIO section below, so
+ * the system suspend freezer parks this thread before the device
+ * suspend callbacks tear the DPMAIF hardware down.
+ */
+ if (try_to_freeze())
+ continue;
+
ret = pm_runtime_resume_and_get(dpmaif_ctrl->dev);
if (ret < 0 && ret != -EACCES)
return ret;
@@ -617,7 +627,7 @@ int t7xx_dpmaif_txq_init(struct dpmaif_tx_queue *txq)
}
txq->worker = alloc_ordered_workqueue("md_dpmaif_tx%d_worker",
- WQ_MEM_RECLAIM | (txq->index ? 0 : WQ_HIGHPRI),
+ WQ_MEM_RECLAIM | WQ_FREEZABLE | (txq->index ? 0 : WQ_HIGHPRI),
txq->index);
if (!txq->worker)
return -ENOMEM;
--
2.43.0
reply other threads:[~2026-06-10 6:10 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20260610061014.597533-1-tim770802@gmail.com \
--to=tim770802@gmail.com \
--cc=Chih.Hung.Huang@wnc.com.tw \
--cc=andrew+netdev@lunn.ch \
--cc=chandrashekar.devegowda@intel.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=haijun.liu@mediatek.com \
--cc=johannes@sipsolutions.net \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=loic.poulain@oss.qualcomm.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=ricardo.martinez@linux.intel.com \
--cc=ryazanov.s.a@gmail.com \
--cc=tim.jh.chen@wnc.com.tw \
/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