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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 */ 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 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 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 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 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