Ver Fonte

qcacld-3.0: Update 11AX - Draft 1.4 MCS support - 2/2

Update driver to conform with Draft 1.4 MCS frame parser changes made
as part of Change-Id: I207db123d463f54ed6b148c9e957eb551d617ca2.

Change-Id: I4007ce0303b87c281b6fb2a94df576ee0da3f3e8
CRs-Fixed: 2130185
Naveen Rawat há 7 anos atrás
pai
commit
aeca1b93d6

+ 20 - 3
core/hdd/src/wlan_hdd_he.c

@@ -53,6 +53,7 @@ static int hdd_he_set_wni_cfg(struct hdd_context *hdd_ctx,
 void hdd_update_tgt_he_cap(struct hdd_context *hdd_ctx,
 			   struct wma_tgt_cfg *cfg)
 {
+	uint8_t chan_width;
 	uint32_t ppet_size = sizeof(tDot11fIEppe_threshold);
 	QDF_STATUS status;
 	tDot11fIEhe_cap *he_cap = &cfg->he_cap;
@@ -108,7 +109,12 @@ void hdd_update_tgt_he_cap(struct hdd_context *hdd_ctx,
 			   he_cap->ops_supp);
 
 	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_DUAL_BAND, he_cap->dual_band);
-	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_CHAN_WIDTH, he_cap->chan_width);
+	chan_width = HE_CH_WIDTH_COMBINE(he_cap->chan_width_0,
+				he_cap->chan_width_1, he_cap->chan_width_2,
+				he_cap->chan_width_3, he_cap->chan_width_4,
+				he_cap->chan_width_5, he_cap->chan_width_6);
+
+	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_CHAN_WIDTH, chan_width);
 	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_RX_PREAM_PUNC,
 			   he_cap->rx_pream_puncturing);
 	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_CLASS_OF_DEVICE,
@@ -165,8 +171,19 @@ void hdd_update_tgt_he_cap(struct hdd_context *hdd_ctx,
 			   he_cap->stbc_gt_80mhz);
 	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_ER_4x_LTF_GI,
 			   he_cap->er_he_ltf_800_gi_4x);
-	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_NSS, he_cap->nss_supported);
-	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MCS, he_cap->mcs_supported);
+
+	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_RX_MCS_MAP_LT_80,
+			he_cap->rx_he_mcs_map_lt_80);
+	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_TX_MCS_MAP_LT_80,
+			he_cap->tx_he_mcs_map_lt_80);
+	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_RX_MCS_MAP_160,
+		*((uint16_t *)he_cap->rx_he_mcs_map_160));
+	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_TX_MCS_MAP_160,
+		*((uint16_t *)he_cap->tx_he_mcs_map_160));
+	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_RX_MCS_MAP_80_80,
+		*((uint16_t *)he_cap->rx_he_mcs_map_80_80));
+	hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_TX_MCS_MAP_80_80,
+		*((uint16_t *)he_cap->tx_he_mcs_map_80_80));
 
 	/* PPET can not be configured by user - Set values from FW */
 	status = sme_cfg_set_str(hdd_ctx->hHal, WNI_CFG_HE_PPET,

+ 83 - 11
core/mac/inc/sir_api.h

@@ -406,8 +406,12 @@ typedef struct sSirSupportedRates {
 	uint16_t vhtTxMCSMap;
 	uint16_t vhtTxHighestDataRate;
 #ifdef WLAN_FEATURE_11AX
-	uint32_t he_rx_mcs;
-	uint32_t he_tx_mcs;
+	uint16_t rx_he_mcs_map_lt_80;
+	uint16_t tx_he_mcs_map_lt_80;
+	uint16_t rx_he_mcs_map_160;
+	uint16_t tx_he_mcs_map_160;
+	uint16_t rx_he_mcs_map_80_80;
+	uint16_t tx_he_mcs_map_80_80;
 #endif
 } tSirSupportedRates, *tpSirSupportedRates;
 
@@ -7574,16 +7578,77 @@ struct wow_enable_params {
 
 #define HE_MAX_PHY_CAP_SIZE 3
 
-/*
- * Three bits are used for each MCS
- * For SS - 1; bits 0-2
- * For SS - 2; bits 3-5
- * MCS values are interpreted as in IEEE 11ax-D1.0 spec
- */
-#define HE_MCS_1x1 0xFFFFFFF8
-#define HE_MCS_2x2 0xFFFFFFC0
+#define HE_CH_WIDTH_GET_BIT(ch_wd, bit)      (((ch_wd) >> (bit)) & 1)
+#define HE_CH_WIDTH_COMBINE(b0, b1, b2, b3, b4, b5, b6)             \
+	((uint8_t)(b0) | ((b1) << 1) | ((b2) << 2) |  ((b3) << 3) | \
+	((b4) << 4) | ((b5) << 5) | ((b6) << 6))
 
-#define HEMCSSIZE 3
+/*
+ * MCS values are interpreted as in IEEE 11ax-D1.4 spec onwards
+ * +-----------------------------------------------------+
+ * |  SS8  |  SS7  |  SS6  | SS5 | SS4 | SS3 | SS2 | SS1 |
+ * +-----------------------------------------------------+
+ * | 15-14 | 13-12 | 11-10 | 9-8 | 7-6 | 5-4 | 3-2 | 1-0 |
+ * +-----------------------------------------------------+
+ */
+#define HE_MCS_NSS_SHIFT(nss)                 (((nss) - 1) << 1)
+#define HE_MCS_MSK_4_NSS(nss)                 (3 << HE_MCS_NSS_SHIFT(nss))
+#define HE_MCS_INV_MSK_4_NSS(nss)             (~HE_MCS_MSK_4_NSS(nss))
+#define HE_GET_MCS_4_NSS(mcs_set, nss)             \
+	(((mcs_set) >> HE_MCS_NSS_SHIFT(nss)) & 3)
+#define HE_SET_MCS_4_NSS(mcs_set, mcs, nss)        \
+	(((mcs_set) & HE_MCS_INV_MSK_4_NSS(nss)) | \
+	((mcs) << HE_MCS_NSS_SHIFT(nss)))
+#define HE_MCS_IS_NSS_ENABLED(mcs_set, nss)        \
+	((HE_MCS_MSK_4_NSS(nss) & (mcs_set)) != HE_MCS_MSK_4_NSS(nss))
+
+#define HE_MCS_ALL_DISABLED                   0xFFFF
+/*
+ * Following formuala has been arrived at using karnaugh map and unit tested
+ * with sample code. Take MCS for each NSS as 2 bit value first and solve for
+ * 2 bit intersection of NSS. Use following table/Matrix as guide for solving
+ * K-Maps
+ * MCS 1\MCS 2    00         01         10         11
+ *    00          00         00         00         11
+ *    01          00         01         01         11
+ *    10          00         01         10         11
+ *    11          11         11         11         11
+ * if output MCS is o1o0, then as per K-map reduction:
+ * o0 = m1.m0 | n1.n0 | (~m1).m0.(n1^n0) | (~n1).n0.(m1^m0)
+ * o1 = m1.m0 | n1.n0 | m1.(~m0).n1.(~n0)
+ *
+ * Please note: Calculating MCS intersection is 80211 protocol specific and
+ * should be implemented in PE. WMA can use this macro rather than calling any
+ * lim API to do the intersection.
+ */
+#define HE_INTERSECT_MCS_BITS_PER_NSS(m1, m0, n1, n0)                \
+	(((m1 & m0) | (n1 & n0) | (((~m1) & m0) & (n1 ^ n0))  |      \
+	(((~n1) & n0) & (m1 ^ m0))) | (((m1 & m0) | (n1 & n0) |      \
+	(m1 & ~m0 & n1 & ~n0)) << 1))
+
+/* following takes MCS as 2 bits */
+#define HE_INTERSECT_MCS_PER_NSS(mcs_1, mcs_2)                       \
+	HE_INTERSECT_MCS_BITS_PER_NSS((mcs_1 >> 1), (mcs_1 & 1),     \
+				      (mcs_2 >> 1), (mcs_2 & 1))
+
+/* following takes MCS as 16 bits */
+#define HE_INTERSECT_MCS(mcs_1, mcs_2)                             ( \
+	HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 1),         \
+		HE_GET_MCS_4_NSS(mcs_2, 1)) << HE_MCS_NSS_SHIFT(1) | \
+	HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 2),         \
+		HE_GET_MCS_4_NSS(mcs_2, 2)) << HE_MCS_NSS_SHIFT(2) | \
+	HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 3),         \
+		HE_GET_MCS_4_NSS(mcs_2, 3)) << HE_MCS_NSS_SHIFT(3) | \
+	HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 4),         \
+		HE_GET_MCS_4_NSS(mcs_2, 4)) << HE_MCS_NSS_SHIFT(4) | \
+	HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 5),         \
+		HE_GET_MCS_4_NSS(mcs_2, 5)) << HE_MCS_NSS_SHIFT(5) | \
+	HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 6),         \
+		HE_GET_MCS_4_NSS(mcs_2, 6)) << HE_MCS_NSS_SHIFT(6) | \
+	HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 7),         \
+		HE_GET_MCS_4_NSS(mcs_2, 7)) << HE_MCS_NSS_SHIFT(7) | \
+	HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 8),         \
+		HE_GET_MCS_4_NSS(mcs_2, 8)) << HE_MCS_NSS_SHIFT(8))
 
 /**
  * struct he_capability - to store 11ax HE capabilities
@@ -7600,6 +7665,13 @@ struct he_capability {
 };
 #endif
 
+#define HE_GET_NSS(mcs, nss)                                         \
+	do {                                                         \
+		(nss) = 0;                                           \
+		while ((((mcs) >> ((nss)*2)) & 3) != 3 && nss <= 8)  \
+			(nss)++;                                     \
+	} while (0)
+
 /**
  * struct sir_del_all_tdls_peers - delete all tdls peers
  * @msg_type: type of message

+ 17 - 8
core/mac/inc/sir_mac_prot_def.h

@@ -2175,10 +2175,12 @@ struct he_capability_info {
 	uint8_t reserved2:3;
 	uint8_t er_he_ltf_800_gi_4x:1;
 
-	uint16_t rx_bw_bitmap:5;
-	uint16_t tx_bw_bitmap:5;
-	uint16_t mcs_supported:3;
-	uint16_t nss_supported:3;
+	uint16_t tx_he_mcs_map_80_80;
+	uint16_t rx_he_mcs_map_80_80;
+	uint16_t tx_he_mcs_map_160;
+	uint16_t rx_he_mcs_map_160;
+	uint16_t tx_he_mcs_map_lt_80;
+	uint16_t rx_he_mcs_map_lt_80;
 #else
 	uint32_t htc_he:1;
 	uint32_t twt_request:1;
@@ -2251,14 +2253,21 @@ struct he_capability_info {
 	uint8_t er_he_ltf_800_gi_4x:1;
 	uint8_t reserved3:7;
 
-	uint16_t nss_supported:3;
-	uint16_t mcs_supported:3;
-	uint16_t tx_bw_bitmap:5;
-	uint16_t rx_bw_bitmap:5;
+	uint16_t rx_he_mcs_map_lt_80;
+	uint16_t tx_he_mcs_map_lt_80;
+	uint16_t rx_he_mcs_map_160;
+	uint16_t tx_he_mcs_map_160;
+	uint16_t rx_he_mcs_map_80_80;
+	uint16_t tx_he_mcs_map_80_80;
 #endif
 } qdf_packed;
 #endif
 
+/*
+ * frame parser does not include optional 160 and 80+80 mcs set for MIN IE len
+ */
+#define SIR_MAC_HE_CAP_MIN_LEN       (DOT11F_IE_HE_CAP_MIN_LEN + 8)
+
 /* QOS action frame definitions */
 
 /* max number of possible tclas elements in any frame */

