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