1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3 * Copyright (C) 2022 - 2024 Intel Corporation
4 */
5 #include "mvm.h"
6 #include "time-event.h"
7
8 #define HANDLE_ESR_REASONS(HOW) \
9 HOW(BLOCKED_PREVENTION) \
10 HOW(BLOCKED_WOWLAN) \
11 HOW(BLOCKED_TPT) \
12 HOW(BLOCKED_FW) \
13 HOW(BLOCKED_NON_BSS) \
14 HOW(BLOCKED_ROC) \
15 HOW(EXIT_MISSED_BEACON) \
16 HOW(EXIT_LOW_RSSI) \
17 HOW(EXIT_COEX) \
18 HOW(EXIT_BANDWIDTH) \
19 HOW(EXIT_CSA) \
20 HOW(EXIT_LINK_USAGE)
21
22 static const char *const iwl_mvm_esr_states_names[] = {
23 #define NAME_ENTRY(x) [ilog2(IWL_MVM_ESR_##x)] = #x,
24 HANDLE_ESR_REASONS(NAME_ENTRY)
25 };
26
iwl_get_esr_state_string(enum iwl_mvm_esr_state state)27 const char *iwl_get_esr_state_string(enum iwl_mvm_esr_state state)
28 {
29 int offs = ilog2(state);
30
31 if (offs >= ARRAY_SIZE(iwl_mvm_esr_states_names) ||
32 !iwl_mvm_esr_states_names[offs])
33 return "UNKNOWN";
34
35 return iwl_mvm_esr_states_names[offs];
36 }
37
iwl_mvm_print_esr_state(struct iwl_mvm * mvm,u32 mask)38 static void iwl_mvm_print_esr_state(struct iwl_mvm *mvm, u32 mask)
39 {
40 #define NAME_FMT(x) "%s"
41 #define NAME_PR(x) (mask & IWL_MVM_ESR_##x) ? "[" #x "]" : "",
42 IWL_DEBUG_INFO(mvm,
43 "EMLSR state = " HANDLE_ESR_REASONS(NAME_FMT)
44 " (0x%x)\n",
45 HANDLE_ESR_REASONS(NAME_PR)
46 mask);
47 #undef NAME_FMT
48 #undef NAME_PR
49 }
50
iwl_mvm_get_free_fw_link_id(struct iwl_mvm * mvm,struct iwl_mvm_vif * mvm_vif)51 static u32 iwl_mvm_get_free_fw_link_id(struct iwl_mvm *mvm,
52 struct iwl_mvm_vif *mvm_vif)
53 {
54 u32 i;
55
56 lockdep_assert_held(&mvm->mutex);
57
58 for (i = 0; i < ARRAY_SIZE(mvm->link_id_to_link_conf); i++)
59 if (!rcu_access_pointer(mvm->link_id_to_link_conf[i]))
60 return i;
61
62 return IWL_MVM_FW_LINK_ID_INVALID;
63 }
64
iwl_mvm_link_cmd_send(struct iwl_mvm * mvm,struct iwl_link_config_cmd * cmd,enum iwl_ctxt_action action)65 static int iwl_mvm_link_cmd_send(struct iwl_mvm *mvm,
66 struct iwl_link_config_cmd *cmd,
67 enum iwl_ctxt_action action)
68 {
69 int ret;
70
71 cmd->action = cpu_to_le32(action);
72 ret = iwl_mvm_send_cmd_pdu(mvm,
73 WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD), 0,
74 sizeof(*cmd), cmd);
75 if (ret)
76 IWL_ERR(mvm, "Failed to send LINK_CONFIG_CMD (action:%d): %d\n",
77 action, ret);
78 return ret;
79 }
80
iwl_mvm_set_link_mapping(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)81 int iwl_mvm_set_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
82 struct ieee80211_bss_conf *link_conf)
83 {
84 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
85 struct iwl_mvm_vif_link_info *link_info =
86 mvmvif->link[link_conf->link_id];
87
88 if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID) {
89 link_info->fw_link_id = iwl_mvm_get_free_fw_link_id(mvm,
90 mvmvif);
91 if (link_info->fw_link_id >=
92 ARRAY_SIZE(mvm->link_id_to_link_conf))
93 return -EINVAL;
94
95 rcu_assign_pointer(mvm->link_id_to_link_conf[link_info->fw_link_id],
96 link_conf);
97 }
98
99 return 0;
100 }
101
iwl_mvm_add_link(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)102 int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
103 struct ieee80211_bss_conf *link_conf)
104 {
105 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
106 unsigned int link_id = link_conf->link_id;
107 struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
108 struct iwl_link_config_cmd cmd = {};
109 unsigned int cmd_id = WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD);
110 u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 1);
111 int ret;
112
113 if (WARN_ON_ONCE(!link_info))
114 return -EINVAL;
115
116 ret = iwl_mvm_set_link_mapping(mvm, vif, link_conf);
117 if (ret)
118 return ret;
119
120 /* Update SF - Disable if needed. if this fails, SF might still be on
121 * while many macs are bound, which is forbidden - so fail the binding.
122 */
123 if (iwl_mvm_sf_update(mvm, vif, false))
124 return -EINVAL;
125
126 cmd.link_id = cpu_to_le32(link_info->fw_link_id);
127 cmd.mac_id = cpu_to_le32(mvmvif->id);
128 cmd.spec_link_id = link_conf->link_id;
129 WARN_ON_ONCE(link_info->phy_ctxt);
130 cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);
131
132 memcpy(cmd.local_link_addr, link_conf->addr, ETH_ALEN);
133
134 if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid)
135 memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN);
136
137 if (cmd_ver < 2)
138 cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac);
139
140 return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD);
141 }
142
143 struct iwl_mvm_esr_iter_data {
144 struct ieee80211_vif *vif;
145 unsigned int link_id;
146 bool lift_block;
147 };
148
iwl_mvm_esr_vif_iterator(void * _data,u8 * mac,struct ieee80211_vif * vif)149 static void iwl_mvm_esr_vif_iterator(void *_data, u8 *mac,
150 struct ieee80211_vif *vif)
151 {
152 struct iwl_mvm_esr_iter_data *data = _data;
153 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
154 int link_id;
155
156 if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION)
157 return;
158
159 for_each_mvm_vif_valid_link(mvmvif, link_id) {
160 struct iwl_mvm_vif_link_info *link_info =
161 mvmvif->link[link_id];
162 if (vif == data->vif && link_id == data->link_id)
163 continue;
164 if (link_info->active)
165 data->lift_block = false;
166 }
167 }
168
iwl_mvm_esr_non_bss_link(struct iwl_mvm * mvm,struct ieee80211_vif * vif,unsigned int link_id,bool active)169 int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
170 unsigned int link_id, bool active)
171 {
172 /* An active link of a non-station vif blocks EMLSR. Upon activation
173 * block EMLSR on the bss vif. Upon deactivation, check if this link
174 * was the last non-station link active, and if so unblock the bss vif
175 */
176 struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm);
177 struct iwl_mvm_esr_iter_data data = {
178 .vif = vif,
179 .link_id = link_id,
180 .lift_block = true,
181 };
182
183 if (IS_ERR_OR_NULL(bss_vif))
184 return 0;
185
186 if (active)
187 return iwl_mvm_block_esr_sync(mvm, bss_vif,
188 IWL_MVM_ESR_BLOCKED_NON_BSS);
189
190 ieee80211_iterate_active_interfaces(mvm->hw,
191 IEEE80211_IFACE_ITER_NORMAL,
192 iwl_mvm_esr_vif_iterator, &data);
193 if (data.lift_block) {
194 mutex_lock(&mvm->mutex);
195 iwl_mvm_unblock_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_NON_BSS);
196 mutex_unlock(&mvm->mutex);
197 }
198
199 return 0;
200 }
201
iwl_mvm_link_changed(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf,u32 changes,bool active)202 int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
203 struct ieee80211_bss_conf *link_conf,
204 u32 changes, bool active)
205 {
206 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
207 unsigned int link_id = link_conf->link_id;
208 struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
209 struct iwl_mvm_phy_ctxt *phyctxt;
210 struct iwl_link_config_cmd cmd = {};
211 u32 ht_flag, flags = 0, flags_mask = 0;
212 int ret;
213 unsigned int cmd_id = WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD);
214 u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 1);
215
216 if (WARN_ON_ONCE(!link_info ||
217 link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID))
218 return -EINVAL;
219
220 if (changes & LINK_CONTEXT_MODIFY_ACTIVE) {
221 /* When activating a link, phy context should be valid;
222 * when deactivating a link, it also should be valid since
223 * the link was active before. So, do nothing in this case.
224 * Since a link is added first with FW_CTXT_INVALID, then we
225 * can get here in case it's removed before it was activated.
226 */
227 if (!link_info->phy_ctxt)
228 return 0;
229
230 /* Catch early if driver tries to activate or deactivate a link
231 * twice.
232 */
233 WARN_ON_ONCE(active == link_info->active);
234
235 /* When deactivating a link session protection should
236 * be stopped
237 */
238 if (!active && vif->type == NL80211_IFTYPE_STATION)
239 iwl_mvm_stop_session_protection(mvm, vif);
240 }
241
242 cmd.link_id = cpu_to_le32(link_info->fw_link_id);
243
244 /* The phy_id, link address and listen_lmac can be modified only until
245 * the link becomes active, otherwise they will be ignored.
246 */
247 phyctxt = link_info->phy_ctxt;
248 if (phyctxt)
249 cmd.phy_id = cpu_to_le32(phyctxt->id);
250 else
251 cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);
252 cmd.mac_id = cpu_to_le32(mvmvif->id);
253
254 memcpy(cmd.local_link_addr, link_conf->addr, ETH_ALEN);
255
256 cmd.active = cpu_to_le32(active);
257
258 if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid)
259 memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN);
260
261 iwl_mvm_set_fw_basic_rates(mvm, vif, link_conf,
262 &cmd.cck_rates, &cmd.ofdm_rates);
263
264 cmd.cck_short_preamble = cpu_to_le32(link_conf->use_short_preamble);
265 cmd.short_slot = cpu_to_le32(link_conf->use_short_slot);
266
267 /* The fw does not distinguish between ht and fat */
268 ht_flag = LINK_PROT_FLG_HT_PROT | LINK_PROT_FLG_FAT_PROT;
269 iwl_mvm_set_fw_protection_flags(mvm, vif, link_conf,
270 &cmd.protection_flags,
271 ht_flag, LINK_PROT_FLG_TGG_PROTECT);
272
273 iwl_mvm_set_fw_qos_params(mvm, vif, link_conf, cmd.ac,
274 &cmd.qos_flags);
275
276
277 cmd.bi = cpu_to_le32(link_conf->beacon_int);
278 cmd.dtim_interval = cpu_to_le32(link_conf->beacon_int *
279 link_conf->dtim_period);
280
281 if (!link_conf->he_support || iwlwifi_mod_params.disable_11ax ||
282 (vif->type == NL80211_IFTYPE_STATION && !vif->cfg.assoc)) {
283 changes &= ~LINK_CONTEXT_MODIFY_HE_PARAMS;
284 goto send_cmd;
285 }
286
287 cmd.htc_trig_based_pkt_ext = link_conf->htc_trig_based_pkt_ext;
288
289 if (link_conf->uora_exists) {
290 cmd.rand_alloc_ecwmin =
291 link_conf->uora_ocw_range & 0x7;
292 cmd.rand_alloc_ecwmax =
293 (link_conf->uora_ocw_range >> 3) & 0x7;
294 }
295
296 /* TODO how to set ndp_fdbk_buff_th_exp? */
297
298 if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif->link[link_id],
299 &cmd.trig_based_txf[0])) {
300 flags |= LINK_FLG_MU_EDCA_CW;
301 flags_mask |= LINK_FLG_MU_EDCA_CW;
302 }
303
304 if (changes & LINK_CONTEXT_MODIFY_EHT_PARAMS) {
305 struct ieee80211_chanctx_conf *ctx;
306 struct cfg80211_chan_def *def = NULL;
307
308 rcu_read_lock();
309 ctx = rcu_dereference(link_conf->chanctx_conf);
310 if (ctx)
311 def = iwl_mvm_chanctx_def(mvm, ctx);
312
313 if (iwlwifi_mod_params.disable_11be ||
314 !link_conf->eht_support || !def ||
315 iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1) >= 6)
316 changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS;
317 else
318 cmd.puncture_mask = cpu_to_le16(def->punctured);
319 rcu_read_unlock();
320 }
321
322 cmd.bss_color = link_conf->he_bss_color.color;
323
324 if (!link_conf->he_bss_color.enabled) {
325 flags |= LINK_FLG_BSS_COLOR_DIS;
326 flags_mask |= LINK_FLG_BSS_COLOR_DIS;
327 }
328
329 cmd.frame_time_rts_th = cpu_to_le16(link_conf->frame_time_rts_th);
330
331 /* Block 26-tone RU OFDMA transmissions */
332 if (link_info->he_ru_2mhz_block) {
333 flags |= LINK_FLG_RU_2MHZ_BLOCK;
334 flags_mask |= LINK_FLG_RU_2MHZ_BLOCK;
335 }
336
337 if (link_conf->nontransmitted) {
338 ether_addr_copy(cmd.ref_bssid_addr,
339 link_conf->transmitter_bssid);
340 cmd.bssid_index = link_conf->bssid_index;
341 }
342
343 send_cmd:
344 cmd.modify_mask = cpu_to_le32(changes);
345 cmd.flags = cpu_to_le32(flags);
346 cmd.flags_mask = cpu_to_le32(flags_mask);
347 cmd.spec_link_id = link_conf->link_id;
348 if (cmd_ver < 2)
349 cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac);
350
351 ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_MODIFY);
352 if (!ret && (changes & LINK_CONTEXT_MODIFY_ACTIVE))
353 link_info->active = active;
354
355 return ret;
356 }
357
iwl_mvm_unset_link_mapping(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)358 int iwl_mvm_unset_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
359 struct ieee80211_bss_conf *link_conf)
360 {
361 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
362 struct iwl_mvm_vif_link_info *link_info =
363 mvmvif->link[link_conf->link_id];
364
365 /* mac80211 thought we have the link, but it was never configured */
366 if (WARN_ON(!link_info ||
367 link_info->fw_link_id >=
368 ARRAY_SIZE(mvm->link_id_to_link_conf)))
369 return -EINVAL;
370
371 RCU_INIT_POINTER(mvm->link_id_to_link_conf[link_info->fw_link_id],
372 NULL);
373 return 0;
374 }
375
iwl_mvm_remove_link(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)376 int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
377 struct ieee80211_bss_conf *link_conf)
378 {
379 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
380 unsigned int link_id = link_conf->link_id;
381 struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
382 struct iwl_link_config_cmd cmd = {};
383 int ret;
384
385 ret = iwl_mvm_unset_link_mapping(mvm, vif, link_conf);
386 if (ret)
387 return 0;
388
389 cmd.link_id = cpu_to_le32(link_info->fw_link_id);
390 link_info->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
391 cmd.spec_link_id = link_conf->link_id;
392 cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);
393
394 ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_REMOVE);
395
396 if (!ret)
397 if (iwl_mvm_sf_update(mvm, vif, true))
398 IWL_ERR(mvm, "Failed to update SF state\n");
399
400 return ret;
401 }
402
403 /* link should be deactivated before removal, so in most cases we need to
404 * perform these two operations together
405 */
iwl_mvm_disable_link(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_bss_conf * link_conf)406 int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
407 struct ieee80211_bss_conf *link_conf)
408 {
409 int ret;
410
411 ret = iwl_mvm_link_changed(mvm, vif, link_conf,
412 LINK_CONTEXT_MODIFY_ACTIVE, false);
413 if (ret)
414 return ret;
415
416 ret = iwl_mvm_remove_link(mvm, vif, link_conf);
417 if (ret)
418 return ret;
419
420 return ret;
421 }
422
423 struct iwl_mvm_rssi_to_grade {
424 s8 rssi[2];
425 u16 grade;
426 };
427
428 #define RSSI_TO_GRADE_LINE(_lb, _hb_uhb, _grade) \
429 { \
430 .rssi = {_lb, _hb_uhb}, \
431 .grade = _grade \
432 }
433
434 /*
435 * This array must be sorted by increasing RSSI for proper functionality.
436 * The grades are actually estimated throughput, represented as fixed-point
437 * with a scale factor of 1/10.
438 */
439 static const struct iwl_mvm_rssi_to_grade rssi_to_grade_map[] = {
440 RSSI_TO_GRADE_LINE(-85, -89, 177),
441 RSSI_TO_GRADE_LINE(-83, -86, 344),
442 RSSI_TO_GRADE_LINE(-82, -85, 516),
443 RSSI_TO_GRADE_LINE(-80, -83, 688),
444 RSSI_TO_GRADE_LINE(-77, -79, 1032),
445 RSSI_TO_GRADE_LINE(-73, -76, 1376),
446 RSSI_TO_GRADE_LINE(-70, -74, 1548),
447 RSSI_TO_GRADE_LINE(-69, -72, 1750),
448 RSSI_TO_GRADE_LINE(-65, -68, 2064),
449 RSSI_TO_GRADE_LINE(-61, -66, 2294),
450 RSSI_TO_GRADE_LINE(-58, -61, 2580),
451 RSSI_TO_GRADE_LINE(-55, -58, 2868),
452 RSSI_TO_GRADE_LINE(-46, -55, 3098),
453 RSSI_TO_GRADE_LINE(-43, -54, 3442)
454 };
455
456 #define MAX_GRADE (rssi_to_grade_map[ARRAY_SIZE(rssi_to_grade_map) - 1].grade)
457
458 #define DEFAULT_CHAN_LOAD_LB 30
459 #define DEFAULT_CHAN_LOAD_HB 15
460 #define DEFAULT_CHAN_LOAD_UHB 0
461
462 /* Factors calculation is done with fixed-point with a scaling factor of 1/256 */
463 #define SCALE_FACTOR 256
464
465 /* Convert a percentage from [0,100] to [0,255] */
466 #define NORMALIZE_PERCENT_TO_255(percentage) ((percentage) * SCALE_FACTOR / 100)
467
468 static unsigned int
iwl_mvm_get_puncturing_factor(const struct ieee80211_bss_conf * link_conf)469 iwl_mvm_get_puncturing_factor(const struct ieee80211_bss_conf *link_conf)
470 {
471 enum nl80211_chan_width chan_width =
472 link_conf->chanreq.oper.width;
473 int mhz = nl80211_chan_width_to_mhz(chan_width);
474 unsigned int n_subchannels, n_punctured, puncturing_penalty;
475
476 if (WARN_ONCE(mhz < 20 || mhz > 320,
477 "Invalid channel width : (%d)\n", mhz))
478 return SCALE_FACTOR;
479
480 /* No puncturing, no penalty */
481 if (mhz < 80)
482 return SCALE_FACTOR;
483
484 /* total number of subchannels */
485 n_subchannels = mhz / 20;
486 /* how many of these are punctured */
487 n_punctured = hweight16(link_conf->chanreq.oper.punctured);
488
489 puncturing_penalty = n_punctured * SCALE_FACTOR / n_subchannels;
490 return SCALE_FACTOR - puncturing_penalty;
491 }
492
493 static unsigned int
iwl_mvm_get_chan_load(struct ieee80211_bss_conf * link_conf)494 iwl_mvm_get_chan_load(struct ieee80211_bss_conf *link_conf)
495 {
496 struct ieee80211_vif *vif = link_conf->vif;
497 struct iwl_mvm_vif_link_info *mvm_link =
498 iwl_mvm_vif_from_mac80211(link_conf->vif)->link[link_conf->link_id];
499 const struct element *bss_load_elem;
500 const struct ieee80211_bss_load_elem *bss_load;
501 enum nl80211_band band = link_conf->chanreq.oper.chan->band;
502 const struct cfg80211_bss_ies *ies;
503 unsigned int chan_load;
504 u32 chan_load_by_us;
505
506 rcu_read_lock();
507 if (ieee80211_vif_link_active(vif, link_conf->link_id))
508 ies = rcu_dereference(link_conf->bss->beacon_ies);
509 else
510 ies = rcu_dereference(link_conf->bss->ies);
511
512 if (ies)
513 bss_load_elem = cfg80211_find_elem(WLAN_EID_QBSS_LOAD,
514 ies->data, ies->len);
515 else
516 bss_load_elem = NULL;
517
518 /* If there isn't BSS Load element, take the defaults */
519 if (!bss_load_elem ||
520 bss_load_elem->datalen != sizeof(*bss_load)) {
521 rcu_read_unlock();
522 switch (band) {
523 case NL80211_BAND_2GHZ:
524 chan_load = DEFAULT_CHAN_LOAD_LB;
525 break;
526 case NL80211_BAND_5GHZ:
527 chan_load = DEFAULT_CHAN_LOAD_HB;
528 break;
529 case NL80211_BAND_6GHZ:
530 chan_load = DEFAULT_CHAN_LOAD_UHB;
531 break;
532 default:
533 chan_load = 0;
534 break;
535 }
536 /* The defaults are given in percentage */
537 return NORMALIZE_PERCENT_TO_255(chan_load);
538 }
539
540 bss_load = (const void *)bss_load_elem->data;
541 /* Channel util is in range 0-255 */
542 chan_load = bss_load->channel_util;
543 rcu_read_unlock();
544
545 if (!mvm_link || !mvm_link->active)
546 return chan_load;
547
548 if (WARN_ONCE(!mvm_link->phy_ctxt,
549 "Active link (%u) without phy ctxt assigned!\n",
550 link_conf->link_id))
551 return chan_load;
552
553 /* channel load by us is given in percentage */
554 chan_load_by_us =
555 NORMALIZE_PERCENT_TO_255(mvm_link->phy_ctxt->channel_load_by_us);
556
557 /* Use only values that firmware sends that can possibly be valid */
558 if (chan_load_by_us <= chan_load)
559 chan_load -= chan_load_by_us;
560
561 return chan_load;
562 }
563
564 static unsigned int
iwl_mvm_get_chan_load_factor(struct ieee80211_bss_conf * link_conf)565 iwl_mvm_get_chan_load_factor(struct ieee80211_bss_conf *link_conf)
566 {
567 return SCALE_FACTOR - iwl_mvm_get_chan_load(link_conf);
568 }
569
570 /* This function calculates the grade of a link. Returns 0 in error case */
571 VISIBLE_IF_IWLWIFI_KUNIT
iwl_mvm_get_link_grade(struct ieee80211_bss_conf * link_conf)572 unsigned int iwl_mvm_get_link_grade(struct ieee80211_bss_conf *link_conf)
573 {
574 enum nl80211_band band;
575 int i, rssi_idx;
576 s32 link_rssi;
577 unsigned int grade = MAX_GRADE;
578
579 if (WARN_ON_ONCE(!link_conf))
580 return 0;
581
582 band = link_conf->chanreq.oper.chan->band;
583 if (WARN_ONCE(band != NL80211_BAND_2GHZ &&
584 band != NL80211_BAND_5GHZ &&
585 band != NL80211_BAND_6GHZ,
586 "Invalid band (%u)\n", band))
587 return 0;
588
589 link_rssi = MBM_TO_DBM(link_conf->bss->signal);
590 /*
591 * For 6 GHz the RSSI of the beacons is lower than
592 * the RSSI of the data.
593 */
594 if (band == NL80211_BAND_6GHZ)
595 link_rssi += 4;
596
597 rssi_idx = band == NL80211_BAND_2GHZ ? 0 : 1;
598
599 /* No valid RSSI - take the lowest grade */
600 if (!link_rssi)
601 link_rssi = rssi_to_grade_map[0].rssi[rssi_idx];
602
603 /* Get grade based on RSSI */
604 for (i = 0; i < ARRAY_SIZE(rssi_to_grade_map); i++) {
605 const struct iwl_mvm_rssi_to_grade *line =
606 &rssi_to_grade_map[i];
607
608 if (link_rssi > line->rssi[rssi_idx])
609 continue;
610 grade = line->grade;
611 break;
612 }
613
614 /* apply the channel load and puncturing factors */
615 grade = grade * iwl_mvm_get_chan_load_factor(link_conf) / SCALE_FACTOR;
616 grade = grade * iwl_mvm_get_puncturing_factor(link_conf) / SCALE_FACTOR;
617 return grade;
618 }
619 EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_get_link_grade);
620
621 static
iwl_mvm_set_link_selection_data(struct ieee80211_vif * vif,struct iwl_mvm_link_sel_data * data,unsigned long usable_links,u8 * best_link_idx)622 u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif,
623 struct iwl_mvm_link_sel_data *data,
624 unsigned long usable_links,
625 u8 *best_link_idx)
626 {
627 u8 n_data = 0;
628 u16 max_grade = 0;
629 unsigned long link_id;
630
631 /* TODO: don't select links that weren't discovered in the last scan */
632 for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) {
633 struct ieee80211_bss_conf *link_conf =
634 link_conf_dereference_protected(vif, link_id);
635
636 if (WARN_ON_ONCE(!link_conf))
637 continue;
638
639 data[n_data].link_id = link_id;
640 data[n_data].chandef = &link_conf->chanreq.oper;
641 data[n_data].signal = link_conf->bss->signal / 100;
642 data[n_data].grade = iwl_mvm_get_link_grade(link_conf);
643
644 if (data[n_data].grade > max_grade) {
645 max_grade = data[n_data].grade;
646 *best_link_idx = n_data;
647 }
648 n_data++;
649 }
650
651 return n_data;
652 }
653
654 struct iwl_mvm_bw_to_rssi_threshs {
655 s8 low;
656 s8 high;
657 };
658
659 #define BW_TO_RSSI_THRESHOLDS(_bw) \
660 [IWL_PHY_CHANNEL_MODE ## _bw] = { \
661 .low = IWL_MVM_LOW_RSSI_THRESH_##_bw##MHZ, \
662 .high = IWL_MVM_HIGH_RSSI_THRESH_##_bw##MHZ \
663 }
664
iwl_mvm_get_esr_rssi_thresh(struct iwl_mvm * mvm,const struct cfg80211_chan_def * chandef,bool low)665 s8 iwl_mvm_get_esr_rssi_thresh(struct iwl_mvm *mvm,
666 const struct cfg80211_chan_def *chandef,
667 bool low)
668 {
669 const struct iwl_mvm_bw_to_rssi_threshs bw_to_rssi_threshs_map[] = {
670 BW_TO_RSSI_THRESHOLDS(20),
671 BW_TO_RSSI_THRESHOLDS(40),
672 BW_TO_RSSI_THRESHOLDS(80),
673 BW_TO_RSSI_THRESHOLDS(160)
674 /* 320 MHz has the same thresholds as 20 MHz */
675 };
676 const struct iwl_mvm_bw_to_rssi_threshs *threshs;
677 u8 chan_width = iwl_mvm_get_channel_width(chandef);
678
679 if (WARN_ON(chandef->chan->band != NL80211_BAND_2GHZ &&
680 chandef->chan->band != NL80211_BAND_5GHZ &&
681 chandef->chan->band != NL80211_BAND_6GHZ))
682 return S8_MAX;
683
684 /* 6 GHz will always use 20 MHz thresholds, regardless of the BW */
685 if (chan_width == IWL_PHY_CHANNEL_MODE320)
686 chan_width = IWL_PHY_CHANNEL_MODE20;
687
688 threshs = &bw_to_rssi_threshs_map[chan_width];
689
690 return low ? threshs->low : threshs->high;
691 }
692
693 static u32
iwl_mvm_esr_disallowed_with_link(struct iwl_mvm * mvm,struct ieee80211_vif * vif,const struct iwl_mvm_link_sel_data * link,bool primary)694 iwl_mvm_esr_disallowed_with_link(struct iwl_mvm *mvm,
695 struct ieee80211_vif *vif,
696 const struct iwl_mvm_link_sel_data *link,
697 bool primary)
698 {
699 struct wiphy *wiphy = mvm->hw->wiphy;
700 struct ieee80211_bss_conf *conf;
701 enum iwl_mvm_esr_state ret = 0;
702 s8 thresh;
703
704 conf = wiphy_dereference(wiphy, vif->link_conf[link->link_id]);
705 if (WARN_ON_ONCE(!conf))
706 return false;
707
708 /* BT Coex effects eSR mode only if one of the links is on LB */
709 if (link->chandef->chan->band == NL80211_BAND_2GHZ &&
710 (!iwl_mvm_bt_coex_calculate_esr_mode(mvm, vif, link->signal,
711 primary)))
712 ret |= IWL_MVM_ESR_EXIT_COEX;
713
714 thresh = iwl_mvm_get_esr_rssi_thresh(mvm, link->chandef,
715 false);
716
717 if (link->signal < thresh)
718 ret |= IWL_MVM_ESR_EXIT_LOW_RSSI;
719
720 if (conf->csa_active)
721 ret |= IWL_MVM_ESR_EXIT_CSA;
722
723 if (ret) {
724 IWL_DEBUG_INFO(mvm,
725 "Link %d is not allowed for esr\n",
726 link->link_id);
727 iwl_mvm_print_esr_state(mvm, ret);
728 }
729 return ret;
730 }
731
732 VISIBLE_IF_IWLWIFI_KUNIT
iwl_mvm_mld_valid_link_pair(struct ieee80211_vif * vif,const struct iwl_mvm_link_sel_data * a,const struct iwl_mvm_link_sel_data * b)733 bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif,
734 const struct iwl_mvm_link_sel_data *a,
735 const struct iwl_mvm_link_sel_data *b)
736 {
737 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
738 struct iwl_mvm *mvm = mvmvif->mvm;
739 enum iwl_mvm_esr_state ret = 0;
740
741 /* Per-link considerations */
742 if (iwl_mvm_esr_disallowed_with_link(mvm, vif, a, true) ||
743 iwl_mvm_esr_disallowed_with_link(mvm, vif, b, false))
744 return false;
745
746 if (a->chandef->width != b->chandef->width ||
747 !(a->chandef->chan->band == NL80211_BAND_6GHZ &&
748 b->chandef->chan->band == NL80211_BAND_5GHZ))
749 ret |= IWL_MVM_ESR_EXIT_BANDWIDTH;
750
751 if (ret) {
752 IWL_DEBUG_INFO(mvm,
753 "Links %d and %d are not a valid pair for EMLSR\n",
754 a->link_id, b->link_id);
755 iwl_mvm_print_esr_state(mvm, ret);
756 return false;
757 }
758
759 return true;
760
761 }
762 EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_mld_valid_link_pair);
763
764 /*
765 * Returns the combined eSR grade of two given links.
766 * Returns 0 if eSR is not allowed with these 2 links.
767 */
768 static
iwl_mvm_get_esr_grade(struct ieee80211_vif * vif,const struct iwl_mvm_link_sel_data * a,const struct iwl_mvm_link_sel_data * b,u8 * primary_id)769 unsigned int iwl_mvm_get_esr_grade(struct ieee80211_vif *vif,
770 const struct iwl_mvm_link_sel_data *a,
771 const struct iwl_mvm_link_sel_data *b,
772 u8 *primary_id)
773 {
774 struct ieee80211_bss_conf *primary_conf;
775 struct wiphy *wiphy = ieee80211_vif_to_wdev(vif)->wiphy;
776 unsigned int primary_load;
777
778 lockdep_assert_wiphy(wiphy);
779
780 /* a is always primary, b is always secondary */
781 if (b->grade > a->grade)
782 swap(a, b);
783
784 *primary_id = a->link_id;
785
786 if (!iwl_mvm_mld_valid_link_pair(vif, a, b))
787 return 0;
788
789 primary_conf = wiphy_dereference(wiphy, vif->link_conf[*primary_id]);
790
791 if (WARN_ON_ONCE(!primary_conf))
792 return 0;
793
794 primary_load = iwl_mvm_get_chan_load(primary_conf);
795
796 return a->grade +
797 ((b->grade * primary_load) / SCALE_FACTOR);
798 }
799
iwl_mvm_select_links(struct iwl_mvm * mvm,struct ieee80211_vif * vif)800 void iwl_mvm_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
801 {
802 struct iwl_mvm_link_sel_data data[IEEE80211_MLD_MAX_NUM_LINKS];
803 struct iwl_mvm_link_sel_data *best_link;
804 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
805 u32 max_active_links = iwl_mvm_max_active_links(mvm, vif);
806 u16 usable_links = ieee80211_vif_usable_links(vif);
807 u8 best, primary_link, best_in_pair, n_data;
808 u16 max_esr_grade = 0, new_active_links;
809
810 lockdep_assert_wiphy(mvm->hw->wiphy);
811
812 if (!mvmvif->authorized || !ieee80211_vif_is_mld(vif))
813 return;
814
815 if (!IWL_MVM_AUTO_EML_ENABLE)
816 return;
817
818 /* The logic below is a simple version that doesn't suit more than 2
819 * links
820 */
821 WARN_ON_ONCE(max_active_links > 2);
822
823 n_data = iwl_mvm_set_link_selection_data(vif, data, usable_links,
824 &best);
825
826 if (WARN(!n_data, "Couldn't find a valid grade for any link!\n"))
827 return;
828
829 best_link = &data[best];
830 primary_link = best_link->link_id;
831 new_active_links = BIT(best_link->link_id);
832
833 /* eSR is not supported/blocked, or only one usable link */
834 if (max_active_links == 1 || !iwl_mvm_vif_has_esr_cap(mvm, vif) ||
835 mvmvif->esr_disable_reason || n_data == 1)
836 goto set_active;
837
838 for (u8 a = 0; a < n_data; a++)
839 for (u8 b = a + 1; b < n_data; b++) {
840 u16 esr_grade = iwl_mvm_get_esr_grade(vif, &data[a],
841 &data[b],
842 &best_in_pair);
843
844 if (esr_grade <= max_esr_grade)
845 continue;
846
847 max_esr_grade = esr_grade;
848 primary_link = best_in_pair;
849 new_active_links = BIT(data[a].link_id) |
850 BIT(data[b].link_id);
851 }
852
853 /* No valid pair was found, go with the best link */
854 if (hweight16(new_active_links) <= 1)
855 goto set_active;
856
857 /* For equal grade - prefer EMLSR */
858 if (best_link->grade > max_esr_grade) {
859 primary_link = best_link->link_id;
860 new_active_links = BIT(best_link->link_id);
861 }
862 set_active:
863 IWL_DEBUG_INFO(mvm, "Link selection result: 0x%x. Primary = %d\n",
864 new_active_links, primary_link);
865 ieee80211_set_active_links_async(vif, new_active_links);
866 mvmvif->link_selection_res = new_active_links;
867 mvmvif->link_selection_primary = primary_link;
868 }
869
iwl_mvm_get_primary_link(struct ieee80211_vif * vif)870 u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif)
871 {
872 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
873
874 /* relevant data is written with both locks held, so read with either */
875 lockdep_assert(lockdep_is_held(&mvmvif->mvm->mutex) ||
876 lockdep_is_held(&mvmvif->mvm->hw->wiphy->mtx));
877
878 if (!ieee80211_vif_is_mld(vif))
879 return 0;
880
881 /* In AP mode, there is no primary link */
882 if (vif->type == NL80211_IFTYPE_AP)
883 return __ffs(vif->active_links);
884
885 if (mvmvif->esr_active &&
886 !WARN_ON(!(BIT(mvmvif->primary_link) & vif->active_links)))
887 return mvmvif->primary_link;
888
889 return __ffs(vif->active_links);
890 }
891
892 /*
893 * For non-MLO/single link, this will return the deflink/single active link,
894 * respectively
895 */
iwl_mvm_get_other_link(struct ieee80211_vif * vif,u8 link_id)896 u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id)
897 {
898 switch (hweight16(vif->active_links)) {
899 case 0:
900 return 0;
901 default:
902 WARN_ON(1);
903 fallthrough;
904 case 1:
905 return __ffs(vif->active_links);
906 case 2:
907 return __ffs(vif->active_links & ~BIT(link_id));
908 }
909 }
910
911 /* Reasons that can cause esr prevention */
912 #define IWL_MVM_ESR_PREVENT_REASONS IWL_MVM_ESR_EXIT_MISSED_BEACON
913 #define IWL_MVM_PREVENT_ESR_TIMEOUT (HZ * 400)
914 #define IWL_MVM_ESR_PREVENT_SHORT (HZ * 300)
915 #define IWL_MVM_ESR_PREVENT_LONG (HZ * 600)
916
iwl_mvm_check_esr_prevention(struct iwl_mvm * mvm,struct iwl_mvm_vif * mvmvif,enum iwl_mvm_esr_state reason)917 static bool iwl_mvm_check_esr_prevention(struct iwl_mvm *mvm,
918 struct iwl_mvm_vif *mvmvif,
919 enum iwl_mvm_esr_state reason)
920 {
921 bool timeout_expired = time_after(jiffies,
922 mvmvif->last_esr_exit.ts +
923 IWL_MVM_PREVENT_ESR_TIMEOUT);
924 unsigned long delay;
925
926 lockdep_assert_held(&mvm->mutex);
927
928 /* Only handle reasons that can cause prevention */
929 if (!(reason & IWL_MVM_ESR_PREVENT_REASONS))
930 return false;
931
932 /*
933 * Reset the counter if more than 400 seconds have passed between one
934 * exit and the other, or if we exited due to a different reason.
935 * Will also reset the counter after the long prevention is done.
936 */
937 if (timeout_expired || mvmvif->last_esr_exit.reason != reason) {
938 mvmvif->exit_same_reason_count = 1;
939 return false;
940 }
941
942 mvmvif->exit_same_reason_count++;
943 if (WARN_ON(mvmvif->exit_same_reason_count < 2 ||
944 mvmvif->exit_same_reason_count > 3))
945 return false;
946
947 mvmvif->esr_disable_reason |= IWL_MVM_ESR_BLOCKED_PREVENTION;
948
949 /*
950 * For the second exit, use a short prevention, and for the third one,
951 * use a long prevention.
952 */
953 delay = mvmvif->exit_same_reason_count == 2 ?
954 IWL_MVM_ESR_PREVENT_SHORT :
955 IWL_MVM_ESR_PREVENT_LONG;
956
957 IWL_DEBUG_INFO(mvm,
958 "Preventing EMLSR for %ld seconds due to %u exits with the reason = %s (0x%x)\n",
959 delay / HZ, mvmvif->exit_same_reason_count,
960 iwl_get_esr_state_string(reason), reason);
961
962 wiphy_delayed_work_queue(mvm->hw->wiphy,
963 &mvmvif->prevent_esr_done_wk, delay);
964 return true;
965 }
966
967 #define IWL_MVM_TRIGGER_LINK_SEL_TIME (IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC * HZ)
968
969 /* API to exit eSR mode */
iwl_mvm_exit_esr(struct iwl_mvm * mvm,struct ieee80211_vif * vif,enum iwl_mvm_esr_state reason,u8 link_to_keep)970 void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
971 enum iwl_mvm_esr_state reason,
972 u8 link_to_keep)
973 {
974 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
975 u16 new_active_links;
976 bool prevented;
977
978 lockdep_assert_held(&mvm->mutex);
979
980 if (!IWL_MVM_AUTO_EML_ENABLE)
981 return;
982
983 /* Nothing to do */
984 if (!mvmvif->esr_active)
985 return;
986
987 if (WARN_ON(!ieee80211_vif_is_mld(vif) || !mvmvif->authorized))
988 return;
989
990 if (WARN_ON(!(vif->active_links & BIT(link_to_keep))))
991 link_to_keep = __ffs(vif->active_links);
992
993 new_active_links = BIT(link_to_keep);
994 IWL_DEBUG_INFO(mvm,
995 "Exiting EMLSR. reason = %s (0x%x). Current active links=0x%x, new active links = 0x%x\n",
996 iwl_get_esr_state_string(reason), reason,
997 vif->active_links, new_active_links);
998
999 ieee80211_set_active_links_async(vif, new_active_links);
1000
1001 /* Prevent EMLSR if needed */
1002 prevented = iwl_mvm_check_esr_prevention(mvm, mvmvif, reason);
1003
1004 /* Remember why and when we exited EMLSR */
1005 mvmvif->last_esr_exit.ts = jiffies;
1006 mvmvif->last_esr_exit.reason = reason;
1007
1008 /*
1009 * If EMLSR is prevented now - don't try to get back to EMLSR.
1010 * If we exited due to a blocking event, we will try to get back to
1011 * EMLSR when the corresponding unblocking event will happen.
1012 */
1013 if (prevented || reason & IWL_MVM_BLOCK_ESR_REASONS)
1014 return;
1015
1016 /* If EMLSR is not blocked - try enabling it again in 30 seconds */
1017 wiphy_delayed_work_queue(mvm->hw->wiphy,
1018 &mvmvif->mlo_int_scan_wk,
1019 round_jiffies_relative(IWL_MVM_TRIGGER_LINK_SEL_TIME));
1020 }
1021
iwl_mvm_block_esr(struct iwl_mvm * mvm,struct ieee80211_vif * vif,enum iwl_mvm_esr_state reason,u8 link_to_keep)1022 void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1023 enum iwl_mvm_esr_state reason,
1024 u8 link_to_keep)
1025 {
1026 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1027
1028 lockdep_assert_held(&mvm->mutex);
1029
1030 if (!IWL_MVM_AUTO_EML_ENABLE)
1031 return;
1032
1033 /* This should be called only with disable reasons */
1034 if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS)))
1035 return;
1036
1037 if (mvmvif->esr_disable_reason & reason)
1038 return;
1039
1040 IWL_DEBUG_INFO(mvm,
1041 "Blocking EMLSR mode. reason = %s (0x%x)\n",
1042 iwl_get_esr_state_string(reason), reason);
1043
1044 mvmvif->esr_disable_reason |= reason;
1045
1046 iwl_mvm_print_esr_state(mvm, mvmvif->esr_disable_reason);
1047
1048 iwl_mvm_exit_esr(mvm, vif, reason, link_to_keep);
1049 }
1050
iwl_mvm_block_esr_sync(struct iwl_mvm * mvm,struct ieee80211_vif * vif,enum iwl_mvm_esr_state reason)1051 int iwl_mvm_block_esr_sync(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1052 enum iwl_mvm_esr_state reason)
1053 {
1054 int primary_link = iwl_mvm_get_primary_link(vif);
1055 int ret;
1056
1057 if (!IWL_MVM_AUTO_EML_ENABLE || !ieee80211_vif_is_mld(vif))
1058 return 0;
1059
1060 /* This should be called only with blocking reasons */
1061 if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS)))
1062 return 0;
1063
1064 /* leave ESR immediately, not only async with iwl_mvm_block_esr() */
1065 ret = ieee80211_set_active_links(vif, BIT(primary_link));
1066 if (ret)
1067 return ret;
1068
1069 mutex_lock(&mvm->mutex);
1070 /* only additionally block for consistency and to avoid concurrency */
1071 iwl_mvm_block_esr(mvm, vif, reason, primary_link);
1072 mutex_unlock(&mvm->mutex);
1073
1074 return 0;
1075 }
1076
iwl_mvm_esr_unblocked(struct iwl_mvm * mvm,struct ieee80211_vif * vif)1077 static void iwl_mvm_esr_unblocked(struct iwl_mvm *mvm,
1078 struct ieee80211_vif *vif)
1079 {
1080 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1081 bool need_new_sel = time_after(jiffies, mvmvif->last_esr_exit.ts +
1082 IWL_MVM_TRIGGER_LINK_SEL_TIME);
1083
1084 lockdep_assert_held(&mvm->mutex);
1085
1086 if (!ieee80211_vif_is_mld(vif) || !mvmvif->authorized ||
1087 mvmvif->esr_active)
1088 return;
1089
1090 IWL_DEBUG_INFO(mvm, "EMLSR is unblocked\n");
1091
1092 /* If we exited due to an EXIT reason, and the exit was in less than
1093 * 30 seconds, then a MLO scan was scheduled already.
1094 */
1095 if (!need_new_sel &&
1096 !(mvmvif->last_esr_exit.reason & IWL_MVM_BLOCK_ESR_REASONS)) {
1097 IWL_DEBUG_INFO(mvm, "Wait for MLO scan\n");
1098 return;
1099 }
1100
1101 /*
1102 * If EMLSR was blocked for more than 30 seconds, or the last link
1103 * selection decided to not enter EMLSR, trigger a new scan.
1104 */
1105 if (need_new_sel || hweight16(mvmvif->link_selection_res) < 2) {
1106 IWL_DEBUG_INFO(mvm, "Trigger MLO scan\n");
1107 wiphy_delayed_work_queue(mvm->hw->wiphy,
1108 &mvmvif->mlo_int_scan_wk, 0);
1109 /*
1110 * If EMLSR was blocked for less than 30 seconds, and the last link
1111 * selection decided to use EMLSR, activate EMLSR using the previous
1112 * link selection result.
1113 */
1114 } else {
1115 IWL_DEBUG_INFO(mvm,
1116 "Use the latest link selection result: 0x%x\n",
1117 mvmvif->link_selection_res);
1118 ieee80211_set_active_links_async(vif,
1119 mvmvif->link_selection_res);
1120 }
1121 }
1122
iwl_mvm_unblock_esr(struct iwl_mvm * mvm,struct ieee80211_vif * vif,enum iwl_mvm_esr_state reason)1123 void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1124 enum iwl_mvm_esr_state reason)
1125 {
1126 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1127
1128 lockdep_assert_held(&mvm->mutex);
1129
1130 if (!IWL_MVM_AUTO_EML_ENABLE)
1131 return;
1132
1133 /* This should be called only with disable reasons */
1134 if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS)))
1135 return;
1136
1137 /* No Change */
1138 if (!(mvmvif->esr_disable_reason & reason))
1139 return;
1140
1141 mvmvif->esr_disable_reason &= ~reason;
1142
1143 IWL_DEBUG_INFO(mvm,
1144 "Unblocking EMLSR mode. reason = %s (0x%x)\n",
1145 iwl_get_esr_state_string(reason), reason);
1146 iwl_mvm_print_esr_state(mvm, mvmvif->esr_disable_reason);
1147
1148 if (!mvmvif->esr_disable_reason)
1149 iwl_mvm_esr_unblocked(mvm, vif);
1150 }
1151