+ 28 - 8
core/mac/inc/wni_cfg.h

@@ -315,8 +315,12 @@ enum {
 	WNI_CFG_HE_MAX_NC,
 	WNI_CFG_HE_STBC_GT80,
 	WNI_CFG_HE_ER_4x_LTF_GI,
-	WNI_CFG_HE_NSS,
-	WNI_CFG_HE_MCS,
+	WNI_CFG_HE_RX_MCS_MAP_LT_80,
+	WNI_CFG_HE_TX_MCS_MAP_LT_80,
+	WNI_CFG_HE_RX_MCS_MAP_160,
+	WNI_CFG_HE_TX_MCS_MAP_160,
+	WNI_CFG_HE_RX_MCS_MAP_80_80,
+	WNI_CFG_HE_TX_MCS_MAP_80_80,
 	WNI_CFG_HE_PPET,
 	WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT,
 	WNI_CFG_HE_STA_OBSSPD,
@@ -1617,13 +1621,29 @@ enum {
 #define WNI_CFG_HE_ER_4x_LTF_GI_STAMAX 1
 #define WNI_CFG_HE_ER_4x_LTF_GI_STADEF 0
 
-#define WNI_CFG_HE_NSS_STAMIN 0
-#define WNI_CFG_HE_NSS_STAMAX 0x7
-#define WNI_CFG_HE_NSS_STADEF 0
+#define WNI_CFG_HE_RX_MCS_MAP_LT_80_MIN 0x0000
+#define WNI_CFG_HE_RX_MCS_MAP_LT_80_MAX 0xFFFF
+#define WNI_CFG_HE_RX_MCS_MAP_LT_80_DEF 0xFFF0
 
-#define WNI_CFG_HE_MCS_STAMIN 0
-#define WNI_CFG_HE_MCS_STAMAX 0x7
-#define WNI_CFG_HE_MCS_STADEF 0
+#define WNI_CFG_HE_TX_MCS_MAP_LT_80_MIN 0x0000
+#define WNI_CFG_HE_TX_MCS_MAP_LT_80_MAX 0xFFFF
+#define WNI_CFG_HE_TX_MCS_MAP_LT_80_DEF 0xFFF0
+
+#define WNI_CFG_HE_RX_MCS_MAP_160_MIN 0x0000
+#define WNI_CFG_HE_RX_MCS_MAP_160_MAX 0xFFFF
+#define WNI_CFG_HE_RX_MCS_MAP_160_DEF 0xFFF0
+
+#define WNI_CFG_HE_TX_MCS_MAP_160_MIN 0x0000
+#define WNI_CFG_HE_TX_MCS_MAP_160_MAX 0xFFFF
+#define WNI_CFG_HE_TX_MCS_MAP_160_DEF 0xFFF0
+
+#define WNI_CFG_HE_RX_MCS_MAP_80_80_MIN 0x0000
+#define WNI_CFG_HE_RX_MCS_MAP_80_80_MAX 0xFFFF
+#define WNI_CFG_HE_RX_MCS_MAP_80_80_DEF 0xFFF0
+
+#define WNI_CFG_HE_TX_MCS_MAP_80_80_MIN 0x0000
+#define WNI_CFG_HE_TX_MCS_MAP_80_80_MAX 0xFFFF
+#define WNI_CFG_HE_TX_MCS_MAP_80_80_DEF 0xFFF0
 
 #define WNI_CFG_HE_STA_OBSSPD_STAMIN 0
 #define WNI_CFG_HE_STA_OBSSPD_STAMAX 0xffffffff

+ 6 - 2
core/mac/src/cfg/cfg_param_name.c

@@ -324,8 +324,12 @@ const char *cfg_get_string(uint16_t cfg_id)
 	CASE_RETURN_STRING(WNI_CFG_HE_MAX_NC);
 	CASE_RETURN_STRING(WNI_CFG_HE_STBC_GT80);
 	CASE_RETURN_STRING(WNI_CFG_HE_ER_4x_LTF_GI);
-	CASE_RETURN_STRING(WNI_CFG_HE_NSS);
-	CASE_RETURN_STRING(WNI_CFG_HE_MCS);
+	CASE_RETURN_STRING(WNI_CFG_HE_RX_MCS_MAP_LT_80);
+	CASE_RETURN_STRING(WNI_CFG_HE_TX_MCS_MAP_LT_80);
+	CASE_RETURN_STRING(WNI_CFG_HE_RX_MCS_MAP_160);
+	CASE_RETURN_STRING(WNI_CFG_HE_TX_MCS_MAP_160);
+	CASE_RETURN_STRING(WNI_CFG_HE_RX_MCS_MAP_80_80);
+	CASE_RETURN_STRING(WNI_CFG_HE_TX_MCS_MAP_80_80);
 	CASE_RETURN_STRING(WNI_CFG_HE_PPET);
 	CASE_RETURN_STRING(WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT);
 	CASE_RETURN_STRING(WNI_CFG_HE_STA_OBSSPD);

+ 29 - 6
core/mac/src/cfg/cfg_proc_msg.c

@@ -1409,14 +1409,37 @@ cgstatic cfg_static[CFG_PARAM_MAX_NUM] = {
 	CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT,
 	WNI_CFG_HE_ER_4x_LTF_GI_STAMIN, WNI_CFG_HE_ER_4x_LTF_GI_STAMAX,
 	WNI_CFG_HE_ER_4x_LTF_GI_STADEF},
-	{WNI_CFG_HE_NSS,
+
+	{WNI_CFG_HE_RX_MCS_MAP_LT_80,
+	CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT,
+	WNI_CFG_HE_RX_MCS_MAP_LT_80_MIN, WNI_CFG_HE_RX_MCS_MAP_LT_80_MAX,
+	WNI_CFG_HE_RX_MCS_MAP_LT_80_DEF},
+
+	{WNI_CFG_HE_TX_MCS_MAP_LT_80,
 	CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT,
-	WNI_CFG_HE_NSS_STAMIN, WNI_CFG_HE_NSS_STAMAX,
-	WNI_CFG_HE_NSS_STADEF},
-	{WNI_CFG_HE_MCS,
+	WNI_CFG_HE_TX_MCS_MAP_LT_80_MIN, WNI_CFG_HE_TX_MCS_MAP_LT_80_MAX,
+	WNI_CFG_HE_TX_MCS_MAP_LT_80_DEF},
+
+	{WNI_CFG_HE_RX_MCS_MAP_160,
+	CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT,
+	WNI_CFG_HE_RX_MCS_MAP_160_MIN, WNI_CFG_HE_RX_MCS_MAP_160_MAX,
+	WNI_CFG_HE_RX_MCS_MAP_160_DEF},
+
+	{WNI_CFG_HE_TX_MCS_MAP_160,
 	CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT,
-	WNI_CFG_HE_MCS_STAMIN, WNI_CFG_HE_MCS_STAMAX,
-	WNI_CFG_HE_MCS_STADEF},
+	WNI_CFG_HE_TX_MCS_MAP_160_MIN, WNI_CFG_HE_TX_MCS_MAP_160_MAX,
+	WNI_CFG_HE_TX_MCS_MAP_160_DEF},
+
+	{WNI_CFG_HE_RX_MCS_MAP_80_80,
+	CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT,
+	WNI_CFG_HE_RX_MCS_MAP_80_80_MIN, WNI_CFG_HE_RX_MCS_MAP_80_80_MAX,
+	WNI_CFG_HE_RX_MCS_MAP_80_80_DEF},
+
+	{WNI_CFG_HE_TX_MCS_MAP_80_80,
+	CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT,
+	WNI_CFG_HE_TX_MCS_MAP_80_80_MIN, WNI_CFG_HE_TX_MCS_MAP_80_80_MAX,
+	WNI_CFG_HE_TX_MCS_MAP_80_80_DEF},
+
 	{WNI_CFG_HE_PPET,
 	CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE,
 	0, 0, 0},

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

@@ -1778,7 +1778,7 @@ lim_populate_peer_rate_set(tpAniSirGlobal pMac,
 			psessionEntry, psessionEntry->nss);
 
 	if (IS_DOT11_MODE_HE(psessionEntry->dot11mode) && he_caps) {
-		psessionEntry->nss = he_caps->nss_supported;
+		HE_GET_NSS(he_caps->rx_he_mcs_map_lt_80, psessionEntry->nss);
 	} else if (IS_DOT11_MODE_VHT(psessionEntry->dot11mode)) {
 		if ((pRates->vhtRxMCSMap & MCSMAPMASK2x2) == MCSMAPMASK2x2)
 			psessionEntry->nss = NSS_1x1_MODE;

+ 6 - 5
core/mac/src/pe/lim/lim_process_sme_req_messages.c

@@ -1726,11 +1726,6 @@ __lim_process_sme_join_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf)
 					session->vht_config.su_beam_former);
 		}
 
