qcacld-3.0: Add support for NSS configurability

qcacld-2.0 to qcacld-3.0 propagation

Add support for NSS configurability per vdev type
- Configure the 2g and 5g NSS with the INI value of
each vdev type
- Program the HT and VHT IE to FW for 1x1 and 2x2 mode,
FW will include them in scan probe request frames

Change-Id: I5cbf17a14ab6becad6cf5765ae5039fc284dc309
CRs-Fixed: 869026
diff --git a/core/mac/inc/ani_global.h b/core/mac/inc/ani_global.h
index 1e70972..ec52065 100644
--- a/core/mac/inc/ani_global.h
+++ b/core/mac/inc/ani_global.h
@@ -113,6 +113,27 @@
 /* Minimum size of vendor IE = 3 bytes of oui_data + 1 byte of data */
 #define IE_VENDOR_OUI_SIZE   (4)
 
+/*
+ * NSS cfg bit definition.
+ * STA          BIT[0:1]
+ * SAP          BIT[2:3]
+ * P2P_GO       BIT[4:5]
+ * P2P_CLIENT   BIT[6:7]
+ * IBSS         BIT[8:9]
+ * TDLS         BIT[10:11]
+ * P2P_DEVICE   BIT[12:13]
+ * OCB          BIT[14:15]
+ */
+
+#define CFG_STA_NSS(_x)     ((((_x) >> 0) & 0x3) ? (((_x) >> 0) & 0x3) : 1)
+#define CFG_SAP_NSS(_x)     ((((_x) >> 2) & 0x3) ? (((_x) >> 2) & 0x3) : 1)
+#define CFG_P2P_GO_NSS(_x)  ((((_x) >> 4) & 0x3) ? (((_x) >> 4) & 0x3) : 1)
+#define CFG_P2P_CLI_NSS(_x) ((((_x) >> 6) & 0x3) ? (((_x) >> 6) & 0x3) : 1)
+#define CFG_IBSS_NSS(_x)    ((((_x) >> 8) & 0x3) ? (((_x) >> 8) & 0x3) : 1)
+#define CFG_TDLS_NSS(_x)    ((((_x) >> 10) & 0x3) ? (((_x) >> 10) & 0x3) : 1)
+#define CFG_P2P_DEV_NSS(_x) ((((_x) >> 12) & 0x3) ? (((_x) >> 12) & 0x3) : 1)
+#define CFG_OCB_NSS(_x)     ((((_x) >> 14) & 0x3) ? (((_x) >> 14) & 0x3) : 1)
+
 /**
  * enum log_event_type - Type of event initiating bug report
  * @WLAN_LOG_TYPE_NON_FATAL: Non fatal event
@@ -966,6 +987,29 @@
 	LIM_AUTH_ACK_RCD_SUCCESS,
 	LIM_AUTH_ACK_RCD_FAILURE,
 };
+/**
+ * struct vdev_type_nss - vdev type nss structure
+ * @sta: STA Nss value.
+ * @sap: SAP Nss value.
+ * @p2p_go: P2P GO Nss value.
+ * @p2p_cli: P2P CLI Nss value.
+ * @p2p_dev: P2P device Nss value.
+ * @ibss: IBSS Nss value.
+ * @tdls: TDLS Nss value.
+ * @ocb: OCB Nss value.
+ *
+ * Holds the Nss values of different vdev types.
+ */
+struct vdev_type_nss {
+	uint8_t sta;
+	uint8_t sap;
+	uint8_t p2p_go;
+	uint8_t p2p_cli;
+	uint8_t p2p_dev;
+	uint8_t ibss;
+	uint8_t tdls;
+	uint8_t ocb;
+};
 
 /* ------------------------------------------------------------------- */
 /* / MAC Sirius parameter structure */
@@ -1027,6 +1071,10 @@
 	hdd_ftm_msg_processor ftm_msg_processor_callback;
 	bool policy_manager_enabled;
 	uint32_t fine_time_meas_cap;
