Browse Source

qcacld-3.0: Add API to get max mcs index

Add a new field max_mcs_index in mlme_legacy_priv to save max mcs
index of current vdev.
Add a new field max_real_mcs_idx in hdd_station_info to save max
mcs index of the connected station.

Change-Id: I28908515cbe5c18c79f14f8645defd5c82e3a6f0
CRs-Fixed: 3065838
Bing Sun 3 years ago
parent
commit
6df47a0d95

+ 4 - 0
components/mlme/core/inc/wlan_mlme_main.h

@@ -431,6 +431,7 @@ struct wait_for_key_timer {
  * @ba_2k_jump_iot_ap: This is set to true if connected to the ba 2k jump IOT AP
  * @is_usr_ps_enabled: Is Power save enabled
  * @notify_co_located_ap_upt_rnr: Notify co located AP to update RNR or not
+ * @max_mcs_index: Max supported mcs index of vdev
  */
 struct mlme_legacy_priv {
 	bool chan_switch_in_progress;
@@ -472,6 +473,9 @@ struct mlme_legacy_priv {
 	bool ba_2k_jump_iot_ap;
 	bool is_usr_ps_enabled;
 	bool notify_co_located_ap_upt_rnr;
+#ifdef WLAN_FEATURE_SON
+	uint8_t max_mcs_index;
+#endif
 };
 
 /**

+ 42 - 0
components/mlme/dispatcher/inc/wlan_mlme_api.h

@@ -3520,4 +3520,46 @@ wlan_mlme_get_user_mcc_duty_cycle_percentage(struct wlan_objmgr_psoc *psoc)
 	return 0;
 }
 #endif /* WLAN_FEATURE_MCC_QUOTA */
+
+/**
+ * mlme_get_max_he_mcs_idx() -  get max mcs index from he cap information
+ * @mcs_ch_width: channel width
+ * @hecap_rxmcsnssmap: rx mcs map from he cap
+ * @hecap_txmcsnssmap: tx mcs map from he cap
+ *
+ * Return: the maximum MCS supported
+ */
+uint8_t mlme_get_max_he_mcs_idx(enum phy_ch_width mcs_ch_width,
+				u_int16_t *hecap_rxmcsnssmap,
+				u_int16_t *hecap_txmcsnssmap);
+
+/**
+ * mlme_get_max_vht_mcs_idx() -  get max mcs index from vht cap information
+ * @rx_vht_mcs_map: rx mcs map from vht cap
+ * @tx_vht_mcs_map: tx mcs map from vht cap
+ *
+ * Return: the maximum MCS supported
+ */
+uint8_t mlme_get_max_vht_mcs_idx(u_int16_t rx_vht_mcs_map,
+				 u_int16_t tx_vht_mcs_map);
+
+#ifdef WLAN_FEATURE_SON
+/**
+ * mlme_set_vdev_max_mcs_idx() - Save max mcs index of vdev
+ * @vdev: pointer to vdev object
+ * @max_mcs_idx: max_mcs_idx to save
+ *
+ * Return: QDF Status
+ */
+QDF_STATUS mlme_save_vdev_max_mcs_idx(struct wlan_objmgr_vdev *vdev,
+				      uint8_t max_mcs_idx);
+
+/**
+ * mlme_get_vdev_max_mcs_idx() - Get max mcs index of vdev
+ * @vdev: pointer to vdev object
+ *
+ * Return max mcs index of vdev
+ */
+uint8_t mlme_get_vdev_max_mcs_idx(struct wlan_objmgr_vdev *vdev);
+#endif /* WLAN_FEATURE_SON */
 #endif /* _WLAN_MLME_API_H_ */

+ 5 - 0
components/mlme/dispatcher/inc/wlan_mlme_public_struct.h

@@ -104,6 +104,11 @@
 /* Default beacon interval of 100 ms */
 #define CUSTOM_CONC_GO_BI 100
 
+#define HECAP_TXRX_MCS_NSS_IDX_80    (0)
+#define HECAP_TXRX_MCS_NSS_IDX_160   (1)
+#define HECAP_TXRX_MCS_NSS_IDX_80_80 (2)
+#define INVALID_MCS_NSS_INDEX         0xff
+
 enum diagwlan_status_eventsubtype {
 	DIAG_WLAN_STATUS_CONNECT = 0,
 	DIAG_WLAN_STATUS_DISCONNECT

+ 14 - 0
components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h

@@ -4530,4 +4530,18 @@ ucfg_mlme_get_wds_mode(struct wlan_objmgr_psoc *psoc)
 {
 	return wlan_mlme_get_wds_mode(psoc);
 }
+
+#ifdef WLAN_FEATURE_SON
+/**
+ * ucfg_mlme_get_vdev_max_mcs_idx() - Get max mcs idx of given vdev
+ * @vdev: pointer to vdev object
+ *
+ * Return: max mcs idx of given vdev
+ */
+static inline uint8_t
+ucfg_mlme_get_vdev_max_mcs_idx(struct wlan_objmgr_vdev *vdev)
+{
+	return mlme_get_vdev_max_mcs_idx(vdev);
+}
+#endif /* WLAN_FEATURE_SON */
 #endif /* _WLAN_MLME_UCFG_API_H_ */

+ 98 - 0
components/mlme/dispatcher/src/wlan_mlme_api.c

@@ -5607,3 +5607,101 @@ wlan_mlme_get_user_mcc_duty_cycle_percentage(struct wlan_objmgr_psoc *psoc)
 	return quota_value;
 }
 #endif /* WLAN_FEATURE_MCC_QUOTA */
+
+uint8_t mlme_get_max_he_mcs_idx(enum phy_ch_width mcs_ch_width,
+				u_int16_t *hecap_rxmcsnssmap,
+				u_int16_t *hecap_txmcsnssmap)
+{
+	uint8_t rx_max_mcs, tx_max_mcs, max_mcs = INVALID_MCS_NSS_INDEX;
+
+	switch (mcs_ch_width) {
+	case CH_WIDTH_80P80MHZ:
+		if (hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80] &&
+		    hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80]) {
+			rx_max_mcs = hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80] & 0x03;
+			tx_max_mcs = hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80] & 0x03;
+			max_mcs = rx_max_mcs < tx_max_mcs ? rx_max_mcs : tx_max_mcs;
+			if (max_mcs < 0x03)
+				max_mcs = 7 + 2 * max_mcs;
+		}
+		/* fallthrough */
+	case CH_WIDTH_160MHZ:
+		if (hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_160] &&
+		    hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_160]) {
+			rx_max_mcs = hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_160] & 0x03;
+			tx_max_mcs = hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_160] & 0x03;
+			max_mcs = rx_max_mcs < tx_max_mcs ? rx_max_mcs : tx_max_mcs;
+			if (max_mcs < 0x03)
+				max_mcs = 7 + 2 * max_mcs;
+		}
+		/* fallthrough */
+	default:
+		if (hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80] &&
+		    hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80]) {
+			rx_max_mcs = hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80] & 0x03;
+			tx_max_mcs = hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80] & 0x03;
+			max_mcs = rx_max_mcs < tx_max_mcs ? rx_max_mcs : tx_max_mcs;
+			if (max_mcs < 0x03)
+				max_mcs = 7 + 2 * max_mcs;
+		}
+	}
+
+	return max_mcs;
+}
+
+uint8_t mlme_get_max_vht_mcs_idx(u_int16_t rx_vht_mcs_map,
+				 u_int16_t tx_vht_mcs_map)
+{
+	uint8_t rx_max_mcs, tx_max_mcs, max_mcs = INVALID_MCS_NSS_INDEX;
+
+	if (rx_vht_mcs_map && tx_vht_mcs_map) {
+		rx_max_mcs = rx_vht_mcs_map & 0x03;
+		tx_max_mcs = tx_vht_mcs_map & 0x03;
+		max_mcs = rx_max_mcs < tx_max_mcs ? rx_max_mcs : tx_max_mcs;
+		if (max_mcs < 0x03)
+			return 7 + max_mcs;
+	}
+
+	return max_mcs;
+}
+
+#ifdef WLAN_FEATURE_SON
+QDF_STATUS mlme_save_vdev_max_mcs_idx(struct wlan_objmgr_vdev *vdev,
+				      uint8_t max_mcs_idx)
+{
+	struct mlme_legacy_priv *mlme_priv;
+
+	if (!vdev) {
+		mlme_legacy_err("invalid vdev");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_legacy_err("vdev legacy private object is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	mlme_priv->max_mcs_index = max_mcs_idx;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+uint8_t mlme_get_vdev_max_mcs_idx(struct wlan_objmgr_vdev *vdev)
+{
+	struct mlme_legacy_priv *mlme_priv;
+
+	if (!vdev) {
+		mlme_legacy_err("invalid vdev");
+		return INVALID_MCS_NSS_INDEX;
+	}
+
+	mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev);
+	if (!mlme_priv) {
+		mlme_legacy_err("vdev legacy private object is NULL");
+		return INVALID_MCS_NSS_INDEX;
+	}
+
+	return mlme_priv->max_mcs_index;
+}
+#endif /* WLAN_FEATURE_SON */

+ 0 - 20
components/son/dispatcher/inc/son_api.h

@@ -447,19 +447,6 @@ int wlan_son_anqp_frame(struct wlan_objmgr_vdev *vdev, int subtype,
  */
 uint8_t wlan_son_get_node_tx_power(struct element_info assoc_req_ies);
 
-/**
- * wlan_son_get_max_mcs() - calculate the max mcs supported by the node
- * @mode: current phymode
- * @supp_idx: max supported idx
- * @ext_idx: max extended idx
- * @ht_mcs_idx: max mcs index for HT
- * @vht_mcs_map: mcs map for VHT
- *
- * return: max_mcs for the node
- */
-uint8_t wlan_son_get_max_mcs(uint8_t mode, uint8_t supp_idx, uint8_t ext_idx,
-			     uint8_t ht_mcs_idx, uint8_t vht_mcs_map);
-
 /**
  * wlan_son_get_peer_rrm_info() - Get RRM info for peer
  * @assoc_req_ies: assoc req ies
@@ -548,13 +535,6 @@ uint8_t wlan_son_get_node_tx_power(struct element_info assoc_req_ies)
 	return 0;
 }
 
-static inline
-uint8_t wlan_son_get_max_mcs(uint8_t mode, uint8_t supp_idx, uint8_t ext_idx,
-			     uint8_t ht_mcs_idx, uint8_t vht_mcs_map)
-{
-	return 0;
-}
-
 static inline
 QDF_STATUS wlan_son_get_peer_rrm_info(struct element_info assoc_req_ies,
 				      uint8_t *rrmcaps,

+ 0 - 13
components/son/dispatcher/inc/son_ucfg_api.h

@@ -178,19 +178,6 @@ int ucfg_son_set_cbs_dwell_split_time(struct wlan_objmgr_vdev *vdev,
  */
 uint8_t ucfg_son_get_tx_power(struct element_info assoc_req_ies);
 
-/**
- * ucfg_get_max_mcs() - calculate the max mcs supported by the node
- * @mode: current phy mode
- * @supp_idx: max supported idx
- * @ext_idx: max extended idx
- * @ht_mcs_idx: max mcs index for HT
- * @vht_mcs_map: mcs map for VHT
- *
- * Return: max_mcs for the node
- */
-uint8_t ucfg_son_get_max_mcs(uint8_t mode, uint8_t supp_idx, uint8_t ext_idx,
-			     uint8_t ht_mcs_idx, uint8_t vht_mcs_map);
-
 /**
  * ucfg_son_get_peer_rrm_info() - Get RRM info for peer
  * @assoc_req_ies: assoc req ies

+ 0 - 23
components/son/dispatcher/src/son_api.c

@@ -1341,29 +1341,6 @@ uint8_t wlan_son_get_node_tx_power(struct element_info assoc_req_ies)
 		return 0;
 }
 
-uint8_t wlan_son_get_max_mcs(uint8_t mode, uint8_t supp_idx, uint8_t ext_idx,
-			     uint8_t ht_mcs_idx, uint8_t vht_mcs_map)
-{
-	uint8_t maxidx = MAX_HE_MCS_IDX;
-
-	/* check supported rates */
-	if (supp_idx != 0xff && maxidx < supp_idx)
-		maxidx = supp_idx;
-
-	/* check extended rates */
-	if (ext_idx != 0xff && maxidx < ext_idx)
-		maxidx = ext_idx;
-
-	/* check for HT Mode */
-	if (mode == SIR_SME_PHY_MODE_HT)
-		maxidx = ht_mcs_idx;
-
-	if (mode == SIR_SME_PHY_MODE_VHT)
-		maxidx = (vht_mcs_map & DATA_RATE_11AC_MCS_MASK);
-
-	return maxidx;
-}
-
 QDF_STATUS wlan_son_get_peer_rrm_info(struct element_info assoc_req_ies,
 				      uint8_t *rrmcaps,
 				      bool *is_beacon_meas_supported)

+ 0 - 7
components/son/dispatcher/src/son_ucfg_api.c

@@ -130,13 +130,6 @@ uint8_t ucfg_son_get_tx_power(struct element_info assoc_req_ies)
 	return wlan_son_get_node_tx_power(assoc_req_ies);
 }
 
-uint8_t ucfg_son_get_max_mcs(uint8_t mode, uint8_t supp_idx, uint8_t ext_idx,
-			     uint8_t ht_mcs_idx, uint8_t vht_mcs_map)
-{
-	return wlan_son_get_max_mcs(mode, supp_idx, ext_idx, ht_mcs_idx,
-				    vht_mcs_map);
-}
-
 QDF_STATUS ucfg_son_get_peer_rrm_info(struct element_info assoc_req_ies,
 				      uint8_t *rrmcaps,
 				      bool *is_beacon_meas_supported)

+ 1 - 0
core/hdd/src/wlan_hdd_hostapd.c

@@ -1589,6 +1589,7 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
 	stainfo->max_supp_idx = event->max_supp_idx;
 	stainfo->max_ext_idx = event->max_ext_idx;
 	stainfo->max_mcs_idx = event->max_mcs_idx;
+	stainfo->max_real_mcs_idx = event->max_real_mcs_idx;
 	stainfo->rx_mcs_map = event->rx_mcs_map;
 	stainfo->tx_mcs_map = event->tx_mcs_map;
 	stainfo->assoc_ts = qdf_system_ticks();

+ 6 - 6
core/hdd/src/wlan_hdd_son.c

@@ -2303,11 +2303,11 @@ static QDF_STATUS hdd_son_get_node_info(struct wlan_objmgr_vdev *vdev,
 	ucfg_mlme_get_peer_phymode(psoc, mac_addr, &peer_phymode);
 	node_info->phymode = wlan_hdd_son_get_ieee_phymode(peer_phymode);
 	node_info->max_txpower = ucfg_son_get_tx_power(sta_info->assoc_req_ies);
-	node_info->max_MCS = ucfg_son_get_max_mcs(sta_info->mode,
-						  sta_info->max_supp_idx,
-						  sta_info->max_ext_idx,
-						  sta_info->max_mcs_idx,
-						  sta_info->rx_mcs_map);
+	node_info->max_MCS = sta_info->max_real_mcs_idx;
+	if (node_info->max_MCS == INVALID_MCS_NSS_INDEX) {
+		hdd_err("invalid mcs");
+		return QDF_STATUS_E_FAILURE;
+	}
 	if (sta_info->vht_present)
 		node_info->is_mu_mimo_supported =
 				sta_info->vht_caps.vht_cap_info
@@ -2397,7 +2397,7 @@ uint32_t hdd_son_get_peer_max_mcs_idx(struct wlan_objmgr_vdev *vdev,
 		return ret;
 	}
 
-	ret = sta_info->max_mcs_idx;
+	ret = sta_info->max_real_mcs_idx;
 
 	hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true,
 			     STA_INFO_SOFTAP_GET_STA_INFO);

+ 5 - 1
core/hdd/src/wlan_hdd_sta_info.h

@@ -202,7 +202,10 @@ char *sta_info_string_from_dbgid(wlan_sta_info_dbgid id);
  * @mode: Mode of the connection
  * @max_supp_idx: Max supported rate index of the station
  * @max_ext_idx: Max extended supported rate index of the station
- * @max_mcs_idx: Max supported mcs index of the station
+ * @max_mcs_idx: Max supported mcs index from ht cap of the station
+ * @max_real_mcs_idx: Max supported mcs index from biggest cap of the station.
+ *                    For example, if station supports HE , first check he cap,
+ *                    then vht cap and so on.
  * @rx_mcs_map: VHT Rx mcs map
  * @tx_mcs_map: VHT Tx mcs map
  * @freq : Frequency of the current station
@@ -273,6 +276,7 @@ struct hdd_station_info {
 	uint8_t max_supp_idx;
 	uint8_t max_ext_idx;
 	uint8_t max_mcs_idx;
+	uint8_t max_real_mcs_idx;
 	uint8_t rx_mcs_map;
 	uint8_t tx_mcs_map;
 	uint32_t freq;

+ 1 - 0
core/mac/inc/sir_api.h

@@ -993,6 +993,7 @@ struct assoc_ind {
 	uint8_t max_supp_idx;
 	uint8_t max_ext_idx;
 	uint8_t max_mcs_idx;
+	uint8_t max_real_mcs_idx;
 	uint8_t rx_mcs_map;
 	uint8_t tx_mcs_map;
 	/* Extended CSA capability of station */

+ 43 - 25
core/mac/src/pe/lim/lim_process_assoc_req_frame.c

@@ -2872,20 +2872,6 @@ static void lim_fill_assoc_ind_info(struct mac_context *mac_ctx,
 	return;
 }
 
-static uint8_t lim_get_max_rate_idx(tSirMacRateSet *rateset)
-{
-	uint8_t maxidx;
-	int i;
-
-	maxidx = rateset->rate[0] & 0x7f;
-	for (i = 1; i < rateset->numRates; i++) {
-		if ((rateset->rate[i] & 0x7f) > maxidx)
-			maxidx = rateset->rate[i] & 0x7f;
-	}
-
-	return maxidx;
-}
-
 static void fill_mlm_assoc_ind_vht(tpSirAssocReq assocreq,
 		tpDphHashNode stads,
 		tpLimMlmAssocInd assocind)
@@ -2964,6 +2950,42 @@ static void lim_fill_assoc_ind_he_bw_info(tpLimMlmAssocInd assoc_ind,
 	}
 }
 
+/**
+ * lim_fill_assoc_ind_real_max_mcs_idx() - fill max real mcs index to assoc ind
+ * @assoc_ind: assoc_ind to fill
+ * @assoc_req: pointer to tpSirAssocReq
+ * @sta_ds: pointer to tpDphHashNode
+ * @session: pointer to session
+ *
+ * Return: void
+ */
+static void lim_fill_assoc_ind_real_max_mcs_idx(tpLimMlmAssocInd assoc_ind,
+						tpSirAssocReq assoc_req,
+						tpDphHashNode sta_ds,
+						struct pe_session *session)
+{
+	assoc_ind->max_real_mcs_idx = INVALID_MCS_NSS_INDEX;
+
+	if (lim_is_sta_he_capable(sta_ds) &&
+	    lim_is_session_he_capable(session))
+		assoc_ind->max_real_mcs_idx = lim_get_he_max_mcs_idx(
+					sta_ds->ch_width, &assoc_req->he_cap);
+
+	if (assoc_ind->max_real_mcs_idx == INVALID_MCS_NSS_INDEX &&
+	    sta_ds->mlmStaContext.vhtCapability)
+		assoc_ind->max_real_mcs_idx =
+				lim_get_vht_max_mcs_idx(&assoc_req->VHTCaps);
+
+	if (assoc_ind->max_real_mcs_idx == INVALID_MCS_NSS_INDEX)
+		assoc_ind->max_real_mcs_idx = assoc_ind->max_mcs_idx;
+
+	if (assoc_ind->max_real_mcs_idx == INVALID_MCS_NSS_INDEX)
+		assoc_ind->max_real_mcs_idx = assoc_ind->max_ext_idx;
+
+	if (assoc_ind->max_real_mcs_idx == INVALID_MCS_NSS_INDEX)
+		assoc_ind->max_real_mcs_idx = assoc_ind->max_supp_idx;
+}
+
 bool lim_fill_lim_assoc_ind_params(
 		tpLimMlmAssocInd assoc_ind,
 		struct mac_context *mac_ctx,
@@ -2974,7 +2996,6 @@ bool lim_fill_lim_assoc_ind_params(
 	uint16_t rsn_len;
 	uint32_t phy_mode;
 	const uint8_t *wpsie = NULL;
-	uint8_t maxidx, i;
 	bool wme_enable;
 	struct wlan_objmgr_vdev *vdev;
 	struct vdev_mlme_obj *mlme_obj;
@@ -3132,9 +3153,9 @@ bool lim_fill_lim_assoc_ind_params(
 	assoc_ind->rx_stbc = false;
 	assoc_ind->ch_width = eHT_CHANNEL_WIDTH_20MHZ;
 	assoc_ind->mode = SIR_SME_PHY_MODE_LEGACY;
-	assoc_ind->max_supp_idx = 0xff;
-	assoc_ind->max_ext_idx = 0xff;
-	assoc_ind->max_mcs_idx = 0xff;
+	assoc_ind->max_supp_idx = INVALID_MCS_NSS_INDEX;
+	assoc_ind->max_ext_idx = INVALID_MCS_NSS_INDEX;
+	assoc_ind->max_mcs_idx = INVALID_MCS_NSS_INDEX;
 	assoc_ind->rx_mcs_map = 0xff;
 	assoc_ind->tx_mcs_map = 0xff;
 
@@ -3164,13 +3185,8 @@ bool lim_fill_lim_assoc_ind_params(
 			eHT_CHANNEL_WIDTH_20MHZ;
 		/* mode */
 		assoc_ind->mode = SIR_SME_PHY_MODE_HT;
-		maxidx = 0;
-		for (i = 0; i < 8; i++) {
-			if (assoc_req->HTCaps.supportedMCSSet[0] &
-			    (1 << i))
-				maxidx = i;
-		}
-		assoc_ind->max_mcs_idx = maxidx;
+		assoc_ind->max_mcs_idx = lim_get_ht_max_mcs_idx(
+						&assoc_req->HTCaps);
 	}
 	fill_mlm_assoc_ind_vht(assoc_req, sta_ds, assoc_ind);
 	if (assoc_req->ExtCap.present) {
@@ -3218,6 +3234,8 @@ bool lim_fill_lim_assoc_ind_params(
 				assoc_req->is_sae_authenticated;
 	/* updates HE bandwidth in assoc indication */
 	lim_fill_assoc_ind_he_bw_info(assoc_ind, sta_ds, session_entry);
+	lim_fill_assoc_ind_real_max_mcs_idx(assoc_ind, assoc_req,
+					    sta_ds, session_entry);
 
 	vdev = session_entry->vdev;
 	if (!vdev)

+ 1 - 0
core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c

@@ -787,6 +787,7 @@ lim_fill_sme_assoc_ind_params(
 	sme_assoc_ind->max_supp_idx = assoc_ind->max_supp_idx;
 	sme_assoc_ind->max_ext_idx = assoc_ind->max_ext_idx;
 	sme_assoc_ind->max_mcs_idx = assoc_ind->max_mcs_idx;
+	sme_assoc_ind->max_real_mcs_idx = assoc_ind->max_real_mcs_idx;
 	sme_assoc_ind->rx_mcs_map = assoc_ind->rx_mcs_map;
 	sme_assoc_ind->tx_mcs_map = assoc_ind->tx_mcs_map;
 	sme_assoc_ind->ecsa_capable = assoc_ind->ecsa_capable;

+ 53 - 1
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -741,6 +741,58 @@ static inline void lim_fill_cc_mode(struct mac_context *mac_ctx,
 }
 #endif
 
+#ifdef WLAN_FEATURE_SON
+/**
+ * lim_save_max_mcs_idx() - save max mcs index to mlme component
+ * @mac_ctx: Pointer to Global MAC structure
+ * @session: pointer to pe session
+ *
+ * Return: void
+ */
+static void
+lim_save_max_mcs_idx(struct mac_context *mac_ctx, struct pe_session *session)
+{
+	tDot11fIEVHTCaps vht_cap;
+	tDot11fIEhe_cap he_cap;
+	tDot11fIEHTCaps ht_cap;
+	u_int8_t session_max_mcs_idx = INVALID_MCS_NSS_INDEX;
+
+	if (IS_DOT11_MODE_HE(session->dot11mode)) {
+		qdf_mem_zero(&he_cap, sizeof(tDot11fIEhe_cap));
+		populate_dot11f_he_caps(mac_ctx, session, &he_cap);
+		session_max_mcs_idx = lim_get_he_max_mcs_idx(session->ch_width,
+							     &he_cap);
+	}
+	if (session_max_mcs_idx == INVALID_MCS_NSS_INDEX &&
+	    IS_DOT11_MODE_VHT(session->dot11mode)) {
+		qdf_mem_zero(&vht_cap, sizeof(tDot11fIEVHTCaps));
+		populate_dot11f_vht_caps(mac_ctx, session, &vht_cap);
+		session_max_mcs_idx = lim_get_vht_max_mcs_idx(&vht_cap);
+	}
+	if (session_max_mcs_idx == INVALID_MCS_NSS_INDEX &&
+	    IS_DOT11_MODE_HT(session->dot11mode)) {
+		qdf_mem_zero(&ht_cap, sizeof(tDot11fIEHTCaps));
+		populate_dot11f_ht_caps(mac_ctx, session, &ht_cap);
+		session_max_mcs_idx = lim_get_ht_max_mcs_idx(&ht_cap);
+	}
+	if (session_max_mcs_idx == INVALID_MCS_NSS_INDEX &&
+	    session->extRateSet.numRates)
+		session_max_mcs_idx =
+				lim_get_max_rate_idx(&session->extRateSet);
+
+	if (session_max_mcs_idx == INVALID_MCS_NSS_INDEX &&
+	    session->rateSet.numRates)
+		session_max_mcs_idx =
+				lim_get_max_rate_idx(&session->rateSet);
+
+	mlme_save_vdev_max_mcs_idx(session->vdev, session_max_mcs_idx);
+}
+#else
+static void
+lim_save_max_mcs_idx(struct mac_context *mac_ctx, struct pe_session *session)
+{
+}
+#endif
 
 /**
  * __lim_handle_sme_start_bss_request() - process SME_START_BSS_REQ message
@@ -1146,7 +1198,7 @@ __lim_handle_sme_start_bss_request(struct mac_context *mac_ctx, uint32_t *msg_bu
 			mac_ctx->mlme_cfg->power.local_power_constraint = 0;
 
 		mlm_start_req->beacon_tx_rate = session->beacon_tx_rate;
-
+		lim_save_max_mcs_idx(mac_ctx, session);
 		session->limPrevSmeState = session->limSmeState;
 		session->limSmeState = eLIM_SME_WT_START_BSS_STATE;
 

+ 1 - 0
core/mac/src/pe/lim/lim_types.h

@@ -238,6 +238,7 @@ typedef struct sLimMlmAssocInd {
 	uint8_t max_supp_idx;
 	uint8_t max_ext_idx;
 	uint8_t max_mcs_idx;
+	uint8_t max_real_mcs_idx;
 	uint8_t rx_mcs_map;
 	uint8_t tx_mcs_map;
 	uint8_t ecsa_capable;

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

@@ -9989,3 +9989,71 @@ QDF_STATUS lim_pre_vdev_start(struct mac_context *mac,
 
 	return lim_set_ch_phy_mode(mlme_obj->vdev, session->dot11mode);
 }
+
+uint8_t lim_get_he_max_mcs_idx(enum phy_ch_width ch_width,
+			       tDot11fIEhe_cap *he_cap)
+{
+	uint16_t hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80 + 1];
+	uint16_t hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80 + 1];
+
+	qdf_mem_zero(hecap_rxmcsnssmap, sizeof(hecap_rxmcsnssmap));
+	qdf_mem_zero(hecap_txmcsnssmap, sizeof(hecap_txmcsnssmap));
+
+	qdf_mem_copy(&hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80],
+		     &he_cap->rx_he_mcs_map_lt_80,
+		     sizeof(u_int16_t));
+	qdf_mem_copy(&hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80],
+		     &he_cap->tx_he_mcs_map_lt_80,
+		     sizeof(u_int16_t));
+	if (he_cap->chan_width_2) {
+		qdf_mem_copy(&hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_160],
+			     &he_cap->rx_he_mcs_map_160,
+			     sizeof(u_int16_t));
+		qdf_mem_copy(&hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_160],
+			     &he_cap->tx_he_mcs_map_160,
+			     sizeof(u_int16_t));
+	}
+	if (he_cap->chan_width_3) {
+		qdf_mem_copy(&hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80],
+			     &he_cap->rx_he_mcs_map_80_80,
+			     sizeof(u_int16_t));
+		qdf_mem_copy(&hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80],
+			     &he_cap->tx_he_mcs_map_80_80,
+			     sizeof(u_int16_t));
+	}
+
+	return mlme_get_max_he_mcs_idx(ch_width, hecap_rxmcsnssmap,
+				       hecap_txmcsnssmap);
+}
+
+uint8_t lim_get_vht_max_mcs_idx(tDot11fIEVHTCaps *vht_cap)
+{
+	return mlme_get_max_vht_mcs_idx(vht_cap->rxMCSMap & 0xff,
+					vht_cap->txMCSMap & 0xff);
+}
+
+uint8_t lim_get_ht_max_mcs_idx(tDot11fIEHTCaps *ht_cap)
+{
+	uint8_t i, maxidx = INVALID_MCS_NSS_INDEX;
+
+	for (i = 0; i < 8; i++) {
+		if (ht_cap->supportedMCSSet[0] & (1 << i))
+			maxidx = i;
+	}
+
+	return maxidx;
+}
+
+uint8_t lim_get_max_rate_idx(tSirMacRateSet *rateset)
+{
+	uint8_t maxidx;
+	int i;
+
+	maxidx = rateset->rate[0] & 0x7f;
+	for (i = 1; i < rateset->numRates; i++) {
+		if ((rateset->rate[i] & 0x7f) > maxidx)
+			maxidx = rateset->rate[i] & 0x7f;
+	}
+
+	return maxidx;
+}

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

@@ -2817,4 +2817,37 @@ static inline void lim_process_sae_msg(struct mac_context *mac, void *body);
 {}
 #endif
 
+/**
+ * lim_get_he_max_mcs_idx() - get max mcs index from he cap
+ * @ch_width: channel width
+ * @he_cap: pointer to tDot11fIEhe_cap
+ *
+ * Return: max mcs index from he cap
+ */
+uint8_t lim_get_he_max_mcs_idx(enum phy_ch_width ch_width,
+			       tDot11fIEhe_cap *he_cap);
+
+/**
+ * lim_get_vht_max_mcs_idx() - get max mcs index from vht cap
+ * @vht_cap: pointer to tDot11fIEVHTCaps
+ *
+ * Return: max mcs index from vht cap
+ */
+uint8_t lim_get_vht_max_mcs_idx(tDot11fIEVHTCaps *vht_cap);
+
+/**
+ * lim_get_ht_max_mcs_idx() - get max mcs index from ht cap
+ * @ht_cap: pointer to tDot11fIEHTCaps
+ *
+ * Return: max mcs index from ht cap
+ */
+uint8_t lim_get_ht_max_mcs_idx(tDot11fIEHTCaps *ht_cap);
+
+/**
+ * lim_get_max_rate_idx() - get max rate index from tSirMacRateSet
+ * @rateset: pointer to tSirMacRateSet
+ *
+ * Return: max rate index from tSirMacRateSet
+ */
+uint8_t lim_get_max_rate_idx(tSirMacRateSet *rateset);
 #endif /* __LIM_UTILS_H */

+ 1 - 0
core/sap/inc/sap_api.h

@@ -275,6 +275,7 @@ typedef struct sap_StationAssocReassocCompleteEvent_s {
 	uint8_t max_supp_idx;
 	uint8_t max_ext_idx;
 	uint8_t max_mcs_idx;
+	uint8_t max_real_mcs_idx;
 	uint8_t rx_mcs_map;
 	uint8_t tx_mcs_map;
 	uint8_t ecsa_capable;

+ 2 - 0
core/sap/src/sap_fsm.c

@@ -2287,6 +2287,8 @@ QDF_STATUS sap_signal_hdd_event(struct sap_context *sap_ctx,
 		reassoc_complete->max_supp_idx = csr_roaminfo->max_supp_idx;
 		reassoc_complete->max_ext_idx = csr_roaminfo->max_ext_idx;
 		reassoc_complete->max_mcs_idx = csr_roaminfo->max_mcs_idx;
+		reassoc_complete->max_real_mcs_idx =
+						csr_roaminfo->max_real_mcs_idx;
 		reassoc_complete->rx_mcs_map = csr_roaminfo->rx_mcs_map;
 		reassoc_complete->tx_mcs_map = csr_roaminfo->tx_mcs_map;
 		reassoc_complete->ecsa_capable = csr_roaminfo->ecsa_capable;

+ 2 - 0
core/sme/inc/csr_api.h

@@ -574,6 +574,7 @@ struct csr_roam_info {
 	enum sir_sme_phy_mode mode;
 	uint8_t max_supp_idx;
 	uint8_t max_ext_idx;
+	uint8_t max_real_mcs_idx;
 	uint8_t max_mcs_idx;
 	uint8_t rx_mcs_map;
 	uint8_t tx_mcs_map;
@@ -620,6 +621,7 @@ typedef struct sSirSmeAssocIndToUpperLayerCnf {
 	uint8_t max_supp_idx;
 	uint8_t max_ext_idx;
 	uint8_t max_mcs_idx;
+	uint8_t max_real_mcs_idx;
 	uint8_t rx_mcs_map;
 	uint8_t tx_mcs_map;
 	/* Extended capabilities of STA */

+ 3 - 0
core/sme/src/csr/csr_api_roam.c

@@ -3253,6 +3253,8 @@ void csr_roam_joined_state_msg_processor(struct mac_context *mac, void *msg_buf)
 		roam_info->max_supp_idx = pUpperLayerAssocCnf->max_supp_idx;
 		roam_info->max_ext_idx = pUpperLayerAssocCnf->max_ext_idx;
 		roam_info->max_mcs_idx = pUpperLayerAssocCnf->max_mcs_idx;
+		roam_info->max_real_mcs_idx =
+					pUpperLayerAssocCnf->max_real_mcs_idx;
 		roam_info->rx_mcs_map = pUpperLayerAssocCnf->rx_mcs_map;
 		roam_info->tx_mcs_map = pUpperLayerAssocCnf->tx_mcs_map;
 		roam_info->ecsa_capable = pUpperLayerAssocCnf->ecsa_capable;
@@ -3776,6 +3778,7 @@ csr_send_assoc_ind_to_upper_layer_cnf_msg(struct mac_context *mac,
 	cnf->max_supp_idx = ind->max_supp_idx;
 	cnf->max_ext_idx = ind->max_ext_idx;
 	cnf->max_mcs_idx = ind->max_mcs_idx;
+	cnf->max_real_mcs_idx = ind->max_real_mcs_idx;
 	cnf->rx_mcs_map = ind->rx_mcs_map;
 	cnf->tx_mcs_map = ind->tx_mcs_map;
 	cnf->ecsa_capable = ind->ecsa_capable;

+ 5 - 1
os_if/son/src/os_if_son.c

@@ -1763,7 +1763,11 @@ QDF_STATUS os_if_son_get_node_datarate_info(struct wlan_objmgr_vdev *vdev,
 		ucfg_son_get_min_and_max_power(psoc, &max_tx_power,
 					       &min_tx_power);
 		node_info->max_txpower = max_tx_power;
-		node_info->max_MCS = MAX_HE_MCS_IDX;
+		node_info->max_MCS = ucfg_mlme_get_vdev_max_mcs_idx(vdev);
+		if (node_info->max_MCS == INVALID_MCS_NSS_INDEX) {
+			osif_err("invalid mcs index");
+			return QDF_STATUS_E_INVAL;
+		}
 		osif_debug("node info: max_chwidth: %u, phymode: %u, num_streams: %d, max_mcs: %d, max_txpower: %d",
 			   node_info->max_chwidth, node_info->phymode,
 			   node_info->num_streams, node_info->max_MCS,