-		if (IS_DOT11_MODE_HE(session->dot11mode)) {
-			lim_update_session_he_capable(mac_ctx, session);
-			lim_copy_join_req_he_cap(session, sme_join_req);
-		}
-
 		pe_debug("vhtCapability: %d su_beam_formee: %d txbf_csn_value: %d su_tx_bformer %d",
 				session->vhtCapability,
 				session->vht_config.su_beam_formee,
@@ -1763,6 +1758,12 @@ __lim_process_sme_join_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf)
 			session->ch_width = CH_WIDTH_20MHZ;
 		}
 
+		if (IS_DOT11_MODE_HE(session->dot11mode)) {
+			lim_update_session_he_capable(mac_ctx, session);
+			lim_copy_join_req_he_cap(session, sme_join_req);
+		}
+
+
 		/* Record if management frames need to be protected */
 #ifdef WLAN_FEATURE_11W
 		if (eSIR_ED_AES_128_CMAC == sme_join_req->MgmtEncryptionType)

+ 151 - 82
core/mac/src/pe/lim/lim_utils.c

@@ -7388,10 +7388,23 @@ void lim_copy_join_req_he_cap(tpPESession session,
 {
 	qdf_mem_copy(&(session->he_config), &(sme_join_req->he_config),
 		     sizeof(session->he_config));
+
+	if (session->ch_width <= CH_WIDTH_80MHZ) {
+		*(uint16_t *)session->he_config.rx_he_mcs_map_160 =
+							HE_MCS_ALL_DISABLED;
+		*(uint16_t *)session->he_config.tx_he_mcs_map_160 =
+							HE_MCS_ALL_DISABLED;
+		*(uint16_t *)session->he_config.rx_he_mcs_map_80_80 =
+							HE_MCS_ALL_DISABLED;
+		*(uint16_t *)session->he_config.tx_he_mcs_map_80_80 =
+							HE_MCS_ALL_DISABLED;
+	}
 }
 
 void lim_log_he_cap(tpAniSirGlobal mac, tDot11fIEhe_cap *he_cap)
 {
+	uint8_t chan_width;
+
 	if (!he_cap->present)
 		return;
 
@@ -7448,8 +7461,12 @@ void lim_log_he_cap(tpAniSirGlobal mac, tDot11fIEhe_cap *he_cap)
 
 	/* HE PHY capabilities */
 	pe_debug("\tDual band support: 0x%01x", he_cap->dual_band);
-	pe_debug("\tChannel width support: 0x%07x",
-			he_cap->chan_width);
+	chan_width = HE_CH_WIDTH_COMBINE(he_cap->chan_width_0,
+			he_cap->chan_width_1, he_cap->chan_width_2,
+			he_cap->chan_width_3, he_cap->chan_width_4,
+			he_cap->chan_width_5, he_cap->chan_width_6);
+
+	pe_debug("\tChannel width support: 0x%07x", chan_width);
 	pe_debug("\tPreamble puncturing Rx: 0x%04x",
 			he_cap->rx_pream_puncturing);
 	pe_debug("\tClass of device: 0x%01x", he_cap->device_class);
@@ -7501,12 +7518,18 @@ void lim_log_he_cap(tpAniSirGlobal mac, tDot11fIEhe_cap *he_cap)
 	pe_debug("\tMax Nc: 0x%03x", he_cap->max_nc);
 	pe_debug("\tER 4x HE LTF support: 0x%01x", he_cap->er_he_ltf_800_gi_4x);
 
-	pe_debug("\tHighest NSS supported: 0x%03x",
-			he_cap->nss_supported);
-	pe_debug("\tHighest MCS supported: 0x%03x",
-			he_cap->mcs_supported);
-	pe_debug("\tTX BW bitmap: 0x%05x", he_cap->tx_bw_bitmap);
-	pe_debug("\tRX BW bitmap: 0x%05x ", he_cap->rx_bw_bitmap);
+	pe_debug("\tRx MCS map for <= 80 Mhz: 0x%04x",
+		he_cap->rx_he_mcs_map_lt_80);
+	pe_debug("\tTx MCS map for <= 80 Mhz: 0x%04x",
+		he_cap->tx_he_mcs_map_lt_80);
+	pe_debug("\tRx MCS map for <= 160 Mhz: 0x%04x",
+		*((uint16_t *)he_cap->rx_he_mcs_map_160));
+	pe_debug("\tTx MCS map for <= 160 Mhz: 0x%04x",
+		*((uint16_t *)he_cap->tx_he_mcs_map_160));
+	pe_debug("\tRx MCS map for <= 80+80 Mhz: 0x%04x",
+		*((uint16_t *)he_cap->rx_he_mcs_map_80_80));
+	pe_debug("\tTx MCS map for <= 80+80 Mhz: 0x%04x",
+		*((uint16_t *)he_cap->tx_he_mcs_map_80_80));
 
 	/* HE PPET */
 	if (!he_cap->ppet_present)
@@ -7630,7 +7653,12 @@ void lim_set_he_caps(tpAniSirGlobal mac, tpPESession session, uint8_t *ie_start,
 		he_cap->reserved1 = dot11_cap.reserved1;
 
 		he_cap->dual_band = dot11_cap.dual_band;
-		he_cap->chan_width = dot11_cap.chan_width;
+
+		he_cap->chan_width = HE_CH_WIDTH_COMBINE(dot11_cap.chan_width_0,
+				dot11_cap.chan_width_1, dot11_cap.chan_width_2,
+				dot11_cap.chan_width_3, dot11_cap.chan_width_4,
+				dot11_cap.chan_width_5, dot11_cap.chan_width_6);
+
 		he_cap->rx_pream_puncturing = dot11_cap.rx_pream_puncturing;
 		he_cap->device_class = dot11_cap.device_class;
 		he_cap->ldpc_coding = dot11_cap.ldpc_coding;
@@ -7667,40 +7695,46 @@ void lim_set_he_caps(tpAniSirGlobal mac, tpPESession session, uint8_t *ie_start,
 		he_cap->er_he_ltf_800_gi_4x = dot11_cap.er_he_ltf_800_gi_4x;
 		he_cap->reserved2 = dot11_cap.reserved2;
 
-		he_cap->nss_supported = dot11_cap.nss_supported;
-		he_cap->mcs_supported = dot11_cap.mcs_supported;
-		he_cap->tx_bw_bitmap = dot11_cap.tx_bw_bitmap;
-		he_cap->rx_bw_bitmap = dot11_cap.rx_bw_bitmap;
+		he_cap->rx_he_mcs_map_lt_80 = dot11_cap.rx_he_mcs_map_lt_80;
+		he_cap->tx_he_mcs_map_lt_80 = dot11_cap.tx_he_mcs_map_lt_80;
+		he_cap->rx_he_mcs_map_160 =
+				*((uint16_t *)dot11_cap.rx_he_mcs_map_160);
+		he_cap->tx_he_mcs_map_160 =
+				*((uint16_t *)dot11_cap.tx_he_mcs_map_160);
+		he_cap->rx_he_mcs_map_80_80 =
+				*((uint16_t *)dot11_cap.rx_he_mcs_map_80_80);
+		he_cap->tx_he_mcs_map_80_80 =
+				*((uint16_t *)dot11_cap.tx_he_mcs_map_80_80);
 	}
 }
 
 QDF_STATUS lim_send_he_caps_ie(tpAniSirGlobal mac_ctx, tpPESession session,
 			       uint8_t vdev_id)
 {
-	uint8_t he_caps[DOT11F_IE_HE_CAP_MIN_LEN + 3];
+	uint8_t he_caps[SIR_MAC_HE_CAP_MIN_LEN + 3];
 	struct he_capability_info *he_cap;
 	QDF_STATUS status_5g, status_2g;
 
 	/* Sending only minimal info(no PPET) to FW now, update if required */
-	qdf_mem_zero(he_caps, DOT11F_IE_HE_CAP_MIN_LEN + 3);
+	qdf_mem_zero(he_caps, SIR_MAC_HE_CAP_MIN_LEN + 3);
 	he_caps[0] = DOT11F_EID_HE_CAP;
-	he_caps[1] = DOT11F_IE_HE_CAP_MIN_LEN;
+	he_caps[1] = SIR_MAC_HE_CAP_MIN_LEN;
 	qdf_mem_copy(&he_caps[2], HE_CAP_OUI_TYPE, HE_CAP_OUI_SIZE);
 	lim_set_he_caps(mac_ctx, session, he_caps,
-			DOT11F_IE_HE_CAP_MIN_LEN + 3);
+			SIR_MAC_HE_CAP_MIN_LEN + 3);
 	he_cap = (struct he_capability_info *) (&he_caps[2 + HE_CAP_OUI_SIZE]);
 	he_cap->ppet_present = 0;
 
 	status_5g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_HE_CAP,
 			CDS_BAND_5GHZ, &he_caps[2],
-			DOT11F_IE_HE_CAP_MIN_LEN + 1);
+			SIR_MAC_HE_CAP_MIN_LEN + 1);
 	if (QDF_IS_STATUS_ERROR(status_5g))
 		pe_err("Unable send HE Cap IE for 5GHZ band, status: %d",
 			status_5g);
 
 	status_2g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_HE_CAP,
 			CDS_BAND_2GHZ, &he_caps[2],
