Prechádzať zdrojové kódy

qcacld-3.0: config 11ax linkspeed rate

This change is to support 11ax linkspeed rate
on UI.

It supports different config for gReportMaxLinkSpeed.

Current 11ax rate support to max 80 nss2 mcs11.

Change-Id: Iff8cbafe1354ab50c4b3a90ef8ab698a3350a21d
CRs-Fixed: 2529291
Jingxiang Ge 5 rokov pred
rodič
commit
f1d8159208

+ 1 - 1
core/hdd/inc/wlan_hdd_main.h

@@ -815,7 +815,7 @@ struct hdd_rate_info {
 	uint8_t mode;
 	uint8_t nss;
 	uint8_t mcs;
-	uint8_t rate_flags;
+	enum tx_rate_info rate_flags;
 };
 
 /**

+ 2 - 1
core/hdd/src/wlan_hdd_station_info.c

@@ -372,7 +372,8 @@ static void hdd_get_max_tx_bitrate(struct hdd_context *hdd_ctx,
 				   struct hdd_adapter *adapter)
 {
 	struct station_info sinfo;
-	uint8_t tx_rate_flags, tx_mcs_index, tx_nss = 1;
+	enum tx_rate_info tx_rate_flags;
+	uint8_t tx_mcs_index, tx_nss = 1;
 	uint16_t my_tx_rate;
 	struct hdd_station_ctx *hdd_sta_ctx;
 

+ 187 - 151
core/hdd/src/wlan_hdd_stats.c

@@ -162,15 +162,14 @@ static struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = {
 	{9, {7800, 8667}, {3600, 4000}, {1730, 1920} }
 };
 
-/*array index ponints to MCS and array value points respective rssi*/
-static int rssi_mcs_tbl[][10] = {
-/*MCS 0   1     2   3    4    5    6    7    8    9*/
-	{-82, -79, -77, -74, -70, -66, -65, -64, -59, -57},     /* 20 */
-	{-79, -76, -74, -71, -67, -63, -62, -61, -56, -54},     /* 40 */
-	{-76, -73, -71, -68, -64, -60, -59, -58, -53, -51} /* 80 */
+/*array index points to MCS and array value points respective rssi*/
+static int rssi_mcs_tbl[][12] = {
+/*  MCS 0   1    2   3    4    5    6    7    8    9    10   11*/
+	{-82, -79, -77, -74, -70, -66, -65, -64, -59, -57, -52, -48},  /* 20 */
+	{-79, -76, -74, -71, -67, -63, -62, -61, -56, -54, -49, -45},  /* 40 */
+	{-76, -73, -71, -68, -64, -60, -59, -58, -53, -51, -46, -42}   /* 80 */
 };
 
-
 #ifdef WLAN_FEATURE_LINK_LAYER_STATS
 
 /**
@@ -3346,7 +3345,7 @@ static void hdd_get_max_rate_vht(struct hdd_station_info *stainfo,
  * Return: None
  */
 static void hdd_fill_bw_mcs(struct station_info *sinfo,
-			    uint8_t rate_flags,
+			    enum tx_rate_info rate_flags,
 			    uint8_t mcsidx,
 			    uint8_t nss,
 			    bool vht)
@@ -3383,7 +3382,7 @@ static void hdd_fill_bw_mcs(struct station_info *sinfo,
  * Return: None
  */
 static void hdd_fill_bw_mcs(struct station_info *sinfo,
-			    uint8_t rate_flags,
+			    enum tx_rate_info rate_flags,
 			    uint8_t mcsidx,
 			    uint8_t nss,
 			    bool vht)
@@ -3420,7 +3419,7 @@ static void hdd_fill_bw_mcs(struct station_info *sinfo,
  * Return: None
  */
 static void hdd_fill_bw_mcs_vht(struct station_info *sinfo,
-				uint8_t rate_flags,
+				enum tx_rate_info rate_flags,
 				uint8_t mcsidx,
 				uint8_t nss)
 {
@@ -3513,7 +3512,7 @@ static void hdd_fill_rate_info(struct wlan_objmgr_psoc *psoc,
 			       struct hdd_station_info *stainfo,
 			       struct hdd_fw_txrx_stats *stats)
 {
-	uint8_t rate_flags;
+	enum tx_rate_info rate_flags;
 	uint8_t mcsidx = 0xff;
 	uint32_t myrate, maxrate, tmprate;
 	int rssidx;
@@ -3943,10 +3942,121 @@ static int wlan_hdd_get_station_remote(struct wiphy *wiphy,
 	return status;
 }
 
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) && \
+	defined(WLAN_FEATURE_11AX)
+/**
+ * hdd_map_he_gi_to_os() - map txrate_gi to os guard interval
+ * @guard_interval: guard interval get from fw rate
+ *
+ * Return: os guard interval value
+ */
+static inline uint8_t hdd_map_he_gi_to_os(enum txrate_gi guard_interval)
+{
+	switch (guard_interval) {
+	case TXRATE_GI_0_8_US:
+		return NL80211_RATE_INFO_HE_GI_0_8;
+	case TXRATE_GI_1_6_US:
+		return NL80211_RATE_INFO_HE_GI_1_6;
+	case TXRATE_GI_3_2_US:
+		return NL80211_RATE_INFO_HE_GI_3_2;
+	default:
+		return NL80211_RATE_INFO_HE_GI_0_8;
+	}
+}
+
+/**
+ * wlan_hdd_fill_os_he_rateflags() - Fill HE related rate_info
+ * @os_rate: rate info for os
+ * @rate_flags: rate flags
+ * @dcm: dcm from rate
+ * @guard_interval: guard interval from rate
+ *
+ * Return: none
+ */
+static void wlan_hdd_fill_os_he_rateflags(struct rate_info *os_rate,
+					  enum tx_rate_info rate_flags,
+					  uint8_t dcm,
+					  enum txrate_gi guard_interval)
+{
+	/* as fw not yet report ofdma to host, so we doesn't
+	 * fill RATE_INFO_BW_HE_RU.
+	 */
+	if (rate_flags & (TX_RATE_HE80 | TX_RATE_HE40 |
+		TX_RATE_HE20)) {
+		if (rate_flags & TX_RATE_HE80)
+			hdd_set_rate_bw(os_rate, HDD_RATE_BW_80);
+		else if (rate_flags & TX_RATE_HE40)
+			hdd_set_rate_bw(os_rate, HDD_RATE_BW_40);
+
+		os_rate->flags |= RATE_INFO_FLAGS_HE_MCS;
+
+		os_rate->he_gi = hdd_map_he_gi_to_os(guard_interval);
+		os_rate->he_dcm = dcm;
+	}
+}
+#else
+static void wlan_hdd_fill_os_he_rateflags(struct rate_info *os_rate,
+					  enum tx_rate_info rate_flags,
+					  uint8_t dcm,
+					  enum txrate_gi guard_interval)
+{}
+#endif
+
+/**
+ * wlan_hdd_fill_os_rate_info() - Fill os related rate_info
+ * @rate_flags: rate flags
+ * @legacy_rate: 802.11abg rate
+ * @os_rate: rate info for os
+ * @mcs_index: mcs
+ * @dcm: dcm from rate
+ * @guard_interval: guard interval from rate
+ *
+ * Return: none
+ */
+static void wlan_hdd_fill_os_rate_info(enum tx_rate_info rate_flags,
+				       uint16_t legacy_rate,
+				       struct rate_info *os_rate,
+				       uint8_t mcs_index, uint8_t nss,
+				       uint8_t dcm,
+				       enum txrate_gi guard_interval)
+{
+	if (rate_flags & TX_RATE_LEGACY) {
+		os_rate->legacy = legacy_rate;
+		hdd_debug("Reporting legacy rate %d", os_rate->legacy);
+		return;
+	}
+
+	/* assume basic BW. anything else will override this later */
+	hdd_set_rate_bw(os_rate, HDD_RATE_BW_20);
+	os_rate->mcs = mcs_index;
+	os_rate->nss = nss;
+
+	wlan_hdd_fill_os_he_rateflags(os_rate, rate_flags, dcm, guard_interval);
+
+	if (rate_flags & (TX_RATE_VHT80 | TX_RATE_VHT40 |
+	    TX_RATE_VHT20)) {
+		if (rate_flags & TX_RATE_VHT80)
+			hdd_set_rate_bw(os_rate, HDD_RATE_BW_80);
+		else if (rate_flags & TX_RATE_VHT40)
+			hdd_set_rate_bw(os_rate, HDD_RATE_BW_40);
+		os_rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
+	}
+
+	if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40)) {
+		if (rate_flags & TX_RATE_HT40)
+			hdd_set_rate_bw(os_rate,
+					HDD_RATE_BW_40);
+		os_rate->flags |= RATE_INFO_FLAGS_MCS;
+	}
+
+	if (rate_flags & TX_RATE_SGI)
+		os_rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
+}
+
 bool hdd_report_max_rate(mac_handle_t mac_handle,
 			 struct rate_info *rate,
 			 int8_t signal,
-			 uint8_t rate_flags,
+			 enum tx_rate_info rate_flags,
 			 uint8_t mcs_index,
 			 uint16_t fw_rate, uint8_t nss)
 {
@@ -3961,10 +4071,8 @@ bool hdd_report_max_rate(mac_handle_t mac_handle,
 	qdf_size_t er_leng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX;
 	uint8_t mcs_rates[SIZE_OF_BASIC_MCS_SET];
 	qdf_size_t mcs_leng = SIZE_OF_BASIC_MCS_SET;
-	struct index_vht_data_rate_type *supported_vht_mcs_rate;
 	struct index_data_rate_type *supported_mcs_rate;
 	enum data_rate_11ac_max_mcs vht_max_mcs;
-	uint8_t max_speed_mcs = 0;
 	uint8_t max_mcs_idx = 0;
 	uint8_t rate_flag = 1;
 	int mode = 0, max_ht_idx;
@@ -4065,7 +4173,6 @@ bool hdd_report_max_rate(mac_handle_t mac_handle,
 	 * Only if we are connected in non legacy mode and not reporting
 	 * actual speed
 	 */
-
 	if ((3 != rssidx) && !(rate_flags & TX_RATE_LEGACY)) {
 		if (0 != ucfg_mlme_get_current_mcs_set(hdd_ctx->psoc,
 						       mcs_rates,
@@ -4075,22 +4182,18 @@ bool hdd_report_max_rate(mac_handle_t mac_handle,
 			return false;
 		}
 		rate_flag = 0;
-		supported_vht_mcs_rate = (struct index_vht_data_rate_type *)
-					  ((nss == 1) ?
-					  &supported_vht_mcs_rate_nss1 :
-					  &supported_vht_mcs_rate_nss2);
 
-		if (rate_flags & TX_RATE_VHT80)
+		if (rate_flags & (TX_RATE_VHT80 | TX_RATE_HE80))
 			mode = 2;
-		else if ((rate_flags & TX_RATE_VHT40) ||
-			 (rate_flags & TX_RATE_HT40))
+		else if (rate_flags & (TX_RATE_HT40 |
+			 TX_RATE_VHT40 | TX_RATE_HE40))
 			mode = 1;
 		else
 			mode = 0;
 
-		/* VHT80 rate has separate rate table */
 		if (rate_flags & (TX_RATE_VHT20 | TX_RATE_VHT40 |
-		    TX_RATE_VHT80)) {
+		    TX_RATE_VHT80 | TX_RATE_HE20 | TX_RATE_HE40 |
+		    TX_RATE_HE80)) {
 			stat = ucfg_mlme_cfg_get_vht_tx_mcs_map(hdd_ctx->psoc,
 								&vht_mcs_map);
 			if (QDF_IS_STATUS_ERROR(stat))
@@ -4123,6 +4226,10 @@ bool hdd_report_max_rate(mac_handle_t mac_handle,
 					max_mcs_idx = 9;
 			}
 
+			if (rate_flags & (TX_RATE_HE20 | TX_RATE_HE40 |
+			    TX_RATE_HE80))
+				max_mcs_idx = 11;
+
 			if (rssidx != 0) {
 				for (i = 0; i <= max_mcs_idx; i++) {
 					if (signal <= rssi_mcs_tbl[mode][i]) {
@@ -4132,33 +4239,8 @@ bool hdd_report_max_rate(mac_handle_t mac_handle,
 				}
 			}
 
-			if (rate_flags & TX_RATE_VHT80) {
-				current_rate =
-				  supported_vht_mcs_rate[mcs_index].
-				  supported_VHT80_rate[rate_flag];
-				max_rate =
-				  supported_vht_mcs_rate[max_mcs_idx].
-					supported_VHT80_rate[rate_flag];
-			} else if (rate_flags & TX_RATE_VHT40) {
-				current_rate =
-				  supported_vht_mcs_rate[mcs_index].
-				  supported_VHT40_rate[rate_flag];
-				max_rate =
-				  supported_vht_mcs_rate[max_mcs_idx].
-					supported_VHT40_rate[rate_flag];
-			} else if (rate_flags & TX_RATE_VHT20) {
-				current_rate =
-				  supported_vht_mcs_rate[mcs_index].
-				  supported_VHT20_rate[rate_flag];
-				max_rate =
-				  supported_vht_mcs_rate[max_mcs_idx].
-				  supported_VHT20_rate[rate_flag];
-			}
-
-			max_speed_mcs = 1;
-			if (current_rate > max_rate)
-				max_rate = current_rate;
-
+			max_mcs_idx = (max_mcs_idx > mcs_index) ?
+				max_mcs_idx : mcs_index;
 		} else {
 			if (rate_flags & TX_RATE_HT40)
 				rate_flag |= 1;
@@ -4197,67 +4279,28 @@ bool hdd_report_max_rate(mac_handle_t mac_handle,
 				}
 
 				if ((j < MAX_HT_MCS_IDX) &&
-				    (current_rate > max_rate)) {
+				    (current_rate > max_rate))
 					max_rate = current_rate;
-				}
-				max_speed_mcs = 1;
 			}
+
 			if (nss == 2)
 				max_mcs_idx += MAX_HT_MCS_IDX;
+			max_mcs_idx = (max_mcs_idx > mcs_index) ?
+				max_mcs_idx : mcs_index;
 		}
 	}
 
 	else if (!(rate_flags & TX_RATE_LEGACY)) {
 		max_rate = fw_rate;
-		max_speed_mcs = 1;
 		max_mcs_idx = mcs_index;
 	}
 	/* report a value at least as big as current rate */
 	if ((max_rate < fw_rate) || (0 == max_rate)) {
 		max_rate = fw_rate;
-		if (rate_flags & TX_RATE_LEGACY) {
-			max_speed_mcs = 0;
-		} else {
-			max_speed_mcs = 1;
-			max_mcs_idx = mcs_index;
-			}
 	}
 
-	if (rate_flags & TX_RATE_LEGACY) {
-		rate->legacy = max_rate;
-
-		hdd_info("Reporting legacy rate %d", rate->legacy);
-	} else {
-		rate->mcs = max_mcs_idx;
-		rate->nss = nss;
-		if (rate_flags & TX_RATE_VHT80)
-			hdd_set_rate_bw(rate, HDD_RATE_BW_80);
-		else if (rate_flags & TX_RATE_VHT40)
-			hdd_set_rate_bw(rate, HDD_RATE_BW_40);
-		else if (rate_flags & TX_RATE_VHT20)
-			hdd_set_rate_bw(rate, HDD_RATE_BW_20);
-
-		if (rate_flags &
-		    (TX_RATE_HT20 | TX_RATE_HT40)) {
-			rate->flags |= RATE_INFO_FLAGS_MCS;
-			if (rate_flags & TX_RATE_HT40)
-				hdd_set_rate_bw(rate,
-						HDD_RATE_BW_40);
-			else if (rate_flags & TX_RATE_HT20)
-				hdd_set_rate_bw(rate,
-						HDD_RATE_BW_20);
-		} else {
-			rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
-		}
-
-		if (rate_flags & TX_RATE_SGI) {
-			if (!(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
-				rate->flags |= RATE_INFO_FLAGS_MCS;
-			rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
-		}
-		linkspeed_dbg("Reporting MCS rate %d flags %x\n",
-			      rate->mcs, rate->flags);
-	}
+	wlan_hdd_fill_os_rate_info(rate_flags, max_rate, rate,
+				   max_mcs_idx, nss, 0, 0);
 
 	return true;
 }
@@ -4268,48 +4311,22 @@ bool hdd_report_max_rate(mac_handle_t mac_handle,
  * @rate_flags: The rate flags computed from rate
  * @my_rate: The rate from fw stats
  * @rate: The station_info struct member strust rate_info to be filled
- * @mcs_index; The mcs index computed from rate
+ * @mcs_index: The mcs index computed from rate
  * @nss: The NSS from fw stats
+ * @dcm: the dcm computed from rate
+ * @guard_interval: the guard interval computed from rate
  *
  * Return: None
  */
-static void hdd_report_actual_rate(uint8_t rate_flags, uint16_t my_rate,
+static void hdd_report_actual_rate(enum tx_rate_info rate_flags,
+				   uint16_t my_rate,
 				   struct rate_info *rate, uint8_t mcs_index,
-				   uint8_t nss)
+				   uint8_t nss, uint8_t dcm,
+				   enum txrate_gi guard_interval)
 {
 	/* report current rate instead of max rate */
-
-	if (rate_flags & TX_RATE_LEGACY) {
-		/* provide to the UI in units of 100kbps */
-		rate->legacy = my_rate;
-		linkspeed_dbg("Reporting actual legacy rate %d",
-			      rate->legacy);
-	} else {
-		/* must be MCS */
-		rate->mcs = mcs_index;
-		rate->nss = nss;
-
-		if (rate_flags & TX_RATE_VHT80)
-			hdd_set_rate_bw(rate, HDD_RATE_BW_80);
-		else if (rate_flags & TX_RATE_VHT40)
-			hdd_set_rate_bw(rate, HDD_RATE_BW_40);
-
-		if (rate_flags &
-			(TX_RATE_HT20 | TX_RATE_HT40)) {
-			rate->flags |= RATE_INFO_FLAGS_MCS;
-			if (rate_flags & TX_RATE_HT40)
-				hdd_set_rate_bw(rate, HDD_RATE_BW_40);
-		} else {
-			rate->flags |= RATE_INFO_FLAGS_VHT_MCS;
-		}
-
-		if (rate_flags & TX_RATE_SGI) {
-			rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
-		}
-
-		linkspeed_dbg("Reporting actual MCS rate %d flags %x\n",
-			      rate->mcs, rate->flags);
-	}
+	wlan_hdd_fill_os_rate_info(rate_flags, my_rate, rate,
+				   mcs_index, nss, dcm, guard_interval);
 }
 
 /**
@@ -4395,13 +4412,14 @@ static int wlan_hdd_get_sta_stats(struct wiphy *wiphy,
 				  struct station_info *sinfo)
 {
 	struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
-	uint8_t rate_flags, tx_rate_flags, rx_rate_flags;
+	enum tx_rate_info rate_flags, tx_rate_flags, rx_rate_flags;
 	uint8_t tx_mcs_index, rx_mcs_index;
 	struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy);
 	mac_handle_t mac_handle;
 	int8_t snr = 0;
 	uint16_t my_tx_rate, my_rx_rate;
-	uint8_t tx_nss = 1, rx_nss = 1;
+	uint8_t tx_nss = 1, rx_nss = 1, tx_dcm, rx_dcm;
+	enum txrate_gi tx_gi, rx_gi;
 	int32_t rcpi_value;
 	int link_speed_rssi_high = 0;
 	int link_speed_rssi_mid = 0;
@@ -4482,6 +4500,11 @@ static int wlan_hdd_get_sta_stats(struct wiphy *wiphy,
 	my_tx_rate = adapter->hdd_stats.class_a_stat.tx_rate;
 	my_rx_rate = adapter->hdd_stats.class_a_stat.rx_rate;
 
+	tx_dcm = adapter->hdd_stats.class_a_stat.tx_dcm;
+	rx_dcm = adapter->hdd_stats.class_a_stat.rx_dcm;
+	tx_gi = adapter->hdd_stats.class_a_stat.tx_gi;
+	rx_gi = adapter->hdd_stats.class_a_stat.rx_gi;
+
 	if (!(rate_flags & TX_RATE_LEGACY)) {
 		tx_nss = adapter->hdd_stats.class_a_stat.tx_nss;
 		rx_nss = adapter->hdd_stats.class_a_stat.rx_nss;
@@ -4535,9 +4558,8 @@ static int wlan_hdd_get_sta_stats(struct wiphy *wiphy,
 	hdd_debug("MCS Index: TX: %d, RX: %d", (int)tx_mcs_index,
 		  (int)rx_mcs_index);
 	hdd_debug("NSS: TX: %d, RX: %d", (int)tx_nss, (int)rx_nss);
-
-	/* assume basic BW. anything else will override this later */
-	hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_20);
+	hdd_debug("dcm: TX: %d, RX: %d", (int)tx_dcm, (int)rx_dcm);
+	hdd_debug("guard interval: TX: %d, RX: %d", (int)tx_gi, (int)rx_gi);
 
 	if (!ucfg_mlme_stats_is_link_speed_report_actual(hdd_ctx->psoc)) {
 		bool tx_rate_calc;
@@ -4566,11 +4588,14 @@ static int wlan_hdd_get_sta_stats(struct wiphy *wiphy,
 
 		/* Fill TX stats */
 		hdd_report_actual_rate(tx_rate_flags, my_tx_rate,
-				       &sinfo->txrate, tx_mcs_index, tx_nss);
+				       &sinfo->txrate, tx_mcs_index,
+				       tx_nss, tx_dcm, tx_gi);
+
 
 		/* Fill RX stats */
 		hdd_report_actual_rate(rx_rate_flags, my_rx_rate,
-				       &sinfo->rxrate, rx_mcs_index, rx_nss);
+				       &sinfo->rxrate, rx_mcs_index,
+				       rx_nss, rx_dcm, rx_gi);
 	}
 
 	wlan_hdd_fill_summary_stats(&adapter->hdd_stats.summary_stat, sinfo);
@@ -4594,14 +4619,21 @@ static int wlan_hdd_get_sta_stats(struct wiphy *wiphy,
 			 HDD_INFO_RX_BYTES   |
 			 HDD_INFO_RX_PACKETS;
 
-	if (tx_rate_flags & TX_RATE_LEGACY)
-		hdd_debug("Reporting legacy rate %d pkt cnt tx %d rx %d",
-			sinfo->txrate.legacy, sinfo->tx_packets,
-			sinfo->rx_packets);
-	else
-		hdd_debug("Reporting MCS rate %d flags 0x%x pkt cnt tx %d rx %d",
-			sinfo->txrate.mcs, sinfo->txrate.flags,
-			sinfo->tx_packets, sinfo->rx_packets);
+	if (tx_rate_flags & TX_RATE_LEGACY) {
+		hdd_debug("TX: Reporting legacy rate %d pkt cnt %d",
+			  sinfo->txrate.legacy, sinfo->tx_packets);
+		hdd_debug("RX: Reporting legacy rate %d pkt cnt %d",
+			  sinfo->rxrate.legacy, sinfo->rx_packets);
+	} else {
+		hdd_debug("TX: Reporting MCS rate %d, flags 0x%x pkt cnt %d, nss %d, bw %d",
+			  sinfo->txrate.mcs, sinfo->txrate.flags,
+			  sinfo->tx_packets, sinfo->txrate.nss,
+			  sinfo->rxrate.bw);
+		hdd_debug("RX: Reporting MCS rate %d, flags 0x%x pkt cnt %d, nss %d, bw %d",
+			  sinfo->rxrate.mcs, sinfo->rxrate.flags,
+			  sinfo->rx_packets, sinfo->rxrate.nss,
+			  sinfo->rxrate.bw);
+	}
 
 	hdd_wlan_fill_per_chain_rssi_stats(sinfo, adapter);
 
@@ -5631,7 +5663,6 @@ int wlan_hdd_get_peer_info(struct hdd_adapter *adapter,
 int wlan_hdd_get_station_stats(struct hdd_adapter *adapter)
 {
 	int ret = 0;
-	uint8_t mcs_rate_flags;
 	struct stats_event *stats;
 
 	stats = wlan_cfg80211_mc_cp_stats_get_station_stats(adapter->vdev,
@@ -5690,13 +5721,18 @@ int wlan_hdd_get_station_stats(struct hdd_adapter *adapter)
 	adapter->hdd_stats.class_a_stat.tx_mcs_index =
 		sme_get_mcs_idx(stats->tx_rate, stats->tx_rate_flags,
 				&adapter->hdd_stats.class_a_stat.tx_nss,
-				&mcs_rate_flags);
-	adapter->hdd_stats.class_a_stat.tx_mcs_rate_flags = mcs_rate_flags;
+				&adapter->hdd_stats.class_a_stat.tx_dcm,
+				&adapter->hdd_stats.class_a_stat.tx_gi,
+				&adapter->hdd_stats.class_a_stat.
+					tx_mcs_rate_flags);
+
 	adapter->hdd_stats.class_a_stat.rx_mcs_index =
 		sme_get_mcs_idx(stats->rx_rate, stats->tx_rate_flags,
 				&adapter->hdd_stats.class_a_stat.rx_nss,
-				&mcs_rate_flags);
-	adapter->hdd_stats.class_a_stat.rx_mcs_rate_flags = mcs_rate_flags;
+				&adapter->hdd_stats.class_a_stat.rx_dcm,
+				&adapter->hdd_stats.class_a_stat.rx_gi,
+				&adapter->hdd_stats.class_a_stat.
+					rx_mcs_rate_flags);
 
 	/* save per chain rssi to legacy location */
 	qdf_mem_copy(adapter->hdd_stats.per_chain_rssi_stats.rssi,

+ 1 - 1
core/hdd/src/wlan_hdd_stats.h

@@ -457,7 +457,7 @@ void wlan_hdd_display_txrx_stats(struct hdd_context *hdd_ctx);
 bool hdd_report_max_rate(mac_handle_t mac_handle,
 			 struct rate_info *rate,
 			 int8_t signal,
-			 uint8_t rate_flags,
+			 enum tx_rate_info rate_flags,
 			 uint8_t mcs_index,
 			 uint16_t fw_rate, uint8_t nss);
 

+ 3 - 1
core/mac/src/pe/lim/lim_assoc_utils.c

@@ -4092,8 +4092,10 @@ QDF_STATUS lim_sta_send_add_bss_pre_assoc(struct mac_context *mac,
 	}
 
 	if (lim_is_session_he_capable(pe_session) &&
-	    pBeaconStruct->he_cap.present)
+	    pBeaconStruct->he_cap.present) {
+		lim_update_bss_he_capable(mac, pAddBssParams);
 		lim_add_bss_he_cfg(pAddBssParams, pe_session);
+	}
 	pe_debug("vhtCapable %d ch_width %d", pAddBssParams->vhtCapable,
 		 pAddBssParams->ch_width);
 	/*

+ 8 - 0
core/mac/src/pe/lim/lim_utils.c

@@ -6717,6 +6717,7 @@ void lim_add_bss_he_cap(struct bss_params *add_bss, tpSirAssocRsp assoc_rsp)
 
 	he_cap = &assoc_rsp->he_cap;
 	he_op = &assoc_rsp->he_op;
+	add_bss->he_capable = he_cap->present;
 	if (he_cap)
 		qdf_mem_copy(&add_bss->staContext.he_config,
 			     he_cap, sizeof(*he_cap));
@@ -7124,6 +7125,13 @@ void lim_update_sta_he_capable(struct mac_context *mac,
 	pe_debug("he_capable: %d", add_sta_params->he_capable);
 }
 
+void lim_update_bss_he_capable(struct mac_context *mac,
+			       struct bss_params *add_bss)
+{
+	add_bss->he_capable = true;
+	pe_debug("he_capable: %d", add_bss->he_capable);
+}
+
 void lim_update_stads_he_capable(tpDphHashNode sta_ds, tpSirAssocReq assoc_req)
 {
 	sta_ds->mlmStaContext.he_capable = assoc_req->he_cap.present;

+ 15 - 0
core/mac/src/pe/lim/lim_utils.h

@@ -1137,6 +1137,16 @@ static inline bool lim_is_sta_he_capable(tpDphHashNode sta_ds)
 	return sta_ds->mlmStaContext.he_capable;
 }
 
+/**
+ * lim_update_bss_he_capable() - Update he_capable in add BSS params
+ * @mac: pointer to MAC context
+ * @add_bss: pointer to add BSS params
+ *
+ * Return: None
+ */
+void lim_update_bss_he_capable(struct mac_context *mac,
+			       struct bss_params *add_bss);
+
 /**
  * lim_update_stads_he_capable() - Update he_capable in sta ds context
  * @sta_ds: pointer to sta ds
@@ -1290,6 +1300,11 @@ static inline bool lim_is_sta_he_capable(tpDphHashNode sta_ds)
 	return false;
 }
 
+static inline void lim_update_bss_he_capable(struct mac_context *mac,
+					     struct bss_params *add_bss)
+{
+}
+
 static inline void lim_update_stads_he_capable(tpDphHashNode sta_ds,
 		tpSirAssocReq assoc_req)
 {

+ 7 - 3
core/sme/inc/csr_api.h

@@ -1197,10 +1197,14 @@ typedef struct tagCsrGlobalClassAStatsInfo {
 	/* mcs index for HT20 and HT40 rates */
 	uint32_t tx_mcs_index;
 	uint32_t rx_mcs_index;
-	uint32_t tx_mcs_rate_flags;
-	uint32_t rx_mcs_rate_flags;
+	enum tx_rate_info tx_mcs_rate_flags;
+	enum tx_rate_info rx_mcs_rate_flags;
+	uint8_t  tx_dcm;
+	uint8_t  rx_dcm;
+	enum txrate_gi  tx_gi;
+	enum txrate_gi  rx_gi;
 	/* to diff between HT20 & HT40 rates;short & long guard interval */
-	uint32_t tx_rx_rate_flags;
+	enum tx_rate_info tx_rx_rate_flags;
 
 } tCsrGlobalClassAStatsInfo;
 

+ 7 - 3
core/sme/inc/sme_api.h

@@ -3377,15 +3377,19 @@ static inline void sme_reset_he_caps(mac_handle_t mac_handle, uint8_t vdev_id)
 
 /**
  * sme_get_mcs_idx() - gets mcs index
- * @max_rate: max rate
+ * @raw_rate: raw rate from fw
  * @rate_flags: rate flags
  * @nss: number of nss
+ * @dcm: dcm will be calculated from rate
+ * @guard_interval: guard interval info from rate
  * @mcs_rate_flags: mcs rate flag
  *
  * Return: return mcs index
  */
-uint8_t sme_get_mcs_idx(uint16_t max_rate, uint8_t rate_flags,
-			uint8_t *nss, uint8_t *mcs_rate_flags);
+uint8_t sme_get_mcs_idx(uint16_t raw_rate, enum tx_rate_info rate_flags,
+			uint8_t *nss, uint8_t *dcm,
+			enum txrate_gi *guard_interval,
+			enum tx_rate_info *mcs_rate_flags);
 
 #ifdef WLAN_SUPPORT_TWT
 /**

+ 6 - 3
core/sme/src/common/sme_api.c

@@ -15318,10 +15318,13 @@ void sme_reset_he_caps(mac_handle_t mac_handle, uint8_t vdev_id)
 }
 #endif
 
-uint8_t sme_get_mcs_idx(uint16_t max_rate, uint8_t rate_flags,
-			uint8_t *nss, uint8_t *mcs_rate_flags)
+uint8_t sme_get_mcs_idx(uint16_t raw_rate, enum tx_rate_info rate_flags,
+			uint8_t *nss, uint8_t *dcm,
+			enum txrate_gi *guard_interval,
+			enum tx_rate_info *mcs_rate_flags)
 {
-	return wma_get_mcs_idx(max_rate, rate_flags, nss, mcs_rate_flags);
+	return wma_get_mcs_idx(raw_rate, rate_flags,
+			       nss, dcm, guard_interval, mcs_rate_flags);
 }
 
 bool sme_find_session_by_bssid(mac_handle_t mac_handle, uint8_t *bssid)

+ 1 - 0
core/wma/inc/wma.h

@@ -768,6 +768,7 @@ struct wma_txrx_node {
 	void *del_staself_req;
 	bool is_del_sta_defered;
 	qdf_atomic_t bss_status;
+	enum tx_rate_info rate_flags;
 	uint8_t nss;
 	uint16_t pause_bitmap;
 	int8_t tx_power;

+ 7 - 3
core/wma/inc/wma_api.h

@@ -450,15 +450,19 @@ void wma_wmi_stop(void);
 
 /**
  * wma_get_mcs_idx() - get mcs index
- * @max_rate: max rate
+ * @raw_rate: raw rate from fw
  * @rate_flags: rate flags
  * @nss: nss
+ * @dcm: dcm
+ * @guard_interval: guard interval
  * @mcs_rate_flag: mcs rate flags
  *
  *  Return: mcs index
  */
-uint8_t wma_get_mcs_idx(uint16_t max_rate, uint8_t rate_flags,
-			uint8_t *nss, uint8_t *mcs_rate_flag);
+uint8_t wma_get_mcs_idx(uint16_t raw_rate, enum tx_rate_info rate_flags,
+			uint8_t *nss, uint8_t *dcm,
+			enum txrate_gi *guard_interval,
+			enum tx_rate_info *mcs_rate_flag);
 
 /**
  * wma_get_hidden_ssid_restart_in_progress() - check if hidden ssid restart is

+ 2 - 0
core/wma/inc/wma_if.h

@@ -342,6 +342,7 @@ typedef struct sLimMlmSetKeysReq {
  * @bSpectrumMgtEnabled: Spectrum Management Capability, 1:Enabled, 0:Disabled.
  * @vhtCapable: VHT capablity
  * @ch_width: VHT tx channel width
+ * @he_capable: HE Capability
  * @no_ptk_4_way: Do not need 4-way handshake
  */
 struct bss_params {
@@ -368,6 +369,7 @@ struct bss_params {
 	enum phy_ch_width ch_width;
 	uint8_t nonRoamReassoc;
 #ifdef WLAN_FEATURE_11AX
+	bool he_capable;
 	uint32_t he_sta_obsspd;
 #endif
 	bool no_ptk_4_way;

+ 24 - 0
core/wma/inc/wma_internal.h

@@ -57,8 +57,15 @@
 
 #define MAX_HT_MCS_IDX 8
 #define MAX_VHT_MCS_IDX 10
+#ifdef WLAN_FEATURE_11AX
+#define MAX_HE_MCS_IDX 12
+#endif
 #define INVALID_MCS_IDX 255
 
+#define IS_MCS_HAS_DCM_RATE(val)  \
+		((val) == 0 || (val) == 1 || \
+		 (val) == 3 || (val) == 4)
+
 #define LINK_STATUS_LEGACY      0
 #define LINK_STATUS_VHT         0x1
 #define LINK_STATUS_MIMO        0x2
@@ -96,6 +103,23 @@ struct index_vht_data_rate_type {
 	uint16_t ht80_rate[2];
 };
 
+#ifdef WLAN_FEATURE_11AX
+#define MAX_HE_DCM_INDEX 2
+/**
+ * struct index_he_data_rate_type - he data rate type
+ * @beacon_rate_index: Beacon rate index
+ * @supported_he80_rate: he80 rate
+ * @supported_he40_rate: he40 rate
+ * @supported_he20_rate: he20 rate
+ */
+struct index_he_data_rate_type {
+	uint8_t beacon_rate_index;
+	uint16_t supported_he20_rate[MAX_HE_DCM_INDEX][3];
+	uint16_t supported_he40_rate[MAX_HE_DCM_INDEX][3];
+	uint16_t supported_he80_rate[MAX_HE_DCM_INDEX][3];
+};
+#endif
+
 struct wifi_scan_cmd_req_params;
 /*
  * wma_main.c functions declarations

+ 63 - 19
core/wma/src/wma_data.c

@@ -761,12 +761,48 @@ static void wma_cp_stats_set_rate_flag(tp_wma_handle wma, uint8_t vdev_id)
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID);
 }
 
+#ifdef WLAN_FEATURE_11AX
+/**
+ * wma_set_bss_rate_flags_he() - set rate flags based on BSS capability
+ * @rate_flags: rate_flags pointer
+ * @add_bss: add_bss params
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS wma_set_bss_rate_flags_he(enum tx_rate_info *rate_flags,
+					    struct bss_params *add_bss)
+{
+	if (!add_bss->he_capable)
+		return QDF_STATUS_E_NOSUPPORT;
+
+	/*extend TX_RATE_HE160 in future*/
+	if (add_bss->ch_width == CH_WIDTH_160MHZ ||
+	    add_bss->ch_width == CH_WIDTH_80P80MHZ ||
+	    add_bss->ch_width == CH_WIDTH_80MHZ)
+		*rate_flags |= TX_RATE_HE80;
+
+	else if (add_bss->ch_width)
+		*rate_flags |= TX_RATE_HE40;
+	else
+		*rate_flags |= TX_RATE_HE20;
+
+	wma_debug("he_capable %d", add_bss->he_capable);
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static QDF_STATUS wma_set_bss_rate_flags_he(enum tx_rate_info *rate_flags,
+					    struct bss_params *add_bss)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif
+
 void wma_set_bss_rate_flags(tp_wma_handle wma, uint8_t vdev_id,
 			    struct bss_params *add_bss)
 {
 	struct wma_txrx_node *iface = &wma->interfaces[vdev_id];
 	struct vdev_mlme_obj *vdev_mlme;
-	uint32_t *rate_flags;
+	enum tx_rate_info *rate_flags;
 
 
 	vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(iface->vdev);
@@ -777,24 +813,28 @@ void wma_set_bss_rate_flags(tp_wma_handle wma, uint8_t vdev_id,
 	}
 	rate_flags = &vdev_mlme->mgmt.rate_info.rate_flags;
 	*rate_flags = 0;
-	if (add_bss->vhtCapable) {
-		if (add_bss->ch_width == CH_WIDTH_80P80MHZ)
-			*rate_flags |= TX_RATE_VHT80;
-		if (add_bss->ch_width == CH_WIDTH_160MHZ)
-			*rate_flags |= TX_RATE_VHT80;
-		if (add_bss->ch_width == CH_WIDTH_80MHZ)
-			*rate_flags |= TX_RATE_VHT80;
-		else if (add_bss->ch_width)
-			*rate_flags |= TX_RATE_VHT40;
-		else
-			*rate_flags |= TX_RATE_VHT20;
-	}
-	/* avoid to conflict with htCapable flag */
-	else if (add_bss->htCapable) {
-		if (add_bss->ch_width)
-			*rate_flags |= TX_RATE_HT40;
-		else
-			*rate_flags |= TX_RATE_HT20;
+
+	if (QDF_STATUS_SUCCESS !=
+		wma_set_bss_rate_flags_he(rate_flags, add_bss)) {
+		if (add_bss->vhtCapable) {
+			if (add_bss->ch_width == CH_WIDTH_80P80MHZ)
+				*rate_flags |= TX_RATE_VHT80;
+			if (add_bss->ch_width == CH_WIDTH_160MHZ)
+				*rate_flags |= TX_RATE_VHT80;
+			if (add_bss->ch_width == CH_WIDTH_80MHZ)
+				*rate_flags |= TX_RATE_VHT80;
+			else if (add_bss->ch_width)
+				*rate_flags |= TX_RATE_VHT40;
+			else
+				*rate_flags |= TX_RATE_VHT20;
+		}
+		/* avoid to conflict with htCapable flag */
+		else if (add_bss->htCapable) {
+			if (add_bss->ch_width)
+				*rate_flags |= TX_RATE_HT40;
+			else
+				*rate_flags |= TX_RATE_HT20;
+		}
 	}
 
 	if (add_bss->staContext.fShortGI20Mhz ||
@@ -804,6 +844,10 @@ void wma_set_bss_rate_flags(tp_wma_handle wma, uint8_t vdev_id,
 	if (!add_bss->htCapable && !add_bss->vhtCapable)
 		*rate_flags = TX_RATE_LEGACY;
 
+	wma_debug("capable: vht %u, ht %u, rate_flags %x, ch_width %d",
+		  add_bss->vhtCapable, add_bss->htCapable,
+		  *rate_flags, add_bss->ch_width);
+
 	wma_cp_stats_set_rate_flag(wma, vdev_id);
 }
 

+ 305 - 71
core/wma/src/wma_utils.c

@@ -123,6 +123,91 @@ static struct index_vht_data_rate_type vht_mcs_nss2[] = {
 	{9,  {1730, 1920}, {3600, 4000}, {7800, 8667} }
 };
 
+#ifdef WLAN_FEATURE_11AX
+/* MCS Based HE rate table */
+/* MCS parameters with Nss = 1*/
+static struct index_he_data_rate_type he_mcs_nss1[] = {
+/* MCS,  {dcm0:0.8/1.6/3.2}, {dcm1:0.8/1.6/3.2} */
+	{0,  {{86,   81,   73  }, {43,   40,  36 } }, /* HE20 */
+	     {{172,  163,  146 }, {86,   81,  73 } }, /* HE40 */
+	     {{360,  340,  306 }, {180,  170, 153} } }, /* HE80 */
+	{1,  {{172,  163,  146 }, {86,   81,  73 } },
+	     {{344,  325,  293 }, {172,  163, 146} },
+	     {{721,  681,  613 }, {360,  340, 306} } },
+	{2,  {{258,  244,  219 }, {0} },
+	     {{516,  488,  439 }, {0} },
+	     {{1081, 1021, 919 }, {0} } },
+	{3,  {{344,  325,  293 }, {172,  163, 146} },
+	     {{688,  650,  585 }, {344,  325, 293} },
+	     {{1441, 1361, 1225}, {721,  681, 613} } },
+	{4,  {{516,  488,  439 }, {258,  244, 219} },
+	     {{1032, 975,  878 }, {516,  488, 439} },
+	     {{2162, 2042, 1838}, {1081, 1021, 919} } },
+	{5,  {{688,  650,  585 }, {0} },
+	     {{1376, 1300, 1170}, {0} },
+	     {{2882, 2722, 2450}, {0} } },
+	{6,  {{774,  731,  658 }, {0} },
+	     {{1549, 1463, 1316}, {0} },
+	     {{3243, 3063, 2756}, {0} } },
+	{7,  {{860,  813,  731 }, {0} },
+	     {{1721, 1625, 1463}, {0} },
+	     {{3603, 3403, 3063}, {0} } },
+	{8,  {{1032, 975,  878 }, {0} },
+	     {{2065, 1950, 1755}, {0} },
+	     {{4324, 4083, 3675}, {0} } },
+	{9,  {{1147, 1083, 975 }, {0} },
+	     {{2294, 2167, 1950}, {0} },
+	     {{4804, 4537, 4083}, {0} } },
+	{10, {{1290, 1219, 1097}, {0} },
+	     {{2581, 2438, 2194}, {0} },
+	     {{5404, 5104, 4594}, {0} } },
+	{11, {{1434, 1354, 1219}, {0} },
+	     {{2868, 2708, 2438}, {0} },
+	     {{6004, 5671, 5104}, {0} } }
+};
+
+/*MCS parameters with Nss = 2*/
+static struct index_he_data_rate_type he_mcs_nss2[] = {
+/* MCS,  {dcm0:0.8/1.6/3.2}, {dcm1:0.8/1.6/3.2} */
+	{0,  {{172,   163,   146 }, {86,   81,   73 } }, /* HE20 */
+	     {{344,   325,   293 }, {172,  163,  146} }, /* HE40 */
+	     {{721,   681,   613 }, {360,  340,  306} } }, /* HE80 */
+	{1,  {{344,   325,   293 }, {172,  163,  146} },
+	     {{688,   650,   585 }, {344,  325,  293} },
+	     {{1441,  1361,  1225}, {721,  681,  613} } },
+	{2,  {{516,   488,   439 }, {0} },
+	     {{1032,  975,   878 }, {0} },
+	     {{2162,  2042,  1838}, {0} } },
+	{3,  {{688,   650,   585 }, {344,  325,  293 } },
+	     {{1376,  1300,  1170}, {688,  650,  585  } },
+	     {{2882,  2722,  2450}, {1441, 1361, 1225} } },
+	{4,  {{1032,  975,   878 }, {516,  488,  439 } },
+	     {{2065,  1950,  1755}, {1032, 975,  878 } },
+	     {{4324,  4083,  3675}, {2162, 2042, 1838} } },
+	{5,  {{1376,  1300,  1170}, {0} },
+	     {{2753,  2600,  2340}, {0} },
+	     {{5765,  5444,  4900}, {0} } },
+	{6,  {{1549,  1463,  1316}, {0} },
+	     {{3097,  2925,  2633}, {0} },
+	     {{6485,  6125,  5513}, {0} } },
+	{7,  {{1721,  1625,  1463}, {0} },
+	     {{3441,  3250,  2925}, {0} },
+	     {{7206,  6806,  6125}, {0} } },
+	{8,  {{2065,  1950,  1755}, {0} },
+	     {{4129,  3900,  3510}, {0} },
+	     {{8647,  8167,  7350}, {0} } },
+	{9,  {{2294,  2167,  1950}, {0} },
+	     {{4588,  4333,  3900}, {0} },
+	     {{9607,  9074,  8166}, {0} } },
+	{10, {{2581,  2438,  2194}, {0} },
+	     {{5162,  4875,  4388}, {0} },
+	     {{10809, 10208, 9188}, {0} } },
+	{11, {{2868,  2708,  2438}, {0} },
+	     {{5735,  5417,  4875}, {0} },
+	     {{12010, 11343, 10208}, {0} } }
+};
+#endif
+
 #ifdef BIG_ENDIAN_HOST
 
 /* ############# function definitions ############ */
@@ -151,90 +236,233 @@ void wma_swap_bytes(void *pv, uint32_t n)
 
 /**
  * wma_mcs_rate_match() - find the match mcs rate
- * @match_rate:	the rate to look up
- * @is_sgi:	return if the SGI rate is found
- * @nss:	the nss in use
- * @nss1_rate:	the nss1 rate
- * @nss1_srate:	the nss1 SGI rate
- * @nss2_rate:	the nss2 rate
- * @nss2_srate:	the nss2 SGI rate
+ * @raw_rate: the rate to look up
+ * @is_he: if it is he rate
+ * @nss1_rate: the nss1 rate
+ * @nss2_rate: the nss2 rate
+ * @nss: the nss in use
+ * @guard_interval: to get guard interval from rate
  *
  * This is a helper function to find the match of the tx_rate
- * in terms of the nss1/nss2 rate with non-SGI/SGI.
+ * and return nss/guard interval.
  *
  * Return: the found rate or 0 otherwise
  */
-static inline uint16_t wma_mcs_rate_match(uint16_t match_rate, bool *is_sgi,
-					  uint8_t *nss, uint16_t nss1_rate,
-					  uint16_t nss1_srate,
-					  uint16_t nss2_rate,
-					  uint16_t nss2_srate)
+static inline uint16_t wma_mcs_rate_match(uint16_t raw_rate,
+					  bool is_he,
+					  uint16_t *nss1_rate,
+					  uint16_t *nss2_rate,
+					  uint8_t *nss,
+					  enum txrate_gi *guard_interval)
+{
+	uint8_t gi_index;
+	uint8_t gi_index_max = 2;
+	uint16_t ret_rate = 0;
+
+	WMA_LOGD("%s raw_rate: %u, %u %u %u %u",
+		 __func__, raw_rate, nss1_rate[0],
+		 nss1_rate[1], nss2_rate[0], nss2_rate[1]);
+	if (is_he)
+		WMA_LOGD("%s : is_he %u,  %u, %u",
+			 __func__, is_he, nss1_rate[2], nss2_rate[2]);
+
+	if (is_he)
+		gi_index_max = 3;
+
+	for (gi_index = 0; gi_index < gi_index_max; gi_index++) {
+		if (raw_rate == nss1_rate[gi_index]) {
+			*nss = 1;
+			ret_rate = nss1_rate[gi_index];
+			break;
+		}
+		if (*nss == 2 && raw_rate == nss2_rate[gi_index]) {
+			ret_rate = nss2_rate[gi_index];
+			break;
+		}
+	}
+
+	if (ret_rate) {
+		if (gi_index == 1)
+			*guard_interval =
+				is_he ? TXRATE_GI_1_6_US : TXRATE_GI_0_4_US;
+		else if (is_he && gi_index == 2)
+			*guard_interval = TXRATE_GI_3_2_US;
+		else
+			*guard_interval = TXRATE_GI_0_8_US;
+	}
+
+	WMA_LOGD("%s ret_rate: %u, guard interval %u nss %u",
+		 __func__, ret_rate, *guard_interval, *nss);
+
+	return ret_rate;
+}
+
+#ifdef WLAN_FEATURE_11AX
+/**
+ * wma_get_mcs_idx() - get mcs index
+ * @raw_rate: raw rate from fw
+ * @rate_flags: rate flags
+ * @nss: nss
+ * @dcm: dcm
+ * @guard_interval: guard interval
+ * @mcs_rate_flag: mcs rate flags
+ * @p_index: index for matched rate
+ *
+ *  Return: return match rate if found, else 0
+ */
+static uint16_t wma_match_he_rate(uint16_t raw_rate,
+				  enum tx_rate_info rate_flags,
+				  uint8_t *nss, uint8_t *dcm,
+				  enum txrate_gi *guard_interval,
+				  enum tx_rate_info *mcs_rate_flag,
+				  uint8_t *p_index)
+{
+	uint8_t index = 0;
+	uint8_t dcm_index_max = 1;
+	uint8_t dcm_index = 0;
+	uint16_t match_rate = 0;
+	uint16_t *nss1_rate;
+	uint16_t *nss2_rate;
+
+	*p_index = 0;
+	if (!(rate_flags & (TX_RATE_HE80 | TX_RATE_HE40 |
+		TX_RATE_HE20)))
+		return 0;
+
+	for (index = 0; index < MAX_HE_MCS_IDX; index++) {
+		dcm_index_max = IS_MCS_HAS_DCM_RATE(index) ? 2 : 1;
+
+		for (dcm_index = 0; dcm_index < dcm_index_max;
+			 dcm_index++) {
+			if (rate_flags & TX_RATE_HE80) {
+				nss1_rate = &he_mcs_nss1[index].
+					supported_he80_rate[dcm_index][0];
+				nss2_rate = &he_mcs_nss2[index].
+					supported_he80_rate[dcm_index][0];
+				/* check for he80 nss1/2 rate set */
+				match_rate = wma_mcs_rate_match(raw_rate, 1,
+								nss1_rate,
+								nss2_rate,
+								nss,
+								guard_interval);
+				if (match_rate)
+					goto rate_found;
+			}
+
+			if (rate_flags & (TX_RATE_HE40 | TX_RATE_HE80)) {
+				nss1_rate = &he_mcs_nss1[index].
+					supported_he40_rate[dcm_index][0];
+				nss2_rate = &he_mcs_nss2[index].
+					supported_he40_rate[dcm_index][0];
+				/* check for he40 nss1/2 rate set */
+				match_rate = wma_mcs_rate_match(raw_rate, 1,
+								nss1_rate,
+								nss2_rate,
+								nss,
+								guard_interval);
+
+				if (match_rate) {
+					*mcs_rate_flag &= ~TX_RATE_HE80;
+					goto rate_found;
+				}
+			}
+
+			if (rate_flags & (TX_RATE_HE80 | TX_RATE_HE40 |
+				TX_RATE_HE20)) {
+				nss1_rate = &he_mcs_nss1[index].
+					supported_he20_rate[dcm_index][0];
+				nss2_rate = &he_mcs_nss2[index].
+					supported_he20_rate[dcm_index][0];
+				/* check for he20 nss1/2 rate set */
+				match_rate = wma_mcs_rate_match(raw_rate, 1,
+								nss1_rate,
+								nss2_rate,
+								nss,
+								guard_interval);
+
+				if (match_rate) {
+					*mcs_rate_flag &= TX_RATE_HE20;
+					goto rate_found;
+				}
+			}
+		}
+	}
+
+rate_found:
+	if (match_rate) {
+		if (dcm_index == 1)
+			*dcm = 1;
+		*p_index = index;
+	}
+	return match_rate;
+}
+#else
+static uint16_t wma_match_he_rate(uint16_t raw_rate,
+				  enum tx_rate_info rate_flags,
+				  uint8_t *nss, uint8_t *dcm,
+				  enum txrate_gi *guard_interval,
+				  enum tx_rate_info *mcs_rate_flag,
+				  uint8_t *p_index)
 {
-	WMA_LOGD("%s match_rate: %d, %d %d %d %d",
-		__func__, match_rate, nss1_rate, nss1_srate, nss2_rate,
-		nss2_srate);
-
-	if (match_rate == nss1_rate) {
-		*nss = 1;
-		return nss1_rate;
-	} else if (match_rate == nss1_srate) {
-		*is_sgi = true;
-		*nss = 1;
-		return nss1_srate;
-	} else if (*nss == 2 && match_rate == nss2_rate)
-		return nss2_rate;
-	else if (*nss == 2 && match_rate == nss2_srate) {
-		*is_sgi = true;
-		return nss2_srate;
-	} else
 		return 0;
 }
+#endif
 
-uint8_t wma_get_mcs_idx(uint16_t max_rate, uint8_t rate_flags,
-			uint8_t *nss, uint8_t *mcs_rate_flag)
+uint8_t wma_get_mcs_idx(uint16_t raw_rate, enum tx_rate_info rate_flags,
+			uint8_t *nss, uint8_t *dcm,
+			enum txrate_gi *guard_interval,
+			enum tx_rate_info *mcs_rate_flag)
 {
 	uint8_t  index = 0;
 	uint16_t match_rate = 0;
-	bool is_sgi = false;
+	uint16_t *nss1_rate;
+	uint16_t *nss2_rate;
 
-	WMA_LOGD("%s rate:%d rate_flgs: 0x%x, nss: %d",
-		 __func__, max_rate, rate_flags, *nss);
+	WMA_LOGD("%s enter:  raw_rate:%d rate_flgs: 0x%x, nss: %d",
+		 __func__, raw_rate, rate_flags, *nss);
 
 	*mcs_rate_flag = rate_flags;
-	*mcs_rate_flag &= ~TX_RATE_SGI;
+
+	match_rate = wma_match_he_rate(raw_rate, rate_flags,
+				       nss, dcm, guard_interval,
+				       mcs_rate_flag, &index);
+	if (match_rate)
+		goto rate_found;
+
 	for (index = 0; index < MAX_VHT_MCS_IDX; index++) {
 		if (rate_flags & TX_RATE_VHT80) {
+			nss1_rate = &vht_mcs_nss1[index].ht80_rate[0];
+			nss2_rate = &vht_mcs_nss2[index].ht80_rate[0];
 			/* check for vht80 nss1/2 rate set */
-			match_rate = wma_mcs_rate_match(max_rate, &is_sgi, nss,
-					vht_mcs_nss1[index].ht80_rate[0],
-					vht_mcs_nss1[index].ht80_rate[1],
-					vht_mcs_nss2[index].ht80_rate[0],
-					vht_mcs_nss2[index].ht80_rate[1]);
+			match_rate = wma_mcs_rate_match(raw_rate, 0,
+							nss1_rate,
+							nss2_rate,
+							nss, guard_interval);
 			if (match_rate)
 				goto rate_found;
 		}
-		if ((rate_flags & TX_RATE_VHT40) |
-		    (rate_flags & TX_RATE_VHT80)) {
+		if (rate_flags & (TX_RATE_VHT40 | TX_RATE_VHT80)) {
+			nss1_rate = &vht_mcs_nss1[index].ht40_rate[0];
+			nss2_rate = &vht_mcs_nss2[index].ht40_rate[0];
 			/* check for vht40 nss1/2 rate set */
-			match_rate = wma_mcs_rate_match(max_rate, &is_sgi, nss,
-					vht_mcs_nss1[index].ht40_rate[0],
-					vht_mcs_nss1[index].ht40_rate[1],
-					vht_mcs_nss2[index].ht40_rate[0],
-					vht_mcs_nss2[index].ht40_rate[1]);
+			match_rate = wma_mcs_rate_match(raw_rate, 0,
+							nss1_rate,
+							nss2_rate,
+							nss, guard_interval);
 			if (match_rate) {
 				*mcs_rate_flag &= ~TX_RATE_VHT80;
 				goto rate_found;
 			}
 		}
-		if ((rate_flags & TX_RATE_VHT20) |
-		    (rate_flags & TX_RATE_VHT40) |
-		    (rate_flags & TX_RATE_VHT80)) {
+		if (rate_flags & (TX_RATE_VHT20 | TX_RATE_VHT40 |
+			TX_RATE_VHT80)) {
+			nss1_rate = &vht_mcs_nss1[index].ht20_rate[0];
+			nss2_rate = &vht_mcs_nss2[index].ht20_rate[0];
 			/* check for vht20 nss1/2 rate set */
-			match_rate = wma_mcs_rate_match(max_rate, &is_sgi, nss,
-					vht_mcs_nss1[index].ht20_rate[0],
-					vht_mcs_nss1[index].ht20_rate[1],
-					vht_mcs_nss2[index].ht20_rate[0],
-					vht_mcs_nss2[index].ht20_rate[1]);
+			match_rate = wma_mcs_rate_match(raw_rate, 0,
+							nss1_rate,
+							nss2_rate,
+							nss, guard_interval);
 			if (match_rate) {
 				*mcs_rate_flag &= ~(TX_RATE_VHT80 |
 						TX_RATE_VHT40);
@@ -244,12 +472,13 @@ uint8_t wma_get_mcs_idx(uint16_t max_rate, uint8_t rate_flags,
 	}
 	for (index = 0; index < MAX_HT_MCS_IDX; index++) {
 		if (rate_flags & TX_RATE_HT40) {
+			nss1_rate = &mcs_nss1[index].ht40_rate[0];
+			nss2_rate = &mcs_nss2[index].ht40_rate[0];
 			/* check for ht40 nss1/2 rate set */
-			match_rate = wma_mcs_rate_match(max_rate, &is_sgi, nss,
-					mcs_nss1[index].ht40_rate[0],
-					mcs_nss1[index].ht40_rate[1],
-					mcs_nss2[index].ht40_rate[0],
-					mcs_nss2[index].ht40_rate[1]);
+			match_rate = wma_mcs_rate_match(raw_rate, 0,
+							nss1_rate,
+							nss2_rate,
+							nss, guard_interval);
 			if (match_rate) {
 				*mcs_rate_flag = TX_RATE_HT40;
 				if (*nss == 2)
@@ -257,14 +486,14 @@ uint8_t wma_get_mcs_idx(uint16_t max_rate, uint8_t rate_flags,
 				goto rate_found;
 			}
 		}
-		if ((rate_flags & TX_RATE_HT20) ||
-			(rate_flags & TX_RATE_HT40)) {
+		if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40)) {
+			nss1_rate = &mcs_nss1[index].ht20_rate[0];
+			nss2_rate = &mcs_nss2[index].ht20_rate[0];
 			/* check for ht20 nss1/2 rate set */
-			match_rate = wma_mcs_rate_match(max_rate, &is_sgi, nss,
-					mcs_nss1[index].ht20_rate[0],
-					mcs_nss1[index].ht20_rate[1],
-					mcs_nss2[index].ht20_rate[0],
-					mcs_nss2[index].ht20_rate[1]);
+			match_rate = wma_mcs_rate_match(raw_rate, 0,
+							nss1_rate,
+							nss2_rate,
+							nss, guard_interval);
 			if (match_rate) {
 				*mcs_rate_flag = TX_RATE_HT20;
 				if (*nss == 2)
@@ -275,12 +504,17 @@ uint8_t wma_get_mcs_idx(uint16_t max_rate, uint8_t rate_flags,
 	}
 
 rate_found:
+
 	/* set SGI flag only if this is SGI rate */
-	if (match_rate && is_sgi == true)
+	if (match_rate && *guard_interval == TXRATE_GI_0_4_US)
 		*mcs_rate_flag |= TX_RATE_SGI;
+	else
+		*mcs_rate_flag &= ~TX_RATE_SGI;
 
-	WMA_LOGD("%s - match_rate: %d index: %d rate_flag: 0x%x is_sgi: %d",
-		 __func__, match_rate, index, *mcs_rate_flag, is_sgi);
+	WMA_LOGD("%s exit: match_rate %d index: %d"
+		 " mcs_rate_flag: 0x%x nss %d guard interval %d",
+		 __func__, match_rate, index, *mcs_rate_flag,
+		 *nss, *guard_interval);
 
 	return match_rate ? index : INVALID_MCS_IDX;
 }