1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
3 * Copyright (C) 2022 - 2024 Intel Corporation
6 #include "time-event.h"
8 #define HANDLE_ESR_REASONS(HOW) \
9 HOW(BLOCKED_PREVENTION) \
13 HOW(BLOCKED_NON_BSS) \
15 HOW(BLOCKED_TMP_NON_BSS) \
16 HOW(EXIT_MISSED_BEACON) \
21 HOW(EXIT_LINK_USAGE) \
24 static const char *const iwl_mvm_esr_states_names[] = {
25 #define NAME_ENTRY(x) [ilog2(IWL_MVM_ESR_##x)] = #x,
26 HANDLE_ESR_REASONS(NAME_ENTRY)
29 const char *iwl_get_esr_state_string(enum iwl_mvm_esr_state state)
31 int offs = ilog2(state);
33 if (offs >= ARRAY_SIZE(iwl_mvm_esr_states_names) ||
34 !iwl_mvm_esr_states_names[offs])
37 return iwl_mvm_esr_states_names[offs];
40 static void iwl_mvm_print_esr_state(struct iwl_mvm *mvm, u32 mask)
42 #define NAME_FMT(x) "%s"
43 #define NAME_PR(x) (mask & IWL_MVM_ESR_##x) ? "[" #x "]" : "",
45 "EMLSR state = " HANDLE_ESR_REASONS(NAME_FMT)
47 HANDLE_ESR_REASONS(NAME_PR)
53 static u32 iwl_mvm_get_free_fw_link_id(struct iwl_mvm *mvm,
54 struct iwl_mvm_vif *mvm_vif)
58 lockdep_assert_held(&mvm->mutex);
60 for (i = 0; i < ARRAY_SIZE(mvm->link_id_to_link_conf); i++)
61 if (!rcu_access_pointer(mvm->link_id_to_link_conf[i]))
64 return IWL_MVM_FW_LINK_ID_INVALID;
67 static int iwl_mvm_link_cmd_send(struct iwl_mvm *mvm,
68 struct iwl_link_config_cmd *cmd,
69 enum iwl_ctxt_action action)
73 cmd->action = cpu_to_le32(action);
74 ret = iwl_mvm_send_cmd_pdu(mvm,
75 WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD), 0,
78 IWL_ERR(mvm, "Failed to send LINK_CONFIG_CMD (action:%d): %d\n",
83 int iwl_mvm_set_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
84 struct ieee80211_bss_conf *link_conf)
86 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
87 struct iwl_mvm_vif_link_info *link_info =
88 mvmvif->link[link_conf->link_id];
90 if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID) {
91 link_info->fw_link_id = iwl_mvm_get_free_fw_link_id(mvm,
93 if (link_info->fw_link_id >=
94 ARRAY_SIZE(mvm->link_id_to_link_conf))
97 rcu_assign_pointer(mvm->link_id_to_link_conf[link_info->fw_link_id],
104 int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
105 struct ieee80211_bss_conf *link_conf)
107 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
108 unsigned int link_id = link_conf->link_id;
109 struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
110 struct iwl_link_config_cmd cmd = {};
111 unsigned int cmd_id = WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD);
112 u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 1);
115 if (WARN_ON_ONCE(!link_info))
118 ret = iwl_mvm_set_link_mapping(mvm, vif, link_conf);
122 /* Update SF - Disable if needed. if this fails, SF might still be on
123 * while many macs are bound, which is forbidden - so fail the binding.
125 if (iwl_mvm_sf_update(mvm, vif, false))
128 cmd.link_id = cpu_to_le32(link_info->fw_link_id);
129 cmd.mac_id = cpu_to_le32(mvmvif->id);
130 cmd.spec_link_id = link_conf->link_id;
131 WARN_ON_ONCE(link_info->phy_ctxt);
132 cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);
134 memcpy(cmd.local_link_addr, link_conf->addr, ETH_ALEN);
136 if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid)
137 memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN);
140 cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac);
142 return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD);
145 struct iwl_mvm_esr_iter_data {
146 struct ieee80211_vif *vif;
147 unsigned int link_id;
151 static void iwl_mvm_esr_vif_iterator(void *_data, u8 *mac,
152 struct ieee80211_vif *vif)
154 struct iwl_mvm_esr_iter_data *data = _data;
155 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
158 if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION)
161 for_each_mvm_vif_valid_link(mvmvif, link_id) {
162 struct iwl_mvm_vif_link_info *link_info =
163 mvmvif->link[link_id];
164 if (vif == data->vif && link_id == data->link_id)
166 if (link_info->active)
167 data->lift_block = false;
171 int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
172 unsigned int link_id, bool active)
174 /* An active link of a non-station vif blocks EMLSR. Upon activation
175 * block EMLSR on the bss vif. Upon deactivation, check if this link
176 * was the last non-station link active, and if so unblock the bss vif
178 struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm);
179 struct iwl_mvm_esr_iter_data data = {
185 if (IS_ERR_OR_NULL(bss_vif))
189 return iwl_mvm_block_esr_sync(mvm, bss_vif,
190 IWL_MVM_ESR_BLOCKED_NON_BSS);
192 ieee80211_iterate_active_interfaces(mvm->hw,
193 IEEE80211_IFACE_ITER_NORMAL,
194 iwl_mvm_esr_vif_iterator, &data);
195 if (data.lift_block) {
196 mutex_lock(&mvm->mutex);
197 iwl_mvm_unblock_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_NON_BSS);
198 mutex_unlock(&mvm->mutex);
204 int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
205 struct ieee80211_bss_conf *link_conf,
206 u32 changes, bool active)
208 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
209 unsigned int link_id = link_conf->link_id;
210 struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
211 struct iwl_mvm_phy_ctxt *phyctxt;
212 struct iwl_link_config_cmd cmd = {};
213 u32 ht_flag, flags = 0, flags_mask = 0;
215 unsigned int cmd_id = WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD);
216 u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 1);
218 if (WARN_ON_ONCE(!link_info ||
219 link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID))
222 if (changes & LINK_CONTEXT_MODIFY_ACTIVE) {
223 /* When activating a link, phy context should be valid;
224 * when deactivating a link, it also should be valid since
225 * the link was active before. So, do nothing in this case.
226 * Since a link is added first with FW_CTXT_INVALID, then we
227 * can get here in case it's removed before it was activated.
229 if (!link_info->phy_ctxt)
232 /* Catch early if driver tries to activate or deactivate a link
235 WARN_ON_ONCE(active == link_info->active);
237 /* When deactivating a link session protection should
238 * be stopped. Also let the firmware know if we can't Tx.
240 if (!active && vif->type == NL80211_IFTYPE_STATION) {
241 iwl_mvm_stop_session_protection(mvm, vif);
242 if (link_info->csa_block_tx) {
244 link_info->csa_block_tx = false;
249 cmd.link_id = cpu_to_le32(link_info->fw_link_id);
251 /* The phy_id, link address and listen_lmac can be modified only until
252 * the link becomes active, otherwise they will be ignored.
254 phyctxt = link_info->phy_ctxt;
256 cmd.phy_id = cpu_to_le32(phyctxt->id);
258 cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);
259 cmd.mac_id = cpu_to_le32(mvmvif->id);
261 memcpy(cmd.local_link_addr, link_conf->addr, ETH_ALEN);
263 cmd.active = cpu_to_le32(active);
265 if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid)
266 memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN);
268 iwl_mvm_set_fw_basic_rates(mvm, vif, link_info,
269 &cmd.cck_rates, &cmd.ofdm_rates);
271 cmd.cck_short_preamble = cpu_to_le32(link_conf->use_short_preamble);
272 cmd.short_slot = cpu_to_le32(link_conf->use_short_slot);
274 /* The fw does not distinguish between ht and fat */
275 ht_flag = LINK_PROT_FLG_HT_PROT | LINK_PROT_FLG_FAT_PROT;
276 iwl_mvm_set_fw_protection_flags(mvm, vif, link_conf,
277 &cmd.protection_flags,
278 ht_flag, LINK_PROT_FLG_TGG_PROTECT);
280 iwl_mvm_set_fw_qos_params(mvm, vif, link_conf, cmd.ac,
284 cmd.bi = cpu_to_le32(link_conf->beacon_int);
285 cmd.dtim_interval = cpu_to_le32(link_conf->beacon_int *
286 link_conf->dtim_period);
288 if (!link_conf->he_support || iwlwifi_mod_params.disable_11ax ||
289 (vif->type == NL80211_IFTYPE_STATION && !vif->cfg.assoc)) {
290 changes &= ~LINK_CONTEXT_MODIFY_HE_PARAMS;
294 cmd.htc_trig_based_pkt_ext = link_conf->htc_trig_based_pkt_ext;
296 if (link_conf->uora_exists) {
297 cmd.rand_alloc_ecwmin =
298 link_conf->uora_ocw_range & 0x7;
299 cmd.rand_alloc_ecwmax =
300 (link_conf->uora_ocw_range >> 3) & 0x7;
303 /* ap_sta may be NULL if we're disconnecting */
304 if (changes & LINK_CONTEXT_MODIFY_HE_PARAMS && mvmvif->ap_sta) {
305 struct ieee80211_link_sta *link_sta =
306 link_sta_dereference_check(mvmvif->ap_sta, link_id);
308 if (!WARN_ON(!link_sta) && link_sta->he_cap.has_he &&
309 link_sta->he_cap.he_cap_elem.mac_cap_info[5] &
310 IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX)
311 cmd.ul_mu_data_disable = 1;
314 /* TODO how to set ndp_fdbk_buff_th_exp? */
316 if (iwl_mvm_set_fw_mu_edca_params(mvm, mvmvif->link[link_id],
317 &cmd.trig_based_txf[0])) {
318 flags |= LINK_FLG_MU_EDCA_CW;
319 flags_mask |= LINK_FLG_MU_EDCA_CW;
322 if (changes & LINK_CONTEXT_MODIFY_EHT_PARAMS) {
323 struct ieee80211_chanctx_conf *ctx;
324 struct cfg80211_chan_def *def = NULL;
327 ctx = rcu_dereference(link_conf->chanctx_conf);
329 def = iwl_mvm_chanctx_def(mvm, ctx);
331 if (iwlwifi_mod_params.disable_11be ||
332 !link_conf->eht_support || !def ||
333 iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1) >= 6)
334 changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS;
336 cmd.puncture_mask = cpu_to_le16(def->punctured);
340 cmd.bss_color = link_conf->he_bss_color.color;
342 if (!link_conf->he_bss_color.enabled) {
343 flags |= LINK_FLG_BSS_COLOR_DIS;
344 flags_mask |= LINK_FLG_BSS_COLOR_DIS;
347 cmd.frame_time_rts_th = cpu_to_le16(link_conf->frame_time_rts_th);
349 /* Block 26-tone RU OFDMA transmissions */
350 if (link_info->he_ru_2mhz_block) {
351 flags |= LINK_FLG_RU_2MHZ_BLOCK;
352 flags_mask |= LINK_FLG_RU_2MHZ_BLOCK;
355 if (link_conf->nontransmitted) {
356 ether_addr_copy(cmd.ref_bssid_addr,
357 link_conf->transmitter_bssid);
358 cmd.bssid_index = link_conf->bssid_index;
362 cmd.modify_mask = cpu_to_le32(changes);
363 cmd.flags = cpu_to_le32(flags);
365 cmd.flags_mask = cpu_to_le32(flags_mask);
366 cmd.spec_link_id = link_conf->link_id;
368 cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac);
370 ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_MODIFY);
371 if (!ret && (changes & LINK_CONTEXT_MODIFY_ACTIVE))
372 link_info->active = active;
377 int iwl_mvm_unset_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
378 struct ieee80211_bss_conf *link_conf)
380 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
381 struct iwl_mvm_vif_link_info *link_info =
382 mvmvif->link[link_conf->link_id];
384 /* mac80211 thought we have the link, but it was never configured */
385 if (WARN_ON(!link_info ||
386 link_info->fw_link_id >=
387 ARRAY_SIZE(mvm->link_id_to_link_conf)))
390 RCU_INIT_POINTER(mvm->link_id_to_link_conf[link_info->fw_link_id],
395 int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
396 struct ieee80211_bss_conf *link_conf)
398 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
399 unsigned int link_id = link_conf->link_id;
400 struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id];
401 struct iwl_link_config_cmd cmd = {};
404 ret = iwl_mvm_unset_link_mapping(mvm, vif, link_conf);
408 cmd.link_id = cpu_to_le32(link_info->fw_link_id);
409 link_info->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
410 cmd.spec_link_id = link_conf->link_id;
411 cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID);
413 ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_REMOVE);
415 if (!ret && iwl_mvm_sf_update(mvm, vif, true))
416 IWL_ERR(mvm, "Failed to update SF state\n");
421 /* link should be deactivated before removal, so in most cases we need to
422 * perform these two operations together
424 int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
425 struct ieee80211_bss_conf *link_conf)
429 ret = iwl_mvm_link_changed(mvm, vif, link_conf,
430 LINK_CONTEXT_MODIFY_ACTIVE, false);
434 ret = iwl_mvm_remove_link(mvm, vif, link_conf);
441 struct iwl_mvm_rssi_to_grade {
446 #define RSSI_TO_GRADE_LINE(_lb, _hb_uhb, _grade) \
448 .rssi = {_lb, _hb_uhb}, \
453 * This array must be sorted by increasing RSSI for proper functionality.
454 * The grades are actually estimated throughput, represented as fixed-point
455 * with a scale factor of 1/10.
457 static const struct iwl_mvm_rssi_to_grade rssi_to_grade_map[] = {
458 RSSI_TO_GRADE_LINE(-85, -89, 177),
459 RSSI_TO_GRADE_LINE(-83, -86, 344),
460 RSSI_TO_GRADE_LINE(-82, -85, 516),
461 RSSI_TO_GRADE_LINE(-80, -83, 688),
462 RSSI_TO_GRADE_LINE(-77, -79, 1032),
463 RSSI_TO_GRADE_LINE(-73, -76, 1376),
464 RSSI_TO_GRADE_LINE(-70, -74, 1548),
465 RSSI_TO_GRADE_LINE(-69, -72, 1750),
466 RSSI_TO_GRADE_LINE(-65, -68, 2064),
467 RSSI_TO_GRADE_LINE(-61, -66, 2294),
468 RSSI_TO_GRADE_LINE(-58, -61, 2580),
469 RSSI_TO_GRADE_LINE(-55, -58, 2868),
470 RSSI_TO_GRADE_LINE(-46, -55, 3098),
471 RSSI_TO_GRADE_LINE(-43, -54, 3442)
474 #define MAX_GRADE (rssi_to_grade_map[ARRAY_SIZE(rssi_to_grade_map) - 1].grade)
476 #define DEFAULT_CHAN_LOAD_LB 30
477 #define DEFAULT_CHAN_LOAD_HB 15
478 #define DEFAULT_CHAN_LOAD_UHB 0
480 /* Factors calculation is done with fixed-point with a scaling factor of 1/256 */
481 #define SCALE_FACTOR 256
483 /* Convert a percentage from [0,100] to [0,255] */
484 #define NORMALIZE_PERCENT_TO_255(percentage) ((percentage) * SCALE_FACTOR / 100)
487 iwl_mvm_get_puncturing_factor(const struct ieee80211_bss_conf *link_conf)
489 enum nl80211_chan_width chan_width =
490 link_conf->chanreq.oper.width;
491 int mhz = nl80211_chan_width_to_mhz(chan_width);
492 unsigned int n_subchannels, n_punctured, puncturing_penalty;
494 if (WARN_ONCE(mhz < 20 || mhz > 320,
495 "Invalid channel width : (%d)\n", mhz))
498 /* No puncturing, no penalty */
502 /* total number of subchannels */
503 n_subchannels = mhz / 20;
504 /* how many of these are punctured */
505 n_punctured = hweight16(link_conf->chanreq.oper.punctured);
507 puncturing_penalty = n_punctured * SCALE_FACTOR / n_subchannels;
508 return SCALE_FACTOR - puncturing_penalty;
512 iwl_mvm_get_chan_load(struct ieee80211_bss_conf *link_conf)
514 struct ieee80211_vif *vif = link_conf->vif;
515 struct iwl_mvm_vif_link_info *mvm_link =
516 iwl_mvm_vif_from_mac80211(link_conf->vif)->link[link_conf->link_id];
517 const struct element *bss_load_elem;
518 const struct ieee80211_bss_load_elem *bss_load;
519 enum nl80211_band band = link_conf->chanreq.oper.chan->band;
520 const struct cfg80211_bss_ies *ies;
521 unsigned int chan_load;
525 if (ieee80211_vif_link_active(vif, link_conf->link_id))
526 ies = rcu_dereference(link_conf->bss->beacon_ies);
528 ies = rcu_dereference(link_conf->bss->ies);
531 bss_load_elem = cfg80211_find_elem(WLAN_EID_QBSS_LOAD,
532 ies->data, ies->len);
534 bss_load_elem = NULL;
536 /* If there isn't BSS Load element, take the defaults */
537 if (!bss_load_elem ||
538 bss_load_elem->datalen != sizeof(*bss_load)) {
541 case NL80211_BAND_2GHZ:
542 chan_load = DEFAULT_CHAN_LOAD_LB;
544 case NL80211_BAND_5GHZ:
545 chan_load = DEFAULT_CHAN_LOAD_HB;
547 case NL80211_BAND_6GHZ:
548 chan_load = DEFAULT_CHAN_LOAD_UHB;
554 /* The defaults are given in percentage */
555 return NORMALIZE_PERCENT_TO_255(chan_load);
558 bss_load = (const void *)bss_load_elem->data;
559 /* Channel util is in range 0-255 */
560 chan_load = bss_load->channel_util;
563 if (!mvm_link || !mvm_link->active)
566 if (WARN_ONCE(!mvm_link->phy_ctxt,
567 "Active link (%u) without phy ctxt assigned!\n",
571 /* channel load by us is given in percentage */
573 NORMALIZE_PERCENT_TO_255(mvm_link->phy_ctxt->channel_load_by_us);
575 /* Use only values that firmware sends that can possibly be valid */
576 if (chan_load_by_us <= chan_load)
577 chan_load -= chan_load_by_us;
583 iwl_mvm_get_chan_load_factor(struct ieee80211_bss_conf *link_conf)
585 return SCALE_FACTOR - iwl_mvm_get_chan_load(link_conf);
588 /* This function calculates the grade of a link. Returns 0 in error case */
589 VISIBLE_IF_IWLWIFI_KUNIT
590 unsigned int iwl_mvm_get_link_grade(struct ieee80211_bss_conf *link_conf)
592 enum nl80211_band band;
595 unsigned int grade = MAX_GRADE;
597 if (WARN_ON_ONCE(!link_conf))
600 band = link_conf->chanreq.oper.chan->band;
601 if (WARN_ONCE(band != NL80211_BAND_2GHZ &&
602 band != NL80211_BAND_5GHZ &&
603 band != NL80211_BAND_6GHZ,
604 "Invalid band (%u)\n", band))
607 link_rssi = MBM_TO_DBM(link_conf->bss->signal);
609 * For 6 GHz the RSSI of the beacons is lower than
610 * the RSSI of the data.
612 if (band == NL80211_BAND_6GHZ)
615 rssi_idx = band == NL80211_BAND_2GHZ ? 0 : 1;
617 /* No valid RSSI - take the lowest grade */
619 link_rssi = rssi_to_grade_map[0].rssi[rssi_idx];
621 /* Get grade based on RSSI */
622 for (i = 0; i < ARRAY_SIZE(rssi_to_grade_map); i++) {
623 const struct iwl_mvm_rssi_to_grade *line =
624 &rssi_to_grade_map[i];
626 if (link_rssi > line->rssi[rssi_idx])
632 /* apply the channel load and puncturing factors */
633 grade = grade * iwl_mvm_get_chan_load_factor(link_conf) / SCALE_FACTOR;
634 grade = grade * iwl_mvm_get_puncturing_factor(link_conf) / SCALE_FACTOR;
637 EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_get_link_grade);
640 u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif,
641 struct iwl_mvm_link_sel_data *data,
642 unsigned long usable_links,
647 unsigned long link_id;
649 /* TODO: don't select links that weren't discovered in the last scan */
650 for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) {
651 struct ieee80211_bss_conf *link_conf =
652 link_conf_dereference_protected(vif, link_id);
654 if (WARN_ON_ONCE(!link_conf))
657 data[n_data].link_id = link_id;
658 data[n_data].chandef = &link_conf->chanreq.oper;
659 data[n_data].signal = link_conf->bss->signal / 100;
660 data[n_data].grade = iwl_mvm_get_link_grade(link_conf);
662 if (data[n_data].grade > max_grade) {
663 max_grade = data[n_data].grade;
664 *best_link_idx = n_data;
672 struct iwl_mvm_bw_to_rssi_threshs {
677 #define BW_TO_RSSI_THRESHOLDS(_bw) \
678 [IWL_PHY_CHANNEL_MODE ## _bw] = { \
679 .low = IWL_MVM_LOW_RSSI_THRESH_##_bw##MHZ, \
680 .high = IWL_MVM_HIGH_RSSI_THRESH_##_bw##MHZ \
683 s8 iwl_mvm_get_esr_rssi_thresh(struct iwl_mvm *mvm,
684 const struct cfg80211_chan_def *chandef,
687 const struct iwl_mvm_bw_to_rssi_threshs bw_to_rssi_threshs_map[] = {
688 BW_TO_RSSI_THRESHOLDS(20),
689 BW_TO_RSSI_THRESHOLDS(40),
690 BW_TO_RSSI_THRESHOLDS(80),
691 BW_TO_RSSI_THRESHOLDS(160)
692 /* 320 MHz has the same thresholds as 20 MHz */
694 const struct iwl_mvm_bw_to_rssi_threshs *threshs;
695 u8 chan_width = iwl_mvm_get_channel_width(chandef);
697 if (WARN_ON(chandef->chan->band != NL80211_BAND_2GHZ &&
698 chandef->chan->band != NL80211_BAND_5GHZ &&
699 chandef->chan->band != NL80211_BAND_6GHZ))
702 /* 6 GHz will always use 20 MHz thresholds, regardless of the BW */
703 if (chan_width == IWL_PHY_CHANNEL_MODE320)
704 chan_width = IWL_PHY_CHANNEL_MODE20;
706 threshs = &bw_to_rssi_threshs_map[chan_width];
708 return low ? threshs->low : threshs->high;
712 iwl_mvm_esr_disallowed_with_link(struct iwl_mvm *mvm,
713 struct ieee80211_vif *vif,
714 const struct iwl_mvm_link_sel_data *link,
717 struct wiphy *wiphy = mvm->hw->wiphy;
718 struct ieee80211_bss_conf *conf;
719 enum iwl_mvm_esr_state ret = 0;
722 conf = wiphy_dereference(wiphy, vif->link_conf[link->link_id]);
723 if (WARN_ON_ONCE(!conf))
726 /* BT Coex effects eSR mode only if one of the links is on LB */
727 if (link->chandef->chan->band == NL80211_BAND_2GHZ &&
728 (!iwl_mvm_bt_coex_calculate_esr_mode(mvm, vif, link->signal,
730 ret |= IWL_MVM_ESR_EXIT_COEX;
732 thresh = iwl_mvm_get_esr_rssi_thresh(mvm, link->chandef,
735 if (link->signal < thresh)
736 ret |= IWL_MVM_ESR_EXIT_LOW_RSSI;
738 if (conf->csa_active)
739 ret |= IWL_MVM_ESR_EXIT_CSA;
743 "Link %d is not allowed for esr\n",
745 iwl_mvm_print_esr_state(mvm, ret);
750 VISIBLE_IF_IWLWIFI_KUNIT
751 bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif,
752 const struct iwl_mvm_link_sel_data *a,
753 const struct iwl_mvm_link_sel_data *b)
755 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
756 struct iwl_mvm *mvm = mvmvif->mvm;
757 enum iwl_mvm_esr_state ret = 0;
759 /* Per-link considerations */
760 if (iwl_mvm_esr_disallowed_with_link(mvm, vif, a, true) ||
761 iwl_mvm_esr_disallowed_with_link(mvm, vif, b, false))
764 if (a->chandef->chan->band == b->chandef->chan->band ||
765 a->chandef->width != b->chandef->width)
766 ret |= IWL_MVM_ESR_EXIT_BANDWIDTH;
770 "Links %d and %d are not a valid pair for EMLSR\n",
771 a->link_id, b->link_id);
772 iwl_mvm_print_esr_state(mvm, ret);
779 EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_mld_valid_link_pair);
782 * Returns the combined eSR grade of two given links.
783 * Returns 0 if eSR is not allowed with these 2 links.
786 unsigned int iwl_mvm_get_esr_grade(struct ieee80211_vif *vif,
787 const struct iwl_mvm_link_sel_data *a,
788 const struct iwl_mvm_link_sel_data *b,
791 struct ieee80211_bss_conf *primary_conf;
792 struct wiphy *wiphy = ieee80211_vif_to_wdev(vif)->wiphy;
793 unsigned int primary_load;
795 lockdep_assert_wiphy(wiphy);
797 /* a is always primary, b is always secondary */
798 if (b->grade > a->grade)
801 *primary_id = a->link_id;
803 if (!iwl_mvm_mld_valid_link_pair(vif, a, b))
806 primary_conf = wiphy_dereference(wiphy, vif->link_conf[*primary_id]);
808 if (WARN_ON_ONCE(!primary_conf))
811 primary_load = iwl_mvm_get_chan_load(primary_conf);
814 ((b->grade * primary_load) / SCALE_FACTOR);
817 void iwl_mvm_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
819 struct iwl_mvm_link_sel_data data[IEEE80211_MLD_MAX_NUM_LINKS];
820 struct iwl_mvm_link_sel_data *best_link;
821 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
822 u32 max_active_links = iwl_mvm_max_active_links(mvm, vif);
823 u16 usable_links = ieee80211_vif_usable_links(vif);
824 u8 best, primary_link, best_in_pair, n_data;
825 u16 max_esr_grade = 0, new_active_links;
827 lockdep_assert_wiphy(mvm->hw->wiphy);
829 if (!mvmvif->authorized || !ieee80211_vif_is_mld(vif))
832 if (!IWL_MVM_AUTO_EML_ENABLE)
835 /* The logic below is a simple version that doesn't suit more than 2
838 WARN_ON_ONCE(max_active_links > 2);
840 n_data = iwl_mvm_set_link_selection_data(vif, data, usable_links,
843 if (WARN(!n_data, "Couldn't find a valid grade for any link!\n"))
846 best_link = &data[best];
847 primary_link = best_link->link_id;
848 new_active_links = BIT(best_link->link_id);
850 /* eSR is not supported/blocked, or only one usable link */
851 if (max_active_links == 1 || !iwl_mvm_vif_has_esr_cap(mvm, vif) ||
852 mvmvif->esr_disable_reason || n_data == 1)
855 for (u8 a = 0; a < n_data; a++)
856 for (u8 b = a + 1; b < n_data; b++) {
857 u16 esr_grade = iwl_mvm_get_esr_grade(vif, &data[a],
861 if (esr_grade <= max_esr_grade)
864 max_esr_grade = esr_grade;
865 primary_link = best_in_pair;
866 new_active_links = BIT(data[a].link_id) |
867 BIT(data[b].link_id);
870 /* No valid pair was found, go with the best link */
871 if (hweight16(new_active_links) <= 1)
874 /* For equal grade - prefer EMLSR */
875 if (best_link->grade > max_esr_grade) {
876 primary_link = best_link->link_id;
877 new_active_links = BIT(best_link->link_id);
880 IWL_DEBUG_INFO(mvm, "Link selection result: 0x%x. Primary = %d\n",
881 new_active_links, primary_link);
882 ieee80211_set_active_links_async(vif, new_active_links);
883 mvmvif->link_selection_res = new_active_links;
884 mvmvif->link_selection_primary = primary_link;
887 u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif)
889 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
891 /* relevant data is written with both locks held, so read with either */
892 lockdep_assert(lockdep_is_held(&mvmvif->mvm->mutex) ||
893 lockdep_is_held(&mvmvif->mvm->hw->wiphy->mtx));
895 if (!ieee80211_vif_is_mld(vif))
898 /* In AP mode, there is no primary link */
899 if (vif->type == NL80211_IFTYPE_AP)
900 return __ffs(vif->active_links);
902 if (mvmvif->esr_active &&
903 !WARN_ON(!(BIT(mvmvif->primary_link) & vif->active_links)))
904 return mvmvif->primary_link;
906 return __ffs(vif->active_links);
910 * For non-MLO/single link, this will return the deflink/single active link,
913 u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id)
915 switch (hweight16(vif->active_links)) {
922 return __ffs(vif->active_links);
924 return __ffs(vif->active_links & ~BIT(link_id));
928 /* Reasons that can cause esr prevention */
929 #define IWL_MVM_ESR_PREVENT_REASONS IWL_MVM_ESR_EXIT_MISSED_BEACON
930 #define IWL_MVM_PREVENT_ESR_TIMEOUT (HZ * 400)
931 #define IWL_MVM_ESR_PREVENT_SHORT (HZ * 300)
932 #define IWL_MVM_ESR_PREVENT_LONG (HZ * 600)
934 static bool iwl_mvm_check_esr_prevention(struct iwl_mvm *mvm,
935 struct iwl_mvm_vif *mvmvif,
936 enum iwl_mvm_esr_state reason)
938 bool timeout_expired = time_after(jiffies,
939 mvmvif->last_esr_exit.ts +
940 IWL_MVM_PREVENT_ESR_TIMEOUT);
943 lockdep_assert_held(&mvm->mutex);
945 /* Only handle reasons that can cause prevention */
946 if (!(reason & IWL_MVM_ESR_PREVENT_REASONS))
950 * Reset the counter if more than 400 seconds have passed between one
951 * exit and the other, or if we exited due to a different reason.
952 * Will also reset the counter after the long prevention is done.
954 if (timeout_expired || mvmvif->last_esr_exit.reason != reason) {
955 mvmvif->exit_same_reason_count = 1;
959 mvmvif->exit_same_reason_count++;
960 if (WARN_ON(mvmvif->exit_same_reason_count < 2 ||
961 mvmvif->exit_same_reason_count > 3))
964 mvmvif->esr_disable_reason |= IWL_MVM_ESR_BLOCKED_PREVENTION;
967 * For the second exit, use a short prevention, and for the third one,
968 * use a long prevention.
970 delay = mvmvif->exit_same_reason_count == 2 ?
971 IWL_MVM_ESR_PREVENT_SHORT :
972 IWL_MVM_ESR_PREVENT_LONG;
975 "Preventing EMLSR for %ld seconds due to %u exits with the reason = %s (0x%x)\n",
976 delay / HZ, mvmvif->exit_same_reason_count,
977 iwl_get_esr_state_string(reason), reason);
979 wiphy_delayed_work_queue(mvm->hw->wiphy,
980 &mvmvif->prevent_esr_done_wk, delay);
984 #define IWL_MVM_TRIGGER_LINK_SEL_TIME (IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC * HZ)
986 /* API to exit eSR mode */
987 void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
988 enum iwl_mvm_esr_state reason,
991 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
992 u16 new_active_links;
995 lockdep_assert_held(&mvm->mutex);
997 if (!IWL_MVM_AUTO_EML_ENABLE)
1001 if (!mvmvif->esr_active)
1004 if (WARN_ON(!ieee80211_vif_is_mld(vif) || !mvmvif->authorized))
1007 if (WARN_ON(!(vif->active_links & BIT(link_to_keep))))
1008 link_to_keep = __ffs(vif->active_links);
1010 new_active_links = BIT(link_to_keep);
1012 "Exiting EMLSR. reason = %s (0x%x). Current active links=0x%x, new active links = 0x%x\n",
1013 iwl_get_esr_state_string(reason), reason,
1014 vif->active_links, new_active_links);
1016 ieee80211_set_active_links_async(vif, new_active_links);
1018 /* Prevent EMLSR if needed */
1019 prevented = iwl_mvm_check_esr_prevention(mvm, mvmvif, reason);
1021 /* Remember why and when we exited EMLSR */
1022 mvmvif->last_esr_exit.ts = jiffies;
1023 mvmvif->last_esr_exit.reason = reason;
1026 * If EMLSR is prevented now - don't try to get back to EMLSR.
1027 * If we exited due to a blocking event, we will try to get back to
1028 * EMLSR when the corresponding unblocking event will happen.
1030 if (prevented || reason & IWL_MVM_BLOCK_ESR_REASONS)
1033 /* If EMLSR is not blocked - try enabling it again in 30 seconds */
1034 wiphy_delayed_work_queue(mvm->hw->wiphy,
1035 &mvmvif->mlo_int_scan_wk,
1036 round_jiffies_relative(IWL_MVM_TRIGGER_LINK_SEL_TIME));
1039 void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1040 enum iwl_mvm_esr_state reason,
1043 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1045 lockdep_assert_held(&mvm->mutex);
1047 if (!IWL_MVM_AUTO_EML_ENABLE)
1050 /* This should be called only with disable reasons */
1051 if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS)))
1054 if (mvmvif->esr_disable_reason & reason)
1058 "Blocking EMLSR mode. reason = %s (0x%x)\n",
1059 iwl_get_esr_state_string(reason), reason);
1061 mvmvif->esr_disable_reason |= reason;
1063 iwl_mvm_print_esr_state(mvm, mvmvif->esr_disable_reason);
1065 iwl_mvm_exit_esr(mvm, vif, reason, link_to_keep);
1068 int iwl_mvm_block_esr_sync(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1069 enum iwl_mvm_esr_state reason)
1071 int primary_link = iwl_mvm_get_primary_link(vif);
1074 if (!IWL_MVM_AUTO_EML_ENABLE || !ieee80211_vif_is_mld(vif))
1077 /* This should be called only with blocking reasons */
1078 if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS)))
1081 /* leave ESR immediately, not only async with iwl_mvm_block_esr() */
1082 ret = ieee80211_set_active_links(vif, BIT(primary_link));
1086 mutex_lock(&mvm->mutex);
1087 /* only additionally block for consistency and to avoid concurrency */
1088 iwl_mvm_block_esr(mvm, vif, reason, primary_link);
1089 mutex_unlock(&mvm->mutex);
1094 static void iwl_mvm_esr_unblocked(struct iwl_mvm *mvm,
1095 struct ieee80211_vif *vif)
1097 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1098 bool need_new_sel = time_after(jiffies, mvmvif->last_esr_exit.ts +
1099 IWL_MVM_TRIGGER_LINK_SEL_TIME);
1101 lockdep_assert_held(&mvm->mutex);
1103 if (!ieee80211_vif_is_mld(vif) || !mvmvif->authorized ||
1107 IWL_DEBUG_INFO(mvm, "EMLSR is unblocked\n");
1109 /* If we exited due to an EXIT reason, and the exit was in less than
1110 * 30 seconds, then a MLO scan was scheduled already.
1112 if (!need_new_sel &&
1113 !(mvmvif->last_esr_exit.reason & IWL_MVM_BLOCK_ESR_REASONS)) {
1114 IWL_DEBUG_INFO(mvm, "Wait for MLO scan\n");
1119 * If EMLSR was blocked for more than 30 seconds, or the last link
1120 * selection decided to not enter EMLSR, trigger a new scan.
1122 if (need_new_sel || hweight16(mvmvif->link_selection_res) < 2) {
1123 IWL_DEBUG_INFO(mvm, "Trigger MLO scan\n");
1124 wiphy_delayed_work_queue(mvm->hw->wiphy,
1125 &mvmvif->mlo_int_scan_wk, 0);
1127 * If EMLSR was blocked for less than 30 seconds, and the last link
1128 * selection decided to use EMLSR, activate EMLSR using the previous
1129 * link selection result.
1133 "Use the latest link selection result: 0x%x\n",
1134 mvmvif->link_selection_res);
1135 ieee80211_set_active_links_async(vif,
1136 mvmvif->link_selection_res);
1140 void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1141 enum iwl_mvm_esr_state reason)
1143 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
1145 lockdep_assert_held(&mvm->mutex);
1147 if (!IWL_MVM_AUTO_EML_ENABLE)
1150 /* This should be called only with disable reasons */
1151 if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS)))
1155 if (!(mvmvif->esr_disable_reason & reason))
1158 mvmvif->esr_disable_reason &= ~reason;
1161 "Unblocking EMLSR mode. reason = %s (0x%x)\n",
1162 iwl_get_esr_state_string(reason), reason);
1163 iwl_mvm_print_esr_state(mvm, mvmvif->esr_disable_reason);
1165 if (!mvmvif->esr_disable_reason)
1166 iwl_mvm_esr_unblocked(mvm, vif);
1169 void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link)
1171 link->bcast_sta.sta_id = IWL_INVALID_STA;
1172 link->mcast_sta.sta_id = IWL_INVALID_STA;
1173 link->ap_sta_id = IWL_INVALID_STA;
1175 for (int r = 0; r < NUM_IWL_MVM_SMPS_REQ; r++)
1176 link->smps_requests[r] =
1177 IEEE80211_SMPS_AUTOMATIC;