-			DOT11F_IE_HE_CAP_MIN_LEN + 1);
+			SIR_MAC_HE_CAP_MIN_LEN + 1);
 	if (QDF_IS_STATUS_ERROR(status_2g))
 		pe_err("Unable send HE Cap IE for 2GHZ band, status: %d",
 			status_2g);
@@ -7713,64 +7747,88 @@ QDF_STATUS lim_send_he_caps_ie(tpAniSirGlobal mac_ctx, tpPESession session,
 }
 
 /**
- * MCS-NSS Map will be as follows - Each MCS is 3 bits
- *  - 0 indicates support for HE-MCS 0-7 for n spatial streams
- *  - 1 indicates support for HE-MCS 0-8 for n spatial streams
- *  - 2 indicates support for HE-MCS 0-9 for n spatial streams
- *  - 3 indicates support for HE-MCS 0-10 for n spatial streams
- *  - 4 indicates support for HE-MCS 0-11 for n spatial streams
- *  - 5-6 reserved
- *  - 7 indicates that n spatial streams is not supported
- * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-
- * |  SS |  8  |  7  |  6  |  5  |  4  |  3  |  2  |  1  |
- * +-----+-----+-----+-----+-----+-----+-----+-----+-----+
- * | MCS |   7 |  7  |  7  |  7  |  7  |  7  |  4  |  4  |
- * +-----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * lim_populate_he_mcs_per_bw() - pouldate HE mcs set per BW (le 80, 160, 80+80)
+ * @mac_ctx: Global MAC context
+ * @self_rx: self rx mcs set
+ * @self_tx: self tx mcs set
+ * @peer_rx: peer rx mcs set
+ * @peer_tx: peer tx mcs set
+ * @nss: nss
+ * @cfg_rx_param: rx wni param to read
+ * @cfg_tx_param: tx wni param to read
+ *
+ * MCS values are interpreted as in IEEE 11ax-D1.4 spec onwards
+ * +-----------------------------------------------------+
+ * |  SS8  |  SS7  |  SS6  | SS5 | SS4 | SS3 | SS2 | SS1 |
+ * +-----------------------------------------------------+
+ * | 15-14 | 13-12 | 11-10 | 9-8 | 7-6 | 5-4 | 3-2 | 1-0 |
+ * +-----------------------------------------------------+
+ *
+ * Return: status of operation
  */