+	/* per band chain mask support */
+	bool per_band_chainmask_supp;
+	struct vdev_type_nss vdev_type_nss_2g;
+	struct vdev_type_nss vdev_type_nss_5g;
 
 	/* 802.11p enable */
 	bool enable_dot11p;
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index c0b33c9..c24ec17 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -3657,6 +3657,9 @@
 
 typedef struct sSirUpdateChan {
 	uint8_t numChan;
+	uint8_t ht_en;
+	uint8_t vht_en;
+	uint8_t vht_24_en;
 	tSirUpdateChanParam chanParam[1];
 } tSirUpdateChanList, *tpSirUpdateChanList;
 
@@ -4712,6 +4715,24 @@
 	uint32_t enable;
 };
 
+/**
+ * struct sir_set_ht_vht_cfg - ht, vht IE config
+ * @msg_type: message type
+ * @len: message length
+ * @pdev_id: pdev id
+ * @nss: Nss value
+ * @dot11mode: Dot11 mode.
+ *
+ * Message wrapper structure for set HT/VHT IE req.
+ */
+struct sir_set_ht_vht_cfg {
+	uint16_t msg_type;
+	uint16_t len;
+	uint32_t pdev_id;
+	uint32_t nss;
+	uint32_t dot11mode;
+};
+
 /*---------------------------------------------------------------------------
    WLAN_HAL_LL_NOTIFY_STATS
    ---------------------------------------------------------------------------*/
diff --git a/core/mac/inc/sir_mac_prot_def.h b/core/mac/inc/sir_mac_prot_def.h
index 596f558..4aaac56 100644
--- a/core/mac/inc/sir_mac_prot_def.h
+++ b/core/mac/inc/sir_mac_prot_def.h
@@ -390,7 +390,13 @@
 #define SIR_MAC_VHT_OPMODE_EID         199
 #define SIR_MAC_MAX_SUPPORTED_MCS_SET    16
 
+#define VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1       390
+#define VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1       390
+#define VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2       780
+#define VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2       780
+
 #define VHT_MCS_1x1 0xFFFC
+#define VHT_MCS_2x2 0xFFF3
 
 #ifdef FEATURE_AP_MCC_CH_AVOIDANCE
 #define SIR_MAC_QCOM_VENDOR_EID      200
diff --git a/core/mac/inc/wni_api.h b/core/mac/inc/wni_api.h
index e6dfb2d..160ada1 100644
--- a/core/mac/inc/wni_api.h
+++ b/core/mac/inc/wni_api.h
@@ -250,6 +250,7 @@
 	eWNI_SME_SET_ANTENNA_MODE_RESP,
 	eWNI_SME_TSF_EVENT,
 	eWNI_SME_MON_INIT_SESSION,
+	eWNI_SME_PDEV_SET_HT_VHT_IE,
 	eWNI_SME_MSG_TYPES_END
 };
 
diff --git a/core/mac/src/include/parser_api.h b/core/mac/src/include/parser_api.h
index 2156676..7019d99 100644
--- a/core/mac/src/include/parser_api.h
+++ b/core/mac/src/include/parser_api.h
@@ -55,6 +55,9 @@
 #define IS_2X2_CHAIN(__chain) ((__chain & 0x3) == 0x3)
 #define DISABLE_NSS2_MCS 0xC
 
+#define NSS_1x1_MODE 1
+#define NSS_2x2_MODE 2
+
 #ifdef FEATURE_AP_MCC_CH_AVOIDANCE
 #define QCOM_VENDOR_IE_MCC_AVOID_CH 0x01
 
diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h
index 476e4a6..26910c8 100644
--- a/core/mac/src/include/sir_params.h
+++ b/core/mac/src/include/sir_params.h
@@ -611,6 +611,7 @@
 
 #define SIR_HAL_SET_WISA_PARAMS             (SIR_HAL_ITC_MSG_TYPES_BEGIN + 343)
 #define SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS  (SIR_HAL_ITC_MSG_TYPES_BEGIN + 344)
