xref: /wlan-dirver/qca-wifi-host-cmn/umac/mlme/connection_mgr/core/src/wlan_cm_bss_scoring.c (revision 45a38684b07295822dc8eba39e293408f203eec8)
1 /*
2  * Copyright (c) 2017-2020, 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 
30 #define CM_20MHZ_BW_INDEX                  0
31 #define CM_40MHZ_BW_INDEX                  1
32 #define CM_80MHZ_BW_INDEX                  2
33 #define CM_160MHZ_BW_INDEX                 3
34 #define CM_MAX_BW_INDEX                    4
35 
36 #define CM_PCL_RSSI_THRESHOLD -75
37 
38 #define CM_NSS_1x1_INDEX                   0
39 #define CM_NSS_2x2_INDEX                   1
40 #define CM_NSS_3x3_INDEX                   2
41 #define CM_NSS_4x4_INDEX                   3
42 #define CM_MAX_NSS_INDEX                   4
43 
44 #define CM_BAND_2G_INDEX                   0
45 #define CM_BAND_5G_INDEX                   1
46 #define CM_BAND_6G_INDEX                   2
47 /* 3 is reserved */
48 #define CM_MAX_BAND_INDEX                  4
49 
50 #define CM_SCORE_INDEX_0                   0
51 #define CM_SCORE_INDEX_3                   3
52 #define CM_SCORE_INDEX_7                   7
53 #define CM_SCORE_OFFSET_INDEX_7_4          4
54 #define CM_SCORE_INDEX_11                  11
55 #define CM_SCORE_OFFSET_INDEX_11_8         8
56 #define CM_SCORE_MAX_INDEX                 15
57 #define CM_SCORE_OFFSET_INDEX_15_12        12
58 
59 #define CM_MAX_OCE_WAN_DL_CAP 16
60 
61 #define CM_MAX_CHANNEL_WEIGHT 100
62 #define CM_MAX_CHANNEL_UTILIZATION 100
63 #define CM_MAX_ESTIMATED_AIR_TIME_FRACTION 255
64 #define CM_MAX_AP_LOAD 255
65 
66 #define CM_MAX_WEIGHT_OF_PCL_CHANNELS 255
67 #define CM_PCL_GROUPS_WEIGHT_DIFFERENCE 20
68 
69 /* Congestion threshold (channel load %) to consider band and OCE WAN score */
70 #define CM_CONGESTION_THRSHOLD_FOR_BAND_OCE_SCORE 75
71 
72 #define CM_RSSI_WEIGHTAGE 20
73 #define CM_HT_CAPABILITY_WEIGHTAGE 2
74 #define CM_VHT_CAP_WEIGHTAGE 1
75 #define CM_HE_CAP_WEIGHTAGE 2
76 #define CM_CHAN_WIDTH_WEIGHTAGE 12
77 #define CM_CHAN_BAND_WEIGHTAGE 2
78 #define CM_NSS_WEIGHTAGE 16
79 #define CM_BEAMFORMING_CAP_WEIGHTAGE 2
80 #define CM_PCL_WEIGHT 10
81 #define CM_CHANNEL_CONGESTION_WEIGHTAGE 5
82 #define CM_OCE_WAN_WEIGHTAGE 2
83 #define CM_OCE_AP_TX_POWER_WEIGHTAGE 5
84 #define CM_OCE_SUBNET_ID_WEIGHTAGE 3
85 #define CM_BEST_CANDIDATE_MAX_WEIGHT 200
86 #define CM_MAX_PCT_SCORE 100
87 #define CM_MAX_INDEX_PER_INI 4
88 
89 #define CM_BEST_CANDIDATE_MAX_BSS_SCORE (CM_BEST_CANDIDATE_MAX_WEIGHT * 100)
90 #define CM_AVOID_CANDIDATE_MIN_SCORE 1
91 
92 #define CM_GET_SCORE_PERCENTAGE(value32, bw_index) \
93 	QDF_GET_BITS(value32, (8 * (bw_index)), 8)
94 #define CM_SET_SCORE_PERCENTAGE(value32, score_pcnt, bw_index) \
95 	QDF_SET_BITS(value32, (8 * (bw_index)), 8, score_pcnt)
96 
97 static bool cm_is_better_bss(struct scan_cache_entry *bss1,
98 			     struct scan_cache_entry *bss2)
99 {
100 	if (bss1->bss_score > bss2->bss_score)
101 		return true;
102 	else if (bss1->bss_score == bss2->bss_score)
103 		if (bss1->rssi_raw > bss2->rssi_raw)
104 			return true;
105 
106 	return false;
107 }
108 
109 /**
110  * cm_get_rssi_pcnt_for_slot() - calculate rssi % score based on the slot
111  * index between the high rssi and low rssi threshold
112  * @high_rssi_threshold: High rssi of the window
113  * @low_rssi_threshold: low rssi of the window
114  * @high_rssi_pcnt: % score for the high rssi
115  * @low_rssi_pcnt: %score for the low rssi
116  * @bucket_size: bucket size of the window
117  * @bss_rssi: Input rssi for which value need to be calculated
118  *
119  * Return : rssi pct to use for the given rssi
120  */
121 static inline
122 int8_t cm_get_rssi_pcnt_for_slot(int32_t high_rssi_threshold,
123 				 int32_t low_rssi_threshold,
124 				 uint32_t high_rssi_pcnt,
125 				 uint32_t low_rssi_pcnt,
126 				 uint32_t bucket_size, int8_t bss_rssi)
127 {
128 	int8_t slot_index, slot_size, rssi_diff, num_slot, rssi_pcnt;
129 
130 	num_slot = ((high_rssi_threshold -
131 		     low_rssi_threshold) / bucket_size) + 1;
132 	slot_size = ((high_rssi_pcnt - low_rssi_pcnt) +
133 		     (num_slot / 2)) / (num_slot);
134 	rssi_diff = high_rssi_threshold - bss_rssi;
135 	slot_index = (rssi_diff / bucket_size) + 1;
136 	rssi_pcnt = high_rssi_pcnt - (slot_size * slot_index);
137 	if (rssi_pcnt < low_rssi_pcnt)
138 		rssi_pcnt = low_rssi_pcnt;
139 
140 	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",
141 		   high_rssi_threshold, low_rssi_threshold, high_rssi_pcnt,
142 		   low_rssi_pcnt, bucket_size, bss_rssi, num_slot, slot_size,
143 		   rssi_diff, slot_index, rssi_pcnt);
144 
145 	return rssi_pcnt;
146 }
147 
148 /**
149  * cm_calculate_rssi_score() - Calculate RSSI score based on AP RSSI
150  * @score_param: rssi score params
151  * @rssi: rssi of the AP
152  * @rssi_weightage: rssi_weightage out of total weightage
153  *
154  * Return : rssi score
155  */
156 static int32_t cm_calculate_rssi_score(struct rssi_config_score *score_param,
157 				       int32_t rssi, uint8_t rssi_weightage)
158 {
159 	int8_t rssi_pcnt;
160 	int32_t total_rssi_score;
161 	int32_t best_rssi_threshold;
162 	int32_t good_rssi_threshold;
163 	int32_t bad_rssi_threshold;
164 	uint32_t good_rssi_pcnt;
165 	uint32_t bad_rssi_pcnt;
166 	uint32_t good_bucket_size;
167 	uint32_t bad_bucket_size;
168 
169 	best_rssi_threshold = score_param->best_rssi_threshold * (-1);
170 	good_rssi_threshold = score_param->good_rssi_threshold * (-1);
171 	bad_rssi_threshold = score_param->bad_rssi_threshold * (-1);
172 	good_rssi_pcnt = score_param->good_rssi_pcnt;
173 	bad_rssi_pcnt = score_param->bad_rssi_pcnt;
174 	good_bucket_size = score_param->good_rssi_bucket_size;
175 	bad_bucket_size = score_param->bad_rssi_bucket_size;
176 
177 	total_rssi_score = (CM_MAX_PCT_SCORE * rssi_weightage);
178 
179 	/*
180 	 * If RSSI is better than the best rssi threshold then it return full
181 	 * score.
182 	 */
183 	if (rssi > best_rssi_threshold)
184 		return total_rssi_score;
185 	/*
186 	 * If RSSI is less or equal to bad rssi threshold then it return
187 	 * least score.
188 	 */
189 	if (rssi <= bad_rssi_threshold)
190 		return (total_rssi_score * bad_rssi_pcnt) / 100;
191 
192 	/* RSSI lies between best to good rssi threshold */
193 	if (rssi > good_rssi_threshold)
194 		rssi_pcnt = cm_get_rssi_pcnt_for_slot(best_rssi_threshold,
195 				good_rssi_threshold, 100, good_rssi_pcnt,
196 				good_bucket_size, rssi);
197 	else
198 		rssi_pcnt = cm_get_rssi_pcnt_for_slot(good_rssi_threshold,
199 				bad_rssi_threshold, good_rssi_pcnt,
200 				bad_rssi_pcnt, bad_bucket_size,
201 				rssi);
202 
203 	return (total_rssi_score * rssi_pcnt) / 100;
204 }
205 
206 /**
207  * cm_calculate_pcl_score() - Calculate PCL score based on PCL weightage
208  * @pcl_chan_weight: pcl weight of BSS channel
209  * @pcl_weightage: PCL _weightage out of total weightage
210  *
211  * Return : pcl score
212  */
213 static int32_t cm_calculate_pcl_score(int pcl_chan_weight,
214 				      uint8_t pcl_weightage)
215 {
216 	int32_t pcl_score = 0;
217 	int32_t temp_pcl_chan_weight = 0;
218 
219 	if (pcl_chan_weight) {
220 		temp_pcl_chan_weight =
221 			(CM_MAX_WEIGHT_OF_PCL_CHANNELS - pcl_chan_weight);
222 		temp_pcl_chan_weight = qdf_do_div(temp_pcl_chan_weight,
223 					  CM_PCL_GROUPS_WEIGHT_DIFFERENCE);
224 		pcl_score = pcl_weightage - temp_pcl_chan_weight;
225 		if (pcl_score < 0)
226 			pcl_score = 0;
227 	}
228 
229 	return pcl_score * CM_MAX_PCT_SCORE;
230 }
231 
232 /**
233  * cm_rssi_is_same_bucket() - check if both rssi fall in same bucket
234  * @rssi_top_thresh: high rssi threshold of the the window
235  * @low_rssi_threshold: low rssi of the window
236  * @rssi_ref1: rssi ref one
237  * @rssi_ref2: rssi ref two
238  * @bucket_size: bucket size of the window
239  *
240  * Return : true if both fall in same window
241  */
242 static inline bool cm_rssi_is_same_bucket(int8_t rssi_top_thresh,
243 					  int8_t rssi_ref1, int8_t rssi_ref2,
244 					  int8_t bucket_size)
245 {
246 	int8_t rssi_diff1 = 0;
247 	int8_t rssi_diff2 = 0;
248 
249 	rssi_diff1 = rssi_top_thresh - rssi_ref1;
250 	rssi_diff2 = rssi_top_thresh - rssi_ref2;
251 
252 	return (rssi_diff1 / bucket_size) == (rssi_diff2 / bucket_size);
253 }
254 
255 /**
256  * cm_roam_calculate_prorated_pcnt_by_rssi() - Calculate prorated RSSI score
257  * based on AP RSSI. This will be used to determine HT VHT score
258  * @score_param: rssi score params
259  * @rssi: bss rssi
260  * @rssi_weightage: rssi_weightage out of total weightage
261  *
262  * If rssi is greater than good threshold return 100, if less than bad return 0,
263  * if between good and bad, return prorated rssi score for the index.
264  *
265  * Return : rssi prorated score
266  */
267 static int8_t cm_roam_calculate_prorated_pcnt_by_rssi(
268 	struct rssi_config_score *score_param,
269 	int32_t rssi, uint8_t rssi_weightage)
270 {
271 	int32_t good_rssi_threshold;
272 	int32_t bad_rssi_threshold;
273 	int8_t rssi_pref_5g_rssi_thresh;
274 	bool same_bucket;
275 
276 	good_rssi_threshold = score_param->good_rssi_threshold * (-1);
277 	bad_rssi_threshold = score_param->bad_rssi_threshold * (-1);
278 	rssi_pref_5g_rssi_thresh = score_param->rssi_pref_5g_rssi_thresh * (-1);
279 
280 	/* If RSSI is greater than good rssi return full weight */
281 	if (rssi > good_rssi_threshold)
282 		return CM_MAX_PCT_SCORE;
283 
284 	same_bucket = cm_rssi_is_same_bucket(good_rssi_threshold, rssi,
285 					     rssi_pref_5g_rssi_thresh,
286 					     score_param->bad_rssi_bucket_size);
287 	if (same_bucket || (rssi < rssi_pref_5g_rssi_thresh))
288 		return 0;
289 	/* If RSSI is less or equal to bad rssi threshold then it return 0 */
290 	if (rssi <= bad_rssi_threshold)
291 		return 0;
292 
293 	/* If RSSI is between good and bad threshold */
294 	return cm_get_rssi_pcnt_for_slot(good_rssi_threshold,
295 					 bad_rssi_threshold,
296 					 score_param->good_rssi_pcnt,
297 					 score_param->bad_rssi_pcnt,
298 					 score_param->bad_rssi_bucket_size,
299 					 rssi);
300 }
301 
302 /**
303  * cm_calculate_bandwidth_score() - Calculate BW score
304  * @entry: scan entry
305  * @score_config: scoring config
306  * @phy_config: psoc phy configs
307  * @prorated_pct: prorated % to return dependent on RSSI
308  *
309  * Return : bw score
310  */
311 static int32_t cm_calculate_bandwidth_score(struct scan_cache_entry *entry,
312 					    struct scoring_cfg *score_config,
313 					    struct psoc_phy_config *phy_config,
314 					    uint8_t prorated_pct)
315 {
316 	uint32_t score;
317 	int32_t bw_weight_per_idx;
318 	uint8_t bw_above_20 = 0;
319 	uint8_t ch_width_index;
320 	bool is_vht = false;
321 
322 	bw_weight_per_idx = score_config->bandwidth_weight_per_index;
323 
324 	if (WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) {
325 		bw_above_20 = phy_config->bw_above_20_24ghz;
326 		if (phy_config->vht_24G_cap)
327 			is_vht = true;
328 	} else if (phy_config->vht_cap) {
329 		is_vht = true;
330 		bw_above_20 = phy_config->bw_above_20_5ghz;
331 	}
332 
333 	if (IS_WLAN_PHYMODE_160MHZ(entry->phy_mode))
334 		ch_width_index = CM_160MHZ_BW_INDEX;
335 	else if (IS_WLAN_PHYMODE_80MHZ(entry->phy_mode))
336 		ch_width_index = CM_80MHZ_BW_INDEX;
337 	else if (IS_WLAN_PHYMODE_40MHZ(entry->phy_mode))
338 		ch_width_index = CM_40MHZ_BW_INDEX;
339 	else
340 		ch_width_index = CM_20MHZ_BW_INDEX;
341 
342 	if (!phy_config->ht_cap &&
343 	    ch_width_index > CM_20MHZ_BW_INDEX)
344 		ch_width_index = CM_20MHZ_BW_INDEX;
345 
346 	if (!is_vht && ch_width_index > CM_40MHZ_BW_INDEX)
347 		ch_width_index = CM_40MHZ_BW_INDEX;
348 
349 	if (bw_above_20 && ch_width_index > CM_20MHZ_BW_INDEX)
350 		score = CM_GET_SCORE_PERCENTAGE(bw_weight_per_idx,
351 						ch_width_index);
352 	else
353 		score = CM_GET_SCORE_PERCENTAGE(bw_weight_per_idx,
354 						CM_20MHZ_BW_INDEX);
355 
356 	return (prorated_pct * score *
357 		score_config->weight_config.chan_width_weightage) /
358 		CM_MAX_PCT_SCORE;
359 }
360 
361 /**
362  * cm_get_score_for_index() - get score for the given index
363  * @index: index for which we need the score
364  * @weightage: weigtage for the param
365  * @score: per slot score
366  *
367  * Return : score for the index
368  */
369 static int32_t cm_get_score_for_index(uint8_t index,
370 				      uint8_t weightage,
371 				      struct per_slot_score *score)
372 {
373 	if (index <= CM_SCORE_INDEX_3)
374 		return weightage * CM_GET_SCORE_PERCENTAGE(
375 				   score->score_pcnt3_to_0,
376 				   index);
377 	else if (index <= CM_SCORE_INDEX_7)
378 		return weightage * CM_GET_SCORE_PERCENTAGE(
379 				   score->score_pcnt7_to_4,
380 				   index - CM_SCORE_OFFSET_INDEX_7_4);
381 	else if (index <= CM_SCORE_INDEX_11)
382 		return weightage * CM_GET_SCORE_PERCENTAGE(
383 				   score->score_pcnt11_to_8,
384 				   index - CM_SCORE_OFFSET_INDEX_11_8);
385 	else
386 		return weightage * CM_GET_SCORE_PERCENTAGE(
387 				   score->score_pcnt15_to_12,
388 				   index - CM_SCORE_OFFSET_INDEX_15_12);
389 }
390 
391 /**
392  * cm_get_congestion_pct() - Calculate congestion pct from esp/qbss load
393  * @entry: bss information
394  *
395  * Return : congestion pct
396  */
397 static int32_t cm_get_congestion_pct(struct scan_cache_entry *entry)
398 {
399 	uint32_t ap_load = 0;
400 	uint32_t est_air_time_percentage = 0;
401 	uint32_t congestion = 0;
402 
403 	if (entry->air_time_fraction) {
404 		/* Convert 0-255 range to percentage */
405 		est_air_time_percentage = entry->air_time_fraction *
406 							CM_MAX_CHANNEL_WEIGHT;
407 		est_air_time_percentage = qdf_do_div(est_air_time_percentage,
408 					   CM_MAX_ESTIMATED_AIR_TIME_FRACTION);
409 		/*
410 		 * Calculate channel congestion from estimated air time
411 		 * fraction.
412 		 */
413 		congestion = CM_MAX_CHANNEL_UTILIZATION -
414 					est_air_time_percentage;
415 	} else if (entry->qbss_chan_load) {
416 		ap_load = (entry->qbss_chan_load * CM_MAX_PCT_SCORE);
417 		/*
418 		 * Calculate ap_load in % from qbss channel load from
419 		 * 0-255 range
420 		 */
421 		congestion = qdf_do_div(ap_load, CM_MAX_AP_LOAD);
422 	}
423 
424 	return congestion;
425 }
426 
427 /**
428  * cm_calculate_congestion_score() - Calculate congestion score
429  * @entry: bss information
430  * @score_params: bss score params
431  * @congestion_pct: congestion pct
432  *
433  * Return : congestion score
434  */
435 static int32_t cm_calculate_congestion_score(struct scan_cache_entry *entry,
436 					     struct scoring_cfg *score_params,
437 					     uint32_t *congestion_pct)
438 {
439 	uint32_t window_size;
440 	uint8_t index;
441 	int32_t good_rssi_threshold;
442 
443 	*congestion_pct = cm_get_congestion_pct(entry);
444 
445 	if (!score_params->esp_qbss_scoring.num_slot)
446 		return 0;
447 
448 	if (score_params->esp_qbss_scoring.num_slot >
449 	    CM_SCORE_MAX_INDEX)
450 		score_params->esp_qbss_scoring.num_slot =
451 			CM_SCORE_MAX_INDEX;
452 
453 	good_rssi_threshold =
454 		score_params->rssi_score.good_rssi_threshold * (-1);
455 
456 	/* For bad zone rssi get score from last index */
457 	if (entry->rssi_raw <= good_rssi_threshold)
458 		return cm_get_score_for_index(
459 			score_params->esp_qbss_scoring.num_slot,
460 			score_params->weight_config.channel_congestion_weightage,
461 			&score_params->esp_qbss_scoring);
462 
463 	if (!*congestion_pct)
464 		return score_params->weight_config.channel_congestion_weightage *
465 			   CM_GET_SCORE_PERCENTAGE(
466 			   score_params->esp_qbss_scoring.score_pcnt3_to_0,
467 			   CM_SCORE_INDEX_0);
468 
469 	window_size = CM_MAX_PCT_SCORE /
470 			score_params->esp_qbss_scoring.num_slot;
471 
472 	/* Desired values are from 1 to 15, as 0 is for not present. so do +1 */
473 	index = qdf_do_div(*congestion_pct, window_size) + 1;
474 
475 	if (index > score_params->esp_qbss_scoring.num_slot)
476 		index = score_params->esp_qbss_scoring.num_slot;
477 
478 	return cm_get_score_for_index(index,
479 		score_params->weight_config.channel_congestion_weightage,
480 		&score_params->esp_qbss_scoring);
481 }
482 
483 /**
484  * cm_calculate_nss_score() - Calculate congestion score
485  * @psoc: psoc ptr
486  * @score_config: scoring config
487  * @ap_nss: ap nss
488  * @prorated_pct: prorated % to return dependent on RSSI
489  *
490  * Return : nss score
491  */
492 static int32_t cm_calculate_nss_score(struct wlan_objmgr_psoc *psoc,
493 				      struct scoring_cfg *score_config,
494 				      uint8_t ap_nss, uint8_t prorated_pct,
495 				      uint32_t sta_nss)
496 {
497 	uint8_t nss;
498 	uint8_t score_pct;
499 
500 	nss = ap_nss;
501 	if (sta_nss < nss)
502 		nss = sta_nss;
503 
504 	/* TODO: enhance for 8x8 */
505 	if (nss == 4)
506 		score_pct = CM_GET_SCORE_PERCENTAGE(
507 				score_config->nss_weight_per_index,
508 				CM_NSS_4x4_INDEX);
509 	else if (nss == 3)
510 		score_pct = CM_GET_SCORE_PERCENTAGE(
511 				score_config->nss_weight_per_index,
512 				CM_NSS_3x3_INDEX);
513 	else if (nss == 2)
514 		score_pct = CM_GET_SCORE_PERCENTAGE(
515 				score_config->nss_weight_per_index,
516 				CM_NSS_2x2_INDEX);
517 	else
518 		score_pct = CM_GET_SCORE_PERCENTAGE(
519 				score_config->nss_weight_per_index,
520 				CM_NSS_1x1_INDEX);
521 
522 	return (score_config->weight_config.nss_weightage * score_pct *
523 		prorated_pct) / CM_MAX_PCT_SCORE;
524 }
525 
526 /**
527  * cm_calculate_oce_wan_score() - Calculate oce wan score
528  * @entry: bss information
529  * @score_params: bss score params
530  *
531  * Return : oce wan score
532  */
533 static int32_t cm_calculate_oce_wan_score(
534 	struct scan_cache_entry *entry,
535 	struct scoring_cfg *score_params)
536 {
537 	uint32_t window_size;
538 	uint8_t index;
539 	struct oce_reduced_wan_metrics wan_metrics;
540 	uint8_t *mbo_oce_ie;
541 
542 	if (!score_params->oce_wan_scoring.num_slot)
543 		return 0;
544 
545 	if (score_params->oce_wan_scoring.num_slot >
546 	    CM_SCORE_MAX_INDEX)
547 		score_params->oce_wan_scoring.num_slot =
548 			CM_SCORE_MAX_INDEX;
549 
550 	window_size = CM_SCORE_MAX_INDEX /
551 			score_params->oce_wan_scoring.num_slot;
552 	mbo_oce_ie = util_scan_entry_mbo_oce(entry);
553 	if (wlan_parse_oce_reduced_wan_metrics_ie(mbo_oce_ie, &wan_metrics)) {
554 		mlme_err("downlink_av_cap %d", wan_metrics.downlink_av_cap);
555 		/* if capacity is 0 return 0 score */
556 		if (!wan_metrics.downlink_av_cap)
557 			return 0;
558 		/* Desired values are from 1 to WLAN_SCORE_MAX_INDEX */
559 		index = qdf_do_div(wan_metrics.downlink_av_cap,
560 				   window_size);
561 	} else {
562 		index = CM_SCORE_INDEX_0;
563 	}
564 
565 	if (index > score_params->oce_wan_scoring.num_slot)
566 		index = score_params->oce_wan_scoring.num_slot;
567 
568 	return cm_get_score_for_index(index,
569 			score_params->weight_config.oce_wan_weightage,
570 			&score_params->oce_wan_scoring);
571 }
572 
573 /**
574  * cm_calculate_oce_subnet_id_weightage() - Calculate oce subnet id weightage
575  * @entry: bss entry
576  * @score_params: bss score params
577  * @oce_subnet_id_present: check if subnet id subelement is present in OCE IE
578  *
579  * Return : oce subnet id score
580  */
581 static uint32_t
582 cm_calculate_oce_subnet_id_weightage(struct scan_cache_entry *entry,
583 				     struct scoring_cfg *score_params,
584 				     bool *oce_subnet_id_present)
585 {
586 	uint32_t score = 0;
587 	uint8_t *mbo_oce_ie;
588 
589 	mbo_oce_ie = util_scan_entry_mbo_oce(entry);
590 	*oce_subnet_id_present = wlan_parse_oce_subnet_id_ie(mbo_oce_ie);
591 
592 	/* Consider 50% weightage if subnet id sub element is present */
593 	if (*oce_subnet_id_present)
594 		score  = score_params->weight_config.oce_subnet_id_weightage *
595 				(CM_MAX_PCT_SCORE / 2);
596 
597 	return score;
598 }
599 
600 /**
601  * cm_calculate_oce_ap_tx_pwr_weightage() - Calculate oce ap tx pwr weightage
602  * @entry: bss entry
603  * @score_params: bss score params
604  * @ap_tx_pwr_dbm: pointer to hold ap tx power
605  *
606  * Return : oce ap tx power score
607  */
608 static uint32_t
609 cm_calculate_oce_ap_tx_pwr_weightage(struct scan_cache_entry *entry,
610 				     struct scoring_cfg *score_params,
611 				     int8_t *ap_tx_pwr_dbm)
612 {
613 	uint8_t *mbo_oce_ie, ap_tx_pwr_factor;
614 	struct rssi_config_score *rssi_score_param;
615 	int32_t best_rssi_threshold, good_rssi_threshold, bad_rssi_threshold;
616 	uint32_t good_rssi_pcnt, bad_rssi_pcnt, good_bucket_size;
617 	uint32_t score, normalized_ap_tx_pwr, bad_bucket_size;
618 	bool ap_tx_pwr_cap_present = true;
619 
620 	mbo_oce_ie = util_scan_entry_mbo_oce(entry);
621 	if (!wlan_parse_oce_ap_tx_pwr_ie(mbo_oce_ie, ap_tx_pwr_dbm)) {
622 		ap_tx_pwr_cap_present = false;
623 		/* If no OCE AP TX pwr, consider Uplink RSSI = Downlink RSSI */
624 		normalized_ap_tx_pwr = entry->rssi_raw;
625 	} else {
626 		/*
627 		 * Normalized ap_tx_pwr =
628 		 * Uplink RSSI = (STA TX Power - * (AP TX power - RSSI)) in dBm.
629 		 * Currently assuming STA Tx Power to be 20dBm, though later it
630 		 * need to fetched from hal-phy API.
631 		 */
632 		normalized_ap_tx_pwr = (20 - (*ap_tx_pwr_dbm - entry->rssi_raw));
633 	}
634 
635 	rssi_score_param = &score_params->rssi_score;
636 
637 	best_rssi_threshold = rssi_score_param->best_rssi_threshold * (-1);
638 	good_rssi_threshold = rssi_score_param->good_rssi_threshold * (-1);
639 	bad_rssi_threshold = rssi_score_param->bad_rssi_threshold * (-1);
640 	good_rssi_pcnt = rssi_score_param->good_rssi_pcnt;
641 	bad_rssi_pcnt = rssi_score_param->bad_rssi_pcnt;
642 	good_bucket_size = rssi_score_param->good_rssi_bucket_size;
643 	bad_bucket_size = rssi_score_param->bad_rssi_bucket_size;
644 
645 	/* Uplink RSSI is better than best rssi threshold */
646 	if (normalized_ap_tx_pwr > best_rssi_threshold) {
647 		ap_tx_pwr_factor = CM_MAX_PCT_SCORE;
648 	} else if (normalized_ap_tx_pwr <= bad_rssi_threshold) {
649 		/* Uplink RSSI is less or equal to bad rssi threshold */
650 		ap_tx_pwr_factor = rssi_score_param->bad_rssi_pcnt;
651 	} else if (normalized_ap_tx_pwr > good_rssi_threshold) {
652 		/* Uplink RSSI lies between best to good rssi threshold */
653 		ap_tx_pwr_factor =
654 			cm_get_rssi_pcnt_for_slot(best_rssi_threshold,
655 				good_rssi_threshold, 100, good_rssi_pcnt,
656 				good_bucket_size, normalized_ap_tx_pwr);
657 	} else {
658 		/* Uplink RSSI lies between good to best rssi threshold */
659 		ap_tx_pwr_factor =
660 			cm_get_rssi_pcnt_for_slot(good_rssi_threshold,
661 				bad_rssi_threshold, good_rssi_pcnt,
662 				bad_rssi_pcnt, bad_bucket_size,
663 				normalized_ap_tx_pwr);
664 	}
665 
666 	score  = score_params->weight_config.oce_ap_tx_pwr_weightage *
667 			ap_tx_pwr_factor;
668 
669 	return score;
670 }
671 
672 #ifdef WLAN_POLICY_MGR_ENABLE
673 
674 static uint32_t cm_get_sta_nss(struct wlan_objmgr_psoc *psoc,
675 			       qdf_freq_t bss_channel_freq,
676 			       uint8_t vdev_nss_2g, uint8_t vdev_nss_5g)
677 {
678 	/*
679 	 * If station support nss as 2*2 but AP support NSS as 1*1,
680 	 * this AP will be given half weight compare to AP which are having
681 	 * NSS as 2*2.
682 	 */
683 
684 	if (policy_mgr_is_chnl_in_diff_band(
685 	    psoc, bss_channel_freq) &&
686 	    policy_mgr_is_hw_dbs_capable(psoc) &&
687 	    !(policy_mgr_is_hw_dbs_2x2_capable(psoc)))
688 		return 1;
689 
690 	return (WLAN_REG_IS_24GHZ_CH_FREQ(bss_channel_freq) ?
691 		vdev_nss_2g :
692 		vdev_nss_5g);
693 }
694 #else
695 static uint32_t cm_get_sta_nss(struct wlan_objmgr_psoc *psoc,
696 			       qdf_freq_t bss_channel_freq,
697 			       uint8_t vdev_nss_2g, uint8_t vdev_nss_5g)
698 {
699 	return (WLAN_REG_IS_24GHZ_CH_FREQ(bss_channel_freq) ?
700 		vdev_nss_2g :
701 		vdev_nss_5g);
702 }
703 #endif
704 
705 /**
706  * cm_get_band_score() - Get band prefernce weightage
707  * freq: Operating frequency of the AP
708  * @score_config: Score configuration
709  *
710  * Return : Band score for AP.
711  */
712 static int
713 cm_get_band_score(uint32_t freq, struct scoring_cfg *score_config)
714 {
715 	uint8_t band_index;
716 	struct weight_cfg *weight_config;
717 
718 	weight_config = &score_config->weight_config;
719 
720 	if (WLAN_REG_IS_5GHZ_CH_FREQ(freq))
721 		band_index = CM_BAND_5G_INDEX;
722 	else if (WLAN_REG_IS_24GHZ_CH_FREQ(freq))
723 		band_index = CM_BAND_2G_INDEX;
724 	else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(freq))
725 		band_index = CM_BAND_6G_INDEX;
726 	else
727 		return 0;
728 
729 	return weight_config->chan_band_weightage *
730 	       CM_GET_SCORE_PERCENTAGE(score_config->band_weight_per_index,
731 				       band_index);
732 }
733 
734 static int cm_calculate_bss_score(struct wlan_objmgr_psoc *psoc,
735 				  struct scan_cache_entry *entry,
736 				  int pcl_chan_weight,
737 				  struct qdf_mac_addr *bssid_hint)
738 {
739 	int32_t score = 0;
740 	int32_t rssi_score = 0;
741 	int32_t pcl_score = 0;
742 	int32_t ht_score = 0;
743 	int32_t vht_score = 0;
744 	int32_t he_score = 0;
745 	int32_t bandwidth_score = 0;
746 	int32_t beamformee_score = 0;
747 	int32_t band_score = 0;
748 	int32_t nss_score = 0;
749 	int32_t congestion_score = 0;
750 	int32_t congestion_pct = 0;
751 	int32_t oce_wan_score = 0;
752 	uint8_t oce_ap_tx_pwr_score = 0;
753 	uint8_t oce_subnet_id_score = 0;
754 	bool oce_subnet_id_present = 0;
755 	int8_t ap_tx_pwr_dbm = 0;
756 	uint8_t prorated_pcnt;
757 	bool is_vht = false;
758 	int8_t good_rssi_threshold;
759 	int8_t rssi_pref_5g_rssi_thresh;
760 	bool same_bucket = false;
761 	bool ap_su_beam_former = false;
762 	struct wlan_ie_vhtcaps *vht_cap;
763 	struct scoring_cfg *score_config;
764 	struct weight_cfg *weight_config;
765 	uint32_t sta_nss;
766 	struct psoc_mlme_obj *mlme_psoc_obj;
767 	struct psoc_phy_config *phy_config;
768 
769 	mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc);
770 
771 	if (!mlme_psoc_obj)
772 		return 0;
773 	phy_config = &mlme_psoc_obj->psoc_cfg.phy_config;
774 	score_config = &mlme_psoc_obj->psoc_cfg.score_config;
775 	weight_config = &score_config->weight_config;
776 
777 	if (score_config->is_bssid_hint_priority && bssid_hint &&
778 	    qdf_is_macaddr_equal(bssid_hint, &entry->bssid)) {
779 		entry->bss_score = CM_BEST_CANDIDATE_MAX_BSS_SCORE;
780 		mlme_nofl_debug("Candidate(%pM freq %d): rssi %d BSSID hint given, give max score %d",
781 				entry->bssid.bytes, entry->channel.chan_freq,
782 				entry->rssi_raw,
783 				CM_BEST_CANDIDATE_MAX_BSS_SCORE);
784 		return CM_BEST_CANDIDATE_MAX_BSS_SCORE;
785 	}
786 
787 	rssi_score = cm_calculate_rssi_score(&score_config->rssi_score,
788 					     entry->rssi_raw,
789 					     weight_config->rssi_weightage);
790 	score += rssi_score;
791 
792 	pcl_score = cm_calculate_pcl_score(pcl_chan_weight,
793 					   weight_config->pcl_weightage);
794 	score += pcl_score;
795 
796 	prorated_pcnt = cm_roam_calculate_prorated_pcnt_by_rssi(
797 				&score_config->rssi_score, entry->rssi_raw,
798 				weight_config->rssi_weightage);
799 
800 	/*
801 	 * Add HT weight if HT is supported by the AP. In case
802 	 * of 6 GHZ AP, HT and VHT won't be supported so that
803 	 * these weightage to the same by default to match
804 	 * with 2.4/5 GHZ APs where HT, VHT is supported
805 	 */
806 	if (phy_config->ht_cap && (entry->ie_list.htcap ||
807 	    WLAN_REG_IS_6GHZ_CHAN_FREQ(entry->channel.chan_freq)))
808 		ht_score = prorated_pcnt *
809 				weight_config->ht_caps_weightage;
810 	score += ht_score;
811 
812 	if (WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) {
813 		if (phy_config->vht_24G_cap)
814 			is_vht = true;
815 	} else if (phy_config->vht_cap) {
816 		is_vht = true;
817 	}
818 
819 	/* Add VHT score to 6 GHZ AP to match with 2.4/5 GHZ APs */
820 	if (is_vht && (entry->ie_list.vhtcap ||
821 	    WLAN_REG_IS_6GHZ_CHAN_FREQ(entry->channel.chan_freq)))
822 		vht_score = prorated_pcnt *
823 				 weight_config->vht_caps_weightage;
824 	score += vht_score;
825 
826 	if (phy_config->he_cap && entry->ie_list.hecap)
827 		he_score = prorated_pcnt *
828 				 weight_config->he_caps_weightage;
829 	score += he_score;
830 
831 	bandwidth_score = cm_calculate_bandwidth_score(entry, score_config,
832 						       phy_config,
833 						       prorated_pcnt);
834 	score += bandwidth_score;
835 
836 	good_rssi_threshold =
837 		score_config->rssi_score.good_rssi_threshold * (-1);
838 	rssi_pref_5g_rssi_thresh =
839 		score_config->rssi_score.rssi_pref_5g_rssi_thresh * (-1);
840 	if (entry->rssi_raw < good_rssi_threshold)
841 		same_bucket = cm_rssi_is_same_bucket(good_rssi_threshold,
842 				entry->rssi_raw, rssi_pref_5g_rssi_thresh,
843 				score_config->rssi_score.bad_rssi_bucket_size);
844 
845 	vht_cap = (struct wlan_ie_vhtcaps *)util_scan_entry_vhtcap(entry);
846 	if (vht_cap && vht_cap->su_beam_former)
847 		ap_su_beam_former = true;
848 	if (phy_config->beamformee_cap && is_vht &&
849 	    ap_su_beam_former &&
850 	    (entry->rssi_raw > rssi_pref_5g_rssi_thresh) && !same_bucket)
851 		beamformee_score = CM_MAX_PCT_SCORE *
852 				weight_config->beamforming_cap_weightage;
853 	score += beamformee_score;
854 
855 	congestion_score = cm_calculate_congestion_score(entry, score_config,
856 							 &congestion_pct);
857 	score += congestion_score;
858 	/*
859 	 * Consider OCE WAN score and band preference score only if
860 	 * congestion_pct is greater than CONGESTION_THRSHOLD_FOR_BAND_OCE_SCORE
861 	 */
862 	if (congestion_pct < CM_CONGESTION_THRSHOLD_FOR_BAND_OCE_SCORE) {
863 		/*
864 		 * If AP is on 5/6 GHZ channel , extra weigtage is added to BSS
865 		 * score. if RSSI is greater tha 5g rssi threshold or fall in
866 		 * same bucket else give weigtage to 2.4 GHZ AP.
867 		 */
868 		if ((entry->rssi_raw > rssi_pref_5g_rssi_thresh) &&
869 		    !same_bucket) {
870 			if (!WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq))
871 				band_score = cm_get_band_score(
872 						entry->channel.chan_freq,
873 						score_config);
874 		} else if (WLAN_REG_IS_24GHZ_CH_FREQ(
875 			   entry->channel.chan_freq)) {
876 			band_score = cm_get_band_score(entry->channel.chan_freq,
877 						       score_config);
878 		}
879 		score += band_score;
880 
881 		oce_wan_score = cm_calculate_oce_wan_score(entry, score_config);
882 		score += oce_wan_score;
883 	}
884 
885 	oce_ap_tx_pwr_score =
886 		cm_calculate_oce_ap_tx_pwr_weightage(entry, score_config,
887 						     &ap_tx_pwr_dbm);
888 	score += oce_ap_tx_pwr_score;
889 
890 	oce_subnet_id_score = cm_calculate_oce_subnet_id_weightage(entry,
891 						score_config,
892 						&oce_subnet_id_present);
893 	score += oce_subnet_id_score;
894 
895 	sta_nss = cm_get_sta_nss(psoc, entry->channel.chan_freq,
896 				 phy_config->vdev_nss_24g,
897 				 phy_config->vdev_nss_5g);
898 
899 	/*
900 	 * If station support nss as 2*2 but AP support NSS as 1*1,
901 	 * this AP will be given half weight compare to AP which are having
902 	 * NSS as 2*2.
903 	 */
904 	nss_score = cm_calculate_nss_score(psoc, score_config, entry->nss,
905 					   prorated_pcnt, sta_nss);
906 	score += nss_score;
907 
908 	mlme_nofl_debug("Candidate(%pM 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 prorated_pcnt %d",
909 			entry->bssid.bytes, entry->channel.chan_freq,
910 			entry->rssi_raw, util_scan_entry_htcap(entry) ? 1 : 0,
911 			util_scan_entry_vhtcap(entry) ? 1 : 0,
912 			util_scan_entry_hecap(entry) ? 1 : 0, ap_su_beam_former,
913 			entry->phy_mode, entry->air_time_fraction,
914 			entry->qbss_chan_load, congestion_pct, entry->nss,
915 			ap_tx_pwr_dbm, oce_subnet_id_present, prorated_pcnt);
916 
917 	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 TOTAL %d",
918 			rssi_score, pcl_score, ht_score,
919 			vht_score, he_score, beamformee_score, bandwidth_score,
920 			band_score, congestion_score, nss_score, oce_wan_score,
921 			oce_ap_tx_pwr_score, oce_subnet_id_score, score);
922 
923 	entry->bss_score = score;
924 
925 	return score;
926 }
927 
928 static bool
929 cm_get_pcl_weight_of_channel(uint32_t chan_freq,
930 			     struct pcl_freq_weight_list *pcl_lst,
931 			     int *pcl_chan_weight)
932 {
933 	int i;
934 	bool found = false;
935 
936 	if (!pcl_lst)
937 		return found;
938 
939 	for (i = 0; i < pcl_lst->num_of_pcl_channels; i++) {
940 		if (pcl_lst->pcl_freq_list[i] == chan_freq) {
941 			*pcl_chan_weight = pcl_lst->pcl_weight_list[i];
942 			found = true;
943 			break;
944 		}
945 	}
946 
947 	return found;
948 }
949 
950 static void cm_list_insert_sorted(qdf_list_t *scan_list,
951 				  struct scan_cache_node *scan_entry)
952 {
953 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
954 	struct scan_cache_node *curr_entry;
955 
956 	qdf_list_peek_front(scan_list, &cur_node);
957 	while (cur_node) {
958 		curr_entry = qdf_container_of(cur_node, struct scan_cache_node,
959 					      node);
960 		if (cm_is_better_bss(scan_entry->entry, curr_entry->entry)) {
961 			qdf_list_insert_before(scan_list, &scan_entry->node,
962 					       &curr_entry->node);
963 			break;
964 		}
965 		qdf_list_peek_next(scan_list, cur_node, &next_node);
966 		cur_node = next_node;
967 		next_node = NULL;
968 	}
969 
970 	if (!cur_node)
971 		qdf_list_insert_back(scan_list, &scan_entry->node);
972 }
973 
974 static bool cm_is_assoc_allowed(struct psoc_mlme_obj *mlme_psoc_obj,
975 				struct scan_cache_entry *entry)
976 {
977 	uint8_t reason;
978 	uint8_t *mbo_oce;
979 	bool check_assoc_disallowed;
980 
981 	mbo_oce = util_scan_entry_mbo_oce(entry);
982 
983 	check_assoc_disallowed =
984 	   mlme_psoc_obj->psoc_cfg.score_config.check_assoc_disallowed;
985 
986 	if (check_assoc_disallowed &&
987 	    wlan_parse_oce_assoc_disallowed_ie(mbo_oce, &reason)) {
988 		mlme_nofl_debug("Candidate(%pM freq %d): rssi %d, assoc disallowed set in MBO/OCE IE reason %d",
989 				entry->bssid.bytes, entry->channel.chan_freq,
990 				entry->rssi_raw, reason);
991 		return false;
992 	}
993 
994 	return true;
995 }
996 
997 void wlan_cm_calculate_bss_score(struct wlan_objmgr_pdev *pdev,
998 				 struct pcl_freq_weight_list *pcl_lst,
999 				 qdf_list_t *scan_list,
1000 				 struct qdf_mac_addr *bssid_hint)
1001 {
1002 	struct scan_cache_node *scan_entry;
1003 	qdf_list_node_t *cur_node = NULL, *next_node = NULL;
1004 	struct psoc_mlme_obj *mlme_psoc_obj;
1005 	struct scoring_cfg *score_config;
1006 	int pcl_chan_weight;
1007 	QDF_STATUS status;
1008 	struct psoc_phy_config *config;
1009 	enum cm_blacklist_action blacklist_action;
1010 	struct wlan_objmgr_psoc *psoc;
1011 	bool assoc_allowed;
1012 
1013 	psoc = wlan_pdev_get_psoc(pdev);
1014 
1015 	if (!psoc) {
1016 		mlme_err("psoc NULL");
1017 		return;
1018 	}
1019 	if (!scan_list) {
1020 		mlme_err("Scan list NULL");
1021 		return;
1022 	}
1023 
1024 	mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc);
1025 	if (!mlme_psoc_obj)
1026 		return;
1027 
1028 	score_config = &mlme_psoc_obj->psoc_cfg.score_config;
1029 	config = &mlme_psoc_obj->psoc_cfg.phy_config;
1030 
1031 	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",
1032 			config->ht_cap, config->vht_cap,
1033 			config->he_cap, config->vht_24G_cap,
1034 			config->beamformee_cap, config->bw_above_20_24ghz,
1035 			config->bw_above_20_5ghz, config->vdev_nss_24g,
1036 			config->vdev_nss_5g);
1037 
1038 	/* calculate score for each AP */
1039 	if (qdf_list_peek_front(scan_list, &cur_node) != QDF_STATUS_SUCCESS) {
1040 		mlme_err("failed to peer front of scan list");
1041 		return;
1042 	}
1043 
1044 	while (cur_node) {
1045 		qdf_list_peek_next(scan_list, cur_node, &next_node);
1046 		pcl_chan_weight = 0;
1047 		scan_entry = qdf_container_of(cur_node, struct scan_cache_node,
1048 					      node);
1049 
1050 		assoc_allowed = cm_is_assoc_allowed(mlme_psoc_obj,
1051 						    scan_entry->entry);
1052 
1053 		if (assoc_allowed)
1054 			blacklist_action = wlan_blacklist_action_on_bssid(pdev,
1055 							scan_entry->entry);
1056 		else
1057 			blacklist_action = CM_BLM_REMOVE;
1058 
1059 		if (blacklist_action == CM_BLM_NO_ACTION &&
1060 		    pcl_lst && pcl_lst->num_of_pcl_channels &&
1061 		    scan_entry->entry->rssi_raw > CM_PCL_RSSI_THRESHOLD &&
1062 		    score_config->weight_config.pcl_weightage) {
1063 			if (cm_get_pcl_weight_of_channel(
1064 					scan_entry->entry->channel.chan_freq,
1065 					pcl_lst, &pcl_chan_weight)) {
1066 				mlme_debug("pcl freq %d pcl_chan_weight %d",
1067 					   scan_entry->entry->channel.chan_freq,
1068 					   pcl_chan_weight);
1069 			}
1070 		}
1071 
1072 		if (blacklist_action == CM_BLM_NO_ACTION) {
1073 			cm_calculate_bss_score(psoc, scan_entry->entry,
1074 					       pcl_chan_weight, bssid_hint);
1075 		} else if (blacklist_action == CM_BLM_AVOID) {
1076 			/* add min score so that it is added back in the end */
1077 			scan_entry->entry->bss_score =
1078 					CM_AVOID_CANDIDATE_MIN_SCORE;
1079 			mlme_nofl_debug("Candidate(%pM freq %d): rssi %d, is in Avoidlist, give min score %d",
1080 					scan_entry->entry->bssid.bytes,
1081 					scan_entry->entry->channel.chan_freq,
1082 					scan_entry->entry->rssi_raw,
1083 					scan_entry->entry->bss_score);
1084 		}
1085 
1086 		/* Remove node from current locaion to add node back shorted */
1087 		status = qdf_list_remove_node(scan_list, cur_node);
1088 		if (QDF_IS_STATUS_ERROR(status)) {
1089 			mlme_err("failed to remove node for BSS %pM from scan list",
1090 				 scan_entry->entry->bssid.bytes);
1091 			return;
1092 		}
1093 
1094 		/*
1095 		 * If CM_BLM_REMOVE ie blacklisted or assoc not allowed then
1096 		 * free the entry else add back to the list sorted
1097 		 */
1098 		if (blacklist_action == CM_BLM_REMOVE) {
1099 			if (assoc_allowed)
1100 				mlme_nofl_debug("Candidate(%pM freq %d): rssi %d, is in Blacklist, remove entry",
1101 					scan_entry->entry->bssid.bytes,
1102 					scan_entry->entry->channel.chan_freq,
1103 					scan_entry->entry->rssi_raw);
1104 			util_scan_free_cache_entry(scan_entry->entry);
1105 			qdf_mem_free(scan_entry);
1106 		} else {
1107 			cm_list_insert_sorted(scan_list, scan_entry);
1108 		}
1109 
1110 		cur_node = next_node;
1111 		next_node = NULL;
1112 	}
1113 }
1114 
1115 static uint32_t
1116 cm_limit_max_per_index_score(uint32_t per_index_score)
1117 {
1118 	uint8_t i, score;
1119 
1120 	for (i = 0; i < CM_MAX_INDEX_PER_INI; i++) {
1121 		score = CM_GET_SCORE_PERCENTAGE(per_index_score, i);
1122 		if (score > CM_MAX_PCT_SCORE)
1123 			CM_SET_SCORE_PERCENTAGE(per_index_score,
1124 						CM_MAX_PCT_SCORE, i);
1125 	}
1126 
1127 	return per_index_score;
1128 }
1129 
1130 void wlan_cm_init_score_config(struct wlan_objmgr_psoc *psoc,
1131 			       struct scoring_cfg *score_cfg)
1132 {
1133 	uint32_t total_weight;
1134 
1135 	score_cfg->weight_config.rssi_weightage =
1136 		cfg_get(psoc, CFG_SCORING_RSSI_WEIGHTAGE);
1137 	score_cfg->weight_config.ht_caps_weightage =
1138 		cfg_get(psoc, CFG_SCORING_HT_CAPS_WEIGHTAGE);
1139 	score_cfg->weight_config.vht_caps_weightage =
1140 		cfg_get(psoc, CFG_SCORING_VHT_CAPS_WEIGHTAGE);
1141 	score_cfg->weight_config.he_caps_weightage =
1142 		cfg_get(psoc, CFG_SCORING_HE_CAPS_WEIGHTAGE);
1143 	score_cfg->weight_config.chan_width_weightage =
1144 		cfg_get(psoc, CFG_SCORING_CHAN_WIDTH_WEIGHTAGE);
1145 	score_cfg->weight_config.chan_band_weightage =
1146 		cfg_get(psoc, CFG_SCORING_CHAN_BAND_WEIGHTAGE);
1147 	score_cfg->weight_config.nss_weightage =
1148 		cfg_get(psoc, CFG_SCORING_NSS_WEIGHTAGE);
1149 	score_cfg->weight_config.beamforming_cap_weightage =
1150 		cfg_get(psoc, CFG_SCORING_BEAMFORM_CAP_WEIGHTAGE);
1151 	score_cfg->weight_config.pcl_weightage =
1152 		cfg_get(psoc, CFG_SCORING_PCL_WEIGHTAGE);
1153 	score_cfg->weight_config.channel_congestion_weightage =
1154 		cfg_get(psoc, CFG_SCORING_CHAN_CONGESTION_WEIGHTAGE);
1155 	score_cfg->weight_config.oce_wan_weightage =
1156 		cfg_get(psoc, CFG_SCORING_OCE_WAN_WEIGHTAGE);
1157 	score_cfg->weight_config.oce_ap_tx_pwr_weightage =
1158 				cfg_get(psoc, CFG_OCE_AP_TX_PWR_WEIGHTAGE);
1159 	score_cfg->weight_config.oce_subnet_id_weightage =
1160 				cfg_get(psoc, CFG_OCE_SUBNET_ID_WEIGHTAGE);
1161 
1162 	total_weight =  score_cfg->weight_config.rssi_weightage +
1163 			score_cfg->weight_config.ht_caps_weightage +
1164 			score_cfg->weight_config.vht_caps_weightage +
1165 			score_cfg->weight_config.he_caps_weightage +
1166 			score_cfg->weight_config.chan_width_weightage +
1167 			score_cfg->weight_config.chan_band_weightage +
1168 			score_cfg->weight_config.nss_weightage +
1169 			score_cfg->weight_config.beamforming_cap_weightage +
1170 			score_cfg->weight_config.pcl_weightage +
1171 			score_cfg->weight_config.channel_congestion_weightage +
1172 			score_cfg->weight_config.oce_wan_weightage +
1173 			score_cfg->weight_config.oce_ap_tx_pwr_weightage +
1174 			score_cfg->weight_config.oce_subnet_id_weightage;
1175 
1176 	/*
1177 	 * If configured weights are greater than max weight,
1178 	 * fallback to default weights
1179 	 */
1180 	if (total_weight > CM_BEST_CANDIDATE_MAX_WEIGHT) {
1181 		mlme_err("Total weight greater than %d, using default weights",
1182 			 CM_BEST_CANDIDATE_MAX_WEIGHT);
1183 		score_cfg->weight_config.rssi_weightage = CM_RSSI_WEIGHTAGE;
1184 		score_cfg->weight_config.ht_caps_weightage =
1185 						CM_HT_CAPABILITY_WEIGHTAGE;
1186 		score_cfg->weight_config.vht_caps_weightage =
1187 						CM_VHT_CAP_WEIGHTAGE;
1188 		score_cfg->weight_config.he_caps_weightage =
1189 						CM_HE_CAP_WEIGHTAGE;
1190 		score_cfg->weight_config.chan_width_weightage =
1191 						CM_CHAN_WIDTH_WEIGHTAGE;
1192 		score_cfg->weight_config.chan_band_weightage =
1193 						CM_CHAN_BAND_WEIGHTAGE;
1194 		score_cfg->weight_config.nss_weightage = CM_NSS_WEIGHTAGE;
1195 		score_cfg->weight_config.beamforming_cap_weightage =
1196 						CM_BEAMFORMING_CAP_WEIGHTAGE;
1197 		score_cfg->weight_config.pcl_weightage = CM_PCL_WEIGHT;
1198 		score_cfg->weight_config.channel_congestion_weightage =
1199 						CM_CHANNEL_CONGESTION_WEIGHTAGE;
1200 		score_cfg->weight_config.oce_wan_weightage =
1201 						CM_OCE_WAN_WEIGHTAGE;
1202 		score_cfg->weight_config.oce_ap_tx_pwr_weightage =
1203 						CM_OCE_AP_TX_POWER_WEIGHTAGE;
1204 		score_cfg->weight_config.oce_subnet_id_weightage =
1205 						CM_OCE_SUBNET_ID_WEIGHTAGE;
1206 	}
1207 
1208 	score_cfg->rssi_score.best_rssi_threshold =
1209 		cfg_get(psoc, CFG_SCORING_BEST_RSSI_THRESHOLD);
1210 	score_cfg->rssi_score.good_rssi_threshold =
1211 		cfg_get(psoc, CFG_SCORING_GOOD_RSSI_THRESHOLD);
1212 	score_cfg->rssi_score.bad_rssi_threshold =
1213 		cfg_get(psoc, CFG_SCORING_BAD_RSSI_THRESHOLD);
1214 
1215 	score_cfg->rssi_score.good_rssi_pcnt =
1216 		cfg_get(psoc, CFG_SCORING_GOOD_RSSI_PERCENT);
1217 	score_cfg->rssi_score.bad_rssi_pcnt =
1218 		cfg_get(psoc, CFG_SCORING_BAD_RSSI_PERCENT);
1219 
1220 	score_cfg->rssi_score.good_rssi_bucket_size =
1221 		cfg_get(psoc, CFG_SCORING_GOOD_RSSI_BUCKET_SIZE);
1222 	score_cfg->rssi_score.bad_rssi_bucket_size =
1223 		cfg_get(psoc, CFG_SCORING_BAD_RSSI_BUCKET_SIZE);
1224 
1225 	score_cfg->rssi_score.rssi_pref_5g_rssi_thresh =
1226 		cfg_get(psoc, CFG_SCORING_RSSI_PREF_5G_THRESHOLD);
1227 
1228 	score_cfg->esp_qbss_scoring.num_slot =
1229 		cfg_get(psoc, CFG_SCORING_NUM_ESP_QBSS_SLOTS);
1230 	score_cfg->esp_qbss_scoring.score_pcnt3_to_0 =
1231 		cm_limit_max_per_index_score(
1232 			cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_3_TO_0));
1233 	score_cfg->esp_qbss_scoring.score_pcnt7_to_4 =
1234 		cm_limit_max_per_index_score(
1235 			cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_7_TO_4));
1236 	score_cfg->esp_qbss_scoring.score_pcnt11_to_8 =
1237 		cm_limit_max_per_index_score(
1238 			cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_11_TO_8));
1239 	score_cfg->esp_qbss_scoring.score_pcnt15_to_12 =
1240 		cm_limit_max_per_index_score(
1241 			cfg_get(psoc, CFG_SCORING_ESP_QBSS_SCORE_IDX_15_TO_12));
1242 
1243 	score_cfg->oce_wan_scoring.num_slot =
1244 		cfg_get(psoc, CFG_SCORING_NUM_OCE_WAN_SLOTS);
1245 	score_cfg->oce_wan_scoring.score_pcnt3_to_0 =
1246 		cm_limit_max_per_index_score(
1247 			cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_3_TO_0));
1248 	score_cfg->oce_wan_scoring.score_pcnt7_to_4 =
1249 		cm_limit_max_per_index_score(
1250 			cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_7_TO_4));
1251 	score_cfg->oce_wan_scoring.score_pcnt11_to_8 =
1252 		cm_limit_max_per_index_score(
1253 			cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_11_TO_8));
1254 	score_cfg->oce_wan_scoring.score_pcnt15_to_12 =
1255 		cm_limit_max_per_index_score(
1256 			cfg_get(psoc, CFG_SCORING_OCE_WAN_SCORE_IDX_15_TO_12));
1257 
1258 	score_cfg->bandwidth_weight_per_index =
1259 		cm_limit_max_per_index_score(
1260 			cfg_get(psoc, CFG_SCORING_BW_WEIGHT_PER_IDX));
1261 	score_cfg->nss_weight_per_index =
1262 		cm_limit_max_per_index_score(
1263 			cfg_get(psoc, CFG_SCORING_NSS_WEIGHT_PER_IDX));
1264 	score_cfg->band_weight_per_index =
1265 		cm_limit_max_per_index_score(
1266 			cfg_get(psoc, CFG_SCORING_BAND_WEIGHT_PER_IDX));
1267 	score_cfg->is_bssid_hint_priority =
1268 			cfg_get(psoc, CFG_IS_BSSID_HINT_PRIORITY);
1269 	score_cfg->check_assoc_disallowed = false;
1270 }
1271 
1272 void wlan_cm_set_check_assoc_disallowed(struct wlan_objmgr_psoc *psoc,
1273 					bool value)
1274 {
1275 	struct psoc_mlme_obj *mlme_psoc_obj;
1276 
1277 	mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc);
1278 	if (!mlme_psoc_obj)
1279 		return;
1280 
1281 	mlme_psoc_obj->psoc_cfg.score_config.check_assoc_disallowed = value;
1282 }
1283