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