+#define SIR_HAL_SET_PDEV_IE_REQ             (SIR_HAL_ITC_MSG_TYPES_BEGIN + 345)
 #define SIR_HAL_MSG_TYPES_END                (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF)
 
 /* CFG message types */
diff --git a/core/mac/src/pe/include/lim_session.h b/core/mac/src/pe/include/lim_session.h
index a5bf8f7..8f3f118 100644
--- a/core/mac/src/pe/include/lim_session.h
+++ b/core/mac/src/pe/include/lim_session.h
@@ -475,6 +475,7 @@
 	bool add_bss_failed;
 	/* To hold OBSS Scan IE Parameters */
 	struct obss_scanparam obss_ht40_scanparam;
+	uint8_t vdev_nss;
 	/* Supported NSS is intersection of self and peer NSS */
 	bool supported_nss_1x1;
 	bool is_ext_caps_present;
diff --git a/core/mac/src/pe/lim/lim_assoc_utils.c b/core/mac/src/pe/lim/lim_assoc_utils.c
index 7144f94..2a1dfec 100644
--- a/core/mac/src/pe/lim/lim_assoc_utils.c
+++ b/core/mac/src/pe/lim/lim_assoc_utils.c
@@ -1409,8 +1409,8 @@
 		QDF_MIN(rates->vhtRxHighestDataRate,
 			peer_vht_caps->rxHighSupDataRate);
 
-	if (mac_ctx->roam.configParam.enable2x2) {
-		if (session_entry && mac_ctx->lteCoexAntShare &&
+	if (session_entry && session_entry->vdev_nss == 2) {
+		if (mac_ctx->lteCoexAntShare &&
 			IS_24G_CH(session_entry->currentOperChannel)) {
 			if (IS_2X2_CHAIN(session_entry->chainMask))
 				mcs_map_mask2x2 = MCSMAPMASK2x2;
@@ -1627,6 +1627,8 @@
 			return eSIR_FAILURE;
 		}
 
+		if (session_entry->vdev_nss == 1)
+			rates->supportedMCSSet[1] = 0;
 		/*
 		 * if supported MCS Set of the peer is passed in,
 		 * then do the intersection
@@ -1766,8 +1768,12 @@
 			       )
 			return eSIR_FAILURE;
 		}
-		/* if supported MCS Set of the peer is passed in, then do the intersection */
-		/* else use the MCS set from local CFG. */
+		if (psessionEntry->vdev_nss == 1)
+			pRates->supportedMCSSet[1] = 0;
+
+		/* if supported MCS Set of the peer is passed in, then do the
+		 * intersection, else use the MCS set from local CFG.
+		 */
 		if (pSupportedMCSSet != NULL) {
 			for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++)
 				pRates->supportedMCSSet[i] &=
@@ -1991,6 +1997,9 @@
 			return eSIR_FAILURE;
 		}
 
+		if (session_entry->vdev_nss == 1)
+			mcs_set[1] = 0;
+
 		for (i = 0; i < val; i++)
 			sta_ds->supportedRates.supportedMCSSet[i] =
 				mcs_set[i] & supported_mcs_set[i];
diff --git a/core/mac/src/pe/lim/lim_process_message_queue.c b/core/mac/src/pe/lim/lim_process_message_queue.c
index bebe812..d8031c2 100644
--- a/core/mac/src/pe/lim/lim_process_message_queue.c
+++ b/core/mac/src/pe/lim/lim_process_message_queue.c
@@ -1414,6 +1414,7 @@
 			msg->bodyptr = NULL;
 		}
 		break;
+	case eWNI_SME_PDEV_SET_HT_VHT_IE:
 	case eWNI_SME_SYS_READY_IND:
 	case eWNI_SME_JOIN_REQ:
 	case eWNI_SME_REASSOC_REQ:
diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c
index e58f600..f2d1d99 100644
--- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c
+++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c
@@ -116,7 +116,6 @@
 
 extern void pe_register_wma_handle(tpAniSirGlobal pMac,
 		tSirSmeReadyReq *ready_req);
-
 static void lim_process_ext_change_channel(tpAniSirGlobal mac_ctx,
 						uint32_t *msg);
 
@@ -224,7 +223,7 @@
 
 	req_msg = qdf_mem_malloc(len);
 	if (!req_msg) {
-		lim_log(mac, LOGE, FL("vos_mem_malloc failed"));
+		lim_log(mac, LOGE, FL("qdf_mem_malloc failed"));
 		/* Free the active command list
 		 * Probably the malloc is going to fail there as well?!
 		 */
@@ -631,6 +630,7 @@
 	uint8_t sme_session_id = 0;
 	uint16_t sme_transaction_id = 0;
 	uint32_t chanwidth;
+	struct vdev_type_nss *vdev_type_nss;
 	tSirRetStatus cfg_get_wmi_dfs_master_param = eSIR_SUCCESS;
 
 /* FEATURE_WLAN_DIAG_SUPPORT */
@@ -779,10 +779,6 @@
 			  session->vhtCapability);
 		session->txLdpcIniFeatureEnabled =
 			sme_start_bss_req->txLdpcIniFeatureEnabled;
-		if (mac_ctx->roam.configParam.enable2x2)
-			session->nss = 2;
-		else
-			session->nss = 1;
 #ifdef WLAN_FEATURE_11W
 		session->limRmfEnabled =
 			sme_start_bss_req->pmfCapable ? 1 : 0;
@@ -797,6 +793,11 @@
 			     (void *)&sme_start_bss_req->extendedRateSet,
 			     sizeof(tSirMacRateSet));
 
