From: Paolo Abeni <pabeni@redhat.com>
To: Tim JH Chen <tim770802@gmail.com>, netdev@vger.kernel.org
Cc: 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
Subject: Re: [PATCH] net: wwan: t7xx: fix race between TX thread and system PM suspend
Date: Thu, 4 Jun 2026 11:29:31 +0200 [thread overview]
Message-ID: <c1fcc5f6-8a61-4774-9063-44fc5f458b97@redhat.com> (raw)
In-Reply-To: <20260601015231.3211764-1-tim.jh.chen@wnc.com.tw>
On 6/1/26 3:52 AM, Tim JH Chen wrote:
> When system suspend is triggered while the DPMAIF TX kthread
> (t7xx_dpmaif_tx_hw_push_thread) is running, a deadlock can occur
> leading to a CPU soft lockup.
>
> The root cause is two-fold:
>
> 1. t7xx_dpmaif_suspend() calls t7xx_dpmaif_tx_stop() which only stops
> the TX work-queue items (by clearing txq->que_started and waiting on
> txq->tx_processing). It does NOT signal the kthread and does NOT
> update dpmaif_ctrl->state, which stays DPMAIF_STATE_PWRON.
>
> 2. The kthread's state guard is only checked at the top of each loop
> iteration. If the thread already passed this guard, it proceeds
> unconditionally to call pm_runtime_resume_and_get() — which tries to
> acquire dev->power.lock also contended by the system PM suspend path.
>
> The result is a spinlock deadlock observed as:
>
> watchdog: BUG: soft lockup - CPU#N stuck for 26s! [dpmaif_tx_hw_pu]
> RIP: _raw_spin_unlock_irqrestore
> Call Trace:
> __pm_runtime_resume+0x5b/0x80
> t7xx_dpmaif_tx_hw_push_thread+0xc4 [mtk_t7xx]
>
> The condition requires ASPM L1 enabled on the endpoint (which extends
> the time pm_runtime_resume_and_get() holds dev->power.lock during L1.2
> link retraining) and hundreds of repeated suspend/resume cycles to
> trigger reliably.
>
> Fix by introducing tx_pm_lock (struct mutex) and several coordinated
> changes:
>
> t7xx_dpmaif_suspend():
> After t7xx_dpmaif_tx_stop(), acquire tx_pm_lock. Under the lock,
> snapshot dpmaif_ctrl->state into pre_suspend_state (capturing the
> modem state atomically with respect to the kthread's PM section),
> then set DPMAIF_STATE_PWROFF via WRITE_ONCE(). Release the lock
> and call wake_up() so any sleeping kthread re-evaluates the
> wait_event condition and exits.
>
> t7xx_dpmaif_suspend() acquires tx_pm_lock without holding any PM
> lock. While it waits, the kthread may call pm_runtime_resume_and_get()
> which briefly takes and releases dev->power.lock independently.
> Because the suspend callback does not compete for dev->power.lock at
> this point, the original spinlock deadlock cannot occur. Suspend
> latency increases by at most one TX burst drain time, which is
> bounded by the DRB ring depth.
>
> t7xx_dpmaif_resume():
> When pre_suspend_state is DPMAIF_STATE_PWRON, re-arm the HW fully
> (start_txrx_qs, enable_irq, unmask_dlq_intr, start_hw) before
> publishing the new state. This ensures the kthread cannot issue
> ul_update_hw_drb_cnt() MMIO writes before UL_ALL_Q_EN is set by
> t7xx_dpmaif_start_hw(). Publish the restored state under tx_pm_lock
> to serialise with the kthread's under-lock state check. Wake up the
> kthread only after HW and state are both consistent.
>
> When pre_suspend_state is DPMAIF_STATE_PWROFF (modem was already
> stopped or in exception before suspend), skip HW re-arming entirely
> to avoid leaving DMA engines running while the MD state machine
> considers the modem inactive.
>
> t7xx_dpmaif_tx_hw_push_thread():
> Hold tx_pm_lock across the [state check -> pm_runtime_resume_and_get
> -> pm_runtime_put_autosuspend] sequence. A second READ_ONCE() state
> check under the lock closes the TOCTOU window between the wait_event
> guard at the loop top and the pm_runtime call. READ_ONCE() is used
> in all unguarded state reads in this function.
>
> t7xx_dpmaif_start() / t7xx_dpmaif_stop():
> Use WRITE_ONCE() for state writes to match the READ_ONCE() reads
> used throughout the driver and prevent compiler optimisations from
> obscuring concurrent access.
>
> t7xx_do_tx_hw_push():
> Use READ_ONCE() in the do/while termination condition to match the
> WRITE_ONCE() annotations on the write side.
>
> t7xx_dpmaif_tx_thread_init():
> Initialise tx_pm_lock with mutex_init().
>
> Note: t7xx_dpmaif_start() and t7xx_dpmaif_stop() (called from the
> MD-FSM kthread via t7xx_dpmaif_md_state_callback()) do not hold
> tx_pm_lock. A race where the FSM transitions the modem to
> DPMAIF_STATE_PWROFF concurrently with the TX kthread's last burst is
> pre-existing and not introduced by this patch; the do/while condition
> in t7xx_do_tx_hw_push() now re-checks state with READ_ONCE() at each
> iteration boundary, limiting exposure to at most one burst.
>
> Tested: no soft lockup observed over 500+ suspend/resume cycles with
> SIM registered and ASPM L1 enabled (previously triggered in < 300).
>
> Fixes: 46e8f49ed7b3 ("net: wwan: t7xx: Introduce power management")
> Signed-off-by: Tim JH Chen <tim.jh.chen@wnc.com.tw>
The above is way too verbose and hints that this patch should likely
be split in a series.
Note that process wise there are still several problems:
- missing revision number in the suby prefix
- mismatch between from email message and SoB
- new revision MUST NOT be in reply-to of older ones.
Please try to be accurate with your next resubmission, or we will
have to delay processing this patch for an additional while.
Sashiko has still quite a bit of concerns:
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260601015231.3211764-1-tim.jh.chen%40wnc.com.tw
/P
next prev parent reply other threads:[~2026-06-04 9:29 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-18 7:50 Tim JH Chen
2026-05-21 10:29 ` Paolo Abeni
2026-05-21 10:33 ` Paolo Abeni
2026-05-25 3:13 ` Tim JH Chen
2026-05-28 9:21 ` Paolo Abeni
2026-06-01 1:52 ` Tim JH Chen
2026-06-04 9:29 ` Paolo Abeni [this message]
-- strict thread matches above, loose matches on Subject: below --
2026-05-13 8:37 Tim JH Chen(陳仁鴻)
2026-05-15 0:19 ` Jakub Kicinski
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=c1fcc5f6-8a61-4774-9063-44fc5f458b97@redhat.com \
--to=pabeni@redhat.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=ricardo.martinez@linux.intel.com \
--cc=ryazanov.s.a@gmail.com \
--cc=tim.jh.chen@wnc.com.tw \
--cc=tim770802@gmail.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®