[rdkb][common][bsp][Refactor and sync wifi from openwrt]
[Description]
3a2eef0b [MAC80211][Release][Update release note for Filogic 880/860 MLO Beta release]
cfbd2411 [MAC80211][Release][Filogic 880/860 MLO Beta release]
6c180e3f [MAC80211][WiFi7][misc][Add Eagle BE14000 efem default bin]
a55f34db [MAC80211][Release][Prepare for Filogic 880/860 release]
5b45ebca [MAC80211][WiFi7][hostapd][Add puncture bitmap to ucode]
95bbea73 [MAC80211][WiFi6][mt76][Add PID to only report data-frame TX rate]
b15ced26 [MAC80211][WiFi6][hostapd][Fix DFS channel selection issue]
d59133cb [MAC80211][WiFi6][mt76][Fix pse info not correct information]
3921b4b2 [MAC80211][WiFi6][mt76][Fix incomplete QoS-map setting to FW]
4e7690c7 [MAC80211][WiFi6/7][app][Change ATECHANNEL mapping cmd]
eb37af90 [MAC80211][WiFi7][app][Add support for per-packet bw & primary selection]
0ea82adf [MAC80211][WiFi6][core][Fix DFS CAC issue after CSA]
[Release-log]
Change-Id: I9bec97ec1b2e1c49ed43a812a07a5b21fcbb70a6
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0127-mtk-mt76-mt7996-add-critical-update-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0127-mtk-mt76-mt7996-add-critical-update-support.patch
new file mode 100644
index 0000000..66e1603
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0127-mtk-mt76-mt7996-add-critical-update-support.patch
@@ -0,0 +1,395 @@
+From 8a5fc9a07ebf08ffdd31d05beaa2d399b67f6a10 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Tue, 23 Apr 2024 15:22:24 +0800
+Subject: [PATCH 127/199] mtk: mt76: mt7996: add critical update support
+
+Add critical update support
+modification: wmm configuration
+inclusion: channel switch
+(affiliated link's per-STA profile CSA/eCSA countdown is included)
+
+Fix the CU flag countdown issue of the non-CU link as reported from cert.
+1. Avoid setting the CSA beacon twice during channel switch.
+2. Raise the bypass_seq_bitmap up for the non-CU link.
+
+Reset the beacon when switching channels during CAC
+Otherwise, the FW will not be able to perform the CSA countdown.
+Also, modify the bpcc check since channel switch will add the bpcc twice
+(before CSA and after CSA).
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt76_connac_mcu.h | 2 +
+ mt7996/main.c | 107 +++++++++++++++++++++++++++++++++-------------
+ mt7996/mcu.c | 99 ++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mcu.h | 26 ++++++++++-
+ mt7996/mt7996.h | 4 ++
+ 5 files changed, 208 insertions(+), 30 deletions(-)
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index 870417f3..57cae8ae 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -1380,6 +1380,8 @@ enum {
+ UNI_BSS_INFO_OFFLOAD = 25,
+ UNI_BSS_INFO_MLD = 26,
+ UNI_BSS_INFO_PM_DISABLE = 27,
++ UNI_BSS_INFO_BCN_CRIT_UPDATE = 32,
++ UNI_BSS_INFO_BCN_STA_PROF_CSA = 37,
+ };
+
+ enum {
+diff --git a/mt7996/main.c b/mt7996/main.c
+index f52bb2f9..0d25d763 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -370,6 +370,7 @@ static int mt7996_add_bss_conf(struct mt7996_phy *phy,
+ mconf->mt76.band_idx = band_idx;
+ mconf->mt76.wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3;
+ mconf->link_id = link_id;
++ mconf->bpcc = 0;
+
+ ret = mt7996_mcu_add_dev_info(phy, conf, mconf, true);
+ if (ret)
+@@ -979,7 +980,9 @@ static void mt7996_link_info_changed(struct ieee80211_hw *hw,
+ mconf->mt76.beacon_rates_idx =
+ mt7996_get_rates_table(hw, info, mconf, true, false);
+
+- mt7996_mcu_add_beacon(hw, info, mconf, info->enable_beacon);
++ /* The CSA beacon will be set in channel_switch_beacon */
++ if (!info->csa_active)
++ mt7996_mcu_add_beacon(hw, info, mconf, info->enable_beacon);
+ }
+
+ if (changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
+@@ -1030,21 +1033,45 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_phy *phy = mt7996_band_phy(hw, chandef->chan->band);
+- unsigned long valid_links = vif->valid_links ?: BIT(0);
++ struct ieee80211_bss_conf *conf;
++ struct mt7996_bss_conf *mconf;
++ u16 valid_links = vif->valid_links ?: BIT(0);
+ unsigned int link_id;
+
+ mutex_lock(&dev->mt76.mutex);
+- for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
+- struct mt7996_bss_conf *mconf =
+- mconf_dereference_protected(mvif, link_id);
+- struct ieee80211_bss_conf *conf =
+- link_conf_dereference_protected(vif, link_id);
++ link_id = mvif->band_to_link[phy->mt76->band_idx];
+
+- if (!mconf || phy != mconf->phy)
+- continue;
++ if (!mvif->cs_ready_links)
++ mvif->cs_link_id = link_id;
++
++ mvif->cs_ready_links |= BIT(link_id);
++ if (mvif->cs_ready_links != valid_links)
++ goto out;
++
++ link_id = mvif->cs_link_id;
++ do {
++ valid_links &= ~BIT(link_id);
++ mconf = mconf_dereference_protected(mvif, link_id);
++ conf = link_conf_dereference_protected(vif, link_id);
++ if (!conf || !mconf)
++ goto fail;
++
++ /* Reset the beacon when switching channels during CAC */
++ if (link_id == mvif->cs_link_id &&
++ !cfg80211_reg_can_beacon(hw->wiphy, &phy->mt76->chandef, vif->type))
++ mt7996_mcu_add_beacon(hw, conf, mconf, false);
+
+ mt7996_mcu_add_beacon(hw, conf, mconf, true);
+- }
++ link_id = ffs(valid_links) - 1;
++ } while (valid_links);
++
++out:
++ mutex_unlock(&dev->mt76.mutex);
++ return;
++fail:
++ mvif->cs_ready_links = 0;
++ mvif->cs_link_id = IEEE80211_LINK_UNSPECIFIED;
++ dev_err(dev->mt76.dev, "link %d: failed to switch beacon\n", link_id);
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
+@@ -2534,32 +2561,54 @@ mt7996_switch_vif_chanctx(struct ieee80211_hw *hw,
+ int n_vifs,
+ enum ieee80211_chanctx_switch_mode mode)
+ {
+- struct mt7996_chanctx *old_ctx = mt7996_chanctx_get(vifs->old_ctx);
+- struct mt7996_chanctx *new_ctx = mt7996_chanctx_get(vifs->new_ctx);
+- struct mt7996_phy *phy = old_ctx->phy;
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct mt7996_chanctx *old_ctx;
++ struct mt7996_chanctx *new_ctx;
++ struct mt7996_phy *phy;
++ int i, ret = 0;
+
+- wiphy_info(hw->wiphy, "%s: old=%d, new=%d\n", __func__, vifs->old_ctx->def.chan->hw_value, vifs->new_ctx->def.chan->hw_value);
++ for (i = 0; i < n_vifs; i++) {
++ if (vifs[i].old_ctx == vifs[i].new_ctx)
++ continue;
+
+- if (new_ctx->nbss_assigned && phy->chanctx == new_ctx) {
+- new_ctx->nbss_assigned += n_vifs;
+- return 0;
+- }
++ wiphy_info(hw->wiphy, "%s: old=%d, new=%d\n",
++ __func__, vifs[i].old_ctx->def.chan->hw_value,
++ vifs[i].new_ctx->def.chan->hw_value);
+
+- if (WARN_ON(old_ctx != phy->chanctx))
+- return -EINVAL;
++ mutex_lock(&dev->mt76.mutex);
+
+- mutex_lock(&phy->dev->mt76.mutex);
++ old_ctx = mt7996_chanctx_get(vifs[i].old_ctx);
++ new_ctx = mt7996_chanctx_get(vifs[i].new_ctx);
++ phy = old_ctx->phy;
+
+- phy->chanctx = new_ctx;
+- phy->mt76->radar_enabled = vifs->new_ctx->radar_enabled;
+- new_ctx->assigned = true;
+- new_ctx->chandef = vifs->new_ctx->def;
+- new_ctx->phy = phy;
+- new_ctx->nbss_assigned += n_vifs;
++ if (new_ctx->nbss_assigned && phy->chanctx == new_ctx) {
++ new_ctx->nbss_assigned++;
++ mutex_unlock(&dev->mt76.mutex);
++ continue;
++ }
+
+- mutex_unlock(&phy->dev->mt76.mutex);
++ if (WARN_ON(old_ctx != phy->chanctx)) {
++ ret = -EINVAL;
++ mutex_unlock(&dev->mt76.mutex);
++ goto out;
++ }
++
++ phy->chanctx = new_ctx;
++ phy->mt76->radar_enabled = vifs[i].new_ctx->radar_enabled;
++ new_ctx->assigned = true;
++ new_ctx->chandef = vifs[i].new_ctx->def;
++ new_ctx->phy = phy;
++ new_ctx->nbss_assigned++;
++
++ mutex_unlock(&dev->mt76.mutex);
++
++ ret = mt7996_set_channel(phy, &new_ctx->chandef);
++ if (ret)
++ goto out;
++ }
+
+- return mt7996_set_channel(phy, &new_ctx->chandef);
++out:
++ return ret;
+ }
+
+ static int
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 28123fb7..ea69b66f 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -370,6 +370,7 @@ mt7996_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
+ struct mt76_phy *mphy = (struct mt76_phy *)priv;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct ieee80211_bss_conf *link_conf;
++ unsigned long valid_links = vif->valid_links ?: BIT(0);
+ int link_id, band_idx = mphy->band_idx;
+
+ link_id = mvif->band_to_link[band_idx];
+@@ -378,7 +379,16 @@ mt7996_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
+ if (!link_conf || !link_conf->csa_active || vif->type == NL80211_IFTYPE_STATION)
+ return;
+
++ pr_info("%s: link_id=%d\n", __func__, link_id);
++ mvif->cs_ready_links = 0;
++ mvif->cs_link_id = IEEE80211_LINK_UNSPECIFIED;
+ ieee80211_csa_finish(vif, link_id);
++ /* remove CSA for affiliated links */
++ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
++ if (link_id == link_conf->link_id)
++ continue;
++ ieee80211_csa_finish(vif, link_id);
++ }
+ }
+
+ static void
+@@ -3235,6 +3245,93 @@ mt7996_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb,
+ }
+ }
+
++static bool
++mt7996_mcu_beacon_is_cu_link(struct sk_buff *skb, struct mt7996_bss_conf *mconf,
++ u16 tail_offset)
++{
++ const struct element *elem;
++ u8 *beacon_tail = skb->data + tail_offset;
++ bool has_ml_ie = false;
++ int bpcc;
++
++ for_each_element_extid(elem, WLAN_EID_EXT_EHT_MULTI_LINK,
++ beacon_tail, skb->len - tail_offset)
++ if (ieee80211_mle_type_ok(elem->data + 1,
++ IEEE80211_ML_CONTROL_TYPE_BASIC,
++ elem->datalen - 1)) {
++ has_ml_ie = true;
++ break;
++ }
++
++ if (!has_ml_ie)
++ return false;
++
++ bpcc = ieee80211_mle_get_bss_param_ch_cnt(elem->data + 1);
++ if (bpcc < 0 || bpcc == mconf->bpcc)
++ return false;
++
++ mconf->bpcc = bpcc;
++
++ return true;
++}
++
++static void
++mt7996_mcu_beacon_crit_update(struct sk_buff *rskb, struct sk_buff *skb,
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf,
++ struct ieee80211_mutable_offsets *offs)
++{
++ struct ieee80211_mgmt *mgmt = (void *)skb->data;
++ struct bss_bcn_crit_update_tlv *crit;
++ struct tlv *tlv;
++
++ if (!ieee80211_vif_is_mld(conf->vif) ||
++ !(mgmt->u.beacon.capab_info & WLAN_CAPABILITY_PBCC))
++ return;
++
++ tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_CRIT_UPDATE, sizeof(*crit));
++
++ /* TODO: Support 11vMBSS */
++ crit = (struct bss_bcn_crit_update_tlv *)tlv;
++ crit->bss_bitmap = cpu_to_le32(BIT(0));
++ /* The beacon of the CU link should be set in sequence
++ * to ensure it appears in the air before the beacon of
++ * the non-CU link.
++ */
++ if (!mt7996_mcu_beacon_is_cu_link(skb, mconf, offs->tim_offset))
++ crit->bypass_seq_bitmap = cpu_to_le32(BIT(0));
++ else
++ crit->bypass_seq_bitmap = cpu_to_le32(0);
++ crit->tim_ie_pos[0] = cpu_to_le16(offs->tim_offset);
++ crit->cap_info_ie_pos[0] = cpu_to_le16(offsetof(struct ieee80211_mgmt,
++ u.beacon.capab_info));
++}
++
++static void
++mt7996_mcu_beacon_sta_prof_csa(struct sk_buff *rskb,
++ struct ieee80211_bss_conf *conf,
++ struct ieee80211_mutable_offsets *offs)
++{
++ struct ieee80211_vif *vif = conf->vif;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *cs_mconf;
++ struct bss_bcn_sta_prof_cntdwn_tlv *sta_prof;
++ struct tlv *tlv;
++
++ if (!ieee80211_vif_is_mld(vif) || !offs->sta_prof_cntdwn_offs[0])
++ return;
++
++ cs_mconf = mconf_dereference_protected(mvif, mvif->cs_link_id);
++ if (!cs_mconf)
++ return;
++
++ tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_STA_PROF_CSA, sizeof(*sta_prof));
++
++ sta_prof = (struct bss_bcn_sta_prof_cntdwn_tlv *)tlv;
++ sta_prof->sta_prof_csa_offs = cpu_to_le16(offs->sta_prof_cntdwn_offs[0] - 4);
++ sta_prof->cs_bss_idx = cs_mconf->mt76.idx;
++}
++
+ static void
+ mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
+ struct sk_buff *rskb, struct sk_buff *skb,
+@@ -3315,6 +3412,8 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw,
+ mt7996_mcu_beacon_cont(dev, conf, rskb, skb, bcn, &offs);
+ mt7996_mcu_beacon_mbss(rskb, skb, conf, bcn, &offs);
+ mt7996_mcu_beacon_cntdwn(conf, rskb, skb, &offs);
++ mt7996_mcu_beacon_sta_prof_csa(rskb, conf, &offs);
++ mt7996_mcu_beacon_crit_update(rskb, skb, conf, mconf, &offs);
+ out:
+ dev_kfree_skb(skb);
+ return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index 5e217719..c39dcc3c 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -503,6 +503,27 @@ struct bss_bcn_mbss_tlv {
+ __le16 offset[MAX_BEACON_NUM];
+ } __packed __aligned(4);
+
++struct bss_bcn_crit_update_tlv {
++ __le16 tag;
++ __le16 len;
++ __le32 bss_bitmap;
++ /* Bypass the beacon sequence handling in firmware for the
++ * BSSes in the bitmap. If the flag is set for a BSS, then the
++ * firmware will not set the beacon of the BSS in sequence.
++ */
++ __le32 bypass_seq_bitmap;
++ __le16 tim_ie_pos[32];
++ __le16 cap_info_ie_pos[32];
++} __packed;
++
++struct bss_bcn_sta_prof_cntdwn_tlv {
++ __le16 tag;
++ __le16 len;
++ __le16 sta_prof_csa_offs;
++ u8 cs_bss_idx;
++ u8 pkt_content[9];
++} __packed;
++
+ struct bss_txcmd_tlv {
+ __le16 tag;
+ __le16 len;
+@@ -954,7 +975,10 @@ enum {
+ sizeof(struct bss_bcn_content_tlv) + \
+ 4 + MT_TXD_SIZE + \
+ sizeof(struct bss_bcn_cntdwn_tlv) + \
+- sizeof(struct bss_bcn_mbss_tlv))
++ sizeof(struct bss_bcn_mbss_tlv) + \
++ sizeof(struct bss_bcn_crit_update_tlv) + \
++ sizeof(struct bss_bcn_sta_prof_cntdwn_tlv)) \
++
+ #define MT7996_MAX_BSS_OFFLOAD_SIZE (MT7996_MAX_BEACON_SIZE + \
+ MT7996_BEACON_UPDATE_SIZE)
+
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 827c24bf..78226f7b 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -351,6 +351,7 @@ struct mt7996_bss_conf {
+
+ u8 link_id;
+ u8 own_mld_id;
++ u8 bpcc;
+ };
+
+ struct mt7996_vif {
+@@ -365,6 +366,9 @@ struct mt7996_vif {
+ u8 group_mld_id;
+ u8 mld_remap_id;
+
++ u8 cs_link_id;
++ u16 cs_ready_links;
++
+ u8 band_to_link[__MT_MAX_BAND];
+
+ /* for beacon monitoring */
+--
+2.18.0
+