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