developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 1 | From a025d78199c2a329723707c689075c34d7c780e5 Mon Sep 17 00:00:00 2001 |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 2 | From: Shayne Chen <shayne.chen@mediatek.com> |
| 3 | Date: Fri, 31 May 2024 18:14:59 +0800 |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 4 | Subject: [PATCH 170/223] mtk: mt76: mt7996: add AP affiliated link removal |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 5 | support |
| 6 | |
| 7 | Add support for ap link removal of MLD reconfiguration. |
| 8 | |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 9 | Change-Id: I27a611dcf6698f89f6a3a67f893a166d2afe6b1f |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 10 | Signed-off-by: Shayne Chen <shayne.chen@mediatek.com> |
| 11 | --- |
| 12 | mt76_connac_mcu.h | 3 + |
| 13 | mt7996/main.c | 68 ++++++++++++--- |
| 14 | mt7996/mcu.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++ |
| 15 | mt7996/mcu.h | 89 ++++++++++++++++++- |
| 16 | mt7996/mt7996.h | 2 + |
| 17 | 5 files changed, 367 insertions(+), 12 deletions(-) |
| 18 | |
| 19 | diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 20 | index 302567e3..4976d944 100644 |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 21 | --- a/mt76_connac_mcu.h |
| 22 | +++ b/mt76_connac_mcu.h |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 23 | @@ -1079,6 +1079,7 @@ enum { |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 24 | MCU_UNI_EVENT_PP = 0x5a, |
| 25 | MCU_UNI_EVENT_PER_STA_INFO = 0x6d, |
| 26 | MCU_UNI_EVENT_ALL_STA_INFO = 0x6e, |
| 27 | + MCU_UNI_EVENT_MLD = 0x81, |
| 28 | }; |
| 29 | |
| 30 | #define MCU_UNI_CMD_EVENT BIT(1) |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 31 | @@ -1324,6 +1325,7 @@ enum { |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 32 | MCU_UNI_CMD_ALL_STA_INFO = 0x6e, |
| 33 | MCU_UNI_CMD_ASSERT_DUMP = 0x6f, |
| 34 | MCU_UNI_CMD_PTA_3WIRE_CTRL = 0x78, |
| 35 | + MCU_UNI_CMD_MLD = 0x82, |
| 36 | }; |
| 37 | |
| 38 | enum { |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 39 | @@ -1398,6 +1400,7 @@ enum { |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 40 | UNI_BSS_INFO_PM_DISABLE = 27, |
| 41 | UNI_BSS_INFO_BCN_CRIT_UPDATE = 32, |
| 42 | UNI_BSS_INFO_BCN_STA_PROF_CSA = 37, |
| 43 | + UNI_BSS_INFO_BCN_ML_RECONF = 38, |
| 44 | }; |
| 45 | |
| 46 | enum { |
| 47 | diff --git a/mt7996/main.c b/mt7996/main.c |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 48 | index c95e7e35..6ad4558b 100644 |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 49 | --- a/mt7996/main.c |
| 50 | +++ b/mt7996/main.c |
| 51 | @@ -319,6 +319,21 @@ static void mt7996_remove_bss_conf(struct ieee80211_vif *vif, |
| 52 | list_del_init(&mlink->wcid.poll_list); |
| 53 | spin_unlock_bh(&dev->mt76.sta_poll_lock); |
| 54 | |
| 55 | + /* reassign a new bss wcid if the previous one was removed */ |
| 56 | + if (vif->txq && ieee80211_vif_is_mld(vif) && |
| 57 | + hweight16(vif->valid_links) > 1) { |
| 58 | + struct mt76_txq *mtxq = (struct mt76_txq *)vif->txq->drv_priv; |
| 59 | + |
| 60 | + if (mtxq->wcid == mlink->wcid.idx) { |
| 61 | + u8 new_link = __ffs(vif->valid_links & ~BIT(link_id)); |
| 62 | + struct mt7996_link_sta *new_mlink = |
| 63 | + mlink_dereference_protected(&mvif->sta, new_link); |
| 64 | + |
| 65 | + if (new_mlink) |
| 66 | + mtxq->wcid = new_mlink->wcid.idx; |
| 67 | + } |
| 68 | + } |
| 69 | + |
| 70 | mt76_wcid_cleanup(&dev->mt76, &mlink->wcid); |
| 71 | |
| 72 | if (mlink != &mvif->sta.deflink) |
| 73 | @@ -425,7 +440,7 @@ static int mt7996_add_bss_conf(struct mt7996_phy *phy, |
| 74 | mt7996_mac_wtbl_update(dev, idx, |
| 75 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); |
| 76 | |
| 77 | - if (vif->txq) { |
| 78 | + if (vif->txq && hweight16(vif->valid_links) <= 1) { |
| 79 | mtxq = (struct mt76_txq *)vif->txq->drv_priv; |
| 80 | mtxq->wcid = idx; |
| 81 | } |
| 82 | @@ -1128,6 +1143,8 @@ static void mt7996_remove_link_sta(struct mt7996_dev *dev, |
| 83 | { |
| 84 | struct ieee80211_sta *sta = link_sta->sta; |
| 85 | struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; |
| 86 | + u16 valid_links = sta->valid_links; |
| 87 | + bool pri_changed; |
| 88 | int i; |
| 89 | |
| 90 | if (!mlink) |
| 91 | @@ -1148,6 +1165,7 @@ static void mt7996_remove_link_sta(struct mt7996_dev *dev, |
| 92 | mt7996_mac_twt_teardown_flow(dev, mlink, i); |
| 93 | |
| 94 | rcu_assign_pointer(mlink->sta->link[mlink->wcid.link_id], NULL); |
| 95 | + rcu_assign_pointer(dev->mt76.wcid[mlink->wcid.idx], NULL); |
| 96 | |
| 97 | spin_lock_bh(&dev->mt76.sta_poll_lock); |
| 98 | if (!list_empty(&mlink->wcid.poll_list)) |
| 99 | @@ -1156,17 +1174,41 @@ static void mt7996_remove_link_sta(struct mt7996_dev *dev, |
| 100 | list_del_init(&mlink->rc_list); |
| 101 | spin_unlock_bh(&dev->mt76.sta_poll_lock); |
| 102 | |
| 103 | - /* TODO: update primary link */ |
| 104 | - if (sta->valid_links) { |
| 105 | - if (mlink->wcid.link_id == msta->pri_link) |
| 106 | - msta->pri_link = msta->sec_link; |
| 107 | + valid_links &= ~BIT(mlink->wcid.link_id); |
| 108 | + if (!valid_links) |
| 109 | + goto done; |
| 110 | |
| 111 | - if (sta->valid_links & ~(BIT(msta->pri_link))) |
| 112 | - msta->sec_link = __ffs(sta->valid_links & ~(BIT(msta->pri_link))); |
| 113 | - else |
| 114 | - msta->sec_link = msta->pri_link; |
| 115 | + /* update primary and secondary link */ |
| 116 | + pri_changed = mlink->wcid.link_id == msta->pri_link; |
| 117 | + if (pri_changed) |
| 118 | + msta->pri_link = msta->sec_link; |
| 119 | + |
| 120 | + if (valid_links & ~(BIT(msta->pri_link))) |
| 121 | + msta->sec_link = __ffs(valid_links & ~(BIT(msta->pri_link))); |
| 122 | + else |
| 123 | + msta->sec_link = msta->pri_link; |
| 124 | + |
| 125 | + if (pri_changed) { |
| 126 | + struct mt7996_link_sta *mlink_new = |
| 127 | + mlink_dereference_protected(msta, msta->pri_link); |
| 128 | + |
| 129 | + if (!mlink_new) |
| 130 | + goto done; |
| 131 | + |
| 132 | + mlink_new->wcid.ampdu_state = mlink->wcid.ampdu_state; |
| 133 | + for (i = 0; i < ARRAY_SIZE(mlink->wcid.aggr); i++) |
| 134 | + rcu_assign_pointer(mlink_new->wcid.aggr[i], mlink->wcid.aggr[i]); |
| 135 | + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { |
| 136 | + struct mt76_txq *mtxq; |
| 137 | + |
| 138 | + if (!sta->txq[i]) |
| 139 | + continue; |
| 140 | + mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; |
| 141 | + mtxq->wcid = mlink_new->wcid.idx; |
| 142 | + } |
| 143 | } |
| 144 | |
| 145 | +done: |
| 146 | mt76_wcid_cleanup(&dev->mt76, &mlink->wcid); |
| 147 | mt76_wcid_mask_clear(dev->mt76.wcid_mask, mlink->wcid.idx); |
| 148 | mt76_wcid_mask_clear(dev->mt76.wcid_phy_mask, mlink->wcid.idx); |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 149 | @@ -3108,9 +3150,15 @@ mt7996_change_sta_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 150 | mt76_vif_dbg(vif, "STA %pM old=0x%x, new=0x%x\n", sta->addr, old_links, new_links); |
| 151 | mutex_lock(&dev->mt76.mutex); |
| 152 | |
| 153 | - if (rem) |
| 154 | + if (rem) { |
| 155 | mt7996_mac_sta_remove_links(dev, vif, sta, rem); |
| 156 | |
| 157 | + /* Todo: update hw info of MLD STA */ |
| 158 | + /* ret = mt7996_mcu_add_mld_sta(dev, vif, sta, new_links); */ |
| 159 | + /* if (ret) */ |
| 160 | + /* goto remove; */ |
| 161 | + } |
| 162 | + |
| 163 | ret = mt7996_mac_sta_add_links(dev, vif, sta, add, false); |
| 164 | if (ret) |
| 165 | goto remove; |
| 166 | diff --git a/mt7996/mcu.c b/mt7996/mcu.c |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 167 | index 856168f6..417c38a3 100644 |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 168 | --- a/mt7996/mcu.c |
| 169 | +++ b/mt7996/mcu.c |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 170 | @@ -1355,6 +1355,48 @@ mt7996_mcu_pp_event(struct mt7996_dev *dev, struct sk_buff *skb) |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 171 | } |
| 172 | } |
| 173 | |
| 174 | +static void |
| 175 | +mt7996_mcu_mld_reconf_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) |
| 176 | +{ |
| 177 | + struct mt7996_mld_event_data *data = priv; |
| 178 | + struct mt7996_mcu_mld_ap_reconf_event *reconf = (void *)data->data; |
| 179 | + |
| 180 | + if (!ether_addr_equal(vif->addr, data->mld_addr)) |
| 181 | + return; |
| 182 | + |
| 183 | + ieee80211_links_removed(vif, le16_to_cpu(reconf->link_bitmap)); |
| 184 | +} |
| 185 | + |
| 186 | +static void |
| 187 | +mt7996_mcu_mld_event(struct mt7996_dev *dev, struct sk_buff *skb) |
| 188 | +{ |
| 189 | + struct mt7996_mcu_mld_event *event = (void *)skb->data; |
| 190 | + struct mt7996_mld_event_data data = {}; |
| 191 | + struct tlv *tlv; |
| 192 | + int len; |
| 193 | + |
| 194 | + memcpy(data.mld_addr, event->mld_addr, ETH_ALEN); |
| 195 | + skb_pull(skb, sizeof(*event)); |
| 196 | + tlv = (struct tlv *)skb->data; |
| 197 | + len = skb->len; |
| 198 | + |
| 199 | + while (len > 0 && le16_to_cpu(tlv->len) <= len) { |
| 200 | + switch (le16_to_cpu(tlv->tag)) { |
| 201 | + case UNI_EVENT_MLD_RECONF_AP_REM_TIMER: |
| 202 | + data.data = (u8 *)tlv; |
| 203 | + ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw, |
| 204 | + IEEE80211_IFACE_ITER_RESUME_ALL, |
| 205 | + mt7996_mcu_mld_reconf_finish, &data); |
| 206 | + break; |
| 207 | + default: |
| 208 | + break; |
| 209 | + } |
| 210 | + |
| 211 | + len -= le16_to_cpu(tlv->len); |
| 212 | + tlv = (struct tlv *)((u8 *)(tlv) + le16_to_cpu(tlv->len)); |
| 213 | + } |
| 214 | +} |
| 215 | + |
| 216 | static void |
| 217 | mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) |
| 218 | { |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 219 | @@ -1383,6 +1425,9 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 220 | case MCU_UNI_EVENT_PP: |
| 221 | mt7996_mcu_pp_event(dev, skb); |
| 222 | break; |
| 223 | + case MCU_UNI_EVENT_MLD: |
| 224 | + mt7996_mcu_mld_event(dev, skb); |
| 225 | + break; |
| 226 | #ifdef CONFIG_MTK_DEBUG |
| 227 | case MCU_UNI_EVENT_SR: |
| 228 | mt7996_mcu_rx_sr_event(dev, skb); |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 229 | @@ -3176,6 +3221,44 @@ out: |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 230 | MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); |
| 231 | } |
| 232 | |
| 233 | +int mt7996_mcu_add_mld_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, |
| 234 | + struct ieee80211_sta *sta, unsigned long add) |
| 235 | +{ |
| 236 | + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; |
| 237 | + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; |
| 238 | + u8 link_id; |
| 239 | + |
| 240 | + if (!sta->mlo) |
| 241 | + return 0; |
| 242 | + |
| 243 | + for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { |
| 244 | + struct mt7996_bss_conf *mconf = |
| 245 | + mconf_dereference_protected(mvif, link_id); |
| 246 | + struct mt7996_link_sta *mlink = |
| 247 | + mlink_dereference_protected(msta, link_id); |
| 248 | + struct sk_buff *skb; |
| 249 | + int ret; |
| 250 | + |
| 251 | + if (!mconf || !mlink) |
| 252 | + continue; |
| 253 | + |
| 254 | + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76, |
| 255 | + &mlink->wcid, |
| 256 | + MT7996_STA_UPDATE_MAX_SIZE); |
| 257 | + if (IS_ERR(skb)) |
| 258 | + return PTR_ERR(skb); |
| 259 | + /* starec mld setup */ |
| 260 | + mt7996_mcu_sta_mld_setup_tlv(dev, skb, sta, add); |
| 261 | + /* starec eht mld */ |
| 262 | + mt7996_mcu_sta_eht_mld_tlv(dev, skb, sta); |
| 263 | + ret = mt76_mcu_skb_send_msg(&dev->mt76, skb, |
| 264 | + MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); |
| 265 | + if (ret) |
| 266 | + return ret; |
| 267 | + } |
| 268 | + return 0; |
| 269 | +} |
| 270 | + |
| 271 | int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev, |
| 272 | struct mt7996_bss_conf *mconf, |
| 273 | struct mt7996_link_sta *mlink) |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 274 | @@ -3388,6 +3471,51 @@ int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 275 | &data, sizeof(data), true); |
| 276 | } |
| 277 | |
| 278 | +static int |
| 279 | +mt7996_mcu_mld_reconf(struct mt7996_dev *dev, struct ieee80211_vif *vif, |
| 280 | + u16 removed_links, u16 *removal_count) |
| 281 | +{ |
| 282 | + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; |
| 283 | + struct mld_req_hdr hdr = { .mld_idx = 0xff }; |
| 284 | + struct mld_reconf_timer *rt; |
| 285 | + struct sk_buff *skb; |
| 286 | + struct tlv *tlv; |
| 287 | + int len = sizeof(hdr) + sizeof(*rt); |
| 288 | + unsigned long rem = removed_links; |
| 289 | + u8 link_id; |
| 290 | + |
| 291 | + memcpy(hdr.mld_addr, vif->addr, ETH_ALEN); |
| 292 | + |
| 293 | + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len); |
| 294 | + if (!skb) |
| 295 | + return -ENOMEM; |
| 296 | + |
| 297 | + skb_put_data(skb, &hdr, sizeof(hdr)); |
| 298 | + |
| 299 | + tlv = mt7996_mcu_add_uni_tlv(skb, UNI_CMD_MLD_RECONF_AP_REM_TIMER, sizeof(*rt)); |
| 300 | + rt = (struct mld_reconf_timer *)tlv; |
| 301 | + rt->link_bitmap = cpu_to_le16(removed_links); |
| 302 | + |
| 303 | + for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) { |
| 304 | + struct ieee80211_bss_conf *conf = |
| 305 | + link_conf_dereference_protected(vif, link_id); |
| 306 | + struct mt7996_bss_conf *mconf = |
| 307 | + mconf_dereference_protected(mvif, link_id); |
| 308 | + u8 band_idx; |
| 309 | + u16 to_sec; |
| 310 | + |
| 311 | + if (!conf || !mconf) |
| 312 | + continue; |
| 313 | + |
| 314 | + band_idx = mconf->phy->mt76->band_idx; |
| 315 | + to_sec = conf->beacon_int * removal_count[link_id] / 1000; |
| 316 | + rt->to_sec[band_idx] = cpu_to_le16(to_sec); |
| 317 | + rt->bss_idx[band_idx] = mconf->mt76.idx; |
| 318 | + } |
| 319 | + |
| 320 | + return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(MLD), true); |
| 321 | +} |
| 322 | + |
| 323 | static void |
| 324 | mt7996_mcu_beacon_cntdwn(struct ieee80211_bss_conf *conf, struct sk_buff *rskb, |
| 325 | struct sk_buff *skb, |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 326 | @@ -3582,6 +3710,94 @@ mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf, |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 327 | mt7996_packet_log_to_host(dev, skb->data, skb->len, PKT_BIN_DEBUG_TX, 0); |
| 328 | } |
| 329 | |
| 330 | +static void |
| 331 | +mt7996_mcu_beacon_ml_reconf(struct mt7996_dev *dev, |
| 332 | + struct ieee80211_bss_conf *conf, |
| 333 | + struct sk_buff *rskb, struct sk_buff *skb, |
| 334 | + struct ieee80211_mutable_offsets *offs) |
| 335 | +{ |
| 336 | + struct mt7996_vif *mvif = (struct mt7996_vif *)conf->vif->drv_priv; |
| 337 | + struct bss_bcn_ml_reconf_tlv *reconf; |
| 338 | + struct bss_bcn_ml_reconf_offset *reconf_offs; |
| 339 | + const struct element *elem, *sub; |
| 340 | + struct tlv *tlv; |
| 341 | + u16 removal_offs[IEEE80211_MLD_MAX_NUM_LINKS] = {}; |
| 342 | + u16 removal_count[IEEE80211_MLD_MAX_NUM_LINKS] = {}; |
| 343 | + u16 tail_offset = offs->tim_offset + offs->tim_length; |
| 344 | + unsigned long removed_links = 0; |
| 345 | + bool has_reconf = false; |
| 346 | + u8 link_id, *beacon_tail = skb->data + tail_offset; |
| 347 | + |
| 348 | + if (!ieee80211_vif_is_mld(conf->vif)) |
| 349 | + return; |
| 350 | + |
| 351 | + /* TODO: currently manually parse reconf info directly from the IE, it |
| 352 | + * is expected to be passed from upper layer in the future. |
| 353 | + */ |
| 354 | + for_each_element_extid(elem, WLAN_EID_EXT_EHT_MULTI_LINK, |
| 355 | + beacon_tail, skb->len - tail_offset) { |
| 356 | + if (ieee80211_mle_type_ok(elem->data + 1, |
| 357 | + IEEE80211_ML_CONTROL_TYPE_RECONF, |
| 358 | + elem->datalen - 1)) { |
| 359 | + has_reconf = true; |
| 360 | + break; |
| 361 | + } |
| 362 | + } |
| 363 | + |
| 364 | + if (!has_reconf) |
| 365 | + return; |
| 366 | + |
| 367 | + for_each_mle_subelement(sub, elem->data + 1, elem->datalen - 1) { |
| 368 | + struct ieee80211_mle_per_sta_profile *prof = (void *)sub->data; |
| 369 | + u8 *pos = prof->variable; |
| 370 | + u16 control; |
| 371 | + |
| 372 | + if (sub->id != IEEE80211_MLE_SUBELEM_PER_STA_PROFILE) |
| 373 | + continue; |
| 374 | + |
| 375 | + if (!ieee80211_mle_reconf_sta_prof_size_ok(sub->data, |
| 376 | + sub->datalen)) |
| 377 | + return; |
| 378 | + |
| 379 | + control = le16_to_cpu(prof->control); |
| 380 | + link_id = control & IEEE80211_MLE_STA_RECONF_CONTROL_LINK_ID; |
| 381 | + |
| 382 | + removed_links |= BIT(link_id); |
| 383 | + |
| 384 | + if (control & IEEE80211_MLE_STA_RECONF_CONTROL_STA_MAC_ADDR_PRESENT) |
| 385 | + pos += 6; |
| 386 | + |
| 387 | + if (control & IEEE80211_MLE_STA_RECONF_CONTROL_AP_REM_TIMER_PRESENT) { |
| 388 | + removal_offs[link_id] = pos - skb->data; |
| 389 | + removal_count[link_id] = le16_to_cpu(*(__le16 *)pos); |
| 390 | + } |
| 391 | + } |
| 392 | + |
| 393 | + if (!removed_links) |
| 394 | + return; |
| 395 | + |
| 396 | + /* the first link to be removed */ |
| 397 | + if (conf->link_id == ffs(removed_links) - 1) |
| 398 | + mt7996_mcu_mld_reconf(dev, conf->vif, removed_links, removal_count); |
| 399 | + |
| 400 | + tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_ML_RECONF, |
| 401 | + sizeof(*reconf) + |
| 402 | + sizeof(*reconf_offs) * hweight16(removed_links)); |
| 403 | + reconf = (struct bss_bcn_ml_reconf_tlv *)tlv; |
| 404 | + reconf->reconf_count = hweight16(removed_links); |
| 405 | + |
| 406 | + reconf_offs = (struct bss_bcn_ml_reconf_offset *)reconf->offset; |
| 407 | + for_each_set_bit(link_id, &removed_links, IEEE80211_MLD_MAX_NUM_LINKS) { |
| 408 | + struct mt7996_bss_conf *mconf = |
| 409 | + mconf_dereference_protected(mvif, link_id); |
| 410 | + |
| 411 | + reconf_offs->ap_removal_timer_offs = |
| 412 | + cpu_to_le16(removal_offs[link_id]); |
| 413 | + reconf_offs->bss_idx = mconf->mt76.idx; |
| 414 | + reconf_offs++; |
| 415 | + } |
| 416 | +} |
| 417 | + |
| 418 | int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, |
| 419 | struct ieee80211_bss_conf *conf, |
| 420 | struct mt7996_bss_conf *mconf, int en) |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 421 | @@ -3635,6 +3851,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 422 | mt7996_mcu_beacon_cntdwn(conf, rskb, skb, &offs); |
| 423 | mt7996_mcu_beacon_sta_prof_csa(rskb, conf, &offs); |
| 424 | mt7996_mcu_beacon_crit_update(rskb, skb, conf, mconf, &offs); |
| 425 | + mt7996_mcu_beacon_ml_reconf(dev, conf, rskb, skb, &offs); |
| 426 | out: |
| 427 | dev_kfree_skb(skb); |
| 428 | return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb, |
| 429 | diff --git a/mt7996/mcu.h b/mt7996/mcu.h |
| 430 | index 739e357c..7c559d2b 100644 |
| 431 | --- a/mt7996/mcu.h |
| 432 | +++ b/mt7996/mcu.h |
| 433 | @@ -546,6 +546,20 @@ struct bss_bcn_sta_prof_cntdwn_tlv { |
| 434 | u8 pkt_content[9]; |
| 435 | } __packed; |
| 436 | |
| 437 | +struct bss_bcn_ml_reconf_tlv { |
| 438 | + __le16 tag; |
| 439 | + __le16 len; |
| 440 | + u8 reconf_count; |
| 441 | + u8 rsv[3]; |
| 442 | + u8 offset[]; |
| 443 | +} __packed; |
| 444 | + |
| 445 | +struct bss_bcn_ml_reconf_offset { |
| 446 | + __le16 ap_removal_timer_offs; |
| 447 | + u8 bss_idx; |
| 448 | + u8 rsv; |
| 449 | +} __packed; |
| 450 | + |
| 451 | struct bss_txcmd_tlv { |
| 452 | __le16 tag; |
| 453 | __le16 len; |
| 454 | @@ -594,6 +608,17 @@ struct bss_mld_tlv { |
| 455 | u8 __rsv[3]; |
| 456 | } __packed; |
| 457 | |
| 458 | +struct bss_mld_link_op_tlv { |
| 459 | + __le16 tag; |
| 460 | + __le16 len; |
| 461 | + u8 group_mld_id; |
| 462 | + u8 own_mld_id; |
| 463 | + u8 mac_addr[ETH_ALEN]; |
| 464 | + u8 remap_idx; |
| 465 | + u8 link_operation; |
| 466 | + u8 rsv[2]; |
| 467 | +} __packed; |
| 468 | + |
| 469 | struct sta_rec_ht_uni { |
| 470 | __le16 tag; |
| 471 | __le16 len; |
| 472 | @@ -1003,8 +1028,9 @@ enum { |
| 473 | sizeof(struct bss_bcn_cntdwn_tlv) + \ |
| 474 | sizeof(struct bss_bcn_mbss_tlv) + \ |
| 475 | sizeof(struct bss_bcn_crit_update_tlv) + \ |
| 476 | - sizeof(struct bss_bcn_sta_prof_cntdwn_tlv)) \ |
| 477 | - |
| 478 | + sizeof(struct bss_bcn_sta_prof_cntdwn_tlv) + \ |
| 479 | + sizeof(struct bss_bcn_ml_reconf_tlv) + \ |
| 480 | + 3 * sizeof(struct bss_bcn_ml_reconf_offset)) |
| 481 | #define MT7996_MAX_BSS_OFFLOAD_SIZE (MT7996_MAX_BEACON_SIZE + \ |
| 482 | MT7996_BEACON_UPDATE_SIZE) |
| 483 | |
| 484 | @@ -1105,6 +1131,65 @@ enum { |
| 485 | UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG, |
| 486 | }; |
| 487 | |
| 488 | +struct mld_req_hdr { |
| 489 | + u8 ver; |
| 490 | + u8 mld_addr[ETH_ALEN]; |
| 491 | + u8 mld_idx; |
| 492 | + u8 flag; |
| 493 | + u8 rsv[3]; |
| 494 | + u8 buf[]; |
| 495 | +} __packed; |
| 496 | + |
| 497 | +struct mld_reconf_timer { |
| 498 | + __le16 tag; |
| 499 | + __le16 len; |
| 500 | + __le16 link_bitmap; |
| 501 | + __le16 to_sec[__MT_MAX_BAND]; /* timeout of reconf (second) */ |
| 502 | + u8 bss_idx[__MT_MAX_BAND]; |
| 503 | + u8 rsv; |
| 504 | +} __packed; |
| 505 | + |
| 506 | +struct mld_reconf_stop_link { |
| 507 | + __le16 tag; |
| 508 | + __le16 len; |
| 509 | + __le16 link_bitmap; |
| 510 | + u8 rsv[2]; |
| 511 | + u8 bss_idx[16]; |
| 512 | +} __packed; |
| 513 | + |
| 514 | +enum { |
| 515 | + UNI_CMD_MLD_RECONF_AP_REM_TIMER = 0x03, |
| 516 | +}; |
| 517 | + |
| 518 | +struct mt7996_mcu_mld_event { |
| 519 | + struct mt7996_mcu_rxd rxd; |
| 520 | + |
| 521 | + /* fixed field */ |
| 522 | + u8 ver; |
| 523 | + u8 mld_addr[ETH_ALEN]; |
| 524 | + u8 mld_idx; |
| 525 | + u8 rsv[4]; |
| 526 | + /* tlv */ |
| 527 | + u8 buf[]; |
| 528 | +} __packed; |
| 529 | + |
| 530 | +struct mt7996_mld_event_data { |
| 531 | + u8 mld_addr[ETH_ALEN]; |
| 532 | + u8 *data; |
| 533 | +}; |
| 534 | + |
| 535 | +struct mt7996_mcu_mld_ap_reconf_event { |
| 536 | + __le16 tag; |
| 537 | + __le16 len; |
| 538 | + __le16 link_bitmap; |
| 539 | + u8 bss_idx[3]; |
| 540 | + u8 rsv[3]; |
| 541 | +} __packed; |
| 542 | + |
| 543 | +enum { |
| 544 | + UNI_EVENT_MLD_RECONF_AP_REM_TIMER = 0x04, |
| 545 | +}; |
| 546 | + |
| 547 | struct tx_power_ctrl { |
| 548 | u8 _rsv[4]; |
| 549 | |
| 550 | diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 551 | index a02e976a..a7655a61 100644 |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 552 | --- a/mt7996/mt7996.h |
| 553 | +++ b/mt7996/mt7996.h |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 554 | @@ -1087,6 +1087,8 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 555 | struct mt7996_bss_conf *mconf, |
| 556 | struct ieee80211_link_sta *link_sta, |
| 557 | struct mt7996_link_sta *mlink, bool changed); |
| 558 | +int mt7996_mcu_add_mld_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif, |
| 559 | + struct ieee80211_sta *sta, unsigned long add); |
| 560 | int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef); |
| 561 | int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag, bool sta); |
| 562 | int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct mt7996_bss_conf *mconf); |
| 563 | -- |
developer | d0c8945 | 2024-10-11 16:53:27 +0800 | [diff] [blame^] | 564 | 2.45.2 |
developer | 05f3b2b | 2024-08-19 19:17:34 +0800 | [diff] [blame] | 565 | |