xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlme/connection_mgr/core/src/wlan_cm_bss_scoring.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
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