+		if (IS_5G_CH(session->currentOperChannel))
+			vdev_type_nss = &mac_ctx->vdev_type_nss_5g;
+		else
+			vdev_type_nss = &mac_ctx->vdev_type_nss_2g;
+
 		switch (sme_start_bss_req->bssType) {
 		case eSIR_INFRA_AP_MODE:
 			lim_configure_ap_start_bss_session(mac_ctx, session,
@@ -806,6 +807,9 @@
 					sme_start_bss_req->txbf_ini_enabled;
 				session->txbf_csn_value =
 					sme_start_bss_req->txbf_csn_val;
+				session->vdev_nss = vdev_type_nss->sap;
+			} else {
+				session->vdev_nss = vdev_type_nss->p2p_go;
 			}
 			break;
 		case eSIR_IBSS_MODE:
@@ -819,6 +823,7 @@
 			 * will be updated upon key installation
 			 */
 			session->encryptType = eSIR_ED_NONE;
+			session->vdev_nss = vdev_type_nss->ibss;
 
 			break;
 
@@ -834,6 +839,9 @@
 			break;
 		}
 
+		lim_log(mac_ctx, LOG1, FL("persona - %d, nss - %d"),
+				session->pePersona, session->vdev_nss);
+		session->nss = session->vdev_nss;
 		/*
 		 * Allocate memory for the array of
 		 * parsed (Re)Assoc request structure
@@ -1202,7 +1210,8 @@
 	uint8_t *ht_cap_ie;
 	tSirMsgQ msg;
 	uint16_t i, len;
-	uint16_t ht_cap_len = 0, addn_ie_len = 0;
+	uint16_t ht_cap_len = 0;
+	uint16_t addn_ie_len = 0;
 	uint8_t *vht_cap_ie;
 	uint16_t vht_cap_len = 0;
 	tSirRetStatus status, rc = eSIR_SUCCESS;
@@ -1236,29 +1245,30 @@
 	 * so allocate the memory for (numChannels - 1) and uIEFieldLen
 	 */
 	len = sizeof(tSirScanOffloadReq) +
