From: Felix Fietkau <nbd@nbd.name>
To: linux-wireless@vger.kernel.org
Cc: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Subject: [PATCH mt76-next 02/25] wifi: mt76: mt7996: do not update beacons while CSA is active
Date: Wed, 28 Oct 2026 13:23:40 +0100 [thread overview]
Message-ID: <20261028122403.796394-2-nbd@nbd.name> (raw)
In-Reply-To: <20261028122403.796394-1-nbd@nbd.name>
Each upload of the CSA beacon makes the firmware restart the countdown
from the template, but the driver uploads it more than once. At the
start of a CSA, mt7996_link_info_changed() and
mt7996_channel_switch_beacon() both upload it. mt7996_set_channel()
uploads it once more for the channel switch that
__ieee80211_csa_finalize() performs while csa_active is still set.
Upload the CSA beacon of a link only while the firmware does not hold
it: at the start of the CSA, after offchannel operation and after a
hardware restart. Do this, and the beacon reset for a CSA during CAC,
in mt7996_link_info_changed(), which knows the link of the CSA. Drop
mt7996_channel_switch_beacon(), which selects the link by the band of
the new channel; that band can belong to another radio.
In mt7996_set_channel(), restore only the beacons that were disabled
for offchannel operation. Other beacon updates during CSA are dropped
as well, since mac80211 rejects beacon changes from user space during
CSA and sets the post-CSA beacon right after the switch. A beacon
disable during CSA still goes to the firmware.
Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Fixes: f30906c55a40 ("wifi: mt76: mt7996: disable beacons when going offchannel")
Co-developed-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
.../net/wireless/mediatek/mt76/mt7996/mac.c | 1 +
.../net/wireless/mediatek/mt76/mt7996/main.c | 68 ++++++++-----------
.../net/wireless/mediatek/mt76/mt7996/mcu.c | 13 +++-
.../wireless/mediatek/mt76/mt7996/mt7996.h | 2 +
4 files changed, 40 insertions(+), 44 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index edff4e5a5dff..2e1b67ac2d11 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -2251,6 +2251,7 @@ void mt7996_mac_update_beacons(struct mt7996_phy *phy)
ieee80211_iterate_active_interfaces(phy->mt76->hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7996_update_vif_beacon, phy);
+ phy->offchan_bcn_stopped = phy->mt76->offchannel;
}
static void
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 9f1927cad5c4..a2655784a13d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -349,6 +349,7 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
return -ENOSPC;
link->mld_idx = mld_idx;
+ link->csa_bcn_uploaded = false;
eth_zero_addr(link->bmc_bssid);
mlink->omac_idx = idx;
mlink->band_idx = band_idx;
@@ -703,7 +704,7 @@ int mt7996_set_channel(struct mt76_phy *mphy)
mt7996_mac_reset_counters(phy);
phy->noise = 0;
- if (!mphy->offchannel)
+ if (!mphy->offchannel && phy->offchan_bcn_stopped)
mt7996_mac_update_beacons(phy);
out:
@@ -995,6 +996,30 @@ mt7996_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mutex_unlock(&dev->mt76.mutex);
}
+static void
+mt7996_link_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *link_conf,
+ struct mt7996_vif_link *link, struct mt7996_phy *phy)
+{
+ if (!link_conf->enable_beacon || !link_conf->csa_active) {
+ mt7996_mcu_add_beacon(hw, vif, link_conf,
+ link_conf->enable_beacon);
+ return;
+ }
+
+ /* each upload of the CSA beacon restarts the firmware countdown */
+ if (link->csa_bcn_uploaded)
+ return;
+
+ /* Reset beacon when channel switch triggered during CAC to let
+ * FW correctly perform CSA countdown
+ */
+ if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->mt76->chandef, vif->type))
+ mt7996_mcu_add_beacon(hw, vif, link_conf, false);
+
+ mt7996_mcu_add_beacon(hw, vif, link_conf, true);
+}
+
static void
mt7996_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info, u64 changed)
@@ -1067,7 +1092,7 @@ mt7996_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
link->mt76.beacon_rates_idx =
mt7996_get_rates_table(phy, info, true, false);
- mt7996_mcu_add_beacon(hw, vif, info, info->enable_beacon);
+ mt7996_link_beacon_update(hw, vif, info, link, phy);
}
if (changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
@@ -1087,44 +1112,6 @@ mt7996_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mutex_unlock(&dev->mt76.mutex);
}
-static void
-mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct cfg80211_chan_def *chandef)
-{
- struct mt7996_dev *dev = mt7996_hw_dev(hw);
- struct mt7996_phy *phy = mt7996_band_phy(dev, chandef->chan->band);
- struct ieee80211_bss_conf *link_conf;
- unsigned int link_id;
-
- mutex_lock(&dev->mt76.mutex);
-
- for_each_vif_active_link(vif, link_conf, link_id) {
- struct mt7996_vif_link *link;
- struct mt7996_phy *link_phy;
-
- link = mt7996_vif_link(dev, vif, link_id);
- if (!link)
- continue;
-
- link_phy = mt7996_vif_link_phy(link);
- if (link_phy != phy)
- continue;
-
- /* Reset beacon when channel switch triggered during CAC to let
- * FW correctly perform CSA countdown
- */
- if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->mt76->chandef,
- vif->type))
- mt7996_mcu_add_beacon(hw, vif, link_conf, false);
-
- mt7996_mcu_add_beacon(hw, vif, link_conf, true);
- break;
- }
-
- mutex_unlock(&dev->mt76.mutex);
-}
-
static int
mt7996_post_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
@@ -3093,7 +3080,6 @@ const struct ieee80211_ops mt7996_ops = {
.cancel_remain_on_channel = mt76_cancel_remain_on_channel,
.release_buffered_frames = mt76_release_buffered_frames,
.get_txpower = mt7996_get_txpower,
- .channel_switch_beacon = mt7996_channel_switch_beacon,
.post_channel_switch = mt7996_post_channel_switch,
.get_stats = mt7996_get_stats,
.get_et_sset_count = mt7996_get_et_sset_count,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index e3420ac523ab..7e72174bd6b1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -3254,7 +3254,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct sk_buff *skb, *rskb;
struct tlv *tlv;
struct bss_bcn_content_tlv *bcn;
- int len, extra_len = 0;
+ int len, extra_len = 0, ret;
if (link_conf->nontransmitted)
return 0;
@@ -3262,6 +3262,10 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (!mlink)
return -EINVAL;
+ /* a later CSA needs a new template, also after a failed upload */
+ if (!link_conf->csa_active)
+ link->csa_bcn_uploaded = false;
+
if (mphy && mphy->offchannel)
enabled = false;
@@ -3303,8 +3307,11 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mt7996_mcu_beacon_cntdwn(rskb, skb, &offs, link_conf->csa_active);
out:
dev_kfree_skb(skb);
- return mt76_mcu_skb_send_msg(&dev->mt76, rskb,
- MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
+ ret = mt76_mcu_skb_send_msg(&dev->mt76, rskb,
+ MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
+ link->csa_bcn_uploaded = !ret && enabled && link_conf->csa_active;
+
+ return ret;
}
int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index da9958647b54..84edb905fe06 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -295,6 +295,7 @@ struct mt7996_vif_link {
u8 mld_idx;
u8 bmc_bssid[ETH_ALEN];
+ bool csa_bcn_uploaded;
};
struct mt7996_vif_link_info {
@@ -416,6 +417,7 @@ struct mt7996_phy {
bool has_aux_rx;
bool counter_reset;
bool rdd_tx_paused;
+ bool offchan_bcn_stopped;
};
struct mt7996_dev {
--
2.47.3
next prev parent reply other threads:[~2026-10-28 12:24 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 12:23 [PATCH mt76-next 01/25] wifi: mt76: mt7996: take the link of an 802.3 frame from its station Felix Fietkau
2026-10-28 12:23 ` Felix Fietkau [this message]
2026-10-28 12:23 ` [PATCH mt76-next 03/25] wifi: mt76: mt7996: only remove a BMC STA_REC that was added Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 04/25] wifi: mt76: mt7996: pass the puncturing bitmap to the firmware Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 05/25] wifi: mt76: abort a scan when the chanctx changes Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 06/25] wifi: mt76: set the channel again when the chanctx puncturing changes Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 07/25] wifi: mt76: mt7996: advertise preamble puncturing support Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 08/25] wifi: mt76: mt7996: keep scan and ROC links out of the MLD group Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 09/25] wifi: mt76: mt7996: factor the vif link teardown out of remove_interface Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 10/25] wifi: mt76: mt7996: destroy station links before the MLD group is freed Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 11/25] wifi: mt76: mt7996: send MLD link operations for an AP MLD only Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 12/25] wifi: mt76: mt7996: set up a vif link again on another radio Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 13/25] wifi: mt76: mt7996: describe an MLD peer with the PEER_MLD command Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 14/25] wifi: mt76: mt7915: honour the valid flag in efuse block reads Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 15/25] wifi: mt76: mt7996: skip MLD address translation for encap offload frames Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 16/25] wifi: mt76: mt7921: honour the valid flag in efuse block reads Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 17/25] wifi: mt76: mt7915: upload the CSA beacon only once Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 18/25] wifi: mt76: read the chanctx of a link once Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 19/25] wifi: mt76: restart the beacon monitor of a link that gets a chanctx again Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 20/25] wifi: mt76: publish the beacon monitor interval after its timestamp Felix Fietkau
2026-10-28 12:23 ` [PATCH mt76-next 21/25] wifi: mt76: mt7996: keep rx header translation off while a monitor runs Felix Fietkau
2026-10-28 12:24 ` [PATCH mt76-next 22/25] wifi: mt76: mt7996: apply monitor mode again after a full reset Felix Fietkau
2026-10-28 12:24 ` [PATCH mt76-next 23/25] wifi: mt76: check the RX PN of an MLD peer once per peer Felix Fietkau
2026-10-28 12:24 ` [PATCH mt76-next 24/25] wifi: mt76: mt7996: send no MLD_SETUP when station links only go away Felix Fietkau
2026-10-28 12:24 ` [PATCH mt76-next 25/25] wifi: mt76: mt7996: keep a unicast management frame on its MLO link Felix Fietkau
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=20261028122403.796394-2-nbd@nbd.name \
--to=nbd@nbd.name \
--cc=StanleyYP.Wang@mediatek.com \
--cc=linux-wireless@vger.kernel.org \
/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