瀏覽代碼

qcacmn: Select candidate by ETP when connect

If ini vendor_roam_score_algorithm=1, for initial connect, select
candidate by estimated throughput(ETP). Calculate ETP of all
bssid of ssid selected by high layer, and try to connect AP by
order of ETP, legacy algorithm with following Parameters/Weightage
becomes useless. ETP should be [1Mbps, 20000Mbps],matches score
range: [1, 20000].
Add 11ax support besides 11ac/11abgn.

Change-Id: I3f55d2ae37801128b8a66f6d5c2ac55cb11a56d0
CRs-Fixed: 2704154
Jianmin Zhu 4 年之前
父節點
當前提交
66fcfe0178

+ 492 - 2
umac/mlme/connection_mgr/core/src/wlan_cm_bss_scoring.c

@@ -27,6 +27,10 @@
 #include "wlan_cm_bss_score_param.h"
 #include "wlan_cm_bss_score_param.h"
 #include "wlan_scan_api.h"
 #include "wlan_scan_api.h"
 #include "wlan_crypto_global_api.h"
 #include "wlan_crypto_global_api.h"
+#include "wlan_mgmt_txrx_utils_api.h"
+#ifdef CONN_MGR_ADV_FEATURE
+#include "wlan_mlme_api.h"
+#endif
 
 
 #define CM_20MHZ_BW_INDEX                  0
 #define CM_20MHZ_BW_INDEX                  0
 #define CM_40MHZ_BW_INDEX                  1
 #define CM_40MHZ_BW_INDEX                  1
@@ -96,6 +100,29 @@
 #define CM_SET_SCORE_PERCENTAGE(value32, score_pcnt, bw_index) \
 #define CM_SET_SCORE_PERCENTAGE(value32, score_pcnt, bw_index) \
 	QDF_SET_BITS(value32, (8 * (bw_index)), 8, score_pcnt)
 	QDF_SET_BITS(value32, (8 * (bw_index)), 8, score_pcnt)
 
 
