1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3 * Copyright (C) 2022-2025 Intel Corporation
4 */
5 #include "mvm.h"
6 #include "time-sync.h"
7 #include "sta.h"
8
iwl_mvm_sta_fw_id_mask(struct iwl_mvm * mvm,struct ieee80211_sta * sta,int filter_link_id)9 u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
10 int filter_link_id)
11 {
12 struct iwl_mvm_sta *mvmsta;
13
14 if (!sta)
15 return 0;
16
17 mvmsta = iwl_mvm_sta_from_mac80211(sta);
18
19 return BIT(mvmsta->deflink.sta_id);
20 }
21
iwl_mvm_mld_send_sta_cmd(struct iwl_mvm * mvm,struct iwl_sta_cfg_cmd * cmd)22 static int iwl_mvm_mld_send_sta_cmd(struct iwl_mvm *mvm,
23 struct iwl_sta_cfg_cmd *cmd)
24 {
25 u32 cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD);
26 int cmd_len = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 0) > 1 ?
27 sizeof(*cmd) :
28 sizeof(struct iwl_sta_cfg_cmd_v1);
29 int ret = iwl_mvm_send_cmd_pdu(mvm,
30 WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD),
31 0, cmd_len, cmd);
32 if (ret)
33 IWL_ERR(mvm, "STA_CONFIG_CMD send failed, ret=0x%x\n", ret);
34 return ret;
35 }
36
37 /*
38 * Add an internal station to the FW table
39 */
iwl_mvm_mld_add_int_sta_to_fw(struct iwl_mvm * mvm,struct iwl_mvm_int_sta * sta,const u8 * addr,int link_id)40 static int iwl_mvm_mld_add_int_sta_to_fw(struct iwl_mvm *mvm,
41 struct iwl_mvm_int_sta *sta,
42 const u8 *addr, int link_id)
43 {
44 struct iwl_sta_cfg_cmd cmd;
45
46 lockdep_assert_held(&mvm->mutex);
47
48 memset(&cmd, 0, sizeof(cmd));
49 cmd.sta_id = cpu_to_le32((u8)sta->sta_id);
50
51 cmd.link_id = cpu_to_le32(link_id);
52
53 cmd.station_type = cpu_to_le32(sta->type);
54
55 if (fw_has_capa(&mvm->fw->ucode_capa,
56 IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT) &&
57 sta->type == STATION_TYPE_BCAST_MGMT)
58 cmd.mfp = cpu_to_le32(1);
59
60 if (addr) {
61 memcpy(cmd.peer_mld_address, addr, ETH_ALEN);
62 memcpy(cmd.peer_link_address, addr, ETH_ALEN);
63 }
64
65 return iwl_mvm_mld_send_sta_cmd(mvm, &cmd);
66 }
67
68 /*
69 * Remove a station from the FW table. Before sending the command to remove
70 * the station validate that the station is indeed known to the driver (sanity
71 * only).
72 */
iwl_mvm_mld_rm_sta_from_fw(struct iwl_mvm * mvm,u32 sta_id)73 static int iwl_mvm_mld_rm_sta_from_fw(struct iwl_mvm *mvm, u32 sta_id)
74 {
75 struct iwl_remove_sta_cmd rm_sta_cmd = {
76 .sta_id = cpu_to_le32(sta_id),
77 };
78 int ret;
79
80 /* Note: internal stations are marked as error values */
81 if (!rcu_access_pointer(mvm->fw_id_to_mac_id[sta_id])) {
82 IWL_ERR(mvm, "Invalid station id %d\n", sta_id);
83 return -EINVAL;
84 }
85
86 ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, STA_REMOVE_CMD),
87 0, sizeof(rm_sta_cmd), &rm_sta_cmd);
88 if (ret) {
89 IWL_ERR(mvm, "Failed to remove station. Id=%d\n", sta_id);
90 return ret;
91 }
92
93 return 0;
94 }
95
iwl_mvm_add_aux_sta_to_fw(struct iwl_mvm * mvm,struct iwl_mvm_int_sta * sta,u32 lmac_id)96 static int iwl_mvm_add_aux_sta_to_fw(struct iwl_mvm *mvm,
97 struct iwl_mvm_int_sta *sta,
98 u32 lmac_id)
99 {
100 int ret;
101
102 struct iwl_aux_sta_cmd cmd = {
103 .sta_id = cpu_to_le32(sta->sta_id),
104 .lmac_id = cpu_to_le32(lmac_id),
105 };
106
107 ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, AUX_STA_CMD),
108 0, sizeof(cmd), &cmd);
109 if (ret)
110 IWL_ERR(mvm, "Failed to send AUX_STA_CMD\n");
111 return ret;
112 }
113
114 /*
115 * Adds an internal sta to the FW table with its queues
116 */
iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm * mvm,struct iwl_mvm_int_sta * sta,const u8 * addr,int link_id,u16 * queue,u8 tid,unsigned int * _wdg_timeout)117 int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm,
118 struct iwl_mvm_int_sta *sta,
119 const u8 *addr, int link_id,
120 u16 *queue, u8 tid,
121 unsigned int *_wdg_timeout)
122 {
123 int ret, txq;
124 unsigned int wdg_timeout = _wdg_timeout ? *_wdg_timeout :
125 mvm->trans->mac_cfg->base->wd_timeout;
126
127 if (WARN_ON_ONCE(sta->sta_id == IWL_INVALID_STA))
128 return -ENOSPC;
129
130 if (sta->type == STATION_TYPE_AUX)
131 ret = iwl_mvm_add_aux_sta_to_fw(mvm, sta, link_id);
132 else
133 ret = iwl_mvm_mld_add_int_sta_to_fw(mvm, sta, addr, link_id);
134 if (ret)
135 return ret;
136
137 /*
138 * For 22000 firmware and on we cannot add queue to a station unknown
139 * to firmware so enable queue here - after the station was added
140 */
141 txq = iwl_mvm_tvqm_enable_txq(mvm, NULL, sta->sta_id, tid,
142 wdg_timeout);
143 if (txq < 0) {
144 iwl_mvm_mld_rm_sta_from_fw(mvm, sta->sta_id);
145 return txq;
146 }
147 *queue = txq;
148
149 return 0;
150 }
151
152 /*
153 * Adds a new int sta: allocate it in the driver, add it to the FW table,
154 * and add its queues.
155 */
iwl_mvm_mld_add_int_sta(struct iwl_mvm * mvm,struct iwl_mvm_int_sta * int_sta,u16 * queue,enum nl80211_iftype iftype,enum iwl_fw_sta_type sta_type,int link_id,const u8 * addr,u8 tid,unsigned int * wdg_timeout)156 static int iwl_mvm_mld_add_int_sta(struct iwl_mvm *mvm,
157 struct iwl_mvm_int_sta *int_sta, u16 *queue,
158 enum nl80211_iftype iftype,
159 enum iwl_fw_sta_type sta_type,
160 int link_id, const u8 *addr, u8 tid,
161 unsigned int *wdg_timeout)
162 {
163 int ret;
164
165 lockdep_assert_held(&mvm->mutex);
166
167 /* qmask argument is not used in the new tx api, send a don't care */
168 ret = iwl_mvm_allocate_int_sta(mvm, int_sta, 0, iftype,
169 sta_type);
170 if (ret)
171 return ret;
172
173 ret = iwl_mvm_mld_add_int_sta_with_queue(mvm, int_sta, addr, link_id,
174 queue, tid, wdg_timeout);
175 if (ret) {
176 iwl_mvm_dealloc_int_sta(mvm, int_sta);
177 return ret;
178 }
179
180 return 0;
181 }
182
183 /* Allocate a new station entry for the broadcast station to the given vif,
184 * and send it to the FW.
185 * Note that each P2P mac should have its own broadcast station.
186 */
iwl_mvm_mld_add_bcast_sta(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)187 int iwl_mvm_mld_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
188 struct ieee80211_bss_conf *link_conf)
189 {
190 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
191 struct iwl_mvm_vif_link_info *mvm_link =
192 mvmvif->link[link_conf->link_id];
193 struct iwl_mvm_int_sta *bsta = &mvm_link->bcast_sta;
194 static const u8 _baddr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
195 const u8 *baddr = _baddr;
196 unsigned int wdg_timeout =
197 iwl_mvm_get_wd_timeout(mvm, vif);
198 u16 *queue;
199
200 lockdep_assert_held(&mvm->mutex);
201
202 if (vif->type == NL80211_IFTYPE_ADHOC)
203 baddr = link_conf->bssid;
204
205 if (vif->type == NL80211_IFTYPE_AP ||
206 vif->type == NL80211_IFTYPE_ADHOC) {
207 queue = &mvm_link->mgmt_queue;
208 } else if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
209 queue = &mvm->p2p_dev_queue;
210 } else {
211 WARN(1, "Missing required TXQ for adding bcast STA\n");
212 return -EINVAL;
213 }
214
215 return iwl_mvm_mld_add_int_sta(mvm, bsta, queue,
216 ieee80211_vif_type_p2p(vif),
217 STATION_TYPE_BCAST_MGMT,
218 mvm_link->fw_link_id, baddr,
219 IWL_MAX_TID_COUNT, &wdg_timeout);
220 }
221
222 /* Allocate a new station entry for the multicast station to the given vif,
223 * and send it to the FW.
224 * Note that each AP/GO mac should have its own multicast station.
225 */
iwl_mvm_mld_add_mcast_sta(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)226 int iwl_mvm_mld_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
227 struct ieee80211_bss_conf *link_conf)
228 {
229 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
230 struct iwl_mvm_vif_link_info *mvm_link =
231 mvmvif->link[link_conf->link_id];
232 struct iwl_mvm_int_sta *msta = &mvm_link->mcast_sta;
233 static const u8 _maddr[] = {0x03, 0x00, 0x00, 0x00, 0x00, 0x00};
234 const u8 *maddr = _maddr;
235 unsigned int timeout = iwl_mvm_get_wd_timeout(mvm, vif);
236
237 lockdep_assert_held(&mvm->mutex);
238
239 if (WARN_ON(vif->type != NL80211_IFTYPE_AP &&
240 vif->type != NL80211_IFTYPE_ADHOC))
241 return -EOPNOTSUPP;
242
243 /* In IBSS, ieee80211_check_queues() sets the cab_queue to be
244 * invalid, so make sure we use the queue we want.
245 * Note that this is done here as we want to avoid making DQA
246 * changes in mac80211 layer.
247 */
248 if (vif->type == NL80211_IFTYPE_ADHOC)
249 mvm_link->cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
250
251 return iwl_mvm_mld_add_int_sta(mvm, msta, &mvm_link->cab_queue,
252 vif->type, STATION_TYPE_MCAST,
253 mvm_link->fw_link_id, maddr, 0,
254 &timeout);
255 }
256
257 /* Allocate a new station entry for the sniffer station to the given vif,
258 * and send it to the FW.
259 */
iwl_mvm_mld_add_snif_sta(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)260 int iwl_mvm_mld_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
261 struct ieee80211_bss_conf *link_conf)
262 {
263 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
264 struct iwl_mvm_vif_link_info *mvm_link =
265 mvmvif->link[link_conf->link_id];
266
267 lockdep_assert_held(&mvm->mutex);
268
269 return iwl_mvm_mld_add_int_sta(mvm, &mvm->snif_sta, &mvm->snif_queue,
270 vif->type, STATION_TYPE_BCAST_MGMT,
271 mvm_link->fw_link_id, NULL,
272 IWL_MAX_TID_COUNT, NULL);
273 }
274
iwl_mvm_mld_add_aux_sta(struct iwl_mvm * mvm,u32 lmac_id)275 int iwl_mvm_mld_add_aux_sta(struct iwl_mvm *mvm, u32 lmac_id)
276 {
277 lockdep_assert_held(&mvm->mutex);
278
279 /* In CDB NICs we need to specify which lmac to use for aux activity;
280 * use the link_id argument place to send lmac_id to the function.
281 */
282 return iwl_mvm_mld_add_int_sta(mvm, &mvm->aux_sta, &mvm->aux_queue,
283 NL80211_IFTYPE_UNSPECIFIED,
284 STATION_TYPE_AUX, lmac_id, NULL,
285 IWL_MAX_TID_COUNT, NULL);
286 }
287
iwl_mvm_mld_disable_txq(struct iwl_mvm * mvm,u32 sta_mask,u16 * queueptr,u8 tid)288 static int iwl_mvm_mld_disable_txq(struct iwl_mvm *mvm, u32 sta_mask,
289 u16 *queueptr, u8 tid)
290 {
291 int queue = *queueptr;
292 int ret = 0;
293
294 if (tid == IWL_MAX_TID_COUNT)
295 tid = IWL_MGMT_TID;
296
297 if (mvm->sta_remove_requires_queue_remove) {
298 u32 cmd_id = WIDE_ID(DATA_PATH_GROUP,
299 SCD_QUEUE_CONFIG_CMD);
300 struct iwl_scd_queue_cfg_cmd remove_cmd = {
301 .operation = cpu_to_le32(IWL_SCD_QUEUE_REMOVE),
302 .u.remove.tid = cpu_to_le32(tid),
303 .u.remove.sta_mask = cpu_to_le32(sta_mask),
304 };
305
306 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0,
307 sizeof(remove_cmd),
308 &remove_cmd);
309 }
310
311 iwl_trans_txq_free(mvm->trans, queue);
312 *queueptr = IWL_MVM_INVALID_QUEUE;
313
314 return ret;
315 }
316
317 /* Removes a sta from the FW table, disable its queues, and dealloc it
318 */
iwl_mvm_mld_rm_int_sta(struct iwl_mvm * mvm,struct iwl_mvm_int_sta * int_sta,bool flush,u8 tid,u16 * queuptr)319 static int iwl_mvm_mld_rm_int_sta(struct iwl_mvm *mvm,
320 struct iwl_mvm_int_sta *int_sta,
321 bool flush, u8 tid, u16 *queuptr)
322 {
323 int ret;
324
325 lockdep_assert_held(&mvm->mutex);
326
327 if (WARN_ON_ONCE(int_sta->sta_id == IWL_INVALID_STA))
328 return -EINVAL;
329
330 if (flush)
331 iwl_mvm_flush_sta(mvm, int_sta->sta_id, int_sta->tfd_queue_msk);
332
333 iwl_mvm_mld_disable_txq(mvm, BIT(int_sta->sta_id), queuptr, tid);
334
335 ret = iwl_mvm_mld_rm_sta_from_fw(mvm, int_sta->sta_id);
336 if (ret)
337 IWL_WARN(mvm, "Failed sending remove station\n");
338
339 iwl_mvm_dealloc_int_sta(mvm, int_sta);
340
341 return ret;
342 }
343
iwl_mvm_mld_rm_bcast_sta(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)344 int iwl_mvm_mld_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
345 struct ieee80211_bss_conf *link_conf)
346 {
347 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
348 struct iwl_mvm_vif_link_info *link = mvmvif->link[link_conf->link_id];
349 u16 *queueptr;
350
351 lockdep_assert_held(&mvm->mutex);
352
353 if (WARN_ON(!link))
354 return -EIO;
355
356 switch (vif->type) {
357 case NL80211_IFTYPE_AP:
358 case NL80211_IFTYPE_ADHOC:
359 queueptr = &link->mgmt_queue;
360 break;
361 case NL80211_IFTYPE_P2P_DEVICE:
362 queueptr = &mvm->p2p_dev_queue;
363 break;
364 default:
365 WARN(1, "Can't free bcast queue on vif type %d\n",
366 vif->type);
367 return -EINVAL;
368 }
369
370 return iwl_mvm_mld_rm_int_sta(mvm, &link->bcast_sta,
371 true, IWL_MAX_TID_COUNT, queueptr);
372 }
373
374 /* Send the FW a request to remove the station from it's internal data
375 * structures, and in addition remove it from the local data structure.
376 */
iwl_mvm_mld_rm_mcast_sta(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)377 int iwl_mvm_mld_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
378 struct ieee80211_bss_conf *link_conf)
379 {
380 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
381 struct iwl_mvm_vif_link_info *link = mvmvif->link[link_conf->link_id];
382
383 lockdep_assert_held(&mvm->mutex);
384
385 if (WARN_ON(!link))
386 return -EIO;
387
388 return iwl_mvm_mld_rm_int_sta(mvm, &link->mcast_sta, true, 0,
389 &link->cab_queue);
390 }
391
iwl_mvm_mld_rm_snif_sta(struct iwl_mvm * mvm,struct ieee80211_vif * vif)392 int iwl_mvm_mld_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
393 {
394 lockdep_assert_held(&mvm->mutex);
395
396 return iwl_mvm_mld_rm_int_sta(mvm, &mvm->snif_sta, false,
397 IWL_MAX_TID_COUNT, &mvm->snif_queue);
398 }
399
iwl_mvm_mld_rm_aux_sta(struct iwl_mvm * mvm)400 int iwl_mvm_mld_rm_aux_sta(struct iwl_mvm *mvm)
401 {
402 lockdep_assert_held(&mvm->mutex);
403
404 return iwl_mvm_mld_rm_int_sta(mvm, &mvm->aux_sta, false,
405 IWL_MAX_TID_COUNT, &mvm->aux_queue);
406 }
407
408 /* send a cfg sta command to add/update a sta in firmware */
iwl_mvm_mld_cfg_sta(struct iwl_mvm * mvm,struct ieee80211_sta * sta,struct ieee80211_vif * vif,struct ieee80211_link_sta * link_sta,struct ieee80211_bss_conf * link_conf,struct iwl_mvm_link_sta * mvm_link_sta)409 static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
410 struct ieee80211_vif *vif,
411 struct ieee80211_link_sta *link_sta,
412 struct ieee80211_bss_conf *link_conf,
413 struct iwl_mvm_link_sta *mvm_link_sta)
414 {
415 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
416 struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);
417 struct iwl_mvm_vif_link_info *link_info =
418 mvm_vif->link[link_conf->link_id];
419 struct iwl_sta_cfg_cmd cmd = {
420 .sta_id = cpu_to_le32(mvm_link_sta->sta_id),
421 .station_type = cpu_to_le32(mvm_sta->sta_type),
422 };
423 u32 agg_size = 0, mpdu_dens = 0;
424
425 /* when adding sta, link should exist in FW */
426 if (WARN_ON(link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID))
427 return -EINVAL;
428
429 cmd.link_id = cpu_to_le32(link_info->fw_link_id);
430
431 memcpy(&cmd.peer_mld_address, sta->addr, ETH_ALEN);
432 memcpy(&cmd.peer_link_address, link_sta->addr, ETH_ALEN);
433
434 if (mvm_sta->sta_state >= IEEE80211_STA_ASSOC)
435 cmd.assoc_id = cpu_to_le32(sta->aid);
436
437 if (fw_has_capa(&mvm->fw->ucode_capa,
438 IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT) &&
439 (sta->mfp || mvm_sta->sta_state < IEEE80211_STA_AUTHORIZED))
440 cmd.mfp = cpu_to_le32(1);
441
442 switch (link_sta->rx_nss) {
443 case 1:
444 cmd.mimo = cpu_to_le32(0);
445 break;
446 case 2 ... 8:
447 cmd.mimo = cpu_to_le32(1);
448 break;
449 }
450
451 switch (link_sta->smps_mode) {
452 case IEEE80211_SMPS_AUTOMATIC:
453 case IEEE80211_SMPS_NUM_MODES:
454 WARN_ON(1);
455 break;
456 case IEEE80211_SMPS_STATIC:
457 /* override NSS */
458 cmd.mimo = cpu_to_le32(0);
459 break;
460 case IEEE80211_SMPS_DYNAMIC:
461 cmd.mimo_protection = cpu_to_le32(1);
462 break;
463 case IEEE80211_SMPS_OFF:
464 /* nothing */
465 break;
466 }
467
468 mpdu_dens = iwl_mvm_get_sta_ampdu_dens(link_sta, link_conf, &agg_size);
469 cmd.tx_ampdu_spacing = cpu_to_le32(mpdu_dens);
470 cmd.tx_ampdu_max_size = cpu_to_le32(agg_size);
471
472 if (sta->wme) {
473 cmd.sp_length =
474 cpu_to_le32(sta->max_sp ? sta->max_sp * 2 : 128);
475 cmd.uapsd_acs = cpu_to_le32(iwl_mvm_get_sta_uapsd_acs(sta));
476 }
477
478 if (link_sta->he_cap.has_he) {
479 cmd.trig_rnd_alloc =
480 cpu_to_le32(link_conf->uora_exists ? 1 : 0);
481
482 /* PPE Thresholds */
483 iwl_mvm_set_sta_pkt_ext(mvm, link_sta, &cmd.pkt_ext);
484
485 /* HTC flags */
486 cmd.htc_flags = iwl_mvm_get_sta_htc_flags(sta, link_sta);
487
488 if (link_sta->he_cap.he_cap_elem.mac_cap_info[2] &
489 IEEE80211_HE_MAC_CAP2_ACK_EN)
490 cmd.ack_enabled = cpu_to_le32(1);
491 }
492
493 return iwl_mvm_mld_send_sta_cmd(mvm, &cmd);
494 }
495
iwl_mvm_mld_free_sta_link(struct iwl_mvm * mvm,struct iwl_mvm_sta * mvm_sta,struct iwl_mvm_link_sta * mvm_sta_link,unsigned int link_id)496 void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm,
497 struct iwl_mvm_sta *mvm_sta,
498 struct iwl_mvm_link_sta *mvm_sta_link,
499 unsigned int link_id)
500 {
501 lockdep_assert_wiphy(mvm->hw->wiphy);
502 lockdep_assert_held(&mvm->mutex);
503
504 RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta_link->sta_id], NULL);
505 RCU_INIT_POINTER(mvm->fw_id_to_link_sta[mvm_sta_link->sta_id], NULL);
506 RCU_INIT_POINTER(mvm_sta->link[link_id], NULL);
507
508 if (mvm_sta_link != &mvm_sta->deflink)
509 kfree_rcu(mvm_sta_link, rcu_head);
510 }
511
iwl_mvm_mld_sta_rm_all_sta_links(struct iwl_mvm * mvm,struct iwl_mvm_sta * mvm_sta)512 static void iwl_mvm_mld_sta_rm_all_sta_links(struct iwl_mvm *mvm,
513 struct iwl_mvm_sta *mvm_sta)
514 {
515 unsigned int link_id;
516
517 for (link_id = 0; link_id < ARRAY_SIZE(mvm_sta->link); link_id++) {
518 struct iwl_mvm_link_sta *link =
519 rcu_dereference_protected(mvm_sta->link[link_id],
520 lockdep_is_held(&mvm->mutex));
521
522 if (!link)
523 continue;
524
525 iwl_mvm_mld_free_sta_link(mvm, mvm_sta, link, link_id);
526 }
527 }
528
iwl_mvm_mld_alloc_sta_link(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,unsigned int link_id)529 static int iwl_mvm_mld_alloc_sta_link(struct iwl_mvm *mvm,
530 struct ieee80211_vif *vif,
531 struct ieee80211_sta *sta,
532 unsigned int link_id)
533 {
534 struct ieee80211_link_sta *link_sta =
535 link_sta_dereference_protected(sta, link_id);
536 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
537 struct iwl_mvm_link_sta *link;
538 u32 sta_id = iwl_mvm_find_free_sta_id(mvm,
539 ieee80211_vif_type_p2p(vif));
540
541 lockdep_assert_wiphy(mvm->hw->wiphy);
542 lockdep_assert_held(&mvm->mutex);
543
544 if (sta_id == IWL_INVALID_STA)
545 return -ENOSPC;
546
547 if (rcu_access_pointer(sta->link[link_id]) == &sta->deflink) {
548 link = &mvm_sta->deflink;
549 } else {
550 link = kzalloc_obj(*link);
551 if (!link)
552 return -ENOMEM;
553 }
554
555 link->sta_id = sta_id;
556 rcu_assign_pointer(mvm_sta->link[link_id], link);
557 rcu_assign_pointer(mvm->fw_id_to_mac_id[link->sta_id], sta);
558 rcu_assign_pointer(mvm->fw_id_to_link_sta[link->sta_id],
559 link_sta);
560
561 return 0;
562 }
563
564 /* allocate all the links of a sta, called when the station is first added */
iwl_mvm_mld_alloc_sta_links(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta)565 static int iwl_mvm_mld_alloc_sta_links(struct iwl_mvm *mvm,
566 struct ieee80211_vif *vif,
567 struct ieee80211_sta *sta)
568 {
569 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
570 struct ieee80211_link_sta *link_sta;
571 unsigned int link_id;
572 int ret;
573
574 lockdep_assert_held(&mvm->mutex);
575
576 for_each_sta_active_link(vif, sta, link_sta, link_id) {
577 if (WARN_ON(mvm_sta->link[link_id]))
578 continue;
579
580 ret = iwl_mvm_mld_alloc_sta_link(mvm, vif, sta, link_id);
581 if (ret)
582 goto err;
583 }
584
585 return 0;
586
587 err:
588 iwl_mvm_mld_sta_rm_all_sta_links(mvm, mvm_sta);
589 return ret;
590 }
591
iwl_mvm_mld_set_ap_sta_id(struct ieee80211_sta * sta,struct iwl_mvm_vif_link_info * vif_link,struct iwl_mvm_link_sta * sta_link)592 static void iwl_mvm_mld_set_ap_sta_id(struct ieee80211_sta *sta,
593 struct iwl_mvm_vif_link_info *vif_link,
594 struct iwl_mvm_link_sta *sta_link)
595 {
596 if (!sta->tdls) {
597 WARN_ON(vif_link->ap_sta_id != IWL_INVALID_STA);
598 vif_link->ap_sta_id = sta_link->sta_id;
599 } else {
600 WARN_ON(vif_link->ap_sta_id == IWL_INVALID_STA);
601 }
602 }
603
iwl_mvm_alloc_sta_after_restart(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta)604 static int iwl_mvm_alloc_sta_after_restart(struct iwl_mvm *mvm,
605 struct ieee80211_vif *vif,
606 struct ieee80211_sta *sta)
607 {
608 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
609 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
610 struct ieee80211_link_sta *link_sta;
611 unsigned int link_id;
612 /* no active link found */
613 int ret = -EINVAL;
614 int sta_id;
615
616 lockdep_assert_wiphy(mvm->hw->wiphy);
617 lockdep_assert_held(&mvm->mutex);
618
619 /* First add an empty station since allocating a queue requires
620 * a valid station. Since we need a link_id to allocate a station,
621 * pick up the first valid one.
622 */
623 for_each_sta_active_link(vif, sta, link_sta, link_id) {
624 struct iwl_mvm_vif_link_info *mvm_link;
625 struct ieee80211_bss_conf *link_conf =
626 link_conf_dereference_protected(vif, link_id);
627 struct iwl_mvm_link_sta *mvm_link_sta =
628 rcu_dereference_protected(mvm_sta->link[link_id],
629 lockdep_is_held(&mvm->mutex));
630
631 if (!link_conf)
632 continue;
633
634 mvm_link = mvmvif->link[link_conf->link_id];
635
636 if (!mvm_link || !mvm_link_sta)
637 continue;
638
639 sta_id = mvm_link_sta->sta_id;
640 ret = iwl_mvm_mld_cfg_sta(mvm, sta, vif, link_sta,
641 link_conf, mvm_link_sta);
642 if (ret)
643 return ret;
644
645 rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
646 rcu_assign_pointer(mvm->fw_id_to_link_sta[sta_id], link_sta);
647 ret = 0;
648 }
649
650 iwl_mvm_realloc_queues_after_restart(mvm, sta);
651
652 return ret;
653 }
654
iwl_mvm_mld_add_sta(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta)655 int iwl_mvm_mld_add_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
656 struct ieee80211_sta *sta)
657 {
658 struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);
659 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
660 unsigned long link_sta_added_to_fw = 0;
661 struct ieee80211_link_sta *link_sta;
662 int ret = 0;
663 unsigned int link_id;
664
665 lockdep_assert_held(&mvm->mutex);
666
667 if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
668 ret = iwl_mvm_mld_alloc_sta_links(mvm, vif, sta);
669 if (ret)
670 return ret;
671
672 spin_lock_init(&mvm_sta->lock);
673
674 ret = iwl_mvm_sta_init(mvm, vif, sta, IWL_INVALID_STA,
675 STATION_TYPE_PEER);
676 } else {
677 ret = iwl_mvm_alloc_sta_after_restart(mvm, vif, sta);
678 }
679
680 if (ret)
681 goto err;
682
683 /* at this stage sta link pointers are already allocated */
684 ret = iwl_mvm_mld_update_sta(mvm, vif, sta);
685 if (ret)
686 goto err;
687
688 for_each_sta_active_link(vif, sta, link_sta, link_id) {
689 struct ieee80211_bss_conf *link_conf =
690 link_conf_dereference_protected(vif, link_id);
691 struct iwl_mvm_link_sta *mvm_link_sta =
692 rcu_dereference_protected(mvm_sta->link[link_id],
693 lockdep_is_held(&mvm->mutex));
694
695 if (WARN_ON(!link_conf || !mvm_link_sta)) {
696 ret = -EINVAL;
697 goto err;
698 }
699
700 ret = iwl_mvm_mld_cfg_sta(mvm, sta, vif, link_sta, link_conf,
701 mvm_link_sta);
702 if (ret)
703 goto err;
704
705 link_sta_added_to_fw |= BIT(link_id);
706
707 if (vif->type == NL80211_IFTYPE_STATION)
708 iwl_mvm_mld_set_ap_sta_id(sta, mvm_vif->link[link_id],
709 mvm_link_sta);
710 }
711 return 0;
712
713 err:
714 /* remove all already allocated stations in FW */
715 for_each_set_bit(link_id, &link_sta_added_to_fw,
716 IEEE80211_MLD_MAX_NUM_LINKS) {
717 struct iwl_mvm_link_sta *mvm_link_sta =
718 rcu_dereference_protected(mvm_sta->link[link_id],
719 lockdep_is_held(&mvm->mutex));
720
721 iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_link_sta->sta_id);
722 }
723
724 /* free all sta resources in the driver */
725 iwl_mvm_mld_sta_rm_all_sta_links(mvm, mvm_sta);
726 return ret;
727 }
728
iwl_mvm_mld_update_sta(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta)729 int iwl_mvm_mld_update_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
730 struct ieee80211_sta *sta)
731 {
732 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
733 struct ieee80211_link_sta *link_sta;
734 unsigned int link_id;
735 int ret = -EINVAL;
736
737 lockdep_assert_held(&mvm->mutex);
738
739 for_each_sta_active_link(vif, sta, link_sta, link_id) {
740 struct ieee80211_bss_conf *link_conf =
741 link_conf_dereference_protected(vif, link_id);
742 struct iwl_mvm_link_sta *mvm_link_sta =
743 rcu_dereference_protected(mvm_sta->link[link_id],
744 lockdep_is_held(&mvm->mutex));
745
746 if (WARN_ON(!link_conf || !mvm_link_sta))
747 return -EINVAL;
748
749 ret = iwl_mvm_mld_cfg_sta(mvm, sta, vif, link_sta, link_conf,
750 mvm_link_sta);
751
752 if (ret) {
753 IWL_ERR(mvm, "Failed to update sta link %d\n", link_id);
754 break;
755 }
756 }
757
758 return ret;
759 }
760
iwl_mvm_mld_disable_sta_queues(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta)761 static void iwl_mvm_mld_disable_sta_queues(struct iwl_mvm *mvm,
762 struct ieee80211_vif *vif,
763 struct ieee80211_sta *sta)
764 {
765 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
766 u32 sta_mask = iwl_mvm_sta_fw_id_mask(mvm, sta, -1);
767 int i;
768
769 lockdep_assert_held(&mvm->mutex);
770
771 for (i = 0; i < ARRAY_SIZE(mvm_sta->tid_data); i++) {
772 if (mvm_sta->tid_data[i].txq_id == IWL_MVM_INVALID_QUEUE)
773 continue;
774
775 iwl_mvm_mld_disable_txq(mvm, sta_mask,
776 &mvm_sta->tid_data[i].txq_id, i);
777 mvm_sta->tid_data[i].txq_id = IWL_MVM_INVALID_QUEUE;
778 }
779
780 for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
781 struct iwl_mvm_txq *mvmtxq =
782 iwl_mvm_txq_from_mac80211(sta->txq[i]);
783
784 mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE;
785 }
786 }
787
iwl_mvm_mld_rm_sta(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta)788 int iwl_mvm_mld_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
789 struct ieee80211_sta *sta)
790 {
791 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
792 struct ieee80211_link_sta *link_sta;
793 unsigned int link_id;
794 int ret;
795
796 lockdep_assert_held(&mvm->mutex);
797
798 /* flush its queues here since we are freeing mvm_sta */
799 for_each_sta_active_link(vif, sta, link_sta, link_id) {
800 struct iwl_mvm_link_sta *mvm_link_sta =
801 rcu_dereference_protected(mvm_sta->link[link_id],
802 lockdep_is_held(&mvm->mutex));
803
804 if (WARN_ON(!mvm_link_sta))
805 return -EINVAL;
806
807 ret = iwl_mvm_flush_sta_tids(mvm, mvm_link_sta->sta_id,
808 0xffff);
809 if (ret)
810 return ret;
811 }
812
813 ret = iwl_mvm_wait_sta_queues_empty(mvm, mvm_sta);
814 if (ret)
815 return ret;
816
817 iwl_mvm_mld_disable_sta_queues(mvm, vif, sta);
818
819 for_each_sta_active_link(vif, sta, link_sta, link_id) {
820 struct iwl_mvm_link_sta *mvm_link_sta =
821 rcu_dereference_protected(mvm_sta->link[link_id],
822 lockdep_is_held(&mvm->mutex));
823 iwl_mvm_sta_del(mvm, vif, sta, link_sta);
824
825 ret = iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_link_sta->sta_id);
826
827 iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_link_sta, link_id);
828 }
829
830 return ret;
831 }
832
iwl_mvm_mld_rm_sta_id(struct iwl_mvm * mvm,u8 sta_id)833 int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id)
834 {
835 int ret;
836
837 lockdep_assert_wiphy(mvm->hw->wiphy);
838 lockdep_assert_held(&mvm->mutex);
839
840 if (WARN_ON(sta_id == IWL_INVALID_STA))
841 return 0;
842
843 ret = iwl_mvm_mld_rm_sta_from_fw(mvm, sta_id);
844
845 RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL);
846 RCU_INIT_POINTER(mvm->fw_id_to_link_sta[sta_id], NULL);
847 return ret;
848 }
849
iwl_mvm_mld_sta_modify_disable_tx(struct iwl_mvm * mvm,struct iwl_mvm_sta * mvmsta,bool disable)850 void iwl_mvm_mld_sta_modify_disable_tx(struct iwl_mvm *mvm,
851 struct iwl_mvm_sta *mvmsta,
852 bool disable)
853 {
854 struct iwl_mvm_sta_disable_tx_cmd cmd;
855 int ret;
856
857 cmd.sta_id = cpu_to_le32(mvmsta->deflink.sta_id);
858 cmd.disable = cpu_to_le32(disable);
859
860 if (WARN_ON(iwl_mvm_has_no_host_disable_tx(mvm)))
861 return;
862
863 ret = iwl_mvm_send_cmd_pdu(mvm,
864 WIDE_ID(MAC_CONF_GROUP, STA_DISABLE_TX_CMD),
865 CMD_ASYNC, sizeof(cmd), &cmd);
866 if (ret)
867 IWL_ERR(mvm,
868 "Failed to send STA_DISABLE_TX_CMD command (%d)\n",
869 ret);
870 }
871
iwl_mvm_mld_sta_modify_disable_tx_ap(struct iwl_mvm * mvm,struct ieee80211_sta * sta,bool disable)872 void iwl_mvm_mld_sta_modify_disable_tx_ap(struct iwl_mvm *mvm,
873 struct ieee80211_sta *sta,
874 bool disable)
875 {
876 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
877
878 spin_lock_bh(&mvm_sta->lock);
879
880 if (mvm_sta->disable_tx == disable) {
881 spin_unlock_bh(&mvm_sta->lock);
882 return;
883 }
884
885 iwl_mvm_mld_sta_modify_disable_tx(mvm, mvm_sta, disable);
886
887 spin_unlock_bh(&mvm_sta->lock);
888 }
889
iwl_mvm_mld_modify_all_sta_disable_tx(struct iwl_mvm * mvm,struct iwl_mvm_vif * mvmvif,bool disable)890 void iwl_mvm_mld_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
891 struct iwl_mvm_vif *mvmvif,
892 bool disable)
893 {
894 struct ieee80211_sta *sta;
895 struct iwl_mvm_sta *mvm_sta;
896 int i;
897
898 rcu_read_lock();
899
900 /* Block/unblock all the stations of the given mvmvif */
901 for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
902 sta = rcu_dereference(mvm->fw_id_to_mac_id[i]);
903 if (IS_ERR_OR_NULL(sta))
904 continue;
905
906 mvm_sta = iwl_mvm_sta_from_mac80211(sta);
907 if (mvm_sta->mac_id_n_color !=
908 FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color))
909 continue;
910
911 iwl_mvm_mld_sta_modify_disable_tx(mvm, mvm_sta, disable);
912 }
913
914 rcu_read_unlock();
915 }
916
iwl_mvm_mld_update_sta_queues(struct iwl_mvm * mvm,struct ieee80211_sta * sta,u32 old_sta_mask,u32 new_sta_mask)917 static int iwl_mvm_mld_update_sta_queues(struct iwl_mvm *mvm,
918 struct ieee80211_sta *sta,
919 u32 old_sta_mask,
920 u32 new_sta_mask)
921 {
922 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
923 struct iwl_scd_queue_cfg_cmd cmd = {
924 .operation = cpu_to_le32(IWL_SCD_QUEUE_MODIFY),
925 .u.modify.old_sta_mask = cpu_to_le32(old_sta_mask),
926 .u.modify.new_sta_mask = cpu_to_le32(new_sta_mask),
927 };
928 struct iwl_host_cmd hcmd = {
929 .id = WIDE_ID(DATA_PATH_GROUP, SCD_QUEUE_CONFIG_CMD),
930 .len[0] = sizeof(cmd),
931 .data[0] = &cmd
932 };
933 int tid;
934 int ret;
935
936 lockdep_assert_held(&mvm->mutex);
937
938 for (tid = 0; tid <= IWL_MAX_TID_COUNT; tid++) {
939 struct iwl_mvm_tid_data *tid_data = &mvm_sta->tid_data[tid];
940 int txq_id = tid_data->txq_id;
941
942 if (txq_id == IWL_MVM_INVALID_QUEUE)
943 continue;
944
945 if (tid == IWL_MAX_TID_COUNT)
946 cmd.u.modify.tid = cpu_to_le32(IWL_MGMT_TID);
947 else
948 cmd.u.modify.tid = cpu_to_le32(tid);
949
950 ret = iwl_mvm_send_cmd(mvm, &hcmd);
951 if (ret)
952 return ret;
953 }
954
955 return 0;
956 }
957
iwl_mvm_mld_update_sta_baids(struct iwl_mvm * mvm,u32 old_sta_mask,u32 new_sta_mask)958 static int iwl_mvm_mld_update_sta_baids(struct iwl_mvm *mvm,
959 u32 old_sta_mask,
960 u32 new_sta_mask)
961 {
962 struct iwl_rx_baid_cfg_cmd cmd = {
963 .action = cpu_to_le32(IWL_RX_BAID_ACTION_MODIFY),
964 .modify.old_sta_id_mask = cpu_to_le32(old_sta_mask),
965 .modify.new_sta_id_mask = cpu_to_le32(new_sta_mask),
966 };
967 u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, RX_BAID_ALLOCATION_CONFIG_CMD);
968 int baid;
969
970 /* mac80211 will remove sessions later, but we ignore all that */
971 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
972 return 0;
973
974 BUILD_BUG_ON(sizeof(struct iwl_rx_baid_cfg_resp) != sizeof(baid));
975
976 for (baid = 0; baid < ARRAY_SIZE(mvm->baid_map); baid++) {
977 struct iwl_mvm_baid_data *data;
978 int ret;
979
980 data = rcu_dereference_protected(mvm->baid_map[baid],
981 lockdep_is_held(&mvm->mutex));
982 if (!data)
983 continue;
984
985 if (!(data->sta_mask & old_sta_mask))
986 continue;
987
988 WARN_ONCE(data->sta_mask != old_sta_mask,
989 "BAID data for %d corrupted - expected 0x%x found 0x%x\n",
990 baid, old_sta_mask, data->sta_mask);
991
992 cmd.modify.tid = cpu_to_le32(data->tid);
993
994 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_SEND_IN_RFKILL,
995 sizeof(cmd), &cmd);
996 data->sta_mask = new_sta_mask;
997 if (ret)
998 return ret;
999 }
1000
1001 return 0;
1002 }
1003
iwl_mvm_mld_update_sta_resources(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,u32 old_sta_mask,u32 new_sta_mask)1004 static int iwl_mvm_mld_update_sta_resources(struct iwl_mvm *mvm,
1005 struct ieee80211_vif *vif,
1006 struct ieee80211_sta *sta,
1007 u32 old_sta_mask,
1008 u32 new_sta_mask)
1009 {
1010 int ret;
1011
1012 ret = iwl_mvm_mld_update_sta_queues(mvm, sta,
1013 old_sta_mask,
1014 new_sta_mask);
1015 if (ret)
1016 return ret;
1017
1018 ret = iwl_mvm_mld_update_sta_keys(mvm, vif, sta,
1019 old_sta_mask,
1020 new_sta_mask);
1021 if (ret)
1022 return ret;
1023
1024 return iwl_mvm_mld_update_sta_baids(mvm, old_sta_mask, new_sta_mask);
1025 }
1026
iwl_mvm_mld_update_sta_links(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,u16 old_links,u16 new_links)1027 int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
1028 struct ieee80211_vif *vif,
1029 struct ieee80211_sta *sta,
1030 u16 old_links, u16 new_links)
1031 {
1032 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
1033 struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);
1034 struct iwl_mvm_link_sta *mvm_sta_link;
1035 struct iwl_mvm_vif_link_info *mvm_vif_link;
1036 unsigned long links_to_add = ~old_links & new_links;
1037 unsigned long links_to_rem = old_links & ~new_links;
1038 unsigned long old_links_long = old_links;
1039 u32 current_sta_mask = 0, sta_mask_added = 0, sta_mask_to_rem = 0;
1040 unsigned long link_sta_added_to_fw = 0, link_sta_allocated = 0;
1041 unsigned int link_id;
1042 int ret;
1043
1044 lockdep_assert_wiphy(mvm->hw->wiphy);
1045 lockdep_assert_held(&mvm->mutex);
1046
1047 for_each_set_bit(link_id, &old_links_long,
1048 IEEE80211_MLD_MAX_NUM_LINKS) {
1049 mvm_sta_link =
1050 rcu_dereference_protected(mvm_sta->link[link_id],
1051 lockdep_is_held(&mvm->mutex));
1052
1053 if (WARN_ON(!mvm_sta_link)) {
1054 ret = -EINVAL;
1055 goto err;
1056 }
1057
1058 current_sta_mask |= BIT(mvm_sta_link->sta_id);
1059 if (links_to_rem & BIT(link_id))
1060 sta_mask_to_rem |= BIT(mvm_sta_link->sta_id);
1061 }
1062
1063 if (sta_mask_to_rem) {
1064 ret = iwl_mvm_mld_update_sta_resources(mvm, vif, sta,
1065 current_sta_mask,
1066 current_sta_mask &
1067 ~sta_mask_to_rem);
1068 if (WARN_ON(ret))
1069 goto err;
1070
1071 current_sta_mask &= ~sta_mask_to_rem;
1072 }
1073
1074 for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) {
1075 mvm_sta_link =
1076 rcu_dereference_protected(mvm_sta->link[link_id],
1077 lockdep_is_held(&mvm->mutex));
1078 mvm_vif_link = mvm_vif->link[link_id];
1079
1080 if (WARN_ON(!mvm_sta_link || !mvm_vif_link)) {
1081 ret = -EINVAL;
1082 goto err;
1083 }
1084
1085 ret = iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_sta_link->sta_id);
1086 if (WARN_ON(ret))
1087 goto err;
1088
1089 if (vif->type == NL80211_IFTYPE_STATION)
1090 mvm_vif_link->ap_sta_id = IWL_INVALID_STA;
1091
1092 iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id);
1093 }
1094
1095 for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) {
1096 struct ieee80211_bss_conf *link_conf =
1097 link_conf_dereference_protected(vif, link_id);
1098 struct ieee80211_link_sta *link_sta =
1099 link_sta_dereference_protected(sta, link_id);
1100 mvm_vif_link = mvm_vif->link[link_id];
1101
1102 if (WARN_ON(!mvm_vif_link || !link_conf || !link_sta)) {
1103 ret = -EINVAL;
1104 goto err;
1105 }
1106
1107 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
1108 struct iwl_mvm_link_sta *mvm_link_sta =
1109 rcu_dereference_protected(mvm_sta->link[link_id],
1110 lockdep_is_held(&mvm->mutex));
1111 u32 sta_id;
1112
1113 if (WARN_ON(!mvm_link_sta)) {
1114 ret = -EINVAL;
1115 goto err;
1116 }
1117
1118 sta_id = mvm_link_sta->sta_id;
1119
1120 rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
1121 rcu_assign_pointer(mvm->fw_id_to_link_sta[sta_id],
1122 link_sta);
1123 } else {
1124 if (WARN_ON(mvm_sta->link[link_id])) {
1125 ret = -EINVAL;
1126 goto err;
1127 }
1128 ret = iwl_mvm_mld_alloc_sta_link(mvm, vif, sta,
1129 link_id);
1130 if (WARN_ON(ret))
1131 goto err;
1132 }
1133
1134 link_sta->agg.max_rc_amsdu_len = 1;
1135 ieee80211_sta_recalc_aggregates(sta);
1136
1137 mvm_sta_link =
1138 rcu_dereference_protected(mvm_sta->link[link_id],
1139 lockdep_is_held(&mvm->mutex));
1140
1141 if (WARN_ON(!mvm_sta_link)) {
1142 ret = -EINVAL;
1143 goto err;
1144 }
1145
1146 if (vif->type == NL80211_IFTYPE_STATION)
1147 iwl_mvm_mld_set_ap_sta_id(sta, mvm_vif_link,
1148 mvm_sta_link);
1149
1150 link_sta_allocated |= BIT(link_id);
1151
1152 sta_mask_added |= BIT(mvm_sta_link->sta_id);
1153
1154 ret = iwl_mvm_mld_cfg_sta(mvm, sta, vif, link_sta, link_conf,
1155 mvm_sta_link);
1156 if (WARN_ON(ret))
1157 goto err;
1158
1159 link_sta_added_to_fw |= BIT(link_id);
1160
1161 iwl_mvm_rs_add_sta_link(mvm, mvm_sta_link);
1162
1163 iwl_mvm_rs_rate_init(mvm, vif, sta, link_conf, link_sta,
1164 link_conf->chanreq.oper.chan->band);
1165 }
1166
1167 if (sta_mask_added) {
1168 ret = iwl_mvm_mld_update_sta_resources(mvm, vif, sta,
1169 current_sta_mask,
1170 current_sta_mask |
1171 sta_mask_added);
1172 if (WARN_ON(ret))
1173 goto err;
1174 }
1175
1176 return 0;
1177
1178 err:
1179 /* remove all already allocated stations in FW */
1180 for_each_set_bit(link_id, &link_sta_added_to_fw,
1181 IEEE80211_MLD_MAX_NUM_LINKS) {
1182 mvm_sta_link =
1183 rcu_dereference_protected(mvm_sta->link[link_id],
1184 lockdep_is_held(&mvm->mutex));
1185
1186 iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_sta_link->sta_id);
1187 }
1188
1189 /* remove all already allocated station links in driver */
1190 for_each_set_bit(link_id, &link_sta_allocated,
1191 IEEE80211_MLD_MAX_NUM_LINKS) {
1192 mvm_sta_link =
1193 rcu_dereference_protected(mvm_sta->link[link_id],
1194 lockdep_is_held(&mvm->mutex));
1195
1196 iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id);
1197 }
1198
1199 return ret;
1200 }
1201