-		(pScanReq->channelList.numChannels - 1) + pScanReq->uIEFieldLen;
+		(pScanReq->channelList.numChannels - 1) +
+		pScanReq->uIEFieldLen;
+	if (!pMac->per_band_chainmask_supp) {
+		if (IS_DOT11_MODE_HT(pScanReq->dot11mode)) {
+			lim_log(pMac, LOG1, FL(
+				"Adding HT Caps IE since dot11mode=%d"),
+					pScanReq->dot11mode);
+			/* 2 bytes for EID and Length */
+			ht_cap_len = 2 + sizeof(tHtCaps);
+			len += ht_cap_len;
+			addn_ie_len += ht_cap_len;
+		}
 
-	if (IS_DOT11_MODE_HT(pScanReq->dot11mode)) {
-		lim_log(pMac, LOG1,
-			FL("Adding HT Caps IE since dot11mode=%d"),
-			pScanReq->dot11mode);
-		/* 2 bytes for EID and Length */
-		ht_cap_len = 2 + sizeof(tHtCaps);
-		len += ht_cap_len;
-		addn_ie_len += ht_cap_len;
+		if (IS_DOT11_MODE_VHT(pScanReq->dot11mode)) {
+			lim_log(pMac, LOG1, FL(
+				"Adding VHT Caps IE since dot11mode=%d"),
+				pScanReq->dot11mode);
+			/* 2 bytes for EID and Length */
+			vht_cap_len = 2 + sizeof(tSirMacVHTCapabilityInfo) +
+				sizeof(tSirVhtMcsInfo);
+			len += vht_cap_len;
+			addn_ie_len += vht_cap_len;
+		}
 	}
-
-	if (IS_DOT11_MODE_VHT(pScanReq->dot11mode)) {
-		lim_log(pMac, LOG1,
-			FL("Adding VHT Caps IE since dot11mode=%d"),
-			pScanReq->dot11mode);
-		/* 2 bytes for EID and Length */
-		vht_cap_len = 2 + sizeof(tSirMacVHTCapabilityInfo) +
-				  sizeof(tSirVhtMcsInfo);
-		len += vht_cap_len;
-		addn_ie_len += vht_cap_len;
-	}
-
 	pScanOffloadReq = qdf_mem_malloc(len);
 	if (NULL == pScanOffloadReq) {
 		lim_log(pMac, LOGE,
@@ -1331,33 +1341,33 @@
 		     pScanOffloadReq->uIEFieldOffset,
 		     (uint8_t *) pScanReq + pScanReq->uIEFieldOffset,
 		     pScanReq->uIEFieldLen);
+	if (!pMac->per_band_chainmask_supp) {
+		/* Copy HT Capability info if dot11mode is HT */
+		if (IS_DOT11_MODE_HT(pScanReq->dot11mode)) {
+			/* Populate EID and Length field here */
+			ht_cap_ie = (uint8_t *) pScanOffloadReq +
+				pScanOffloadReq->uIEFieldOffset +
+				pScanOffloadReq->uIEFieldLen;
+			qdf_mem_set(ht_cap_ie, ht_cap_len, 0);
+			*ht_cap_ie = SIR_MAC_HT_CAPABILITIES_EID;
+			*(ht_cap_ie + 1) =  ht_cap_len - 2;
+			lim_set_ht_caps(pMac, NULL, ht_cap_ie, ht_cap_len);
+			pScanOffloadReq->uIEFieldLen += ht_cap_len;
+		}
 
-	/* Copy HT Capability info if dot11mode is HT */
-	if (IS_DOT11_MODE_HT(pScanReq->dot11mode)) {
-		/* Populate EID and Length field here */
-		ht_cap_ie = (uint8_t *) pScanOffloadReq +
-					pScanOffloadReq->uIEFieldOffset +
-					pScanOffloadReq->uIEFieldLen;
-		qdf_mem_set(ht_cap_ie, ht_cap_len, 0);
-		*ht_cap_ie = SIR_MAC_HT_CAPABILITIES_EID;
-		*(ht_cap_ie + 1) =  ht_cap_len - 2;
-		lim_set_ht_caps(pMac, NULL, ht_cap_ie, ht_cap_len);
-		pScanOffloadReq->uIEFieldLen += ht_cap_len;
+		/* Copy VHT Capability info if dot11mode is VHT Capable */
+		if (IS_DOT11_MODE_VHT(pScanReq->dot11mode)) {
+			/* Populate EID and Length field here */
+			vht_cap_ie = (uint8_t *) pScanOffloadReq +
+				pScanOffloadReq->uIEFieldOffset +
+				pScanOffloadReq->uIEFieldLen;
+			qdf_mem_set(vht_cap_ie, vht_cap_len, 0);
+			*vht_cap_ie = SIR_MAC_VHT_CAPABILITIES_EID;
+			*(vht_cap_ie + 1) =  vht_cap_len - 2;
+			lim_set_vht_caps(pMac, NULL, vht_cap_ie, vht_cap_len);
+			pScanOffloadReq->uIEFieldLen += vht_cap_len;
+		}
 	}
-
-	/* Copy VHT Capability info if dot11mode is VHT Capable */
-	if (IS_DOT11_MODE_VHT(pScanReq->dot11mode)) {
-		/* Populate EID and Length field here */
-		vht_cap_ie = (uint8_t *) pScanOffloadReq +
-					 pScanOffloadReq->uIEFieldOffset +
-					 pScanOffloadReq->uIEFieldLen;
-		qdf_mem_set(vht_cap_ie, vht_cap_len, 0);
-		*vht_cap_ie = SIR_MAC_VHT_CAPABILITIES_EID;
-		*(vht_cap_ie + 1) =  vht_cap_len - 2;
-		lim_set_vht_caps(pMac, NULL, vht_cap_ie, vht_cap_len);
-		pScanOffloadReq->uIEFieldLen += vht_cap_len;
-	}
-
 	rc = wma_post_ctrl_msg(pMac, &msg);
 	if (rc != eSIR_SUCCESS) {
 		lim_log(pMac, LOGE, FL("wma_post_ctrl_msg() return failure"));
@@ -1570,6 +1580,7 @@
 	uint16_t ie_len;
 	uint8_t *vendor_ie;
 	tSirBssDescription *bss_desc;
+	struct vdev_type_nss *vdev_type_nss;
 
 /* FEATURE_WLAN_DIAG_SUPPORT */
 #ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM
@@ -1750,10 +1761,23 @@
 			session->supported_nss_1x1,
 			session->pePersona,
 			sme_join_req->cbMode);
-		if (mac_ctx->roam.configParam.enable2x2)
-			session->nss = 2;
+
+		/*Store Persona */
+		session->pePersona = sme_join_req->staPersona;
+		QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO,
+			  FL("PE PERSONA=%d cbMode %u"),
+			  session->pePersona, sme_join_req->cbMode);
+		/* Copy The channel Id to the session Table */
+		session->currentOperChannel = bss_desc->channelId;
+		if (IS_5G_CH(session->currentOperChannel))
+			vdev_type_nss = &mac_ctx->vdev_type_nss_5g;
 		else
-			session->nss = 1;
+			vdev_type_nss = &mac_ctx->vdev_type_nss_2g;
+		if (session->pePersona == QDF_P2P_CLIENT_MODE)
+			session->vdev_nss = vdev_type_nss->p2p_cli;
+		else
+			session->vdev_nss = vdev_type_nss->sta;
+		session->nss = session->vdev_nss;
 		session->vhtCapability =
 			IS_DOT11_MODE_VHT(session->dot11mode);
 		if (session->vhtCapability) {
@@ -1801,8 +1825,6 @@
 		/*Phy mode */
 		session->gLimPhyMode = bss_desc->nwType;
 		handle_ht_capabilityand_ht_info(mac_ctx, session);
-		/* Copy The channel Id to the session Table */
-		session->currentOperChannel = bss_desc->channelId;
 		/* cbMode is already merged value of peer and self -
 		 * done by csr in csr_get_cb_mode_from_ies */
 		session->htSupportedChannelWidthSet =
@@ -4698,6 +4720,179 @@
 }
 
 /**
+ * lim_set_pdev_ht_ie() - sends the set HT IE req to FW
+ * @mac_ctx: Pointer to Global MAC structure
+ * @pdev_id: pdev id to set the IE.
+ * @nss: Nss values to prepare the HT IE.
+ *
+ * Prepares the HT IE with self capabilities for different
+ * Nss values and sends the set HT IE req to FW.
+ *
+ * Return: None
+ */
+static void lim_set_pdev_ht_ie(tpAniSirGlobal mac_ctx, uint8_t pdev_id,
+		uint8_t nss)
+{
+	struct set_ie_param *ie_params;
+	tSirMsgQ msg;
+	tSirRetStatus rc = eSIR_SUCCESS;
+	uint8_t *p_ie = NULL;
+	tHtCaps *p_ht_cap;
+	int i;
+
+	for (i = nss; i > 0; i--) {
+		ie_params = qdf_mem_malloc(sizeof(*ie_params));
+		if (NULL == ie_params) {
+			lim_log(mac_ctx, LOGE, FL("mem alloc failed"));
+			return;
+		}
+		ie_params->nss = i;
+		ie_params->pdev_id = pdev_id;
+		ie_params->ie_type = DOT11_HT_IE;
+		/* 2 for IE len and EID */
+		ie_params->ie_len = 2 + sizeof(tHtCaps);
+		ie_params->ie_ptr = qdf_mem_malloc(ie_params->ie_len);
+		if (NULL == ie_params->ie_ptr) {
+			qdf_mem_free(ie_params);
+			lim_log(mac_ctx, LOGE, FL("mem alloc failed"));
+			return;
+		}
+		*ie_params->ie_ptr = SIR_MAC_HT_CAPABILITIES_EID;
+		*(ie_params->ie_ptr + 1) = ie_params->ie_len - 2;
+		lim_set_ht_caps(mac_ctx, NULL, ie_params->ie_ptr,
+				ie_params->ie_len);
+
+		if (NSS_1x1_MODE == i) {
+			p_ie = lim_get_ie_ptr_new(mac_ctx, ie_params->ie_ptr,
+					ie_params->ie_len,
+					DOT11F_EID_HTCAPS, ONE_BYTE);
+			p_ht_cap = (tHtCaps *)&p_ie[2];
+			p_ht_cap->supportedMCSSet[1] = 0;
+			p_ht_cap->txSTBC = 0;
+		}
+
+		msg.type = WMA_SET_PDEV_IE_REQ;
+		msg.bodyptr = ie_params;
+		msg.bodyval = 0;
+
+		rc = wma_post_ctrl_msg(mac_ctx, &msg);
+		if (rc != eSIR_SUCCESS) {
+			lim_log(mac_ctx, LOGE,
+				FL("wma_post_ctrl_msg() return failure"));
+			qdf_mem_free(ie_params->ie_ptr);
+			qdf_mem_free(ie_params);
+			return;
+		}
+	}
+}
+
+/**
+ * lim_set_pdev_vht_ie() - sends the set VHT IE to req FW
+ * @mac_ctx: Pointer to Global MAC structure
+ * @pdev_id: pdev id to set the IE.
+ * @nss: Nss values to prepare the VHT IE.
+ *
+ * Prepares the VHT IE with self capabilities for different
+ * Nss values and sends the set VHT IE req to FW.
+ *
+ * Return: None
+ */
+static void lim_set_pdev_vht_ie(tpAniSirGlobal mac_ctx, uint8_t pdev_id,
+		uint8_t nss)
+{
+	struct set_ie_param *ie_params;
+	tSirMsgQ msg;
+	tSirRetStatus rc = eSIR_SUCCESS;
+	uint8_t *p_ie = NULL;
+	tSirMacVHTCapabilityInfo *vht_cap;
+	int i;
+	tSirVhtMcsInfo *vht_mcs;
+
+	for (i = nss; i > 0; i--) {
+		ie_params = qdf_mem_malloc(sizeof(*ie_params));
+		if (NULL == ie_params) {
+			lim_log(mac_ctx, LOGE, FL("mem alloc failed"));
+			return;
+		}
+		ie_params->nss = i;
+		ie_params->pdev_id = pdev_id;
+		ie_params->ie_type = DOT11_VHT_IE;
+		/* 2 for IE len and EID */
+		ie_params->ie_len = 2 + sizeof(tSirMacVHTCapabilityInfo) +
+			sizeof(tSirVhtMcsInfo);
+		ie_params->ie_ptr = qdf_mem_malloc(ie_params->ie_len);
+		if (NULL == ie_params->ie_ptr) {
+			qdf_mem_free(ie_params);
+			lim_log(mac_ctx, LOGE, FL("mem alloc failed"));
+			return;
+		}
+		*ie_params->ie_ptr = SIR_MAC_VHT_CAPABILITIES_EID;
+		*(ie_params->ie_ptr + 1) = ie_params->ie_len - 2;
+		lim_set_vht_caps(mac_ctx, NULL, ie_params->ie_ptr,
+				ie_params->ie_len);
+
+		if (NSS_1x1_MODE == i) {
+			p_ie = lim_get_ie_ptr_new(mac_ctx, ie_params->ie_ptr,
+					ie_params->ie_len,
+					DOT11F_EID_VHTCAPS, ONE_BYTE);
+			vht_cap = (tSirMacVHTCapabilityInfo *)&p_ie[2];
+			vht_cap->txSTBC = 0;
+			vht_mcs =
+				(tSirVhtMcsInfo *)&p_ie[2 +
+				sizeof(tSirMacVHTCapabilityInfo)];
+			vht_mcs->rxMcsMap |= DISABLE_NSS2_MCS;
+			vht_mcs->rxHighest =
+				VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1;
+			vht_mcs->txMcsMap |= DISABLE_NSS2_MCS;
+			vht_mcs->txHighest =
+				VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1;
+		}
+		msg.type = WMA_SET_PDEV_IE_REQ;
+		msg.bodyptr = ie_params;
+		msg.bodyval = 0;
+
+		rc = wma_post_ctrl_msg(mac_ctx, &msg);
+		if (rc != eSIR_SUCCESS) {
+			lim_log(mac_ctx, LOGE,
+					FL("wma_post_ctrl_msg failure"));
+			qdf_mem_free(ie_params->ie_ptr);
+			qdf_mem_free(ie_params);
+			return;
+		}
+	}
+}
+
+/**
+ * lim_process_set_pdev_IEs() - process the set pdev IE req
+ * @mac_ctx: Pointer to Global MAC structure
+ * @msg_buf: Pointer to the SME message buffer
+ *
+ * This function is called by limProcessMessageQueue(). This
+ * function sets the PDEV IEs to the FW.
+ *
+ * Return: None
+ */
+static void lim_process_set_pdev_IEs(tpAniSirGlobal mac_ctx, uint32_t *msg_buf)
+{
+	struct sir_set_ht_vht_cfg *ht_vht_cfg;
+
+	ht_vht_cfg = (struct sir_set_ht_vht_cfg *)msg_buf;
+
+	if (NULL == ht_vht_cfg) {
+		lim_log(mac_ctx, LOGE, FL("NULL ht_vht_cfg"));
+		return;
+	}
+
+	lim_log(mac_ctx, LOG1, FL("rcvd set pdev ht vht ie req with nss = %d"),
+			ht_vht_cfg->nss);
+	lim_set_pdev_ht_ie(mac_ctx, ht_vht_cfg->pdev_id, ht_vht_cfg->nss);
+
+	if (IS_DOT11_MODE_VHT(ht_vht_cfg->dot11mode))
+		lim_set_pdev_vht_ie(mac_ctx, ht_vht_cfg->pdev_id,
+				ht_vht_cfg->nss);
+}
+
+/**
  * lim_process_sme_req_messages()
  *
  ***FUNCTION:
@@ -4938,6 +5133,9 @@
 	case eWNI_SME_SET_ANTENNA_MODE_REQ:
 		lim_process_set_antenna_mode_req(pMac, pMsgBuf);
 		break;
+	case eWNI_SME_PDEV_SET_HT_VHT_IE:
+		lim_process_set_pdev_IEs(pMac, pMsgBuf);
+		break;
 	default:
 		qdf_mem_free((void *)pMsg->bodyptr);
 		pMsg->bodyptr = NULL;