1 /* 2 * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /* 18 * DOC: contains bss scoring logic 19 */ 20 21 #ifdef WLAN_POLICY_MGR_ENABLE 22 #include "wlan_policy_mgr_api.h" 23 #endif 24 #include <include/wlan_psoc_mlme.h> 25 #include "wlan_psoc_mlme_api.h" 26 #include "cfg_ucfg_api.h" 27 #include "wlan_cm_bss_score_param.h" 28 #include "wlan_scan_api.h" 29 #include "wlan_crypto_global_api.h" 30 #include "wlan_mgmt_txrx_utils_api.h" 31 #ifdef CONN_MGR_ADV_FEATURE 32 #include "wlan_mlme_api.h" 33 #endif 34 35 #define CM_PCL_RSSI_THRESHOLD -75 36 37 #define CM_BAND_2G_INDEX 0 38 #define CM_BAND_5G_INDEX 1 39 #define CM_BAND_6G_INDEX 2 40 /* 3 is reserved */ 41 #define CM_MAX_BAND_INDEX 4 42 43 #define CM_SCORE_INDEX_0 0 44 #define CM_SCORE_INDEX_3 3 45 #define CM_SCORE_INDEX_7 7 46 #define CM_SCORE_OFFSET_INDEX_7_4 4 47 #define CM_SCORE_INDEX_11 11 48 #define CM_SCORE_OFFSET_INDEX_11_8 8 49 #define CM_SCORE_MAX_INDEX 15 50 #define CM_SCORE_OFFSET_INDEX_15_12 12 51 52 #define CM_MAX_OCE_WAN_DL_CAP 16 53 54 #define CM_MAX_CHANNEL_WEIGHT 100 55 #define CM_MAX_CHANNEL_UTILIZATION 100 56 #define CM_MAX_ESTIMATED_AIR_TIME_FRACTION 255 57 #define CM_MAX_AP_LOAD 255 58 59 #define CM_MAX_WEIGHT_OF_PCL_CHANNELS 255 60 #define CM_PCL_GROUPS_WEIGHT_DIFFERENCE 20 61 62 /* Congestion threshold (channel load %) to consider band and OCE WAN score */ 63 #define CM_CONGESTION_THRSHOLD_FOR_BAND_OCE_SCORE 75 64 65 #define CM_RSSI_WEIGHTAGE 20 66 #define CM_HT_CAPABILITY_WEIGHTAGE 2 67 #define CM_VHT_CAP_WEIGHTAGE 1 68 #define CM_HE_CAP_WEIGHTAGE 2 69 #define CM_CHAN_WIDTH_WEIGHTAGE 12 70 #define CM_CHAN_BAND_WEIGHTAGE 2 71 #define CM_NSS_WEIGHTAGE 16 72 #define CM_BEAMFORMING_CAP_WEIGHTAGE 2 73 #define CM_PCL_WEIGHT 10 74 #define CM_CHANNEL_CONGESTION_WEIGHTAGE 5 75 #define CM_OCE_WAN_WEIGHTAGE 2 76 #define CM_OCE_AP_TX_POWER_WEIGHTAGE 5 77 #define CM_OCE_SUBNET_ID_WEIGHTAGE 3 78 #define CM_SAE_PK_AP_WEIGHTAGE 3 79 #define CM_BEST_CANDIDATE_MAX_WEIGHT 200 80 #define CM_MAX_PCT_SCORE 100 81 #define CM_MAX_INDEX_PER_INI 4 82 83 #define CM_BEST_CANDIDATE_MAX_BSS_SCORE (CM_BEST_CANDIDATE_MAX_WEIGHT * 100) 84 #define CM_AVOID_CANDIDATE_MIN_SCORE 1 85 86 #define CM_GET_SCORE_PERCENTAGE(value32, bw_index) \ 87 QDF_GET_BITS(value32, (8 * (bw_index)), 8) 88 #define CM_SET_SCORE_PERCENTAGE(value32, score_pcnt, bw_index) \ 89 QDF_SET_BITS(value32, (8 * (bw_index)), 8, score_pcnt) 90 91 #ifdef CONN_MGR_ADV_FEATURE 92 /* 3.2 us + 0.8 us(GI) */ 93 #define PPDU_PAYLOAD_SYMBOL_DUR_US 4 94 /* 12.8 us + (0.8 + 1.6)/2 us(GI) */ 95 #define HE_PPDU_PAYLOAD_SYMBOL_DUR_US 14 96 #define MAC_HEADER_LEN 26 97 /* Minimum snrDb supported by LUT */ 98 #define SNR_DB_TO_BIT_PER_TONE_LUT_MIN -10 99 /* Maximum snrDb supported by LUT */ 100 #define SNR_DB_TO_BIT_PER_TONE_LUT_MAX 9 101 #define DB_NUM 20 102 /* 103 * A fudge factor to represent HW implementation margin in dB. 104 * Predicted throughput matches pretty well with OTA throughput with this 105 * fudge factor. 106 */ 107 #define SNR_MARGIN_DB 16 108 #define TWO_IN_DB 3 109 static int32_t 110 SNR_DB_TO_BIT_PER_TONE_LUT[DB_NUM] = {0, 171, 212, 262, 323, 396, 484, 111 586, 706, 844, 1000, 1176, 1370, 1583, 1812, 2058, 2317, 2588, 2870, 3161}; 112 #endif 113 114 static bool cm_is_better_bss(struct scan_cache_entry *bss1, 115 struct scan_cache_entry *bss2) 116 { 117 if (bss1->bss_score > bss2->bss_score) 118 return true; 119 else if (bss1->bss_score == bss2->bss_score) 120 if (bss1->rssi_raw > bss2->rssi_raw) 121 return true; 122 123 return false; 124 } 125 126 /** 127 * cm_get_rssi_pcnt_for_slot() - calculate rssi % score based on the slot 128 * index between the high rssi and low rssi threshold 129 * @high_rssi_threshold: High rssi of the window 130 * @low_rssi_threshold: low rssi of the window 131 * @high_rssi_pcnt: % score for the high rssi 132 * @low_rssi_pcnt: %score for the low rssi 133 * @bucket_size: bucket size of the window 134 * @bss_rssi: Input rssi for which value need to be calculated 135 * 136 * Return: rssi pct to use for the given rssi 137 */ 138 static inline 139 int8_t cm_get_rssi_pcnt_for_slot(int32_t high_rssi_threshold, 140 int32_t low_rssi_threshold, 141 uint32_t high_rssi_pcnt, 142 uint32_t low_rssi_pcnt, 143 uint32_t bucket_size, int8_t bss_rssi) 144 { 145 int8_t slot_index, slot_size, rssi_diff, num_slot, rssi_pcnt; 146 147 num_slot = ((high_rssi_threshold - 148 low_rssi_threshold) / bucket_size) + 1; 149 slot_size = ((high_rssi_pcnt - low_rssi_pcnt) + 150 (num_slot / 2)) / (num_slot); 151 rssi_diff = high_rssi_threshold - bss_rssi; 152 slot_index = (rssi_diff / bucket_size) + 1; 153 rssi_pcnt = high_rssi_pcnt - (slot_size * slot_index); 154 if (rssi_pcnt < low_rssi_pcnt) 155 rssi_pcnt = low_rssi_pcnt; 156 157 mlme_debug("Window %d -> %d pcnt range %d -> %d bucket_size %d bss_rssi %d num_slot %d slot_size %d rssi_diff %d slot_index %d rssi_pcnt %d", 158 high_rssi_threshold, low_rssi_threshold, high_rssi_pcnt, 159 low_rssi_pcnt, bucket_size, bss_rssi, num_slot, slot_size, 160 rssi_diff, slot_index, rssi_pcnt); 161 162 return rssi_pcnt; 163 } 164 165 /** 166 * cm_calculate_rssi_score() - Calculate RSSI score based on AP RSSI 167 * @score_param: rssi score params 168 * @rssi: rssi of the AP 169 * @rssi_weightage: rssi_weightage out of total weightage 170 * 171 * Return: rssi score 172 */ 173 static int32_t cm_calculate_rssi_score(struct rssi_config_score *score_param, 174 int32_t rssi, uint8_t rssi_weightage) 175 { 176 int8_t rssi_pcnt; 177 int32_t total_rssi_score; 178 int32_t best_rssi_threshold; 179 int32_t good_rssi_threshold; 180 int32_t bad_rssi_threshold; 181 uint32_t good_rssi_pcnt; 182 uint32_t bad_rssi_pcnt; 183 uint32_t good_bucket_size; 184 uint32_t bad_bucket_size; 185 186 best_rssi_threshold = score_param->best_rssi_threshold * (-1); 187 good_rssi_threshold = score_param->good_rssi_threshold * (-1); 188 bad_rssi_threshold = score_param->bad_rssi_threshold * (-1); 189 good_rssi_pcnt = score_param->good_rssi_pcnt; 190 bad_rssi_pcnt = score_param->bad_rssi_pcnt; 191 good_bucket_size = score_param->good_rssi_bucket_size; 192 bad_bucket_size = score_param->bad_rssi_bucket_size; 193 194 total_rssi_score = (CM_MAX_PCT_SCORE * rssi_weightage); 195 196 /* 197 * If RSSI is better than the best rssi threshold then it return full 198 * score. 199 */ 200 if (rssi > best_rssi_threshold) 201 return total_rssi_score; 202 /* 203 * If RSSI is less or equal to bad rssi threshold then it return 204 * least score. 205 */ 206 if (rssi <= bad_rssi_threshold) 207 return (total_rssi_score * bad_rssi_pcnt) / 100; 208 209 /* RSSI lies between best to good rssi threshold */ 210 if (rssi > good_rssi_threshold) 211 rssi_pcnt = cm_get_rssi_pcnt_for_slot(best_rssi_threshold, 212 good_rssi_threshold, 100, good_rssi_pcnt, 213 good_bucket_size, rssi); 214 else 215 rssi_pcnt = cm_get_rssi_pcnt_for_slot(good_rssi_threshold, 216 bad_rssi_threshold, good_rssi_pcnt, 217 bad_rssi_pcnt, bad_bucket_size, 218 rssi); 219 220 return (total_rssi_score * rssi_pcnt) / 100; 221 } 222 223 /** 224 * cm_rssi_is_same_bucket() - check if both rssi fall in same bucket 225 * @rssi_top_thresh: high rssi threshold of the the window 226 * @low_rssi_threshold: low rssi of the window 227 * @rssi_ref1: rssi ref one 228 * @rssi_ref2: rssi ref two 229 * @bucket_size: bucket size of the window 230 * 231 * Return: true if both fall in same window 232 */ 233 static inline bool cm_rssi_is_same_bucket(int8_t rssi_top_thresh, 234 int8_t rssi_ref1, int8_t rssi_ref2, 235 int8_t bucket_size) 236 { 237 int8_t rssi_diff1 = 0; 238 int8_t rssi_diff2 = 0; 239 240 rssi_diff1 = rssi_top_thresh - rssi_ref1; 241 rssi_diff2 = rssi_top_thresh - rssi_ref2; 242 243 return (rssi_diff1 / bucket_size) == (rssi_diff2 / bucket_size); 244 } 245 246 /** 247 * cm_roam_calculate_prorated_pcnt_by_rssi() - Calculate prorated RSSI score 248 * based on AP RSSI. This will be used to determine HT VHT score 249 * @score_param: rssi score params 250 * @rssi: bss rssi 251 * @rssi_weightage: rssi_weightage out of total weightage 252 * 253 * If rssi is greater than good threshold return 100, if less than bad return 0, 254 * if between good and bad, return prorated rssi score for the index. 255 * 256 * Return: rssi prorated score 257 */ 258 static int8_t cm_roam_calculate_prorated_pcnt_by_rssi( 259 struct rssi_config_score *score_param, 260 int32_t rssi, uint8_t rssi_weightage) 261 { 262 int32_t good_rssi_threshold; 263 int32_t bad_rssi_threshold; 264 int8_t rssi_pref_5g_rssi_thresh; 265 bool same_bucket; 266 267 good_rssi_threshold = score_param->good_rssi_threshold * (-1); 268 bad_rssi_threshold = score_param->bad_rssi_threshold * (-1); 269 rssi_pref_5g_rssi_thresh = score_param->rssi_pref_5g_rssi_thresh * (-1); 270 271 /* If RSSI is greater than good rssi return full weight */ 272 if (rssi > good_rssi_threshold) 273 return CM_MAX_PCT_SCORE; 274 275 same_bucket = cm_rssi_is_same_bucket(good_rssi_threshold, rssi, 276 rssi_pref_5g_rssi_thresh, 277 score_param->bad_rssi_bucket_size); 278 if (same_bucket || (rssi < rssi_pref_5g_rssi_thresh)) 279 return 0; 280 /* If RSSI is less or equal to bad rssi threshold then it return 0 */ 281 if (rssi <= bad_rssi_threshold) 282 return 0; 283 284 /* If RSSI is between good and bad threshold */ 285 return cm_get_rssi_pcnt_for_slot(good_rssi_threshold, 286 bad_rssi_threshold, 287 score_param->good_rssi_pcnt, 288 score_param->bad_rssi_pcnt, 289 score_param->bad_rssi_bucket_size, 290 rssi); 291 } 292 293 /** 294 * cm_calculate_bandwidth_score() - Calculate BW score 295 * @entry: scan entry 296 * @score_config: scoring config 297 * @phy_config: psoc phy configs 298 * @prorated_pct: prorated % to return dependent on RSSI 299 * 300 * Return: bw score 301 */ 302 static int32_t cm_calculate_bandwidth_score(struct scan_cache_entry *entry, 303 struct scoring_cfg *score_config, 304 struct psoc_phy_config *phy_config, 305 uint8_t prorated_pct) 306 { 307 uint32_t score; 308 int32_t bw_weight_per_idx; 309 uint8_t bw_above_20 = 0; 310 uint8_t ch_width_index; 311 bool is_vht = false; 312 313 bw_weight_per_idx = score_config->bandwidth_weight_per_index[0]; 314 315 if (WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) { 316 bw_above_20 = phy_config->bw_above_20_24ghz; 317 if (phy_config->vht_24G_cap) 318 is_vht = true; 319 } else if (phy_config->vht_cap) { 320 is_vht = true; 321 bw_above_20 = phy_config->bw_above_20_5ghz; 322 } 323 324 if (IS_WLAN_PHYMODE_160MHZ(entry->phy_mode)) 325 ch_width_index = CM_160MHZ_BW_INDEX; 326 else if (IS_WLAN_PHYMODE_80MHZ(entry->phy_mode)) 327 ch_width_index = CM_80MHZ_BW_INDEX; 328 else if (IS_WLAN_PHYMODE_40MHZ(entry->phy_mode)) 329 ch_width_index = CM_40MHZ_BW_INDEX; 330 else 331 ch_width_index = CM_20MHZ_BW_INDEX; 332 333 if (!phy_config->ht_cap && 334 ch_width_index > CM_20MHZ_BW_INDEX) 335 ch_width_index = CM_20MHZ_BW_INDEX; 336 337 if (!is_vht && ch_width_index > CM_40MHZ_BW_INDEX) 338 ch_width_index = CM_40MHZ_BW_INDEX; 339 340 if (bw_above_20 && ch_width_index > CM_20MHZ_BW_INDEX) 341 score = CM_GET_SCORE_PERCENTAGE(bw_weight_per_idx, 342 ch_width_index); 343 else 344 score = CM_GET_SCORE_PERCENTAGE(bw_weight_per_idx, 345 CM_20MHZ_BW_INDEX); 346 347 return (prorated_pct * score * 348 score_config->weight_config.chan_width_weightage) / 349 CM_MAX_PCT_SCORE; 350 } 351 352 /** 353 * cm_get_score_for_index() - get score for the given index 354 * @index: index for which we need the score 355 * @weightage: weigtage for the param 356 * @score: per slot score 357 * 358 * Return: score for the index 359 */ 360 static int32_t cm_get_score_for_index(uint8_t index, 361 uint8_t weightage, 362 struct per_slot_score *score) 363 { 364 if (index <= CM_SCORE_INDEX_3) 365 return weightage * CM_GET_SCORE_PERCENTAGE( 366 score->score_pcnt3_to_0, 367 index); 368 else if (index <= CM_SCORE_INDEX_7) 369 return weightage * CM_GET_SCORE_PERCENTAGE( 370 score->score_pcnt7_to_4, 371 index - CM_SCORE_OFFSET_INDEX_7_4); 372 else if (index <= CM_SCORE_INDEX_11) 373 return weightage * CM_GET_SCORE_PERCENTAGE( 374 score->score_pcnt11_to_8, 375 index - CM_SCORE_OFFSET_INDEX_11_8); 376 else 377 return weightage * CM_GET_SCORE_PERCENTAGE( 378 score->score_pcnt15_to_12, 379 index - CM_SCORE_OFFSET_INDEX_15_12); 380 } 381 382 /** 383 * cm_get_congestion_pct() - Calculate congestion pct from esp/qbss load 384 * @entry: bss information 385 * 386 * Return: congestion pct 387 */ 388 static int32_t cm_get_congestion_pct(struct scan_cache_entry *entry) 389 { 390 uint32_t ap_load = 0; 391 uint32_t est_air_time_percentage = 0; 392 uint32_t congestion = 0; 393 394 if (entry->air_time_fraction) { 395 /* Convert 0-255 range to percentage */ 396 est_air_time_percentage = entry->air_time_fraction * 397 CM_MAX_CHANNEL_WEIGHT; 398 est_air_time_percentage = qdf_do_div(est_air_time_percentage, 399 CM_MAX_ESTIMATED_AIR_TIME_FRACTION); 400 /* 401 * Calculate channel congestion from estimated air time 402 * fraction. 403 */ 404 congestion = CM_MAX_CHANNEL_UTILIZATION - 405 est_air_time_percentage; 406 if (!congestion) 407 congestion = 1; 408 } else if (util_scan_entry_qbssload(entry)) { 409 ap_load = (entry->qbss_chan_load * CM_MAX_PCT_SCORE); 410 /* 411 * Calculate ap_load in % from qbss channel load from 412 * 0-255 range 413 */ 414 congestion = qdf_do_div(ap_load, CM_MAX_AP_LOAD); 415 if (!congestion) 416 congestion = 1; 417 } 418 419 return congestion; 420 } 421 422 /** 423 * cm_calculate_congestion_score() - Calculate congestion score 424 * @entry: bss information 425 * @score_params: bss score params 426 * @congestion_pct: congestion pct 427 * 428 * Return: congestion score 429 */ 430 static int32_t cm_calculate_congestion_score(struct scan_cache_entry *entry, 431 struct scoring_cfg *score_params, 432 uint32_t *congestion_pct) 433 { 434 uint32_t window_size; 435 uint8_t index; 436 int32_t good_rssi_threshold; 437 uint8_t chan_congestion_weight; 438 439 *congestion_pct = cm_get_congestion_pct(entry); 440 441 if (!score_params->esp_qbss_scoring.num_slot) 442 return 0; 443 444 if (score_params->esp_qbss_scoring.num_slot > 445 CM_SCORE_MAX_INDEX) 446 score_params->esp_qbss_scoring.num_slot = 447 CM_SCORE_MAX_INDEX; 448 449 good_rssi_threshold = 450 score_params->rssi_score.good_rssi_threshold * (-1); 451 452 chan_congestion_weight = 453 score_params->weight_config.channel_congestion_weightage; 454 455 /* For bad zone rssi get score from last index */ 456 if (entry->rssi_raw <= good_rssi_threshold) 457 return cm_get_score_for_index( 458 score_params->esp_qbss_scoring.num_slot, 459 chan_congestion_weight, 460 &score_params->esp_qbss_scoring); 461 462 if (!*congestion_pct) 463 return chan_congestion_weight * 464 CM_GET_SCORE_PERCENTAGE( 465 score_params->esp_qbss_scoring.score_pcnt3_to_0, 466 CM_SCORE_INDEX_0); 467 468 window_size = CM_MAX_PCT_SCORE / 469 score_params->esp_qbss_scoring.num_slot; 470 471 /* Desired values are from 1 to 15, as 0 is for not present. so do +1 */ 472 index = qdf_do_div(*congestion_pct, window_size) + 1; 473 474 if (index > score_params->esp_qbss_scoring.num_slot) 475 index = score_params->esp_qbss_scoring.num_slot; 476 477 return cm_get_score_for_index(index, 478 chan_congestion_weight, 479 &score_params->esp_qbss_scoring); 480 } 481 482 /** 483 * cm_calculate_nss_score() - Calculate congestion score 484 * @psoc: psoc ptr 485 * @score_config: scoring config 486 * @ap_nss: ap nss 487 * @prorated_pct: prorated % to return dependent on RSSI 488 * 489 * Return: nss score 490 */ 491 static int32_t cm_calculate_nss_score(struct wlan_objmgr_psoc *psoc, 492 struct scoring_cfg *score_config, 493 uint8_t ap_nss, uint8_t prorated_pct, 494 uint32_t sta_nss) 495 { 496 uint8_t nss; 497 uint8_t score_pct; 498 499 nss = ap_nss; 500 if (sta_nss < nss) 501 nss = sta_nss; 502 503 /* TODO: enhance for 8x8 */ 504 if (nss == 4) 505 score_pct = CM_GET_SCORE_PERCENTAGE( 506 score_config->nss_weight_per_index[0], 507 CM_NSS_4x4_INDEX); 508 else if (nss == 3) 509 score_pct = CM_GET_SCORE_PERCENTAGE( 510 score_config->nss_weight_per_index[0], 511 CM_NSS_3x3_INDEX); 512 else if (nss == 2) 513 score_pct = CM_GET_SCORE_PERCENTAGE( 514 score_config->nss_weight_per_index[0], 515 CM_NSS_2x2_INDEX); 516 else 517 score_pct = CM_GET_SCORE_PERCENTAGE( 518 score_config->nss_weight_per_index[0], 519 CM_NSS_1x1_INDEX); 520 521 return (score_config->weight_config.nss_weightage * score_pct * 522 prorated_pct) / CM_MAX_PCT_SCORE; 523 } 524 525 #ifdef WLAN_POLICY_MGR_ENABLE 526 static uint32_t cm_get_sta_nss(struct wlan_objmgr_psoc *psoc, 527 qdf_freq_t bss_channel_freq, 528 uint8_t vdev_nss_2g, uint8_t vdev_nss_5g) 529 { 530 /* 531 * If station support nss as 2*2 but AP support NSS as 1*1, 532 * this AP will be given half weight compare to AP which are having 533 * NSS as 2*2. 534 */ 535 536 if (policy_mgr_is_chnl_in_diff_band( 537 psoc, bss_channel_freq) && 538 policy_mgr_is_hw_dbs_capable(psoc) && 539 !(policy_mgr_is_hw_dbs_2x2_capable(psoc))) 540 return 1; 541 542 return (WLAN_REG_IS_24GHZ_CH_FREQ(bss_channel_freq) ? 543 vdev_nss_2g : 544 vdev_nss_5g); 545 } 546 #else 547 static uint32_t cm_get_sta_nss(struct wlan_objmgr_psoc *psoc, 548 qdf_freq_t bss_channel_freq, 549 uint8_t vdev_nss_2g, uint8_t vdev_nss_5g) 550 { 551 return (WLAN_REG_IS_24GHZ_CH_FREQ(bss_channel_freq) ? 552 vdev_nss_2g : 553 vdev_nss_5g); 554 } 555 #endif 556 557 #ifdef CONN_MGR_ADV_FEATURE 558 static bool 559 cm_get_pcl_weight_of_channel(uint32_t chan_freq, 560 struct pcl_freq_weight_list *pcl_lst, 561 int *pcl_chan_weight) 562 { 563 int i; 564 bool found = false; 565 566 if (!pcl_lst) 567 return found; 568 569 for (i = 0; i < pcl_lst->num_of_pcl_channels; i++) { 570 if (pcl_lst->pcl_freq_list[i] == chan_freq) { 571 *pcl_chan_weight = pcl_lst->pcl_weight_list[i]; 572 found = true; 573 break; 574 } 575 } 576 577 return found; 578 } 579 580 /** 581 * cm_calculate_pcl_score() - Calculate PCL score based on PCL weightage 582 * @psoc: psoc ptr 583 * @pcl_chan_weight: pcl weight of BSS channel 584 * @pcl_weightage: PCL _weightage out of total weightage 585 * 586 * Return: pcl score 587 */ 588 static int32_t cm_calculate_pcl_score(struct wlan_objmgr_psoc *psoc, 589 int pcl_chan_weight, 590 uint8_t pcl_weightage) 591 { 592 int32_t pcl_score = 0; 593 int32_t temp_pcl_chan_weight = 0; 594 595 /* 596 * Don’t consider pcl weightage for STA connection, 597 * if primary interface is configured. 598 */ 599 if (!policy_mgr_is_pcl_weightage_required(psoc)) 600 return 0; 601 602 if (pcl_chan_weight) { 603 temp_pcl_chan_weight = 604 (CM_MAX_WEIGHT_OF_PCL_CHANNELS - pcl_chan_weight); 605 temp_pcl_chan_weight = qdf_do_div( 606 temp_pcl_chan_weight, 607 CM_PCL_GROUPS_WEIGHT_DIFFERENCE); 608 pcl_score = pcl_weightage - temp_pcl_chan_weight; 609 if (pcl_score < 0) 610 pcl_score = 0; 611 } 612 613 return pcl_score * CM_MAX_PCT_SCORE; 614 } 615 616 /** 617 * cm_calculate_oce_wan_score() - Calculate oce wan score 618 * @entry: bss information 619 * @score_params: bss score params 620 * 621 * Return: oce wan score 622 */ 623 static int32_t cm_calculate_oce_wan_score( 624 struct scan_cache_entry *entry, 625 struct scoring_cfg *score_params) 626 { 627 uint32_t window_size; 628 uint8_t index; 629 struct oce_reduced_wan_metrics wan_metrics; 630 uint8_t *mbo_oce_ie; 631 632 if (!score_params->oce_wan_scoring.num_slot) 633 return 0; 634 635 if (score_params->oce_wan_scoring.num_slot > 636 CM_SCORE_MAX_INDEX) 637 score_params->oce_wan_scoring.num_slot = 638 CM_SCORE_MAX_INDEX; 639 640 window_size = CM_SCORE_MAX_INDEX / 641 score_params->oce_wan_scoring.num_slot; 642 mbo_oce_ie = util_scan_entry_mbo_oce(entry); 643 if (wlan_parse_oce_reduced_wan_metrics_ie(mbo_oce_ie, &wan_metrics)) { 644 mlme_err("downlink_av_cap %d", wan_metrics.downlink_av_cap); 645 /* if capacity is 0 return 0 score */ 646 if (!wan_metrics.downlink_av_cap) 647 return 0; 648 /* Desired values are from 1 to WLAN_SCORE_MAX_INDEX */ 649 index = qdf_do_div(wan_metrics.downlink_av_cap, 650 window_size); 651 } else { 652 index = CM_SCORE_INDEX_0; 653 } 654 655 if (index > score_params->oce_wan_scoring.num_slot) 656 index = score_params->oce_wan_scoring.num_slot; 657 658 return cm_get_score_for_index(index, 659 score_params->weight_config.oce_wan_weightage, 660 &score_params->oce_wan_scoring); 661 } 662 663 /** 664 * cm_calculate_oce_subnet_id_weightage() - Calculate oce subnet id weightage 665 * @entry: bss entry 666 * @score_params: bss score params 667 * @oce_subnet_id_present: check if subnet id subelement is present in OCE IE 668 * 669 * Return: oce subnet id score 670 */ 671 static uint32_t 672 cm_calculate_oce_subnet_id_weightage(struct scan_cache_entry *entry, 673 struct scoring_cfg *score_params, 674 bool *oce_subnet_id_present) 675 { 676 uint32_t score = 0; 677 uint8_t *mbo_oce_ie; 678 679 mbo_oce_ie = util_scan_entry_mbo_oce(entry); 680 *oce_subnet_id_present = wlan_parse_oce_subnet_id_ie(mbo_oce_ie); 681 682 /* Consider 50% weightage if subnet id sub element is present */ 683 if (*oce_subnet_id_present) 684 score = score_params->weight_config.oce_subnet_id_weightage * 685 (CM_MAX_PCT_SCORE / 2); 686 687 return score; 688 } 689 690 /** 691 * cm_calculate_sae_pk_ap_weightage() - Calculate SAE-PK AP weightage 692 * @entry: bss entry 693 * @score_params: bss score params 694 * @sae_pk_cap_present: sae_pk cap presetn in RSNXE capability field 695 * 696 * Return: SAE-PK AP weightage score 697 */ 698 static uint32_t 699 cm_calculate_sae_pk_ap_weightage(struct scan_cache_entry *entry, 700 struct scoring_cfg *score_params, 701 bool *sae_pk_cap_present) 702 { 703 const uint8_t *rsnxe_ie; 704 const uint8_t *rsnxe_cap; 705 uint8_t cap_len; 706 707 rsnxe_ie = util_scan_entry_rsnxe(entry); 708 709 rsnxe_cap = wlan_crypto_parse_rsnxe_ie(rsnxe_ie, &cap_len); 710 711 if (!rsnxe_cap) 712 return 0; 713 714 *sae_pk_cap_present = *rsnxe_cap & WLAN_CRYPTO_RSNX_CAP_SAE_PK; 715 if (*sae_pk_cap_present) 716 return score_params->weight_config.sae_pk_ap_weightage * 717 CM_MAX_PCT_SCORE; 718 719 return 0; 720 } 721 722 /** 723 * cm_calculate_oce_ap_tx_pwr_weightage() - Calculate oce ap tx pwr weightage 724 * @entry: bss entry 725 * @score_params: bss score params 726 * @ap_tx_pwr_dbm: pointer to hold ap tx power 727 * 728 * Return: oce ap tx power score 729 */ 730 static uint32_t 731 cm_calculate_oce_ap_tx_pwr_weightage(struct scan_cache_entry *entry, 732 struct scoring_cfg *score_params, 733 int8_t *ap_tx_pwr_dbm) 734 { 735 uint8_t *mbo_oce_ie, ap_tx_pwr_factor; 736 struct rssi_config_score *rssi_score_param; 737 int32_t best_rssi_threshold, good_rssi_threshold, bad_rssi_threshold; 738 uint32_t good_rssi_pcnt, bad_rssi_pcnt, good_bucket_size; 739 uint32_t score, normalized_ap_tx_pwr, bad_bucket_size; 740 bool ap_tx_pwr_cap_present = true; 741 742 mbo_oce_ie = util_scan_entry_mbo_oce(entry); 743 if (!wlan_parse_oce_ap_tx_pwr_ie(mbo_oce_ie, ap_tx_pwr_dbm)) { 744 ap_tx_pwr_cap_present = false; 745 /* If no OCE AP TX pwr, consider Uplink RSSI = Downlink RSSI */ 746 normalized_ap_tx_pwr = entry->rssi_raw; 747 } else { 748 /* 749 * Normalized ap_tx_pwr = 750 * Uplink RSSI = (STA TX Power - * (AP TX power - RSSI)) in dBm. 751 * Currently assuming STA Tx Power to be 20dBm, though later it 752 * need to fetched from hal-phy API. 753 */ 754 normalized_ap_tx_pwr = 755 (20 - (*ap_tx_pwr_dbm - entry->rssi_raw)); 756 } 757 758 rssi_score_param = &score_params->rssi_score; 759 760 best_rssi_threshold = rssi_score_param->best_rssi_threshold * (-1); 761 good_rssi_threshold = rssi_score_param->good_rssi_threshold * (-1); 762 bad_rssi_threshold = rssi_score_param->bad_rssi_threshold * (-1); 763 good_rssi_pcnt = rssi_score_param->good_rssi_pcnt; 764 bad_rssi_pcnt = rssi_score_param->bad_rssi_pcnt; 765 good_bucket_size = rssi_score_param->good_rssi_bucket_size; 766 bad_bucket_size = rssi_score_param->bad_rssi_bucket_size; 767 768 /* Uplink RSSI is better than best rssi threshold */ 769 if (normalized_ap_tx_pwr > best_rssi_threshold) { 770 ap_tx_pwr_factor = CM_MAX_PCT_SCORE; 771 } else if (normalized_ap_tx_pwr <= bad_rssi_threshold) { 772 /* Uplink RSSI is less or equal to bad rssi threshold */ 773 ap_tx_pwr_factor = rssi_score_param->bad_rssi_pcnt; 774 } else if (normalized_ap_tx_pwr > good_rssi_threshold) { 775 /* Uplink RSSI lies between best to good rssi threshold */ 776 ap_tx_pwr_factor = 777 cm_get_rssi_pcnt_for_slot( 778 best_rssi_threshold, 779 good_rssi_threshold, 100, 780 good_rssi_pcnt, 781 good_bucket_size, normalized_ap_tx_pwr); 782 } else { 783 /* Uplink RSSI lies between good to best rssi threshold */ 784 ap_tx_pwr_factor = 785 cm_get_rssi_pcnt_for_slot( 786 good_rssi_threshold, 787 bad_rssi_threshold, good_rssi_pcnt, 788 bad_rssi_pcnt, bad_bucket_size, 789 normalized_ap_tx_pwr); 790 } 791 792 score = score_params->weight_config.oce_ap_tx_pwr_weightage * 793 ap_tx_pwr_factor; 794 795 return score; 796 } 797 798 static bool cm_is_assoc_allowed(struct psoc_mlme_obj *mlme_psoc_obj, 799 struct scan_cache_entry *entry) 800 { 801 uint8_t reason; 802 uint8_t *mbo_oce; 803 bool check_assoc_disallowed; 804 805 mbo_oce = util_scan_entry_mbo_oce(entry); 806 807 check_assoc_disallowed = 808 mlme_psoc_obj->psoc_cfg.score_config.check_assoc_disallowed; 809 810 if (check_assoc_disallowed && 811 wlan_parse_oce_assoc_disallowed_ie(mbo_oce, &reason)) { 812 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d, assoc disallowed set in MBO/OCE IE reason %d", 813 QDF_MAC_ADDR_REF(entry->bssid.bytes), 814 entry->channel.chan_freq, 815 entry->rssi_raw, reason); 816 return false; 817 } 818 819 return true; 820 } 821 822 void wlan_cm_set_check_assoc_disallowed(struct wlan_objmgr_psoc *psoc, 823 bool value) 824 { 825 struct psoc_mlme_obj *mlme_psoc_obj; 826 827 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 828 if (!mlme_psoc_obj) 829 return; 830 831 mlme_psoc_obj->psoc_cfg.score_config.check_assoc_disallowed = value; 832 } 833 834 void wlan_cm_get_check_assoc_disallowed(struct wlan_objmgr_psoc *psoc, 835 bool *value) 836 { 837 struct psoc_mlme_obj *mlme_psoc_obj; 838 839 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 840 if (!mlme_psoc_obj) { 841 *value = false; 842 return; 843 } 844 845 *value = mlme_psoc_obj->psoc_cfg.score_config.check_assoc_disallowed; 846 } 847 848 static enum phy_ch_width 849 cm_calculate_bandwidth(struct scan_cache_entry *entry, 850 struct psoc_phy_config *phy_config) 851 { 852 uint8_t bw_above_20 = 0; 853 bool is_vht = false; 854 enum phy_ch_width ch_width; 855 856 if (WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) { 857 bw_above_20 = phy_config->bw_above_20_24ghz; 858 if (phy_config->vht_24G_cap) 859 is_vht = true; 860 } else if (phy_config->vht_cap) { 861 is_vht = true; 862 bw_above_20 = phy_config->bw_above_20_5ghz; 863 } 864 865 if (IS_WLAN_PHYMODE_160MHZ(entry->phy_mode)) 866 ch_width = CH_WIDTH_160MHZ; 867 else if (IS_WLAN_PHYMODE_80MHZ(entry->phy_mode)) 868 ch_width = CH_WIDTH_80MHZ; 869 else if (IS_WLAN_PHYMODE_40MHZ(entry->phy_mode)) 870 ch_width = CH_WIDTH_40MHZ; 871 else 872 ch_width = CH_WIDTH_20MHZ; 873 874 if (!phy_config->ht_cap && 875 ch_width >= CH_WIDTH_20MHZ) 876 ch_width = CH_WIDTH_20MHZ; 877 878 if (!is_vht && ch_width > CH_WIDTH_40MHZ) 879 ch_width = CH_WIDTH_40MHZ; 880 881 if (!bw_above_20) 882 ch_width = CH_WIDTH_20MHZ; 883 884 return ch_width; 885 } 886 887 static uint8_t cm_etp_get_ba_win_size_from_esp(uint8_t esp_ba_win_size) 888 { 889 /* 890 * BA Window Size subfield is three bits in length and indicates the 891 * size of the Block Ack window that is. 892 * 802.11-2016.pdf Table 9-262 BA Window Size subfield encoding 893 */ 894 switch (esp_ba_win_size) { 895 case 1: return 2; 896 case 2: return 4; 897 case 3: return 6; 898 case 4: return 8; 899 case 5: return 16; 900 case 6: return 32; 901 case 7: return 64; 902 default: return 1; 903 } 904 } 905 906 static uint16_t cm_get_etp_ntone(bool is_ht, bool is_vht, 907 enum phy_ch_width ch_width) 908 { 909 uint16_t n_sd = 52, n_seg = 1; 910 911 if (is_vht) { 912 /* Refer Table 21-5 in IEEE80211-2016 Spec */ 913 if (ch_width == CH_WIDTH_20MHZ) 914 n_sd = 52; 915 else if (ch_width == CH_WIDTH_40MHZ) 916 n_sd = 108; 917 else if (ch_width == CH_WIDTH_80MHZ) 918 n_sd = 234; 919 else if (ch_width == CH_WIDTH_80P80MHZ) 920 n_sd = 234, n_seg = 2; 921 else if (ch_width == CH_WIDTH_160MHZ) 922 n_sd = 468; 923 } else if (is_ht) { 924 /* Refer Table 19-6 in IEEE80211-2016 Spec */ 925 if (ch_width == CH_WIDTH_20MHZ) 926 n_sd = 52; 927 if (ch_width == CH_WIDTH_40MHZ) 928 n_sd = 108; 929 } else { 930 n_sd = 48; 931 } 932 933 return (n_sd * n_seg); 934 } 935 936 /* Refer Table 27-64 etc in Draft P802.11ax_D7.0.txt */ 937 static uint16_t cm_get_etp_he_ntone(enum phy_ch_width ch_width) 938 { 939 uint16_t n_sd = 234, n_seg = 1; 940 941 if (ch_width == CH_WIDTH_20MHZ) 942 n_sd = 234; 943 else if (ch_width == CH_WIDTH_40MHZ) 944 n_sd = 468; 945 else if (ch_width == CH_WIDTH_80MHZ) 946 n_sd = 980; 947 else if (ch_width == CH_WIDTH_80P80MHZ) 948 n_sd = 980, n_seg = 2; 949 else if (ch_width == CH_WIDTH_160MHZ) 950 n_sd = 1960; 951 952 return (n_sd * n_seg); 953 } 954 955 static uint16_t cm_get_etp_phy_header_dur_us(bool is_ht, bool is_vht, 956 uint8_t nss) 957 { 958 uint16_t dur_us = 0; 959 960 if (is_vht) { 961 /* 962 * Refer Figure 21-4 in 80211-2016 Spec 963 * 8 (L-STF) + 8 (L-LTF) + 4 (L-SIG) + 964 * 8 (VHT-SIG-A) + 4 (VHT-STF) + 4 (VHT-SIG-B) 965 */ 966 dur_us = 36; 967 /* (nss * VHT-LTF) = (nss * 4) */ 968 dur_us += (nss << 2); 969 } else if (is_ht) { 970 /* 971 * Refer Figure 19-1 in 80211-2016 Spec 972 * 8 (L-STF) + 8 (L-LTF) + 4 (L-SIG) + 8 (HT-SIG) + 973 * 4 (HT-STF) 974 */ 975 dur_us = 32; 976 /* (nss * HT-LTF = nss * 4) */ 977 dur_us += (nss << 2); 978 } else { 979 /* 980 * non-HT 981 * Refer Figure 19-1 in 80211-2016 Spec 982 * 8 (L-STF) + 8 (L-LTF) + 4 (L-SIG) 983 */ 984 dur_us = 20; 985 } 986 return dur_us; 987 } 988 989 static uint32_t 990 cm_get_etp_max_bits_per_sc_1000x_for_nss(struct wlan_objmgr_psoc *psoc, 991 struct scan_cache_entry *entry, 992 uint8_t nss, 993 struct psoc_phy_config *phy_config) 994 { 995 uint32_t max_bits_per_sc_1000x = 5000; /* 5 * 1000 */ 996 uint8_t mcs_map; 997 struct wlan_ie_vhtcaps *bss_vht_cap; 998 struct wlan_ie_hecaps *bss_he_cap; 999 uint32_t self_rx_mcs_map; 1000 QDF_STATUS status; 1001 1002 bss_vht_cap = (struct wlan_ie_vhtcaps *)util_scan_entry_vhtcap(entry); 1003 bss_he_cap = (struct wlan_ie_hecaps *)util_scan_entry_hecap(entry); 1004 if (!phy_config->vht_cap || !bss_vht_cap) { 1005 mlme_err("vht unsupported"); 1006 return max_bits_per_sc_1000x; 1007 } 1008 1009 status = wlan_mlme_cfg_get_vht_rx_mcs_map(psoc, &self_rx_mcs_map); 1010 if (QDF_IS_STATUS_ERROR(status)) 1011 return max_bits_per_sc_1000x; 1012 1013 if (nss == 4) { 1014 mcs_map = (self_rx_mcs_map & 0xC0) >> 6; 1015 mcs_map = QDF_MIN(mcs_map, 1016 (bss_vht_cap->rx_mcs_map & 0xC0) >> 6); 1017 } else if (nss == 3) { 1018 mcs_map = (self_rx_mcs_map & 0x30) >> 4; 1019 mcs_map = QDF_MIN(mcs_map, 1020 (bss_vht_cap->rx_mcs_map & 0x30) >> 4); 1021 } else if (nss == 2) { 1022 mcs_map = (self_rx_mcs_map & 0x0C) >> 2; 1023 mcs_map = QDF_MIN(mcs_map, 1024 (bss_vht_cap->rx_mcs_map & 0x0C) >> 2); 1025 } else { 1026 mcs_map = (self_rx_mcs_map & 0x03); 1027 mcs_map = QDF_MIN(mcs_map, (bss_vht_cap->rx_mcs_map & 0x03)); 1028 } 1029 if (bss_he_cap) { 1030 if (mcs_map == 2) 1031 max_bits_per_sc_1000x = 8333; /* 10 *5/6 * 1000 */ 1032 else if (mcs_map == 1) 1033 max_bits_per_sc_1000x = 7500; /* 10 * 3/4 * 1000 */ 1034 } else { 1035 if (mcs_map == 2) 1036 max_bits_per_sc_1000x = 6667; /* 8 * 5/6 * 1000 */ 1037 else if (mcs_map == 1) 1038 max_bits_per_sc_1000x = 6000; /* 8 * 3/4 * 1000 */ 1039 } 1040 return max_bits_per_sc_1000x; 1041 } 1042 1043 /* Refer Table 9-163 in 80211-2016 Spec */ 1044 static uint32_t cm_etp_get_min_mpdu_ss_us_100x(struct htcap_cmn_ie *htcap) 1045 { 1046 tSirMacHTParametersInfo *ampdu_param; 1047 uint8_t ampdu_density; 1048 1049 ampdu_param = (tSirMacHTParametersInfo *)&htcap->ampdu_param; 1050 ampdu_density = ampdu_param->mpduDensity; 1051 1052 if (ampdu_density == 1) 1053 return 25; /* (1/4) * 100 */ 1054 else if (ampdu_density == 2) 1055 return 50; /* (1/2) * 100 */ 1056 else if (ampdu_density == 3) 1057 return 100; /* 1 * 100 */ 1058 else if (ampdu_density == 4) 1059 return 200; /* 2 * 100 */ 1060 else if (ampdu_density == 5) 1061 return 400; /* 4 * 100 */ 1062 else if (ampdu_density == 6) 1063 return 800; /* 8 * 100 */ 1064 else if (ampdu_density == 7) 1065 return 1600; /* 16 * 100 */ 1066 else 1067 return 100; 1068 } 1069 1070 /* Refer Table 9-162 in 80211-2016 Spec */ 1071 static uint32_t cm_etp_get_max_amsdu_len(struct wlan_objmgr_psoc *psoc, 1072 struct htcap_cmn_ie *htcap) 1073 { 1074 uint8_t bss_max_amsdu; 1075 uint32_t bss_max_amsdu_len; 1076 QDF_STATUS status; 1077 1078 status = wlan_mlme_get_max_amsdu_num(psoc, &bss_max_amsdu); 1079 if (QDF_IS_STATUS_ERROR(status)) 1080 bss_max_amsdu_len = 3839; 1081 else if (bss_max_amsdu == 1) 1082 bss_max_amsdu_len = 7935; 1083 else 1084 bss_max_amsdu_len = 3839; 1085 1086 return bss_max_amsdu_len; 1087 } 1088 1089 // Calculate the number of bits per tone based on the input of SNR in dB 1090 // The output is scaled up by BIT_PER_TONE_SCALE for integer representation 1091 static uint32_t 1092 calculate_bit_per_tone(int32_t rssi, enum phy_ch_width ch_width) 1093 { 1094 int32_t noise_floor_db_boost; 1095 int32_t noise_floor_dbm; 1096 int32_t snr_db; 1097 int32_t bit_per_tone; 1098 int32_t lut_in_idx; 1099 1100 noise_floor_db_boost = TWO_IN_DB * ch_width; 1101 noise_floor_dbm = WLAN_NOISE_FLOOR_DBM_DEFAULT + noise_floor_db_boost + 1102 SNR_MARGIN_DB; 1103 snr_db = rssi - noise_floor_dbm; 1104 if (snr_db <= SNR_DB_TO_BIT_PER_TONE_LUT_MAX) { 1105 lut_in_idx = QDF_MAX(snr_db, SNR_DB_TO_BIT_PER_TONE_LUT_MIN) 1106 - SNR_DB_TO_BIT_PER_TONE_LUT_MIN; 1107 lut_in_idx = QDF_MIN(lut_in_idx, DB_NUM - 1); 1108 bit_per_tone = SNR_DB_TO_BIT_PER_TONE_LUT[lut_in_idx]; 1109 } else { 1110 /* 1111 * SNR_tone = 10^(SNR/10) 1112 * log2(1+SNR_tone) ~= log2(SNR_tone) = 1113 * log10(SNR_tone)/log10(2) = log10(10^(SNR/10)) / 0.3 1114 * = (SNR/10) / 0.3 = SNR/3 1115 * So log2(1+SNR_tone) = SNR/3. 1000x for this is SNR*334 1116 */ 1117 bit_per_tone = snr_db * 334; 1118 } 1119 1120 return bit_per_tone; 1121 } 1122 1123 static uint32_t 1124 cm_calculate_etp(struct wlan_objmgr_psoc *psoc, 1125 struct scan_cache_entry *entry, 1126 struct etp_params *etp_param, 1127 uint8_t max_nss, enum phy_ch_width ch_width, 1128 bool is_ht, bool is_vht, bool is_he, 1129 int8_t rssi, 1130 struct psoc_phy_config *phy_config) 1131 { 1132 uint16_t ntone; 1133 uint16_t phy_hdr_dur_us, max_amsdu_len = 1500, min_mpdu_ss_us_100x = 0; 1134 uint32_t max_bits_per_sc_1000x, log_2_snr_tone_1000x; 1135 uint32_t ppdu_payload_dur_us = 0, mpdu_per_ampdu, mpdu_per_ppdu; 1136 uint32_t single_ppdu_dur_us, estimated_throughput_mbps, data_rate_kbps; 1137 struct htcap_cmn_ie *htcap; 1138 1139 htcap = (struct htcap_cmn_ie *)util_scan_entry_htcap(entry); 1140 if (ch_width > CH_WIDTH_160MHZ) 1141 return CM_AVOID_CANDIDATE_MIN_SCORE; 1142 1143 if (is_he) 1144 ntone = cm_get_etp_he_ntone(ch_width); 1145 else 1146 ntone = cm_get_etp_ntone(is_ht, is_vht, ch_width); 1147 phy_hdr_dur_us = cm_get_etp_phy_header_dur_us(is_ht, is_vht, max_nss); 1148 1149 max_bits_per_sc_1000x = 1150 cm_get_etp_max_bits_per_sc_1000x_for_nss(psoc, entry, 1151 max_nss, phy_config); 1152 if (rssi < WLAN_NOISE_FLOOR_DBM_DEFAULT) 1153 return CM_AVOID_CANDIDATE_MIN_SCORE; 1154 1155 log_2_snr_tone_1000x = calculate_bit_per_tone(rssi, ch_width); 1156 1157 /* Eq. R-2 Pg:3508 in 80211-2016 Spec */ 1158 if (is_he) 1159 data_rate_kbps = 1160 QDF_MIN(log_2_snr_tone_1000x, max_bits_per_sc_1000x) * 1161 (max_nss * ntone) / HE_PPDU_PAYLOAD_SYMBOL_DUR_US; 1162 else 1163 data_rate_kbps = 1164 QDF_MIN(log_2_snr_tone_1000x, max_bits_per_sc_1000x) * 1165 (max_nss * ntone) / PPDU_PAYLOAD_SYMBOL_DUR_US; 1166 mlme_debug("data_rate_kbps: %d", data_rate_kbps); 1167 if (data_rate_kbps < 1000) { 1168 /* Return ETP as 1 since datarate is not even 1 Mbps */ 1169 return CM_AVOID_CANDIDATE_MIN_SCORE; 1170 } 1171 /* compute MPDU_p_PPDU */ 1172 if (is_ht) { 1173 min_mpdu_ss_us_100x = 1174 cm_etp_get_min_mpdu_ss_us_100x(htcap); 1175 max_amsdu_len = 1176 cm_etp_get_max_amsdu_len(psoc, htcap); 1177 ppdu_payload_dur_us = 1178 etp_param->data_ppdu_dur_target_us - phy_hdr_dur_us; 1179 mpdu_per_ampdu = 1180 QDF_MIN(qdf_ceil(ppdu_payload_dur_us * 100, 1181 min_mpdu_ss_us_100x), 1182 qdf_ceil(ppdu_payload_dur_us * 1183 (data_rate_kbps / 1000), 1184 (MAC_HEADER_LEN + max_amsdu_len) * 8)); 1185 mpdu_per_ppdu = QDF_MIN(etp_param->ba_window_size, 1186 QDF_MAX(1, mpdu_per_ampdu)); 1187 } else { 1188 mpdu_per_ppdu = 1; 1189 } 1190 1191 /* compute PPDU_Dur */ 1192 single_ppdu_dur_us = 1193 qdf_ceil((MAC_HEADER_LEN + max_amsdu_len) * mpdu_per_ppdu * 8, 1194 (data_rate_kbps / 1000) * PPDU_PAYLOAD_SYMBOL_DUR_US); 1195 single_ppdu_dur_us *= PPDU_PAYLOAD_SYMBOL_DUR_US; 1196 single_ppdu_dur_us += phy_hdr_dur_us; 1197 1198 estimated_throughput_mbps = 1199 qdf_ceil(mpdu_per_ppdu * max_amsdu_len * 8, single_ppdu_dur_us); 1200 estimated_throughput_mbps = 1201 (estimated_throughput_mbps * 1202 etp_param->airtime_fraction) / 1203 CM_MAX_ESTIMATED_AIR_TIME_FRACTION; 1204 1205 if (estimated_throughput_mbps < CM_AVOID_CANDIDATE_MIN_SCORE) 1206 estimated_throughput_mbps = CM_AVOID_CANDIDATE_MIN_SCORE; 1207 if (estimated_throughput_mbps > CM_BEST_CANDIDATE_MAX_BSS_SCORE) 1208 estimated_throughput_mbps = CM_BEST_CANDIDATE_MAX_BSS_SCORE; 1209 1210 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d HT %d VHT %d HE %d ATF: %d NSS %d, ch_width: %d", 1211 QDF_MAC_ADDR_REF(entry->bssid.bytes), 1212 entry->channel.chan_freq, 1213 entry->rssi_raw, is_ht, is_vht, is_he, 1214 etp_param->airtime_fraction, 1215 entry->nss, ch_width); 1216 if (is_ht) 1217 mlme_nofl_debug("min_mpdu_ss_us_100x = %d, max_amsdu_len = %d, ppdu_payload_dur_us = %d, mpdu_per_ampdu = %d, mpdu_per_ppdu = %d, ba_window_size = %d", 1218 min_mpdu_ss_us_100x, max_amsdu_len, 1219 ppdu_payload_dur_us, mpdu_per_ampdu, 1220 mpdu_per_ppdu, etp_param->ba_window_size); 1221 mlme_nofl_debug("ETP score params: ntone: %d, phy_hdr_dur_us: %d, max_bits_per_sc_1000x: %d, log_2_snr_tone_1000x: %d mpdu_p_ppdu = %d, max_amsdu_len = %d, ppdu_dur_us = %d, total score = %d", 1222 ntone, phy_hdr_dur_us, max_bits_per_sc_1000x, 1223 log_2_snr_tone_1000x, mpdu_per_ppdu, max_amsdu_len, 1224 single_ppdu_dur_us, estimated_throughput_mbps); 1225 1226 return estimated_throughput_mbps; 1227 } 1228 1229 static uint32_t 1230 cm_calculate_etp_score(struct wlan_objmgr_psoc *psoc, 1231 struct scan_cache_entry *entry, 1232 struct psoc_phy_config *phy_config) 1233 { 1234 enum phy_ch_width ch_width; 1235 uint32_t nss; 1236 bool is_he_intersect = false; 1237 bool is_vht_intersect = false; 1238 bool is_ht_intersect = false; 1239 struct wlan_esp_info *esp; 1240 struct wlan_esp_ie *esp_ie; 1241 struct etp_params etp_param; 1242 1243 if (phy_config->he_cap && entry->ie_list.hecap) 1244 is_he_intersect = true; 1245 if ((phy_config->vht_cap || phy_config->vht_24G_cap) && 1246 (entry->ie_list.vhtcap || 1247 WLAN_REG_IS_6GHZ_CHAN_FREQ(entry->channel.chan_freq))) 1248 is_vht_intersect = true; 1249 if (phy_config->ht_cap && entry->ie_list.htcap) 1250 is_ht_intersect = true; 1251 nss = cm_get_sta_nss(psoc, entry->channel.chan_freq, 1252 phy_config->vdev_nss_24g, 1253 phy_config->vdev_nss_5g); 1254 nss = QDF_MIN(nss, entry->nss); 1255 ch_width = cm_calculate_bandwidth(entry, phy_config); 1256 1257 /* Initialize default ETP params */ 1258 etp_param.airtime_fraction = 255 / 2; 1259 etp_param.ba_window_size = 32; 1260 etp_param.data_ppdu_dur_target_us = 5000; /* 5 msec */ 1261 1262 if (entry->air_time_fraction) { 1263 etp_param.airtime_fraction = entry->air_time_fraction; 1264 esp_ie = (struct wlan_esp_ie *) 1265 util_scan_entry_esp_info(entry); 1266 if (esp_ie) { 1267 esp = &esp_ie->esp_info_AC_BE; 1268 etp_param.ba_window_size = 1269 cm_etp_get_ba_win_size_from_esp(esp->ba_window_size); 1270 etp_param.data_ppdu_dur_target_us = 1271 50 * esp->ppdu_duration; 1272 mlme_debug("esp ba_window_size: %d, ppdu_duration: %d", 1273 esp->ba_window_size, esp->ppdu_duration); 1274 } 1275 } else if (entry->qbss_chan_load) { 1276 mlme_debug("qbss_chan_load: %d", entry->qbss_chan_load); 1277 etp_param.airtime_fraction = 1278 CM_MAX_ESTIMATED_AIR_TIME_FRACTION - 1279 entry->qbss_chan_load; 1280 } 1281 /* If ini vendor_roam_score_algorithm=1, just calculate ETP of all 1282 * bssid of ssid selected by high layer, and try to connect AP by 1283 * order of ETP, legacy algorithm with following Parameters/Weightage 1284 * becomes useless. ETP should be [1Mbps, 20000Mbps],matches score 1285 * range: [1, 20000] 1286 */ 1287 return cm_calculate_etp(psoc, entry, 1288 &etp_param, 1289 nss, 1290 ch_width, 1291 is_ht_intersect, 1292 is_vht_intersect, 1293 is_he_intersect, 1294 entry->rssi_raw, 1295 phy_config); 1296 } 1297 #else 1298 static bool 1299 cm_get_pcl_weight_of_channel(uint32_t chan_freq, 1300 struct pcl_freq_weight_list *pcl_lst, 1301 int *pcl_chan_weight) 1302 { 1303 return false; 1304 } 1305 1306 static int32_t cm_calculate_pcl_score(struct wlan_objmgr_psoc *psoc, 1307 int pcl_chan_weight, 1308 uint8_t pcl_weightage) 1309 { 1310 return 0; 1311 } 1312 1313 static int32_t cm_calculate_oce_wan_score(struct scan_cache_entry *entry, 1314 struct scoring_cfg *score_params) 1315 { 1316 return 0; 1317 } 1318 1319 static uint32_t 1320 cm_calculate_oce_subnet_id_weightage(struct scan_cache_entry *entry, 1321 struct scoring_cfg *score_params, 1322 bool *oce_subnet_id_present) 1323 { 1324 return 0; 1325 } 1326 1327 static uint32_t 1328 cm_calculate_sae_pk_ap_weightage(struct scan_cache_entry *entry, 1329 struct scoring_cfg *score_params, 1330 bool *sae_pk_cap_present) 1331 { 1332 return 0; 1333 } 1334 1335 static uint32_t 1336 cm_calculate_oce_ap_tx_pwr_weightage(struct scan_cache_entry *entry, 1337 struct scoring_cfg *score_params, 1338 int8_t *ap_tx_pwr_dbm) 1339 { 1340 return 0; 1341 } 1342 1343 static inline bool cm_is_assoc_allowed(struct psoc_mlme_obj *mlme_psoc_obj, 1344 struct scan_cache_entry *entry) 1345 { 1346 return true; 1347 } 1348 1349 static uint32_t 1350 cm_calculate_etp_score(struct wlan_objmgr_psoc *psoc, 1351 struct scan_cache_entry *entry, 1352 struct psoc_phy_config *phy_config) 1353 { 1354 return 0; 1355 } 1356 #endif 1357 1358 /** 1359 * cm_get_band_score() - Get band prefernce weightage 1360 * freq: Operating frequency of the AP 1361 * @score_config: Score configuration 1362 * 1363 * Return: Band score for AP. 1364 */ 1365 static int 1366 cm_get_band_score(uint32_t freq, struct scoring_cfg *score_config) 1367 { 1368 uint8_t band_index; 1369 struct weight_cfg *weight_config; 1370 1371 weight_config = &score_config->weight_config; 1372 1373 if (WLAN_REG_IS_5GHZ_CH_FREQ(freq)) 1374 band_index = CM_BAND_5G_INDEX; 1375 else if (WLAN_REG_IS_24GHZ_CH_FREQ(freq)) 1376 band_index = CM_BAND_2G_INDEX; 1377 else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(freq)) 1378 band_index = CM_BAND_6G_INDEX; 1379 else 1380 return 0; 1381 1382 return weight_config->chan_band_weightage * 1383 CM_GET_SCORE_PERCENTAGE(score_config->band_weight_per_index, 1384 band_index); 1385 } 1386 1387 #ifdef WLAN_FEATURE_11BE_MLO 1388 static int8_t cm_get_partner_link_rssi(struct scan_cache_entry *entry, 1389 uint8_t link_idx) 1390 { 1391 /* TODO: Get RSSI from partner bracon/derive from ML IE*/ 1392 return entry->rssi_raw; 1393 } 1394 1395 static uint8_t cm_get_parter_link_index(struct scan_cache_entry *entry) 1396 { 1397 /* TODO: Return best partner link index from entry->ml_info 1398 * or 1399 * take decision to calculate score for all possible combinations. 1400 * example: if the entry is a 2G beacon of 3-link AP then calculate 1401 * scores for 2G+5G & 2G+6G ML 1402 */ 1403 return 0; 1404 } 1405 1406 static int8_t cm_get_joint_rssi(struct scan_cache_entry *entry, 1407 struct weight_cfg *weight_config, 1408 uint8_t link_idx) 1409 { 1410 int8_t low_band_rssi; 1411 int8_t high_band_rssi; 1412 uint8_t alpha = weight_config->joint_rssi_alpha; 1413 1414 if (entry->channel.chan_freq < 1415 entry->ml_info.link_info[link_idx].freq) { 1416 low_band_rssi = entry->rssi_raw; 1417 high_band_rssi = cm_get_partner_link_rssi(entry, link_idx); 1418 } else { 1419 low_band_rssi = cm_get_partner_link_rssi(entry, link_idx); 1420 high_band_rssi = entry->rssi_raw; 1421 } 1422 1423 if (((alpha < 50) && (weight_config->low_band_rssi_boost)) || 1424 ((alpha > 50) && (!weight_config->low_band_rssi_boost))) 1425 alpha = 100 - alpha; 1426 1427 return ((low_band_rssi * alpha) + 1428 (high_band_rssi * (100 - alpha))) / 100; 1429 } 1430 1431 static int cm_calculate_eht_score(struct scan_cache_entry *entry, 1432 struct scoring_cfg *score_config, 1433 struct psoc_phy_config *phy_config) 1434 { 1435 uint32_t eht_caps_score; 1436 uint32_t mlo_score; 1437 uint32_t joint_rssi_score = 0; 1438 /* TODO: calculate joint OCE/ESP score using ML_IE/Partner beacon */ 1439 uint32_t joint_esp_score = 0; 1440 uint32_t joint_oce_score = 0; 1441 uint32_t wlm_indication_score = 0; 1442 uint32_t mlsr_score = 0; 1443 uint32_t emlsr_score = 0; 1444 uint8_t prorated_pcnt; 1445 int8_t joint_rssi; 1446 struct weight_cfg *weight_config; 1447 uint8_t partner_link_idx = cm_get_parter_link_index(entry); 1448 1449 if (!phy_config->eht_cap || !entry->ie_list.ehtcap) 1450 return 0; 1451 1452 /* TODO: get partner entry and return ml_score for that if it is 1453 * non-zero 1454 */ 1455 1456 weight_config = &score_config->weight_config; 1457 1458 joint_rssi = cm_get_joint_rssi(entry, weight_config, partner_link_idx); 1459 1460 joint_rssi_score = cm_calculate_rssi_score( 1461 &score_config->rssi_score, joint_rssi, 1462 weight_config->rssi_weightage); 1463 1464 prorated_pcnt = cm_roam_calculate_prorated_pcnt_by_rssi( 1465 &score_config->rssi_score, joint_rssi, 1466 weight_config->rssi_weightage); 1467 1468 eht_caps_score = prorated_pcnt * weight_config->eht_caps_weightage; 1469 mlo_score = prorated_pcnt * weight_config->mlo_weightage; 1470 1471 mlme_nofl_debug("EHT Scores: eht_caps_score:%d mlo_score:%d joint_rssi_score:%d joint_esp_score:%d joint_oce_score:%d wlm_indication_score:%d mlsr_score:%d emlsr_score:%d", 1472 eht_caps_score, mlo_score, joint_rssi_score, 1473 joint_esp_score, joint_oce_score, wlm_indication_score, 1474 mlsr_score, emlsr_score); 1475 1476 entry->ml_info.ml_bss_score = eht_caps_score + mlo_score + 1477 joint_rssi_score + joint_esp_score + 1478 joint_oce_score + wlm_indication_score + 1479 mlsr_score + emlsr_score; 1480 1481 return entry->ml_info.ml_bss_score; 1482 } 1483 1484 static int32_t 1485 cm_calculate_raw_rssi_score(struct rssi_config_score *score_param, 1486 int32_t rssi, uint8_t rssi_weightage) 1487 { 1488 return 0; 1489 } 1490 #else 1491 static int cm_calculate_eht_score(struct scan_cache_entry *entry, 1492 struct scoring_cfg *score_config, 1493 struct psoc_phy_config *phy_config) 1494 { 1495 return 0; 1496 } 1497 1498 static int32_t 1499 cm_calculate_raw_rssi_score(struct rssi_config_score *score_param, 1500 int32_t rssi, uint8_t rssi_weightage) 1501 { 1502 return cm_calculate_rssi_score(score_param, rssi, rssi_weightage); 1503 } 1504 #endif 1505 1506 static int cm_calculate_bss_score(struct wlan_objmgr_psoc *psoc, 1507 struct scan_cache_entry *entry, 1508 int pcl_chan_weight, 1509 struct qdf_mac_addr *bssid_hint) 1510 { 1511 int32_t score = 0; 1512 int32_t rssi_score = 0; 1513 int32_t pcl_score = 0; 1514 int32_t ht_score = 0; 1515 int32_t vht_score = 0; 1516 int32_t he_score = 0; 1517 int32_t bandwidth_score = 0; 1518 int32_t beamformee_score = 0; 1519 int32_t band_score = 0; 1520 int32_t nss_score = 0; 1521 int32_t congestion_score = 0; 1522 int32_t congestion_pct = 0; 1523 int32_t oce_wan_score = 0; 1524 uint8_t oce_ap_tx_pwr_score = 0; 1525 uint8_t oce_subnet_id_score = 0; 1526 uint32_t sae_pk_score = 0; 1527 bool oce_subnet_id_present = 0; 1528 bool sae_pk_cap_present = 0; 1529 int8_t ap_tx_pwr_dbm = 0; 1530 uint8_t prorated_pcnt; 1531 bool is_vht = false; 1532 int8_t good_rssi_threshold; 1533 int8_t rssi_pref_5g_rssi_thresh; 1534 bool same_bucket = false; 1535 bool ap_su_beam_former = false; 1536 struct wlan_ie_vhtcaps *vht_cap; 1537 struct scoring_cfg *score_config; 1538 struct weight_cfg *weight_config; 1539 uint32_t sta_nss; 1540 struct psoc_mlme_obj *mlme_psoc_obj; 1541 struct psoc_phy_config *phy_config; 1542 uint32_t eht_score; 1543 1544 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 1545 if (!mlme_psoc_obj) 1546 return 0; 1547 1548 phy_config = &mlme_psoc_obj->psoc_cfg.phy_config; 1549 score_config = &mlme_psoc_obj->psoc_cfg.score_config; 1550 weight_config = &score_config->weight_config; 1551 1552 if (score_config->is_bssid_hint_priority && bssid_hint && 1553 qdf_is_macaddr_equal(bssid_hint, &entry->bssid)) { 1554 entry->bss_score = CM_BEST_CANDIDATE_MAX_BSS_SCORE; 1555 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d BSSID hint given, give max score %d", 1556 QDF_MAC_ADDR_REF(entry->bssid.bytes), 1557 entry->channel.chan_freq, 1558 entry->rssi_raw, 1559 CM_BEST_CANDIDATE_MAX_BSS_SCORE); 1560 return CM_BEST_CANDIDATE_MAX_BSS_SCORE; 1561 } 1562 if (score_config->vendor_roam_score_algorithm) { 1563 score = cm_calculate_etp_score(psoc, entry, phy_config); 1564 entry->bss_score = score; 1565 return score; 1566 } 1567 rssi_score = cm_calculate_raw_rssi_score(&score_config->rssi_score, 1568 entry->rssi_raw, 1569 weight_config->rssi_weightage); 1570 score += rssi_score; 1571 1572 pcl_score = cm_calculate_pcl_score(psoc, pcl_chan_weight, 1573 weight_config->pcl_weightage); 1574 score += pcl_score; 1575 1576 prorated_pcnt = cm_roam_calculate_prorated_pcnt_by_rssi( 1577 &score_config->rssi_score, entry->rssi_raw, 1578 weight_config->rssi_weightage); 1579 1580 /* 1581 * Add HT weight if HT is supported by the AP. In case 1582 * of 6 GHZ AP, HT and VHT won't be supported so that 1583 * these weightage to the same by default to match 1584 * with 2.4/5 GHZ APs where HT, VHT is supported 1585 */ 1586 if (phy_config->ht_cap && (entry->ie_list.htcap || 1587 WLAN_REG_IS_6GHZ_CHAN_FREQ(entry->channel.chan_freq))) 1588 ht_score = prorated_pcnt * 1589 weight_config->ht_caps_weightage; 1590 score += ht_score; 1591 1592 if (WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) { 1593 if (phy_config->vht_24G_cap) 1594 is_vht = true; 1595 } else if (phy_config->vht_cap) { 1596 is_vht = true; 1597 } 1598 1599 /* Add VHT score to 6 GHZ AP to match with 2.4/5 GHZ APs */ 1600 if (is_vht && (entry->ie_list.vhtcap || 1601 WLAN_REG_IS_6GHZ_CHAN_FREQ(entry->channel.chan_freq))) 1602 vht_score = prorated_pcnt * 1603 weight_config->vht_caps_weightage; 1604 score += vht_score; 1605 1606 if (phy_config->he_cap && entry->ie_list.hecap) 1607 he_score = prorated_pcnt * 1608 weight_config->he_caps_weightage; 1609 score += he_score; 1610 1611 bandwidth_score = cm_calculate_bandwidth_score(entry, score_config, 1612 phy_config, 1613 prorated_pcnt); 1614 score += bandwidth_score; 1615 1616 good_rssi_threshold = 1617 score_config->rssi_score.good_rssi_threshold * (-1); 1618 rssi_pref_5g_rssi_thresh = 1619 score_config->rssi_score.rssi_pref_5g_rssi_thresh * (-1); 1620 if (entry->rssi_raw < good_rssi_threshold) 1621 same_bucket = cm_rssi_is_same_bucket(good_rssi_threshold, 1622 entry->rssi_raw, rssi_pref_5g_rssi_thresh, 1623 score_config->rssi_score.bad_rssi_bucket_size); 1624 1625 vht_cap = (struct wlan_ie_vhtcaps *)util_scan_entry_vhtcap(entry); 1626 if (vht_cap && vht_cap->su_beam_former) 1627 ap_su_beam_former = true; 1628 if (phy_config->beamformee_cap && is_vht && 1629 ap_su_beam_former && 1630 (entry->rssi_raw > rssi_pref_5g_rssi_thresh) && !same_bucket) 1631 beamformee_score = CM_MAX_PCT_SCORE * 1632 weight_config->beamforming_cap_weightage; 1633 score += beamformee_score; 1634 1635 congestion_score = cm_calculate_congestion_score(entry, score_config, 1636 &congestion_pct); 1637 score += congestion_score; 1638 /* 1639 * Consider OCE WAN score and band preference score only if 1640 * congestion_pct is greater than CONGESTION_THRSHOLD_FOR_BAND_OCE_SCORE 1641 */ 1642 if (congestion_pct < CM_CONGESTION_THRSHOLD_FOR_BAND_OCE_SCORE) { 1643 /* 1644 * If AP is on 5/6 GHZ channel , extra weigtage is added to BSS 1645 * score. if RSSI is greater tha 5g rssi threshold or fall in 1646 * same bucket else give weigtage to 2.4 GHZ AP. 1647 */ 1648 if ((entry->rssi_raw > rssi_pref_5g_rssi_thresh) && 1649 !same_bucket) { 1650 if (!WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) 1651 band_score = cm_get_band_score( 1652 entry->channel.chan_freq, 1653 score_config); 1654 } else if (WLAN_REG_IS_24GHZ_CH_FREQ( 1655 entry->channel.chan_freq)) { 1656 band_score = cm_get_band_score(entry->channel.chan_freq, 1657 score_config); 1658 } 1659 score += band_score; 1660 1661 oce_wan_score = cm_calculate_oce_wan_score(entry, score_config); 1662 score += oce_wan_score; 1663 } 1664 1665 oce_ap_tx_pwr_score = 1666 cm_calculate_oce_ap_tx_pwr_weightage(entry, score_config, 1667 &ap_tx_pwr_dbm); 1668 score += oce_ap_tx_pwr_score; 1669 1670 oce_subnet_id_score = cm_calculate_oce_subnet_id_weightage(entry, 1671 score_config, 1672 &oce_subnet_id_present); 1673 score += oce_subnet_id_score; 1674 1675 sae_pk_score = cm_calculate_sae_pk_ap_weightage(entry, score_config, 1676 &sae_pk_cap_present); 1677 score += sae_pk_score; 1678 1679 sta_nss = cm_get_sta_nss(psoc, entry->channel.chan_freq, 1680 phy_config->vdev_nss_24g, 1681 phy_config->vdev_nss_5g); 1682 1683 /* 1684 * If station support nss as 2*2 but AP support NSS as 1*1, 1685 * this AP will be given half weight compare to AP which are having 1686 * NSS as 2*2. 1687 */ 1688 nss_score = cm_calculate_nss_score(psoc, score_config, entry->nss, 1689 prorated_pcnt, sta_nss); 1690 score += nss_score; 1691 1692 eht_score = cm_calculate_eht_score(entry, score_config, phy_config); 1693 1694 score += eht_score; 1695 1696 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d HT %d VHT %d HE %d su bfer %d phy %d air time frac %d qbss %d cong_pct %d NSS %d ap_tx_pwr_dbm %d oce_subnet_id_present %d sae_pk_cap_present %d prorated_pcnt %d", 1697 QDF_MAC_ADDR_REF(entry->bssid.bytes), 1698 entry->channel.chan_freq, 1699 entry->rssi_raw, util_scan_entry_htcap(entry) ? 1 : 0, 1700 util_scan_entry_vhtcap(entry) ? 1 : 0, 1701 util_scan_entry_hecap(entry) ? 1 : 0, ap_su_beam_former, 1702 entry->phy_mode, entry->air_time_fraction, 1703 entry->qbss_chan_load, congestion_pct, entry->nss, 1704 ap_tx_pwr_dbm, oce_subnet_id_present, 1705 sae_pk_cap_present, prorated_pcnt); 1706 1707 mlme_nofl_debug("Scores: rssi %d pcl %d ht %d vht %d he %d bfee %d bw %d band %d congestion %d nss %d oce wan %d oce ap tx pwr %d subnet %d sae_pk %d eht %d TOTAL %d", 1708 rssi_score, pcl_score, ht_score, 1709 vht_score, he_score, beamformee_score, bandwidth_score, 1710 band_score, congestion_score, nss_score, oce_wan_score, 1711 oce_ap_tx_pwr_score, oce_subnet_id_score, 1712 sae_pk_score, eht_score, score); 1713 1714 entry->bss_score = score; 1715 1716 return score; 1717 } 1718 1719 static void cm_list_insert_sorted(qdf_list_t *scan_list, 1720 struct scan_cache_node *scan_entry) 1721 { 1722 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1723 struct scan_cache_node *curr_entry; 1724 1725 qdf_list_peek_front(scan_list, &cur_node); 1726 while (cur_node) { 1727 curr_entry = qdf_container_of(cur_node, struct scan_cache_node, 1728 node); 1729 if (cm_is_better_bss(scan_entry->entry, curr_entry->entry)) { 1730 qdf_list_insert_before(scan_list, &scan_entry->node, 1731 &curr_entry->node); 1732 break; 1733 } 1734 qdf_list_peek_next(scan_list, cur_node, &next_node); 1735 cur_node = next_node; 1736 next_node = NULL; 1737 } 1738 1739 if (!cur_node) 1740 qdf_list_insert_back(scan_list, &scan_entry->node); 1741 } 1742 1743 void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev, 1744 struct pcl_freq_weight_list *pcl_lst, 1745 qdf_list_t *scan_list, 1746 struct qdf_mac_addr *bssid_hint) 1747 { 1748 struct scan_cache_node *scan_entry; 1749 qdf_list_node_t *cur_node = NULL, *next_node = NULL; 1750 struct psoc_mlme_obj *mlme_psoc_obj; 1751 struct scoring_cfg *score_config; 1752 int pcl_chan_weight; 1753 QDF_STATUS status; 1754 struct psoc_phy_config *config; 1755 enum cm_blacklist_action blacklist_action; 1756 struct wlan_objmgr_psoc *psoc; 1757 bool assoc_allowed; 1758 struct scan_cache_node *force_connect_candidate = NULL; 1759 bool are_all_candidate_blacklisted = true; 1760 1761 psoc = wlan_pdev_get_psoc(pdev); 1762 1763 if (!psoc) { 1764 mlme_err("psoc NULL"); 1765 return; 1766 } 1767 if (!scan_list) { 1768 mlme_err("Scan list NULL"); 1769 return; 1770 } 1771 1772 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 1773 if (!mlme_psoc_obj) 1774 return; 1775 1776 score_config = &mlme_psoc_obj->psoc_cfg.score_config; 1777 config = &mlme_psoc_obj->psoc_cfg.phy_config; 1778 1779 mlme_nofl_debug("Self caps: HT %d VHT %d HE %d VHT_24Ghz %d BF cap %d bw_above_20_24ghz %d bw_above_20_5ghz %d 2.4G NSS %d 5G NSS %d", 1780 config->ht_cap, config->vht_cap, 1781 config->he_cap, config->vht_24G_cap, 1782 config->beamformee_cap, config->bw_above_20_24ghz, 1783 config->bw_above_20_5ghz, config->vdev_nss_24g, 1784 config->vdev_nss_5g); 1785 1786 /* calculate score for each AP */ 1787 if (qdf_list_peek_front(scan_list, &cur_node) != QDF_STATUS_SUCCESS) { 1788 mlme_err("failed to peer front of scan list"); 1789 return; 1790 } 1791 1792 while (cur_node) { 1793 qdf_list_peek_next(scan_list, cur_node, &next_node); 1794 pcl_chan_weight = 0; 1795 scan_entry = qdf_container_of(cur_node, struct scan_cache_node, 1796 node); 1797 1798 assoc_allowed = cm_is_assoc_allowed(mlme_psoc_obj, 1799 scan_entry->entry); 1800 1801 if (assoc_allowed) 1802 blacklist_action = wlan_blacklist_action_on_bssid(pdev, 1803 scan_entry->entry); 1804 else 1805 blacklist_action = CM_BLM_FORCE_REMOVE; 1806 1807 if (blacklist_action == CM_BLM_NO_ACTION || 1808 blacklist_action == CM_BLM_AVOID) 1809 are_all_candidate_blacklisted = false; 1810 1811 if (blacklist_action == CM_BLM_NO_ACTION && 1812 pcl_lst && pcl_lst->num_of_pcl_channels && 1813 scan_entry->entry->rssi_raw > CM_PCL_RSSI_THRESHOLD && 1814 score_config->weight_config.pcl_weightage) { 1815 if (cm_get_pcl_weight_of_channel( 1816 scan_entry->entry->channel.chan_freq, 1817 pcl_lst, &pcl_chan_weight)) { 1818 mlme_debug("pcl freq %d pcl_chan_weight %d", 1819 scan_entry->entry->channel.chan_freq, 1820 pcl_chan_weight); 1821 } 1822 } 1823 1824 if (blacklist_action == CM_BLM_NO_ACTION || 1825 (are_all_candidate_blacklisted && blacklist_action == CM_BLM_REMOVE)) { 1826 cm_calculate_bss_score(psoc, scan_entry->entry, 1827 pcl_chan_weight, bssid_hint); 1828 } else if (blacklist_action == CM_BLM_AVOID) { 1829 /* add min score so that it is added back in the end */ 1830 scan_entry->entry->bss_score = 1831 CM_AVOID_CANDIDATE_MIN_SCORE; 1832 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d, is in Avoidlist, give min score %d", 1833 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes), 1834 scan_entry->entry->channel.chan_freq, 1835 scan_entry->entry->rssi_raw, 1836 scan_entry->entry->bss_score); 1837 } 1838 1839 /* 1840 * The below logic is added to select the best candidate 1841 * amongst the blacklisted candidates. This is done to 1842 * handle a case where all the BSSIDs become blacklisted 1843 * and hence there are continuous connection failures. 1844 * With the below logic if the action on BSSID is to remove 1845 * then we keep a backup node and restore the candidate 1846 * list. 1847 */ 1848 if (blacklist_action == CM_BLM_REMOVE && 1849 are_all_candidate_blacklisted) { 1850 if (!force_connect_candidate) { 1851 force_connect_candidate = 1852 qdf_mem_malloc( 1853 sizeof(*force_connect_candidate)); 1854 if (!force_connect_candidate) 1855 return; 1856 force_connect_candidate->entry = 1857 util_scan_copy_cache_entry(scan_entry->entry); 1858 if (!force_connect_candidate->entry) 1859 return; 1860 } else if (cm_is_better_bss( 1861 scan_entry->entry, 1862 force_connect_candidate->entry)) { 1863 util_scan_free_cache_entry( 1864 force_connect_candidate->entry); 1865 force_connect_candidate->entry = 1866 util_scan_copy_cache_entry(scan_entry->entry); 1867 if (!force_connect_candidate->entry) 1868 return; 1869 } 1870 } 1871 1872 /* Remove node from current location to add node back sorted */ 1873 status = qdf_list_remove_node(scan_list, cur_node); 1874 if (QDF_IS_STATUS_ERROR(status)) { 1875 mlme_err("failed to remove node for BSS "QDF_MAC_ADDR_FMT" from scan list", 1876 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes)); 1877 return; 1878 } 1879 1880 /* 1881 * If CM_BLM_REMOVE ie blacklisted or assoc not allowed then 1882 * free the entry else add back to the list sorted 1883 */ 1884 if (blacklist_action == CM_BLM_REMOVE || 1885 blacklist_action == CM_BLM_FORCE_REMOVE) { 1886 if (assoc_allowed) 1887 mlme_nofl_debug("Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d, blm action %d is in Blacklist, remove entry", 1888 QDF_MAC_ADDR_REF(scan_entry->entry->bssid.bytes), 1889 scan_entry->entry->channel.chan_freq, 1890 scan_entry->entry->rssi_raw, 1891 blacklist_action); 1892 util_scan_free_cache_entry(scan_entry->entry); 1893 qdf_mem_free(scan_entry); 1894 } else { 1895 cm_list_insert_sorted(scan_list, scan_entry); 1896 } 1897 1898 cur_node = next_node; 1899 next_node = NULL; 1900 } 1901 1902 if (are_all_candidate_blacklisted && force_connect_candidate) { 1903 mlme_nofl_debug("All candidates in blacklist, Candidate("QDF_MAC_ADDR_FMT" freq %d): rssi %d, selected for connection", 1904 QDF_MAC_ADDR_REF(force_connect_candidate->entry->bssid.bytes), 1905 force_connect_candidate->entry->channel.chan_freq, 1906 force_connect_candidate->entry->rssi_raw); 1907 cm_list_insert_sorted(scan_list, force_connect_candidate); 1908 } else if (force_connect_candidate) { 1909 util_scan_free_cache_entry(force_connect_candidate->entry); 1910 qdf_mem_free(force_connect_candidate); 1911 } 1912 } 1913 1914 #ifdef CONFIG_BAND_6GHZ 1915 static bool cm_check_h2e_support(const uint8_t *rsnxe) 1916 { 1917 const uint8_t *rsnxe_cap; 1918 uint8_t cap_len; 1919 1920 rsnxe_cap = wlan_crypto_parse_rsnxe_ie(rsnxe, &cap_len); 1921 if (!rsnxe_cap) { 1922 mlme_debug("RSNXE caps not present"); 1923 return false; 1924 } 1925 1926 if (*rsnxe_cap & WLAN_CRYPTO_RSNX_CAP_SAE_H2E) 1927 return true; 1928 1929 mlme_debug("RSNXE caps %x dont have H2E support", *rsnxe_cap); 1930 1931 return false; 1932 } 1933 1934 bool wlan_cm_6ghz_allowed_for_akm(struct wlan_objmgr_psoc *psoc, 1935 uint32_t key_mgmt, uint16_t rsn_caps, 1936 const uint8_t *rsnxe, uint8_t sae_pwe, 1937 bool is_wps) 1938 { 1939 struct psoc_mlme_obj *mlme_psoc_obj; 1940 struct scoring_cfg *config; 1941 1942 /* Allow connection for WPS security */ 1943 if (is_wps) 1944 return true; 1945 1946 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 1947 if (!mlme_psoc_obj) 1948 return false; 1949 1950 config = &mlme_psoc_obj->psoc_cfg.score_config; 1951 /* 1952 * if check_6ghz_security is not set check if key_mgmt_mask_6ghz is set 1953 * if key_mgmt_mask_6ghz is set check if AKM matches the user configured 1954 * 6Ghz security 1955 */ 1956 if (!config->check_6ghz_security) { 1957 if (!config->key_mgmt_mask_6ghz) 1958 return true; 1959 /* Check if AKM is allowed as per user 6Ghz allowed AKM mask */ 1960 if ((config->key_mgmt_mask_6ghz & key_mgmt) != key_mgmt) { 1961 mlme_debug("user configured mask %x didnt match AKM %x", 1962 config->key_mgmt_mask_6ghz , key_mgmt); 1963 return false; 1964 } 1965 1966 return true; 1967 } 1968 1969 /* Check if the AKM is allowed as per the 6Ghz allowed AKM mask */ 1970 if ((key_mgmt & ALLOWED_KEYMGMT_6G_MASK) != key_mgmt) 1971 return false; 1972 1973 /* if check_6ghz_security is set validate all checks for 6Ghz */ 1974 if (!(rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)) { 1975 mlme_debug("PMF not enabled for 6GHz AP"); 1976 return false; 1977 } 1978 1979 /* for SAE we need to check H2E support */ 1980 if (!(QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE) || 1981 QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE))) 1982 return true; 1983 1984 return cm_check_h2e_support(rsnxe); 1985 } 1986 1987 void wlan_cm_set_check_6ghz_security(struct wlan_objmgr_psoc *psoc, 1988 bool value) 1989 { 1990 struct psoc_mlme_obj *mlme_psoc_obj; 1991 1992 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 1993 if (!mlme_psoc_obj) 1994 return; 1995 1996 mlme_debug("6ghz security check val %x", value); 1997 mlme_psoc_obj->psoc_cfg.score_config.check_6ghz_security = value; 1998 } 1999 2000 void wlan_cm_reset_check_6ghz_security(struct wlan_objmgr_psoc *psoc) 2001 { 2002 struct psoc_mlme_obj *mlme_psoc_obj; 2003 2004 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 2005 if (!mlme_psoc_obj) 2006 return; 2007 2008 mlme_psoc_obj->psoc_cfg.score_config.check_6ghz_security = 2009 cfg_get(psoc, CFG_CHECK_6GHZ_SECURITY); 2010 } 2011 2012 bool wlan_cm_get_check_6ghz_security(struct wlan_objmgr_psoc *psoc) 2013 { 2014 struct psoc_mlme_obj *mlme_psoc_obj; 2015 2016 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 2017 if (!mlme_psoc_obj) 2018 return false; 2019 2020 return mlme_psoc_obj->psoc_cfg.score_config.check_6ghz_security; 2021 } 2022 2023 void wlan_cm_set_6ghz_key_mgmt_mask(struct wlan_objmgr_psoc *psoc, 2024 uint32_t value) 2025 { 2026 struct psoc_mlme_obj *mlme_psoc_obj; 2027 2028 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 2029 if (!mlme_psoc_obj) 2030 return; 2031 2032 mlme_debug("key_mgmt_mask_6ghz %x", value); 2033 mlme_psoc_obj->psoc_cfg.score_config.key_mgmt_mask_6ghz = value; 2034 } 2035 2036 uint32_t wlan_cm_get_6ghz_key_mgmt_mask(struct wlan_objmgr_psoc *psoc) 2037 { 2038 struct psoc_mlme_obj *mlme_psoc_obj; 2039 2040 mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); 2041 if (!mlme_psoc_obj) 2042 return DEFAULT_KEYMGMT_6G_MASK; 2043 2044 return mlme_psoc_obj->psoc_cfg.score_config.key_mgmt_mask_6ghz; 2045 } 2046 2047 static void cm_fill_6ghz_params(struct wlan_objmgr_psoc *psoc, 2048 struct scoring_cfg *score_cfg) 2049 { 2050 /* Allow all security in 6Ghz by default */ 2051 score_cfg->check_6ghz_security = cfg_get(psoc, CFG_CHECK_6GHZ_SECURITY); 2052 score_cfg->key_mgmt_mask_6ghz = 2053 cfg_get(psoc, CFG_6GHZ_ALLOWED_AKM_MASK); 2054 } 2055 #else 2056 static inline void cm_fill_6ghz_params(struct wlan_objmgr_psoc *psoc, 2057 struct scoring_cfg *score_cfg) 2058 { 2059 } 2060 #endif 2061 2062 static uint32_t 2063 cm_limit_max_per_index_score(uint32_t per_index_score) 2064 { 2065 uint8_t i, score; 2066 2067 for (i = 0; i < CM_MAX_INDEX_PER_INI; i++) { 2068 score = CM_GET_SCORE_PERCENTAGE(per_index_score, i); 2069 if (score > CM_MAX_PCT_SCORE) 2070 CM_SET_SCORE_PERCENTAGE(per_index_score, 2071 CM_MAX_PCT_SCORE, i); 2072 } 2073 2074 return per_index_score; 2075 } 2076 2077 #ifdef WLAN_FEATURE_11BE_MLO 2078 2079 #define CM_EHT_CAP_WEIGHTAGE 2 2080 #define CM_MLO_WEIGHTAGE 3 2081 #define CM_WLM_INDICATION_WEIGHTAGE 2 2082 #define CM_EMLSR_WEIGHTAGE 3 2083 2084 static void cm_init_mlo_score_config(struct wlan_objmgr_psoc *psoc, 2085 struct scoring_cfg *score_cfg, 2086 uint32_t *total_weight) 2087 { 2088 score_cfg->weight_config.eht_caps_weightage = 2089 cfg_get(psoc, CFG_SCORING_EHT_CAPS_WEIGHTAGE); 2090 2091 score_cfg->weight_config.mlo_weightage = 2092 cfg_get(psoc, CFG_SCORING_MLO_WEIGHTAGE); 2093 2094 score_cfg->weight_config.wlm_indication_weightage = 2095 cfg_get(psoc, CFG_SCORING_WLM_INDICATION_WEIGHTAGE); 2096 2097 score_cfg->weight_config.joint_rssi_alpha = 2098 cfg_get(psoc, CFG_SCORING_JOINT_RSSI_ALPHA); 2099 2100 score_cfg->weight_config.low_band_rssi_boost = 2101 cfg_get(psoc, CFG_SCORING_LOW_BAND_RSSI_BOOST); 2102 2103 score_cfg->weight_config.joint_esp_alpha = 2104 cfg_get(psoc, CFG_SCORING_JOINT_ESP_ALPHA); 2105 2106 score_cfg->weight_config.low_band_esp_boost = 2107 cfg_get(psoc, CFG_SCORING_LOW_BAND_ESP_BOOST); 2108 2109 score_cfg->weight_config.joint_oce_alpha = 2110 cfg_get(psoc, CFG_SCORING_JOINT_OCE_ALPHA); 2111 2112 score_cfg->weight_config.low_band_oce_boost = 2113 cfg_get(psoc, CFG_SCORING_LOW_BAND_OCE_BOOST); 2114 2115 score_cfg->weight_config.emlsr_weightage = 2116 cfg_get(psoc, CFG_SCORING_EMLSR_WEIGHTAGE); 2117 2118 score_cfg->mlsr_link_selection = 2119 cfg_get(psoc, CFG_SCORING_MLSR_LINK_SELECTION); 2120 2121 *total_weight += score_cfg->weight_config.eht_caps_weightage + 2122 score_cfg->weight_config.mlo_weightage + 2123 score_cfg->weight_config.wlm_indication_weightage + 2124 score_cfg->weight_config.emlsr_weightage; 2125 } 2126 2127 static void cm_set_default_mlo_weights(struct scoring_cfg *score_cfg) 2128 { 2129 score_cfg->weight_config.eht_caps_weightage = CM_EHT_CAP_WEIGHTAGE; 2130 score_cfg->weight_config.mlo_weightage = CM_MLO_WEIGHTAGE; 2131 score_cfg->weight_config.wlm_indication_weightage = 2132 CM_WLM_INDICATION_WEIGHTAGE; 2133 score_cfg->weight_config.emlsr_weightage = CM_EMLSR_WEIGHTAGE; 2134 } 2135 2136 static void cm_init_bw_weight_per_index(struct wlan_objmgr_psoc *psoc, 2137 struct scoring_cfg *score_cfg) 2138 { 2139 score_cfg->bandwidth_weight_per_index[0] = 2140 cm_limit_max_per_index_score( 2141 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX)); 2142 2143 score_cfg->bandwidth_weight_per_index[1] = 2144 cm_limit_max_per_index_score( 2145 cfg_get(psoc, CFG_SCORING_ML_BW_WEIGHT_PER_IDX_4_TO_7)); 2146 2147 score_cfg->bandwidth_weight_per_index[2] = 2148 cm_limit_max_per_index_score( 2149 cfg_get(psoc, CFG_SCORING_ML_BW_WEIGHT_PER_IDX_8_TO_11)); 2150 2151 score_cfg->bandwidth_weight_per_index[3] = 2152 cm_limit_max_per_index_score( 2153 cfg_get(psoc, CFG_SCORING_ML_BW_WEIGHT_PER_IDX_12_TO_15)); 2154 } 2155 2156 static void cm_init_nss_weight_per_index(struct wlan_objmgr_psoc *psoc, 2157 struct scoring_cfg *score_cfg) 2158 { 2159 score_cfg->nss_weight_per_index[0] = 2160 cm_limit_max_per_index_score( 2161 cfg_get(psoc, CFG_SCORING_NSS_WEIGHT_PER_IDX)); 2162 2163 score_cfg->nss_weight_per_index[1] = 2164 cm_limit_max_per_index_score( 2165 cfg_get(psoc, CFG_SCORING_ML_NSS_WEIGHT_PER_IDX_4_TO_7)); 2166 } 2167 #else 2168 static void cm_init_mlo_score_config(struct wlan_objmgr_psoc *psoc, 2169 struct scoring_cfg *score_cfg, 2170 uint32_t *total_weight) 2171 { 2172 } 2173 2174 static void cm_set_default_mlo_weights(struct scoring_cfg *score_cfg) 2175 { 2176 } 2177 2178 static void cm_init_bw_weight_per_index(struct wlan_objmgr_psoc *psoc, 2179 struct scoring_cfg *score_cfg) 2180 { 2181 score_cfg->bandwidth_weight_per_index[0] = 2182 cm_limit_max_per_index_score( 2183 cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX)); 2184 } 2185 2186 static void cm_init_nss_weight_per_index(struct wlan_objmgr_psoc *psoc, 2187 struct scoring_cfg *score_cfg) 2188 { 2189 score_cfg->nss_weight_per_index[0] = 2190 cm_limit_max_per_index_score( 2191 cfg_get(psoc, CFG_SCORING_NSS_WEIGHT_PER_IDX)); 2192 } 2193 #endif 2194 2195 void wlan_cm_init_score_config(struct wlan_objmgr_psoc *psoc, 2196 struct scoring_cfg *score_cfg) 2197 { 2198 uint32_t total_weight; 2199 2200 score_cfg->weight_config.rssi_weightage = 2201 cfg_get(psoc, CFG_SCORING_RSSI_WEIGHTAGE); 2202 score_cfg->weight_config.ht_caps_weightage = 2203 cfg_get(psoc, CFG_SCORING_HT_CAPS_WEIGHTAGE); 2204 score_cfg->weight_config.vht_caps_weightage = 2205 cfg_get(psoc, CFG_SCORING_VHT_CAPS_WEIGHTAGE); 2206 score_cfg->weight_config.he_caps_weightage = 2207 cfg_get(psoc, CFG_SCORING_HE_CAPS_WEIGHTAGE); 2208 score_cfg->weight_config.chan_width_weightage = 2209 cfg_get(psoc, CFG_SCORING_CHAN_WIDTH_WEIGHTAGE); 2210 score_cfg->weight_config.chan_band_weightage = 2211 cfg_get(psoc, CFG_SCORING_CHAN_BAND_WEIGHTAGE); 2212 score_cfg->weight_config.nss_weightage = 2213 cfg_get(psoc, CFG_SCORING_NSS_WEIGHTAGE); 2214 score_cfg->weight_config.beamforming_cap_weightage = 2215 cfg_get(psoc, CFG_SCORING_BEAMFORM_CAP_WEIGHTAGE); 2216 score_cfg->weight_config.pcl_weightage = 2217 cfg_get(psoc, CFG_SCORING_PCL_WEIGHTAGE); 2218 score_cfg->weight_config.channel_congestion_weightage = 2219 cfg_get(psoc, CFG_SCORING_CHAN_CONGESTION_WEIGHTAGE); 2220 score_cfg->weight_config.oce_wan_weightage = 2221 cfg_get(psoc, CFG_SCORING_OCE_WAN_WEIGHTAGE); 2222 score_cfg->weight_config.oce_ap_tx_pwr_weightage = 2223 cfg_get(psoc, CFG_OCE_AP_TX_PWR_WEIGHTAGE); 2224 score_cfg->weight_config.oce_subnet_id_weightage = 2225 cfg_get(psoc, CFG_OCE_SUBNET_ID_WEIGHTAGE); 2226 score_cfg->weight_config.sae_pk_ap_weightage = 2227 cfg_get(psoc, CFG_SAE_PK_AP_WEIGHTAGE); 2228 2229 cm_init_mlo_score_config(psoc, score_cfg, &total_weight); 2230 2231 total_weight = score_cfg->weight_config.rssi_weightage + 2232 score_cfg->weight_config.ht_caps_weightage + 2233 score_cfg->weight_config.vht_caps_weightage + 2234 score_cfg->weight_config.he_caps_weightage + 2235 score_cfg->weight_config.chan_width_weightage + 2236 score_cfg->weight_config.chan_band_weightage + 2237 score_cfg->weight_config.nss_weightage + 2238 score_cfg->weight_config.beamforming_cap_weightage + 2239 score_cfg->weight_config.pcl_weightage + 2240 score_cfg->weight_config.channel_congestion_weightage + 2241 score_cfg->weight_config.oce_wan_weightage + 2242 score_cfg->weight_config.oce_ap_tx_pwr_weightage + 2243 score_cfg->weight_config.oce_subnet_id_weightage + 2244 score_cfg->weight_config.sae_pk_ap_weightage; 2245 2246 /* 2247 * If configured weights are greater than max weight, 2248 * fallback to default weights 2249 */ 2250 if (total_weight > CM_BEST_CANDIDATE_MAX_WEIGHT) { 2251 mlme_err("Total weight greater than %d, using default weights", 2252 CM_BEST_CANDIDATE_MAX_WEIGHT); 2253 score_cfg->weight_config.rssi_weightage = CM_RSSI_WEIGHTAGE; 2254 score_cfg->weight_config.ht_caps_weightage = 2255 CM_HT_CAPABILITY_WEIGHTAGE; 2256 score_cfg->weight_config.vht_caps_weightage = 2257 CM_VHT_CAP_WEIGHTAGE; 2258 score_cfg->weight_config.he_caps_weightage = 2259 CM_HE_CAP_WEIGHTAGE; 2260 score_cfg->weight_config.chan_width_weightage = 2261 CM_CHAN_WIDTH_WEIGHTAGE; 2262 score_cfg->weight_config.chan_band_weightage = 2263 CM_CHAN_BAND_WEIGHTAGE; 2264 score_cfg->weight_config.nss_weightage = CM_NSS_WEIGHTAGE; 2265 score_cfg->weight_config.beamforming_cap_weightage = 2266 CM_BEAMFORMING_CAP_WEIGHTAGE; 2267 score_cfg->weight_config.pcl_weightage = CM_PCL_WEIGHT; 2268 score_cfg->weight_config.channel_congestion_weightage = 2269 CM_CHANNEL_CONGESTION_WEIGHTAGE; 2270 score_cfg->weight_config.oce_wan_weightage = 2271 CM_OCE_WAN_WEIGHTAGE; 2272 score_cfg->weight_config.oce_ap_tx_pwr_weightage = 2273 CM_OCE_AP_TX_POWER_WEIGHTAGE; 2274 score_cfg->weight_config.oce_subnet_id_weightage = 2275 CM_OCE_SUBNET_ID_WEIGHTAGE; 2276 score_cfg->weight_config.sae_pk_ap_weightage = 2277 CM_SAE_PK_AP_WEIGHTAGE; 2278 cm_set_default_mlo_weights(score_cfg); 2279 } 2280 2281 score_cfg->rssi_score.best_rssi_threshold = 2282 cfg_get(psoc, CFG_SCORING_BEST_RSSI_THRESHOLD); 2283 score_cfg->rssi_score.good_rssi_threshold = 2284 cfg_get(psoc, CFG_SCORING_GOOD_RSSI_THRESHOLD); 2285 score_cfg->rssi_score.bad_rssi_threshold = 2286 cfg_get(psoc, CFG_SCORING_BAD_RSSI_THRESHOLD); 2287 2288 score_cfg->rssi_score.good_rssi_pcnt = 2289 cfg_get(psoc, CFG_SCORING_GOOD_RSSI_PERCENT); 2290 score_cfg->rssi_score.bad_rssi_pcnt = 2291 cfg_get(psoc, CFG_SCORING_BAD_RSSI_PERCENT); 2292 2293 score_cfg->rssi_score.good_rssi_bucket_size = 2294 cfg_get(psoc, CFG_SCORING_GOOD_RSSI_BUCKET_SIZE); 2295 score_cfg->rssi_score.bad_rssi_bucket_size = 2296 cfg_get(psoc, CFG_SCORING_BAD_RSSI_BUCKET_SIZE); 2297 2298 score_cfg->rssi_score.rssi_pref_5g_rssi_thresh = 2299 cfg_get(psoc, CFG_SCORING_RSSI_PREF_5G_THRESHOLD); 2300 2301 score_cfg->esp_qbss_scoring.num_slot = 2302 cfg_get(psoc, CFG_SCORING_NUM_ESP_QBSS_SLOTS); 2303 score_cfg->esp_qbss_scoring.score_pcnt3_to_0 = 2304 cm_limit_max_per_index_score( 2305 cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_3_TO_0)); 2306 score_cfg->esp_qbss_scoring.score_pcnt7_to_4 = 2307 cm_limit_max_per_index_score( 2308 cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_7_TO_4)); 2309 score_cfg->esp_qbss_scoring.score_pcnt11_to_8 = 2310 cm_limit_max_per_index_score( 2311 cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_11_TO_8)); 2312 score_cfg->esp_qbss_scoring.score_pcnt15_to_12 = 2313 cm_limit_max_per_index_score( 2314 cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_15_TO_12)); 2315 2316 score_cfg->oce_wan_scoring.num_slot = 2317 cfg_get(psoc, CFG_SCORING_NUM_OCE_WAN_SLOTS); 2318 score_cfg->oce_wan_scoring.score_pcnt3_to_0 = 2319 cm_limit_max_per_index_score( 2320 cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_3_TO_0)); 2321 score_cfg->oce_wan_scoring.score_pcnt7_to_4 = 2322 cm_limit_max_per_index_score( 2323 cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_7_TO_4)); 2324 score_cfg->oce_wan_scoring.score_pcnt11_to_8 = 2325 cm_limit_max_per_index_score( 2326 cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_11_TO_8)); 2327 score_cfg->oce_wan_scoring.score_pcnt15_to_12 = 2328 cm_limit_max_per_index_score( 2329 cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_15_TO_12)); 2330 2331 score_cfg->band_weight_per_index = 2332 cm_limit_max_per_index_score( 2333 cfg_get(psoc, CFG_SCORING_BAND_WEIGHT_PER_IDX)); 2334 score_cfg->is_bssid_hint_priority = 2335 cfg_get(psoc, CFG_IS_BSSID_HINT_PRIORITY); 2336 score_cfg->vendor_roam_score_algorithm = 2337 cfg_get(psoc, CFG_VENDOR_ROAM_SCORE_ALGORITHM); 2338 score_cfg->check_assoc_disallowed = true; 2339 cm_fill_6ghz_params(psoc, score_cfg); 2340 2341 cm_init_bw_weight_per_index(psoc, score_cfg); 2342 cm_init_nss_weight_per_index(psoc, score_cfg); 2343 } 2344