+#ifdef CONN_MGR_ADV_FEATURE
+/* 3.2 us + 0.8 us(GI) */
+#define PPDU_PAYLOAD_SYMBOL_DUR_US 4
+/* 12.8 us + (0.8 + 1.6)/2 us(GI) */
+#define HE_PPDU_PAYLOAD_SYMBOL_DUR_US 14
+#define MAC_HEADER_LEN 26
+/* Minimum snrDb supported by LUT */
+#define SNR_DB_TO_BIT_PER_TONE_LUT_MIN -10
+/* Maximum snrDb supported by LUT */
+#define SNR_DB_TO_BIT_PER_TONE_LUT_MAX 9
+#define DB_NUM 20
+/*
+ * A fudge factor to represent HW implementation margin in dB.
+ * Predicted throughput matches pretty well with OTA throughput with this
+ * fudge factor.
+ */
+#define SNR_MARGIN_DB 16
+#define TWO_IN_DB 3
+static int32_t
+SNR_DB_TO_BIT_PER_TONE_LUT[DB_NUM] = {0, 171, 212, 262, 323, 396, 484,
+586, 706, 844, 1000, 1176, 1370, 1583, 1812, 2058, 2317, 2588, 2870, 3161};
+#endif
+
 static bool cm_is_better_bss(struct scan_cache_entry *bss1,
 static bool cm_is_better_bss(struct scan_cache_entry *bss1,
 			     struct scan_cache_entry *bss2)
 			     struct scan_cache_entry *bss2)
 {
 {
@@ -815,6 +842,455 @@ void wlan_cm_get_check_assoc_disallowed(struct wlan_objmgr_psoc *psoc,
 	*value = mlme_psoc_obj->psoc_cfg.score_config.check_assoc_disallowed;
 	*value = mlme_psoc_obj->psoc_cfg.score_config.check_assoc_disallowed;
 }
 }
 
 
+static enum phy_ch_width
+cm_calculate_bandwidth(struct scan_cache_entry *entry,
+		       struct psoc_phy_config *phy_config)
+{
+	uint8_t bw_above_20 = 0;
+	bool is_vht = false;
+	enum phy_ch_width ch_width;
+
+	if (WLAN_REG_IS_24GHZ_CH_FREQ(entry->channel.chan_freq)) {
+		bw_above_20 = phy_config->bw_above_20_24ghz;
+		if (phy_config->vht_24G_cap)
+			is_vht = true;
+	} else if (phy_config->vht_cap) {
+		is_vht = true;
+		bw_above_20 = phy_config->bw_above_20_5ghz;
+	}
+
+	if (IS_WLAN_PHYMODE_160MHZ(entry->phy_mode))
+		ch_width = CH_WIDTH_160MHZ;
+	else if (IS_WLAN_PHYMODE_80MHZ(entry->phy_mode))
+		ch_width = CH_WIDTH_80MHZ;
+	else if (IS_WLAN_PHYMODE_40MHZ(entry->phy_mode))
+		ch_width = CH_WIDTH_40MHZ;
+	else
+		ch_width = CH_WIDTH_20MHZ;
+
+	if (!phy_config->ht_cap &&
+	    ch_width >= CH_WIDTH_20MHZ)
+		ch_width = CH_WIDTH_20MHZ;
+
+	if (!is_vht && ch_width > CH_WIDTH_40MHZ)
+		ch_width = CH_WIDTH_40MHZ;
+
+	if (!bw_above_20)
+		ch_width = CH_WIDTH_20MHZ;
+
+	return ch_width;
+}
+
+static uint8_t cm_etp_get_ba_win_size_from_esp(uint8_t esp_ba_win_size)
+{
+	/*
+	 * BA Window Size subfield is three bits in length and indicates the
+	 * size of the Block Ack window that is.
+	 * 802.11-2016.pdf Table 9-262 BA Window Size subfield encoding
+	 */
+	switch (esp_ba_win_size) {
+	case 1: return 2;
+	case 2: return 4;
+	case 3: return 6;
+	case 4: return 8;
+	case 5: return 16;
+	case 6: return 32;
+	case 7: return 64;
+	default: return 1;
+	}
+}
+
+static uint16_t cm_get_etp_ntone(bool is_ht, bool is_vht,
+				 enum phy_ch_width ch_width)
+{
+	uint16_t n_sd = 52, n_seg = 1;
+
+	if (is_vht) {
+		/* Refer Table 21-5 in IEEE80211-2016 Spec */
+		if (ch_width == CH_WIDTH_20MHZ)
+			n_sd = 52;
+		else if (ch_width == CH_WIDTH_40MHZ)
+			n_sd = 108;
+		else if (ch_width == CH_WIDTH_80MHZ)
+			n_sd = 234;
+		else if (ch_width == CH_WIDTH_80P80MHZ)
+			n_sd = 234, n_seg = 2;
+		else if (ch_width == CH_WIDTH_160MHZ)
+			n_sd = 468;
+	} else if (is_ht) {
+		/* Refer Table 19-6 in IEEE80211-2016 Spec */
+		if (ch_width == CH_WIDTH_20MHZ)
+			n_sd = 52;
+		if (ch_width == CH_WIDTH_40MHZ)
+			n_sd = 108;
+	} else {
+		n_sd = 48;
+	}
+
+	return (n_sd * n_seg);
+}
+
+/* Refer Table 27-64 etc in Draft P802.11ax_D7.0.txt */
+static uint16_t cm_get_etp_he_ntone(enum phy_ch_width ch_width)
+{
+	uint16_t n_sd = 234, n_seg = 1;
+
+	if (ch_width == CH_WIDTH_20MHZ)
+		n_sd = 234;
+	else if (ch_width == CH_WIDTH_40MHZ)
+		n_sd = 468;
+	else if (ch_width == CH_WIDTH_80MHZ)
+		n_sd = 980;
+	else if (ch_width == CH_WIDTH_80P80MHZ)
+		n_sd = 980, n_seg = 2;
+	else if (ch_width == CH_WIDTH_160MHZ)
+		n_sd = 1960;
+
+	return (n_sd * n_seg);
+}
+
+static uint16_t cm_get_etp_phy_header_dur_us(bool is_ht, bool is_vht,
+					     uint8_t nss)
+{
+	uint16_t dur_us = 0;
+
+	if (is_vht) {
+		/*
+		 * Refer Figure 21-4 in 80211-2016 Spec
+		 * 8 (L-STF) + 8 (L-LTF) + 4 (L-SIG) +
+		 * 8 (VHT-SIG-A) + 4 (VHT-STF) + 4 (VHT-SIG-B)
+		 */
+		dur_us = 36;
+		/* (nss * VHT-LTF) = (nss * 4) */
+		dur_us += (nss << 2);
+	} else if (is_ht) {
+		/*
+		 * Refer Figure 19-1 in 80211-2016 Spec
+		 * 8 (L-STF) + 8 (L-LTF) + 4 (L-SIG) + 8 (HT-SIG) +
+		 * 4 (HT-STF)
+		 */
+		dur_us = 32;
+		/* (nss * HT-LTF = nss * 4) */
+		dur_us += (nss << 2);
+	} else {
+		/*
+		 * non-HT
+		 * Refer Figure 19-1 in 80211-2016 Spec
+		 * 8 (L-STF) + 8 (L-LTF) + 4 (L-SIG)
+		 */
+		dur_us = 20;
+	}
+	return dur_us;
+}
+
+static uint32_t
+cm_get_etp_max_bits_per_sc_1000x_for_nss(struct wlan_objmgr_psoc *psoc,
+					 struct scan_cache_entry *entry,
+					 uint8_t nss,
+					 struct psoc_phy_config *phy_config)
+{
+	uint32_t max_bits_per_sc_1000x = 5000; /* 5 * 1000 */
+	uint8_t mcs_map;
+	struct wlan_ie_vhtcaps *bss_vht_cap;
+	struct wlan_ie_hecaps *bss_he_cap;
+	uint32_t self_rx_mcs_map;
+	QDF_STATUS status;
+
+	bss_vht_cap = (struct wlan_ie_vhtcaps *)util_scan_entry_vhtcap(entry);
+	bss_he_cap = (struct wlan_ie_hecaps *)util_scan_entry_hecap(entry);
+	if (!phy_config->vht_cap || !bss_vht_cap) {
+		mlme_err("vht unsupported");
+		return max_bits_per_sc_1000x;
+	}
+
+	status = wlan_mlme_cfg_get_vht_rx_mcs_map(psoc, &self_rx_mcs_map);
+	if (QDF_IS_STATUS_ERROR(status))
+		return max_bits_per_sc_1000x;
+
+	if (nss == 4) {
+		mcs_map = (self_rx_mcs_map & 0xC0) >> 6;
+		mcs_map = QDF_MIN(mcs_map,
+				  (bss_vht_cap->rx_mcs_map & 0xC0) >> 6);
+	} else if (nss == 3) {
+		mcs_map = (self_rx_mcs_map & 0x30) >> 4;
+		mcs_map = QDF_MIN(mcs_map,
+				  (bss_vht_cap->rx_mcs_map & 0x30) >> 4);
+	} else if (nss == 2) {
+		mcs_map = (self_rx_mcs_map & 0x0C) >> 2;
+		mcs_map = QDF_MIN(mcs_map,
+				  (bss_vht_cap->rx_mcs_map & 0x0C) >> 2);
+	} else {
+		mcs_map = (self_rx_mcs_map & 0x03);
+		mcs_map = QDF_MIN(mcs_map, (bss_vht_cap->rx_mcs_map & 0x03));
+	}
+	if (bss_he_cap) {
+		if (mcs_map == 2)
+			max_bits_per_sc_1000x = 8333; /* 10 *5/6 * 1000 */
+		else if (mcs_map == 1)
+			max_bits_per_sc_1000x = 7500; /* 10 * 3/4 * 1000 */
+	} else {
+		if (mcs_map == 2)
+			max_bits_per_sc_1000x = 6667; /* 8 * 5/6 * 1000 */
+		else if (mcs_map == 1)
+			max_bits_per_sc_1000x = 6000; /* 8 * 3/4 * 1000 */
+	}
+	return max_bits_per_sc_1000x;
+}
+
+/* Refer Table 9-163 in 80211-2016 Spec */
+static uint32_t cm_etp_get_min_mpdu_ss_us_100x(struct htcap_cmn_ie *htcap)
+{
+	tSirMacHTParametersInfo *ampdu_param;
+	uint8_t ampdu_density;
+
+	ampdu_param = (tSirMacHTParametersInfo *)&htcap->ampdu_param;
+	ampdu_density = ampdu_param->mpduDensity;
+
+	if (ampdu_density == 1)
+		return 25; /* (1/4) * 100 */
+	else if (ampdu_density == 2)
+		return 50; /* (1/2) * 100 */
+	else if (ampdu_density == 3)
+		return 100; /* 1 * 100 */
+	else if (ampdu_density == 4)
+		return 200; /* 2 * 100 */
+	else if (ampdu_density == 5)
+		return 400; /* 4 * 100 */
+	else if (ampdu_density == 6)
+		return 800; /* 8 * 100 */
+	else if (ampdu_density == 7)
+		return 1600; /* 16 * 100 */
+	else
+		return 100;
+}
+
+/* Refer Table 9-162 in 80211-2016 Spec */
+static uint32_t cm_etp_get_max_amsdu_len(struct wlan_objmgr_psoc *psoc,
+					 struct htcap_cmn_ie *htcap)
+{
+	uint8_t bss_max_amsdu;
+	uint32_t bss_max_amsdu_len;
+	QDF_STATUS status;
+
+	status = wlan_mlme_get_max_amsdu_num(psoc, &bss_max_amsdu);
+	if (QDF_IS_STATUS_ERROR(status))
+		bss_max_amsdu_len = 3839;
+	else if (bss_max_amsdu == 1)
+		bss_max_amsdu_len =  7935;
+	else
+		bss_max_amsdu_len = 3839;
+
+	return bss_max_amsdu_len;
+}
+
+   // Calculate the number of bits per tone based on the input of SNR in dB
+    // The output is scaled up by BIT_PER_TONE_SCALE for integer representation
+static uint32_t
+calculate_bit_per_tone(int32_t rssi, enum phy_ch_width ch_width)
+{
+	int32_t noise_floor_db_boost;
+	int32_t noise_floor_dbm;
+	int32_t snr_db;
+	int32_t bit_per_tone;
+	int32_t lut_in_idx;
+
+	noise_floor_db_boost = TWO_IN_DB * ch_width;
+	noise_floor_dbm = WLAN_NOISE_FLOOR_DBM_DEFAULT + noise_floor_db_boost +
+			SNR_MARGIN_DB;
+	snr_db = rssi - noise_floor_dbm;
+	if (snr_db <= SNR_DB_TO_BIT_PER_TONE_LUT_MAX) {
+		lut_in_idx = QDF_MAX(snr_db, SNR_DB_TO_BIT_PER_TONE_LUT_MIN)
+			- SNR_DB_TO_BIT_PER_TONE_LUT_MIN;
+		lut_in_idx = QDF_MIN(lut_in_idx, DB_NUM - 1);
+		bit_per_tone = SNR_DB_TO_BIT_PER_TONE_LUT[lut_in_idx];
+	} else {
+		/*
+		 * SNR_tone = 10^(SNR/10)
+		 * log2(1+SNR_tone) ~= log2(SNR_tone) =
+		 * log10(SNR_tone)/log10(2) = log10(10^(SNR/10)) / 0.3
+		 * = (SNR/10) / 0.3 = SNR/3
+		 * So log2(1+SNR_tone) = SNR/3. 1000x for this is SNR*334
+		 */
+		bit_per_tone = snr_db * 334;
+	}
+
+	return bit_per_tone;
+}
+
+static uint32_t
+cm_calculate_etp(struct wlan_objmgr_psoc *psoc,
+		 struct scan_cache_entry *entry,
+		 struct etp_params  *etp_param,
+		 uint8_t max_nss, enum phy_ch_width ch_width,
+		 bool is_ht, bool is_vht, bool is_he,
+		 int8_t rssi,
+		 struct psoc_phy_config *phy_config)
+{
+	uint16_t ntone;
+	uint16_t phy_hdr_dur_us, max_amsdu_len = 1500, min_mpdu_ss_us_100x = 0;
+	uint32_t max_bits_per_sc_1000x, log_2_snr_tone_1000x;
+	uint32_t ppdu_payload_dur_us = 0, mpdu_per_ampdu, mpdu_per_ppdu;
+	uint32_t single_ppdu_dur_us, estimated_throughput_mbps, data_rate_kbps;
+	struct htcap_cmn_ie *htcap;
+
+	htcap = (struct htcap_cmn_ie *)util_scan_entry_htcap(entry);
+	if (ch_width > CH_WIDTH_160MHZ)
+		return CM_AVOID_CANDIDATE_MIN_SCORE;
+
+	if (is_he)
+		ntone = cm_get_etp_he_ntone(ch_width);
+	else
+		ntone = cm_get_etp_ntone(is_ht, is_vht, ch_width);
+	phy_hdr_dur_us = cm_get_etp_phy_header_dur_us(is_ht, is_vht, max_nss);
+
+	max_bits_per_sc_1000x =
+		cm_get_etp_max_bits_per_sc_1000x_for_nss(psoc, entry,
+							 max_nss, phy_config);
+	if (rssi < WLAN_NOISE_FLOOR_DBM_DEFAULT)
+		return CM_AVOID_CANDIDATE_MIN_SCORE;
+
+	log_2_snr_tone_1000x = calculate_bit_per_tone(rssi, ch_width);
+
+	/* Eq. R-2 Pg:3508 in 80211-2016 Spec */
+	if (is_he)
+		data_rate_kbps =
+			QDF_MIN(log_2_snr_tone_1000x, max_bits_per_sc_1000x) *
+			(max_nss * ntone) / HE_PPDU_PAYLOAD_SYMBOL_DUR_US;
+	else
+		data_rate_kbps =
+			QDF_MIN(log_2_snr_tone_1000x, max_bits_per_sc_1000x) *
+			(max_nss * ntone) / PPDU_PAYLOAD_SYMBOL_DUR_US;
+	mlme_debug("data_rate_kbps: %d", data_rate_kbps);
+	if (data_rate_kbps < 1000) {
+		/* Return ETP as 1 since datarate is not even 1 Mbps */
+		return CM_AVOID_CANDIDATE_MIN_SCORE;
+	}
+	/* compute MPDU_p_PPDU */
+	if (is_ht) {
+		min_mpdu_ss_us_100x =
+			cm_etp_get_min_mpdu_ss_us_100x(htcap);
+		max_amsdu_len =
+			cm_etp_get_max_amsdu_len(psoc, htcap);
+		ppdu_payload_dur_us =
+			etp_param->data_ppdu_dur_target_us - phy_hdr_dur_us;
+		mpdu_per_ampdu =
+			QDF_MIN(qdf_ceil(ppdu_payload_dur_us * 100,
+					 min_mpdu_ss_us_100x),
+				qdf_ceil(ppdu_payload_dur_us *
+					 (data_rate_kbps / 1000),
+					 (MAC_HEADER_LEN + max_amsdu_len) * 8));
+		mpdu_per_ppdu = QDF_MIN(etp_param->ba_window_size,
+					QDF_MAX(1, mpdu_per_ampdu));
+	} else {
+		mpdu_per_ppdu = 1;
+	}
+
+	/* compute PPDU_Dur */
+	single_ppdu_dur_us =
+		qdf_ceil((MAC_HEADER_LEN + max_amsdu_len) * mpdu_per_ppdu * 8,
+			 (data_rate_kbps / 1000) * PPDU_PAYLOAD_SYMBOL_DUR_US);
+	single_ppdu_dur_us *= PPDU_PAYLOAD_SYMBOL_DUR_US;
+	single_ppdu_dur_us += phy_hdr_dur_us;
+
+	estimated_throughput_mbps =
+		qdf_ceil(mpdu_per_ppdu * max_amsdu_len * 8, single_ppdu_dur_us);
+	estimated_throughput_mbps =
+		(estimated_throughput_mbps *
+		 etp_param->airtime_fraction) /
+		 CM_MAX_ESTIMATED_AIR_TIME_FRACTION;
+
+	if (estimated_throughput_mbps < CM_AVOID_CANDIDATE_MIN_SCORE)
+		estimated_throughput_mbps = CM_AVOID_CANDIDATE_MIN_SCORE;
+	if (estimated_throughput_mbps > CM_BEST_CANDIDATE_MAX_BSS_SCORE)
+		estimated_throughput_mbps = CM_BEST_CANDIDATE_MAX_BSS_SCORE;
+
+	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",
+			QDF_MAC_ADDR_REF(entry->bssid.bytes),
+			entry->channel.chan_freq,
+			entry->rssi_raw, is_ht, is_vht, is_he,
+			etp_param->airtime_fraction,
+			entry->nss, ch_width);
+	if (is_ht)
+		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",
+				min_mpdu_ss_us_100x, max_amsdu_len,
+				ppdu_payload_dur_us, mpdu_per_ampdu,
+				mpdu_per_ppdu, etp_param->ba_window_size);
+	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",
+			ntone, phy_hdr_dur_us, max_bits_per_sc_1000x,
+			log_2_snr_tone_1000x, mpdu_per_ppdu, max_amsdu_len,
+			single_ppdu_dur_us, estimated_throughput_mbps);
+
+	return estimated_throughput_mbps;
+}
+
+static uint32_t
+cm_calculate_etp_score(struct wlan_objmgr_psoc *psoc,
+		       struct scan_cache_entry *entry,
+		       struct psoc_phy_config *phy_config)
+{
+	enum phy_ch_width ch_width;
+	uint32_t nss;
+	bool is_he_intersect = false;
+	bool is_vht_intersect = false;
+	bool is_ht_intersect = false;
+	struct wlan_esp_info *esp;
+	struct wlan_esp_ie *esp_ie;
+	struct etp_params etp_param;
+
+	if (phy_config->he_cap && entry->ie_list.hecap)
+		is_he_intersect = true;
+	if ((phy_config->vht_cap || phy_config->vht_24G_cap) &&
+	    (entry->ie_list.vhtcap ||
+	     WLAN_REG_IS_6GHZ_CHAN_FREQ(entry->channel.chan_freq)))
+		is_vht_intersect = true;
+	if (phy_config->ht_cap && entry->ie_list.htcap)
+		is_ht_intersect = true;
+	nss = cm_get_sta_nss(psoc, entry->channel.chan_freq,
+			     phy_config->vdev_nss_24g,
+			     phy_config->vdev_nss_5g);
+	nss = QDF_MIN(nss, entry->nss);
+	ch_width = cm_calculate_bandwidth(entry, phy_config);
+
+	/* Initialize default ETP params */
+	etp_param.airtime_fraction = 255 / 2;
+	etp_param.ba_window_size = 32;
+	etp_param.data_ppdu_dur_target_us = 5000; /* 5 msec */
+
+	if (entry->air_time_fraction) {
+		etp_param.airtime_fraction = entry->air_time_fraction;
+		esp_ie = (struct wlan_esp_ie *)
+			util_scan_entry_esp_info(entry);
+		if (esp_ie) {
+			esp = &esp_ie->esp_info_AC_BE;
+			etp_param.ba_window_size =
+				cm_etp_get_ba_win_size_from_esp(esp->ba_window_size);
+			etp_param.data_ppdu_dur_target_us =
+					50 * esp->ppdu_duration;
+			mlme_debug("esp ba_window_size: %d, ppdu_duration: %d",
+				   esp->ba_window_size, esp->ppdu_duration);
+		}
+	} else if (entry->qbss_chan_load) {
+		mlme_debug("qbss_chan_load: %d", entry->qbss_chan_load);
+		etp_param.airtime_fraction =
+			CM_MAX_ESTIMATED_AIR_TIME_FRACTION -
+			entry->qbss_chan_load;
+	}
+	/* If ini vendor_roam_score_algorithm=1, just calculate ETP of all
+	 * bssid of ssid selected by high layer, and try to connect AP by
+	 * order of ETP, legacy algorithm with following Parameters/Weightage
+	 * becomes useless. ETP should be [1Mbps, 20000Mbps],matches score
+	 * range: [1, 20000]
+	 */
+	return cm_calculate_etp(psoc, entry,
+				  &etp_param,
+				  nss,
+				  ch_width,
+				  is_ht_intersect,
+				  is_vht_intersect,
+				  is_he_intersect,
+				  entry->rssi_raw,
+				  phy_config);
+}
 #else
 #else
 static bool
 static bool
 cm_get_pcl_weight_of_channel(uint32_t chan_freq,
 cm_get_pcl_weight_of_channel(uint32_t chan_freq,
@@ -865,6 +1341,14 @@ static inline bool cm_is_assoc_allowed(struct psoc_mlme_obj *mlme_psoc_obj,
 {
 {
 	return true;
 	return true;
 }
 }
+
+static uint32_t
+cm_calculate_etp_score(struct wlan_objmgr_psoc *psoc,
+		       struct scan_cache_entry *entry,
+		       struct psoc_phy_config *phy_config)
+{
+	return 0;
+}
 #endif
 #endif
 
 
 /**
 /**
@@ -934,9 +1418,9 @@ static int cm_calculate_bss_score(struct wlan_objmgr_psoc *psoc,
 	struct psoc_phy_config *phy_config;
 	struct psoc_phy_config *phy_config;
 
 
 	mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc);
 	mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc);
-
 	if (!mlme_psoc_obj)
 	if (!mlme_psoc_obj)
 		return 0;
 		return 0;
+
 	phy_config = &mlme_psoc_obj->psoc_cfg.phy_config;
 	phy_config = &mlme_psoc_obj->psoc_cfg.phy_config;
 	score_config = &mlme_psoc_obj->psoc_cfg.score_config;
 	score_config = &mlme_psoc_obj->psoc_cfg.score_config;
 	weight_config = &score_config->weight_config;
 	weight_config = &score_config->weight_config;
@@ -951,7 +1435,11 @@ static int cm_calculate_bss_score(struct wlan_objmgr_psoc *psoc,
 				CM_BEST_CANDIDATE_MAX_BSS_SCORE);
 				CM_BEST_CANDIDATE_MAX_BSS_SCORE);
 		return CM_BEST_CANDIDATE_MAX_BSS_SCORE;
 		return CM_BEST_CANDIDATE_MAX_BSS_SCORE;
 	}
 	}
-
+	if (score_config->vendor_roam_score_algorithm) {
+		score = cm_calculate_etp_score(psoc, entry, phy_config);
+		entry->bss_score = score;
+		return score;
+	}
 	rssi_score = cm_calculate_rssi_score(&score_config->rssi_score,
 	rssi_score = cm_calculate_rssi_score(&score_config->rssi_score,
 					     entry->rssi_raw,
 					     entry->rssi_raw,
 					     weight_config->rssi_weightage);
 					     weight_config->rssi_weightage);
@@ -1401,5 +1889,7 @@ void wlan_cm_init_score_config(struct wlan_objmgr_psoc *psoc,
 			cfg_get(psoc, CFG_SCORING_BAND_WEIGHT_PER_IDX));
 			cfg_get(psoc, CFG_SCORING_BAND_WEIGHT_PER_IDX));
 	score_cfg->is_bssid_hint_priority =
 	score_cfg->is_bssid_hint_priority =
 			cfg_get(psoc, CFG_IS_BSSID_HINT_PRIORITY);
 			cfg_get(psoc, CFG_IS_BSSID_HINT_PRIORITY);
+	score_cfg->vendor_roam_score_algorithm =
+			cfg_get(psoc, CFG_VENDOR_ROAM_SCORE_ALGORITHM);
 	score_cfg->check_assoc_disallowed = true;
 	score_cfg->check_assoc_disallowed = true;
 }
 }

+ 26 - 1
umac/mlme/connection_mgr/dispatcher/inc/cfg_mlme_score_params.h

@@ -1080,6 +1080,30 @@
 			CFG_VALUE_OR_DEFAULT, \
 			CFG_VALUE_OR_DEFAULT, \
 			"Set priority for connection with bssid_hint")
 			"Set priority for connection with bssid_hint")
 
 
+/*
+ * <ini>
+ * vendor_roam_score_algorithm - Algorithm to calculate AP score
+ * @Min: false
+ * @Max: true
+ * @Default: false
+ *
+ * By default the value is false and default roam algorithm will be used.
+ * When the value is true, the V2 roaming algorithm will be used:
+ * For this V2 algo, AP score calculation is based on ETP and below equation:
+ * AP Score = (RSSIfactor * rssiweight(0.65)) + (CUfactor *cuweight(0.35))
+ *
+ * Related: None
+ *
+ * Supported Feature: roam score algorithm
+ *
+ * Usage: External
+ *
+ * </ini>
+ */
+#define CFG_VENDOR_ROAM_SCORE_ALGORITHM \
+	CFG_INI_BOOL("vendor_roam_score_algorithm", false, \
+	"Roam candidate selection score algorithm")
+
 #define CFG_MLME_SCORE_ALL \
 #define CFG_MLME_SCORE_ALL \
 	CFG(CFG_SCORING_RSSI_WEIGHTAGE) \
 	CFG(CFG_SCORING_RSSI_WEIGHTAGE) \
 	CFG(CFG_SCORING_HT_CAPS_WEIGHTAGE) \
 	CFG(CFG_SCORING_HT_CAPS_WEIGHTAGE) \
@@ -1116,6 +1140,7 @@
 	CFG(CFG_SCORING_OCE_WAN_SCORE_IDX_7_TO_4) \
 	CFG(CFG_SCORING_OCE_WAN_SCORE_IDX_7_TO_4) \
 	CFG(CFG_SCORING_OCE_WAN_SCORE_IDX_11_TO_8) \
 	CFG(CFG_SCORING_OCE_WAN_SCORE_IDX_11_TO_8) \
 	CFG(CFG_SCORING_OCE_WAN_SCORE_IDX_15_TO_12) \
 	CFG(CFG_SCORING_OCE_WAN_SCORE_IDX_15_TO_12) \
-	CFG(CFG_IS_BSSID_HINT_PRIORITY)
+	CFG(CFG_IS_BSSID_HINT_PRIORITY) \
+	CFG(CFG_VENDOR_ROAM_SCORE_ALGORITHM)
 
 
 #endif /* __CFG_MLME_SCORE_PARAMS_H */
 #endif /* __CFG_MLME_SCORE_PARAMS_H */

+ 14 - 0
umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_bss_score_param.h

@@ -127,6 +127,7 @@ struct per_slot_score {
  * @band_weight_per_index: band weight per index
  * @band_weight_per_index: band weight per index
  * @is_bssid_hint_priority: True if bssid_hint is given priority
  * @is_bssid_hint_priority: True if bssid_hint is given priority
  * @check_assoc_disallowed: Should assoc be disallowed if MBO OCE IE indicate so
  * @check_assoc_disallowed: Should assoc be disallowed if MBO OCE IE indicate so
+ * @vendor_roam_score_algorithm: Preferred ETP vendor roam score algorithm
  */
  */
 struct scoring_cfg {
 struct scoring_cfg {
 	struct weight_cfg weight_config;
 	struct weight_cfg weight_config;
@@ -138,6 +139,7 @@ struct scoring_cfg {
 	uint32_t band_weight_per_index;
 	uint32_t band_weight_per_index;
 	bool is_bssid_hint_priority;
 	bool is_bssid_hint_priority;
 	bool check_assoc_disallowed;
 	bool check_assoc_disallowed;
+	bool vendor_roam_score_algorithm;
 };
 };
 
 
 /**
 /**
@@ -164,6 +166,18 @@ enum cm_blacklist_action {
 	CM_BLM_AVOID,
 	CM_BLM_AVOID,
 };
 };
 
 
+/**
+ * struct etp_params - params for estimated throughput
+ * @airtime_fraction: Portion of airtime available for outbound transmissions
+ * @data_ppdu_dur_target_us: Expected duration of a single PPDU, in us
+ * @ba_window_size: Block ack window size of the transmitter
+ */
+struct etp_params {
+	uint32_t airtime_fraction;
+	uint32_t data_ppdu_dur_target_us;
+	uint32_t ba_window_size;
+};
+
 #ifdef FEATURE_BLACKLIST_MGR
 #ifdef FEATURE_BLACKLIST_MGR
 enum cm_blacklist_action
 enum cm_blacklist_action
 wlan_blacklist_action_on_bssid(struct wlan_objmgr_pdev *pdev,
 wlan_blacklist_action_on_bssid(struct wlan_objmgr_pdev *pdev,