[PATCH wireless] wifi: mt76: mt792x: tell mac80211 when a disconnect cancels its ROC
Devin Wittmayer
lucid_duck at justthetip.ca
Thu Oct 22 18:48:27 PDT 2026
A disconnect during a remain-on-channel (ROC) cancels the ROC in
firmware without telling mac80211, which then waits for a ROC that is
already gone. Scans stall, and after an AP deauth the station does not
reconnect.
Tell mac80211 when the driver cancels a ROC that mac80211 started.
Fixes: 41ac53c899bd ("wifi: mt76: mt7921: introduce chanctx support")
Fixes: 5ed54896b6bd ("wifi: mt76: mt7921: fix a potential scan no APs")
Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
Fixes: 45064d19fd3a ("wifi: mt76: mt7925: fix a potential association failure upon resuming")
Signed-off-by: Devin Wittmayer <lucid_duck at justthetip.ca>
---
Tested on an MT7922 and an MT7925U: without this, scans stall after a
disconnect during a ROC. With it they work, and the station is back
about 4 s after an AP deauth. mac80211's own cancel stays silent, since
it ends that ROC itself.
drivers/net/wireless/mediatek/mt76/mt7921/main.c | 14 +++++++++++++-
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 15 ++++++++++++++-
drivers/net/wireless/mediatek/mt76/mt792x.h | 1 +
3 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 09574d4417cd..019c1ff5b0a3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -381,6 +381,9 @@ void mt7921_roc_abort_sync(struct mt792x_dev *dev)
ieee80211_iterate_interfaces(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_roc_iter, (void *)phy);
+
+ if (phy->roc_mac80211)
+ ieee80211_remain_on_channel_expired(mt76_hw(dev));
}
EXPORT_SYMBOL_GPL(mt7921_roc_abort_sync);
@@ -405,16 +408,21 @@ void mt7921_roc_work(struct work_struct *work)
static int mt7921_abort_roc(struct mt792x_phy *phy, struct mt792x_vif *vif)
{
+ bool aborted;
int err = 0;
timer_delete_sync(&phy->roc_timer);
cancel_work_sync(&phy->roc_work);
mt792x_mutex_acquire(phy->dev);
- if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
+ aborted = test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state);
+ if (aborted)
err = mt7921_mcu_abort_roc(phy, vif, phy->roc_token_id);
mt792x_mutex_release(phy->dev);
+ if (aborted && phy->roc_mac80211)
+ ieee80211_remain_on_channel_expired(phy->mt76->hw);
+
return err;
}
@@ -430,6 +438,7 @@ static int mt7921_set_roc(struct mt792x_phy *phy,
return -EBUSY;
phy->roc_grant = false;
+ phy->roc_mac80211 = type == MT7921_ROC_REQ_ROC;
err = mt7921_mcu_set_roc(phy, vif, chan, duration, type,
++phy->roc_token_id);
@@ -471,6 +480,9 @@ static int mt7921_cancel_remain_on_channel(struct ieee80211_hw *hw,
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt792x_phy *phy = mt792x_hw_phy(hw);
+ /* mac80211 ends this ROC itself */
+ phy->roc_mac80211 = false;
+
return mt7921_abort_roc(phy, mvif);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 22cc5b49da0a..0394250d46e5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -527,6 +527,9 @@ void mt7925_roc_abort_sync(struct mt792x_dev *dev)
ieee80211_iterate_interfaces(mt76_hw(dev),
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7925_roc_iter, (void *)phy);
+
+ if (phy->roc_mac80211)
+ ieee80211_remain_on_channel_expired(mt76_hw(dev));
}
EXPORT_SYMBOL_GPL(mt7925_roc_abort_sync);
@@ -551,16 +554,21 @@ void mt7925_roc_work(struct work_struct *work)
static int mt7925_abort_roc(struct mt792x_phy *phy,
struct mt792x_bss_conf *mconf)
{
+ bool aborted;
int err = 0;
timer_delete_sync(&phy->roc_timer);
cancel_work_sync(&phy->roc_work);
mt792x_mutex_acquire(phy->dev);
- if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
+ aborted = test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state);
+ if (aborted)
err = mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id);
mt792x_mutex_release(phy->dev);
+ if (aborted && phy->roc_mac80211)
+ ieee80211_remain_on_channel_expired(phy->mt76->hw);
+
return err;
}
@@ -576,6 +584,7 @@ static int mt7925_set_roc(struct mt792x_phy *phy,
return -EBUSY;
phy->roc_grant = false;
+ phy->roc_mac80211 = type == MT7925_ROC_REQ_ROC;
err = mt7925_mcu_set_roc(phy, mconf, chan, duration, type,
++phy->roc_token_id);
@@ -604,6 +613,7 @@ static int mt7925_set_mlo_roc(struct mt792x_phy *phy,
return -EBUSY;
phy->roc_grant = false;
+ phy->roc_mac80211 = false;
err = mt7925_mcu_set_mlo_roc(phy, mconf, sel_links, 5, ++phy->roc_token_id);
if (err < 0) {
@@ -645,6 +655,9 @@ static int mt7925_cancel_remain_on_channel(struct ieee80211_hw *hw,
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt792x_phy *phy = mt792x_hw_phy(hw);
+ /* mac80211 ends this ROC itself */
+ phy->roc_mac80211 = false;
+
return mt7925_abort_roc(phy, &mvif->bss_conf);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h
index a7d71e007da0..1cc8475dc608 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x.h
@@ -240,6 +240,7 @@ struct mt792x_phy {
wait_queue_head_t roc_wait;
u8 roc_token_id;
bool roc_grant;
+ bool roc_mac80211;
};
struct mt792x_irq_map {
--
2.56.0
More information about the Linux-mediatek
mailing list