+static QDF_STATUS lim_populate_he_mcs_per_bw(tpAniSirGlobal mac_ctx,
+				uint16_t *self_rx, uint16_t *self_tx,
+				uint16_t peer_rx, uint16_t peer_tx, uint8_t nss,
+				uint32_t cfg_rx_param, uint32_t cfg_tx_param)
+{
+	uint32_t val;
+
+	pe_debug("peer rates: rx_mcs - 0x%04x tx_mcs - 0x%04x",
+		 peer_rx, peer_tx);
+	if (wlan_cfg_get_int(mac_ctx, cfg_rx_param, &val) != eSIR_SUCCESS) {
+		pe_err("could not retrieve HE_MCS");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*self_rx = (uint16_t) val;
+	if (wlan_cfg_get_int(mac_ctx, cfg_tx_param, &val) != eSIR_SUCCESS) {
+		pe_err("could not retrieve HE_MCS");
+		return QDF_STATUS_E_FAILURE;
+	}
+	*self_tx = (uint16_t) val;
+
+	*self_rx = HE_INTERSECT_MCS(*self_rx, peer_tx);
+	*self_tx = HE_INTERSECT_MCS(*self_tx, peer_rx);
+
+	if (nss == NSS_1x1_MODE) {
+		*self_rx |= HE_MCS_INV_MSK_4_NSS(1);
+		*self_tx |= HE_MCS_INV_MSK_4_NSS(1);
+	}
+	/* if nss is 2, disable higher NSS */
+	if (nss == NSS_2x2_MODE) {
+		*self_rx |= (HE_MCS_INV_MSK_4_NSS(1) & HE_MCS_INV_MSK_4_NSS(2));
+		*self_tx |= (HE_MCS_INV_MSK_4_NSS(1) & HE_MCS_INV_MSK_4_NSS(2));
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 QDF_STATUS lim_populate_he_mcs_set(tpAniSirGlobal mac_ctx,
 				   tpSirSupportedRates rates,
 				   tDot11fIEhe_cap *peer_he_caps,
 				   tpPESession session_entry, uint8_t nss)
 {
-	uint32_t val;
-	uint32_t self_sta_dot11mode = 0;
-	uint8_t self_mcs, peer_mcs, negotiated_mcs;
-	uint32_t mcsmap = 0xFFFFFFFF;
 	bool support_2x2 = false;
+	uint32_t self_sta_dot11mode = 0;
 
 	wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_sta_dot11mode);
 
 	if (!IS_DOT11_MODE_HE(self_sta_dot11mode))
 		return QDF_STATUS_SUCCESS;
 
-	if (wlan_cfg_get_int(mac_ctx, WNI_CFG_HE_MCS, &val) != eSIR_SUCCESS) {
-		pe_err("could not retrieve HE_MCS");
-		goto error;
-	}
-
-	self_mcs = (uint16_t) val;
-	if (NSS_1x1_MODE == nss) {
-		/* Add MCS for SS-1 */
-		mcsmap = self_mcs;
-		mcsmap |= HE_MCS_1x1;
-	} else if (NSS_2x2_MODE == nss) {
-		/* Add MCS for SS-1 */
-		mcsmap = self_mcs;
-		/* Add MCS for SS-2 */
-		mcsmap |= (self_mcs << HEMCSSIZE);
-		mcsmap |= HE_MCS_2x2;
-
-	}
-	rates->he_rx_mcs = rates->he_tx_mcs = mcsmap;
-
 	if ((peer_he_caps == NULL) || (!peer_he_caps->present)) {
-		pe_debug("self rate: nss %d he_rx_mcs - %x he_tx_mcs - %x",
-			nss, rates->he_rx_mcs, rates->he_tx_mcs);
+		pe_debug("peer not he capable or he_caps NULL");
 		return QDF_STATUS_SUCCESS;
 	}
 
-	pe_debug("peer rates: rx_mcs - %x tx_mcs - %x",
-		peer_he_caps->mcs_supported, peer_he_caps->mcs_supported);
+	pe_debug("peer rates lt 80: rx_mcs - 0x%04x tx_mcs - 0x%04x",
+		peer_he_caps->rx_he_mcs_map_lt_80,
+		peer_he_caps->tx_he_mcs_map_lt_80);
+	pe_debug("peer rates 160: rx_mcs - 0x%04x tx_mcs - 0x%04x",
+		(*(uint16_t *)peer_he_caps->rx_he_mcs_map_160),
+		(*(uint16_t *)peer_he_caps->tx_he_mcs_map_160));
+	pe_debug("peer rates 80+80: rx_mcs - 0x%04x tx_mcs - 0x%04x",
+		(*(uint16_t *)peer_he_caps->rx_he_mcs_map_80_80),
+		(*(uint16_t *)peer_he_caps->tx_he_mcs_map_80_80));
 
 	if (session_entry && session_entry->nss == NSS_2x2_MODE) {
 		if (mac_ctx->lteCoexAntShare &&
@@ -7785,29 +7843,40 @@ QDF_STATUS lim_populate_he_mcs_set(tpAniSirGlobal mac_ctx,
 		}
 	}
 
-	peer_mcs = peer_he_caps->mcs_supported;
-	negotiated_mcs = QDF_MIN(peer_mcs, self_mcs);
-
-	if (support_2x2) {
-		/* Add MCS for SS-1 */
-		mcsmap = negotiated_mcs;
-		/* Add MCS for SS-2 */
-		mcsmap |= (negotiated_mcs << HEMCSSIZE);
-		mcsmap |= HE_MCS_2x2;
-	} else {
-		/* Add MCS for SS-1 */
-		mcsmap = negotiated_mcs;
-		mcsmap |= HE_MCS_1x1;
-	}
-	rates->he_rx_mcs = rates->he_tx_mcs = mcsmap;
-
-	pe_debug("enable2x2 - %d nss %d he_rx_mcs - %x he_tx_mcs - %x",
-		mac_ctx->roam.configParam.enable2x2, nss,
-		rates->he_rx_mcs, rates->he_tx_mcs);
-
+	lim_populate_he_mcs_per_bw(mac_ctx,
+		&rates->rx_he_mcs_map_lt_80, &rates->tx_he_mcs_map_lt_80,
+		peer_he_caps->rx_he_mcs_map_lt_80,
+		peer_he_caps->tx_he_mcs_map_lt_80, nss,
+		WNI_CFG_HE_RX_MCS_MAP_LT_80, WNI_CFG_HE_TX_MCS_MAP_LT_80);
+	lim_populate_he_mcs_per_bw(mac_ctx,
+		&rates->rx_he_mcs_map_160, &rates->tx_he_mcs_map_160,
+		*((uint16_t *)peer_he_caps->rx_he_mcs_map_160),
+		*((uint16_t *)peer_he_caps->tx_he_mcs_map_160), nss,
+		WNI_CFG_HE_RX_MCS_MAP_160, WNI_CFG_HE_TX_MCS_MAP_160);
+	lim_populate_he_mcs_per_bw(mac_ctx,
+		&rates->rx_he_mcs_map_80_80, &rates->tx_he_mcs_map_80_80,
+		*((uint16_t *)peer_he_caps->rx_he_mcs_map_80_80),
+		*((uint16_t *)peer_he_caps->tx_he_mcs_map_80_80), nss,
+		WNI_CFG_HE_RX_MCS_MAP_80_80, WNI_CFG_HE_TX_MCS_MAP_80_80);
+	if (!support_2x2) {
+		/* disable 2 and higher NSS MCS sets */
+		rates->rx_he_mcs_map_lt_80 |= 0xFFFD;
+		rates->tx_he_mcs_map_lt_80 |= 0xFFFD;
+		rates->rx_he_mcs_map_160 |= 0xFFFD;
+		rates->tx_he_mcs_map_160 |= 0xFFFD;
+		rates->rx_he_mcs_map_80_80 |= 0xFFFD;
+		rates->tx_he_mcs_map_80_80 |= 0xFFFD;
+	}
+
+	pe_debug("enable2x2 - %d nss %d",
+		mac_ctx->roam.configParam.enable2x2, nss);
+	pe_debug("he_rx_lt_80 - 0x%x he_tx_lt_80 0x%x",
+		rates->rx_he_mcs_map_lt_80, rates->tx_he_mcs_map_lt_80);
+	pe_debug("he_rx_160 - 0x%x he_tx_160 0x%x",
+		rates->rx_he_mcs_map_160, rates->tx_he_mcs_map_160);
+	pe_debug("he_rx_80_80 - 0x%x he_tx_80_80 0x%x",
+		rates->rx_he_mcs_map_80_80, rates->tx_he_mcs_map_80_80);
 	return QDF_STATUS_SUCCESS;
-error:
-	return QDF_STATUS_E_FAILURE;
 }
 #endif
 

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

@@ -855,6 +855,7 @@ void lim_copy_bss_he_cap(tpPESession session,
 
 /**
  * lim_copy_join_req_he_cap() - Copy HE capability to PE session from Join req
+ * and update as per bandwidth supported
  * @session: pointer to PE session
  * @sme_join_req: pointer to SME join request
  *

+ 25 - 5
core/mac/src/sys/legacy/src/utils/src/parser_api.c

@@ -6118,7 +6118,14 @@ QDF_STATUS populate_dot11f_he_caps(tpAniSirGlobal mac_ctx, tpPESession session,
 		CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_DUAL_BAND, value);
 		he_cap->dual_band = value;
 		CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_CHAN_WIDTH, value);
-		he_cap->chan_width = value;
+		he_cap->chan_width_0 = HE_CH_WIDTH_GET_BIT(value, 0);
+		he_cap->chan_width_1 = HE_CH_WIDTH_GET_BIT(value, 1);
+		he_cap->chan_width_2 = HE_CH_WIDTH_GET_BIT(value, 2);
+		he_cap->chan_width_3 = HE_CH_WIDTH_GET_BIT(value, 3);
+		he_cap->chan_width_4 = HE_CH_WIDTH_GET_BIT(value, 4);
+		he_cap->chan_width_5 = HE_CH_WIDTH_GET_BIT(value, 5);
+		he_cap->chan_width_6 = HE_CH_WIDTH_GET_BIT(value, 6);
+
 		CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_RX_PREAM_PUNC, value);
 		he_cap->rx_pream_puncturing = value;
 		CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_CLASS_OF_DEVICE, value);
@@ -6183,10 +6190,23 @@ QDF_STATUS populate_dot11f_he_caps(tpAniSirGlobal mac_ctx, tpPESession session,
 		he_cap->stbc_gt_80mhz = value;
 		CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_ER_4x_LTF_GI, value);
 		he_cap->er_he_ltf_800_gi_4x = value;
-		CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_NSS, value);
-		he_cap->nss_supported = value;
-		CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_MCS, value);
-		he_cap->mcs_supported = value;
+
+		CFG_GET_INT(status, mac_ctx,
+			WNI_CFG_HE_RX_MCS_MAP_LT_80, value);
+		he_cap->rx_he_mcs_map_lt_80 = value;
+		CFG_GET_INT(status, mac_ctx,
+			WNI_CFG_HE_TX_MCS_MAP_LT_80, value);
+		he_cap->tx_he_mcs_map_lt_80 = value;
+		CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_RX_MCS_MAP_160, value);
+		*((uint16_t *)he_cap->rx_he_mcs_map_160) = value;
+		CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_TX_MCS_MAP_160, value);
+		*((uint16_t *)he_cap->tx_he_mcs_map_160) = value;
+		CFG_GET_INT(status, mac_ctx,
+			WNI_CFG_HE_RX_MCS_MAP_80_80, value);
+		*((uint16_t *)he_cap->rx_he_mcs_map_80_80) = value;
+		CFG_GET_INT(status, mac_ctx,
+			WNI_CFG_HE_TX_MCS_MAP_80_80, value);
+		*((uint16_t *)he_cap->tx_he_mcs_map_80_80) = value;
 
 		if (he_cap->ppet_present) {
 			value = WNI_CFG_HE_PPET_LEN;

+ 21 - 5
core/sme/src/csr/csr_api_roam.c

@@ -2329,7 +2329,14 @@ static void csr_update_session_he_cap(tpAniSirGlobal mac_ctx,
 	sme_cfg_get_int(mac_ctx, WNI_CFG_HE_DUAL_BAND, &value);
 	he_cap->dual_band = value;
 	sme_cfg_get_int(mac_ctx, WNI_CFG_HE_CHAN_WIDTH, &value);
-	he_cap->chan_width = value;
+	he_cap->chan_width_0 = HE_CH_WIDTH_GET_BIT(value, 0);
+	he_cap->chan_width_1 = HE_CH_WIDTH_GET_BIT(value, 1);
+	he_cap->chan_width_2 = HE_CH_WIDTH_GET_BIT(value, 2);
+	he_cap->chan_width_3 = HE_CH_WIDTH_GET_BIT(value, 3);
+	he_cap->chan_width_4 = HE_CH_WIDTH_GET_BIT(value, 4);
+	he_cap->chan_width_5 = HE_CH_WIDTH_GET_BIT(value, 5);
+	he_cap->chan_width_6 = HE_CH_WIDTH_GET_BIT(value, 6);
+
 	sme_cfg_get_int(mac_ctx, WNI_CFG_HE_RX_PREAM_PUNC, &value);
 	he_cap->rx_pream_puncturing = value;
 	sme_cfg_get_int(mac_ctx, WNI_CFG_HE_CLASS_OF_DEVICE, &value);
@@ -2394,10 +2401,19 @@ static void csr_update_session_he_cap(tpAniSirGlobal mac_ctx,
 	he_cap->stbc_gt_80mhz = value;
 	sme_cfg_get_int(mac_ctx, WNI_CFG_HE_ER_4x_LTF_GI, &value);
 	he_cap->er_he_ltf_800_gi_4x = value;
-	sme_cfg_get_int(mac_ctx, WNI_CFG_HE_NSS, &value);
-	he_cap->nss_supported = value;
-	sme_cfg_get_int(mac_ctx, WNI_CFG_HE_MCS, &value);
-	he_cap->mcs_supported = value;
+
+	sme_cfg_get_int(mac_ctx, WNI_CFG_HE_RX_MCS_MAP_LT_80, &value);
+	he_cap->rx_he_mcs_map_lt_80 = value;
+	sme_cfg_get_int(mac_ctx, WNI_CFG_HE_TX_MCS_MAP_LT_80, &value);
+	he_cap->tx_he_mcs_map_lt_80 = value;
+	sme_cfg_get_int(mac_ctx, WNI_CFG_HE_RX_MCS_MAP_160, &value);
+	*((uint16_t *)he_cap->rx_he_mcs_map_160) = value;
+	sme_cfg_get_int(mac_ctx, WNI_CFG_HE_TX_MCS_MAP_160, &value);
+	*((uint16_t *)he_cap->tx_he_mcs_map_160) = value;
+	sme_cfg_get_int(mac_ctx, WNI_CFG_HE_RX_MCS_MAP_80_80, &value);
+	*((uint16_t *)he_cap->rx_he_mcs_map_80_80) = value;
+	sme_cfg_get_int(mac_ctx, WNI_CFG_HE_TX_MCS_MAP_80_80, &value);
+	*((uint16_t *)he_cap->tx_he_mcs_map_80_80) = value;
 
 	if (he_cap->ppet_present) {
 		value = WNI_CFG_HE_PPET_LEN;

+ 122 - 43
core/wma/src/wma_he.c

@@ -194,21 +194,14 @@ static void wma_convert_he_cap(tDot11fIEhe_cap *he_cap, uint32_t mac_cap,
 			       uint32_t supp_mcs, uint32_t tx_chain_mask,
 			       uint32_t rx_chain_mask)
 {
+	uint8_t nss, chan_width;
+	uint16_t rx_mcs_le_80, tx_mcs_le_80, rx_mcs_160, tx_mcs_160;
 	struct wmi_host_ppe_threshold *ppet = he_ppet;
-	uint8_t mcs, nss, k, mcs_temp;
 
 	nss = QDF_MAX(wma_get_num_of_setbits_from_bitmask(tx_chain_mask),
-		      wma_get_num_of_setbits_from_bitmask(rx_chain_mask));
-
-	mcs = 0;
-	for (k = 1; k < nss; k++) {
-		mcs_temp = WMI_HE_MAX_MCS_4_SS_MASK(supp_mcs, k);
-		if (mcs_temp > mcs)
-			mcs = mcs_temp;
-	}
+			wma_get_num_of_setbits_from_bitmask(rx_chain_mask));
 
 	he_cap->present = true;
-
 	/* HE MAC capabilities */
 	he_cap->htc_he = WMI_HECAP_MAC_HECTRL_GET(mac_cap);
 	he_cap->twt_request = WMI_HECAP_MAC_TWTREQ_GET(mac_cap);
@@ -242,7 +235,14 @@ static void wma_convert_he_cap(tDot11fIEhe_cap *he_cap, uint32_t mac_cap,
 
 	/* HE PHY capabilities */
 	he_cap->dual_band = WMI_HECAP_PHY_DB_GET(phy_cap);
-	he_cap->chan_width = WMI_HECAP_PHY_CBW_GET(phy_cap);
+	chan_width = WMI_HECAP_PHY_CBW_GET(phy_cap);
+	he_cap->chan_width_0 = HE_CH_WIDTH_GET_BIT(chan_width, 0);
+	he_cap->chan_width_1 = HE_CH_WIDTH_GET_BIT(chan_width, 1);
+	he_cap->chan_width_2 = HE_CH_WIDTH_GET_BIT(chan_width, 2);
+	he_cap->chan_width_3 = HE_CH_WIDTH_GET_BIT(chan_width, 3);
+	he_cap->chan_width_4 = HE_CH_WIDTH_GET_BIT(chan_width, 4);
+	he_cap->chan_width_5 = HE_CH_WIDTH_GET_BIT(chan_width, 5);
+	he_cap->chan_width_6 = HE_CH_WIDTH_GET_BIT(chan_width, 6);
 	he_cap->rx_pream_puncturing = WMI_HECAP_PHY_PREAMBLEPUNCRX_GET(phy_cap);
 	he_cap->device_class = WMI_HECAP_PHY_COD_GET(phy_cap);
 	he_cap->ldpc_coding = WMI_HECAP_PHY_LDPC_GET(phy_cap);
@@ -287,12 +287,28 @@ static void wma_convert_he_cap(tDot11fIEhe_cap *he_cap, uint32_t mac_cap,
 	he_cap->er_he_ltf_800_gi_4x =
 			WMI_HECAP_PHY_ERSU4X800NSECGI_GET(phy_cap);
 
-	he_cap->nss_supported = nss - 1;
-	he_cap->mcs_supported = mcs;
-
-	/* For Draft 1.0, following fields will be zero */
-	he_cap->tx_bw_bitmap = 0;
-	he_cap->rx_bw_bitmap = 0;
+	/*
+	 * supp_mcs is split into 16 bits with lower indicating le_80 and
+	 * upper indicating 160 and 80_80.
+	 */
+	WMA_LOGD(FL("supported_mcs: 0x%08x\n"), supp_mcs);
+	rx_mcs_le_80 = supp_mcs & 0xFFFF;
+	tx_mcs_le_80 = supp_mcs & 0xFFFF;
+	rx_mcs_160 = (supp_mcs & 0xFFFF0000) >> 16;
+	tx_mcs_160 = (supp_mcs & 0xFFFF0000) >> 16;
+	/* if FW indicated it is using 1x1 disable upper NSS-MCS sets */
+	if (nss == NSS_1x1_MODE) {
+		rx_mcs_le_80 |= HE_MCS_INV_MSK_4_NSS(1);
+		tx_mcs_le_80 |= HE_MCS_INV_MSK_4_NSS(1);
+		rx_mcs_160 |= HE_MCS_INV_MSK_4_NSS(1);
+		tx_mcs_160 |= HE_MCS_INV_MSK_4_NSS(1);
+	}
+	he_cap->rx_he_mcs_map_lt_80 = rx_mcs_le_80;
+	he_cap->tx_he_mcs_map_lt_80 = tx_mcs_le_80;
+	*((uint16_t *)he_cap->tx_he_mcs_map_160) = rx_mcs_160;
+	*((uint16_t *)he_cap->rx_he_mcs_map_160) = tx_mcs_160;
+	*((uint16_t *)he_cap->rx_he_mcs_map_80_80) = rx_mcs_160;
+	*((uint16_t *)he_cap->tx_he_mcs_map_80_80) = tx_mcs_160;
 
 	wma_convert_he_ppet(&he_cap->ppe_threshold, ppet);
 }
@@ -313,6 +329,8 @@ static void wma_convert_he_cap(tDot11fIEhe_cap *he_cap, uint32_t mac_cap,
 static void wma_derive_ext_he_cap(t_wma_handle *wma_handle,
 		tDot11fIEhe_cap *he_cap, tDot11fIEhe_cap *new_cap)
 {
+	uint16_t mcs_1, mcs_2;
+
 	if (!he_cap->present) {
 		/* First time update, copy the capability as is */
 		qdf_mem_copy(he_cap, new_cap, sizeof(*he_cap));
@@ -375,8 +393,22 @@ static void wma_derive_ext_he_cap(t_wma_handle *wma_handle,
 
 		he_cap->dual_band = QDF_MIN(he_cap->dual_band,
 					    new_cap->dual_band);
-		he_cap->chan_width = QDF_MIN(he_cap->chan_width,
-					     new_cap->chan_width);
+
+		he_cap->chan_width_0 = he_cap->chan_width_0 &
+						new_cap->chan_width_0;
+		he_cap->chan_width_1 = he_cap->chan_width_1 &
+						new_cap->chan_width_1;
+		he_cap->chan_width_2 = he_cap->chan_width_2 &
+						new_cap->chan_width_2;
+		he_cap->chan_width_3 = he_cap->chan_width_3 &
+						new_cap->chan_width_3;
+		he_cap->chan_width_4 = he_cap->chan_width_4 &
+						new_cap->chan_width_4;
+		he_cap->chan_width_5 = he_cap->chan_width_5 &
+						new_cap->chan_width_5;
+		he_cap->chan_width_6 = he_cap->chan_width_6 &
+						new_cap->chan_width_6;
+
 		he_cap->rx_pream_puncturing =
 			QDF_MIN(he_cap->rx_pream_puncturing,
 				new_cap->rx_pream_puncturing);
@@ -438,20 +470,37 @@ static void wma_derive_ext_he_cap(t_wma_handle *wma_handle,
 					       new_cap->he_ltf_800_gi_4x);
 		he_cap->reserved2 = QDF_MIN(he_cap->reserved2,
 					    new_cap->reserved2);
-		he_cap->nss_supported = QDF_MIN(he_cap->nss_supported,
-						new_cap->nss_supported);
-		he_cap->mcs_supported = QDF_MIN(he_cap->mcs_supported,
-						new_cap->mcs_supported);
-		he_cap->tx_bw_bitmap = QDF_MIN(he_cap->tx_bw_bitmap,
-					       new_cap->tx_bw_bitmap);
-		he_cap->rx_bw_bitmap = QDF_MIN(he_cap->rx_bw_bitmap,
-					       new_cap->rx_bw_bitmap);
 
+		/* take intersection for MCS map */
+		mcs_1 = he_cap->rx_he_mcs_map_lt_80;
+		mcs_2 = new_cap->rx_he_mcs_map_lt_80;
+		he_cap->rx_he_mcs_map_lt_80 = HE_INTERSECT_MCS(mcs_1, mcs_2);
+		mcs_1 = he_cap->tx_he_mcs_map_lt_80;
+		mcs_2 = new_cap->tx_he_mcs_map_lt_80;
+		he_cap->tx_he_mcs_map_lt_80 = HE_INTERSECT_MCS(mcs_1, mcs_2);
+		mcs_1 = *((uint16_t *)he_cap->rx_he_mcs_map_160);
+		mcs_2 = *((uint16_t *)new_cap->rx_he_mcs_map_160);
+		*((uint16_t *)he_cap->rx_he_mcs_map_160) =
+						HE_INTERSECT_MCS(mcs_1, mcs_2);
+		mcs_1 = *((uint16_t *)he_cap->tx_he_mcs_map_160);
+		mcs_2 = *((uint16_t *)new_cap->tx_he_mcs_map_160);
+		*((uint16_t *)he_cap->tx_he_mcs_map_160) =
+						HE_INTERSECT_MCS(mcs_1, mcs_2);
+		mcs_1 = *((uint16_t *)he_cap->rx_he_mcs_map_80_80);
+		mcs_2 = *((uint16_t *)new_cap->rx_he_mcs_map_80_80);
+		*((uint16_t *)he_cap->rx_he_mcs_map_80_80) =
+						HE_INTERSECT_MCS(mcs_1, mcs_2);
+		mcs_1 = *((uint16_t *)he_cap->tx_he_mcs_map_80_80);
+		mcs_2 = *((uint16_t *)new_cap->tx_he_mcs_map_80_80);
+		*((uint16_t *)he_cap->tx_he_mcs_map_80_80) =
+						HE_INTERSECT_MCS(mcs_1, mcs_2);
 	}
 }
 
 void wma_print_he_cap(tDot11fIEhe_cap *he_cap)
 {
+	uint8_t chan_width;
+
 	if (!he_cap->present) {
 		WMA_LOGI(FL("HE Capabilities not present"));
 		return;
@@ -491,7 +540,12 @@ void wma_print_he_cap(tDot11fIEhe_cap *he_cap)
 
 	/* HE PHY capabilities */
 	WMA_LOGD("\tDual band support: 0x%01x", he_cap->dual_band);
-	WMA_LOGD("\tChannel width support: 0x%07x", he_cap->chan_width);
+	chan_width = HE_CH_WIDTH_COMBINE(he_cap->chan_width_0,
+				he_cap->chan_width_1, he_cap->chan_width_2,
+				he_cap->chan_width_3, he_cap->chan_width_4,
+				he_cap->chan_width_5, he_cap->chan_width_6);
+
+	WMA_LOGD("\tChannel width support: 0x%07x", chan_width);
 	WMA_LOGD("\tPreamble puncturing Rx: 0x%04x",
 			he_cap->rx_pream_puncturing);
 	WMA_LOGD("\tClass of device: 0x%01x", he_cap->device_class);
@@ -532,10 +586,18 @@ void wma_print_he_cap(tDot11fIEhe_cap *he_cap)
 	WMA_LOGD("\tPower boost factor: 0x%01x", he_cap->power_boost);
 	WMA_LOGD("\t4x HE LTF support: 0x%01x", he_cap->he_ltf_800_gi_4x);
 
-	WMA_LOGD("\tHighest NSS supported: 0x%03x", he_cap->nss_supported);
-	WMA_LOGD("\tHighest MCS supported: 0x%03x", he_cap->mcs_supported);
-	WMA_LOGD("\tTX BW bitmap: 0x%05x", he_cap->tx_bw_bitmap);
-	WMA_LOGD("\tRX BW bitmap: 0x%05x ", he_cap->rx_bw_bitmap);
+	WMA_LOGD("\tRx MCS MAP for BW <= 80 MHz: 0x%x",
+		he_cap->rx_he_mcs_map_lt_80);
+	WMA_LOGD("\tTx MCS MAP for BW <= 80 MHz: 0x%x",
+		he_cap->tx_he_mcs_map_lt_80);
+	WMA_LOGD("\tRx MCS MAP for BW = 160 MHz: 0x%x",
+		*((uint16_t *)he_cap->rx_he_mcs_map_160));
+	WMA_LOGD("\tTx MCS MAP for BW = 160 MHz: 0x%x",
+		*((uint16_t *)he_cap->tx_he_mcs_map_160));
+	WMA_LOGD("\tRx MCS MAP for BW = 80 + 80 MHz: 0x%x",
+		*((uint16_t *)he_cap->rx_he_mcs_map_80_80));
+	WMA_LOGD("\tTx MCS MAP for BW = 80 + 80 MHz: 0x%x",
+		*((uint16_t *)he_cap->tx_he_mcs_map_80_80));
 
 	/* HE PPET */
 	WMA_LOGD("\tNSS: %d", he_cap->ppe_threshold.nss_count + 1);
@@ -934,7 +996,7 @@ void wma_populate_peer_he_cap(struct peer_assoc_params *peer,
 	tDot11fIEhe_op *he_op = &params->he_op;
 	uint32_t *phy_cap = peer->peer_he_cap_phyinfo;
 	uint32_t mac_cap = 0, he_ops = 0;
-	uint8_t temp, i;
+	uint8_t temp, i, chan_width;
 
 	if (params->he_capable)
 		peer->peer_flags |= WMI_PEER_HE;
@@ -975,7 +1037,11 @@ void wma_populate_peer_he_cap(struct peer_assoc_params *peer,
 
 	/* HE PHY capabilities */
 	WMI_HECAP_PHY_DB_SET(phy_cap, he_cap->dual_band);
-	WMI_HECAP_PHY_CBW_SET(phy_cap, he_cap->chan_width);
+	chan_width = HE_CH_WIDTH_COMBINE(he_cap->chan_width_0,
+				he_cap->chan_width_1, he_cap->chan_width_2,
+				he_cap->chan_width_3, he_cap->chan_width_4,
+				he_cap->chan_width_5, he_cap->chan_width_6);
+	WMI_HECAP_PHY_CBW_SET(phy_cap, chan_width);
 	WMI_HECAP_PHY_PREAMBLEPUNCRX_SET(phy_cap, he_cap->rx_pream_puncturing);
 	WMI_HECAP_PHY_COD_SET(phy_cap, he_cap->device_class);
 	WMI_HECAP_PHY_LDPC_SET(phy_cap, he_cap->ldpc_coding);
@@ -1031,17 +1097,30 @@ void wma_populate_peer_he_cap(struct peer_assoc_params *peer,
 
 	WMI_HECAP_PHY_ERSU4X800NSECGI_SET(phy_cap, he_cap->er_he_ltf_800_gi_4x);
 
-	/* until further update in standard */
-	peer->peer_he_mcs_count = WMI_HOST_MAX_HE_RATE_SET;
-	for (i = 0; i < peer->peer_he_mcs_count; i++) {
-		peer->peer_he_rx_mcs_set[i] = params->supportedRates.he_rx_mcs;
-		peer->peer_he_tx_mcs_set[i] = params->supportedRates.he_tx_mcs;
-
-		WMA_LOGD(FL("[HE - MCS Map: %d] rx_mcs: %x, tx_mcs: %x"), i,
-			 peer->peer_he_rx_mcs_set[i],
-			 peer->peer_he_tx_mcs_set[i]);
+	/* as per 11ax draft 1.4 */
+	peer->peer_he_mcs_count = 1;
+	peer->peer_he_rx_mcs_set[0] =
+		params->supportedRates.rx_he_mcs_map_lt_80;
+	peer->peer_he_tx_mcs_set[0] =
+		params->supportedRates.tx_he_mcs_map_lt_80;
+
+	if (params->ch_width > CH_WIDTH_80MHZ) {
+		peer->peer_he_mcs_count = WMI_HOST_MAX_HE_RATE_SET;
+		peer->peer_he_rx_mcs_set[1] =
+			params->supportedRates.rx_he_mcs_map_160;
+		peer->peer_he_tx_mcs_set[1] =
+			params->supportedRates.tx_he_mcs_map_160;
+		peer->peer_he_rx_mcs_set[2] =
+			params->supportedRates.rx_he_mcs_map_80_80;
+		peer->peer_he_tx_mcs_set[2] =
+			params->supportedRates.tx_he_mcs_map_80_80;
 	}
 
+	for (i = 0; i < peer->peer_he_mcs_count; i++)
+		WMA_LOGD(FL("[HE - MCS Map: %d] rx_mcs: 0x%x, tx_mcs: 0x%x"), i,
+			peer->peer_he_rx_mcs_set[i],
+			peer->peer_he_tx_mcs_set[i]);
+
 	WMI_HEOPS_COLOR_SET(he_ops, he_op->bss_color);
 	WMI_HEOPS_DEFPE_SET(he_ops, he_op->default_pe);
 	WMI_HEOPS_TWT_SET(he_ops, he_op->twt_required);