* [PATCH] wifi: mt76: mt7915: keep the tx worker off the txq scheduler during hw restart
@ 2026-07-27 19:59 bookmailer3000
2026-07-27 20:04 ` Lucas Zampieri
0 siblings, 1 reply; 2+ messages in thread
From: bookmailer3000 @ 2026-07-27 19:59 UTC (permalink / raw)
To: Felix Fietkau, Lorenzo Bianconi, Ryder Lee
Cc: Shayne Chen, Sean Wang, linux-wireless, linux-mediatek, stable
mt7915_mac_full_reset() calls ieee80211_restart_hw(), whose asynchronous
mac80211 reconfiguration tears down and rebuilds every station's TXQs.
Nothing keeps the mt76 tx worker off the mac80211 txq scheduler in that
window, so it dereferences freed TXQs and panics in the mt76-tx kthread.
mt76_txq_schedule_list <- mt76_tx_worker_run <- mt76_tx_worker
Gate the worker at its entry point instead. Add a reset_pending counter
to struct mt76_dev, raised per band in mt7915_mac_full_reset() and
released as each band's reconfig completes in mt7915_reconfig_complete().
mt76_tx_worker_run() returns immediately while the counter is nonzero,
and the worker is kicked once it drops back to zero. A run already in
flight when the reset starts is serialized by the existing
mt76_worker_disable() in mt7915_mac_restart().
The worker cannot simply be parked across the restart. Driver callbacks
invoked during the reconfiguration (mt7915_mcu_add_tx_ba(),
__mt76_set_channel()) pause and unconditionally resume it, and kthread
parking does not nest.
On MT7981 the panic reproduces within a few resets under tx load via the
sys_recovery debugfs knob. With this patch it no longer occurs, across
forced resets and two weeks of production firmware-triggered resets.
The same restart/reconfig pattern exists in mt7996.
Fixes: 8a55712d124f ("wifi: mt76: mt7915: enable full system reset support")
Cc: stable@vger.kernel.org
Signed-off-by: Lucas Zampieri <lcasmz54@gmail.com>
---
mt76.h | 2 ++
mt7915/mac.c | 3 +++
mt7915/main.c | 5 +++++
tx.c | 3 +++
4 files changed, 13 insertions(+)
diff --git a/mt76.h b/mt76.h
index dda5034b..ed30768f 100644
--- a/mt76.h
+++ b/mt76.h
@@ -974,6 +974,8 @@ struct mt76_dev {
enum mt76_hwrro_mode hwrro_mode;
struct mt76_worker tx_worker;
+ /* nonzero while a hw restart reconfig is rebuilding the TXQs */
+ atomic_t reset_pending;
struct napi_struct tx_napi;
spinlock_t token_lock;
diff --git a/mt7915/mac.c b/mt7915/mac.c
index cd123253..5f459c63 100644
--- a/mt7915/mac.c
+++ b/mt7915/mac.c
@@ -1428,6 +1428,9 @@ mt7915_mac_full_reset(struct mt7915_dev *dev)
dev->recovery.hw_full_reset = true;
+ /* released per band in mt7915_reconfig_complete() */
+ atomic_add(ext_phy ? 2 : 1, &dev->mt76.reset_pending);
+
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
ieee80211_stop_queues(mt76_hw(dev));
diff --git a/mt7915/main.c b/mt7915/main.c
index 42c548a3..73479d6c 100644
--- a/mt7915/main.c
+++ b/mt7915/main.c
@@ -1833,6 +1833,11 @@ mt7915_reconfig_complete(struct ieee80211_hw *hw,
enum ieee80211_reconfig_type reconfig_type)
{
struct mt7915_phy *phy = mt7915_hw_phy(hw);
+ struct mt7915_dev *dev = phy->dev;
+
+ if (reconfig_type == IEEE80211_RECONFIG_TYPE_RESTART &&
+ !atomic_dec_if_positive(&dev->mt76.reset_pending))
+ mt76_worker_schedule(&dev->mt76.tx_worker);
ieee80211_wake_queues(hw);
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
diff --git a/tx.c b/tx.c
index 4507fd15..e8e86e46 100644
--- a/tx.c
+++ b/tx.c
@@ -767,6 +767,9 @@ void mt76_tx_worker_run(struct mt76_dev *dev)
struct mt76_phy *phy;
int i;
+ if (atomic_read(&dev->reset_pending))
+ return;
+
mt76_txq_schedule_all(&dev->phy);
for (i = 0; i < ARRAY_SIZE(dev->phys); i++) {
phy = dev->phys[i];
--
2.47.3
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH] wifi: mt76: mt7915: keep the tx worker off the txq scheduler during hw restart
2026-07-27 19:59 [PATCH] wifi: mt76: mt7915: keep the tx worker off the txq scheduler during hw restart bookmailer3000
@ 2026-07-27 20:04 ` Lucas Zampieri
0 siblings, 0 replies; 2+ messages in thread
From: Lucas Zampieri @ 2026-07-27 20:04 UTC (permalink / raw)
To: Felix Fietkau, Lorenzo Bianconi, Ryder Lee
Cc: Shayne Chen, Sean Wang, linux-wireless, linux-mediatek, stable
mt7915_mac_full_reset() calls ieee80211_restart_hw(), whose asynchronous
mac80211 reconfiguration tears down and rebuilds every station's TXQs.
Nothing keeps the mt76 tx worker off the mac80211 txq scheduler in that
window, so it dereferences freed TXQs and panics in the mt76-tx kthread.
mt76_txq_schedule_list <- mt76_tx_worker_run <- mt76_tx_worker
Gate the worker at its entry point instead. Add a reset_pending counter
to struct mt76_dev, raised per band in mt7915_mac_full_reset() and
released as each band's reconfig completes in mt7915_reconfig_complete().
mt76_tx_worker_run() returns immediately while the counter is nonzero,
and the worker is kicked once it drops back to zero. A run already in
flight when the reset starts is serialized by the existing
mt76_worker_disable() in mt7915_mac_restart().
The worker cannot simply be parked across the restart. Driver callbacks
invoked during the reconfiguration (mt7915_mcu_add_tx_ba(),
__mt76_set_channel()) pause and unconditionally resume it, and kthread
parking does not nest.
On MT7981 the panic reproduces within a few resets under tx load via the
sys_recovery debugfs knob. With this patch it no longer occurs, across
forced resets and two weeks of production firmware-triggered resets.
The same restart/reconfig pattern exists in mt7996.
Fixes: 8a55712d124f ("wifi: mt76: mt7915: enable full system reset support")
Cc: stable@vger.kernel.org
Signed-off-by: Lucas Zampieri <lcasmz54@gmail.com>
---
Resent from my own address; please disregard the earlier copy of this
patch sent from an unrelated account by mistake.
mt76.h | 2 ++
mt7915/mac.c | 3 +++
mt7915/main.c | 5 +++++
tx.c | 3 +++
4 files changed, 13 insertions(+)
diff --git a/mt76.h b/mt76.h
index dda5034b..ed30768f 100644
--- a/mt76.h
+++ b/mt76.h
@@ -974,6 +974,8 @@ struct mt76_dev {
enum mt76_hwrro_mode hwrro_mode;
struct mt76_worker tx_worker;
+ /* nonzero while a hw restart reconfig is rebuilding the TXQs */
+ atomic_t reset_pending;
struct napi_struct tx_napi;
spinlock_t token_lock;
diff --git a/mt7915/mac.c b/mt7915/mac.c
index cd123253..5f459c63 100644
--- a/mt7915/mac.c
+++ b/mt7915/mac.c
@@ -1428,6 +1428,9 @@ mt7915_mac_full_reset(struct mt7915_dev *dev)
dev->recovery.hw_full_reset = true;
+ /* released per band in mt7915_reconfig_complete() */
+ atomic_add(ext_phy ? 2 : 1, &dev->mt76.reset_pending);
+
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
ieee80211_stop_queues(mt76_hw(dev));
diff --git a/mt7915/main.c b/mt7915/main.c
index 42c548a3..73479d6c 100644
--- a/mt7915/main.c
+++ b/mt7915/main.c
@@ -1833,6 +1833,11 @@ mt7915_reconfig_complete(struct ieee80211_hw *hw,
enum ieee80211_reconfig_type reconfig_type)
{
struct mt7915_phy *phy = mt7915_hw_phy(hw);
+ struct mt7915_dev *dev = phy->dev;
+
+ if (reconfig_type == IEEE80211_RECONFIG_TYPE_RESTART &&
+ !atomic_dec_if_positive(&dev->mt76.reset_pending))
+ mt76_worker_schedule(&dev->mt76.tx_worker);
ieee80211_wake_queues(hw);
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
diff --git a/tx.c b/tx.c
index 4507fd15..e8e86e46 100644
--- a/tx.c
+++ b/tx.c
@@ -767,6 +767,9 @@ void mt76_tx_worker_run(struct mt76_dev *dev)
struct mt76_phy *phy;
int i;
+ if (atomic_read(&dev->reset_pending))
+ return;
+
mt76_txq_schedule_all(&dev->phy);
for (i = 0; i < ARRAY_SIZE(dev->phys); i++) {
phy = dev->phys[i];
--
2.47.3
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-27 20:04 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-27 19:59 [PATCH] wifi: mt76: mt7915: keep the tx worker off the txq scheduler during hw restart bookmailer3000
2026-07-27 20:04 ` Lucas Zampieri
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox